diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index 2eb88d02f7f..e9c7cb238c7 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -1004,10 +1004,12 @@ inactive state. Takes one of , , , , , , , , - , and . In - system mode, all options are allowed. In user mode, only , - , , and - are allowed. Both options default to . + , , , + , , , + and . In system mode, all options are + allowed. In user mode, only , , + , and are + allowed. Both options default to . If is set, no action will be triggered. causes a reboot following the normal shutdown procedure (i.e. equivalent to systemctl @@ -1016,18 +1018,20 @@ systemctl reboot -f) and causes immediate execution of the reboot2 system - call, which might result in data loss (i.e. equivalent to systemctl reboot - -ff). Similarly, , , - have the effect of powering down the system with similar + call, which might result in data loss (i.e. equivalent to systemctl reboot -ff). + Similarly, , , + , , , + , and have the + effect of powering down the system, executing kexec, and halting the system respectively with similar semantics. causes the manager to exit following the normal shutdown procedure, and causes it terminate without shutting down services. When or is used by default the exit status of the main process of the unit (if this applies) is returned from the service manager. However, this may be overridden with - FailureActionExitStatus=/SuccessActionExitStatus=, see - below. will trigger a userspace reboot - operation. does that too, but does not go through the shutdown - transaction beforehand. + FailureActionExitStatus=/SuccessActionExitStatus=, see below. + will trigger a userspace reboot operation. + does that too, but does not go through the shutdown transaction + beforehand. diff --git a/src/core/emergency-action.c b/src/core/emergency-action.c index 0b458ebf28e..e2cd9316717 100644 --- a/src/core/emergency-action.c +++ b/src/core/emergency-action.c @@ -24,6 +24,11 @@ static const char* const emergency_action_table[_EMERGENCY_ACTION_MAX] = { [EMERGENCY_ACTION_EXIT_FORCE] = "exit-force", [EMERGENCY_ACTION_SOFT_REBOOT] = "soft-reboot", [EMERGENCY_ACTION_SOFT_REBOOT_FORCE] = "soft-reboot-force", + [EMERGENCY_ACTION_KEXEC] = "kexec", + [EMERGENCY_ACTION_KEXEC_FORCE] = "kexec-force", + [EMERGENCY_ACTION_HALT] = "halt", + [EMERGENCY_ACTION_HALT_FORCE] = "halt-force", + [EMERGENCY_ACTION_HALT_IMMEDIATE] = "halt-immediate", }; static void log_and_status(Manager *m, bool warn, const char *message, const char *reason) { @@ -49,7 +54,13 @@ void emergency_action( assert(action < _EMERGENCY_ACTION_MAX); /* Is the special shutdown target active or queued? If so, we are in shutdown state */ - if (IN_SET(action, EMERGENCY_ACTION_REBOOT, EMERGENCY_ACTION_SOFT_REBOOT, EMERGENCY_ACTION_POWEROFF, EMERGENCY_ACTION_EXIT)) { + if (IN_SET(action, + EMERGENCY_ACTION_REBOOT, + EMERGENCY_ACTION_SOFT_REBOOT, + EMERGENCY_ACTION_POWEROFF, + EMERGENCY_ACTION_EXIT, + EMERGENCY_ACTION_KEXEC, + EMERGENCY_ACTION_HALT)) { u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET); if (u && unit_active_or_pending(u)) { log_notice("Shutdown is already active. Skipping emergency action request %s.", @@ -158,6 +169,35 @@ void emergency_action( (void) reboot(RB_POWER_OFF); break; + case EMERGENCY_ACTION_KEXEC: + log_and_status(m, warn, "Executing kexec", reason); + (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_KEXEC_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL, NULL); + break; + + case EMERGENCY_ACTION_KEXEC_FORCE: + log_and_status(m, warn, "Forcibly executing kexec", reason); + m->objective = MANAGER_KEXEC; + break; + + case EMERGENCY_ACTION_HALT: + log_and_status(m, warn, "Halting", reason); + (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_HALT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL, NULL); + break; + + case EMERGENCY_ACTION_HALT_FORCE: + log_and_status(m, warn, "Forcibly halting", reason); + m->objective = MANAGER_HALT; + break; + + case EMERGENCY_ACTION_HALT_IMMEDIATE: + log_and_status(m, warn, "Halting immediately", reason); + + sync(); + + log_info("Halting."); + (void) reboot(RB_HALT_SYSTEM); + break; + default: assert_not_reached(); } diff --git a/src/core/emergency-action.h b/src/core/emergency-action.h index 2c61c9c7d61..33e0ec6ffc5 100644 --- a/src/core/emergency-action.h +++ b/src/core/emergency-action.h @@ -18,6 +18,11 @@ typedef enum EmergencyAction { EMERGENCY_ACTION_EXIT_FORCE, EMERGENCY_ACTION_SOFT_REBOOT, EMERGENCY_ACTION_SOFT_REBOOT_FORCE, + EMERGENCY_ACTION_KEXEC, + EMERGENCY_ACTION_KEXEC_FORCE, + EMERGENCY_ACTION_HALT, + EMERGENCY_ACTION_HALT_FORCE, + EMERGENCY_ACTION_HALT_IMMEDIATE, _EMERGENCY_ACTION_MAX, _EMERGENCY_ACTION_INVALID = -EINVAL, } EmergencyAction; diff --git a/src/test/test-emergency-action.c b/src/test/test-emergency-action.c index b2e6af8d627..5c0ce7f0530 100644 --- a/src/test/test-emergency-action.c +++ b/src/test/test-emergency-action.c @@ -38,6 +38,14 @@ TEST(parse_emergency_action) { assert_se(parse_emergency_action("exit-force", RUNTIME_SCOPE_SYSTEM, &x) == 0); assert_se(parse_emergency_action("exit-forcee", RUNTIME_SCOPE_SYSTEM, &x) == -EINVAL); assert_se(x == EMERGENCY_ACTION_EXIT_FORCE); + assert_se(parse_emergency_action("kexec", RUNTIME_SCOPE_SYSTEM, &x) == 0); + assert_se(parse_emergency_action("kexec-force", RUNTIME_SCOPE_SYSTEM, &x) == 0); + assert_se(parse_emergency_action("kexec-forcee", RUNTIME_SCOPE_SYSTEM, &x) == -EINVAL); + assert_se(x == EMERGENCY_ACTION_KEXEC_FORCE); + assert_se(parse_emergency_action("halt", RUNTIME_SCOPE_SYSTEM, &x) == 0); + assert_se(parse_emergency_action("halt-force", RUNTIME_SCOPE_SYSTEM, &x) == 0); + assert_se(parse_emergency_action("halt-forcee", RUNTIME_SCOPE_SYSTEM, &x) == -EINVAL); + assert_se(x == EMERGENCY_ACTION_HALT_FORCE); } DEFINE_TEST_MAIN(LOG_INFO); diff --git a/units/systemd-halt.service b/units/systemd-halt.service index 3ce976f539d..e3a35cc30d0 100644 --- a/units/systemd-halt.service +++ b/units/systemd-halt.service @@ -13,7 +13,4 @@ Documentation=man:systemd-halt.service(8) DefaultDependencies=no Requires=shutdown.target umount.target final.target After=shutdown.target umount.target final.target - -[Service] -Type=oneshot -ExecStart=systemctl --force halt +SuccessAction=halt-force diff --git a/units/systemd-kexec.service b/units/systemd-kexec.service index 916995c9d43..243fa3b3da4 100644 --- a/units/systemd-kexec.service +++ b/units/systemd-kexec.service @@ -13,7 +13,4 @@ Documentation=man:systemd-kexec.service(8) DefaultDependencies=no Requires=shutdown.target umount.target final.target After=shutdown.target umount.target final.target - -[Service] -Type=oneshot -ExecStart=systemctl --force kexec +SuccessAction=kexec-force