chiark / gitweb /
Rename suspend-to-hibernate to suspend-then-hibernate
authorMario Limonciello <mario.limonciello@dell.com>
Wed, 28 Mar 2018 16:00:06 +0000 (11:00 -0500)
committerSven Eden <yamakuzure@gmx.net>
Fri, 24 Aug 2018 14:47:08 +0000 (16:47 +0200)
Per some discussion with Gnome folks, they would prefer this name
as it's more descriptive of what's happening.

man/logind.conf.xml
man/rules/meson.build
src/basic/special.h
src/login/logind-action.c
src/login/logind-action.h
src/login/logind-dbus.c
src/login/org.freedesktop.login1.conf
src/shared/sleep-config.c
src/sleep/sleep.c

index 9c5dfe1eaade010b40ebd817869bb672e8f96cac..a932cbb9fc3383af96fee2c980682a38b507e10c 100644 (file)
@@ -1,6 +1,9 @@
 <?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
 <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY % entities SYSTEM "custom-entities.ent" >
+%entities;
+]>
 
 <!--
   SPDX-License-Identifier: LGPL-2.1+
         corresponding to the session and all processes inside that scope will be
         terminated. If false, the scope is "abandoned", see
         <citerefentry><refentrytitle>systemd.scope</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+        and processes are not killed. Defaults to <literal>&KILL_USER_PROCESSES;</literal>,
         --><!-- else -->
         user should be killed when the user logs out. If true, the processes
         listed in their session cgroup will be terminated. If false, the session cgroup
         is ignored
         <!-- // 0 -->
-        and processes are not killed. Defaults to <literal>yes</literal>,
         but see the options <varname>KillOnlyUsers=</varname> and
         <varname>KillExcludeUsers=</varname> below.</para>
 
         <literal>kexec</literal>,
         <literal>suspend</literal>,
         <literal>hibernate</literal>,
-        <literal>hybrid-sleep</literal>, and
+        <literal>hybrid-sleep</literal>,
+        <literal>suspend-then-hibernate</literal>, and
         <literal>lock</literal>.
         Defaults to <literal>ignore</literal>.</para>
 
         <literal>kexec</literal>,
         <literal>suspend</literal>,
         <literal>hibernate</literal>,
-        <literal>hybrid-sleep</literal>, and
+        <literal>hybrid-sleep</literal>,
+        <literal>suspend-then-hibernate</literal>, and
         <literal>lock</literal>.
         If <literal>ignore</literal>, logind will never handle these
         keys. If <literal>lock</literal>, all running sessions will be
