gpt-auto-generator.c revision 821b2e792159e237a1e5a1ea4bb6ae2e55d64be5
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;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering _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"
1b4f6e79ec51a57003896a0b605fba427b4a98d2Lennart 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"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering "Type=oneshot\n"
1b4f6e79ec51a57003896a0b605fba427b4a98d2Lennart 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);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart 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);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n, NULL);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart 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"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering "JobTimeoutSec=0\n"); /* the binary handles timeouts anyway */
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering log_error("Failed to write device drop-in: %s", strerror(-r));
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering const char *post) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering _cleanup_free_ char *unit = NULL, *lnk = NULL, *crypto_what = NULL, *p = NULL;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart 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);
65b200e70d01cb7c513114b602c9b5cf41348f77Lennart Poettering "# Automatically generated by systemd-gpt-auto-generator\n\n"
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering "Description=%s\n"
547973dea7abd6c124ff6c79fe2bbe322a7314aeLennart Poettering "Documentation=man:systemd-gpt-auto-generator(8)\n",
b826ab586c9e0a9c0d438a75c28cf3a8ab485929Tom Gundersen r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart 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);
6af47493de0ef2b66d4c3fbcdd4a2e12fec4bfbaLennart Poettering const char *post) {
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering _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;
f57e3cd5fa709ec0f52531eccba909ac0851927cLennart Poettering _cleanup_udev_unref_ struct udev *udev = NULL;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering _cleanup_free_ char *home = NULL, *srv = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering d = udev_device_new_from_devnum(udev, 'b', devnum);
8bf52d3d17d364438191077d0750b8b80b5dc53aLennart Poettering log_debug("Not a partitioned device, ignoring.");
8bf52d3d17d364438191077d0750b8b80b5dc53aLennart 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 blkid_probe_enable_partitions(b, 1);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
9de3e3294065e8697ff10130b53f274319cdcf6fZbigniew Jędrzejewski-Szmek if (r == -2 || r == 1) /* no result or uncertain */
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering else if (r != 0) {
9de3e3294065e8697ff10130b53f274319cdcf6fZbigniew Jędrzejewski-Szmek log_error("Failed to probe %s: %m", node);
9de3e3294065e8697ff10130b53f274319cdcf6fZbigniew Jędrzejewski-Szmek r = blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersen log_error("Failed to determine partition table type of %s: %m", node);
42cc2eebb01056beb7acd3ecfe8e533558237f84Lennart Poettering /* We only do this all for GPT... */
42cc2eebb01056beb7acd3ecfe8e533558237f84Lennart Poettering log_debug("Not a GPT partition table, ignoring.");
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek pl = blkid_probe_get_partitions(b);
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek log_error("Failed to list partitions of %s: %m", node);
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen r = udev_enumerate_add_match_parent(e, parent);
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek r = udev_enumerate_add_match_subsystem(e, "block");
48d45d2b49d2adb870cd5f1bc7cb389b33655f1cZbigniew Jędrzejewski-Szmek log_error("Failed to enumerate partitions on %s: %s", node, strerror(-r));
9de3e3294065e8697ff10130b53f274319cdcf6fZbigniew Jędrzejewski-Szmek first = udev_enumerate_get_list_entry(e);
9de3e3294065e8697ff10130b53f274319cdcf6fZbigniew Jędrzejewski-Szmek _cleanup_udev_device_unref_ struct udev_device *q;
7b50eb2efa122200e39646c19a29abab302f7d24Lennart Poettering unsigned long long flags;
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart 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 */
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering stype = blkid_partition_get_type_string(pp);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart 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 */
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering } else if (sd_id128_equal(type_id, GPT_SRV)) {
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering /* We only care for the first /srv partition */
fd0b4602f6332c3f1660eb208c8f5c719709a009Lennart Poettering k = probe_and_add_mount("home", home, "/home", home_rw, "Home Partition", SPECIAL_LOCAL_FS_TARGET);
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart 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) {
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering struct btrfs_ioctl_fs_info_args fsi = {};
2e276efc7b0398a3086629a52970bdd4ab7252f9Zbigniew Jędrzejewski-Szmek if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering /* We won't do this for btrfs RAID */
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) {
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmekstatic int get_block_device(const char *path, dev_t *dev) {
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek return get_btrfs_block_device(path, dev);
03664a62914782dbd8f069bbcf8a0c8ca1df7010Lukas Nykrynstatic int parse_proc_cmdline_item(const char *key, const char *value) {
03664a62914782dbd8f069bbcf8a0c8ca1df7010Lukas Nykryn if (STR_IN_SET(key, "systemd.gpt_auto", "rd.systemd.gpt_auto") && value) {
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek log_warning("Failed to parse gpt-auto switch %s. Ignoring.", value);
50f1e641a93cacfc693b0c3d300bee5df0c8c460Tom Gundersen /* Disable root disk logic if there's a root= value
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen * specified (unless it happens to be "gpt-auto") */
48d45d2b49d2adb870cd5f1bc7cb389b33655f1cZbigniew Jędrzejewski-Szmekstatic int add_root_mount(void) {
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering 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. */
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek "Root Partition",
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_LOCAL_FS_TARGET);
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek r = get_block_device("/", &devno);
7c6423e19136a7b7b6ef3fe06b94822e582dda27Tom Gundersen log_error("Failed to determine block device of root file system: %s", strerror(-r));
7c6423e19136a7b7b6ef3fe06b94822e582dda27Tom Gundersen } else if (r == 0) {
7c6423e19136a7b7b6ef3fe06b94822e582dda27Tom Gundersen log_debug("Root file system not on a (single) block device.");
50f1e641a93cacfc693b0c3d300bee5df0c8c460Tom Gundersen log_error("This program takes three or no arguments.");
50f1e641a93cacfc693b0c3d300bee5df0c8c460Tom Gundersen if (parse_proc_cmdline(parse_proc_cmdline_item) < 0)