]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/gpt-auto-generator/gpt-auto-generator.c
tree-wide: make parse_proc_cmdline() strip "rd." prefix automatically
[thirdparty/systemd.git] / src / gpt-auto-generator / gpt-auto-generator.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2013 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <blkid/blkid.h>
21 #include <stdlib.h>
22 #include <sys/statfs.h>
23 #include <unistd.h>
24
25 #include "libudev.h"
26 #include "sd-id128.h"
27
28 #include "alloc-util.h"
29 #include "blkid-util.h"
30 #include "btrfs-util.h"
31 #include "dirent-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 "mount-util.h"
41 #include "parse-util.h"
42 #include "path-util.h"
43 #include "proc-cmdline.h"
44 #include "special.h"
45 #include "stat-util.h"
46 #include "string-util.h"
47 #include "udev-util.h"
48 #include "unit-name.h"
49 #include "util.h"
50 #include "virt.h"
51
52 static const char *arg_dest = "/tmp";
53 static bool arg_enabled = true;
54 static bool arg_root_enabled = true;
55 static bool arg_root_rw = false;
56
57 static int add_cryptsetup(const char *id, const char *what, bool rw, char **device) {
58 _cleanup_free_ char *e = NULL, *n = NULL, *p = NULL, *d = NULL, *to = NULL;
59 _cleanup_fclose_ FILE *f = NULL;
60 char *from, *ret;
61 int r;
62
63 assert(id);
64 assert(what);
65 assert(device);
66
67 r = unit_name_from_path(what, ".device", &d);
68 if (r < 0)
69 return log_error_errno(r, "Failed to generate unit name: %m");
70
71 e = unit_name_escape(id);
72 if (!e)
73 return log_oom();
74
75 r = unit_name_build("systemd-cryptsetup", e, ".service", &n);
76 if (r < 0)
77 return log_error_errno(r, "Failed to generate unit name: %m");
78
79 p = strjoin(arg_dest, "/", n, NULL);
80 if (!p)
81 return log_oom();
82
83 f = fopen(p, "wxe");
84 if (!f)
85 return log_error_errno(errno, "Failed to create unit file %s: %m", p);
86
87 fprintf(f,
88 "# Automatically generated by systemd-gpt-auto-generator\n\n"
89 "[Unit]\n"
90 "Description=Cryptography Setup for %%I\n"
91 "Documentation=man:systemd-gpt-auto-generator(8) man:systemd-cryptsetup@.service(8)\n"
92 "DefaultDependencies=no\n"
93 "Conflicts=umount.target\n"
94 "BindsTo=dev-mapper-%%i.device %s\n"
95 "Before=umount.target cryptsetup.target\n"
96 "After=%s\n"
97 "IgnoreOnIsolate=true\n"
98 "[Service]\n"
99 "Type=oneshot\n"
100 "RemainAfterExit=yes\n"
101 "TimeoutSec=0\n" /* the binary handles timeouts anyway */
102 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '' '%s'\n"
103 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
104 d, d,
105 id, what, rw ? "" : "read-only",
106 id);
107
108 r = fflush_and_check(f);
109 if (r < 0)
110 return log_error_errno(r, "Failed to write file %s: %m", p);
111
112 from = strjoina("../", n);
113
114 to = strjoin(arg_dest, "/", d, ".wants/", n, NULL);
115 if (!to)
116 return log_oom();
117
118 mkdir_parents_label(to, 0755);
119 if (symlink(from, to) < 0)
120 return log_error_errno(errno, "Failed to create symlink %s: %m", to);
121
122 free(to);
123 to = strjoin(arg_dest, "/cryptsetup.target.requires/", n, NULL);
124 if (!to)
125 return log_oom();
126
127 mkdir_parents_label(to, 0755);
128 if (symlink(from, to) < 0)
129 return log_error_errno(errno, "Failed to create symlink %s: %m", to);
130
131 free(to);
132 to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n, NULL);
133 if (!to)
134 return log_oom();
135
136 mkdir_parents_label(to, 0755);
137 if (symlink(from, to) < 0)
138 return log_error_errno(errno, "Failed to create symlink %s: %m", to);
139
140 free(p);
141 p = strjoin(arg_dest, "/dev-mapper-", e, ".device.d/50-job-timeout-sec-0.conf", NULL);
142 if (!p)
143 return log_oom();
144
145 mkdir_parents_label(p, 0755);
146 r = write_string_file(p,
147 "# Automatically generated by systemd-gpt-auto-generator\n\n"
148 "[Unit]\n"
149 "JobTimeoutSec=0\n",
150 WRITE_STRING_FILE_CREATE); /* the binary handles timeouts anyway */
151 if (r < 0)
152 return log_error_errno(r, "Failed to write device drop-in: %m");
153
154 ret = strappend("/dev/mapper/", id);
155 if (!ret)
156 return log_oom();
157
158 *device = ret;
159 return 0;
160 }
161
162 static int add_mount(
163 const char *id,
164 const char *what,
165 const char *where,
166 const char *fstype,
167 bool rw,
168 const char *options,
169 const char *description,
170 const char *post) {
171
172 _cleanup_free_ char *unit = NULL, *lnk = NULL, *crypto_what = NULL, *p = NULL;
173 _cleanup_fclose_ FILE *f = NULL;
174 int r;
175
176 assert(id);
177 assert(what);
178 assert(where);
179 assert(description);
180
181 log_debug("Adding %s: %s %s", where, what, strna(fstype));
182
183 if (streq_ptr(fstype, "crypto_LUKS")) {
184
185 r = add_cryptsetup(id, what, rw, &crypto_what);
186 if (r < 0)
187 return r;
188
189 what = crypto_what;
190 fstype = NULL;
191 }
192
193 r = unit_name_from_path(where, ".mount", &unit);
194 if (r < 0)
195 return log_error_errno(r, "Failed to generate unit name: %m");
196
197 p = strjoin(arg_dest, "/", unit, NULL);
198 if (!p)
199 return log_oom();
200
201 f = fopen(p, "wxe");
202 if (!f)
203 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
204
205 fprintf(f,
206 "# Automatically generated by systemd-gpt-auto-generator\n\n"
207 "[Unit]\n"
208 "Description=%s\n"
209 "Documentation=man:systemd-gpt-auto-generator(8)\n",
210 description);
211
212 if (post)
213 fprintf(f, "Before=%s\n", post);
214
215 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
216 if (r < 0)
217 return r;
218
219 fprintf(f,
220 "\n"
221 "[Mount]\n"
222 "What=%s\n"
223 "Where=%s\n",
224 what, where);
225
226 if (fstype)
227 fprintf(f, "Type=%s\n", fstype);
228
229 if (options)
230 fprintf(f, "Options=%s,%s\n", options, rw ? "rw" : "ro");
231 else
232 fprintf(f, "Options=%s\n", rw ? "rw" : "ro");
233
234 r = fflush_and_check(f);
235 if (r < 0)
236 return log_error_errno(r, "Failed to write unit file %s: %m", p);
237
238 if (post) {
239 lnk = strjoin(arg_dest, "/", post, ".requires/", unit, NULL);
240 if (!lnk)
241 return log_oom();
242
243 mkdir_parents_label(lnk, 0755);
244 if (symlink(p, lnk) < 0)
245 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
246 }
247
248 return 0;
249 }
250
251 static bool path_is_busy(const char *where) {
252 int r;
253
254 /* already a mountpoint; generators run during reload */
255 r = path_is_mount_point(where, AT_SYMLINK_FOLLOW);
256 if (r > 0)
257 return false;
258
259 /* the directory might not exist on a stateless system */
260 if (r == -ENOENT)
261 return false;
262
263 if (r < 0)
264 return true;
265
266 /* not a mountpoint but it contains files */
267 if (dir_is_empty(where) <= 0)
268 return true;
269
270 return false;
271 }
272
273 static int probe_and_add_mount(
274 const char *id,
275 const char *what,
276 const char *where,
277 bool rw,
278 const char *description,
279 const char *post) {
280
281 _cleanup_blkid_free_probe_ blkid_probe b = NULL;
282 const char *fstype = NULL;
283 int r;
284
285 assert(id);
286 assert(what);
287 assert(where);
288 assert(description);
289
290 if (path_is_busy(where)) {
291 log_debug("%s already populated, ignoring.", where);
292 return 0;
293 }
294
295 /* Let's check the partition type here, so that we know
296 * whether to do LUKS magic. */
297
298 errno = 0;
299 b = blkid_new_probe_from_filename(what);
300 if (!b) {
301 if (errno == 0)
302 return log_oom();
303 return log_error_errno(errno, "Failed to allocate prober: %m");
304 }
305
306 blkid_probe_enable_superblocks(b, 1);
307 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
308
309 errno = 0;
310 r = blkid_do_safeprobe(b);
311 if (r == -2 || r == 1) /* no result or uncertain */
312 return 0;
313 else if (r != 0)
314 return log_error_errno(errno ?: EIO, "Failed to probe %s: %m", what);
315
316 /* add_mount is OK with fstype being NULL. */
317 (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
318
319 return add_mount(
320 id,
321 what,
322 where,
323 fstype,
324 rw,
325 NULL,
326 description,
327 post);
328 }
329
330 static int add_swap(const char *path) {
331 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
332 _cleanup_fclose_ FILE *f = NULL;
333 int r;
334
335 assert(path);
336
337 log_debug("Adding swap: %s", path);
338
339 r = unit_name_from_path(path, ".swap", &name);
340 if (r < 0)
341 return log_error_errno(r, "Failed to generate unit name: %m");
342
343 unit = strjoin(arg_dest, "/", name, NULL);
344 if (!unit)
345 return log_oom();
346
347 f = fopen(unit, "wxe");
348 if (!f)
349 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
350
351 fprintf(f,
352 "# Automatically generated by systemd-gpt-auto-generator\n\n"
353 "[Unit]\n"
354 "Description=Swap Partition\n"
355 "Documentation=man:systemd-gpt-auto-generator(8)\n\n"
356 "[Swap]\n"
357 "What=%s\n",
358 path);
359
360 r = fflush_and_check(f);
361 if (r < 0)
362 return log_error_errno(r, "Failed to write unit file %s: %m", unit);
363
364 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
365 if (!lnk)
366 return log_oom();
367
368 mkdir_parents_label(lnk, 0755);
369 if (symlink(unit, lnk) < 0)
370 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
371
372 return 0;
373 }
374
375 #ifdef ENABLE_EFI
376 static int add_automount(
377 const char *id,
378 const char *what,
379 const char *where,
380 const char *fstype,
381 bool rw,
382 const char *options,
383 const char *description,
384 usec_t timeout) {
385
386 _cleanup_free_ char *unit = NULL, *lnk = NULL;
387 _cleanup_free_ char *opt, *p = NULL;
388 _cleanup_fclose_ FILE *f = NULL;
389 int r;
390
391 assert(id);
392 assert(where);
393 assert(description);
394
395 if (options)
396 opt = strjoin(options, ",noauto", NULL);
397 else
398 opt = strdup("noauto");
399 if (!opt)
400 return log_oom();
401
402 r = add_mount(id,
403 what,
404 where,
405 fstype,
406 rw,
407 opt,
408 description,
409 NULL);
410 if (r < 0)
411 return r;
412
413 r = unit_name_from_path(where, ".automount", &unit);
414 if (r < 0)
415 return log_error_errno(r, "Failed to generate unit name: %m");
416
417 p = strjoin(arg_dest, "/", unit, NULL);
418 if (!p)
419 return log_oom();
420
421 f = fopen(p, "wxe");
422 if (!f)
423 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
424
425 fprintf(f,
426 "# Automatically generated by systemd-gpt-auto-generator\n\n"
427 "[Unit]\n"
428 "Description=%s\n"
429 "Documentation=man:systemd-gpt-auto-generator(8)\n"
430 "[Automount]\n"
431 "Where=%s\n"
432 "TimeoutIdleSec=%lld\n",
433 description,
434 where,
435 (unsigned long long)timeout / USEC_PER_SEC);
436
437 r = fflush_and_check(f);
438 if (r < 0)
439 return log_error_errno(r, "Failed to write unit file %s: %m", p);
440
441 lnk = strjoin(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".wants/", unit, NULL);
442 if (!lnk)
443 return log_oom();
444 mkdir_parents_label(lnk, 0755);
445
446 if (symlink(p, lnk) < 0)
447 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
448
449 return 0;
450 }
451
452 static int add_boot(const char *what) {
453 const char *esp;
454 int r;
455
456 assert(what);
457
458 if (in_initrd()) {
459 log_debug("In initrd, ignoring the ESP.");
460 return 0;
461 }
462
463 if (detect_container() > 0) {
464 log_debug("In a container, ignoring the ESP.");
465 return 0;
466 }
467
468 /* If /efi exists we'll use that. Otherwise we'll use /boot, as that's usually the better choice */
469 esp = access("/efi/", F_OK) >= 0 ? "/efi" : "/boot";
470
471 /* We create an .automount which is not overridden by the .mount from the fstab generator. */
472 if (fstab_is_mount_point(esp)) {
473 log_debug("%s specified in fstab, ignoring.", esp);
474 return 0;
475 }
476
477 if (path_is_busy(esp)) {
478 log_debug("%s already populated, ignoring.", esp);
479 return 0;
480 }
481
482 if (is_efi_boot()) {
483 _cleanup_blkid_free_probe_ blkid_probe b = NULL;
484 const char *fstype = NULL, *uuid_string = NULL;
485 sd_id128_t loader_uuid, part_uuid;
486
487 /* If this is an EFI boot, be extra careful, and only mount the ESP if it was the ESP used for booting. */
488
489 r = efi_loader_get_device_part_uuid(&loader_uuid);
490 if (r == -ENOENT) {
491 log_debug("EFI loader partition unknown.");
492 return 0;
493 }
494 if (r < 0)
495 return log_error_errno(r, "Failed to read ESP partition UUID: %m");
496
497 errno = 0;
498 b = blkid_new_probe_from_filename(what);
499 if (!b) {
500 if (errno == 0)
501 return log_oom();
502 return log_error_errno(errno, "Failed to allocate prober: %m");
503 }
504
505 blkid_probe_enable_partitions(b, 1);
506 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
507
508 errno = 0;
509 r = blkid_do_safeprobe(b);
510 if (r == -2 || r == 1) /* no result or uncertain */
511 return 0;
512 else if (r != 0)
513 return log_error_errno(errno ?: EIO, "Failed to probe %s: %m", what);
514
515 (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
516 if (!streq_ptr(fstype, "vfat")) {
517 log_debug("Partition for %s is not a FAT filesystem, ignoring.", esp);
518 return 0;
519 }
520
521 errno = 0;
522 r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &uuid_string, NULL);
523 if (r != 0) {
524 log_debug_errno(errno, "Partition for %s does not have a UUID, ignoring.", esp);
525 return 0;
526 }
527
528 if (sd_id128_from_string(uuid_string, &part_uuid) < 0) {
529 log_debug("Partition for %s does not have a valid UUID, ignoring.", esp);
530 return 0;
531 }
532
533 if (!sd_id128_equal(part_uuid, loader_uuid)) {
534 log_debug("Partition for %s does not appear to be the partition we are booted from.", esp);
535 return 0;
536 }
537 } else
538 log_debug("Not an EFI boot, skipping ESP check.");
539
540 return add_automount("boot",
541 what,
542 esp,
543 "vfat",
544 true,
545 "umask=0077",
546 "EFI System Partition Automount",
547 120 * USEC_PER_SEC);
548 }
549 #else
550 static int add_boot(const char *what) {
551 return 0;
552 }
553 #endif
554
555 static int enumerate_partitions(dev_t devnum) {
556
557 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
558 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
559 _cleanup_blkid_free_probe_ blkid_probe b = NULL;
560 _cleanup_udev_unref_ struct udev *udev = NULL;
561 _cleanup_free_ char *boot = NULL, *home = NULL, *srv = NULL;
562 struct udev_list_entry *first, *item;
563 struct udev_device *parent = NULL;
564 const char *name, *node, *pttype, *devtype;
565 int boot_nr = -1, home_nr = -1, srv_nr = -1;
566 bool home_rw = true, srv_rw = true;
567 blkid_partlist pl;
568 int r, k;
569 dev_t pn;
570
571 udev = udev_new();
572 if (!udev)
573 return log_oom();
574
575 d = udev_device_new_from_devnum(udev, 'b', devnum);
576 if (!d)
577 return log_oom();
578
579 name = udev_device_get_devnode(d);
580 if (!name)
581 name = udev_device_get_syspath(d);
582 if (!name) {
583 log_debug("Device %u:%u does not have a name, ignoring.",
584 major(devnum), minor(devnum));
585 return 0;
586 }
587
588 parent = udev_device_get_parent(d);
589 if (!parent) {
590 log_debug("%s: not a partitioned device, ignoring.", name);
591 return 0;
592 }
593
594 /* Does it have a devtype? */
595 devtype = udev_device_get_devtype(parent);
596 if (!devtype) {
597 log_debug("%s: parent doesn't have a device type, ignoring.", name);
598 return 0;
599 }
600
601 /* Is this a disk or a partition? We only care for disks... */
602 if (!streq(devtype, "disk")) {
603 log_debug("%s: parent isn't a raw disk, ignoring.", name);
604 return 0;
605 }
606
607 /* Does it have a device node? */
608 node = udev_device_get_devnode(parent);
609 if (!node) {
610 log_debug("%s: parent device does not have device node, ignoring.", name);
611 return 0;
612 }
613
614 log_debug("%s: root device %s.", name, node);
615
616 pn = udev_device_get_devnum(parent);
617 if (major(pn) == 0)
618 return 0;
619
620 errno = 0;
621 b = blkid_new_probe_from_filename(node);
622 if (!b) {
623 if (errno == 0)
624 return log_oom();
625
626 return log_error_errno(errno, "%s: failed to allocate prober: %m", node);
627 }
628
629 blkid_probe_enable_partitions(b, 1);
630 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
631
632 errno = 0;
633 r = blkid_do_safeprobe(b);
634 if (r == 1)
635 return 0; /* no results */
636 else if (r == -2) {
637 log_warning("%s: probe gave ambiguous results, ignoring.", node);
638 return 0;
639 } else if (r != 0)
640 return log_error_errno(errno ?: EIO, "%s: failed to probe: %m", node);
641
642 errno = 0;
643 r = blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
644 if (r != 0) {
645 if (errno == 0)
646 return 0; /* No partition table found. */
647
648 return log_error_errno(errno, "%s: failed to determine partition table type: %m", node);
649 }
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, void *data) {
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 if (in_initrd()) {
960 r = generator_write_initrd_root_device_deps(arg_dest, "/dev/gpt-auto-root");
961 if (r < 0)
962 return 0;
963 }
964
965 return add_mount(
966 "root",
967 "/dev/gpt-auto-root",
968 in_initrd() ? "/sysroot" : "/",
969 NULL,
970 arg_root_rw,
971 NULL,
972 "Root Partition",
973 in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_LOCAL_FS_TARGET);
974 #else
975 return 0;
976 #endif
977 }
978
979 static int add_mounts(void) {
980 dev_t devno;
981 int r;
982
983 r = get_block_device_harder("/", &devno);
984 if (r < 0)
985 return log_error_errno(r, "Failed to determine block device of root file system: %m");
986 else if (r == 0) {
987 r = get_block_device_harder("/usr", &devno);
988 if (r < 0)
989 return log_error_errno(r, "Failed to determine block device of /usr file system: %m");
990 else if (r == 0) {
991 log_debug("Neither root nor /usr file system are on a (single) block device.");
992 return 0;
993 }
994 }
995
996 return enumerate_partitions(devno);
997 }
998
999 int main(int argc, char *argv[]) {
1000 int r = 0;
1001
1002 if (argc > 1 && argc != 4) {
1003 log_error("This program takes three or no arguments.");
1004 return EXIT_FAILURE;
1005 }
1006
1007 if (argc > 1)
1008 arg_dest = argv[3];
1009
1010 log_set_target(LOG_TARGET_SAFE);
1011 log_parse_environment();
1012 log_open();
1013
1014 umask(0022);
1015
1016 if (detect_container() > 0) {
1017 log_debug("In a container, exiting.");
1018 return EXIT_SUCCESS;
1019 }
1020
1021 r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, false);
1022 if (r < 0)
1023 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
1024
1025 if (!arg_enabled) {
1026 log_debug("Disabled, exiting.");
1027 return EXIT_SUCCESS;
1028 }
1029
1030 if (arg_root_enabled)
1031 r = add_root_mount();
1032
1033 if (!in_initrd()) {
1034 int k;
1035
1036 k = add_mounts();
1037 if (k < 0)
1038 r = k;
1039 }
1040
1041 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1042 }