diff --git a/man/kernel-command-line.xml b/man/kernel-command-line.xml
index eb73727027..2f81746b5e 100644
--- a/man/kernel-command-line.xml
+++ b/man/kernel-command-line.xml
@@ -79,8 +79,9 @@
systemd.unit=rd.systemd.unit=systemd.dump_core=
- systemd.crash_shell=systemd.crash_chvt=
+ systemd.crash_shell=
+ systemd.crash_reboot=systemd.confirm_spawn=systemd.show_status=systemd.log_target=
diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml
index a4ba0959ea..56db9ff17e 100644
--- a/man/systemd-system.conf.xml
+++ b/man/systemd-system.conf.xml
@@ -90,9 +90,10 @@
LogColor=LogLocation=DumpCore=yes
+ CrashChangeVT=noCrashShell=no
+ CrashReboot=noShowStatus=yes
- CrashChVT=1DefaultStandardOutput=journalDefaultStandardError=inherit
diff --git a/man/systemd.xml b/man/systemd.xml
index 479f55de76..9e927c3204 100644
--- a/man/systemd.xml
+++ b/man/systemd.xml
@@ -1,4 +1,4 @@
-
+
@@ -131,17 +131,48 @@
- Dump core on crash. This switch has no effect
- when run as user instance.
+ Enable core dumping on crash. This switch has
+ no effect when running as user instance. This setting may also
+ be enabled during boot on the kernel command line via the
+ systemd.dump_core= option, see
+ below.
+
+
+ VT
+
+ Switch to a specific virtual console (VT) on
+ crash. Takes a positive integer in the range 1..63, or a
+ boolean argument. If an integer is passed, selects which VT to
+ switch to. If yes, the VT kernel messages
+ are written to is selected. If no, no VT
+ switch is attempted. This switch has no effect when running as
+ user instance. This setting may also be enabled during boot,
+ on the kernel command line via the
+ systemd.crash_vt= option, see
+ below.
+
+
- Run shell on
- crash. This switch has no effect when
- run as user
- instance.
+ Run a shell on crash. This switch has no
+ effect when running as user instance. This setting may also be
+ enabled during boot, on the kernel command line via the
+ systemd.crash_shell= option, see
+ below.
+
+
+
+
+ Automatically reboot the system on crash. This
+ switch has no effect when running as user instance. This
+ setting may also be enabled during boot, on the kernel command
+ line via the systemd.crash_reboot= option,
+ see below.
+
+
@@ -854,50 +885,67 @@
systemd.dump_core=Takes a boolean argument. If
- , systemd dumps core when it crashes.
- Otherwise, no core dump is created. Defaults to
- .
+ , the systemd manager (PID 1) dumps core
+ when it crashes. Otherwise, no core dump is created. Defaults
+ to .
+
+
+
+ systemd.crash_chvt=
+
+ Takes a positive integer, or a boolean
+ argument. If a positive integer (in the range 1..63) is
+ specified the system manager (PID 1) will activate the specified
+ virtual terminal (VT) when it crashes. Defaults to
+ no, meaning that no such switch is
+ attempted. If set to yes the VT the
+ kernel messages are written to is selected.systemd.crash_shell=Takes a boolean argument. If
- , systemd spawns a shell when it crashes.
- Otherwise, no shell is spawned. Defaults to
- , for security reasons, as the shell is
- not protected by any password
+ , the system manager (PID 1) spawns a
+ shell when it crashes, after a 10s delay. Otherwise, no shell
+ is spawned. Defaults to , for security
+ reasons, as the shell is not protected by password
authentication.
- systemd.crash_chvt=
+ systemd.crash_reboot=
- Takes an integer argument. If positive systemd
- activates the specified virtual terminal when it crashes.
- Defaults to -1.
+ Takes a boolean argument. If
+ , 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
+ , in order to avoid a reboot loop. If
+ combined with systemd.crash_shell=, it is
+ first attempted to invoke a shell, and if this is not
+ successful the system is rebooted.systemd.confirm_spawn=Takes a boolean argument. If
- , asks for confirmation when spawning
- processes. Defaults to
- .
+ , the system manager (PID 1) asks for
+ confirmation when spawning processes. Defaults to
+ .
systemd.show_status=Takes a boolean argument or the constant
- auto. If , shows
- terse service status updates on the console during bootup.
- auto behaves like
- until a service fails or there is a significant delay in boot.
- Defaults to , unless
- is passed as kernel command line option
- in which case it defaults to
+ auto. If , the
+ systemd manager (PID 1) shows terse service status updates on
+ the console during bootup. auto behaves
+ like until a service fails or there is
+ a significant delay in boot. Defaults to
+ , unless is passed
+ as kernel command line option in which case it defaults to
auto.
diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c
index dd3d525854..287e0dfa13 100644
--- a/src/basic/terminal-util.c
+++ b/src/basic/terminal-util.c
@@ -48,7 +48,7 @@ int chvt(int vt) {
if (fd < 0)
return -errno;
- if (vt < 0) {
+ if (vt <= 0) {
int tiocl[2] = {
TIOCL_GETKMSGREDIRECT,
0
diff --git a/src/core/main.c b/src/core/main.c
index 9634feb8a6..bac2043281 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -27,6 +27,7 @@
#include
#include
#include
+#include
#include
#include
#ifdef HAVE_SECCOMP
@@ -87,8 +88,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;
@@ -123,6 +125,21 @@ 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) {
if (getpid() != 1)
@@ -188,7 +205,7 @@ noreturn static void crash(int sig) {
}
}
- if (arg_crash_chvt)
+ if (arg_crash_chvt >= 0)
(void) chvt(arg_crash_chvt);
if (arg_crash_shell) {
@@ -198,7 +215,7 @@ noreturn static void crash(int sig) {
};
pid_t pid;
- log_info("Executing crash shell in 10s...");
+ log_notice("Executing crash shell in 10s...");
(void) sleep(10);
/* Let the kernel reap children for us */
@@ -208,17 +225,20 @@ noreturn static void crash(int sig) {
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) execle("/bin/sh", "/bin/sh", NULL, environ);
log_emergency_errno(errno, "execle() failed: %m");
+ freeze_or_reboot();
_exit(EXIT_FAILURE);
- } else
- log_info("Successfully spawned crash shell as PID "PID_FMT".", pid);
+ } else {
+ log_info("Spawned crash shell as PID "PID_FMT".", pid);
+ freeze();
+ }
}
- log_emergency("Freezing execution.");
- freeze();
+ freeze_or_reboot();
}
static void install_crash_handler(void) {
@@ -252,6 +272,24 @@ static int console_setup(void) {
return 0;
}
+static int parse_crash_chvt(const char *value) {
+ int b;
+
+ if (safe_atoi(value, &arg_crash_chvt) >= 0)
+ return 0;
+
+ b = parse_boolean(value);
+ if (b < 0)
+ return b;
+
+ if (b > 0)
+ arg_crash_chvt = 0; /* switch to where kmsg goes */
+ else
+ arg_crash_chvt = -1; /* turn off switching */
+
+ return 0;
+}
+
static int parse_proc_cmdline_item(const char *key, const char *value) {
static const char * const rlmap[] = {
@@ -290,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);
@@ -298,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) {
@@ -461,6 +505,34 @@ static int config_parse_show_status(
return 0;
}
+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) {
+
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ 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;
+ }
+
+ return 0;
+}
+
static int config_parse_join_controllers(const char *unit,
const char *filename,
unsigned line,
@@ -571,9 +643,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 },
@@ -661,7 +735,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,
@@ -684,7 +760,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 },
@@ -802,21 +880,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:
@@ -846,17 +945,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;
@@ -916,14 +1014,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);
@@ -1032,7 +1132,7 @@ 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();
+ freeze_or_reboot();
}
static void test_usr(void) {
@@ -1964,7 +2064,7 @@ finish:
manager_status_printf(NULL, STATUS_TYPE_EMERGENCY,
ANSI_HIGHLIGHT_RED "!!!!!!" ANSI_NORMAL,
"%s, freezing.", error_message);
- freeze();
+ freeze_or_reboot();
}
return retval;
diff --git a/src/core/shutdown.c b/src/core/shutdown.c
index 5296efce1d..27c581d9c1 100644
--- a/src/core/shutdown.c
+++ b/src/core/shutdown.c
@@ -430,6 +430,5 @@ int main(int argc, char *argv[]) {
error:
log_emergency_errno(r, "Critical error while doing system shutdown: %m");
-
freeze();
}
diff --git a/src/core/system.conf b/src/core/system.conf
index 231609033b..c30c595413 100644
--- a/src/core/system.conf
+++ b/src/core/system.conf
@@ -17,9 +17,10 @@
#LogColor=yes
#LogLocation=no
#DumpCore=yes
-#CrashShell=no
#ShowStatus=yes
-#CrashChVT=1
+#CrashChangeVT=no
+#CrashShell=no
+#CrashReboot=no
#CPUAffinity=1 2
#JoinControllers=cpu,cpuacct net_cls,net_prio
#RuntimeWatchdogSec=0