From 477def8097245a124f8ff51d17415cf78cde691b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 8 Nov 2013 19:32:45 +0100 Subject: [PATCH] shutdown: unify handling of reboot() syscall a bit --- TODO | 4 ++- src/core/shutdown.c | 72 +++++++++++++++++++++++++++------------ src/shared/util.c | 1 + src/systemctl/systemctl.c | 41 +++++++++++----------- 4 files changed, 74 insertions(+), 44 deletions(-) diff --git a/TODO b/TODO index e08e11e2d..9f83a2441 100644 --- a/TODO +++ b/TODO @@ -46,9 +46,11 @@ CGroup Rework Completion: Features: +* increase journal files by a few MB each time, instead of piecemeal + * add field to transient units that indicate whether systemd or somebody else saves/restores its settings, for integration with libvirt -* wait filter, reboot() filter unification, unify dispatch table in systemctl_main() and friends, convert all to bus_log_create_error() +* wait filter, unify dispatch table in systemctl_main() and friends, convert all to bus_log_create_error() * bus: access policy as vtable flag diff --git a/src/core/shutdown.c b/src/core/shutdown.c index 377c1971a..b5eb8b12d 100644 --- a/src/core/shutdown.c +++ b/src/core/shutdown.c @@ -135,7 +135,7 @@ static int pivot_to_new_root(void) { int main(int argc, char *argv[]) { bool need_umount = true, need_swapoff = true, need_loop_detach = true, need_dm_detach = true; bool in_container, use_watchdog = false; - _cleanup_free_ char *line = NULL, *cgroup = NULL, *param = NULL; + _cleanup_free_ char *line = NULL, *cgroup = NULL; char *arguments[3]; unsigned retries; int cmd, r; @@ -174,11 +174,9 @@ int main(int argc, char *argv[]) { in_container = detect_container(NULL) > 0; - if (streq(argv[1], "reboot")) { + if (streq(argv[1], "reboot")) cmd = RB_AUTOBOOT; - /* if this fails, that's OK */ - read_one_line_file(REBOOT_PARAM_FILE, ¶m); - } else if (streq(argv[1], "poweroff")) + else if (streq(argv[1], "poweroff")) cmd = RB_POWER_OFF; else if (streq(argv[1], "halt")) cmd = RB_HALT_SYSTEM; @@ -318,39 +316,69 @@ int main(int argc, char *argv[]) { if (!in_container) sync(); - if (cmd == LINUX_REBOOT_CMD_KEXEC) { + switch (cmd) { + + case LINUX_REBOOT_CMD_KEXEC: if (!in_container) { /* We cheat and exec kexec to avoid doing all its work */ - pid_t pid = fork(); + pid_t pid; + + log_info("Rebooting with kexec."); + pid = fork(); if (pid < 0) - log_error("Could not fork: %m. Falling back to normal reboot."); - else if (pid > 0) { - wait_for_terminate_and_warn("kexec", pid); - log_warning("kexec failed. Falling back to normal reboot."); - } else { + log_error("Failed to fork: %m"); + else if (pid == 0) { + + const char * const args[] = { + KEXEC, "-e", NULL + }; + /* Child */ - const char *args[3] = { KEXEC, "-e", NULL }; + execv(args[0], (char * const *) args); - return EXIT_FAILURE; - } + _exit(EXIT_FAILURE); + } else + wait_for_terminate_and_warn("kexec", pid); } cmd = RB_AUTOBOOT; - } + /* Fall through */ - if (param) - syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, - LINUX_REBOOT_CMD_RESTART2, param); - else - reboot(cmd); + case RB_AUTOBOOT: + + if (!in_container) { + _cleanup_free_ char *param = NULL; + + if (read_one_line_file(REBOOT_PARAM_FILE, ¶m) >= 0) { + log_info("Rebooting with argument '%s'.", param); + syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, + LINUX_REBOOT_CMD_RESTART2, param); + } + } + + log_info("Rebooting."); + break; + + case RB_POWER_OFF: + log_info("Powering off."); + break; + + case RB_HALT_SYSTEM: + log_info("Halting system."); + break; + + default: + assert_not_reached("Unknown magic"); + } + reboot(cmd); if (errno == EPERM && in_container) { /* If we are in a container, and we lacked * CAP_SYS_BOOT just exit, this will kill our * container for good. */ - log_error("Exiting container."); + log_info("Exiting container."); exit(0); } diff --git a/src/shared/util.c b/src/shared/util.c index a6669c5a9..838885a46 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -77,6 +77,7 @@ #include "utf8.h" #include "gunicode.h" #include "virt.h" +#include "def.h" int saved_argc = 0; char **saved_argv = NULL; diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 63800864a..c042da550 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -135,7 +135,7 @@ static OutputMode arg_output = OUTPUT_SHORT; static bool arg_plain = false; static int daemon_reload(sd_bus *bus, char **args); -static void halt_now(enum action a); +static int halt_now(enum action a); static void pager_open_if_enabled(void) { @@ -2033,7 +2033,7 @@ static int start_special(sd_bus *bus, char **args) { (a == ACTION_HALT || a == ACTION_POWEROFF || a == ACTION_REBOOT)) - halt_now(a); + return halt_now(a); if (arg_force >= 1 && (a == ACTION_HALT || @@ -5609,11 +5609,9 @@ done: return 0; } -static _noreturn_ void halt_now(enum action a) { +static int halt_now(enum action a) { - _cleanup_free_ char *param = NULL; - - /* Make sure C-A-D is handled by the kernel from this +/* Make sure C-A-D is handled by the kernel from this * point on... */ reboot(RB_ENABLE_CAD); @@ -5622,30 +5620,30 @@ static _noreturn_ void halt_now(enum action a) { case ACTION_HALT: log_info("Halting."); reboot(RB_HALT_SYSTEM); - break; + return -errno; case ACTION_POWEROFF: log_info("Powering off."); reboot(RB_POWER_OFF); - break; + return -errno; - case ACTION_REBOOT: + case ACTION_REBOOT: { + _cleanup_free_ char *param = NULL; - if (read_one_line_file(REBOOT_PARAM_FILE, ¶m) == 0) { - log_info("Rebooting with arg '%s'.", param); + if (read_one_line_file(REBOOT_PARAM_FILE, ¶m) >= 0) { + log_info("Rebooting with argument '%s'.", param); syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, param); - } else { - log_info("Rebooting."); - reboot(RB_AUTOBOOT); } - break; - default: - assert_not_reached("Unknown halt action."); + log_info("Rebooting."); + reboot(RB_AUTOBOOT); + return -errno; } - assert_not_reached("Uh? This shouldn't happen."); + default: + assert_not_reached("Unknown action."); + } } static int halt_main(sd_bus *bus) { @@ -5717,9 +5715,10 @@ static int halt_main(sd_bus *bus) { if (arg_dry) return 0; - halt_now(arg_action); - /* We should never reach this. */ - return -ENOSYS; + r = halt_now(arg_action); + log_error("Failed to reboot: %s", strerror(-r)); + + return r; } static int runlevel_main(void) { -- 2.30.2