From c7664c071ec935f67fed7aceebc296513d17ea15 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 14 Nov 2017 23:25:13 +0100 Subject: [PATCH] machine-image: add a generic API to determine metadata of any image This adds an internal API that permits querying metadata from any type of image, including both subvol/dir images, and raw/block images. In the latter case we use the new dissection API we just added. --- src/shared/machine-image.c | 123 +++++++++++++++++++++++++++++++++++++ src/shared/machine-image.h | 9 +++ 2 files changed, 132 insertions(+) diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c index a9e5d608a52..2dff66d00aa 100644 --- a/src/shared/machine-image.c +++ b/src/shared/machine-image.c @@ -34,12 +34,17 @@ #include "chattr-util.h" #include "copy.h" #include "dirent-util.h" +#include "dissect-image.h" #include "env-util.h" #include "fd-util.h" +#include "fileio.h" #include "fs-util.h" #include "hashmap.h" +#include "hostname-util.h" +#include "id128-util.h" #include "lockfile-util.h" #include "log.h" +#include "loop-util.h" #include "machine-image.h" #include "macro.h" #include "mkdir.h" @@ -65,6 +70,11 @@ Image *image_unref(Image *i) { free(i->name); free(i->path); + + free(i->hostname); + strv_free(i->machine_info); + strv_free(i->os_release); + return mfree(i); } @@ -761,6 +771,7 @@ int image_clone(Image *i, const char *new_name, bool read_only) { int image_read_only(Image *i, bool b) { _cleanup_release_lock_file_ LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT; int r; + assert(i); if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i)) @@ -924,6 +935,118 @@ int image_set_limit(Image *i, uint64_t referenced_max) { return btrfs_subvol_set_subtree_quota_limit(i->path, 0, referenced_max); } +int image_read_metadata(Image *i) { + _cleanup_release_lock_file_ LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT; + int r; + + assert(i); + + r = image_path_lock(i->path, LOCK_SH|LOCK_NB, &global_lock, &local_lock); + if (r < 0) + return r; + + switch (i->type) { + + case IMAGE_SUBVOLUME: + case IMAGE_DIRECTORY: { + _cleanup_strv_free_ char **machine_info = NULL, **os_release = NULL; + sd_id128_t machine_id = SD_ID128_NULL; + _cleanup_free_ char *hostname = NULL; + _cleanup_free_ char *path = NULL; + + r = chase_symlinks("/etc/hostname", i->path, CHASE_PREFIX_ROOT, &path); + if (r < 0 && r != -ENOENT) + log_debug_errno(r, "Failed to chase /etc/hostname in image %s: %m", i->name); + else if (r >= 0) { + r = read_etc_hostname(path, &hostname); + if (r < 0) + log_debug_errno(errno, "Failed to read /etc/hostname of image %s: %m", i->name); + } + + path = mfree(path); + + r = chase_symlinks("/etc/machine-id", i->path, CHASE_PREFIX_ROOT, &path); + if (r < 0 && r != -ENOENT) + log_debug_errno(r, "Failed to chase /etc/machine-id in image %s: %m", i->name); + else if (r >= 0) { + _cleanup_close_ int fd = -1; + + fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) + log_debug_errno(errno, "Failed to open %s: %m", path); + else { + r = id128_read_fd(fd, ID128_PLAIN, &machine_id); + if (r < 0) + log_debug_errno(r, "Image %s contains invalid machine ID.", i->name); + } + } + + path = mfree(path); + + r = chase_symlinks("/etc/machine-info", i->path, CHASE_PREFIX_ROOT, &path); + if (r < 0 && r != -ENOENT) + log_debug_errno(r, "Failed to chase /etc/machine-info in image %s: %m", i->name); + else if (r >= 0) { + r = load_env_file_pairs(NULL, path, NULL, &machine_info); + if (r < 0) + log_debug_errno(r, "Failed to parse machine-info data of %s: %m", i->name); + } + + path = mfree(path); + + r = chase_symlinks("/etc/os-release", i->path, CHASE_PREFIX_ROOT, &path); + if (r == -ENOENT) + r = chase_symlinks("/usr/lib/os-release", i->path, CHASE_PREFIX_ROOT, &path); + if (r < 0 && r != -ENOENT) + log_debug_errno(r, "Failed to chase os-release in image: %m"); + else if (r >= 0) { + r = load_env_file_pairs(NULL, path, NULL, &os_release); + if (r < 0) + log_debug_errno(r, "Failed to parse os-release data of %s: %m", i->name); + } + + free_and_replace(i->hostname, hostname); + i->machine_id = machine_id; + strv_free_and_replace(i->machine_info, machine_info); + strv_free_and_replace(i->os_release, os_release); + + break; + } + + case IMAGE_RAW: + case IMAGE_BLOCK: { + _cleanup_(loop_device_unrefp) LoopDevice *d = NULL; + _cleanup_(dissected_image_unrefp) DissectedImage *m = NULL; + + r = loop_device_make_by_path(i->path, O_RDONLY, &d); + if (r < 0) + return r; + + r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_REQUIRE_ROOT, &m); + if (r < 0) + return r; + + r = dissected_image_acquire_metadata(m); + if (r < 0) + return r; + + free_and_replace(i->hostname, m->hostname); + i->machine_id = m->machine_id; + strv_free_and_replace(i->machine_info, m->machine_info); + strv_free_and_replace(i->os_release, m->os_release); + + break; + } + + default: + return -EOPNOTSUPP; + } + + i->metadata_valid = true; + + return 0; +} + int image_name_lock(const char *name, int operation, LockFile *ret) { const char *p; diff --git a/src/shared/machine-image.h b/src/shared/machine-image.h index 1b1194e4426..9573000a5ac 100644 --- a/src/shared/machine-image.h +++ b/src/shared/machine-image.h @@ -53,6 +53,13 @@ typedef struct Image { uint64_t limit; uint64_t limit_exclusive; + char *hostname; + sd_id128_t machine_id; + char **machine_info; + char **os_release; + + bool metadata_valid; + void *userdata; } Image; @@ -80,6 +87,8 @@ int image_name_lock(const char *name, int operation, LockFile *ret); int image_set_limit(Image *i, uint64_t referenced_max); +int image_read_metadata(Image *i); + static inline bool IMAGE_IS_HIDDEN(const struct Image *i) { assert(i);