diff --git a/src/basic/meson.build b/src/basic/meson.build index d0e499d0d2a..c71599db7b6 100644 --- a/src/basic/meson.build +++ b/src/basic/meson.build @@ -157,6 +157,9 @@ basic_sources = files(''' ratelimit.c ratelimit.h raw-clone.h + raw-reboot.h + reboot-util.c + reboot-util.h refcnt.h replace-var.c replace-var.h diff --git a/src/basic/missing_syscall.h b/src/basic/missing_syscall.h index d7d4e9e4593..bf282ac3f07 100644 --- a/src/basic/missing_syscall.h +++ b/src/basic/missing_syscall.h @@ -27,7 +27,7 @@ #if !HAVE_PIVOT_ROOT static inline int missing_pivot_root(const char *new_root, const char *put_old) { - return syscall(SYS_pivot_root, new_root, put_old); + return syscall(__NR_pivot_root, new_root, put_old); } # define pivot_root missing_pivot_root @@ -129,7 +129,7 @@ static inline int missing_getrandom(void *buffer, size_t count, unsigned flags) #if !HAVE_GETTID static inline pid_t missing_gettid(void) { - return (pid_t) syscall(SYS_gettid); + return (pid_t) syscall(__NR_gettid); } # define gettid missing_gettid @@ -415,9 +415,9 @@ static inline int missing_bpf(int cmd, union bpf_attr *attr, size_t size) { #if !HAVE_STATX # ifndef __NR_statx # if defined __i386__ -# define __NR_bpf 383 +# define __NR_statx 383 # elif defined __x86_64__ -# define __NR_bpf 332 +# define __NR_statx 332 # else # warning "__NR_statx not defined for your architecture" # endif diff --git a/src/basic/raw-reboot.h b/src/basic/raw-reboot.h new file mode 100644 index 00000000000..8ecefe9e213 --- /dev/null +++ b/src/basic/raw-reboot.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include +#include +#include + +/* glibc defines the reboot() API call, which is a wrapper around the system call of the same name, but without the + * extra "arg" parameter. Since we need that parameter for some calls, let's add a "raw" wrapper that is defined the + * same way, except it takes the additional argument. */ + +static inline int raw_reboot(int cmd, const void *arg) { + return (int) syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, arg); +} diff --git a/src/basic/reboot-util.c b/src/basic/reboot-util.c new file mode 100644 index 00000000000..ca40159b966 --- /dev/null +++ b/src/basic/reboot-util.c @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include +#include + +#include "alloc-util.h" +#include "fileio.h" +#include "log.h" +#include "raw-reboot.h" +#include "reboot-util.h" +#include "string-util.h" +#include "umask-util.h" +#include "virt.h" + +int update_reboot_parameter_and_warn(const char *parameter) { + int r; + + if (isempty(parameter)) { + if (unlink("/run/systemd/reboot-param") < 0) { + if (errno == ENOENT) + return 0; + + return log_warning_errno(errno, "Failed to unlink reboot parameter file: %m"); + } + + return 0; + } + + RUN_WITH_UMASK(0022) { + r = write_string_file("/run/systemd/reboot-param", parameter, + WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC); + if (r < 0) + return log_warning_errno(r, "Failed to write reboot parameter file: %m"); + } + + return 0; +} + +int reboot_with_parameter(RebootFlags flags) { + int r; + + /* Reboots the system with a parameter that is read from /run/systemd/reboot-param. Returns 0 if REBOOT_DRY_RUN + * was set and the actual reboot operation was hence skipped. If REBOOT_FALLBACK is set and the reboot with + * parameter doesn't work out a fallback to classic reboot() is attempted. If REBOOT_FALLBACK is not set, 0 is + * returned instead, which should be considered indication for the caller to fall back to reboot() on its own, + * or somehow else deal with this. If REBOOT_LOG is specified will log about what it is going to do, as well as + * all errors. */ + + if (detect_container() == 0) { + _cleanup_free_ char *parameter = NULL; + + r = read_one_line_file("/run/systemd/reboot-param", ¶meter); + if (r < 0 && r != -ENOENT) + log_full_errno(flags & REBOOT_LOG ? LOG_WARNING : LOG_DEBUG, r, + "Failed to read reboot parameter file, ignoring: %m"); + + if (!isempty(parameter)) { + + log_full(flags & REBOOT_LOG ? LOG_INFO : LOG_DEBUG, + "Rebooting with argument '%s'.", parameter); + + if (flags & REBOOT_DRY_RUN) + return 0; + + (void) raw_reboot(LINUX_REBOOT_CMD_RESTART2, parameter); + + log_full_errno(flags & REBOOT_LOG ? LOG_WARNING : LOG_DEBUG, errno, + "Failed to reboot with parameter, retrying without: %m"); + } + } + + if (!(flags & REBOOT_FALLBACK)) + return 0; + + log_full(flags & REBOOT_LOG ? LOG_INFO : LOG_DEBUG, "Rebooting."); + + if (flags & REBOOT_DRY_RUN) + return 0; + + (void) reboot(RB_AUTOBOOT); + + return log_full_errno(flags & REBOOT_LOG ? LOG_ERR : LOG_DEBUG, errno, "Failed to reboot: %m"); +} diff --git a/src/basic/reboot-util.h b/src/basic/reboot-util.h new file mode 100644 index 00000000000..d4aa4412906 --- /dev/null +++ b/src/basic/reboot-util.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +int update_reboot_parameter_and_warn(const char *parameter); + +typedef enum RebootFlags { + REBOOT_LOG = 1U << 0, /* log about what we are going to do and all errors */ + REBOOT_DRY_RUN = 1U << 1, /* return 0 right before actually doing the reboot */ + REBOOT_FALLBACK = 1U << 2, /* fallback to plain reboot() if argument-based reboot doesn't work, isn't configured or doesn't apply otherwise */ +} RebootFlags; + +int reboot_with_parameter(RebootFlags flags); diff --git a/src/basic/util.c b/src/basic/util.c index c7f1513f3eb..7863a14fb29 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -518,29 +518,6 @@ uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) { return m / max; } -int update_reboot_parameter_and_warn(const char *param) { - int r; - - if (isempty(param)) { - if (unlink("/run/systemd/reboot-param") < 0) { - if (errno == ENOENT) - return 0; - - return log_warning_errno(errno, "Failed to unlink reboot parameter file: %m"); - } - - return 0; - } - - RUN_WITH_UMASK(0022) { - r = write_string_file("/run/systemd/reboot-param", param, WRITE_STRING_FILE_CREATE); - if (r < 0) - return log_warning_errno(r, "Failed to write reboot parameter file: %m"); - } - - return 0; -} - int version(void) { puts(PACKAGE_STRING "\n" SYSTEMD_FEATURES); diff --git a/src/basic/util.h b/src/basic/util.h index 9d1b10756b2..6f8d8bef34e 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -186,8 +186,6 @@ uint64_t physical_memory_scale(uint64_t v, uint64_t max); uint64_t system_tasks_max(void); uint64_t system_tasks_max_scale(uint64_t v, uint64_t max); -int update_reboot_parameter_and_warn(const char *param); - int version(void); int str_verscmp(const char *s1, const char *s2); diff --git a/src/core/emergency-action.c b/src/core/emergency-action.c index decfacd6005..3d37a986bc6 100644 --- a/src/core/emergency-action.c +++ b/src/core/emergency-action.c @@ -20,11 +20,12 @@ ***/ #include -#include #include "bus-error.h" #include "bus-util.h" #include "emergency-action.h" +#include "raw-reboot.h" +#include "reboot-util.h" #include "special.h" #include "string-table.h" #include "terminal-util.h" @@ -88,12 +89,12 @@ int emergency_action( if (!isempty(reboot_arg)) { log_info("Rebooting with argument '%s'.", reboot_arg); - syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, reboot_arg); + (void) raw_reboot(LINUX_REBOOT_CMD_RESTART2, reboot_arg); log_warning_errno(errno, "Failed to reboot with parameter, retrying without: %m"); } log_info("Rebooting."); - reboot(RB_AUTOBOOT); + (void) reboot(RB_AUTOBOOT); break; case EMERGENCY_ACTION_POWEROFF: @@ -112,7 +113,7 @@ int emergency_action( sync(); log_info("Powering off."); - reboot(RB_POWER_OFF); + (void) reboot(RB_POWER_OFF); break; default: diff --git a/src/core/shutdown.c b/src/core/shutdown.c index 0326a7808d3..58c9a9de79e 100644 --- a/src/core/shutdown.c +++ b/src/core/shutdown.c @@ -42,6 +42,7 @@ #include "missing.h" #include "parse-util.h" #include "process-util.h" +#include "reboot-util.h" #include "signal-util.h" #include "string-util.h" #include "switch-root.h" @@ -484,12 +485,9 @@ int main(int argc, char *argv[]) { if (streq(arg_verb, "exit")) { if (in_container) - exit(arg_exit_code); - else { - /* We cannot exit() on the host, fallback on another - * method. */ - cmd = RB_POWER_OFF; - } + return arg_exit_code; + + cmd = RB_POWER_OFF; /* We cannot exit() on the host, fallback on another method. */ } switch (cmd) { @@ -517,22 +515,9 @@ int main(int argc, char *argv[]) { cmd = RB_AUTOBOOT; _fallthrough_; + case RB_AUTOBOOT: - - if (!in_container) { - _cleanup_free_ char *param = NULL; - - r = read_one_line_file("/run/systemd/reboot-param", ¶m); - if (r < 0 && r != -ENOENT) - log_warning_errno(r, "Failed to read reboot parameter file: %m"); - - if (!isempty(param)) { - log_info("Rebooting with argument '%s'.", param); - syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, param); - log_warning_errno(errno, "Failed to reboot with parameter, retrying without: %m"); - } - } - + (void) reboot_with_parameter(REBOOT_LOG); log_info("Rebooting."); break; @@ -548,13 +533,13 @@ int main(int argc, char *argv[]) { assert_not_reached("Unknown magic"); } - reboot(cmd); + (void) reboot(cmd); if (errno == EPERM && in_container) { /* If we are in a container, and we lacked * CAP_SYS_BOOT just exit, this will kill our * container for good. */ log_info("Exiting container."); - exit(EXIT_SUCCESS); + return EXIT_SUCCESS; } r = log_error_errno(errno, "Failed to invoke reboot(): %m"); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 99ad2fc4b0f..6eec0171c6b 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -57,8 +56,8 @@ #include "format-util.h" #include "fs-util.h" #include "glob-util.h" -#include "hostname-util.h" #include "hexdecoct.h" +#include "hostname-util.h" #include "initreq.h" #include "install.h" #include "io-util.h" @@ -73,6 +72,7 @@ #include "path-lookup.h" #include "path-util.h" #include "process-util.h" +#include "reboot-util.h" #include "rlimit-util.h" #include "set.h" #include "sigbus.h" @@ -8472,11 +8472,9 @@ static int start_with_fallback(void) { } static int halt_now(enum action a) { - int r; - /* The kernel will automaticall flush ATA disks and suchlike - * on reboot(), but the file systems need to be synce'd - * explicitly in advance. */ + /* The kernel will automatically flush ATA disks and suchlike on reboot(), but the file systems need to be + * synce'd explicitly in advance. */ if (!arg_no_sync && !arg_dry_run) (void) sync(); @@ -8503,30 +8501,10 @@ static int halt_now(enum action a) { return -errno; case ACTION_KEXEC: - case ACTION_REBOOT: { - _cleanup_free_ char *param = NULL; - - r = read_one_line_file("/run/systemd/reboot-param", ¶m); - if (r < 0 && r != -ENOENT) - log_warning_errno(r, "Failed to read reboot parameter file: %m"); - - if (!isempty(param)) { - if (!arg_quiet) - log_info("Rebooting with argument '%s'.", param); - if (!arg_dry_run) { - (void) syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, - LINUX_REBOOT_CMD_RESTART2, param); - log_warning_errno(errno, "Failed to reboot with parameter, retrying without: %m"); - } - } - - if (!arg_quiet) - log_info("Rebooting."); - if (arg_dry_run) - return 0; - (void) reboot(RB_AUTOBOOT); - return -errno; - } + case ACTION_REBOOT: + return reboot_with_parameter(REBOOT_FALLBACK | + (arg_quiet ? 0 : REBOOT_LOG) | + (arg_dry_run ? REBOOT_DRY_RUN : 0)); default: assert_not_reached("Unknown action.");