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_errno(errno, "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_errno(errno, "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_errno(errno, "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_errno(errno, "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"
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",
154 id, what, rw ? "" : "read-only",
159 log_error_errno(errno, "Failed to write file %s: %m", p);
163 from = strappenda("../", n);
165 to = strjoin(arg_dest, "/", d, ".wants/", n, NULL);
169 mkdir_parents_label(to, 0755);
170 if (symlink(from, to) < 0) {
171 log_error_errno(errno, "Failed to create symlink %s: %m", to);
176 to = strjoin(arg_dest, "/cryptsetup.target.requires/", n, NULL);
180 mkdir_parents_label(to, 0755);
181 if (symlink(from, to) < 0) {
182 log_error_errno(errno, "Failed to create symlink %s: %m", to);
187 to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n, NULL);
191 mkdir_parents_label(to, 0755);
192 if (symlink(from, to) < 0) {
193 log_error_errno(errno, "Failed to create symlink %s: %m", to);
198 p = strjoin(arg_dest, "/dev-mapper-", e, ".device.d/50-job-timeout-sec-0.conf", NULL);
202 mkdir_parents_label(p, 0755);
203 r = write_string_file(p,
204 "# Automatically generated by systemd-gpt-auto-generator\n\n"
206 "JobTimeoutSec=0\n"); /* the binary handles timeouts anyway */
208 return log_error_errno(r, "Failed to write device drop-in: %m");
210 ret = strappend("/dev/mapper/", id);
218 static int add_mount(
224 const char *description,
227 _cleanup_free_ char *unit = NULL, *lnk = NULL, *crypto_what = NULL, *p = NULL;
228 _cleanup_fclose_ FILE *f = NULL;
236 log_debug("Adding %s: %s %s", where, what, strna(fstype));
238 if (streq_ptr(fstype, "crypto_LUKS")) {
240 r = add_cryptsetup(id, what, rw, &crypto_what);
248 unit = unit_name_from_path(where, ".mount");
252 p = strjoin(arg_dest, "/", unit, NULL);
258 log_error_errno(errno, "Failed to create unit file %s: %m", unit);
263 "# Automatically generated by systemd-gpt-auto-generator\n\n"
266 "Documentation=man:systemd-gpt-auto-generator(8)\n",
270 fprintf(f, "Before=%s\n", post);
272 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
284 fprintf(f, "Type=%s\n", fstype);
286 fprintf(f, "Options=%s\n", rw ? "rw" : "ro");
290 log_error_errno(errno, "Failed to write unit file %s: %m", p);
295 lnk = strjoin(arg_dest, "/", post, ".requires/", unit, NULL);
299 mkdir_parents_label(lnk, 0755);
300 if (symlink(p, lnk) < 0) {
301 log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
309 static int probe_and_add_mount(
314 const char *description,
317 _cleanup_blkid_free_probe_ blkid_probe b = NULL;
326 if (path_is_mount_point(where, true) <= 0 &&
327 dir_is_empty(where) <= 0) {
328 log_debug("%s already populated, ignoring.", where);
332 /* Let's check the partition type here, so that we know
333 * whether to do LUKS magic. */
336 b = blkid_new_probe_from_filename(what);
340 log_error_errno(errno, "Failed to allocate prober: %m");
344 blkid_probe_enable_superblocks(b, 1);
345 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
348 r = blkid_do_safeprobe(b);
349 if (r == -2 || r == 1) /* no result or uncertain */
354 log_error_errno(errno, "Failed to probe %s: %m", what);
358 blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
370 static int enumerate_partitions(dev_t devnum) {
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;
390 d = udev_device_new_from_devnum(udev, 'b', devnum);
394 parent = udev_device_get_parent(d);
396 log_debug("Not a partitioned device, ignoring.");
400 /* Does it have a devtype? */
401 devtype = udev_device_get_devtype(parent);
403 log_debug("Parent doesn't have a device type, ignoring.");
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.");
413 /* Does it have a device node? */
414 node = udev_device_get_devnode(parent);
416 log_debug("Parent device does not have device node, ignoring.");
420 log_debug("Root device %s.", node);
422 pn = udev_device_get_devnum(parent);
427 b = blkid_new_probe_from_filename(node);
432 log_error_errno(errno, "Failed allocate prober: %m");
436 blkid_probe_enable_partitions(b, 1);
437 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
440 r = blkid_do_safeprobe(b);
441 if (r == -2 || r == 1) /* no result or uncertain */
446 log_error_errno(errno, "Failed to probe %s: %m", node);
451 r = blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
455 log_error_errno(errno, "Failed to determine partition table type of %s: %m", node);
459 /* We only do this all for GPT... */
460 if (!streq_ptr(pttype, "gpt")) {
461 log_debug("Not a GPT partition table, ignoring.");
466 pl = blkid_probe_get_partitions(b);
471 log_error_errno(errno, "Failed to list partitions of %s: %m", node);
475 e = udev_enumerate_new(udev);
479 r = udev_enumerate_add_match_parent(e, parent);
483 r = udev_enumerate_add_match_subsystem(e, "block");
487 r = udev_enumerate_scan_devices(e);
489 return log_error_errno(r, "Failed to enumerate partitions on %s: %m", node);
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;
499 unsigned long long flags;
501 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
505 qn = udev_device_get_devnum(q);
515 subnode = udev_device_get_devnode(q);
519 pp = blkid_partlist_devno_to_partition(pl, qn);
523 flags = blkid_partition_get_flags(pp);
525 /* Ignore partitions that are not marked for automatic
526 * mounting on discovery */
527 if (flags & GPT_FLAG_NO_AUTO)
530 nr = blkid_partition_get_partno(pp);
534 stype = blkid_partition_get_type_string(pp);
538 if (sd_id128_from_string(stype, &type_id) < 0)
541 if (sd_id128_equal(type_id, GPT_SWAP)) {
543 if (flags & GPT_FLAG_READ_ONLY) {
544 log_debug("%s marked as read-only swap partition, which is bogus, ignoring.", subnode);
548 k = add_swap(subnode);
552 } else if (sd_id128_equal(type_id, GPT_HOME)) {
554 /* We only care for the first /home partition */
555 if (home && nr >= home_nr)
559 home_rw = !(flags & GPT_FLAG_READ_ONLY),
562 home = strdup(subnode);
566 } else if (sd_id128_equal(type_id, GPT_SRV)) {
568 /* We only care for the first /srv partition */
569 if (srv && nr >= srv_nr)
573 srv_rw = !(flags & GPT_FLAG_READ_ONLY),
583 k = probe_and_add_mount("home", home, "/home", home_rw, "Home Partition", SPECIAL_LOCAL_FS_TARGET);
589 k = probe_and_add_mount("srv", srv, "/srv", srv_rw, "Server Data Partition", SPECIAL_LOCAL_FS_TARGET);
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;
605 fd = open(path, O_DIRECTORY|O_CLOEXEC);
609 if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
612 /* We won't do this for btrfs RAID */
613 if (fsi.num_devices != 1)
616 for (id = 1; id <= fsi.max_id; id++) {
617 struct btrfs_ioctl_dev_info_args di = {
622 if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
629 if (stat((char*) di.path, &st) < 0)
632 if (!S_ISBLK(st.st_mode))
635 if (major(st.st_rdev) == 0)
645 static int get_block_device(const char *path, dev_t *dev) {
652 if (lstat(path, &st))
655 if (major(st.st_dev) != 0) {
660 if (statfs(path, &sfs) < 0)
663 if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
664 return get_btrfs_block_device(path, dev);
669 static int parse_proc_cmdline_item(const char *key, const char *value) {
674 if (STR_IN_SET(key, "systemd.gpt_auto", "rd.systemd.gpt_auto") && value) {
676 r = parse_boolean(value);
678 log_warning("Failed to parse gpt-auto switch %s. Ignoring.", value);
682 } else if (streq(key, "root") && value) {
684 /* Disable root disk logic if there's a root= value
685 * specified (unless it happens to be "gpt-auto") */
687 arg_root_enabled = streq(value, "gpt-auto");
689 } else if (streq(key, "rw") && !value)
691 else if (streq(key, "ro") && !value)
697 static int add_root_mount(void) {
702 if (!is_efi_boot()) {
703 log_debug("Not a EFI boot, not creating root mount.");
707 r = efi_loader_get_device_part_uuid(NULL);
709 log_debug("EFI loader partition unknown, exiting.");
712 return log_error_errno(r, "Failed to read ESP partition UUID: %m");
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. */
720 "/dev/gpt-auto-root",
721 in_initrd() ? "/sysroot" : "/",
725 in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_LOCAL_FS_TARGET);
731 static int add_mounts(void) {
735 r = get_block_device("/", &devno);
737 return log_error_errno(r, "Failed to determine block device of root file system: %m");
739 log_debug("Root file system not on a (single) block device.");
743 return enumerate_partitions(devno);
746 int main(int argc, char *argv[]) {
749 if (argc > 1 && argc != 4) {
750 log_error("This program takes three or no arguments.");
757 log_set_target(LOG_TARGET_SAFE);
758 log_parse_environment();
763 if (detect_container(NULL) > 0) {
764 log_debug("In a container, exiting.");
768 r = parse_proc_cmdline(parse_proc_cmdline_item);
770 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
773 log_debug("Disabled, exiting.");
777 if (arg_root_enabled)
778 r = add_root_mount();
788 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;