diff --git a/src/hibernate-resume/hibernate-resume-config.c b/src/hibernate-resume/hibernate-resume-config.c new file mode 100644 index 0000000000..4aac6234d0 --- /dev/null +++ b/src/hibernate-resume/hibernate-resume-config.c @@ -0,0 +1,264 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include + +#include "alloc-util.h" +#include "device-nodes.h" +#include "fstab-util.h" +#include "hibernate-resume-config.h" +#include "json.h" +#include "os-util.h" +#include "parse-util.h" +#include "path-util.h" +#include "proc-cmdline.h" +#include "efivars.h" + +static KernelHibernateLocation* kernel_hibernate_location_free(KernelHibernateLocation *k) { + if (!k) + return NULL; + + free(k->device); + + return mfree(k); +} + +DEFINE_TRIVIAL_CLEANUP_FUNC(KernelHibernateLocation*, kernel_hibernate_location_free); + +static EFIHibernateLocation* efi_hibernate_location_free(EFIHibernateLocation *e) { + if (!e) + return NULL; + + free(e->device); + + free(e->kernel_version); + free(e->id); + free(e->image_id); + free(e->image_version); + + return mfree(e); +} + +DEFINE_TRIVIAL_CLEANUP_FUNC(EFIHibernateLocation*, efi_hibernate_location_free); + +void hibernate_info_done(HibernateInfo *info) { + assert(info); + + kernel_hibernate_location_free(info->cmdline); + efi_hibernate_location_free(info->efi); +} + +static int parse_proc_cmdline_item(const char *key, const char *value, void *data) { + KernelHibernateLocation *k = ASSERT_PTR(data); + int r; + + assert(key); + + if (streq(key, "resume")) { + _cleanup_free_ char *d = NULL; + + if (proc_cmdline_value_missing(key, value)) + return 0; + + d = fstab_node_to_udev_node(value); + if (!d) + return log_oom(); + + free_and_replace(k->device, d); + + } else if (proc_cmdline_key_streq(key, "resume_offset")) { + + if (proc_cmdline_value_missing(key, value)) + return 0; + + r = safe_atou64(value, &k->offset); + if (r < 0) + return log_error_errno(r, "Failed to parse resume_offset=%s: %m", value); + + k->offset_set = true; + } + + return 0; +} + +static int get_kernel_hibernate_location(KernelHibernateLocation **ret) { + _cleanup_(kernel_hibernate_location_freep) KernelHibernateLocation *k = NULL; + int r; + + assert(ret); + + k = new0(KernelHibernateLocation, 1); + if (!k) + return log_oom(); + + r = proc_cmdline_parse(parse_proc_cmdline_item, k, 0); + if (r < 0) + return log_error_errno(r, "Failed to parse kernel command line: %m"); + + if (!k->device) { + if (k->offset_set) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Found resume_offset=%" PRIu64 " but resume= is unset, refusing.", + k->offset); + + *ret = NULL; + return 0; + } + + *ret = TAKE_PTR(k); + return 1; +} + +#if ENABLE_EFI +static bool validate_efi_hibernate_location(EFIHibernateLocation *e) { + _cleanup_free_ char *id = NULL, *image_id = NULL, *version_id = NULL, *image_version = NULL; + struct utsname uts = {}; + int r; + + assert(e); + + if (uname(&uts) < 0) + log_warning_errno(errno, "Failed to get kernel info, ignoring: %m"); + + r = parse_os_release(NULL, + "ID", &id, + "IMAGE_ID", &image_id, + "VERSION_ID", &version_id, + "IMAGE_VERSION", &image_version); + if (r < 0) + log_warning_errno(r, "Failed to parse os-release, ignoring: %m"); + + if (!streq(uts.release, strempty(e->kernel_version)) || + !streq_ptr(id, e->id) || + !streq_ptr(image_id, e->image_id) || + !streq_ptr(version_id, e->version_id) || + !streq_ptr(image_version, e->image_version)) { + + log_notice("HibernateLocation system info doesn't match with current running system, not resuming from it."); + return false; + } + + return true; +} + +static int get_efi_hibernate_location(EFIHibernateLocation **ret) { + + static const JsonDispatch dispatch_table[] = { + { "uuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(EFIHibernateLocation, uuid), JSON_MANDATORY }, + { "offset", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(EFIHibernateLocation, offset), JSON_MANDATORY }, + { "kernelVersion", JSON_VARIANT_STRING, json_dispatch_string, offsetof(EFIHibernateLocation, kernel_version), JSON_PERMISSIVE|JSON_DEBUG }, + { "osReleaseId", JSON_VARIANT_STRING, json_dispatch_string, offsetof(EFIHibernateLocation, id), JSON_PERMISSIVE|JSON_DEBUG }, + { "osReleaseImageId", JSON_VARIANT_STRING, json_dispatch_string, offsetof(EFIHibernateLocation, image_id), JSON_PERMISSIVE|JSON_DEBUG }, + { "osReleaseVersionId", JSON_VARIANT_STRING, json_dispatch_string, offsetof(EFIHibernateLocation, version_id), JSON_PERMISSIVE|JSON_DEBUG }, + { "osReleaseImageVersion", JSON_VARIANT_STRING, json_dispatch_string, offsetof(EFIHibernateLocation, image_version), JSON_PERMISSIVE|JSON_DEBUG }, + {}, + }; + + _cleanup_(efi_hibernate_location_freep) EFIHibernateLocation *e = NULL; + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + _cleanup_free_ char *location_str = NULL; + int r; + + assert(ret); + + if (!is_efi_boot()) + goto skip; + + r = efi_get_variable_string(EFI_SYSTEMD_VARIABLE(HibernateLocation), &location_str); + if (r == -ENOENT) { + log_debug_errno(r, "EFI variable HibernateLocation is not set, skipping."); + goto skip; + } + if (r < 0) + return log_error_errno(r, "Failed to get EFI variable HibernateLocation: %m"); + + r = json_parse(location_str, 0, &v, NULL, NULL); + if (r < 0) + return log_error_errno(r, "Failed to parse HibernateLocation JSON object: %m"); + + e = new0(EFIHibernateLocation, 1); + if (!e) + return log_oom(); + + r = json_dispatch(v, dispatch_table, NULL, JSON_LOG, e); + if (r < 0) + return r; + + if (!validate_efi_hibernate_location(e)) + goto skip; + + if (asprintf(&e->device, "/dev/disk/by-uuid/" SD_ID128_UUID_FORMAT_STR, SD_ID128_FORMAT_VAL(e->uuid)) < 0) + return log_oom(); + + *ret = TAKE_PTR(e); + return 1; + +skip: + *ret = NULL; + return 0; +} + +void compare_hibernate_location_and_warn(const HibernateInfo *info) { + int r; + + assert(info); + assert(info->from_efi || info->cmdline); + + if (info->from_efi) + return; + if (!info->efi) + return; + + if (!path_equal(info->cmdline->device, info->efi->device)) { + r = devnode_same(info->cmdline->device, info->efi->device); + if (r < 0) + log_warning_errno(r, + "Failed to check if resume=%s is the same device as EFI HibernateLocation device '%s', ignoring: %m", + info->cmdline->device, info->efi->device); + if (r == 0) + log_warning("resume=%s doesn't match with EFI HibernateLocation device '%s', proceeding anyway with resume=.", + info->cmdline->device, info->efi->device); + } + + if (info->cmdline->offset != info->efi->offset) + log_warning("resume_offset=%" PRIu64 " doesn't match with EFI HibernateLocation offset %" PRIu64 ", proceeding anyway with resume_offset=.", + info->cmdline->offset, info->efi->offset); +} + +void clear_efi_hibernate_location(void) { + int r; + + if (!is_efi_boot()) + return; + + r = efi_set_variable(EFI_SYSTEMD_VARIABLE(HibernateLocation), NULL, 0); + if (r < 0) + log_warning_errno(r, "Failed to clear EFI variable HibernateLocation, ignoring: %m"); +} +#endif + +int acquire_hibernate_info(HibernateInfo *ret) { + _cleanup_(hibernate_info_done) HibernateInfo i = {}; + int r; + + r = get_kernel_hibernate_location(&i.cmdline); + if (r < 0) + return r; + +#if ENABLE_EFI + r = get_efi_hibernate_location(&i.efi); + if (r < 0) + return r; +#endif + + if (i.cmdline) { + i.device = i.cmdline->device; + i.from_efi = false; + } else if (i.efi) { + i.device = i.efi->device; + i.from_efi = true; + } else + return -ENODEV; + + *ret = TAKE_STRUCT(i); + return 0; +} diff --git a/src/hibernate-resume/hibernate-resume-config.h b/src/hibernate-resume/hibernate-resume-config.h new file mode 100644 index 0000000000..a77d29c891 --- /dev/null +++ b/src/hibernate-resume/hibernate-resume-config.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include + +#include "sd-id128.h" + +typedef struct KernelHibernateLocation { + char *device; + uint64_t offset; + bool offset_set; +} KernelHibernateLocation; + +typedef struct EFIHibernateLocation { + char *device; + + sd_id128_t uuid; + uint64_t offset; + + char *kernel_version; + char *id; + char *image_id; + char *version_id; + char *image_version; +} EFIHibernateLocation; + +typedef struct HibernateInfo { + const char *device; + uint64_t offset; /* in memory pages */ + bool from_efi; + + KernelHibernateLocation *cmdline; + EFIHibernateLocation *efi; +} HibernateInfo; + +void hibernate_info_done(HibernateInfo *info); + +int acquire_hibernate_info(HibernateInfo *ret); + +#if ENABLE_EFI + +void compare_hibernate_location_and_warn(const HibernateInfo *info); + +void clear_efi_hibernate_location(void); + +#else + +static inline void compare_hibernate_location_and_warn(const HibernateInfo *info) { + return; +} + +static inline void clear_efi_hibernate_location(void) { + return; +} + +#endif diff --git a/src/hibernate-resume/hibernate-resume-generator.c b/src/hibernate-resume/hibernate-resume-generator.c index 8b83ad6bdb..c1c21a2c13 100644 --- a/src/hibernate-resume/hibernate-resume-generator.c +++ b/src/hibernate-resume/hibernate-resume-generator.c @@ -1,87 +1,31 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include -#include -#include -#include - -#include "sd-id128.h" - #include "alloc-util.h" -#include "device-nodes.h" #include "dropin.h" -#include "efivars.h" -#include "escape.h" -#include "fd-util.h" -#include "fileio.h" -#include "fstab-util.h" #include "generator.h" -#include "id128-util.h" +#include "hibernate-resume-config.h" #include "initrd-util.h" -#include "json.h" #include "log.h" #include "main-func.h" -#include "os-util.h" #include "parse-util.h" -#include "path-util.h" #include "proc-cmdline.h" #include "special.h" +#include "static-destruct.h" #include "string-util.h" #include "unit-name.h" static const char *arg_dest = NULL; -static char *arg_resume_device = NULL; static char *arg_resume_options = NULL; static char *arg_root_options = NULL; static bool arg_noresume = false; -static uint64_t arg_resume_offset = 0; -static bool arg_resume_offset_set = false; -STATIC_DESTRUCTOR_REGISTER(arg_resume_device, freep); STATIC_DESTRUCTOR_REGISTER(arg_resume_options, freep); STATIC_DESTRUCTOR_REGISTER(arg_root_options, freep); -#if ENABLE_EFI -typedef struct EFIHibernateLocation { - sd_id128_t uuid; - uint64_t offset; - const char *kernel_version; - const char *id; - const char *image_id; - const char *version_id; - const char *image_version; -} EFIHibernateLocation; -#endif - static int parse_proc_cmdline_item(const char *key, const char *value, void *data) { - int r; - assert(key); - if (streq(key, "resume")) { - char *s; - - if (proc_cmdline_value_missing(key, value)) - return 0; - - s = fstab_node_to_udev_node(value); - if (!s) - return log_oom(); - - free_and_replace(arg_resume_device, s); - - } else if (proc_cmdline_key_streq(key, "resume_offset")) { - - if (proc_cmdline_value_missing(key, value)) - return 0; - - r = safe_atou64(value, &arg_resume_offset); - if (r < 0) - return log_error_errno(r, "Failed to parse resume_offset=%s: %m", value); - - arg_resume_offset_set = true; - - } else if (streq(key, "resumeflags")) { + if (streq(key, "resumeflags")) { if (proc_cmdline_value_missing(key, value)) return 0; @@ -100,7 +44,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat } else if (streq(key, "noresume")) { if (value) { - log_warning("\"noresume\" kernel command line switch specified with an argument, ignoring."); + log_warning("'noresume' kernel command line option specified with an argument, ignoring."); return 0; } @@ -110,106 +54,15 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat return 0; } -static int parse_efi_hibernate_location(void) { - int r = 0; - -#if ENABLE_EFI - static const JsonDispatch dispatch_table[] = { - { "uuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(EFIHibernateLocation, uuid), JSON_MANDATORY }, - { "offset", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(EFIHibernateLocation, offset), JSON_MANDATORY }, - { "kernelVersion", JSON_VARIANT_STRING, json_dispatch_const_string, offsetof(EFIHibernateLocation, kernel_version), JSON_PERMISSIVE|JSON_DEBUG }, - { "osReleaseId", JSON_VARIANT_STRING, json_dispatch_const_string, offsetof(EFIHibernateLocation, id), JSON_PERMISSIVE|JSON_DEBUG }, - { "osReleaseImageId", JSON_VARIANT_STRING, json_dispatch_const_string, offsetof(EFIHibernateLocation, image_id), JSON_PERMISSIVE|JSON_DEBUG }, - { "osReleaseVersionId", JSON_VARIANT_STRING, json_dispatch_const_string, offsetof(EFIHibernateLocation, version_id), JSON_PERMISSIVE|JSON_DEBUG }, - { "osReleaseImageVersion", JSON_VARIANT_STRING, json_dispatch_const_string, offsetof(EFIHibernateLocation, image_version), JSON_PERMISSIVE|JSON_DEBUG }, - {}, - }; - - _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; - _cleanup_free_ char *location_str = NULL, *device = NULL, *id = NULL, *image_id = NULL, - *version_id = NULL, *image_version = NULL; - struct utsname uts = {}; - EFIHibernateLocation location = {}; - - r = efi_get_variable_string(EFI_SYSTEMD_VARIABLE(HibernateLocation), &location_str); - if (r == -ENOENT) { - log_debug_errno(r, "EFI variable HibernateLocation is not set, skipping."); - return 0; - } - if (r < 0) - return log_error_errno(r, "Failed to get EFI variable HibernateLocation: %m"); - - r = json_parse(location_str, 0, &v, NULL, NULL); - if (r < 0) - return log_error_errno(r, "Failed to parse HibernateLocation JSON object: %m"); - - r = json_dispatch(v, dispatch_table, NULL, JSON_LOG, &location); - if (r < 0) - return r; - - if (uname(&uts) < 0) - log_warning_errno(errno, "Failed to get kernel info, ignoring: %m"); - - r = parse_os_release(NULL, - "ID", &id, - "IMAGE_ID", &image_id, - "VERSION_ID", &version_id, - "IMAGE_VERSION", &image_version); - if (r < 0) - log_warning_errno(r, "Failed to parse os-release, ignoring: %m"); - - if (!streq(uts.release, strempty(location.kernel_version)) || - !streq_ptr(id, location.id) || - !streq_ptr(image_id, location.image_id) || - !streq_ptr(version_id, location.version_id) || - !streq_ptr(image_version, location.image_version)) { - - log_notice("HibernateLocation system info doesn't match with current running system, not resuming from it."); - return 0; - } - - if (asprintf(&device, "/dev/disk/by-uuid/" SD_ID128_UUID_FORMAT_STR, SD_ID128_FORMAT_VAL(location.uuid)) < 0) - return log_oom(); - - if (!arg_resume_device) { - arg_resume_device = TAKE_PTR(device); - arg_resume_offset = location.offset; - } else { - if (!path_equal(arg_resume_device, device)) { - r = devnode_same(arg_resume_device, device); - if (r < 0) - log_debug_errno(r, - "Failed to check if resume=%s is the same device as HibernateLocation device '%s', ignoring: %m", - arg_resume_device, device); - if (r == 0) - log_warning("resume=%s doesn't match with HibernateLocation device '%s', proceeding anyway with resume=.", - arg_resume_device, device); - } - - if (arg_resume_offset != location.offset) - log_warning("resume_offset=%" PRIu64 " doesn't match with HibernateLocation offset %" PRIu64 ", proceeding anyway with resume_offset=.", - arg_resume_offset, location.offset); - } - - r = efi_set_variable(EFI_SYSTEMD_VARIABLE(HibernateLocation), NULL, 0); - if (r < 0) - log_warning_errno(r, "Failed to clear EFI variable HibernateLocation, ignoring: %m"); -#endif - - return r; -} - -static int process_resume(void) { - _cleanup_free_ char *device_unit = NULL, *device_escaped = NULL; - _cleanup_fclose_ FILE *f = NULL; +static int process_resume(const char *device) { + _cleanup_free_ char *device_unit = NULL; int r; - if (!arg_resume_device) - return 0; + assert(device); - r = unit_name_from_path(arg_resume_device, ".device", &device_unit); + r = unit_name_from_path(device, ".device", &device_unit); if (r < 0) - return log_error_errno(r, "Failed to generate device unit name from path '%s': %m", arg_resume_device); + return log_error_errno(r, "Failed to generate device unit name from path '%s': %m", device); r = write_drop_in(arg_dest, device_unit, 40, "device-timeout", "# Automatically generated by systemd-hibernate-resume-generator\n\n" @@ -218,59 +71,35 @@ static int process_resume(void) { if (r < 0) log_warning_errno(r, "Failed to write device timeout drop-in, ignoring: %m"); - device_escaped = cescape(arg_resume_device); - if (!device_escaped) - return log_oom(); - - r = generator_open_unit_file(arg_dest, NULL, SPECIAL_HIBERNATE_RESUME_SERVICE, &f); - if (r < 0) - return r; - - fprintf(f, - "[Unit]\n" - "Description=Resume from hibernation\n" - "Documentation=man:systemd-hibernate-resume.service(8)\n" - "DefaultDependencies=no\n" - "BindsTo=%1$s\n" - "Wants=local-fs-pre.target\n" - "After=%1$s\n" - "Before=local-fs-pre.target\n" - "AssertPathExists=/etc/initrd-release\n" - "\n" - "[Service]\n" - "Type=oneshot\n" - "ExecStart=" LIBEXECDIR "/systemd-hibernate-resume %2$s %3$" PRIu64 "\n", - device_unit, - device_escaped, - arg_resume_offset); - - r = fflush_and_check(f); - if (r < 0) - return log_error_errno(r, "Failed to create " SPECIAL_HIBERNATE_RESUME_SERVICE ": %m"); - - r = generator_add_symlink(arg_dest, SPECIAL_SYSINIT_TARGET, "wants", SPECIAL_HIBERNATE_RESUME_SERVICE); - if (r < 0) - return r; - r = generator_write_timeouts(arg_dest, - arg_resume_device, - arg_resume_device, + device, + device, arg_resume_options ?: arg_root_options, NULL); if (r < 0) - return r; + log_warning_errno(r, "Failed to write device timeout drop-in, ignoring: %m"); - return 0; + r = write_drop_in_format(arg_dest, SPECIAL_HIBERNATE_RESUME_SERVICE, 90, "device-dependency", + "# Automatically generated by systemd-hibernate-resume-generator\n\n" + "[Unit]\n" + "BindsTo=%1$s\n" + "After=%1$s\n", + device_unit); + if (r < 0) + return log_error_errno(r, "Failed to write device dependency drop-in: %m"); + + return generator_add_symlink(arg_dest, SPECIAL_SYSINIT_TARGET, "wants", SPECIAL_HIBERNATE_RESUME_SERVICE); } static int run(const char *dest, const char *dest_early, const char *dest_late) { + _cleanup_(hibernate_info_done) HibernateInfo info = {}; int r; arg_dest = ASSERT_PTR(dest); /* Don't even consider resuming outside of initrd. */ if (!in_initrd()) { - log_debug("Not running in an initrd, exiting."); + log_debug("Not running in initrd, exiting."); return 0; } @@ -279,20 +108,19 @@ static int run(const char *dest, const char *dest_early, const char *dest_late) log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m"); if (arg_noresume) { - log_info("Found \"noresume\" on the kernel command line, exiting."); + log_info("Found 'noresume' on the kernel command line, exiting."); return 0; } - if (!arg_resume_device && arg_resume_offset_set) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Found resume_offset=%" PRIu64 " but resume= is unset, refusing.", - arg_resume_offset); - - r = parse_efi_hibernate_location(); - if (r == -ENOMEM) + r = acquire_hibernate_info(&info); + if (r == -ENODEV) { + log_debug_errno(r, "No resume device found, exiting."); + return 0; + } + if (r < 0) return r; - return process_resume(); + return process_resume(info.device); } DEFINE_MAIN_GENERATOR_FUNCTION(run); 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 #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_resume_offset); - if (r < 0) - return log_error_errno(r, "Failed to parse resume offset %s: %m", argv[2]); + 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 (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; } diff --git a/src/hibernate-resume/meson.build b/src/hibernate-resume/meson.build index b14ea356c5..4a6430cc49 100644 --- a/src/hibernate-resume/meson.build +++ b/src/hibernate-resume/meson.build @@ -4,11 +4,11 @@ executables += [ generator_template + { 'name' : 'systemd-hibernate-resume-generator', 'conditions' : ['ENABLE_HIBERNATE'], - 'sources' : files('hibernate-resume-generator.c'), + 'sources' : files('hibernate-resume-generator.c', 'hibernate-resume-config.c'), }, libexec_template + { 'name' : 'systemd-hibernate-resume', 'conditions' : ['ENABLE_HIBERNATE'], - 'sources' : files('hibernate-resume.c'), + 'sources' : files('hibernate-resume.c', 'hibernate-resume-config.c'), }, ] diff --git a/units/meson.build b/units/meson.build index 2e649d6e5f..2fb87934b8 100644 --- a/units/meson.build +++ b/units/meson.build @@ -291,6 +291,10 @@ units = [ { 'file' : 'systemd-growfs-root.service.in' }, { 'file' : 'systemd-growfs@.service.in' }, { 'file' : 'systemd-halt.service' }, + { + 'file' : 'systemd-hibernate-resume.service.in', + 'conditions' : ['ENABLE_HIBERNATE'], + }, { 'file' : 'systemd-hibernate.service.in', 'conditions' : ['ENABLE_HIBERNATE'], diff --git a/units/systemd-hibernate-resume.service.in b/units/systemd-hibernate-resume.service.in new file mode 100644 index 0000000000..dce4f0ffe1 --- /dev/null +++ b/units/systemd-hibernate-resume.service.in @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# 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 +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=Resume from hibernation +Documentation=man:systemd-hibernate-resume.service(8) + +ConditionKernelCommandLine=!noresume + +DefaultDependencies=no +Wants=local-fs-pre.target +Before=local-fs-pre.target + +AssertPathExists=/etc/initrd-release + +[Service] +Type=oneshot +ExecStart={{LIBEXECDIR}}/systemd-hibernate-resume