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