summaryrefslogtreecommitdiffstats
path: root/src/systemctl
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2019-03-29 20:23:33 +0100
committerLennart Poettering <lennart@poettering.net>2019-07-11 12:18:51 +0200
commita7056cde56577798a91c1ddb09f052c5a3ccc23d (patch)
tree42a28ff53376f93321991bec317e222bd6535a28 /src/systemctl
parentsystemctl: add new "clean" operation to systemctl (diff)
downloadsystemd-a7056cde56577798a91c1ddb09f052c5a3ccc23d.tar.xz
systemd-a7056cde56577798a91c1ddb09f052c5a3ccc23d.zip
systemctl: port "systemctl start --wait" logic to new bus-wait-for-units.c API
Diffstat (limited to 'src/systemctl')
-rw-r--r--src/systemctl/systemctl.c186
1 files changed, 15 insertions, 171 deletions
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 616ac0f5d4..7b39f5d95b 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -2793,158 +2793,6 @@ static const char *verb_to_job_type(const char *verb) {
return "start";
}
-typedef struct {
- sd_bus_slot *match;
- sd_event *event;
- Set *unit_paths;
- bool any_failed;
-} WaitContext;
-
-static void wait_context_free(WaitContext *c) {
- c->match = sd_bus_slot_unref(c->match);
- c->event = sd_event_unref(c->event);
- c->unit_paths = set_free_free(c->unit_paths);
-}
-
-static int on_properties_changed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
- const char *path, *interface, *active_state = NULL, *job_path = NULL;
- WaitContext *c = userdata;
- bool is_failed;
- int r;
-
- /* Called whenever we get a PropertiesChanged signal. Checks if ActiveState changed to inactive/failed.
- *
- * Signal parameters: (s interface, a{sv} changed_properties, as invalidated_properties) */
-
- path = sd_bus_message_get_path(m);
- if (!set_contains(c->unit_paths, path))
- return 0;
-
- r = sd_bus_message_read(m, "s", &interface);
- if (r < 0)
- return bus_log_parse_error(r);
-
- if (!streq(interface, "org.freedesktop.systemd1.Unit")) /* ActiveState is on the Unit interface */
- return 0;
-
- r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
- if (r < 0)
- return bus_log_parse_error(r);
-
- for (;;) {
- const char *s;
-
- r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv");
- if (r < 0)
- return bus_log_parse_error(r);
- if (r == 0) /* end of array */
- break;
-
- r = sd_bus_message_read(m, "s", &s); /* Property name */
- if (r < 0)
- return bus_log_parse_error(r);
-
- if (streq(s, "ActiveState")) {
- r = sd_bus_message_read(m, "v", "s", &active_state);
- if (r < 0)
- return bus_log_parse_error(r);
-
- if (job_path) /* Found everything we need */
- break;
-
- } else if (streq(s, "Job")) {
- uint32_t job_id;
-
- r = sd_bus_message_read(m, "v", "(uo)", &job_id, &job_path);
- if (r < 0)
- return bus_log_parse_error(r);
-
- /* There's still a job pending for this unit, let's ignore this for now, and return right-away. */
- if (job_id != 0)
- return 0;
-
- if (active_state) /* Found everything we need */
- break;
-
- } else {
- r = sd_bus_message_skip(m, "v"); /* Other property */
- if (r < 0)
- return bus_log_parse_error(r);
- }
-
- r = sd_bus_message_exit_container(m);
- if (r < 0)
- return bus_log_parse_error(r);
- }
-
- /* If this didn't contain the ActiveState property we can't do anything */
- if (!active_state)
- return 0;
-
- is_failed = streq(active_state, "failed");
- if (streq(active_state, "inactive") || is_failed) {
- log_debug("%s became %s, dropping from --wait tracking", path, active_state);
- free(set_remove(c->unit_paths, path));
- c->any_failed = c->any_failed || is_failed;
- } else
- log_debug("ActiveState on %s changed to %s", path, active_state);
-
- if (set_isempty(c->unit_paths))
- sd_event_exit(c->event, EXIT_SUCCESS);
-
- return 0;
-}
-
-static int wait_context_watch(
- WaitContext *wait_context,
- sd_bus *bus,
- const char *name) {
-
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_free_ char *unit_path = NULL;
- int r;
-
- assert(wait_context);
- assert(name);
-
- log_debug("Watching for property changes of %s", name);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "RefUnit",
- &error,
- NULL,
- "s", name);
- if (r < 0)
- return log_error_errno(r, "Failed to add reference to unit %s: %s", name, bus_error_message(&error, r));
-
- unit_path = unit_dbus_path_from_name(name);
- if (!unit_path)
- return log_oom();
-
- r = set_ensure_allocated(&wait_context->unit_paths, &string_hash_ops);
- if (r < 0)
- return log_oom();
-
- r = set_put_strdup(wait_context->unit_paths, unit_path);
- if (r < 0)
- return log_error_errno(r, "Failed to add unit path %s to set: %m", unit_path);
-
- r = sd_bus_match_signal_async(bus,
- &wait_context->match,
- NULL,
- unit_path,
- "org.freedesktop.DBus.Properties",
- "PropertiesChanged",
- on_properties_changed, NULL, wait_context);
- if (r < 0)
- return log_error_errno(r, "Failed to request match for PropertiesChanged signal: %m");
-
- return 0;
-}
-
static int start_unit_one(
sd_bus *bus,
const char *method, /* When using classic per-job bus methods */
@@ -2953,7 +2801,7 @@ static int start_unit_one(
const char *mode,
sd_bus_error *error,
BusWaitForJobs *w,
- WaitContext *wait_context) {
+ BusWaitForUnits *wu) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
const char *path;
@@ -2965,12 +2813,6 @@ static int start_unit_one(
assert(mode);
assert(error);
- if (wait_context) {
- r = wait_context_watch(wait_context, bus, name);
- if (r < 0)
- return r;
- }
-
log_debug("%s dbus call org.freedesktop.systemd1.Manager %s(%s, %s)",
arg_dry_run ? "Would execute" : "Executing",
method, name, mode);
@@ -3059,6 +2901,12 @@ static int start_unit_one(
return log_error_errno(r, "Failed to watch job for %s: %m", name);
}
+ if (wu) {
+ r = bus_wait_for_units_add_unit(wu, name, BUS_WAIT_FOR_INACTIVE|BUS_WAIT_NO_JOB, NULL, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to watch unit %s: %m", name);
+ }
+
return 0;
fail:
@@ -3190,8 +3038,8 @@ static const char** make_extra_args(const char *extra_args[static 4]) {
}
static int start_unit(int argc, char *argv[], void *userdata) {
+ _cleanup_(bus_wait_for_units_freep) BusWaitForUnits *wu = NULL;
_cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
- _cleanup_(wait_context_free) WaitContext wait_context = {};
const char *method, *job_type, *mode, *one_name, *suffix = NULL;
_cleanup_free_ char **stopped_units = NULL; /* Do not use _cleanup_strv_free_ */
_cleanup_strv_free_ char **names = NULL;
@@ -3279,19 +3127,15 @@ static int start_unit(int argc, char *argv[], void *userdata) {
if (r < 0)
return log_error_errno(r, "Failed to enable subscription: %m");
- r = sd_event_default(&wait_context.event);
+ r = bus_wait_for_units_new(bus, &wu);
if (r < 0)
- return log_error_errno(r, "Failed to allocate event loop: %m");
-
- r = sd_bus_attach_event(bus, wait_context.event, 0);
- if (r < 0)
- return log_error_errno(r, "Failed to attach bus to event loop: %m");
+ return log_error_errno(r, "Failed to allocate unit watch context: %m");
}
STRV_FOREACH(name, names) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- r = start_unit_one(bus, method, job_type, *name, mode, &error, w, arg_wait ? &wait_context : NULL);
+ r = start_unit_one(bus, method, job_type, *name, mode, &error, w, wu);
if (ret == EXIT_SUCCESS && r < 0)
ret = translate_bus_error_to_exit_status(r, &error);
@@ -3316,11 +3160,11 @@ static int start_unit(int argc, char *argv[], void *userdata) {
(void) check_triggering_units(bus, *name);
}
- if (ret == EXIT_SUCCESS && arg_wait && !set_isempty(wait_context.unit_paths)) {
- r = sd_event_loop(wait_context.event);
+ if (arg_wait) {
+ r = bus_wait_for_units_run(wu);
if (r < 0)
- return log_error_errno(r, "Failed to run event loop: %m");
- if (wait_context.any_failed)
+ return log_error_errno(r, "Failed to wait for units: %m");
+ if (r == BUS_WAIT_FAILURE && ret == EXIT_SUCCESS)
ret = EXIT_FAILURE;
}