diff options
Diffstat (limited to 'src/core/main.c')
-rw-r--r-- | src/core/main.c | 519 |
1 files changed, 267 insertions, 252 deletions
diff --git a/src/core/main.c b/src/core/main.c index c9657505c3..87b3af92bc 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -19,63 +19,64 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <errno.h> -#include <string.h> -#include <unistd.h> -#include <sys/stat.h> +#include <fcntl.h> #include <getopt.h> #include <signal.h> -#include <fcntl.h> -#include <sys/prctl.h> +#include <stdio.h> +#include <string.h> #include <sys/mount.h> - -#ifdef HAVE_VALGRIND_VALGRIND_H -#include <valgrind/valgrind.h> -#endif +#include <sys/prctl.h> +#include <sys/reboot.h> +#include <sys/stat.h> +#include <unistd.h> #ifdef HAVE_SECCOMP #include <seccomp.h> #endif +#ifdef HAVE_VALGRIND_VALGRIND_H +#include <valgrind/valgrind.h> +#endif #include "sd-daemon.h" #include "sd-bus.h" -#include "log.h" -#include "fdset.h" -#include "special.h" -#include "conf-parser.h" -#include "missing.h" -#include "pager.h" -#include "build.h" -#include "strv.h" -#include "def.h" -#include "virt.h" + #include "architecture.h" -#include "watchdog.h" -#include "switch-root.h" +#include "build.h" +#include "bus-error.h" +#include "bus-util.h" #include "capability.h" -#include "killall.h" -#include "env-util.h" #include "clock-util.h" +#include "conf-parser.h" +#include "cpu-set-util.h" +#include "dbus-manager.h" +#include "def.h" +#include "env-util.h" +#include "fdset.h" #include "fileio.h" -#include "bus-error.h" -#include "bus-util.h" -#include "selinux-util.h" #include "formats-util.h" -#include "process-util.h" -#include "terminal-util.h" -#include "signal-util.h" -#include "manager.h" -#include "dbus-manager.h" +#include "hostname-setup.h" +#include "ima-setup.h" +#include "killall.h" +#include "kmod-setup.h" #include "load-fragment.h" - -#include "mount-setup.h" +#include "log.h" #include "loopback-setup.h" -#include "hostname-setup.h" #include "machine-id-setup.h" +#include "manager.h" +#include "missing.h" +#include "mount-setup.h" +#include "pager.h" +#include "process-util.h" #include "selinux-setup.h" -#include "ima-setup.h" +#include "selinux-util.h" +#include "signal-util.h" #include "smack-setup.h" -#include "kmod-setup.h" +#include "special.h" +#include "strv.h" +#include "switch-root.h" +#include "terminal-util.h" +#include "virt.h" +#include "watchdog.h" static enum { ACTION_RUN, @@ -88,8 +89,9 @@ static enum { static char *arg_default_unit = NULL; static ManagerRunningAs arg_running_as = _MANAGER_RUNNING_AS_INVALID; static bool arg_dump_core = true; -static bool arg_crash_shell = false; static int arg_crash_chvt = -1; +static bool arg_crash_shell = false; +static bool arg_crash_reboot = false; static bool arg_confirm_spawn = false; static ShowStatus arg_show_status = _SHOW_STATUS_UNSET; static bool arg_switched_root = false; @@ -114,8 +116,7 @@ static FILE* arg_serialization = NULL; static bool arg_default_cpu_accounting = false; static bool arg_default_blockio_accounting = false; static bool arg_default_memory_accounting = false; - -static void nop_handler(int sig) {} +static bool arg_default_tasks_accounting = false; static void pager_open_if_enabled(void) { @@ -125,49 +126,66 @@ static void pager_open_if_enabled(void) { pager_open(false); } +noreturn static void freeze_or_reboot(void) { + + 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."); + freeze(); +} + noreturn static void crash(int sig) { + struct sigaction sa; + pid_t pid; if (getpid() != 1) /* Pass this on immediately, if this is not PID 1 */ - raise(sig); + (void) raise(sig); else if (!arg_dump_core) log_emergency("Caught <%s>, not dumping core.", signal_to_string(sig)); else { - struct sigaction sa = { - .sa_handler = nop_handler, + sa = (struct sigaction) { + .sa_handler = nop_signal_handler, .sa_flags = SA_NOCLDSTOP|SA_RESTART, }; - pid_t pid; /* We want to wait for the core process, hence let's enable SIGCHLD */ - sigaction(SIGCHLD, &sa, NULL); + (void) sigaction(SIGCHLD, &sa, NULL); pid = raw_clone(SIGCHLD, NULL); if (pid < 0) log_emergency_errno(errno, "Caught <%s>, cannot fork for core dump: %m", signal_to_string(sig)); - else if (pid == 0) { - struct rlimit rl = {}; + struct rlimit rl = { + .rlim_cur = RLIM_INFINITY, + .rlim_max = RLIM_INFINITY, + }; /* Enable default signal handler for core dump */ - zero(sa); - sa.sa_handler = SIG_DFL; - sigaction(sig, &sa, NULL); + sa = (struct sigaction) { + .sa_handler = SIG_DFL, + }; + (void) sigaction(sig, &sa, NULL); /* Don't limit the core dump size */ - rl.rlim_cur = RLIM_INFINITY; - rl.rlim_max = RLIM_INFINITY; - setrlimit(RLIMIT_CORE, &rl); + (void) setrlimit(RLIMIT_CORE, &rl); /* Just to be sure... */ (void) chdir("/"); /* Raise the signal again */ pid = raw_getpid(); - kill(pid, sig); /* raise() would kill the parent */ + (void) kill(pid, sig); /* raise() would kill the parent */ assert_not_reached("We shouldn't be here..."); - _exit(1); + _exit(EXIT_FAILURE); } else { siginfo_t status; int r; @@ -189,37 +207,38 @@ noreturn static void crash(int sig) { } } - if (arg_crash_chvt) - chvt(arg_crash_chvt); + if (arg_crash_chvt >= 0) + (void) chvt(arg_crash_chvt); - if (arg_crash_shell) { - struct sigaction sa = { - .sa_handler = SIG_IGN, - .sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART, - }; - pid_t pid; + sa = (struct sigaction) { + .sa_handler = SIG_IGN, + .sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART, + }; - log_info("Executing crash shell in 10s..."); - sleep(10); + /* Let the kernel reap children for us */ + (void) sigaction(SIGCHLD, &sa, NULL); - /* Let the kernel reap children for us */ - assert_se(sigaction(SIGCHLD, &sa, NULL) == 0); + if (arg_crash_shell) { + log_notice("Executing crash shell in 10s..."); + (void) sleep(10); pid = raw_clone(SIGCHLD, NULL); if (pid < 0) log_emergency_errno(errno, "Failed to fork off crash shell: %m"); else if (pid == 0) { - make_console_stdio(); - execle("/bin/sh", "/bin/sh", NULL, environ); + (void) setsid(); + (void) make_console_stdio(); + (void) execle("/bin/sh", "/bin/sh", NULL, environ); log_emergency_errno(errno, "execle() failed: %m"); - _exit(1); - } else - log_info("Successfully spawned crash shell as PID "PID_FMT".", pid); + _exit(EXIT_FAILURE); + } else { + log_info("Spawned crash shell as PID "PID_FMT".", pid); + (void) wait_for_terminate(pid, NULL); + } } - log_emergency("Freezing execution."); - freeze(); + freeze_or_reboot(); } static void install_crash_handler(void) { @@ -253,17 +272,20 @@ static int console_setup(void) { return 0; } -static int set_default_unit(const char *u) { - char *c; +static int parse_crash_chvt(const char *value) { + int b; - assert(u); + if (safe_atoi(value, &arg_crash_chvt) >= 0) + return 0; - c = strdup(u); - if (!c) - return -ENOMEM; + b = parse_boolean(value); + if (b < 0) + return b; - free(arg_default_unit); - arg_default_unit = c; + if (b > 0) + arg_crash_chvt = 0; /* switch to where kmsg goes */ + else + arg_crash_chvt = -1; /* turn off switching */ return 0; } @@ -291,12 +313,12 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { if (streq(key, "systemd.unit") && value) { if (!in_initrd()) - return set_default_unit(value); + return free_and_strdup(&arg_default_unit, value); } else if (streq(key, "rd.systemd.unit") && value) { if (in_initrd()) - return set_default_unit(value); + return free_and_strdup(&arg_default_unit, value); } else if (streq(key, "systemd.dump_core") && value) { @@ -306,6 +328,11 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { else arg_dump_core = r; + } else if (streq(key, "systemd.crash_chvt") && value) { + + if (parse_crash_chvt(value) < 0) + log_warning("Failed to parse crash chvt switch %s. Ignoring.", value); + } else if (streq(key, "systemd.crash_shell") && value) { r = parse_boolean(value); @@ -314,12 +341,13 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { else arg_crash_shell = r; - } else if (streq(key, "systemd.crash_chvt") && value) { + } else if (streq(key, "systemd.crash_reboot") && value) { - if (safe_atoi(value, &r) < 0) - log_warning("Failed to parse crash chvt switch %s. Ignoring.", value); + r = parse_boolean(value); + if (r < 0) + log_warning("Failed to parse crash reboot switch %s. Ignoring.", value); else - arg_crash_chvt = r; + arg_crash_reboot = r; } else if (streq(key, "systemd.confirm_spawn") && value) { @@ -383,7 +411,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { /* SysV compatibility */ for (i = 0; i < ELEMENTSOF(rlmap); i += 2) if (streq(key, rlmap[i])) - return set_default_unit(rlmap[i+1]); + return free_and_strdup(&arg_default_unit, rlmap[i+1]); } return 0; @@ -409,9 +437,9 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { \ r = func(rvalue); \ if (r < 0) \ - log_syntax(unit, LOG_ERR, filename, line, -r, \ - "Invalid " descr "'%s': %s", \ - rvalue, strerror(-r)); \ + log_syntax(unit, LOG_ERR, filename, line, r, \ + "Invalid " descr "'%s': %m", \ + rvalue); \ \ return 0; \ } @@ -433,48 +461,15 @@ static int config_parse_cpu_affinity2( void *data, void *userdata) { - const char *whole_rvalue = rvalue; _cleanup_cpu_free_ cpu_set_t *c = NULL; - unsigned ncpus = 0; + int ncpus; - assert(filename); - assert(lvalue); - assert(rvalue); + ncpus = parse_cpu_set_and_warn(rvalue, &c, unit, filename, line, lvalue); + if (ncpus < 0) + return ncpus; - for (;;) { - _cleanup_free_ char *word = NULL; - unsigned cpu; - int r; - - r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Invalid value for %s: %s", lvalue, whole_rvalue); - return r; - } - if (r == 0) - break; - - r = safe_atou(word, &cpu); - - if (!c) - if (!(c = cpu_set_malloc(&ncpus))) - return log_oom(); - - if (r < 0 || cpu >= ncpus) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to parse CPU affinity '%s'", rvalue); - return -EBADMSG; - } - - CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c); - } - if (!isempty(rvalue)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Trailing garbage, ignoring."); - - if (c) - if (sched_setaffinity(0, CPU_ALLOC_SIZE(ncpus), c) < 0) - log_warning("Failed to set CPU affinity: %m"); + if (sched_setaffinity(0, CPU_ALLOC_SIZE(ncpus), c) < 0) + log_warning("Failed to set CPU affinity: %m"); return 0; } @@ -501,29 +496,38 @@ static int config_parse_show_status( k = parse_show_status(rvalue, b); if (k < 0) { - log_syntax(unit, LOG_ERR, filename, line, -k, - "Failed to parse show status setting, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse show status setting, ignoring: %s", rvalue); return 0; } return 0; } -static void strv_free_free(char ***l) { - char ***i; +static int config_parse_crash_chvt( + const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { - if (!l) - return; + int r; - for (i = l; *i; i++) - strv_free(*i); + assert(filename); + assert(lvalue); + assert(rvalue); - free(l); -} + r = parse_crash_chvt(rvalue); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CrashChangeVT= setting, ignoring: %s", rvalue); + return 0; + } -static void free_join_controllers(void) { - strv_free_free(arg_join_controllers); - arg_join_controllers = NULL; + return 0; } static int config_parse_join_controllers(const char *unit, @@ -544,7 +548,7 @@ static int config_parse_join_controllers(const char *unit, assert(lvalue); assert(rvalue); - free_join_controllers(); + arg_join_controllers = strv_free_free(arg_join_controllers); for (;;) { _cleanup_free_ char *word = NULL; @@ -561,7 +565,7 @@ static int config_parse_join_controllers(const char *unit, l = strv_split(word, ","); if (!l) - log_oom(); + return log_oom(); strv_uniq(l); if (strv_length(l) <= 1) { @@ -595,7 +599,7 @@ static int config_parse_join_controllers(const char *unit, for (a = arg_join_controllers; *a; a++) { if (strv_overlap(*a, l)) { - if (strv_extend_strv(&l, *a) < 0) { + if (strv_extend_strv(&l, *a, false) < 0) { strv_free(l); strv_free_free(t); return log_oom(); @@ -622,8 +626,7 @@ static int config_parse_join_controllers(const char *unit, } } if (!isempty(rvalue)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Trailing garbage, ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); return 0; } @@ -636,9 +639,11 @@ static int parse_config_file(void) { { "Manager", "LogColor", config_parse_color, 0, NULL }, { "Manager", "LogLocation", config_parse_location, 0, NULL }, { "Manager", "DumpCore", config_parse_bool, 0, &arg_dump_core }, + { "Manager", "CrashChVT", /* legacy */ config_parse_crash_chvt, 0, NULL }, + { "Manager", "CrashChangeVT", config_parse_crash_chvt, 0, NULL }, { "Manager", "CrashShell", config_parse_bool, 0, &arg_crash_shell }, + { "Manager", "CrashReboot", config_parse_bool, 0, &arg_crash_reboot }, { "Manager", "ShowStatus", config_parse_show_status, 0, &arg_show_status }, - { "Manager", "CrashChVT", config_parse_int, 0, &arg_crash_chvt }, { "Manager", "CPUAffinity", config_parse_cpu_affinity2, 0, NULL }, { "Manager", "JoinControllers", config_parse_join_controllers, 0, &arg_join_controllers }, { "Manager", "RuntimeWatchdogSec", config_parse_sec, 0, &arg_runtime_watchdog }, @@ -676,6 +681,7 @@ static int parse_config_file(void) { { "Manager", "DefaultCPUAccounting", config_parse_bool, 0, &arg_default_cpu_accounting }, { "Manager", "DefaultBlockIOAccounting", config_parse_bool, 0, &arg_default_blockio_accounting }, { "Manager", "DefaultMemoryAccounting", config_parse_bool, 0, &arg_default_memory_accounting }, + { "Manager", "DefaultTasksAccounting", config_parse_bool, 0, &arg_default_tasks_accounting }, {} }; @@ -704,6 +710,7 @@ static void manager_set_defaults(Manager *m) { m->default_cpu_accounting = arg_default_cpu_accounting; m->default_blockio_accounting = arg_default_blockio_accounting; m->default_memory_accounting = arg_default_memory_accounting; + m->default_tasks_accounting = arg_default_tasks_accounting; manager_set_default_rlimits(m, arg_default_rlimit); manager_environment_add(m, NULL, arg_default_environment); @@ -724,7 +731,9 @@ static int parse_argv(int argc, char *argv[]) { ARG_VERSION, ARG_DUMP_CONFIGURATION_ITEMS, ARG_DUMP_CORE, + ARG_CRASH_CHVT, ARG_CRASH_SHELL, + ARG_CRASH_REBOOT, ARG_CONFIRM_SPAWN, ARG_SHOW_STATUS, ARG_DESERIALIZE, @@ -747,7 +756,9 @@ static int parse_argv(int argc, char *argv[]) { { "version", no_argument, NULL, ARG_VERSION }, { "dump-configuration-items", no_argument, NULL, ARG_DUMP_CONFIGURATION_ITEMS }, { "dump-core", optional_argument, NULL, ARG_DUMP_CORE }, + { "crash-chvt", required_argument, NULL, ARG_CRASH_CHVT }, { "crash-shell", optional_argument, NULL, ARG_CRASH_SHELL }, + { "crash-reboot", optional_argument, NULL, ARG_CRASH_REBOOT }, { "confirm-spawn", optional_argument, NULL, ARG_CONFIRM_SPAWN }, { "show-status", optional_argument, NULL, ARG_SHOW_STATUS }, { "deserialize", required_argument, NULL, ARG_DESERIALIZE }, @@ -832,7 +843,7 @@ static int parse_argv(int argc, char *argv[]) { case ARG_UNIT: - r = set_default_unit(optarg); + r = free_and_strdup(&arg_default_unit, optarg); if (r < 0) return log_error_errno(r, "Failed to set default unit %s: %m", optarg); @@ -865,21 +876,42 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_DUMP_CORE: - r = optarg ? parse_boolean(optarg) : 1; - if (r < 0) { - log_error("Failed to parse dump core boolean %s.", optarg); - return r; + if (!optarg) + arg_dump_core = true; + else { + r = parse_boolean(optarg); + if (r < 0) + return log_error_errno(r, "Failed to parse dump core boolean: %s", optarg); + arg_dump_core = r; } - arg_dump_core = r; + break; + + case ARG_CRASH_CHVT: + r = parse_crash_chvt(optarg); + if (r < 0) + return log_error_errno(r, "Failed to parse crash virtual terminal index: %s", optarg); break; case ARG_CRASH_SHELL: - r = optarg ? parse_boolean(optarg) : 1; - if (r < 0) { - log_error("Failed to parse crash shell boolean %s.", optarg); - return r; + if (!optarg) + arg_crash_shell = true; + else { + r = parse_boolean(optarg); + if (r < 0) + return log_error_errno(r, "Failed to parse crash shell boolean: %s", optarg); + arg_crash_shell = r; + } + break; + + case ARG_CRASH_REBOOT: + if (!optarg) + arg_crash_reboot = true; + else { + r = parse_boolean(optarg); + if (r < 0) + return log_error_errno(r, "Failed to parse crash shell boolean: %s", optarg); + arg_crash_reboot = r; } - arg_crash_shell = r; break; case ARG_CONFIRM_SPAWN: @@ -909,17 +941,16 @@ static int parse_argv(int argc, char *argv[]) { r = safe_atoi(optarg, &fd); if (r < 0 || fd < 0) { log_error("Failed to parse deserialize option %s.", optarg); - return r < 0 ? r : -EINVAL; + return -EINVAL; } - fd_cloexec(fd, true); + (void) fd_cloexec(fd, true); f = fdopen(fd, "r"); if (!f) return log_error_errno(errno, "Failed to open serialization fd: %m"); safe_fclose(arg_serialization); - arg_serialization = f; break; @@ -979,14 +1010,16 @@ static int help(void) { " --unit=UNIT Set default unit\n" " --system Run a system instance, even if PID != 1\n" " --user Run a user instance\n" - " --dump-core[=0|1] Dump core on crash\n" - " --crash-shell[=0|1] Run shell on crash\n" - " --confirm-spawn[=0|1] Ask for confirmation when spawning processes\n" - " --show-status[=0|1] Show status updates on the console during bootup\n" + " --dump-core[=BOOL] Dump core on crash\n" + " --crash-vt=NR Change to specified VT on crash\n" + " --crash-reboot[=BOOL] Reboot on crash\n" + " --crash-shell[=BOOL] Run shell on crash\n" + " --confirm-spawn[=BOOL] Ask for confirmation when spawning processes\n" + " --show-status[=BOOL] Show status updates on the console during bootup\n" " --log-target=TARGET Set log target (console, journal, kmsg, journal-or-kmsg, null)\n" " --log-level=LEVEL Set log level (debug, info, notice, warning, err, crit, alert, emerg)\n" - " --log-color[=0|1] Highlight important log messages\n" - " --log-location[=0|1] Include code location in log messages\n" + " --log-color[=BOOL] Highlight important log messages\n" + " --log-location[=BOOL] Include code location in log messages\n" " --default-standard-output= Set default standard output for services\n" " --default-standard-error= Set default standard error output for services\n", program_invocation_short_name); @@ -994,16 +1027,9 @@ static int help(void) { return 0; } -static int version(void) { - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - - return 0; -} - static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds, bool switching_root) { - FILE *f = NULL; - FDSet *fds = NULL; + _cleanup_fdset_free_ FDSet *fds = NULL; + _cleanup_fclose_ FILE *f = NULL; int r; assert(m); @@ -1011,56 +1037,39 @@ static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds, bool switching assert(_fds); r = manager_open_serialization(m, &f); - if (r < 0) { - log_error_errno(r, "Failed to create serialization file: %m"); - goto fail; - } + if (r < 0) + return log_error_errno(r, "Failed to create serialization file: %m"); /* Make sure nothing is really destructed when we shut down */ m->n_reloading ++; bus_manager_send_reloading(m, true); fds = fdset_new(); - if (!fds) { - r = -ENOMEM; - log_error_errno(r, "Failed to allocate fd set: %m"); - goto fail; - } + if (!fds) + return log_oom(); r = manager_serialize(m, f, fds, switching_root); - if (r < 0) { - log_error_errno(r, "Failed to serialize state: %m"); - goto fail; - } + if (r < 0) + return log_error_errno(r, "Failed to serialize state: %m"); - if (fseeko(f, 0, SEEK_SET) < 0) { - log_error_errno(errno, "Failed to rewind serialization fd: %m"); - goto fail; - } + if (fseeko(f, 0, SEEK_SET) == (off_t) -1) + return log_error_errno(errno, "Failed to rewind serialization fd: %m"); r = fd_cloexec(fileno(f), false); - if (r < 0) { - log_error_errno(r, "Failed to disable O_CLOEXEC for serialization: %m"); - goto fail; - } + if (r < 0) + return log_error_errno(r, "Failed to disable O_CLOEXEC for serialization: %m"); r = fdset_cloexec(fds, false); - if (r < 0) { - log_error_errno(r, "Failed to disable O_CLOEXEC for serialization fds: %m"); - goto fail; - } + if (r < 0) + return log_error_errno(r, "Failed to disable O_CLOEXEC for serialization fds: %m"); *_f = f; *_fds = fds; - return 0; - -fail: - fdset_free(fds); - - safe_fclose(f); + f = NULL; + fds = NULL; - return r; + return 0; } static int bump_rlimit_nofile(struct rlimit *saved_rlimit) { @@ -1118,8 +1127,8 @@ static void test_mtab(void) { log_error("/etc/mtab is not a symlink or not pointing to /proc/self/mounts. " "This is not supported anymore. " - "Please make sure to replace this file by a symlink to avoid incorrect or misleading mount(8) output."); - freeze(); + "Please replace /etc/mtab with a symlink to /proc/self/mounts."); + freeze_or_reboot(); } static void test_usr(void) { @@ -1145,15 +1154,19 @@ static int initialize_join_controllers(void) { return -ENOMEM; arg_join_controllers[0] = strv_new("cpu", "cpuacct", NULL); - arg_join_controllers[1] = strv_new("net_cls", "net_prio", NULL); - arg_join_controllers[2] = NULL; + if (!arg_join_controllers[0]) + goto oom; - if (!arg_join_controllers[0] || !arg_join_controllers[1]) { - free_join_controllers(); - return -ENOMEM; - } + arg_join_controllers[1] = strv_new("net_cls", "net_prio", NULL); + if (!arg_join_controllers[1]) + goto oom; + arg_join_controllers[2] = NULL; return 0; + +oom: + arg_join_controllers = strv_free_free(arg_join_controllers); + return -ENOMEM; } static int enforce_syscall_archs(Set *archs) { @@ -1397,7 +1410,7 @@ int main(int argc, char *argv[]) { } /* Initialize default unit */ - r = set_default_unit(SPECIAL_DEFAULT_TARGET); + r = free_and_strdup(&arg_default_unit, SPECIAL_DEFAULT_TARGET); if (r < 0) { log_emergency_errno(r, "Failed to set default unit %s: %m", SPECIAL_DEFAULT_TARGET); error_message = "Failed to set default unit"; @@ -1674,8 +1687,7 @@ int main(int argc, char *argv[]) { /* This will close all file descriptors that were opened, but * not claimed by any unit. */ - fdset_free(fds); - fds = NULL; + fds = fdset_free(fds); arg_serialization = safe_fclose(arg_serialization); @@ -1761,11 +1773,6 @@ int main(int argc, char *argv[]) { switch (m->exit_code) { - case MANAGER_EXIT: - retval = EXIT_SUCCESS; - log_debug("Exit."); - goto finish; - case MANAGER_RELOAD: log_info("Reloading."); @@ -1807,11 +1814,21 @@ int main(int argc, char *argv[]) { log_notice("Switching root."); goto finish; + case MANAGER_EXIT: + retval = m->return_value; + + if (m->running_as == MANAGER_USER) { + log_debug("Exit."); + goto finish; + } + + /* fallthrough */ case MANAGER_REBOOT: case MANAGER_POWEROFF: case MANAGER_HALT: case MANAGER_KEXEC: { static const char * const table[_MANAGER_EXIT_CODE_MAX] = { + [MANAGER_EXIT] = "exit", [MANAGER_REBOOT] = "reboot", [MANAGER_POWEROFF] = "poweroff", [MANAGER_HALT] = "halt", @@ -1835,17 +1852,15 @@ finish: if (m) arg_shutdown_watchdog = m->shutdown_watchdog; + m = manager_free(m); for (j = 0; j < ELEMENTSOF(arg_default_rlimit); j++) arg_default_rlimit[j] = mfree(arg_default_rlimit[j]); arg_default_unit = mfree(arg_default_unit); - - free_join_controllers(); - + arg_join_controllers = strv_free_free(arg_join_controllers); arg_default_environment = strv_free(arg_default_environment); - arg_syscall_archs = set_free(arg_syscall_archs); mac_selinux_finish(); @@ -1863,7 +1878,7 @@ finish: * that the new systemd can pass the kernel default to * its child processes */ if (saved_rlimit_nofile.rlim_cur > 0) - setrlimit(RLIMIT_NOFILE, &saved_rlimit_nofile); + (void) setrlimit(RLIMIT_NOFILE, &saved_rlimit_nofile); if (switch_root_dir) { /* Kill all remaining processes from the @@ -1905,10 +1920,10 @@ finish: /* do not pass along the environment we inherit from the kernel or initrd */ if (switch_root_dir) - clearenv(); + (void) clearenv(); assert(i <= args_size); - execv(args[0], (char* const*) args); + (void) execv(args[0], (char* const*) args); } /* Try the fallback, if there is any, without any @@ -1918,14 +1933,10 @@ finish: * but let's hope that doesn't matter.) */ arg_serialization = safe_fclose(arg_serialization); - - if (fds) { - fdset_free(fds); - fds = NULL; - } + fds = fdset_free(fds); /* Reopen the console */ - make_console_stdio(); + (void) make_console_stdio(); for (j = 1, i = 1; j < (unsigned) argc; j++) args[i++] = argv[j]; @@ -1939,30 +1950,26 @@ finish: if (switch_root_init) { args[0] = switch_root_init; - execv(args[0], (char* const*) args); + (void) execv(args[0], (char* const*) args); log_warning_errno(errno, "Failed to execute configured init, trying fallback: %m"); } args[0] = "/sbin/init"; - execv(args[0], (char* const*) args); + (void) execv(args[0], (char* const*) args); if (errno == ENOENT) { log_warning("No /sbin/init, trying fallback"); args[0] = "/bin/sh"; args[1] = NULL; - execv(args[0], (char* const*) args); + (void) execv(args[0], (char* const*) args); log_error_errno(errno, "Failed to execute /bin/sh, giving up: %m"); } else log_warning_errno(errno, "Failed to execute /sbin/init, giving up: %m"); } arg_serialization = safe_fclose(arg_serialization); - - if (fds) { - fdset_free(fds); - fds = NULL; - } + fds = fdset_free(fds); #ifdef HAVE_VALGRIND_VALGRIND_H /* If we are PID 1 and running under valgrind, then let's exit @@ -1975,7 +1982,8 @@ finish: if (shutdown_verb) { char log_level[DECIMAL_STR_MAX(int) + 1]; - const char* command_line[9] = { + char exit_code[DECIMAL_STR_MAX(uint8_t) + 1]; + const char* command_line[11] = { SYSTEMD_SHUTDOWN_BINARY_PATH, shutdown_verb, "--log-level", log_level, @@ -1990,6 +1998,7 @@ finish: xsprintf(log_level, "%d", log_get_max_level()); switch (log_get_target()) { + case LOG_TARGET_KMSG: case LOG_TARGET_JOURNAL_OR_KMSG: case LOG_TARGET_SYSLOG_OR_KMSG: @@ -2012,6 +2021,12 @@ finish: if (log_get_show_location()) command_line[pos++] = "--log-location"; + if (streq(shutdown_verb, "exit")) { + command_line[pos++] = "--exit-code"; + command_line[pos++] = exit_code; + xsprintf(exit_code, "%d", retval); + } + assert(pos < ELEMENTSOF(command_line)); if (arm_reboot_watchdog && arg_shutdown_watchdog > 0) { @@ -2025,7 +2040,7 @@ finish: /* Tell the binary how often to ping, ignore failure */ if (asprintf(&e, "WATCHDOG_USEC="USEC_FMT, arg_shutdown_watchdog) > 0) - strv_push(&env_block, e); + (void) strv_push(&env_block, e); } else watchdog_close(true); @@ -2043,9 +2058,9 @@ finish: if (getpid() == 1) { if (error_message) manager_status_printf(NULL, STATUS_TYPE_EMERGENCY, - ANSI_HIGHLIGHT_RED_ON "!!!!!!" ANSI_HIGHLIGHT_OFF, + ANSI_HIGHLIGHT_RED "!!!!!!" ANSI_NORMAL, "%s, freezing.", error_message); - freeze(); + freeze_or_reboot(); } return retval; |