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