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/>.
24 #include <sys/statfs.h>
25 #include <blkid/blkid.h>
29 #include "path-util.h"
33 #include "udev-util.h"
35 #include "unit-name.h"
37 #include "generator.h"
41 #include "blkid-util.h"
42 #include "btrfs-util.h"
44 static const char *arg_dest = "/tmp";
45 static bool arg_enabled = true;
46 static bool arg_root_enabled = true;
47 static bool arg_root_rw = false;
49 static int add_swap(const char *path) {
50 _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
51 _cleanup_fclose_ FILE *f = NULL;
55 log_debug("Adding swap: %s", path);
57 name = unit_name_from_path(path, ".swap");
61 unit = strjoin(arg_dest, "/", name, NULL);
65 f = fopen(unit, "wxe");
67 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
70 "# Automatically generated by systemd-gpt-auto-generator\n\n"
72 "Description=Swap Partition\n"
73 "Documentation=man:systemd-gpt-auto-generator(8)\n\n"
80 return log_error_errno(errno, "Failed to write unit file %s: %m", unit);
82 lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
86 mkdir_parents_label(lnk, 0755);
87 if (symlink(unit, lnk) < 0)
88 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
93 static int add_cryptsetup(const char *id, const char *what, bool rw, char **device) {
94 _cleanup_free_ char *e = NULL, *n = NULL, *p = NULL, *d = NULL, *to = NULL;
95 _cleanup_fclose_ FILE *f = NULL;
103 d = unit_name_from_path(what, ".device");
107 e = unit_name_escape(id);
111 n = unit_name_build("systemd-cryptsetup", e, ".service");
115 p = strjoin(arg_dest, "/", n, NULL);
121 return log_error_errno(errno, "Failed to create unit file %s: %m", p);
124 "# Automatically generated by systemd-gpt-auto-generator\n\n"
126 "Description=Cryptography Setup for %%I\n"
127 "Documentation=man:systemd-gpt-auto-generator(8) man:systemd-cryptsetup@.service(8)\n"
128 "DefaultDependencies=no\n"
129 "Conflicts=umount.target\n"
130 "BindsTo=dev-mapper-%%i.device %s\n"
131 "Before=umount.target cryptsetup.target\n"
133 "IgnoreOnIsolate=true\n"
136 "RemainAfterExit=yes\n"
137 "TimeoutSec=0\n" /* the binary handles timeouts anyway */
138 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '' '%s'\n"
139 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
141 id, what, rw ? "" : "read-only",
146 return log_error_errno(errno, "Failed to write file %s: %m", p);
148 from = strjoina("../", n);
150 to = strjoin(arg_dest, "/", d, ".wants/", n, NULL);
154 mkdir_parents_label(to, 0755);
155 if (symlink(from, to) < 0)
156 return log_error_errno(errno, "Failed to create symlink %s: %m", to);
159 to = strjoin(arg_dest, "/cryptsetup.target.requires/", n, NULL);
163 mkdir_parents_label(to, 0755);
164 if (symlink(from, to) < 0)
165 return log_error_errno(errno, "Failed to create symlink %s: %m", to);
168 to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n, NULL);
172 mkdir_parents_label(to, 0755);
173 if (symlink(from, to) < 0)
174 return log_error_errno(errno, "Failed to create symlink %s: %m", to);
177 p = strjoin(arg_dest, "/dev-mapper-", e, ".device.d/50-job-timeout-sec-0.conf", NULL);
181 mkdir_parents_label(p, 0755);
182 r = write_string_file(p,
183 "# Automatically generated by systemd-gpt-auto-generator\n\n"
185 "JobTimeoutSec=0\n"); /* the binary handles timeouts anyway */
187 return log_error_errno(r, "Failed to write device drop-in: %m");
189 ret = strappend("/dev/mapper/", id);
197 static int add_mount(
203 const char *description,
206 _cleanup_free_ char *unit = NULL, *lnk = NULL, *crypto_what = NULL, *p = NULL;
207 _cleanup_fclose_ FILE *f = NULL;
215 log_debug("Adding %s: %s %s", where, what, strna(fstype));
217 if (streq_ptr(fstype, "crypto_LUKS")) {
219 r = add_cryptsetup(id, what, rw, &crypto_what);
227 unit = unit_name_from_path(where, ".mount");
231 p = strjoin(arg_dest, "/", unit, NULL);
237 return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
240 "# Automatically generated by systemd-gpt-auto-generator\n\n"
243 "Documentation=man:systemd-gpt-auto-generator(8)\n",
247 fprintf(f, "Before=%s\n", post);
249 r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
261 fprintf(f, "Type=%s\n", fstype);
263 fprintf(f, "Options=%s\n", rw ? "rw" : "ro");
267 return log_error_errno(errno, "Failed to write unit file %s: %m", p);
270 lnk = strjoin(arg_dest, "/", post, ".requires/", unit, NULL);
274 mkdir_parents_label(lnk, 0755);
275 if (symlink(p, lnk) < 0)
276 return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
282 static int probe_and_add_mount(
287 const char *description,
290 _cleanup_blkid_free_probe_ blkid_probe b = NULL;
299 if (path_is_mount_point(where, true) <= 0 &&
300 dir_is_empty(where) <= 0) {
301 log_debug("%s already populated, ignoring.", where);
305 /* Let's check the partition type here, so that we know
306 * whether to do LUKS magic. */
309 b = blkid_new_probe_from_filename(what);
313 log_error_errno(errno, "Failed to allocate prober: %m");
317 blkid_probe_enable_superblocks(b, 1);
318 blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
321 r = blkid_do_safeprobe(b);
322 if (r == -2 || r == 1) /* no result or uncertain */
327 log_error_errno(errno, "Failed to probe %s: %m", what);
331 blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
343 static int enumerate_partitions(dev_t devnum) {
345 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
346 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
347 _cleanup_blkid_free_probe_ blkid_probe b = NULL;
348 _cleanup_udev_unref_ struct udev *udev = NULL;
349 _cleanup_free_ char *home = NULL, *srv = NULL;
350 struct udev_list_entry *first, *item;
351 struct udev_device *parent = NULL;
352 const char *node, *pttype, *devtype;
353 int home_nr = -1, srv_nr = -1;
354 bool home_rw = true, srv_rw = true;
363 d = udev_device_new_from_devnum(udev, 'b', devnum);
367 parent = udev_device_get_parent(d);
369 log_debug("Not a partitioned device, ignoring.");
373 /* Does it have a devtype? */
374 devtype = udev_device_get_devtype(parent);
376 log_debug("Parent doesn't have a device type, ignoring.");
380 /* Is this a disk or a partition? We only care for disks... */
381 if (!streq(devtype, "disk")) {
382 log_debug("Parent isn't a raw disk, ignoring.");
386 /* Does it have a device node? */
387 node = udev_device_get_devnode(parent);
389 log_debug("Parent device does not have device node, ignoring.");
393 log_debug("Root device %s.", node);
395 pn = udev_device_get_devnum(parent);
400 b = blkid_new_probe_from_filename(node);
405 log_error_errno(errno, "Failed allocate prober: %m");
409 blkid_probe_enable_partitions(b, 1);
410 blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
413 r = blkid_do_safeprobe(b);
414 if (r == -2 || r == 1) /* no result or uncertain */
419 log_error_errno(errno, "Failed to probe %s: %m", node);
424 r = blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
428 log_error_errno(errno, "Failed to determine partition table type of %s: %m", node);
432 /* We only do this all for GPT... */
433 if (!streq_ptr(pttype, "gpt")) {
434 log_debug("Not a GPT partition table, ignoring.");
439 pl = blkid_probe_get_partitions(b);
444 log_error_errno(errno, "Failed to list partitions of %s: %m", node);
448 e = udev_enumerate_new(udev);
452 r = udev_enumerate_add_match_parent(e, parent);
456 r = udev_enumerate_add_match_subsystem(e, "block");
460 r = udev_enumerate_scan_devices(e);
462 return log_error_errno(r, "Failed to enumerate partitions on %s: %m", node);
464 first = udev_enumerate_get_list_entry(e);
465 udev_list_entry_foreach(item, first) {
466 _cleanup_udev_device_unref_ struct udev_device *q;
467 const char *stype, *subnode;
472 unsigned long long flags;
474 q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
478 qn = udev_device_get_devnum(q);
488 subnode = udev_device_get_devnode(q);
492 pp = blkid_partlist_devno_to_partition(pl, qn);
496 flags = blkid_partition_get_flags(pp);
498 /* Ignore partitions that are not marked for automatic
499 * mounting on discovery */
500 if (flags & GPT_FLAG_NO_AUTO)
503 nr = blkid_partition_get_partno(pp);
507 stype = blkid_partition_get_type_string(pp);
511 if (sd_id128_from_string(stype, &type_id) < 0)
514 if (sd_id128_equal(type_id, GPT_SWAP)) {
516 if (flags & GPT_FLAG_READ_ONLY) {
517 log_debug("%s marked as read-only swap partition, which is bogus, ignoring.", subnode);
521 k = add_swap(subnode);
525 } else if (sd_id128_equal(type_id, GPT_HOME)) {
527 /* We only care for the first /home partition */
528 if (home && nr >= home_nr)
532 home_rw = !(flags & GPT_FLAG_READ_ONLY),
535 home = strdup(subnode);
539 } else if (sd_id128_equal(type_id, GPT_SRV)) {
541 /* We only care for the first /srv partition */
542 if (srv && nr >= srv_nr)
546 srv_rw = !(flags & GPT_FLAG_READ_ONLY),
556 k = probe_and_add_mount("home", home, "/home", home_rw, "Home Partition", SPECIAL_LOCAL_FS_TARGET);
562 k = probe_and_add_mount("srv", srv, "/srv", srv_rw, "Server Data Partition", SPECIAL_LOCAL_FS_TARGET);
570 static int get_block_device(const char *path, dev_t *dev) {
577 if (lstat(path, &st))
580 if (major(st.st_dev) != 0) {
585 if (statfs(path, &sfs) < 0)
588 if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
589 return btrfs_get_block_device(path, dev);
594 static int parse_proc_cmdline_item(const char *key, const char *value) {
599 if (STR_IN_SET(key, "systemd.gpt_auto", "rd.systemd.gpt_auto") && value) {
601 r = parse_boolean(value);
603 log_warning("Failed to parse gpt-auto switch %s. Ignoring.", value);
607 } else if (streq(key, "root") && value) {
609 /* Disable root disk logic if there's a root= value
610 * specified (unless it happens to be "gpt-auto") */
612 arg_root_enabled = streq(value, "gpt-auto");
614 } else if (streq(key, "rw") && !value)
616 else if (streq(key, "ro") && !value)
622 static int add_root_mount(void) {
627 if (!is_efi_boot()) {
628 log_debug("Not a EFI boot, not creating root mount.");
632 r = efi_loader_get_device_part_uuid(NULL);
634 log_debug("EFI loader partition unknown, exiting.");
637 return log_error_errno(r, "Failed to read ESP partition UUID: %m");
639 /* OK, we have an ESP partition, this is fantastic, so let's
640 * wait for a root device to show up. A udev rule will create
641 * the link for us under the right name. */
645 "/dev/gpt-auto-root",
646 in_initrd() ? "/sysroot" : "/",
650 in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_LOCAL_FS_TARGET);
656 static int add_mounts(void) {
660 r = get_block_device("/", &devno);
662 return log_error_errno(r, "Failed to determine block device of root file system: %m");
664 log_debug("Root file system not on a (single) block device.");
668 return enumerate_partitions(devno);
671 int main(int argc, char *argv[]) {
674 if (argc > 1 && argc != 4) {
675 log_error("This program takes three or no arguments.");
682 log_set_target(LOG_TARGET_SAFE);
683 log_parse_environment();
688 if (detect_container(NULL) > 0) {
689 log_debug("In a container, exiting.");
693 r = parse_proc_cmdline(parse_proc_cmdline_item);
695 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
698 log_debug("Disabled, exiting.");
702 if (arg_root_enabled)
703 r = add_root_mount();
713 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;