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, bool rw, 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' '' '%s'\n"
153 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
155 id, what, rw ? "" : "read-only",
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, rw, &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);
289 fprintf(f, "Options=%s\n", rw ? "rw" : "ro");
293 log_error("Failed to write unit file %s: %m", p);
298 lnk = strjoin(arg_dest, "/", post, ".requires/", unit, NULL);
302 mkdir_parents_label(lnk, 0755);
303 if (symlink(p, lnk) < 0) {
304 log_error("Failed to create symlink %s: %m", lnk);
312 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;
384 bool home_rw = true, srv_rw = true;
393 d = udev_device_new_from_devnum(udev, 'b', devnum);
397 parent = udev_device_get_parent(d);
399 log_debug("Not a partitioned device, ignoring.");
403 /* Does it have a devtype? */
404 devtype = udev_device_get_devtype(parent);
406 log_debug("Parent doesn't have a device type, ignoring.");
410 /* Is this a disk or a partition? We only care for disks... */
411 if (!streq(devtype, "disk")) {
412 log_debug("Parent isn't a raw disk, ignoring.");
416 /* Does it have a device node? */
417 node = udev_device_get_devnode(parent);
419 log_debug("Parent device does not have device node, ignoring.");
423 log_debug("Root device %s.", node);
425 pn = udev_device_get_devnum(parent);
430 b = blkid_new_probe_from_filename(node);
435 log_error("Failed allocate prober: %m");
439 blkid_probe_enable_partitions(b, 1);
440 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
443 r = blkid_do_safeprobe(b);
444 if (r == -2 || r == 1) /* no result or uncertain */
449 log_error("Failed to probe %s: %m", node);
454 r = blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
458 log_error("Failed to determine partition table type of %s: %m", node);
462 /* We only do this all for GPT... */
463 if (!streq_ptr(pttype, "gpt")) {
464 log_debug("Not a GPT partition table, ignoring.");
469 pl = blkid_probe_get_partitions(b);
474 log_error("Failed to list partitions of %s: %m", node);
478 e = udev_enumerate_new(udev);
482 r = udev_enumerate_add_match_parent(e, parent);
486 r = udev_enumerate_add_match_subsystem(e, "block");
490 r = udev_enumerate_scan_devices(e);
492 log_error("Failed to enumerate partitions on %s: %s", node, strerror(-r));
496 first = udev_enumerate_get_list_entry(e);
497 udev_list_entry_foreach(item, first) {
498 _cleanup_udev_device_unref_ struct udev_device *q;
499 const char *stype, *subnode;
504 unsigned long long flags;
506 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
510 qn = udev_device_get_devnum(q);
520 subnode = udev_device_get_devnode(q);
524 pp = blkid_partlist_devno_to_partition(pl, qn);
528 flags = blkid_partition_get_flags(pp);
530 /* Ignore partitions that are not marked for automatic
531 * mounting on discovery */
532 if (flags & GPT_FLAG_NO_AUTO)
535 nr = blkid_partition_get_partno(pp);
539 stype = blkid_partition_get_type_string(pp);
543 if (sd_id128_from_string(stype, &type_id) < 0)
546 if (sd_id128_equal(type_id, GPT_SWAP)) {
548 if (flags & GPT_FLAG_READ_ONLY) {
549 log_debug("%s marked as read-only swap partition, which is bogus, ignoring.", subnode);
553 k = add_swap(subnode);
557 } else if (sd_id128_equal(type_id, GPT_HOME)) {
559 /* We only care for the first /home partition */
560 if (home && nr >= home_nr)
564 home_rw = !(flags & GPT_FLAG_READ_ONLY),
567 home = strdup(subnode);
571 } else if (sd_id128_equal(type_id, GPT_SRV)) {
573 /* We only care for the first /srv partition */
574 if (srv && nr >= srv_nr)
578 srv_rw = !(flags & GPT_FLAG_READ_ONLY),
588 k = probe_and_add_mount("home", home, "/home", home_rw, "Home Partition", SPECIAL_LOCAL_FS_TARGET);
594 k = probe_and_add_mount("srv", srv, "/srv", srv_rw, "Server Data Partition", SPECIAL_LOCAL_FS_TARGET);
602 static int get_btrfs_block_device(const char *path, dev_t *dev) {
603 struct btrfs_ioctl_fs_info_args fsi = {};
604 _cleanup_close_ int fd = -1;
610 fd = open(path, O_DIRECTORY|O_CLOEXEC);
614 if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
617 /* We won't do this for btrfs RAID */
618 if (fsi.num_devices != 1)
621 for (id = 1; id <= fsi.max_id; id++) {
622 struct btrfs_ioctl_dev_info_args di = {
627 if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
634 if (stat((char*) di.path, &st) < 0)
637 if (!S_ISBLK(st.st_mode))
640 if (major(st.st_rdev) == 0)
650 static int get_block_device(const char *path, dev_t *dev) {
657 if (lstat(path, &st))
660 if (major(st.st_dev) != 0) {
665 if (statfs(path, &sfs) < 0)
668 if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
669 return get_btrfs_block_device(path, dev);
674 static int parse_proc_cmdline_item(const char *key, const char *value) {
679 if (STR_IN_SET(key, "systemd.gpt_auto", "rd.systemd.gpt_auto") && value) {
681 r = parse_boolean(value);
683 log_warning("Failed to parse gpt-auto switch %s. Ignoring.", value);
687 } else if (streq(key, "root") && value) {
689 /* Disable root disk logic if there's a root= value
690 * specified (unless it happens to be "gpt-auto") */
692 arg_root_enabled = streq(value, "gpt-auto");
694 } else if (streq(key, "rw") && !value)
696 else if (streq(key, "ro") && !value)
702 static int add_root_mount(void) {
707 if (!is_efi_boot()) {
708 log_debug("Not a EFI boot, not creating root mount.");
712 r = efi_loader_get_device_part_uuid(NULL);
714 log_debug("EFI loader partition unknown, exiting.");
717 log_error("Failed to read ESP partition UUID: %s", strerror(-r));
721 /* OK, we have an ESP partition, this is fantastic, so let's
722 * wait for a root device to show up. A udev rule will create
723 * the link for us under the right name. */
727 "/dev/gpt-auto-root",
728 in_initrd() ? "/sysroot" : "/",
732 in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_LOCAL_FS_TARGET);
738 static int add_mounts(void) {
742 r = get_block_device("/", &devno);
744 log_error("Failed to determine block device of root file system: %s", strerror(-r));
747 log_debug("Root file system not on a (single) block device.");
751 return enumerate_partitions(devno);
754 int main(int argc, char *argv[]) {
757 if (argc > 1 && argc != 4) {
758 log_error("This program takes three or no arguments.");
765 log_set_target(LOG_TARGET_SAFE);
766 log_parse_environment();
771 if (detect_container(NULL) > 0) {
772 log_debug("In a container, exiting.");
776 if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)
780 log_debug("Disabled, exiting.");
784 if (arg_root_enabled)
785 r = add_root_mount();
795 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;