]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: Add halt and kexec emergency actions
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Wed, 21 Jun 2023 09:59:27 +0000 (11:59 +0200)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Thu, 22 Jun 2023 09:33:13 +0000 (10:33 +0100)
Let's complete the picture by adding the missing halt and kexec
emergency actions.

man/systemd.unit.xml
src/core/emergency-action.c
src/core/emergency-action.h
src/test/test-emergency-action.c

index 2eb88d02f7f14b8f15a5c60e1314263367c6f261..e9c7cb238c72d73de0a2553cd9d25195acb83f11 100644 (file)
         inactive state.  Takes one of <option>none</option>, <option>reboot</option>,
         <option>reboot-force</option>, <option>reboot-immediate</option>, <option>poweroff</option>,
         <option>poweroff-force</option>, <option>poweroff-immediate</option>, <option>exit</option>,
-        <option>exit-force</option>, <option>soft-reboot</option> and <option>soft-reboot-force</option>. In
-        system mode, all options are allowed. In user mode, only <option>none</option>,
-        <option>exit</option>, <option>exit-force</option>, <option>soft-reboot</option> and
-        <option>soft-reboot-force</option> are allowed. Both options default to <option>none</option>.</para>
+        <option>exit-force</option>, <option>soft-reboot</option>, <option>soft-reboot-force</option>,
+        <option>kexec</option>, <option>kexec-force</option>, <option>halt</option>,
+        <option>halt-force</option> and <option>halt-immediate</option>. In system mode, all options are
+        allowed. In user mode, only <option>none</option>, <option>exit</option>,
+        <option>exit-force</option>, <option>soft-reboot</option> and <option>soft-reboot-force</option> are
+        allowed. Both options default to <option>none</option>.</para>
 
         <para>If <option>none</option> is set, no action will be triggered. <option>reboot</option> causes a
         reboot following the normal shutdown procedure (i.e. equivalent to <command>systemctl
         <command>systemctl reboot -f</command>) and <option>reboot-immediate</option> causes immediate
         execution of the
         <citerefentry><refentrytitle>reboot</refentrytitle><manvolnum>2</manvolnum></citerefentry> system
-        call, which might result in data loss (i.e. equivalent to <command>systemctl reboot
-        -ff</command>). Similarly, <option>poweroff</option>, <option>poweroff-force</option>,
-        <option>poweroff-immediate</option> have the effect of powering down the system with similar
+        call, which might result in data loss (i.e. equivalent to <command>systemctl reboot -ff</command>).
+        Similarly, <option>poweroff</option>, <option>poweroff-force</option>,
+        <option>poweroff-immediate</option>, <option>kexec</option>, <option>kexec-force</option>,
+        <option>halt</option>, <option>halt-force</option> and <option>halt-immediate</option> have the
+        effect of powering down the system, executing kexec, and halting the system respectively with similar
         semantics. <option>exit</option> causes the manager to exit following the normal shutdown procedure,
         and <option>exit-force</option> causes it terminate without shutting down services. When
         <option>exit</option> or <option>exit-force</option> 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
-        <varname>FailureActionExitStatus=</varname>/<varname>SuccessActionExitStatus=</varname>, see
-        below. <option>soft-reboot</option> will trigger a userspace reboot
-        operation. <option>soft-reboot-force</option> does that too, but does not go through the shutdown
-        transaction beforehand.</para></listitem>
+        <varname>FailureActionExitStatus=</varname>/<varname>SuccessActionExitStatus=</varname>, see below.
+        <option>soft-reboot</option> will trigger a userspace reboot operation.
+        <option>soft-reboot-force</option> does that too, but does not go through the shutdown transaction
+        beforehand.</para></listitem>
       </varlistentry>
 
       <varlistentry>
index 0b458ebf28e8959d0712e40bd6126aaf769b1e76..e2cd931671714bda84f0e5312d9f1e1db2fb24c2 100644 (file)
@@ -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();
         }
index 2c61c9c7d6124599f22542e76cfeb3ca8a40b3f5..33e0ec6ffc57b1b81194d258854a8c5187c46d3c 100644 (file)
@@ -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;
index b2e6af8d627627060b732892b40991c3521c46d0..5c0ce7f05306e9146331498be61724e001f402d4 100644 (file)
@@ -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);