gpt-auto-generator.c revision f9ac15442e4132f00eca5495d53c17062aae13e0
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 unit = strjoin(arg_dest, "/", name, NULL);
58db254ade4fb2ef77de68f28c4f13814819f6a1Lennart Poettering return log_error_errno(errno, "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"
36d9205d669bcdcb04fa730d1f3549a9fc9a9001Tom Gundersen return log_error_errno(errno, "Failed to write unit file %s: %m", unit);
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET ".wants/", name, NULL);
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering return log_error_errno(errno, "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;
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering d = unit_name_from_path(what, ".device");
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering n = unit_name_build("systemd-cryptsetup", e, ".service");
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering return log_error_errno(errno, "Failed to create unit file %s: %m", p);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart 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"
1b4f6e79ec51a57003896a0b605fba427b4a98d2Lennart Poettering "IgnoreOnIsolate=true\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",
1b4f6e79ec51a57003896a0b605fba427b4a98d2Lennart Poettering return log_error_errno(errno, "Failed to write file %s: %m", p);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering to = strjoin(arg_dest, "/", d, ".wants/", n, NULL);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering return log_error_errno(errno, "Failed to create symlink %s: %m", to);
28b9b7640603f88cb49f95609331fa5072715f15Lennart Poettering to = strjoin(arg_dest, "/cryptsetup.target.requires/", n, NULL);
28b9b7640603f88cb49f95609331fa5072715f15Lennart Poettering return log_error_errno(errno, "Failed to create symlink %s: %m", to);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n, NULL);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering return log_error_errno(errno, "Failed to create symlink %s: %m", to);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart 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"
105e151299dc1208855380be2b22d0db2d66ebc6Lennart Poettering "JobTimeoutSec=0\n"); /* the binary handles timeouts anyway */
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering return log_error_errno(r, "Failed to write device drop-in: %m");
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering const char *post) {
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering _cleanup_free_ char *unit = NULL, *lnk = NULL, *crypto_what = NULL, *p = NULL;
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering log_debug("Adding %s: %s %s", where, what, strna(fstype));
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering r = add_cryptsetup(id, what, rw, &crypto_what);
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering return log_error_errno(errno, "Failed to create unit file %s: %m", unit);
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering "# Automatically generated by systemd-gpt-auto-generator\n\n"
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering "Description=%s\n"
801ad6a6a9cd8fbd58b9f9c27f20dbb3c87d47ddLennart Poettering "Documentation=man:systemd-gpt-auto-generator(8)\n",
5d27351f8546530cf779847b0b04b0172c09f9d0Tom Gundersen r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
547973dea7abd6c124ff6c79fe2bbe322a7314aeLennart Poettering fprintf(f, "Options=%s\n", rw ? "rw" : "ro");
547973dea7abd6c124ff6c79fe2bbe322a7314aeLennart Poettering return log_error_errno(errno, "Failed to write unit file %s: %m", p);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering lnk = strjoin(arg_dest, "/", post, ".requires/", unit, NULL);
b826ab586c9e0a9c0d438a75c28cf3a8ab485929Tom Gundersen return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering const char *post) {
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering _cleanup_blkid_free_probe_ blkid_probe b = NULL;
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering if (path_is_mount_point(where, true) <= 0 &&
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering log_debug("%s already populated, ignoring.", where);
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt /* Let's check the partition type here, so that we know
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt * whether to do LUKS magic. */
6af47493de0ef2b66d4c3fbcdd4a2e12fec4bfbaLennart Poettering log_error_errno(errno, "Failed to allocate prober: %m");
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering if (r == -2 || r == 1) /* no result or uncertain */
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering else if (r != 0) {
c52a97b896c914e17ba5be73c0e806455fd9ad4dLennart Poettering log_error_errno(errno, "Failed to probe %s: %m", what);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
ee3d6aff9bd73c1b23e29d1fa1fa6f7a1ef0533bLennart Poetteringstatic int enumerate_partitions(dev_t devnum) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering _cleanup_udev_device_unref_ struct udev_device *d = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering _cleanup_blkid_free_probe_ blkid_probe b = NULL;
8bf52d3d17d364438191077d0750b8b80b5dc53aLennart Poettering _cleanup_udev_unref_ struct udev *udev = NULL;
8bf52d3d17d364438191077d0750b8b80b5dc53aLennart Poettering _cleanup_free_ char *home = NULL, *srv = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering d = udev_device_new_from_devnum(udev, 'b', devnum);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart 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.");
9de3e3294065e8697ff10130b53f274319cdcf6fZbigniew Jędrzejewski-Szmek /* Is this a disk or a partition? We only care for disks... */
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering log_debug("Parent isn't a raw disk, ignoring.");
9de3e3294065e8697ff10130b53f274319cdcf6fZbigniew Jędrzejewski-Szmek /* Does it have a device node? */
9de3e3294065e8697ff10130b53f274319cdcf6fZbigniew Jędrzejewski-Szmek node = udev_device_get_devnode(parent);
8ac4e9e1e54397f6d1745c2a7a806132418c7da2Lennart Poettering log_debug("Parent device does not have device node, ignoring.");
9de3e3294065e8697ff10130b53f274319cdcf6fZbigniew Jędrzejewski-Szmek log_debug("Root device %s.", node);
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering log_error_errno(errno, "Failed allocate prober: %m");
946c70944ebdf428ffeb9991a7449edbd4011461Zbigniew Jędrzejewski-Szmek blkid_probe_enable_partitions(b, 1);
9de3e3294065e8697ff10130b53f274319cdcf6fZbigniew Jędrzejewski-Szmek blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersen if (r == -2 || r == 1) /* no result or uncertain */
42cc2eebb01056beb7acd3ecfe8e533558237f84Lennart Poettering else if (r != 0) {
42cc2eebb01056beb7acd3ecfe8e533558237f84Lennart Poettering log_error_errno(errno, "Failed to probe %s: %m", node);
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek r = blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek log_error_errno(errno, "Failed to determine partition table type of %s: %m", node);
50f1e641a93cacfc693b0c3d300bee5df0c8c460Tom Gundersen /* We only do this all for GPT... */
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen log_debug("Not a GPT partition table, ignoring.");
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering log_error_errno(errno, "Failed to list partitions of %s: %m", node);
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering r = udev_enumerate_add_match_parent(e, parent);
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering r = udev_enumerate_add_match_subsystem(e, "block");
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering return log_error_errno(r, "Failed to enumerate partitions on %s: %m", node);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering first = udev_enumerate_get_list_entry(e);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart 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);
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering /* Ignore partitions that are not marked for automatic
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart 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);
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering } else if (sd_id128_equal(type_id, GPT_HOME)) {
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering /* We only care for the first /home partition */
fd0b4602f6332c3f1660eb208c8f5c719709a009Lennart Poettering } else if (sd_id128_equal(type_id, GPT_SRV)) {
9c92ce6d67f88beb31dd6555d12ae3f632218a39Lennart Poettering /* We only care for the first /srv partition */
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poettering k = probe_and_add_mount("home", home, "/home", home_rw, "Home Partition", SPECIAL_LOCAL_FS_TARGET);
2001c80560e3dae69e14fd994d3978c187af48b8Lennart Poettering k = probe_and_add_mount("srv", srv, "/srv", srv_rw, "Server Data Partition", SPECIAL_LOCAL_FS_TARGET);
2d4c5cbc0ed3ccb09dc086a040088b454c22c644Lennart Poetteringstatic int get_block_device(const char *path, dev_t *dev) {
946c70944ebdf428ffeb9991a7449edbd4011461Zbigniew Jędrzejewski-Szmek if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC))
946c70944ebdf428ffeb9991a7449edbd4011461Zbigniew Jędrzejewski-Szmek return btrfs_get_block_device(path, dev);
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmekstatic int parse_proc_cmdline_item(const char *key, const char *value) {
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek if (STR_IN_SET(key, "systemd.gpt_auto", "rd.systemd.gpt_auto") && value) {
abf126a355e2f2b62b6c51ab3bb37895d1e3eee7Tom Gundersen log_warning("Failed to parse gpt-auto switch %s. Ignoring.", value);
42cc2eebb01056beb7acd3ecfe8e533558237f84Lennart Poettering } else if (streq(key, "root") && value) {
42cc2eebb01056beb7acd3ecfe8e533558237f84Lennart Poettering /* Disable root disk logic if there's a root= value
549c1a2564b56f2bb38f1203d59c747ea15817f3Tom Gundersen * specified (unless it happens to be "gpt-auto") */
42cc2eebb01056beb7acd3ecfe8e533558237f84Lennart Poettering arg_root_enabled = streq(value, "gpt-auto");
8db0d2f5c37e7e8f5bfce016cfdad7947a3ea939Zbigniew Jędrzejewski-Szmek else if (streq(key, "ro") && !value)
03664a62914782dbd8f069bbcf8a0c8ca1df7010Lukas Nykrynstatic int add_root_mount(void) {
03664a62914782dbd8f069bbcf8a0c8ca1df7010Lukas Nykryn log_debug("Not a EFI boot, not creating root mount.");
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek r = efi_loader_get_device_part_uuid(NULL);
151226ab4bf276d60d51864330a99f886b923697Zbigniew Jędrzejewski-Szmek log_debug("EFI loader partition unknown, exiting.");
50f1e641a93cacfc693b0c3d300bee5df0c8c460Tom Gundersen } else if (r < 0)
50f1e641a93cacfc693b0c3d300bee5df0c8c460Tom Gundersen return log_error_errno(r, "Failed to read ESP partition UUID: %m");
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen /* OK, we have an ESP partition, this is fantastic, so let's
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen * wait for a root device to show up. A udev rule will create
5d45a8808431987c370706d365fb0cc95cf03d52Tom Gundersen * the link for us under the right name. */
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering "Root Partition",
322345fdb9865ef2477fba8e4bdde0e1183ef505Lennart Poettering in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_LOCAL_FS_TARGET);
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek r = get_block_device("/", &devno);
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek return log_error_errno(r, "Failed to determine block device of root file system: %m");
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek else if (r == 0) {
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek log_debug("Root file system not on a (single) block device.");
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek return enumerate_partitions(devno);
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmekint main(int argc, char *argv[]) {
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek log_error("This program takes three or no arguments.");
0dae31d468b1a0e22d98921f7b0dbd92fd217167Zbigniew Jędrzejewski-Szmek log_set_target(LOG_TARGET_SAFE);
7c6423e19136a7b7b6ef3fe06b94822e582dda27Tom Gundersen r = parse_proc_cmdline(parse_proc_cmdline_item);
7c6423e19136a7b7b6ef3fe06b94822e582dda27Tom Gundersen log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");