diff options
author | Lennart Poettering <lennart@poettering.net> | 2012-10-28 00:49:04 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2012-10-28 00:50:35 +0200 |
commit | 6524990fdc98370ecba5d9f73e67161e8798c010 (patch) | |
tree | 870ed57ed3c756dd34a0223692d1ec5b9e5ef44d | |
parent | 2001208c2ab631a69896d1f670c26846b70d1fb7 (diff) |
logind: support for hybrid sleep (i.e. suspend+hibernate at the same time)
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile.am | 17 | ||||
-rw-r--r-- | man/logind.conf.xml | 5 | ||||
-rw-r--r-- | man/systemctl.xml | 5 | ||||
-rw-r--r-- | man/systemd-suspend.service.xml | 42 | ||||
-rw-r--r-- | man/systemd.special.xml | 15 | ||||
-rw-r--r-- | src/core/special.h | 1 | ||||
-rw-r--r-- | src/login/logind-button.c | 21 | ||||
-rw-r--r-- | src/login/logind-button.h | 1 | ||||
-rw-r--r-- | src/login/logind-dbus.c | 69 | ||||
-rw-r--r-- | src/shared/util.c | 24 | ||||
-rw-r--r-- | src/shared/util.h | 1 | ||||
-rw-r--r-- | src/sleep/sleep.c | 20 | ||||
-rw-r--r-- | src/systemctl/systemctl.c | 17 | ||||
-rw-r--r-- | src/test/test-sleep.c | 39 | ||||
-rw-r--r-- | units/.gitignore | 1 | ||||
-rw-r--r-- | units/hybrid-sleep.target | 13 | ||||
-rw-r--r-- | units/systemd-hybrid-sleep.service.in | 17 |
18 files changed, 264 insertions, 45 deletions
diff --git a/.gitignore b/.gitignore index 2fc2bfd287..94a85423ab 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /test-journal-enum +/test-sleep /localectl /hostnamectl /timedatectl diff --git a/Makefile.am b/Makefile.am index 3d96500c89..fadc1c7b59 100644 --- a/Makefile.am +++ b/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 diff --git a/man/logind.conf.xml b/man/logind.conf.xml index 3d83d2c81c..29469d37e1 100644 --- a/man/logind.conf.xml +++ b/man/logind.conf.xml @@ -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 diff --git a/man/systemctl.xml b/man/systemctl.xml index d547410696..786c2bdfcf 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -1181,6 +1181,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> <listitem><para>Switches to a diff --git a/man/systemd-suspend.service.xml b/man/systemd-suspend.service.xml index 604aab6f6b..b9464c8826 100644 --- a/man/systemd-suspend.service.xml +++ b/man/systemd-suspend.service.xml @@ -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> - - <para>Immediately before entering system suspend and - hibernation - <filename>systemd-suspend.service</filename> will run - all executables in + 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/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> diff --git a/man/systemd.special.xml b/man/systemd.special.xml index 3e5f653494..6b8e0ec7f0 100644 --- a/man/systemd.special.xml +++ b/man/systemd.special.xml @@ -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>, @@ -303,6 +304,15 @@ </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> <para>A special target unit @@ -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> diff --git a/src/core/special.h b/src/core/special.h index e3004a518d..8923f340ba 100644 --- a/src/core/special.h +++ b/src/core/special.h @@ -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" diff --git a/src/login/logind-button.c b/src/login/logind-button.c index 8fdab789bc..753d95454c 100644 --- a/src/login/logind-button.c +++ b/src/login/logind-button.c @@ -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"); diff --git a/src/login/logind-button.h b/src/login/logind-button.h index ca820ed7e5..827a03e460 100644 --- a/src/login/logind-button.h +++ b/src/login/logind-button.h @@ -32,6 +32,7 @@ typedef enum HandleButton { HANDLE_KEXEC, HANDLE_SUSPEND, HANDLE_HIBERNATE, + HANDLE_HYBRID_SLEEP, _HANDLE_BUTTON_MAX, _HANDLE_BUTTON_INVALID = -1 } HandleButton; diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index a7647e3c80..3bcb91bf13 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -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); diff --git a/src/shared/util.c b/src/shared/util.c index db8e75b628..2d4a4c1102 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -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); diff --git a/src/shared/util.h b/src/shared/util.h index f6a4c1ea6c..f726263dd3 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -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); diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c index 2f312675c5..218de3a567 100644 --- a/src/sleep/sleep.c +++ b/src/sleep/sleep.c @@ -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); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 41dcefb675..b9e64a677d 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -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 }, diff --git a/src/test/test-sleep.c b/src/test/test-sleep.c new file mode 100644 index 0000000000..5a98ecda2f --- /dev/null +++ b/src/test/test-sleep.c @@ -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; +} diff --git a/units/.gitignore b/units/.gitignore index c72e2cbee3..63c7ba06bb 100644 --- a/units/.gitignore +++ b/units/.gitignore @@ -1,3 +1,4 @@ +/systemd-hybrid-sleep.service /systemd-journal-gatewayd.service /systemd-journal-flush.service /systemd-hibernate.service diff --git a/units/hybrid-sleep.target b/units/hybrid-sleep.target new file mode 100644 index 0000000000..d2d3409225 --- /dev/null +++ b/units/hybrid-sleep.target @@ -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 diff --git a/units/systemd-hybrid-sleep.service.in b/units/systemd-hybrid-sleep.service.in new file mode 100644 index 0000000000..914b686c36 --- /dev/null +++ b/units/systemd-hybrid-sleep.service.in @@ -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 |