]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
pid1: split out crash handler logic into its own .c/.h file 22695/head
authorLennart Poettering <lennart@poettering.net>
Thu, 10 Mar 2022 08:33:05 +0000 (09:33 +0100)
committerLennart Poettering <lennart@poettering.net>
Thu, 10 Mar 2022 12:45:14 +0000 (13:45 +0100)
This stuff is sufficiently different from the rest of main.c, let's move
it to its own .c/.h file, to make main.c a bit shorter.

No code changes, just some refactoring.

src/core/crash-handler.c [new file with mode: 0644]
src/core/crash-handler.h [new file with mode: 0644]
src/core/main.c
src/core/main.h [new file with mode: 0644]
src/core/meson.build

diff --git a/src/core/crash-handler.c b/src/core/crash-handler.c
new file mode 100644 (file)
index 0000000..561b7fc
--- /dev/null
@@ -0,0 +1,166 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <sys/reboot.h>
+
+#include "crash-handler.h"
+#include "exit-status.h"
+#include "macro.h"
+#include "main.h"
+#include "missing_syscall.h"
+#include "process-util.h"
+#include "raw-clone.h"
+#include "rlimit-util.h"
+#include "signal-util.h"
+#include "terminal-util.h"
+#include "virt.h"
+
+_noreturn_ void freeze_or_exit_or_reboot(void) {
+
+        /* If we are running in a container, let's prefer exiting, after all we can propagate an exit code to
+         * the container manager, and thus inform it that something went wrong. */
+        if (detect_container() > 0) {
+                log_emergency("Exiting PID 1...");
+                _exit(EXIT_EXCEPTION);
+        }
+
+        if (arg_crash_reboot) {
+                log_notice("Rebooting in 10s...");
+                (void) sleep(10);
+
+                log_notice("Rebooting now...");
+                (void) reboot(RB_AUTOBOOT);
+                log_emergency_errno(errno, "Failed to reboot: %m");
+        }
+
+        log_emergency("Freezing execution.");
+        sync();
+        freeze();
+}
+
+_noreturn_ static void crash(int sig, siginfo_t *siginfo, void *context) {
+        struct sigaction sa;
+        pid_t pid;
+
+        /* NB: ðŸ’£ ðŸ’£ ðŸ’£ This is a signal handler, most likely executed in a situation where we have corrupted
+         * memory. Thus: please avoid any libc memory allocation here, or any functions that internally use
+         * memory allocation, as we cannot rely on memory allocation still working at this point! (Note that
+         * memory allocation is not async-signal-safe anyway â€” see signal-safety(7) for details â€”, and thus
+         * is not permissible in signal handlers.) */
+
+        if (getpid_cached() != 1)
+                /* Pass this on immediately, if this is not PID 1 */
+                (void) raise(sig);
+        else if (!arg_dump_core)
+                log_emergency("Caught <%s>, not dumping core.", signal_to_string(sig));
+        else {
+                sa = (struct sigaction) {
+                        .sa_handler = nop_signal_handler,
+                        .sa_flags = SA_NOCLDSTOP|SA_RESTART,
+                };
+
+                /* We want to wait for the core process, hence let's enable SIGCHLD */
+                (void) sigaction(SIGCHLD, &sa, NULL);
+
+                pid = raw_clone(SIGCHLD);
+                if (pid < 0)
+                        log_emergency_errno(errno, "Caught <%s>, cannot fork for core dump: %m", signal_to_string(sig));
+                else if (pid == 0) {
+                        /* Enable default signal handler for core dump */
+
+                        sa = (struct sigaction) {
+                                .sa_handler = SIG_DFL,
+                        };
+                        (void) sigaction(sig, &sa, NULL);
+
+                        /* Don't limit the coredump size */
+                        (void) setrlimit(RLIMIT_CORE, &RLIMIT_MAKE_CONST(RLIM_INFINITY));
+
+                        /* Just to be sure... */
+                        (void) chdir("/");
+
+                        /* Raise the signal again */
+                        pid = raw_getpid();
+                        (void) kill(pid, sig); /* raise() would kill the parent */
+
+                        assert_not_reached();
+                        _exit(EXIT_EXCEPTION);
+                } else {
+                        siginfo_t status;
+                        int r;
+
+                        if (siginfo) {
+                                if (siginfo->si_pid == 0)
+                                        log_emergency("Caught <%s> from unknown sender process.", signal_to_string(sig));
+                                else if (siginfo->si_pid == 1)
+                                        log_emergency("Caught <%s> from our own process.", signal_to_string(sig));
+                                else
+                                        log_emergency("Caught <%s> from PID "PID_FMT".", signal_to_string(sig), siginfo->si_pid);
+                        }
+
+                        /* Order things nicely. */
+                        r = wait_for_terminate(pid, &status);
+                        if (r < 0)
+                                log_emergency_errno(r, "Caught <%s>, waitpid() failed: %m", signal_to_string(sig));
+                        else if (status.si_code != CLD_DUMPED) {
+                                const char *s = status.si_code == CLD_EXITED
+                                        ? exit_status_to_string(status.si_status, EXIT_STATUS_LIBC)
+                                        : signal_to_string(status.si_status);
+
+                                log_emergency("Caught <%s>, core dump failed (child "PID_FMT", code=%s, status=%i/%s).",
+                                              signal_to_string(sig),
+                                              pid,
+                                              sigchld_code_to_string(status.si_code),
+                                              status.si_status, strna(s));
+                        } else
+                                log_emergency("Caught <%s>, dumped core as pid "PID_FMT".",
+                                              signal_to_string(sig), pid);
+                }
+        }
+
+        if (arg_crash_chvt >= 0)
+                (void) chvt(arg_crash_chvt);
+
+        sa = (struct sigaction) {
+                .sa_handler = SIG_IGN,
+                .sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART,
+        };
+
+        /* Let the kernel reap children for us */
+        (void) sigaction(SIGCHLD, &sa, NULL);
+
+        if (arg_crash_shell) {
+                log_notice("Executing crash shell in 10s...");
+                (void) sleep(10);
+
+                pid = raw_clone(SIGCHLD);
+                if (pid < 0)
+                        log_emergency_errno(errno, "Failed to fork off crash shell: %m");
+                else if (pid == 0) {
+                        (void) setsid();
+                        (void) make_console_stdio();
+                        (void) rlimit_nofile_safe();
+                        (void) execle("/bin/sh", "/bin/sh", NULL, environ);
+
+                        log_emergency_errno(errno, "execle() failed: %m");
+                        _exit(EXIT_EXCEPTION);
+                } else {
+                        log_info("Spawned crash shell as PID "PID_FMT".", pid);
+                        (void) wait_for_terminate(pid, NULL);
+                }
+        }
+
+        freeze_or_exit_or_reboot();
+}
+
+void install_crash_handler(void) {
+        static const struct sigaction sa = {
+                .sa_sigaction = crash,
+                .sa_flags = SA_NODEFER | SA_SIGINFO, /* So that we can raise the signal again from the signal handler */
+        };
+        int r;
+
+        /* We ignore the return value here, since, we don't mind if we cannot set up a crash handler */
+        r = sigaction_many(&sa, SIGNALS_CRASH_HANDLER);
+        if (r < 0)
+                log_debug_errno(r, "I had trouble setting up the crash handler, ignoring: %m");
+}
diff --git a/src/core/crash-handler.h b/src/core/crash-handler.h
new file mode 100644 (file)
index 0000000..dc14335
--- /dev/null
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include "macro.h"
+
+_noreturn_ void freeze_or_exit_or_reboot(void);
+void install_crash_handler(void);
index fc524867ef6117e2c1d545a0e3ec95647ac63550..81db601a2cb1d74d1683c9493f58e46909c5d317 100644 (file)
@@ -6,7 +6,6 @@
 #include <linux/oom.h>
 #include <sys/mount.h>
 #include <sys/prctl.h>
