]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/gpt-auto-generator/gpt-auto-generator.c
gpt-auto-generator: rename function for clarity
[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 int add_xbootldr(DissectedPartition *p) {
447 int r;
448
449 assert(p);
450
451 if (in_initrd()) {
452 log_debug("In initrd, ignoring the XBOOTLDR partition.");
453 return 0;
454 }
455
456 r = fstab_is_mount_point("/boot");
457 if (r < 0)
458 return log_error_errno(r, "Failed to parse fstab: %m");
459 if (r > 0) {
460 log_debug("/boot specified in fstab, ignoring XBOOTLDR partition.");
461 return 0;
462 }
463
464 r = path_is_busy("/boot");
465 if (r < 0)
466 return r;
467 if (r > 0)
468 return 0;
469
470 return add_automount("boot",
471 p->node,
472 "/boot",
473 p->fstype,
474 true,
475 "umask=0077",
476 "Boot Loader Partition",
477 120 * USEC_PER_SEC);
478 }
479
480 #if ENABLE_EFI
481 static int add_esp(DissectedPartition *p, bool has_xbootldr) {
482 const char *esp_path = NULL, *id = NULL;
483 int r;
484
485 assert(p);
486
487 if (in_initrd()) {
488 log_debug("In initrd, ignoring the ESP.");
489 return 0;
490 }
491
492 /* If /efi exists we'll use that. Otherwise we'll use /boot, as that's usually the better choice, but
493 * only if there's no explicit XBOOTLDR partition around. */
494 if (access("/efi", F_OK) < 0) {
495 if (errno != ENOENT)
496 return log_error_errno(errno, "Failed to determine whether /efi exists: %m");
497
498 /* Use /boot as fallback, but only if there's no XBOOTLDR partition */
499 if (!has_xbootldr) {
500 esp_path = "/boot";
501 id = "boot";
502 }
503 }
504 if (!esp_path)
505 esp_path = "/efi";
506 if (!id)
507 id = "efi";
508
509 /* We create an .automount which is not overridden by the .mount from the fstab generator. */
510 r = fstab_is_mount_point(esp_path);
511 if (r < 0)
512 return log_error_errno(r, "Failed to parse fstab: %m");
513 if (r > 0) {
514 log_debug("%s specified in fstab, ignoring.", esp_path);
515 return 0;
516 }
517
518 r = path_is_busy(esp_path);
519 if (r < 0)
520 return r;
521 if (r > 0)
522 return 0;
523
524 if (is_efi_boot()) {
525 sd_id128_t loader_uuid;
526
527 /* If this is an EFI boot, be extra careful, and only mount the ESP if it was the ESP used for booting. */
528
529 r = efi_loader_get_device_part_uuid(&loader_uuid);
530 if (r == -ENOENT) {
531 log_debug("EFI loader partition unknown.");
532 return 0;
533 }
534 if (r < 0)
535 return log_error_errno(r, "Failed to read ESP partition UUID: %m");
536
537 if (!sd_id128_equal(p->uuid, loader_uuid)) {
538 log_debug("Partition for %s does not appear to be the partition we are booted from.", p->node);
539 return 0;
540 }
541 } else
542 log_debug("Not an EFI boot, skipping ESP check.");
543
544 return add_automount(id,
545 p->node,
546 esp_path,
547 p->fstype,
548 true,
549 "umask=0077",
550 "EFI System Partition Automount",
551 120 * USEC_PER_SEC);
552 }
553 #else
554 static int add_esp(DissectedPartition *p, bool has_xbootldr) {
555 return 0;
556 }
557 #endif
558
559 static int add_root_rw(DissectedPartition *p) {
560 const char *path;
561 int r;
562
563 assert(p);
564
565 if (in_initrd()) {
566 log_debug("In initrd, not generating drop-in for systemd-remount-fs.service.");
567 return 0;
568 }
569
570 if (arg_root_rw >= 0) {
571 log_debug("Parameter ro/rw specified on kernel command line, not generating drop-in for systemd-remount-fs.service.");
572 return 0;
573 }
574
575 if (!p->rw) {
576 log_debug("Root partition marked read-only in GPT partition table, not generating drop-in for systemd-remount-fs.service.");
577 return 0;
578 }
579
580 (void) generator_enable_remount_fs_service(arg_dest);
581
582 path = strjoina(arg_dest, "/systemd-remount-fs.service.d/50-remount-rw.conf");
583
584 r = write_string_file(path,
585 "# Automatically generated by systemd-gpt-generator\n\n"
586 "[Service]\n"
587 "Environment=SYSTEMD_REMOUNT_ROOT_RW=1\n",
588 WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_NOFOLLOW|WRITE_STRING_FILE_MKDIR_0755);
589 if (r < 0)
590 return log_error_errno(r, "Failed to write drop-in file %s: %m", path);
591
592 return 0;
593 }
594
595 #if ENABLE_EFI
596 static int add_root_cryptsetup(void) {
597
598 /* If a device /dev/gpt-auto-root-luks appears, then make it pull in systemd-cryptsetup-root.service, which
599 * sets it up, and causes /dev/gpt-auto-root to appear which is all we are looking for. */
600
601 return add_cryptsetup("root", "/dev/gpt-auto-root-luks", true, false, NULL);
602 }
603 #endif
604
605 static int add_root_mount(void) {
606 #if ENABLE_EFI
607 int r;
608
609 if (!is_efi_boot()) {
610 log_debug("Not a EFI boot, not creating root mount.");
611 return 0;
612 }
613
614 r = efi_loader_get_device_part_uuid(NULL);
615 if (r == -ENOENT) {
616 log_notice("EFI loader partition unknown, exiting.\n"
617 "(The boot loader did not set EFI variable LoaderDevicePartUUID.)");
618 return 0;
619 } else if (r < 0)
620 return log_error_errno(r, "Failed to read ESP partition UUID: %m");
621
622 /* OK, we have an ESP partition, this is fantastic, so let's
623 * wait for a root device to show up. A udev rule will create
624 * the link for us under the right name. */
625
626 if (in_initrd()) {
627 r = generator_write_initrd_root_device_deps(arg_dest, "/dev/gpt-auto-root");
628 if (r < 0)
629 return 0;
630
631 r = add_root_cryptsetup();
632 if (r < 0)
633 return r;
634 }
635
636 /* Note that we do not need to enable systemd-remount-fs.service here. If
637 * /etc/fstab exists, systemd-fstab-generator will pull it in for us. */
638
639 return add_mount(
640 "root",
641 "/dev/gpt-auto-root",
642 in_initrd() ? "/sysroot" : "/",
643 NULL,
644 arg_root_rw > 0,
645 NULL,
646 "Root Partition",
647 in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_LOCAL_FS_TARGET);
648 #else
649 return 0;
650 #endif
651 }
652
653 static int enumerate_partitions(dev_t devnum) {
654 _cleanup_close_ int fd = -1;
655 _cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
656 int r, k;
657
658 r = open_parent_block_device(devnum, &fd);
659 if (r <= 0)
660 return r;
661
662 r = dissect_image(fd, NULL, 0, DISSECT_IMAGE_GPT_ONLY|DISSECT_IMAGE_NO_UDEV, &m);
663 if (r == -ENOPKG) {
664 log_debug_errno(r, "No suitable partition table found, ignoring.");
665 return 0;
666 }
667 if (r < 0)
668 return log_error_errno(r, "Failed to dissect: %m");
669
670 if (m->partitions[PARTITION_SWAP].found) {
671 k = add_swap(m->partitions[PARTITION_SWAP].node);
672 if (k < 0)
673 r = k;
674 }
675
676 if (m->partitions[PARTITION_XBOOTLDR].found) {
677 k = add_xbootldr(m->partitions + PARTITION_XBOOTLDR);
678 if (k < 0)
679 r = k;
680 }
681
682 if (m->partitions[PARTITION_ESP].found) {
683 k = add_esp(m->partitions + PARTITION_ESP, m->partitions[PARTITION_XBOOTLDR].found);
684 if (k < 0)
685 r = k;
686 }
687
688 if (m->partitions[PARTITION_HOME].found) {
689 k = add_partition_mount(m->partitions + PARTITION_HOME, "home", "/home", "Home Partition");
690 if (k < 0)
691 r = k;
692 }
693
694 if (m->partitions[PARTITION_SRV].found) {
695 k = add_partition_mount(m->partitions + PARTITION_SRV, "srv", "/srv", "Server Data Partition");
696 if (k < 0)
697 r = k;
698 }
699
700 if (m->partitions[PARTITION_ROOT].found) {
701 k = add_root_rw(m->partitions + PARTITION_ROOT);
702 if (k < 0)
703 r = k;
704 }
705
706 return r;
707 }
708
709 static int add_mounts(void) {
710 dev_t devno;
711 int r;
712
713 r = get_block_device_harder("/", &devno);
714 if (r < 0)
715 return log_error_errno(r, "Failed to determine block device of root file system: %m");
716 if (r == 0) {
717 r = get_block_device_harder("/usr", &devno);
718 if (r < 0)
719 return log_error_errno(r, "Failed to determine block device of /usr file system: %m");
720 if (r == 0) {
721 _cleanup_free_ char *p = NULL;
722 mode_t m;
723
724 /* If the root mount has been replaced by some form of volatile file system (overlayfs), the
725 * original root block device node is symlinked in /run/systemd/volatile-root. Let's read that
726 * here. */
727 r = readlink_malloc("/run/systemd/volatile-root", &p);
728 if (r == -ENOENT) {
729 log_debug("Neither root nor /usr file system are on a (single) block device.");
730 return 0;
731 }
732 if (r < 0)
733 return log_error_errno(r, "Failed to read symlink /run/systemd/volatile-root: %m");
734
735 r = device_path_parse_major_minor(p, &m, &devno);
736 if (r < 0)
737 return log_error_errno(r, "Failed to parse major/minor device node: %m");
738 if (!S_ISBLK(m))
739 return log_error_errno(SYNTHETIC_ERRNO(ENOTBLK), "Volatile root device is of wrong type.");
740 }
741 }
742
743 return enumerate_partitions(devno);
744 }
745
746 static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
747 int r;
748
749 assert(key);
750
751 if (proc_cmdline_key_streq(key, "systemd.gpt_auto") ||
752 proc_cmdline_key_streq(key, "rd.systemd.gpt_auto")) {
753
754 r = value ? parse_boolean(value) : 1;
755 if (r < 0)
756 log_warning_errno(r, "Failed to parse gpt-auto switch \"%s\", ignoring: %m", value);
757 else
758 arg_enabled = r;
759
760 } else if (proc_cmdline_key_streq(key, "root")) {
761
762 if (proc_cmdline_value_missing(key, value))
763 return 0;
764
765 /* Disable root disk logic if there's a root= value
766 * specified (unless it happens to be "gpt-auto") */
767
768 if (!streq(value, "gpt-auto")) {
769 arg_root_enabled = false;
770 log_debug("Disabling root partition auto-detection, root= is defined.");
771 }
772
773 } else if (proc_cmdline_key_streq(key, "roothash")) {
774
775 if (proc_cmdline_value_missing(key, value))
776 return 0;
777
778 /* Disable root disk logic if there's roothash= defined (i.e. verity enabled) */
779
780 arg_root_enabled = false;
781
782 } else if (proc_cmdline_key_streq(key, "rw") && !value)
783 arg_root_rw = true;
784 else if (proc_cmdline_key_streq(key, "ro") && !value)
785 arg_root_rw = false;
786
787 return 0;
788 }
789
790 static int run(const char *dest, const char *dest_early, const char *dest_late) {
791 int r, k;
792
793 assert_se(arg_dest = dest_late);
794
795 if (detect_container() > 0) {
796 log_debug("In a container, exiting.");
797 return 0;
798 }
799
800 r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
801 if (r < 0)
802 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
803
804 if (!arg_enabled) {
805 log_debug("Disabled, exiting.");
806 return 0;
807 }
808
809 if (arg_root_enabled)
810 r = add_root_mount();
811
812 if (!in_initrd()) {
813 k = add_mounts();
814 if (r >= 0)
815 r = k;
816 }
817
818 return r;
819 }
820
821 DEFINE_MAIN_GENERATOR_FUNCTION(run);