chiark / gitweb /
units: rename [Meta] section to [Unit]
[elogind.git] / main.c
diff --git a/main.c b/main.c
index 68a90210839f127748f29d465d35966cf7d79185..c473ced2b41c04e0e2bd01e1424423ddd0e6c582 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"
@@ -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;
 }