summaryrefslogtreecommitdiffstats
path: root/src/sleep/sleep.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sleep/sleep.c')
-rw-r--r--src/sleep/sleep.c90
1 files changed, 42 insertions, 48 deletions
diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c
index 21062b2..0402bb0 100644
--- a/src/sleep/sleep.c
+++ b/src/sleep/sleep.c
@@ -23,10 +23,12 @@
#include "build.h"
#include "bus-error.h"
#include "bus-locator.h"
+#include "bus-unit-util.h"
#include "bus-util.h"
#include "constants.h"
#include "devnum-util.h"
#include "efivars.h"
+#include "env-util.h"
#include "exec-util.h"
#include "fd-util.h"
#include "fileio.h"
@@ -149,22 +151,22 @@ static int write_state(int fd, char * const *states) {
return r;
}
-static int write_mode(char * const *modes) {
- int r = 0;
+static int write_mode(const char *path, char * const *modes) {
+ int r, ret = 0;
- STRV_FOREACH(mode, modes) {
- int k;
+ assert(path);
- k = write_string_file("/sys/power/disk", *mode, WRITE_STRING_FILE_DISABLE_BUFFER);
- if (k >= 0) {
- log_debug("Using sleep disk mode '%s'.", *mode);
+ STRV_FOREACH(mode, modes) {
+ r = write_string_file(path, *mode, WRITE_STRING_FILE_DISABLE_BUFFER);
+ if (r >= 0) {
+ log_debug("Using sleep mode '%s' for %s.", *mode, path);
return 0;
}
- RET_GATHER(r, log_debug_errno(k, "Failed to write '%s' to /sys/power/disk: %m", *mode));
+ RET_GATHER(ret, log_debug_errno(r, "Failed to write '%s' to %s: %m", *mode, path));
}
- return r;
+ return ret;
}
static int lock_all_homes(void) {
@@ -218,7 +220,6 @@ static int execute(
NULL
};
- _cleanup_(hibernation_device_done) HibernationDevice hibernation_device = {};
_cleanup_close_ int state_fd = -EBADF;
int r;
@@ -234,10 +235,17 @@ static int execute(
/* This file is opened first, so that if we hit an error, we can abort before modifying any state. */
state_fd = open("/sys/power/state", O_WRONLY|O_CLOEXEC);
if (state_fd < 0)
- return -errno;
+ return log_error_errno(errno, "Failed to open /sys/power/state: %m");
+
+ if (SLEEP_NEEDS_MEM_SLEEP(sleep_config, operation)) {
+ r = write_mode("/sys/power/mem_sleep", sleep_config->mem_modes);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write mode to /sys/power/mem_sleep: %m");
+ }
/* Configure hibernation settings if we are supposed to hibernate */
- if (sleep_operation_is_hibernation(operation)) {
+ if (SLEEP_OPERATION_IS_HIBERNATION(operation)) {
+ _cleanup_(hibernation_device_done) HibernationDevice hibernation_device = {};
bool resume_set;
r = find_suitable_hibernation_device(&hibernation_device);
@@ -257,7 +265,7 @@ static int execute(
goto fail;
}
- r = write_mode(sleep_config->modes[operation]);
+ r = write_mode("/sys/power/disk", sleep_config->modes[operation]);
if (r < 0) {
log_error_errno(r, "Failed to write mode to /sys/power/disk: %m");
goto fail;
@@ -299,8 +307,8 @@ static int execute(
return 0;
fail:
- if (sleep_operation_is_hibernation(operation) && is_efi_boot())
- (void) efi_set_variable(EFI_SYSTEMD_VARIABLE(HibernateLocation), NULL, 0);
+ if (SLEEP_OPERATION_IS_HIBERNATION(operation))
+ (void) clear_efi_hibernate_location_and_warn();
return r;
}
@@ -427,15 +435,13 @@ static int custom_timer_suspend(const SleepConfig *sleep_config) {
if (r < 0)
log_warning_errno(r, "Failed to estimate and update battery discharge rate, ignoring: %m");
} else
- log_debug("System woke up too early to estimate discharge rate");
+ log_debug("System woke up too early to estimate discharge rate.");
if (!woken_by_timer)
/* Return as manual wakeup done. This also will return in case battery was charged during suspension */
return 0;
r = check_wakeup_type();
- if (r < 0)
- log_debug_errno(r, "Failed to check hardware wakeup type, ignoring: %m");
if (r > 0) {
log_debug("wakeup type is APM timer");
/* system should hibernate */
@@ -446,48 +452,21 @@ static int custom_timer_suspend(const SleepConfig *sleep_config) {
return 1;
}
-/* Freeze when invoked and thaw on cleanup */
-static int freeze_thaw_user_slice(const char **method) {
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
- int r;
-
- if (!method || !*method)
- return 0;
-
- r = bus_connect_system_systemd(&bus);
- if (r < 0)
- return log_debug_errno(r, "Failed to open connection to systemd: %m");
-
- (void) sd_bus_set_method_call_timeout(bus, FREEZE_TIMEOUT);
-
- r = bus_call_method(bus, bus_systemd_mgr, *method, &error, NULL, "s", SPECIAL_USER_SLICE);
- if (r < 0)
- return log_debug_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
-
- return 1;
-}
-
static int execute_s2h(const SleepConfig *sleep_config) {
- _unused_ _cleanup_(freeze_thaw_user_slice) const char *auto_method_thaw = "ThawUnit";
int r;
assert(sleep_config);
- r = freeze_thaw_user_slice(&(const char*) { "FreezeUnit" });
- if (r < 0)
- log_debug_errno(r, "Failed to freeze unit user.slice, ignoring: %m");
-
/* Only check if we have automated battery alarms if HibernateDelaySec= is not set, as in that case
* we'll busy poll for the configured interval instead */
if (!timestamp_is_set(sleep_config->hibernate_delay_usec)) {
r = check_wakeup_type();
if (r < 0)
- log_debug_errno(r, "Failed to check hardware wakeup type, ignoring: %m");
+ log_warning_errno(r, "Failed to check hardware wakeup type, ignoring: %m");
else {
r = battery_trip_point_alarm_exists();
if (r < 0)
- log_debug_errno(r, "Failed to check whether acpi_btp support is enabled or not, ignoring: %m");
+ log_warning_errno(r, "Failed to check whether acpi_btp support is enabled or not, ignoring: %m");
}
} else
r = 0; /* Force fallback path */
@@ -500,7 +479,7 @@ static int execute_s2h(const SleepConfig *sleep_config) {
r = check_wakeup_type();
if (r < 0)
- return log_debug_errno(r, "Failed to check hardware wakeup type: %m");
+ return log_error_errno(r, "Failed to check hardware wakeup type: %m");
if (r == 0)
/* For APM Timer wakeup, system should hibernate else wakeup */
@@ -601,6 +580,7 @@ static int parse_argv(int argc, char *argv[]) {
}
static int run(int argc, char *argv[]) {
+ _cleanup_(unit_freezer_freep) UnitFreezer *user_slice_freezer = NULL;
_cleanup_(sleep_config_freep) SleepConfig *sleep_config = NULL;
int r;
@@ -619,6 +599,17 @@ static int run(int argc, char *argv[]) {
"Sleep operation \"%s\" is disabled by configuration, refusing.",
sleep_operation_to_string(arg_operation));
+ /* Freeze the user sessions */
+ r = getenv_bool("SYSTEMD_SLEEP_FREEZE_USER_SESSIONS");
+ if (r < 0 && r != -ENXIO)
+ log_warning_errno(r, "Cannot parse value of $SYSTEMD_SLEEP_FREEZE_USER_SESSIONS, ignoring.");
+ if (r != 0)
+ (void) unit_freezer_new_freeze(SPECIAL_USER_SLICE, &user_slice_freezer);
+ else
+ log_notice("User sessions remain unfrozen on explicit request ($SYSTEMD_SLEEP_FREEZE_USER_SESSIONS=0).\n"
+ "This is not recommended, and might result in unexpected behavior, particularly\n"
+ "in suspend-then-hibernate operations or setups with encrypted home directories.");
+
switch (arg_operation) {
case SLEEP_SUSPEND_THEN_HIBERNATE:
@@ -645,6 +636,9 @@ static int run(int argc, char *argv[]) {
}
+ if (user_slice_freezer)
+ RET_GATHER(r, unit_freezer_thaw(user_slice_freezer));
+
return r;
}