chiark / gitweb /
machined: add new GetImage() bus call for retrieving the bus path for an image
authorLennart Poettering <lennart@poettering.net>
Fri, 19 Dec 2014 19:07:23 +0000 (20:07 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 19 Dec 2014 19:07:23 +0000 (20:07 +0100)
src/libsystemd/sd-bus/bus-common-errors.c
src/libsystemd/sd-bus/bus-common-errors.h
src/machine/image.c
src/machine/image.h
src/machine/machined-dbus.c
src/machine/org.freedesktop.machine1.conf
src/shared/util.c
src/shared/util.h

index 3dc00b5..8e90738 100644 (file)
@@ -45,6 +45,7 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = {
         SD_BUS_ERROR_MAP(BUS_ERROR_SCOPE_NOT_RUNNING,            EHOSTDOWN),
 
         SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_MACHINE,              ENXIO),
+        SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_IMAGE,                ENOENT),
         SD_BUS_ERROR_MAP(BUS_ERROR_NO_MACHINE_FOR_PID,           ENXIO),
         SD_BUS_ERROR_MAP(BUS_ERROR_MACHINE_EXISTS,               EEXIST),
         SD_BUS_ERROR_MAP(BUS_ERROR_NO_PRIVATE_NETWORKING,        ENOSYS),
index 5b7f41e..9007b85 100644 (file)
@@ -43,6 +43,7 @@
 #define BUS_ERROR_SCOPE_NOT_RUNNING "org.freedesktop.systemd1.ScopeNotRunning"
 
 #define BUS_ERROR_NO_SUCH_MACHINE "org.freedesktop.machine1.NoSuchMachine"
+#define BUS_ERROR_NO_SUCH_IMAGE "org.freedesktop.machine1.NoSuchImage"
 #define BUS_ERROR_NO_MACHINE_FOR_PID "org.freedesktop.machine1.NoMachineForPID"
 #define BUS_ERROR_MACHINE_EXISTS "org.freedesktop.machine1.MachineExists"
 #define BUS_ERROR_NO_PRIVATE_NETWORKING "org.freedesktop.machine1.NoPrivateNetworking"
index 0ba9652..8f577ad 100644 (file)
 #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;
                 }
         }
 
index c77fd19..f298fc3 100644 (file)
@@ -46,6 +46,7 @@ Image *image_unref(Image *i);
 
 void image_hashmap_free(Hashmap *map);
 
+int image_find(const char *name, Image **ret);
 int image_discover(Hashmap *map);
 
 char *image_bus_path(const char *name);
index 949c7d6..0229564 100644 (file)
@@ -68,6 +68,33 @@ static int method_get_machine(sd_bus *bus, sd_bus_message *message, void *userda
         return sd_bus_reply_method_return(message, "o", p);
 }
 
+static int method_get_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        _cleanup_free_ char *p = NULL;
+        Manager *m = userdata;
+        const char *name;
+        int r;
+
+        assert(bus);
+        assert(message);
+        assert(m);
+
+        r = sd_bus_message_read(message, "s", &name);
+        if (r < 0)
+                return r;
+
+        r = image_find(name, NULL);
+        if (r == 0)
+                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
+        if (r < 0)
+                return r;
+
+        p = image_bus_path(name);
+        if (!p)
+                return -ENOMEM;
+
+        return sd_bus_reply_method_return(message, "o", p);
+}
+
 static int method_get_machine_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
         _cleanup_free_ char *p = NULL;
         Manager *m = userdata;
@@ -491,6 +518,7 @@ static int method_list_images(sd_bus *bus, sd_bus_message *message, void *userda
 const sd_bus_vtable manager_vtable[] = {
         SD_BUS_VTABLE_START(0),
         SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("ListImages", NULL, "a(ssbo)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
index 3745c52..bd8fbef 100644 (file)
 
                 <allow send_destination="org.freedesktop.machine1"
                        send_interface="org.freedesktop.machine1.Manager"
+                       send_member="GetImage"/>
+
+                <allow send_destination="org.freedesktop.machine1"
+                       send_interface="org.freedesktop.machine1.Manager"
                        send_member="GetMachineAddresses"/>
 
                 <allow send_destination="org.freedesktop.machine1"
index 1ad82b2..06b6077 100644 (file)
@@ -4257,6 +4257,23 @@ bool machine_name_is_valid(const char *s) {
         return true;
 }
 
+bool image_name_is_valid(const char *s) {
+        if (!filename_is_valid(s))
+                return false;
+
+        if (string_has_cc(s, NULL))
+                return false;
+
+        if (!utf8_is_valid(s))
+                return false;
+
+        /* Temporary files for atomically creating new files */
+        if (startswith(s, ".#"))
+                return false;
+
+        return true;
+}
+
 int pipe_eof(int fd) {
         struct pollfd pollfd = {
                 .fd = fd,
index 712f65a..1804b8c 100644 (file)
@@ -545,6 +545,7 @@ bool hostname_is_valid(const char *s) _pure_;
 char* hostname_cleanup(char *s, bool lowercase);
 
 bool machine_name_is_valid(const char *s) _pure_;
+bool image_name_is_valid(const char *s) _pure_;
 
 char* strshorten(char *s, size_t l);