From: Filipe Brandenburger Date: Sat, 4 Aug 2018 06:10:54 +0000 (-0700) Subject: systemctl: add support for --wait to is-system-running X-Git-Tag: v240~857 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=adb6cd9be2b7e9e614d2b5835c7b70cf8eacc852;p=thirdparty%2Fsystemd.git systemctl: add support for --wait to is-system-running This makes it possible to wait until boot is finished without having to poll for this command repeatedly, instead using the syntax: $ systemctl is-system-running --wait Waiting is implemented by waiting for the StartupFinished signal to be posted on the bus. Register the matcher before checking for the property to avoid race conditions. Tested by artificially delaying startup with a oneshot service and calling this command, checked that it emitted `running` and exited with a 0 return code as soon as the delay service completed startup. Also tested that booting to degraded state unblocks the command. Inserted a delay between getting the property and waiting for the signal and confirmed this seems to work free of race conditions. Updated the --help text (under --wait) and the man page to document the new feature. --- diff --git a/man/systemctl.xml b/man/systemctl.xml index 850135cbc00..318311a4c01 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -372,6 +372,9 @@ Note that this will wait forever if any given unit never terminates (by itself or by getting stopped explicitly); particularly services which use RemainAfterExit=yes. + + When used with is-system-running, wait + until the boot process is completed before returning. @@ -1636,6 +1639,15 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err output, see the table below. Use to suppress this output. + Use to wait until the boot + process is completed before printing the current state and + returning the appropriate error status. If + is in use, states initializing or + starting will not be reported, instead + the command will block until a later state (such as + running or degraded) + is reached. + <command>is-system-running</command> output diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index abd4b92a24d..046bffdf055 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -18,6 +18,7 @@ #include "sd-bus.h" #include "sd-daemon.h" +#include "sd-event.h" #include "sd-login.h" #include "alloc-util.h" @@ -6629,8 +6630,29 @@ static int unit_is_enabled(int argc, char *argv[], void *userdata) { return enabled ? EXIT_SUCCESS : EXIT_FAILURE; } +static int match_startup_finished(sd_bus_message *m, void *userdata, sd_bus_error *error) { + char **state = userdata; + int r; + + assert(state); + + r = sd_bus_get_property_string( + sd_bus_message_get_bus(m), + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "SystemState", + NULL, + state); + + sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), r); + return 0; +} + static int is_system_running(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot_startup_finished = NULL; + _cleanup_(sd_event_unrefp) sd_event* event = NULL; _cleanup_free_ char *state = NULL; sd_bus *bus; int r; @@ -6645,6 +6667,25 @@ static int is_system_running(int argc, char *argv[], void *userdata) { if (r < 0) return r; + if (arg_wait) { + r = sd_event_default(&event); + if (r >= 0) + r = sd_bus_attach_event(bus, event, 0); + if (r >= 0) + r = sd_bus_match_signal_async( + bus, + &slot_startup_finished, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "StartupFinished", + match_startup_finished, NULL, &state); + if (r < 0) { + log_warning_errno(r, "Failed to request match for StartupFinished: %m"); + arg_wait = false; + } + } + r = sd_bus_get_property_string( bus, "org.freedesktop.systemd1", @@ -6654,13 +6695,23 @@ static int is_system_running(int argc, char *argv[], void *userdata) { &error, &state); if (r < 0) { - log_debug_errno(r, "Failed to query system state: %s", bus_error_message(&error, r)); + log_warning_errno(r, "Failed to query system state: %s", bus_error_message(&error, r)); if (!arg_quiet) puts("unknown"); return EXIT_FAILURE; } + if (arg_wait && STR_IN_SET(state, "initializing", "starting")) { + r = sd_event_loop(event); + if (r < 0) { + log_warning_errno(r, "Failed to get property from event loop: %m"); + if (!arg_quiet) + puts("unknown"); + return EXIT_FAILURE; + } + } + if (!arg_quiet) puts(state); @@ -7082,6 +7133,7 @@ static void systemctl_help(void) { " --dry-run Only print what would be done\n" " -q --quiet Suppress output\n" " --wait For (re)start, wait until service stopped again\n" + " For is-system-running, wait until startup is completed\n" " --no-block Do not wait until operation finished\n" " --no-wall Don't send wall message before halt/power-off/reboot\n" " --no-reload Don't reload daemon after en-/dis-abling unit files\n"