From: Yu Watanabe Date: Thu, 6 Apr 2023 19:49:07 +0000 (+0900) Subject: update-utmp: reconnect after sleep when PID1 is reexecuting X-Git-Tag: v254-rc1~391^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=fcb2343175d80b45659817e02a7d0d4771d0a854;p=thirdparty%2Fsystemd.git update-utmp: reconnect after sleep when PID1 is reexecuting Fixes #27167. --- diff --git a/src/update-utmp/update-utmp.c b/src/update-utmp/update-utmp.c index 2f6d582da92..5651ec11dac 100644 --- a/src/update-utmp/update-utmp.c +++ b/src/update-utmp/update-utmp.c @@ -20,6 +20,7 @@ #include "macro.h" #include "main-func.h" #include "process-util.h" +#include "random-util.h" #include "special.h" #include "stdio-util.h" #include "strv.h" @@ -76,35 +77,59 @@ static int get_current_runlevel(Context *c) { { '3', SPECIAL_MULTI_USER_TARGET }, { '1', SPECIAL_RESCUE_TARGET }, }; - - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(c); - for (size_t i = 0; i < ELEMENTSOF(table); i++) { - _cleanup_free_ char *state = NULL, *path = NULL; - - path = unit_dbus_path_from_name(table[i].special); - if (!path) - return log_oom(); - - r = sd_bus_get_property_string( - c->bus, - "org.freedesktop.systemd1", - path, - "org.freedesktop.systemd1.Unit", - "ActiveState", - &error, - &state); - if (r < 0) - return log_warning_errno(r, "Failed to get state: %s", bus_error_message(&error, r)); + for (unsigned n_attempts = 0;;) { + FOREACH_ARRAY(e, table, ELEMENTSOF(table)) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_free_ char *state = NULL, *path = NULL; + + path = unit_dbus_path_from_name(e->special); + if (!path) + return log_oom(); + + r = sd_bus_get_property_string( + c->bus, + "org.freedesktop.systemd1", + path, + "org.freedesktop.systemd1.Unit", + "ActiveState", + &error, + &state); + if ((r == -ENOTCONN || + sd_bus_error_has_names(&error, + SD_BUS_ERROR_NO_REPLY, + SD_BUS_ERROR_DISCONNECTED)) && + ++n_attempts < 64) { + + /* systemd might have dropped off momentarily, let's not make this an error, + * and wait some random time. Let's pick a random time in the range 0ms…250ms, + * linearly scaled by the number of failed attempts. */ + + usec_t usec = random_u64_range(UINT64_C(10) * USEC_PER_MSEC + + UINT64_C(240) * USEC_PER_MSEC * n_attempts/64); + log_debug_errno(r, "Failed to get state of %s, retrying after %s: %s", + e->special, FORMAT_TIMESPAN(usec, USEC_PER_MSEC), bus_error_message(&error, r)); + (void) usleep(usec); + goto reconnect; + } + if (r < 0) + return log_warning_errno(r, "Failed to get state of %s: %s", e->special, bus_error_message(&error, r)); + + if (STR_IN_SET(state, "active", "reloading")) + return e->runlevel; + } - if (STR_IN_SET(state, "active", "reloading")) - return table[i].runlevel; - } + return 0; - return 0; +reconnect: + c->bus = sd_bus_flush_close_unref(c->bus); + r = bus_connect_system_systemd(&c->bus); + if (r < 0) + return log_error_errno(r, "Failed to reconnect to system bus: %m"); + } } static int on_reboot(int argc, char *argv[], void *userdata) {