-#include <sys/reboot.h>
 #include <unistd.h>
 #if HAVE_SECCOMP
 #include <seccomp.h>
@@ -33,6 +32,7 @@
 #include "clock-util.h"
 #include "conf-parser.h"
 #include "cpu-set-util.h"
+#include "crash-handler.h"
 #include "dbus-manager.h"
 #include "dbus.h"
 #include "def.h"
@@ -57,6 +57,7 @@
 #include "log.h"
 #include "loopback-setup.h"
 #include "machine-id-setup.h"
+#include "main.h"
 #include "manager.h"
 #include "manager-dump.h"
 #include "manager-serialize.h"
@@ -71,7 +72,6 @@
 #include "proc-cmdline.h"
 #include "process-util.h"
 #include "random-util.h"
-#include "raw-clone.h"
 #include "rlimit-util.h"
 #if HAVE_SECCOMP
 #include "seccomp-util.h"
@@ -116,10 +116,10 @@ static const char *arg_bus_introspect = NULL;
  * defaults are assigned in reset_arguments() below. */
 static char *arg_default_unit;
 static bool arg_system;
-static bool arg_dump_core;
-static int arg_crash_chvt;
-static bool arg_crash_shell;
-static bool arg_crash_reboot;
+bool arg_dump_core;
+int arg_crash_chvt;
+bool arg_crash_shell;
+bool arg_crash_reboot;
 static char *arg_confirm_spawn;
 static ShowStatus arg_show_status;
 static StatusUnitFormat arg_status_unit_format;
