diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-12 03:50:42 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-12 03:50:42 +0000 |
commit | 78e9bb837c258ac0ec7712b3d612cc2f407e731e (patch) | |
tree | f515d16b6efd858a9aeb5b0ef5d6f90bf288283d /src/hibernate-resume | |
parent | Adding debian version 255.5-1. (diff) | |
download | systemd-78e9bb837c258ac0ec7712b3d612cc2f407e731e.tar.xz systemd-78e9bb837c258ac0ec7712b3d612cc2f407e731e.zip |
Merging upstream version 256.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/hibernate-resume')
-rw-r--r-- | src/hibernate-resume/hibernate-resume-config.c | 44 | ||||
-rw-r--r-- | src/hibernate-resume/hibernate-resume-config.h | 29 | ||||
-rw-r--r-- | src/hibernate-resume/hibernate-resume.c | 126 |
3 files changed, 140 insertions, 59 deletions
diff --git a/src/hibernate-resume/hibernate-resume-config.c b/src/hibernate-resume/hibernate-resume-config.c index e4be7ca..c7ed1bc 100644 --- a/src/hibernate-resume/hibernate-resume-config.c +++ b/src/hibernate-resume/hibernate-resume-config.c @@ -11,6 +11,12 @@ #include "proc-cmdline.h" #include "efivars.h" +typedef struct KernelHibernateLocation { + char *device; + uint64_t offset; + bool offset_set; +} KernelHibernateLocation; + static KernelHibernateLocation* kernel_hibernate_location_free(KernelHibernateLocation *k) { if (!k) return NULL; @@ -22,7 +28,7 @@ static KernelHibernateLocation* kernel_hibernate_location_free(KernelHibernateLo DEFINE_TRIVIAL_CLEANUP_FUNC(KernelHibernateLocation*, kernel_hibernate_location_free); -static EFIHibernateLocation* efi_hibernate_location_free(EFIHibernateLocation *e) { +EFIHibernateLocation* efi_hibernate_location_free(EFIHibernateLocation *e) { if (!e) return NULL; @@ -36,8 +42,6 @@ static EFIHibernateLocation* efi_hibernate_location_free(EFIHibernateLocation *e return mfree(e); } -DEFINE_TRIVIAL_CLEANUP_FUNC(EFIHibernateLocation*, efi_hibernate_location_free); - void hibernate_info_done(HibernateInfo *info) { assert(info); @@ -121,7 +125,7 @@ static bool validate_efi_hibernate_location(EFIHibernateLocation *e) { if (!streq_ptr(id, e->id) || !streq_ptr(image_id, e->image_id)) { - log_notice("HibernateLocation system identifier doesn't match currently running system, not resuming from it."); + log_notice("HibernateLocation system identifier doesn't match currently running system, would not resume from it."); return false; } @@ -133,9 +137,10 @@ static bool validate_efi_hibernate_location(EFIHibernateLocation *e) { return true; } +#endif -static int get_efi_hibernate_location(EFIHibernateLocation **ret) { - +int get_efi_hibernate_location(EFIHibernateLocation **ret) { +#if ENABLE_EFI static const JsonDispatch dispatch_table[] = { { "uuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(EFIHibernateLocation, uuid), JSON_MANDATORY }, { "offset", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint64, offsetof(EFIHibernateLocation, offset), JSON_MANDATORY }, @@ -152,8 +157,6 @@ static int get_efi_hibernate_location(EFIHibernateLocation **ret) { _cleanup_free_ char *location_str = NULL; int r; - assert(ret); - if (!is_efi_boot()) goto skip; @@ -173,7 +176,7 @@ static int get_efi_hibernate_location(EFIHibernateLocation **ret) { if (!e) return log_oom(); - r = json_dispatch(v, dispatch_table, JSON_LOG, e); + r = json_dispatch(v, dispatch_table, JSON_LOG|JSON_ALLOW_EXTENSIONS, e); if (r < 0) return r; @@ -192,15 +195,19 @@ static int get_efi_hibernate_location(EFIHibernateLocation **ret) { 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); + if (ret) + *ret = TAKE_PTR(e); return 1; skip: - *ret = NULL; +#endif + if (ret) + *ret = NULL; return 0; } void compare_hibernate_location_and_warn(const HibernateInfo *info) { +#if ENABLE_EFI int r; assert(info); @@ -224,19 +231,8 @@ void compare_hibernate_location_and_warn(const HibernateInfo *info) { 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 = {}; @@ -246,11 +242,9 @@ int acquire_hibernate_info(HibernateInfo *ret) { 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; diff --git a/src/hibernate-resume/hibernate-resume-config.h b/src/hibernate-resume/hibernate-resume-config.h index 365d9cc..68ef075 100644 --- a/src/hibernate-resume/hibernate-resume-config.h +++ b/src/hibernate-resume/hibernate-resume-config.h @@ -5,11 +5,9 @@ #include "sd-id128.h" -typedef struct KernelHibernateLocation { - char *device; - uint64_t offset; - bool offset_set; -} KernelHibernateLocation; +#include "macro.h" + +typedef struct KernelHibernateLocation KernelHibernateLocation; typedef struct EFIHibernateLocation { char *device; @@ -24,6 +22,11 @@ typedef struct EFIHibernateLocation { char *image_version; } EFIHibernateLocation; +EFIHibernateLocation* efi_hibernate_location_free(EFIHibernateLocation *e); +DEFINE_TRIVIAL_CLEANUP_FUNC(EFIHibernateLocation*, efi_hibernate_location_free); + +int get_efi_hibernate_location(EFIHibernateLocation **ret); + typedef struct HibernateInfo { const char *device; uint64_t offset; /* in memory pages */ @@ -36,20 +39,4 @@ 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.c b/src/hibernate-resume/hibernate-resume.c index 175a0bd..c6494b9 100644 --- a/src/hibernate-resume/hibernate-resume.c +++ b/src/hibernate-resume/hibernate-resume.c @@ -1,8 +1,10 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include <errno.h> +#include <getopt.h> #include <sys/stat.h> +#include "build.h" #include "devnum-util.h" #include "hibernate-resume-config.h" #include "hibernate-util.h" @@ -10,12 +12,84 @@ #include "log.h" #include "main-func.h" #include "parse-util.h" +#include "pretty-print.h" #include "static-destruct.h" +#include "terminal-util.h" static HibernateInfo arg_info = {}; +static bool arg_clear = false; STATIC_DESTRUCTOR_REGISTER(arg_info, hibernate_info_done); +static int help(void) { + _cleanup_free_ char *link = NULL; + int r; + + r = terminal_urlify_man("systemd-hibernate-resume", "8", &link); + if (r < 0) + return log_oom(); + + printf("%s [OPTIONS...] [DEVICE [OFFSET]]\n" + "\n%sInitiate resume from hibernation.%s\n\n" + " -h --help Show this help\n" + " --version Show package version\n" + " --clear Clear hibernation storage information from EFI and exit\n" + "\nSee the %s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + link); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_VERSION = 0x100, + ARG_CLEAR, + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "clear", no_argument, NULL, ARG_CLEAR }, + {} + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) + + switch (c) { + + case 'h': + return help(); + + case ARG_VERSION: + return version(); + + case ARG_CLEAR: + arg_clear = true; + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached(); + } + + if (argc > optind && arg_clear) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Extraneous arguments specified with --clear, refusing."); + + return 1; +} + static int setup_hibernate_info_and_warn(void) { int r; @@ -32,42 +106,68 @@ static int setup_hibernate_info_and_warn(void) { return 1; } +static int action_clear(void) { + int r; + + assert(arg_clear); + + /* Let's insist that the system identifier is verified still. After all if things don't match, + * the resume wouldn't get triggered in the first place. We should not erase the var if booted + * from LiveCD/portable systems/... */ + r = get_efi_hibernate_location(/* ret = */ NULL); + if (r <= 0) + return r; + + r = clear_efi_hibernate_location_and_warn(); + if (r > 0) + log_notice("Successfully cleared HibernateLocation EFI variable."); + return r; +} + static int run(int argc, char *argv[]) { struct stat st; int r; log_setup(); - if (argc < 1 || argc > 3) + r = parse_argv(argc, argv); + if (r <= 0) + return r; + + if (argc - optind > 2) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program expects zero, one, or two arguments."); umask(0022); - if (!in_initrd()) - return 0; + if (arg_clear) + return action_clear(); - if (argc > 1) { - arg_info.device = argv[1]; + if (!in_initrd()) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Not running in initrd, refusing to initiate resume from hibernation."); - 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 { + if (argc <= optind) { r = setup_hibernate_info_and_warn(); if (r <= 0) return r; if (arg_info.efi) - clear_efi_hibernate_location(); + (void) clear_efi_hibernate_location_and_warn(); + } else { + arg_info.device = ASSERT_PTR(argv[optind]); + + if (argc - optind == 2) { + r = safe_atou64(argv[optind + 1], &arg_info.offset); + if (r < 0) + return log_error_errno(r, "Failed to parse resume offset %s: %m", argv[optind + 1]); + } } 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), + return log_error_errno(SYNTHETIC_ERRNO(ENOTBLK), "Resume device '%s' is not a block device.", arg_info.device); /* The write shall not return if a resume takes place. */ |