[systemd-commits] 2 commits - .gitignore Makefile.am TODO man/logind.conf.xml man/systemctl.xml man/systemd-suspend.service.xml man/systemd.special.xml src/core src/login src/shared src/sleep src/systemctl src/test units/.gitignore units/hybrid-sleep.target units/systemd-hybrid-sleep.service.in

Lennart Poettering lennart at kemper.freedesktop.org
Sat Oct 27 15:51:26 PDT 2012


 .gitignore                            |    1 
 Makefile.am                           |   17 +++++++-
 TODO                                  |   10 +---
 man/logind.conf.xml                   |    5 +-
 man/systemctl.xml                     |    5 ++
 man/systemd-suspend.service.xml       |   42 ++++++++++++--------
 man/systemd.special.xml               |   15 +++++--
 src/core/special.h                    |    1 
 src/login/logind-button.c             |   21 +++++-----
 src/login/logind-button.h             |    1 
 src/login/logind-dbus.c               |   69 ++++++++++++++++++++++++++++++----
 src/shared/util.c                     |   24 +++++++++++
 src/shared/util.h                     |    1 
 src/sleep/sleep.c                     |   20 ++++++++-
 src/systemctl/systemctl.c             |   17 ++++++--
 src/test/test-sleep.c                 |   39 +++++++++++++++++++
 units/.gitignore                      |    1 
 units/hybrid-sleep.target             |   13 ++++++
 units/systemd-hybrid-sleep.service.in |   17 ++++++++
 19 files changed, 268 insertions(+), 51 deletions(-)

New commits:
commit 9ec82de1725ddaab333149171b790d62c47ae133
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Oct 28 00:49:49 2012 +0200

    update TODO

diff --git a/TODO b/TODO
index d82fca0..88cfb4b 100644
--- a/TODO
+++ b/TODO
@@ -19,6 +19,10 @@ F18:
 
 Features:
 
+* sd_journal_enumerate_data() implies XZ-decoding compressed field, this sucks hard
+
+* if booted in "quiet" mode, and an error happens, turn on status output again, so that the emergency mode isn't totally surprising
+
 * localectl: add listing support for X11 keymaps, by parsing /usr/share/X11/xkb/rules/xorg.lst
 
 * libunwind support for coredump pattern hook, and includes this in
@@ -26,10 +30,6 @@ Features:
   unwind coredumps since a few weeks ago. This probably requires that
   we have nice support for multi-line messages on display in logs-show.c.
 
-* coredumpctl: show dates for coredumps
-
-* coredumpctl: add gdb command that invokes gdb on the selected coredump an binary in one go
-
 * figure out relation of --all and --full in the various tools
 
 * journal: when writing journal auto-rotate if time jumps backwards
@@ -78,8 +78,6 @@ Features:
 
 * clean up date formatting and parsing so that all absolute/relative timestamps we format can also be parsed
 
-* introduce hybrid-sleep.target
-
 * document unit_name_mangle()
 
 * add new command to systemctl: "systemctl system-reexec" which reexecs as many daemons as virtually possible

commit 6524990fdc98370ecba5d9f73e67161e8798c010
Author: Lennart Poettering <lennart at poettering.net>
Date:   Sun Oct 28 00:49:04 2012 +0200

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

diff --git a/.gitignore b/.gitignore
index 2fc2bfd..94a8542 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 3d96500..fadc1c7 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 at .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 3d83d2c..29469d3 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 d547410..786c2bd 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 604aab6..b9464c8 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 3e5f653..6b8e0ec 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 e3004a5..8923f34 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 8fdab78..753d954 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 ca820ed..827a03e 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 a7647e3..3bcb91b 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 db8e75b..2d4a4c1 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 f6a4c1e..f726263 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 2f31267..218de3a 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 41dcefb..b9e64a6 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 0000000..5a98ecd
--- /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 c72e2cb..63c7ba0 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 0000000..d2d3409
--- /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 0000000..914b686
--- /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



More information about the systemd-commits mailing list