1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 Copyright © 2018 Dell Inc.
9 #include <linux/magic.h>
12 #include <sys/ioctl.h>
14 #include <sys/types.h>
18 #include "sd-device.h"
20 #include "alloc-util.h"
21 #include "battery-util.h"
22 #include "blockdev-util.h"
23 #include "btrfs-util.h"
24 #include "conf-parser.h"
25 #include "constants.h"
26 #include "device-private.h"
27 #include "device-util.h"
28 #include "devnum-util.h"
30 #include "errno-util.h"
33 #include "hexdecoct.h"
34 #include "id128-util.h"
37 #include "path-util.h"
38 #include "siphash24.h"
39 #include "sleep-util.h"
40 #include "stat-util.h"
41 #include "stdio-util.h"
42 #include "string-table.h"
43 #include "string-util.h"
45 #include "time-util.h"
47 #define DISCHARGE_RATE_FILEPATH "/var/lib/systemd/sleep/battery_discharge_percentage_rate_per_hour"
48 #define BATTERY_DISCHARGE_RATE_HASH_KEY SD_ID128_MAKE(5f,9a,20,18,38,76,46,07,8d,36,58,0b,bb,c4,e0,63)
50 static void *CAPACITY_TO_PTR(int capacity
) {
51 assert(capacity
>= 0);
52 assert(capacity
<= 100);
53 return INT_TO_PTR(capacity
+ 1);
56 static int PTR_TO_CAPACITY(void *p
) {
57 int capacity
= PTR_TO_INT(p
) - 1;
58 assert(capacity
>= 0);
59 assert(capacity
<= 100);
63 int parse_sleep_config(SleepConfig
**ret_sleep_config
) {
64 _cleanup_(free_sleep_configp
) SleepConfig
*sc
= NULL
;
65 int allow_suspend
= -1, allow_hibernate
= -1,
66 allow_s2h
= -1, allow_hybrid_sleep
= -1;
68 sc
= new(SleepConfig
, 1);
73 .hibernate_delay_usec
= USEC_INFINITY
,
76 const ConfigTableItem items
[] = {
77 { "Sleep", "AllowSuspend", config_parse_tristate
, 0, &allow_suspend
},
78 { "Sleep", "AllowHibernation", config_parse_tristate
, 0, &allow_hibernate
},
79 { "Sleep", "AllowSuspendThenHibernate", config_parse_tristate
, 0, &allow_s2h
},
80 { "Sleep", "AllowHybridSleep", config_parse_tristate
, 0, &allow_hybrid_sleep
},
82 { "Sleep", "SuspendMode", config_parse_strv
, 0, sc
->modes
+ SLEEP_SUSPEND
},
83 { "Sleep", "SuspendState", config_parse_strv
, 0, sc
->states
+ SLEEP_SUSPEND
},
84 { "Sleep", "HibernateMode", config_parse_strv
, 0, sc
->modes
+ SLEEP_HIBERNATE
},
85 { "Sleep", "HibernateState", config_parse_strv
, 0, sc
->states
+ SLEEP_HIBERNATE
},
86 { "Sleep", "HybridSleepMode", config_parse_strv
, 0, sc
->modes
+ SLEEP_HYBRID_SLEEP
},
87 { "Sleep", "HybridSleepState", config_parse_strv
, 0, sc
->states
+ SLEEP_HYBRID_SLEEP
},
89 { "Sleep", "HibernateDelaySec", config_parse_sec
, 0, &sc
->hibernate_delay_usec
},
90 { "Sleep", "SuspendEstimationSec", config_parse_sec
, 0, &sc
->suspend_estimation_usec
},
94 (void) config_parse_config_file("sleep.conf", "Sleep\0",
95 config_item_table_lookup
, items
,
96 CONFIG_PARSE_WARN
, NULL
);
98 /* use default values unless set */
99 sc
->allow
[SLEEP_SUSPEND
] = allow_suspend
!= 0;
100 sc
->allow
[SLEEP_HIBERNATE
] = allow_hibernate
!= 0;
101 sc
->allow
[SLEEP_HYBRID_SLEEP
] = allow_hybrid_sleep
>= 0 ? allow_hybrid_sleep
102 : (allow_suspend
!= 0 && allow_hibernate
!= 0);
103 sc
->allow
[SLEEP_SUSPEND_THEN_HIBERNATE
] = allow_s2h
>= 0 ? allow_s2h
104 : (allow_suspend
!= 0 && allow_hibernate
!= 0);
106 if (!sc
->states
[SLEEP_SUSPEND
])
107 sc
->states
[SLEEP_SUSPEND
] = strv_new("mem", "standby", "freeze");
108 if (!sc
->modes
[SLEEP_HIBERNATE
])
109 sc
->modes
[SLEEP_HIBERNATE
] = strv_new("platform", "shutdown");
110 if (!sc
->states
[SLEEP_HIBERNATE
])
111 sc
->states
[SLEEP_HIBERNATE
] = strv_new("disk");
112 if (!sc
->modes
[SLEEP_HYBRID_SLEEP
])
113 sc
->modes
[SLEEP_HYBRID_SLEEP
] = strv_new("suspend", "platform", "shutdown");
114 if (!sc
->states
[SLEEP_HYBRID_SLEEP
])
115 sc
->states
[SLEEP_HYBRID_SLEEP
] = strv_new("disk");
116 if (sc
->suspend_estimation_usec
== 0)
117 sc
->suspend_estimation_usec
= DEFAULT_SUSPEND_ESTIMATION_USEC
;
119 /* Ensure values set for all required fields */
120 if (!sc
->states
[SLEEP_SUSPEND
] || !sc
->modes
[SLEEP_HIBERNATE
]
121 || !sc
->states
[SLEEP_HIBERNATE
] || !sc
->modes
[SLEEP_HYBRID_SLEEP
] || !sc
->states
[SLEEP_HYBRID_SLEEP
])
124 *ret_sleep_config
= TAKE_PTR(sc
);
129 int get_capacity_by_name(Hashmap
*capacities_by_name
, const char *name
) {
132 assert(capacities_by_name
);
135 p
= hashmap_get(capacities_by_name
, name
);
139 return PTR_TO_CAPACITY(p
);
142 /* Store current capacity of each battery before suspension and timestamp */
143 int fetch_batteries_capacity_by_name(Hashmap
**ret
) {
144 _cleanup_(sd_device_enumerator_unrefp
) sd_device_enumerator
*e
= NULL
;
145 _cleanup_hashmap_free_ Hashmap
*batteries_capacity_by_name
= NULL
;
151 batteries_capacity_by_name
= hashmap_new(&string_hash_ops_free
);
152 if (!batteries_capacity_by_name
)
153 return log_oom_debug();
155 r
= battery_enumerator_new(&e
);
157 return log_debug_errno(r
, "Failed to initialize battery enumerator: %m");
159 FOREACH_DEVICE(e
, dev
) {
160 _cleanup_free_
char *battery_name_copy
= NULL
;
161 const char *battery_name
;
162 int battery_capacity
;
164 battery_capacity
= r
= battery_read_capacity_percentage(dev
);
168 r
= sd_device_get_property_value(dev
, "POWER_SUPPLY_NAME", &battery_name
);
170 log_device_debug_errno(dev
, r
, "Failed to get POWER_SUPPLY_NAME property, ignoring: %m");
174 battery_name_copy
= strdup(battery_name
);
175 if (!battery_name_copy
)
176 return log_oom_debug();
178 r
= hashmap_put(batteries_capacity_by_name
, battery_name_copy
, CAPACITY_TO_PTR(battery_capacity
));
180 return log_device_debug_errno(dev
, r
, "Failed to store battery capacity: %m");
182 TAKE_PTR(battery_name_copy
);
185 *ret
= TAKE_PTR(batteries_capacity_by_name
);
190 static int siphash24_compress_device_sysattr(sd_device
*dev
, const char *attr
, struct siphash
*state
) {
198 r
= sd_device_get_sysattr_value(dev
, attr
, &x
);
200 return log_device_debug_errno(dev
, r
, "Failed to read '%s' attribute: %m", attr
);
203 siphash24_compress_string(x
, state
);
208 static int siphash24_compress_id128(int (*getter
)(sd_id128_t
*), const char *name
, struct siphash
*state
) {
217 return log_debug_errno(r
, "Failed to get %s ID: %m", name
);
219 siphash24_compress(&id
, sizeof(sd_id128_t
), state
);
223 /* Read system and battery identifier from specific location and generate hash of it */
224 static int get_system_battery_identifier_hash(sd_device
*dev
, uint64_t *ret
) {
225 struct siphash state
;
230 siphash24_init(&state
, BATTERY_DISCHARGE_RATE_HASH_KEY
.bytes
);
232 (void) siphash24_compress_device_sysattr(dev
, "manufacturer", &state
);
233 (void) siphash24_compress_device_sysattr(dev
, "model_name", &state
);
234 (void) siphash24_compress_device_sysattr(dev
, "serial_number", &state
);
235 (void) siphash24_compress_id128(sd_id128_get_machine
, "machine", &state
);
236 (void) siphash24_compress_id128(id128_get_product
, "product", &state
);
238 *ret
= siphash24_finalize(&state
);
242 /* Return success if battery percentage discharge rate per hour is in the range 1–199 */
243 static bool battery_discharge_rate_is_valid(int battery_discharge_rate
) {
244 return battery_discharge_rate
> 0 && battery_discharge_rate
< 200;
247 /* Battery percentage discharge rate per hour is read from specific file. It is stored along with system
248 * and battery identifier hash to maintain the integrity of discharge rate value */
249 static int get_battery_discharge_rate(sd_device
*dev
, int *ret
) {
250 _cleanup_fclose_
FILE *f
= NULL
;
251 uint64_t current_hash_id
;
258 f
= fopen(DISCHARGE_RATE_FILEPATH
, "re");
260 return log_debug_errno(errno
, "Failed to read discharge rate from " DISCHARGE_RATE_FILEPATH
": %m");
262 r
= get_system_battery_identifier_hash(dev
, ¤t_hash_id
);
264 return log_device_debug_errno(dev
, r
, "Failed to generate system battery identifier hash: %m");
267 _cleanup_free_
char *stored_hash_id
= NULL
, *stored_discharge_rate
= NULL
, *line
= NULL
;
271 r
= read_line(f
, LONG_LINE_MAX
, &line
);
273 return log_debug_errno(r
, "Failed to read discharge rate from " DISCHARGE_RATE_FILEPATH
": %m");
278 r
= extract_many_words(&p
, NULL
, 0, &stored_hash_id
, &stored_discharge_rate
, NULL
);
280 return log_debug_errno(r
, "Failed to parse hash_id and discharge_rate read from " DISCHARGE_RATE_FILEPATH
": %m");
282 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "Invalid number of items fetched from " DISCHARGE_RATE_FILEPATH
);
284 r
= safe_atou64(stored_hash_id
, &hash_id
);
286 return log_debug_errno(r
, "Failed to parse hash ID read from " DISCHARGE_RATE_FILEPATH
" location: %m");
288 if (current_hash_id
!= hash_id
)
289 /* matching device not found, move to next line */
292 r
= safe_atoi(stored_discharge_rate
, &discharge_rate
);
294 return log_device_debug_errno(dev
, r
, "Failed to parse discharge rate read from " DISCHARGE_RATE_FILEPATH
": %m");
296 if (!battery_discharge_rate_is_valid(discharge_rate
))
297 return log_device_debug_errno(dev
, SYNTHETIC_ERRNO(ERANGE
), "Invalid battery discharge percentage rate per hour: %m");
299 *ret
= discharge_rate
;
300 return 0; /* matching device found, exit iteration */
306 /* Write battery percentage discharge rate per hour along with system and battery identifier hash to file */
307 static int put_battery_discharge_rate(int estimated_battery_discharge_rate
, uint64_t system_hash_id
, bool trunc
) {
310 if (!battery_discharge_rate_is_valid(estimated_battery_discharge_rate
))
311 return log_debug_errno(SYNTHETIC_ERRNO(ERANGE
),
312 "Invalid battery discharge rate %d%% per hour: %m",
313 estimated_battery_discharge_rate
);
315 r
= write_string_filef(
316 DISCHARGE_RATE_FILEPATH
,
317 WRITE_STRING_FILE_CREATE
| WRITE_STRING_FILE_MKDIR_0755
| (trunc
? WRITE_STRING_FILE_TRUNCATE
: 0),
320 estimated_battery_discharge_rate
);
322 return log_debug_errno(r
, "Failed to update %s: %m", DISCHARGE_RATE_FILEPATH
);
324 log_debug("Estimated discharge rate %d%% per hour successfully saved to %s", estimated_battery_discharge_rate
, DISCHARGE_RATE_FILEPATH
);
329 /* Estimate battery discharge rate using stored previous and current capacity over timestamp difference */
330 int estimate_battery_discharge_rate_per_hour(
331 Hashmap
*last_capacity
,
332 Hashmap
*current_capacity
,
333 usec_t before_timestamp
,
334 usec_t after_timestamp
) {
336 _cleanup_(sd_device_enumerator_unrefp
) sd_device_enumerator
*e
= NULL
;
341 assert(last_capacity
);
342 assert(current_capacity
);
343 assert(before_timestamp
< after_timestamp
);
345 r
= battery_enumerator_new(&e
);
347 return log_debug_errno(r
, "Failed to initialize battery enumerator: %m");
349 FOREACH_DEVICE(e
, dev
) {
350 int battery_last_capacity
, battery_current_capacity
, battery_discharge_rate
;
351 const char *battery_name
;
352 uint64_t system_hash_id
;
354 r
= sd_device_get_property_value(dev
, "POWER_SUPPLY_NAME", &battery_name
);
356 log_device_debug_errno(dev
, r
, "Failed to read battery name, ignoring: %m");
360 battery_last_capacity
= get_capacity_by_name(last_capacity
, battery_name
);
361 if (battery_last_capacity
< 0)
364 battery_current_capacity
= get_capacity_by_name(current_capacity
, battery_name
);
365 if (battery_current_capacity
< 0)
368 if (battery_current_capacity
>= battery_last_capacity
) {
369 log_device_debug(dev
, "Battery was not discharged during suspension");
373 r
= get_system_battery_identifier_hash(dev
, &system_hash_id
);
375 return log_device_debug_errno(dev
, r
, "Failed to generate system battery identifier hash: %m");
377 log_device_debug(dev
,
378 "%d%% was discharged in %s. Estimating discharge rate...",
379 battery_last_capacity
- battery_current_capacity
,
380 FORMAT_TIMESPAN(after_timestamp
- before_timestamp
, USEC_PER_SEC
));
382 battery_discharge_rate
= (battery_last_capacity
- battery_current_capacity
) * USEC_PER_HOUR
/ (after_timestamp
- before_timestamp
);
383 r
= put_battery_discharge_rate(battery_discharge_rate
, system_hash_id
, trunc
);
385 log_device_warning_errno(dev
, r
, "Failed to update battery discharge rate, ignoring: %m");
393 /* Calculate the suspend interval for each battery and then return their sum */
394 int get_total_suspend_interval(Hashmap
*last_capacity
, usec_t
*ret
) {
395 _cleanup_(sd_device_enumerator_unrefp
) sd_device_enumerator
*e
= NULL
;
396 usec_t total_suspend_interval
= 0;
400 assert(last_capacity
);
403 r
= battery_enumerator_new(&e
);
405 return log_debug_errno(r
, "Failed to initialize battery enumerator: %m");
407 FOREACH_DEVICE(e
, dev
) {
408 int battery_last_capacity
, previous_discharge_rate
= 0;
409 const char *battery_name
;
410 usec_t suspend_interval
;
412 r
= sd_device_get_property_value(dev
, "POWER_SUPPLY_NAME", &battery_name
);
414 log_device_debug_errno(dev
, r
, "Failed to read battery name, ignoring: %m");
418 battery_last_capacity
= get_capacity_by_name(last_capacity
, battery_name
);
419 if (battery_last_capacity
<= 0)
422 r
= get_battery_discharge_rate(dev
, &previous_discharge_rate
);
424 log_device_debug_errno(dev
, r
, "Failed to get discharge rate, ignoring: %m");
428 if (previous_discharge_rate
== 0)
431 if (battery_last_capacity
* 2 <= previous_discharge_rate
) {
432 log_device_debug(dev
, "Current battery capacity percentage too low compared to discharge rate");
435 suspend_interval
= battery_last_capacity
* USEC_PER_HOUR
/ previous_discharge_rate
;
437 total_suspend_interval
= usec_add(total_suspend_interval
, suspend_interval
);
439 /* Previous discharge rate is stored in per hour basis converted to usec.
440 * Subtract 30 minutes from the result to keep a buffer of 30 minutes before battery gets critical */
441 total_suspend_interval
= usec_sub_unsigned(total_suspend_interval
, 30 * USEC_PER_MINUTE
);
442 if (total_suspend_interval
== 0)
445 *ret
= total_suspend_interval
;
450 /* Return true if all batteries have acpi_btp support */
451 int battery_trip_point_alarm_exists(void) {
452 _cleanup_(sd_device_enumerator_unrefp
) sd_device_enumerator
*e
= NULL
;
456 r
= battery_enumerator_new(&e
);
458 return log_debug_errno(r
, "Failed to initialize battery enumerator: %m");
460 FOREACH_DEVICE(e
, dev
) {
464 r
= sd_device_get_sysattr_value(dev
, "alarm", &s
);
466 return log_device_debug_errno(dev
, r
, "Failed to read battery alarm: %m");
468 r
= safe_atoi(s
, &battery_alarm
);
470 return log_device_debug_errno(dev
, r
, "Failed to parse battery alarm: %m");
471 if (battery_alarm
<= 0)
478 /* Return true if wakeup type is APM timer */
479 int check_wakeup_type(void) {
480 static const char dmi_object_path
[] = "/sys/firmware/dmi/entries/1-0/raw";
481 uint8_t wakeup_type_byte
, tablesize
;
482 _cleanup_free_
char *buf
= NULL
;
486 /* implementation via dmi/entries */
487 r
= read_full_virtual_file(dmi_object_path
, &buf
, &bufsize
);
489 return log_debug_errno(r
, "Unable to read %s: %m", dmi_object_path
);
491 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "Only read %zu bytes from %s (expected 25)", bufsize
, dmi_object_path
);
493 /* index 1 stores the size of table */
494 tablesize
= (uint8_t) buf
[1];
496 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "Table size lesser than the index[0x18] where waketype byte is available.");
498 wakeup_type_byte
= (uint8_t) buf
[24];
499 /* 0 is Reserved and 8 is AC Power Restored. As per table 12 in
500 * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.4.0.pdf */
501 if (wakeup_type_byte
>= 128)
502 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "Expected value in range 0-127");
504 if (wakeup_type_byte
== 3) {
505 log_debug("DMI BIOS System Information indicates wakeup type is APM Timer");
512 int can_sleep_state(char **requested_types
) {
513 _cleanup_free_
char *text
= NULL
;
516 if (strv_isempty(requested_types
))
519 /* If /sys is read-only we cannot sleep */
520 if (access("/sys/power/state", W_OK
) < 0) {
521 log_debug_errno(errno
, "/sys/power/state is not writable, cannot sleep: %m");
525 r
= read_one_line_file("/sys/power/state", &text
);
527 log_debug_errno(r
, "Failed to read /sys/power/state, cannot sleep: %m");
532 r
= string_contains_word_strv(text
, NULL
, requested_types
, &found
);
534 return log_debug_errno(r
, "Failed to parse /sys/power/state: %m");
536 log_debug("Sleep mode \"%s\" is supported by the kernel.", found
);
537 else if (DEBUG_LOGGING
) {
538 _cleanup_free_
char *t
= strv_join(requested_types
, "/");
539 log_debug("Sleep mode %s not supported by the kernel, sorry.", strnull(t
));
544 int can_sleep_disk(char **types
) {
545 _cleanup_free_
char *text
= NULL
;
548 if (strv_isempty(types
))
551 /* If /sys is read-only we cannot sleep */
552 if (access("/sys/power/disk", W_OK
) < 0) {
553 log_debug_errno(errno
, "/sys/power/disk is not writable: %m");
557 r
= read_one_line_file("/sys/power/disk", &text
);
559 log_debug_errno(r
, "Couldn't read /sys/power/disk: %m");
563 for (const char *p
= text
;;) {
564 _cleanup_free_
char *word
= NULL
;
566 r
= extract_first_word(&p
, &word
, NULL
, 0);
568 return log_debug_errno(r
, "Failed to parse /sys/power/disk: %m");
573 size_t l
= strlen(s
);
574 if (s
[0] == '[' && s
[l
-1] == ']') {
579 if (strv_contains(types
, s
)) {
580 log_debug("Disk sleep mode \"%s\" is supported by the kernel.", s
);
586 _cleanup_free_
char *t
= strv_join(types
, "/");
587 log_debug("Disk sleep mode %s not supported by the kernel, sorry.", strnull(t
));
592 #define HIBERNATION_SWAP_THRESHOLD 0.98
594 SwapEntry
* swap_entry_free(SwapEntry
*se
) {
603 HibernateLocation
* hibernate_location_free(HibernateLocation
*hl
) {
607 swap_entry_free(hl
->swap
);
612 static int swap_device_to_devnum(const SwapEntry
*swap
, dev_t
*ret_dev
) {
613 _cleanup_close_
int fd
= -EBADF
;
620 fd
= open(swap
->path
, O_CLOEXEC
|O_PATH
);
624 if (fstat(fd
, &sb
) < 0)
627 if (swap
->type
== SWAP_BLOCK
) {
628 if (!S_ISBLK(sb
.st_mode
))
631 *ret_dev
= sb
.st_rdev
;
635 r
= stat_verify_regular(&sb
);
639 return get_block_device_fd(fd
, ret_dev
);
643 * Attempt to calculate the swap file offset on supported filesystems. On unsupported
644 * filesystems, a debug message is logged and ret_offset is set to UINT64_MAX.
646 static int calculate_swap_file_offset(const SwapEntry
*swap
, uint64_t *ret_offset
) {
647 _cleanup_close_
int fd
= -EBADF
;
648 _cleanup_free_
struct fiemap
*fiemap
= NULL
;
653 assert(swap
->type
== SWAP_FILE
);
656 fd
= open(swap
->path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
658 return log_debug_errno(errno
, "Failed to open swap file %s to determine on-disk offset: %m", swap
->path
);
660 r
= fd_verify_regular(fd
);
662 return log_debug_errno(r
, "Selected swap file is not a regular file.");
664 r
= fd_is_fs_type(fd
, BTRFS_SUPER_MAGIC
);
666 return log_debug_errno(r
, "Error checking %s for Btrfs filesystem: %m", swap
->path
);
668 log_debug("%s: detection of swap file offset on Btrfs is not supported", swap
->path
);
669 *ret_offset
= UINT64_MAX
;
673 r
= read_fiemap(fd
, &fiemap
);
675 return log_debug_errno(r
, "Unable to read extent map for '%s': %m", swap
->path
);
677 *ret_offset
= fiemap
->fm_extents
[0].fe_physical
/ page_size();
681 static int read_resume_files(dev_t
*ret_resume
, uint64_t *ret_resume_offset
) {
682 _cleanup_free_
char *resume_str
= NULL
, *resume_offset_str
= NULL
;
683 uint64_t resume_offset
;
688 assert(ret_resume_offset
);
690 r
= read_one_line_file("/sys/power/resume", &resume_str
);
692 return log_debug_errno(r
, "Error reading /sys/power/resume: %m");
694 r
= parse_devnum(resume_str
, &resume
);
696 return log_debug_errno(r
, "Error parsing /sys/power/resume device: %s: %m", resume_str
);
698 r
= read_one_line_file("/sys/power/resume_offset", &resume_offset_str
);
700 log_debug_errno(r
, "Kernel does not support resume_offset; swap file offset detection will be skipped.");
703 return log_debug_errno(r
, "Error reading /sys/power/resume_offset: %m");
705 r
= safe_atou64(resume_offset_str
, &resume_offset
);
707 return log_debug_errno(r
, "Failed to parse value in /sys/power/resume_offset \"%s\": %m", resume_offset_str
);
710 if (resume_offset
> 0 && resume
== 0)
711 log_debug("Warning: found /sys/power/resume_offset==%" PRIu64
", but /sys/power/resume unset. Misconfiguration?",
714 *ret_resume
= resume
;
715 *ret_resume_offset
= resume_offset
;
720 * Determine if the HibernateLocation matches the resume= (device) and resume_offset= (file).
722 static bool location_is_resume_device(const HibernateLocation
*location
, dev_t sys_resume
, uint64_t sys_offset
) {
726 return sys_resume
> 0 &&
727 sys_resume
== location
->devno
&&
728 (sys_offset
== location
->offset
|| (sys_offset
> 0 && location
->offset
== UINT64_MAX
));
732 * Attempt to find the hibernation location by parsing /proc/swaps, /sys/power/resume, and
733 * /sys/power/resume_offset.
736 * Never use a device or file as location that hasn't been somehow specified by a user that would also be
737 * entrusted with full system memory access (for example via /sys/power/resume) or that isn't an already
739 * Otherwise various security attacks might become possible, for example an attacker could silently attach
740 * such a device and circumvent full disk encryption when it would be automatically used for hibernation.
741 * Also, having a swap area on top of encryption is not per se enough to protect from all such attacks.
744 * 1 - Values are set in /sys/power/resume and /sys/power/resume_offset.
745 * ret_hibernate_location will represent matching /proc/swap entry if identified or NULL if not.
747 * 0 - No values are set in /sys/power/resume and /sys/power/resume_offset.
748 ret_hibernate_location will represent the highest priority swap with most remaining space discovered in /proc/swaps.
750 * Negative value in the case of error.
752 int find_hibernate_location(HibernateLocation
**ret_hibernate_location
) {
753 _cleanup_fclose_
FILE *f
= NULL
;
754 _cleanup_(hibernate_location_freep
) HibernateLocation
*hibernate_location
= NULL
;
755 dev_t sys_resume
= 0; /* Unnecessary initialization to appease gcc */
756 uint64_t sys_offset
= 0;
757 bool resume_match
= false;
760 /* read the /sys/power/resume & /sys/power/resume_offset values */
761 r
= read_resume_files(&sys_resume
, &sys_offset
);
765 f
= fopen("/proc/swaps", "re");
767 log_debug_errno(errno
, "Failed to open /proc/swaps: %m");
768 return errno
== ENOENT
? -EOPNOTSUPP
: -errno
; /* Convert swap not supported to a recognizable error */
771 (void) fscanf(f
, "%*s %*s %*s %*s %*s\n");
772 for (unsigned i
= 1;; i
++) {
773 _cleanup_(swap_entry_freep
) SwapEntry
*swap
= NULL
;
774 _cleanup_free_
char *type
= NULL
;
775 uint64_t swap_offset
= 0;
778 swap
= new(SwapEntry
, 1);
782 *swap
= (SwapEntry
) {
783 .type
= _SWAP_TYPE_INVALID
,
787 "%ms " /* device/file path */
788 "%ms " /* type of swap */
789 "%" PRIu64
/* swap size */
790 "%" PRIu64
/* used */
791 "%i\n", /* priority */
792 &swap
->path
, &type
, &swap
->size
, &swap
->used
, &swap
->priority
);
796 log_debug("Failed to parse /proc/swaps:%u, ignoring", i
);
800 if (streq(type
, "file")) {
802 if (endswith(swap
->path
, "\\040(deleted)")) {
803 log_debug("Ignoring deleted swap file '%s'.", swap
->path
);
807 swap
->type
= SWAP_FILE
;
809 r
= calculate_swap_file_offset(swap
, &swap_offset
);
813 } else if (streq(type
, "partition")) {
816 fn
= path_startswith(swap
->path
, "/dev/");
817 if (fn
&& startswith(fn
, "zram")) {
818 log_debug("%s: ignoring zram swap", swap
->path
);
822 swap
->type
= SWAP_BLOCK
;
825 log_debug("%s: swap type %s is unsupported for hibernation, ignoring", swap
->path
, type
);
829 /* prefer resume device or highest priority swap with most remaining space */
830 if (sys_resume
== 0) {
831 if (hibernate_location
&& swap
->priority
< hibernate_location
->swap
->priority
) {
832 log_debug("%s: ignoring device with lower priority", swap
->path
);
835 if (hibernate_location
&&
836 (swap
->priority
== hibernate_location
->swap
->priority
837 && swap
->size
- swap
->used
< hibernate_location
->swap
->size
- hibernate_location
->swap
->used
)) {
838 log_debug("%s: ignoring device with lower usable space", swap
->path
);
844 r
= swap_device_to_devnum(swap
, &swap_devno
);
846 return log_debug_errno(r
, "%s: failed to query device number: %m", swap
->path
);
848 return log_debug_errno(SYNTHETIC_ERRNO(ENODEV
), "%s: not backed by block device.", swap
->path
);
850 hibernate_location
= hibernate_location_free(hibernate_location
);
851 hibernate_location
= new(HibernateLocation
, 1);
852 if (!hibernate_location
)
855 *hibernate_location
= (HibernateLocation
) {
857 .offset
= swap_offset
,
858 .swap
= TAKE_PTR(swap
),
861 /* if the swap is the resume device, stop the loop */
862 if (location_is_resume_device(hibernate_location
, sys_resume
, sys_offset
)) {
863 log_debug("%s: device matches configured resume settings.", hibernate_location
->swap
->path
);
868 log_debug("%s: is a candidate device.", hibernate_location
->swap
->path
);
871 /* We found nothing at all */
872 if (!hibernate_location
)
873 return log_debug_errno(SYNTHETIC_ERRNO(ENOSYS
),
874 "No possible swap partitions or files suitable for hibernation were found in /proc/swaps.");
876 /* resume= is set but a matching /proc/swaps entry was not found */
877 if (sys_resume
!= 0 && !resume_match
)
878 return log_debug_errno(SYNTHETIC_ERRNO(ENOSYS
),
879 "No swap partitions or files matching resume config were found in /proc/swaps.");
881 if (hibernate_location
->offset
== UINT64_MAX
) {
883 return log_debug_errno(SYNTHETIC_ERRNO(ENOSYS
), "Offset detection failed and /sys/power/resume_offset is not set.");
885 hibernate_location
->offset
= sys_offset
;
889 log_debug("Hibernation will attempt to use swap entry with path: %s, device: %u:%u, offset: %" PRIu64
", priority: %i",
890 hibernate_location
->swap
->path
, major(hibernate_location
->devno
), minor(hibernate_location
->devno
),
891 hibernate_location
->offset
, hibernate_location
->swap
->priority
);
893 log_debug("/sys/power/resume is not configured; attempting to hibernate with path: %s, device: %u:%u, offset: %" PRIu64
", priority: %i",
894 hibernate_location
->swap
->path
, major(hibernate_location
->devno
), minor(hibernate_location
->devno
),
895 hibernate_location
->offset
, hibernate_location
->swap
->priority
);
897 *ret_hibernate_location
= TAKE_PTR(hibernate_location
);
905 static bool enough_swap_for_hibernation(void) {
906 _cleanup_free_
char *active
= NULL
;
907 _cleanup_(hibernate_location_freep
) HibernateLocation
*hibernate_location
= NULL
;
908 unsigned long long act
= 0;
911 if (getenv_bool("SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK") > 0)
914 r
= find_hibernate_location(&hibernate_location
);
918 /* If /sys/power/{resume,resume_offset} is configured but a matching entry
919 * could not be identified in /proc/swaps, user is likely using Btrfs with a swapfile;
920 * return true and let the system attempt hibernation.
922 if (r
> 0 && !hibernate_location
) {
923 log_debug("Unable to determine remaining swap space; hibernation may fail");
927 if (!hibernate_location
)
930 r
= get_proc_field("/proc/meminfo", "Active(anon)", WHITESPACE
, &active
);
932 log_debug_errno(r
, "Failed to retrieve Active(anon) from /proc/meminfo: %m");
936 r
= safe_atollu(active
, &act
);
938 log_debug_errno(r
, "Failed to parse Active(anon) from /proc/meminfo: %s: %m", active
);
942 r
= act
<= (hibernate_location
->swap
->size
- hibernate_location
->swap
->used
) * HIBERNATION_SWAP_THRESHOLD
;
943 log_debug("%s swap for hibernation, Active(anon)=%llu kB, size=%" PRIu64
" kB, used=%" PRIu64
" kB, threshold=%.2g%%",
944 r
? "Enough" : "Not enough", act
, hibernate_location
->swap
->size
, hibernate_location
->swap
->used
, 100*HIBERNATION_SWAP_THRESHOLD
);
949 int read_fiemap(int fd
, struct fiemap
**ret
) {
950 _cleanup_free_
struct fiemap
*fiemap
= NULL
, *result_fiemap
= NULL
;
951 struct stat statinfo
;
952 uint32_t result_extents
= 0;
953 uint64_t fiemap_start
= 0, fiemap_length
;
954 const size_t n_extra
= DIV_ROUND_UP(sizeof(struct fiemap
), sizeof(struct fiemap_extent
));
956 if (fstat(fd
, &statinfo
) < 0)
957 return log_debug_errno(errno
, "Cannot determine file size: %m");
958 if (!S_ISREG(statinfo
.st_mode
))
960 fiemap_length
= statinfo
.st_size
;
962 /* Zero this out in case we run on a file with no extents */
963 fiemap
= calloc(n_extra
, sizeof(struct fiemap_extent
));
967 result_fiemap
= malloc_multiply(n_extra
, sizeof(struct fiemap_extent
));
971 /* XFS filesystem has incorrect implementation of fiemap ioctl and
972 * returns extents for only one block-group at a time, so we need
973 * to handle it manually, starting the next fiemap call from the end
976 while (fiemap_start
< fiemap_length
) {
977 *fiemap
= (struct fiemap
) {
978 .fm_start
= fiemap_start
,
979 .fm_length
= fiemap_length
,
980 .fm_flags
= FIEMAP_FLAG_SYNC
,
983 /* Find out how many extents there are */
984 if (ioctl(fd
, FS_IOC_FIEMAP
, fiemap
) < 0)
985 return log_debug_errno(errno
, "Failed to read extents: %m");
987 /* Nothing to process */
988 if (fiemap
->fm_mapped_extents
== 0)
991 /* Resize fiemap to allow us to read in the extents, result fiemap has to hold all
992 * the extents for the whole file. Add space for the initial struct fiemap. */
993 if (!greedy_realloc0((void**) &fiemap
, n_extra
+ fiemap
->fm_mapped_extents
, sizeof(struct fiemap_extent
)))
996 fiemap
->fm_extent_count
= fiemap
->fm_mapped_extents
;
997 fiemap
->fm_mapped_extents
= 0;
999 if (ioctl(fd
, FS_IOC_FIEMAP
, fiemap
) < 0)
1000 return log_debug_errno(errno
, "Failed to read extents: %m");
1002 /* Resize result_fiemap to allow us to copy in the extents */
1003 if (!greedy_realloc((void**) &result_fiemap
,
1004 n_extra
+ result_extents
+ fiemap
->fm_mapped_extents
, sizeof(struct fiemap_extent
)))
1007 memcpy(result_fiemap
->fm_extents
+ result_extents
,
1009 sizeof(struct fiemap_extent
) * fiemap
->fm_mapped_extents
);
1011 result_extents
+= fiemap
->fm_mapped_extents
;
1013 /* Highly unlikely that it is zero */
1014 if (_likely_(fiemap
->fm_mapped_extents
> 0)) {
1015 uint32_t i
= fiemap
->fm_mapped_extents
- 1;
1017 fiemap_start
= fiemap
->fm_extents
[i
].fe_logical
+
1018 fiemap
->fm_extents
[i
].fe_length
;
1020 if (fiemap
->fm_extents
[i
].fe_flags
& FIEMAP_EXTENT_LAST
)
1025 memcpy(result_fiemap
, fiemap
, sizeof(struct fiemap
));
1026 result_fiemap
->fm_mapped_extents
= result_extents
;
1027 *ret
= TAKE_PTR(result_fiemap
);
1031 int write_resume_config(dev_t devno
, uint64_t offset
, const char *device
) {
1032 char offset_str
[DECIMAL_STR_MAX(uint64_t)];
1033 _cleanup_free_
char *path
= NULL
;
1034 const char *devno_str
;
1037 devno_str
= FORMAT_DEVNUM(devno
);
1038 xsprintf(offset_str
, "%" PRIu64
, offset
);
1041 r
= device_path_make_canonical(S_IFBLK
, devno
, &path
);
1043 return log_error_errno(r
,
1044 "Failed to format canonical device path for devno '" DEVNUM_FORMAT_STR
"': %m",
1045 DEVNUM_FORMAT_VAL(devno
));
1049 /* We write the offset first since it's safer. Note that this file is only available in 4.17+, so
1050 * fail gracefully if it doesn't exist and we're only overwriting it with 0. */
1051 r
= write_string_file("/sys/power/resume_offset", offset_str
, WRITE_STRING_FILE_DISABLE_BUFFER
);
1054 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
1055 "Can't configure hibernation offset %" PRIu64
", kernel does not support /sys/power/resume_offset. Refusing.",
1058 log_warning_errno(r
, "/sys/power/resume_offset is unavailable, skipping writing swap file offset.");
1060 return log_error_errno(r
,
1061 "Failed to write swap file offset %s to /sys/power/resume_offset for device '%s': %m",
1062 offset_str
, device
);
1064 log_debug("Wrote resume_offset=%s for device '%s' to /sys/power/resume_offset.",
1065 offset_str
, device
);
1067 r
= write_string_file("/sys/power/resume", devno_str
, WRITE_STRING_FILE_DISABLE_BUFFER
);
1069 return log_error_errno(r
,
1070 "Failed to write device '%s' (%s) to /sys/power/resume: %m",
1072 log_debug("Wrote resume=%s for device '%s' to /sys/power/resume.", devno_str
, device
);
1077 static int can_sleep_internal(const SleepConfig
*sleep_config
, SleepOperation operation
, bool check_allowed
);
1079 static bool can_s2h(const SleepConfig
*sleep_config
) {
1081 static const SleepOperation operations
[] = {
1088 if (!clock_supported(CLOCK_BOOTTIME_ALARM
)) {
1089 log_debug("CLOCK_BOOTTIME_ALARM is not supported.");
1093 for (size_t i
= 0; i
< ELEMENTSOF(operations
); i
++) {
1094 r
= can_sleep_internal(sleep_config
, operations
[i
], false);
1095 if (IN_SET(r
, 0, -ENOSPC
)) {
1096 log_debug("Unable to %s system.", sleep_operation_to_string(operations
[i
]));
1100 return log_debug_errno(r
, "Failed to check if %s is possible: %m", sleep_operation_to_string(operations
[i
]));
1106 static int can_sleep_internal(
1107 const SleepConfig
*sleep_config
,
1108 SleepOperation operation
,
1109 bool check_allowed
) {
1111 assert(operation
>= 0);
1112 assert(operation
< _SLEEP_OPERATION_MAX
);
1114 if (check_allowed
&& !sleep_config
->allow
[operation
]) {
1115 log_debug("Sleep mode \"%s\" is disabled by configuration.", sleep_operation_to_string(operation
));
1119 if (operation
== SLEEP_SUSPEND_THEN_HIBERNATE
)
1120 return can_s2h(sleep_config
);
1122 if (can_sleep_state(sleep_config
->states
[operation
]) <= 0 ||
1123 can_sleep_disk(sleep_config
->modes
[operation
]) <= 0)
1126 if (operation
== SLEEP_SUSPEND
)
1129 if (!enough_swap_for_hibernation())
1135 int can_sleep(SleepOperation operation
) {
1136 _cleanup_(free_sleep_configp
) SleepConfig
*sleep_config
= NULL
;
1139 r
= parse_sleep_config(&sleep_config
);
1143 return can_sleep_internal(sleep_config
, operation
, true);
1146 SleepConfig
* free_sleep_config(SleepConfig
*sc
) {
1150 for (SleepOperation i
= 0; i
< _SLEEP_OPERATION_MAX
; i
++) {
1151 strv_free(sc
->modes
[i
]);
1152 strv_free(sc
->states
[i
]);
1158 static const char* const sleep_operation_table
[_SLEEP_OPERATION_MAX
] = {
1159 [SLEEP_SUSPEND
] = "suspend",
1160 [SLEEP_HIBERNATE
] = "hibernate",
1161 [SLEEP_HYBRID_SLEEP
] = "hybrid-sleep",
1162 [SLEEP_SUSPEND_THEN_HIBERNATE
] = "suspend-then-hibernate",
1165 DEFINE_STRING_TABLE_LOOKUP(sleep_operation
, SleepOperation
);