diff options
author | Mario Limonciello <superm1@gmail.com> | 2018-03-08 21:17:33 +0800 |
---|---|---|
committer | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2018-03-08 14:17:33 +0100 |
commit | c58493c00af97146d3b6c24da9c0371978124703 (patch) | |
tree | eef8dce2e68194b33df3faec0631bee8543a175b /src | |
parent | fc17f194ded93b51899aa0bbd4e66870d975fe5a (diff) | |
download | systemd-c58493c00af97146d3b6c24da9c0371978124703.tar.gz |
Introduce suspend-to-hibernate (#8274)
Suspend to Hibernate is a new sleep method that invokes suspend
for a predefined period of time before automatically waking up
and hibernating the system.
It's similar to HybridSleep however there isn't a performance
impact on every suspend cycle.
It's intended to use with systems that may have a higher power
drain in their supported suspend states to prevent battery and
data loss over an extended suspend cycle.
Signed-off-by: Mario Limonciello <mario.limonciello@dell.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/basic/special.h | 1 | ||||
-rw-r--r-- | src/login/logind-action.c | 13 | ||||
-rw-r--r-- | src/login/logind-action.h | 1 | ||||
-rw-r--r-- | src/login/logind-dbus.c | 29 | ||||
-rw-r--r-- | src/login/org.freedesktop.login1.conf | 8 | ||||
-rw-r--r-- | src/shared/sleep-config.c | 54 | ||||
-rw-r--r-- | src/shared/sleep-config.h | 4 | ||||
-rw-r--r-- | src/sleep/sleep.c | 94 | ||||
-rw-r--r-- | src/systemctl/systemctl.c | 46 | ||||
-rw-r--r-- | src/test/test-sleep.c | 1 |
10 files changed, 219 insertions, 32 deletions
diff --git a/src/basic/special.h b/src/basic/special.h index c058b1d852..81078ffee9 100644 --- a/src/basic/special.h +++ b/src/basic/special.h @@ -37,6 +37,7 @@ #define SPECIAL_SUSPEND_TARGET "suspend.target" #define SPECIAL_HIBERNATE_TARGET "hibernate.target" #define SPECIAL_HYBRID_SLEEP_TARGET "hybrid-sleep.target" +#define SPECIAL_SUSPEND_TO_HIBERNATE_TARGET "suspend-to-hibernate.target" /* Special boot targets */ #define SPECIAL_RESCUE_TARGET "rescue.target" diff --git a/src/login/logind-action.c b/src/login/logind-action.c index 852ea9f949..0e8e0b2e4a 100644 --- a/src/login/logind-action.c +++ b/src/login/logind-action.c @@ -47,7 +47,8 @@ int manager_handle_action( [HANDLE_KEXEC] = "Rebooting via kexec...", [HANDLE_SUSPEND] = "Suspending...", [HANDLE_HIBERNATE] = "Hibernating...", - [HANDLE_HYBRID_SLEEP] = "Hibernating and suspending..." + [HANDLE_HYBRID_SLEEP] = "Hibernating and suspending...", + [HANDLE_SUSPEND_TO_HIBERNATE] = "Suspending to hibernate...", }; static const char * const target_table[_HANDLE_ACTION_MAX] = { @@ -57,7 +58,8 @@ int manager_handle_action( [HANDLE_KEXEC] = SPECIAL_KEXEC_TARGET, [HANDLE_SUSPEND] = SPECIAL_SUSPEND_TARGET, [HANDLE_HIBERNATE] = SPECIAL_HIBERNATE_TARGET, - [HANDLE_HYBRID_SLEEP] = SPECIAL_HYBRID_SLEEP_TARGET + [HANDLE_HYBRID_SLEEP] = SPECIAL_HYBRID_SLEEP_TARGET, + [HANDLE_SUSPEND_TO_HIBERNATE] = SPECIAL_SUSPEND_TO_HIBERNATE_TARGET, }; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; @@ -110,6 +112,8 @@ int manager_handle_action( supported = can_sleep("hibernate") > 0; else if (handle == HANDLE_HYBRID_SLEEP) supported = can_sleep("hybrid-sleep") > 0; + else if (handle == HANDLE_SUSPEND_TO_HIBERNATE) + supported = can_sleep("suspend-to-hibernate") > 0; else if (handle == HANDLE_KEXEC) supported = access(KEXEC, X_OK) >= 0; else @@ -125,7 +129,9 @@ int manager_handle_action( return -EALREADY; } - inhibit_operation = IN_SET(handle, HANDLE_SUSPEND, HANDLE_HIBERNATE, HANDLE_HYBRID_SLEEP) ? INHIBIT_SLEEP : INHIBIT_SHUTDOWN; + inhibit_operation = IN_SET(handle, HANDLE_SUSPEND, HANDLE_HIBERNATE, + HANDLE_HYBRID_SLEEP, + HANDLE_SUSPEND_TO_HIBERNATE) ? INHIBIT_SLEEP : INHIBIT_SHUTDOWN; /* If the actual operation is inhibited, warn and fail */ if (!ignore_inhibited && @@ -172,6 +178,7 @@ static const char* const handle_action_table[_HANDLE_ACTION_MAX] = { [HANDLE_SUSPEND] = "suspend", [HANDLE_HIBERNATE] = "hibernate", [HANDLE_HYBRID_SLEEP] = "hybrid-sleep", + [HANDLE_SUSPEND_TO_HIBERNATE] = "suspend-to-hibernate", [HANDLE_LOCK] = "lock" }; diff --git a/src/login/logind-action.h b/src/login/logind-action.h index 8c31ec42be..1ee8c812ff 100644 --- a/src/login/logind-action.h +++ b/src/login/logind-action.h @@ -29,6 +29,7 @@ typedef enum HandleAction { HANDLE_SUSPEND, HANDLE_HIBERNATE, HANDLE_HYBRID_SLEEP, + HANDLE_SUSPEND_TO_HIBERNATE, HANDLE_LOCK, _HANDLE_ACTION_MAX, _HANDLE_ACTION_INVALID = -1 diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 07cb257151..ef5c478fef 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -1933,6 +1933,20 @@ static int method_hybrid_sleep(sd_bus_message *message, void *userdata, sd_bus_e error); } +static int method_suspend_to_hibernate(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + + return method_do_shutdown_or_sleep( + m, message, + SPECIAL_SUSPEND_TO_HIBERNATE_TARGET, + INHIBIT_SLEEP, + "org.freedesktop.login1.hibernate", + "org.freedesktop.login1.hibernate-multiple-sessions", + "org.freedesktop.login1.hibernate-ignore-inhibit", + "hybrid-sleep", + error); +} + static int nologin_timeout_handler( sd_event_source *s, uint64_t usec, @@ -2386,6 +2400,19 @@ static int method_can_hybrid_sleep(sd_bus_message *message, void *userdata, sd_b error); } +static int method_can_suspend_to_hibernate(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + + return method_can_shutdown_or_sleep( + m, message, + INHIBIT_SLEEP, + "org.freedesktop.login1.hibernate", + "org.freedesktop.login1.hibernate-multiple-sessions", + "org.freedesktop.login1.hibernate-ignore-inhibit", + "suspend-to-hibernate", + error); +} + static int property_get_reboot_to_firmware_setup( sd_bus *bus, const char *path, @@ -2706,12 +2733,14 @@ const sd_bus_vtable manager_vtable[] = { SD_BUS_METHOD("Suspend", "b", NULL, method_suspend, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Hibernate", "b", NULL, method_hibernate, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("HybridSleep", "b", NULL, method_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SuspendToHibernate", "b", NULL, method_suspend_to_hibernate, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CanPowerOff", NULL, "s", method_can_poweroff, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CanReboot", NULL, "s", method_can_reboot, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CanHalt", NULL, "s", method_can_halt, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CanSuspend", NULL, "s", method_can_suspend, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CanHibernate", NULL, "s", method_can_hibernate, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CanHybridSleep", NULL, "s", method_can_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("CanSuspendToHibernate", NULL, "s", method_can_suspend_to_hibernate, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("ScheduleShutdown", "st", NULL, method_schedule_shutdown, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CancelScheduledShutdown", NULL, "b", method_cancel_scheduled_shutdown, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Inhibit", "ssss", "h", method_inhibit, SD_BUS_VTABLE_UNPRIVILEGED), diff --git a/src/login/org.freedesktop.login1.conf b/src/login/org.freedesktop.login1.conf index d842411781..970a217df1 100644 --- a/src/login/org.freedesktop.login1.conf +++ b/src/login/org.freedesktop.login1.conf @@ -152,6 +152,10 @@ <allow send_destination="org.freedesktop.login1" send_interface="org.freedesktop.login1.Manager" + send_member="SuspendToHibernate"/> + + <allow send_destination="org.freedesktop.login1" + send_interface="org.freedesktop.login1.Manager" send_member="CanPowerOff"/> <allow send_destination="org.freedesktop.login1" @@ -176,6 +180,10 @@ <allow send_destination="org.freedesktop.login1" send_interface="org.freedesktop.login1.Manager" + send_member="CanSuspendToHibernate"/> + + <allow send_destination="org.freedesktop.login1" + send_interface="org.freedesktop.login1.Manager" send_member="ScheduleShutdown"/> <allow send_destination="org.freedesktop.login1" diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c index ecac98e0ab..feb2c5281d 100644 --- a/src/shared/sleep-config.c +++ b/src/shared/sleep-config.c @@ -3,6 +3,7 @@ This file is part of systemd. Copyright 2013 Zbigniew Jędrzejewski-Szmek + Copyright 2018 Dell Inc. systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -41,13 +42,14 @@ #define USE(x, y) do { (x) = (y); (y) = NULL; } while (0) -int parse_sleep_config(const char *verb, char ***_modes, char ***_states) { +int parse_sleep_config(const char *verb, char ***_modes, char ***_states, usec_t *_delay) { _cleanup_strv_free_ char **suspend_mode = NULL, **suspend_state = NULL, **hibernate_mode = NULL, **hibernate_state = NULL, **hybrid_mode = NULL, **hybrid_state = NULL; char **modes, **states; + usec_t delay; const ConfigTableItem items[] = { { "Sleep", "SuspendMode", config_parse_strv, 0, &suspend_mode }, @@ -56,6 +58,7 @@ int parse_sleep_config(const char *verb, char ***_modes, char ***_states) { { "Sleep", "HibernateState", config_parse_strv, 0, &hibernate_state }, { "Sleep", "HybridSleepMode", config_parse_strv, 0, &hybrid_mode }, { "Sleep", "HybridSleepState", config_parse_strv, 0, &hybrid_state }, + { "Sleep", "HibernateDelaySec", config_parse_sec, 0, &delay}, {} }; @@ -94,18 +97,26 @@ int parse_sleep_config(const char *verb, char ***_modes, char ***_states) { USE(states, hybrid_state); else states = strv_new("disk", NULL); - + } else if (streq(verb, "suspend-to-hibernate")) { + if (delay == 0) + delay = 180 * USEC_PER_MINUTE; } else assert_not_reached("what verb"); - if ((!modes && !streq(verb, "suspend")) || !states) { + if ((!modes && (streq(verb, "hibernate") || streq(verb, "hybrid-sleep"))) || + (!states && !streq(verb, "suspend-to-hibernate"))) { strv_free(modes); strv_free(states); return log_oom(); } - *_modes = modes; - *_states = states; + if (_modes) + *_modes = modes; + if (_states) + *_states = states; + if (_delay) + *_delay = delay; + return 0; } @@ -260,15 +271,44 @@ static bool enough_memory_for_hibernation(void) { return r; } +static bool can_s2h(void) { + int r; + + r = access("/sys/class/rtc/rtc0/wakealarm", W_OK); + if (r < 0) { + log_full(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, + "/sys/class/rct/rct0/wakealarm is not writable %m"); + return false; + } + + r = can_sleep("suspend"); + if (r < 0) { + log_debug_errno(r, "Unable to suspend system."); + return false; + } + + r = can_sleep("hibernate"); + if (r < 0) { + log_debug_errno(r, "Unable to hibernate system."); + return false; + } + + return true; +} + int can_sleep(const char *verb) { _cleanup_strv_free_ char **modes = NULL, **states = NULL; int r; assert(streq(verb, "suspend") || streq(verb, "hibernate") || - streq(verb, "hybrid-sleep")); + streq(verb, "hybrid-sleep") || + streq(verb, "suspend-to-hibernate")); + + if (streq(verb, "suspend-to-hibernate")) + return can_s2h(); - r = parse_sleep_config(verb, &modes, &states); + r = parse_sleep_config(verb, &modes, &states, NULL); if (r < 0) return false; diff --git a/src/shared/sleep-config.h b/src/shared/sleep-config.h index fc5a81d954..3dacda0d80 100644 --- a/src/shared/sleep-config.h +++ b/src/shared/sleep-config.h @@ -20,7 +20,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -int parse_sleep_config(const char *verb, char ***modes, char ***states); +#include "time-util.h" + +int parse_sleep_config(const char *verb, char ***modes, char ***states, usec_t *delay); int can_sleep(const char *verb); int can_sleep_disk(char **types); diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c index 518032ec69..48e7c386f3 100644 --- a/src/sleep/sleep.c +++ b/src/sleep/sleep.c @@ -4,6 +4,7 @@ Copyright 2012 Lennart Poettering Copyright 2013 Zbigniew Jędrzejewski-Szmek + Copyright 2018 Dell Inc. systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -25,12 +26,14 @@ #include "sd-messages.h" +#include "parse-util.h" #include "def.h" #include "exec-util.h" #include "fd-util.h" #include "fileio.h" #include "log.h" #include "sleep-config.h" +#include "stdio-util.h" #include "string-util.h" #include "strv.h" #include "util.h" @@ -135,6 +138,83 @@ static int execute(char **modes, char **states) { return r; } +static int read_wakealarm(uint64_t *result) { + _cleanup_free_ char *t = NULL; + + if (read_one_line_file("/sys/class/rtc/rtc0/since_epoch", &t) >= 0) + return safe_atou64(t, result); + return -EBADF; +} + +static int write_wakealarm(const char *str) { + + _cleanup_fclose_ FILE *f = NULL; + int r; + + f = fopen("/sys/class/rtc/rtc0/wakealarm", "we"); + if (!f) + return log_error_errno(errno, "Failed to open /sys/class/rtc/rtc0/wakealarm: %m"); + + r = write_string_stream(f, str, 0); + if (r < 0) + return log_error_errno(r, "Failed to write '%s' to /sys/class/rtc/rtc0/wakealarm: %m", str); + + return 0; +} + +static int execute_s2h(usec_t hibernate_delay_sec) { + + _cleanup_strv_free_ char **hibernate_modes = NULL, **hibernate_states = NULL, + **suspend_modes = NULL, **suspend_states = NULL; + usec_t orig_time, cmp_time; + char time_str[DECIMAL_STR_MAX(uint64_t)]; + int r; + + r = parse_sleep_config("suspend", &suspend_modes, &suspend_states, + NULL); + if (r < 0) + return r; + + r = parse_sleep_config("hibernate", &hibernate_modes, + &hibernate_states, NULL); + if (r < 0) + return r; + + r = read_wakealarm(&orig_time); + if (r < 0) + return log_error_errno(errno, "Failed to read time: %d", r); + + orig_time += hibernate_delay_sec / USEC_PER_SEC; + xsprintf(time_str, "%" PRIu64, orig_time); + + r = write_wakealarm(time_str); + if (r < 0) + return r; + + log_debug("Set RTC wake alarm for %s", time_str); + + r = execute(suspend_modes, suspend_states); + if (r < 0) + return r; + + r = read_wakealarm(&cmp_time); + if (r < 0) + return log_error_errno(errno, "Failed to read time: %d", r); + + /* reset RTC */ + r = write_wakealarm("0"); + if (r < 0) + return r; + + log_debug("Woke up at %"PRIu64, cmp_time); + + /* if woken up after alarm time, hibernate */ + if (cmp_time >= orig_time) + r = execute(hibernate_modes, hibernate_states); + + return r; +} + static void help(void) { printf("%s COMMAND\n\n" "Suspend the system, hibernate the system, or both.\n\n" @@ -144,6 +224,8 @@ static void help(void) { " suspend Suspend the system\n" " hibernate Hibernate the system\n" " hybrid-sleep Both hibernate and suspend the system\n" + " suspend-to-hibernate Initially suspend and then hibernate\n" + " the system after a fixed period of time\n" , program_invocation_short_name); } @@ -189,7 +271,8 @@ static int parse_argv(int argc, char *argv[]) { if (!streq(arg_verb, "suspend") && !streq(arg_verb, "hibernate") && - !streq(arg_verb, "hybrid-sleep")) { + !streq(arg_verb, "hybrid-sleep") && + !streq(arg_verb, "suspend-to-hibernate")) { log_error("Unknown command '%s'.", arg_verb); return -EINVAL; } @@ -199,6 +282,7 @@ static int parse_argv(int argc, char *argv[]) { int main(int argc, char *argv[]) { _cleanup_strv_free_ char **modes = NULL, **states = NULL; + usec_t delay = 0; int r; log_set_target(LOG_TARGET_AUTO); @@ -209,12 +293,14 @@ int main(int argc, char *argv[]) { if (r <= 0) goto finish; - r = parse_sleep_config(arg_verb, &modes, &states); + r = parse_sleep_config(arg_verb, &modes, &states, &delay); if (r < 0) goto finish; - r = execute(modes, states); - + if (streq(arg_verb, "suspend-to-hibernate")) + r = execute_s2h(delay); + else + r = execute(modes, states); finish: return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 1e975a5f2f..3b2538066d 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -160,6 +160,7 @@ static enum action { ACTION_SUSPEND, ACTION_HIBERNATE, ACTION_HYBRID_SLEEP, + ACTION_SUSPEND_TO_HIBERNATE, ACTION_RUNLEVEL2, ACTION_RUNLEVEL3, ACTION_RUNLEVEL4, @@ -3033,21 +3034,22 @@ static const struct { const char *verb; const char *mode; } action_table[_ACTION_MAX] = { - [ACTION_HALT] = { SPECIAL_HALT_TARGET, "halt", "replace-irreversibly" }, - [ACTION_POWEROFF] = { SPECIAL_POWEROFF_TARGET, "poweroff", "replace-irreversibly" }, - [ACTION_REBOOT] = { SPECIAL_REBOOT_TARGET, "reboot", "replace-irreversibly" }, - [ACTION_KEXEC] = { SPECIAL_KEXEC_TARGET, "kexec", "replace-irreversibly" }, - [ACTION_RUNLEVEL2] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" }, - [ACTION_RUNLEVEL3] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" }, - [ACTION_RUNLEVEL4] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" }, - [ACTION_RUNLEVEL5] = { SPECIAL_GRAPHICAL_TARGET, NULL, "isolate" }, - [ACTION_RESCUE] = { SPECIAL_RESCUE_TARGET, "rescue", "isolate" }, - [ACTION_EMERGENCY] = { SPECIAL_EMERGENCY_TARGET, "emergency", "isolate" }, - [ACTION_DEFAULT] = { SPECIAL_DEFAULT_TARGET, "default", "isolate" }, - [ACTION_EXIT] = { SPECIAL_EXIT_TARGET, "exit", "replace-irreversibly" }, - [ACTION_SUSPEND] = { SPECIAL_SUSPEND_TARGET, "suspend", "replace-irreversibly" }, - [ACTION_HIBERNATE] = { SPECIAL_HIBERNATE_TARGET, "hibernate", "replace-irreversibly" }, - [ACTION_HYBRID_SLEEP] = { SPECIAL_HYBRID_SLEEP_TARGET, "hybrid-sleep", "replace-irreversibly" }, + [ACTION_HALT] = { SPECIAL_HALT_TARGET, "halt", "replace-irreversibly" }, + [ACTION_POWEROFF] = { SPECIAL_POWEROFF_TARGET, "poweroff", "replace-irreversibly" }, + [ACTION_REBOOT] = { SPECIAL_REBOOT_TARGET, "reboot", "replace-irreversibly" }, + [ACTION_KEXEC] = { SPECIAL_KEXEC_TARGET, "kexec", "replace-irreversibly" }, + [ACTION_RUNLEVEL2] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" }, + [ACTION_RUNLEVEL3] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" }, + [ACTION_RUNLEVEL4] = { SPECIAL_MULTI_USER_TARGET, NULL, "isolate" }, + [ACTION_RUNLEVEL5] = { SPECIAL_GRAPHICAL_TARGET, NULL, "isolate" }, + [ACTION_RESCUE] = { SPECIAL_RESCUE_TARGET, "rescue", "isolate" }, + [ACTION_EMERGENCY] = { SPECIAL_EMERGENCY_TARGET, "emergency", "isolate" }, + [ACTION_DEFAULT] = { SPECIAL_DEFAULT_TARGET, "default", "isolate" }, + [ACTION_EXIT] = { SPECIAL_EXIT_TARGET, "exit", "replace-irreversibly" }, + [ACTION_SUSPEND] = { SPECIAL_SUSPEND_TARGET, "suspend", "replace-irreversibly" }, + [ACTION_HIBERNATE] = { SPECIAL_HIBERNATE_TARGET, "hibernate", "replace-irreversibly" }, + [ACTION_HYBRID_SLEEP] = { SPECIAL_HYBRID_SLEEP_TARGET, "hybrid-sleep", "replace-irreversibly" }, + [ACTION_SUSPEND_TO_HIBERNATE] = { SPECIAL_SUSPEND_TO_HIBERNATE_TARGET, "suspend-to-hibernate", "replace-irreversibly" }, }; static enum action verb_to_action(const char *verb) { @@ -3278,6 +3280,11 @@ static int logind_reboot(enum action a) { description = "put system into hybrid sleep"; break; + case ACTION_SUSPEND_TO_HIBERNATE: + method = "SuspendToHibernate"; + description = "put system into suspend followed by hibernate"; + break; + default: return -EINVAL; } @@ -3629,7 +3636,8 @@ static int start_special(int argc, char *argv[], void *userdata) { ACTION_HALT, ACTION_SUSPEND, ACTION_HIBERNATE, - ACTION_HYBRID_SLEEP)) { + ACTION_HYBRID_SLEEP, + ACTION_SUSPEND_TO_HIBERNATE)) { r = logind_reboot(a); if (r >= 0) @@ -7326,7 +7334,9 @@ static void systemctl_help(void) { " switch-root ROOT [INIT] Change to a different root file system\n" " suspend Suspend the system\n" " hibernate Hibernate the system\n" - " hybrid-sleep Hibernate and suspend the system\n", + " hybrid-sleep Hibernate and suspend the system\n" + " suspend-to-hibernate Suspend the system, wake after a period of\n" + " time and put it into hibernate\n", program_invocation_short_name); } @@ -8423,6 +8433,7 @@ static int systemctl_main(int argc, char *argv[]) { { "suspend", VERB_ANY, 1, VERB_ONLINE_ONLY, start_system_special }, { "hibernate", VERB_ANY, 1, VERB_ONLINE_ONLY, start_system_special }, { "hybrid-sleep", VERB_ANY, 1, VERB_ONLINE_ONLY, start_system_special }, + { "suspend-to-hibernate", VERB_ANY, 1, VERB_ONLINE_ONLY, start_system_special }, { "default", VERB_ANY, 1, VERB_ONLINE_ONLY, start_special }, { "rescue", VERB_ANY, 1, VERB_ONLINE_ONLY, start_system_special }, { "emergency", VERB_ANY, 1, VERB_ONLINE_ONLY, start_system_special }, @@ -8754,6 +8765,7 @@ int main(int argc, char*argv[]) { case ACTION_SUSPEND: case ACTION_HIBERNATE: case ACTION_HYBRID_SLEEP: + case ACTION_SUSPEND_TO_HIBERNATE: case ACTION_EMERGENCY: case ACTION_DEFAULT: /* systemctl verbs with no equivalent in the legacy commands. diff --git a/src/test/test-sleep.c b/src/test/test-sleep.c index 3c2b115fbf..e49ecbe494 100644 --- a/src/test/test-sleep.c +++ b/src/test/test-sleep.c @@ -48,6 +48,7 @@ static void test_sleep(void) { log_info("Suspend configured and possible: %s", yes_no(can_sleep("suspend") > 0)); log_info("Hibernation configured and possible: %s", yes_no(can_sleep("hibernate") > 0)); log_info("Hybrid-sleep configured and possible: %s", yes_no(can_sleep("hybrid-sleep") > 0)); + log_info("Suspend-to-Hibernate configured and possible: %s", yes_no(can_sleep("suspend-to-hibernate") > 0)); } int main(int argc, char* argv[]) { |