diff --git a/src/core/main.c b/src/core/main.c index f347b74b11..fabca41189 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1751,11 +1751,11 @@ static void update_cpu_affinity(bool skip_setup) { assert(arg_cpu_affinity.allocated > 0); - mask = cpu_set_to_string(&arg_cpu_affinity); - log_debug("Setting CPU affinity to %s.", strnull(mask)); + mask = cpu_set_to_range_string(&arg_cpu_affinity); + log_debug("Setting CPU affinity to {%s}.", strnull(mask)); if (sched_setaffinity(0, arg_cpu_affinity.allocated, arg_cpu_affinity.set) < 0) - log_warning_errno(errno, "Failed to set CPU affinity: %m"); + log_warning_errno(errno, "Failed to set CPU affinity, ignoring: %m"); } static void update_numa_policy(bool skip_setup) { @@ -1769,14 +1769,14 @@ static void update_numa_policy(bool skip_setup) { if (DEBUG_LOGGING) { policy = mpol_to_string(numa_policy_get_type(&arg_numa_policy)); nodes = cpu_set_to_range_string(&arg_numa_policy.nodes); - log_debug("Setting NUMA policy to %s, with nodes %s.", strnull(policy), strnull(nodes)); + log_debug("Setting NUMA policy to %s, with nodes {%s}.", strnull(policy), strnull(nodes)); } r = apply_numa_policy(&arg_numa_policy); if (r == -EOPNOTSUPP) log_debug_errno(r, "NUMA support not available, ignoring."); else if (r < 0) - log_warning_errno(r, "Failed to set NUMA memory policy: %m"); + log_warning_errno(r, "Failed to set NUMA memory policy, ignoring: %m"); } static void filter_args( @@ -1824,7 +1824,8 @@ static void filter_args( } } -static void do_reexecute( +static int do_reexecute( + ManagerObjective objective, int argc, char* argv[], const struct rlimit *saved_rlimit_nofile, @@ -1838,6 +1839,7 @@ static void do_reexecute( const char **args; int r; + assert(IN_SET(objective, MANAGER_REEXECUTE, MANAGER_SWITCH_ROOT)); assert(argc >= 0); assert(saved_rlimit_nofile); assert(saved_rlimit_memlock); @@ -1901,6 +1903,12 @@ static void do_reexecute( args[0] = SYSTEMD_BINARY_PATH; (void) execv(args[0], (char* const*) args); + + if (objective == MANAGER_REEXECUTE) { + *ret_error_message = "Failed to execute our own binary"; + return log_error_errno(errno, "Failed to execute our own binary %s: %m", args[0]); + } + log_debug_errno(errno, "Failed to execute our own binary %s, trying fallback: %m", args[0]); } @@ -1938,24 +1946,22 @@ static void do_reexecute( ANSI_HIGHLIGHT_RED " !! " ANSI_NORMAL, "Failed to execute /sbin/init"); + *ret_error_message = "Failed to execute fallback shell"; if (r == -ENOENT) { log_warning("No /sbin/init, trying fallback"); args[0] = "/bin/sh"; args[1] = NULL; (void) execve(args[0], (char* const*) args, saved_env); - log_error_errno(errno, "Failed to execute /bin/sh, giving up: %m"); + return log_error_errno(errno, "Failed to execute /bin/sh, giving up: %m"); } else - log_warning_errno(r, "Failed to execute /sbin/init, giving up: %m"); - - *ret_error_message = "Failed to execute fallback shell"; + return log_error_errno(r, "Failed to execute /sbin/init, giving up: %m"); } static int invoke_main_loop( Manager *m, const struct rlimit *saved_rlimit_nofile, const struct rlimit *saved_rlimit_memlock, - bool *ret_reexecute, int *ret_retval, /* Return parameters relevant for shutting down */ const char **ret_shutdown_verb, /* … */ FDSet **ret_fds, /* Return parameters for reexecuting */ @@ -1968,7 +1974,6 @@ static int invoke_main_loop( assert(m); assert(saved_rlimit_nofile); assert(saved_rlimit_memlock); - assert(ret_reexecute); assert(ret_retval); assert(ret_shutdown_verb); assert(ret_fds); @@ -1977,13 +1982,13 @@ static int invoke_main_loop( assert(ret_error_message); for (;;) { - r = manager_loop(m); - if (r < 0) { + int objective = manager_loop(m); + if (objective < 0) { *ret_error_message = "Failed to run main loop"; - return log_emergency_errno(r, "Failed to run main loop: %m"); + return log_emergency_errno(objective, "Failed to run main loop: %m"); } - switch ((ManagerObjective) r) { + switch (objective) { case MANAGER_RELOAD: { LogTarget saved_log_target; @@ -2010,17 +2015,15 @@ static int invoke_main_loop( if (saved_log_target >= 0) manager_override_log_target(m, saved_log_target); - r = manager_reload(m); - if (r < 0) + if (manager_reload(m) < 0) /* Reloading failed before the point of no return. * Let's continue running as if nothing happened. */ m->objective = MANAGER_OK; - break; + continue; } case MANAGER_REEXECUTE: - r = prepare_reexecute(m, &arg_serialization, ret_fds, false); if (r < 0) { *ret_error_message = "Failed to prepare for reexecution"; @@ -2029,12 +2032,11 @@ static int invoke_main_loop( log_notice("Reexecuting."); - *ret_reexecute = true; *ret_retval = EXIT_SUCCESS; *ret_shutdown_verb = NULL; *ret_switch_root_dir = *ret_switch_root_init = NULL; - return 0; + return objective; case MANAGER_SWITCH_ROOT: if (!m->switch_root_init) { @@ -2048,7 +2050,6 @@ static int invoke_main_loop( log_notice("Switching root."); - *ret_reexecute = true; *ret_retval = EXIT_SUCCESS; *ret_shutdown_verb = NULL; @@ -2056,20 +2057,18 @@ static int invoke_main_loop( *ret_switch_root_dir = TAKE_PTR(m->switch_root); *ret_switch_root_init = TAKE_PTR(m->switch_root_init); - return 0; + return objective; case MANAGER_EXIT: - if (MANAGER_IS_USER(m)) { log_debug("Exit."); - *ret_reexecute = false; *ret_retval = m->return_value; *ret_shutdown_verb = NULL; *ret_fds = NULL; *ret_switch_root_dir = *ret_switch_root_init = NULL; - return 0; + return objective; } _fallthrough_; @@ -2077,7 +2076,7 @@ static int invoke_main_loop( case MANAGER_POWEROFF: case MANAGER_HALT: case MANAGER_KEXEC: { - static const char * const table[_MANAGER_OBJECTIVE_MAX] = { + static const char* const table[_MANAGER_OBJECTIVE_MAX] = { [MANAGER_EXIT] = "exit", [MANAGER_REBOOT] = "reboot", [MANAGER_POWEROFF] = "poweroff", @@ -2087,13 +2086,12 @@ static int invoke_main_loop( log_notice("Shutting down."); - *ret_reexecute = false; *ret_retval = m->return_value; assert_se(*ret_shutdown_verb = table[m->objective]); *ret_fds = NULL; *ret_switch_root_dir = *ret_switch_root_init = NULL; - return 0; + return objective; } default: @@ -2259,7 +2257,7 @@ static int initialize_runtime( if (!arg_system) /* Become reaper of our children */ if (prctl(PR_SET_CHILD_SUBREAPER, 1) < 0) - log_warning_errno(errno, "Failed to make us a subreaper: %m"); + log_warning_errno(errno, "Failed to make us a subreaper, ignoring: %m"); /* Bump up RLIMIT_NOFILE for systemd itself */ (void) bump_rlimit_nofile(saved_rlimit_nofile); @@ -2709,15 +2707,18 @@ static int save_env(void) { } int main(int argc, char *argv[]) { - - dual_timestamp initrd_timestamp = DUAL_TIMESTAMP_NULL, userspace_timestamp = DUAL_TIMESTAMP_NULL, kernel_timestamp = DUAL_TIMESTAMP_NULL, - security_start_timestamp = DUAL_TIMESTAMP_NULL, security_finish_timestamp = DUAL_TIMESTAMP_NULL; + dual_timestamp + initrd_timestamp = DUAL_TIMESTAMP_NULL, + userspace_timestamp = DUAL_TIMESTAMP_NULL, + kernel_timestamp = DUAL_TIMESTAMP_NULL, + security_start_timestamp = DUAL_TIMESTAMP_NULL, + security_finish_timestamp = DUAL_TIMESTAMP_NULL; struct rlimit saved_rlimit_nofile = RLIMIT_MAKE_CONST(0), saved_rlimit_memlock = RLIMIT_MAKE_CONST(RLIM_INFINITY); /* The original rlimits we passed * in. Note we use different values * for the two that indicate whether * these fields are initialized! */ - bool skip_setup, loaded_policy = false, queue_default_job = false, first_boot = false, reexecute = false; + bool skip_setup, loaded_policy = false, queue_default_job = false, first_boot = false; char *switch_root_dir = NULL, *switch_root_init = NULL; usec_t before_startup, after_startup; static char systemd[] = "systemd"; @@ -3023,16 +3024,23 @@ int main(int argc, char *argv[]) { goto finish; } - (void) invoke_main_loop(m, - &saved_rlimit_nofile, - &saved_rlimit_memlock, - &reexecute, - &retval, - &shutdown_verb, - &fds, - &switch_root_dir, - &switch_root_init, - &error_message); + r = invoke_main_loop(m, + &saved_rlimit_nofile, + &saved_rlimit_memlock, + &retval, + &shutdown_verb, + &fds, + &switch_root_dir, + &switch_root_init, + &error_message); + assert(r < 0 || IN_SET(r, MANAGER_EXIT, /* MANAGER_OK is not expected here. */ + MANAGER_RELOAD, + MANAGER_REEXECUTE, + MANAGER_REBOOT, + MANAGER_POWEROFF, + MANAGER_HALT, + MANAGER_KEXEC, + MANAGER_SWITCH_ROOT)); finish: pager_close(); @@ -3045,14 +3053,15 @@ finish: mac_selinux_finish(); - if (reexecute) - do_reexecute(argc, argv, - &saved_rlimit_nofile, - &saved_rlimit_memlock, - fds, - switch_root_dir, - switch_root_init, - &error_message); /* This only returns if reexecution failed */ + if (IN_SET(r, MANAGER_REEXECUTE, MANAGER_SWITCH_ROOT)) + r = do_reexecute(r, + argc, argv, + &saved_rlimit_nofile, + &saved_rlimit_memlock, + fds, + switch_root_dir, + switch_root_init, + &error_message); /* This only returns if reexecution failed */ arg_serialization = safe_fclose(arg_serialization); fds = fdset_free(fds); @@ -3078,7 +3087,9 @@ finish: __lsan_do_leak_check(); #endif - if (shutdown_verb) { + /* Try to invoke the shutdown binary unless we already failed. + * If we failed above, we want to freeze after finishing cleanup. */ + if (r >= 0 && shutdown_verb) { r = become_shutdown(shutdown_verb, retval); log_error_errno(r, "Failed to execute shutdown binary, %s: %m", getpid_cached() == 1 ? "freezing" : "quitting"); error_message = "Failed to execute shutdown binary"; diff --git a/test/units/testsuite-36.sh b/test/units/testsuite-36.sh index b6c00c4845..f9dfd0810c 100755 --- a/test/units/testsuite-36.sh +++ b/test/units/testsuite-36.sh @@ -181,7 +181,7 @@ else echo "PID1 NUMAPolicy support - Bind policy w/o mask" writePID1NUMAPolicy "bind" pid1ReloadWithJournal - grep "Failed to set NUMA memory policy: Invalid argument" "$journalLog" + grep "Failed to set NUMA memory policy, ignoring: Invalid argument" "$journalLog" echo "PID1 NUMAPolicy support - Bind policy w/ mask" writePID1NUMAPolicy "bind" "0" @@ -191,7 +191,7 @@ else echo "PID1 NUMAPolicy support - Interleave policy w/o mask" writePID1NUMAPolicy "interleave" pid1ReloadWithJournal - grep "Failed to set NUMA memory policy: Invalid argument" "$journalLog" + grep "Failed to set NUMA memory policy, ignoring: Invalid argument" "$journalLog" echo "PID1 NUMAPolicy support - Interleave policy w/ mask" writePID1NUMAPolicy "interleave" "0" @@ -202,7 +202,7 @@ else writePID1NUMAPolicy "preferred" pid1ReloadWithJournal # Preferred policy with empty node mask is actually allowed and should reset allocation policy to default - grep "Failed to set NUMA memory policy: Invalid argument" "$journalLog" && { echo >&2 "unexpected pass"; exit 1; } + grep "Failed to set NUMA memory policy, ignoring: Invalid argument" "$journalLog" && { echo >&2 "unexpected pass"; exit 1; } echo "PID1 NUMAPolicy support - Preferred policy w/ mask" writePID1NUMAPolicy "preferred" "0"