2020-11-09 04:23:58 +00:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
2014-08-26 20:17:44 +00:00
|
|
|
|
|
|
|
#include <errno.h>
|
2024-03-31 11:47:34 +00:00
|
|
|
#include <getopt.h>
|
2014-08-26 20:17:44 +00:00
|
|
|
#include <sys/stat.h>
|
|
|
|
|
2024-03-31 11:47:34 +00:00
|
|
|
#include "build.h"
|
2022-04-13 14:13:10 +00:00
|
|
|
#include "devnum-util.h"
|
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.
2023-09-05 13:50:04 +00:00
|
|
|
#include "hibernate-resume-config.h"
|
2023-09-27 13:35:45 +00:00
|
|
|
#include "hibernate-util.h"
|
2022-11-05 16:29:43 +00:00
|
|
|
#include "initrd-util.h"
|
2014-08-26 20:17:44 +00:00
|
|
|
#include "log.h"
|
2023-04-18 17:21:55 +00:00
|
|
|
#include "main-func.h"
|
|
|
|
#include "parse-util.h"
|
2024-03-31 11:47:34 +00:00
|
|
|
#include "pretty-print.h"
|
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.
2023-09-05 13:50:04 +00:00
|
|
|
#include "static-destruct.h"
|
2024-03-31 11:47:34 +00:00
|
|
|
#include "terminal-util.h"
|
2014-08-26 20:17:44 +00:00
|
|
|
|
2023-10-23 13:02:25 +00:00
|
|
|
static HibernateInfo arg_info = {};
|
2024-03-31 12:30:50 +00:00
|
|
|
static bool arg_clear = false;
|
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.
2023-09-05 13:50:04 +00:00
|
|
|
|
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_info, hibernate_info_done);
|
|
|
|
|
2024-03-31 11:47:34 +00:00
|
|
|
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"
|
2024-03-31 12:30:50 +00:00
|
|
|
" --clear Clear hibernation storage information from EFI and exit\n"
|
2024-03-31 11:47:34 +00:00
|
|
|
"\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,
|
2024-03-31 12:30:50 +00:00
|
|
|
ARG_CLEAR,
|
2024-03-31 11:47:34 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const struct option options[] = {
|
|
|
|
{ "help", no_argument, NULL, 'h' },
|
|
|
|
{ "version", no_argument, NULL, ARG_VERSION },
|
2024-03-31 12:30:50 +00:00
|
|
|
{ "clear", no_argument, NULL, ARG_CLEAR },
|
2024-03-31 11:47:34 +00:00
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
2024-03-31 12:30:50 +00:00
|
|
|
case ARG_CLEAR:
|
|
|
|
arg_clear = true;
|
|
|
|
break;
|
|
|
|
|
2024-03-31 11:47:34 +00:00
|
|
|
case '?':
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
default:
|
|
|
|
assert_not_reached();
|
|
|
|
}
|
|
|
|
|
2024-03-31 12:30:50 +00:00
|
|
|
if (argc > optind && arg_clear)
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
"Extraneous arguments specified with --clear, refusing.");
|
|
|
|
|
2024-03-31 11:47:34 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
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.
2023-09-05 13:50:04 +00:00
|
|
|
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;
|
|
|
|
}
|
2023-04-18 17:21:55 +00:00
|
|
|
|
2024-03-31 12:30:50 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2023-04-18 17:21:55 +00:00
|
|
|
static int run(int argc, char *argv[]) {
|
2014-08-26 20:17:44 +00:00
|
|
|
struct stat st;
|
|
|
|
int r;
|
|
|
|
|
2021-01-17 06:12:28 +00:00
|
|
|
log_setup();
|
2014-08-26 20:17:44 +00:00
|
|
|
|
2024-03-31 11:47:34 +00:00
|
|
|
r = parse_argv(argc, argv);
|
|
|
|
if (r <= 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
if (argc - optind > 2)
|
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.
2023-09-05 13:50:04 +00:00
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program expects zero, one, or two arguments.");
|
2023-04-18 17:21:55 +00:00
|
|
|
|
2014-08-26 20:17:44 +00:00
|
|
|
umask(0022);
|
|
|
|
|
2024-03-31 12:30:50 +00:00
|
|
|
if (arg_clear)
|
|
|
|
return action_clear();
|
|
|
|
|
2014-08-28 18:24:12 +00:00
|
|
|
if (!in_initrd())
|
2024-03-31 12:30:50 +00:00
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
|
|
|
|
"Not running in initrd, refusing to initiate resume from hibernation.");
|
2014-08-28 18:24:12 +00:00
|
|
|
|
2024-03-31 11:47:34 +00:00
|
|
|
if (argc <= optind) {
|
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.
2023-09-05 13:50:04 +00:00
|
|
|
r = setup_hibernate_info_and_warn();
|
|
|
|
if (r <= 0)
|
|
|
|
return r;
|
2014-08-26 20:17:44 +00:00
|
|
|
|
2023-12-05 08:37:36 +00:00
|
|
|
if (arg_info.efi)
|
2024-03-31 12:17:14 +00:00
|
|
|
(void) clear_efi_hibernate_location_and_warn();
|
2024-03-31 11:47:34 +00:00
|
|
|
} 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]);
|
|
|
|
}
|
2014-08-26 20:17:44 +00:00
|
|
|
}
|
|
|
|
|
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.
2023-09-05 13:50:04 +00:00
|
|
|
if (stat(arg_info.device, &st) < 0)
|
|
|
|
return log_error_errno(errno, "Failed to stat resume device '%s': %m", arg_info.device);
|
2014-08-26 20:17:44 +00:00
|
|
|
|
2023-04-18 17:21:55 +00:00
|
|
|
if (!S_ISBLK(st.st_mode))
|
2024-04-02 16:51:37 +00:00
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(ENOTBLK),
|
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.
2023-09-05 13:50:04 +00:00
|
|
|
"Resume device '%s' is not a block device.", arg_info.device);
|
2014-08-26 20:17:44 +00:00
|
|
|
|
2023-04-18 17:21:55 +00:00
|
|
|
/* The write shall not return if a resume takes place. */
|
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.
2023-09-05 13:50:04 +00:00
|
|
|
r = write_resume_config(st.st_rdev, arg_info.offset, arg_info.device);
|
2023-04-18 17:21:55 +00:00
|
|
|
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.",
|
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.
2023-09-05 13:50:04 +00:00
|
|
|
arg_info.device, DEVNUM_FORMAT_VAL(st.st_rdev), arg_info.offset);
|
2014-08-26 20:17:44 +00:00
|
|
|
|
2023-04-18 17:21:55 +00:00
|
|
|
return r;
|
2014-08-26 20:17:44 +00:00
|
|
|
}
|
2023-04-18 17:21:55 +00:00
|
|
|
|
|
|
|
DEFINE_MAIN_FUNCTION(run);
|