summaryrefslogtreecommitdiff
path: root/src/core/dbus-unit.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2019-03-22 20:57:30 +0100
committerLennart Poettering <lennart@poettering.net>2019-03-27 12:37:37 +0100
commit50cbaba4fe5a32850998682699322d012e597e4a (patch)
treee5c26a2e173f20ce57e67168c55859a0b90abbb2 /src/core/dbus-unit.c
parent49bd196d693efe0acfc8d56c4e3d8f7ba9f91b5d (diff)
downloadsystemd-50cbaba4fe5a32850998682699322d012e597e4a.tar.gz
core: add new API for enqueing a job with returning the transaction data
Diffstat (limited to 'src/core/dbus-unit.c')
-rw-r--r--src/core/dbus-unit.c157
1 files changed, 139 insertions, 18 deletions
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index e1b4af1050..6f1a74d6b5 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -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(