diff options
author | Mike Yuan <me@yhndnzj.com> | 2023-03-05 23:27:44 +0800 |
---|---|---|
committer | Mike Yuan <me@yhndnzj.com> | 2023-03-14 19:21:11 +0800 |
commit | 1433e1f998465b7acf472c73d58c14e7e2eb3f13 (patch) | |
tree | 89ffc9ccc34b5a6b8f56069106e78b4e1bd9b5d6 /src/systemctl | |
parent | 92b00e867844948bdf559758739343c4308570c0 (diff) | |
download | systemd-1433e1f998465b7acf472c73d58c14e7e2eb3f13.tar.gz |
systemctl: add option --when for scheduled shutdown
Pass an empty string or "cancel" will cancel the action.
Pass "show" will show the scheduled actions.
Replaces #17258
Diffstat (limited to 'src/systemctl')
-rw-r--r-- | src/systemctl/systemctl-logind.c | 26 | ||||
-rw-r--r-- | src/systemctl/systemctl-start-special.c | 33 | ||||
-rw-r--r-- | src/systemctl/systemctl.c | 28 |
3 files changed, 66 insertions, 21 deletions
diff --git a/src/systemctl/systemctl-logind.c b/src/systemctl/systemctl-logind.c index 068f54e18b..fd8ca09de8 100644 --- a/src/systemctl/systemctl-logind.c +++ b/src/systemctl/systemctl-logind.c @@ -356,7 +356,7 @@ int logind_show_shutdown(void) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; sd_bus *bus; - const char *action = NULL; + const char *action, *pretty_action; uint64_t elapse; int r; @@ -376,17 +376,23 @@ int logind_show_shutdown(void) { return log_error_errno(SYNTHETIC_ERRNO(ENODATA), "No scheduled shutdown."); if (STR_IN_SET(action, "halt", "poweroff", "exit")) - action = "Shutdown"; + pretty_action = "Shutdown"; else if (streq(action, "kexec")) - action = "Reboot via kexec"; + pretty_action = "Reboot via kexec"; else if (streq(action, "reboot")) - action = "Reboot"; - - /* If we don't recognize the action string, we'll show it as-is */ - - log_info("%s scheduled for %s, use 'shutdown -c' to cancel.", - action, - FORMAT_TIMESTAMP_STYLE(elapse, arg_timestamp_style)); + pretty_action = "Reboot"; + else /* If we don't recognize the action string, we'll show it as-is */ + pretty_action = action; + + if (arg_action == ACTION_SYSTEMCTL) + log_info("%s scheduled for %s, use 'systemctl %s --when=cancel' to cancel.", + pretty_action, + FORMAT_TIMESTAMP_STYLE(elapse, arg_timestamp_style), + action); + else + log_info("%s scheduled for %s, use 'shutdown -c' to cancel.", + pretty_action, + FORMAT_TIMESTAMP_STYLE(elapse, arg_timestamp_style)); return 0; #else diff --git a/src/systemctl/systemctl-start-special.c b/src/systemctl/systemctl-start-special.c index 1c50adff6e..93432953b0 100644 --- a/src/systemctl/systemctl-start-special.c +++ b/src/systemctl/systemctl-start-special.c @@ -197,22 +197,33 @@ int verb_start_special(int argc, char *argv[], void *userdata) { ACTION_POWEROFF, ACTION_REBOOT, ACTION_KEXEC, - ACTION_HALT, - ACTION_SUSPEND, - ACTION_HIBERNATE, - ACTION_HYBRID_SLEEP, - ACTION_SUSPEND_THEN_HIBERNATE)) { - - r = logind_reboot(a); - if (r >= 0) - return r; - if (IN_SET(r, -EACCES, -EOPNOTSUPP, -EINPROGRESS)) - /* Requested operation requires auth, is not supported or already in progress */ + ACTION_HALT)) { + + if (arg_when == 0) + r = logind_reboot(a); + else if (arg_when != USEC_INFINITY) + r = logind_schedule_shutdown(a); + else /* arg_when == USEC_INFINITY */ + r = logind_cancel_shutdown(); + if (r >= 0 || IN_SET(r, -EACCES, -EOPNOTSUPP, -EINPROGRESS)) + /* The latter indicates that the requested operation requires auth, + * is not supported or already in progress, in which cases we ignore the error. */ return r; /* On all other errors, try low-level operation. In order to minimize the difference * between operation with and without logind, we explicitly enable non-blocking mode * for this, as logind's shutdown operations are always non-blocking. */ + arg_no_block = true; + + } else if (IN_SET(a, + ACTION_SUSPEND, + ACTION_HIBERNATE, + ACTION_HYBRID_SLEEP, + ACTION_SUSPEND_THEN_HIBERNATE)) { + + r = logind_reboot(a); + if (r >= 0 || IN_SET(r, -EACCES, -EOPNOTSUPP, -EINPROGRESS)) + return r; arg_no_block = true; diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 862edada08..1a5beabc72 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -323,6 +323,8 @@ static int systemctl_help(void) { " --mkdir Create directory before mounting, if missing\n" " --marked Restart/reload previously marked units\n" " --drop-in=NAME Edit unit files using the specified drop-in file name\n" + " --when=TIME Schedule halt/power-off/reboot/kexec action after\n" + " a certain timestamp\n" "\nSee the %2$s for details.\n", program_invocation_short_name, link, @@ -447,6 +449,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { ARG_MARKED, ARG_NO_WARN, ARG_DROP_IN, + ARG_WHEN, }; static const struct option options[] = { @@ -511,6 +514,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { { "mkdir", no_argument, NULL, ARG_MKDIR }, { "marked", no_argument, NULL, ARG_MARKED }, { "drop-in", required_argument, NULL, ARG_DROP_IN }, + { "when", required_argument, NULL, ARG_WHEN }, {} }; @@ -975,6 +979,30 @@ static int systemctl_parse_argv(int argc, char *argv[]) { arg_drop_in = optarg; break; + case ARG_WHEN: + if (streq(optarg, "show")) { + r = logind_show_shutdown(); + if (r < 0 && r != -ENODATA) + return r; + + return 0; + } + + if (STR_IN_SET(optarg, "", "cancel")) { + arg_when = USEC_INFINITY; + break; + } + + r = parse_timestamp(optarg, &arg_when); + if (r < 0) + return log_error_errno(r, "Failed to parse --when= argument '%s': %m", optarg); + + if (!timestamp_is_set(arg_when)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Invalid timestamp '%s' specified for --when=.", optarg); + + break; + case '.': /* Output an error mimicking getopt, and print a hint afterwards */ log_error("%s: invalid option -- '.'", program_invocation_name); |