diff options
Diffstat (limited to 'src/sleep/sleep.c')
-rw-r--r-- | src/sleep/sleep.c | 90 |
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; } |