]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/gpt-auto-generator/gpt-auto-generator.c
Merge pull request #1690 from evverx/run-runtime-directory
[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 log_error_errno(errno, "Failed to allocate prober: %m");
306 return -errno;
307 }
308
309 blkid_probe_enable_superblocks(b, 1);
310 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
311
312 errno = 0;
313 r = blkid_do_safeprobe(b);
314 if (r == -2 || r == 1) /* no result or uncertain */
315 return 0;
316 else if (r != 0)
317 return log_error_errno(errno ?: EIO, "Failed to probe %s: %m", what);
318
319 /* add_mount is OK with fstype being NULL. */
320 (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
321
322 return add_mount(
323 id,
324 what,
325 where,
326 fstype,
327 rw,
328 NULL,
329 description,
330 post);
331 }
332
333 static int add_swap(const char *path) {
334 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
335 _cleanup_fclose_ FILE *f = NULL;
336 int r;
337
338 assert(path);
339
340 log_debug("Adding swap: %s", path);
341
342 r = unit_name_from_path(path, ".swap", &name);
343 if (r < 0)
344 return log_error_errno(r, "Failed to generate unit name: %m");
345
346 unit = strjoin(arg_dest, "/", name, NULL);
347 if (!unit)
348 return log_oom();
349
350 f = fopen(unit, "wxe");
351 if (!f)
352 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
353
354 fprintf(f,
355 "# Automatically generated by systemd-gpt-auto-generator\n\n"
356 "[Unit]\n"
357 "Description=Swap Partition\n"
358 "Documentation=man:systemd-gpt-auto-generator(8)\n\n"
359 "[Swap]\n"
360 "What=%s\n",
361 path);
362
363 r = fflush_and_check(f);
364 if (r < 0)
365 return log_error_errno(r, "Failed to write unit file %s: %m", unit);
366
367 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
368 if (!lnk)
369 return log_oom();
370
371 mkdir_parents_label(lnk, 0755);
372 if (symlink(unit, lnk) < 0)
373 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
374
375 return 0;
376 }
377
378 #ifdef ENABLE_EFI
379 static int add_automount(
380 const char *id,
381 const char *what,
382 const char *where,
383 const char *fstype,
384 bool rw,
385 const char *options,
386 const char *description,
387 usec_t timeout) {
388
389 _cleanup_free_ char *unit = NULL, *lnk = NULL;
390 _cleanup_free_ char *opt, *p = NULL;
391 _cleanup_fclose_ FILE *f = NULL;
392 int r;
393
394 assert(id);
395 assert(where);
396 assert(description);
397
398 if (options)
399 opt = strjoin(options, ",noauto", NULL);
400 else
401 opt = strdup("noauto");
402 if (!opt)
403 return log_oom();
404
405 r = add_mount(id,
406 what,
407 where,
408 fstype,
409 rw,
410 opt,
411 description,
412 NULL);
413 if (r < 0)
414 return r;
415
416 r = unit_name_from_path(where, ".automount", &unit);
417 if (r < 0)
418 return log_error_errno(r, "Failed to generate unit name: %m");
419
420 p = strjoin(arg_dest, "/", unit, NULL);
421 if (!p)
422 return log_oom();
423
424 f = fopen(p, "wxe");
425 if (!f)
426 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
427
428 fprintf(f,
429 "# Automatically generated by systemd-gpt-auto-generator\n\n"
430 "[Unit]\n"
431 "Description=%s\n"
432 "Documentation=man:systemd-gpt-auto-generator(8)\n"
433 "[Automount]\n"
434 "Where=%s\n"
435 "TimeoutIdleSec=%lld\n",
436 description,
437 where,
438 (unsigned long long)timeout / USEC_PER_SEC);
439
440 r = fflush_and_check(f);
441 if (r < 0)
442 return log_error_errno(r, "Failed to write unit file %s: %m", p);
443
444 lnk = strjoin(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".wants/", unit, NULL);
445 if (!lnk)
446 return log_oom();
447 mkdir_parents_label(lnk, 0755);
448
449 if (symlink(p, lnk) < 0)
450 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
451
452 return 0;
453 }
454
455 static int add_boot(const char *what) {
456 _cleanup_blkid_free_probe_ blkid_probe b = NULL;
457 const char *fstype = NULL, *uuid = NULL;
458 sd_id128_t id, type_id;
459 int r;
460
461 assert(what);
462
463 if (!is_efi_boot()) {
464 log_debug("Not an EFI boot, ignoring /boot.");
465 return 0;
466 }
467
468 if (in_initrd()) {
469 log_debug("In initrd, ignoring /boot.");
470 return 0;
471 }
472
473 if (detect_container() > 0) {
474 log_debug("In a container, ignoring /boot.");
475 return 0;
476 }
477
478 /* We create an .automount which is not overridden by the .mount from the fstab generator. */
479 if (fstab_is_mount_point("/boot")) {
480 log_debug("/boot specified in fstab, ignoring.");
481 return 0;
482 }
483
484 if (path_is_busy("/boot")) {
485 log_debug("/boot already populated, ignoring.");
486 return 0;
487 }
488
489 r = efi_loader_get_device_part_uuid(&id);
490 if (r == -ENOENT) {
491 log_debug("EFI loader partition unknown.");
492 return 0;
493 }
494
495 if (r < 0) {
496 log_error_errno(r, "Failed to read ESP partition UUID: %m");
497 return r;
498 }
499
500 errno = 0;
501 b = blkid_new_probe_from_filename(what);
502 if (!b) {
503 if (errno == 0)
504 return log_oom();
505 log_error_errno(errno, "Failed to allocate prober: %m");
506 return -errno;
507 }
508
509 blkid_probe_enable_partitions(b, 1);
510 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
511
512 errno = 0;
513 r = blkid_do_safeprobe(b);
514 if (r == -2 || r == 1) /* no result or uncertain */
515 return 0;
516 else if (r != 0)
517 return log_error_errno(errno ?: EIO, "Failed to probe %s: %m", what);
518
519 (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
520 if (!streq(fstype, "vfat")) {
521 log_debug("Partition for /boot is not a FAT filesystem, ignoring.");
522 return 0;
523 }
524
525 r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &uuid, NULL);
526 if (r != 0) {
527 log_debug_errno(r, "Partition for /boot does not have a UUID, ignoring. %m");
528 return 0;
529 }
530
531 if (sd_id128_from_string(uuid, &type_id) < 0) {
532 log_debug("Partition for /boot does not have a valid UUID, ignoring.");
533 return 0;
534 }
535
536 if (!sd_id128_equal(type_id, id)) {
537 log_debug("Partition for /boot does not appear to be the partition we are booted from.");
538 return 0;
539 }
540
541 r = add_automount("boot",
542 what,
543 "/boot",
544 "vfat",
545 true,
546 "umask=0077",
547 "EFI System Partition Automount",
548 120 * USEC_PER_SEC);
549
550 return r;
551 }
552 #else
553 static int add_boot(const char *what) {
554 return 0;
555 }
556 #endif
557
558 static int enumerate_partitions(dev_t devnum) {
559
560 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
561 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
562 _cleanup_blkid_free_probe_ blkid_probe b = NULL;
563 _cleanup_udev_unref_ struct udev *udev = NULL;
564 _cleanup_free_ char *boot = NULL, *home = NULL, *srv = NULL;
565 struct udev_list_entry *first, *item;
566 struct udev_device *parent = NULL;
567 const char *name, *node, *pttype, *devtype;
568 int boot_nr = -1, home_nr = -1, srv_nr = -1;
569 bool home_rw = true, srv_rw = true;
570 blkid_partlist pl;
571 int r, k;
572 dev_t pn;
573
574 udev = udev_new();
575 if (!udev)
576 return log_oom();
577
578 d = udev_device_new_from_devnum(udev, 'b', devnum);
579 if (!d)
580 return log_oom();
581
582 name = udev_device_get_devnode(d);
583 if (!name)
584 name = udev_device_get_syspath(d);
585 if (!name) {
586 log_debug("Device %u:%u does not have a name, ignoring.",
587 major(devnum), minor(devnum));
588 return 0;
589 }
590
591 parent = udev_device_get_parent(d);
592 if (!parent) {
593 log_debug("%s: not a partitioned device, ignoring.", name);
594 return 0;
595 }
596
597 /* Does it have a devtype? */
598 devtype = udev_device_get_devtype(parent);
599 if (!devtype) {
600 log_debug("%s: parent doesn't have a device type, ignoring.", name);
601 return 0;
602 }
603
604 /* Is this a disk or a partition? We only care for disks... */
605 if (!streq(devtype, "disk")) {
606 log_debug("%s: parent isn't a raw disk, ignoring.", name);
607 return 0;
608 }
609
610 /* Does it have a device node? */
611 node = udev_device_get_devnode(parent);
612 if (!node) {
613 log_debug("%s: parent device does not have device node, ignoring.", name);
614 return 0;
615 }
616
617 log_debug("%s: root device %s.", name, node);
618
619 pn = udev_device_get_devnum(parent);
620 if (major(pn) == 0)
621 return 0;
622
623 errno = 0;
624 b = blkid_new_probe_from_filename(node);
625 if (!b) {
626 if (errno == 0)
627 return log_oom();
628
629 return log_error_errno(errno, "%s: failed to allocate prober: %m", node);
630 }
631
632 blkid_probe_enable_partitions(b, 1);
633 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
634
635 errno = 0;
636 r = blkid_do_safeprobe(b);
637 if (r == 1)
638 return 0; /* no results */
639 else if (r == -2) {
640 log_warning("%s: probe gave ambiguous results, ignoring", node);
641 return 0;
642 } else if (r != 0)
643 return log_error_errno(errno ?: EIO, "%s: failed to probe: %m", node);
644
645 errno = 0;
646 r = blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
647 if (r != 0)
648 return log_error_errno(errno ?: EIO,
649 "%s: failed to determine partition table type: %m", node);
650
651 /* We only do this all for GPT... */
652 if (!streq_ptr(pttype, "gpt")) {
653 log_debug("%s: not a GPT partition table, ignoring.", node);
654 return 0;
655 }
656
657 errno = 0;
658 pl = blkid_probe_get_partitions(b);
659 if (!pl) {
660 if (errno == 0)
661 return log_oom();
662
663 return log_error_errno(errno, "%s: failed to list partitions: %m", node);
664 }
665
666 e = udev_enumerate_new(udev);
667 if (!e)
668 return log_oom();
669
670 r = udev_enumerate_add_match_parent(e, parent);
671 if (r < 0)
672 return log_oom();
673
674 r = udev_enumerate_add_match_subsystem(e, "block");
675 if (r < 0)
676 return log_oom();
677
678 r = udev_enumerate_scan_devices(e);
679 if (r < 0)
680 return log_error_errno(r, "%s: failed to enumerate partitions: %m", node);
681
682 first = udev_enumerate_get_list_entry(e);
683 udev_list_entry_foreach(item, first) {
684 _cleanup_udev_device_unref_ struct udev_device *q;
685 unsigned long long flags;
686 const char *stype, *subnode;
687 sd_id128_t type_id;
688 blkid_partition pp;
689 dev_t qn;
690 int nr;
691
692 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
693 if (!q)
694 continue;
695
696 qn = udev_device_get_devnum(q);
697 if (major(qn) == 0)
698 continue;
699
700 if (qn == devnum)
701 continue;
702
703 if (qn == pn)
704 continue;
705
706 subnode = udev_device_get_devnode(q);
707 if (!subnode)
708 continue;
709
710 pp = blkid_partlist_devno_to_partition(pl, qn);
711 if (!pp)
712 continue;
713
714 nr = blkid_partition_get_partno(pp);
715 if (nr < 0)
716 continue;
717
718 stype = blkid_partition_get_type_string(pp);
719 if (!stype)
720 continue;
721
722 if (sd_id128_from_string(stype, &type_id) < 0)
723 continue;
724
725 flags = blkid_partition_get_flags(pp);
726
727 if (sd_id128_equal(type_id, GPT_SWAP)) {
728
729 if (flags & GPT_FLAG_NO_AUTO)
730 continue;
731
732 if (flags & GPT_FLAG_READ_ONLY) {
733 log_debug("%s marked as read-only swap partition, which is bogus. Ignoring.", subnode);
734 continue;
735 }
736
737 k = add_swap(subnode);
738 if (k < 0)
739 r = k;
740
741 } else if (sd_id128_equal(type_id, GPT_ESP)) {
742
743 /* We only care for the first /boot partition */
744 if (boot && nr >= boot_nr)
745 continue;
746
747 /* Note that we do not honour the "no-auto"
748 * flag for the ESP, as it is often unset, to
749 * hide it from Windows. */
750
751 boot_nr = nr;
752
753 r = free_and_strdup(&boot, subnode);
754 if (r < 0)
755 return log_oom();
756
757 } else if (sd_id128_equal(type_id, GPT_HOME)) {
758
759 if (flags & GPT_FLAG_NO_AUTO)
760 continue;
761
762 /* We only care for the first /home partition */
763 if (home && nr >= home_nr)
764 continue;
765
766 home_nr = nr;
767 home_rw = !(flags & GPT_FLAG_READ_ONLY),
768
769 r = free_and_strdup(&home, subnode);
770 if (r < 0)
771 return log_oom();
772
773 } else if (sd_id128_equal(type_id, GPT_SRV)) {
774
775 if (flags & GPT_FLAG_NO_AUTO)
776 continue;
777
778 /* We only care for the first /srv partition */
779 if (srv && nr >= srv_nr)
780 continue;
781
782 srv_nr = nr;
783 srv_rw = !(flags & GPT_FLAG_READ_ONLY),
784
785 r = free_and_strdup(&srv, subnode);
786 if (r < 0)
787 return log_oom();
788 }
789 }
790
791 if (boot) {
792 k = add_boot(boot);
793 if (k < 0)
794 r = k;
795 }
796
797 if (home) {
798 k = probe_and_add_mount("home", home, "/home", home_rw, "Home Partition", SPECIAL_LOCAL_FS_TARGET);
799 if (k < 0)
800 r = k;
801 }
802
803 if (srv) {
804 k = probe_and_add_mount("srv", srv, "/srv", srv_rw, "Server Data Partition", SPECIAL_LOCAL_FS_TARGET);
805 if (k < 0)
806 r = k;
807 }
808
809 return r;
810 }
811
812 static int get_block_device(const char *path, dev_t *dev) {
813 struct stat st;
814 struct statfs sfs;
815
816 assert(path);
817 assert(dev);
818
819 /* Get's the block device directly backing a file system. If
820 * the block device is encrypted, returns the device mapper
821 * block device. */
822
823 if (lstat(path, &st))
824 return -errno;
825
826 if (major(st.st_dev) != 0) {
827 *dev = st.st_dev;
828 return 1;
829 }
830
831 if (statfs(path, &sfs) < 0)
832 return -errno;
833
834 if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
835 return btrfs_get_block_device(path, dev);
836
837 return 0;
838 }
839
840 static int get_block_device_harder(const char *path, dev_t *dev) {
841 _cleanup_closedir_ DIR *d = NULL;
842 _cleanup_free_ char *p = NULL, *t = NULL;
843 struct dirent *de, *found = NULL;
844 const char *q;
845 unsigned maj, min;
846 dev_t dt;
847 int r;
848
849 assert(path);
850 assert(dev);
851
852 /* Gets the backing block device for a file system, and
853 * handles LUKS encrypted file systems, looking for its
854 * immediate parent, if there is one. */
855
856 r = get_block_device(path, &dt);
857 if (r <= 0)
858 return r;
859
860 if (asprintf(&p, "/sys/dev/block/%u:%u/slaves", major(dt), minor(dt)) < 0)
861 return -ENOMEM;
862
863 d = opendir(p);
864 if (!d) {
865 if (errno == ENOENT)
866 goto fallback;
867
868 return -errno;
869 }
870
871 FOREACH_DIRENT_ALL(de, d, return -errno) {
872
873 if (STR_IN_SET(de->d_name, ".", ".."))
874 continue;
875
876 if (!IN_SET(de->d_type, DT_LNK, DT_UNKNOWN))
877 continue;
878
879 if (found) /* Don't try to support multiple backing block devices */
880 goto fallback;
881
882 found = de;
883 }
884
885 if (!found)
886 goto fallback;
887
888 q = strjoina(p, "/", found->d_name, "/dev");
889
890 r = read_one_line_file(q, &t);
891 if (r == -ENOENT)
892 goto fallback;
893 if (r < 0)
894 return r;
895
896 if (sscanf(t, "%u:%u", &maj, &min) != 2)
897 return -EINVAL;
898
899 if (maj == 0)
900 goto fallback;
901
902 *dev = makedev(maj, min);
903 return 1;
904
905 fallback:
906 *dev = dt;
907 return 1;
908 }
909
910 static int parse_proc_cmdline_item(const char *key, const char *value) {
911 int r;
912
913 assert(key);
914
915 if (STR_IN_SET(key, "systemd.gpt_auto", "rd.systemd.gpt_auto") && value) {
916
917 r = parse_boolean(value);
918 if (r < 0)
919 log_warning("Failed to parse gpt-auto switch \"%s\". Ignoring.", value);
920 else
921 arg_enabled = r;
922
923 } else if (streq(key, "root") && value) {
924
925 /* Disable root disk logic if there's a root= value
926 * specified (unless it happens to be "gpt-auto") */
927
928 arg_root_enabled = streq(value, "gpt-auto");
929
930 } else if (streq(key, "rw") && !value)
931 arg_root_rw = true;
932 else if (streq(key, "ro") && !value)
933 arg_root_rw = false;
934
935 return 0;
936 }
937
938 static int add_root_mount(void) {
939
940 #ifdef ENABLE_EFI
941 int r;
942
943 if (!is_efi_boot()) {
944 log_debug("Not a EFI boot, not creating root mount.");
945 return 0;
946 }
947
948 r = efi_loader_get_device_part_uuid(NULL);
949 if (r == -ENOENT) {
950 log_debug("EFI loader partition unknown, exiting.");
951 return 0;
952 } else if (r < 0)
953 return log_error_errno(r, "Failed to read ESP partition UUID: %m");
954
955 /* OK, we have an ESP partition, this is fantastic, so let's
956 * wait for a root device to show up. A udev rule will create
957 * the link for us under the right name. */
958
959 return add_mount(
960 "root",
961 "/dev/gpt-auto-root",
962 in_initrd() ? "/sysroot" : "/",
963 NULL,
964 arg_root_rw,
965 NULL,
966 "Root Partition",
967 in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_LOCAL_FS_TARGET);
968 #else
969 return 0;
970 #endif
971 }
972
973 static int add_mounts(void) {
974 dev_t devno;
975 int r;
976
977 r = get_block_device_harder("/", &devno);
978 if (r < 0)
979 return log_error_errno(r, "Failed to determine block device of root file system: %m");
980 else if (r == 0) {
981 r = get_block_device_harder("/usr", &devno);
982 if (r < 0)
983 return log_error_errno(r, "Failed to determine block device of /usr file system: %m");
984 else if (r == 0) {
985 log_debug("Neither root nor /usr file system are on a (single) block device.");
986 return 0;
987 }
988 }
989
990 return enumerate_partitions(devno);
991 }
992
993 int main(int argc, char *argv[]) {
994 int r = 0;
995
996 if (argc > 1 && argc != 4) {
997 log_error("This program takes three or no arguments.");
998 return EXIT_FAILURE;
999 }
1000
1001 if (argc > 1)
1002 arg_dest = argv[3];
1003
1004 log_set_target(LOG_TARGET_SAFE);
1005 log_parse_environment();
1006 log_open();
1007
1008 umask(0022);
1009
1010 if (detect_container() > 0) {
1011 log_debug("In a container, exiting.");
1012 return EXIT_SUCCESS;
1013 }
1014
1015 r = parse_proc_cmdline(parse_proc_cmdline_item);
1016 if (r < 0)
1017 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
1018
1019 if (!arg_enabled) {
1020 log_debug("Disabled, exiting.");
1021 return EXIT_SUCCESS;
1022 }
1023
1024 if (arg_root_enabled)
1025 r = add_root_mount();
1026
1027 if (!in_initrd()) {
1028 int k;
1029
1030 k = add_mounts();
1031 if (k < 0)
1032 r = k;
1033 }
1034
1035 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1036 }