+ r = bus_match_parse(match, &components, &n_components);
+ if (r < 0)
+ goto finish;
+
+ if (bus->bus_client) {
+ cookie = ++bus->match_cookie;
+
+ r = bus_add_match_internal(bus, match, components, n_components, cookie);
+ if (r < 0)
+ goto finish;
+ }
+
+ bus->match_callbacks_modified = true;
+ r = bus_match_add(&bus->match_callbacks, components, n_components, callback, userdata, cookie, NULL);
+ if (r < 0) {
+ if (bus->bus_client)
+ bus_remove_match_internal(bus, match, cookie);
+ }
+
+finish:
+ bus_match_parse_free(components, n_components);
+ return r;
+}
+
+_public_ int sd_bus_remove_match(sd_bus *bus,
+ const char *match,
+ sd_bus_message_handler_t callback,
+ void *userdata) {
+
+ struct bus_match_component *components = NULL;
+ unsigned n_components = 0;
+ int r = 0, q = 0;
+ uint64_t cookie = 0;
+
+ assert_return(bus, -EINVAL);
+ assert_return(match, -EINVAL);
+ assert_return(!bus_pid_changed(bus), -ECHILD);
+
+ r = bus_match_parse(match, &components, &n_components);
+ if (r < 0)
+ return r;
+
+ bus->match_callbacks_modified = true;
+ r = bus_match_remove(&bus->match_callbacks, components, n_components, callback, userdata, &cookie);
+
+ if (bus->bus_client)
+ q = bus_remove_match_internal(bus, match, cookie);
+
+ bus_match_parse_free(components, n_components);
+
+ return r < 0 ? r : q;
+}
+
+bool bus_pid_changed(sd_bus *bus) {
+ assert(bus);
+
+ /* We don't support people creating a bus connection and
+ * keeping it around over a fork(). Let's complain. */
+
+ return bus->original_pid != getpid();
+}
+
+static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+ sd_bus *bus = userdata;