machined: add new GetImage() bus call for retrieving the bus path for an image
This commit is contained in:
parent
821d4b6e06
commit
c2ce6a3d82
|
@ -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),
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue