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