diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml index 13771a459a..9e64e58fe3 100644 --- a/man/org.freedesktop.systemd1.xml +++ b/man/org.freedesktop.systemd1.xml @@ -176,6 +176,7 @@ node /org/freedesktop/systemd1 { UnsetEnvironment(in as names); UnsetAndSetEnvironment(in as names, in as assignments); + EnqueueMarkedJobs(out ao jobs); ListUnitFiles(out a(ss) unit_files); ListUnitFilesByPatterns(in as states, in as patterns, @@ -848,6 +849,8 @@ node /org/freedesktop/systemd1 { + + @@ -1171,6 +1174,11 @@ node /org/freedesktop/systemd1 { the "Try" flavor is used in which case a service that isn't running is not affected by the restart. The "ReloadOrRestart" flavors attempt a reload if the unit supports it and use a restart otherwise. + EnqueueMarkedJobs() creates reload/restart jobs for units which have been + appropriately marked, see Marks property above. This is equivalent to calling + TryRestartUnit() or ReloadOrTryRestartUnit() for the marked + units. + BindMountUnit() can be used to bind mount new files or directories into a running service mount namespace. diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 9053d48149..c4b7aa427b 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -1807,6 +1807,75 @@ static int method_get_dynamic_users(sd_bus_message *message, void *userdata, sd_ return sd_bus_send(NULL, reply, NULL); } +static int method_enqueue_marked_jobs(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + int r; + + assert(message); + assert(m); + + r = mac_selinux_access_check(message, "start", error); + if (r < 0) + return r; + + r = bus_verify_manage_units_async(m, 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 */ + + log_info("Queuing reload/restart jobs for marked units…"); + + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + r = sd_bus_message_new_method_return(message, &reply); + if (r < 0) + return r; + + r = sd_bus_message_open_container(reply, 'a', "o"); + if (r < 0) + return r; + + Unit *u; + char *k; + int ret = 0; + HASHMAP_FOREACH_KEY(u, k, m->units) { + /* ignore aliases */ + if (u->id != k) + continue; + + BusUnitQueueFlags flags; + if (FLAGS_SET(u->markers, 1u << UNIT_MARKER_NEEDS_RESTART)) + flags = 0; + else if (FLAGS_SET(u->markers, 1u << UNIT_MARKER_NEEDS_RELOAD)) + flags = BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE; + else + continue; + + r = mac_selinux_unit_access_check(u, message, "start", error); + if (r >= 0) + r = bus_unit_queue_job_one(message, u, + JOB_TRY_RESTART, JOB_FAIL, flags, + reply, error); + if (r < 0) { + if (ERRNO_IS_RESOURCE(r)) + return r; + if (ret >= 0) + ret = r; + sd_bus_error_free(error); + } + } + + if (ret < 0) + return sd_bus_error_set_errnof(error, ret, + "Failed to enqueue some jobs, see logs for details: %m"); + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + return sd_bus_send(NULL, reply, NULL); +} + static int list_unit_files_by_patterns(sd_bus_message *message, void *userdata, sd_bus_error *error, char **states, char **patterns) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; Manager *m = userdata; @@ -3007,6 +3076,12 @@ const sd_bus_vtable bus_manager_vtable[] = { NULL,, method_unset_and_set_environment, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("EnqueueMarkedJobs", + NULL,, + "ao", + SD_BUS_PARAM(jobs), + method_enqueue_marked_jobs, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("ListUnitFiles", NULL,, "a(ss)", diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index 1e7e51ffba..d8351a4d43 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -1716,6 +1716,89 @@ void bus_unit_send_removed_signal(Unit *u) { log_unit_debug_errno(u, r, "Failed to send unit remove signal for %s: %m", u->id); } +int bus_unit_queue_job_one( + sd_bus_message *message, + Unit *u, + JobType type, + JobMode mode, + BusUnitQueueFlags flags, + sd_bus_message *reply, + sd_bus_error *error) { + + _cleanup_set_free_ Set *affected = NULL; + _cleanup_free_ char *job_path = NULL, *unit_path = NULL; + Job *j, *a; + int r; + + 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; + + r = bus_job_track_sender(j, message); + if (r < 0) + return r; + + /* Before we send the method reply, force out the announcement JobNew for this job */ + bus_job_send_pending_change_signal(j, true); + + 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_message_append(reply, "o", job_path); + + /* In verbose mode respond with the anchor job plus everything that has been affected */ + + 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) { + 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; + } + + return sd_bus_message_close_container(reply); +} + int bus_unit_queue_job( sd_bus_message *message, Unit *u, @@ -1725,9 +1808,6 @@ int bus_unit_queue_job( sd_bus_error *error) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; - _cleanup_free_ char *job_path = NULL, *unit_path = NULL; - _cleanup_set_free_ Set *affected = NULL; - Job *j, *a; int r; assert(message); @@ -1760,77 +1840,11 @@ 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); - 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; - - r = bus_job_track_sender(j, message); - if (r < 0) - return r; - - /* Before we send the method reply, force out the announcement JobNew for this job */ - bus_job_send_pending_change_signal(j, true); - - 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) { - - 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); + r = bus_unit_queue_job_one(message, u, type, mode, flags, reply, error); if (r < 0) return r; diff --git a/src/core/dbus-unit.h b/src/core/dbus-unit.h index 1da3cfeb96..a3ac320496 100644 --- a/src/core/dbus-unit.h +++ b/src/core/dbus-unit.h @@ -33,7 +33,21 @@ typedef enum BusUnitQueueFlags { 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_queue_job_one( + sd_bus_message *message, + Unit *u, + JobType type, + JobMode mode, + BusUnitQueueFlags flags, + sd_bus_message *reply, + sd_bus_error *error); +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);