X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fcore%2Fshutdown.c;h=31129b7697edf01ae5de5787b7c5b75816fe4e64;hp=c02a14d66e2f18bcb43171f15b4ca57bc70a969b;hb=3fa5dd6de798e17d93531bc900b8e2dc587c38f3;hpb=ec26be514ff3c5367b21f9881369080bda54fd2d diff --git a/src/core/shutdown.c b/src/core/shutdown.c index c02a14d66..31129b769 100644 --- a/src/core/shutdown.c +++ b/src/core/shutdown.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -46,6 +45,8 @@ #include "virt.h" #include "watchdog.h" #include "killall.h" +#include "cgroup-util.h" +#include "def.h" #define FINALIZE_ATTEMPTS 50 @@ -131,24 +132,25 @@ static int pivot_to_new_root(void) { } int main(int argc, char *argv[]) { - _cleanup_free_ char *line = NULL; - int cmd, r; - unsigned retries; 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; char *arguments[3]; + unsigned retries; + int cmd, r; /* suppress shutdown status output if 'quiet' is used */ - r = read_one_line_file("/proc/cmdline", &line); - if (r >= 0) { + r = proc_cmdline(&line); + if (r > 0) { char *w, *state; size_t l; - FOREACH_WORD_QUOTED(w, l, line, state) - if (streq(w, "quiet")) { + FOREACH_WORD_QUOTED(w, l, line, state) { + if (l == 5 && memcmp(w, "quiet", 5) == 0) { log_set_max_level(LOG_WARNING); break; } + } } log_parse_environment(); @@ -185,16 +187,18 @@ int main(int argc, char *argv[]) { goto error; } + cg_get_root_path(&cgroup); + use_watchdog = !!getenv("WATCHDOG_USEC"); /* lock us into memory */ mlockall(MCL_CURRENT|MCL_FUTURE); log_info("Sending SIGTERM to remaining processes..."); - broadcast_signal(SIGTERM, true); + broadcast_signal(SIGTERM, true, true); log_info("Sending SIGKILL to remaining processes..."); - broadcast_signal(SIGKILL, true); + broadcast_signal(SIGKILL, true, false); if (in_container) { need_swapoff = false; @@ -209,6 +213,13 @@ int main(int argc, char *argv[]) { if (use_watchdog) watchdog_ping(); + /* Let's trim the cgroup tree on each iteration so + that we leave an empty cgroup tree around, so that + container managers get a nice notify event when we + are down */ + if (cgroup) + cg_trim(SYSTEMD_CGROUP_CONTROLLER, cgroup, false); + if (need_umount) { log_info("Unmounting file systems."); r = umount_all(&changed); @@ -304,35 +315,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] = { "/sbin/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 */ + + 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); }