index e33dc4393bf010461bcfdb33724c9801991c3d03..fbd163e0e5e9653c1cd3e6f8b2e250894f211fbf 100644 (file)
@@ -1,6 +1,5 @@
 # Do not edit. Generated by make-man-rules.py.
 manpages = [
- ['pam_elogind', '8', [], 'HAVE_PAM'],
 ['binfmt.d', '5', [], 'ENABLE_BINFMT'],
  ['bootctl', '1', [], 'ENABLE_EFI'],
  ['bootup', '7', [], ''],
@@ -43,6 +42,7 @@ manpages = [
  ['nss-resolve', '8', ['libnss_resolve.so.2'], 'ENABLE_RESOLVE'],
  ['nss-elogind', '8', ['libnss_elogind.so.2'], 'ENABLE_NSS_SYSTEMD'],
  ['os-release', '5', [], ''],
+ ['pam_elogind', '8', [], 'HAVE_PAM'],
  ['resolved.conf', '5', ['resolved.conf.d'], 'ENABLE_RESOLVE'],
  ['runlevel', '8', [], 'ENABLE_UTMP'],
  ['sd-boot', '7', [], 'ENABLE_EFI'],
@@ -517,7 +517,6 @@ manpages = [
   ['elogind-ask-password-console.path',
    'elogind-ask-password-wall.path',
    'elogind-ask-password-wall.service'],
-  ''],
  ['elogind-ask-password', '1', [], ''],
  ['elogind-backlight@.service', '8', ['elogind-backlight'], 'ENABLE_BACKLIGHT'],
  ['elogind-binfmt.service', '8', ['elogind-binfmt'], 'ENABLE_BINFMT'],
@@ -525,6 +524,7 @@ manpages = [
  ['elogind-cgls', '1', [], ''],
  ['elogind-cgtop', '1', [], ''],
  ['elogind-coredump',
+  ''],
   '8',
   ['elogind-coredump.socket', 'elogind-coredump@.service'],
   'ENABLE_COREDUMP'],
@@ -543,18 +543,18 @@ manpages = [
  ['elogind-escape', '1', [], ''],
  ['elogind-firstboot', '1', ['elogind-firstboot.service'], 'ENABLE_FIRSTBOOT'],
  ['elogind-fsck@.service',
-  '8',
   ['elogind-fsck', 'elogind-fsck-root.service'],
-  ''],
  ['elogind-fstab-generator', '8', [], ''],
  ['elogind-getty-generator', '8', [], ''],
  ['elogind-gpt-auto-generator', '8', [], ''],
  ['elogind-halt.service',
-  '8',
   ['elogind-kexec.service',
    'elogind-poweroff.service',
    'elogind-reboot.service',
    'elogind-shutdown'],
+  '8',
+  ''],
+  '8',
   ''],
  ['elogind-hibernate-resume-generator', '8', [], 'ENABLE_HIBERNATE'],
  ['elogind-hibernate-resume@.service',
@@ -576,27 +576,27 @@ manpages = [
  ['elogind-journal-remote', '8', [], 'HAVE_MICROHTTPD'],
  ['elogind-journal-upload', '8', [], 'HAVE_MICROHTTPD'],
  ['elogind-journald.service',
-  '8',
   ['elogind-journald',
    'elogind-journald-audit.socket',
    'elogind-journald-dev-log.socket',
    'elogind-journald.socket'],
-  ''],
  ['elogind-localed.service', '8', ['elogind-localed'], 'ENABLE_LOCALED'],
  ['elogind.service', '8', ['elogind'], 'ENABLE_LOGIND'],
  ['elogind-machine-id-commit.service', '8', [], ''],
  ['elogind-machine-id-setup', '1', [], ''],
  ['elogind-machined.service', '8', ['elogind-machined'], 'ENABLE_MACHINED'],
  ['elogind-makefs@.service',
-  '8',
   ['elogind-growfs',
    'elogind-growfs@.service',
    'elogind-makefs',
    'elogind-makeswap@.service'],
-  ''],
  ['elogind-modules-load.service', '8', ['elogind-modules-load'], 'HAVE_KMOD'],
  ['elogind-mount', '1', ['elogind-umount'], ''],
  ['elogind-networkd-wait-online.service',
+  '8',
+  ''],
+  '8',
+  ''],
   '8',
   ['elogind-networkd-wait-online'],
   'ENABLE_NETWORKD'],
@@ -625,15 +625,15 @@ manpages = [
  ['elogind-socket-activate', '1', [], ''],
  ['elogind-socket-proxyd', '8', [], ''],
  ['elogind-suspend.service',
-  '8',
   ['elogind-hibernate.service',
    'elogind-hybrid-sleep.service',
-   'elogind-suspend-to-hibernate.service',
    'elogind-sleep'],
-  ''],
  ['elogind-sysctl.service', '8', ['elogind-sysctl'], ''],
  ['elogind-system-update-generator', '8', [], ''],
  ['elogind-system.conf',
+  '8',
+   'elogind-suspend-then-hibernate.service',
+  ''],
   '5',
   ['system.conf.d', 'elogind-user.conf', 'user.conf.d'],
   ''],
@@ -643,18 +643,18 @@ manpages = [
  ['elogind-timedated.service', '8', ['elogind-timedated'], 'ENABLE_TIMEDATED'],
  ['elogind-timesyncd.service', '8', ['elogind-timesyncd'], 'ENABLE_TIMESYNCD'],
  ['elogind-tmpfiles',
-  '8',
   ['elogind-tmpfiles-clean.service',
    'elogind-tmpfiles-clean.timer',
    'elogind-tmpfiles-setup-dev.service',
    'elogind-tmpfiles-setup.service'],
-  ''],
  ['elogind-tty-ask-password-agent', '1', [], ''],
  ['elogind-udevd.service',
-  '8',
   ['elogind-udevd',
    'elogind-udevd-control.socket',
    'elogind-udevd-kernel.socket'],
+  '8',
+  ''],
+  '8',
   ''],
  ['elogind-update-done.service', '8', ['elogind-update-done'], ''],
  ['elogind-update-utmp.service',
index c058b1d85255cb4f89e42f970d974e4335d95f22..808d8896ae681cb97842be3bed9eec12f6be7564 100644 (file)
@@ -37,6 +37,7 @@
 #define SPECIAL_SUSPEND_TARGET "suspend.target"
 #define SPECIAL_HIBERNATE_TARGET "hibernate.target"
 #define SPECIAL_HYBRID_SLEEP_TARGET "hybrid-sleep.target"
+#define SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET "suspend-then-hibernate.target"
 
 /* Special boot targets */
 #define SPECIAL_RESCUE_TARGET "rescue.target"
index bae42db999dad0340a23a2255750fcd8975ef3cb..f431a1b80d3ea40c33e0eee0b2d66fae8562ee7d 100644 (file)
@@ -53,7 +53,8 @@ int manager_handle_action(
                 [HANDLE_KEXEC] = "Rebooting via kexec...",
                 [HANDLE_SUSPEND] = "Suspending...",
                 [HANDLE_HIBERNATE] = "Hibernating...",
-                [HANDLE_HYBRID_SLEEP] = "Hibernating and suspending..."
+                [HANDLE_HYBRID_SLEEP] = "Hibernating and suspending...",
+                [HANDLE_SUSPEND_THEN_HIBERNATE] = "Suspending, then hibernating...",
         };
 
 #if 0 /// elogind does this itself. No target table required
@@ -64,7 +65,8 @@ int manager_handle_action(
                 [HANDLE_KEXEC] = SPECIAL_KEXEC_TARGET,
                 [HANDLE_SUSPEND] = SPECIAL_SUSPEND_TARGET,
                 [HANDLE_HIBERNATE] = SPECIAL_HIBERNATE_TARGET,
-                [HANDLE_HYBRID_SLEEP] = SPECIAL_HYBRID_SLEEP_TARGET
+                [HANDLE_HYBRID_SLEEP] = SPECIAL_HYBRID_SLEEP_TARGET,
+                [HANDLE_SUSPEND_THEN_HIBERNATE] = SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET,
         };
 #endif // 0
 
@@ -119,6 +121,8 @@ int manager_handle_action(
                 supported = can_sleep("hibernate") > 0;
         else if (handle == HANDLE_HYBRID_SLEEP)
                 supported = can_sleep("hybrid-sleep") > 0;
+        else if (handle == HANDLE_SUSPEND_THEN_HIBERNATE)
+                supported = can_sleep("suspend-then-hibernate") > 0;
 #else
         if (handle == HANDLE_SUSPEND)
                 supported = can_sleep(m, "suspend") > 0;
@@ -142,7 +146,9 @@ int manager_handle_action(
                 return -EALREADY;
         }
 
-        inhibit_operation = IN_SET(handle, HANDLE_SUSPEND, HANDLE_HIBERNATE, HANDLE_HYBRID_SLEEP) ? INHIBIT_SLEEP : INHIBIT_SHUTDOWN;
+        inhibit_operation = IN_SET(handle, HANDLE_SUSPEND, HANDLE_HIBERNATE,
+                                           HANDLE_HYBRID_SLEEP,
+                                           HANDLE_SUSPEND_THEN_HIBERNATE) ? INHIBIT_SLEEP : INHIBIT_SHUTDOWN;
 
         /* If the actual operation is inhibited, warn and fail */
         if (!ignore_inhibited &&
@@ -193,6 +199,7 @@ static const char* const handle_action_table[_HANDLE_ACTION_MAX] = {
         [HANDLE_SUSPEND] = "suspend",
         [HANDLE_HIBERNATE] = "hibernate",
         [HANDLE_HYBRID_SLEEP] = "hybrid-sleep",
+        [HANDLE_SUSPEND_THEN_HIBERNATE] = "suspend-then-hibernate",
         [HANDLE_LOCK] = "lock"
 };
 
index 8c31ec42becd7606168e5cb929cee0cb993cf08f..9f5dee684cfea1db9230db0d346ff568c8cd860a 100644 (file)
@@ -29,6 +29,7 @@ typedef enum HandleAction {
         HANDLE_SUSPEND,
         HANDLE_HIBERNATE,
         HANDLE_HYBRID_SLEEP,
+        HANDLE_SUSPEND_THEN_HIBERNATE,
         HANDLE_LOCK,
         _HANDLE_ACTION_MAX,
         _HANDLE_ACTION_INVALID = -1
index 165274461d069235f5c585927b0c94c04c3b1cd8..7f99a8cce26a9ea9711e86157adb6a8c5b2080e3 100644 (file)
@@ -661,10 +661,9 @@ static int method_list_inhibitors(sd_bus_message *message, void *userdata, sd_bu
 
 static int method_create_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         const char *service, *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *desktop;
-        uint32_t audit_id = 0;
-        _cleanup_free_ char *unit = NULL;
-        _cleanup_free_ char *id = NULL;
+        _cleanup_free_ char *unit = NULL, *id = NULL;
         Session *session = NULL;
+        uint32_t audit_id = 0;
         Manager *m = userdata;
         User *user = NULL;
         Seat *seat = NULL;
@@ -688,7 +687,7 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
 
         if (!uid_is_valid(uid))
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid UID");
-        if (leader < 0 || leader == 1)
+        if (leader < 0 || leader == 1 || leader == getpid_cached())
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
 
         if (isempty(type))
@@ -734,7 +733,7 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
                 if (v <= 0)
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot determine VT number from virtual console TTY %s", tty);
 
-                if (!vtnr)
+                if (vtnr == 0)
                         vtnr = (uint32_t) v;
                 else if (vtnr != (uint32_t) v)
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified TTY and VT number do not match");
@@ -752,7 +751,7 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
 
         if (seat) {
                 if (seat_has_vts(seat)) {
-                        if (!vtnr || vtnr > 63)
+                        if (vtnr <= 0 || vtnr > 63)
                                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "VT number out of range");
                 } else {
                         if (vtnr != 0)
@@ -792,16 +791,13 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
                         return r;
         }
 
-        /*
-         * Check if we are already in a logind session.  Or if we are in user@.service
-         * which is a special PAM session that avoids creating a logind session.
-         */
-        r = cg_pid_get_unit(leader, &unit);
+        /* Check if we are already in a logind session. Or if we are in user@.service which is a special PAM session
+         * that avoids creating a logind session. */
+        r = manager_get_user_by_pid(m, leader, NULL);
         if (r < 0)
                 return r;
-        if (hashmap_get(m->session_units, unit) ||
-            hashmap_get(m->user_units, unit))
-                return sd_bus_error_setf(error, BUS_ERROR_SESSION_BUSY, "Already running in a session");
+        if (r > 0)
+                return sd_bus_error_setf(error, BUS_ERROR_SESSION_BUSY, "Already running in a session or user slice");
 
         /*
          * Old gdm and lightdm start the user-session on the same VT as
@@ -835,9 +831,8 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
                  * the audit data and let's better register a new
                  * ID */
                 if (hashmap_get(m->sessions, id)) {
-                        log_warning("Existing logind session ID %s used by new audit session, ignoring", id);
+                        log_warning("Existing logind session ID %s used by new audit session, ignoring.", id);
                         audit_id = AUDIT_SESSION_INVALID;
-
                         id = mfree(id);
                 }
         }
@@ -930,8 +925,7 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
         session->create_message = sd_bus_message_ref(message);
 
 #if 0 /// UNNEEDED by elogind
-        /* Now, let's wait until the slice unit and stuff got
-         * created. We send the reply back from
+        /* Now, let's wait until the slice unit and stuff got created. We send the reply back from
          * session_send_create_reply(). */
 #else
         /* We reply directly. */
@@ -2045,12 +2039,12 @@ static int method_hybrid_sleep(sd_bus_message *message, void *userdata, sd_bus_e
                         error);
 }
 
-static int method_suspend_to_hibernate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_suspend_then_hibernate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
 
         return method_do_shutdown_or_sleep(
                         m, message,
-                        SPECIAL_SUSPEND_TO_HIBERNATE_TARGET,
+                        SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET,
 #else
                         HANDLE_HYBRID_SLEEP,
 #endif // 0
@@ -2542,7 +2536,7 @@ static int method_can_hybrid_sleep(sd_bus_message *message, void *userdata, sd_b
                         error);
 }
 
-static int method_can_suspend_to_hibernate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_can_suspend_then_hibernate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
 
         return method_can_shutdown_or_sleep(
@@ -2551,7 +2545,7 @@ static int method_can_suspend_to_hibernate(sd_bus_message *message, void *userda
                         "org.freedesktop.login1.hibernate",
                         "org.freedesktop.login1.hibernate-multiple-sessions",
                         "org.freedesktop.login1.hibernate-ignore-inhibit",
-                        "suspend-to-hibernate",
+                        "suspend-then-hibernate",
                         error);
 }
 
@@ -2889,14 +2883,14 @@ const sd_bus_vtable manager_vtable[] = {
         SD_BUS_METHOD("Suspend", "b", NULL, method_suspend, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("Hibernate", "b", NULL, method_hibernate, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("HybridSleep", "b", NULL, method_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("SuspendToHibernate", "b", NULL, method_suspend_to_hibernate, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SuspendThenHibernate", "b", NULL, method_suspend_then_hibernate, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CanPowerOff", NULL, "s", method_can_poweroff, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CanReboot", NULL, "s", method_can_reboot, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CanHalt", NULL, "s", method_can_halt, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CanSuspend", NULL, "s", method_can_suspend, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CanHibernate", NULL, "s", method_can_hibernate, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CanHybridSleep", NULL, "s", method_can_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("CanSuspendToHibernate", NULL, "s", method_can_suspend_to_hibernate, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("CanSuspendThenHibernate", NULL, "s", method_can_suspend_then_hibernate, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("ScheduleShutdown", "st", NULL, method_schedule_shutdown, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CancelScheduledShutdown", NULL, "b", method_cancel_scheduled_shutdown, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("Inhibit", "ssss", "h", method_inhibit, SD_BUS_VTABLE_UNPRIVILEGED),
@@ -3253,13 +3247,8 @@ int manager_start_scope(
                         return r;
         }
 
-        /* cgroup empty notification is not available in containers
-         * currently. To make this less problematic, let's shorten the
-         * stop timeout for sessions, so that we don't wait
-         * forever. */
-
-        /* Make sure that the session shells are terminated with
-         * SIGHUP since bash and friends tend to ignore SIGTERM */
+        /* Make sure that the session shells are terminated with SIGHUP since bash and friends tend to ignore
+         * SIGTERM */
         r = sd_bus_message_append(m, "(sv)", "SendSIGHUP", "b", true);
         if (r < 0)
                 return r;
index a25eb44016d9af9f8b3193565cf73eec39c3aa8a..1f81604b5c497e7ace76cdcf28450de929ca1e0a 100644 (file)
                        send_interface="org.freedesktop.login1.Manager"
                        send_member="HybridSleep"/>
 
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="SuspendThenHibernate"/>
+
                 <allow send_destination="org.freedesktop.login1"
                        send_interface="org.freedesktop.login1.Manager"
                        send_member="CanPowerOff"/>
                        send_interface="org.freedesktop.login1.Manager"
                        send_member="CanHybridSleep"/>
 
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="CanSuspendThenHibernate"/>
+
                 <allow send_destination="org.freedesktop.login1"
                        send_interface="org.freedesktop.login1.Manager"
                        send_member="ScheduleShutdown"/>
index 1f7792ae5b3098508bf5dacb004a623b0a31cd84..a9167fc29687a20affd310c45caf600a904fde6d 100644 (file)
@@ -97,13 +97,13 @@ int parse_sleep_config(const char *verb, char ***_modes, char ***_states, usec_t
                 else
                         states = strv_new("disk", NULL);
 
-        } else if (streq(verb, "suspend-to-hibernate"))
+        } else if (streq(verb, "suspend-then-hibernate"))
                 modes = states = NULL;
         else
                 assert_not_reached("what verb");
 
         if ((!modes && STR_IN_SET(verb, "hibernate", "hybrid-sleep")) ||
-            (!states && !streq(verb, "suspend-to-hibernate"))) {
+            (!states && !streq(verb, "suspend-then-hibernate"))) {
                 strv_free(modes);
                 strv_free(states);
                 return log_oom();
@@ -319,12 +319,14 @@ int can_sleep(const char *verb) {
             || !can_sleep_disk(m->suspend_mode) ) )
                 return false;
         assert(STR_IN_SET(verb, "suspend", "hibernate", "hybrid-sleep", "suspend-to-hibernate"));
+        assert(STR_IN_SET(verb, "suspend", "hibernate", "hybrid-sleep", "suspend-then-hibernate"));
 
         if ( streq(verb, "hibernate")
           && ( !can_sleep_state(m->hibernate_state)
             || !can_sleep_disk(m->hibernate_mode) ) )
                 return false;
         if (streq(verb, "suspend-to-hibernate"))
+        if (streq(verb, "suspend-then-hibernate"))
                 return can_s2h();
 
         if ( streq(verb, "hybrid-sleep")
index f0873c989f12518926d487929365cc15acb40542..66c9d04fb4a60a7949195e030a4c9af1894cab95 100644 (file)
@@ -4,6 +4,7 @@
 
   Copyright 2012 Lennart Poettering
   Copyright 2013 Zbigniew JÄ™drzejewski-Szmek
+  Copyright 2018 Dell Inc.
 
   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
 
 #include "sd-messages.h"
 
+//#include "parse-util.h"
 #include "def.h"
 #include "exec-util.h"
 #include "fd-util.h"
 #include "fileio.h"
 //#include "log.h"
 //#include "sleep-config.h"
+//#include "stdio-util.h"
 //#include "string-util.h"
 #include "strv.h"
 //#include "util.h"
@@ -138,6 +141,83 @@ static int execute(char **modes, char **states) {
         return r;
 }
 
+static int read_wakealarm(uint64_t *result) {
+        _cleanup_free_ char *t = NULL;
+
+        if (read_one_line_file("/sys/class/rtc/rtc0/since_epoch", &t) >= 0)
+                return safe_atou64(t, result);
+        return -EBADF;
+}
+
+static int write_wakealarm(const char *str) {
+
+        _cleanup_fclose_ FILE *f = NULL;
+        int r;
+
+        f = fopen("/sys/class/rtc/rtc0/wakealarm", "we");
+        if (!f)
+                return log_error_errno(errno, "Failed to open /sys/class/rtc/rtc0/wakealarm: %m");
+
+        r = write_string_stream(f, str, 0);
+        if (r < 0)
+                return log_error_errno(r, "Failed to write '%s' to /sys/class/rtc/rtc0/wakealarm: %m", str);
+
+        return 0;
+}
+
+static int execute_s2h(usec_t hibernate_delay_sec) {
+
+        _cleanup_strv_free_ char **hibernate_modes = NULL, **hibernate_states = NULL,
+                                 **suspend_modes = NULL, **suspend_states = NULL;
+        usec_t orig_time, cmp_time;
+        char time_str[DECIMAL_STR_MAX(uint64_t)];
+        int r;
+
+        r = parse_sleep_config("suspend", &suspend_modes, &suspend_states,
+                               NULL);
+        if (r < 0)
+                return r;
+
+        r = parse_sleep_config("hibernate", &hibernate_modes,
+                               &hibernate_states, NULL);
+        if (r < 0)
+                return r;
+
+        r = read_wakealarm(&orig_time);
+        if (r < 0)
+                return log_error_errno(errno, "Failed to read time: %d", r);
+
+        orig_time += hibernate_delay_sec / USEC_PER_SEC;
+        xsprintf(time_str, "%" PRIu64, orig_time);
+
+        r = write_wakealarm(time_str);
+        if (r < 0)
+                return r;
+
+        log_debug("Set RTC wake alarm for %s", time_str);
+
+        r = execute(suspend_modes, suspend_states);
+        if (r < 0)
+                return r;
+
+        r = read_wakealarm(&cmp_time);
+        if (r < 0)
+                return log_error_errno(errno, "Failed to read time: %d", r);
+
+        /* reset RTC */
+        r = write_wakealarm("0");
+        if (r < 0)
+                return r;
+
+        log_debug("Woke up at %"PRIu64, cmp_time);
+
+        /* if woken up after alarm time, hibernate */
+        if (cmp_time >= orig_time)
+                r = execute(hibernate_modes, hibernate_states);
+
+        return r;
+}
+
 #if 0 /// elogind calls execute() by itself and does not need another binary
 static void help(void) {
         printf("%s COMMAND\n\n"
@@ -148,6 +228,8 @@ static void help(void) {
                "  suspend              Suspend the system\n"
                "  hibernate            Hibernate the system\n"
                "  hybrid-sleep         Both hibernate and suspend the system\n"
+               "  suspend-then-hibernate Initially suspend and then hibernate\n"
+               "                       the system after a fixed period of time\n"
                , program_invocation_short_name);
 }
 
@@ -193,7 +275,8 @@ static int parse_argv(int argc, char *argv[]) {
 
         if (!streq(arg_verb, "suspend") &&
             !streq(arg_verb, "hibernate") &&
-            !streq(arg_verb, "hybrid-sleep")) {
+            !streq(arg_verb, "hybrid-sleep") &&
+            !streq(arg_verb, "suspend-then-hibernate")) {
                 log_error("Unknown command '%s'.", arg_verb);
                 return -EINVAL;
         }
@@ -203,6 +286,7 @@ static int parse_argv(int argc, char *argv[]) {
 
 int main(int argc, char *argv[]) {
         _cleanup_strv_free_ char **modes = NULL, **states = NULL;
+        usec_t delay = 0;
         int r;
 
         log_set_target(LOG_TARGET_AUTO);
@@ -213,12 +297,14 @@ int main(int argc, char *argv[]) {
         if (r <= 0)
                 goto finish;
 
-        r = parse_sleep_config(arg_verb, &modes, &states);
+        r = parse_sleep_config(arg_verb, &modes, &states, &delay);
         if (r < 0)
                 goto finish;
 
-        r = execute(modes, states);
-
+        if (streq(arg_verb, "suspend-then-hibernate"))
+                r = execute_s2h(delay);
+        else
+                r = execute(modes, states);
 finish:
         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 }