chiark / gitweb /
machined: fix writability check for GPT images
[elogind.git] / src / machine / image.c
index 0ba96524977812b8f6f8090619d59403e771bc28..2ffe9444e3e511a4a20a65d15acf1d2681d2ecdf 100644 (file)
 #include "strv.h"
 #include "utf8.h"
 #include "btrfs-util.h"
+#include "path-util.h"
 #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)
@@ -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;
 
@@ -68,141 +71,186 @@ static int add_image(
                 return -ENOMEM;
 
         if (path) {
-                i->path = strdup(path);
+                i->path = strjoin(path, "/", name, NULL);
                 if (!i->path)
                         return -ENOMEM;
-        }
 
-        r = hashmap_put(h, i->name, i);
-        if (r < 0)
-                return r;
+                path_kill_slashes(i->path);
+        }
 
+        *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 & 0222),
+                              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;
                 }
         }
 
@@ -218,18 +266,6 @@ void image_hashmap_free(Hashmap *map) {
         hashmap_free(map);
 }
 
-char *image_bus_path(const char *name) {
-        _cleanup_free_ char *e = NULL;
-
-        assert(name);
-
-        e = bus_label_escape(name);
-        if (!e)
-                return NULL;
-
-        return strappend("/org/freedesktop/machine1/image/", e);
-}
-
 static const char* const image_type_table[_IMAGE_TYPE_MAX] = {
         [IMAGE_DIRECTORY] = "directory",
         [IMAGE_SUBVOLUME] = "subvolume",