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