]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/gpt-auto-generator/gpt-auto-generator.c
util-lib: move /proc/cmdline parsing code to proc-cmdline.[ch]
[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>
1a14a53c 24#include <sys/statfs.h>
96115cdf 25#include <blkid/blkid.h>
1a14a53c 26
1af72119 27#include "libudev.h"
07630cea
LP
28#include "sd-id128.h"
29
30#include "blkid-util.h"
31#include "btrfs-util.h"
a0956174 32#include "dirent-util.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
cca1dfdd 58static int add_cryptsetup(const char *id, const char *what, bool rw, char **device) {
1af72119
LP
59 _cleanup_free_ char *e = NULL, *n = NULL, *p = NULL, *d = NULL, *to = NULL;
60 _cleanup_fclose_ FILE *f = NULL;
61 char *from, *ret;
62 int r;
63
64 assert(id);
65 assert(what);
66 assert(device);
67
7410616c
LP
68 r = unit_name_from_path(what, ".device", &d);
69 if (r < 0)
70 return log_error_errno(r, "Failed to generate unit name: %m");
1af72119
LP
71
72 e = unit_name_escape(id);
73 if (!e)
74 return log_oom();
75
7410616c
LP
76 r = unit_name_build("systemd-cryptsetup", e, ".service", &n);
77 if (r < 0)
78 return log_error_errno(r, "Failed to generate unit name: %m");
1af72119
LP
79
80 p = strjoin(arg_dest, "/", n, NULL);
821b2e79 81 if (!p)
1af72119
LP
82 return log_oom();
83
84 f = fopen(p, "wxe");
4a62c710
MS
85 if (!f)
86 return log_error_errno(errno, "Failed to create unit file %s: %m", p);
1af72119
LP
87
88 fprintf(f,
89 "# Automatically generated by systemd-gpt-auto-generator\n\n"
90 "[Unit]\n"
91 "Description=Cryptography Setup for %%I\n"
c3834f9b 92 "Documentation=man:systemd-gpt-auto-generator(8) man:systemd-cryptsetup@.service(8)\n"
1af72119
LP
93 "DefaultDependencies=no\n"
94 "Conflicts=umount.target\n"
95 "BindsTo=dev-mapper-%%i.device %s\n"
96 "Before=umount.target cryptsetup.target\n"
97 "After=%s\n"
98 "IgnoreOnIsolate=true\n"
1af72119
LP
99 "[Service]\n"
100 "Type=oneshot\n"
101 "RemainAfterExit=yes\n"
102 "TimeoutSec=0\n" /* the binary handles timeouts anyway */
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
63c372cb 113 from = strjoina("../", n);
1af72119
LP
114
115 to = strjoin(arg_dest, "/", d, ".wants/", n, NULL);
116 if (!to)
117 return log_oom();
118
119 mkdir_parents_label(to, 0755);
4a62c710
MS
120 if (symlink(from, to) < 0)
121 return log_error_errno(errno, "Failed to create symlink %s: %m", to);
1af72119
LP
122
123 free(to);
124 to = strjoin(arg_dest, "/cryptsetup.target.requires/", n, NULL);
125 if (!to)
126 return log_oom();
127
128 mkdir_parents_label(to, 0755);
4a62c710
MS
129 if (symlink(from, to) < 0)
130 return log_error_errno(errno, "Failed to create symlink %s: %m", to);
1af72119
LP
131
132 free(to);
133 to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n, NULL);
134 if (!to)
135 return log_oom();
136
137 mkdir_parents_label(to, 0755);
4a62c710
MS
138 if (symlink(from, to) < 0)
139 return log_error_errno(errno, "Failed to create symlink %s: %m", to);
1af72119
LP
140
141 free(p);
142 p = strjoin(arg_dest, "/dev-mapper-", e, ".device.d/50-job-timeout-sec-0.conf", NULL);
143 if (!p)
144 return log_oom();
145
146 mkdir_parents_label(p, 0755);
147 r = write_string_file(p,
148 "# Automatically generated by systemd-gpt-auto-generator\n\n"
149 "[Unit]\n"
4c1fc3e4
DM
150 "JobTimeoutSec=0\n",
151 WRITE_STRING_FILE_CREATE); /* the binary handles timeouts anyway */
23bbb0de
MS
152 if (r < 0)
153 return log_error_errno(r, "Failed to write device drop-in: %m");
1af72119
LP
154
155 ret = strappend("/dev/mapper/", id);
156 if (!ret)
157 return log_oom();
158
159 *device = ret;
160 return 0;
161}
162
73b80ec2
LP
163static int add_mount(
164 const char *id,
165 const char *what,
166 const char *where,
167 const char *fstype,
cca1dfdd 168 bool rw,
59512f21 169 const char *options,
73b80ec2
LP
170 const char *description,
171 const char *post) {
172
1af72119 173 _cleanup_free_ char *unit = NULL, *lnk = NULL, *crypto_what = NULL, *p = NULL;
1a14a53c 174 _cleanup_fclose_ FILE *f = NULL;
e48fdd84 175 int r;
1a14a53c 176
1af72119
LP
177 assert(id);
178 assert(what);
179 assert(where);
1af72119
LP
180 assert(description);
181
73b80ec2 182 log_debug("Adding %s: %s %s", where, what, strna(fstype));
1a14a53c 183
73b80ec2 184 if (streq_ptr(fstype, "crypto_LUKS")) {
1af72119 185
cca1dfdd 186 r = add_cryptsetup(id, what, rw, &crypto_what);
1af72119
LP
187 if (r < 0)
188 return r;
189
190 what = crypto_what;
191 fstype = NULL;
192 }
193
7410616c
LP
194 r = unit_name_from_path(where, ".mount", &unit);
195 if (r < 0)
196 return log_error_errno(r, "Failed to generate unit name: %m");
1a14a53c 197
e48fdd84
LP
198 p = strjoin(arg_dest, "/", unit, NULL);
199 if (!p)
200 return log_oom();
201
202 f = fopen(p, "wxe");
4a62c710
MS
203 if (!f)
204 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
1a14a53c
LP
205
206 fprintf(f,
207 "# Automatically generated by systemd-gpt-auto-generator\n\n"
208 "[Unit]\n"
c3834f9b
LP
209 "Description=%s\n"
210 "Documentation=man:systemd-gpt-auto-generator(8)\n",
e48fdd84
LP
211 description);
212
73b80ec2
LP
213 if (post)
214 fprintf(f, "Before=%s\n", post);
215
e48fdd84
LP
216 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
217 if (r < 0)
218 return r;
219
220 fprintf(f,
221 "\n"
1a14a53c
LP
222 "[Mount]\n"
223 "What=%s\n"
1af72119
LP
224 "Where=%s\n",
225 what, where);
226
73b80ec2
LP
227 if (fstype)
228 fprintf(f, "Type=%s\n", fstype);
229
59512f21
KS
230 if (options)
231 fprintf(f, "Options=%s,%s\n", options, rw ? "rw" : "ro");
232 else
233 fprintf(f, "Options=%s\n", rw ? "rw" : "ro");
1a14a53c 234
dacd6cee
LP
235 r = fflush_and_check(f);
236 if (r < 0)
237 return log_error_errno(r, "Failed to write unit file %s: %m", p);
1a14a53c 238
73b80ec2
LP
239 if (post) {
240 lnk = strjoin(arg_dest, "/", post, ".requires/", unit, NULL);
241 if (!lnk)
242 return log_oom();
1a14a53c 243
73b80ec2 244 mkdir_parents_label(lnk, 0755);
4a62c710
MS
245 if (symlink(p, lnk) < 0)
246 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
1a14a53c
LP
247 }
248
249 return 0;
250}
251
59512f21
KS
252static bool path_is_busy(const char *where) {
253 int r;
254
255 /* already a mountpoint; generators run during reload */
256 r = path_is_mount_point(where, AT_SYMLINK_FOLLOW);
257 if (r > 0)
258 return false;
259
260 /* the directory might not exist on a stateless system */
261 if (r == -ENOENT)
262 return false;
263
264 if (r < 0)
265 return true;
266
267 /* not a mountpoint but it contains files */
268 if (dir_is_empty(where) <= 0)
269 return true;
270
271 return false;
272}
273
61331eab
LP
274static int probe_and_add_mount(
275 const char *id,
276 const char *what,
277 const char *where,
cca1dfdd 278 bool rw,
61331eab
LP
279 const char *description,
280 const char *post) {
281
282 _cleanup_blkid_free_probe_ blkid_probe b = NULL;
a0b1209c 283 const char *fstype = NULL;
61331eab
LP
284 int r;
285
286 assert(id);
287 assert(what);
288 assert(where);
289 assert(description);
290
59512f21 291 if (path_is_busy(where)) {
61331eab
LP
292 log_debug("%s already populated, ignoring.", where);
293 return 0;
294 }
295
296 /* Let's check the partition type here, so that we know
297 * whether to do LUKS magic. */
298
299 errno = 0;
300 b = blkid_new_probe_from_filename(what);
301 if (!b) {
302 if (errno == 0)
303 return log_oom();
56f64d95 304 log_error_errno(errno, "Failed to allocate prober: %m");
61331eab
LP
305 return -errno;
306 }
307
308 blkid_probe_enable_superblocks(b, 1);
309 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
310
311 errno = 0;
312 r = blkid_do_safeprobe(b);
313 if (r == -2 || r == 1) /* no result or uncertain */
314 return 0;
a0b1209c
ZJS
315 else if (r != 0)
316 return log_error_errno(errno ?: EIO, "Failed to probe %s: %m", what);
61331eab 317
a0b1209c
ZJS
318 /* add_mount is OK with fstype being NULL. */
319 (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
61331eab
LP
320
321 return add_mount(
322 id,
323 what,
324 where,
325 fstype,
cca1dfdd 326 rw,
59512f21 327 NULL,
61331eab
LP
328 description,
329 post);
330}
331
59512f21
KS
332static int add_swap(const char *path) {
333 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
334 _cleanup_fclose_ FILE *f = NULL;
335 int r;
336
337 assert(path);
338
339 log_debug("Adding swap: %s", path);
340
341 r = unit_name_from_path(path, ".swap", &name);
342 if (r < 0)
343 return log_error_errno(r, "Failed to generate unit name: %m");
344
345 unit = strjoin(arg_dest, "/", name, NULL);
346 if (!unit)
347 return log_oom();
348
349 f = fopen(unit, "wxe");
350 if (!f)
351 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
352
353 fprintf(f,
354 "# Automatically generated by systemd-gpt-auto-generator\n\n"
355 "[Unit]\n"
356 "Description=Swap Partition\n"
357 "Documentation=man:systemd-gpt-auto-generator(8)\n\n"
358 "[Swap]\n"
359 "What=%s\n",
360 path);
361
dacd6cee
LP
362 r = fflush_and_check(f);
363 if (r < 0)
364 return log_error_errno(r, "Failed to write unit file %s: %m", unit);
59512f21
KS
365
366 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
367 if (!lnk)
368 return log_oom();
369
370 mkdir_parents_label(lnk, 0755);
371 if (symlink(unit, lnk) < 0)
372 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
373
374 return 0;
375}
376
59512f21 377#ifdef ENABLE_EFI
7a1494aa
TG
378static int add_automount(
379 const char *id,
380 const char *what,
381 const char *where,
382 const char *fstype,
383 bool rw,
384 const char *options,
385 const char *description,
386 usec_t timeout) {
387
388 _cleanup_free_ char *unit = NULL, *lnk = NULL;
389 _cleanup_free_ char *opt, *p = NULL;
390 _cleanup_fclose_ FILE *f = NULL;
391 int r;
392
393 assert(id);
394 assert(where);
395 assert(description);
396
397 if (options)
398 opt = strjoin(options, ",noauto", NULL);
399 else
400 opt = strdup("noauto");
401 if (!opt)
402 return log_oom();
403
404 r = add_mount(id,
405 what,
406 where,
407 fstype,
408 rw,
409 opt,
410 description,
411 NULL);
412 if (r < 0)
413 return r;
414
415 r = unit_name_from_path(where, ".automount", &unit);
416 if (r < 0)
417 return log_error_errno(r, "Failed to generate unit name: %m");
418
419 p = strjoin(arg_dest, "/", unit, NULL);
420 if (!p)
421 return log_oom();
422
423 f = fopen(p, "wxe");
424 if (!f)
425 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
426
427 fprintf(f,
428 "# Automatically generated by systemd-gpt-auto-generator\n\n"
429 "[Unit]\n"
430 "Description=%s\n"
431 "Documentation=man:systemd-gpt-auto-generator(8)\n"
432 "[Automount]\n"
433 "Where=%s\n"
434 "TimeoutIdleSec=%lld\n",
435 description,
436 where,
437 (unsigned long long)timeout / USEC_PER_SEC);
438
439 r = fflush_and_check(f);
440 if (r < 0)
441 return log_error_errno(r, "Failed to write unit file %s: %m", p);
442
443 lnk = strjoin(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".wants/", unit, NULL);
444 if (!lnk)
445 return log_oom();
446 mkdir_parents_label(lnk, 0755);
447
448 if (symlink(p, lnk) < 0)
449 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
450
451 return 0;
452}
453
454static int add_boot(const char *what) {
59512f21
KS
455 _cleanup_blkid_free_probe_ blkid_probe b = NULL;
456 const char *fstype = NULL, *uuid = NULL;
457 sd_id128_t id, type_id;
458 int r;
459
460 assert(what);
461
462 if (!is_efi_boot()) {
463 log_debug("Not an EFI boot, ignoring /boot.");
464 return 0;
465 }
466
467 if (in_initrd()) {
468 log_debug("In initrd, ignoring /boot.");
469 return 0;
470 }
471
75f86906 472 if (detect_container() > 0) {
59512f21
KS
473 log_debug("In a container, ignoring /boot.");
474 return 0;
475 }
476
0b6b6787
KS
477 /* We create an .automount which is not overridden by the .mount from the fstab generator. */
478 if (fstab_is_mount_point("/boot")) {
479 log_debug("/boot specified in fstab, ignoring.");
480 return 0;
481 }
482
59512f21
KS
483 if (path_is_busy("/boot")) {
484 log_debug("/boot already populated, ignoring.");
485 return 0;
486 }
487
488 r = efi_loader_get_device_part_uuid(&id);
489 if (r == -ENOENT) {
490 log_debug("EFI loader partition unknown.");
491 return 0;
492 }
493
494 if (r < 0) {
495 log_error_errno(r, "Failed to read ESP partition UUID: %m");
496 return r;
497 }
498
499 errno = 0;
500 b = blkid_new_probe_from_filename(what);
501 if (!b) {
502 if (errno == 0)
503 return log_oom();
504 log_error_errno(errno, "Failed to allocate prober: %m");
505 return -errno;
506 }
507
508 blkid_probe_enable_partitions(b, 1);
509 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
510
511 errno = 0;
512 r = blkid_do_safeprobe(b);
513 if (r == -2 || r == 1) /* no result or uncertain */
514 return 0;
515 else if (r != 0)
516 return log_error_errno(errno ?: EIO, "Failed to probe %s: %m", what);
517
518 (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
519 if (!streq(fstype, "vfat")) {
520 log_debug("Partition for /boot is not a FAT filesystem, ignoring.");
521 return 0;
522 }
523
524 r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &uuid, NULL);
525 if (r != 0) {
526 log_debug_errno(r, "Partition for /boot does not have a UUID, ignoring. %m");
527 return 0;
528 }
529
530 if (sd_id128_from_string(uuid, &type_id) < 0) {
531 log_debug("Partition for /boot does not have a valid UUID, ignoring.");
532 return 0;
533 }
534
535 if (!sd_id128_equal(type_id, id)) {
536 log_debug("Partition for /boot does not appear to be the partition we are booted from.");
537 return 0;
538 }
539
540 r = add_automount("boot",
541 what,
542 "/boot",
543 "vfat",
158df4b6 544 true,
59512f21 545 "umask=0077",
158df4b6 546 "EFI System Partition Automount",
59512f21
KS
547 120 * USEC_PER_SEC);
548
549 return r;
7a1494aa 550}
59512f21 551#else
7a1494aa 552static int add_boot(const char *what) {
59512f21 553 return 0;
59512f21 554}
7a1494aa 555#endif
59512f21 556
61331eab
LP
557static int enumerate_partitions(dev_t devnum) {
558
1ca208fb
ZJS
559 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
560 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
61331eab
LP
561 _cleanup_blkid_free_probe_ blkid_probe b = NULL;
562 _cleanup_udev_unref_ struct udev *udev = NULL;
59512f21 563 _cleanup_free_ char *boot = NULL, *home = NULL, *srv = NULL;
1a14a53c 564 struct udev_list_entry *first, *item;
e48fdd84 565 struct udev_device *parent = NULL;
d2a62382 566 const char *name, *node, *pttype, *devtype;
59512f21 567 int boot_nr = -1, home_nr = -1, srv_nr = -1;
cca1dfdd 568 bool home_rw = true, srv_rw = true;
61331eab 569 blkid_partlist pl;
73b80ec2 570 int r, k;
61331eab 571 dev_t pn;
1a14a53c 572
61331eab
LP
573 udev = udev_new();
574 if (!udev)
b47d419c 575 return log_oom();
1a14a53c 576
61331eab 577 d = udev_device_new_from_devnum(udev, 'b', devnum);
1ca208fb
ZJS
578 if (!d)
579 return log_oom();
1a14a53c 580
d2a62382
ZJS
581 name = udev_device_get_devnode(d);
582 if (!name)
583 name = udev_device_get_syspath(d);
584 if (!name) {
585 log_debug("Device %u:%u does not have a name, ignoring.",
586 major(devnum), minor(devnum));
587 return 0;
588 }
589
1a14a53c 590 parent = udev_device_get_parent(d);
fa041593 591 if (!parent) {
d2a62382 592 log_debug("%s: not a partitioned device, ignoring.", name);
9c4495ca 593 return 0;
fa041593 594 }
1a14a53c 595
61331eab
LP
596 /* Does it have a devtype? */
597 devtype = udev_device_get_devtype(parent);
fa041593 598 if (!devtype) {
d2a62382 599 log_debug("%s: parent doesn't have a device type, ignoring.", name);
61331eab 600 return 0;
fa041593 601 }
61331eab
LP
602
603 /* Is this a disk or a partition? We only care for disks... */
fa041593 604 if (!streq(devtype, "disk")) {
d2a62382 605 log_debug("%s: parent isn't a raw disk, ignoring.", name);
61331eab 606 return 0;
fa041593 607 }
61331eab
LP
608
609 /* Does it have a device node? */
610 node = udev_device_get_devnode(parent);
fa041593 611 if (!node) {
d2a62382 612 log_debug("%s: parent device does not have device node, ignoring.", name);
61331eab 613 return 0;
fa041593 614 }
61331eab 615
d2a62382 616 log_debug("%s: root device %s.", name, node);
61331eab
LP
617
618 pn = udev_device_get_devnum(parent);
619 if (major(pn) == 0)
620 return 0;
621
622 errno = 0;
623 b = blkid_new_probe_from_filename(node);
624 if (!b) {
625 if (errno == 0)
626 return log_oom();
627
d2a62382 628 return log_error_errno(errno, "%s: failed to allocate prober: %m", node);
61331eab
LP
629 }
630
61331eab
LP
631 blkid_probe_enable_partitions(b, 1);
632 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
633
634 errno = 0;
635 r = blkid_do_safeprobe(b);
458a2f85
TG
636 if (r == 1)
637 return 0; /* no results */
638 else if (r == -2) {
639 log_warning("%s: probe gave ambiguous results, ignoring", node);
61331eab 640 return 0;
458a2f85 641 } else if (r != 0)
d2a62382 642 return log_error_errno(errno ?: EIO, "%s: failed to probe: %m", node);
61331eab
LP
643
644 errno = 0;
645 r = blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
d2a62382
ZJS
646 if (r != 0)
647 return log_error_errno(errno ?: EIO,
648 "%s: failed to determine partition table type: %m", node);
61331eab
LP
649
650 /* We only do this all for GPT... */
fa041593 651 if (!streq_ptr(pttype, "gpt")) {
d2a62382 652 log_debug("%s: not a GPT partition table, ignoring.", node);
61331eab 653 return 0;
fa041593 654 }
61331eab
LP
655
656 errno = 0;
657 pl = blkid_probe_get_partitions(b);
658 if (!pl) {
659 if (errno == 0)
660 return log_oom();
661
d2a62382 662 return log_error_errno(errno, "%s: failed to list partitions: %m", node);
61331eab
LP
663 }
664
665 e = udev_enumerate_new(udev);
666 if (!e)
667 return log_oom();
668
1a14a53c 669 r = udev_enumerate_add_match_parent(e, parent);
1ca208fb
ZJS
670 if (r < 0)
671 return log_oom();
1a14a53c
LP
672
673 r = udev_enumerate_add_match_subsystem(e, "block");
1ca208fb
ZJS
674 if (r < 0)
675 return log_oom();
1a14a53c
LP
676
677 r = udev_enumerate_scan_devices(e);
23bbb0de 678 if (r < 0)
d2a62382 679 return log_error_errno(r, "%s: failed to enumerate partitions: %m", node);
1a14a53c
LP
680
681 first = udev_enumerate_get_list_entry(e);
682 udev_list_entry_foreach(item, first) {
e48fdd84 683 _cleanup_udev_device_unref_ struct udev_device *q;
dd2c31bb 684 unsigned long long flags;
61331eab 685 const char *stype, *subnode;
1a14a53c 686 sd_id128_t type_id;
61331eab
LP
687 blkid_partition pp;
688 dev_t qn;
689 int nr;
1a14a53c
LP
690
691 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
1ca208fb 692 if (!q)
61331eab 693 continue;
1a14a53c 694
61331eab
LP
695 qn = udev_device_get_devnum(q);
696 if (major(qn) == 0)
1ca208fb 697 continue;
1a14a53c 698
61331eab 699 if (qn == devnum)
1ca208fb 700 continue;
1a14a53c 701
61331eab
LP
702 if (qn == pn)
703 continue;
1a14a53c 704
61331eab
LP
705 subnode = udev_device_get_devnode(q);
706 if (!subnode)
707 continue;
73b80ec2 708
61331eab
LP
709 pp = blkid_partlist_devno_to_partition(pl, qn);
710 if (!pp)
73b80ec2 711 continue;
61331eab
LP
712
713 nr = blkid_partition_get_partno(pp);
714 if (nr < 0)
715 continue;
716
717 stype = blkid_partition_get_type_string(pp);
718 if (!stype)
719 continue;
720
721 if (sd_id128_from_string(stype, &type_id) < 0)
1ca208fb 722 continue;
1a14a53c 723
dd2c31bb
LP
724 flags = blkid_partition_get_flags(pp);
725
73b80ec2 726 if (sd_id128_equal(type_id, GPT_SWAP)) {
0238d4c6 727
0238d4c6
KS
728 if (flags & GPT_FLAG_NO_AUTO)
729 continue;
73b80ec2 730
cca1dfdd 731 if (flags & GPT_FLAG_READ_ONLY) {
d2a62382 732 log_debug("%s marked as read-only swap partition, which is bogus. Ignoring.", subnode);
cca1dfdd
LP
733 continue;
734 }
735
61331eab 736 k = add_swap(subnode);
73b80ec2
LP
737 if (k < 0)
738 r = k;
e48fdd84 739
59512f21
KS
740 } else if (sd_id128_equal(type_id, GPT_ESP)) {
741
742 /* We only care for the first /boot partition */
743 if (boot && nr >= boot_nr)
744 continue;
745
dd2c31bb
LP
746 /* Note that we do not honour the "no-auto"
747 * flag for the ESP, as it is often unset, to
748 * hide it from Windows. */
749
59512f21
KS
750 boot_nr = nr;
751
2fc09a9c
DM
752 r = free_and_strdup(&boot, subnode);
753 if (r < 0)
59512f21
KS
754 return log_oom();
755
73b80ec2 756 } else if (sd_id128_equal(type_id, GPT_HOME)) {
0238d4c6 757
0238d4c6
KS
758 if (flags & GPT_FLAG_NO_AUTO)
759 continue;
e48fdd84
LP
760
761 /* We only care for the first /home partition */
762 if (home && nr >= home_nr)
763 continue;
764
765 home_nr = nr;
cca1dfdd 766 home_rw = !(flags & GPT_FLAG_READ_ONLY),
e48fdd84 767
2fc09a9c
DM
768 r = free_and_strdup(&home, subnode);
769 if (r < 0)
e48fdd84
LP
770 return log_oom();
771
e48fdd84 772 } else if (sd_id128_equal(type_id, GPT_SRV)) {
0238d4c6 773
0238d4c6
KS
774 if (flags & GPT_FLAG_NO_AUTO)
775 continue;
e48fdd84
LP
776
777 /* We only care for the first /srv partition */
778 if (srv && nr >= srv_nr)
779 continue;
780
781 srv_nr = nr;
cca1dfdd 782 srv_rw = !(flags & GPT_FLAG_READ_ONLY),
e48fdd84 783
2fc09a9c
DM
784 r = free_and_strdup(&srv, subnode);
785 if (r < 0)
e48fdd84 786 return log_oom();
1a14a53c 787 }
1a14a53c
LP
788 }
789
59512f21
KS
790 if (boot) {
791 k = add_boot(boot);
792 if (k < 0)
793 r = k;
794 }
795
61331eab 796 if (home) {
cca1dfdd 797 k = probe_and_add_mount("home", home, "/home", home_rw, "Home Partition", SPECIAL_LOCAL_FS_TARGET);
73b80ec2
LP
798 if (k < 0)
799 r = k;
800 }
e48fdd84 801
61331eab 802 if (srv) {
cca1dfdd 803 k = probe_and_add_mount("srv", srv, "/srv", srv_rw, "Server Data Partition", SPECIAL_LOCAL_FS_TARGET);
73b80ec2
LP
804 if (k < 0)
805 r = k;
806 }
1a14a53c 807
1a14a53c
LP
808 return r;
809}
810
1a14a53c
LP
811static int get_block_device(const char *path, dev_t *dev) {
812 struct stat st;
813 struct statfs sfs;
814
815 assert(path);
816 assert(dev);
817
c6ba0c18
LP
818 /* Get's the block device directly backing a file system. If
819 * the block device is encrypted, returns the device mapper
820 * block device. */
821
e48fdd84 822 if (lstat(path, &st))
1a14a53c
LP
823 return -errno;
824
825 if (major(st.st_dev) != 0) {
826 *dev = st.st_dev;
827 return 1;
828 }
829
e48fdd84 830 if (statfs(path, &sfs) < 0)
1a14a53c
LP
831 return -errno;
832
c51cf056 833 if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
f9ac1544 834 return btrfs_get_block_device(path, dev);
1a14a53c
LP
835
836 return 0;
837}
838
c6ba0c18
LP
839static int get_block_device_harder(const char *path, dev_t *dev) {
840 _cleanup_closedir_ DIR *d = NULL;
841 _cleanup_free_ char *p = NULL, *t = NULL;
842 struct dirent *de, *found = NULL;
843 const char *q;
844 unsigned maj, min;
845 dev_t dt;
846 int r;
847
848 assert(path);
849 assert(dev);
850
851 /* Gets the backing block device for a file system, and
852 * handles LUKS encrypted file systems, looking for its
853 * immediate parent, if there is one. */
854
855 r = get_block_device(path, &dt);
856 if (r <= 0)
857 return r;
858
859 if (asprintf(&p, "/sys/dev/block/%u:%u/slaves", major(dt), minor(dt)) < 0)
860 return -ENOMEM;
861
862 d = opendir(p);
863 if (!d) {
864 if (errno == ENOENT)
865 goto fallback;
866
867 return -errno;
868 }
869
870 FOREACH_DIRENT_ALL(de, d, return -errno) {
871
872 if (STR_IN_SET(de->d_name, ".", ".."))
873 continue;
874
875 if (!IN_SET(de->d_type, DT_LNK, DT_UNKNOWN))
876 continue;
877
878 if (found) /* Don't try to support multiple backing block devices */
879 goto fallback;
880
881 found = de;
c6ba0c18
LP
882 }
883
884 if (!found)
885 goto fallback;
886
887 q = strjoina(p, "/", found->d_name, "/dev");
888
889 r = read_one_line_file(q, &t);
890 if (r == -ENOENT)
891 goto fallback;
892 if (r < 0)
893 return r;
894
895 if (sscanf(t, "%u:%u", &maj, &min) != 2)
896 return -EINVAL;
897
898 if (maj == 0)
899 goto fallback;
900
901 *dev = makedev(maj, min);
902 return 1;
903
904fallback:
905 *dev = dt;
906 return 1;
907}
908
73b80ec2
LP
909static int parse_proc_cmdline_item(const char *key, const char *value) {
910 int r;
1a14a53c 911
73b80ec2 912 assert(key);
1a14a53c 913
73b80ec2 914 if (STR_IN_SET(key, "systemd.gpt_auto", "rd.systemd.gpt_auto") && value) {
1a14a53c 915
73b80ec2
LP
916 r = parse_boolean(value);
917 if (r < 0)
d2a62382 918 log_warning("Failed to parse gpt-auto switch \"%s\". Ignoring.", value);
8086ffac
ZJS
919 else
920 arg_enabled = r;
1a14a53c 921
73b80ec2
LP
922 } else if (streq(key, "root") && value) {
923
924 /* Disable root disk logic if there's a root= value
925 * specified (unless it happens to be "gpt-auto") */
926
927 arg_root_enabled = streq(value, "gpt-auto");
928
929 } else if (streq(key, "rw") && !value)
930 arg_root_rw = true;
931 else if (streq(key, "ro") && !value)
932 arg_root_rw = false;
73b80ec2
LP
933
934 return 0;
935}
936
937static int add_root_mount(void) {
938
939#ifdef ENABLE_EFI
940 int r;
941
942 if (!is_efi_boot()) {
943 log_debug("Not a EFI boot, not creating root mount.");
944 return 0;
9a5cb137
ZJS
945 }
946
73b80ec2
LP
947 r = efi_loader_get_device_part_uuid(NULL);
948 if (r == -ENOENT) {
949 log_debug("EFI loader partition unknown, exiting.");
950 return 0;
23bbb0de
MS
951 } else if (r < 0)
952 return log_error_errno(r, "Failed to read ESP partition UUID: %m");
1a14a53c 953
73b80ec2
LP
954 /* OK, we have an ESP partition, this is fantastic, so let's
955 * wait for a root device to show up. A udev rule will create
956 * the link for us under the right name. */
957
958 return add_mount(
959 "root",
98b2f766 960 "/dev/gpt-auto-root",
73b80ec2
LP
961 in_initrd() ? "/sysroot" : "/",
962 NULL,
cca1dfdd 963 arg_root_rw,
59512f21 964 NULL,
73b80ec2
LP
965 "Root Partition",
966 in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_LOCAL_FS_TARGET);
967#else
968 return 0;
969#endif
970}
971
972static int add_mounts(void) {
73b80ec2
LP
973 dev_t devno;
974 int r;
975
c6ba0c18 976 r = get_block_device_harder("/", &devno);
23bbb0de
MS
977 if (r < 0)
978 return log_error_errno(r, "Failed to determine block device of root file system: %m");
979 else if (r == 0) {
c6ba0c18 980 r = get_block_device_harder("/usr", &devno);
eafe88e3
TH
981 if (r < 0)
982 return log_error_errno(r, "Failed to determine block device of /usr file system: %m");
983 else if (r == 0) {
984 log_debug("Neither root nor /usr file system are on a (single) block device.");
985 return 0;
986 }
3db604b9
LP
987 }
988
61331eab 989 return enumerate_partitions(devno);
73b80ec2
LP
990}
991
992int main(int argc, char *argv[]) {
993 int r = 0;
994
995 if (argc > 1 && argc != 4) {
996 log_error("This program takes three or no arguments.");
997 return EXIT_FAILURE;
998 }
999
1000 if (argc > 1)
1001 arg_dest = argv[3];
1002
1003 log_set_target(LOG_TARGET_SAFE);
1004 log_parse_environment();
1005 log_open();
1006
1007 umask(0022);
1008
75f86906 1009 if (detect_container() > 0) {
73b80ec2 1010 log_debug("In a container, exiting.");
e48fdd84 1011 return EXIT_SUCCESS;
1a14a53c 1012 }
3db604b9 1013
b5884878
LP
1014 r = parse_proc_cmdline(parse_proc_cmdline_item);
1015 if (r < 0)
da927ba9 1016 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
1a14a53c 1017
73b80ec2
LP
1018 if (!arg_enabled) {
1019 log_debug("Disabled, exiting.");
1020 return EXIT_SUCCESS;
1021 }
1022
1023 if (arg_root_enabled)
1024 r = add_root_mount();
1025
1026 if (!in_initrd()) {
1027 int k;
1028
1029 k = add_mounts();
1030 if (k < 0)
1031 r = k;
1032 }
1033
1034 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1a14a53c 1035}