diff --git a/NEWS b/NEWS
index 42027a4c8f..566ee2a9d5 100644
--- a/NEWS
+++ b/NEWS
@@ -66,6 +66,9 @@ CHANGES WITH 256-rc1:
'D' stanzas. For example, with the combination of 'R /foo' and 'x
/foo/bar', /foo/bar will now be excluded from removal.
+ * systemd.crash_reboot and related settings are deprecated in favor of
+ systemd.crash_action=.
+
General Changes and New Features:
* Various programs will now attempt to load the main configuration file
@@ -251,6 +254,10 @@ CHANGES WITH 256-rc1:
that have /usr/bin/ and /usr/sbin/ separate. It's generally
recommended to make the latter a symlink to the former these days.
+ * A new systemd.crash_action= kernel command line option has been added
+ that configures what to do after the system manager (PID 1) crashes.
+ This can also be configured through CrashAction= in systemd.conf.
+
Journal:
* systemd-journald can now forward journal entries to a socket
diff --git a/man/kernel-command-line.xml b/man/kernel-command-line.xml
index 28250a2720..3dd5449bd0 100644
--- a/man/kernel-command-line.xml
+++ b/man/kernel-command-line.xml
@@ -54,7 +54,7 @@
systemd.dump_core
systemd.crash_chvt
systemd.crash_shell
- systemd.crash_reboot
+ systemd.crash_action=
systemd.confirm_spawn
systemd.service_watchdogs
systemd.show_status
diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml
index 88f13d05b6..ae5b61b149 100644
--- a/man/systemd-system.conf.xml
+++ b/man/systemd-system.conf.xml
@@ -78,7 +78,7 @@
DumpCore=yes
CrashChangeVT=no
CrashShell=no
- CrashReboot=no
+ CrashAction=freeze
ShowStatus=yes
DefaultStandardOutput=journal
DefaultStandardError=inherit
diff --git a/man/systemd.xml b/man/systemd.xml
index df0027886c..66db5bbf25 100644
--- a/man/systemd.xml
+++ b/man/systemd.xml
@@ -853,16 +853,18 @@
- systemd.crash_reboot
+ systemd.crash_action=
- Takes a boolean argument or enables the option if specified
- without an argument. If enabled, the system manager (PID 1) will reboot the
- machine automatically when it crashes, after a 10s delay. Otherwise, the
- system will hang indefinitely. Defaults to disabled, in order to avoid a
- reboot loop. If combined with systemd.crash_shell, the
- system is rebooted after the shell exits.
+ Takes one of freeze, reboot or
+ poweroff. Defaults to freeze. If set to
+ freeze, the system will hang indefinitely when the system manager (PID 1) crashes.
+ If set to reboot, the system manager (PID 1) will reboot the machine automatically
+ when it crashes, after a 10s delay. If set to poweroff, the system manager (PID 1)
+ will power off the machine immediately when it crashes. If combined with
+ systemd.crash_shell, the configured crash action is executed after the shell
+ exits.
-
+
@@ -1390,12 +1392,13 @@
-
+
- Automatically reboot the system on crash. This switch has no effect when running as
- user instance. See systemd.crash_reboot above.
+ Specify what to do when the system manager (PID 1) crashes. This switch has no
+ effect when systemd is running as user instance. See systemd.crash_action=
+ above.
-
+
diff --git a/src/basic/getopt-defs.h b/src/basic/getopt-defs.h
index 3efeb6df80..9abef6f156 100644
--- a/src/basic/getopt-defs.h
+++ b/src/basic/getopt-defs.h
@@ -26,6 +26,7 @@
ARG_CRASH_CHVT, \
ARG_CRASH_SHELL, \
ARG_CRASH_REBOOT, \
+ ARG_CRASH_ACTION, \
ARG_CONFIRM_SPAWN, \
ARG_SHOW_STATUS, \
ARG_DESERIALIZE, \
@@ -61,6 +62,7 @@
{ "crash-chvt", required_argument, NULL, ARG_CRASH_CHVT }, \
{ "crash-shell", optional_argument, NULL, ARG_CRASH_SHELL }, \
{ "crash-reboot", optional_argument, NULL, ARG_CRASH_REBOOT }, \
+ { "crash-action", required_argument, NULL, ARG_CRASH_ACTION }, \
{ "confirm-spawn", optional_argument, NULL, ARG_CONFIRM_SPAWN }, \
{ "show-status", optional_argument, NULL, ARG_SHOW_STATUS }, \
{ "deserialize", required_argument, NULL, ARG_DESERIALIZE }, \
diff --git a/src/core/crash-handler.c b/src/core/crash-handler.c
index f5c31b6b74..4a3fc017fa 100644
--- a/src/core/crash-handler.c
+++ b/src/core/crash-handler.c
@@ -27,7 +27,13 @@ _noreturn_ void freeze_or_exit_or_reboot(void) {
_exit(EXIT_EXCEPTION);
}
- if (arg_crash_reboot) {
+ if (arg_crash_action == CRASH_POWEROFF) {
+ log_notice("Shutting down...");
+ (void) reboot(RB_POWER_OFF);
+ log_struct_errno(LOG_EMERG, errno,
+ LOG_MESSAGE("Failed to power off: %m"),
+ "MESSAGE_ID=" SD_MESSAGE_CRASH_FAILED_STR);
+ } else if (arg_crash_action == CRASH_REBOOT) {
log_notice("Rebooting in 10s...");
(void) sleep(10);
diff --git a/src/core/main.c b/src/core/main.c
index 7362a6a822..f3a40f65bb 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -88,6 +88,7 @@
#include "special.h"
#include "stat-util.h"
#include "stdio-util.h"
+#include "string-table.h"
#include "strv.h"
#include "switch-root.h"
#include "sysctl-util.h"
@@ -122,7 +123,7 @@ static RuntimeScope arg_runtime_scope;
bool arg_dump_core;
int arg_crash_chvt;
bool arg_crash_shell;
-bool arg_crash_reboot;
+CrashAction arg_crash_action;
static char *arg_confirm_spawn;
static ShowStatus arg_show_status;
static StatusUnitFormat arg_status_unit_format;
@@ -161,6 +162,16 @@ static char **saved_env = NULL;
static int parse_configuration(const struct rlimit *saved_rlimit_nofile,
const struct rlimit *saved_rlimit_memlock);
+static const char* const crash_action_table[_CRASH_ACTION_MAX] = {
+ [CRASH_FREEZE] = "freeze",
+ [CRASH_REBOOT] = "reboot",
+ [CRASH_POWEROFF] = "poweroff",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(crash_action, CrashAction);
+
+static DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_crash_action, crash_action, CrashAction, CRASH_FREEZE, "Invalid crash action");
+
static int manager_find_user_config_paths(char ***ret_files, char ***ret_dirs) {
_cleanup_free_ char *base = NULL;
_cleanup_strv_free_ char **files = NULL, **dirs = NULL;
@@ -279,7 +290,18 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
if (r < 0)
log_warning_errno(r, "Failed to parse crash reboot switch %s, ignoring: %m", value);
else
- arg_crash_reboot = r;
+ arg_crash_action = r ? CRASH_REBOOT : CRASH_FREEZE;
+
+ } else if (proc_cmdline_key_streq(key, "systemd.crash_action")) {
+
+ if (proc_cmdline_value_missing(key, value))
+ return 0;
+
+ r = crash_action_from_string(value);
+ if (r < 0)
+ log_warning_errno(r, "Failed to parse crash action switch %s, ignoring: %m", value);
+ else
+ arg_crash_action = r;
} else if (proc_cmdline_key_streq(key, "systemd.confirm_spawn")) {
char *s;
@@ -653,6 +675,36 @@ static int config_parse_protect_system_pid1(
return 0;
}
+static int config_parse_crash_reboot(
+ 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) {
+
+ CrashAction *v = ASSERT_PTR(data);
+ int r;
+
+ if (isempty(rvalue)) {
+ *v = CRASH_REBOOT;
+ return 0;
+ }
+
+ r = parse_boolean(rvalue);
+ if (r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse CrashReboot= argument '%s', ignoring: %m", rvalue);
+ return 0;
+ }
+
+ *v = r > 0 ? CRASH_REBOOT : CRASH_FREEZE;
+ return 0;
+}
+
static int parse_config_file(void) {
const ConfigTableItem items[] = {
{ "Manager", "LogLevel", config_parse_level2, 0, NULL },
@@ -664,7 +716,8 @@ static int parse_config_file(void) {
{ "Manager", "CrashChVT", /* legacy */ config_parse_crash_chvt, 0, &arg_crash_chvt },
{ "Manager", "CrashChangeVT", config_parse_crash_chvt, 0, &arg_crash_chvt },
{ "Manager", "CrashShell", config_parse_bool, 0, &arg_crash_shell },
- { "Manager", "CrashReboot", config_parse_bool, 0, &arg_crash_reboot },
+ { "Manager", "CrashReboot", config_parse_crash_reboot, 0, &arg_crash_action },
+ { "Manager", "CrashAction", config_parse_crash_action, 0, &arg_crash_action },
{ "Manager", "ShowStatus", config_parse_show_status, 0, &arg_show_status },
{ "Manager", "StatusUnitFormat", config_parse_status_unit_format, 0, &arg_status_unit_format },
{ "Manager", "CPUAffinity", config_parse_cpu_affinity2, 0, &arg_cpu_affinity },
@@ -980,9 +1033,17 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_CRASH_REBOOT:
- r = parse_boolean_argument("--crash-reboot", optarg, &arg_crash_reboot);
+ r = parse_boolean_argument("--crash-reboot", optarg, NULL);
if (r < 0)
return r;
+ arg_crash_action = r > 0 ? CRASH_REBOOT : CRASH_FREEZE;
+ break;
+
+ case ARG_CRASH_ACTION:
+ r = crash_action_from_string(optarg);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse crash action \"%s\": %m", optarg);
+ arg_crash_action = r;
break;
case ARG_CONFIRM_SPAWN:
@@ -1098,7 +1159,7 @@ static int help(void) {
" --unit=UNIT Set default unit\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-action=ACTION Specify what to do 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 boot\n"
@@ -2590,7 +2651,7 @@ static void reset_arguments(void) {
arg_dump_core = true;
arg_crash_chvt = -1;
arg_crash_shell = false;
- arg_crash_reboot = false;
+ arg_crash_action = CRASH_FREEZE;
arg_confirm_spawn = mfree(arg_confirm_spawn);
arg_show_status = _SHOW_STATUS_INVALID;
arg_status_unit_format = STATUS_UNIT_FORMAT_DEFAULT;
diff --git a/src/core/main.h b/src/core/main.h
index b12a1ccfd7..1949a08588 100644
--- a/src/core/main.h
+++ b/src/core/main.h
@@ -1,9 +1,21 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
+#include
#include
+typedef enum CrashAction {
+ CRASH_FREEZE,
+ CRASH_REBOOT,
+ CRASH_POWEROFF,
+ _CRASH_ACTION_MAX,
+ _CRASH_ACTION_INVALID = -EINVAL,
+} CrashAction;
+
+const char* crash_action_to_string(CrashAction action);
+CrashAction crash_action_from_string(const char *action);
+
extern bool arg_dump_core;
extern int arg_crash_chvt;
extern bool arg_crash_shell;
-extern bool arg_crash_reboot;
+extern CrashAction arg_crash_action;
diff --git a/src/core/system.conf.in b/src/core/system.conf.in
index 9b89a6aa77..1c08aa4d22 100644
--- a/src/core/system.conf.in
+++ b/src/core/system.conf.in
@@ -26,7 +26,7 @@
#ShowStatus=yes
#CrashChangeVT=no
#CrashShell=no
-#CrashReboot=no
+#CrashAction=freeze
#CtrlAltDelBurstAction=reboot-force
#CPUAffinity=
#NUMAPolicy=default
diff --git a/test/fuzz/fuzz-unit-file/directives-all.service b/test/fuzz/fuzz-unit-file/directives-all.service
index 670e589bab..dbd56ec752 100644
--- a/test/fuzz/fuzz-unit-file/directives-all.service
+++ b/test/fuzz/fuzz-unit-file/directives-all.service
@@ -706,6 +706,7 @@ CPUAffinity=
CapabilityBoundingSet=
CrashChangeVT=
CrashReboot=
+CrashAction=
CrashShell=
CtrlAltDelBurstAction=
DefaultBlockIOAccounting=