summaryrefslogtreecommitdiffstats
path: root/src/hibernate-resume/hibernate-resume.c
diff options
context:
space:
mode:
authorMike Yuan <me@yhndnzj.com>2023-09-05 15:50:04 +0200
committerMike Yuan <me@yhndnzj.com>2023-09-07 14:21:16 +0200
commita628d933cc67cc8b183dc809ba1451aa5b2996e5 (patch)
tree4440309c1b40d99372a6dffcded8f680e4f541f7 /src/hibernate-resume/hibernate-resume.c
parentMerge pull request #28957 from yuwata/core-mount-set-dirty-on-umount (diff)
downloadsystemd-a628d933cc67cc8b183dc809ba1451aa5b2996e5.tar.xz
systemd-a628d933cc67cc8b183dc809ba1451aa5b2996e5.zip
hibernate-resume: split out the logic of finding hibernate location
Before this commit, the hibernate location logic only exists in the generator. Also, we compare device nodes (devnode_same()) and clear EFI variable HibernateLocation in the generator too. This is not ideal though: when the generator gets to run, udev hasn't yet started, so effectively devnode_same() always fails. Moreover, if the boot process is interrupted by e.g. battery-check, the hibernate information is lost. Therefore, let's split out the logic of finding hibernate location. The generator only does the initial validation of system info and enables systemd-hibernate-resume.service, and when the service actually runs we validate everything again, which includes comparing the device nodes and clearing the EFI variable. This should make things more robust, plus systems that don't utilize a systemd-enabled initrd can use the exact same logic to resume using the EFI variable. I.e., systemd-hibernate-resume can be used standalone.
Diffstat (limited to 'src/hibernate-resume/hibernate-resume.c')
-rw-r--r--src/hibernate-resume/hibernate-resume.c56
1 files changed, 42 insertions, 14 deletions
diff --git a/src/hibernate-resume/hibernate-resume.c b/src/hibernate-resume/hibernate-resume.c
index 28cab191fc..3c8335e175 100644
--- a/src/hibernate-resume/hibernate-resume.c
+++ b/src/hibernate-resume/hibernate-resume.c
@@ -4,14 +4,33 @@
#include <sys/stat.h>
#include "devnum-util.h"
+#include "hibernate-resume-config.h"
#include "initrd-util.h"
#include "log.h"
#include "main-func.h"
#include "parse-util.h"
#include "sleep-util.h"
+#include "static-destruct.h"
-static const char *arg_resume_device = NULL;
-static uint64_t arg_resume_offset = 0; /* in memory pages */
+HibernateInfo arg_info = {};
+
+STATIC_DESTRUCTOR_REGISTER(arg_info, hibernate_info_done);
+
+static int setup_hibernate_info_and_warn(void) {
+ int r;
+
+ r = acquire_hibernate_info(&arg_info);
+ if (r == -ENODEV) {
+ log_info_errno(r, "No resume device found, exiting.");
+ return 0;
+ }
+ if (r < 0)
+ return r;
+
+ compare_hibernate_location_and_warn(&arg_info);
+
+ return 1;
+}
static int run(int argc, char *argv[]) {
struct stat st;
@@ -19,35 +38,44 @@ static int run(int argc, char *argv[]) {
log_setup();
- if (argc < 2 || argc > 3)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program expects one or two arguments.");
+ if (argc < 1 || argc > 3)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program expects zero, one, or two arguments.");
umask(0022);
if (!in_initrd())
return 0;
- arg_resume_device = argv[1];
+ if (argc > 1) {
+ arg_info.device = argv[1];
+
+ if (argc == 3) {
+ r = safe_atou64(argv[2], &arg_info.offset);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse resume offset %s: %m", argv[2]);
+ }
+ } else {
+ r = setup_hibernate_info_and_warn();
+ if (r <= 0)
+ return r;
- if (argc == 3) {
- r = safe_atou64(argv[2], &arg_resume_offset);
- if (r < 0)
- return log_error_errno(r, "Failed to parse resume offset %s: %m", argv[2]);
+ if (arg_info.from_efi)
+ clear_efi_hibernate_location();
}
- if (stat(arg_resume_device, &st) < 0)
- return log_error_errno(errno, "Failed to stat resume device '%s': %m", arg_resume_device);
+ if (stat(arg_info.device, &st) < 0)
+ return log_error_errno(errno, "Failed to stat resume device '%s': %m", arg_info.device);
if (!S_ISBLK(st.st_mode))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Resume device '%s' is not a block device.", arg_resume_device);
+ "Resume device '%s' is not a block device.", arg_info.device);
/* The write shall not return if a resume takes place. */
- r = write_resume_config(st.st_rdev, arg_resume_offset, arg_resume_device);
+ r = write_resume_config(st.st_rdev, arg_info.offset, arg_info.device);
log_full_errno(r < 0 ? LOG_ERR : LOG_DEBUG,
r < 0 ? r : SYNTHETIC_ERRNO(ENOENT),
"Unable to resume from device '%s' (" DEVNUM_FORMAT_STR ") offset %" PRIu64 ", continuing boot process.",
- arg_resume_device, DEVNUM_FORMAT_VAL(st.st_rdev), arg_resume_offset);
+ arg_info.device, DEVNUM_FORMAT_VAL(st.st_rdev), arg_info.offset);
return r;
}