1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
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.
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.
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/>.
25 #include <sys/ioctl.h>
26 #include <sys/statfs.h>
27 #include <blkid/blkid.h>
29 #ifdef HAVE_LINUX_BTRFS_H
30 #include <linux/btrfs.h>
35 #include "path-util.h"
39 #include "udev-util.h"
41 #include "unit-name.h"
43 #include "generator.h"
47 #include "blkid-util.h"
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;
54 static int add_swap(const char *path) {
55 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
56 _cleanup_fclose_ FILE *f = NULL;
60 log_debug("Adding swap: %s", path);
62 name = unit_name_from_path(path, ".swap");
66 unit = strjoin(arg_dest, "/", name, NULL);
70 f = fopen(unit, "wxe");
72 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
75 "# Automatically generated by systemd-gpt-auto-generator\n\n"
77 "Description=Swap Partition\n"
78 "Documentation=man:systemd-gpt-auto-generator(8)\n\n"
85 return log_error_errno(errno, "Failed to write unit file %s: %m", unit);
87 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
91 mkdir_parents_label(lnk, 0755);
92 if (symlink(unit, lnk) < 0)
93 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
98 static int add_cryptsetup(const char *id, const char *what, bool rw, char **device) {
99 _cleanup_free_ char *e = NULL, *n = NULL, *p = NULL, *d = NULL, *to = NULL;
100 _cleanup_fclose_ FILE *f = NULL;
108 d = unit_name_from_path(what, ".device");
112 e = unit_name_escape(id);
116 n = unit_name_build("systemd-cryptsetup", e, ".service");
120 p = strjoin(arg_dest, "/", n, NULL);
126 return log_error_errno(errno, "Failed to create unit file %s: %m", p);
129 "# Automatically generated by systemd-gpt-auto-generator\n\n"
131 "Description=Cryptography Setup for %%I\n"
132 "Documentation=man:systemd-gpt-auto-generator(8) man:systemd-cryptsetup@.service(8)\n"
133 "DefaultDependencies=no\n"
134 "Conflicts=umount.target\n"
135 "BindsTo=dev-mapper-%%i.device %s\n"
136 "Before=umount.target cryptsetup.target\n"
138 "IgnoreOnIsolate=true\n"
141 "RemainAfterExit=yes\n"
142 "TimeoutSec=0\n" /* the binary handles timeouts anyway */
143 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '' '%s'\n"
144 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
146 id, what, rw ? "" : "read-only",
151 return log_error_errno(errno, "Failed to write file %s: %m", p);
153 from = strappenda("../", n);
155 to = strjoin(arg_dest, "/", d, ".wants/", n, NULL);
159 mkdir_parents_label(to, 0755);
160 if (symlink(from, to) < 0)
161 return log_error_errno(errno, "Failed to create symlink %s: %m", to);
164 to = strjoin(arg_dest, "/cryptsetup.target.requires/", n, NULL);
168 mkdir_parents_label(to, 0755);
169 if (symlink(from, to) < 0)
170 return log_error_errno(errno, "Failed to create symlink %s: %m", to);
173 to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n, NULL);
177 mkdir_parents_label(to, 0755);
178 if (symlink(from, to) < 0)
179 return log_error_errno(errno, "Failed to create symlink %s: %m", to);
182 p = strjoin(arg_dest, "/dev-mapper-", e, ".device.d/50-job-timeout-sec-0.conf", NULL);
186 mkdir_parents_label(p, 0755);
187 r = write_string_file(p,
188 "# Automatically generated by systemd-gpt-auto-generator\n\n"
190 "JobTimeoutSec=0\n"); /* the binary handles timeouts anyway */
192 return log_error_errno(r, "Failed to write device drop-in: %m");
194 ret = strappend("/dev/mapper/", id);
202 static int add_mount(
208 const char *description,
211 _cleanup_free_ char *unit = NULL, *lnk = NULL, *crypto_what = NULL, *p = NULL;
212 _cleanup_fclose_ FILE *f = NULL;
220 log_debug("Adding %s: %s %s", where, what, strna(fstype));
222 if (streq_ptr(fstype, "crypto_LUKS")) {
224 r = add_cryptsetup(id, what, rw, &crypto_what);
232 unit = unit_name_from_path(where, ".mount");
236 p = strjoin(arg_dest, "/", unit, NULL);
242 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
245 "# Automatically generated by systemd-gpt-auto-generator\n\n"
248 "Documentation=man:systemd-gpt-auto-generator(8)\n",
252 fprintf(f, "Before=%s\n", post);
254 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
266 fprintf(f, "Type=%s\n", fstype);
268 fprintf(f, "Options=%s\n", rw ? "rw" : "ro");
272 return log_error_errno(errno, "Failed to write unit file %s: %m", p);
275 lnk = strjoin(arg_dest, "/", post, ".requires/", unit, NULL);
279 mkdir_parents_label(lnk, 0755);
280 if (symlink(p, lnk) < 0)
281 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
287 static int probe_and_add_mount(
292 const char *description,
295 _cleanup_blkid_free_probe_ blkid_probe b = NULL;
304 if (path_is_mount_point(where, true) <= 0 &&
305 dir_is_empty(where) <= 0) {
306 log_debug("%s already populated, ignoring.", where);
310 /* Let's check the partition type here, so that we know
311 * whether to do LUKS magic. */
314 b = blkid_new_probe_from_filename(what);
318 log_error_errno(errno, "Failed to allocate prober: %m");
322 blkid_probe_enable_superblocks(b, 1);
323 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
326 r = blkid_do_safeprobe(b);
327 if (r == -2 || r == 1) /* no result or uncertain */
332 log_error_errno(errno, "Failed to probe %s: %m", what);
336 blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
348 static int enumerate_partitions(dev_t devnum) {
350 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
351 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
352 _cleanup_blkid_free_probe_ blkid_probe b = NULL;
353 _cleanup_udev_unref_ struct udev *udev = NULL;
354 _cleanup_free_ char *home = NULL, *srv = NULL;
355 struct udev_list_entry *first, *item;
356 struct udev_device *parent = NULL;
357 const char *node, *pttype, *devtype;
358 int home_nr = -1, srv_nr = -1;
359 bool home_rw = true, srv_rw = true;
368 d = udev_device_new_from_devnum(udev, 'b', devnum);
372 parent = udev_device_get_parent(d);
374 log_debug("Not a partitioned device, ignoring.");
378 /* Does it have a devtype? */
379 devtype = udev_device_get_devtype(parent);
381 log_debug("Parent doesn't have a device type, ignoring.");
385 /* Is this a disk or a partition? We only care for disks... */
386 if (!streq(devtype, "disk")) {
387 log_debug("Parent isn't a raw disk, ignoring.");
391 /* Does it have a device node? */
392 node = udev_device_get_devnode(parent);
394 log_debug("Parent device does not have device node, ignoring.");
398 log_debug("Root device %s.", node);
400 pn = udev_device_get_devnum(parent);
405 b = blkid_new_probe_from_filename(node);
410 log_error_errno(errno, "Failed allocate prober: %m");
414 blkid_probe_enable_partitions(b, 1);
415 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
418 r = blkid_do_safeprobe(b);
419 if (r == -2 || r == 1) /* no result or uncertain */
424 log_error_errno(errno, "Failed to probe %s: %m", node);
429 r = blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
433 log_error_errno(errno, "Failed to determine partition table type of %s: %m", node);
437 /* We only do this all for GPT... */
438 if (!streq_ptr(pttype, "gpt")) {
439 log_debug("Not a GPT partition table, ignoring.");
444 pl = blkid_probe_get_partitions(b);
449 log_error_errno(errno, "Failed to list partitions of %s: %m", node);
453 e = udev_enumerate_new(udev);
457 r = udev_enumerate_add_match_parent(e, parent);
461 r = udev_enumerate_add_match_subsystem(e, "block");
465 r = udev_enumerate_scan_devices(e);
467 return log_error_errno(r, "Failed to enumerate partitions on %s: %m", node);
469 first = udev_enumerate_get_list_entry(e);
470 udev_list_entry_foreach(item, first) {
471 _cleanup_udev_device_unref_ struct udev_device *q;
472 const char *stype, *subnode;
477 unsigned long long flags;
479 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
483 qn = udev_device_get_devnum(q);
493 subnode = udev_device_get_devnode(q);
497 pp = blkid_partlist_devno_to_partition(pl, qn);
501 flags = blkid_partition_get_flags(pp);
503 /* Ignore partitions that are not marked for automatic
504 * mounting on discovery */
505 if (flags & GPT_FLAG_NO_AUTO)
508 nr = blkid_partition_get_partno(pp);
512 stype = blkid_partition_get_type_string(pp);
516 if (sd_id128_from_string(stype, &type_id) < 0)
519 if (sd_id128_equal(type_id, GPT_SWAP)) {
521 if (flags & GPT_FLAG_READ_ONLY) {
522 log_debug("%s marked as read-only swap partition, which is bogus, ignoring.", subnode);
526 k = add_swap(subnode);
530 } else if (sd_id128_equal(type_id, GPT_HOME)) {
532 /* We only care for the first /home partition */
533 if (home && nr >= home_nr)
537 home_rw = !(flags & GPT_FLAG_READ_ONLY),
540 home = strdup(subnode);
544 } else if (sd_id128_equal(type_id, GPT_SRV)) {
546 /* We only care for the first /srv partition */
547 if (srv && nr >= srv_nr)
551 srv_rw = !(flags & GPT_FLAG_READ_ONLY),
561 k = probe_and_add_mount("home", home, "/home", home_rw, "Home Partition", SPECIAL_LOCAL_FS_TARGET);
567 k = probe_and_add_mount("srv", srv, "/srv", srv_rw, "Server Data Partition", SPECIAL_LOCAL_FS_TARGET);
575 static int get_btrfs_block_device(const char *path, dev_t *dev) {
576 struct btrfs_ioctl_fs_info_args fsi = {};
577 _cleanup_close_ int fd = -1;
583 fd = open(path, O_DIRECTORY|O_CLOEXEC);
587 if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
590 /* We won't do this for btrfs RAID */
591 if (fsi.num_devices != 1)
594 for (id = 1; id <= fsi.max_id; id++) {
595 struct btrfs_ioctl_dev_info_args di = {
600 if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
607 if (stat((char*) di.path, &st) < 0)
610 if (!S_ISBLK(st.st_mode))
613 if (major(st.st_rdev) == 0)
623 static int get_block_device(const char *path, dev_t *dev) {
630 if (lstat(path, &st))
633 if (major(st.st_dev) != 0) {
638 if (statfs(path, &sfs) < 0)
641 if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
642 return get_btrfs_block_device(path, dev);
647 static int parse_proc_cmdline_item(const char *key, const char *value) {
652 if (STR_IN_SET(key, "systemd.gpt_auto", "rd.systemd.gpt_auto") && value) {
654 r = parse_boolean(value);
656 log_warning("Failed to parse gpt-auto switch %s. Ignoring.", value);
660 } else if (streq(key, "root") && value) {
662 /* Disable root disk logic if there's a root= value
663 * specified (unless it happens to be "gpt-auto") */
665 arg_root_enabled = streq(value, "gpt-auto");
667 } else if (streq(key, "rw") && !value)
669 else if (streq(key, "ro") && !value)
675 static int add_root_mount(void) {
680 if (!is_efi_boot()) {
681 log_debug("Not a EFI boot, not creating root mount.");
685 r = efi_loader_get_device_part_uuid(NULL);
687 log_debug("EFI loader partition unknown, exiting.");
690 return log_error_errno(r, "Failed to read ESP partition UUID: %m");
692 /* OK, we have an ESP partition, this is fantastic, so let's
693 * wait for a root device to show up. A udev rule will create
694 * the link for us under the right name. */
698 "/dev/gpt-auto-root",
699 in_initrd() ? "/sysroot" : "/",
703 in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_LOCAL_FS_TARGET);
709 static int add_mounts(void) {
713 r = get_block_device("/", &devno);
715 return log_error_errno(r, "Failed to determine block device of root file system: %m");
717 log_debug("Root file system not on a (single) block device.");
721 return enumerate_partitions(devno);
724 int main(int argc, char *argv[]) {
727 if (argc > 1 && argc != 4) {
728 log_error("This program takes three or no arguments.");
735 log_set_target(LOG_TARGET_SAFE);
736 log_parse_environment();
741 if (detect_container(NULL) > 0) {
742 log_debug("In a container, exiting.");
746 r = parse_proc_cmdline(parse_proc_cmdline_item);
748 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
751 log_debug("Disabled, exiting.");
755 if (arg_root_enabled)
756 r = add_root_mount();
766 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;