]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/gpt-auto-generator/gpt-auto-generator.c
Merge pull request #977 from richardmaw-codethink/machinectl-userns-login-v2
[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 r = fflush_and_check(f);
101 if (r < 0)
102 return log_error_errno(r, "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 r = fflush_and_check(f);
227 if (r < 0)
228 return log_error_errno(r, "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 bool path_is_busy(const char *where) {
244 int r;
245
246 /* already a mountpoint; generators run during reload */
247 r = path_is_mount_point(where, AT_SYMLINK_FOLLOW);
248 if (r > 0)
249 return false;
250
251 /* the directory might not exist on a stateless system */
252 if (r == -ENOENT)
253 return false;
254
255 if (r < 0)
256 return true;
257
258 /* not a mountpoint but it contains files */
259 if (dir_is_empty(where) <= 0)
260 return true;
261
262 return false;
263 }
264
265 static int probe_and_add_mount(
266 const char *id,
267 const char *what,
268 const char *where,
269 bool rw,
270 const char *description,
271 const char *post) {
272
273 _cleanup_blkid_free_probe_ blkid_probe b = NULL;
274 const char *fstype = NULL;
275 int r;
276
277 assert(id);
278 assert(what);
279 assert(where);
280 assert(description);
281
282 if (path_is_busy(where)) {
283 log_debug("%s already populated, ignoring.", where);
284 return 0;
285 }
286
287 /* Let's check the partition type here, so that we know
288 * whether to do LUKS magic. */
289
290 errno = 0;
291 b = blkid_new_probe_from_filename(what);
292 if (!b) {
293 if (errno == 0)
294 return log_oom();
295 log_error_errno(errno, "Failed to allocate prober: %m");
296 return -errno;
297 }
298
299 blkid_probe_enable_superblocks(b, 1);
300 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
301
302 errno = 0;
303 r = blkid_do_safeprobe(b);
304 if (r == -2 || r == 1) /* no result or uncertain */
305 return 0;
306 else if (r != 0)
307 return log_error_errno(errno ?: EIO, "Failed to probe %s: %m", what);
308
309 /* add_mount is OK with fstype being NULL. */
310 (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
311
312 return add_mount(
313 id,
314 what,
315 where,
316 fstype,
317 rw,
318 NULL,
319 description,
320 post);
321 }
322
323 static int add_swap(const char *path) {
324 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
325 _cleanup_fclose_ FILE *f = NULL;
326 int r;
327
328 assert(path);
329
330 log_debug("Adding swap: %s", path);
331
332 r = unit_name_from_path(path, ".swap", &name);
333 if (r < 0)
334 return log_error_errno(r, "Failed to generate unit name: %m");
335
336 unit = strjoin(arg_dest, "/", name, NULL);
337 if (!unit)
338 return log_oom();
339
340 f = fopen(unit, "wxe");
341 if (!f)
342 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
343
344 fprintf(f,
345 "# Automatically generated by systemd-gpt-auto-generator\n\n"
346 "[Unit]\n"
347 "Description=Swap Partition\n"
348 "Documentation=man:systemd-gpt-auto-generator(8)\n\n"
349 "[Swap]\n"
350 "What=%s\n",
351 path);
352
353 r = fflush_and_check(f);
354 if (r < 0)
355 return log_error_errno(r, "Failed to write unit file %s: %m", unit);
356
357 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
358 if (!lnk)
359 return log_oom();
360
361 mkdir_parents_label(lnk, 0755);
362 if (symlink(unit, lnk) < 0)
363 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
364
365 return 0;
366 }
367
368 #ifdef ENABLE_EFI
369 static int add_automount(
370 const char *id,
371 const char *what,
372 const char *where,
373 const char *fstype,
374 bool rw,
375 const char *options,
376 const char *description,
377 usec_t timeout) {
378
379 _cleanup_free_ char *unit = NULL, *lnk = NULL;
380 _cleanup_free_ char *opt, *p = NULL;
381 _cleanup_fclose_ FILE *f = NULL;
382 int r;
383
384 assert(id);
385 assert(where);
386 assert(description);
387
388 if (options)
389 opt = strjoin(options, ",noauto", NULL);
390 else
391 opt = strdup("noauto");
392 if (!opt)
393 return log_oom();
394
395 r = add_mount(id,
396 what,
397 where,
398 fstype,
399 rw,
400 opt,
401 description,
402 NULL);
403 if (r < 0)
404 return r;
405
406 r = unit_name_from_path(where, ".automount", &unit);
407 if (r < 0)
408 return log_error_errno(r, "Failed to generate unit name: %m");
409
410 p = strjoin(arg_dest, "/", unit, NULL);
411 if (!p)
412 return log_oom();
413
414 f = fopen(p, "wxe");
415 if (!f)
416 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
417
418 fprintf(f,
419 "# Automatically generated by systemd-gpt-auto-generator\n\n"
420 "[Unit]\n"
421 "Description=%s\n"
422 "Documentation=man:systemd-gpt-auto-generator(8)\n"
423 "[Automount]\n"
424 "Where=%s\n"
425 "TimeoutIdleSec=%lld\n",
426 description,
427 where,
428 (unsigned long long)timeout / USEC_PER_SEC);
429
430 r = fflush_and_check(f);
431 if (r < 0)
432 return log_error_errno(r, "Failed to write unit file %s: %m", p);
433
434 lnk = strjoin(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".wants/", unit, NULL);
435 if (!lnk)
436 return log_oom();
437 mkdir_parents_label(lnk, 0755);
438
439 if (symlink(p, lnk) < 0)
440 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
441
442 return 0;
443 }
444
445 static int add_boot(const char *what) {
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 }
536 #else
537 static int add_boot(const char *what) {
538 return 0;
539 }
540 #endif
541
542 static int enumerate_partitions(dev_t devnum) {
543
544 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
545 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
546 _cleanup_blkid_free_probe_ blkid_probe b = NULL;
547 _cleanup_udev_unref_ struct udev *udev = NULL;
548 _cleanup_free_ char *boot = NULL, *home = NULL, *srv = NULL;
549 struct udev_list_entry *first, *item;
550 struct udev_device *parent = NULL;
551 const char *name, *node, *pttype, *devtype;
552 int boot_nr = -1, home_nr = -1, srv_nr = -1;
553 bool home_rw = true, srv_rw = true;
554 blkid_partlist pl;
555 int r, k;
556 dev_t pn;
557
558 udev = udev_new();
559 if (!udev)
560 return log_oom();
561
562 d = udev_device_new_from_devnum(udev, 'b', devnum);
563 if (!d)
564 return log_oom();
565
566 name = udev_device_get_devnode(d);
567 if (!name)
568 name = udev_device_get_syspath(d);
569 if (!name) {
570 log_debug("Device %u:%u does not have a name, ignoring.",
571 major(devnum), minor(devnum));
572 return 0;
573 }
574
575 parent = udev_device_get_parent(d);
576 if (!parent) {
577 log_debug("%s: not a partitioned device, ignoring.", name);
578 return 0;
579 }
580
581 /* Does it have a devtype? */
582 devtype = udev_device_get_devtype(parent);
583 if (!devtype) {
584 log_debug("%s: parent doesn't have a device type, ignoring.", name);
585 return 0;
586 }
587
588 /* Is this a disk or a partition? We only care for disks... */
589 if (!streq(devtype, "disk")) {
590 log_debug("%s: parent isn't a raw disk, ignoring.", name);
591 return 0;
592 }
593
594 /* Does it have a device node? */
595 node = udev_device_get_devnode(parent);
596 if (!node) {
597 log_debug("%s: parent device does not have device node, ignoring.", name);
598 return 0;
599 }
600
601 log_debug("%s: root device %s.", name, node);
602
603 pn = udev_device_get_devnum(parent);
604 if (major(pn) == 0)
605 return 0;
606
607 errno = 0;
608 b = blkid_new_probe_from_filename(node);
609 if (!b) {
610 if (errno == 0)
611 return log_oom();
612
613 return log_error_errno(errno, "%s: failed to allocate prober: %m", node);
614 }
615
616 blkid_probe_enable_partitions(b, 1);
617 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
618
619 errno = 0;
620 r = blkid_do_safeprobe(b);
621 if (r == 1)
622 return 0; /* no results */
623 else if (r == -2) {
624 log_warning("%s: probe gave ambiguous results, ignoring", node);
625 return 0;
626 } else if (r != 0)
627 return log_error_errno(errno ?: EIO, "%s: failed to probe: %m", node);
628
629 errno = 0;
630 r = blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
631 if (r != 0)
632 return log_error_errno(errno ?: EIO,
633 "%s: failed to determine partition table type: %m", node);
634
635 /* We only do this all for GPT... */
636 if (!streq_ptr(pttype, "gpt")) {
637 log_debug("%s: not a GPT partition table, ignoring.", node);
638 return 0;
639 }
640
641 errno = 0;
642 pl = blkid_probe_get_partitions(b);
643 if (!pl) {
644 if (errno == 0)
645 return log_oom();
646
647 return log_error_errno(errno, "%s: failed to list partitions: %m", node);
648 }
649
650 e = udev_enumerate_new(udev);
651 if (!e)
652 return log_oom();
653
654 r = udev_enumerate_add_match_parent(e, parent);
655 if (r < 0)
656 return log_oom();
657
658 r = udev_enumerate_add_match_subsystem(e, "block");
659 if (r < 0)
660 return log_oom();
661
662 r = udev_enumerate_scan_devices(e);
663 if (r < 0)
664 return log_error_errno(r, "%s: failed to enumerate partitions: %m", node);
665
666 first = udev_enumerate_get_list_entry(e);
667 udev_list_entry_foreach(item, first) {
668 _cleanup_udev_device_unref_ struct udev_device *q;
669 const char *stype, *subnode;
670 sd_id128_t type_id;
671 blkid_partition pp;
672 dev_t qn;
673 int nr;
674
675 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
676 if (!q)
677 continue;
678
679 qn = udev_device_get_devnum(q);
680 if (major(qn) == 0)
681 continue;
682
683 if (qn == devnum)
684 continue;
685
686 if (qn == pn)
687 continue;
688
689 subnode = udev_device_get_devnode(q);
690 if (!subnode)
691 continue;
692
693 pp = blkid_partlist_devno_to_partition(pl, qn);
694 if (!pp)
695 continue;
696
697 nr = blkid_partition_get_partno(pp);
698 if (nr < 0)
699 continue;
700
701 stype = blkid_partition_get_type_string(pp);
702 if (!stype)
703 continue;
704
705 if (sd_id128_from_string(stype, &type_id) < 0)
706 continue;
707
708 if (sd_id128_equal(type_id, GPT_SWAP)) {
709 unsigned long long flags;
710
711 flags = blkid_partition_get_flags(pp);
712 if (flags & GPT_FLAG_NO_AUTO)
713 continue;
714
715 if (flags & GPT_FLAG_READ_ONLY) {
716 log_debug("%s marked as read-only swap partition, which is bogus. Ignoring.", subnode);
717 continue;
718 }
719
720 k = add_swap(subnode);
721 if (k < 0)
722 r = k;
723
724 } else if (sd_id128_equal(type_id, GPT_ESP)) {
725
726 /* We only care for the first /boot partition */
727 if (boot && nr >= boot_nr)
728 continue;
729
730 boot_nr = nr;
731
732 r = free_and_strdup(&boot, subnode);
733 if (r < 0)
734 return log_oom();
735
736 } else if (sd_id128_equal(type_id, GPT_HOME)) {
737 unsigned long long flags;
738
739 flags = blkid_partition_get_flags(pp);
740 if (flags & GPT_FLAG_NO_AUTO)
741 continue;
742
743 /* We only care for the first /home partition */
744 if (home && nr >= home_nr)
745 continue;
746
747 home_nr = nr;
748 home_rw = !(flags & GPT_FLAG_READ_ONLY),
749
750 r = free_and_strdup(&home, subnode);
751 if (r < 0)
752 return log_oom();
753
754 } else if (sd_id128_equal(type_id, GPT_SRV)) {
755 unsigned long long flags;
756
757 flags = blkid_partition_get_flags(pp);
758 if (flags & GPT_FLAG_NO_AUTO)
759 continue;
760
761 /* We only care for the first /srv partition */
762 if (srv && nr >= srv_nr)
763 continue;
764
765 srv_nr = nr;
766 srv_rw = !(flags & GPT_FLAG_READ_ONLY),
767
768 r = free_and_strdup(&srv, subnode);
769 if (r < 0)
770 return log_oom();
771 }
772 }
773
774 if (boot) {
775 k = add_boot(boot);
776 if (k < 0)
777 r = k;
778 }
779
780 if (home) {
781 k = probe_and_add_mount("home", home, "/home", home_rw, "Home Partition", SPECIAL_LOCAL_FS_TARGET);
782 if (k < 0)
783 r = k;
784 }
785
786 if (srv) {
787 k = probe_and_add_mount("srv", srv, "/srv", srv_rw, "Server Data Partition", SPECIAL_LOCAL_FS_TARGET);
788 if (k < 0)
789 r = k;
790 }
791
792 return r;
793 }
794
795 static int get_block_device(const char *path, dev_t *dev) {
796 struct stat st;
797 struct statfs sfs;
798
799 assert(path);
800 assert(dev);
801
802 if (lstat(path, &st))
803 return -errno;
804
805 if (major(st.st_dev) != 0) {
806 *dev = st.st_dev;
807 return 1;
808 }
809
810 if (statfs(path, &sfs) < 0)
811 return -errno;
812
813 if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
814 return btrfs_get_block_device(path, dev);
815
816 return 0;
817 }
818
819 static int parse_proc_cmdline_item(const char *key, const char *value) {
820 int r;
821
822 assert(key);
823
824 if (STR_IN_SET(key, "systemd.gpt_auto", "rd.systemd.gpt_auto") && value) {
825
826 r = parse_boolean(value);
827 if (r < 0)
828 log_warning("Failed to parse gpt-auto switch \"%s\". Ignoring.", value);
829 else
830 arg_enabled = r;
831
832 } else if (streq(key, "root") && value) {
833
834 /* Disable root disk logic if there's a root= value
835 * specified (unless it happens to be "gpt-auto") */
836
837 arg_root_enabled = streq(value, "gpt-auto");
838
839 } else if (streq(key, "rw") && !value)
840 arg_root_rw = true;
841 else if (streq(key, "ro") && !value)
842 arg_root_rw = false;
843
844 return 0;
845 }
846
847 static int add_root_mount(void) {
848
849 #ifdef ENABLE_EFI
850 int r;
851
852 if (!is_efi_boot()) {
853 log_debug("Not a EFI boot, not creating root mount.");
854 return 0;
855 }
856
857 r = efi_loader_get_device_part_uuid(NULL);
858 if (r == -ENOENT) {
859 log_debug("EFI loader partition unknown, exiting.");
860 return 0;
861 } else if (r < 0)
862 return log_error_errno(r, "Failed to read ESP partition UUID: %m");
863
864 /* OK, we have an ESP partition, this is fantastic, so let's
865 * wait for a root device to show up. A udev rule will create
866 * the link for us under the right name. */
867
868 return add_mount(
869 "root",
870 "/dev/gpt-auto-root",
871 in_initrd() ? "/sysroot" : "/",
872 NULL,
873 arg_root_rw,
874 NULL,
875 "Root Partition",
876 in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_LOCAL_FS_TARGET);
877 #else
878 return 0;
879 #endif
880 }
881
882 static int add_mounts(void) {
883 dev_t devno;
884 int r;
885
886 r = get_block_device("/", &devno);
887 if (r < 0)
888 return log_error_errno(r, "Failed to determine block device of root file system: %m");
889 else if (r == 0) {
890 r = get_block_device("/usr", &devno);
891 if (r < 0)
892 return log_error_errno(r, "Failed to determine block device of /usr file system: %m");
893 else if (r == 0) {
894 log_debug("Neither root nor /usr file system are on a (single) block device.");
895 return 0;
896 }
897 }
898
899 return enumerate_partitions(devno);
900 }
901
902 int main(int argc, char *argv[]) {
903 int r = 0;
904
905 if (argc > 1 && argc != 4) {
906 log_error("This program takes three or no arguments.");
907 return EXIT_FAILURE;
908 }
909
910 if (argc > 1)
911 arg_dest = argv[3];
912
913 log_set_target(LOG_TARGET_SAFE);
914 log_parse_environment();
915 log_open();
916
917 umask(0022);
918
919 if (detect_container(NULL) > 0) {
920 log_debug("In a container, exiting.");
921 return EXIT_SUCCESS;
922 }
923
924 r = parse_proc_cmdline(parse_proc_cmdline_item);
925 if (r < 0)
926 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
927
928 if (!arg_enabled) {
929 log_debug("Disabled, exiting.");
930 return EXIT_SUCCESS;
931 }
932
933 if (arg_root_enabled)
934 r = add_root_mount();
935
936 if (!in_initrd()) {
937 int k;
938
939 k = add_mounts();
940 if (k < 0)
941 r = k;
942 }
943
944 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
945 }