mirror of
https://github.com/systemd/systemd.git
synced 2024-12-18 06:33:36 +08:00
logind: support for hybrid sleep (i.e. suspend+hibernate at the same time)
This commit is contained in:
parent
2001208c2a
commit
6524990fdc
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,5 @@
|
||||
/test-journal-enum
|
||||
/test-sleep
|
||||
/localectl
|
||||
/hostnamectl
|
||||
/timedatectl
|
||||
|
17
Makefile.am
17
Makefile.am
@ -273,6 +273,7 @@ dist_systemunit_DATA = \
|
||||
units/nss-user-lookup.target \
|
||||
units/mail-transfer-agent.target \
|
||||
units/hibernate.target \
|
||||
units/hybrid-sleep.target \
|
||||
units/http-daemon.target \
|
||||
units/poweroff.target \
|
||||
units/reboot.target \
|
||||
@ -329,6 +330,7 @@ nodist_systemunit_DATA = \
|
||||
units/rescue.service \
|
||||
units/user@.service \
|
||||
units/systemd-hibernate.service \
|
||||
units/systemd-hybrid-sleep.service \
|
||||
units/systemd-suspend.service \
|
||||
units/systemd-halt.service \
|
||||
units/systemd-poweroff.service \
|
||||
@ -379,6 +381,7 @@ EXTRA_DIST += \
|
||||
units/systemd-udev-settle.service \
|
||||
units/debug-shell.service.in \
|
||||
units/systemd-hibernate.service.in \
|
||||
units/systemd-hybrid-sleep.service.in \
|
||||
units/systemd-suspend.service.in \
|
||||
units/quotaon.service.in \
|
||||
introspect.awk \
|
||||
@ -534,6 +537,7 @@ MANPAGES_ALIAS = \
|
||||
man/systemd-shutdownd.socket.8 \
|
||||
man/systemd-shutdownd.8 \
|
||||
man/systemd-hibernate.service.8 \
|
||||
man/systemd-hybrid-sleep.service.8 \
|
||||
man/systemd-sleep.8 \
|
||||
man/systemd-shutdown.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.8: man/systemd-shutdownd.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-shutdown.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-log \
|
||||
test-unit-file \
|
||||
test-date
|
||||
test-date \
|
||||
test-sleep
|
||||
|
||||
TESTS += \
|
||||
test-job-type \
|
||||
@ -1184,7 +1190,8 @@ TESTS += \
|
||||
test-strv \
|
||||
test-unit-name \
|
||||
test-unit-file \
|
||||
test-date
|
||||
test-date \
|
||||
test-sleep
|
||||
|
||||
test_engine_SOURCES = \
|
||||
src/test/test-engine.c
|
||||
@ -1252,6 +1259,12 @@ test_date_SOURCES = \
|
||||
test_date_LDADD = \
|
||||
libsystemd-core.la
|
||||
|
||||
test_sleep_SOURCES = \
|
||||
src/test/test-sleep.c
|
||||
|
||||
test_sleep_LDADD = \
|
||||
libsystemd-core.la
|
||||
|
||||
test_daemon_SOURCES = \
|
||||
src/test/test-daemon.c
|
||||
|
||||
|
@ -211,8 +211,9 @@
|
||||
<literal>poweroff</literal>,
|
||||
<literal>reboot</literal>,
|
||||
<literal>halt</literal>,
|
||||
<literal>kexec</literal> and
|
||||
<literal>hibernate</literal>. If
|
||||
<literal>kexec</literal>,
|
||||
<literal>hibernate</literal> and
|
||||
<literal>hybrid-sleep</literal>. If
|
||||
<literal>ignore</literal> logind will
|
||||
never handle these keys. Otherwise the
|
||||
specified action will be taken in the
|
||||
|
@ -1180,6 +1180,11 @@
|
||||
|
||||
<listitem><para>Hibernate the system.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><command>hybrid-sleep</command></term>
|
||||
|
||||
<listitem><para>Hibernate and suspend the system.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><command>switch-root [ROOT] [INIT]</command></term>
|
||||
|
||||
|
@ -45,6 +45,7 @@
|
||||
<refnamediv>
|
||||
<refname>systemd-suspend.service</refname>
|
||||
<refname>systemd-hibernate.service</refname>
|
||||
<refname>systemd-hybrid-sleep.service</refname>
|
||||
<refname>systemd-sleep</refname>
|
||||
<refpurpose>System sleep state logic</refpurpose>
|
||||
</refnamediv>
|
||||
@ -52,6 +53,7 @@
|
||||
<refsynopsisdiv>
|
||||
<para><filename>systemd-suspend.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>
|
||||
</refsynopsisdiv>
|
||||
|
||||
@ -64,19 +66,25 @@
|
||||
for the actual system suspend. Similar,
|
||||
<filename>systemd-hibernate.service</filename> is
|
||||
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
|
||||
hibernation
|
||||
<filename>systemd-suspend.service</filename> will run
|
||||
all executables in
|
||||
<para>Immediately before entering system suspend
|
||||
and/or hibernation
|
||||
<filename>systemd-suspend.service</filename> (and the
|
||||
other mentioned units, respectively) will run all
|
||||
executables in
|
||||
<filename>/usr/lib/systemd/system-sleep/</filename>
|
||||
and pass two arguments to them. The first argument
|
||||
will be "<literal>pre</literal>", the second either
|
||||
"<literal>suspend</literal>" or
|
||||
"<literal>hibernate</literal>", depending on the
|
||||
"<literal>suspend</literal>",
|
||||
"<literal>hibernate</literal>", or
|
||||
"<literal>hybrid-sleep</literal>" depending on the
|
||||
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
|
||||
"<literal>post</literal>". All executables in this
|
||||
directory are executed in parallel, and execution of
|
||||
@ -87,15 +95,17 @@
|
||||
<filename>/usr/lib/systemd/system-sleep/</filename>
|
||||
are intended for local use only and should be
|
||||
considered hacks. If applications want to be notified
|
||||
of system suspend and resume there are much nicer
|
||||
interfaces available.</para>
|
||||
of system suspend/hibernation and resume there are
|
||||
much nicer interfaces available.</para>
|
||||
|
||||
<para>Note that
|
||||
<filename>systemd-suspend.service</filename> and
|
||||
<filename>systemd-hibernate.service</filename> should
|
||||
never be executed directly. Instead, trigger system
|
||||
sleep states with a command such as "<literal>systemctl
|
||||
suspend</literal>" or suchlike.</para>
|
||||
<filename>systemd-suspend.service</filename>,
|
||||
<filename>systemd-hibernate.service</filename> and
|
||||
<filename>systemd-hybrid-sleep.service</filename>
|
||||
should never be executed directly. Instead, trigger
|
||||
system sleep states with a command such as
|
||||
"<literal>systemctl suspend</literal>" or
|
||||
similar.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
@ -63,6 +63,7 @@
|
||||
<filename>graphical.target</filename>,
|
||||
<filename>hibernate.target</filename>,
|
||||
<filename>http-daemon.target</filename>,
|
||||
<filename>hybrid-sleep.target</filename>,
|
||||
<filename>halt.target</filename>,
|
||||
<filename>kbrequest.target</filename>,
|
||||
<filename>kexec.target</filename>,
|
||||
@ -302,6 +303,15 @@
|
||||
facility.</para>
|
||||
</listitem>
|
||||
</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>
|
||||
<term><filename>halt.target</filename></term>
|
||||
<listitem>
|
||||
@ -652,9 +662,8 @@
|
||||
<listitem>
|
||||
<para>A special target unit
|
||||
that is pulled in by
|
||||
<filename>suspend.target</filename>
|
||||
and
|
||||
<filename>hibernate.target</filename>
|
||||
<filename>suspend.target</filename>,
|
||||
<filename>hibernate.target</filename> and <filename>hybrid-sleep.target</filename>
|
||||
and may be used to hook units
|
||||
into the sleep state
|
||||
logic.</para>
|
||||
|
@ -37,6 +37,7 @@
|
||||
#define SPECIAL_EXIT_TARGET "exit.target"
|
||||
#define SPECIAL_SUSPEND_TARGET "suspend.target"
|
||||
#define SPECIAL_HIBERNATE_TARGET "hibernate.target"
|
||||
#define SPECIAL_HYBRID_SLEEP_TARGET "hybrid-sleep.target"
|
||||
|
||||
/* Special boot targets */
|
||||
#define SPECIAL_RESCUE_TARGET "rescue.target"
|
||||
|
@ -163,16 +163,18 @@ static int button_handle(
|
||||
[HANDLE_HALT] = "Halting...",
|
||||
[HANDLE_KEXEC] = "Rebooting via kexec...",
|
||||
[HANDLE_SUSPEND] = "Suspending...",
|
||||
[HANDLE_HIBERNATE] = "Hibernating..."
|
||||
[HANDLE_HIBERNATE] = "Hibernating...",
|
||||
[HANDLE_HYBRID_SLEEP] = "Hibernating and suspend...",
|
||||
};
|
||||
|
||||
static const char * const target_table[_HANDLE_BUTTON_MAX] = {
|
||||
[HANDLE_POWEROFF] = "poweroff.target",
|
||||
[HANDLE_REBOOT] = "reboot.target",
|
||||
[HANDLE_HALT] = "halt.target",
|
||||
[HANDLE_KEXEC] = "kexec.target",
|
||||
[HANDLE_SUSPEND] = "suspend.target",
|
||||
[HANDLE_HIBERNATE] = "hibernate.target"
|
||||
[HANDLE_POWEROFF] = SPECIAL_POWEROFF_TARGET,
|
||||
[HANDLE_REBOOT] = SPECIAL_REBOOT_TARGET,
|
||||
[HANDLE_HALT] = SPECIAL_HALT_TARGET,
|
||||
[HANDLE_KEXEC] = SPECIAL_KEXEC_TARGET,
|
||||
[HANDLE_SUSPEND] = SPECIAL_SUSPEND_TARGET,
|
||||
[HANDLE_HIBERNATE] = SPECIAL_HIBERNATE_TARGET,
|
||||
[HANDLE_HYBRID_SLEEP] = SPECIAL_HYBRID_SLEEP_TARGET
|
||||
};
|
||||
|
||||
DBusError error;
|
||||
@ -193,7 +195,7 @@ static int button_handle(
|
||||
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 (!ignore_inhibited &&
|
||||
@ -305,7 +307,8 @@ static const char* const handle_button_table[_HANDLE_BUTTON_MAX] = {
|
||||
[HANDLE_HALT] = "halt",
|
||||
[HANDLE_KEXEC] = "kexec",
|
||||
[HANDLE_SUSPEND] = "suspend",
|
||||
[HANDLE_HIBERNATE] = "hibernate"
|
||||
[HANDLE_HIBERNATE] = "hibernate",
|
||||
[HANDLE_HYBRID_SLEEP] = "hybrid-sleep",
|
||||
};
|
||||
DEFINE_STRING_TABLE_LOOKUP(handle_button, HandleButton);
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_handle_button, handle_button, HandleButton, "Failed to parse handle button setting");
|
||||
|
@ -32,6 +32,7 @@ typedef enum HandleButton {
|
||||
HANDLE_KEXEC,
|
||||
HANDLE_SUSPEND,
|
||||
HANDLE_HIBERNATE,
|
||||
HANDLE_HYBRID_SLEEP,
|
||||
_HANDLE_BUTTON_MAX,
|
||||
_HANDLE_BUTTON_INVALID = -1
|
||||
} HandleButton;
|
||||
|
@ -145,6 +145,9 @@
|
||||
" <method name=\"Hibernate\">\n" \
|
||||
" <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
|
||||
" </method>\n" \
|
||||
" <method name=\"HybridSleep\">\n" \
|
||||
" <arg name=\"interactive\" type=\"b\" direction=\"in\"/>\n" \
|
||||
" </method>\n" \
|
||||
" <method name=\"CanPowerOff\">\n" \
|
||||
" <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
|
||||
" </method>\n" \
|
||||
@ -157,6 +160,9 @@
|
||||
" <method name=\"CanHibernate\">\n" \
|
||||
" <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
|
||||
" </method>\n" \
|
||||
" <method name=\"CanHybridSleep\">\n" \
|
||||
" <arg name=\"result\" type=\"s\" direction=\"out\"/>\n" \
|
||||
" </method>\n" \
|
||||
" <method name=\"Inhibit\">\n" \
|
||||
" <arg name=\"what\" 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_ignore_inhibit,
|
||||
const char *sleep_type,
|
||||
const char *sleep_disk_type,
|
||||
DBusError *error,
|
||||
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);
|
||||
if (ul == (unsigned long) -1)
|
||||
return -EIO;
|
||||
@ -1234,6 +1252,7 @@ static int bus_manager_do_shutdown_or_sleep(
|
||||
const char *action_multiple_sessions,
|
||||
const char *action_ignore_inhibit,
|
||||
const char *sleep_type,
|
||||
const char *sleep_disk_type,
|
||||
DBusError *error,
|
||||
DBusMessage **_reply) {
|
||||
|
||||
@ -1271,6 +1290,15 @@ static int bus_manager_do_shutdown_or_sleep(
|
||||
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);
|
||||
if (ul == (unsigned long) -1)
|
||||
return -EIO;
|
||||
@ -2065,7 +2093,7 @@ static DBusHandlerResult manager_message_handler(
|
||||
"org.freedesktop.login1.power-off",
|
||||
"org.freedesktop.login1.power-off-multiple-sessions",
|
||||
"org.freedesktop.login1.power-off-ignore-inhibit",
|
||||
NULL,
|
||||
NULL, NULL,
|
||||
&error, &reply);
|
||||
if (r < 0)
|
||||
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-multiple-sessions",
|
||||
"org.freedesktop.login1.reboot-ignore-inhibit",
|
||||
NULL,
|
||||
NULL, NULL,
|
||||
&error, &reply);
|
||||
if (r < 0)
|
||||
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-multiple-sessions",
|
||||
"org.freedesktop.login1.suspend-ignore-inhibit",
|
||||
"mem",
|
||||
"mem", NULL,
|
||||
&error, &reply);
|
||||
if (r < 0)
|
||||
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-multiple-sessions",
|
||||
"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);
|
||||
if (r < 0)
|
||||
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-multiple-sessions",
|
||||
"org.freedesktop.login1.power-off-ignore-inhibit",
|
||||
NULL,
|
||||
NULL, NULL,
|
||||
&error, &reply);
|
||||
if (r < 0)
|
||||
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-multiple-sessions",
|
||||
"org.freedesktop.login1.reboot-ignore-inhibit",
|
||||
NULL,
|
||||
NULL, NULL,
|
||||
&error, &reply);
|
||||
if (r < 0)
|
||||
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-multiple-sessions",
|
||||
"org.freedesktop.login1.suspend-ignore-inhibit",
|
||||
"mem",
|
||||
"mem", NULL,
|
||||
&error, &reply);
|
||||
if (r < 0)
|
||||
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-multiple-sessions",
|
||||
"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);
|
||||
if (r < 0)
|
||||
return bus_send_error_reply(connection, message, &error, r);
|
||||
|
@ -5691,6 +5691,30 @@ int can_sleep(const char *type) {
|
||||
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) {
|
||||
assert(url);
|
||||
|
||||
|
@ -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 can_sleep(const char *type);
|
||||
int can_sleep_disk(const char *type);
|
||||
|
||||
bool is_valid_documentation_url(const char *url);
|
||||
|
||||
|
@ -46,7 +46,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
if (streq(argv[1], "suspend"))
|
||||
verb = "mem";
|
||||
else if (streq(argv[1], "hibernate"))
|
||||
else if (streq(argv[1], "hibernate") || streq(argv[1], "hybrid-sleep"))
|
||||
verb = "disk";
|
||||
else {
|
||||
log_error("Unknown action '%s'.", argv[1]);
|
||||
@ -54,6 +54,16 @@ int main(int argc, char *argv[]) {
|
||||
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");
|
||||
if (!f) {
|
||||
log_error("Failed to open /sys/power/state: %m");
|
||||
@ -73,12 +83,18 @@ int main(int argc, char *argv[]) {
|
||||
"MESSAGE=Suspending system...",
|
||||
"SLEEP=suspend",
|
||||
NULL);
|
||||
else
|
||||
else if (streq(argv[1], "hibernate"))
|
||||
log_struct(LOG_INFO,
|
||||
MESSAGE_ID(SD_MESSAGE_SLEEP_START),
|
||||
"MESSAGE=Hibernating system...",
|
||||
"SLEEP=hibernate",
|
||||
NULL);
|
||||
else
|
||||
log_struct(LOG_INFO,
|
||||
MESSAGE_ID(SD_MESSAGE_SLEEP_START),
|
||||
"MESSAGE=Hibernating and suspending system...",
|
||||
"SLEEP=hybrid-sleep",
|
||||
NULL);
|
||||
|
||||
fputs(verb, f);
|
||||
fputc('\n', f);
|
||||
|
@ -99,6 +99,7 @@ static enum action {
|
||||
ACTION_EXIT,
|
||||
ACTION_SUSPEND,
|
||||
ACTION_HIBERNATE,
|
||||
ACTION_HYBRID_SLEEP,
|
||||
ACTION_RUNLEVEL2,
|
||||
ACTION_RUNLEVEL3,
|
||||
ACTION_RUNLEVEL4,
|
||||
@ -1608,6 +1609,8 @@ static enum action verb_to_action(const char *verb) {
|
||||
return ACTION_SUSPEND;
|
||||
else if (streq(verb, "hibernate"))
|
||||
return ACTION_HIBERNATE;
|
||||
else if (streq(verb, "hybrid-sleep"))
|
||||
return ACTION_HYBRID_SLEEP;
|
||||
else
|
||||
return ACTION_INVALID;
|
||||
}
|
||||
@ -1628,7 +1631,8 @@ static int start_unit(DBusConnection *bus, char **args) {
|
||||
[ACTION_DEFAULT] = SPECIAL_DEFAULT_TARGET,
|
||||
[ACTION_EXIT] = SPECIAL_EXIT_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;
|
||||
@ -1764,6 +1768,10 @@ static int reboot_with_logind(DBusConnection *bus, enum action a) {
|
||||
method = "Hibernate";
|
||||
break;
|
||||
|
||||
case ACTION_HYBRID_SLEEP:
|
||||
method = "HybridSleep";
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -1815,7 +1823,8 @@ static int start_special(DBusConnection *bus, char **args) {
|
||||
(a == ACTION_POWEROFF ||
|
||||
a == ACTION_REBOOT ||
|
||||
a == ACTION_SUSPEND ||
|
||||
a == ACTION_HIBERNATE)) {
|
||||
a == ACTION_HIBERNATE ||
|
||||
a == ACTION_HYBRID_SLEEP)) {
|
||||
r = reboot_with_logind(bus, a);
|
||||
if (r >= 0)
|
||||
return r;
|
||||
@ -3967,7 +3976,8 @@ static int systemctl_help(void) {
|
||||
" exit Request user instance exit\n"
|
||||
" switch-root [ROOT] [INIT] Change to a different root file 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);
|
||||
|
||||
return 0;
|
||||
@ -4896,6 +4906,7 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
|
||||
{ "kexec", EQUAL, 1, start_special },
|
||||
{ "suspend", EQUAL, 1, start_special },
|
||||
{ "hibernate", EQUAL, 1, start_special },
|
||||
{ "hybrid-sleep", EQUAL, 1, start_special },
|
||||
{ "default", EQUAL, 1, start_special },
|
||||
{ "rescue", EQUAL, 1, start_special },
|
||||
{ "emergency", EQUAL, 1, start_special },
|
||||
|
39
src/test/test-sleep.c
Normal file
39
src/test/test-sleep.c
Normal 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
1
units/.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
/systemd-hybrid-sleep.service
|
||||
/systemd-journal-gatewayd.service
|
||||
/systemd-journal-flush.service
|
||||
/systemd-hibernate.service
|
||||
|
13
units/hybrid-sleep.target
Normal file
13
units/hybrid-sleep.target
Normal 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
|
17
units/systemd-hybrid-sleep.service.in
Normal file
17
units/systemd-hybrid-sleep.service.in
Normal 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
|
Loading…
Reference in New Issue
Block a user