logind: support for hybrid sleep (i.e. suspend+hibernate at the same time)

This commit is contained in:
Lennart Poettering 2012-10-28 00:49:04 +02:00
parent 2001208c2a
commit 6524990fdc
18 changed files with 263 additions and 44 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
/test-journal-enum /test-journal-enum
/test-sleep
/localectl /localectl
/hostnamectl /hostnamectl
/timedatectl /timedatectl

View File

@ -273,6 +273,7 @@ dist_systemunit_DATA = \
units/nss-user-lookup.target \ units/nss-user-lookup.target \
units/mail-transfer-agent.target \ units/mail-transfer-agent.target \
units/hibernate.target \ units/hibernate.target \
units/hybrid-sleep.target \
units/http-daemon.target \ units/http-daemon.target \
units/poweroff.target \ units/poweroff.target \
units/reboot.target \ units/reboot.target \
@ -329,6 +330,7 @@ nodist_systemunit_DATA = \
units/rescue.service \ units/rescue.service \
units/user@.service \ units/user@.service \
units/systemd-hibernate.service \ units/systemd-hibernate.service \
units/systemd-hybrid-sleep.service \
units/systemd-suspend.service \ units/systemd-suspend.service \
units/systemd-halt.service \ units/systemd-halt.service \
units/systemd-poweroff.service \ units/systemd-poweroff.service \
@ -379,6 +381,7 @@ EXTRA_DIST += \
units/systemd-udev-settle.service \ units/systemd-udev-settle.service \
units/debug-shell.service.in \ units/debug-shell.service.in \
units/systemd-hibernate.service.in \ units/systemd-hibernate.service.in \
units/systemd-hybrid-sleep.service.in \
units/systemd-suspend.service.in \ units/systemd-suspend.service.in \
units/quotaon.service.in \ units/quotaon.service.in \
introspect.awk \ introspect.awk \
@ -534,6 +537,7 @@ MANPAGES_ALIAS = \
man/systemd-shutdownd.socket.8 \ man/systemd-shutdownd.socket.8 \
man/systemd-shutdownd.8 \ man/systemd-shutdownd.8 \
man/systemd-hibernate.service.8 \ man/systemd-hibernate.service.8 \
man/systemd-hybrid-sleep.service.8 \
man/systemd-sleep.8 \ man/systemd-sleep.8 \
man/systemd-shutdown.8 \ man/systemd-shutdown.8 \
man/systemd-poweroff.service.8 \ man/systemd-poweroff.service.8 \
@ -608,6 +612,7 @@ man/systemd-initctl.8: man/systemd-initctl.service.8
man/systemd-shutdownd.socket.8: man/systemd-shutdownd.service.8 man/systemd-shutdownd.socket.8: man/systemd-shutdownd.service.8
man/systemd-shutdownd.8: man/systemd-shutdownd.service.8 man/systemd-shutdownd.8: man/systemd-shutdownd.service.8
man/systemd-hibernate.service.8: man/systemd-suspend.service.8 man/systemd-hibernate.service.8: man/systemd-suspend.service.8
man/systemd-hybrid-sleep.service.8: man/systemd-suspend.service.8
man/systemd-sleep.8: man/systemd-suspend.service.8 man/systemd-sleep.8: man/systemd-suspend.service.8
man/systemd-shutdown.8: man/systemd-halt.service.8 man/systemd-shutdown.8: man/systemd-halt.service.8
man/systemd-poweroff.service.8: man/systemd-halt.service.8 man/systemd-poweroff.service.8: man/systemd-halt.service.8
@ -1176,7 +1181,8 @@ noinst_PROGRAMS += \
test-unit-name \ test-unit-name \
test-log \ test-log \
test-unit-file \ test-unit-file \
test-date test-date \
test-sleep
TESTS += \ TESTS += \
test-job-type \ test-job-type \
@ -1184,7 +1190,8 @@ TESTS += \
test-strv \ test-strv \
test-unit-name \ test-unit-name \
test-unit-file \ test-unit-file \
test-date test-date \
test-sleep
test_engine_SOURCES = \ test_engine_SOURCES = \
src/test/test-engine.c src/test/test-engine.c
@ -1252,6 +1259,12 @@ test_date_SOURCES = \
test_date_LDADD = \ test_date_LDADD = \
libsystemd-core.la libsystemd-core.la
test_sleep_SOURCES = \
src/test/test-sleep.c
test_sleep_LDADD = \
libsystemd-core.la
test_daemon_SOURCES = \ test_daemon_SOURCES = \
src/test/test-daemon.c src/test/test-daemon.c

