machined: add new GetImage() bus call for retrieving the bus path for an image

This commit is contained in:
Lennart Poettering 2014-12-19 20:07:23 +01:00
parent 821d4b6e06
commit c2ce6a3d82
8 changed files with 205 additions and 106 deletions

View 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),

View 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"

View file

@ -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,21 +76,148 @@ static int add_image(
return -ENOMEM;
}
r = hashmap_put(h, i->name, i);
if (r < 0)
return r;
*ret = i;
i = NULL;
return 0;
}
static int image_make(int dfd, const char *name, const char *path, Image **ret) {
struct stat st;
int r;
assert(dfd >= 0);
assert(name);
/* We explicitly *do* follow symlinks here, since we want to
* allow symlinking trees into /var/lib/container/, and treat
* them normally. */
if (fstatat(dfd, name, &st, 0) < 0)
return -errno;
if (S_ISDIR(st.st_mode)) {
if (!ret)
return 1;
/* btrfs subvolumes have inode 256 */
if (st.st_ino == 256) {
_cleanup_close_ int fd = -1;
struct statfs sfs;
fd = openat(dfd, name, O_CLOEXEC|O_NOCTTY|O_DIRECTORY);
if (fd < 0)
return -errno;
if (fstatfs(fd, &sfs) < 0)
return -errno;
if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC)) {
usec_t btime = 0;
int ro;
/* It's a btrfs subvolume */
ro = btrfs_subvol_is_read_only_fd(fd);
if (ro < 0)
return ro;
/* 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;
}
}
/* It's just a normal directory. */
r = image_new(IMAGE_DIRECTORY,
name,
path,
false,
0,
0,
ret);
if (r < 0)
return r;
return 1;
} else if (S_ISREG(st.st_mode) && endswith(name, ".gpt")) {
/* It's a GPT block device */
if (!ret)
return 1;
r = image_new(IMAGE_GPT,
name,
path,
!!(st.st_mode & 0111),
timespec_load(&st.st_mtim),
0,
ret);
if (r < 0)
return r;
return 1;
}
return 0;
}
int image_find(const char *name, Image **ret) {
const char *path;
int r;
assert(name);
/* There are no images with invalid names */
if (!image_name_is_valid(name))
return 0;
NULSTR_FOREACH(path, image_search_path) {
_cleanup_closedir_ DIR *d = NULL;
d = opendir(path);
if (!d) {
if (errno == ENOENT)
continue;
return -errno;
}
r = image_make(dirfd(d), name, path, ret);
if (r == 0 || r == -ENOENT)
continue;
if (r < 0)
return r;
return 1;
}
return 0;
};
int image_discover(Hashmap *h) {
const char *path;
int r;
assert(h);
FOREACH_STRING(path, "/var/lib/container", "/var/lib/machine") {
NULSTR_FOREACH(path, image_search_path) {
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
@ -100,109 +230,25 @@ int image_discover(Hashmap *h) {
}
FOREACH_DIRENT_ALL(de, d, return -errno) {
struct stat st;
_cleanup_(image_unrefp) Image *image = NULL;
if (STR_IN_SET(de->d_name, ".", ".."))
continue;
/* Temporary files for atomically creating new files */
if (startswith(de->d_name, ".#"))
continue;
if (string_has_cc(de->d_name, NULL))
continue;
if (!utf8_is_valid(de->d_name))
if (!image_name_is_valid(de->d_name))
continue;
if (hashmap_contains(h, de->d_name))
continue;
/* 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;
r = image_make(dirfd(d), de->d_name, path, &image);
if (r == 0 || r == -ENOENT)
continue;
if (r < 0)
return r;
return -errno;
}
r = hashmap_put(h, image->name, image);
if (r < 0)
return r;
if (S_ISDIR(st.st_mode)) {
/* btrfs subvolumes have inode 256 */
if (st.st_ino == 256) {
_cleanup_close_ int fd = -1;
struct statfs sfs;
fd = openat(dirfd(d), de->d_name, O_CLOEXEC|O_NOCTTY|O_DIRECTORY);
if (fd < 0) {
if (errno == ENOENT)
continue;
return -errno;
}
if (fstatfs(fd, &sfs) < 0)
return -errno;
if (F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC)) {
usec_t btime = 0;
int ro;
/* It's a btrfs subvolume */
ro = btrfs_subvol_is_read_only_fd(fd);
if (ro < 0)
return ro;
/* r = btrfs_subvol_get_btime(fd, &btime); */
/* if (r < 0) */
/* return r; */
r = add_image(h,
IMAGE_SUBVOLUME,
de->d_name,
path,
ro,
0,
btime);
if (r < 0)
return r;
continue;
}
}
/* It's just a normal directory. */
r = add_image(h,
IMAGE_DIRECTORY,
de->d_name,
path,
false,
0,
0);
if (r < 0)
return r;
} else if (S_ISREG(st.st_mode) &&
endswith(de->d_name, ".gpt")) {
/* It's a GPT block device */
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;
}
image = NULL;
}
}

View 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);

View 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),

View file

@ -52,6 +52,10 @@
send_interface="org.freedesktop.machine1.Manager"
send_member="GetMachineByPID"/>
<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"/>

View 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,

View 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);