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