+static int session_jobs_reply(Session *s, const char *unit, const char *result) {
+ int r = 0;
+
+ assert(s);
+ assert(unit);
+
+ if (!s->started)
+ return r;
+
+ if (streq(result, "done"))
+ r = session_send_create_reply(s, NULL);
+ else {
+ _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
+
+ sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
+ r = session_send_create_reply(s, &e);
+ }
+
+ return r;
+}
+
+int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ const char *path, *result, *unit;
+ Manager *m = userdata;
+ Session *session;
+ uint32_t id;
+ User *user;
+ int r;
+
+ assert(bus);
+ assert(message);
+ assert(m);
+
+ r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
+ if (r < 0) {
+ bus_log_parse_error(r);
+ return r;
+ }
+
+ if (m->action_job && streq(m->action_job, path)) {
+ log_info("Operation finished.");
+
+ /* Tell people that they now may take a lock again */
+ send_prepare_for(m, m->action_what, false);
+
+ free(m->action_job);
+ m->action_job = NULL;
+ m->action_unit = NULL;
+ m->action_what = 0;
+ return 0;
+ }
+
+ session = hashmap_get(m->session_units, unit);
+ if (session) {
+
+ if (streq_ptr(path, session->scope_job)) {
+ free(session->scope_job);
+ session->scope_job = NULL;
+ }
+
+ session_jobs_reply(session, unit, result);
+
+ session_save(session);
+ session_add_to_gc_queue(session);
+ }
+
+ user = hashmap_get(m->user_units, unit);
+ if (user) {
+
+ if (streq_ptr(path, user->service_job)) {
+ free(user->service_job);
+ user->service_job = NULL;
+ }
+
+ if (streq_ptr(path, user->slice_job)) {
+ free(user->slice_job);
+ user->slice_job = NULL;
+ }
+
+ LIST_FOREACH(sessions_by_user, session, user->sessions) {
+ session_jobs_reply(session, unit, result);
+ }
+
+ user_save(user);
+ user_add_to_gc_queue(user);
+ }
+
+ return 0;
+}
+
+int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ const char *path, *unit;
+ Manager *m = userdata;
+ Session *session;
+ User *user;
+ int r;
+
+ assert(bus);
+ assert(message);
+ assert(m);
+
+ r = sd_bus_message_read(message, "so", &unit, &path);
+ if (r < 0) {
+ bus_log_parse_error(r);
+ return r;
+ }
+
+ session = hashmap_get(m->session_units, unit);
+ if (session)
+ session_add_to_gc_queue(session);
+
+ user = hashmap_get(m->user_units, unit);
+ if (user)
+ user_add_to_gc_queue(user);
+
+ return 0;
+}
+
+int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ _cleanup_free_ char *unit = NULL;
+ Manager *m = userdata;
+ const char *path;
+ Session *session;
+ User *user;
+ int r;
+
+ assert(bus);
+ assert(message);
+ assert(m);
+
+ path = sd_bus_message_get_path(message);
+ if (!path)
+ return 0;
+
+ r = unit_name_from_dbus_path(path, &unit);
+ if (r == -EINVAL) /* not a unit */
+ return 0;
+ if (r < 0)
+ return r;
+
+ session = hashmap_get(m->session_units, unit);
+ if (session)
+ session_add_to_gc_queue(session);
+
+ user = hashmap_get(m->user_units, unit);
+ if (user)
+ user_add_to_gc_queue(user);
+
+ return 0;
+}
+
+int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+ Session *session;
+ Iterator i;
+ int b, r;
+
+ assert(bus);
+
+ r = sd_bus_message_read(message, "b", &b);
+ if (r < 0) {
+ bus_log_parse_error(r);
+ return r;
+ }
+
+ if (b)
+ return 0;
+
+ /* systemd finished reloading, let's recheck all our sessions */
+ log_debug("System manager has been reloaded, rechecking sessions...");
+
+ HASHMAP_FOREACH(session, m->sessions, i)
+ session_add_to_gc_queue(session);
+
+ return 0;
+}
+
+int match_name_owner_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ const char *name, *old, *new;
+ Manager *m = userdata;
+ Session *session;
+ Iterator i;
+ int r;
+
+
+ char *key;
+
+ r = sd_bus_message_read(message, "sss", &name, &old, &new);
+ if (r < 0) {
+ bus_log_parse_error(r);
+ return r;
+ }
+
+ if (isempty(old) || !isempty(new))
+ return 0;
+
+ key = set_remove(m->busnames, (char*) old);
+ if (!key)
+ return 0;
+
+ /* Drop all controllers owned by this name */
+
+ free(key);
+
+ HASHMAP_FOREACH(session, m->sessions, i)
+ if (session_is_controller(session, old))
+ session_drop_controller(session);
+
+ return 0;
+}
+