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