X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fshutdown.c;h=9f65b1dab0b78aeed203717b75ba3852cc3ceb1e;hb=07cd4fc16806783d3b6b3008db222ac6a024805c;hp=0905ef5b3a96ab5523d9aa5a26db1814e1f64085;hpb=3b8a1f3fee7bf83af5bbae541166508cf172b67c;p=elogind.git diff --git a/src/shutdown.c b/src/shutdown.c index 0905ef5b3..9f65b1dab 100644 --- a/src/shutdown.c +++ b/src/shutdown.c @@ -41,34 +41,54 @@ #include "log.h" #include "umount.h" #include "util.h" +#include "virt.h" +#include "watchdog.h" #define TIMEOUT_USEC (5 * USEC_PER_SEC) #define FINALIZE_ATTEMPTS 50 static bool ignore_proc(pid_t pid) { + char buf[PATH_MAX]; + FILE *f; + char c; + size_t count; + uid_t uid; + int r; + + /* We are PID 1, let's not commit suicide */ if (pid == 1) return true; - /* TODO: add more ignore rules here: device-mapper, etc */ + r = get_process_uid(pid, &uid); + if (r < 0) + return true; /* not really, but better safe than sorry */ - return false; -} + /* Non-root processes otherwise are always subject to be killed */ + if (uid != 0) + return false; -static bool is_kernel_thread(pid_t pid) -{ - char buf[PATH_MAX]; - FILE *f; - char c; - size_t count; + snprintf(buf, sizeof(buf), "/proc/%lu/cmdline", (unsigned long) pid); + char_array_0(buf); - snprintf(buf, sizeof(buf), "/proc/%lu/cmdline", (unsigned long)pid); f = fopen(buf, "re"); if (!f) return true; /* not really, but has the desired effect */ count = fread(&c, 1, 1, f); fclose(f); - return count != 1; + + /* Kernel threads have an empty cmdline */ + if (count <= 0) + return true; + + /* Processes with argv[0][0] = '@' we ignore from the killing + * spree. + * + * http://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons */ + if (count == 1 && c == '@') + return true; + + return false; } static int killall(int sign) { @@ -76,7 +96,8 @@ static int killall(int sign) { struct dirent *d; unsigned int n_processes = 0; - if ((dir = opendir("/proc")) == NULL) + dir = opendir("/proc"); + if (!dir) return -errno; while ((d = readdir(dir))) { @@ -85,9 +106,6 @@ static int killall(int sign) { if (parse_pid(d->d_name, &pid) < 0) continue; - if (is_kernel_thread(pid)) - continue; - if (ignore_proc(pid)) continue; @@ -276,6 +294,10 @@ static int pivot_to_new_root(void) { log_error("Failed to open /dev/console: %m"); else { make_stdio(fd); + + /* Initialize the controlling terminal */ + setsid(); + ioctl(STDIN_FILENO, TIOCSCTTY, NULL); } return 0; @@ -285,12 +307,14 @@ int main(int argc, char *argv[]) { int cmd, r; unsigned retries; bool need_umount = true, need_swapoff = true, need_loop_detach = true, need_dm_detach = true; - bool killed_everbody = false, in_container; + bool killed_everbody = false, in_container, use_watchdog = false; log_parse_environment(); log_set_target(LOG_TARGET_CONSOLE); /* syslog will die if not gone yet */ log_open(); + umask(0022); + if (getpid() != 1) { log_error("Not executed by init (pid 1)."); r = -EPERM; @@ -319,6 +343,8 @@ int main(int argc, char *argv[]) { goto error; } + use_watchdog = !!getenv("WATCHDOG_USEC"); + /* lock us into memory */ if (mlockall(MCL_CURRENT|MCL_FUTURE) != 0) log_warning("Cannot lock process memory: %m"); @@ -336,6 +362,9 @@ int main(int argc, char *argv[]) { for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) { bool changed = false; + if (use_watchdog) + watchdog_ping(); + if (need_umount) { log_info("Unmounting file systems."); r = umount_all(&changed); @@ -380,9 +409,12 @@ int main(int argc, char *argv[]) { log_error("Failed to detach DM devices: %s", strerror(-r)); } - if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach) + if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach) { + if (retries > 0) + log_info("All filesystems, swaps, loop devices, DM devices detached."); /* Yay, done */ break; + } /* If in this iteration we didn't manage to * unmount/deactivate anything, we either kill more