summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libsystemd/sd-bus/bus-common-errors.c1
-rw-r--r--src/libsystemd/sd-bus/bus-common-errors.h1
-rw-r--r--src/machine/image.c248
-rw-r--r--src/machine/image.h1
-rw-r--r--src/machine/machined-dbus.c28
-rw-r--r--src/machine/org.freedesktop.machine1.conf4
-rw-r--r--src/shared/util.c17
-rw-r--r--src/shared/util.h1
8 files changed, 200 insertions, 101 deletions
diff --git a/src/libsystemd/sd-bus/bus-common-errors.c b/src/libsystemd/sd-bus/bus-common-errors.c
index 3dc00b5e4a..8e90738790 100644
--- a/src/libsystemd/sd-bus/bus-common-errors.c
+++ b/src/libsystemd/sd-bus/bus-common-errors.c
@@ -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),
diff --git a/src/libsystemd/sd-bus/bus-common-errors.h b/src/libsystemd/sd-bus/bus-common-errors.h
index 5b7f41ef19..9007b85c19 100644
--- a/src/libsystemd/sd-bus/bus-common-errors.h
+++ b/src/libsystemd/sd-bus/bus-common-errors.h
@@ -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"
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;
}
}
diff --git a/src/machine/image.h b/src/machine/image.h
index c77fd19d8d..f298fc3049 100644
--- a/src/machine/image.h
+++ b/src/machine/image.h
@@ -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);
diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c
index 949c7d6b20..0229564234 100644
--- a/src/machine/machined-dbus.c
+++ b/src/machine/machined-dbus.c
@@ -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),
diff --git a/src/machine/org.freedesktop.machine1.conf b/src/machine/org.freedesktop.machine1.conf
index 3745c527ff..bd8fbeff4f 100644
--- a/src/machine/org.freedesktop.machine1.conf
+++ b/src/machine/org.freedesktop.machine1.conf
@@ -54,6 +54,10 @@
<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"
diff --git a/src/shared/util.c b/src/shared/util.c
index 1ad82b27dd..06b6077843 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -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,
diff --git a/src/shared/util.h b/src/shared/util.h
index 712f65a957..1804b8c3a2 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -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);