X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fgpt-auto-generator%2Fgpt-auto-generator.c;h=6267d9dba5f7caaeb39fdd9d1344146250eec22f;hb=6a3f892a23db71544d0439355f96c44350dafa8f;hp=d2b4213af2ebafaba55170a515623fdae795fc8d;hpb=9a5cb1371b6d8b0a04bd08665bcf9b06cb40c64c;p=elogind.git diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index d2b4213af..6267d9dba 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #ifdef HAVE_LINUX_BTRFS_H #include @@ -36,24 +36,16 @@ #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 - * - */ +#include "generator.h" +#include "gpt.h" static const char *arg_dest = "/tmp"; -static inline void blkid_free_probep(blkid_probe *b) { - if (*b) - blkid_free_probe(*b); -} +DEFINE_TRIVIAL_CLEANUP_FUNC(blkid_probe, blkid_free_probe); #define _cleanup_blkid_freep_probe_ _cleanup_(blkid_free_probep) static int verify_gpt_partition(const char *node, sd_id128_t *type, unsigned *nr, char **fstype) { @@ -73,10 +65,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; @@ -113,13 +103,13 @@ static int verify_gpt_partition(const char *node, sd_id128_t *type, unsigned *nr if (fstype) { - char *fst; - errno = 0; r = blkid_probe_lookup_value(b, "TYPE", &v, NULL); if (r != 0) *fstype = NULL; else { + char *fst; + fst = strdup(v); if (!fst) return -ENOMEM; @@ -153,10 +143,6 @@ 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" "[Swap]\n" "What=%s\n", path); @@ -180,20 +166,27 @@ 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; +static int add_mount(const char *what, const char *where, const char *fstype, const char *description) { + _cleanup_free_ char *unit = NULL, *lnk = NULL, *p = NULL; _cleanup_fclose_ FILE *f = NULL; + int r; - if (dir_is_empty("/home") <= 0) + 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"); + 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; @@ -202,16 +195,20 @@ static int add_home(const char *path, const char *fstype) { fprintf(f, "# Automatically generated by systemd-gpt-auto-generator\n\n" "[Unit]\n" - "DefaultDependencies=no\n" - "After=" SPECIAL_LOCAL_FS_PRE_TARGET "\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" - "FsckPassNo=2\n", - path, fstype); + "Where=%s\n" + "Type=%s\n", + what, where, fstype); fflush(f); if (ferror(f)) { @@ -219,11 +216,10 @@ 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(); - mkdir_parents_label(lnk, 0755); if (symlink(unit, lnk) < 0) { log_error("Failed to create symlink %s: %m", lnk); @@ -234,126 +230,123 @@ static int add_home(const char *path, const char *fstype) { } static int enumerate_partitions(struct udev *udev, dev_t dev) { - struct udev_enumerate *e = NULL; - struct udev_device *parent = NULL, *d = 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); - if (!e) { - r = log_oom(); - goto finish; - } + if (!e) + return log_oom(); d = udev_device_new_from_devnum(udev, 'b', dev); - if (!d) { - r = log_oom(); - goto finish; - } + if (!d) + return log_oom(); parent = udev_device_get_parent(d); - if (!parent) { - r = log_oom(); - goto finish; - } + if (!parent) + return log_oom(); r = udev_enumerate_add_match_parent(e, parent); - if (r < 0) { - r = log_oom(); - goto finish; - } + if (r < 0) + return log_oom(); r = udev_enumerate_add_match_subsystem(e, "block"); - if (r < 0) { - r = log_oom(); - goto finish; - } + if (r < 0) + return log_oom(); 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)); - goto finish; + 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; - struct udev_device *q; sd_id128_t type_id; unsigned nr; q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)); - if (!q) { - r = log_oom(); - goto finish; - } + if (!q) + return log_oom(); if (udev_device_get_devnum(q) == udev_device_get_devnum(d)) - goto skip; + continue; if (udev_device_get_devnum(q) == udev_device_get_devnum(parent)) - goto skip; + continue; node = udev_device_get_devnode(q); - if (!node) { - r = log_oom(); - goto finish; - } + if (!node) + return log_oom(); r = verify_gpt_partition(node, &type_id, &nr, &fstype); if (r < 0) { - log_error("Failed to verify GPT partition %s: %s", - node, strerror(-r)); - udev_device_unref(q); - goto finish; + /* 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) - goto skip; + continue; - if (sd_id128_equal(type_id, SD_ID128_MAKE(06,57,fd,6d,a4,ab,43,c4,84,e5,09,33,c8,4b,4f,4f))) + if (sd_id128_equal(type_id, GPT_SWAP)) add_swap(node, fstype); - else if (sd_id128_equal(type_id, SD_ID128_MAKE(93,3a,c7,e1,2e,b4,4f,13,b8,44,0e,14,e2,ae,f9,15))) { - - if (!home || nr < home_nr) { - free(home); - home = strdup(node); - if (!home) { - r = log_oom(); - goto finish; - } - - home_nr = nr; - - free(home_fstype); - home_fstype = fstype; - fstype = NULL; - } - } - skip: - udev_device_unref(q); - } + else if (sd_id128_equal(type_id, GPT_HOME)) { - if (home && home_fstype) - add_home(home, home_fstype); + /* 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)) { -finish: - if (d) - udev_device_unref(d); + /* 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 (e) - udev_enumerate_unref(e); + if (home && home_fstype) + add_mount(home, "/home", home_fstype, "Home Partition"); + if (srv && srv_fstype) + add_mount(srv, "/srv", srv_fstype, "Server Data Partition"); return r; } static int get_btrfs_block_device(const char *path, dev_t *dev) { - struct btrfs_ioctl_fs_info_args fsi; + struct btrfs_ioctl_fs_info_args fsi = {}; _cleanup_close_ int fd = -1; uint64_t id; @@ -364,7 +357,6 @@ static int get_btrfs_block_device(const char *path, dev_t *dev) { if (fd < 0) return -errno; - zero(fsi); if (ioctl(fd, BTRFS_IOC_FS_INFO, &fsi) < 0) return -errno; @@ -373,12 +365,11 @@ static int get_btrfs_block_device(const char *path, dev_t *dev) { return 0; for (id = 1; id <= fsi.max_id; id++) { - struct btrfs_ioctl_dev_info_args di; + struct btrfs_ioctl_dev_info_args di = { + .devid = id, + }; struct stat st; - zero(di); - di.devid = id; - if (ioctl(fd, BTRFS_IOC_DEV_INFO, &di) < 0) { if (errno == ENODEV) continue; @@ -409,7 +400,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) { @@ -417,7 +408,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)) @@ -427,49 +418,35 @@ static int get_block_device(const char *path, dev_t *dev) { } static int devno_to_devnode(struct udev *udev, dev_t devno, char **ret) { - struct udev_device *d = NULL; + _cleanup_udev_device_unref_ struct udev_device *d; const char *t; char *n; - int r; d = udev_device_new_from_devnum(udev, 'b', devno); - if (!d) { - r = log_oom(); - goto finish; - } + if (!d) + return log_oom(); t = udev_device_get_devnode(d); - if (!t) { - r = -ENODEV; - goto finish; - } + if (!t) + return -ENODEV; n = strdup(t); - if (!n) { - r = -ENOMEM; - goto finish; - } + if (!n) + return -ENOMEM; *ret = n; - r = 0; - -finish: - if (d) - udev_device_unref(d); - - return r; + return 0; } int main(int argc, char *argv[]) { + _cleanup_udev_unref_ struct udev *udev = NULL; _cleanup_free_ char *node = NULL; - struct udev *udev = NULL; dev_t devno; - int r; + 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) @@ -483,36 +460,33 @@ int main(int argc, char *argv[]) { if (in_initrd()) { log_debug("In initrd, exiting."); - r = 0; - goto finish; + return EXIT_SUCCESS; } if (detect_container(NULL) > 0) { log_debug("In a container, exiting."); - r = 0; - 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); @@ -520,16 +494,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: - if (udev) - udev_unref(udev); - - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + return EXIT_SUCCESS; }