<?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
# 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', [], ''],
['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'],
['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'],
['elogind-cgls', '1', [], ''],
['elogind-cgtop', '1', [], ''],
['elogind-coredump',
+ ''],
'8',
['elogind-coredump.socket', 'elogind-coredump@.service'],
'ENABLE_COREDUMP'],
['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',
['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-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'],
''],
['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',
#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"
[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
[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
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;
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 &&
[HANDLE_SUSPEND] = "suspend",
[HANDLE_HIBERNATE] = "hibernate",
[HANDLE_HYBRID_SLEEP] = "hybrid-sleep",
+ [HANDLE_SUSPEND_THEN_HIBERNATE] = "suspend-then-hibernate",
[HANDLE_LOCK] = "lock"
};
HANDLE_SUSPEND,
HANDLE_HIBERNATE,
HANDLE_HYBRID_SLEEP,
+ HANDLE_SUSPEND_THEN_HIBERNATE,
HANDLE_LOCK,
_HANDLE_ACTION_MAX,
_HANDLE_ACTION_INVALID = -1
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;
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))
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");
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)
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
* 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);
}
}
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. */
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
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(
"org.freedesktop.login1.hibernate",
"org.freedesktop.login1.hibernate-multiple-sessions",
"org.freedesktop.login1.hibernate-ignore-inhibit",
- "suspend-to-hibernate",
+ "suspend-then-hibernate",
error);
}
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),
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;
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"/>
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();
|| !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")
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"
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"
" 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);
}
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;
}
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);
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;
}