diff options
Diffstat (limited to 'src/machine/image.c')
-rw-r--r-- | src/machine/image.c | 248 |
1 files changed, 147 insertions, 101 deletions
diff --git a/src/machine/image.c b/src/machine/image.c index 0ba9652497..8f577adb59 100644 --- a/src/machine/image.c +++ b/src/machine/image.c @@ -27,6 +27,10 @@ #include "image.h" #include "bus-label.h" +static const char image_search_path[] = + "/var/lib/container\0" + "/var/lib/machine\0"; + Image *image_unref(Image *i) { if (!i) return NULL; @@ -37,24 +41,23 @@ Image *image_unref(Image *i) { return NULL; } -static int add_image( - Hashmap *h, +static int image_new( ImageType t, const char *name, const char *path, bool read_only, usec_t mtime, - usec_t btime) { + usec_t btime, + Image **ret) { _cleanup_(image_unrefp) Image *i = NULL; - int r; - assert(h); assert(t >= 0); assert(t < _IMAGE_TYPE_MAX); assert(name); + assert(ret); - i = new(Image, 1); + i = new0(Image, 1); if (!i) return -ENOMEM; @@ -73,136 +76,179 @@ static int add_image( return -ENOMEM; } - r = hashmap_put(h, i->name, i); - if (r < 0) - return r; - + *ret = i; i = NULL; + return 0; } -int image_discover(Hashmap *h) { - const char *path; +static int image_make(int dfd, const char *name, const char *path, Image **ret) { + struct stat st; int r; - assert(h); + assert(dfd >= 0); + assert(name); - FOREACH_STRING(path, "/var/lib/container", "/var/lib/machine") { - _cleanup_closedir_ DIR *d = NULL; - struct dirent *de; + /* We explicitly *do* follow symlinks here, since we want to + * allow symlinking trees into /var/lib/container/, and treat + * them normally. */ - d = opendir(path); - if (!d) { - if (errno == ENOENT) - return 0; + if (fstatat(dfd, name, &st, 0) < 0) + return -errno; - return -errno; - } + if (S_ISDIR(st.st_mode)) { - FOREACH_DIRENT_ALL(de, d, return -errno) { - struct stat st; + if (!ret) + return 1; - if (STR_IN_SET(de->d_name, ".", "..")) - continue; + /* btrfs subvolumes have inode 256 */ + if (st.st_ino == 256) { + _cleanup_close_ int fd = -1; + struct statfs sfs; - /* Temporary files for atomically creating new files */ - if (startswith(de->d_name, ".#")) - continue; + fd = openat(dfd, name, O_CLOEXEC|O_NOCTTY|O_DIRECTORY); + if (fd < 0) + return -errno; - if (string_has_cc(de->d_name, NULL)) - continue; + if (fstatfs(fd, &sfs) < 0) + return -errno; - if (!utf8_is_valid(de->d_name)) - continue; + if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC)) { + usec_t btime = 0; + int ro; - if (hashmap_contains(h, de->d_name)) - continue; + /* It's a btrfs subvolume */ - /* We explicitly *do* follow symlinks here, - * since we want to allow symlinking trees - * into /var/lib/container/, and treat them - * normally. */ - if (fstatat(dirfd(d), de->d_name, &st, 0) < 0) { - if (errno == ENOENT) - continue; + ro = btrfs_subvol_is_read_only_fd(fd); + if (ro < 0) + return ro; - return -errno; + /* r = btrfs_subvol_get_btime(fd, &btime); */ + /* if (r < 0) */ + /* return r; */ + + r = image_new(IMAGE_SUBVOLUME, + name, + path, + ro, + 0, + btime, + ret); + if (r < 0) + return r; + + return 1; } + } - if (S_ISDIR(st.st_mode)) { + /* It's just a normal directory. */ - /* btrfs subvolumes have inode 256 */ - if (st.st_ino == 256) { - _cleanup_close_ int fd = -1; - struct statfs sfs; + r = image_new(IMAGE_DIRECTORY, + name, + path, + false, + 0, + 0, + ret); + if (r < 0) + return r; - fd = openat(dirfd(d), de->d_name, O_CLOEXEC|O_NOCTTY|O_DIRECTORY); - if (fd < 0) { - if (errno == ENOENT) - continue; + return 1; - return -errno; - } + } else if (S_ISREG(st.st_mode) && endswith(name, ".gpt")) { - if (fstatfs(fd, &sfs) < 0) - return -errno; + /* It's a GPT block device */ - if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC)) { - usec_t btime = 0; - int ro; + if (!ret) + return 1; - /* It's a btrfs subvolume */ + r = image_new(IMAGE_GPT, + name, + path, + !!(st.st_mode & 0111), + timespec_load(&st.st_mtim), + 0, + ret); + if (r < 0) + return r; - ro = btrfs_subvol_is_read_only_fd(fd); - if (ro < 0) - return ro; + return 1; + } - /* r = btrfs_subvol_get_btime(fd, &btime); */ - /* if (r < 0) */ - /* return r; */ + return 0; +} - r = add_image(h, - IMAGE_SUBVOLUME, - de->d_name, - path, - ro, - 0, - btime); +int image_find(const char *name, Image **ret) { + const char *path; + int r; - if (r < 0) - return r; + assert(name); - continue; - } - } + /* There are no images with invalid names */ + if (!image_name_is_valid(name)) + return 0; - /* It's just a normal directory. */ + NULSTR_FOREACH(path, image_search_path) { + _cleanup_closedir_ DIR *d = NULL; - r = add_image(h, - IMAGE_DIRECTORY, - de->d_name, - path, - false, - 0, - 0); - if (r < 0) - return r; + d = opendir(path); + if (!d) { + if (errno == ENOENT) + continue; - } else if (S_ISREG(st.st_mode) && - endswith(de->d_name, ".gpt")) { + return -errno; + } - /* It's a GPT block device */ + r = image_make(dirfd(d), name, path, ret); + if (r == 0 || r == -ENOENT) + continue; + if (r < 0) + return r; - r = add_image(h, - IMAGE_GPT, - de->d_name, - path, - !!(st.st_mode & 0111), - timespec_load(&st.st_mtim), - 0); - if (r < 0) - return r; - } + return 1; + } + + return 0; +}; + +int image_discover(Hashmap *h) { + const char *path; + int r; + + assert(h); + + NULSTR_FOREACH(path, image_search_path) { + _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; + + d = opendir(path); + if (!d) { + if (errno == ENOENT) + return 0; + + return -errno; + } + + FOREACH_DIRENT_ALL(de, d, return -errno) { + _cleanup_(image_unrefp) Image *image = NULL; + + if (!image_name_is_valid(de->d_name)) + continue; + + if (hashmap_contains(h, de->d_name)) + continue; + + r = image_make(dirfd(d), de->d_name, path, &image); + if (r == 0 || r == -ENOENT) + continue; + if (r < 0) + return r; + + r = hashmap_put(h, image->name, image); + if (r < 0) + return r; + + image = NULL; } } |