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