From 665a3d6d15c09428debcabd46e8a2e27afc51a46 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Thu, 19 Oct 2023 13:58:03 +0100 Subject: [PATCH] systemctl: automatically softreboot/kexec if set up on reboot Automatically softreboot if the nextroot has been set up with an OS tree, or automatically kexec if a kernel has been loaded with kexec --load. Add SYSTEMCTL_SKIP_AUTO_KEXEC and SYSTEMCTL_SKIP_AUTO_SOFT_REBOOT to skip the automated switchover. --- docs/ENVIRONMENT.md | 7 +++++++ man/org.freedesktop.login1.xml | 18 +++++++++++------- man/systemctl.xml | 15 +++++++++++++++ man/systemd-soft-reboot.service.xml | 4 ++++ src/basic/login-util.h | 3 ++- src/login/logind-dbus.c | 9 +++++---- src/systemctl/systemctl-logind.c | 7 ++++++- src/systemctl/systemctl.c | 5 +---- test/units/testsuite-82.sh | 5 +++-- 9 files changed, 54 insertions(+), 19 deletions(-) diff --git a/docs/ENVIRONMENT.md b/docs/ENVIRONMENT.md index 65d28e6bfa6..b6e5c2e1567 100644 --- a/docs/ENVIRONMENT.md +++ b/docs/ENVIRONMENT.md @@ -136,6 +136,13 @@ All tools: * `$SYSTEMCTL_SKIP_SYSV=1` — if set, do not call SysV compatibility hooks. +* `$SYSTEMCTL_SKIP_AUTO_KEXEC=1` — if set, do not automatically kexec instead of + reboot when a new kernel has been loaded. + +* `$SYSTEMCTL_SKIP_AUTO_SOFT_REBOOT=1` — if set, do not automatically soft-reboot + instead of reboot when a new root file system has been loaded in + `/run/nextroot`. + `systemd-nspawn`: * `$SYSTEMD_NSPAWN_UNIFIED_HIERARCHY=1` — if set, force `systemd-nspawn` into diff --git a/man/org.freedesktop.login1.xml b/man/org.freedesktop.login1.xml index 4a94656f662..954518992be 100644 --- a/man/org.freedesktop.login1.xml +++ b/man/org.freedesktop.login1.xml @@ -595,16 +595,20 @@ node /org/freedesktop/login1 { SuspendThenHibernateWithFlags() add flags to allow for extendability, defined as follows: -#define SD_LOGIND_ROOT_CHECK_INHIBITORS (UINT64_C(1) << 0) -#define SD_LOGIND_KEXEC_REBOOT (UINT64_C(1) << 1) -#define SD_LOGIND_SOFT_REBOOT (UINT64_C(1) << 2) +#define SD_LOGIND_ROOT_CHECK_INHIBITORS (UINT64_C(1) << 0) +#define SD_LOGIND_KEXEC_REBOOT (UINT64_C(1) << 1) +#define SD_LOGIND_SOFT_REBOOT (UINT64_C(1) << 2) +#define SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP (UINT64_C(1) << 3) When the flags is 0 then these methods behave just like the versions without flags. When SD_LOGIND_ROOT_CHECK_INHIBITORS (0x01) is set, active inhibitors are - honoured for privileged users too. When SD_LOGIND_KEXEC_REBOOT (0x02) is set, then - RebootWithFlags() performs a kexec reboot if kexec kernel is loaded. When - SD_LOGIND_SOFT_REBOOT (0x04) is set, then RebootWithFlags() - performs a userspace reboot only. + honoured for privileged users too. When SD_LOGIND_KEXEC_REBOOT (0x02) is set, + then RebootWithFlags() performs a kexec reboot if kexec kernel is loaded. When + SD_LOGIND_SOFT_REBOOT (0x04) is set, or + SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP (0x08) is set and a new root file system + has been set up on /run/nextroot/, then RebootWithFlags() + performs a userspace reboot only. SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP and + SD_LOGIND_KEXEC_REBOOT can be combined, with soft-reboot having precedence. SetRebootParameter() sets a parameter for a subsequent reboot operation. See the description of reboot in diff --git a/man/systemctl.xml b/man/systemctl.xml index 419d4a82438..217010ca1c8 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -1652,6 +1652,13 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err This command honors and in a similar way as halt. + If a new kernel has been loaded via kexec --load, a + kexec will be performed instead of a reboot, unless + SYSTEMCTL_SKIP_AUTO_KEXEC=1 has been set. If a new root file system has + been setup on /run/nextroot, a soft-reboot will be + performed instead of a reboot, unless SYSTEMCTL_SKIP_AUTO_SOFT_REBOOT=1 has + been set. + @@ -1681,6 +1688,10 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err This command honors and similarly to halt. + + If a new kernel has been loaded via kexec --load, a + kexec will be performed when reboot is invoked, unless + SYSTEMCTL_SKIP_AUTO_KEXEC=1 has been set. @@ -1700,6 +1711,10 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err systemd-soft-reboot.service8 for details. + If a new root file system has been setup on /run/nextroot, a + soft-reboot will be performed when reboot is invoked, + unless SYSTEMCTL_SKIP_AUTO_SOFT_REBOOT=1 has been set. + diff --git a/man/systemd-soft-reboot.service.xml b/man/systemd-soft-reboot.service.xml index 1de2fbc5f37..2419b866049 100644 --- a/man/systemd-soft-reboot.service.xml +++ b/man/systemd-soft-reboot.service.xml @@ -164,6 +164,10 @@ ExecStart=sleep infinity Note that systemd-soft-reboot.service (and related units) should never be executed directly. Instead, trigger system shutdown with a command such as systemctl soft-reboot. + + Note that if a new root file system has been setup on /run/nextroot, a + soft-reboot will be performed when the reboot command is + invoked. diff --git a/src/basic/login-util.h b/src/basic/login-util.h index 613fb0f86f4..4c9cae0f4fc 100644 --- a/src/basic/login-util.h +++ b/src/basic/login-util.h @@ -7,11 +7,12 @@ #define SD_LOGIND_ROOT_CHECK_INHIBITORS (UINT64_C(1) << 0) #define SD_LOGIND_REBOOT_VIA_KEXEC (UINT64_C(1) << 1) #define SD_LOGIND_SOFT_REBOOT (UINT64_C(1) << 2) +#define SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP (UINT64_C(1) << 3) /* For internal use only */ #define SD_LOGIND_INTERACTIVE (UINT64_C(1) << 63) -#define SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC (SD_LOGIND_ROOT_CHECK_INHIBITORS|SD_LOGIND_REBOOT_VIA_KEXEC|SD_LOGIND_SOFT_REBOOT) +#define SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC (SD_LOGIND_ROOT_CHECK_INHIBITORS|SD_LOGIND_REBOOT_VIA_KEXEC|SD_LOGIND_SOFT_REBOOT|SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP) #define SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_ALL (SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC|SD_LOGIND_INTERACTIVE) bool session_id_valid(const char *id); diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index b458359c971..d631a307166 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -1895,7 +1895,7 @@ static int method_do_shutdown_or_sleep( if (flags & SD_LOGIND_REBOOT_VIA_KEXEC) return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Reboot via kexec option is only applicable with reboot operations"); - if (flags & SD_LOGIND_SOFT_REBOOT) + if ((flags & SD_LOGIND_SOFT_REBOOT) || (flags & SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP)) return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Soft reboot option is only applicable with reboot operations"); } @@ -1912,10 +1912,11 @@ static int method_do_shutdown_or_sleep( flags = interactive ? SD_LOGIND_INTERACTIVE : 0; } - if ((flags & SD_LOGIND_REBOOT_VIA_KEXEC) && kexec_loaded()) - a = handle_action_lookup(HANDLE_KEXEC); - else if ((flags & SD_LOGIND_SOFT_REBOOT)) + if ((flags & SD_LOGIND_SOFT_REBOOT) || + ((flags & SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP) && path_is_os_tree("/run/nextroot") > 0)) a = handle_action_lookup(HANDLE_SOFT_REBOOT); + else if ((flags & SD_LOGIND_REBOOT_VIA_KEXEC) && kexec_loaded()) + a = handle_action_lookup(HANDLE_KEXEC); /* Don't allow multiple jobs being executed at the same time */ if (m->delayed_action) diff --git a/src/systemctl/systemctl-logind.c b/src/systemctl/systemctl-logind.c index 2a697b84e53..cd83d29474a 100644 --- a/src/systemctl/systemctl-logind.c +++ b/src/systemctl/systemctl-logind.c @@ -80,7 +80,12 @@ int logind_reboot(enum action a) { return 0; SET_FLAG(flags, SD_LOGIND_ROOT_CHECK_INHIBITORS, arg_check_inhibitors > 0); - SET_FLAG(flags, SD_LOGIND_REBOOT_VIA_KEXEC, a == ACTION_KEXEC); + SET_FLAG(flags, + SD_LOGIND_REBOOT_VIA_KEXEC, + a == ACTION_KEXEC || (a == ACTION_REBOOT && getenv_bool("SYSTEMCTL_SKIP_AUTO_KEXEC") <= 0)); + SET_FLAG(flags, + SD_LOGIND_SOFT_REBOOT_IF_NEXTROOT_SET_UP, + a == ACTION_REBOOT && getenv_bool("SYSTEMCTL_SKIP_AUTO_SOFT_REBOOT") <= 0); SET_FLAG(flags, SD_LOGIND_SOFT_REBOOT, a == ACTION_SOFT_REBOOT); r = bus_call_method(bus, bus_login_mgr, method_with_flags, &error, NULL, "t", flags); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index dcd4dcc68aa..70b8c162494 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -1090,10 +1090,7 @@ int systemctl_dispatch_parse_argv(int argc, char *argv[]) { return halt_parse_argv(argc, argv); } else if (invoked_as(argv, "reboot")) { - if (kexec_loaded()) - arg_action = ACTION_KEXEC; - else - arg_action = ACTION_REBOOT; + arg_action = ACTION_REBOOT; return halt_parse_argv(argc, argv); } else if (invoked_as(argv, "shutdown")) { diff --git a/test/units/testsuite-82.sh b/test/units/testsuite-82.sh index 15243ab6a22..e0f9573f541 100755 --- a/test/units/testsuite-82.sh +++ b/test/units/testsuite-82.sh @@ -133,9 +133,10 @@ elif [ -f /run/testsuite82.touch ]; then # Restart the unit that is not supposed to survive systemd-run --collect --service-type=exec --unit=testsuite-82-nosurvive.service sleep infinity - # Now issue the soft reboot. We should be right back soon. + # Now issue the soft reboot. We should be right back soon. Given /run/nextroot exists, we should + # automatically do a softreboot instead of normal reboot. touch /run/testsuite82.touch2 - systemctl --no-block soft-reboot + systemctl --no-block reboot # Now block until the soft-boot killing spree kills us exec sleep infinity