diff options
author | Lennart Poettering <lennart@poettering.net> | 2014-12-19 18:42:50 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2014-12-19 19:19:29 +0100 |
commit | cd61c3bfd718fb398cc53ced906266a9297782c9 (patch) | |
tree | d727549baccec28d473212b85c55f2e24af25678 /src/machine/image.c | |
parent | 8eebf6ad553adb22d7ea5d291de0b0da38606f4d (diff) |
machined/machinectl: add logic to show list of available images
This adds a new bus call to machined that enumerates /var/lib/container
and returns all trees stored in it, distuingishing three types:
- GPT disk images, which are files suffixed with ".gpt"
- directory trees
- btrfs subvolumes
Diffstat (limited to 'src/machine/image.c')
-rw-r--r-- | src/machine/image.c | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/src/machine/image.c b/src/machine/image.c new file mode 100644 index 0000000000..0ba9652497 --- /dev/null +++ b/src/machine/image.c @@ -0,0 +1,239 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <sys/statfs.h> + +#include "strv.h" +#include "utf8.h" +#include "btrfs-util.h" +#include "image.h" +#include "bus-label.h" + +Image *image_unref(Image *i) { + if (!i) + return NULL; + + free(i->name); + free(i->path); + free(i); + return NULL; +} + +static int add_image( + Hashmap *h, + ImageType t, + const char *name, + const char *path, + bool read_only, + usec_t mtime, + usec_t btime) { + + _cleanup_(image_unrefp) Image *i = NULL; + int r; + + assert(h); + assert(t >= 0); + assert(t < _IMAGE_TYPE_MAX); + assert(name); + + i = new(Image, 1); + if (!i) + return -ENOMEM; + + i->type = t; + i->read_only = read_only; + i->mtime = mtime; + i->btime = btime; + + i->name = strdup(name); + if (!i->name) + return -ENOMEM; + + if (path) { + i->path = strdup(path); + if (!i->path) + return -ENOMEM; + } + + r = hashmap_put(h, i->name, i); + if (r < 0) + return r; + + i = NULL; + return 0; +} + +int image_discover(Hashmap *h) { + const char *path; + int r; + + assert(h); + + FOREACH_STRING(path, "/var/lib/container", "/var/lib/machine") { + _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) { + struct stat st; + + 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)) + 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; + + return -errno; + } + + 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; + } + } + } + + return 0; +} + +void image_hashmap_free(Hashmap *map) { + Image *i; + + while ((i = hashmap_steal_first(map))) + image_unref(i); + + 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", + [IMAGE_GPT] = "gpt", +}; + +DEFINE_STRING_TABLE_LOOKUP(image_type, ImageType); |