mirror of
https://github.com/systemd/systemd.git
synced 2025-01-11 09:18:07 +03:00
hibernate-resume: support resuming through efivar HibernateLocation
This commit is contained in:
parent
90efe8a6d4
commit
9deeca1275
@ -32,7 +32,8 @@
|
||||
It creates the
|
||||
<citerefentry><refentrytitle>systemd-hibernate-resume.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
unit according to the value of <option>resume=</option> parameter
|
||||
specified on the kernel command line, which will instruct the kernel
|
||||
specified on the kernel command line, or the value of EFI variable
|
||||
<varname>HibernateLocation</varname>, which will instruct the kernel
|
||||
to resume the system from the hibernation image on that device.</para>
|
||||
</refsect1>
|
||||
|
||||
|
@ -2,17 +2,24 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sd-id128.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "dropin.h"
|
||||
#include "efivars.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "fstab-util.h"
|
||||
#include "generator.h"
|
||||
#include "id128-util.h"
|
||||
#include "initrd-util.h"
|
||||
#include "json.h"
|
||||
#include "log.h"
|
||||
#include "main-func.h"
|
||||
#include "os-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "proc-cmdline.h"
|
||||
#include "special.h"
|
||||
@ -30,6 +37,18 @@ 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;
|
||||
|
||||
@ -82,6 +101,88 @@ 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 (!streq(arg_resume_device, device))
|
||||
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;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
@ -162,6 +263,10 @@ static int run(const char *dest, const char *dest_early, const char *dest_late)
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = parse_efi_hibernate_location();
|
||||
if (r == -ENOMEM)
|
||||
return r;
|
||||
|
||||
return process_resume();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user