]> git.ipfire.org Git - thirdparty/systemd.git/blame_incremental - src/hibernate-resume/hibernate-resume-generator.c
presets: Disable by default for initrd presets
[thirdparty/systemd.git] / src / hibernate-resume / hibernate-resume-generator.c
... / ...
CommitLineData
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3#include "alloc-util.h"
4#include "dropin.h"
5#include "efi-loader.h"
6#include "fd-util.h"
7#include "fileio.h"
8#include "generator.h"
9#include "hibernate-resume-config.h"
10#include "initrd-util.h"
11#include "log.h"
12#include "proc-cmdline.h"
13#include "special.h"
14#include "static-destruct.h"
15#include "string-util.h"
16#include "unit-name.h"
17
18static const char *arg_dest = NULL;
19static const char *arg_dest_late = NULL;
20static char *arg_resume_options = NULL;
21static char *arg_root_options = NULL;
22static bool arg_noresume = false;
23
24STATIC_DESTRUCTOR_REGISTER(arg_resume_options, freep);
25STATIC_DESTRUCTOR_REGISTER(arg_root_options, freep);
26
27static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
28 assert(key);
29
30 if (streq(key, "resumeflags")) {
31
32 if (proc_cmdline_value_missing(key, value))
33 return 0;
34
35 if (!strextend_with_separator(&arg_resume_options, ",", value))
36 return log_oom();
37
38 } else if (streq(key, "rootflags")) {
39
40 if (proc_cmdline_value_missing(key, value))
41 return 0;
42
43 if (!strextend_with_separator(&arg_root_options, ",", value))
44 return log_oom();
45
46 } else if (streq(key, "noresume")) {
47
48 if (value) {
49 log_warning("'noresume' kernel command line option specified with an argument, ignoring.");
50 return 0;
51 }
52
53 arg_noresume = true;
54 }
55
56 return 0;
57}
58
59#define DISSECTED_SWAP_LUKS_DEVICE "/dev/disk/by-designator/swap-luks"
60#define DISSECTED_SWAP_LUKS_DEVICE_UNIT "dev-disk-by\\x2ddesignator-swap\\x2dluks.device"
61
62static int add_dissected_swap_cryptsetup(void) {
63
64#if HAVE_LIBCRYPTSETUP
65 _cleanup_fclose_ FILE *f = NULL;
66 int r;
67
68 /* Write out cryptsetup unit for the "auto" swap device (/dev/disk/by-designator/swap-luks), so that
69 * resume from hibernation can be automatically initiated there. This mostly follows what gpt-auto does,
70 * but operates in initrd. */
71
72 r = generator_open_unit_file(arg_dest_late, /* source = */ NULL, "systemd-cryptsetup@swap.service", &f);
73 if (r < 0)
74 return r;
75
76 r = generator_write_cryptsetup_unit_section(f, /* source = */ NULL);
77 if (r < 0)
78 return r;
79
80 fputs("Before=umount.target cryptsetup.target\n"
81 "Conflicts=umount.target\n"
82 "BindsTo="DISSECTED_SWAP_LUKS_DEVICE_UNIT"\n"
83 "After="DISSECTED_SWAP_LUKS_DEVICE_UNIT"\n",
84 f);
85
86 r = generator_write_cryptsetup_service_section(
87 f, "swap", DISSECTED_SWAP_LUKS_DEVICE,
88 /* key_file = */ NULL,
89 efi_measured_uki(LOG_DEBUG) > 0 ? "tpm2-device=auto" : NULL);
90 if (r < 0)
91 return r;
92
93 r = fflush_and_check(f);
94 if (r < 0)
95 return log_error_errno(r, "Failed to write cryptsetup unit for " DISSECTED_SWAP_LUKS_DEVICE ": %m");
96
97 r = generator_write_device_timeout(arg_dest_late,
98 DISSECTED_SWAP_LUKS_DEVICE,
99 arg_resume_options ?: arg_root_options, /* filtered = */ NULL);
100 if (r < 0)
101 return r;
102
103 return generator_add_symlink(arg_dest_late, DISSECTED_SWAP_LUKS_DEVICE_UNIT, "wants", "systemd-cryptsetup@swap.service");
104#else
105 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
106 "systemd-hibernate-resume-generator was compiled without libcryptsetup support, "
107 "not generating cryptsetup unit for " DISSECTED_SWAP_LUKS_DEVICE ".");
108#endif
109}
110
111static int process_resume(const HibernateInfo *info) {
112 _cleanup_free_ char *device_unit = NULL;
113 int r;
114
115 assert(info);
116
117 r = unit_name_from_path(info->device, ".device", &device_unit);
118 if (r < 0)
119 return log_error_errno(r, "Failed to generate device unit name from path '%s': %m", info->device);
120
121 r = generator_write_device_timeout(arg_dest, info->device, arg_resume_options ?: arg_root_options, NULL);
122 if (r < 0)
123 log_warning_errno(r, "Failed to write device timeout drop-in, ignoring: %m");
124 if (r <= 0) {
125 /* No timeout explicitly defined? Wait infinitely if resume= is specified, 2min if from EFI
126 * HibernateLocation variable. In the latter case, we avoid blocking the boot process forever
127 * if a stale var is detected while the swap device is not present. */
128 r = write_drop_in_format(arg_dest, device_unit, 40, "device-timeout",
129 "# Automatically generated by systemd-hibernate-resume-generator\n\n"
130 "[Unit]\n"
131 "JobTimeoutSec=%s\n",
132 info->cmdline ? "infinity" : "2min");
133 if (r < 0)
134 log_warning_errno(r, "Failed to write fallback device timeout drop-in, ignoring: %m");
135 }
136
137 r = write_drop_in_format(arg_dest, SPECIAL_HIBERNATE_RESUME_SERVICE, 90, "device-dependency",
138 "# Automatically generated by systemd-hibernate-resume-generator\n\n"
139 "[Unit]\n"
140 "BindsTo=%1$s\n"
141 "After=%1$s\n",
142 device_unit);
143 if (r < 0)
144 return log_error_errno(r, "Failed to write device dependency drop-in: %m");
145
146 /* Generate cryptsetup unit for /dev/disk/by-designator/swap-luks if we hibernated into it, but only
147 * if resume= is not specified, on the assumption that the user would have everything configured
148 * manually otherwise. */
149 if (!info->cmdline && info->efi->auto_swap)
150 (void) add_dissected_swap_cryptsetup();
151
152 return generator_add_symlink(arg_dest, SPECIAL_SYSINIT_TARGET, "wants", SPECIAL_HIBERNATE_RESUME_SERVICE);
153}
154
155static int run(const char *dest, const char *dest_early, const char *dest_late) {
156 _cleanup_(hibernate_info_done) HibernateInfo info = {};
157 int r;
158
159 arg_dest = ASSERT_PTR(dest);
160 arg_dest_late = ASSERT_PTR(dest_late);
161
162 /* Don't even consider resuming outside of initrd. */
163 if (!in_initrd()) {
164 log_debug("Not running in initrd, exiting.");
165 return 0;
166 }
167
168 if (generator_soft_rebooted()) {
169 log_debug("Running in an initrd entered through soft-reboot, not initiating resume.");
170 return 0;
171 }
172
173 r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
174 if (r < 0)
175 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
176
177 if (arg_noresume) {
178 log_info("Found 'noresume' on the kernel command line, exiting.");
179 return 0;
180 }
181
182 r = acquire_hibernate_info(&info);
183 if (r == -ENODEV) {
184 log_debug_errno(r, "No resume device found, exiting.");
185 return 0;
186 }
187 if (r < 0)
188 return r;
189
190 return process_resume(&info);
191}
192
193DEFINE_MAIN_GENERATOR_FUNCTION(run);