From fd91e3ef49af021d9b2b8d006e202f1ccc4e400f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Feb 2018 17:25:01 +0100 Subject: [PATCH 1/7] missing: Fix statx syscall ifdeffery Fix a copy/paste mistake. Fixes: #8238 --- src/basic/missing_syscall.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/basic/missing_syscall.h b/src/basic/missing_syscall.h index d7d4e9e4593..d15b4bf78e0 100644 --- a/src/basic/missing_syscall.h +++ b/src/basic/missing_syscall.h @@ -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 From d06f3829cdfcf1798419a9efded245fd1202f0db Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Feb 2018 17:27:34 +0100 Subject: [PATCH 2/7] missing: always use __NR_ as prefix for syscall numbers Apparently, both __NR_ and SYS_ are useful, but we mostly use __NR_ hence use it for these two cases too, so that we settle on __NR_ exclusively. --- src/basic/missing_syscall.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/basic/missing_syscall.h b/src/basic/missing_syscall.h index d15b4bf78e0..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 From c52a937b460f8f32d6bb55a405faf247822b70a7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Feb 2018 17:42:59 +0100 Subject: [PATCH 3/7] basic: add a common syscall wrapper around reboot() This mimics the raw_clone() call we have in place already and establishes a new syscall wrapper raw_reboot() that wraps the kernel's reboot() system call in a bit more low-level fashion that glibc's reboot() wrapper. The main difference is that the extra "arg" argument is supported. Ultimately this just replaces the syscall wrapper implementation we currently have at three places in our codebase by a single one. With this change this means that all our syscall() invocations are neatly separated out in static inline system call wrappers in our header functions. --- src/basic/meson.build | 1 + src/basic/raw-reboot.h | 14 ++++++++++++++ src/core/emergency-action.c | 4 ++-- src/core/shutdown.c | 4 ++-- src/systemctl/systemctl.c | 7 +++---- 5 files changed, 22 insertions(+), 8 deletions(-) create mode 100644 src/basic/raw-reboot.h diff --git a/src/basic/meson.build b/src/basic/meson.build index d0e499d0d2a..811085eec10 100644 --- a/src/basic/meson.build +++ b/src/basic/meson.build @@ -157,6 +157,7 @@ basic_sources = files(''' ratelimit.c ratelimit.h raw-clone.h + raw-reboot.h refcnt.h replace-var.c replace-var.h 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/core/emergency-action.c b/src/core/emergency-action.c index decfacd6005..095033732b1 100644 --- a/src/core/emergency-action.c +++ b/src/core/emergency-action.c @@ -20,11 +20,11 @@ ***/ #include -#include #include "bus-error.h" #include "bus-util.h" #include "emergency-action.h" +#include "raw-reboot.h" #include "special.h" #include "string-table.h" #include "terminal-util.h" @@ -88,7 +88,7 @@ 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"); } diff --git a/src/core/shutdown.c b/src/core/shutdown.c index 0326a7808d3..8907c4b0a36 100644 --- a/src/core/shutdown.c +++ b/src/core/shutdown.c @@ -20,7 +20,6 @@ #include #include -#include #include #include #include @@ -42,6 +41,7 @@ #include "missing.h" #include "parse-util.h" #include "process-util.h" +#include "raw-reboot.h" #include "signal-util.h" #include "string-util.h" #include "switch-root.h" @@ -528,7 +528,7 @@ int main(int argc, char *argv[]) { if (!isempty(param)) { log_info("Rebooting with argument '%s'.", param); - syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, param); + (void) raw_reboot(LINUX_REBOOT_CMD_RESTART2, param); log_warning_errno(errno, "Failed to reboot with parameter, retrying without: %m"); } } diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 99ad2fc4b0f..800f8629389 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 "raw-reboot.h" #include "rlimit-util.h" #include "set.h" #include "sigbus.h" @@ -8514,8 +8514,7 @@ static int halt_now(enum action a) { 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); + (void) raw_reboot(LINUX_REBOOT_CMD_RESTART2, param); log_warning_errno(errno, "Failed to reboot with parameter, retrying without: %m"); } } From 118cf9523b94a6be0d45b2fa59ef37f2e89454da Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Feb 2018 17:46:55 +0100 Subject: [PATCH 4/7] tree-wide: voidify reboot() invocations We use (void) in most cases for reboot() already, let's add it to the others as well. --- src/core/emergency-action.c | 4 ++-- src/core/shutdown.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/emergency-action.c b/src/core/emergency-action.c index 095033732b1..be3ca8f20d1 100644 --- a/src/core/emergency-action.c +++ b/src/core/emergency-action.c @@ -93,7 +93,7 @@ int emergency_action( } log_info("Rebooting."); - reboot(RB_AUTOBOOT); + (void) reboot(RB_AUTOBOOT); break; case EMERGENCY_ACTION_POWEROFF: @@ -112,7 +112,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 8907c4b0a36..33751c5ff55 100644 --- a/src/core/shutdown.c +++ b/src/core/shutdown.c @@ -548,7 +548,7 @@ 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 From e3631d1c809e368a5116d01e4fb9b9c7d2dddcca Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Feb 2018 17:54:35 +0100 Subject: [PATCH 5/7] basic: split out update_reboot_parameter_and_warn() into its own .c/.h files This is primarily preparation for a follow-up commit that adds a common implementation of the other side of the reboot parameter file, i.e. the code that reads the file and issues reboot() for it. --- src/basic/meson.build | 2 ++ src/basic/reboot-util.c | 34 ++++++++++++++++++++++++++++++++++ src/basic/reboot-util.h | 4 ++++ src/basic/util.c | 23 ----------------------- src/basic/util.h | 2 -- src/core/emergency-action.c | 1 + src/systemctl/systemctl.c | 1 + 7 files changed, 42 insertions(+), 25 deletions(-) create mode 100644 src/basic/reboot-util.c create mode 100644 src/basic/reboot-util.h diff --git a/src/basic/meson.build b/src/basic/meson.build index 811085eec10..c71599db7b6 100644 --- a/src/basic/meson.build +++ b/src/basic/meson.build @@ -158,6 +158,8 @@ basic_sources = files(''' 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/reboot-util.c b/src/basic/reboot-util.c new file mode 100644 index 00000000000..68910a6a34e --- /dev/null +++ b/src/basic/reboot-util.c @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include +#include + +#include "fileio.h" +#include "log.h" +#include "reboot-util.h" +#include "string-util.h" +#include "umask-util.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; +} diff --git a/src/basic/reboot-util.h b/src/basic/reboot-util.h new file mode 100644 index 00000000000..6f1d24c1f5e --- /dev/null +++ b/src/basic/reboot-util.h @@ -0,0 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +int update_reboot_parameter_and_warn(const char *parameter); 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 be3ca8f20d1..3d37a986bc6 100644 --- a/src/core/emergency-action.c +++ b/src/core/emergency-action.c @@ -25,6 +25,7 @@ #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" diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 800f8629389..0d3d0d0daa5 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -73,6 +73,7 @@ #include "path-util.h" #include "process-util.h" #include "raw-reboot.h" +#include "reboot-util.h" #include "rlimit-util.h" #include "set.h" #include "sigbus.h" From c01dcddf803a009dd9118dee0873cb9dd1dd02ce Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Feb 2018 18:48:49 +0100 Subject: [PATCH 6/7] reboot-util: unify reboot with parameter in a single implementation So far, we had two implementations of reboot-with-parameter doing pretty much the same. Let's unify that in a generic implementation used by both. This is particulary nice as it unifies all /run/systemd/reboot-param handling in a single .c file. --- src/basic/reboot-util.c | 49 +++++++++++++++++++++++++++++++++++++++ src/basic/reboot-util.h | 8 +++++++ src/core/shutdown.c | 20 ++++------------ src/systemctl/systemctl.c | 34 +++++---------------------- 4 files changed, 67 insertions(+), 44 deletions(-) diff --git a/src/basic/reboot-util.c b/src/basic/reboot-util.c index 68910a6a34e..ca40159b966 100644 --- a/src/basic/reboot-util.c +++ b/src/basic/reboot-util.c @@ -3,11 +3,14 @@ #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; @@ -32,3 +35,49 @@ int update_reboot_parameter_and_warn(const char *parameter) { 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 index 6f1d24c1f5e..d4aa4412906 100644 --- a/src/basic/reboot-util.h +++ b/src/basic/reboot-util.h @@ -2,3 +2,11 @@ #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/core/shutdown.c b/src/core/shutdown.c index 33751c5ff55..de689aea311 100644 --- a/src/core/shutdown.c +++ b/src/core/shutdown.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -41,7 +42,7 @@ #include "missing.h" #include "parse-util.h" #include "process-util.h" -#include "raw-reboot.h" +#include "reboot-util.h" #include "signal-util.h" #include "string-util.h" #include "switch-root.h" @@ -517,22 +518,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); - (void) raw_reboot(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; diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 0d3d0d0daa5..6eec0171c6b 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -72,7 +72,6 @@ #include "path-lookup.h" #include "path-util.h" #include "process-util.h" -#include "raw-reboot.h" #include "reboot-util.h" #include "rlimit-util.h" #include "set.h" @@ -8473,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(); @@ -8504,29 +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) raw_reboot(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."); From 1f409a0cbb81e2fb55281623c836e117e77b5e32 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Feb 2018 18:50:34 +0100 Subject: [PATCH 7/7] shutdown: let's not use exit() needlessly Generally we prefer 'return' from main() over exit() so that automatic cleanups and such work correct. Let's do that in shutdown.c too, becuase there's not really any reason not to. With this we are pretty good in consistently using return from main() rather than exit() all across the codebase. Yay! --- src/core/shutdown.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/core/shutdown.c b/src/core/shutdown.c index de689aea311..58c9a9de79e 100644 --- a/src/core/shutdown.c +++ b/src/core/shutdown.c @@ -485,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) { @@ -542,7 +539,7 @@ int main(int argc, char *argv[]) { * 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");