@@ -205,157 +205,6 @@ static int manager_find_user_config_paths(char ***ret_files, char ***ret_dirs) {
         return 0;
 }
 
-_noreturn_ static void freeze_or_exit_or_reboot(void) {
-
-        /* If we are running in a container, let's prefer exiting, after all we can propagate an exit code to
-         * the container manager, and thus inform it that something went wrong. */
-        if (detect_container() > 0) {
-                log_emergency("Exiting PID 1...");
-                _exit(EXIT_EXCEPTION);
-        }
-
-        if (arg_crash_reboot) {
-                log_notice("Rebooting in 10s...");
-                (void) sleep(10);
-
-                log_notice("Rebooting now...");
-                (void) reboot(RB_AUTOBOOT);
-                log_emergency_errno(errno, "Failed to reboot: %m");
-        }
-
-        log_emergency("Freezing execution.");
-        sync();
-        freeze();
-}
-
-_noreturn_ static void crash(int sig, siginfo_t *siginfo, void *context) {
-        struct sigaction sa;
-        pid_t pid;
-
-        /* NB: ðŸ’£ ðŸ’£ ðŸ’£ This is a signal handler, most likely executed in a situation where we have corrupted
-         * memory. Thus: please avoid any libc memory allocation here, or any functions that internally use
-         * memory allocation, as we cannot rely on memory allocation still working at this point! (Note that
-         * memory allocation is not async-signal-safe anyway â€” see signal-safety(7) for details â€”, and thus
-         * is not permissible in signal handlers.) */
-
-        if (getpid_cached() != 1)
-                /* Pass this on immediately, if this is not PID 1 */
-                (void) raise(sig);
-        else if (!arg_dump_core)
-                log_emergency("Caught <%s>, not dumping core.", signal_to_string(sig));
-        else {
-                sa = (struct sigaction) {
-                        .sa_handler = nop_signal_handler,
-                        .sa_flags = SA_NOCLDSTOP|SA_RESTART,
-                };
-
-                /* We want to wait for the core process, hence let's enable SIGCHLD */
-                (void) sigaction(SIGCHLD, &sa, NULL);
-
-                pid = raw_clone(SIGCHLD);
-                if (pid < 0)
-                        log_emergency_errno(errno, "Caught <%s>, cannot fork for core dump: %m", signal_to_string(sig));
-                else if (pid == 0) {
-                        /* Enable default signal handler for core dump */
-
-                        sa = (struct sigaction) {
-                                .sa_handler = SIG_DFL,
-                        };
-                        (void) sigaction(sig, &sa, NULL);
-
-                        /* Don't limit the coredump size */
-                        (void) setrlimit(RLIMIT_CORE, &RLIMIT_MAKE_CONST(RLIM_INFINITY));
-
-                        /* Just to be sure... */
-                        (void) chdir("/");
-
-                        /* Raise the signal again */
-                        pid = raw_getpid();
-                        (void) kill(pid, sig); /* raise() would kill the parent */
-
-                        assert_not_reached();
-                        _exit(EXIT_EXCEPTION);
-                } else {
-                        siginfo_t status;
-                        int r;
-
-                        if (siginfo) {
-                                if (siginfo->si_pid == 0)
-                                        log_emergency("Caught <%s> from unknown sender process.", signal_to_string(sig));
-                                else if (siginfo->si_pid == 1)
-                                        log_emergency("Caught <%s> from our own process.", signal_to_string(sig));
-                                else
-                                        log_emergency("Caught <%s> from PID "PID_FMT".", signal_to_string(sig), siginfo->si_pid);
-                        }
-
-                        /* Order things nicely. */
-                        r = wait_for_terminate(pid, &status);
-                        if (r < 0)
-                                log_emergency_errno(r, "Caught <%s>, waitpid() failed: %m", signal_to_string(sig));
-                        else if (status.si_code != CLD_DUMPED) {
-                                const char *s = status.si_code == CLD_EXITED
-                                        ? exit_status_to_string(status.si_status, EXIT_STATUS_LIBC)
-                                        : signal_to_string(status.si_status);
-
-                                log_emergency("Caught <%s>, core dump failed (child "PID_FMT", code=%s, status=%i/%s).",
-                                              signal_to_string(sig),
-                                              pid,
-                                              sigchld_code_to_string(status.si_code),
-                                              status.si_status, strna(s));
-                        } else
-                                log_emergency("Caught <%s>, dumped core as pid "PID_FMT".",
-                                              signal_to_string(sig), pid);
-                }
-        }
-
-        if (arg_crash_chvt >= 0)
-                (void) chvt(arg_crash_chvt);
-
-        sa = (struct sigaction) {
-                .sa_handler = SIG_IGN,
-                .sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART,
-        };
-
-        /* Let the kernel reap children for us */
-        (void) sigaction(SIGCHLD, &sa, NULL);
-
-        if (arg_crash_shell) {
-                log_notice("Executing crash shell in 10s...");
-                (void) sleep(10);
-
-                pid = raw_clone(SIGCHLD);
-                if (pid < 0)
-                        log_emergency_errno(errno, "Failed to fork off crash shell: %m");
-                else if (pid == 0) {
-                        (void) setsid();
-                        (void) make_console_stdio();
-                        (void) rlimit_nofile_safe();
-                        (void) execle("/bin/sh", "/bin/sh", NULL, environ);
-
-                        log_emergency_errno(errno, "execle() failed: %m");
-                        _exit(EXIT_EXCEPTION);
-                } else {
-                        log_info("Spawned crash shell as PID "PID_FMT".", pid);
-                        (void) wait_for_terminate(pid, NULL);
-                }
-        }
-
-        freeze_or_exit_or_reboot();
-}
-
-static void install_crash_handler(void) {
-        static const struct sigaction sa = {
-                .sa_sigaction = crash,
-                .sa_flags = SA_NODEFER | SA_SIGINFO, /* So that we can raise the signal again from the signal handler */
-        };
-        int r;
-
-        /* We ignore the return value here, since, we don't mind if we cannot set up a crash handler */
-        r = sigaction_many(&sa, SIGNALS_CRASH_HANDLER);
-        if (r < 0)
-                log_debug_errno(r, "I had trouble setting up the crash handler, ignoring: %m");
-}
-
 static int console_setup(void) {
         _cleanup_close_ int tty_fd = -1;
         int r;
diff --git a/src/core/main.h b/src/core/main.h
new file mode 100644 (file)
index 0000000..b12a1cc
--- /dev/null
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <stdbool.h>
+
+extern bool arg_dump_core;
+extern int arg_crash_chvt;
+extern bool arg_crash_shell;
+extern bool arg_crash_reboot;
index 94cb3132e8bb281f71b52500348919700e1aceee..f5e04b37ca2b90403eff8d43d36a57fb32102f0b 100644 (file)
@@ -197,7 +197,12 @@ libcore = shared_library(
 
 core_includes = [includes, include_directories('.')]
 
-systemd_sources = files('main.c')
+systemd_sources = files(
+        'main.c',
+        'main.h',
+        'crash-handler.c',
+        'crash-handler.h',
+)
 
 in_files = [['system.conf',                     pkgsysconfdir],
             ['user.conf',                       pkgsysconfdir],