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