]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/gpt-auto-generator/gpt-auto-generator.c
gpt-auto-generator: honour read-only and no-auto flag from GPT data
[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>
24#include <fcntl.h>
1a14a53c
LP
25#include <sys/ioctl.h>
26#include <sys/statfs.h>
96115cdf 27#include <blkid/blkid.h>
1a14a53c 28
4b357e15
MM
29#ifdef HAVE_LINUX_BTRFS_H
30#include <linux/btrfs.h>
31#endif
32
1af72119
LP
33#include "sd-id128.h"
34#include "libudev.h"
1a14a53c
LP
35#include "path-util.h"
36#include "util.h"
37#include "mkdir.h"
38#include "missing.h"
1ca208fb 39#include "udev-util.h"
1a14a53c
LP
40#include "special.h"
41#include "unit-name.h"
9a5cb137 42#include "virt.h"
e48fdd84
LP
43#include "generator.h"
44#include "gpt.h"
1af72119 45#include "fileio.h"
73b80ec2 46#include "efivars.h"
1b9e5b12 47#include "blkid-util.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
61331eab 54static int add_swap(const char *path) {
1a14a53c
LP
55 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
56 _cleanup_fclose_ FILE *f = NULL;
57
61331eab
LP
58 assert(path);
59
60 log_debug("Adding swap: %s", path);
1a14a53c
LP
61
62 name = unit_name_from_path(path, ".swap");
63 if (!name)
64 return log_oom();
65
66 unit = strjoin(arg_dest, "/", name, NULL);
67 if (!unit)
68 return log_oom();
69
70 f = fopen(unit, "wxe");
71 if (!f) {
72 log_error("Failed to create unit file %s: %m", unit);
73 return -errno;
74 }
75
76 fprintf(f,
77 "# Automatically generated by systemd-gpt-auto-generator\n\n"
1ebab691 78 "[Unit]\n"
c3834f9b
LP
79 "Description=Swap Partition\n"
80 "Documentation=man:systemd-gpt-auto-generator(8)\n\n"
ee530d8b 81 "[Swap]\n"
1a14a53c
LP
82 "What=%s\n",
83 path);
84
85 fflush(f);
86 if (ferror(f)) {
87 log_error("Failed to write unit file %s: %m", unit);
88 return -errno;
89 }
90
91 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
92 if (!lnk)
93 return log_oom();
94
95 mkdir_parents_label(lnk, 0755);
96 if (symlink(unit, lnk) < 0) {
97 log_error("Failed to create symlink %s: %m", lnk);
98 return -errno;
99 }
100
101 return 0;
102}
103
cca1dfdd 104static int add_cryptsetup(const char *id, const char *what, bool rw, char **device) {
1af72119
LP
105 _cleanup_free_ char *e = NULL, *n = NULL, *p = NULL, *d = NULL, *to = NULL;
106 _cleanup_fclose_ FILE *f = NULL;
107 char *from, *ret;
108 int r;
109
110 assert(id);
111 assert(what);
112 assert(device);
113
114 d = unit_name_from_path(what, ".device");
115 if (!d)
116 return log_oom();
117
118 e = unit_name_escape(id);
119 if (!e)
120 return log_oom();
121
122 n = unit_name_build("systemd-cryptsetup", e, ".service");
123 if (!n)
124 return log_oom();
125
126 p = strjoin(arg_dest, "/", n, NULL);
127 if (!n)
128 return log_oom();
129
130 f = fopen(p, "wxe");
131 if (!f) {
132 log_error("Failed to create unit file %s: %m", p);
133 return -errno;
134 }
135
136 fprintf(f,
137 "# Automatically generated by systemd-gpt-auto-generator\n\n"
138 "[Unit]\n"
139 "Description=Cryptography Setup for %%I\n"
c3834f9b 140 "Documentation=man:systemd-gpt-auto-generator(8) man:systemd-cryptsetup@.service(8)\n"
1af72119
LP
141 "DefaultDependencies=no\n"
142 "Conflicts=umount.target\n"
143 "BindsTo=dev-mapper-%%i.device %s\n"
144 "Before=umount.target cryptsetup.target\n"
145 "After=%s\n"
146 "IgnoreOnIsolate=true\n"
147 "After=systemd-readahead-collect.service systemd-readahead-replay.service\n\n"
148 "[Service]\n"
149 "Type=oneshot\n"
150 "RemainAfterExit=yes\n"
151 "TimeoutSec=0\n" /* the binary handles timeouts anyway */
cca1dfdd 152 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '' '%s'\n"
1af72119
LP
153 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
154 d, d,
cca1dfdd 155 id, what, rw ? "" : "read-only",
1af72119
LP
156 id);
157
158 fflush(f);
159 if (ferror(f)) {
160 log_error("Failed to write file %s: %m", p);
161 return -errno;
162 }
163
164 from = strappenda("../", n);
165
166 to = strjoin(arg_dest, "/", d, ".wants/", n, NULL);
167 if (!to)
168 return log_oom();
169
170 mkdir_parents_label(to, 0755);
171 if (symlink(from, to) < 0) {
172 log_error("Failed to create symlink %s: %m", to);
173 return -errno;
174 }
175
176 free(to);
177 to = strjoin(arg_dest, "/cryptsetup.target.requires/", n, NULL);
178 if (!to)
179 return log_oom();
180
181 mkdir_parents_label(to, 0755);
182 if (symlink(from, to) < 0) {
183 log_error("Failed to create symlink %s: %m", to);
184 return -errno;
185 }
186
187 free(to);
188 to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n, NULL);
189 if (!to)
190 return log_oom();
191
192 mkdir_parents_label(to, 0755);
193 if (symlink(from, to) < 0) {
194 log_error("Failed to create symlink %s: %m", to);
195 return -errno;
196 }
197
198 free(p);
199 p = strjoin(arg_dest, "/dev-mapper-", e, ".device.d/50-job-timeout-sec-0.conf", NULL);
200 if (!p)
201 return log_oom();
202
203 mkdir_parents_label(p, 0755);
204 r = write_string_file(p,
205 "# Automatically generated by systemd-gpt-auto-generator\n\n"
206 "[Unit]\n"
207 "JobTimeoutSec=0\n"); /* the binary handles timeouts anyway */
208 if (r < 0) {
209 log_error("Failed to write device drop-in: %s", strerror(-r));
210 return r;
211 }
212
213 ret = strappend("/dev/mapper/", id);
214 if (!ret)
215 return log_oom();
216
217 *device = ret;
218 return 0;
219}
220
73b80ec2
LP
221static int add_mount(
222 const char *id,
223 const char *what,
224 const char *where,
225 const char *fstype,
cca1dfdd 226 bool rw,
73b80ec2
LP
227 const char *description,
228 const char *post) {
229
1af72119 230 _cleanup_free_ char *unit = NULL, *lnk = NULL, *crypto_what = NULL, *p = NULL;
1a14a53c 231 _cleanup_fclose_ FILE *f = NULL;
e48fdd84 232 int r;
1a14a53c 233
1af72119
LP
234 assert(id);
235 assert(what);
236 assert(where);
1af72119
LP
237 assert(description);
238
73b80ec2 239 log_debug("Adding %s: %s %s", where, what, strna(fstype));
1a14a53c 240
73b80ec2 241 if (streq_ptr(fstype, "crypto_LUKS")) {
1af72119 242
cca1dfdd 243 r = add_cryptsetup(id, what, rw, &crypto_what);
1af72119
LP
244 if (r < 0)
245 return r;
246
247 what = crypto_what;
248 fstype = NULL;
249 }
250
e48fdd84 251 unit = unit_name_from_path(where, ".mount");
1a14a53c
LP
252 if (!unit)
253 return log_oom();
254
e48fdd84
LP
255 p = strjoin(arg_dest, "/", unit, NULL);
256 if (!p)
257 return log_oom();
258
259 f = fopen(p, "wxe");
1a14a53c
LP
260 if (!f) {
261 log_error("Failed to create unit file %s: %m", unit);
262 return -errno;
263 }
264
265 fprintf(f,
266 "# Automatically generated by systemd-gpt-auto-generator\n\n"
267 "[Unit]\n"
c3834f9b
LP
268 "Description=%s\n"
269 "Documentation=man:systemd-gpt-auto-generator(8)\n",
e48fdd84
LP
270 description);
271
73b80ec2
LP
272 if (post)
273 fprintf(f, "Before=%s\n", post);
274
e48fdd84
LP
275 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
276 if (r < 0)
277 return r;
278
279 fprintf(f,
280 "\n"
1a14a53c
LP
281 "[Mount]\n"
282 "What=%s\n"
1af72119
LP
283 "Where=%s\n",
284 what, where);
285
73b80ec2
LP
286 if (fstype)
287 fprintf(f, "Type=%s\n", fstype);
288
cca1dfdd 289 fprintf(f, "Options=%s\n", rw ? "rw" : "ro");
1a14a53c
LP
290
291 fflush(f);
292 if (ferror(f)) {
73b80ec2 293 log_error("Failed to write unit file %s: %m", p);
1a14a53c
LP
294 return -errno;
295 }
296
73b80ec2
LP
297 if (post) {
298 lnk = strjoin(arg_dest, "/", post, ".requires/", unit, NULL);
299 if (!lnk)
300 return log_oom();
1a14a53c 301
73b80ec2
LP
302 mkdir_parents_label(lnk, 0755);
303 if (symlink(p, lnk) < 0) {
304 log_error("Failed to create symlink %s: %m", lnk);
305 return -errno;
306 }
1a14a53c
LP
307 }
308
309 return 0;
310}
311
61331eab
LP
312static int probe_and_add_mount(
313 const char *id,
314 const char *what,
315 const char *where,
cca1dfdd 316 bool rw,
61331eab
LP
317 const char *description,
318 const char *post) {
319
320 _cleanup_blkid_free_probe_ blkid_probe b = NULL;
321 const char *fstype;
322 int r;
323
324 assert(id);
325 assert(what);
326 assert(where);
327 assert(description);
328
329 if (path_is_mount_point(where, true) <= 0 &&
330 dir_is_empty(where) <= 0) {
331 log_debug("%s already populated, ignoring.", where);
332 return 0;
333 }
334
335 /* Let's check the partition type here, so that we know
336 * whether to do LUKS magic. */
337
338 errno = 0;
339 b = blkid_new_probe_from_filename(what);
340 if (!b) {
341 if (errno == 0)
342 return log_oom();
343 log_error("Failed to allocate prober: %m");
344 return -errno;
345 }
346
347 blkid_probe_enable_superblocks(b, 1);
348 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
349
350 errno = 0;
351 r = blkid_do_safeprobe(b);
352 if (r == -2 || r == 1) /* no result or uncertain */
353 return 0;
354 else if (r != 0) {
355 if (errno == 0)
356 errno = EIO;
357 log_error("Failed to probe %s: %m", what);
358 return -errno;
359 }
360
361 blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
362
363 return add_mount(
364 id,
365 what,
366 where,
367 fstype,
cca1dfdd 368 rw,
61331eab
LP
369 description,
370 post);
371}
372
373static int enumerate_partitions(dev_t devnum) {
374
1ca208fb
ZJS
375 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
376 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
61331eab
LP
377 _cleanup_blkid_free_probe_ blkid_probe b = NULL;
378 _cleanup_udev_unref_ struct udev *udev = NULL;
379 _cleanup_free_ char *home = NULL, *srv = NULL;
1a14a53c 380 struct udev_list_entry *first, *item;
e48fdd84 381 struct udev_device *parent = NULL;
61331eab
LP
382 const char *node, *pttype, *devtype;
383 int home_nr = -1, srv_nr = -1;
cca1dfdd 384 bool home_rw = true, srv_rw = true;
61331eab 385 blkid_partlist pl;
73b80ec2 386 int r, k;
61331eab 387 dev_t pn;
1a14a53c 388
61331eab
LP
389 udev = udev_new();
390 if (!udev)
b47d419c 391 return log_oom();
1a14a53c 392
61331eab 393 d = udev_device_new_from_devnum(udev, 'b', devnum);
1ca208fb
ZJS
394 if (!d)
395 return log_oom();
1a14a53c
LP
396
397 parent = udev_device_get_parent(d);
1ca208fb 398 if (!parent)
9c4495ca 399 return 0;
1a14a53c 400
61331eab
LP
401 /* Does it have a devtype? */
402 devtype = udev_device_get_devtype(parent);
403 if (!devtype)
404 return 0;
405
406 /* Is this a disk or a partition? We only care for disks... */
407 if (!streq(devtype, "disk"))
408 return 0;
409
410 /* Does it have a device node? */
411 node = udev_device_get_devnode(parent);
412 if (!node)
413 return 0;
414
415 log_debug("Root device %s.", node);
416
417 pn = udev_device_get_devnum(parent);
418 if (major(pn) == 0)
419 return 0;
420
421 errno = 0;
422 b = blkid_new_probe_from_filename(node);
423 if (!b) {
424 if (errno == 0)
425 return log_oom();
426
427 log_error("Failed allocate prober: %m");
428 return -errno;
429 }
430
431 blkid_probe_enable_superblocks(b, 1);
432 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
433 blkid_probe_enable_partitions(b, 1);
434 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
435
436 errno = 0;
437 r = blkid_do_safeprobe(b);
438 if (r == -2 || r == 1) /* no result or uncertain */
439 return 0;
440 else if (r != 0) {
441 if (errno == 0)
442 errno = EIO;
443 log_error("Failed to probe %s: %m", node);
444 return -errno;
445 }
446
447 errno = 0;
448 r = blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
449 if (r != 0) {
450 if (errno == 0)
451 errno = EIO;
452 log_error("Failed to determine partition table type of %s: %m", node);
453 return -errno;
454 }
455
456 /* We only do this all for GPT... */
457 if (!streq_ptr(pttype, "gpt"))
458 return 0;
459
460 errno = 0;
461 pl = blkid_probe_get_partitions(b);
462 if (!pl) {
463 if (errno == 0)
464 return log_oom();
465
1b9e5b12 466 log_error("Failed to list partitions of %s: %m", node);
61331eab
LP
467 return -errno;
468 }
469
470 e = udev_enumerate_new(udev);
471 if (!e)
472 return log_oom();
473
1a14a53c 474 r = udev_enumerate_add_match_parent(e, parent);
1ca208fb
ZJS
475 if (r < 0)
476 return log_oom();
1a14a53c
LP
477
478 r = udev_enumerate_add_match_subsystem(e, "block");
1ca208fb
ZJS
479 if (r < 0)
480 return log_oom();
1a14a53c
LP
481
482 r = udev_enumerate_scan_devices(e);
483 if (r < 0) {
61331eab 484 log_error("Failed to enumerate partitions on %s: %s", node, strerror(-r));
1ca208fb 485 return r;
1a14a53c
LP
486 }
487
488 first = udev_enumerate_get_list_entry(e);
489 udev_list_entry_foreach(item, first) {
e48fdd84 490 _cleanup_udev_device_unref_ struct udev_device *q;
61331eab 491 const char *stype, *subnode;
1a14a53c 492 sd_id128_t type_id;
61331eab
LP
493 blkid_partition pp;
494 dev_t qn;
495 int nr;
cca1dfdd 496 unsigned long long flags;
1a14a53c
LP
497
498 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
1ca208fb 499 if (!q)
61331eab 500 continue;
1a14a53c 501
61331eab
LP
502 qn = udev_device_get_devnum(q);
503 if (major(qn) == 0)
1ca208fb 504 continue;
1a14a53c 505
61331eab 506 if (qn == devnum)
1ca208fb 507 continue;
1a14a53c 508
61331eab
LP
509 if (qn == pn)
510 continue;
1a14a53c 511
61331eab
LP
512 subnode = udev_device_get_devnode(q);
513 if (!subnode)
514 continue;
73b80ec2 515
61331eab
LP
516 pp = blkid_partlist_devno_to_partition(pl, qn);
517 if (!pp)
73b80ec2 518 continue;
61331eab 519
cca1dfdd
LP
520 flags = blkid_partition_get_flags(pp);
521
522 /* Ignore partitions that are not marked for automatic
523 * mounting on discovery */
524 if (flags & GPT_FLAG_NO_AUTO)
525 continue;
526
61331eab
LP
527 nr = blkid_partition_get_partno(pp);
528 if (nr < 0)
529 continue;
530
531 stype = blkid_partition_get_type_string(pp);
532 if (!stype)
533 continue;
534
535 if (sd_id128_from_string(stype, &type_id) < 0)
1ca208fb 536 continue;
1a14a53c 537
73b80ec2
LP
538 if (sd_id128_equal(type_id, GPT_SWAP)) {
539
cca1dfdd
LP
540 if (flags & GPT_FLAG_READ_ONLY) {
541 log_debug("%s marked as read-only swap partition, which is bogus, ignoring.", subnode);
542 continue;
543 }
544
61331eab 545 k = add_swap(subnode);
73b80ec2
LP
546 if (k < 0)
547 r = k;
e48fdd84 548
73b80ec2 549 } else if (sd_id128_equal(type_id, GPT_HOME)) {
e48fdd84
LP
550
551 /* We only care for the first /home partition */
552 if (home && nr >= home_nr)
553 continue;
554
555 home_nr = nr;
cca1dfdd 556 home_rw = !(flags & GPT_FLAG_READ_ONLY),
e48fdd84
LP
557
558 free(home);
61331eab 559 home = strdup(subnode);
e48fdd84
LP
560 if (!home)
561 return log_oom();
562
e48fdd84
LP
563 } else if (sd_id128_equal(type_id, GPT_SRV)) {
564
565 /* We only care for the first /srv partition */
566 if (srv && nr >= srv_nr)
567 continue;
568
569 srv_nr = nr;
cca1dfdd 570 srv_rw = !(flags & GPT_FLAG_READ_ONLY),
e48fdd84
LP
571
572 free(srv);
573 srv = strdup(node);
574 if (!srv)
575 return log_oom();
1a14a53c 576 }
1a14a53c
LP
577 }
578
61331eab 579 if (home) {
cca1dfdd 580 k = probe_and_add_mount("home", home, "/home", home_rw, "Home Partition", SPECIAL_LOCAL_FS_TARGET);
73b80ec2
LP
581 if (k < 0)
582 r = k;
583 }
e48fdd84 584
61331eab 585 if (srv) {
cca1dfdd 586 k = probe_and_add_mount("srv", srv, "/srv", srv_rw, "Server Data Partition", SPECIAL_LOCAL_FS_TARGET);
73b80ec2
LP
587 if (k < 0)
588 r = k;
589 }
1a14a53c 590
1a14a53c
LP
591 return r;
592}
593
594static int get_btrfs_block_device(const char *path, dev_t *dev) {
b47d419c 595 struct btrfs_ioctl_fs_info_args fsi = {};
1a14a53c
LP
596 _cleanup_close_ int fd = -1;
597 uint64_t id;
598
599 assert(path);
600 assert(dev);
601
602 fd = open(path, O_DIRECTORY|O_CLOEXEC);
603 if (fd < 0)
604 return -errno;
605
1a14a53c
LP
606 if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
607 return -errno;
608
609 /* We won't do this for btrfs RAID */
610 if (fsi.num_devices != 1)
611 return 0;
612
613 for (id = 1; id <= fsi.max_id; id++) {
b47d419c
ZJS
614 struct btrfs_ioctl_dev_info_args di = {
615 .devid = id,
616 };
1a14a53c
LP
617 struct stat st;
618
1a14a53c
LP
619 if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
620 if (errno == ENODEV)
621 continue;
622
623 return -errno;
624 }
625
626 if (stat((char*) di.path, &st) < 0)
627 return -errno;
628
629 if (!S_ISBLK(st.st_mode))
630 return -ENODEV;
631
632 if (major(st.st_rdev) == 0)
633 return -ENODEV;
634
635 *dev = st.st_rdev;
636 return 1;
637 }
638
639 return -ENODEV;
640}
641
642static int get_block_device(const char *path, dev_t *dev) {
643 struct stat st;
644 struct statfs sfs;
645
646 assert(path);
647 assert(dev);
648
e48fdd84 649 if (lstat(path, &st))
1a14a53c
LP
650 return -errno;
651
652 if (major(st.st_dev) != 0) {
653 *dev = st.st_dev;
654 return 1;
655 }
656
e48fdd84 657 if (statfs(path, &sfs) < 0)
1a14a53c
LP
658 return -errno;
659
c51cf056 660 if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
1a14a53c
LP
661 return get_btrfs_block_device(path, dev);
662
663 return 0;
664}
665
73b80ec2
LP
666static int parse_proc_cmdline_item(const char *key, const char *value) {
667 int r;
1a14a53c 668
73b80ec2 669 assert(key);
1a14a53c 670
73b80ec2 671 if (STR_IN_SET(key, "systemd.gpt_auto", "rd.systemd.gpt_auto") && value) {
1a14a53c 672
73b80ec2
LP
673 r = parse_boolean(value);
674 if (r < 0)
675 log_warning("Failed to parse gpt-auto switch %s. Ignoring.", value);
1a14a53c 676
73b80ec2 677 arg_enabled = r;
1a14a53c 678
73b80ec2
LP
679 } else if (streq(key, "root") && value) {
680
681 /* Disable root disk logic if there's a root= value
682 * specified (unless it happens to be "gpt-auto") */
683
684 arg_root_enabled = streq(value, "gpt-auto");
685
686 } else if (streq(key, "rw") && !value)
687 arg_root_rw = true;
688 else if (streq(key, "ro") && !value)
689 arg_root_rw = false;
690 else if (startswith(key, "systemd.gpt-auto.") || startswith(key, "rd.systemd.gpt-auto."))
691 log_warning("Unknown kernel switch %s. Ignoring.", key);
692
693 return 0;
694}
695
696static int add_root_mount(void) {
697
698#ifdef ENABLE_EFI
699 int r;
700
701 if (!is_efi_boot()) {
702 log_debug("Not a EFI boot, not creating root mount.");
703 return 0;
9a5cb137
ZJS
704 }
705
73b80ec2
LP
706 r = efi_loader_get_device_part_uuid(NULL);
707 if (r == -ENOENT) {
708 log_debug("EFI loader partition unknown, exiting.");
709 return 0;
710 } else if (r < 0) {
711 log_error("Failed to read ESP partition UUID: %s", strerror(-r));
712 return r;
3db604b9 713 }
1a14a53c 714
73b80ec2
LP
715 /* OK, we have an ESP partition, this is fantastic, so let's
716 * wait for a root device to show up. A udev rule will create
717 * the link for us under the right name. */
718
719 return add_mount(
720 "root",
98b2f766 721 "/dev/gpt-auto-root",
73b80ec2
LP
722 in_initrd() ? "/sysroot" : "/",
723 NULL,
cca1dfdd 724 arg_root_rw,
73b80ec2
LP
725 "Root Partition",
726 in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_LOCAL_FS_TARGET);
727#else
728 return 0;
729#endif
730}
731
732static int add_mounts(void) {
73b80ec2
LP
733 dev_t devno;
734 int r;
735
3db604b9 736 r = get_block_device("/", &devno);
1a14a53c
LP
737 if (r < 0) {
738 log_error("Failed to determine block device of root file system: %s", strerror(-r));
73b80ec2 739 return r;
e48fdd84 740 } else if (r == 0) {
1a14a53c 741 log_debug("Root file system not on a (single) block device.");
73b80ec2 742 return 0;
3db604b9
LP
743 }
744
61331eab 745 return enumerate_partitions(devno);
73b80ec2
LP
746}
747
748int main(int argc, char *argv[]) {
749 int r = 0;
750
751 if (argc > 1 && argc != 4) {
752 log_error("This program takes three or no arguments.");
753 return EXIT_FAILURE;
754 }
755
756 if (argc > 1)
757 arg_dest = argv[3];
758
759 log_set_target(LOG_TARGET_SAFE);
760 log_parse_environment();
761 log_open();
762
763 umask(0022);
764
765 if (detect_container(NULL) > 0) {
766 log_debug("In a container, exiting.");
e48fdd84 767 return EXIT_SUCCESS;
1a14a53c 768 }
3db604b9 769
73b80ec2 770 if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)
e48fdd84 771 return EXIT_FAILURE;
1a14a53c 772
73b80ec2
LP
773 if (!arg_enabled) {
774 log_debug("Disabled, exiting.");
775 return EXIT_SUCCESS;
776 }
777
778 if (arg_root_enabled)
779 r = add_root_mount();
780
781 if (!in_initrd()) {
782 int k;
783
784 k = add_mounts();
785 if (k < 0)
786 r = k;
787 }
788
789 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1a14a53c 790}