gpt-auto-generator.c revision 8086ffacdb1bfec5ec115d24626538bda6cc372e
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering This file is part of systemd.
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering Copyright 2013 Lennart Poettering
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering systemd is free software; you can redistribute it and/or modify it
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering under the terms of the GNU Lesser General Public License as published by
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering (at your option) any later version.
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering systemd is distributed in the hope that it will be useful, but
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering Lesser General Public License for more details.
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering You should have received a copy of the GNU Lesser General Public License
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poetteringstatic bool arg_enabled = true;
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poetteringstatic bool arg_root_enabled = true;
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poetteringstatic bool arg_root_rw = false;
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering name = unit_name_from_path(path, ".swap");
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering unit = strjoin(arg_dest, "/", name, NULL);
821b2e792159e237a1e5a1ea4bb6ae2e55d64be5Lukas Nykryn log_error("Failed to create unit file %s: %m", unit);
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt "# Automatically generated by systemd-gpt-auto-generator\n\n"
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering "Description=Swap Partition\n"
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering "Documentation=man:systemd-gpt-auto-generator(8)\n\n"
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering log_error("Failed to write unit file %s: %m", unit);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
cca1dfddd4ce4357113663532696488427cc54e4Lennart Poettering log_error("Failed to create symlink %s: %m", lnk);
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poetteringstatic int add_cryptsetup(const char *id, const char *what, bool rw, char **device) {
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering _cleanup_free_ char *e = NULL, *n = NULL, *p = NULL, *d = NULL, *to = NULL;
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering d = unit_name_from_path(what, ".device");
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering n = unit_name_build("systemd-cryptsetup", e, ".service");
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering log_error("Failed to create unit file %s: %m", p);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering "# Automatically generated by systemd-gpt-auto-generator\n\n"
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering "Description=Cryptography Setup for %%I\n"
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering "Documentation=man:systemd-gpt-auto-generator(8) man:systemd-cryptsetup@.service(8)\n"
4c1fc3e404d648c70bd2f50ac50aeac6ece8872eDaniel Mack "DefaultDependencies=no\n"
4c1fc3e404d648c70bd2f50ac50aeac6ece8872eDaniel Mack "Conflicts=umount.target\n"
23bbb0de4e3f85d9704a5c12a5afa2dfa0159e41Michal Schmidt "BindsTo=dev-mapper-%%i.device %s\n"
23bbb0de4e3f85d9704a5c12a5afa2dfa0159e41Michal Schmidt "Before=umount.target cryptsetup.target\n"
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering "IgnoreOnIsolate=true\n"
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering "Type=oneshot\n"
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering "RemainAfterExit=yes\n"
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering "TimeoutSec=0\n" /* the binary handles timeouts anyway */
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '' '%s'\n"
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
cca1dfddd4ce4357113663532696488427cc54e4Lennart Poettering log_error("Failed to write file %s: %m", p);
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering to = strjoin(arg_dest, "/", d, ".wants/", n, NULL);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering log_error("Failed to create symlink %s: %m", to);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering to = strjoin(arg_dest, "/cryptsetup.target.requires/", n, NULL);
1af7211984a8dba3c5ba40fae794c4c55f5e6bd3Lennart Poettering log_error("Failed to create symlink %s: %m", to);
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n, NULL);
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering log_error("Failed to create symlink %s: %m", to);
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering p = strjoin(arg_dest, "/dev-mapper-", e, ".device.d/50-job-timeout-sec-0.conf", NULL);
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering "# Automatically generated by systemd-gpt-auto-generator\n\n"
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering "JobTimeoutSec=0\n"); /* the binary handles timeouts anyway */
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering log_error("Failed to write device drop-in: %s", strerror(-r));
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers const char *id,
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers const char *what,
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers const char *where,
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering const char *post) {
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering _cleanup_free_ char *unit = NULL, *lnk = NULL, *crypto_what = NULL, *p = NULL;
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering log_debug("Adding %s: %s %s", where, what, strna(fstype));
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering r = add_cryptsetup(id, what, rw, &crypto_what);
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers log_error("Failed to create unit file %s: %m", unit);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering "# Automatically generated by systemd-gpt-auto-generator\n\n"
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering "Description=%s\n"
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering "Documentation=man:systemd-gpt-auto-generator(8)\n",
a0b1209c4a59754f428894e0485413542da50014Zbigniew Jędrzejewski-Szmek r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers "Where=%s\n",
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering fprintf(f, "Options=%s\n", rw ? "rw" : "ro");
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering log_error("Failed to write unit file %s: %m", p);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering lnk = strjoin(arg_dest, "/", post, ".requires/", unit, NULL);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering log_error("Failed to create symlink %s: %m", lnk);
cca1dfddd4ce4357113663532696488427cc54e4Lennart Poettering const char *post) {
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering _cleanup_blkid_free_probe_ blkid_probe b = NULL;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers log_debug("%s already populated, ignoring.", where);
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers /* Let's check the partition type here, so that we know
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers * whether to do LUKS magic. */
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers if (r == -2 || r == 1) /* no result or uncertain */
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering else if (r != 0) {
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersenstatic int enumerate_partitions(dev_t devnum) {
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen _cleanup_udev_device_unref_ struct udev_device *d = NULL;
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen _cleanup_blkid_free_probe_ blkid_probe b = NULL;
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen _cleanup_udev_unref_ struct udev *udev = NULL;
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen _cleanup_free_ char *home = NULL, *srv = NULL;
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen d = udev_device_new_from_devnum(udev, 'b', devnum);
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen log_debug("Not a partitioned device, ignoring.");
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen /* Does it have a devtype? */
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen log_debug("Parent doesn't have a device type, ignoring.");
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen /* Is this a disk or a partition? We only care for disks... */
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen log_debug("Parent isn't a raw disk, ignoring.");
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen /* Does it have a device node? */
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen log_debug("Parent device does not have device node, ignoring.");
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen if (r == -2 || r == 1) /* no result or uncertain */
7a1494aa4e4a131d73e866cf1e7eb7b6e47dbab8Tom Gundersen else if (r != 0) {
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers r = blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers if (r != 0) {
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers log_error("Failed to determine partition table type of %s: %m", node);
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers /* We only do this all for GPT... */
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers log_debug("Not a GPT partition table, ignoring.");
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers log_error("Failed to list partitions of %s: %m", node);
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers r = udev_enumerate_add_match_subsystem(e, "block");
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers if (r < 0) {
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers log_error("Failed to enumerate partitions on %s: %s", node, strerror(-r));
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers _cleanup_udev_device_unref_ struct udev_device *q;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers unsigned long long flags;
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers /* Ignore partitions that are not marked for automatic
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers * mounting on discovery */
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering if (sd_id128_from_string(stype, &type_id) < 0)
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek if (sd_id128_equal(type_id, GPT_SWAP)) {
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers log_debug("%s marked as read-only swap partition, which is bogus, ignoring.", subnode);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering } else if (sd_id128_equal(type_id, GPT_HOME)) {
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering /* We only care for the first /home partition */
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek home_rw = !(flags & GPT_FLAG_READ_ONLY),
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmek } else if (sd_id128_equal(type_id, GPT_SRV)) {
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmek /* We only care for the first /srv partition */
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmek srv_rw = !(flags & GPT_FLAG_READ_ONLY),
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering k = probe_and_add_mount("home", home, "/home", home_rw, "Home Partition", SPECIAL_LOCAL_FS_TARGET);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering k = probe_and_add_mount("srv", srv, "/srv", srv_rw, "Server Data Partition", SPECIAL_LOCAL_FS_TARGET);
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmekstatic int get_btrfs_block_device(const char *path, dev_t *dev) {
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering struct btrfs_ioctl_fs_info_args fsi = {};
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmek if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering /* We won't do this for btrfs RAID */
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poetteringstatic int get_block_device(const char *path, dev_t *dev) {
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering return get_btrfs_block_device(path, dev);
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmekstatic int parse_proc_cmdline_item(const char *key, const char *value) {
1ca208fb4f93e5869704af1812cbff7130a2fc03Zbigniew Jędrzejewski-Szmek if (STR_IN_SET(key, "systemd.gpt_auto", "rd.systemd.gpt_auto") && value) {
1a14a53cfded6e78c6e8dfb73fdff0039971d642Lennart Poettering log_warning("Failed to parse gpt-auto switch %s. Ignoring.", value);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering } else if (streq(key, "root") && value) {
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering /* Disable root disk logic if there's a root= value
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering * specified (unless it happens to be "gpt-auto") */
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering arg_root_enabled = streq(value, "gpt-auto");
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poetteringstatic int add_root_mount(void) {
0238d4c660e732dd03ba0cdb54a29ec5870ee849Kay Sievers log_debug("Not a EFI boot, not creating root mount.");
73b80ec2d999c45ce13f3e034704249d80829f7eLennart Poettering r = efi_loader_get_device_part_uuid(NULL);
d2a623823f8d83c97c35fcd28f90e8cd59066f8aZbigniew Jędrzejewski-Szmek log_debug("EFI loader partition unknown, exiting.");
cca1dfddd4ce4357113663532696488427cc54e4Lennart Poettering } else if (r < 0) {
cca1dfddd4ce4357113663532696488427cc54e4Lennart Poettering log_error("Failed to read ESP partition UUID: %s", strerror(-r));
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering /* OK, we have an ESP partition, this is fantastic, so let's
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers * wait for a root device to show up. A udev rule will create
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers * the link for us under the right name. */
2fc09a9cdd1ad25bc7c53a23d5301eb952e1ce3dDaniel Mack "Root Partition",
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_LOCAL_FS_TARGET);
0238d4c660e732dd03ba0cdb54a29ec5870ee849Kay Sieversstatic int add_mounts(void) {
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering log_error("Failed to determine block device of root file system: %s", strerror(-r));
cca1dfddd4ce4357113663532696488427cc54e4Lennart Poettering } else if (r == 0) {
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering log_debug("Root file system not on a (single) block device.");
e48fdd84432bbf9c2ecc339183258c7c33116032Lennart Poettering log_error("This program takes three or no arguments.");
59512f21d77d984cf1363fb0d1770218c5e17020Kay Sievers r = parse_proc_cmdline(parse_proc_cmdline_item);
61331eab0a53cd9b8446eab6d1ebf1a046d8efc1Lennart Poettering log_warning("Failed to parse kernel command line, ignoring: %s", strerror(-r));