1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
6 #include "alloc-util.h"
8 #include "devnum-util.h"
9 #include "hibernate-resume-config.h"
10 #include "hibernate-util.h"
11 #include "initrd-util.h"
13 #include "main-func.h"
14 #include "parse-util.h"
15 #include "pretty-print.h"
16 #include "static-destruct.h"
18 static HibernateInfo arg_info
= {};
19 static bool arg_clear
= false;
21 STATIC_DESTRUCTOR_REGISTER(arg_info
, hibernate_info_done
);
23 static int help(void) {
24 _cleanup_free_
char *link
= NULL
;
27 r
= terminal_urlify_man("systemd-hibernate-resume", "8", &link
);
31 printf("%s [OPTIONS...] [DEVICE [OFFSET]]\n"
32 "\n%sInitiate resume from hibernation.%s\n\n"
33 " -h --help Show this help\n"
34 " --version Show package version\n"
35 " --clear Clear hibernation storage information from EFI and exit\n"
36 "\nSee the %s for details.\n",
37 program_invocation_short_name
,
45 static int parse_argv(int argc
, char *argv
[]) {
52 static const struct option options
[] = {
53 { "help", no_argument
, NULL
, 'h' },
54 { "version", no_argument
, NULL
, ARG_VERSION
},
55 { "clear", no_argument
, NULL
, ARG_CLEAR
},
64 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0)
85 if (argc
> optind
&& arg_clear
)
86 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
87 "Extraneous arguments specified with --clear, refusing.");
92 static int setup_hibernate_info_and_warn(void) {
95 r
= acquire_hibernate_info(&arg_info
);
97 log_info_errno(r
, "No resume device found, exiting.");
103 compare_hibernate_location_and_warn(&arg_info
);
108 static int action_clear(void) {
113 /* Let's insist that the system identifier is verified still. After all if things don't match,
114 * the resume wouldn't get triggered in the first place. We should not erase the var if booted
115 * from LiveCD/portable systems/... */
116 r
= get_efi_hibernate_location(/* ret = */ NULL
);
120 r
= clear_efi_hibernate_location_and_warn();
122 log_notice("Successfully cleared HibernateLocation EFI variable.");
126 static int run(int argc
, char *argv
[]) {
132 r
= parse_argv(argc
, argv
);
136 if (argc
- optind
> 2)
137 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "This program expects zero, one, or two arguments.");
142 return action_clear();
145 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
146 "Not running in initrd, refusing to initiate resume from hibernation.");
148 if (argc
<= optind
) {
149 r
= setup_hibernate_info_and_warn();
154 (void) clear_efi_hibernate_location_and_warn();
156 arg_info
.device
= ASSERT_PTR(argv
[optind
]);
158 if (argc
- optind
== 2) {
159 r
= safe_atou64(argv
[optind
+ 1], &arg_info
.offset
);
161 return log_error_errno(r
, "Failed to parse resume offset %s: %m", argv
[optind
+ 1]);
165 if (stat(arg_info
.device
, &st
) < 0)
166 return log_error_errno(errno
, "Failed to stat resume device '%s': %m", arg_info
.device
);
168 if (!S_ISBLK(st
.st_mode
))
169 return log_error_errno(SYNTHETIC_ERRNO(ENOTBLK
),
170 "Resume device '%s' is not a block device.", arg_info
.device
);
172 /* The write shall not return if a resume takes place. */
173 r
= write_resume_config(st
.st_rdev
, arg_info
.offset
, arg_info
.device
);
174 log_full_errno(r
< 0 || arg_info
.efi
? LOG_WARNING
: LOG_INFO
,
175 r
< 0 ? r
: SYNTHETIC_ERRNO(ENOENT
),
176 "Unable to resume from device '%s' (" DEVNUM_FORMAT_STR
") offset %" PRIu64
", continuing boot process.",
177 arg_info
.device
, DEVNUM_FORMAT_VAL(st
.st_rdev
), arg_info
.offset
);
181 DEFINE_MAIN_FUNCTION(run
);