From 5b3562898af7ca5bb80208f046b26a27111f0708 Mon Sep 17 00:00:00 2001 From: Mike Yuan Date: Fri, 3 Nov 2023 21:25:42 +0800 Subject: [PATCH] systemctl: add support for Sleep() logind call --- man/systemctl.xml | 18 ++++++++++++++++++ src/systemctl/systemctl-logind.c | 5 +++-- src/systemctl/systemctl-start-special.c | 3 +++ src/systemctl/systemctl-start-unit.c | 3 +++ src/systemctl/systemctl.c | 4 ++++ src/systemctl/systemctl.h | 1 + 6 files changed, 32 insertions(+), 2 deletions(-) diff --git a/man/systemctl.xml b/man/systemctl.xml index 1d791b44fd3..6029434ae6b 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -1755,6 +1755,24 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err + + sleep + + + Put the system to sleep, through suspend, hibernate, + hybrid-sleep, or suspend-then-hibernate. The sleep operation + to use is automatically selected by + systemd-logind.service8. + By default, suspend-then-hibernate is used, and falls back to suspend + and then hibernate if not supported. Refer to SleepOperation= + setting in logind.conf5 + for more details. This command is asynchronous, and will return after the sleep operation is + successfully enqueued. It will not wait for the sleep/resume cycle to complete. + + + + + suspend diff --git a/src/systemctl/systemctl-logind.c b/src/systemctl/systemctl-logind.c index 268e528856a..2e35413b5fd 100644 --- a/src/systemctl/systemctl-logind.c +++ b/src/systemctl/systemctl-logind.c @@ -51,6 +51,7 @@ int logind_reboot(enum action a) { [ACTION_HIBERNATE] = "Hibernate", [ACTION_HYBRID_SLEEP] = "HybridSleep", [ACTION_SUSPEND_THEN_HIBERNATE] = "SuspendThenHibernate", + [ACTION_SLEEP] = "Sleep", }; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; @@ -71,7 +72,7 @@ int logind_reboot(enum action a) { polkit_agent_open_maybe(); (void) logind_set_wall_message(bus); - const char *method_with_flags = strjoina(actions[a], "WithFlags"); + const char *method_with_flags = a == ACTION_SLEEP ? actions[a] : strjoina(actions[a], "WithFlags"); log_debug("%s org.freedesktop.login1.Manager %s dbus call.", arg_dry_run ? "Would execute" : "Executing", method_with_flags); @@ -103,7 +104,7 @@ int logind_reboot(enum action a) { } if (r >= 0) return 0; - if (!sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) + if (!sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD) || a == ACTION_SLEEP) return log_error_errno(r, "Call to %s failed: %s", actions[a], bus_error_message(&error, r)); /* Fall back to original methods in case there is an older version of systemd-logind */ diff --git a/src/systemctl/systemctl-start-special.c b/src/systemctl/systemctl-start-special.c index d93bffb7591..2cf746c5a60 100644 --- a/src/systemctl/systemctl-start-special.c +++ b/src/systemctl/systemctl-start-special.c @@ -229,6 +229,9 @@ int verb_start_special(int argc, char *argv[], void *userdata) { arg_no_block = true; break; + case ACTION_SLEEP: + return logind_reboot(a); + case ACTION_EXIT: /* Since exit is so close in behaviour to power-off/reboot, let's also make * it asynchronous, in order to not confuse the user needlessly with unexpected diff --git a/src/systemctl/systemctl-start-unit.c b/src/systemctl/systemctl-start-unit.c index 6927e977479..ae7e25eedb6 100644 --- a/src/systemctl/systemctl-start-unit.c +++ b/src/systemctl/systemctl-start-unit.c @@ -236,6 +236,7 @@ const struct action_metadata action_table[_ACTION_MAX] = { [ACTION_HIBERNATE] = { SPECIAL_HIBERNATE_TARGET, "hibernate", "replace-irreversibly" }, [ACTION_HYBRID_SLEEP] = { SPECIAL_HYBRID_SLEEP_TARGET, "hybrid-sleep", "replace-irreversibly" }, [ACTION_SUSPEND_THEN_HIBERNATE] = { SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET, "suspend-then-hibernate", "replace-irreversibly" }, + [ACTION_SLEEP] = { NULL, /* handled only by logind */ "sleep", NULL }, }; enum action verb_to_action(const char *verb) { @@ -294,6 +295,8 @@ int verb_start(int argc, char *argv[], void *userdata) { action = verb_to_action(argv[0]); + assert(action != ACTION_SLEEP); + if (action != _ACTION_INVALID) { /* A command in style "systemctl reboot", "systemctl poweroff", … */ method = "StartUnit"; diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index dd6f6c9873e..0fa672eb905 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -249,6 +249,8 @@ static int systemctl_help(void) { " soft-reboot Shut down and reboot userspace\n" " exit [EXIT_CODE] Request user instance or container exit\n" " switch-root [ROOT [INIT]] Change to a different root file system\n" + " sleep Put the system to sleep (through one of\n" + " the operations below)\n" " suspend Suspend the system\n" " hibernate Hibernate the system\n" " hybrid-sleep Hibernate and suspend the system\n" @@ -1179,6 +1181,7 @@ static int systemctl_main(int argc, char *argv[]) { { "reboot", VERB_ANY, 1, VERB_ONLINE_ONLY, verb_start_system_special }, { "kexec", VERB_ANY, 1, VERB_ONLINE_ONLY, verb_start_system_special }, { "soft-reboot", VERB_ANY, 1, VERB_ONLINE_ONLY, verb_start_system_special }, + { "sleep", VERB_ANY, 1, VERB_ONLINE_ONLY, verb_start_system_special }, { "suspend", VERB_ANY, 1, VERB_ONLINE_ONLY, verb_start_system_special }, { "hibernate", VERB_ANY, 1, VERB_ONLINE_ONLY, verb_start_system_special }, { "hybrid-sleep", VERB_ANY, 1, VERB_ONLINE_ONLY, verb_start_system_special }, @@ -1323,6 +1326,7 @@ static int run(int argc, char *argv[]) { break; case ACTION_EXIT: + case ACTION_SLEEP: case ACTION_SUSPEND: case ACTION_HIBERNATE: case ACTION_HYBRID_SLEEP: diff --git a/src/systemctl/systemctl.h b/src/systemctl/systemctl.h index e8ba8f76a07..a42fc36a2e4 100644 --- a/src/systemctl/systemctl.h +++ b/src/systemctl/systemctl.h @@ -18,6 +18,7 @@ enum action { ACTION_KEXEC, ACTION_SOFT_REBOOT, ACTION_EXIT, + ACTION_SLEEP, ACTION_SUSPEND, ACTION_HIBERNATE, ACTION_HYBRID_SLEEP, -- 2.47.3