chiark / gitweb /
main: when ignoring a signal set SA_RESTART
[elogind.git] / main.c
diff --git a/main.c b/main.c
index 5f0aeba85752c09293120fccd3e2da72f41f9322..3e2bfe10ca94b5ed384a9e6ca205d848c5de8e08 100644 (file)
--- a/main.c
+++ b/main.c
@@ -30,6 +30,7 @@
 #include <getopt.h>
 #include <signal.h>
 #include <sys/wait.h>
+#include <fcntl.h>
 
 #include "manager.h"
 #include "log.h"
@@ -48,7 +49,10 @@ static char *default_unit = NULL;
 static ManagerRunningAs running_as = _MANAGER_RUNNING_AS_INVALID;
 
 static bool dump_core = true;
-static bool crash_shell = true;
+static bool crash_shell = false;
+static int crash_chvt = -1;
+
+static bool confirm_spawn = false;
 
 _noreturn static void freeze(void) {
         for (;;)
@@ -102,6 +106,9 @@ _noreturn static void crash(int sig) {
                 }
         }
 
+        if (crash_chvt)
+                chvt(crash_chvt);
+
         if (crash_shell) {
                 log_info("Executing crash shell in 10s...");
                 sleep(10);
@@ -123,9 +130,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;
 
@@ -170,7 +228,7 @@ static int parse_proc_cmdline_word(const char *word) {
                 int r;
 
                 if ((r = parse_boolean(word + 18)) < 0)
-                        log_warning("Failed to parse dump core switch %s, Ignoring", word + 18);
+                        log_warning("Failed to parse dump core switch %s, Ignoring.", word + 18);
                 else
                         dump_core = r;
 
@@ -178,10 +236,18 @@ static int parse_proc_cmdline_word(const char *word) {
                 int r;
 
                 if ((r = parse_boolean(word + 20)) < 0)
-                        log_warning("Failed to parse crash shell switch %s, Ignoring", word + 20);
+                        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);
@@ -192,6 +258,7 @@ static int parse_proc_cmdline_word(const char *word) {
                 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;
@@ -247,7 +314,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[] = {
@@ -258,6 +326,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 }
         };
 
@@ -316,6 +385,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;
@@ -340,7 +413,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;
@@ -370,6 +444,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);
 
@@ -401,11 +479,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);
@@ -414,7 +497,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();
 
@@ -423,7 +507,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;
         }