]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/gpt-auto-generator/gpt-auto-generator.c
Fixes for vscode/intellisense parsing (#38040)
[thirdparty/systemd.git] / src / gpt-auto-generator / gpt-auto-generator.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
1a14a53c 2
41bc4849 3#include <sys/file.h>
1a14a53c 4
07630cea
LP
5#include "sd-id128.h"
6
b5efdb8a 7#include "alloc-util.h"
18c528e9 8#include "blockdev-util.h"
133432cc 9#include "device-util.h"
7176f06c 10#include "devnum-util.h"
72e18a98 11#include "dissect-image.h"
1fac34b9 12#include "dropin.h"
0bb2f0f1 13#include "efi-loader.h"
8857aa74
DDM
14#include "efivars.h"
15#include "errno-util.h"
1c0b8270 16#include "factory-reset.h"
3ffd4af2 17#include "fd-util.h"
07630cea
LP
18#include "fileio.h"
19#include "fstab-util.h"
20#include "generator.h"
21#include "gpt.h"
84be0c71 22#include "image-policy.h"
baa6a42d 23#include "initrd-util.h"
8857aa74 24#include "loop-util.h"
049af8ad 25#include "mountpoint-util.h"
6bedfcbb 26#include "parse-util.h"
07630cea 27#include "path-util.h"
4e731273 28#include "proc-cmdline.h"
1a14a53c 29#include "special.h"
8fcde012 30#include "stat-util.h"
07630cea 31#include "string-util.h"
85624f01 32#include "strv.h"
8857aa74 33#include "time-util.h"
1a14a53c 34#include "unit-name.h"
9a5cb137 35#include "virt.h"
1a14a53c 36
f872373a
LP
37typedef enum MountPointFlags {
38 MOUNT_RW = 1 << 0,
39 MOUNT_GROWFS = 1 << 1,
40 MOUNT_MEASURE = 1 << 2,
41 MOUNT_VALIDATEFS = 1 << 3,
42} MountPointFlags;
43
ec6e9597 44static const char *arg_dest = NULL;
e5d2701b 45static const char *arg_dest_late = NULL;
73b80ec2 46static bool arg_enabled = true;
14ab9aaf 47static GptAutoRoot arg_auto_root = _GPT_AUTO_ROOT_INVALID;
7852e301 48static GptAutoRoot arg_auto_usr = _GPT_AUTO_ROOT_INVALID;
9a2982b6 49static bool arg_swap_enabled = true;
cf451f38
LP
50static char *arg_root_fstype = NULL;
51static char *arg_root_options = NULL;
c94b2417 52static int arg_root_rw = -1;
7852e301
LP
53static char *arg_usr_fstype = NULL;
54static char *arg_usr_options = NULL;
84be0c71 55static ImagePolicy *arg_image_policy = NULL;
74cfd092 56static ImageFilter *arg_image_filter = NULL;
84be0c71 57
cf451f38
LP
58STATIC_DESTRUCTOR_REGISTER(arg_root_fstype, freep);
59STATIC_DESTRUCTOR_REGISTER(arg_root_options, freep);
7852e301
LP
60STATIC_DESTRUCTOR_REGISTER(arg_usr_fstype, freep);
61STATIC_DESTRUCTOR_REGISTER(arg_usr_options, freep);
cec81b23
AAF
62STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
63STATIC_DESTRUCTOR_REGISTER(arg_image_filter, image_filter_freep);
cf451f38 64
756b6749
MY
65#define LOADER_PARTITION_IDLE_USEC (120 * USEC_PER_SEC)
66
06648fa9
LP
67static int add_cryptsetup(
68 const char *id,
69 const char *what,
f4a65d5f 70 const char *mount_opts,
f872373a 71 MountPointFlags flags,
06648fa9
LP
72 bool require,
73 char **ret_device) {
74
5b137503 75#if HAVE_LIBCRYPTSETUP
ff386f98 76 _cleanup_free_ char *e = NULL, *n = NULL, *d = NULL, *options = NULL;
1af72119 77 _cleanup_fclose_ FILE *f = NULL;
1af72119
LP
78 int r;
79
80 assert(id);
81 assert(what);
1af72119 82
7410616c
LP
83 r = unit_name_from_path(what, ".device", &d);
84 if (r < 0)
85 return log_error_errno(r, "Failed to generate unit name: %m");
1af72119
LP
86
87 e = unit_name_escape(id);
88 if (!e)
89 return log_oom();
90
7410616c
LP
91 r = unit_name_build("systemd-cryptsetup", e, ".service", &n);
92 if (r < 0)
93 return log_error_errno(r, "Failed to generate unit name: %m");
1af72119 94
e5d2701b 95 r = generator_open_unit_file(arg_dest_late, /* source = */ NULL, n, &f);
a7e88558
LP
96 if (r < 0)
97 return r;
98bad05e 98
a7e88558
LP
99 r = generator_write_cryptsetup_unit_section(f, NULL);
100 if (r < 0)
101 return r;
1af72119
LP
102
103 fprintf(f,
1af72119 104 "Before=umount.target cryptsetup.target\n"
a7e88558
LP
105 "Conflicts=umount.target\n"
106 "BindsTo=%s\n"
107 "After=%s\n",
108 d, d);
109
f872373a 110 if (!FLAGS_SET(flags, MOUNT_RW)) {
ff386f98
LP
111 options = strdup("read-only");
112 if (!options)
113 return log_oom();
114 }
115
0d5f59a2
LP
116 r = efi_measured_uki(LOG_WARNING);
117 if (r > 0)
118 /* Enable TPM2 based unlocking automatically, if we have a TPM. See #30176. */
119 if (!strextend_with_separator(&options, ",", "tpm2-device=auto"))
120 return log_oom();
121
f872373a 122 if (FLAGS_SET(flags, MOUNT_MEASURE)) {
ff386f98
LP
123 /* We only measure the root volume key into PCR 15 if we are booted with sd-stub (i.e. in a
124 * UKI), and sd-stub measured the UKI. We do this in order not to step into people's own PCR
125 * assignment, under the assumption that people who are fine to use sd-stub with its PCR
126 * assignments are also OK with our PCR 15 use here. */
0d5f59a2 127 if (r > 0)
2f6c52b9
ZJS
128 if (!strextend_with_separator(&options, ",", "tpm2-measure-pcr=yes"))
129 return log_oom();
0d5f59a2
LP
130 if (r == 0)
131 log_debug("Will not measure volume key of volume '%s', not booted via systemd-stub with measurements enabled.", id);
ff386f98
LP
132 }
133
134 r = generator_write_cryptsetup_service_section(f, id, what, NULL, options);
a7e88558
LP
135 if (r < 0)
136 return r;
1af72119 137
dacd6cee
LP
138 r = fflush_and_check(f);
139 if (r < 0)
a7e88558 140 return log_error_errno(r, "Failed to write file %s: %m", n);
1af72119 141
e5d2701b 142 r = generator_write_device_timeout(arg_dest_late, what, mount_opts, /* filtered = */ NULL);
f4a65d5f
MY
143 if (r < 0)
144 return r;
145
e5d2701b 146 r = generator_add_symlink(arg_dest_late, d, "wants", n);
9cdcf368
ZJS
147 if (r < 0)
148 return r;
1af72119 149
6a488fa7 150 const char *dmname = strjoina("dev-mapper-", e, ".device");
1af72119 151
1fac34b9 152 if (require) {
e5d2701b 153 r = generator_add_symlink(arg_dest_late, "cryptsetup.target", "requires", n);
9cdcf368
ZJS
154 if (r < 0)
155 return r;
01af8c01 156
e5d2701b 157 r = generator_add_symlink(arg_dest_late, dmname, "requires", n);
9cdcf368
ZJS
158 if (r < 0)
159 return r;
01af8c01 160 }
1af72119 161
e5d2701b 162 r = write_drop_in_format(arg_dest_late, dmname, 50, "job-timeout",
1fac34b9
ZJS
163 "# Automatically generated by systemd-gpt-auto-generator\n\n"
164 "[Unit]\n"
a9b837aa 165 "JobTimeoutSec=infinity"); /* the binary handles timeouts anyway */
23bbb0de 166 if (r < 0)
1fac34b9 167 log_warning_errno(r, "Failed to write device timeout drop-in, ignoring: %m");
1af72119 168
06648fa9
LP
169 if (ret_device) {
170 char *s;
2aa2860b 171
06648fa9
LP
172 s = path_join("/dev/mapper", id);
173 if (!s)
2aa2860b 174 return log_oom();
1af72119 175
06648fa9 176 *ret_device = s;
2aa2860b
ZJS
177 }
178
1af72119 179 return 0;
5b137503 180#else
6a488fa7 181 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
4e494e6a 182 "Partition is encrypted, but systemd-gpt-auto-generator was compiled without libcryptsetup support.");
5b137503 183#endif
1af72119
LP
184}
185
0a64b7ba
LP
186#if ENABLE_EFI
187static int add_veritysetup(
188 const char *id,
189 const char *data_what,
190 const char *hash_what,
191 const char *mount_opts) {
192
193#if HAVE_LIBCRYPTSETUP
194 int r;
195
196 assert(id);
197 assert(data_what);
198 assert(hash_what);
199
200 _cleanup_free_ char *dd = NULL;
201 r = unit_name_from_path(data_what, ".device", &dd);
202 if (r < 0)
203 return log_error_errno(r, "Failed to generate data device unit name: %m");
204
205 _cleanup_free_ char *dh = NULL;
206 r = unit_name_from_path(hash_what, ".device", &dh);
207 if (r < 0)
208 return log_error_errno(r, "Failed to generate hash device unit name: %m");
209
210 _cleanup_free_ char *e = unit_name_escape(id);
211 if (!e)
212 return log_oom();
213
214 _cleanup_free_ char *n = NULL;
215 r = unit_name_build("systemd-veritysetup", e, ".service", &n);
216 if (r < 0)
217 return log_error_errno(r, "Failed to generate unit name: %m");
218
219 _cleanup_fclose_ FILE *f = NULL;
e5d2701b 220 r = generator_open_unit_file(arg_dest_late, /* source= */ NULL, n, &f);
0a64b7ba
LP
221 if (r < 0)
222 return r;
223
224 r = generator_write_veritysetup_unit_section(f, /* source= */ NULL);
225 if (r < 0)
226 return r;
227
228 fprintf(f,
229 "Before=veritysetup.target\n"
230 "BindsTo=%1$s %2$s\n"
231 "After=%1$s %2$s\n",
232 dd, dh);
233
234 r = generator_write_veritysetup_service_section(
235 f,
236 id,
237 data_what,
238 hash_what,
239 /* roothash= */ NULL, /* NULL means: derive root hash from udev property ID_DISSECT_PART_ROOTHASH */
240 "root-hash-signature=auto"); /* auto means: derive signature from udev property ID_DISSECT_PART_ROOTHASH_SIG */
241 if (r < 0)
242 return r;
243
244 r = fflush_and_check(f);
245 if (r < 0)
246 return log_error_errno(r, "Failed to write file %s: %m", n);
247
e5d2701b 248 r = generator_write_device_timeout(arg_dest_late, data_what, mount_opts, /* filtered= */ NULL);
0a64b7ba
LP
249 if (r < 0)
250 return r;
251
e5d2701b 252 r = generator_write_device_timeout(arg_dest_late, hash_what, mount_opts, /* filtered= */ NULL);
0a64b7ba
LP
253 if (r < 0)
254 return r;
255
e5d2701b 256 r = generator_add_symlink(arg_dest_late, dd, "wants", n);
0a64b7ba
LP
257 if (r < 0)
258 return r;
259
e5d2701b 260 r = generator_add_symlink(arg_dest_late, dh, "wants", n);
0a64b7ba
LP
261 if (r < 0)
262 return r;
263
264 _cleanup_free_ char *dmname = NULL;
265 dmname = strjoin("dev-mapper-", e, ".device");
266 if (!dmname)
267 return log_oom();
268
269 r = write_drop_in_format(
e5d2701b 270 arg_dest_late,
0a64b7ba
LP
271 dmname, 50, "job-timeout",
272 "# Automatically generated by systemd-gpt-auto-generator\n\n"
273 "[Unit]\n"
274 "JobTimeoutSec=infinity"); /* the binary handles timeouts anyway */
275 if (r < 0)
276 return log_error_errno(r, "Failed to write device timeout drop-in: %m");
277
278 return 0;
279#else
280 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
281 "Partition is Verity protected, but systemd-gpt-auto-generator was compiled without libcryptsetup support.");
282#endif
283}
284#endif
285
73b80ec2
LP
286static int add_mount(
287 const char *id,
288 const char *what,
289 const char *where,
290 const char *fstype,
f872373a 291 MountPointFlags flags,
59512f21 292 const char *options,
73b80ec2
LP
293 const char *description,
294 const char *post) {
295
f4a65d5f 296 _cleanup_free_ char *unit = NULL, *crypto_what = NULL, *opts_filtered = NULL;
1a14a53c 297 _cleanup_fclose_ FILE *f = NULL;
e48fdd84 298 int r;
1a14a53c 299
98bad05e
LP
300 /* Note that we don't apply specifier escaping on the input strings here, since we know they are not configured
301 * externally, but all originate from our own sources here, and hence we know they contain no % characters that
302 * could potentially be understood as specifiers. */
303
1af72119
LP
304 assert(id);
305 assert(what);
306 assert(where);
1af72119
LP
307 assert(description);
308
074cdb95 309 log_debug("Adding %s: %s fstype=%s", where, what, fstype ?: "(any)");
1a14a53c 310
73b80ec2 311 if (streq_ptr(fstype, "crypto_LUKS")) {
f4a65d5f
MY
312 /* Mount options passed are determined by partition_pick_mount_options(), whose result
313 * is known to not contain timeout options. */
f872373a 314 r = add_cryptsetup(id, what, /* mount_opts = */ NULL, flags, /* require= */ true, &crypto_what);
1af72119
LP
315 if (r < 0)
316 return r;
317
318 what = crypto_what;
319 fstype = NULL;
80ce8580
LP
320 } else if (fstype) {
321 r = dissect_fstype_ok(fstype);
322 if (r < 0)
323 return log_error_errno(r, "Unable to determine of dissected file system type '%s' is permitted: %m", fstype);
324 if (!r)
325 return log_error_errno(
326 SYNTHETIC_ERRNO(EIDRM),
327 "Refusing to automatically mount uncommon file system '%s' to '%s'.",
328 fstype, where);
1af72119
LP
329 }
330
e5d2701b 331 r = generator_write_device_timeout(arg_dest_late, what, options, &opts_filtered);
f4a65d5f
MY
332 if (r < 0)
333 return r;
334
7410616c
LP
335 r = unit_name_from_path(where, ".mount", &unit);
336 if (r < 0)
337 return log_error_errno(r, "Failed to generate unit name: %m");
1a14a53c 338
e5d2701b 339 r = generator_open_unit_file(arg_dest_late, /* source = */ NULL, unit, &f);
121ce4a6
MY
340 if (r < 0)
341 return r;
1a14a53c
LP
342
343 fprintf(f,
1a14a53c 344 "[Unit]\n"
c3834f9b
LP
345 "Description=%s\n"
346 "Documentation=man:systemd-gpt-auto-generator(8)\n",
e48fdd84
LP
347 description);
348
73b80ec2
LP
349 if (post)
350 fprintf(f, "Before=%s\n", post);
351
e5d2701b
LP
352 /* NB: here we do not write to arg_dest_late, but to arg_dest! We typically leave the normal
353 * generator drop-in dir for explicit configuration via systemd-fstab-generator or similar, and put
354 * out automatic configuration in the arg_dest_late directory. But this one is an exception, since we
355 * need to override the static version of the fsck root service file. */
bed3ff8e 356 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype, opts_filtered);
e48fdd84
LP
357 if (r < 0)
358 return r;
359
a7e88558
LP
360 r = generator_write_blockdev_dependency(f, what);
361 if (r < 0)
362 return r;
363
e48fdd84
LP
364 fprintf(f,
365 "\n"
1a14a53c
LP
366 "[Mount]\n"
367 "What=%s\n"
1af72119
LP
368 "Where=%s\n",
369 what, where);
370
73b80ec2
LP
371 if (fstype)
372 fprintf(f, "Type=%s\n", fstype);
373
f4a65d5f
MY
374 if (opts_filtered)
375 fprintf(f, "Options=%s\n", opts_filtered);
376
377 r = generator_write_mount_timeout(f, where, opts_filtered);
378 if (r < 0)
379 return r;
1a14a53c 380
dacd6cee
LP
381 r = fflush_and_check(f);
382 if (r < 0)
121ce4a6 383 return log_error_errno(r, "Failed to write unit %s: %m", unit);
1a14a53c 384
f872373a 385 if (FLAGS_SET(flags, MOUNT_VALIDATEFS)) {
e5d2701b 386 r = generator_hook_up_validatefs(arg_dest_late, where, post);
f872373a
LP
387 if (r < 0)
388 return r;
389 }
390
391 if (FLAGS_SET(flags, MOUNT_GROWFS)) {
e5d2701b 392 r = generator_hook_up_growfs(arg_dest_late, where, post);
400c1e8f
LP
393 if (r < 0)
394 return r;
395 }
396
f872373a 397 if (FLAGS_SET(flags, MOUNT_MEASURE)) {
e5d2701b 398 r = generator_hook_up_pcrfs(arg_dest_late, where, post);
04959faa
LP
399 if (r < 0)
400 return r;
401 }
402
400c1e8f 403 if (post) {
e5d2701b 404 r = generator_add_symlink(arg_dest_late, post, "requires", unit);
400c1e8f
LP
405 if (r < 0)
406 return r;
407 }
408
1a14a53c
LP
409 return 0;
410}
411
e137880b 412static int path_is_busy(const char *where) {
59512f21
KS
413 int r;
414
6a488fa7
ZJS
415 assert(where);
416
59512f21 417 /* already a mountpoint; generators run during reload */
b409aacb 418 r = path_is_mount_point_full(where, /* root = */ NULL, AT_SYMLINK_FOLLOW);
59512f21
KS
419 if (r > 0)
420 return false;
6a488fa7 421 /* The directory will be created by the mount or automount unit when it is started. */
59512f21
KS
422 if (r == -ENOENT)
423 return false;
424
425 if (r < 0)
e137880b 426 return log_warning_errno(r, "Cannot check if \"%s\" is a mount point: %m", where);
59512f21
KS
427
428 /* not a mountpoint but it contains files */
db55bbf2 429 r = dir_is_empty(where, /* ignore_hidden_or_backup= */ false);
6a488fa7
ZJS
430 if (r == -ENOTDIR) {
431 log_debug("\"%s\" is not a directory, ignoring.", where);
432 return true;
433 } else if (r < 0)
e137880b 434 return log_warning_errno(r, "Cannot check if \"%s\" is empty: %m", where);
6a488fa7
ZJS
435 else if (r == 0) {
436 log_debug("\"%s\" already populated, ignoring.", where);
437 return true;
438 }
59512f21 439
6a488fa7 440 return false;
59512f21
KS
441}
442
72e18a98 443static int add_partition_mount(
de1461ac 444 PartitionDesignator d,
72e18a98 445 DissectedPartition *p,
61331eab 446 const char *id,
61331eab 447 const char *where,
72e18a98 448 const char *description) {
61331eab 449
de1461ac 450 _cleanup_free_ char *options = NULL;
e137880b 451 int r;
de1461ac 452
72e18a98 453 assert(p);
61331eab 454
e137880b
ZJS
455 r = path_is_busy(where);
456 if (r != 0)
457 return r < 0 ? r : 0;
61331eab 458
de1461ac
LP
459 r = partition_pick_mount_options(
460 d,
461 dissected_partition_fstype(p),
462 p->rw,
463 /* discard= */ true,
464 &options,
465 /* ret_ms_flags= */ NULL);
466 if (r < 0)
467 return r;
468
61331eab
LP
469 return add_mount(
470 id,
72e18a98 471 p->node,
61331eab 472 where,
72e18a98 473 p->fstype,
f872373a
LP
474 (p->rw ? MOUNT_RW : 0) |
475 MOUNT_VALIDATEFS |
476 (p->growfs ? MOUNT_GROWFS : 0) |
477 (STR_IN_SET(id, "root", "var") ? MOUNT_MEASURE : 0), /* by default measure rootfs and /var, since they contain the "identity" of the system */
de1461ac 478 options,
61331eab 479 description,
72e18a98 480 SPECIAL_LOCAL_FS_TARGET);
61331eab
LP
481}
482
235ae69c 483static int add_partition_swap(DissectedPartition *p) {
8859b8f7 484 const char *what;
121ce4a6 485 _cleanup_free_ char *name = NULL, *crypto_what = NULL;
59512f21
KS
486 _cleanup_fclose_ FILE *f = NULL;
487 int r;
488
8859b8f7
HOB
489 assert(p);
490 assert(p->node);
59512f21 491
9a2982b6
DT
492 if (!arg_swap_enabled)
493 return 0;
494
fc5bc384
FB
495 /* Disable the swap auto logic if at least one swap is defined in /etc/fstab, see #6192. */
496 r = fstab_has_fstype("swap");
497 if (r < 0)
498 return log_error_errno(r, "Failed to parse fstab: %m");
1a680ae3 499 if (r > 0) {
fc5bc384
FB
500 log_debug("swap specified in fstab, ignoring.");
501 return 0;
502 }
503
8859b8f7 504 if (streq_ptr(p->fstype, "crypto_LUKS")) {
f872373a 505 r = add_cryptsetup("swap", p->node, /* mount_opts = */ NULL, MOUNT_RW, /* require= */ true, &crypto_what);
8859b8f7
HOB
506 if (r < 0)
507 return r;
508 what = crypto_what;
509 } else
510 what = p->node;
511
512 log_debug("Adding swap: %s", what);
59512f21 513
8859b8f7 514 r = unit_name_from_path(what, ".swap", &name);
59512f21
KS
515 if (r < 0)
516 return log_error_errno(r, "Failed to generate unit name: %m");
517
e5d2701b 518 r = generator_open_unit_file(arg_dest_late, /* source = */ NULL, name, &f);
121ce4a6
MY
519 if (r < 0)
520 return r;
59512f21
KS
521
522 fprintf(f,
59512f21
KS
523 "[Unit]\n"
524 "Description=Swap Partition\n"
a7e88558
LP
525 "Documentation=man:systemd-gpt-auto-generator(8)\n");
526
8859b8f7 527 r = generator_write_blockdev_dependency(f, what);
a7e88558
LP
528 if (r < 0)
529 return r;
530
531 fprintf(f,
532 "\n"
59512f21
KS
533 "[Swap]\n"
534 "What=%s\n",
8859b8f7 535 what);
59512f21 536
dacd6cee
LP
537 r = fflush_and_check(f);
538 if (r < 0)
121ce4a6 539 return log_error_errno(r, "Failed to write unit %s: %m", name);
59512f21 540
e5d2701b 541 return generator_add_symlink(arg_dest_late, SPECIAL_SWAP_TARGET, "wants", name);
59512f21
KS
542}
543
7a1494aa
TG
544static int add_automount(
545 const char *id,
546 const char *what,
547 const char *where,
548 const char *fstype,
f872373a 549 MountPointFlags flags,
7a1494aa
TG
550 const char *options,
551 const char *description,
552 usec_t timeout) {
553
121ce4a6 554 _cleanup_free_ char *unit = NULL;
7a1494aa
TG
555 _cleanup_fclose_ FILE *f = NULL;
556 int r;
557
558 assert(id);
559 assert(where);
560 assert(description);
561
7a1494aa
TG
562 r = add_mount(id,
563 what,
564 where,
565 fstype,
f872373a 566 flags,
d22771fc 567 options,
7a1494aa 568 description,
f872373a 569 /* post= */ NULL);
7a1494aa
TG
570 if (r < 0)
571 return r;
572
573 r = unit_name_from_path(where, ".automount", &unit);
574 if (r < 0)
575 return log_error_errno(r, "Failed to generate unit name: %m");
576
e5d2701b 577 r = generator_open_unit_file(arg_dest_late, /* source = */ NULL, unit, &f);
121ce4a6
MY
578 if (r < 0)
579 return r;
7a1494aa
TG
580
581 fprintf(f,
7a1494aa
TG
582 "[Unit]\n"
583 "Description=%s\n"
584 "Documentation=man:systemd-gpt-auto-generator(8)\n"
585 "[Automount]\n"
586 "Where=%s\n"
70887c5f 587 "TimeoutIdleSec="USEC_FMT"\n",
7a1494aa
TG
588 description,
589 where,
70887c5f 590 timeout / USEC_PER_SEC);
7a1494aa
TG
591
592 r = fflush_and_check(f);
593 if (r < 0)
121ce4a6 594 return log_error_errno(r, "Failed to write unit %s: %m", unit);
7a1494aa 595
e5d2701b 596 return generator_add_symlink(arg_dest_late, SPECIAL_LOCAL_FS_TARGET, "wants", unit);
7a1494aa
TG
597}
598
235ae69c 599static int add_partition_xbootldr(DissectedPartition *p) {
de1461ac 600 _cleanup_free_ char *options = NULL;
9f1cb0c1
LP
601 int r;
602
603 assert(p);
87bffa1e 604 assert(!in_initrd());
9f1cb0c1 605
9f1cb0c1
LP
606 r = path_is_busy("/boot");
607 if (r < 0)
608 return r;
609 if (r > 0)
610 return 0;
611
de1461ac
LP
612 r = partition_pick_mount_options(
613 PARTITION_XBOOTLDR,
614 dissected_partition_fstype(p),
615 /* rw= */ true,
616 /* discard= */ false,
617 &options,
618 /* ret_ms_flags= */ NULL);
619 if (r < 0)
6a488fa7
ZJS
620 return log_error_errno(r, "Failed to determine default mount options for /boot/: %m");
621
622 return add_automount(
623 "boot",
624 p->node,
625 "/boot",
626 p->fstype,
f872373a 627 MOUNT_RW,
6a488fa7
ZJS
628 options,
629 "Boot Loader Partition",
756b6749 630 LOADER_PARTITION_IDLE_USEC);
9f1cb0c1
LP
631}
632
633#if ENABLE_EFI
235ae69c 634static int add_partition_esp(DissectedPartition *p, bool has_xbootldr) {
9f1cb0c1 635 const char *esp_path = NULL, *id = NULL;
de1461ac 636 _cleanup_free_ char *options = NULL;
59512f21
KS
637 int r;
638
72e18a98 639 assert(p);
87bffa1e 640 assert(!in_initrd());
59512f21 641
7893a547
MY
642 /* Check if there's an existing fstab entry for ESP. If so, we just skip the gpt-auto logic. */
643 r = fstab_has_node(p->node);
644 if (r < 0)
622f2dcc
MY
645 log_warning_errno(r, "Failed to check if fstab entry for device '%s' exists, ignoring: %m",
646 p->node);
7893a547
MY
647 if (r > 0)
648 return 0;
649
28dbee46 650 /* If XBOOTLDR partition is not present and /boot/ is unused and empty, we'll take that.
6a488fa7 651 * Otherwise, if /efi/ is unused and empty (or missing), we'll take that.
7893a547 652 * Otherwise, we do nothing. */
28dbee46 653 if (!has_xbootldr) {
8a132658 654 r = path_is_busy("/boot");
6a488fa7
ZJS
655 if (r < 0)
656 return r;
657 if (r == 0) {
8a132658
FB
658 esp_path = "/boot";
659 id = "boot";
9f1cb0c1
LP
660 }
661 }
6a488fa7
ZJS
662
663 if (!esp_path) {
6a488fa7
ZJS
664 r = path_is_busy("/efi");
665 if (r < 0)
666 return r;
667 if (r > 0)
668 return 0;
669
9f1cb0c1 670 esp_path = "/efi";
9f1cb0c1 671 id = "efi";
59512f21
KS
672 }
673
de1461ac
LP
674 r = partition_pick_mount_options(
675 PARTITION_ESP,
676 dissected_partition_fstype(p),
677 /* rw= */ true,
678 /* discard= */ false,
679 &options,
680 /* ret_ms_flags= */ NULL);
681 if (r < 0)
6a488fa7
ZJS
682 return log_error_errno(r, "Failed to determine default mount options for %s: %m", esp_path);
683
684 return add_automount(
685 id,
686 p->node,
687 esp_path,
688 p->fstype,
f872373a 689 MOUNT_RW,
6a488fa7
ZJS
690 options,
691 "EFI System Partition Automount",
756b6749 692 LOADER_PARTITION_IDLE_USEC);
7a1494aa 693}
59512f21 694#else
235ae69c 695static int add_partition_esp(DissectedPartition *p, bool has_xbootldr) {
59512f21 696 return 0;
59512f21 697}
7a1494aa 698#endif
59512f21 699
235ae69c 700static int add_partition_root_rw(DissectedPartition *p) {
fd89051e
LP
701 const char *path;
702 int r;
703
704 assert(p);
5253b4a9 705 assert(!in_initrd());
fd89051e 706
5253b4a9 707 /* Invoked on the main system (not initrd), to honour GPT flag 60 on the root fs (ro) */
fd89051e
LP
708
709 if (arg_root_rw >= 0) {
710 log_debug("Parameter ro/rw specified on kernel command line, not generating drop-in for systemd-remount-fs.service.");
711 return 0;
712 }
713
714 if (!p->rw) {
715 log_debug("Root partition marked read-only in GPT partition table, not generating drop-in for systemd-remount-fs.service.");
716 return 0;
717 }
718
e5d2701b 719 r = generator_enable_remount_fs_service(arg_dest_late);
40b1224e
LP
720 if (r < 0)
721 return r;
9b69569d 722
e5d2701b 723 path = strjoina(arg_dest_late, "/systemd-remount-fs.service.d/50-remount-rw.conf");
fd89051e
LP
724
725 r = write_string_file(path,
dd23292c 726 "# Automatically generated by systemd-gpt-auto-generator\n\n"
fd89051e
LP
727 "[Service]\n"
728 "Environment=SYSTEMD_REMOUNT_ROOT_RW=1\n",
e82e549f 729 WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_NOFOLLOW|WRITE_STRING_FILE_MKDIR_0755);
fd89051e
LP
730 if (r < 0)
731 return log_error_errno(r, "Failed to write drop-in file %s: %m", path);
732
733 return 0;
734}
735
6b5fe5d7
LP
736static int add_partition_root_growfs(DissectedPartition *p) {
737
738 assert(p);
739 assert(!in_initrd());
740
741 /* Invoked on the main system (not initrd), to honour GPT flag 59 on the root fs (growfs) */
742
743 if (!p->growfs) {
744 log_debug("Root partition not marked for growing the file system in the GPT partition table, not generating drop-in for systemd-growfs-root.service.");
745 return 0;
746 }
747
e5d2701b 748 return generator_hook_up_growfs(arg_dest_late, "/", SPECIAL_LOCAL_FS_TARGET);
6b5fe5d7
LP
749}
750
751static int add_partition_root_flags(DissectedPartition *p) {
752 int r = 0;
753
754 assert(p);
755 assert(!in_initrd());
756
757 RET_GATHER(r, add_partition_root_growfs(p));
758 RET_GATHER(r, add_partition_root_rw(p));
759
760 return r;
761}
762
9fe6f5cc
ZJS
763#if ENABLE_EFI
764static int add_root_cryptsetup(void) {
d0523bb0 765#if HAVE_LIBCRYPTSETUP
1a14a53c 766
198f7bad 767 assert(arg_auto_root != GPT_AUTO_ROOT_OFF);
1a14a53c 768
198f7bad
LP
769 /* If a device /dev/gpt-auto-root-luks or /dev/disk/by-designator/root-luks appears, then make it
770 * pull in systemd-cryptsetup@root.service, which sets it up, and causes /dev/gpt-auto-root or
771 * /dev/disk/by-designator/root to appear which is all we are looking for. */
1c0b8270 772
198f7bad
LP
773 const char *bdev =
774 IN_SET(arg_auto_root, GPT_AUTO_ROOT_DISSECT, GPT_AUTO_ROOT_DISSECT_FORCE) ?
775 "/dev/disk/by-designator/root-luks" : "/dev/gpt-auto-root-luks";
776
777 if (IN_SET(arg_auto_root, GPT_AUTO_ROOT_FORCE, GPT_AUTO_ROOT_DISSECT_FORCE)) {
1c0b8270
LP
778 /* Similar logic as in add_root_mount(), see below */
779 FactoryResetMode f = factory_reset_mode();
780 if (f < 0)
781 log_warning_errno(f, "Failed to determine whether we are in factory reset mode, assuming not: %m");
782
783 if (IN_SET(f, FACTORY_RESET_ON, FACTORY_RESET_COMPLETE))
198f7bad
LP
784 bdev =
785 IN_SET(arg_auto_root, GPT_AUTO_ROOT_DISSECT, GPT_AUTO_ROOT_DISSECT_FORCE) ?
786 "/dev/disk/by-designator/root-luks-ignore-factory-reset" :
787 "/dev/gpt-auto-root-luks-ignore-factory-reset";
1c0b8270
LP
788 }
789
7852e301
LP
790 return add_cryptsetup(
791 "root",
792 bdev,
793 arg_root_options,
794 MOUNT_RW|MOUNT_MEASURE,
795 /* require= */ false,
796 /* ret_device= */ NULL);
d0523bb0
DS
797#else
798 return 0;
799#endif
9fe6f5cc
ZJS
800}
801#endif
d2a62382 802
9fe6f5cc
ZJS
803static int add_root_mount(void) {
804#if ENABLE_EFI
de1461ac 805 _cleanup_free_ char *options = NULL;
9fe6f5cc 806 int r;
1a14a53c 807
1a95fc87 808 /* Explicitly disabled? Then exit immediately */
1c0b8270 809 if (arg_auto_root == GPT_AUTO_ROOT_OFF)
8090b41e 810 return 0;
61331eab 811
1a95fc87 812 /* Neither explicitly enabled nor disabled? Then decide based on the EFI partition variables to be set */
14ab9aaf 813 if (arg_auto_root < 0) {
1a95fc87
LP
814 if (!is_efi_boot()) {
815 log_debug("Not an EFI boot, not creating root mount.");
816 return 0;
817 }
818
1cce9d93 819 r = efi_loader_get_device_part_uuid(/* ret= */ NULL);
1a95fc87 820 if (r == -ENOENT) {
bcc1eebd
ZJS
821 log_notice("EFI loader partition unknown, not processing %s.\n"
822 "(The boot loader did not set EFI variable LoaderDevicePartUUID.)",
823 in_initrd() ? "/sysroot" : "/");
1a95fc87
LP
824 return 0;
825 }
826 if (r < 0)
827 return log_error_errno(r, "Failed to read loader partition UUID: %m");
828 }
61331eab 829
1a95fc87 830 /* OK, we shall look for a root device, so let's wait for a root device to show up. A udev rule will
1c0b8270
LP
831 * create the link for us under the right name.
832 *
833 * There are two distinct names: the /dev/gpt-auto-root-ignore-factory-reset symlink is created for
834 * the root partition if factory reset mode is enabled or complete, and the /dev/gpt-auto-root
835 * symlink is only created if factory reset mode is off or already complete (thus taking factory
836 * reset state into account). In scenarios where the root disk is partially reformatted during
837 * factory reset the latter is the link to use, otherwise the former (so that we don't accidentally
838 * mount a root partition too early that is about to be wiped and replaced by another one). */
839
198f7bad
LP
840 const char *bdev =
841 IN_SET(arg_auto_root, GPT_AUTO_ROOT_DISSECT, GPT_AUTO_ROOT_DISSECT_FORCE) ?
842 "/dev/disk/by-designator/root" : "/dev/gpt-auto-root";
843 if (IN_SET(arg_auto_root, GPT_AUTO_ROOT_FORCE, GPT_AUTO_ROOT_DISSECT_FORCE)) {
1c0b8270
LP
844 FactoryResetMode f = factory_reset_mode();
845 if (f < 0)
846 log_warning_errno(f, "Failed to determine whether we are in factory reset mode, assuming not: %m");
847
848 if (IN_SET(f, FACTORY_RESET_ON, FACTORY_RESET_COMPLETE))
198f7bad
LP
849 bdev =
850 IN_SET(arg_auto_root, GPT_AUTO_ROOT_DISSECT, GPT_AUTO_ROOT_DISSECT_FORCE) ?
851 "/dev/disk/by-designator/root-ignore-factory-reset" :
852 "/dev/gpt-auto-root-ignore-factory-reset";
1c0b8270 853 }
61331eab 854
9fe6f5cc 855 if (in_initrd()) {
e5d2701b 856 r = generator_write_initrd_root_device_deps(arg_dest_late, bdev);
9fe6f5cc
ZJS
857 if (r < 0)
858 return 0;
61331eab 859
9fe6f5cc
ZJS
860 r = add_root_cryptsetup();
861 if (r < 0)
862 return r;
0a64b7ba
LP
863
864 /* If a device /dev/disk/by-designator/root-verity or
865 * /dev/disk/by-designator/root-verity-data appears, then make it pull in
866 * systemd-cryptsetup@root.service, which sets it up, and causes /dev/disk/by-designator/root
867 * to appear. */
868 r = add_veritysetup(
869 "root",
870 "/dev/disk/by-designator/root-verity-data",
871 "/dev/disk/by-designator/root-verity",
872 arg_root_options);
873 if (r < 0)
874 return r;
61331eab
LP
875 }
876
6b5fe5d7
LP
877 /* Note that we do not need to enable systemd-remount-fs.service here. If /etc/fstab exists,
878 * systemd-fstab-generator will pull it in for us, and otherwise add_partition_root_flags() will do
879 * it, after the initrd transition. */
61331eab 880
de1461ac
LP
881 r = partition_pick_mount_options(
882 PARTITION_ROOT,
883 arg_root_fstype,
884 arg_root_rw > 0,
885 /* discard= */ true,
886 &options,
887 /* ret_ms_flags= */ NULL);
888 if (r < 0)
889 return log_error_errno(r, "Failed to pick root mount options: %m");
890
891 if (arg_root_options)
892 if (!strextend_with_separator(&options, ",", arg_root_options))
893 return log_oom();
894
9fe6f5cc
ZJS
895 return add_mount(
896 "root",
1c0b8270 897 bdev,
9fe6f5cc 898 in_initrd() ? "/sysroot" : "/",
cf451f38 899 arg_root_fstype,
f872373a
LP
900 (arg_root_rw > 0 ? MOUNT_RW : 0) |
901 (in_initrd() ? MOUNT_VALIDATEFS : 0) |
902 MOUNT_MEASURE,
de1461ac 903 options,
9fe6f5cc
ZJS
904 "Root Partition",
905 in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_LOCAL_FS_TARGET);
906#else
907 return 0;
908#endif
72e18a98 909}
cb971249 910
7852e301
LP
911static int add_usr_mount(void) {
912#if ENABLE_EFI
913 int r;
914
915 /* /usr/ discovery must be enabled explicitly. */
39642b01 916 if (arg_auto_usr <= 0)
7852e301
LP
917 return 0;
918
919 /* We do not support the other gpt-auto modes for /usr/, but the parser should already have checked that. */
920 assert(arg_auto_usr == GPT_AUTO_ROOT_DISSECT);
921
922 if (arg_root_fstype && !arg_usr_fstype) {
923 arg_usr_fstype = strdup(arg_root_fstype);
924 if (!arg_usr_fstype)
925 return log_oom();
926 }
927
928 if (arg_root_options && !arg_usr_options) {
929 arg_usr_options = strdup(arg_root_options);
930 if (!arg_usr_options)
931 return log_oom();
932 }
933
934 if (in_initrd()) {
935 r = add_cryptsetup(
936 "usr",
937 "/dev/disk/by-designator/usr-luks",
938 arg_usr_options,
939 MOUNT_RW|MOUNT_MEASURE,
940 /* require= */ false,
941 /* ret_device= */ NULL);
942 if (r < 0)
943 return r;
0a64b7ba
LP
944
945 /* If a device /dev/disk/by-designator/usr-verity or
946 * /dev/disk/by-designator/usr-verity-data appears, then make it pull in
947 * systemd-cryptsetup@usr.service, which sets it up, and causes /dev/disk/by-designator/usr
948 * to appear. */
949 r = add_veritysetup(
950 "usr",
951 "/dev/disk/by-designator/usr-verity-data",
952 "/dev/disk/by-designator/usr-verity",
953 arg_usr_options);
954 if (r < 0)
955 return r;
7852e301
LP
956 }
957
958 _cleanup_free_ char *options = NULL;
959 r = partition_pick_mount_options(
960 PARTITION_USR,
961 arg_usr_fstype,
962 /* rw= */ false,
963 /* discard= */ true,
964 &options,
965 /* ret_ms_flags= */ NULL);
966 if (r < 0)
967 return log_error_errno(r, "Failed to pick /usr/ mount options: %m");
968
969 if (arg_usr_options)
970 if (!strextend_with_separator(&options, ",", arg_usr_options))
971 return log_oom();
972
973 r = add_mount("usr",
974 "/dev/disk/by-designator/usr",
975 in_initrd() ? "/sysusr/usr" : "/usr",
976 arg_usr_fstype,
7369c037 977 /* flags = */ 0,
7852e301
LP
978 options,
979 "/usr/ Partition",
980 in_initrd() ? SPECIAL_INITRD_USR_FS_TARGET : SPECIAL_LOCAL_FS_TARGET);
981 if (r < 0)
982 return r;
983
39642b01
MY
984 if (in_initrd()) {
985 log_debug("Synthesizing entry what=/sysusr/usr where=/sysroot/usr opts=bind");
986
987 r = add_mount("usr-bind",
988 "/sysusr/usr",
989 "/sysroot/usr",
990 /* fstype= */ NULL,
7369c037 991 MOUNT_VALIDATEFS,
39642b01
MY
992 "bind",
993 "/usr/ Partition (Final)",
994 SPECIAL_INITRD_FS_TARGET);
995 if (r < 0)
996 return r;
997 }
7852e301 998#endif
39642b01 999 return 0;
7852e301
LP
1000}
1001
68f8a86a
MY
1002static int process_loader_partitions(DissectedPartition *esp, DissectedPartition *xbootldr) {
1003 sd_id128_t loader_uuid;
fa989c74 1004 int r;
68f8a86a
MY
1005
1006 assert(esp);
1007 assert(xbootldr);
1008
8a132658
FB
1009 /* If any paths in fstab look similar to our favorite paths for ESP or XBOOTLDR, we just exit
1010 * early. We also don't bother with cases where one is configured explicitly and the other shall be
1011 * mounted automatically. */
1012
1013 r = fstab_has_mount_point_prefix_strv(STRV_MAKE("/boot", "/efi"));
1014 if (r > 0) {
1015 log_debug("Found mount entries in the /boot/ or /efi/ hierarchies in fstab, not generating ESP or XBOOTLDR mounts.");
1016 return 0;
1017 }
1018 if (r < 0)
1019 log_debug_errno(r, "Failed to check fstab existing paths, ignoring: %m");
1020
68f8a86a
MY
1021 if (!is_efi_boot()) {
1022 log_debug("Not an EFI boot, skipping loader partition UUID check.");
1023 goto mount;
1024 }
1025
1026 /* Let's check if LoaderDevicePartUUID points to either ESP or XBOOTLDR. We prefer it pointing
1027 * to the ESP, but we accept XBOOTLDR too. If it points to neither of them, don't mount any
1028 * loader partitions, since they are not the ones used for booting. */
1029
1030 r = efi_loader_get_device_part_uuid(&loader_uuid);
1031 if (r == -ENOENT) {
1032 log_debug_errno(r, "EFI loader partition unknown, skipping ESP and XBOOTLDR mounts.");
1033 return 0;
1034 }
1035 if (r < 0)
1036 return log_debug_errno(r, "Failed to read loader partition UUID, ignoring: %m");
1037
1038 if (esp->found && sd_id128_equal(esp->uuid, loader_uuid))
1039 goto mount;
1040
1041 if (xbootldr->found && sd_id128_equal(xbootldr->uuid, loader_uuid)) {
1042 log_debug("LoaderDevicePartUUID points to XBOOTLDR partition.");
1043 goto mount;
1044 }
1045
1046 log_debug("LoaderDevicePartUUID points to neither ESP nor XBOOTLDR, ignoring.");
1047 return 0;
1048
1049mount:
fa989c74 1050 r = 0;
68f8a86a 1051
fa989c74
ZJS
1052 if (xbootldr->found)
1053 RET_GATHER(r, add_partition_xbootldr(xbootldr));
1054 if (esp->found)
1055 RET_GATHER(r, add_partition_esp(esp, xbootldr->found));
68f8a86a 1056
fa989c74 1057 return r;
68f8a86a
MY
1058}
1059
72e18a98 1060static int enumerate_partitions(dev_t devnum) {
72e18a98 1061 _cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
55a065cd
YW
1062 _cleanup_(loop_device_unrefp) LoopDevice *loop = NULL;
1063 _cleanup_free_ char *devname = NULL;
fa989c74 1064 int r;
61331eab 1065
6d6538fb
LP
1066 static const PartitionDesignator ignore_designators[] = {
1067 PARTITION_ROOT,
1068 PARTITION_ROOT_VERITY,
1069 PARTITION_ROOT_VERITY_SIG,
1070 PARTITION_USR,
1071 PARTITION_USR_VERITY,
1072 PARTITION_USR_VERITY_SIG,
1073 };
1074
ca8ac0f9
LP
1075 assert(!in_initrd());
1076
1077 /* Run on the final root fs (not in the initrd), to mount auxiliary partitions, and hook in rw
1078 * remount and growfs of the root partition */
1079
55a065cd
YW
1080 r = block_get_whole_disk(devnum, &devnum);
1081 if (r < 0)
1082 return log_debug_errno(r, "Failed to get whole block device for " DEVNUM_FORMAT_STR ": %m",
1083 DEVNUM_FORMAT_VAL(devnum));
1084
1085 r = devname_from_devnum(S_IFBLK, devnum, &devname);
1086 if (r < 0)
1087 return log_debug_errno(r, "Failed to get device node of " DEVNUM_FORMAT_STR ": %m",
1088 DEVNUM_FORMAT_VAL(devnum));
61331eab 1089
6d6538fb
LP
1090 _cleanup_(image_policy_freep) ImagePolicy *image_policy = NULL;
1091 r = image_policy_ignore_designators(
1092 arg_image_policy ?: &image_policy_host,
1093 ignore_designators, ELEMENTSOF(ignore_designators),
1094 &image_policy);
1095 if (r < 0)
1096 return log_debug_errno(r, "Failed to mark root/usr designators as ignore in image policy: %m");
1097
41bc4849
LP
1098 /* Let's take a LOCK_SH lock on the block device, in case udevd is already running. If we don't take
1099 * the lock, udevd might end up issuing BLKRRPART in the middle, and we don't want that, since that
1100 * might remove all partitions while we are operating on them. */
de3b7f16 1101 r = loop_device_open_from_path(devname, O_RDONLY, LOCK_SH, &loop);
55a065cd 1102 if (r < 0)
af3d3873 1103 return log_debug_errno(r, "Failed to open %s: %m", devname);
41bc4849 1104
55a065cd
YW
1105 r = dissect_loop_device(
1106 loop,
84be0c71
LP
1107 /* verity= */ NULL,
1108 /* mount_options= */ NULL,
6d6538fb 1109 image_policy,
74cfd092 1110 arg_image_filter,
d04faa4e 1111 DISSECT_IMAGE_GPT_ONLY|
8716a76c 1112 DISSECT_IMAGE_USR_NO_ROOT|
ee0e6e47
YW
1113 DISSECT_IMAGE_DISKSEQ_DEVNODE|
1114 DISSECT_IMAGE_ALLOW_EMPTY,
73d88b80
LP
1115 /* NB! Unlike most other places where we dissect block devices we do not use
1116 * DISSECT_IMAGE_ADD_PARTITION_DEVICES here: we want that the kernel finds the
1117 * devices, and udev probes them before we mount them via .mount units much later
1118 * on. And thus we also don't set DISSECT_IMAGE_PIN_PARTITION_DEVICES here, because
1119 * we don't actually mount anything immediately. */
d04faa4e 1120 &m);
4953e39c
ZJS
1121 if (r < 0) {
1122 bool ok = r == -ENOPKG;
1123 dissect_log_error(ok ? LOG_DEBUG : LOG_ERR, r, devname, NULL);
1124 return ok ? 0 : r;
61331eab 1125 }
0238d4c6 1126
fa989c74
ZJS
1127 if (m->partitions[PARTITION_SWAP].found)
1128 RET_GATHER(r, add_partition_swap(m->partitions + PARTITION_SWAP));
1a14a53c 1129
fa989c74 1130 RET_GATHER(r, process_loader_partitions(m->partitions + PARTITION_ESP, m->partitions + PARTITION_XBOOTLDR));
59512f21 1131
fa989c74
ZJS
1132 if (m->partitions[PARTITION_HOME].found)
1133 RET_GATHER(r, add_partition_mount(PARTITION_HOME, m->partitions + PARTITION_HOME,
1134 "home", "/home", "Home Partition"));
e48fdd84 1135
fa989c74
ZJS
1136 if (m->partitions[PARTITION_SRV].found)
1137 RET_GATHER(r, add_partition_mount(PARTITION_SRV, m->partitions + PARTITION_SRV,
1138 "srv", "/srv", "Server Data Partition"));
1a14a53c 1139
fa989c74
ZJS
1140 if (m->partitions[PARTITION_VAR].found)
1141 RET_GATHER(r, add_partition_mount(PARTITION_VAR, m->partitions + PARTITION_VAR,
1142 "var", "/var", "Variable Data Partition"));
d4dffb85 1143
fa989c74
ZJS
1144 if (m->partitions[PARTITION_TMP].found)
1145 RET_GATHER(r, add_partition_mount(PARTITION_TMP, m->partitions + PARTITION_TMP,
1146 "var-tmp", "/var/tmp", "Temporary Data Partition"));
d4dffb85 1147
fa989c74 1148 if (m->partitions[PARTITION_ROOT].found)
6b5fe5d7 1149 RET_GATHER(r, add_partition_root_flags(m->partitions + PARTITION_ROOT));
fd89051e 1150
1a14a53c
LP
1151 return r;
1152}
1153
9fe6f5cc 1154static int add_mounts(void) {
b00651cf 1155 dev_t devno;
c56be2c2 1156 int r;
9fe6f5cc 1157
87bffa1e
LP
1158 if (in_initrd())
1159 return 0;
1160
c56be2c2
LP
1161 r = blockdev_get_root(LOG_ERR, &devno);
1162 if (r < 0)
1163 return r;
1164 if (r == 0) {
1165 log_debug("Skipping automatic GPT dissection logic, root file system not backed by a (single) whole block device.");
1166 return 0;
9fe6f5cc
ZJS
1167 }
1168
1169 return enumerate_partitions(devno);
1170}
1171
96287a49 1172static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
73b80ec2 1173 int r;
1a14a53c 1174
73b80ec2 1175 assert(key);
1a14a53c 1176
8a9c44ed
LP
1177 if (proc_cmdline_key_streq(key, "systemd.gpt_auto") ||
1178 proc_cmdline_key_streq(key, "rd.systemd.gpt_auto")) {
1a14a53c 1179
1d84ad94 1180 r = value ? parse_boolean(value) : 1;
73b80ec2 1181 if (r < 0)
0a1b9449 1182 log_warning_errno(r, "Failed to parse gpt-auto switch \"%s\", ignoring: %m", value);
8086ffac
ZJS
1183 else
1184 arg_enabled = r;
1a14a53c 1185
a8d3315b 1186 } else if (streq(key, "root")) {
1d84ad94
LP
1187
1188 if (proc_cmdline_value_missing(key, value))
1189 return 0;
73b80ec2 1190
1c0b8270
LP
1191 /* Disable root disk logic if there's a root= value specified (unless it happens to be
1192 * "gpt-auto" or "gpt-auto-force") */
73b80ec2 1193
7852e301 1194 arg_auto_root = parse_gpt_auto_root("root=", value);
14ab9aaf 1195 assert(arg_auto_root >= 0);
73b80ec2 1196
a8d3315b 1197 } else if (streq(key, "roothash")) {
2f3dfc6f
LP
1198
1199 if (proc_cmdline_value_missing(key, value))
1200 return 0;
1201
1202 /* Disable root disk logic if there's roothash= defined (i.e. verity enabled) */
1203
1c0b8270 1204 arg_auto_root = GPT_AUTO_ROOT_OFF;
1a95fc87 1205 log_debug("Disabling root partition auto-detection, roothash= is set.");
2f3dfc6f 1206
cf451f38
LP
1207 } else if (streq(key, "rootfstype")) {
1208
1209 if (proc_cmdline_value_missing(key, value))
1210 return 0;
1211
1212 return free_and_strdup_warn(&arg_root_fstype, value);
1213
1214 } else if (streq(key, "rootflags")) {
1215
1216 if (proc_cmdline_value_missing(key, value))
1217 return 0;
1218
1219 if (!strextend_with_separator(&arg_root_options, ",", value))
1220 return log_oom();
1221
7852e301
LP
1222 } else if (streq(key, "mount.usr")) {
1223
1224 if (proc_cmdline_value_missing(key, value))
1225 return 0;
1226
1227 /* Disable root disk logic if there's a root= value specified (unless it happens to be
1228 * "gpt-auto" or "gpt-auto-force") */
1229
1230 arg_auto_usr = parse_gpt_auto_root("mount.usr=", value);
1231 assert(arg_auto_usr >= 0);
1232
1233 if (IN_SET(arg_auto_usr, GPT_AUTO_ROOT_ON, GPT_AUTO_ROOT_FORCE, GPT_AUTO_ROOT_DISSECT_FORCE)) {
1234 log_warning("'gpt-auto', 'gpt-auto-force' and 'dissect-force' are not supported for mount.usr=. Automatically resorting to mount.usr=dissect mode instead.");
1235 arg_auto_usr = GPT_AUTO_ROOT_DISSECT;
1236 }
1237
1238 } else if (streq(key, "mount.usrfstype")) {
1239
1240 if (proc_cmdline_value_missing(key, value))
1241 return 0;
1242
1243 return free_and_strdup_warn(&arg_usr_fstype, empty_to_null(value));
1244
1245 } else if (streq(key, "mount.usrflags")) {
1246
1247 if (proc_cmdline_value_missing(key, value))
1248 return 0;
1249
1250 if (!strextend_with_separator(&arg_usr_options, ",", value))
1251 return log_oom();
1252
a8d3315b 1253 } else if (streq(key, "rw") && !value)
73b80ec2 1254 arg_root_rw = true;
a8d3315b 1255 else if (streq(key, "ro") && !value)
73b80ec2 1256 arg_root_rw = false;
06e78680 1257 else if (proc_cmdline_key_streq(key, "systemd.image_policy"))
d0a0059c 1258 return parse_image_policy_argument(value, &arg_image_policy);
74cfd092
LP
1259 else if (proc_cmdline_key_streq(key, "systemd.image_filter")) {
1260 _cleanup_(image_filter_freep) ImageFilter *f = NULL;
73b80ec2 1261
74cfd092
LP
1262 r = image_filter_parse(value, &f);
1263 if (r < 0)
1264 return log_error_errno(r, "Failed to parse image filter: %s", value);
1265
1266 image_filter_free(arg_image_filter);
1267 arg_image_filter = TAKE_PTR(f);
1268
1269 } else if (streq(key, "systemd.swap")) {
9a2982b6
DT
1270
1271 r = value ? parse_boolean(value) : 1;
1272 if (r < 0)
1273 log_warning_errno(r, "Failed to parse swap switch \"%s\", ignoring: %m", value);
1274 else
1275 arg_swap_enabled = r;
1276
1277 if (!arg_swap_enabled)
1278 log_debug("Disabling swap partitions auto-detection, systemd.swap=no is defined.");
1279
1280 }
1281
73b80ec2
LP
1282 return 0;
1283}
1284
ec6e9597 1285static int run(const char *dest, const char *dest_early, const char *dest_late) {
1cfe9737 1286 int r;
73b80ec2 1287
e5d2701b
LP
1288 assert_se(arg_dest = dest);
1289 assert_se(arg_dest_late = dest_late);
73b80ec2 1290
75f86906 1291 if (detect_container() > 0) {
73b80ec2 1292 log_debug("In a container, exiting.");
ec6e9597 1293 return 0;
1a14a53c 1294 }
3db604b9 1295
1d84ad94 1296 r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
b5884878 1297 if (r < 0)
da927ba9 1298 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
1a14a53c 1299
73b80ec2
LP
1300 if (!arg_enabled) {
1301 log_debug("Disabled, exiting.");
ec6e9597 1302 return 0;
73b80ec2
LP
1303 }
1304
87bffa1e
LP
1305 r = 0;
1306 RET_GATHER(r, add_root_mount());
7852e301 1307 RET_GATHER(r, add_usr_mount());
87bffa1e 1308 RET_GATHER(r, add_mounts());
73b80ec2 1309
ec6e9597 1310 return r;
1a14a53c 1311}
ec6e9597
ZJS
1312
1313DEFINE_MAIN_GENERATOR_FUNCTION(run);