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