]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: add new API for enqueing a job with returning the transaction data
authorLennart Poettering <lennart@poettering.net>
Fri, 22 Mar 2019 19:57:30 +0000 (20:57 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 27 Mar 2019 11:37:37 +0000 (12:37 +0100)
19 files changed:
src/analyze/analyze-verify.c
src/core/automount.c
src/core/dbus-manager.c
src/core/dbus-unit.c
src/core/dbus-unit.h
src/core/dbus.c
src/core/device.c
src/core/emergency-action.c
src/core/main.c
src/core/manager.c
src/core/manager.h
src/core/path.c
src/core/service.c
src/core/socket.c
src/core/timer.c
src/core/transaction.c
src/core/transaction.h
src/core/unit.c
src/test/test-engine.c

index 1d8a1ed7b3249f3d2624241df02df43806cf7802..16b07cc8563a9c41f7b2b69c285eb9fff053d411 100644 (file)
@@ -202,7 +202,7 @@ static int verify_unit(Unit *u, bool check_man) {
                 unit_dump(u, stdout, "\t");
 
         log_unit_debug(u, "Creating %s/start job", u->id);
-        r = manager_add_job(u->manager, JOB_START, u, JOB_REPLACE, &err, NULL);
+        r = manager_add_job(u->manager, JOB_START, u, JOB_REPLACE, NULL, &err, NULL);
         if (r < 0)
                 log_unit_error_errno(u, r, "Failed to create %s/start: %s", u->id, bus_error_message(&err, r));
 
index 8ffdad18c70035bd367ddb401b5d5effe7ff3fba..28786158ee472d161e15938d5e0d9895a1f0698d 100644 (file)
@@ -781,7 +781,7 @@ static void automount_enter_running(Automount *a) {
                 goto fail;
         }
 
-        r = manager_add_job(UNIT(a)->manager, JOB_START, trigger, JOB_REPLACE, &error, NULL);
+        r = manager_add_job(UNIT(a)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL);
         if (r < 0) {
                 log_unit_warning(UNIT(a), "Failed to queue mount startup job: %s", bus_error_message(&error, r));
                 goto fail;
@@ -1035,7 +1035,7 @@ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, vo
                         goto fail;
                 }
 
-                r = manager_add_job(UNIT(a)->manager, JOB_STOP, trigger, JOB_REPLACE, &error, NULL);
+                r = manager_add_job(UNIT(a)->manager, JOB_STOP, trigger, JOB_REPLACE, NULL, &error, NULL);
                 if (r < 0) {
                         log_unit_warning(UNIT(a), "Failed to queue umount startup job: %s", bus_error_message(&error, r));
                         goto fail;
index 88e4c6bb952099f9805936aec0e5dda4010cc364..f0029081b6a60f0390fe1d78a1f376c8651641f2 100644 (file)
@@ -574,6 +574,26 @@ static int method_reload_or_try_restart_unit(sd_bus_message *message, void *user
         return method_start_unit_generic(message, userdata, JOB_TRY_RESTART, true, error);
 }
 
+static int method_enqueue_unit_job(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        Manager *m = userdata;
+        const char *name;
+        Unit *u;
+        int r;
+
+        assert(message);
+        assert(m);
+
+        r = sd_bus_message_read(message, "s", &name);
+        if (r < 0)
+                return r;
+
+        r = manager_load_unit(m, name, NULL, error, &u);
+        if (r < 0)
+                return r;
+
+        return bus_unit_method_enqueue_job(message, u, error);
+}
+
 static int method_start_unit_replace(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
         const char *old_name;
@@ -955,7 +975,7 @@ static int method_start_transient_unit(sd_bus_message *message, void *userdata,
                 return r;
 
         /* Finally, start it */
-        return bus_unit_queue_job(message, u, JOB_START, mode, false, error);
+        return bus_unit_queue_job(message, u, JOB_START, mode, 0, error);
 }
 
 static int method_get_job(sd_bus_message *message, void *userdata, sd_bus_error *error) {
@@ -2553,6 +2573,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
         SD_BUS_METHOD("TryRestartUnit", "ss", "o", method_try_restart_unit, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("ReloadOrRestartUnit", "ss", "o", method_reload_or_restart_unit, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("ReloadOrTryRestartUnit", "ss", "o", method_reload_or_try_restart_unit, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("EnqueueUnitJob", "sss", "uososa(uosos)", method_enqueue_unit_job, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("KillUnit", "ssi", NULL, method_kill_unit, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("ResetFailedUnit", "s", NULL, method_reset_failed_unit, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("SetUnitProperties", "sba(sv)", NULL, method_set_unit_properties, SD_BUS_VTABLE_UNPRIVILEGED),
index e1b4af10501e55d336b4e1442f8c6bb42c7c043b..6f1a74d6b5605abf319deb55a9fc8fa14e0d0c37 100644 (file)
@@ -312,6 +312,14 @@ static int bus_verify_manage_units_async_full(
                         error);
 }
 
+static const char *const polkit_message_for_job[_JOB_TYPE_MAX] = {
+        [JOB_START]       = N_("Authentication is required to start '$(unit)'."),
+        [JOB_STOP]        = N_("Authentication is required to stop '$(unit)'."),
+        [JOB_RELOAD]      = N_("Authentication is required to reload '$(unit)'."),
+        [JOB_RESTART]     = N_("Authentication is required to restart '$(unit)'."),
+        [JOB_TRY_RESTART] = N_("Authentication is required to restart '$(unit)'."),
+};
+
 int bus_unit_method_start_generic(
                 sd_bus_message *message,
                 Unit *u,
@@ -321,13 +329,6 @@ int bus_unit_method_start_generic(
 
         const char *smode, *verb;
         JobMode mode;
-        static const char *const polkit_message_for_job[_JOB_TYPE_MAX] = {
-                [JOB_START]       = N_("Authentication is required to start '$(unit)'."),
-                [JOB_STOP]        = N_("Authentication is required to stop '$(unit)'."),
-                [JOB_RELOAD]      = N_("Authentication is required to reload '$(unit)'."),
-                [JOB_RESTART]     = N_("Authentication is required to restart '$(unit)'."),
-                [JOB_TRY_RESTART] = N_("Authentication is required to restart '$(unit)'."),
-        };
         int r;
 
         assert(message);
@@ -367,7 +368,8 @@ int bus_unit_method_start_generic(
         if (r == 0)
                 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
 
-        return bus_unit_queue_job(message, u, job_type, mode, reload_if_possible, error);
+        return bus_unit_queue_job(message, u, job_type, mode,
+                                  reload_if_possible ? BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE : 0, error);
 }
 
 static int method_start(sd_bus_message *message, void *userdata, sd_bus_error *error) {
@@ -398,6 +400,62 @@ static int method_reload_or_try_restart(sd_bus_message *message, void *userdata,
         return bus_unit_method_start_generic(message, userdata, JOB_TRY_RESTART, true, error);
 }
 
+int bus_unit_method_enqueue_job(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        BusUnitQueueFlags flags = BUS_UNIT_QUEUE_VERBOSE_REPLY;
+        const char *jtype, *smode;
+        Unit *u = userdata;
+        JobType type;
+        JobMode mode;
+        int r;
+
+        assert(message);
+        assert(u);
+
+        r = sd_bus_message_read(message, "ss", &jtype, &smode);
+        if (r < 0)
+                return r;
+
+        /* Parse the two magic reload types "reload-or-…" manually */
+        if (streq(jtype, "reload-or-restart")) {
+                type = JOB_RESTART;
+                flags |= BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE;
+        } else if (streq(jtype, "reload-or-try-restart")) {
+                type = JOB_TRY_RESTART;
+                flags |= BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE;
+        } else {
+                /* And the rest generically */
+                type = job_type_from_string(jtype);
+                if (type < 0)
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job type %s invalid", jtype);
+        }
+
+        mode = job_mode_from_string(smode);
+        if (mode < 0)
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s invalid", smode);
+
+        r = mac_selinux_unit_access_check(
+                        u, message,
+                        job_type_to_access_method(type),
+                        error);
+        if (r < 0)
+                return r;
+
+        r = bus_verify_manage_units_async_full(
+                        u,
+                        jtype,
+                        CAP_SYS_ADMIN,
+                        polkit_message_for_job[type],
+                        true,
+                        message,
+                        error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+
+        return bus_unit_queue_job(message, u, type, mode, flags, error);
+}
+
 int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Unit *u = userdata;
         const char *swho;
@@ -683,6 +741,7 @@ const sd_bus_vtable bus_unit_vtable[] = {
         SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("EnqueueJob", "ss", "uososa(uosos)", bus_unit_method_enqueue_job, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, SD_BUS_VTABLE_UNPRIVILEGED),
@@ -1269,11 +1328,14 @@ int bus_unit_queue_job(
                 Unit *u,
                 JobType type,
                 JobMode mode,
-                bool reload_if_possible,
+                BusUnitQueueFlags flags,
                 sd_bus_error *error) {
 
-        _cleanup_free_ char *path = NULL;
-        Job *j;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        _cleanup_free_ char *job_path = NULL, *unit_path = NULL;
+        _cleanup_(set_freep) Set *affected = NULL;
+        Iterator i;
+        Job *j, *a;
         int r;
 
         assert(message);
@@ -1288,7 +1350,7 @@ int bus_unit_queue_job(
         if (r < 0)
                 return r;
 
-        if (reload_if_possible && unit_can_reload(u)) {
+        if (FLAGS_SET(flags, BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE) && unit_can_reload(u)) {
                 if (type == JOB_RESTART)
                         type = JOB_RELOAD_OR_START;
                 else if (type == JOB_TRY_RESTART)
@@ -1306,7 +1368,13 @@ int bus_unit_queue_job(
             (type == JOB_RELOAD_OR_START && job_type_collapse(type, u) == JOB_START && u->refuse_manual_start))
                 return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only (it is configured to refuse manual start/stop).", u->id);
 
-        r = manager_add_job(u->manager, type, u, mode, error, &j);
+        if (FLAGS_SET(flags, BUS_UNIT_QUEUE_VERBOSE_REPLY)) {
+                affected = set_new(NULL);
+                if (!affected)
+                        return -ENOMEM;
+        }
+
+        r = manager_add_job(u->manager, type, u, mode, affected, error, &j);
         if (r < 0)
                 return r;
 
@@ -1314,14 +1382,67 @@ int bus_unit_queue_job(
         if (r < 0)
                 return r;
 
-        path = job_dbus_path(j);
-        if (!path)
-                return -ENOMEM;
-
         /* Before we send the method reply, force out the announcement JobNew for this job */
         bus_job_send_pending_change_signal(j, true);
 
-        return sd_bus_reply_method_return(message, "o", path);
+        job_path = job_dbus_path(j);
+        if (!job_path)
+                return -ENOMEM;
+
+        /* The classic response is just a job object path */
+        if (!FLAGS_SET(flags, BUS_UNIT_QUEUE_VERBOSE_REPLY))
+                return sd_bus_reply_method_return(message, "o", job_path);
+
+        /* In verbose mode respond with the anchor job plus everything that has been affected */
+        r = sd_bus_message_new_method_return(message, &reply);
+        if (r < 0)
+                return r;
+
+        unit_path = unit_dbus_path(j->unit);
+        if (!unit_path)
+                return -ENOMEM;
+
+        r = sd_bus_message_append(reply, "uosos",
+                                  j->id, job_path,
+                                  j->unit->id, unit_path,
+                                  job_type_to_string(j->type));
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_open_container(reply, 'a', "(uosos)");
+        if (r < 0)
+                return r;
+
+        SET_FOREACH(a, affected, i) {
+
+                if (a->id == j->id)
+                        continue;
+
+                /* Free paths from previous iteration */
+                job_path = mfree(job_path);
+                unit_path = mfree(unit_path);
+
+                job_path = job_dbus_path(a);
+                if (!job_path)
+                        return -ENOMEM;
+
+                unit_path = unit_dbus_path(a->unit);
+                if (!unit_path)
+                        return -ENOMEM;
+
+                r = sd_bus_message_append(reply, "(uosos)",
+                                          a->id, job_path,
+                                          a->unit->id, unit_path,
+                                          job_type_to_string(a->type));
+                if (r < 0)
+                        return r;
+        }
+
+        r = sd_bus_message_close_container(reply);
+        if (r < 0)
+                return r;
+
+        return sd_bus_send(NULL, reply, NULL);
 }
 
 static int bus_unit_set_live_property(
index 345345e3ebadea254c0ab0bd1697b40b15fea79c..740bb1c86bcbc16c929b8776f1f23afcaa98cb4d 100644 (file)
@@ -15,6 +15,7 @@ void bus_unit_send_pending_change_signal(Unit *u, bool including_new);
 void bus_unit_send_removed_signal(Unit *u);
 
 int bus_unit_method_start_generic(sd_bus_message *message, Unit *u, JobType job_type, bool reload_if_possible, sd_bus_error *error);
+int bus_unit_method_enqueue_job(sd_bus_message *message, void *userdata, sd_bus_error *error);
 int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error);
 int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus_error *error);
 
@@ -25,7 +26,12 @@ int bus_unit_method_attach_processes(sd_bus_message *message, void *userdata, sd
 int bus_unit_method_ref(sd_bus_message *message, void *userdata, sd_bus_error *error);
 int bus_unit_method_unref(sd_bus_message *message, void *userdata, sd_bus_error *error);
 
-int bus_unit_queue_job(sd_bus_message *message, Unit *u, JobType type, JobMode mode, bool reload_if_possible, sd_bus_error *error);
+typedef enum BusUnitQueueFlags {
+        BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE = 1 << 0,
+        BUS_UNIT_QUEUE_VERBOSE_REPLY      = 1 << 1,
+} BusUnitQueueFlags;
+
+int bus_unit_queue_job(sd_bus_message *message, Unit *u, JobType type, JobMode mode, BusUnitQueueFlags flags, sd_bus_error *error);
 int bus_unit_validate_load_state(Unit *u, sd_bus_error *error);
 
 int bus_unit_track_add_name(Unit *u, const char *name);
index 255b86e7a41930eaa098675e840a483755253c6c..74b1c51c1d00222b54c11a923e9da2880c81767f 100644 (file)
@@ -177,7 +177,7 @@ static int signal_activation_request(sd_bus_message *message, void *userdata, sd
                 goto failed;
         }
 
-        r = manager_add_job(m, JOB_START, u, JOB_REPLACE, &error, NULL);
+        r = manager_add_job(m, JOB_START, u, JOB_REPLACE, NULL, &error, NULL);
         if (r < 0)
                 goto failed;
 
index 506bf744788a2538902ded2e0f582097a989f353..771239f53b60cf5bcf0f544e563b535bba4f94b9 100644 (file)
@@ -433,7 +433,7 @@ static int device_add_udev_wants(Unit *u, sd_device *dev) {
                         if (strv_contains(d->wants_property, *i)) /* Was this unit already listed before? */
                                 continue;
 
-                        r = manager_add_job_by_name(u->manager, JOB_START, *i, JOB_FAIL, &error, NULL);
+                        r = manager_add_job_by_name(u->manager, JOB_START, *i, JOB_FAIL, NULL, &error, NULL);
                         if (r < 0)
                                 log_unit_warning_errno(u, r, "Failed to enqueue SYSTEMD_WANTS= job, ignoring: %s", bus_error_message(&error, r));
                 }
index 09f8d74092705e5558448e62e104479caa8767a6..4330c0f2c1cd25e367d9f33f57ccdacce14433fd 100644 (file)
@@ -48,8 +48,7 @@ void emergency_action(
                 log_and_status(m, warn, "Rebooting", reason);
 
                 (void) update_reboot_parameter_and_warn(reboot_arg, true);
-                (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL);
-
+                (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL, NULL);
                 break;
 
         case EMERGENCY_ACTION_REBOOT_FORCE:
@@ -82,7 +81,7 @@ void emergency_action(
 
                 if (MANAGER_IS_USER(m) || detect_container() > 0) {
                         log_and_status(m, warn, "Exiting", reason);
-                        (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_EXIT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL);
+                        (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_EXIT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL, NULL);
                         break;
                 }
 
@@ -91,7 +90,7 @@ void emergency_action(
 
         case EMERGENCY_ACTION_POWEROFF:
                 log_and_status(m, warn, "Powering off", reason);
-                (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL);
+                (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL, NULL);
                 break;
 
         case EMERGENCY_ACTION_EXIT_FORCE:
index 6f6f4e5c5e5e875dc1d21077b33f5d5d3038886d..0ba22f815d91da3061fc015645baba1746132883 100644 (file)
@@ -2121,13 +2121,13 @@ static int do_queue_default_job(
 
         assert(target->load_state == UNIT_LOADED);
 
-        r = manager_add_job(m, JOB_START, target, JOB_ISOLATE, &error, &default_unit_job);
+        r = manager_add_job(m, JOB_START, target, JOB_ISOLATE, NULL, &error, &default_unit_job);
         if (r == -EPERM) {
                 log_debug_errno(r, "Default target could not be isolated, starting instead: %s", bus_error_message(&error, r));
 
                 sd_bus_error_free(&error);
 
-                r = manager_add_job(m, JOB_START, target, JOB_REPLACE, &error, &default_unit_job);
+                r = manager_add_job(m, JOB_START, target, JOB_REPLACE, NULL, &error, &default_unit_job);
                 if (r < 0) {
                         *ret_error_message = "Failed to start default target";
                         return log_emergency_errno(r, "Failed to start default target: %s", bus_error_message(&error, r));
index 7f4f71b9e95d0132a371db77f50b2b6f464c13b9..f8a8ac346b98ce4ff11b001e0a7e71db96c9a118 100644 (file)
@@ -1253,7 +1253,7 @@ static unsigned manager_dispatch_stop_when_unneeded_queue(Manager *m) {
                 }
 
                 /* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */
-                r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, &error, NULL);
+                r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, NULL, &error, NULL);
                 if (r < 0)
                         log_unit_warning_errno(u, r, "Failed to enqueue stop job, ignoring: %s", bus_error_message(&error, r));
         }
@@ -1730,9 +1730,17 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
         return 0;
 }
 
-int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_error *e, Job **_ret) {
-        int r;
+int manager_add_job(
+                Manager *m,
+                JobType type,
+                Unit *unit,
+                JobMode mode,
+                Set *affected_jobs,
+                sd_bus_error *error,
+                Job **ret) {
+
         Transaction *tr;
+        int r;
 
         assert(m);
         assert(type < _JOB_TYPE_MAX);
@@ -1740,10 +1748,10 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_e
         assert(mode < _JOB_MODE_MAX);
 
         if (mode == JOB_ISOLATE && type != JOB_START)
-                return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Isolate is only valid for start.");
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Isolate is only valid for start.");
 
         if (mode == JOB_ISOLATE && !unit->allow_isolate)
-                return sd_bus_error_setf(e, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated.");
+                return sd_bus_error_setf(error, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated.");
 
         log_unit_debug(unit, "Trying to enqueue job %s/%s/%s", unit->id, job_type_to_string(type), job_mode_to_string(mode));
 
@@ -1755,7 +1763,7 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_e
 
         r = transaction_add_job_and_dependencies(tr, type, unit, NULL, true, false,
                                                  IN_SET(mode, JOB_IGNORE_DEPENDENCIES, JOB_IGNORE_REQUIREMENTS),
-                                                 mode == JOB_IGNORE_DEPENDENCIES, e);
+                                                 mode == JOB_IGNORE_DEPENDENCIES, error);
         if (r < 0)
                 goto tr_abort;
 
@@ -1765,7 +1773,7 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_e
                         goto tr_abort;
         }
 
-        r = transaction_activate(tr, m, mode, e);
+        r = transaction_activate(tr, m, mode, affected_jobs, error);
         if (r < 0)
                 goto tr_abort;
 
@@ -1773,8 +1781,8 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_e
                        "Enqueued job %s/%s as %u", unit->id,
                        job_type_to_string(type), (unsigned) tr->anchor_job->id);
 
-        if (_ret)
-                *_ret = tr->anchor_job;
+        if (ret)
+                *ret = tr->anchor_job;
 
         transaction_free(tr);
         return 0;
@@ -1785,7 +1793,7 @@ tr_abort:
         return r;
 }
 
-int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, sd_bus_error *e, Job **ret) {
+int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, Set *affected_jobs, sd_bus_error *e, Job **ret) {
         Unit *unit = NULL;  /* just to appease gcc, initialization is not really necessary */
         int r;
 
@@ -1799,10 +1807,10 @@ int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode
                 return r;
         assert(unit);
 
-        return manager_add_job(m, type, unit, mode, e, ret);
+        return manager_add_job(m, type, unit, mode, affected_jobs, e, ret);
 }
 
-int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Job **ret) {
+int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Set *affected_jobs, Job **ret) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         int r;
 
@@ -1811,7 +1819,7 @@ int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name,
         assert(name);
         assert(mode < _JOB_MODE_MAX);
 
-        r = manager_add_job_by_name(m, type, name, mode, &error, ret);
+        r = manager_add_job_by_name(m, type, name, mode, affected_jobs, &error, ret);
         if (r < 0)
                 return log_warning_errno(r, "Failed to enqueue %s job for %s: %s", job_mode_to_string(mode), name, bus_error_message(&error, r));
 
@@ -1839,7 +1847,7 @@ int manager_propagate_reload(Manager *m, Unit *unit, JobMode mode, sd_bus_error
         /* Failure in adding individual dependencies is ignored, so this always succeeds. */
         transaction_add_propagate_reload_jobs(tr, unit, tr->anchor_job, mode == JOB_IGNORE_DEPENDENCIES, e);
 
-        r = transaction_activate(tr, m, mode, e);
+        r = transaction_activate(tr, m, mode, NULL, e);
         if (r < 0)
                 goto tr_abort;
 
@@ -2549,7 +2557,7 @@ static void manager_start_target(Manager *m, const char *name, JobMode mode) {
 
         log_debug("Activating special unit %s", name);
 
-        r = manager_add_job_by_name(m, JOB_START, name, mode, &error, NULL);
+        r = manager_add_job_by_name(m, JOB_START, name, mode, NULL, &error, NULL);
         if (r < 0)
                 log_error("Failed to enqueue %s job: %s", name, bus_error_message(&error, r));
 }
index c43c587a79ddc295ebaedfc72434c6d28b39a719..8c7bd7e231912430c70341198b1e0ee9f7ca1dc2 100644 (file)
@@ -425,9 +425,9 @@ int manager_load_unit(Manager *m, const char *name, const char *path, sd_bus_err
 int manager_load_startable_unit_or_warn(Manager *m, const char *name, const char *path, Unit **ret);
 int manager_load_unit_from_dbus_path(Manager *m, const char *s, sd_bus_error *e, Unit **_u);
 
-int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_error *e, Job **_ret);
-int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, sd_bus_error *e, Job **_ret);
-int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Job **ret);
+int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, Set *affected_jobs, sd_bus_error *e, Job **_ret);
+int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, Set *affected_jobs, sd_bus_error *e, Job **_ret);
+int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Set *affected_jobs,  Job **ret);
 int manager_propagate_reload(Manager *m, Unit *unit, JobMode mode, sd_bus_error *e);
 
 void manager_dump_units(Manager *s, FILE *f, const char *prefix);
index 3fe14ef2bcf801ba0c37dc64d6434e3a3522fd35..5a00150e9b3096aa51f9a7c3a10a5bc58a3e3aeb 100644 (file)
@@ -474,7 +474,7 @@ static void path_enter_running(Path *p) {
                 return;
         }
 
-        r = manager_add_job(UNIT(p)->manager, JOB_START, trigger, JOB_REPLACE, &error, NULL);
+        r = manager_add_job(UNIT(p)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL);
         if (r < 0)
                 goto fail;
 
index 89029b6d115eaa72c0c43ae04fbf19264b49800c..d05d7c669197a08b8a27c960510951657969b23a 100644 (file)
@@ -2181,7 +2181,7 @@ static void service_enter_restart(Service *s) {
          * restarted. We use JOB_RESTART (instead of the more obvious
          * JOB_START) here so that those dependency jobs will be added
          * as well. */
-        r = manager_add_job(UNIT(s)->manager, JOB_RESTART, UNIT(s), JOB_REPLACE, &error, NULL);
+        r = manager_add_job(UNIT(s)->manager, JOB_RESTART, UNIT(s), JOB_REPLACE, NULL, &error, NULL);
         if (r < 0)
                 goto fail;
 
index 1396842b26926eb1444418ee8636596052ad0943..95976ed44d706f68b665e6cfa38f5db034a7ac77 100644 (file)
@@ -2310,7 +2310,7 @@ static void socket_enter_running(Socket *s, int cfd) {
                                 goto fail;
                         }
 
-                        r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT_DEREF(s->service), JOB_REPLACE, &error, NULL);
+                        r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT_DEREF(s->service), JOB_REPLACE, NULL, &error, NULL);
                         if (r < 0)
                                 goto fail;
                 }
@@ -2385,7 +2385,7 @@ static void socket_enter_running(Socket *s, int cfd) {
 
                 service->peer = TAKE_PTR(p); /* Pass ownership of the peer reference */
 
-                r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, &error, NULL);
+                r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, NULL, &error, NULL);
                 if (r < 0) {
                         /* We failed to activate the new service, but it still exists. Let's make sure the service
                          * closes and forgets the connection fd again, immediately. */
index d1e351c30dc26f59bb6a13d6a00a30755f320e3b..acf4417f4c53bfc3864ddf20d09e96591f1efacb 100644 (file)
@@ -575,7 +575,7 @@ static void timer_enter_running(Timer *t) {
                 return;
         }
 
-        r = manager_add_job(UNIT(t)->manager, JOB_START, trigger, JOB_REPLACE, &error, NULL);
+        r = manager_add_job(UNIT(t)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL);
         if (r < 0)
                 goto fail;
 
index 2418332b9a406b0ca504c57dd67ce19136a07141..e0ba3c845fb20ed6db1ab9a6f0916a15e9e3bf86 100644 (file)
@@ -589,7 +589,12 @@ rescan:
         }
 }
 
-static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) {
+static int transaction_apply(
+                Transaction *tr,
+                Manager *m,
+                JobMode mode,
+                Set *affected_jobs) {
+
         Iterator i;
         Job *j;
         int r;
@@ -646,6 +651,11 @@ static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) {
                 job_add_to_dbus_queue(j);
                 job_start_timer(j, false);
                 job_shutdown_magic(j);
+
+                /* When 'affected' is specified, let's track all in it all jobs that were touched because of
+                 * this transaction. */
+                if (affected_jobs)
+                        (void) set_put(affected_jobs, j);
         }
 
         return 0;
@@ -658,7 +668,13 @@ rollback:
         return r;
 }
 
-int transaction_activate(Transaction *tr, Manager *m, JobMode mode, sd_bus_error *e) {
+int transaction_activate(
+                Transaction *tr,
+                Manager *m,
+                JobMode mode,
+                Set *affected_jobs,
+                sd_bus_error *e) {
+
         Iterator i;
         Job *j;
         int r;
@@ -735,7 +751,7 @@ int transaction_activate(Transaction *tr, Manager *m, JobMode mode, sd_bus_error
                 return log_notice_errno(r, "Requested transaction contradicts existing jobs: %s", bus_error_message(e, r));
 
         /* Tenth step: apply changes */
-        r = transaction_apply(tr, m, mode);
+        r = transaction_apply(tr, m, mode, affected_jobs);
         if (r < 0)
                 return log_warning_errno(r, "Failed to apply transaction: %m");
 
index 70d74a4ccb52ba3e870a5cb7855be94ad5c85e4e..4b5620f5c86763501c3485bef312d781ae64051e 100644 (file)
@@ -29,6 +29,6 @@ int transaction_add_job_and_dependencies(
                 bool ignore_requirements,
                 bool ignore_order,
                 sd_bus_error *e);
-int transaction_activate(Transaction *tr, Manager *m, JobMode mode, sd_bus_error *e);
+int transaction_activate(Transaction *tr, Manager *m, JobMode mode, Set *affected, sd_bus_error *e);
 int transaction_add_isolate_jobs(Transaction *tr, Manager *m);
 void transaction_abort(Transaction *tr);
index 2d7cb1457cd9e6c69c5e2704e7dc2c56c454ff3e..35c268cd3b454849441cb20b17f315a827a1ed71 100644 (file)
@@ -2035,7 +2035,7 @@ static void unit_check_binds_to(Unit *u) {
         log_unit_info(u, "Unit is bound to inactive unit %s. Stopping, too.", other->id);
 
         /* A unit we need to run is gone. Sniff. Let's stop this. */
-        r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, &error, NULL);
+        r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, NULL, &error, NULL);
         if (r < 0)
                 log_unit_warning_errno(u, r, "Failed to enqueue stop job, ignoring: %s", bus_error_message(&error, r));
 }
@@ -2051,25 +2051,25 @@ static void retroactively_start_dependencies(Unit *u) {
         HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_REQUIRES], i)
                 if (!hashmap_get(u->dependencies[UNIT_AFTER], other) &&
                     !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, NULL, NULL);
+                        manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, NULL, NULL, NULL);
 
         HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_BINDS_TO], i)
                 if (!hashmap_get(u->dependencies[UNIT_AFTER], other) &&
                     !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, NULL, NULL);
+                        manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, NULL, NULL, NULL);
 
         HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_WANTS], i)
                 if (!hashmap_get(u->dependencies[UNIT_AFTER], other) &&
                     !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->manager, JOB_START, other, JOB_FAIL, NULL, NULL);
+                        manager_add_job(u->manager, JOB_START, other, JOB_FAIL, NULL, NULL, NULL);
 
         HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_CONFLICTS], i)
                 if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL);
