]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
shutdown: remove kexec-tools dependency
authorLuca Boccassi <luca.boccassi@gmail.com>
Fri, 27 Mar 2026 19:32:29 +0000 (19:32 +0000)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Fri, 27 Mar 2026 22:03:01 +0000 (23:03 +0100)
'kexec -e' is just a small wrapper that does the xen hypercall
on xen, or otherwise just calls reboot(). Drop the dependency,
and reuse the existing xen hypercall helper.

src/login/logind-action.c
src/shared/reboot-util.c
src/shared/reboot-util.h
src/shutdown/shutdown.c

index 843bb1a5a085c30725e64d83cf77e8eeb840950e..48f2031fc47c7d8294a6f0ec31f66cad733122d5 100644 (file)
@@ -222,10 +222,6 @@ static int handle_action_execute(
         assert(m);
         assert(!IN_SET(handle, HANDLE_IGNORE, HANDLE_LOCK, HANDLE_SLEEP));
 
-        if (handle == HANDLE_KEXEC && access(KEXEC, X_OK) < 0)
-                return log_warning_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
-                                         "Requested %s operation not supported, ignoring.", handle_action_to_string(handle));
-
         if (m->delayed_action)
                 return log_debug_errno(SYNTHETIC_ERRNO(EALREADY),
                                        "Action %s already in progress, ignoring requested %s operation.",
index 55ec6c0f0aac63bda97b5cf4c498b32e872b2cbe..d9ff532921b3892937d0df04099010118083a053 100644 (file)
@@ -139,13 +139,15 @@ bool shall_restore_state(void) {
         return (cached = b);
 }
 
-static int xen_kexec_loaded(void) {
 #if HAVE_XENCTRL
+static int xen_kexec_command(uint64_t cmd) {
         _cleanup_close_ int privcmd_fd = -EBADF, buf_fd = -EBADF;
-        xen_kexec_status_t *buffer;
+        void *buffer;
         size_t size;
         int r;
 
+        assert(IN_SET(cmd, KEXEC_CMD_kexec, KEXEC_CMD_kexec_status));
+
         if (access("/proc/xen", F_OK) < 0) {
                 if (errno == ENOENT)
                         return -EOPNOTSUPP;
@@ -153,7 +155,8 @@ static int xen_kexec_loaded(void) {
         }
 
         size = page_size();
-        if (sizeof(xen_kexec_status_t) > size)
+        if ((cmd == KEXEC_CMD_kexec_status && sizeof(xen_kexec_status_t) > size) ||
+            (cmd == KEXEC_CMD_kexec && sizeof(xen_kexec_exec_t) > size))
                 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "page_size is too small for hypercall");
 
         privcmd_fd = open("/dev/xen/privcmd", O_RDWR|O_CLOEXEC);
@@ -168,25 +171,44 @@ static int xen_kexec_loaded(void) {
         if (buffer == MAP_FAILED)
                 return log_debug_errno(errno, "Cannot allocate buffer for hypercall: %m");
 
-        *buffer = (xen_kexec_status_t) {
-                .type = KEXEC_TYPE_DEFAULT,
-        };
+        if (cmd == KEXEC_CMD_kexec_status)
+                *(xen_kexec_status_t *)buffer = (xen_kexec_status_t) {
+                        .type = KEXEC_TYPE_DEFAULT,
+                };
+        else
+                *(xen_kexec_exec_t *)buffer = (xen_kexec_exec_t) {
+                        .type = KEXEC_TYPE_DEFAULT,
+                };
 
         privcmd_hypercall_t call = {
                 .op = __HYPERVISOR_kexec_op,
                 .arg = {
-                        KEXEC_CMD_kexec_status,
+                        cmd,
                         PTR_TO_UINT64(buffer),
                 },
         };
 
         r = RET_NERRNO(ioctl(privcmd_fd, IOCTL_PRIVCMD_HYPERCALL, &call));
         if (r < 0)
-                log_debug_errno(r, "kexec_status failed: %m");
+                log_debug_errno(r, "kexec%s failed: %m", cmd == KEXEC_CMD_kexec_status ? "_status" : "");
 
         munmap(buffer, size);
 
         return r;
+}
+#endif
+
+static int xen_kexec(void) {
+#if HAVE_XENCTRL
+        return xen_kexec_command(KEXEC_CMD_kexec);
+#else
+        return -EOPNOTSUPP;
+#endif
+}
+
+static int xen_kexec_loaded(void) {
+#if HAVE_XENCTRL
+        return xen_kexec_command(KEXEC_CMD_kexec_status);
 #else
         return -EOPNOTSUPP;
 #endif
@@ -210,6 +232,20 @@ bool kexec_loaded(void) {
        return s[0] == '1';
 }
 
+int kexec(void) {
+        int r;
+
+        r = xen_kexec();
+        if (r < 0 && r != -EOPNOTSUPP)
+                return log_error_errno(r, "Failed to call xen kexec: %m");
+
+        r = reboot(LINUX_REBOOT_CMD_KEXEC);
+        if (r < 0)
+                return log_error_errno(errno, "Failed to kexec: %m");
+
+        return 0;
+}
+
 int create_shutdown_run_nologin_or_warn(void) {
         int r;
 
index eaa6614df05ea8c8d15aa5a04146aac13ecda30f..4548903a4c311919f6d648abd0a477fad6b62f39 100644 (file)
@@ -26,5 +26,6 @@ int reboot_with_parameter(RebootFlags flags);
 bool shall_restore_state(void);
 
 bool kexec_loaded(void);
+int kexec(void);
 
 int create_shutdown_run_nologin_or_warn(void);
index fc6df238bed9e9ecd6b33f85880df23436a76866..73c6dd6d8708b0fcc332bc2811753151744c5694 100644 (file)
@@ -609,23 +609,9 @@ int main(int argc, char *argv[]) {
         case LINUX_REBOOT_CMD_KEXEC:
 
                 if (!in_container) {
-                        /* We cheat and exec kexec to avoid doing all its work */
                         log_info("Rebooting with kexec.");
 
-                        r = pidref_safe_fork(
-                                        "(sd-kexec)",
-                                        FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_LOG|FORK_WAIT,
-                                        /* ret= */ NULL);
-                        if (r == 0) {
-                                /* Child */
-
-                                (void) execl(KEXEC, KEXEC, "-e", NULL);
-                                log_debug_errno(errno, "Failed to execute '" KEXEC "' binary, proceeding with reboot(RB_KEXEC): %m");
-
-                                /* execv failed (kexec binary missing?), so try simply reboot(RB_KEXEC) */
-                                (void) reboot(cmd);
-                                _exit(EXIT_FAILURE);
-                        }
+                        (void) kexec();
 
                         /* If we are still running, then the kexec can't have worked, let's fall through */
                 }