View File

@ -211,8 +211,9 @@
<literal>poweroff</literal>, <literal>poweroff</literal>,
<literal>reboot</literal>, <literal>reboot</literal>,
<literal>halt</literal>, <literal>halt</literal>,
<literal>kexec</literal> and <literal>kexec</literal>,
<literal>hibernate</literal>. If <literal>hibernate</literal> and
<literal>hybrid-sleep</literal>. If
<literal>ignore</literal> logind will <literal>ignore</literal> logind will
never handle these keys. Otherwise the never handle these keys. Otherwise the
specified action will be taken in the specified action will be taken in the

View File

@ -1180,6 +1180,11 @@
<listitem><para>Hibernate the system.</para></listitem> <listitem><para>Hibernate the system.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><command>hybrid-sleep</command></term>
<listitem><para>Hibernate and suspend the system.</para></listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><command>switch-root [ROOT] [INIT]</command></term> <term><command>switch-root [ROOT] [INIT]</command></term>

View File

@ -45,6 +45,7 @@
<refnamediv> <refnamediv>
<refname>systemd-suspend.service</refname> <refname>systemd-suspend.service</refname>
<refname>systemd-hibernate.service</refname> <refname>systemd-hibernate.service</refname>
<refname>systemd-hybrid-sleep.service</refname>
<refname>systemd-sleep</refname> <refname>systemd-sleep</refname>
<refpurpose>System sleep state logic</refpurpose> <refpurpose>System sleep state logic</refpurpose>
</refnamediv> </refnamediv>
@ -52,6 +53,7 @@
<refsynopsisdiv> <refsynopsisdiv>
<para><filename>systemd-suspend.service</filename></para> <para><filename>systemd-suspend.service</filename></para>
<para><filename>systemd-hibernate.service</filename></para> <para><filename>systemd-hibernate.service</filename></para>
<para><filename>systemd-hybrid-sleep.service</filename></para>
<para><filename>/usr/lib/systemd/systemd-sleep</filename></para> <para><filename>/usr/lib/systemd/systemd-sleep</filename></para>
</refsynopsisdiv> </refsynopsisdiv>
@ -64,19 +66,25 @@
for the actual system suspend. Similar, for the actual system suspend. Similar,
<filename>systemd-hibernate.service</filename> is <filename>systemd-hibernate.service</filename> is
pulled in by <filename>hibernate.target</filename> to pulled in by <filename>hibernate.target</filename> to
execute the actual hibernation.</para> execute the actual hibernation. Finally,
<filename>systemd-hybrid-sleep.service</filename> is
pulled in by <filename>hybrid-sleep.target</filename>
to execute hybrid hibernation with system
suspend.</para>
<para>Immediately before entering system suspend and <para>Immediately before entering system suspend
hibernation and/or hibernation
<filename>systemd-suspend.service</filename> will run <filename>systemd-suspend.service</filename> (and the
all executables in other mentioned units, respectively) will run all
executables in
<filename>/usr/lib/systemd/system-sleep/</filename> <filename>/usr/lib/systemd/system-sleep/</filename>
and pass two arguments to them. The first argument and pass two arguments to them. The first argument
will be "<literal>pre</literal>", the second either will be "<literal>pre</literal>", the second either
"<literal>suspend</literal>" or "<literal>suspend</literal>",
"<literal>hibernate</literal>", depending on the "<literal>hibernate</literal>", or
"<literal>hybrid-sleep</literal>" depending on the
chosen action. Immediately after leaving system chosen action. Immediately after leaving system
suspend and hibernation the same executables are run, suspend and/or hibernation the same executables are run,
but the first argument is now but the first argument is now
"<literal>post</literal>". All executables in this "<literal>post</literal>". All executables in this
directory are executed in parallel, and execution of directory are executed in parallel, and execution of
@ -87,15 +95,17 @@
<filename>/usr/lib/systemd/system-sleep/</filename> <filename>/usr/lib/systemd/system-sleep/</filename>
are intended for local use only and should be are intended for local use only and should be
considered hacks. If applications want to be notified considered hacks. If applications want to be notified
of system suspend and resume there are much nicer of system suspend/hibernation and resume there are
interfaces available.</para> much nicer interfaces available.</para>
<para>Note that <para>Note that
<filename>systemd-suspend.service</filename> and <filename>systemd-suspend.service</filename>,
<filename>systemd-hibernate.service</filename> should <filename>systemd-hibernate.service</filename> and
never be executed directly. Instead, trigger system <filename>systemd-hybrid-sleep.service</filename>
sleep states with a command such as "<literal>systemctl should never be executed directly. Instead, trigger
suspend</literal>" or suchlike.</para> system sleep states with a command such as
"<literal>systemctl suspend</literal>" or
similar.</para>
</refsect1> </refsect1>
<refsect1> <refsect1>

