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);