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