View File

@ -63,6 +63,7 @@
<filename>graphical.target</filename>, <filename>graphical.target</filename>,
<filename>hibernate.target</filename>, <filename>hibernate.target</filename>,
<filename>http-daemon.target</filename>, <filename>http-daemon.target</filename>,
<filename>hybrid-sleep.target</filename>,
<filename>halt.target</filename>, <filename>halt.target</filename>,
<filename>kbrequest.target</filename>, <filename>kbrequest.target</filename>,
<filename>kexec.target</filename>, <filename>kexec.target</filename>,
@ -302,6 +303,15 @@
facility.</para> facility.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><filename>hybrid-sleep.target</filename></term>
<listitem>
<para>A special target unit
for hibernating and suspending the
system at the same time. This pulls in
<filename>sleep.target</filename>.</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><filename>halt.target</filename></term> <term><filename>halt.target</filename></term>
<listitem> <listitem>
@ -652,9 +662,8 @@
<listitem> <listitem>
<para>A special target unit <para>A special target unit
that is pulled in by that is pulled in by
<filename>suspend.target</filename> <filename>suspend.target</filename>,
and <filename>hibernate.target</filename> and <filename>hybrid-sleep.target</filename>
<filename>hibernate.target</filename>
and may be used to hook units and may be used to hook units
into the sleep state into the sleep state
logic.</para> logic.</para>

View File

@ -37,6 +37,7 @@
#define SPECIAL_EXIT_TARGET "exit.target" #define SPECIAL_EXIT_TARGET "exit.target"
#define SPECIAL_SUSPEND_TARGET "suspend.target" #define SPECIAL_SUSPEND_TARGET "suspend.target"
#define SPECIAL_HIBERNATE_TARGET "hibernate.target" #define SPECIAL_HIBERNATE_TARGET "hibernate.target"
#define SPECIAL_HYBRID_SLEEP_TARGET "hybrid-sleep.target"
/* Special boot targets */ /* Special boot targets */
#define SPECIAL_RESCUE_TARGET "rescue.target" #define SPECIAL_RESCUE_TARGET "rescue.target"

View File

