summaryrefslogtreecommitdiff
path: root/src/machine/image.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/machine/image.c')
-rw-r--r--src/machine/image.c248
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;
}
}