#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"
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;
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;
return 0;
}
+ r = parse_efi_hibernate_location();
+ if (r == -ENOMEM)
+ return r;
+
return process_resume();
}