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