]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/gpt-auto-generator/gpt-auto-generator.c
Merge pull request #2453 from poettering/journalctl-f
[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 <blkid/blkid.h>
23 #include <stdlib.h>
24 #include <sys/statfs.h>
25 #include <unistd.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 if (errno == 0)
647 return 0; /* No partition table found. */
648
649 return log_error_errno(errno, "%s: failed to determine partition table type: %m", node);
650 }
651
652 /* We only do this all for GPT... */
653 if (!streq_ptr(pttype, "gpt")) {
654 log_debug("%s: not a GPT partition table, ignoring.", node);
655 return 0;
656 }
657
658 errno = 0;
659 pl = blkid_probe_get_partitions(b);
660 if (!pl) {
661 if (errno == 0)
662 return log_oom();
663
664 return log_error_errno(errno, "%s: failed to list partitions: %m", node);
665 }
666
667 e = udev_enumerate_new(udev);
668 if (!e)
669 return log_oom();
670
671 r = udev_enumerate_add_match_parent(e, parent);
672 if (r < 0)
673 return log_oom();
674
675 r = udev_enumerate_add_match_subsystem(e, "block");
676 if (r < 0)
677 return log_oom();
678
679 r = udev_enumerate_scan_devices(e);
680 if (r < 0)
681 return log_error_errno(r, "%s: failed to enumerate partitions: %m", node);
682
683 first = udev_enumerate_get_list_entry(e);
684 udev_list_entry_foreach(item, first) {
685 _cleanup_udev_device_unref_ struct udev_device *q;
686 unsigned long long flags;
687 const char *stype, *subnode;
688 sd_id128_t type_id;
689 blkid_partition pp;
690 dev_t qn;
691 int nr;
692
693 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
694 if (!q)
695 continue;
696
697 qn = udev_device_get_devnum(q);
698 if (major(qn) == 0)
699 continue;
700
701 if (qn == devnum)
702 continue;
703
704 if (qn == pn)
705 continue;
706
707 subnode = udev_device_get_devnode(q);
708 if (!subnode)
709 continue;
710
711 pp = blkid_partlist_devno_to_partition(pl, qn);
712 if (!pp)
713 continue;
714
715 nr = blkid_partition_get_partno(pp);
716 if (nr < 0)
717 continue;
718
719 stype = blkid_partition_get_type_string(pp);
720 if (!stype)
721 continue;
722
723 if (sd_id128_from_string(stype, &type_id) < 0)
724 continue;
725
726 flags = blkid_partition_get_flags(pp);
727
728 if (sd_id128_equal(type_id, GPT_SWAP)) {
729
730 if (flags & GPT_FLAG_NO_AUTO)
731 continue;
732
733 if (flags & GPT_FLAG_READ_ONLY) {
734 log_debug("%s marked as read-only swap partition, which is bogus. Ignoring.", subnode);
735 continue;
736 }
737
738 k = add_swap(subnode);
739 if (k < 0)
740 r = k;
741
742 } else if (sd_id128_equal(type_id, GPT_ESP)) {
743
744 /* We only care for the first /boot partition */
745 if (boot && nr >= boot_nr)
746 continue;
747
748 /* Note that we do not honour the "no-auto"
749 * flag for the ESP, as it is often unset, to
750 * hide it from Windows. */
751
752 boot_nr = nr;
753
754 r = free_and_strdup(&boot, subnode);
755 if (r < 0)
756 return log_oom();
757
758 } else if (sd_id128_equal(type_id, GPT_HOME)) {
759
760 if (flags & GPT_FLAG_NO_AUTO)
761 continue;
762
763 /* We only care for the first /home partition */
764 if (home && nr >= home_nr)
765 continue;
766
767 home_nr = nr;
768 home_rw = !(flags & GPT_FLAG_READ_ONLY),
769
770 r = free_and_strdup(&home, subnode);
771 if (r < 0)
772 return log_oom();
773
774 } else if (sd_id128_equal(type_id, GPT_SRV)) {
775
776 if (flags & GPT_FLAG_NO_AUTO)
777 continue;
778
779 /* We only care for the first /srv partition */
780 if (srv && nr >= srv_nr)
781 continue;
782
783 srv_nr = nr;
784 srv_rw = !(flags & GPT_FLAG_READ_ONLY),
785
786 r = free_and_strdup(&srv, subnode);
787 if (r < 0)
788 return log_oom();
789 }
790 }
791
792 if (boot) {
793 k = add_boot(boot);
794 if (k < 0)
795 r = k;
796 }
797
798 if (home) {
799 k = probe_and_add_mount("home", home, "/home", home_rw, "Home Partition", SPECIAL_LOCAL_FS_TARGET);
800 if (k < 0)
801 r = k;
802 }
803
804 if (srv) {
805 k = probe_and_add_mount("srv", srv, "/srv", srv_rw, "Server Data Partition", SPECIAL_LOCAL_FS_TARGET);
806 if (k < 0)
807 r = k;
808 }
809
810 return r;
811 }
812
813 static int get_block_device(const char *path, dev_t *dev) {
814 struct stat st;
815 struct statfs sfs;
816
817 assert(path);
818 assert(dev);
819
820 /* Get's the block device directly backing a file system. If
821 * the block device is encrypted, returns the device mapper
822 * block device. */
823
824 if (lstat(path, &st))
825 return -errno;
826
827 if (major(st.st_dev) != 0) {
828 *dev = st.st_dev;
829 return 1;
830 }
831
832 if (statfs(path, &sfs) < 0)
833 return -errno;
834
835 if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
836 return btrfs_get_block_device(path, dev);
837
838 return 0;
839 }
840
841 static int get_block_device_harder(const char *path, dev_t *dev) {
842 _cleanup_closedir_ DIR *d = NULL;
843 _cleanup_free_ char *p = NULL, *t = NULL;
844 struct dirent *de, *found = NULL;
845 const char *q;
846 unsigned maj, min;
847 dev_t dt;
848 int r;
849
850 assert(path);
851 assert(dev);
852
853 /* Gets the backing block device for a file system, and
854 * handles LUKS encrypted file systems, looking for its
855 * immediate parent, if there is one. */
856
857 r = get_block_device(path, &dt);
858 if (r <= 0)
859 return r;
860
861 if (asprintf(&p, "/sys/dev/block/%u:%u/slaves", major(dt), minor(dt)) < 0)
862 return -ENOMEM;
863
864 d = opendir(p);
865 if (!d) {
866 if (errno == ENOENT)
867 goto fallback;
868
869 return -errno;
870 }
871
872 FOREACH_DIRENT_ALL(de, d, return -errno) {
873
874 if (STR_IN_SET(de->d_name, ".", ".."))
875 continue;
876
877 if (!IN_SET(de->d_type, DT_LNK, DT_UNKNOWN))
878 continue;
879
880 if (found) /* Don't try to support multiple backing block devices */
881 goto fallback;
882
883 found = de;
884 }
885
886 if (!found)
887 goto fallback;
888
889 q = strjoina(p, "/", found->d_name, "/dev");
890
891 r = read_one_line_file(q, &t);
892 if (r == -ENOENT)
893 goto fallback;
894 if (r < 0)
895 return r;
896
897 if (sscanf(t, "%u:%u", &maj, &min) != 2)
898 return -EINVAL;
899
900 if (maj == 0)
901 goto fallback;
902
903 *dev = makedev(maj, min);
904 return 1;
905
906 fallback:
907 *dev = dt;
908 return 1;
909 }
910
911 static int parse_proc_cmdline_item(const char *key, const char *value) {
912 int r;
913
914 assert(key);
915
916 if (STR_IN_SET(key, "systemd.gpt_auto", "rd.systemd.gpt_auto") && value) {
917
918 r = parse_boolean(value);
919 if (r < 0)
920 log_warning("Failed to parse gpt-auto switch \"%s\". Ignoring.", value);
921 else
922 arg_enabled = r;
923
924 } else if (streq(key, "root") && value) {
925
926 /* Disable root disk logic if there's a root= value
927 * specified (unless it happens to be "gpt-auto") */
928
929 arg_root_enabled = streq(value, "gpt-auto");
930
931 } else if (streq(key, "rw") && !value)
932 arg_root_rw = true;
933 else if (streq(key, "ro") && !value)
934 arg_root_rw = false;
935
936 return 0;
937 }
938
939 static int add_root_mount(void) {
940
941 #ifdef ENABLE_EFI
942 int r;
943
944 if (!is_efi_boot()) {
945 log_debug("Not a EFI boot, not creating root mount.");
946 return 0;
947 }
948
949 r = efi_loader_get_device_part_uuid(NULL);
950 if (r == -ENOENT) {
951 log_debug("EFI loader partition unknown, exiting.");
952 return 0;
953 } else if (r < 0)
954 return log_error_errno(r, "Failed to read ESP partition UUID: %m");
955
956 /* OK, we have an ESP partition, this is fantastic, so let's
957 * wait for a root device to show up. A udev rule will create
958 * the link for us under the right name. */
959
960 return add_mount(
961 "root",
962 "/dev/gpt-auto-root",
963 in_initrd() ? "/sysroot" : "/",
964 NULL,
965 arg_root_rw,
966 NULL,
967 "Root Partition",
968 in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_LOCAL_FS_TARGET);
969 #else
970 return 0;
971 #endif
972 }
973
974 static int add_mounts(void) {
975 dev_t devno;
976 int r;
977
978 r = get_block_device_harder("/", &devno);
979 if (r < 0)
980 return log_error_errno(r, "Failed to determine block device of root file system: %m");
981 else if (r == 0) {
982 r = get_block_device_harder("/usr", &devno);
983 if (r < 0)
984 return log_error_errno(r, "Failed to determine block device of /usr file system: %m");
985 else if (r == 0) {
986 log_debug("Neither root nor /usr file system are on a (single) block device.");
987 return 0;
988 }
989 }
990
991 return enumerate_partitions(devno);
992 }
993
994 int main(int argc, char *argv[]) {
995 int r = 0;
996
997 if (argc > 1 && argc != 4) {
998 log_error("This program takes three or no arguments.");
999 return EXIT_FAILURE;
1000 }
1001
1002 if (argc > 1)
1003 arg_dest = argv[3];
1004
1005 log_set_target(LOG_TARGET_SAFE);
1006 log_parse_environment();
1007 log_open();
1008
1009 umask(0022);
1010
1011 if (detect_container() > 0) {
1012 log_debug("In a container, exiting.");
1013 return EXIT_SUCCESS;
1014 }
1015
1016 r = parse_proc_cmdline(parse_proc_cmdline_item);
1017 if (r < 0)
1018 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
1019
1020 if (!arg_enabled) {
1021 log_debug("Disabled, exiting.");
1022 return EXIT_SUCCESS;
1023 }
1024
1025 if (arg_root_enabled)
1026 r = add_root_mount();
1027
1028 if (!in_initrd()) {
1029 int k;
1030
1031 k = add_mounts();
1032 if (k < 0)
1033 r = k;
1034 }
1035
1036 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1037 }