]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/gpt-auto-generator/gpt-auto-generator.c
tree-wide: drop license boilerplate
[thirdparty/systemd.git] / src / gpt-auto-generator / gpt-auto-generator.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
1a14a53c
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2013 Lennart Poettering
1a14a53c
LP
6***/
7
6b5cf3ea 8#include <blkid.h>
1a14a53c 9#include <stdlib.h>
1a14a53c 10#include <sys/statfs.h>
cf0fbc49 11#include <unistd.h>
1a14a53c 12
b4bbcaa9 13#include "libudev.h"
07630cea
LP
14#include "sd-id128.h"
15
b5efdb8a 16#include "alloc-util.h"
07630cea 17#include "blkid-util.h"
18c528e9 18#include "blockdev-util.h"
07630cea 19#include "btrfs-util.h"
a0956174 20#include "dirent-util.h"
72e18a98 21#include "dissect-image.h"
07630cea 22#include "efivars.h"
3ffd4af2 23#include "fd-util.h"
07630cea
LP
24#include "fileio.h"
25#include "fstab-util.h"
26#include "generator.h"
27#include "gpt.h"
1a14a53c 28#include "missing.h"
07630cea 29#include "mkdir.h"
4349cd7c 30#include "mount-util.h"
6bedfcbb 31#include "parse-util.h"
07630cea 32#include "path-util.h"
4e731273 33#include "proc-cmdline.h"
1a14a53c 34#include "special.h"
98bad05e 35#include "specifier.h"
8fcde012 36#include "stat-util.h"
07630cea
LP
37#include "string-util.h"
38#include "udev-util.h"
1a14a53c 39#include "unit-name.h"
07630cea 40#include "util.h"
9a5cb137 41#include "virt.h"
1a14a53c 42
1a14a53c 43static const char *arg_dest = "/tmp";
73b80ec2
LP
44static bool arg_enabled = true;
45static bool arg_root_enabled = true;
46static bool arg_root_rw = false;
1a14a53c 47
01af8c01 48static int add_cryptsetup(const char *id, const char *what, bool rw, bool require, char **device) {
98bad05e 49 _cleanup_free_ char *e = NULL, *n = NULL, *p = NULL, *d = NULL, *id_escaped = NULL, *what_escaped = NULL;
1af72119 50 _cleanup_fclose_ FILE *f = NULL;
9cdcf368 51 char *ret;
1af72119
LP
52 int r;
53
54 assert(id);
55 assert(what);
1af72119 56
7410616c
LP
57 r = unit_name_from_path(what, ".device", &d);
58 if (r < 0)
59 return log_error_errno(r, "Failed to generate unit name: %m");
1af72119
LP
60
61 e = unit_name_escape(id);
62 if (!e)
63 return log_oom();
64
7410616c
LP
65 r = unit_name_build("systemd-cryptsetup", e, ".service", &n);
66 if (r < 0)
67 return log_error_errno(r, "Failed to generate unit name: %m");
1af72119 68
98bad05e
LP
69 id_escaped = specifier_escape(id);
70 if (!id_escaped)
71 return log_oom();
72
73 what_escaped = specifier_escape(what);
74 if (!what_escaped)
75 return log_oom();
76
605405c6 77 p = strjoin(arg_dest, "/", n);
821b2e79 78 if (!p)
1af72119
LP
79 return log_oom();
80
81 f = fopen(p, "wxe");
4a62c710
MS
82 if (!f)
83 return log_error_errno(errno, "Failed to create unit file %s: %m", p);
1af72119
LP
84
85 fprintf(f,
86 "# Automatically generated by systemd-gpt-auto-generator\n\n"
87 "[Unit]\n"
88 "Description=Cryptography Setup for %%I\n"
c3834f9b 89 "Documentation=man:systemd-gpt-auto-generator(8) man:systemd-cryptsetup@.service(8)\n"
1af72119
LP
90 "DefaultDependencies=no\n"
91 "Conflicts=umount.target\n"
92 "BindsTo=dev-mapper-%%i.device %s\n"
93 "Before=umount.target cryptsetup.target\n"
94 "After=%s\n"
95 "IgnoreOnIsolate=true\n"
1af72119
LP
96 "[Service]\n"
97 "Type=oneshot\n"
98 "RemainAfterExit=yes\n"
99 "TimeoutSec=0\n" /* the binary handles timeouts anyway */
0b1f68ac 100 "KeyringMode=shared\n" /* make sure we can share cached keys among instances */
cca1dfdd 101 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '' '%s'\n"
1af72119
LP
102 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
103 d, d,
98bad05e
LP
104 id_escaped, what_escaped, rw ? "" : "read-only",
105 id_escaped);
1af72119 106
dacd6cee
LP
107 r = fflush_and_check(f);
108 if (r < 0)
109 return log_error_errno(r, "Failed to write file %s: %m", p);
1af72119 110
9cdcf368
ZJS
111 r = generator_add_symlink(arg_dest, d, "wants", n);
112 if (r < 0)
113 return r;
1af72119 114
01af8c01 115 if (require) {
9cdcf368 116 const char *dmname;
1af72119 117
9cdcf368
ZJS
118 r = generator_add_symlink(arg_dest, "cryptsetup.target", "requires", n);
119 if (r < 0)
120 return r;
01af8c01 121
9cdcf368
ZJS
122 dmname = strjoina("dev-mapper-", e, ".device");
123 r = generator_add_symlink(arg_dest, dmname, "requires", n);
124 if (r < 0)
125 return r;
01af8c01 126 }
1af72119
LP
127
128 free(p);
605405c6 129 p = strjoin(arg_dest, "/dev-mapper-", e, ".device.d/50-job-timeout-sec-0.conf");
1af72119
LP
130 if (!p)
131 return log_oom();
132
133 mkdir_parents_label(p, 0755);
134 r = write_string_file(p,
135 "# Automatically generated by systemd-gpt-auto-generator\n\n"
136 "[Unit]\n"
4c1fc3e4
DM
137 "JobTimeoutSec=0\n",
138 WRITE_STRING_FILE_CREATE); /* the binary handles timeouts anyway */
23bbb0de
MS
139 if (r < 0)
140 return log_error_errno(r, "Failed to write device drop-in: %m");
1af72119
LP
141
142 ret = strappend("/dev/mapper/", id);
143 if (!ret)
144 return log_oom();
145
01af8c01
LP
146 if (device)
147 *device = ret;
1af72119
LP
148 return 0;
149}
150
73b80ec2
LP
151static int add_mount(
152 const char *id,
153 const char *what,
154 const char *where,
155 const char *fstype,
cca1dfdd 156 bool rw,
59512f21 157 const char *options,
73b80ec2
LP
158 const char *description,
159 const char *post) {
160
9cdcf368 161 _cleanup_free_ char *unit = NULL, *crypto_what = NULL, *p = NULL;
1a14a53c 162 _cleanup_fclose_ FILE *f = NULL;
e48fdd84 163 int r;
1a14a53c 164
98bad05e
LP
165 /* Note that we don't apply specifier escaping on the input strings here, since we know they are not configured
166 * externally, but all originate from our own sources here, and hence we know they contain no % characters that
167 * could potentially be understood as specifiers. */
168
1af72119
LP
169 assert(id);
170 assert(what);
171 assert(where);
1af72119
LP
172 assert(description);
173
73b80ec2 174 log_debug("Adding %s: %s %s", where, what, strna(fstype));
1a14a53c 175
73b80ec2 176 if (streq_ptr(fstype, "crypto_LUKS")) {
1af72119 177
01af8c01 178 r = add_cryptsetup(id, what, rw, true, &crypto_what);
1af72119
LP
179 if (r < 0)
180 return r;
181
182 what = crypto_what;
183 fstype = NULL;
184 }
185
7410616c
LP
186 r = unit_name_from_path(where, ".mount", &unit);
187 if (r < 0)
188 return log_error_errno(r, "Failed to generate unit name: %m");
1a14a53c 189
605405c6 190 p = strjoin(arg_dest, "/", unit);
e48fdd84
LP
191 if (!p)
192 return log_oom();
193
194 f = fopen(p, "wxe");
4a62c710
MS
195 if (!f)
196 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
1a14a53c
LP
197
198 fprintf(f,
199 "# Automatically generated by systemd-gpt-auto-generator\n\n"
200 "[Unit]\n"
c3834f9b
LP
201 "Description=%s\n"
202 "Documentation=man:systemd-gpt-auto-generator(8)\n",
e48fdd84
LP
203 description);
204
73b80ec2
LP
205 if (post)
206 fprintf(f, "Before=%s\n", post);
207
e48fdd84
LP
208 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
209 if (r < 0)
210 return r;
211
212 fprintf(f,
213 "\n"
1a14a53c
LP
214 "[Mount]\n"
215 "What=%s\n"
1af72119
LP
216 "Where=%s\n",
217 what, where);
218
73b80ec2
LP
219 if (fstype)
220 fprintf(f, "Type=%s\n", fstype);
221
59512f21
KS
222 if (options)
223 fprintf(f, "Options=%s,%s\n", options, rw ? "rw" : "ro");
224 else
225 fprintf(f, "Options=%s\n", rw ? "rw" : "ro");
1a14a53c 226
dacd6cee
LP
227 r = fflush_and_check(f);
228 if (r < 0)
229 return log_error_errno(r, "Failed to write unit file %s: %m", p);
1a14a53c 230
9cdcf368
ZJS
231 if (post)
232 return generator_add_symlink(arg_dest, post, "requires", unit);
1a14a53c
LP
233 return 0;
234}
235
59512f21
KS
236static bool path_is_busy(const char *where) {
237 int r;
238
239 /* already a mountpoint; generators run during reload */
e1873695 240 r = path_is_mount_point(where, NULL, AT_SYMLINK_FOLLOW);
59512f21
KS
241 if (r > 0)
242 return false;
243
244 /* the directory might not exist on a stateless system */
245 if (r == -ENOENT)
246 return false;
247
248 if (r < 0)
249 return true;
250
251 /* not a mountpoint but it contains files */
252 if (dir_is_empty(where) <= 0)
253 return true;
254
255 return false;
256}
257
72e18a98
LP
258static int add_partition_mount(
259 DissectedPartition *p,
61331eab 260 const char *id,
61331eab 261 const char *where,
72e18a98 262 const char *description) {
61331eab 263
72e18a98 264 assert(p);
61331eab 265
59512f21 266 if (path_is_busy(where)) {
61331eab
LP
267 log_debug("%s already populated, ignoring.", where);
268 return 0;
269 }
270
61331eab
LP
271 return add_mount(
272 id,
72e18a98 273 p->node,
61331eab 274 where,
72e18a98
LP
275 p->fstype,
276 p->rw,
59512f21 277 NULL,
61331eab 278 description,
72e18a98 279 SPECIAL_LOCAL_FS_TARGET);
61331eab
LP
280}
281
59512f21 282static int add_swap(const char *path) {
9cdcf368 283 _cleanup_free_ char *name = NULL, *unit = NULL;
59512f21
KS
284 _cleanup_fclose_ FILE *f = NULL;
285 int r;
286
287 assert(path);
288
fc5bc384
FB
289 /* Disable the swap auto logic if at least one swap is defined in /etc/fstab, see #6192. */
290 r = fstab_has_fstype("swap");
291 if (r < 0)
292 return log_error_errno(r, "Failed to parse fstab: %m");
1a680ae3 293 if (r > 0) {
fc5bc384
FB
294 log_debug("swap specified in fstab, ignoring.");
295 return 0;
296 }
297
59512f21
KS
298 log_debug("Adding swap: %s", path);
299
300 r = unit_name_from_path(path, ".swap", &name);
301 if (r < 0)
302 return log_error_errno(r, "Failed to generate unit name: %m");
303
605405c6 304 unit = strjoin(arg_dest, "/", name);
59512f21
KS
305 if (!unit)
306 return log_oom();
307
308 f = fopen(unit, "wxe");
309 if (!f)
310 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
311
312 fprintf(f,
313 "# Automatically generated by systemd-gpt-auto-generator\n\n"
314 "[Unit]\n"
315 "Description=Swap Partition\n"
316 "Documentation=man:systemd-gpt-auto-generator(8)\n\n"
317 "[Swap]\n"
318 "What=%s\n",
319 path);
320
dacd6cee
LP
321 r = fflush_and_check(f);
322 if (r < 0)
323 return log_error_errno(r, "Failed to write unit file %s: %m", unit);
59512f21 324
9cdcf368 325 return generator_add_symlink(arg_dest, SPECIAL_SWAP_TARGET, "wants", name);
59512f21
KS
326}
327
349cc4a5 328#if ENABLE_EFI
7a1494aa
TG
329static int add_automount(
330 const char *id,
331 const char *what,
332 const char *where,
333 const char *fstype,
334 bool rw,
335 const char *options,
336 const char *description,
337 usec_t timeout) {
338
9cdcf368 339 _cleanup_free_ char *unit = NULL;
7a1494aa
TG
340 _cleanup_free_ char *opt, *p = NULL;
341 _cleanup_fclose_ FILE *f = NULL;
342 int r;
343
344 assert(id);
345 assert(where);
346 assert(description);
347
348 if (options)
605405c6 349 opt = strjoin(options, ",noauto");
7a1494aa
TG
350 else
351 opt = strdup("noauto");
352 if (!opt)
353 return log_oom();
354
355 r = add_mount(id,
356 what,
357 where,
358 fstype,
359 rw,
360 opt,
361 description,
362 NULL);
363 if (r < 0)
364 return r;
365
366 r = unit_name_from_path(where, ".automount", &unit);
367 if (r < 0)
368 return log_error_errno(r, "Failed to generate unit name: %m");
369
605405c6 370 p = strjoin(arg_dest, "/", unit);
7a1494aa
TG
371 if (!p)
372 return log_oom();
373
374 f = fopen(p, "wxe");
375 if (!f)
376 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
377
378 fprintf(f,
379 "# Automatically generated by systemd-gpt-auto-generator\n\n"
380 "[Unit]\n"
381 "Description=%s\n"
382 "Documentation=man:systemd-gpt-auto-generator(8)\n"
383 "[Automount]\n"
384 "Where=%s\n"
70887c5f 385 "TimeoutIdleSec="USEC_FMT"\n",
7a1494aa
TG
386 description,
387 where,
70887c5f 388 timeout / USEC_PER_SEC);
7a1494aa
TG
389
390 r = fflush_and_check(f);
391 if (r < 0)
392 return log_error_errno(r, "Failed to write unit file %s: %m", p);
393
9cdcf368 394 return generator_add_symlink(arg_dest, SPECIAL_LOCAL_FS_TARGET, "wants", unit);
7a1494aa
TG
395}
396
72e18a98 397static int add_esp(DissectedPartition *p) {
b52a109a 398 const char *esp;
59512f21
KS
399 int r;
400
72e18a98 401 assert(p);
59512f21 402
59512f21 403 if (in_initrd()) {
b52a109a 404 log_debug("In initrd, ignoring the ESP.");
59512f21
KS
405 return 0;
406 }
407
b52a109a
LP
408 /* If /efi exists we'll use that. Otherwise we'll use /boot, as that's usually the better choice */
409 esp = access("/efi/", F_OK) >= 0 ? "/efi" : "/boot";
59512f21 410
0b6b6787 411 /* We create an .automount which is not overridden by the .mount from the fstab generator. */
b9088048
FB
412 r = fstab_is_mount_point(esp);
413 if (r < 0)
414 return log_error_errno(r, "Failed to parse fstab: %m");
39b6a511 415 if (r > 0) {
b52a109a 416 log_debug("%s specified in fstab, ignoring.", esp);
59512f21
KS
417 return 0;
418 }
419
b52a109a
LP
420 if (path_is_busy(esp)) {
421 log_debug("%s already populated, ignoring.", esp);
59512f21
KS
422 return 0;
423 }
424
7ba25ab5 425 if (is_efi_boot()) {
72e18a98 426 sd_id128_t loader_uuid;
59512f21 427
7ba25ab5 428 /* If this is an EFI boot, be extra careful, and only mount the ESP if it was the ESP used for booting. */
59512f21 429
7ba25ab5
LP
430 r = efi_loader_get_device_part_uuid(&loader_uuid);
431 if (r == -ENOENT) {
432 log_debug("EFI loader partition unknown.");
433 return 0;
434 }
e28973ee
ZJS
435 if (r < 0)
436 return log_error_errno(r, "Failed to read ESP partition UUID: %m");
7ba25ab5 437
72e18a98 438 if (!sd_id128_equal(p->uuid, loader_uuid)) {
7ba25ab5
LP
439 log_debug("Partition for %s does not appear to be the partition we are booted from.", esp);
440 return 0;
441 }
442 } else
443 log_debug("Not an EFI boot, skipping ESP check.");
444
445 return add_automount("boot",
72e18a98
LP
446 p->node,
447 esp,
448 p->fstype,
449 true,
450 "umask=0077",
451 "EFI System Partition Automount",
452 120 * USEC_PER_SEC);
7a1494aa 453}
59512f21 454#else
d97beb0e 455static int add_esp(DissectedPartition *p) {
59512f21 456 return 0;
59512f21 457}
7a1494aa 458#endif
59512f21 459
72e18a98 460static int open_parent(dev_t devnum, int *ret) {
1ca208fb 461 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
61331eab 462 _cleanup_udev_unref_ struct udev *udev = NULL;
72e18a98
LP
463 const char *name, *devtype, *node;
464 struct udev_device *parent;
61331eab 465 dev_t pn;
72e18a98
LP
466 int fd;
467
468 assert(ret);
1a14a53c 469
61331eab
LP
470 udev = udev_new();
471 if (!udev)
b47d419c 472 return log_oom();
1a14a53c 473
61331eab 474 d = udev_device_new_from_devnum(udev, 'b', devnum);
1ca208fb
ZJS
475 if (!d)
476 return log_oom();
1a14a53c 477
d2a62382
ZJS
478 name = udev_device_get_devnode(d);
479 if (!name)
480 name = udev_device_get_syspath(d);
481 if (!name) {
72e18a98
LP
482 log_debug("Device %u:%u does not have a name, ignoring.", major(devnum), minor(devnum));
483 goto not_found;
d2a62382
ZJS
484 }
485
1a14a53c 486 parent = udev_device_get_parent(d);
fa041593 487 if (!parent) {
d2a62382 488 log_debug("%s: not a partitioned device, ignoring.", name);
72e18a98 489 goto not_found;
fa041593 490 }
1a14a53c 491
61331eab
LP
492 /* Does it have a devtype? */
493 devtype = udev_device_get_devtype(parent);
fa041593 494 if (!devtype) {
d2a62382 495 log_debug("%s: parent doesn't have a device type, ignoring.", name);
72e18a98 496 goto not_found;
fa041593 497 }
61331eab
LP
498
499 /* Is this a disk or a partition? We only care for disks... */
fa041593 500 if (!streq(devtype, "disk")) {
d2a62382 501 log_debug("%s: parent isn't a raw disk, ignoring.", name);
72e18a98 502 goto not_found;
fa041593 503 }
61331eab
LP
504
505 /* Does it have a device node? */
506 node = udev_device_get_devnode(parent);
fa041593 507 if (!node) {
d2a62382 508 log_debug("%s: parent device does not have device node, ignoring.", name);
72e18a98 509 goto not_found;
fa041593 510 }
61331eab 511
d2a62382 512 log_debug("%s: root device %s.", name, node);
61331eab
LP
513
514 pn = udev_device_get_devnum(parent);
72e18a98
LP
515 if (major(pn) == 0) {
516 log_debug("%s: parent device is not a proper block device, ignoring.", name);
517 goto not_found;
61331eab
LP
518 }
519
72e18a98
LP
520 fd = open(node, O_RDONLY|O_CLOEXEC|O_NOCTTY);
521 if (fd < 0)
522 return log_error_errno(errno, "Failed to open %s: %m", node);
61331eab 523
72e18a98
LP
524 *ret = fd;
525 return 1;
61331eab 526
72e18a98
LP
527not_found:
528 *ret = -1;
529 return 0;
530}
cb971249 531
72e18a98 532static int enumerate_partitions(dev_t devnum) {
61331eab 533
72e18a98
LP
534 _cleanup_close_ int fd = -1;
535 _cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
536 int r, k;
61331eab 537
72e18a98
LP
538 r = open_parent(devnum, &fd);
539 if (r <= 0)
540 return r;
61331eab 541
72e18a98
LP
542 r = dissect_image(fd, NULL, 0, DISSECT_IMAGE_GPT_ONLY, &m);
543 if (r == -ENOPKG) {
544 log_debug_errno(r, "No suitable partition table found, ignoring.");
545 return 0;
61331eab 546 }
23bbb0de 547 if (r < 0)
72e18a98 548 return log_error_errno(r, "Failed to dissect: %m");
0238d4c6 549
72e18a98
LP
550 if (m->partitions[PARTITION_SWAP].found) {
551 k = add_swap(m->partitions[PARTITION_SWAP].node);
552 if (k < 0)
553 r = k;
1a14a53c
LP
554 }
555
72e18a98
LP
556 if (m->partitions[PARTITION_ESP].found) {
557 k = add_esp(m->partitions + PARTITION_ESP);
59512f21
KS
558 if (k < 0)
559 r = k;
560 }
561
72e18a98
LP
562 if (m->partitions[PARTITION_HOME].found) {
563 k = add_partition_mount(m->partitions + PARTITION_HOME, "home", "/home", "Home Partition");
73b80ec2
LP
564 if (k < 0)
565 r = k;
566 }
e48fdd84 567
72e18a98
LP
568 if (m->partitions[PARTITION_SRV].found) {
569 k = add_partition_mount(m->partitions + PARTITION_SRV, "srv", "/srv", "Server Data Partition");
73b80ec2
LP
570 if (k < 0)
571 r = k;
572 }
1a14a53c 573
1a14a53c
LP
574 return r;
575}
576
96287a49 577static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
73b80ec2 578 int r;
1a14a53c 579
73b80ec2 580 assert(key);
1a14a53c 581
1d84ad94 582 if (STR_IN_SET(key, "systemd.gpt_auto", "rd.systemd.gpt_auto")) {
1a14a53c 583
1d84ad94 584 r = value ? parse_boolean(value) : 1;
73b80ec2 585 if (r < 0)
d2a62382 586 log_warning("Failed to parse gpt-auto switch \"%s\". Ignoring.", value);
8086ffac
ZJS
587 else
588 arg_enabled = r;
1a14a53c 589
1d84ad94
LP
590 } else if (streq(key, "root")) {
591
592 if (proc_cmdline_value_missing(key, value))
593 return 0;
73b80ec2
LP
594
595 /* Disable root disk logic if there's a root= value
596 * specified (unless it happens to be "gpt-auto") */
597
598 arg_root_enabled = streq(value, "gpt-auto");
599
2f3dfc6f
LP
600 } else if (streq(key, "roothash")) {
601
602 if (proc_cmdline_value_missing(key, value))
603 return 0;
604
605 /* Disable root disk logic if there's roothash= defined (i.e. verity enabled) */
606
607 arg_root_enabled = false;
608
73b80ec2
LP
609 } else if (streq(key, "rw") && !value)
610 arg_root_rw = true;
611 else if (streq(key, "ro") && !value)
612 arg_root_rw = false;
73b80ec2
LP
613
614 return 0;
615}
616
349cc4a5 617#if ENABLE_EFI
01af8c01
LP
618static int add_root_cryptsetup(void) {
619
620 /* If a device /dev/gpt-auto-root-luks appears, then make it pull in systemd-cryptsetup-root.service, which
621 * sets it up, and causes /dev/gpt-auto-root to appear which is all we are looking for. */
622
623 return add_cryptsetup("root", "/dev/gpt-auto-root-luks", true, false, NULL);
624}
625#endif
626
73b80ec2
LP
627static int add_root_mount(void) {
628
349cc4a5 629#if ENABLE_EFI
73b80ec2
LP
630 int r;
631
632 if (!is_efi_boot()) {
633 log_debug("Not a EFI boot, not creating root mount.");
634 return 0;
9a5cb137
ZJS
635 }
636
73b80ec2
LP
637 r = efi_loader_get_device_part_uuid(NULL);
638 if (r == -ENOENT) {
639 log_debug("EFI loader partition unknown, exiting.");
640 return 0;
23bbb0de
MS
641 } else if (r < 0)
642 return log_error_errno(r, "Failed to read ESP partition UUID: %m");
1a14a53c 643
73b80ec2
LP
644 /* OK, we have an ESP partition, this is fantastic, so let's
645 * wait for a root device to show up. A udev rule will create
646 * the link for us under the right name. */
647
7163e1ca
DD
648 if (in_initrd()) {
649 r = generator_write_initrd_root_device_deps(arg_dest, "/dev/gpt-auto-root");
650 if (r < 0)
651 return 0;
01af8c01
LP
652
653 r = add_root_cryptsetup();
654 if (r < 0)
655 return r;
7163e1ca
DD
656 }
657
73b80ec2
LP
658 return add_mount(
659 "root",
98b2f766 660 "/dev/gpt-auto-root",
73b80ec2
LP
661 in_initrd() ? "/sysroot" : "/",
662 NULL,
cca1dfdd 663 arg_root_rw,
59512f21 664 NULL,
73b80ec2
LP
665 "Root Partition",
666 in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_LOCAL_FS_TARGET);
667#else
668 return 0;
669#endif
670}
671
672static int add_mounts(void) {
73b80ec2
LP
673 dev_t devno;
674 int r;
675
c6ba0c18 676 r = get_block_device_harder("/", &devno);
23bbb0de
MS
677 if (r < 0)
678 return log_error_errno(r, "Failed to determine block device of root file system: %m");
57ab9f89 679 if (r == 0) {
c6ba0c18 680 r = get_block_device_harder("/usr", &devno);
eafe88e3
TH
681 if (r < 0)
682 return log_error_errno(r, "Failed to determine block device of /usr file system: %m");
57ab9f89 683 if (r == 0) {
eafe88e3
TH
684 log_debug("Neither root nor /usr file system are on a (single) block device.");
685 return 0;
686 }
3db604b9
LP
687 }
688
61331eab 689 return enumerate_partitions(devno);
73b80ec2
LP
690}
691
692int main(int argc, char *argv[]) {
8f50e86a 693 int r, k;
73b80ec2
LP
694
695 if (argc > 1 && argc != 4) {
696 log_error("This program takes three or no arguments.");
697 return EXIT_FAILURE;
698 }
699
700 if (argc > 1)
701 arg_dest = argv[3];
702
6c347d50
LP
703 log_set_prohibit_ipc(true);
704 log_set_target(LOG_TARGET_AUTO);
73b80ec2
LP
705 log_parse_environment();
706 log_open();
707
708 umask(0022);
709
75f86906 710 if (detect_container() > 0) {
73b80ec2 711 log_debug("In a container, exiting.");
e48fdd84 712 return EXIT_SUCCESS;
1a14a53c 713 }
3db604b9 714
1d84ad94 715 r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
b5884878 716 if (r < 0)
da927ba9 717 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
1a14a53c 718
73b80ec2
LP
719 if (!arg_enabled) {
720 log_debug("Disabled, exiting.");
721 return EXIT_SUCCESS;
722 }
723
724 if (arg_root_enabled)
725 r = add_root_mount();
8f50e86a
LP
726 else
727 r = 0;
73b80ec2
LP
728
729 if (!in_initrd()) {
73b80ec2
LP
730 k = add_mounts();
731 if (k < 0)
732 r = k;
733 }
734
735 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1a14a53c 736}