@ -163,16 +163,18 @@ static int button_handle(
[HANDLE_HALT] = "Halting...", [HANDLE_HALT] = "Halting...",
[HANDLE_KEXEC] = "Rebooting via kexec...", [HANDLE_KEXEC] = "Rebooting via kexec...",
[HANDLE_SUSPEND] = "Suspending...", [HANDLE_SUSPEND] = "Suspending...",
[HANDLE_HIBERNATE] = "Hibernating..." [HANDLE_HIBERNATE] = "Hibernating...",
[HANDLE_HYBRID_SLEEP] = "Hibernating and suspend...",
}; };
static const char * const target_table[_HANDLE_BUTTON_MAX] = { static const char * const target_table[_HANDLE_BUTTON_MAX] = {
[HANDLE_POWEROFF] = "poweroff.target", [HANDLE_POWEROFF] = SPECIAL_POWEROFF_TARGET,
[HANDLE_REBOOT] = "reboot.target", [HANDLE_REBOOT] = SPECIAL_REBOOT_TARGET,
[HANDLE_HALT] = "halt.target", [HANDLE_HALT] = SPECIAL_HALT_TARGET,
[HANDLE_KEXEC] = "kexec.target", [HANDLE_KEXEC] = SPECIAL_KEXEC_TARGET,
[HANDLE_SUSPEND] = "suspend.target", [HANDLE_SUSPEND] = SPECIAL_SUSPEND_TARGET,
[HANDLE_HIBERNATE] = "hibernate.target" [HANDLE_HIBERNATE] = SPECIAL_HIBERNATE_TARGET,
[HANDLE_HYBRID_SLEEP] = SPECIAL_HYBRID_SLEEP_TARGET
}; };
DBusError error; DBusError error;
@ -193,7 +195,7 @@ static int button_handle(
return 0; return 0;
} }
inhibit_operation = handle == HANDLE_SUSPEND || handle == HANDLE_HIBERNATE ? INHIBIT_SLEEP : INHIBIT_SHUTDOWN; inhibit_operation = handle == HANDLE_SUSPEND || handle == HANDLE_HIBERNATE || handle == HANDLE_HYBRID_SLEEP ? INHIBIT_SLEEP : INHIBIT_SHUTDOWN;
/* If the actual operation is inhibited, warn and fail */ /* If the actual operation is inhibited, warn and fail */
if (!ignore_inhibited && if (!ignore_inhibited &&
@ -305,7 +307,8 @@ static const char* const handle_button_table[_HANDLE_BUTTON_MAX] = {
[HANDLE_HALT] = "halt", [HANDLE_HALT] = "halt",
[HANDLE_KEXEC] = "kexec", [HANDLE_KEXEC] = "kexec",
[HANDLE_SUSPEND] = "suspend", [HANDLE_SUSPEND] = "suspend",
[HANDLE_HIBERNATE] = "hibernate" [HANDLE_HIBERNATE] = "hibernate",
[HANDLE_HYBRID_SLEEP] = "hybrid-sleep",
}; };
DEFINE_STRING_TABLE_LOOKUP(handle_button, HandleButton); DEFINE_STRING_TABLE_LOOKUP(handle_button, HandleButton);
DEFINE_CONFIG_PARSE_ENUM(config_parse_handle_button, handle_button, HandleButton, "Failed to parse handle button setting"); DEFINE_CONFIG_PARSE_ENUM(config_parse_handle_button, handle_button, HandleButton, "Failed to parse handle button setting");

View File

@ -32,6 +32,7 @@ typedef enum HandleButton {
HANDLE_KEXEC, HANDLE_KEXEC,
HANDLE_SUSPEND, HANDLE_SUSPEND,
HANDLE_HIBERNATE, HANDLE_HIBERNATE,
HANDLE_HYBRID_SLEEP,
_HANDLE_BUTTON_MAX, _HANDLE_BUTTON_MAX,
_HANDLE_BUTTON_INVALID = -1 _HANDLE_BUTTON_INVALID = -1
} HandleButton; } HandleButton;

View File

