summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/logind.conf.xml13
-rw-r--r--man/rules/meson.build30
-rw-r--r--src/basic/special.h1
-rw-r--r--src/login/logind-action.c13
-rw-r--r--src/login/logind-action.h1
-rw-r--r--src/login/logind-dbus.c51
-rw-r--r--src/login/org.freedesktop.login1.conf8
-rw-r--r--src/shared/sleep-config.c6
-rw-r--r--src/sleep/sleep.c94
9 files changed, 158 insertions, 59 deletions
diff --git a/man/logind.conf.xml b/man/logind.conf.xml
index 9c5dfe1ea..a932cbb9f 100644
--- a/man/logind.conf.xml
+++ b/man/logind.conf.xml
@@ -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+
@@ -156,12 +159,12 @@
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>
@@ -216,7 +219,8 @@
<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>
@@ -265,7 +269,8 @@
<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
diff --git a/man/rules/meson.build b/man/rules/meson.build
index e33dc4393..fbd163e0e 100644
--- a/man/rules/meson.build
+++ b/man/rules/meson.build
@@ -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,28 +576,28 @@ 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'],
['elogind-networkd.service', '8', ['elogind-networkd'], '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',
diff --git a/src/basic/special.h b/src/basic/special.h
index c058b1d85..808d8896a 100644
--- a/src/basic/special.h
+++ b/src/basic/special.h
@@ -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"
diff --git a/src/login/logind-action.c b/src/login/logind-action.c
index bae42db99..f431a1b80 100644
--- a/src/login/logind-action.c
+++ b/src/login/logind-action.c
@@ -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"
};
diff --git a/src/login/logind-action.h b/src/login/logind-action.h
index 8c31ec42b..9f5dee684 100644
--- a/src/login/logind-action.h
+++ b/src/login/logind-action.h
@@ -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
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index 165274461..7f99a8cce 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -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;
diff --git a/src/login/org.freedesktop.login1.conf b/src/login/org.freedesktop.login1.conf
index a25eb4401..1f81604b5 100644
--- a/src/login/org.freedesktop.login1.conf
+++ b/src/login/org.freedesktop.login1.conf
@@ -152,6 +152,10 @@
<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"/>
<allow send_destination="org.freedesktop.login1"
@@ -176,6 +180,10 @@
<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"/>
<allow send_destination="org.freedesktop.login1"
diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c
index 1f7792ae5..a9167fc29 100644
--- a/src/shared/sleep-config.c
+++ b/src/shared/sleep-config.c
@@ -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")
diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c
index f0873c989..66c9d04fb 100644
--- a/src/sleep/sleep.c
+++ b/src/sleep/sleep.c
@@ -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
@@ -25,12 +26,14 @@
#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;
}