X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=main.c;h=c473ced2b41c04e0e2bd01e1424423ddd0e6c582;hp=68a90210839f127748f29d465d35966cf7d79185;hb=09477267f6b353ab607be55e59d2924187d401c4;hpb=601f6a1e820462b1df6ff632d112bef241d556b1 diff --git a/main.c b/main.c index 68a902108..c473ced2b 100644 --- a/main.c +++ b/main.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "manager.h" #include "log.h" @@ -51,23 +52,34 @@ static bool dump_core = true; static bool crash_shell = false; static int crash_chvt = -1; +static bool confirm_spawn = false; + _noreturn static void freeze(void) { for (;;) pause(); } +static void nop_handler(int sig) { +} + _noreturn static void crash(int sig) { if (!dump_core) log_error("Caught <%s>, not dumping core.", strsignal(sig)); else { + struct sigaction sa; pid_t pid; + /* We want to wait for the core process, hence let's enable SIGCHLD */ + zero(sa); + sa.sa_handler = nop_handler; + sa.sa_flags = SA_NOCLDSTOP|SA_RESTART; + assert_se(sigaction(SIGCHLD, &sa, NULL) == 0); + if ((pid = fork()) < 0) log_error("Caught <%s>, cannot fork for core dump: %s", strsignal(sig), strerror(errno)); else if (pid == 0) { - struct sigaction sa; struct rlimit rl; /* Enable default signal handler for core dump */ @@ -107,11 +119,28 @@ _noreturn static void crash(int sig) { chvt(crash_chvt); if (crash_shell) { + struct sigaction sa; + pid_t pid; + log_info("Executing crash shell in 10s..."); sleep(10); - execl("/bin/sh", "/bin/sh", NULL); - log_error("execl() failed: %s", strerror(errno)); + /* Let the kernel reap children for us */ + zero(sa); + sa.sa_handler = SIG_IGN; + sa.sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART; + assert_se(sigaction(SIGCHLD, &sa, NULL) == 0); + + if ((pid = fork()) < 0) + log_error("Failed to fork off crash shell: %s", strerror(errno)); + else if (pid == 0) { + execl("/bin/sh", "/bin/sh", NULL); + + log_error("execl() failed: %s", strerror(errno)); + _exit(1); + } + + log_info("Successfully spawned crash shall as pid %llu.", (unsigned long long) pid); } log_info("Freezing execution."); @@ -127,9 +156,60 @@ static void install_crash_handler(void) { sa.sa_flags = SA_NODEFER; assert_se(sigaction(SIGSEGV, &sa, NULL) == 0); + assert_se(sigaction(SIGILL, &sa, NULL) == 0); + assert_se(sigaction(SIGFPE, &sa, NULL) == 0); + assert_se(sigaction(SIGBUS, &sa, NULL) == 0); + assert_se(sigaction(SIGQUIT, &sa, NULL) == 0); assert_se(sigaction(SIGABRT, &sa, NULL) == 0); } +static int console_setup(void) { + int tty_fd = -1, null_fd = -1, r = 0; + + /* If we are init, we connect stdout/stderr to /dev/console + * and stdin to /dev/null and make sure we don't have a + * controlling tty. */ + + release_terminal(); + + if ((tty_fd = open_terminal("/dev/console", O_WRONLY)) < 0) { + log_error("Failed to open /dev/console: %s", strerror(-tty_fd)); + r = -tty_fd; + goto finish; + } + + if ((null_fd = open("/dev/null", O_RDONLY)) < 0) { + log_error("Failed to open /dev/null: %m"); + r = -errno; + goto finish; + } + + assert(tty_fd >= 3); + assert(null_fd >= 3); + + if (reset_terminal(tty_fd) < 0) + log_error("Failed to reset /dev/console: %m"); + + if (dup2(tty_fd, STDOUT_FILENO) < 0 || + dup2(tty_fd, STDERR_FILENO) < 0 || + dup2(null_fd, STDIN_FILENO) < 0) { + log_error("Failed to dup2() device: %m"); + r = -errno; + goto finish; + } + + r = 0; + +finish: + if (tty_fd >= 0) + close_nointr(tty_fd); + + if (null_fd >= 0) + close_nointr(null_fd); + + return r; +} + static int set_default_unit(const char *u) { char *c; @@ -186,6 +266,15 @@ static int parse_proc_cmdline_word(const char *word) { else crash_shell = r; + + } else if (startswith(word, "systemd.confirm_spawn=")) { + int r; + + if ((r = parse_boolean(word + 22)) < 0) + log_warning("Failed to parse confirm spawn switch %s, Ignoring.", word + 22); + else + confirm_spawn = r; + } else if (startswith(word, "systemd.crash_chvt=")) { int k; @@ -205,6 +294,7 @@ static int parse_proc_cmdline_word(const char *word) { log_info("systemd.dump_core=0|1 Dump core on crash"); log_info("systemd.crash_shell=0|1 On crash run shell"); log_info("systemd.crash_chvt=N Change to VT #N on crash"); + log_info("systemd.confirm_spawn=0|1 Confirm every process spawn"); } else { unsigned i; @@ -260,7 +350,8 @@ static int parse_argv(int argc, char *argv[]) { ARG_DEFAULT, ARG_RUNNING_AS, ARG_TEST, - ARG_DUMP_CONFIGURATION_ITEMS + ARG_DUMP_CONFIGURATION_ITEMS, + ARG_CONFIRM_SPAWN }; static const struct option options[] = { @@ -271,6 +362,7 @@ static int parse_argv(int argc, char *argv[]) { { "test", no_argument, NULL, ARG_TEST }, { "help", no_argument, NULL, 'h' }, { "dump-configuration-items", no_argument, NULL, ARG_DUMP_CONFIGURATION_ITEMS }, + { "confirm-spawn", no_argument, NULL, ARG_CONFIRM_SPAWN }, { NULL, 0, NULL, 0 } }; @@ -329,6 +421,10 @@ static int parse_argv(int argc, char *argv[]) { action = ACTION_DUMP_CONFIGURATION_ITEMS; break; + case ARG_CONFIRM_SPAWN: + confirm_spawn = true; + break; + case 'h': action = ACTION_HELP; break; @@ -353,7 +449,8 @@ static int help(void) { " --log-target=TARGET Set log target (console, syslog, kmsg)\n" " --running-as=AS Set running as (init, system, session)\n" " --test Determine startup sequence, dump it and exit\n" - " --dump-configuration-items Dump understood unit configuration items\n", + " --dump-configuration-items Dump understood unit configuration items\n" + " --confirm-spawn Ask for confirmation when spawning processes\n", __progname); return 0; @@ -383,6 +480,10 @@ int main(int argc, char *argv[]) { /* Reset all signal handlers. */ assert_se(reset_all_signal_handlers() == 0); + /* If we are init, we can block sigkill. Yay. */ + ignore_signal(SIGKILL); + ignore_signal(SIGPIPE); + /* Close all open files */ assert_se(close_all_fds(NULL, 0) == 0); @@ -414,11 +515,16 @@ int main(int argc, char *argv[]) { /* Move out of the way, so that we won't block unmounts */ assert_se(chdir("/") == 0); - /* Become a session leader if we aren't one yet. */ - setsid(); + if (running_as != MANAGER_SESSION) { + /* Become a session leader if we aren't one yet. */ + setsid(); + + /* Disable the umask logic */ + umask(0); + } - /* Disable the umask logic */ - umask(0); + if (running_as == MANAGER_INIT) + console_setup(); /* Make sure D-Bus doesn't fiddle with the SIGPIPE handlers */ dbus_connection_set_change_sigpipe(FALSE); @@ -427,7 +533,8 @@ int main(int argc, char *argv[]) { log_open_syslog(); log_open_kmsg(); - /* Make sure we leave a core dump */ + /* Make sure we leave a core dump without panicing the + * kernel. */ if (getpid() == 1) install_crash_handler(); @@ -436,7 +543,7 @@ int main(int argc, char *argv[]) { if (running_as == MANAGER_INIT) hostname_setup(); - if ((r = manager_new(running_as, &m)) < 0) { + if ((r = manager_new(running_as, confirm_spawn, &m)) < 0) { log_error("Failed to allocate manager object: %s", strerror(-r)); goto finish; } @@ -448,11 +555,11 @@ int main(int argc, char *argv[]) { log_debug("Activating default unit: %s", default_unit); - if ((r = manager_load_unit(m, default_unit, &target)) < 0) { + if ((r = manager_load_unit(m, default_unit, NULL, &target)) < 0) { log_error("Failed to load default target: %s", strerror(-r)); log_info("Trying to load rescue target..."); - if ((r = manager_load_unit(m, SPECIAL_RESCUE_TARGET, &target)) < 0) { + if ((r = manager_load_unit(m, SPECIAL_RESCUE_TARGET, NULL, &target)) < 0) { log_error("Failed to load rescue target: %s", strerror(-r)); goto finish; } @@ -496,5 +603,8 @@ finish: dbus_shutdown(); + if (getpid() == 1) + freeze(); + return retval; }