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 log_error("Failed to create unit file %s: %m", unit);
77 "# Automatically generated by systemd-gpt-auto-generator\n\n"
79 "Description=Swap Partition\n"
80 "Documentation=man:systemd-gpt-auto-generator(8)\n\n"
87 log_error("Failed to write unit file %s: %m", unit);
91 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
95 mkdir_parents_label(lnk, 0755);
96 if (symlink(unit, lnk) < 0) {
97 log_error("Failed to create symlink %s: %m", lnk);
104 static int add_cryptsetup(const char *id, const char *what, char **device) {
105 _cleanup_free_ char *e = NULL, *n = NULL, *p = NULL, *d = NULL, *to = NULL;
106 _cleanup_fclose_ FILE *f = NULL;
114 d = unit_name_from_path(what, ".device");
118 e = unit_name_escape(id);
122 n = unit_name_build("systemd-cryptsetup", e, ".service");
126 p = strjoin(arg_dest, "/", n, NULL);
132 log_error("Failed to create unit file %s: %m", p);
137 "# Automatically generated by systemd-gpt-auto-generator\n\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"
146 "IgnoreOnIsolate=true\n"
147 "After=systemd-readahead-collect.service systemd-readahead-replay.service\n\n"
150 "RemainAfterExit=yes\n"
151 "TimeoutSec=0\n" /* the binary handles timeouts anyway */
152 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s'\n"
153 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
160 log_error("Failed to write file %s: %m", p);
164 from = strappenda("../", n);
166 to = strjoin(arg_dest, "/", d, ".wants/", n, NULL);
170 mkdir_parents_label(to, 0755);
171 if (symlink(from, to) < 0) {
172 log_error("Failed to create symlink %s: %m", to);
177 to = strjoin(arg_dest, "/cryptsetup.target.requires/", n, NULL);
181 mkdir_parents_label(to, 0755);
182 if (symlink(from, to) < 0) {
183 log_error("Failed to create symlink %s: %m", to);
188 to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n, NULL);
192 mkdir_parents_label(to, 0755);
193 if (symlink(from, to) < 0) {
194 log_error("Failed to create symlink %s: %m", to);
199 p = strjoin(arg_dest, "/dev-mapper-", e, ".device.d/50-job-timeout-sec-0.conf", NULL);
203 mkdir_parents_label(p, 0755);
204 r = write_string_file(p,
205 "# Automatically generated by systemd-gpt-auto-generator\n\n"
207 "JobTimeoutSec=0\n"); /* the binary handles timeouts anyway */
209 log_error("Failed to write device drop-in: %s", strerror(-r));
213 ret = strappend("/dev/mapper/", id);
221 static int add_mount(
227 const char *description,
230 _cleanup_free_ char *unit = NULL, *lnk = NULL, *crypto_what = NULL, *p = NULL;
231 _cleanup_fclose_ FILE *f = NULL;
239 log_debug("Adding %s: %s %s", where, what, strna(fstype));
241 if (streq_ptr(fstype, "crypto_LUKS")) {
243 r = add_cryptsetup(id, what, &crypto_what);
251 unit = unit_name_from_path(where, ".mount");
255 p = strjoin(arg_dest, "/", unit, NULL);
261 log_error("Failed to create unit file %s: %m", unit);
266 "# Automatically generated by systemd-gpt-auto-generator\n\n"
269 "Documentation=man:systemd-gpt-auto-generator(8)\n",
273 fprintf(f, "Before=%s\n", post);
275 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
287 fprintf(f, "Type=%s\n", fstype);
290 fprintf(f, "Options=%s\n", options);
294 log_error("Failed to write unit file %s: %m", p);
299 lnk = strjoin(arg_dest, "/", post, ".requires/", unit, NULL);
303 mkdir_parents_label(lnk, 0755);
304 if (symlink(p, lnk) < 0) {
305 log_error("Failed to create symlink %s: %m", lnk);
313 static int probe_and_add_mount(
317 const char *description,
320 _cleanup_blkid_free_probe_ blkid_probe b = NULL;
329 if (path_is_mount_point(where, true) <= 0 &&
330 dir_is_empty(where) <= 0) {
331 log_debug("%s already populated, ignoring.", where);
335 /* Let's check the partition type here, so that we know
336 * whether to do LUKS magic. */
339 b = blkid_new_probe_from_filename(what);
343 log_error("Failed to allocate prober: %m");
347 blkid_probe_enable_superblocks(b, 1);
348 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
351 r = blkid_do_safeprobe(b);
352 if (r == -2 || r == 1) /* no result or uncertain */
357 log_error("Failed to probe %s: %m", what);
361 blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
373 static int enumerate_partitions(dev_t devnum) {
375 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
376 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
377 _cleanup_blkid_free_probe_ blkid_probe b = NULL;
378 _cleanup_udev_unref_ struct udev *udev = NULL;
379 _cleanup_free_ char *home = NULL, *srv = NULL;
380 struct udev_list_entry *first, *item;
381 struct udev_device *parent = NULL;
382 const char *node, *pttype, *devtype;
383 int home_nr = -1, srv_nr = -1;
392 d = udev_device_new_from_devnum(udev, 'b', devnum);
396 parent = udev_device_get_parent(d);
400 /* Does it have a devtype? */
401 devtype = udev_device_get_devtype(parent);
405 /* Is this a disk or a partition? We only care for disks... */
406 if (!streq(devtype, "disk"))
409 /* Does it have a device node? */
410 node = udev_device_get_devnode(parent);
414 log_debug("Root device %s.", node);
416 pn = udev_device_get_devnum(parent);
421 b = blkid_new_probe_from_filename(node);
426 log_error("Failed allocate prober: %m");
430 blkid_probe_enable_superblocks(b, 1);
431 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
432 blkid_probe_enable_partitions(b, 1);
433 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
436 r = blkid_do_safeprobe(b);
437 if (r == -2 || r == 1) /* no result or uncertain */
442 log_error("Failed to probe %s: %m", node);
447 r = blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
451 log_error("Failed to determine partition table type of %s: %m", node);
455 /* We only do this all for GPT... */
456 if (!streq_ptr(pttype, "gpt"))
460 pl = blkid_probe_get_partitions(b);
465 log_error("Failed to list partitions of %s: %m", node);
469 e = udev_enumerate_new(udev);
473 r = udev_enumerate_add_match_parent(e, parent);
477 r = udev_enumerate_add_match_subsystem(e, "block");
481 r = udev_enumerate_scan_devices(e);
483 log_error("Failed to enumerate partitions on %s: %s", node, strerror(-r));
487 first = udev_enumerate_get_list_entry(e);
488 udev_list_entry_foreach(item, first) {
489 _cleanup_udev_device_unref_ struct udev_device *q;
490 const char *stype, *subnode;
496 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
500 qn = udev_device_get_devnum(q);
510 subnode = udev_device_get_devnode(q);
514 pp = blkid_partlist_devno_to_partition(pl, qn);
518 nr = blkid_partition_get_partno(pp);
522 stype = blkid_partition_get_type_string(pp);
526 if (sd_id128_from_string(stype, &type_id) < 0)
529 if (sd_id128_equal(type_id, GPT_SWAP)) {
531 k = add_swap(subnode);
535 } else if (sd_id128_equal(type_id, GPT_HOME)) {
537 /* We only care for the first /home partition */
538 if (home && nr >= home_nr)
544 home = strdup(subnode);
548 } else if (sd_id128_equal(type_id, GPT_SRV)) {
550 /* We only care for the first /srv partition */
551 if (srv && nr >= srv_nr)
564 k = probe_and_add_mount("home", home, "/home", "Home Partition", SPECIAL_LOCAL_FS_TARGET);
570 k = probe_and_add_mount("srv", srv, "/srv", "Server Data Partition", SPECIAL_LOCAL_FS_TARGET);
578 static int get_btrfs_block_device(const char *path, dev_t *dev) {
579 struct btrfs_ioctl_fs_info_args fsi = {};
580 _cleanup_close_ int fd = -1;
586 fd = open(path, O_DIRECTORY|O_CLOEXEC);
590 if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
593 /* We won't do this for btrfs RAID */
594 if (fsi.num_devices != 1)
597 for (id = 1; id <= fsi.max_id; id++) {
598 struct btrfs_ioctl_dev_info_args di = {
603 if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
610 if (stat((char*) di.path, &st) < 0)
613 if (!S_ISBLK(st.st_mode))
616 if (major(st.st_rdev) == 0)
626 static int get_block_device(const char *path, dev_t *dev) {
633 if (lstat(path, &st))
636 if (major(st.st_dev) != 0) {
641 if (statfs(path, &sfs) < 0)
644 if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
645 return get_btrfs_block_device(path, dev);
650 static int parse_proc_cmdline_item(const char *key, const char *value) {
655 if (STR_IN_SET(key, "systemd.gpt_auto", "rd.systemd.gpt_auto") && value) {
657 r = parse_boolean(value);
659 log_warning("Failed to parse gpt-auto switch %s. Ignoring.", value);
663 } else if (streq(key, "root") && value) {
665 /* Disable root disk logic if there's a root= value
666 * specified (unless it happens to be "gpt-auto") */
668 arg_root_enabled = streq(value, "gpt-auto");
670 } else if (streq(key, "rw") && !value)
672 else if (streq(key, "ro") && !value)
674 else if (startswith(key, "systemd.gpt-auto.") || startswith(key, "rd.systemd.gpt-auto."))
675 log_warning("Unknown kernel switch %s. Ignoring.", key);
680 static int add_root_mount(void) {
685 if (!is_efi_boot()) {
686 log_debug("Not a EFI boot, not creating root mount.");
690 r = efi_loader_get_device_part_uuid(NULL);
692 log_debug("EFI loader partition unknown, exiting.");
695 log_error("Failed to read ESP partition UUID: %s", strerror(-r));
699 /* OK, we have an ESP partition, this is fantastic, so let's
700 * wait for a root device to show up. A udev rule will create
701 * the link for us under the right name. */
705 "/dev/gpt-auto-root",
706 in_initrd() ? "/sysroot" : "/",
708 arg_root_rw ? "rw" : "ro",
710 in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_LOCAL_FS_TARGET);
716 static int add_mounts(void) {
720 r = get_block_device("/", &devno);
722 log_error("Failed to determine block device of root file system: %s", strerror(-r));
725 log_debug("Root file system not on a (single) block device.");
729 return enumerate_partitions(devno);
732 int main(int argc, char *argv[]) {
735 if (argc > 1 && argc != 4) {
736 log_error("This program takes three or no arguments.");
743 log_set_target(LOG_TARGET_SAFE);
744 log_parse_environment();
749 if (detect_container(NULL) > 0) {
750 log_debug("In a container, exiting.");
754 if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)
758 log_debug("Disabled, exiting.");
762 if (arg_root_enabled)
763 r = add_root_mount();
773 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;