@ -145,6 +145,9 @@
" <method name=\"Hibernate\">\n" \ " <method name=\"Hibernate\">\n" \
" <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \ " <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
" </method>\n" \ " </method>\n" \
" <method name=\"HybridSleep\">\n" \
" <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
" </method>\n" \
" <method name=\"CanPowerOff\">\n" \ " <method name=\"CanPowerOff\">\n" \
" <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \ " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
" </method>\n" \ " </method>\n" \
@ -157,6 +160,9 @@
" <method name=\"CanHibernate\">\n" \ " <method name=\"CanHibernate\">\n" \
" <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \ " <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
" </method>\n" \ " </method>\n" \
" <method name=\"CanHybridSleep\">\n" \
" <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
" </method>\n" \
" <method name=\"Inhibit\">\n" \ " <method name=\"Inhibit\">\n" \
" <arg name=\"what\" type=\"s\" direction=\"in\"/>\n" \ " <arg name=\"what\" type=\"s\" direction=\"in\"/>\n" \
" <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \ " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
@ -1054,6 +1060,7 @@ static int bus_manager_can_shutdown_or_sleep(
const char *action_multiple_sessions, const char *action_multiple_sessions,
const char *action_ignore_inhibit, const char *action_ignore_inhibit,
const char *sleep_type, const char *sleep_type,
const char *sleep_disk_type,
DBusError *error, DBusError *error,
DBusMessage **_reply) { DBusMessage **_reply) {
@ -1085,6 +1092,17 @@ static int bus_manager_can_shutdown_or_sleep(
} }
} }
if (sleep_disk_type) {
r = can_sleep_disk(sleep_disk_type);
if (r < 0)
return r;
if (r == 0) {
result = "na";
goto finish;
}
}
ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error); ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
if (ul == (unsigned long) -1) if (ul == (unsigned long) -1)
return -EIO; return -EIO;
@ -1234,6 +1252,7 @@ static int bus_manager_do_shutdown_or_sleep(
const char *action_multiple_sessions, const char *action_multiple_sessions,
const char *action_ignore_inhibit, const char *action_ignore_inhibit,
const char *sleep_type, const char *sleep_type,
const char *sleep_disk_type,
DBusError *error, DBusError *error,
DBusMessage **_reply) { DBusMessage **_reply) {
@ -1271,6 +1290,15 @@ static int bus_manager_do_shutdown_or_sleep(
return -ENOTSUP; return -ENOTSUP;
} }
if (sleep_disk_type) {
r = can_sleep_disk(sleep_disk_type);
if (r < 0)
return r;
if (r == 0)
return -ENOTSUP;
}
ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error); ul = dbus_bus_get_unix_user(connection, dbus_message_get_sender(message), error);
if (ul == (unsigned long) -1) if (ul == (unsigned long) -1)
return -EIO; return -EIO;
@ -2065,7 +2093,7 @@ static DBusHandlerResult manager_message_handler(
"org.freedesktop.login1.power-off", "org.freedesktop.login1.power-off",
"org.freedesktop.login1.power-off-multiple-sessions", "org.freedesktop.login1.power-off-multiple-sessions",
"org.freedesktop.login1.power-off-ignore-inhibit", "org.freedesktop.login1.power-off-ignore-inhibit",
NULL, NULL, NULL,
&error, &reply); &error, &reply);
if (r < 0) if (r < 0)
return bus_send_error_reply(connection, message, &error, r); return bus_send_error_reply(connection, message, &error, r);
@ -2077,7 +2105,7 @@ static DBusHandlerResult manager_message_handler(
"org.freedesktop.login1.reboot", "org.freedesktop.login1.reboot",
"org.freedesktop.login1.reboot-multiple-sessions", "org.freedesktop.login1.reboot-multiple-sessions",
"org.freedesktop.login1.reboot-ignore-inhibit", "org.freedesktop.login1.reboot-ignore-inhibit",
NULL, NULL, NULL,
&error, &reply); &error, &reply);
if (r < 0) if (r < 0)
return bus_send_error_reply(connection, message, &error, r); return bus_send_error_reply(connection, message, &error, r);
@ -2090,7 +2118,7 @@ static DBusHandlerResult manager_message_handler(
"org.freedesktop.login1.suspend", "org.freedesktop.login1.suspend",
"org.freedesktop.login1.suspend-multiple-sessions", "org.freedesktop.login1.suspend-multiple-sessions",
"org.freedesktop.login1.suspend-ignore-inhibit", "org.freedesktop.login1.suspend-ignore-inhibit",
"mem", "mem", NULL,
&error, &reply); &error, &reply);
if (r < 0) if (r < 0)
return bus_send_error_reply(connection, message, &error, r); return bus_send_error_reply(connection, message, &error, r);
@ -2102,7 +2130,20 @@ static DBusHandlerResult manager_message_handler(
"org.freedesktop.login1.hibernate", "org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-multiple-sessions", "org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit", "org.freedesktop.login1.hibernate-ignore-inhibit",
"disk", "disk", NULL,
&error, &reply);
if (r < 0)
return bus_send_error_reply(connection, message, &error, r);
} else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "HybridSleep")) {
r = bus_manager_do_shutdown_or_sleep(
m, connection, message,
SPECIAL_HYBRID_SLEEP_TARGET,
INHIBIT_SLEEP,
"org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit",
"disk", "suspend",
&error, &reply); &error, &reply);
if (r < 0) if (r < 0)
return bus_send_error_reply(connection, message, &error, r); return bus_send_error_reply(connection, message, &error, r);
@ -2115,7 +2156,7 @@ static DBusHandlerResult manager_message_handler(
"org.freedesktop.login1.power-off", "org.freedesktop.login1.power-off",
"org.freedesktop.login1.power-off-multiple-sessions", "org.freedesktop.login1.power-off-multiple-sessions",
"org.freedesktop.login1.power-off-ignore-inhibit", "org.freedesktop.login1.power-off-ignore-inhibit",
NULL, NULL, NULL,
&error, &reply); &error, &reply);
if (r < 0) if (r < 0)
return bus_send_error_reply(connection, message, &error, r); return bus_send_error_reply(connection, message, &error, r);
@ -2126,7 +2167,7 @@ static DBusHandlerResult manager_message_handler(
"org.freedesktop.login1.reboot", "org.freedesktop.login1.reboot",
"org.freedesktop.login1.reboot-multiple-sessions", "org.freedesktop.login1.reboot-multiple-sessions",
"org.freedesktop.login1.reboot-ignore-inhibit", "org.freedesktop.login1.reboot-ignore-inhibit",
NULL, NULL, NULL,
&error, &reply); &error, &reply);
if (r < 0) if (r < 0)
return bus_send_error_reply(connection, message, &error, r); return bus_send_error_reply(connection, message, &error, r);
@ -2138,7 +2179,7 @@ static DBusHandlerResult manager_message_handler(
"org.freedesktop.login1.suspend", "org.freedesktop.login1.suspend",
"org.freedesktop.login1.suspend-multiple-sessions", "org.freedesktop.login1.suspend-multiple-sessions",
"org.freedesktop.login1.suspend-ignore-inhibit", "org.freedesktop.login1.suspend-ignore-inhibit",
"mem", "mem", NULL,
&error, &reply); &error, &reply);
if (r < 0) if (r < 0)
return bus_send_error_reply(connection, message, &error, r); return bus_send_error_reply(connection, message, &error, r);
@ -2150,7 +2191,19 @@ static DBusHandlerResult manager_message_handler(
"org.freedesktop.login1.hibernate", "org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-multiple-sessions", "org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit", "org.freedesktop.login1.hibernate-ignore-inhibit",
"disk", "disk", NULL,
&error, &reply);
if (r < 0)
return bus_send_error_reply(connection, message, &error, r);
} else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CanHybridSleep")) {
r = bus_manager_can_shutdown_or_sleep(
m, connection, message,
INHIBIT_SLEEP,
"org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit",
"disk", "suspend",
&error, &reply); &error, &reply);
if (r < 0) if (r < 0)
return bus_send_error_reply(connection, message, &error, r); return bus_send_error_reply(connection, message, &error, r);

