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