X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;ds=sidebyside;f=main.c;h=7dbcc90d5ebff9ae9695883782af49ddb7777975;hb=8d0e8067af90e2a05d2051e7fdbe0b7f847dd167;hp=f314efd30c106a38ab36326b1316d9ef257438ee;hpb=18149b9f57f8971ebc7d6401fc0a08a3173bcb29;p=elogind.git diff --git a/main.c b/main.c index f314efd30..7dbcc90d5 100644 --- a/main.c +++ b/main.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "manager.h" #include "log.h" @@ -45,7 +46,10 @@ static enum { static char *default_unit = NULL; static ManagerRunningAs running_as = _MANAGER_RUNNING_AS_INVALID; + static bool dump_core = true; +static bool crash_shell = false; +static int crash_chvt = -1; _noreturn static void freeze(void) { for (;;) @@ -59,10 +63,8 @@ _noreturn static void crash(int sig) { else { pid_t pid; - log_warning("Caugh <%s>, dumping core.", strsignal(sig)); - if ((pid = fork()) < 0) - log_error("Caught <%s>, cannot dump core: %s", strsignal(sig), strerror(errno)); + log_error("Caught <%s>, cannot fork for core dump: %s", strsignal(sig), strerror(errno)); else if (pid == 0) { struct sigaction sa; @@ -87,10 +89,32 @@ _noreturn static void crash(int sig) { assert_not_reached("We shouldn't be here..."); _exit(1); + + } else { + int status, r; + + /* Order things nicely. */ + if ((r = waitpid(pid, &status, 0)) < 0) + log_error("Caught <%s>, waitpid() failed: %s", strsignal(sig), strerror(errno)); + else if (!WCOREDUMP(status)) + log_error("Caught <%s>, core dump failed.", strsignal(sig)); + else + log_error("Caught <%s>, dumped core as pid %llu.", strsignal(sig), (unsigned long long) pid); } } - log_error("Freezing execution."); + if (crash_chvt) + chvt(crash_chvt); + + if (crash_shell) { + log_info("Executing crash shell in 10s..."); + sleep(10); + + execl("/bin/sh", "/bin/sh", NULL); + log_error("execl() failed: %s", strerror(errno)); + } + + log_info("Freezing execution."); freeze(); } @@ -103,6 +127,10 @@ 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); } @@ -146,6 +174,42 @@ static int parse_proc_cmdline_word(const char *word) { if (log_set_max_level_from_string(word + 18) < 0) log_warning("Failed to parse log level %s. Ignoring.", word + 18); + } else if (startswith(word, "systemd.dump_core=")) { + int r; + + if ((r = parse_boolean(word + 18)) < 0) + log_warning("Failed to parse dump core switch %s, Ignoring.", word + 18); + else + dump_core = r; + + } else if (startswith(word, "systemd.crash_shell=")) { + int r; + + if ((r = parse_boolean(word + 20)) < 0) + log_warning("Failed to parse crash shell switch %s, Ignoring.", word + 20); + else + crash_shell = r; + + } else if (startswith(word, "systemd.crash_chvt=")) { + int k; + + if (safe_atoi(word + 19, &k) < 0) + log_warning("Failed to parse crash chvt switch %s, Ignoring.", word + 19); + else + crash_chvt = k; + + } else if (startswith(word, "systemd.")) { + + log_warning("Unknown kernel switch %s. Ignoring.", word); + + log_info("Supported kernel switches:"); + log_info("systemd.default=UNIT Default unit to start"); + log_info("systemd.log_target=console|kmsg|syslog Log target"); + log_info("systemd.log_level=LEVEL Log level"); + 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"); + } else { unsigned i; @@ -323,6 +387,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. */ + signal(SIGKILL, SIG_IGN); + signal(SIGPIPE, SIG_IGN); + /* Close all open files */ assert_se(close_all_fds(NULL, 0) == 0); @@ -367,8 +435,10 @@ int main(int argc, char *argv[]) { log_open_syslog(); log_open_kmsg(); - /* Make sure we leave a core dump */ - install_crash_handler(); + /* Make sure we leave a core dump without panicing the + * kernel. */ + if (getpid() == 1) + install_crash_handler(); log_debug("systemd running in %s mode.", manager_running_as_to_string(running_as));