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