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"
48 static const char *arg_dest = "/tmp";
49 static bool arg_enabled = true;
50 static bool arg_root_enabled = true;
51 static bool arg_root_rw = false;
53 DEFINE_TRIVIAL_CLEANUP_FUNC(blkid_probe, blkid_free_probe);
54 #define _cleanup_blkid_free_probe_ _cleanup_(blkid_free_probep)
56 static int add_swap(const char *path) {
57 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
58 _cleanup_fclose_ FILE *f = NULL;
62 log_debug("Adding swap: %s", path);
64 name = unit_name_from_path(path, ".swap");
68 unit = strjoin(arg_dest, "/", name, NULL);
72 f = fopen(unit, "wxe");
74 log_error("Failed to create unit file %s: %m", unit);
79 "# Automatically generated by systemd-gpt-auto-generator\n\n"
81 "Description=Swap Partition\n"
82 "Documentation=man:systemd-gpt-auto-generator(8)\n\n"
89 log_error("Failed to write unit file %s: %m", unit);
93 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
97 mkdir_parents_label(lnk, 0755);
98 if (symlink(unit, lnk) < 0) {
99 log_error("Failed to create symlink %s: %m", lnk);
106 static int add_cryptsetup(const char *id, const char *what, char **device) {
107 _cleanup_free_ char *e = NULL, *n = NULL, *p = NULL, *d = NULL, *to = NULL;
108 _cleanup_fclose_ FILE *f = NULL;
116 d = unit_name_from_path(what, ".device");
120 e = unit_name_escape(id);
124 n = unit_name_build("systemd-cryptsetup", e, ".service");
128 p = strjoin(arg_dest, "/", n, NULL);
134 log_error("Failed to create unit file %s: %m", p);
139 "# Automatically generated by systemd-gpt-auto-generator\n\n"
141 "Description=Cryptography Setup for %%I\n"
142 "Documentation=man:systemd-gpt-auto-generator(8) man:systemd-cryptsetup@.service(8)\n"
143 "DefaultDependencies=no\n"
144 "Conflicts=umount.target\n"
145 "BindsTo=dev-mapper-%%i.device %s\n"
146 "Before=umount.target cryptsetup.target\n"
148 "IgnoreOnIsolate=true\n"
149 "After=systemd-readahead-collect.service systemd-readahead-replay.service\n\n"
152 "RemainAfterExit=yes\n"
153 "TimeoutSec=0\n" /* the binary handles timeouts anyway */
154 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s'\n"
155 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
162 log_error("Failed to write file %s: %m", p);
166 from = strappenda("../", n);
168 to = strjoin(arg_dest, "/", d, ".wants/", n, NULL);
172 mkdir_parents_label(to, 0755);
173 if (symlink(from, to) < 0) {
174 log_error("Failed to create symlink %s: %m", to);
179 to = strjoin(arg_dest, "/cryptsetup.target.requires/", n, NULL);
183 mkdir_parents_label(to, 0755);
184 if (symlink(from, to) < 0) {
185 log_error("Failed to create symlink %s: %m", to);
190 to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n, NULL);
194 mkdir_parents_label(to, 0755);
195 if (symlink(from, to) < 0) {
196 log_error("Failed to create symlink %s: %m", to);
201 p = strjoin(arg_dest, "/dev-mapper-", e, ".device.d/50-job-timeout-sec-0.conf", NULL);
205 mkdir_parents_label(p, 0755);
206 r = write_string_file(p,
207 "# Automatically generated by systemd-gpt-auto-generator\n\n"
209 "JobTimeoutSec=0\n"); /* the binary handles timeouts anyway */
211 log_error("Failed to write device drop-in: %s", strerror(-r));
215 ret = strappend("/dev/mapper/", id);
223 static int add_mount(
229 const char *description,
232 _cleanup_free_ char *unit = NULL, *lnk = NULL, *crypto_what = NULL, *p = NULL;
233 _cleanup_fclose_ FILE *f = NULL;
241 log_debug("Adding %s: %s %s", where, what, strna(fstype));
243 if (streq_ptr(fstype, "crypto_LUKS")) {
245 r = add_cryptsetup(id, what, &crypto_what);
253 unit = unit_name_from_path(where, ".mount");
257 p = strjoin(arg_dest, "/", unit, NULL);
263 log_error("Failed to create unit file %s: %m", unit);
268 "# Automatically generated by systemd-gpt-auto-generator\n\n"
271 "Documentation=man:systemd-gpt-auto-generator(8)\n",
275 fprintf(f, "Before=%s\n", post);
277 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
289 fprintf(f, "Type=%s\n", fstype);
292 fprintf(f, "Options=%s\n", options);
296 log_error("Failed to write unit file %s: %m", p);
301 lnk = strjoin(arg_dest, "/", post, ".requires/", unit, NULL);
305 mkdir_parents_label(lnk, 0755);
306 if (symlink(p, lnk) < 0) {
307 log_error("Failed to create symlink %s: %m", lnk);
315 static int probe_and_add_mount(
319 const char *description,
322 _cleanup_blkid_free_probe_ blkid_probe b = NULL;
331 if (path_is_mount_point(where, true) <= 0 &&
332 dir_is_empty(where) <= 0) {
333 log_debug("%s already populated, ignoring.", where);
337 /* Let's check the partition type here, so that we know
338 * whether to do LUKS magic. */
341 b = blkid_new_probe_from_filename(what);
345 log_error("Failed to allocate prober: %m");
349 blkid_probe_enable_superblocks(b, 1);
350 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
353 r = blkid_do_safeprobe(b);
354 if (r == -2 || r == 1) /* no result or uncertain */
359 log_error("Failed to probe %s: %m", what);
363 blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
375 static int enumerate_partitions(dev_t devnum) {
377 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
378 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
379 _cleanup_blkid_free_probe_ blkid_probe b = NULL;
380 _cleanup_udev_unref_ struct udev *udev = NULL;
381 _cleanup_free_ char *home = NULL, *srv = NULL;
382 struct udev_list_entry *first, *item;
383 struct udev_device *parent = NULL;
384 const char *node, *pttype, *devtype;
385 int home_nr = -1, srv_nr = -1;
394 d = udev_device_new_from_devnum(udev, 'b', devnum);
398 parent = udev_device_get_parent(d);
402 /* Does it have a devtype? */
403 devtype = udev_device_get_devtype(parent);
407 /* Is this a disk or a partition? We only care for disks... */
408 if (!streq(devtype, "disk"))
411 /* Does it have a device node? */
412 node = udev_device_get_devnode(parent);
416 log_debug("Root device %s.", node);
418 pn = udev_device_get_devnum(parent);
423 b = blkid_new_probe_from_filename(node);
428 log_error("Failed allocate prober: %m");
432 blkid_probe_enable_superblocks(b, 1);
433 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
434 blkid_probe_enable_partitions(b, 1);
435 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
438 r = blkid_do_safeprobe(b);
439 if (r == -2 || r == 1) /* no result or uncertain */
444 log_error("Failed to probe %s: %m", node);
449 r = blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
453 log_error("Failed to determine partition table type of %s: %m", node);
457 /* We only do this all for GPT... */
458 if (!streq_ptr(pttype, "gpt"))
462 pl = blkid_probe_get_partitions(b);
467 log_error("Failed to list of partitions of %s: %m", node);
471 e = udev_enumerate_new(udev);
475 r = udev_enumerate_add_match_parent(e, parent);
479 r = udev_enumerate_add_match_subsystem(e, "block");
483 r = udev_enumerate_scan_devices(e);
485 log_error("Failed to enumerate partitions on %s: %s", node, strerror(-r));
489 first = udev_enumerate_get_list_entry(e);
490 udev_list_entry_foreach(item, first) {
491 _cleanup_udev_device_unref_ struct udev_device *q;
492 const char *stype, *subnode;
498 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
502 qn = udev_device_get_devnum(q);
512 subnode = udev_device_get_devnode(q);
516 pp = blkid_partlist_devno_to_partition(pl, qn);
520 nr = blkid_partition_get_partno(pp);
524 stype = blkid_partition_get_type_string(pp);
528 if (sd_id128_from_string(stype, &type_id) < 0)
531 if (sd_id128_equal(type_id, GPT_SWAP)) {
533 k = add_swap(subnode);
537 } else if (sd_id128_equal(type_id, GPT_HOME)) {
539 /* We only care for the first /home partition */
540 if (home && nr >= home_nr)
546 home = strdup(subnode);
550 } else if (sd_id128_equal(type_id, GPT_SRV)) {
552 /* We only care for the first /srv partition */
553 if (srv && nr >= srv_nr)
566 k = probe_and_add_mount("home", home, "/home", "Home Partition", SPECIAL_LOCAL_FS_TARGET);
572 k = probe_and_add_mount("srv", srv, "/srv", "Server Data Partition", SPECIAL_LOCAL_FS_TARGET);
580 static int get_btrfs_block_device(const char *path, dev_t *dev) {
581 struct btrfs_ioctl_fs_info_args fsi = {};
582 _cleanup_close_ int fd = -1;
588 fd = open(path, O_DIRECTORY|O_CLOEXEC);
592 if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
595 /* We won't do this for btrfs RAID */
596 if (fsi.num_devices != 1)
599 for (id = 1; id <= fsi.max_id; id++) {
600 struct btrfs_ioctl_dev_info_args di = {
605 if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
612 if (stat((char*) di.path, &st) < 0)
615 if (!S_ISBLK(st.st_mode))
618 if (major(st.st_rdev) == 0)
628 static int get_block_device(const char *path, dev_t *dev) {
635 if (lstat(path, &st))
638 if (major(st.st_dev) != 0) {
643 if (statfs(path, &sfs) < 0)
646 if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
647 return get_btrfs_block_device(path, dev);
652 static int parse_proc_cmdline_item(const char *key, const char *value) {
657 if (STR_IN_SET(key, "systemd.gpt_auto", "rd.systemd.gpt_auto") && value) {
659 r = parse_boolean(value);
661 log_warning("Failed to parse gpt-auto switch %s. Ignoring.", value);
665 } else if (streq(key, "root") && value) {
667 /* Disable root disk logic if there's a root= value
668 * specified (unless it happens to be "gpt-auto") */
670 arg_root_enabled = streq(value, "gpt-auto");
672 } else if (streq(key, "rw") && !value)
674 else if (streq(key, "ro") && !value)
676 else if (startswith(key, "systemd.gpt-auto.") || startswith(key, "rd.systemd.gpt-auto."))
677 log_warning("Unknown kernel switch %s. Ignoring.", key);
682 static int add_root_mount(void) {
687 if (!is_efi_boot()) {
688 log_debug("Not a EFI boot, not creating root mount.");
692 r = efi_loader_get_device_part_uuid(NULL);
694 log_debug("EFI loader partition unknown, exiting.");
697 log_error("Failed to read ESP partition UUID: %s", strerror(-r));
701 /* OK, we have an ESP partition, this is fantastic, so let's
702 * wait for a root device to show up. A udev rule will create
703 * the link for us under the right name. */
707 "/dev/disk/by-id/gpt-auto-root",
708 in_initrd() ? "/sysroot" : "/",
710 arg_root_rw ? "rw" : "ro",
712 in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_LOCAL_FS_TARGET);
718 static int add_mounts(void) {
722 r = get_block_device("/", &devno);
724 log_error("Failed to determine block device of root file system: %s", strerror(-r));
727 log_debug("Root file system not on a (single) block device.");
731 return enumerate_partitions(devno);
734 int main(int argc, char *argv[]) {
737 if (argc > 1 && argc != 4) {
738 log_error("This program takes three or no arguments.");
745 log_set_target(LOG_TARGET_SAFE);
746 log_parse_environment();
751 if (detect_container(NULL) > 0) {
752 log_debug("In a container, exiting.");
756 if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)
760 log_debug("Disabled, exiting.");
764 if (arg_root_enabled)
765 r = add_root_mount();
775 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;