]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/gpt-auto-generator/gpt-auto-generator.c
Merge pull request #14293 from keur/systemctl_with_dependencies
[thirdparty/systemd.git] / src / gpt-auto-generator / gpt-auto-generator.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <stdlib.h>
4 #include <unistd.h>
5
6 #include "sd-device.h"
7 #include "sd-id128.h"
8
9 #include "alloc-util.h"
10 #include "blkid-util.h"
11 #include "blockdev-util.h"
12 #include "btrfs-util.h"
13 #include "device-util.h"
14 #include "dirent-util.h"
15 #include "dissect-image.h"
16 #include "dropin.h"
17 #include "efi-loader.h"
18 #include "fd-util.h"
19 #include "fileio.h"
20 #include "fs-util.h"
21 #include "fstab-util.h"
22 #include "generator.h"
23 #include "gpt.h"
24 #include "mkdir.h"
25 #include "mountpoint-util.h"
26 #include "parse-util.h"
27 #include "path-util.h"
28 #include "proc-cmdline.h"
29 #include "special.h"
30 #include "specifier.h"
31 #include "stat-util.h"
32 #include "string-util.h"
33 #include "strv.h"
34 #include "unit-name.h"
35 #include "util.h"
36 #include "virt.h"
37
38 static const char *arg_dest = NULL;
39 static bool arg_enabled = true;
40 static bool arg_root_enabled = true;
41 static int arg_root_rw = -1;
42
43 static int open_parent_block_device(dev_t devnum, int *ret_fd) {
44 _cleanup_(sd_device_unrefp) sd_device *d = NULL;
45 const char *name, *devtype, *node;
46 sd_device *parent;
47 dev_t pn;
48 int fd, r;
49
50 assert(ret_fd);
51
52 r = sd_device_new_from_devnum(&d, 'b', devnum);
53 if (r < 0)
54 return log_debug_errno(r, "Failed to open device: %m");
55
56 if (sd_device_get_devname(d, &name) < 0) {
57 r = sd_device_get_syspath(d, &name);
58 if (r < 0) {
59 log_device_debug_errno(d, r, "Device %u:%u does not have a name, ignoring: %m",
60 major(devnum), minor(devnum));
61 return 0;
62 }
63 }
64
65 r = sd_device_get_parent(d, &parent);
66 if (r < 0) {
67 log_device_debug_errno(d, r, "Not a partitioned device, ignoring: %m");
68 return 0;
69 }
70
71 /* Does it have a devtype? */
72 r = sd_device_get_devtype(parent, &devtype);
73 if (r < 0) {
74 log_device_debug_errno(parent, r, "Parent doesn't have a device type, ignoring: %m");
75 return 0;
76 }
77
78 /* Is this a disk or a partition? We only care for disks... */
79 if (!streq(devtype, "disk")) {
80 log_device_debug(parent, "Parent isn't a raw disk, ignoring.");
81 return 0;
82 }
83
84 /* Does it have a device node? */
85 r = sd_device_get_devname(parent, &node);
86 if (r < 0) {
87 log_device_debug_errno(parent, r, "Parent device does not have device node, ignoring: %m");
88 return 0;
89 }
90
91 log_device_debug(d, "Root device %s.", node);
92
93 r = sd_device_get_devnum(parent, &pn);
94 if (r < 0) {
95 log_device_debug_errno(parent, r, "Parent device is not a proper block device, ignoring: %m");
96 return 0;
97 }
98
99 fd = open(node, O_RDONLY|O_CLOEXEC|O_NOCTTY);
100 if (fd < 0)
101 return log_error_errno(errno, "Failed to open %s: %m", node);
102
103 *ret_fd = fd;
104 return 1;
105 }
106
107 static int add_cryptsetup(const char *id, const char *what, bool rw, bool require, char **device) {
108 _cleanup_free_ char *e = NULL, *n = NULL, *d = NULL, *id_escaped = NULL, *what_escaped = NULL;
109 _cleanup_fclose_ FILE *f = NULL;
110 const char *p;
111 int r;
112
113 assert(id);
114 assert(what);
115
116 r = unit_name_from_path(what, ".device", &d);
117 if (r < 0)
118 return log_error_errno(r, "Failed to generate unit name: %m");
119
120 e = unit_name_escape(id);
121 if (!e)
122 return log_oom();
123
124 r = unit_name_build("systemd-cryptsetup", e, ".service", &n);
125 if (r < 0)
126 return log_error_errno(r, "Failed to generate unit name: %m");
127
128 id_escaped = specifier_escape(id);
129 if (!id_escaped)
130 return log_oom();
131
132 what_escaped = specifier_escape(what);
133 if (!what_escaped)
134 return log_oom();
135
136 p = prefix_roota(arg_dest, n);
137 f = fopen(p, "wxe");
138 if (!f)
139 return log_error_errno(errno, "Failed to create unit file %s: %m", p);
140
141 fprintf(f,
142 "# Automatically generated by systemd-gpt-auto-generator\n\n"
143 "[Unit]\n"
144 "Description=Cryptography Setup for %%I\n"
145 "Documentation=man:systemd-gpt-auto-generator(8) man:systemd-cryptsetup@.service(8)\n"
146 "DefaultDependencies=no\n"
147 "Conflicts=umount.target\n"
148 "BindsTo=dev-mapper-%%i.device %s\n"
149 "Before=umount.target cryptsetup.target\n"
150 "After=%s\n"
151 "IgnoreOnIsolate=true\n"
152 "[Service]\n"
153 "Type=oneshot\n"
154 "RemainAfterExit=yes\n"
155 "TimeoutSec=0\n" /* the binary handles timeouts anyway */
156 "KeyringMode=shared\n" /* make sure we can share cached keys among instances */
157 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '' '%s'\n"
158 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
159 d, d,
160 id_escaped, what_escaped, rw ? "" : "read-only",
161 id_escaped);
162
163 r = fflush_and_check(f);
164 if (r < 0)
165 return log_error_errno(r, "Failed to write file %s: %m", p);
166
167 r = generator_add_symlink(arg_dest, d, "wants", n);
168 if (r < 0)
169 return r;
170
171 const char *dmname;
172 dmname = strjoina("dev-mapper-", e, ".device");
173
174 if (require) {
175 r = generator_add_symlink(arg_dest, "cryptsetup.target", "requires", n);
176 if (r < 0)
177 return r;
178
179 r = generator_add_symlink(arg_dest, dmname, "requires", n);
180 if (r < 0)
181 return r;
182 }
183
184 r = write_drop_in_format(arg_dest, dmname, 50, "job-timeout",
185 "# Automatically generated by systemd-gpt-auto-generator\n\n"
186 "[Unit]\n"
187 "JobTimeoutSec=0"); /* the binary handles timeouts anyway */
188 if (r < 0)
189 log_warning_errno(r, "Failed to write device timeout drop-in, ignoring: %m");
190
191 if (device) {
192 char *ret;
193
194 ret = path_join("/dev/mapper", id);
195 if (!ret)
196 return log_oom();
197
198 *device = ret;
199 }
200
201 return 0;
202 }
203
204 static int add_mount(
205 const char *id,
206 const char *what,
207 const char *where,
208 const char *fstype,
209 bool rw,
210 const char *options,
211 const char *description,
212 const char *post) {
213
214 _cleanup_free_ char *unit = NULL, *crypto_what = NULL, *p = NULL;
215 _cleanup_fclose_ FILE *f = NULL;
216 int r;
217
218 /* Note that we don't apply specifier escaping on the input strings here, since we know they are not configured
219 * externally, but all originate from our own sources here, and hence we know they contain no % characters that
220 * could potentially be understood as specifiers. */
221
222 assert(id);
223 assert(what);
224 assert(where);
225 assert(description);
226
227 log_debug("Adding %s: %s fstype=%s", where, what, fstype ?: "(any)");
228
229 if (streq_ptr(fstype, "crypto_LUKS")) {
230
231 r = add_cryptsetup(id, what, rw, true, &crypto_what);
232 if (r < 0)
233 return r;
234
235 what = crypto_what;
236 fstype = NULL;
237 }
238
239 r = unit_name_from_path(where, ".mount", &unit);
240 if (r < 0)
241 return log_error_errno(r, "Failed to generate unit name: %m");
242
243 p = path_join(empty_to_root(arg_dest), unit);
244 if (!p)
245 return log_oom();
246
247 f = fopen(p, "wxe");
248 if (!f)
249 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
250
251 fprintf(f,
252 "# Automatically generated by systemd-gpt-auto-generator\n\n"
253 "[Unit]\n"
254 "Description=%s\n"
255 "Documentation=man:systemd-gpt-auto-generator(8)\n",
256 description);
257
258 if (post)
259 fprintf(f, "Before=%s\n", post);
260
261 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
262 if (r < 0)
263 return r;
264
265 fprintf(f,
266 "\n"
267 "[Mount]\n"
268 "What=%s\n"
269 "Where=%s\n",
270 what, where);
271
272 if (fstype)
273 fprintf(f, "Type=%s\n", fstype);
274
275 if (options)
276 fprintf(f, "Options=%s,%s\n", options, rw ? "rw" : "ro");
277 else
278 fprintf(f, "Options=%s\n", rw ? "rw" : "ro");
279
280 r = fflush_and_check(f);
281 if (r < 0)
282 return log_error_errno(r, "Failed to write unit file %s: %m", p);
283
284 if (post)
285 return generator_add_symlink(arg_dest, post, "requires", unit);
286 return 0;
287 }
288
289 static int path_is_busy(const char *where) {
290 int r;
291
292 /* already a mountpoint; generators run during reload */
293 r = path_is_mount_point(where, NULL, AT_SYMLINK_FOLLOW);
294 if (r > 0)
295 return false;
296
297 /* the directory might not exist on a stateless system */
298 if (r == -ENOENT)
299 return false;
300
301 if (r < 0)
302 return log_warning_errno(r, "Cannot check if \"%s\" is a mount point: %m", where);
303
304 /* not a mountpoint but it contains files */
305 r = dir_is_empty(where);
306 if (r < 0)
307 return log_warning_errno(r, "Cannot check if \"%s\" is empty: %m", where);
308 if (r > 0)
309 return false;
310
311 log_debug("\"%s\" already populated, ignoring.", where);
312 return true;
313 }
314
315 static int add_partition_mount(
316 DissectedPartition *p,
317 const char *id,
318 const char *where,
319 const char *description) {
320
321 int r;
322 assert(p);
323
324 r = path_is_busy(where);
325 if (r != 0)
326 return r < 0 ? r : 0;
327
328 return add_mount(
329 id,
330 p->node,
331 where,
332 p->fstype,
333 p->rw,
334 NULL,
335 description,
336 SPECIAL_LOCAL_FS_TARGET);
337 }
338
339 static int add_swap(const char *path) {
340 _cleanup_free_ char *name = NULL, *unit = NULL;
341 _cleanup_fclose_ FILE *f = NULL;
342 int r;
343
344 assert(path);
345
346 /* Disable the swap auto logic if at least one swap is defined in /etc/fstab, see #6192. */
347 r = fstab_has_fstype("swap");
348 if (r < 0)
349 return log_error_errno(r, "Failed to parse fstab: %m");
350 if (r > 0) {
351 log_debug("swap specified in fstab, ignoring.");
352 return 0;
353 }
354
355 log_debug("Adding swap: %s", path);
356
357 r = unit_name_from_path(path, ".swap", &name);
358 if (r < 0)
359 return log_error_errno(r, "Failed to generate unit name: %m");
360
361 unit = path_join(empty_to_root(arg_dest), name);
362 if (!unit)
363 return log_oom();
364
365 f = fopen(unit, "wxe");
366 if (!f)
367 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
368
369 fprintf(f,
370 "# Automatically generated by systemd-gpt-auto-generator\n\n"
371 "[Unit]\n"
372 "Description=Swap Partition\n"
373 "Documentation=man:systemd-gpt-auto-generator(8)\n\n"
374 "[Swap]\n"
375 "What=%s\n",
376 path);
377
378 r = fflush_and_check(f);
379 if (r < 0)
380 return log_error_errno(r, "Failed to write unit file %s: %m", unit);
381
382 return generator_add_symlink(arg_dest, SPECIAL_SWAP_TARGET, "wants", name);
383 }
384
385 static int add_automount(
386 const char *id,
387 const char *what,
388 const char *where,
389 const char *fstype,
390 bool rw,
391 const char *options,
392 const char *description,
393 usec_t timeout) {
394
395 _cleanup_free_ char *unit = NULL;
396 _cleanup_fclose_ FILE *f = NULL;
397 const char *opt = "noauto", *p;
398 int r;
399
400 assert(id);
401 assert(where);
402 assert(description);
403
404 if (options)
405 opt = strjoina(options, ",", opt);
406
407 r = add_mount(id,
408 what,
409 where,
410 fstype,
411 rw,
412 opt,
413 description,
414 NULL);
415 if (r < 0)
416 return r;
417
418 r = unit_name_from_path(where, ".automount", &unit);
419 if (r < 0)
420 return log_error_errno(r, "Failed to generate unit name: %m");
421
422 p = prefix_roota(arg_dest, unit);
423 f = fopen(p, "wxe");
424 if (!f)
425 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
426
427 fprintf(f,
428 "# Automatically generated by systemd-gpt-auto-generator\n\n"
429 "[Unit]\n"
430 "Description=%s\n"
431 "Documentation=man:systemd-gpt-auto-generator(8)\n"
432 "[Automount]\n"
433 "Where=%s\n"
434 "TimeoutIdleSec="USEC_FMT"\n",
435 description,
436 where,
437 timeout / USEC_PER_SEC);
438
439 r = fflush_and_check(f);
440 if (r < 0)
441 return log_error_errno(r, "Failed to write unit file %s: %m", p);
442
443 return generator_add_symlink(arg_dest, SPECIAL_LOCAL_FS_TARGET, "wants", unit);
444 }
445
446 static const char *esp_or_xbootldr_options(const DissectedPartition *p) {
447 assert(p);
448
449 /* if we probed vfat or have no idea about the file system then assume these file systems are vfat
450 * and thus understand "umask=0077". If we detected something else then don't specify any options and
451 * use kernel defaults. */
452
453 if (!p->fstype || streq(p->fstype, "vfat"))
454 return "umask=0077";
455
456 return NULL;
457 }
458
459 static int add_xbootldr(DissectedPartition *p) {
460 int r;
461
462 assert(p);
463
464 if (in_initrd()) {
465 log_debug("In initrd, ignoring the XBOOTLDR partition.");
466 return 0;
467 }
468
469 r = fstab_is_mount_point("/boot");
470 if (r < 0)
471 return log_error_errno(r, "Failed to parse fstab: %m");
472 if (r > 0) {
473 log_debug("/boot specified in fstab, ignoring XBOOTLDR partition.");
474 return 0;
475 }
476
477 r = path_is_busy("/boot");
478 if (r < 0)
479 return r;
480 if (r > 0)
481 return 0;
482
483 return add_automount("boot",
484 p->node,
485 "/boot",
486 p->fstype,
487 true,
488 esp_or_xbootldr_options(p),
489 "Boot Loader Partition",
490 120 * USEC_PER_SEC);
491 }
492
493 #if ENABLE_EFI
494 static int add_esp(DissectedPartition *p, bool has_xbootldr) {
495 const char *esp_path = NULL, *id = NULL;
496 int r;
497
498 assert(p);
499
500 if (in_initrd()) {
501 log_debug("In initrd, ignoring the ESP.");
502 return 0;
503 }
504
505 /* If /efi exists we'll use that. Otherwise we'll use /boot, as that's usually the better choice, but
506 * only if there's no explicit XBOOTLDR partition around. */
507 if (access("/efi", F_OK) < 0) {
508 if (errno != ENOENT)
509 return log_error_errno(errno, "Failed to determine whether /efi exists: %m");
510
511 /* Use /boot as fallback, but only if there's no XBOOTLDR partition */
512 if (!has_xbootldr) {
513 esp_path = "/boot";
514 id = "boot";
515 }
516 }
517 if (!esp_path)
518 esp_path = "/efi";
519 if (!id)
520 id = "efi";
521
522 /* We create an .automount which is not overridden by the .mount from the fstab generator. */
523 r = fstab_is_mount_point(esp_path);
524 if (r < 0)
525 return log_error_errno(r, "Failed to parse fstab: %m");
526 if (r > 0) {
527 log_debug("%s specified in fstab, ignoring.", esp_path);
528 return 0;
529 }
530
531 r = path_is_busy(esp_path);
532 if (r < 0)
533 return r;
534 if (r > 0)
535 return 0;
536
537 if (is_efi_boot()) {
538 sd_id128_t loader_uuid;
539
540 /* If this is an EFI boot, be extra careful, and only mount the ESP if it was the ESP used for booting. */
541
542 r = efi_loader_get_device_part_uuid(&loader_uuid);
543 if (r == -ENOENT) {
544 log_debug("EFI loader partition unknown.");
545 return 0;
546 }
547 if (r < 0)
548 return log_error_errno(r, "Failed to read ESP partition UUID: %m");
549
550 if (!sd_id128_equal(p->uuid, loader_uuid)) {
551 log_debug("Partition for %s does not appear to be the partition we are booted from.", p->node);
552 return 0;
553 }
554 } else
555 log_debug("Not an EFI boot, skipping ESP check.");
556
557 return add_automount(id,
558 p->node,
559 esp_path,
560 p->fstype,
561 true,
562 esp_or_xbootldr_options(p),
563 "EFI System Partition Automount",
564 120 * USEC_PER_SEC);
565 }
566 #else
567 static int add_esp(DissectedPartition *p, bool has_xbootldr) {
568 return 0;
569 }
570 #endif
571
572 static int add_root_rw(DissectedPartition *p) {
573 const char *path;
574 int r;
575
576 assert(p);
577
578 if (in_initrd()) {
579 log_debug("In initrd, not generating drop-in for systemd-remount-fs.service.");
580 return 0;
581 }
582
583 if (arg_root_rw >= 0) {
584 log_debug("Parameter ro/rw specified on kernel command line, not generating drop-in for systemd-remount-fs.service.");
585 return 0;
586 }
587
588 if (!p->rw) {
589 log_debug("Root partition marked read-only in GPT partition table, not generating drop-in for systemd-remount-fs.service.");
590 return 0;
591 }
592
593 (void) generator_enable_remount_fs_service(arg_dest);
594
595 path = strjoina(arg_dest, "/systemd-remount-fs.service.d/50-remount-rw.conf");
596
597 r = write_string_file(path,
598 "# Automatically generated by systemd-gpt-generator\n\n"
599 "[Service]\n"
600 "Environment=SYSTEMD_REMOUNT_ROOT_RW=1\n",
601 WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_NOFOLLOW|WRITE_STRING_FILE_MKDIR_0755);
602 if (r < 0)
603 return log_error_errno(r, "Failed to write drop-in file %s: %m", path);
604
605 return 0;
606 }
607
608 #if ENABLE_EFI
609 static int add_root_cryptsetup(void) {
610
611 /* If a device /dev/gpt-auto-root-luks appears, then make it pull in systemd-cryptsetup-root.service, which
612 * sets it up, and causes /dev/gpt-auto-root to appear which is all we are looking for. */
613
614 return add_cryptsetup("root", "/dev/gpt-auto-root-luks", true, false, NULL);
615 }
616 #endif
617
618 static int add_root_mount(void) {
619 #if ENABLE_EFI
620 int r;
621
622 if (!is_efi_boot()) {
623 log_debug("Not a EFI boot, not creating root mount.");
624 return 0;
625 }
626
627 r = efi_loader_get_device_part_uuid(NULL);
628 if (r == -ENOENT) {
629 log_notice("EFI loader partition unknown, exiting.\n"
630 "(The boot loader did not set EFI variable LoaderDevicePartUUID.)");
631 return 0;
632 } else if (r < 0)
633 return log_error_errno(r, "Failed to read ESP partition UUID: %m");
634
635 /* OK, we have an ESP partition, this is fantastic, so let's
636 * wait for a root device to show up. A udev rule will create
637 * the link for us under the right name. */
638
639 if (in_initrd()) {
640 r = generator_write_initrd_root_device_deps(arg_dest, "/dev/gpt-auto-root");
641 if (r < 0)
642 return 0;
643
644 r = add_root_cryptsetup();
645 if (r < 0)
646 return r;
647 }
648
649 /* Note that we do not need to enable systemd-remount-fs.service here. If
650 * /etc/fstab exists, systemd-fstab-generator will pull it in for us. */
651
652 return add_mount(
653 "root",
654 "/dev/gpt-auto-root",
655 in_initrd() ? "/sysroot" : "/",
656 NULL,
657 arg_root_rw > 0,
658 NULL,
659 "Root Partition",
660 in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_LOCAL_FS_TARGET);
661 #else
662 return 0;
663 #endif
664 }
665
666 static int enumerate_partitions(dev_t devnum) {
667 _cleanup_close_ int fd = -1;
668 _cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
669 int r, k;
670
671 r = open_parent_block_device(devnum, &fd);
672 if (r <= 0)
673 return r;
674
675 r = dissect_image(fd, NULL, 0, DISSECT_IMAGE_GPT_ONLY|DISSECT_IMAGE_NO_UDEV, &m);
676 if (r == -ENOPKG) {
677 log_debug_errno(r, "No suitable partition table found, ignoring.");
678 return 0;
679 }
680 if (r < 0)
681 return log_error_errno(r, "Failed to dissect: %m");
682
683 if (m->partitions[PARTITION_SWAP].found) {
684 k = add_swap(m->partitions[PARTITION_SWAP].node);
685 if (k < 0)
686 r = k;
687 }
688
689 if (m->partitions[PARTITION_XBOOTLDR].found) {
690 k = add_xbootldr(m->partitions + PARTITION_XBOOTLDR);
691 if (k < 0)
692 r = k;
693 }
694
695 if (m->partitions[PARTITION_ESP].found) {
696 k = add_esp(m->partitions + PARTITION_ESP, m->partitions[PARTITION_XBOOTLDR].found);
697 if (k < 0)
698 r = k;
699 }
700
701 if (m->partitions[PARTITION_HOME].found) {
702 k = add_partition_mount(m->partitions + PARTITION_HOME, "home", "/home", "Home Partition");
703 if (k < 0)
704 r = k;
705 }
706
707 if (m->partitions[PARTITION_SRV].found) {
708 k = add_partition_mount(m->partitions + PARTITION_SRV, "srv", "/srv", "Server Data Partition");
709 if (k < 0)
710 r = k;
711 }
712
713 if (m->partitions[PARTITION_ROOT].found) {
714 k = add_root_rw(m->partitions + PARTITION_ROOT);
715 if (k < 0)
716 r = k;
717 }
718
719 return r;
720 }
721
722 static int add_mounts(void) {
723 dev_t devno;
724 int r;
725
726 r = get_block_device_harder("/", &devno);
727 if (r < 0)
728 return log_error_errno(r, "Failed to determine block device of root file system: %m");
729 if (r == 0) {
730 r = get_block_device_harder("/usr", &devno);
731 if (r < 0)
732 return log_error_errno(r, "Failed to determine block device of /usr file system: %m");
733 if (r == 0) {
734 _cleanup_free_ char *p = NULL;
735 mode_t m;
736
737 /* If the root mount has been replaced by some form of volatile file system (overlayfs), the
738 * original root block device node is symlinked in /run/systemd/volatile-root. Let's read that
739 * here. */
740 r = readlink_malloc("/run/systemd/volatile-root", &p);
741 if (r == -ENOENT) {
742 log_debug("Neither root nor /usr file system are on a (single) block device.");
743 return 0;
744 }
745 if (r < 0)
746 return log_error_errno(r, "Failed to read symlink /run/systemd/volatile-root: %m");
747
748 r = device_path_parse_major_minor(p, &m, &devno);
749 if (r < 0)
750 return log_error_errno(r, "Failed to parse major/minor device node: %m");
751 if (!S_ISBLK(m))
752 return log_error_errno(SYNTHETIC_ERRNO(ENOTBLK), "Volatile root device is of wrong type.");
753 }
754 }
755
756 return enumerate_partitions(devno);
757 }
758
759 static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
760 int r;
761
762 assert(key);
763
764 if (proc_cmdline_key_streq(key, "systemd.gpt_auto") ||
765 proc_cmdline_key_streq(key, "rd.systemd.gpt_auto")) {
766
767 r = value ? parse_boolean(value) : 1;
768 if (r < 0)
769 log_warning_errno(r, "Failed to parse gpt-auto switch \"%s\", ignoring: %m", value);
770 else
771 arg_enabled = r;
772
773 } else if (proc_cmdline_key_streq(key, "root")) {
774
775 if (proc_cmdline_value_missing(key, value))
776 return 0;
777
778 /* Disable root disk logic if there's a root= value
779 * specified (unless it happens to be "gpt-auto") */
780
781 if (!streq(value, "gpt-auto")) {
782 arg_root_enabled = false;
783 log_debug("Disabling root partition auto-detection, root= is defined.");
784 }
785
786 } else if (proc_cmdline_key_streq(key, "roothash")) {
787
788 if (proc_cmdline_value_missing(key, value))
789 return 0;
790
791 /* Disable root disk logic if there's roothash= defined (i.e. verity enabled) */
792
793 arg_root_enabled = false;
794
795 } else if (proc_cmdline_key_streq(key, "rw") && !value)
796 arg_root_rw = true;
797 else if (proc_cmdline_key_streq(key, "ro") && !value)
798 arg_root_rw = false;
799
800 return 0;
801 }
802
803 static int run(const char *dest, const char *dest_early, const char *dest_late) {
804 int r, k;
805
806 assert_se(arg_dest = dest_late);
807
808 if (detect_container() > 0) {
809 log_debug("In a container, exiting.");
810 return 0;
811 }
812
813 r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
814 if (r < 0)
815 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
816
817 if (!arg_enabled) {
818 log_debug("Disabled, exiting.");
819 return 0;
820 }
821
822 if (arg_root_enabled)
823 r = add_root_mount();
824
825 if (!in_initrd()) {
826 k = add_mounts();
827 if (r >= 0)
828 r = k;
829 }
830
831 return r;
832 }
833
834 DEFINE_MAIN_GENERATOR_FUNCTION(run);