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