]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/hibernate-resume/hibernate-resume.c
ask-password-api: Add more debug logging
[thirdparty/systemd.git] / src / hibernate-resume / hibernate-resume.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
42483a74 2
89c727e0 3#include <getopt.h>
42483a74 4#include <sys/stat.h>
42483a74 5
decad482 6#include "alloc-util.h"
89c727e0 7#include "build.h"
ec61371f 8#include "devnum-util.h"
a628d933 9#include "hibernate-resume-config.h"
54d7fcc6 10#include "hibernate-util.h"
baa6a42d 11#include "initrd-util.h"
42483a74 12#include "log.h"
760e99bb
MY
13#include "main-func.h"
14#include "parse-util.h"
89c727e0 15#include "pretty-print.h"
a628d933 16#include "static-destruct.h"
42483a74 17
a3f7047f 18static HibernateInfo arg_info = {};
8f8e481f 19static bool arg_clear = false;
a628d933
MY
20
21STATIC_DESTRUCTOR_REGISTER(arg_info, hibernate_info_done);
22
89c727e0
MY
23static int help(void) {
24 _cleanup_free_ char *link = NULL;
25 int r;
26
27 r = terminal_urlify_man("systemd-hibernate-resume", "8", &link);
28 if (r < 0)
29 return log_oom();
30
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"
8f8e481f 35 " --clear Clear hibernation storage information from EFI and exit\n"
89c727e0
MY
36 "\nSee the %s for details.\n",
37 program_invocation_short_name,
38 ansi_highlight(),
39 ansi_normal(),
40 link);
41
42 return 0;
43}
44
45static int parse_argv(int argc, char *argv[]) {
46
47 enum {
48 ARG_VERSION = 0x100,
8f8e481f 49 ARG_CLEAR,
89c727e0
MY
50 };
51
52 static const struct option options[] = {
53 { "help", no_argument, NULL, 'h' },
54 { "version", no_argument, NULL, ARG_VERSION },
8f8e481f 55 { "clear", no_argument, NULL, ARG_CLEAR },
89c727e0
MY
56 {}
57 };
58
59 int c;
60
61 assert(argc >= 0);
62 assert(argv);
63
64 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
65
66 switch (c) {
67
68 case 'h':
69 return help();
70
71 case ARG_VERSION:
72 return version();
73
8f8e481f
MY
74 case ARG_CLEAR:
75 arg_clear = true;
76 break;
77
89c727e0
MY
78 case '?':
79 return -EINVAL;
80
81 default:
82 assert_not_reached();
83 }
84
8f8e481f
MY
85 if (argc > optind && arg_clear)
86 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
87 "Extraneous arguments specified with --clear, refusing.");
88
89c727e0
MY
89 return 1;
90}
91
a628d933
MY
92static int setup_hibernate_info_and_warn(void) {
93 int r;
94
95 r = acquire_hibernate_info(&arg_info);
96 if (r == -ENODEV) {
97 log_info_errno(r, "No resume device found, exiting.");
98 return 0;
99 }
100 if (r < 0)
101 return r;
102
103 compare_hibernate_location_and_warn(&arg_info);
104
105 return 1;
106}
760e99bb 107
8f8e481f
MY
108static int action_clear(void) {
109 int r;
110
111 assert(arg_clear);
112
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);
117 if (r <= 0)
118 return r;
119
120 r = clear_efi_hibernate_location_and_warn();
121 if (r > 0)
e14e9c9f 122 log_notice("Successfully cleared HibernateLocation EFI variable.");
8f8e481f
MY
123 return r;
124}
125
760e99bb 126static int run(int argc, char *argv[]) {
42483a74 127 struct stat st;
42483a74
IS
128 int r;
129
d2acb93d 130 log_setup();
42483a74 131
89c727e0
MY
132 r = parse_argv(argc, argv);
133 if (r <= 0)
134 return r;
135
136 if (argc - optind > 2)
a628d933 137 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program expects zero, one, or two arguments.");
760e99bb 138
42483a74
IS
139 umask(0022);
140
8f8e481f
MY
141 if (arg_clear)
142 return action_clear();
143
ac528e3e 144 if (!in_initrd())
8f8e481f
MY
145 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
146 "Not running in initrd, refusing to initiate resume from hibernation.");
ac528e3e 147
89c727e0 148 if (argc <= optind) {
a628d933
MY
149 r = setup_hibernate_info_and_warn();
150 if (r <= 0)
151 return r;
42483a74 152
24ab77c3 153 if (arg_info.efi)
fbc88824 154 (void) clear_efi_hibernate_location_and_warn();
89c727e0
MY
155 } else {
156 arg_info.device = ASSERT_PTR(argv[optind]);
157
158 if (argc - optind == 2) {
159 r = safe_atou64(argv[optind + 1], &arg_info.offset);
160 if (r < 0)
161 return log_error_errno(r, "Failed to parse resume offset %s: %m", argv[optind + 1]);
162 }
42483a74
IS
163 }
164
a628d933
MY
165 if (stat(arg_info.device, &st) < 0)
166 return log_error_errno(errno, "Failed to stat resume device '%s': %m", arg_info.device);
42483a74 167
760e99bb 168 if (!S_ISBLK(st.st_mode))
667b0c48 169 return log_error_errno(SYNTHETIC_ERRNO(ENOTBLK),
a628d933 170 "Resume device '%s' is not a block device.", arg_info.device);
42483a74 171
760e99bb 172 /* The write shall not return if a resume takes place. */
a628d933 173 r = write_resume_config(st.st_rdev, arg_info.offset, arg_info.device);
61b76b3a 174 log_full_errno(r < 0 || arg_info.efi ? LOG_WARNING : LOG_INFO,
760e99bb
MY
175 r < 0 ? r : SYNTHETIC_ERRNO(ENOENT),
176 "Unable to resume from device '%s' (" DEVNUM_FORMAT_STR ") offset %" PRIu64 ", continuing boot process.",
a628d933 177 arg_info.device, DEVNUM_FORMAT_VAL(st.st_rdev), arg_info.offset);
760e99bb 178 return r;
42483a74 179}
760e99bb
MY
180
181DEFINE_MAIN_FUNCTION(run);