]> git.ipfire.org Git - thirdparty/systemd.git/blame_incremental - src/hibernate-resume/hibernate-resume.c
analyze: fix typo
[thirdparty/systemd.git] / src / hibernate-resume / hibernate-resume.c
... / ...
CommitLineData
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3#include <getopt.h>
4#include <sys/stat.h>
5
6#include "alloc-util.h"
7#include "build.h"
8#include "devnum-util.h"
9#include "hibernate-resume-config.h"
10#include "hibernate-util.h"
11#include "initrd-util.h"
12#include "log.h"
13#include "main-func.h"
14#include "parse-util.h"
15#include "pretty-print.h"
16#include "static-destruct.h"
17
18static HibernateInfo arg_info = {};
19static bool arg_clear = false;
20
21STATIC_DESTRUCTOR_REGISTER(arg_info, hibernate_info_done);
22
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"
35 " --clear Clear hibernation storage information from EFI and exit\n"
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,
49 ARG_CLEAR,
50 };
51
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 },
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
74 case ARG_CLEAR:
75 arg_clear = true;
76 break;
77
78 case '?':
79 return -EINVAL;
80
81 default:
82 assert_not_reached();
83 }
84
85 if (argc > optind && arg_clear)
86 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
87 "Extraneous arguments specified with --clear, refusing.");
88
89 return 1;
90}
91
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}
107
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)
122 log_notice("Successfully cleared HibernateLocation EFI variable.");
123 return r;
124}
125
126static int run(int argc, char *argv[]) {
127 struct stat st;
128 int r;
129
130 log_setup();
131
132 r = parse_argv(argc, argv);
133 if (r <= 0)
134 return r;
135
136 if (argc - optind > 2)
137 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program expects zero, one, or two arguments.");
138
139 umask(0022);
140
141 if (arg_clear)
142 return action_clear();
143
144 if (!in_initrd())
145 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE),
146 "Not running in initrd, refusing to initiate resume from hibernation.");
147
148 if (argc <= optind) {
149 r = setup_hibernate_info_and_warn();
150 if (r <= 0)
151 return r;
152
153 if (arg_info.efi)
154 (void) clear_efi_hibernate_location_and_warn();
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 }
163 }
164
165 if (stat(arg_info.device, &st) < 0)
166 return log_error_errno(errno, "Failed to stat resume device '%s': %m", arg_info.device);
167
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);
171
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);
178 return r;
179}
180
181DEFINE_MAIN_FUNCTION(run);