]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/gpt-auto-generator/gpt-auto-generator.c
treewide: use log_*_errno whenever %m is in the format string
[thirdparty/systemd.git] / src / gpt-auto-generator / gpt-auto-generator.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2013 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <unistd.h>
23 #include <stdlib.h>
24 #include <fcntl.h>
25 #include <sys/ioctl.h>
26 #include <sys/statfs.h>
27 #include <blkid/blkid.h>
28
29 #ifdef HAVE_LINUX_BTRFS_H
30 #include <linux/btrfs.h>
31 #endif
32
33 #include "sd-id128.h"
34 #include "libudev.h"
35 #include "path-util.h"
36 #include "util.h"
37 #include "mkdir.h"
38 #include "missing.h"
39 #include "udev-util.h"
40 #include "special.h"
41 #include "unit-name.h"
42 #include "virt.h"
43 #include "generator.h"
44 #include "gpt.h"
45 #include "fileio.h"
46 #include "efivars.h"
47 #include "blkid-util.h"
48
49 static const char *arg_dest = "/tmp";
50 static bool arg_enabled = true;
51 static bool arg_root_enabled = true;
52 static bool arg_root_rw = false;
53
54 static int add_swap(const char *path) {
55 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
56 _cleanup_fclose_ FILE *f = NULL;
57
58 assert(path);
59
60 log_debug("Adding swap: %s", path);
61
62 name = unit_name_from_path(path, ".swap");
63 if (!name)
64 return log_oom();
65
66 unit = strjoin(arg_dest, "/", name, NULL);
67 if (!unit)
68 return log_oom();
69
70 f = fopen(unit, "wxe");
71 if (!f) {
72 log_error_errno(errno, "Failed to create unit file %s: %m", unit);
73 return -errno;
74 }
75
76 fprintf(f,
77 "# Automatically generated by systemd-gpt-auto-generator\n\n"
78 "[Unit]\n"
79 "Description=Swap Partition\n"
80 "Documentation=man:systemd-gpt-auto-generator(8)\n\n"
81 "[Swap]\n"
82 "What=%s\n",
83 path);
84
85 fflush(f);
86 if (ferror(f)) {
87 log_error_errno(errno, "Failed to write unit file %s: %m", unit);
88 return -errno;
89 }
90
91 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
92 if (!lnk)
93 return log_oom();
94
95 mkdir_parents_label(lnk, 0755);
96 if (symlink(unit, lnk) < 0) {
97 log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
98 return -errno;
99 }
100
101 return 0;
102 }
103
104 static int add_cryptsetup(const char *id, const char *what, bool rw, char **device) {
105 _cleanup_free_ char *e = NULL, *n = NULL, *p = NULL, *d = NULL, *to = NULL;
106 _cleanup_fclose_ FILE *f = NULL;
107 char *from, *ret;
108 int r;
109
110 assert(id);
111 assert(what);
112 assert(device);
113
114 d = unit_name_from_path(what, ".device");
115 if (!d)
116 return log_oom();
117
118 e = unit_name_escape(id);
119 if (!e)
120 return log_oom();
121
122 n = unit_name_build("systemd-cryptsetup", e, ".service");
123 if (!n)
124 return log_oom();
125
126 p = strjoin(arg_dest, "/", n, NULL);
127 if (!p)
128 return log_oom();
129
130 f = fopen(p, "wxe");
131 if (!f) {
132 log_error_errno(errno, "Failed to create unit file %s: %m", p);
133 return -errno;
134 }
135
136 fprintf(f,
137 "# Automatically generated by systemd-gpt-auto-generator\n\n"
138 "[Unit]\n"
139 "Description=Cryptography Setup for %%I\n"
140 "Documentation=man:systemd-gpt-auto-generator(8) man:systemd-cryptsetup@.service(8)\n"
141 "DefaultDependencies=no\n"
142 "Conflicts=umount.target\n"
143 "BindsTo=dev-mapper-%%i.device %s\n"
144 "Before=umount.target cryptsetup.target\n"
145 "After=%s\n"
146 "IgnoreOnIsolate=true\n"
147 "[Service]\n"
148 "Type=oneshot\n"
149 "RemainAfterExit=yes\n"
150 "TimeoutSec=0\n" /* the binary handles timeouts anyway */
151 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '' '%s'\n"
152 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
153 d, d,
154 id, what, rw ? "" : "read-only",
155 id);
156
157 fflush(f);
158 if (ferror(f)) {
159 log_error_errno(errno, "Failed to write file %s: %m", p);
160 return -errno;
161 }
162
163 from = strappenda("../", n);
164
165 to = strjoin(arg_dest, "/", d, ".wants/", n, NULL);
166 if (!to)
167 return log_oom();
168
169 mkdir_parents_label(to, 0755);
170 if (symlink(from, to) < 0) {
171 log_error_errno(errno, "Failed to create symlink %s: %m", to);
172 return -errno;
173 }
174
175 free(to);
176 to = strjoin(arg_dest, "/cryptsetup.target.requires/", n, NULL);
177 if (!to)
178 return log_oom();
179
180 mkdir_parents_label(to, 0755);
181 if (symlink(from, to) < 0) {
182 log_error_errno(errno, "Failed to create symlink %s: %m", to);
183 return -errno;
184 }
185
186 free(to);
187 to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n, NULL);
188 if (!to)
189 return log_oom();
190
191 mkdir_parents_label(to, 0755);
192 if (symlink(from, to) < 0) {
193 log_error_errno(errno, "Failed to create symlink %s: %m", to);
194 return -errno;
195 }
196
197 free(p);
198 p = strjoin(arg_dest, "/dev-mapper-", e, ".device.d/50-job-timeout-sec-0.conf", NULL);
199 if (!p)
200 return log_oom();
201
202 mkdir_parents_label(p, 0755);
203 r = write_string_file(p,
204 "# Automatically generated by systemd-gpt-auto-generator\n\n"
205 "[Unit]\n"
206 "JobTimeoutSec=0\n"); /* the binary handles timeouts anyway */
207 if (r < 0)
208 return log_error_errno(r, "Failed to write device drop-in: %m");
209
210 ret = strappend("/dev/mapper/", id);
211 if (!ret)
212 return log_oom();
213
214 *device = ret;
215 return 0;
216 }
217
218 static int add_mount(
219 const char *id,
220 const char *what,
221 const char *where,
222 const char *fstype,
223 bool rw,
224 const char *description,
225 const char *post) {
226
227 _cleanup_free_ char *unit = NULL, *lnk = NULL, *crypto_what = NULL, *p = NULL;
228 _cleanup_fclose_ FILE *f = NULL;
229 int r;
230
231 assert(id);
232 assert(what);
233 assert(where);
234 assert(description);
235
236 log_debug("Adding %s: %s %s", where, what, strna(fstype));
237
238 if (streq_ptr(fstype, "crypto_LUKS")) {
239
240 r = add_cryptsetup(id, what, rw, &crypto_what);
241 if (r < 0)
242 return r;
243
244 what = crypto_what;
245 fstype = NULL;
246 }
247
248 unit = unit_name_from_path(where, ".mount");
249 if (!unit)
250 return log_oom();
251
252 p = strjoin(arg_dest, "/", unit, NULL);
253 if (!p)
254 return log_oom();
255
256 f = fopen(p, "wxe");
257 if (!f) {
258 log_error_errno(errno, "Failed to create unit file %s: %m", unit);
259 return -errno;
260 }
261
262 fprintf(f,
263 "# Automatically generated by systemd-gpt-auto-generator\n\n"
264 "[Unit]\n"
265 "Description=%s\n"
266 "Documentation=man:systemd-gpt-auto-generator(8)\n",
267 description);
268
269 if (post)
270 fprintf(f, "Before=%s\n", post);
271
272 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
273 if (r < 0)
274 return r;
275
276 fprintf(f,
277 "\n"
278 "[Mount]\n"
279 "What=%s\n"
280 "Where=%s\n",
281 what, where);
282
283 if (fstype)
284 fprintf(f, "Type=%s\n", fstype);
285
286 fprintf(f, "Options=%s\n", rw ? "rw" : "ro");
287
288 fflush(f);
289 if (ferror(f)) {
290 log_error_errno(errno, "Failed to write unit file %s: %m", p);
291 return -errno;
292 }
293
294 if (post) {
295 lnk = strjoin(arg_dest, "/", post, ".requires/", unit, NULL);
296 if (!lnk)
297 return log_oom();
298
299 mkdir_parents_label(lnk, 0755);
300 if (symlink(p, lnk) < 0) {
301 log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
302 return -errno;
303 }
304 }
305
306 return 0;
307 }
308
309 static int probe_and_add_mount(
310 const char *id,
311 const char *what,
312 const char *where,
313 bool rw,
314 const char *description,
315 const char *post) {
316
317 _cleanup_blkid_free_probe_ blkid_probe b = NULL;
318 const char *fstype;
319 int r;
320
321 assert(id);
322 assert(what);
323 assert(where);
324 assert(description);
325
326 if (path_is_mount_point(where, true) <= 0 &&
327 dir_is_empty(where) <= 0) {
328 log_debug("%s already populated, ignoring.", where);
329 return 0;
330 }
331
332 /* Let's check the partition type here, so that we know
333 * whether to do LUKS magic. */
334
335 errno = 0;
336 b = blkid_new_probe_from_filename(what);
337 if (!b) {
338 if (errno == 0)
339 return log_oom();
340 log_error_errno(errno, "Failed to allocate prober: %m");
341 return -errno;
342 }
343
344 blkid_probe_enable_superblocks(b, 1);
345 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
346
347 errno = 0;
348 r = blkid_do_safeprobe(b);
349 if (r == -2 || r == 1) /* no result or uncertain */
350 return 0;
351 else if (r != 0) {
352 if (errno == 0)
353 errno = EIO;
354 log_error_errno(errno, "Failed to probe %s: %m", what);
355 return -errno;
356 }
357
358 blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
359
360 return add_mount(
361 id,
362 what,
363 where,
364 fstype,
365 rw,
366 description,
367 post);
368 }
369
370 static int enumerate_partitions(dev_t devnum) {
371
372 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
373 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
374 _cleanup_blkid_free_probe_ blkid_probe b = NULL;
375 _cleanup_udev_unref_ struct udev *udev = NULL;
376 _cleanup_free_ char *home = NULL, *srv = NULL;
377 struct udev_list_entry *first, *item;
378 struct udev_device *parent = NULL;
379 const char *node, *pttype, *devtype;
380 int home_nr = -1, srv_nr = -1;
381 bool home_rw = true, srv_rw = true;
382 blkid_partlist pl;
383 int r, k;
384 dev_t pn;
385
386 udev = udev_new();
387 if (!udev)
388 return log_oom();
389
390 d = udev_device_new_from_devnum(udev, 'b', devnum);
391 if (!d)
392 return log_oom();
393
394 parent = udev_device_get_parent(d);
395 if (!parent) {
396 log_debug("Not a partitioned device, ignoring.");
397 return 0;
398 }
399
400 /* Does it have a devtype? */
401 devtype = udev_device_get_devtype(parent);
402 if (!devtype) {
403 log_debug("Parent doesn't have a device type, ignoring.");
404 return 0;
405 }
406
407 /* Is this a disk or a partition? We only care for disks... */
408 if (!streq(devtype, "disk")) {
409 log_debug("Parent isn't a raw disk, ignoring.");
410 return 0;
411 }
412
413 /* Does it have a device node? */
414 node = udev_device_get_devnode(parent);
415 if (!node) {
416 log_debug("Parent device does not have device node, ignoring.");
417 return 0;
418 }
419
420 log_debug("Root device %s.", node);
421
422 pn = udev_device_get_devnum(parent);
423 if (major(pn) == 0)
424 return 0;
425
426 errno = 0;
427 b = blkid_new_probe_from_filename(node);
428 if (!b) {
429 if (errno == 0)
430 return log_oom();
431
432 log_error_errno(errno, "Failed allocate prober: %m");
433 return -errno;
434 }
435
436 blkid_probe_enable_partitions(b, 1);
437 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
438
439 errno = 0;
440 r = blkid_do_safeprobe(b);
441 if (r == -2 || r == 1) /* no result or uncertain */
442 return 0;
443 else if (r != 0) {
444 if (errno == 0)
445 errno = EIO;
446 log_error_errno(errno, "Failed to probe %s: %m", node);
447 return -errno;
448 }
449
450 errno = 0;
451 r = blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
452 if (r != 0) {
453 if (errno == 0)
454 errno = EIO;
455 log_error_errno(errno, "Failed to determine partition table type of %s: %m", node);
456 return -errno;
457 }
458
459 /* We only do this all for GPT... */
460 if (!streq_ptr(pttype, "gpt")) {
461 log_debug("Not a GPT partition table, ignoring.");
462 return 0;
463 }
464
465 errno = 0;
466 pl = blkid_probe_get_partitions(b);
467 if (!pl) {
468 if (errno == 0)
469 return log_oom();
470
471 log_error_errno(errno, "Failed to list partitions of %s: %m", node);
472 return -errno;
473 }
474
475 e = udev_enumerate_new(udev);
476 if (!e)
477 return log_oom();
478
479 r = udev_enumerate_add_match_parent(e, parent);
480 if (r < 0)
481 return log_oom();
482
483 r = udev_enumerate_add_match_subsystem(e, "block");
484 if (r < 0)
485 return log_oom();
486
487 r = udev_enumerate_scan_devices(e);
488 if (r < 0)
489 return log_error_errno(r, "Failed to enumerate partitions on %s: %m", node);
490
491 first = udev_enumerate_get_list_entry(e);
492 udev_list_entry_foreach(item, first) {
493 _cleanup_udev_device_unref_ struct udev_device *q;
494 const char *stype, *subnode;
495 sd_id128_t type_id;
496 blkid_partition pp;
497 dev_t qn;
498 int nr;
499 unsigned long long flags;
500
501 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
502 if (!q)
503 continue;
504
505 qn = udev_device_get_devnum(q);
506 if (major(qn) == 0)
507 continue;
508
509 if (qn == devnum)
510 continue;
511
512 if (qn == pn)
513 continue;
514
515 subnode = udev_device_get_devnode(q);
516 if (!subnode)
517 continue;
518
519 pp = blkid_partlist_devno_to_partition(pl, qn);
520 if (!pp)
521 continue;
522
523 flags = blkid_partition_get_flags(pp);
524
525 /* Ignore partitions that are not marked for automatic
526 * mounting on discovery */
527 if (flags & GPT_FLAG_NO_AUTO)
528 continue;
529
530 nr = blkid_partition_get_partno(pp);
531 if (nr < 0)
532 continue;
533
534 stype = blkid_partition_get_type_string(pp);
535 if (!stype)
536 continue;
537
538 if (sd_id128_from_string(stype, &type_id) < 0)
539 continue;
540
541 if (sd_id128_equal(type_id, GPT_SWAP)) {
542
543 if (flags & GPT_FLAG_READ_ONLY) {
544 log_debug("%s marked as read-only swap partition, which is bogus, ignoring.", subnode);
545 continue;
546 }
547
548 k = add_swap(subnode);
549 if (k < 0)
550 r = k;
551
552 } else if (sd_id128_equal(type_id, GPT_HOME)) {
553
554 /* We only care for the first /home partition */
555 if (home && nr >= home_nr)
556 continue;
557
558 home_nr = nr;
559 home_rw = !(flags & GPT_FLAG_READ_ONLY),
560
561 free(home);
562 home = strdup(subnode);
563 if (!home)
564 return log_oom();
565
566 } else if (sd_id128_equal(type_id, GPT_SRV)) {
567
568 /* We only care for the first /srv partition */
569 if (srv && nr >= srv_nr)
570 continue;
571
572 srv_nr = nr;
573 srv_rw = !(flags & GPT_FLAG_READ_ONLY),
574
575 free(srv);
576 srv = strdup(node);
577 if (!srv)
578 return log_oom();
579 }
580 }
581
582 if (home) {
583 k = probe_and_add_mount("home", home, "/home", home_rw, "Home Partition", SPECIAL_LOCAL_FS_TARGET);
584 if (k < 0)
585 r = k;
586 }
587
588 if (srv) {
589 k = probe_and_add_mount("srv", srv, "/srv", srv_rw, "Server Data Partition", SPECIAL_LOCAL_FS_TARGET);
590 if (k < 0)
591 r = k;
592 }
593
594 return r;
595 }
596
597 static int get_btrfs_block_device(const char *path, dev_t *dev) {
598 struct btrfs_ioctl_fs_info_args fsi = {};
599 _cleanup_close_ int fd = -1;
600 uint64_t id;
601
602 assert(path);
603 assert(dev);
604
605 fd = open(path, O_DIRECTORY|O_CLOEXEC);
606 if (fd < 0)
607 return -errno;
608
609 if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
610 return -errno;
611
612 /* We won't do this for btrfs RAID */
613 if (fsi.num_devices != 1)
614 return 0;
615
616 for (id = 1; id <= fsi.max_id; id++) {
617 struct btrfs_ioctl_dev_info_args di = {
618 .devid = id,
619 };
620 struct stat st;
621
622 if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
623 if (errno == ENODEV)
624 continue;
625
626 return -errno;
627 }
628
629 if (stat((char*) di.path, &st) < 0)
630 return -errno;
631
632 if (!S_ISBLK(st.st_mode))
633 return -ENODEV;
634
635 if (major(st.st_rdev) == 0)
636 return -ENODEV;
637
638 *dev = st.st_rdev;
639 return 1;
640 }
641
642 return -ENODEV;
643 }
644
645 static int get_block_device(const char *path, dev_t *dev) {
646 struct stat st;
647 struct statfs sfs;
648
649 assert(path);
650 assert(dev);
651
652 if (lstat(path, &st))
653 return -errno;
654
655 if (major(st.st_dev) != 0) {
656 *dev = st.st_dev;
657 return 1;
658 }
659
660 if (statfs(path, &sfs) < 0)
661 return -errno;
662
663 if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
664 return get_btrfs_block_device(path, dev);
665
666 return 0;
667 }
668
669 static int parse_proc_cmdline_item(const char *key, const char *value) {
670 int r;
671
672 assert(key);
673
674 if (STR_IN_SET(key, "systemd.gpt_auto", "rd.systemd.gpt_auto") && value) {
675
676 r = parse_boolean(value);
677 if (r < 0)
678 log_warning("Failed to parse gpt-auto switch %s. Ignoring.", value);
679 else
680 arg_enabled = r;
681
682 } else if (streq(key, "root") && value) {
683
684 /* Disable root disk logic if there's a root= value
685 * specified (unless it happens to be "gpt-auto") */
686
687 arg_root_enabled = streq(value, "gpt-auto");
688
689 } else if (streq(key, "rw") && !value)
690 arg_root_rw = true;
691 else if (streq(key, "ro") && !value)
692 arg_root_rw = false;
693
694 return 0;
695 }
696
697 static int add_root_mount(void) {
698
699 #ifdef ENABLE_EFI
700 int r;
701
702 if (!is_efi_boot()) {
703 log_debug("Not a EFI boot, not creating root mount.");
704 return 0;
705 }
706
707 r = efi_loader_get_device_part_uuid(NULL);
708 if (r == -ENOENT) {
709 log_debug("EFI loader partition unknown, exiting.");
710 return 0;
711 } else if (r < 0)
712 return log_error_errno(r, "Failed to read ESP partition UUID: %m");
713
714 /* OK, we have an ESP partition, this is fantastic, so let's
715 * wait for a root device to show up. A udev rule will create
716 * the link for us under the right name. */
717
718 return add_mount(
719 "root",
720 "/dev/gpt-auto-root",
721 in_initrd() ? "/sysroot" : "/",
722 NULL,
723 arg_root_rw,
724 "Root Partition",
725 in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_LOCAL_FS_TARGET);
726 #else
727 return 0;
728 #endif
729 }
730
731 static int add_mounts(void) {
732 dev_t devno;
733 int r;
734
735 r = get_block_device("/", &devno);
736 if (r < 0)
737 return log_error_errno(r, "Failed to determine block device of root file system: %m");
738 else if (r == 0) {
739 log_debug("Root file system not on a (single) block device.");
740 return 0;
741 }
742
743 return enumerate_partitions(devno);
744 }
745
746 int main(int argc, char *argv[]) {
747 int r = 0;
748
749 if (argc > 1 && argc != 4) {
750 log_error("This program takes three or no arguments.");
751 return EXIT_FAILURE;
752 }
753
754 if (argc > 1)
755 arg_dest = argv[3];
756
757 log_set_target(LOG_TARGET_SAFE);
758 log_parse_environment();
759 log_open();
760
761 umask(0022);
762
763 if (detect_container(NULL) > 0) {
764 log_debug("In a container, exiting.");
765 return EXIT_SUCCESS;
766 }
767
768 r = parse_proc_cmdline(parse_proc_cmdline_item);
769 if (r < 0)
770 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
771
772 if (!arg_enabled) {
773 log_debug("Disabled, exiting.");
774 return EXIT_SUCCESS;
775 }
776
777 if (arg_root_enabled)
778 r = add_root_mount();
779
780 if (!in_initrd()) {
781 int k;
782
783 k = add_mounts();
784 if (k < 0)
785 r = k;
786 }
787
788 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
789 }