X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fgpt-auto-generator%2Fgpt-auto-generator.c;h=c4109f39b71eb2bde28d35ba34effe0f7d8b4567;hp=017c35dcd6414014745169e708296ee32946527f;hb=1ebab691c7749779072741f71865bd0e055b7ecf;hpb=96115cdfe0241ae9b4e7177cd3874c0a93d00b39 diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index 017c35dcd..c4109f39b 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -30,27 +30,19 @@ #include #endif +#include "sd-id128.h" +#include "libudev.h" #include "path-util.h" #include "util.h" #include "mkdir.h" #include "missing.h" -#include "sd-id128.h" -#include "libudev.h" #include "udev-util.h" #include "special.h" #include "unit-name.h" #include "virt.h" - -/* TODO: - * - * - Properly handle cryptsetup partitions - * - Define new partition type for encrypted swap - * - Make /home automount rather than mount - * - */ - -#define GPT_SWAP SD_ID128_MAKE(06,57,fd,6d,a4,ab,43,c4,84,e5,09,33,c8,4b,4f,4f) -#define GPT_HOME SD_ID128_MAKE(93,3a,c7,e1,2e,b4,4f,13,b8,44,0e,14,e2,ae,f9,15) +#include "generator.h" +#include "gpt.h" +#include "fileio.h" static const char *arg_dest = "/tmp"; @@ -74,10 +66,8 @@ static int verify_gpt_partition(const char *node, sd_id128_t *type, unsigned *nr errno = 0; r = blkid_do_safeprobe(b); - if (r == -2) - return -ENODEV; - else if (r == 1) - return -ENODEV; + if (r == -2 || r == 1) /* no result or uncertain */ + return -EBADSLT; else if (r != 0) return errno ? -errno : -EIO; @@ -155,9 +145,7 @@ static int add_swap(const char *path, const char *fstype) { fprintf(f, "# Automatically generated by systemd-gpt-auto-generator\n\n" "[Unit]\n" - "DefaultDependencies=no\n" - "Conflicts=" SPECIAL_UMOUNT_TARGET "\n" - "Before=" SPECIAL_UMOUNT_TARGET " " SPECIAL_SWAP_TARGET "\n\n" + "Description=Swap Partition\n\n" "[Swap]\n" "What=%s\n", path); @@ -181,42 +169,187 @@ static int add_swap(const char *path, const char *fstype) { return 0; } -static int add_home(const char *path, const char *fstype) { - _cleanup_free_ char *unit = NULL, *lnk = NULL, *fsck = NULL; +static int add_cryptsetup(const char *id, const char *what, char **device) { + _cleanup_free_ char *e = NULL, *n = NULL, *p = NULL, *d = NULL, *to = NULL; + _cleanup_fclose_ FILE *f = NULL; + char *from, *ret; + int r; + + assert(id); + assert(what); + assert(device); + + d = unit_name_from_path(what, ".device"); + if (!d) + return log_oom(); + + e = unit_name_escape(id); + if (!e) + return log_oom(); + + n = unit_name_build("systemd-cryptsetup", e, ".service"); + if (!n) + return log_oom(); + + p = strjoin(arg_dest, "/", n, NULL); + if (!n) + return log_oom(); + + f = fopen(p, "wxe"); + if (!f) { + log_error("Failed to create unit file %s: %m", p); + return -errno; + } + + fprintf(f, + "# Automatically generated by systemd-gpt-auto-generator\n\n" + "[Unit]\n" + "Description=Cryptography Setup for %%I\n" + "Documentation=man:systemd-cryptsetup@.service(8)\n" + "DefaultDependencies=no\n" + "Conflicts=umount.target\n" + "BindsTo=dev-mapper-%%i.device %s\n" + "Before=umount.target cryptsetup.target\n" + "After=%s\n" + "IgnoreOnIsolate=true\n" + "After=systemd-readahead-collect.service systemd-readahead-replay.service\n\n" + "[Service]\n" + "Type=oneshot\n" + "RemainAfterExit=yes\n" + "TimeoutSec=0\n" /* the binary handles timeouts anyway */ + "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s'\n" + "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n", + d, d, + id, what, + id); + + fflush(f); + if (ferror(f)) { + log_error("Failed to write file %s: %m", p); + return -errno; + } + + from = strappenda("../", n); + + to = strjoin(arg_dest, "/", d, ".wants/", n, NULL); + if (!to) + return log_oom(); + + mkdir_parents_label(to, 0755); + if (symlink(from, to) < 0) { + log_error("Failed to create symlink %s: %m", to); + return -errno; + } + + free(to); + to = strjoin(arg_dest, "/cryptsetup.target.requires/", n, NULL); + if (!to) + return log_oom(); + + mkdir_parents_label(to, 0755); + if (symlink(from, to) < 0) { + log_error("Failed to create symlink %s: %m", to); + return -errno; + } + + free(to); + to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n, NULL); + if (!to) + return log_oom(); + + mkdir_parents_label(to, 0755); + if (symlink(from, to) < 0) { + log_error("Failed to create symlink %s: %m", to); + return -errno; + } + + free(p); + p = strjoin(arg_dest, "/dev-mapper-", e, ".device.d/50-job-timeout-sec-0.conf", NULL); + if (!p) + return log_oom(); + + mkdir_parents_label(p, 0755); + r = write_string_file(p, + "# Automatically generated by systemd-gpt-auto-generator\n\n" + "[Unit]\n" + "JobTimeoutSec=0\n"); /* the binary handles timeouts anyway */ + if (r < 0) { + log_error("Failed to write device drop-in: %s", strerror(-r)); + return r; + } + + ret = strappend("/dev/mapper/", id); + if (!ret) + return log_oom(); + + *device = ret; + return 0; +} + +static int add_mount(const char *id, const char *what, const char *where, const char *fstype, const char *description) { + _cleanup_free_ char *unit = NULL, *lnk = NULL, *crypto_what = NULL, *p = NULL; _cleanup_fclose_ FILE *f = NULL; + int r; - if (dir_is_empty("/home") <= 0) + assert(id); + assert(what); + assert(where); + assert(fstype); + assert(description); + + if (dir_is_empty(where) <= 0) { + log_debug("%s already populated, ignoring.", where); return 0; + } - log_debug("Adding home: %s %s", path, fstype); + log_debug("Adding %s: %s %s", where, what, fstype); - unit = strappend(arg_dest, "/home.mount"); + if (streq(fstype, "crypto_LUKS")) { + + r = add_cryptsetup(id, what, &crypto_what); + if (r < 0) + return r; + + what = crypto_what; + fstype = NULL; + } + + unit = unit_name_from_path(where, ".mount"); if (!unit) return log_oom(); - f = fopen(unit, "wxe"); + p = strjoin(arg_dest, "/", unit, NULL); + if (!p) + return log_oom(); + + f = fopen(p, "wxe"); if (!f) { log_error("Failed to create unit file %s: %m", unit); return -errno; } - fsck = unit_name_from_path_instance("systemd-fsck", path, ".service"); - if (!fsck) - return log_oom(); - fprintf(f, "# Automatically generated by systemd-gpt-auto-generator\n\n" "[Unit]\n" - "DefaultDependencies=no\n" - "Requires=%s\n" - "After=" SPECIAL_LOCAL_FS_PRE_TARGET " %s\n" - "Conflicts=" SPECIAL_UMOUNT_TARGET "\n" - "Before=" SPECIAL_UMOUNT_TARGET " " SPECIAL_LOCAL_FS_TARGET "\n\n" + "Description=%s\n", + description); + + r = generator_write_fsck_deps(f, arg_dest, what, where, fstype); + if (r < 0) + return r; + + fprintf(f, + "\n" "[Mount]\n" "What=%s\n" - "Where=/home\n" - "Type=%s\n", - fsck, fsck, path, fstype); + "Where=%s\n", + what, where); + + if (fstype) { + fprintf(f, + "Type=%s\n", + fstype); + } fflush(f); if (ferror(f)) { @@ -224,7 +357,7 @@ static int add_home(const char *path, const char *fstype) { return -errno; } - lnk = strjoin(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".requires/home.mount", NULL); + lnk = strjoin(arg_dest, "/" SPECIAL_LOCAL_FS_TARGET ".requires/", unit, NULL); if (!lnk) return log_oom(); @@ -238,12 +371,12 @@ static int add_home(const char *path, const char *fstype) { } static int enumerate_partitions(struct udev *udev, dev_t dev) { - struct udev_device *parent = NULL; _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL; _cleanup_udev_device_unref_ struct udev_device *d = NULL; + _cleanup_free_ char *home = NULL, *home_fstype = NULL, *srv = NULL, *srv_fstype = NULL; + unsigned home_nr = (unsigned) -1, srv_nr = (unsigned )-1; struct udev_list_entry *first, *item; - unsigned home_nr = (unsigned) -1; - _cleanup_free_ char *home = NULL, *home_fstype = NULL; + struct udev_device *parent = NULL; int r; e = udev_enumerate_new(udev); @@ -268,16 +401,15 @@ static int enumerate_partitions(struct udev *udev, dev_t dev) { r = udev_enumerate_scan_devices(e); if (r < 0) { - log_error("Failed to enumerate partitions on /dev/block/%u:%u: %s", - major(dev), minor(dev), strerror(-r)); + log_error("Failed to enumerate partitions on /dev/block/%u:%u: %s", major(dev), minor(dev), strerror(-r)); return r; } first = udev_enumerate_get_list_entry(e); udev_list_entry_foreach(item, first) { + _cleanup_udev_device_unref_ struct udev_device *q; _cleanup_free_ char *fstype = NULL; const char *node = NULL; - _cleanup_udev_device_unref_ struct udev_device *q; sd_id128_t type_id; unsigned nr; @@ -297,8 +429,10 @@ static int enumerate_partitions(struct udev *udev, dev_t dev) { r = verify_gpt_partition(node, &type_id, &nr, &fstype); if (r < 0) { - log_error("Failed to verify GPT partition %s: %s", - node, strerror(-r)); + /* skip child devices which are not detected properly */ + if (r == -EBADSLT) + continue; + log_error("Failed to verify GPT partition %s: %s", node, strerror(-r)); return r; } if (r == 0) @@ -306,24 +440,48 @@ static int enumerate_partitions(struct udev *udev, dev_t dev) { if (sd_id128_equal(type_id, GPT_SWAP)) add_swap(node, fstype); + else if (sd_id128_equal(type_id, GPT_HOME)) { - if (!home || nr < home_nr) { - free(home); - home = strdup(node); - if (!home) - return log_oom(); - - home_nr = nr; - - free(home_fstype); - home_fstype = fstype; - fstype = NULL; - } + + /* We only care for the first /home partition */ + if (home && nr >= home_nr) + continue; + + home_nr = nr; + + free(home); + home = strdup(node); + if (!home) + return log_oom(); + + free(home_fstype); + home_fstype = fstype; + fstype = NULL; + + } else if (sd_id128_equal(type_id, GPT_SRV)) { + + /* We only care for the first /srv partition */ + if (srv && nr >= srv_nr) + continue; + + srv_nr = nr; + + free(srv); + srv = strdup(node); + if (!srv) + return log_oom(); + + free(srv_fstype); + srv_fstype = fstype; + fstype = NULL; } } if (home && home_fstype) - add_home(home, home_fstype); + add_mount("home", home, "/home", home_fstype, "Home Partition"); + + if (srv && srv_fstype) + add_mount("srv", srv, "/srv", srv_fstype, "Server Data Partition"); return r; } @@ -383,7 +541,7 @@ static int get_block_device(const char *path, dev_t *dev) { assert(path); assert(dev); - if (lstat("/", &st)) + if (lstat(path, &st)) return -errno; if (major(st.st_dev) != 0) { @@ -391,7 +549,7 @@ static int get_block_device(const char *path, dev_t *dev) { return 1; } - if (statfs("/", &sfs) < 0) + if (statfs(path, &sfs) < 0) return -errno; if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC)) @@ -422,15 +580,14 @@ static int devno_to_devnode(struct udev *udev, dev_t devno, char **ret) { } int main(int argc, char *argv[]) { - _cleanup_free_ char *node = NULL; _cleanup_udev_unref_ struct udev *udev = NULL; + _cleanup_free_ char *node = NULL; dev_t devno; int r = 0; if (argc > 1 && argc != 4) { log_error("This program takes three or no arguments."); - r = -EINVAL; - goto finish; + return EXIT_FAILURE; } if (argc > 1) @@ -444,34 +601,33 @@ int main(int argc, char *argv[]) { if (in_initrd()) { log_debug("In initrd, exiting."); - goto finish; + return EXIT_SUCCESS; } if (detect_container(NULL) > 0) { log_debug("In a container, exiting."); - goto finish; + return EXIT_SUCCESS; } r = get_block_device("/", &devno); if (r < 0) { log_error("Failed to determine block device of root file system: %s", strerror(-r)); - goto finish; - } - if (r == 0) { + return EXIT_FAILURE; + } else if (r == 0) { log_debug("Root file system not on a (single) block device."); - goto finish; + return EXIT_SUCCESS; } udev = udev_new(); if (!udev) { - r = log_oom(); - goto finish; + log_oom(); + return EXIT_FAILURE; } r = devno_to_devnode(udev, devno, &node); if (r < 0) { log_error("Failed to determine block device node from major/minor: %s", strerror(-r)); - goto finish; + return EXIT_FAILURE; } log_debug("Root device %s.", node); @@ -479,13 +635,16 @@ int main(int argc, char *argv[]) { r = verify_gpt_partition(node, NULL, NULL, NULL); if (r < 0) { log_error("Failed to verify GPT partition %s: %s", node, strerror(-r)); - goto finish; + return EXIT_FAILURE; + } + if (r == 0) { + log_debug("Not a GPT disk, exiting."); + return EXIT_SUCCESS; } - if (r == 0) - goto finish; r = enumerate_partitions(udev, devno); + if (r < 0) + return EXIT_FAILURE; -finish: - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + return EXIT_SUCCESS; }