]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/gpt-auto-generator/gpt-auto-generator.c
machined: when renaming/removing/cloning images, always take care of .roothash file too
[thirdparty/systemd.git] / src / gpt-auto-generator / gpt-auto-generator.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2013 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <blkid/blkid.h>
21 #include <stdlib.h>
22 #include <sys/statfs.h>
23 #include <unistd.h>
24
25 #include "libudev.h"
26 #include "sd-id128.h"
27
28 #include "alloc-util.h"
29 #include "blkid-util.h"
30 #include "btrfs-util.h"
31 #include "dirent-util.h"
32 #include "dissect-image.h"
33 #include "efivars.h"
34 #include "fd-util.h"
35 #include "fileio.h"
36 #include "fstab-util.h"
37 #include "generator.h"
38 #include "gpt.h"
39 #include "missing.h"
40 #include "mkdir.h"
41 #include "mount-util.h"
42 #include "parse-util.h"
43 #include "path-util.h"
44 #include "proc-cmdline.h"
45 #include "special.h"
46 #include "stat-util.h"
47 #include "string-util.h"
48 #include "udev-util.h"
49 #include "unit-name.h"
50 #include "util.h"
51 #include "virt.h"
52
53 static const char *arg_dest = "/tmp";
54 static bool arg_enabled = true;
55 static bool arg_root_enabled = true;
56 static bool arg_root_rw = false;
57
58 static int add_cryptsetup(const char *id, const char *what, bool rw, bool require, char **device) {
59 _cleanup_free_ char *e = NULL, *n = NULL, *p = NULL, *d = NULL, *to = NULL;
60 _cleanup_fclose_ FILE *f = NULL;
61 char *from, *ret;
62 int r;
63
64 assert(id);
65 assert(what);
66
67 r = unit_name_from_path(what, ".device", &d);
68 if (r < 0)
69 return log_error_errno(r, "Failed to generate unit name: %m");
70
71 e = unit_name_escape(id);
72 if (!e)
73 return log_oom();
74
75 r = unit_name_build("systemd-cryptsetup", e, ".service", &n);
76 if (r < 0)
77 return log_error_errno(r, "Failed to generate unit name: %m");
78
79 p = strjoin(arg_dest, "/", n);
80 if (!p)
81 return log_oom();
82
83 f = fopen(p, "wxe");
84 if (!f)
85 return log_error_errno(errno, "Failed to create unit file %s: %m", p);
86
87 fprintf(f,
88 "# Automatically generated by systemd-gpt-auto-generator\n\n"
89 "[Unit]\n"
90 "Description=Cryptography Setup for %%I\n"
91 "Documentation=man:systemd-gpt-auto-generator(8) man:systemd-cryptsetup@.service(8)\n"
92 "DefaultDependencies=no\n"
93 "Conflicts=umount.target\n"
94 "BindsTo=dev-mapper-%%i.device %s\n"
95 "Before=umount.target cryptsetup.target\n"
96 "After=%s\n"
97 "IgnoreOnIsolate=true\n"
98 "[Service]\n"
99 "Type=oneshot\n"
100 "RemainAfterExit=yes\n"
101 "TimeoutSec=0\n" /* the binary handles timeouts anyway */
102 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '' '%s'\n"
103 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
104 d, d,
105 id, what, rw ? "" : "read-only",
106 id);
107
108 r = fflush_and_check(f);
109 if (r < 0)
110 return log_error_errno(r, "Failed to write file %s: %m", p);
111
112 from = strjoina("../", n);
113
114 to = strjoin(arg_dest, "/", d, ".wants/", n);
115 if (!to)
116 return log_oom();
117
118 mkdir_parents_label(to, 0755);
119 if (symlink(from, to) < 0)
120 return log_error_errno(errno, "Failed to create symlink %s: %m", to);
121
122 if (require) {
123 free(to);
124
125 to = strjoin(arg_dest, "/cryptsetup.target.requires/", n);
126 if (!to)
127 return log_oom();
128
129 mkdir_parents_label(to, 0755);
130 if (symlink(from, to) < 0)
131 return log_error_errno(errno, "Failed to create symlink %s: %m", to);
132
133 free(to);
134 to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n);
135 if (!to)
136 return log_oom();
137
138 mkdir_parents_label(to, 0755);
139 if (symlink(from, to) < 0)
140 return log_error_errno(errno, "Failed to create symlink %s: %m", to);
141 }
142
143 free(p);
144 p = strjoin(arg_dest, "/dev-mapper-", e, ".device.d/50-job-timeout-sec-0.conf");
145 if (!p)
146 return log_oom();
147
148 mkdir_parents_label(p, 0755);
149 r = write_string_file(p,
150 "# Automatically generated by systemd-gpt-auto-generator\n\n"
151 "[Unit]\n"
152 "JobTimeoutSec=0\n",
153 WRITE_STRING_FILE_CREATE); /* the binary handles timeouts anyway */
154 if (r < 0)
155 return log_error_errno(r, "Failed to write device drop-in: %m");
156
157 ret = strappend("/dev/mapper/", id);
158 if (!ret)
159 return log_oom();
160
161 if (device)
162 *device = ret;
163 return 0;
164 }
165
166 static int add_mount(
167 const char *id,
168 const char *what,
169 const char *where,
170 const char *fstype,
171 bool rw,
172 const char *options,
173 const char *description,
174 const char *post) {
175
176 _cleanup_free_ char *unit = NULL, *lnk = NULL, *crypto_what = NULL, *p = NULL;
177 _cleanup_fclose_ FILE *f = NULL;
178 int r;
179
180 assert(id);
181 assert(what);
182 assert(where);
183 assert(description);
184
185 log_debug("Adding %s: %s %s", where, what, strna(fstype));
186
187 if (streq_ptr(fstype, "crypto_LUKS")) {
188
189 r = add_cryptsetup(id, what, rw, true, &crypto_what);
190 if (r < 0)
191 return r;
192
193 what = crypto_what;
194 fstype = NULL;
195 }
196
197 r = unit_name_from_path(where, ".mount", &unit);
198 if (r < 0)
199 return log_error_errno(r, "Failed to generate unit name: %m");
200
201 p = strjoin(arg_dest, "/", unit);
202 if (!p)
203 return log_oom();
204
205 f = fopen(p, "wxe");
206 if (!f)
207 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
208
209 fprintf(f,
210 "# Automatically generated by systemd-gpt-auto-generator\n\n"
211 "[Unit]\n"
212 "Description=%s\n"
213 "Documentation=man:systemd-gpt-auto-generator(8)\n",
214 description);
215
216 if (post)
217 fprintf(f, "Before=%s\n", post);
218
219 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
220 if (r < 0)
221 return r;
222
223 fprintf(f,
224 "\n"
225 "[Mount]\n"
226 "What=%s\n"
227 "Where=%s\n",
228 what, where);
229
230 if (fstype)
231 fprintf(f, "Type=%s\n", fstype);
232
233 if (options)
234 fprintf(f, "Options=%s,%s\n", options, rw ? "rw" : "ro");
235 else
236 fprintf(f, "Options=%s\n", rw ? "rw" : "ro");
237
238 r = fflush_and_check(f);
239 if (r < 0)
240 return log_error_errno(r, "Failed to write unit file %s: %m", p);
241
242 if (post) {
243 lnk = strjoin(arg_dest, "/", post, ".requires/", unit);
244 if (!lnk)
245 return log_oom();
246
247 mkdir_parents_label(lnk, 0755);
248 if (symlink(p, lnk) < 0)
249 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
250 }
251
252 return 0;
253 }
254
255 static bool path_is_busy(const char *where) {
256 int r;
257
258 /* already a mountpoint; generators run during reload */
259 r = path_is_mount_point(where, NULL, AT_SYMLINK_FOLLOW);
260 if (r > 0)
261 return false;
262
263 /* the directory might not exist on a stateless system */
264 if (r == -ENOENT)
265 return false;
266
267 if (r < 0)
268 return true;
269
270 /* not a mountpoint but it contains files */
271 if (dir_is_empty(where) <= 0)
272 return true;
273
274 return false;
275 }
276
277 static int add_partition_mount(
278 DissectedPartition *p,
279 const char *id,
280 const char *where,
281 const char *description) {
282
283 assert(p);
284
285 if (path_is_busy(where)) {
286 log_debug("%s already populated, ignoring.", where);
287 return 0;
288 }
289
290 return add_mount(
291 id,
292 p->node,
293 where,
294 p->fstype,
295 p->rw,
296 NULL,
297 description,
298 SPECIAL_LOCAL_FS_TARGET);
299 }
300
301 static int add_swap(const char *path) {
302 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
303 _cleanup_fclose_ FILE *f = NULL;
304 int r;
305
306 assert(path);
307
308 log_debug("Adding swap: %s", path);
309
310 r = unit_name_from_path(path, ".swap", &name);
311 if (r < 0)
312 return log_error_errno(r, "Failed to generate unit name: %m");
313
314 unit = strjoin(arg_dest, "/", name);
315 if (!unit)
316 return log_oom();
317
318 f = fopen(unit, "wxe");
319 if (!f)
320 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
321
322 fprintf(f,
323 "# Automatically generated by systemd-gpt-auto-generator\n\n"
324 "[Unit]\n"
325 "Description=Swap Partition\n"
326 "Documentation=man:systemd-gpt-auto-generator(8)\n\n"
327 "[Swap]\n"
328 "What=%s\n",
329 path);
330
331 r = fflush_and_check(f);
332 if (r < 0)
333 return log_error_errno(r, "Failed to write unit file %s: %m", unit);
334
335 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name);
336 if (!lnk)
337 return log_oom();
338
339 mkdir_parents_label(lnk, 0755);
340 if (symlink(unit, lnk) < 0)
341 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
342
343 return 0;
344 }
345
346 #ifdef ENABLE_EFI
347 static int add_automount(
348 const char *id,
349 const char *what,
350 const char *where,
351 const char *fstype,
352 bool rw,
353 const char *options,
354 const char *description,
355 usec_t timeout) {
356
357 _cleanup_free_ char *unit = NULL, *lnk = NULL;
358 _cleanup_free_ char *opt, *p = NULL;
359 _cleanup_fclose_ FILE *f = NULL;
360 int r;
361
362 assert(id);
363 assert(where);
364 assert(description);
365
366 if (options)
367 opt = strjoin(options, ",noauto");
368 else
369 opt = strdup("noauto");
370 if (!opt)
371 return log_oom();
372
373 r = add_mount(id,
374 what,
375 where,
376 fstype,
377 rw,
378 opt,
379 description,
380 NULL);
381 if (r < 0)
382 return r;
383
384 r = unit_name_from_path(where, ".automount", &unit);
385 if (r < 0)
386 return log_error_errno(r, "Failed to generate unit name: %m");
387
388 p = strjoin(arg_dest, "/", unit);
389 if (!p)
390 return log_oom();
391
392 f = fopen(p, "wxe");
393 if (!f)
394 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
395
396 fprintf(f,
397 "# Automatically generated by systemd-gpt-auto-generator\n\n"
398 "[Unit]\n"
399 "Description=%s\n"
400 "Documentation=man:systemd-gpt-auto-generator(8)\n"
401 "[Automount]\n"
402 "Where=%s\n"
403 "TimeoutIdleSec="USEC_FMT"\n",
404 description,
405 where,
406 timeout / USEC_PER_SEC);
407
408 r = fflush_and_check(f);
409 if (r < 0)
410 return log_error_errno(r, "Failed to write unit file %s: %m", p);
411
412 lnk = strjoin(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".wants/", unit);
413 if (!lnk)
414 return log_oom();
415 mkdir_parents_label(lnk, 0755);
416
417 if (symlink(p, lnk) < 0)
418 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
419
420 return 0;
421 }
422
423 static int add_esp(DissectedPartition *p) {
424 const char *esp;
425 int r;
426
427 assert(p);
428
429 if (in_initrd()) {
430 log_debug("In initrd, ignoring the ESP.");
431 return 0;
432 }
433
434 /* If /efi exists we'll use that. Otherwise we'll use /boot, as that's usually the better choice */
435 esp = access("/efi/", F_OK) >= 0 ? "/efi" : "/boot";
436
437 /* We create an .automount which is not overridden by the .mount from the fstab generator. */
438 if (fstab_is_mount_point(esp)) {
439 log_debug("%s specified in fstab, ignoring.", esp);
440 return 0;
441 }
442
443 if (path_is_busy(esp)) {
444 log_debug("%s already populated, ignoring.", esp);
445 return 0;
446 }
447
448 if (is_efi_boot()) {
449 sd_id128_t loader_uuid;
450
451 /* If this is an EFI boot, be extra careful, and only mount the ESP if it was the ESP used for booting. */
452
453 r = efi_loader_get_device_part_uuid(&loader_uuid);
454 if (r == -ENOENT) {
455 log_debug("EFI loader partition unknown.");
456 return 0;
457 }
458 if (r < 0)
459 return log_error_errno(r, "Failed to read ESP partition UUID: %m");
460
461 if (!sd_id128_equal(p->uuid, loader_uuid)) {
462 log_debug("Partition for %s does not appear to be the partition we are booted from.", esp);
463 return 0;
464 }
465 } else
466 log_debug("Not an EFI boot, skipping ESP check.");
467
468 return add_automount("boot",
469 p->node,
470 esp,
471 p->fstype,
472 true,
473 "umask=0077",
474 "EFI System Partition Automount",
475 120 * USEC_PER_SEC);
476 }
477 #else
478 static int add_esp(const char *what) {
479 return 0;
480 }
481 #endif
482
483 static int open_parent(dev_t devnum, int *ret) {
484 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
485 _cleanup_udev_unref_ struct udev *udev = NULL;
486 const char *name, *devtype, *node;
487 struct udev_device *parent;
488 dev_t pn;
489 int fd;
490
491 assert(ret);
492
493 udev = udev_new();
494 if (!udev)
495 return log_oom();
496
497 d = udev_device_new_from_devnum(udev, 'b', devnum);
498 if (!d)
499 return log_oom();
500
501 name = udev_device_get_devnode(d);
502 if (!name)
503 name = udev_device_get_syspath(d);
504 if (!name) {
505 log_debug("Device %u:%u does not have a name, ignoring.", major(devnum), minor(devnum));
506 goto not_found;
507 }
508
509 parent = udev_device_get_parent(d);
510 if (!parent) {
511 log_debug("%s: not a partitioned device, ignoring.", name);
512 goto not_found;
513 }
514
515 /* Does it have a devtype? */
516 devtype = udev_device_get_devtype(parent);
517 if (!devtype) {
518 log_debug("%s: parent doesn't have a device type, ignoring.", name);
519 goto not_found;
520 }
521
522 /* Is this a disk or a partition? We only care for disks... */
523 if (!streq(devtype, "disk")) {
524 log_debug("%s: parent isn't a raw disk, ignoring.", name);
525 goto not_found;
526 }
527
528 /* Does it have a device node? */
529 node = udev_device_get_devnode(parent);
530 if (!node) {
531 log_debug("%s: parent device does not have device node, ignoring.", name);
532 goto not_found;
533 }
534
535 log_debug("%s: root device %s.", name, node);
536
537 pn = udev_device_get_devnum(parent);
538 if (major(pn) == 0) {
539 log_debug("%s: parent device is not a proper block device, ignoring.", name);
540 goto not_found;
541 }
542
543 fd = open(node, O_RDONLY|O_CLOEXEC|O_NOCTTY);
544 if (fd < 0)
545 return log_error_errno(errno, "Failed to open %s: %m", node);
546
547 *ret = fd;
548 return 1;
549
550 not_found:
551 *ret = -1;
552 return 0;
553 }
554
555 static int enumerate_partitions(dev_t devnum) {
556
557 _cleanup_close_ int fd = -1;
558 _cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
559 int r, k;
560
561 r = open_parent(devnum, &fd);
562 if (r <= 0)
563 return r;
564
565 r = dissect_image(fd, NULL, 0, DISSECT_IMAGE_GPT_ONLY, &m);
566 if (r == -ENOPKG) {
567 log_debug_errno(r, "No suitable partition table found, ignoring.");
568 return 0;
569 }
570 if (r < 0)
571 return log_error_errno(r, "Failed to dissect: %m");
572
573 if (m->partitions[PARTITION_SWAP].found) {
574 k = add_swap(m->partitions[PARTITION_SWAP].node);
575 if (k < 0)
576 r = k;
577 }
578
579 if (m->partitions[PARTITION_ESP].found) {
580 k = add_esp(m->partitions + PARTITION_ESP);
581 if (k < 0)
582 r = k;
583 }
584
585 if (m->partitions[PARTITION_HOME].found) {
586 k = add_partition_mount(m->partitions + PARTITION_HOME, "home", "/home", "Home Partition");
587 if (k < 0)
588 r = k;
589 }
590
591 if (m->partitions[PARTITION_SRV].found) {
592 k = add_partition_mount(m->partitions + PARTITION_SRV, "srv", "/srv", "Server Data Partition");
593 if (k < 0)
594 r = k;
595 }
596
597 return r;
598 }
599
600 static int get_block_device(const char *path, dev_t *dev) {
601 struct stat st;
602 struct statfs sfs;
603
604 assert(path);
605 assert(dev);
606
607 /* Get's the block device directly backing a file system. If
608 * the block device is encrypted, returns the device mapper
609 * block device. */
610
611 if (lstat(path, &st))
612 return -errno;
613
614 if (major(st.st_dev) != 0) {
615 *dev = st.st_dev;
616 return 1;
617 }
618
619 if (statfs(path, &sfs) < 0)
620 return -errno;
621
622 if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
623 return btrfs_get_block_device(path, dev);
624
625 return 0;
626 }
627
628 static int get_block_device_harder(const char *path, dev_t *dev) {
629 _cleanup_closedir_ DIR *d = NULL;
630 _cleanup_free_ char *p = NULL, *t = NULL;
631 struct dirent *de, *found = NULL;
632 const char *q;
633 unsigned maj, min;
634 dev_t dt;
635 int r;
636
637 assert(path);
638 assert(dev);
639
640 /* Gets the backing block device for a file system, and
641 * handles LUKS encrypted file systems, looking for its
642 * immediate parent, if there is one. */
643
644 r = get_block_device(path, &dt);
645 if (r <= 0)
646 return r;
647
648 if (asprintf(&p, "/sys/dev/block/%u:%u/slaves", major(dt), minor(dt)) < 0)
649 return -ENOMEM;
650
651 d = opendir(p);
652 if (!d) {
653 if (errno == ENOENT)
654 goto fallback;
655
656 return -errno;
657 }
658
659 FOREACH_DIRENT_ALL(de, d, return -errno) {
660
661 if (STR_IN_SET(de->d_name, ".", ".."))
662 continue;
663
664 if (!IN_SET(de->d_type, DT_LNK, DT_UNKNOWN))
665 continue;
666
667 if (found) {
668 _cleanup_free_ char *u = NULL, *v = NULL, *a = NULL, *b = NULL;
669
670 /* We found a device backed by multiple other devices. We don't really support automatic
671 * discovery on such setups, with the exception of dm-verity partitions. In this case there are
672 * two backing devices: the data partitoin and the hash partition. We are fine with such
673 * setups, however, only if both partitions are on the same physical device. Hence, let's
674 * verify this. */
675
676 u = strjoin(p, "/", de->d_name, "/../dev");
677 if (!u)
678 return -ENOMEM;
679
680 v = strjoin(p, "/", found->d_name, "/../dev");
681 if (!v)
682 return -ENOMEM;
683
684 r = read_one_line_file(u, &a);
685 if (r < 0) {
686 log_debug_errno(r, "Failed to read %s: %m", u);
687 goto fallback;
688 }
689
690 r = read_one_line_file(v, &b);
691 if (r < 0) {
692 log_debug_errno(r, "Failed to read %s: %m", v);
693 goto fallback;
694 }
695
696 /* Check if the parent device is the same. If not, then the two backing devices are on
697 * different physical devices, and we don't support that. */
698 if (!streq(a, b))
699 goto fallback;
700 }
701
702 found = de;
703 }
704
705 if (!found)
706 goto fallback;
707
708 q = strjoina(p, "/", found->d_name, "/dev");
709
710 r = read_one_line_file(q, &t);
711 if (r == -ENOENT)
712 goto fallback;
713 if (r < 0)
714 return r;
715
716 if (sscanf(t, "%u:%u", &maj, &min) != 2)
717 return -EINVAL;
718
719 if (maj == 0)
720 goto fallback;
721
722 *dev = makedev(maj, min);
723 return 1;
724
725 fallback:
726 *dev = dt;
727 return 1;
728 }
729
730 static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
731 int r;
732
733 assert(key);
734
735 if (STR_IN_SET(key, "systemd.gpt_auto", "rd.systemd.gpt_auto")) {
736
737 r = value ? parse_boolean(value) : 1;
738 if (r < 0)
739 log_warning("Failed to parse gpt-auto switch \"%s\". Ignoring.", value);
740 else
741 arg_enabled = r;
742
743 } else if (streq(key, "root")) {
744
745 if (proc_cmdline_value_missing(key, value))
746 return 0;
747
748 /* Disable root disk logic if there's a root= value
749 * specified (unless it happens to be "gpt-auto") */
750
751 arg_root_enabled = streq(value, "gpt-auto");
752
753 } else if (streq(key, "roothash")) {
754
755 if (proc_cmdline_value_missing(key, value))
756 return 0;
757
758 /* Disable root disk logic if there's roothash= defined (i.e. verity enabled) */
759
760 arg_root_enabled = false;
761
762 } else if (streq(key, "rw") && !value)
763 arg_root_rw = true;
764 else if (streq(key, "ro") && !value)
765 arg_root_rw = false;
766
767 return 0;
768 }
769
770 #ifdef ENABLE_EFI
771 static int add_root_cryptsetup(void) {
772
773 /* If a device /dev/gpt-auto-root-luks appears, then make it pull in systemd-cryptsetup-root.service, which
774 * sets it up, and causes /dev/gpt-auto-root to appear which is all we are looking for. */
775
776 return add_cryptsetup("root", "/dev/gpt-auto-root-luks", true, false, NULL);
777 }
778 #endif
779
780 static int add_root_mount(void) {
781
782 #ifdef ENABLE_EFI
783 int r;
784
785 if (!is_efi_boot()) {
786 log_debug("Not a EFI boot, not creating root mount.");
787 return 0;
788 }
789
790 r = efi_loader_get_device_part_uuid(NULL);
791 if (r == -ENOENT) {
792 log_debug("EFI loader partition unknown, exiting.");
793 return 0;
794 } else if (r < 0)
795 return log_error_errno(r, "Failed to read ESP partition UUID: %m");
796
797 /* OK, we have an ESP partition, this is fantastic, so let's
798 * wait for a root device to show up. A udev rule will create
799 * the link for us under the right name. */
800
801 if (in_initrd()) {
802 r = generator_write_initrd_root_device_deps(arg_dest, "/dev/gpt-auto-root");
803 if (r < 0)
804 return 0;
805
806 r = add_root_cryptsetup();
807 if (r < 0)
808 return r;
809 }
810
811 return add_mount(
812 "root",
813 "/dev/gpt-auto-root",
814 in_initrd() ? "/sysroot" : "/",
815 NULL,
816 arg_root_rw,
817 NULL,
818 "Root Partition",
819 in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_LOCAL_FS_TARGET);
820 #else
821 return 0;
822 #endif
823 }
824
825 static int add_mounts(void) {
826 dev_t devno;
827 int r;
828
829 r = get_block_device_harder("/", &devno);
830 if (r < 0)
831 return log_error_errno(r, "Failed to determine block device of root file system: %m");
832 if (r == 0) {
833 r = get_block_device_harder("/usr", &devno);
834 if (r < 0)
835 return log_error_errno(r, "Failed to determine block device of /usr file system: %m");
836 if (r == 0) {
837 log_debug("Neither root nor /usr file system are on a (single) block device.");
838 return 0;
839 }
840 }
841
842 return enumerate_partitions(devno);
843 }
844
845 int main(int argc, char *argv[]) {
846 int r = 0, k;
847
848 if (argc > 1 && argc != 4) {
849 log_error("This program takes three or no arguments.");
850 return EXIT_FAILURE;
851 }
852
853 if (argc > 1)
854 arg_dest = argv[3];
855
856 log_set_target(LOG_TARGET_SAFE);
857 log_parse_environment();
858 log_open();
859
860 umask(0022);
861
862 if (detect_container() > 0) {
863 log_debug("In a container, exiting.");
864 return EXIT_SUCCESS;
865 }
866
867 r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
868 if (r < 0)
869 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
870
871 if (!arg_enabled) {
872 log_debug("Disabled, exiting.");
873 return EXIT_SUCCESS;
874 }
875
876 if (arg_root_enabled)
877 r = add_root_mount();
878
879 if (!in_initrd()) {
880 k = add_mounts();
881 if (k < 0)
882 r = k;
883 }
884
885 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
886 }