+                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL, NULL);
 
         HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_CONFLICTED_BY], i)
                 if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL);
+                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL, NULL);
 }
 
 static void retroactively_stop_dependencies(Unit *u) {
@@ -2083,7 +2083,7 @@ static void retroactively_stop_dependencies(Unit *u) {
         /* Pull down units which are bound to us recursively if enabled */
         HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_BOUND_BY], i)
                 if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL);
+                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL, NULL);
 }
 
 void unit_start_on_failure(Unit *u) {
@@ -2102,7 +2102,7 @@ void unit_start_on_failure(Unit *u) {
         HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_ON_FAILURE], i) {
                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
 
-                r = manager_add_job(u->manager, JOB_START, other, u->on_failure_job_mode, &error, NULL);
+                r = manager_add_job(u->manager, JOB_START, other, u->on_failure_job_mode, NULL, &error, NULL);
                 if (r < 0)
                         log_unit_warning_errno(u, r, "Failed to enqueue OnFailure= job, ignoring: %s", bus_error_message(&error, r));
         }
index 0673d36b6225aabb06f50b9ed886743e3f87fe9b..701594fe538f45375e0a73520d28d244813f90b1 100644 (file)
@@ -40,7 +40,7 @@ int main(int argc, char *argv[]) {
         manager_dump_units(m, stdout, "\t");
 
         printf("Test1: (Trivial)\n");
-        r = manager_add_job(m, JOB_START, c, JOB_REPLACE, &err, &j);
+        r = manager_add_job(m, JOB_START, c, JOB_REPLACE, NULL, &err, &j);
         if (sd_bus_error_is_set(&err))
                 log_error("error: %s: %s", err.name, err.message);
         assert_se(r == 0);
@@ -53,15 +53,15 @@ int main(int argc, char *argv[]) {
         manager_dump_units(m, stdout, "\t");
 
         printf("Test2: (Cyclic Order, Unfixable)\n");
-        assert_se(manager_add_job(m, JOB_START, d, JOB_REPLACE, NULL, &j) == -EDEADLK);
+        assert_se(manager_add_job(m, JOB_START, d, JOB_REPLACE, NULL, NULL, &j) == -EDEADLK);
         manager_dump_jobs(m, stdout, "\t");
 
         printf("Test3: (Cyclic Order, Fixable, Garbage Collector)\n");
-        assert_se(manager_add_job(m, JOB_START, e, JOB_REPLACE, NULL, &j) == 0);
+        assert_se(manager_add_job(m, JOB_START, e, JOB_REPLACE, NULL, NULL, &j) == 0);
         manager_dump_jobs(m, stdout, "\t");
 
         printf("Test4: (Identical transaction)\n");
-        assert_se(manager_add_job(m, JOB_START, e, JOB_FAIL, NULL, &j) == 0);
+        assert_se(manager_add_job(m, JOB_START, e, JOB_FAIL, NULL, NULL, &j) == 0);
         manager_dump_jobs(m, stdout, "\t");
 
         printf("Load3:\n");
@@ -69,21 +69,21 @@ int main(int argc, char *argv[]) {
         manager_dump_units(m, stdout, "\t");
 
         printf("Test5: (Colliding transaction, fail)\n");
-        assert_se(manager_add_job(m, JOB_START, g, JOB_FAIL, NULL, &j) == -EDEADLK);
+        assert_se(manager_add_job(m, JOB_START, g, JOB_FAIL, NULL, NULL, &j) == -EDEADLK);
 
         printf("Test6: (Colliding transaction, replace)\n");
-        assert_se(manager_add_job(m, JOB_START, g, JOB_REPLACE, NULL, &j) == 0);
+        assert_se(manager_add_job(m, JOB_START, g, JOB_REPLACE, NULL, NULL, &j) == 0);
         manager_dump_jobs(m, stdout, "\t");
 
         printf("Test7: (Unmergeable job type, fail)\n");
-        assert_se(manager_add_job(m, JOB_STOP, g, JOB_FAIL, NULL, &j) == -EDEADLK);
+        assert_se(manager_add_job(m, JOB_STOP, g, JOB_FAIL, NULL, NULL, &j) == -EDEADLK);
 
         printf("Test8: (Mergeable job type, fail)\n");
-        assert_se(manager_add_job(m, JOB_RESTART, g, JOB_FAIL, NULL, &j) == 0);
+        assert_se(manager_add_job(m, JOB_RESTART, g, JOB_FAIL, NULL, NULL, &j) == 0);
         manager_dump_jobs(m, stdout, "\t");
 
         printf("Test9: (Unmergeable job type, replace)\n");
-        assert_se(manager_add_job(m, JOB_STOP, g, JOB_REPLACE, NULL, &j) == 0);
+        assert_se(manager_add_job(m, JOB_STOP, g, JOB_REPLACE, NULL, NULL, &j) == 0);
         manager_dump_jobs(m, stdout, "\t");
 
         printf("Load4:\n");
@@ -91,7 +91,7 @@ int main(int argc, char *argv[]) {
         manager_dump_units(m, stdout, "\t");
 
         printf("Test10: (Unmergeable job type of auxiliary job, fail)\n");
-        assert_se(manager_add_job(m, JOB_START, h, JOB_FAIL, NULL, &j) == 0);
+        assert_se(manager_add_job(m, JOB_START, h, JOB_FAIL, NULL, NULL, &j) == 0);
         manager_dump_jobs(m, stdout, "\t");
 
         assert_se(!hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], b));