View File

@ -5691,6 +5691,30 @@ int can_sleep(const char *type) {
return false; return false;
} }
int can_sleep_disk(const char *type) {
char *w, *state;
size_t l, k;
int r;
_cleanup_free_ char *p = NULL;
assert(type);
r = read_one_line_file("/sys/power/disk", &p);
if (r < 0)
return r == -ENOENT ? 0 : r;
k = strlen(type);
FOREACH_WORD_SEPARATOR(w, l, p, WHITESPACE, state) {
if (l == k && memcmp(w, type, l) == 0)
return true;
if (l == k + 2 && w[0] == '[' && memcmp(w + 1, type, l - 2) == 0 && w[l-1] == ']')
return true;
}
return false;
}
bool is_valid_documentation_url(const char *url) { bool is_valid_documentation_url(const char *url) {
assert(url); assert(url);

View File

@ -529,6 +529,7 @@ int setrlimit_closest(int resource, const struct rlimit *rlim);
int getenv_for_pid(pid_t pid, const char *field, char **_value); int getenv_for_pid(pid_t pid, const char *field, char **_value);
int can_sleep(const char *type); int can_sleep(const char *type);
int can_sleep_disk(const char *type);
bool is_valid_documentation_url(const char *url); bool is_valid_documentation_url(const char *url);

View File

@ -46,7 +46,7 @@ int main(int argc, char *argv[]) {
if (streq(argv[1], "suspend")) if (streq(argv[1], "suspend"))
verb = "mem"; verb = "mem";
else if (streq(argv[1], "hibernate")) else if (streq(argv[1], "hibernate") || streq(argv[1], "hybrid-sleep"))
verb = "disk"; verb = "disk";
else { else {
log_error("Unknown action '%s'.", argv[1]); log_error("Unknown action '%s'.", argv[1]);
@ -54,6 +54,16 @@ int main(int argc, char *argv[]) {
goto finish; goto finish;
} }
/* Configure the hibernation mode */
if (streq(argv[1], "hibernate")) {
if (write_one_line_file("/sys/power/disk", "platform") < 0)
write_one_line_file("/sys/power/disk", "shutdown");
} else if (streq(argv[1], "hybrid-sleep")) {
if (write_one_line_file("/sys/power/disk", "suspend") < 0)
if (write_one_line_file("/sys/power/disk", "platform") < 0)
write_one_line_file("/sys/power/disk", "shutdown");
}
f = fopen("/sys/power/state", "we"); f = fopen("/sys/power/state", "we");
if (!f) { if (!f) {
log_error("Failed to open /sys/power/state: %m"); log_error("Failed to open /sys/power/state: %m");
@ -73,12 +83,18 @@ int main(int argc, char *argv[]) {
"MESSAGE=Suspending system...", "MESSAGE=Suspending system...",
"SLEEP=suspend", "SLEEP=suspend",
NULL); NULL);
else else if (streq(argv[1], "hibernate"))
log_struct(LOG_INFO, log_struct(LOG_INFO,
MESSAGE_ID(SD_MESSAGE_SLEEP_START), MESSAGE_ID(SD_MESSAGE_SLEEP_START),
"MESSAGE=Hibernating system...", "MESSAGE=Hibernating system...",
"SLEEP=hibernate", "SLEEP=hibernate",
NULL); NULL);
else
log_struct(LOG_INFO,
MESSAGE_ID(SD_MESSAGE_SLEEP_START),
"MESSAGE=Hibernating and suspending system...",
"SLEEP=hybrid-sleep",
NULL);
fputs(verb, f); fputs(verb, f);
fputc('\n', f); fputc('\n', f);

View File

@ -99,6 +99,7 @@ static enum action {
ACTION_EXIT, ACTION_EXIT,
ACTION_SUSPEND, ACTION_SUSPEND,
ACTION_HIBERNATE, ACTION_HIBERNATE,
ACTION_HYBRID_SLEEP,
ACTION_RUNLEVEL2, ACTION_RUNLEVEL2,
ACTION_RUNLEVEL3, ACTION_RUNLEVEL3,
ACTION_RUNLEVEL4, ACTION_RUNLEVEL4,
@ -1608,6 +1609,8 @@ static enum action verb_to_action(const char *verb) {
return ACTION_SUSPEND; return ACTION_SUSPEND;
else if (streq(verb, "hibernate")) else if (streq(verb, "hibernate"))
return ACTION_HIBERNATE; return ACTION_HIBERNATE;
else if (streq(verb, "hybrid-sleep"))
return ACTION_HYBRID_SLEEP;
else else
return ACTION_INVALID; return ACTION_INVALID;
} }
@ -1628,7 +1631,8 @@ static int start_unit(DBusConnection *bus, char **args) {
[ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET, [ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET,
[ACTION_EXIT] = SPECIAL_EXIT_TARGET, [ACTION_EXIT] = SPECIAL_EXIT_TARGET,
[ACTION_SUSPEND] = SPECIAL_SUSPEND_TARGET, [ACTION_SUSPEND] = SPECIAL_SUSPEND_TARGET,
[ACTION_HIBERNATE] = SPECIAL_HIBERNATE_TARGET [ACTION_HIBERNATE] = SPECIAL_HIBERNATE_TARGET,
[ACTION_HYBRID_SLEEP] = SPECIAL_HYBRID_SLEEP_TARGET
}; };
int r, ret = 0; int r, ret = 0;
@ -1764,6 +1768,10 @@ static int reboot_with_logind(DBusConnection *bus, enum action a) {
method = "Hibernate"; method = "Hibernate";
break; break;
case ACTION_HYBRID_SLEEP:
method = "HybridSleep";
break;
default: default:
return -EINVAL; return -EINVAL;
} }
@ -1815,7 +1823,8 @@ static int start_special(DBusConnection *bus, char **args) {
(a == ACTION_POWEROFF || (a == ACTION_POWEROFF ||
a == ACTION_REBOOT || a == ACTION_REBOOT ||
a == ACTION_SUSPEND || a == ACTION_SUSPEND ||
a == ACTION_HIBERNATE)) { a == ACTION_HIBERNATE ||
a == ACTION_HYBRID_SLEEP)) {
r = reboot_with_logind(bus, a); r = reboot_with_logind(bus, a);
if (r >= 0) if (r >= 0)
return r; return r;
@ -3967,7 +3976,8 @@ static int systemctl_help(void) {
" exit Request user instance exit\n" " exit Request user instance exit\n"
" switch-root [ROOT] [INIT] Change to a different root file system\n" " switch-root [ROOT] [INIT] Change to a different root file system\n"
" suspend Suspend the system\n" " suspend Suspend the system\n"
" hibernate Hibernate the system\n", " hibernate Hibernate the system\n"
" hybrid-sleep Hibernate and suspend the system\n",
program_invocation_short_name); program_invocation_short_name);
return 0; return 0;
@ -4896,6 +4906,7 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
{ "kexec", EQUAL, 1, start_special }, { "kexec", EQUAL, 1, start_special },
{ "suspend", EQUAL, 1, start_special }, { "suspend", EQUAL, 1, start_special },
{ "hibernate", EQUAL, 1, start_special }, { "hibernate", EQUAL, 1, start_special },
{ "hybrid-sleep", EQUAL, 1, start_special },
{ "default", EQUAL, 1, start_special }, { "default", EQUAL, 1, start_special },
{ "rescue", EQUAL, 1, start_special }, { "rescue", EQUAL, 1, start_special },
{ "emergency", EQUAL, 1, start_special }, { "emergency", EQUAL, 1, start_special },

39
src/test/test-sleep.c Normal file
View File

@ -0,0 +1,39 @@
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2012 Lennart Poettering
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
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include "util.h"
#include "log.h"
int main(int argc, char* argv[]) {
log_info("Can Suspend: %s", yes_no(can_sleep("mem") > 0));
log_info("Can Hibernate: %s", yes_no(can_sleep("disk") > 0));
log_info("Can Hibernate+Suspend (Hybrid-Sleep): %s", yes_no(can_sleep_disk("suspend") > 0));
log_info("Can Hibernate+Reboot: %s", yes_no(can_sleep_disk("reboot") > 0));
log_info("Can Hibernate+Platform: %s", yes_no(can_sleep_disk("platform") > 0));
log_info("Can Hibernate+Shutdown: %s", yes_no(can_sleep_disk("shutdown") > 0));
return 0;
}

1
units/.gitignore vendored
View File

@ -1,3 +1,4 @@
/systemd-hybrid-sleep.service
/systemd-journal-gatewayd.service /systemd-journal-gatewayd.service
/systemd-journal-flush.service /systemd-journal-flush.service
/systemd-hibernate.service /systemd-hibernate.service

13
units/hybrid-sleep.target Normal file
View File

@ -0,0 +1,13 @@
# This file is part of systemd.
#
# 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
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Hybrid Suspend+Hibernate
Documentation=man:systemd.special(7)
DefaultDependencies=no
BindsTo=systemd-hybrid-sleep.service
After=systemd-hybrid-sleep.service

View File

@ -0,0 +1,17 @@
# This file is part of systemd.
#
# 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
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Hybrid Suspend+Hibernate
Documentation=man:systemd-suspend.service(8)
DefaultDependencies=no
Requires=sleep.target
After=sleep.target
[Service]
Type=oneshot
ExecStart=@rootlibexecdir@/systemd-sleep hybrid-sleep