summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2017-11-14 23:25:13 +0100
committerLennart Poettering <lennart@poettering.net>2017-11-20 16:43:15 +0100
commitc7664c071ec935f67fed7aceebc296513d17ea15 (patch)
tree27a9f3d781c28290c5cd74d1e25042be2e40a8e3 /src
parentdissect: update dissect tool to show image metadata (diff)
downloadsystemd-c7664c071ec935f67fed7aceebc296513d17ea15.tar.xz
systemd-c7664c071ec935f67fed7aceebc296513d17ea15.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/shared/machine-image.c123
-rw-r--r--src/shared/machine-image.h9
2 files changed, 132 insertions, 0 deletions
diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c
index a9e5d608a5..2dff66d00a 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 1b1194e442..9573000a5a 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);