gpt-auto-generator.c revision fa041593fe04b12ffd7e81d8b3598a7a6f313fb3
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering This file is part of systemd.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Copyright 2013 Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is free software; you can redistribute it and/or modify it
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering under the terms of the GNU Lesser General Public License as published by
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering (at your option) any later version.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering systemd is distributed in the hope that it will be useful, but
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering Lesser General Public License for more details.
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering You should have received a copy of the GNU Lesser General Public License
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic bool arg_enabled = true;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic bool arg_root_enabled = true;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic bool arg_root_rw = false;
36d9205d669bcdcb04fa730d1f3549a9fc9a9001Tom Gundersen _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
58db254ade4fb2ef77de68f28c4f13814819f6a1Lennart Poettering name = unit_name_from_path(path, ".swap");
58db254ade4fb2ef77de68f28c4f13814819f6a1Lennart Poettering unit = strjoin(arg_dest, "/", name, NULL);
58db254ade4fb2ef77de68f28c4f13814819f6a1Lennart Poettering log_error("Failed to create unit file %s: %m", unit);
58db254ade4fb2ef77de68f28c4f13814819f6a1Lennart Poettering "# Automatically generated by systemd-gpt-auto-generator\n\n"
58db254ade4fb2ef77de68f28c4f13814819f6a1Lennart Poettering "Description=Swap Partition\n"
58db254ade4fb2ef77de68f28c4f13814819f6a1Lennart Poettering "Documentation=man:systemd-gpt-auto-generator(8)\n\n"
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering log_error("Failed to write unit file %s: %m", unit);
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering log_error("Failed to create symlink %s: %m", lnk);
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poetteringstatic int add_cryptsetup(const char *id, const char *what, bool rw, char **device) {
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering _cleanup_free_ char *e = NULL, *n = NULL, *p = NULL, *d = NULL, *to = NULL;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering d = unit_name_from_path(what, ".device");
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering n = unit_name_build("systemd-cryptsetup", e, ".service");
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering log_error("Failed to create unit file %s: %m", p);
1b4f6e79ec51a57003896a0b605fba427b4a98d2Lennart Poettering "# Automatically generated by systemd-gpt-auto-generator\n\n"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering "Description=Cryptography Setup for %%I\n"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering "Documentation=man:systemd-gpt-auto-generator(8) man:systemd-cryptsetup@.service(8)\n"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering "DefaultDependencies=no\n"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering "Conflicts=umount.target\n"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering "BindsTo=dev-mapper-%%i.device %s\n"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering "Before=umount.target cryptsetup.target\n"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering "IgnoreOnIsolate=true\n"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering "After=systemd-readahead-collect.service systemd-readahead-replay.service\n\n"
1b4f6e79ec51a57003896a0b605fba427b4a98d2Lennart Poettering "Type=oneshot\n"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering "RemainAfterExit=yes\n"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering "TimeoutSec=0\n" /* the binary handles timeouts anyway */
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '' '%s'\n"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering log_error("Failed to write file %s: %m", p);
28b9b7640603f88cb49f95609331fa5072715f15Lennart Poettering to = strjoin(arg_dest, "/", d, ".wants/", n, NULL);
4d247a6cd3f69acbc5a09e8ac7e4fbb50eaa3228Lennart Poettering log_error("Failed to create symlink %s: %m", to);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering to = strjoin(arg_dest, "/cryptsetup.target.requires/", n, NULL);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering log_error("Failed to create symlink %s: %m", to);
105e151299dc1208855380be2b22d0db2d66ebc6Lennart Poettering to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n, NULL);
4d247a6cd3f69acbc5a09e8ac7e4fbb50eaa3228Lennart Poettering log_error("Failed to create symlink %s: %m", to);
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering p = strjoin(arg_dest, "/dev-mapper-", e, ".device.d/50-job-timeout-sec-0.conf", NULL);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering "# Automatically generated by systemd-gpt-auto-generator\n\n"
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering "JobTimeoutSec=0\n"); /* the binary handles timeouts anyway */
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering log_error("Failed to write device drop-in: %s", strerror(-r));
5d27351f8546530cf779847b0b04b0172c09f9d0Tom Gundersen const char *post) {
5d27351f8546530cf779847b0b04b0172c09f9d0Tom Gundersen _cleanup_free_ char *unit = NULL, *lnk = NULL, *crypto_what = NULL, *p = NULL;
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering log_debug("Adding %s: %s %s", where, what, strna(fstype));
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering r = add_cryptsetup(id, what, rw, &crypto_what);
547973dea7abd6c124ff6c79fe2bbe322a7314aeLennart Poettering log_error("Failed to create unit file %s: %m", unit);
547973dea7abd6c124ff6c79fe2bbe322a7314aeLennart Poettering "# Automatically generated by systemd-gpt-auto-generator\n\n"
547973dea7abd6c124ff6c79fe2bbe322a7314aeLennart Poettering "Description=%s\n"
547973dea7abd6c124ff6c79fe2bbe322a7314aeLennart Poettering "Documentation=man:systemd-gpt-auto-generator(8)\n",
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering fprintf(f, "Options=%s\n", rw ? "rw" : "ro");
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering log_error("Failed to write unit file %s: %m", p);
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering lnk = strjoin(arg_dest, "/", post, ".requires/", unit, NULL);
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering log_error("Failed to create symlink %s: %m", lnk);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering const char *post) {
d23a27a964748967e1ad20e86de869a753af555bTom Gundersen _cleanup_blkid_free_probe_ blkid_probe b = NULL;
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering if (path_is_mount_point(where, true) <= 0 &&
f2af5ea3cbf54998ed41d2d21a3448abb92ca7ffLennart Poettering log_debug("%s already populated, ignoring.", where);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering /* Let's check the partition type here, so that we know
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering * whether to do LUKS magic. */
f57e3cd5fa709ec0f52531eccba909ac0851927cLennart Poettering log_error("Failed to allocate prober: %m");
f57e3cd5fa709ec0f52531eccba909ac0851927cLennart Poettering blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
f57e3cd5fa709ec0f52531eccba909ac0851927cLennart Poettering if (r == -2 || r == 1) /* no result or uncertain */
f57e3cd5fa709ec0f52531eccba909ac0851927cLennart Poettering else if (r != 0) {
f57e3cd5fa709ec0f52531eccba909ac0851927cLennart Poettering log_error("Failed to probe %s: %m", what);
f57e3cd5fa709ec0f52531eccba909ac0851927cLennart Poettering blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
f57e3cd5fa709ec0f52531eccba909ac0851927cLennart Poetteringstatic int enumerate_partitions(dev_t devnum) {
f57e3cd5fa709ec0f52531eccba909ac0851927cLennart Poettering _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
f57e3cd5fa709ec0f52531eccba909ac0851927cLennart Poettering _cleanup_udev_device_unref_ struct udev_device *d = NULL;
f57e3cd5fa709ec0f52531eccba909ac0851927cLennart Poettering _cleanup_blkid_free_probe_ blkid_probe b = NULL;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering _cleanup_udev_unref_ struct udev *udev = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering _cleanup_free_ char *home = NULL, *srv = NULL;
8bf52d3d17d364438191077d0750b8b80b5dc53aLennart Poettering d = udev_device_new_from_devnum(udev, 'b', devnum);
8bf52d3d17d364438191077d0750b8b80b5dc53aLennart Poettering log_debug("Not a partitioned device, ignoring.");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Does it have a devtype? */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering devtype = udev_device_get_devtype(parent);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_debug("Parent doesn't have a device type, ignoring.");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Is this a disk or a partition? We only care for disks... */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_debug("Parent isn't a raw disk, ignoring.");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering /* Does it have a device node? */
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering log_debug("Parent device does not have device node, ignoring.");
9de3e3294065e8697ff10130b53f274319cdcf6fZbigniew Jędrzejewski-Szmek pn = udev_device_get_devnum(parent);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
9de3e3294065e8697ff10130b53f274319cdcf6fZbigniew Jędrzejewski-Szmek blkid_probe_enable_partitions(b, 1);
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
9de3e3294065e8697ff10130b53f274319cdcf6fZbigniew Jędrzejewski-Szmek if (r == -2 || r == 1) /* no result or uncertain */
9de3e3294065e8697ff10130b53f274319cdcf6fZbigniew Jędrzejewski-Szmek else if (r != 0) {
9de3e3294065e8697ff10130b53f274319cdcf6fZbigniew Jędrzejewski-Szmek log_error("Failed to probe %s: %m", node);
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering r = blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersen if (r != 0) {
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersen log_error("Failed to determine partition table type of %s: %m", node);
42cc2eebb01056beb7acd3ecfe8e533558237f84Lennart Poettering /* We only do this all for GPT... */
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek if (!streq_ptr(pttype, "gpt")) {
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek log_debug("Not a GPT partition table, ignoring.");
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek pl = blkid_probe_get_partitions(b);
50f1e641a93cacfc693b0c3d300bee5df0c8c460Tom Gundersen log_error("Failed to list partitions of %s: %m", node);
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen r = udev_enumerate_add_match_parent(e, parent);
9de3e3294065e8697ff10130b53f274319cdcf6fZbigniew Jędrzejewski-Szmek r = udev_enumerate_add_match_subsystem(e, "block");
9de3e3294065e8697ff10130b53f274319cdcf6fZbigniew Jędrzejewski-Szmek r = udev_enumerate_scan_devices(e);
a8812dd7f161a3e459c1730ac92ff2bbc9986ff1Lennart Poettering log_error("Failed to enumerate partitions on %s: %s", node, strerror(-r));
7b50eb2efa122200e39646c19a29abab302f7d24Lennart Poettering first = udev_enumerate_get_list_entry(e);
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering _cleanup_udev_device_unref_ struct udev_device *q;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering unsigned long long flags;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering pp = blkid_partlist_devno_to_partition(pl, qn);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering /* Ignore partitions that are not marked for automatic
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering * mounting on discovery */
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering stype = blkid_partition_get_type_string(pp);
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering if (sd_id128_from_string(stype, &type_id) < 0)
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering log_debug("%s marked as read-only swap partition, which is bogus, ignoring.", subnode);
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering } else if (sd_id128_equal(type_id, GPT_HOME)) {
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering /* We only care for the first /home partition */
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering } else if (sd_id128_equal(type_id, GPT_SRV)) {
4d247a6cd3f69acbc5a09e8ac7e4fbb50eaa3228Lennart Poettering /* We only care for the first /srv partition */
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering k = probe_and_add_mount("home", home, "/home", home_rw, "Home Partition", SPECIAL_LOCAL_FS_TARGET);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering k = probe_and_add_mount("srv", srv, "/srv", srv_rw, "Server Data Partition", SPECIAL_LOCAL_FS_TARGET);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poetteringstatic int get_btrfs_block_device(const char *path, dev_t *dev) {
9de3e3294065e8697ff10130b53f274319cdcf6fZbigniew Jędrzejewski-Szmek struct btrfs_ioctl_fs_info_args fsi = {};
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering /* We won't do this for btrfs RAID */
946c70944ebdf428ffeb9991a7449edbd4011461Zbigniew Jędrzejewski-Szmek if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek if (stat((char*) di.path, &st) < 0)
42cc2eebb01056beb7acd3ecfe8e533558237f84Lennart Poetteringstatic int get_block_device(const char *path, dev_t *dev) {
03664a62914782dbd8f069bbcf8a0c8ca1df7010Lukas Nykryn if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmekstatic int parse_proc_cmdline_item(const char *key, const char *value) {
50f1e641a93cacfc693b0c3d300bee5df0c8c460Tom Gundersen if (STR_IN_SET(key, "systemd.gpt_auto", "rd.systemd.gpt_auto") && value) {
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen log_warning("Failed to parse gpt-auto switch %s. Ignoring.", value);
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen /* Disable root disk logic if there's a root= value
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen * specified (unless it happens to be "gpt-auto") */
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering arg_root_enabled = streq(value, "gpt-auto");
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek else if (startswith(key, "systemd.gpt-auto.") || startswith(key, "rd.systemd.gpt-auto."))
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek log_warning("Unknown kernel switch %s. Ignoring.", key);
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmekstatic int add_root_mount(void) {
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek log_debug("Not a EFI boot, not creating root mount.");
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek r = efi_loader_get_device_part_uuid(NULL);
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek log_debug("EFI loader partition unknown, exiting.");
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek } else if (r < 0) {
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek log_error("Failed to read ESP partition UUID: %s", strerror(-r));
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek /* OK, we have an ESP partition, this is fantastic, so let's
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek * wait for a root device to show up. A udev rule will create
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek * the link for us under the right name. */
7c6423e19136a7b7b6ef3fe06b94822e582dda27Tom Gundersen "Root Partition",
7c6423e19136a7b7b6ef3fe06b94822e582dda27Tom Gundersen in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_LOCAL_FS_TARGET);
7c6423e19136a7b7b6ef3fe06b94822e582dda27Tom Gundersenstatic int add_mounts(void) {
cb57dd41595adddb08095298bb1ed258c8ea4877Tom Gundersen log_error("Failed to determine block device of root file system: %s", strerror(-r));
50f1e641a93cacfc693b0c3d300bee5df0c8c460Tom Gundersen } else if (r == 0) {
50f1e641a93cacfc693b0c3d300bee5df0c8c460Tom Gundersen log_debug("Root file system not on a (single) block device.");
50f1e641a93cacfc693b0c3d300bee5df0c8c460Tom Gundersen log_error("This program takes three or no arguments.");
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)