diff --git a/man/systemctl.xml b/man/systemctl.xml
index 1d791b44fd..6029434ae6 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 268e528856..2e35413b5f 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 d93bffb759..2cf746c5a6 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 6927e97747..ae7e25eedb 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 dd6f6c9873..0fa672eb90 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 e8ba8f76a0..a42fc36a2e 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,