diff --git a/man/systemctl.xml b/man/systemctl.xml
index 63ea80a4536..6b2798ecdec 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -1924,23 +1924,21 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
- When system shutdown or sleep state is request, this option controls how to deal with
- inhibitor locks. It takes one of auto, yes or
+ When system shutdown or sleep state is requested, this option controls checking of inhibitor
+ locks. It takes one of auto, yes or
no. Defaults to auto, which will behave like
- yes for interactive invocations (i.e. from a TTY) and no
- for non-interactive invocations.
- yes will let the request respect inhibitor locks.
- no will let the request ignore inhibitor locks.
-
- Applications can establish inhibitor locks to avoid that certain important operations
- (such as CD burning or suchlike) are interrupted by system shutdown or a sleep state. Any user may
- take these locks and privileged users may override these locks.
- If any locks are taken, shutdown and sleep state requests will normally fail (unless privileged)
- and a list of active locks is printed.
- However, if no is specified or auto is specified on a
- non-interactive requests, the established locks are ignored and not shown, and the operation
- attempted anyway, possibly requiring additional privileges.
- May be overridden by .
+ yes for interactive invocations (i.e. from a TTY) and no for
+ non-interactive invocations. yes lets the request respect inhibitor locks.
+ no lets the request ignore inhibitor locks.
+
+ Applications can establish inhibitor locks to prevent certain important operations (such as
+ CD burning) from being interrupted by system shutdown or sleep. Any user may take these locks and
+ privileged users may override these locks. If any locks are taken, shutdown and sleep state
+ requests will normally fail (unless privileged). However, if no is specified or
+ auto is specified on a non-interactive requests, the operation will be
+ attempted. If locks are present, the operation may require additional privileges.
+
+ Option provides another way to override inhibitors.
diff --git a/src/login/logind-action.c b/src/login/logind-action.c
index 6a873009bc0..c6a36a1556c 100644
--- a/src/login/logind-action.c
+++ b/src/login/logind-action.c
@@ -129,15 +129,15 @@ int manager_handle_action(
bool is_edge) {
static const char * const message_table[_HANDLE_ACTION_MAX] = {
- [HANDLE_POWEROFF] = "Powering Off...",
- [HANDLE_REBOOT] = "Rebooting...",
- [HANDLE_HALT] = "Halting...",
- [HANDLE_KEXEC] = "Rebooting via kexec...",
- [HANDLE_SUSPEND] = "Suspending...",
- [HANDLE_HIBERNATE] = "Hibernating...",
- [HANDLE_HYBRID_SLEEP] = "Hibernating and suspending...",
+ [HANDLE_POWEROFF] = "Powering off...",
+ [HANDLE_REBOOT] = "Rebooting...",
+ [HANDLE_HALT] = "Halting...",
+ [HANDLE_KEXEC] = "Rebooting via kexec...",
+ [HANDLE_SUSPEND] = "Suspending...",
+ [HANDLE_HIBERNATE] = "Hibernating...",
+ [HANDLE_HYBRID_SLEEP] = "Hibernating and suspending...",
[HANDLE_SUSPEND_THEN_HIBERNATE] = "Suspending, then hibernating...",
- [HANDLE_FACTORY_RESET] = "Performing factory reset...",
+ [HANDLE_FACTORY_RESET] = "Performing factory reset...",
};
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -251,18 +251,34 @@ int manager_handle_action(
return 1;
}
+static const char* const handle_action_verb_table[_HANDLE_ACTION_MAX] = {
+ [HANDLE_IGNORE] = "do nothing",
+ [HANDLE_POWEROFF] = "power off",
+ [HANDLE_REBOOT] = "reboot",
+ [HANDLE_HALT] = "halt",
+ [HANDLE_KEXEC] = "kexec",
+ [HANDLE_SUSPEND] = "suspend",
+ [HANDLE_HIBERNATE] = "hibernate",
+ [HANDLE_HYBRID_SLEEP] = "enter hybrid sleep",
+ [HANDLE_SUSPEND_THEN_HIBERNATE] = "suspend and later hibernate",
+ [HANDLE_FACTORY_RESET] = "perform a factory reset",
+ [HANDLE_LOCK] = "be locked",
+};
+
+DEFINE_STRING_TABLE_LOOKUP_TO_STRING(handle_action_verb, HandleAction);
+
static const char* const handle_action_table[_HANDLE_ACTION_MAX] = {
- [HANDLE_IGNORE] = "ignore",
- [HANDLE_POWEROFF] = "poweroff",
- [HANDLE_REBOOT] = "reboot",
- [HANDLE_HALT] = "halt",
- [HANDLE_KEXEC] = "kexec",
- [HANDLE_SUSPEND] = "suspend",
- [HANDLE_HIBERNATE] = "hibernate",
- [HANDLE_HYBRID_SLEEP] = "hybrid-sleep",
+ [HANDLE_IGNORE] = "ignore",
+ [HANDLE_POWEROFF] = "poweroff",
+ [HANDLE_REBOOT] = "reboot",
+ [HANDLE_HALT] = "halt",
+ [HANDLE_KEXEC] = "kexec",
+ [HANDLE_SUSPEND] = "suspend",
+ [HANDLE_HIBERNATE] = "hibernate",
+ [HANDLE_HYBRID_SLEEP] = "hybrid-sleep",
[HANDLE_SUSPEND_THEN_HIBERNATE] = "suspend-then-hibernate",
- [HANDLE_FACTORY_RESET] = "factory-reset",
- [HANDLE_LOCK] = "lock",
+ [HANDLE_FACTORY_RESET] = "factory-reset",
+ [HANDLE_LOCK] = "lock",
};
DEFINE_STRING_TABLE_LOOKUP(handle_action, HandleAction);
diff --git a/src/login/logind-action.h b/src/login/logind-action.h
index c891787e6cd..9a01af16908 100644
--- a/src/login/logind-action.h
+++ b/src/login/logind-action.h
@@ -49,6 +49,8 @@ int manager_handle_action(
bool ignore_inhibited,
bool is_edge);
+const char* handle_action_verb_to_string(HandleAction h) _const_;
+
const char* handle_action_to_string(HandleAction h) _const_;
HandleAction handle_action_from_string(const char *s) _pure_;
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index c40d8defaf1..031b96e9f15 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -1888,9 +1888,11 @@ static int method_do_shutdown_or_sleep(
if (r < 0)
return r;
if ((flags & ~SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC) != 0)
- return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter");
+ return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS,
+ "Invalid flags parameter");
if (a->handle != HANDLE_REBOOT && (flags & SD_LOGIND_REBOOT_VIA_KEXEC))
- return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Reboot via kexec is only applicable with reboot operations");
+ return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS,
+ "Reboot via kexec is only applicable with reboot operations");
} else {
/* Old style method: no flags parameter, but interactive bool passed as boolean in
* payload. Let's convert this argument to the new-style flags parameter for our internal
@@ -1919,7 +1921,8 @@ static int method_do_shutdown_or_sleep(
"Not enough swap space for hibernation");
if (r == 0)
return sd_bus_error_setf(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED,
- "Sleep verb \"%s\" not supported", sleep_operation_to_string(a->sleep_operation));
+ "Sleep verb \"%s\" not supported",
+ sleep_operation_to_string(a->sleep_operation));
if (r < 0)
return r;
}
@@ -2355,7 +2358,7 @@ static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userd
}
username = uid_to_name(uid);
- utmp_wall("The system shutdown has been cancelled",
+ utmp_wall("System shutdown has been cancelled",
username, tty, logind_wall_tty_filter, m);
}
diff --git a/src/login/logind-utmp.c b/src/login/logind-utmp.c
index 7d761a0d674..36a3fcd0e93 100644
--- a/src/login/logind-utmp.c
+++ b/src/login/logind-utmp.c
@@ -21,9 +21,6 @@
#include "utmp-wtmp.h"
_const_ static usec_t when_wall(usec_t n, usec_t elapse) {
-
- usec_t left;
- unsigned i;
static const int wall_timers[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
25, 40, 55, 70, 100, 130, 150, 180,
@@ -33,9 +30,9 @@ _const_ static usec_t when_wall(usec_t n, usec_t elapse) {
if (n >= elapse)
return 0;
- left = elapse - n;
+ usec_t left = elapse - n;
- for (i = 1; i < ELEMENTSOF(wall_timers); i++)
+ for (unsigned i = 1; i < ELEMENTSOF(wall_timers); i++)
if (wall_timers[i] * USEC_PER_MINUTE >= left)
return left - wall_timers[i-1] * USEC_PER_MINUTE;
@@ -67,8 +64,6 @@ bool logind_wall_tty_filter(const char *tty, bool is_local, void *userdata) {
}
static int warn_wall(Manager *m, usec_t n) {
- _cleanup_free_ char *l = NULL, *username = NULL;
- usec_t left;
int r;
assert(m);
@@ -76,13 +71,15 @@ static int warn_wall(Manager *m, usec_t n) {
if (!m->enable_wall_messages || !m->scheduled_shutdown_action)
return 0;
- left = m->scheduled_shutdown_timeout > n;
+ usec_t left = m->scheduled_shutdown_timeout > n;
- r = asprintf(&l, "%s%sThe system is going down for %s %s%s!",
+ _cleanup_free_ char *l = NULL, *username = NULL;
+
+ r = asprintf(&l, "%s%sThe system will %s %s%s!",
strempty(m->wall_message),
isempty(m->wall_message) ? "" : "\n",
- handle_action_to_string(m->scheduled_shutdown_action->handle),
- left ? "at " : "NOW",
+ handle_action_verb_to_string(m->scheduled_shutdown_action->handle),
+ left ? "at " : "now",
left ? FORMAT_TIMESTAMP(m->scheduled_shutdown_timeout) : "");
if (r < 0) {
log_oom();
@@ -100,20 +97,18 @@ static int wall_message_timeout_handler(
uint64_t usec,
void *userdata) {
- Manager *m = userdata;
- usec_t n, next;
+ Manager *m = ASSERT_PTR(userdata);
int r;
- assert(m);
assert(s == m->wall_message_timeout_source);
- n = now(CLOCK_REALTIME);
+ usec_t n = now(CLOCK_REALTIME);
r = warn_wall(m, n);
if (r == 0)
return 0;
- next = when_wall(n, m->scheduled_shutdown_timeout);
+ usec_t next = when_wall(n, m->scheduled_shutdown_timeout);
if (next > 0) {
r = sd_event_source_set_time(s, n + next);
if (r < 0)
@@ -128,14 +123,12 @@ static int wall_message_timeout_handler(
}
int manager_setup_wall_message_timer(Manager *m) {
-
- usec_t n, elapse;
int r;
assert(m);
- n = now(CLOCK_REALTIME);
- elapse = m->scheduled_shutdown_timeout;
+ usec_t n = now(CLOCK_REALTIME);
+ usec_t elapse = m->scheduled_shutdown_timeout;
/* wall message handling */
diff --git a/src/login/logind.c b/src/login/logind.c
index 0483902edd9..aa854805484 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -972,7 +972,7 @@ static int manager_dispatch_idle_action(sd_event_source *s, uint64_t t, void *us
if (n >= since.monotonic + m->idle_action_usec &&
(m->idle_action_not_before_usec <= 0 || n >= m->idle_action_not_before_usec + m->idle_action_usec)) {
- log_info("System idle. Doing %s operation.", handle_action_to_string(m->idle_action));
+ log_info("System idle. Will %s now.", handle_action_verb_to_string(m->idle_action));
manager_handle_action(m, 0, m->idle_action, false, false);
m->idle_action_not_before_usec = n;
diff --git a/src/shared/pager.c b/src/shared/pager.c
index 1a93deb6284..dc717cd1fe8 100644
--- a/src/shared/pager.c
+++ b/src/shared/pager.c
@@ -219,31 +219,30 @@ void pager_open(PagerFlags flags) {
/* Debian's alternatives command for pagers is called 'pager'. Note that we do not call
* sensible-pagers here, since that is just a shell script that implements a logic that is
* similar to this one anyway, but is Debian-specific. */
- FOREACH_STRING(exe, "pager", "less", "more") {
- /* Only less implements secure mode right now. */
- if (use_secure_mode && !streq(exe, "less"))
+ static const char* pagers[] = { "pager", "less", "more", "(built-in)" };
+
+ for (unsigned i = 0; i < ELEMENTSOF(pagers); i++) {
+ /* Only less (and our trivial fallback) implement secure mode right now. */
+ if (use_secure_mode && !STR_IN_SET(pagers[i], "less", "(built-in)"))
continue;
- r = loop_write(exe_name_pipe[1], exe, strlen(exe) + 1, false);
- if (r < 0) {
+ r = loop_write(exe_name_pipe[1], pagers[i], strlen(pagers[i]) + 1, false);
+ if (r < 0) {
log_error_errno(r, "Failed to write pager name to socket: %m");
_exit(EXIT_FAILURE);
}
- execlp(exe, exe, NULL);
- log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno,
- "Failed to execute '%s', using next fallback pager: %m", exe);
- }
- /* Our builtin is also very secure. */
- r = loop_write(exe_name_pipe[1], "(built-in)", strlen("(built-in)") + 1, false);
- if (r < 0) {
- log_error_errno(r, "Failed to write pager name to socket: %m");
- _exit(EXIT_FAILURE);
+ if (i < ELEMENTSOF(pagers) - 1) {
+ execlp(pagers[i], pagers[i], NULL);
+ log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno,
+ "Failed to execute '%s', will try '%s' next: %m", pagers[i], pagers[i+1]);
+ } else {
+ /* Close pipe to signal the parent to start sending data */
+ safe_close_pair(exe_name_pipe);
+ pager_fallback();
+ assert_not_reached();
+ }
}
- /* Close pipe to signal the parent to start sending data */
- safe_close_pair(exe_name_pipe);
- pager_fallback();
- /* not reached */
}
/* Return in the parent */
diff --git a/src/systemctl/systemctl-logind.c b/src/systemctl/systemctl-logind.c
index 40521b85954..1c3b68f09f1 100644
--- a/src/systemctl/systemctl-logind.c
+++ b/src/systemctl/systemctl-logind.c
@@ -15,17 +15,12 @@
#include "terminal-util.h"
#include "user-util.h"
-int logind_set_wall_message(void) {
+static int logind_set_wall_message(sd_bus *bus) {
#if ENABLE_LOGIND
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- sd_bus *bus;
_cleanup_free_ char *m = NULL;
int r;
- r = acquire_bus(BUS_FULL, &bus);
- if (r < 0)
- return r;
-
m = strv_join(arg_wall, " ");
if (!m)
return log_oom();
@@ -44,27 +39,23 @@ int logind_set_wall_message(void) {
/* Ask systemd-logind, which might grant access to unprivileged users through polkit */
int logind_reboot(enum action a) {
#if ENABLE_LOGIND
- static const struct {
- const char *method;
- const char *description;
- } actions[_ACTION_MAX] = {
- [ACTION_POWEROFF] = { "PowerOff", "power off system" },
- [ACTION_REBOOT] = { "Reboot", "reboot system" },
- [ACTION_KEXEC] = { "Reboot", "kexec reboot system" },
- [ACTION_HALT] = { "Halt", "halt system" },
- [ACTION_SUSPEND] = { "Suspend", "suspend system" },
- [ACTION_HIBERNATE] = { "Hibernate", "hibernate system" },
- [ACTION_HYBRID_SLEEP] = { "HybridSleep", "put system into hybrid sleep" },
- [ACTION_SUSPEND_THEN_HIBERNATE] = { "SuspendThenHibernate", "suspend system, hibernate later" },
+ static const char* actions[_ACTION_MAX] = {
+ [ACTION_POWEROFF] = "PowerOff",
+ [ACTION_REBOOT] = "Reboot",
+ [ACTION_KEXEC] = "Reboot",
+ [ACTION_HALT] = "Halt",
+ [ACTION_SUSPEND] = "Suspend",
+ [ACTION_HIBERNATE] = "Hibernate",
+ [ACTION_HYBRID_SLEEP] = "HybridSleep",
+ [ACTION_SUSPEND_THEN_HIBERNATE] = "SuspendThenHibernate",
};
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- const char *method_with_flags;
uint64_t flags = 0;
sd_bus *bus;
int r;
- if (a < 0 || a >= _ACTION_MAX || !actions[a].method)
+ if (a < 0 || a >= _ACTION_MAX || !actions[a])
return -EINVAL;
r = acquire_bus(BUS_FULL, &bus);
@@ -72,9 +63,12 @@ int logind_reboot(enum action a) {
return r;
polkit_agent_open_maybe();
- (void) logind_set_wall_message();
+ (void) logind_set_wall_message(bus);
- log_debug("%s org.freedesktop.login1.Manager %s dbus call.", arg_dry_run ? "Would execute" : "Executing", actions[a].method);
+ const char *method_with_flags = strjoina(actions[a], "WithFlags");
+
+ log_debug("%s org.freedesktop.login1.Manager %s dbus call.",
+ arg_dry_run ? "Would execute" : "Executing", method_with_flags);
if (arg_dry_run)
return 0;
@@ -82,21 +76,19 @@ int logind_reboot(enum action a) {
SET_FLAG(flags, SD_LOGIND_ROOT_CHECK_INHIBITORS, arg_check_inhibitors > 0);
SET_FLAG(flags, SD_LOGIND_REBOOT_VIA_KEXEC, a == ACTION_KEXEC);
- method_with_flags = strjoina(actions[a].method, "WithFlags");
-
r = bus_call_method(bus, bus_login_mgr, method_with_flags, &error, NULL, "t", flags);
if (r >= 0)
return 0;
if (!sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD))
- return log_error_errno(r, "Failed to %s via logind: %s", actions[a].description, bus_error_message(&error, r));
+ return log_error_errno(r, "Call to %s failed: %s", actions[a], bus_error_message(&error, r));
- /* Fallback to original methods in case there is older version of systemd-logind */
- log_debug("Method %s not available: %s. Falling back to %s", method_with_flags, bus_error_message(&error, r), actions[a].method);
+ /* Fall back to original methods in case there is an older version of systemd-logind */
+ log_debug("Method %s not available: %s. Falling back to %s", method_with_flags, bus_error_message(&error, r), actions[a]);
sd_bus_error_free(&error);
- r = bus_call_method(bus, bus_login_mgr, actions[a].method, &error, NULL, "b", arg_ask_password);
+ r = bus_call_method(bus, bus_login_mgr, actions[a], &error, NULL, "b", arg_ask_password);
if (r < 0)
- return log_error_errno(r, "Failed to %s via logind: %s", actions[a].description, bus_error_message(&error, r));
+ return log_error_errno(r, "Call to %s failed: %s", actions[a], bus_error_message(&error, r));
return 0;
#else
@@ -310,7 +302,7 @@ int logind_schedule_shutdown(void) {
if (arg_dry_run)
action = strjoina("dry-", action);
- (void) logind_set_wall_message();
+ (void) logind_set_wall_message(bus);
r = bus_call_method(bus, bus_login_mgr, "ScheduleShutdown", &error, NULL, "st", action, arg_when);
if (r < 0)
@@ -336,7 +328,7 @@ int logind_cancel_shutdown(void) {
if (r < 0)
return r;
- (void) logind_set_wall_message();
+ (void) logind_set_wall_message(bus);
r = bus_call_method(bus, bus_login_mgr, "CancelScheduledShutdown", &error, NULL, NULL);
if (r < 0)
diff --git a/src/systemctl/systemctl-logind.h b/src/systemctl/systemctl-logind.h
index 6e73cb76252..925f4559c1b 100644
--- a/src/systemctl/systemctl-logind.h
+++ b/src/systemctl/systemctl-logind.h
@@ -3,8 +3,6 @@
#include "systemctl.h"
-int logind_set_wall_message(void);
-
int logind_reboot(enum action a);
int logind_check_inhibitors(enum action a);
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 97ec51b7d94..d1cb4b70033 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -257,8 +257,8 @@ static int systemctl_help(void) {
" --show-types When showing sockets, explicitly show their type\n"
" --value When showing properties, only print the value\n"
" --check-inhibitors=MODE\n"
- " Specify if checking inhibitors before shutting down,\n"
- " sleeping or hibernating\n"
+ " Whether to check inhibitors before shutting down,\n"
+ " sleeping, or hibernating\n"
" -i Shortcut for --check-inhibitors=no\n"
" --kill-who=WHO Whom to send signal to\n"
" -s --signal=SIGNAL Which signal to send\n"
diff --git a/test/test-shutdown.py b/test/test-shutdown.py
index 77ac3a7d9fb..060a0e651af 100755
--- a/test/test-shutdown.py
+++ b/test/test-shutdown.py
@@ -54,7 +54,7 @@ def run(args):
console.send('0')
logger.info("verify broadcast message")
console.expect('Broadcast message from root@H on %s' % pty, 2)
- console.expect('The system is going down for reboot at %s' % date, 2)
+ console.expect('The system will reboot at %s' % date, 2)
logger.info("check show output")
console.sendline('shutdown --show')
@@ -64,13 +64,13 @@ def run(args):
console.sendline('shutdown -c')
console.sendcontrol('a')
console.send('1')
- console.expect('The system shutdown has been cancelled', 2)
+ console.expect('System shutdown has been cancelled', 2)
logger.info("call for reboot")
console.sendline('sleep 10; shutdown -r now')
console.sendcontrol('a')
console.send('0')
- console.expect("The system is going down for reboot NOW!", 12)
+ console.expect("The system will reboot now!", 12)
logger.info("waiting for reboot")