diff options
author | Lennart Poettering <lennart@poettering.net> | 2019-03-29 20:23:33 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2019-07-11 12:18:51 +0200 |
commit | a7056cde56577798a91c1ddb09f052c5a3ccc23d (patch) | |
tree | 42a28ff53376f93321991bec317e222bd6535a28 /src/systemctl | |
parent | systemctl: add new "clean" operation to systemctl (diff) | |
download | systemd-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.c | 186 |
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; } |