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