From d577d4a432dd7bb056d2f7df53956122ebcb1ab0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 12 Jan 2021 17:18:53 +0100 Subject: [PATCH] machine-image: properly support searching for images below some --root= path systemd-sysext supports --root= for everything but the image discovery. Fix that. --- src/import/export.c | 4 +- src/import/import-fs.c | 2 +- src/import/import.c | 4 +- src/import/pull.c | 4 +- src/machine/image-dbus.c | 4 +- src/machine/machined-dbus.c | 8 +-- src/nspawn/nspawn.c | 2 +- src/portable/portable.c | 8 +-- src/portable/portabled-image-bus.c | 2 +- src/portable/portabled-image.c | 2 +- src/shared/machine-image.c | 93 ++++++++++++++++++------------ src/shared/machine-image.h | 8 +-- src/sysext/sysext.c | 2 +- 13 files changed, 82 insertions(+), 61 deletions(-) diff --git a/src/import/export.c b/src/import/export.c index b8507330ac0..9c44fcf35cc 100644 --- a/src/import/export.c +++ b/src/import/export.c @@ -66,7 +66,7 @@ static int export_tar(int argc, char *argv[], void *userdata) { int r, fd; if (hostname_is_valid(argv[1], 0)) { - r = image_find(IMAGE_MACHINE, argv[1], &image); + r = image_find(IMAGE_MACHINE, argv[1], NULL, &image); if (r == -ENOENT) return log_error_errno(r, "Machine image %s not found.", argv[1]); if (r < 0) @@ -142,7 +142,7 @@ static int export_raw(int argc, char *argv[], void *userdata) { int r, fd; if (hostname_is_valid(argv[1], 0)) { - r = image_find(IMAGE_MACHINE, argv[1], &image); + r = image_find(IMAGE_MACHINE, argv[1], NULL, &image); if (r == -ENOENT) return log_error_errno(r, "Machine image %s not found.", argv[1]); if (r < 0) diff --git a/src/import/import-fs.c b/src/import/import-fs.c index a22eef82558..a36ab24fb8e 100644 --- a/src/import/import-fs.c +++ b/src/import/import-fs.c @@ -132,7 +132,7 @@ static int import_fs(int argc, char *argv[], void *userdata) { local); if (!arg_force) { - r = image_find(IMAGE_MACHINE, local, NULL); + r = image_find(IMAGE_MACHINE, local, NULL, NULL); if (r < 0) { if (r != -ENOENT) return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local); diff --git a/src/import/import.c b/src/import/import.c index 9ea8e7f16dd..3fd99d11603 100644 --- a/src/import/import.c +++ b/src/import/import.c @@ -70,7 +70,7 @@ static int import_tar(int argc, char *argv[], void *userdata) { local); if (!arg_force) { - r = image_find(IMAGE_MACHINE, local, NULL); + r = image_find(IMAGE_MACHINE, local, NULL, NULL); if (r < 0) { if (r != -ENOENT) return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local); @@ -165,7 +165,7 @@ static int import_raw(int argc, char *argv[], void *userdata) { local); if (!arg_force) { - r = image_find(IMAGE_MACHINE, local, NULL); + r = image_find(IMAGE_MACHINE, local, NULL, NULL); if (r < 0) { if (r != -ENOENT) return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local); diff --git a/src/import/pull.c b/src/import/pull.c index a4cec9448e2..e80d8abe6f5 100644 --- a/src/import/pull.c +++ b/src/import/pull.c @@ -78,7 +78,7 @@ static int pull_tar(int argc, char *argv[], void *userdata) { local); if (!arg_force) { - r = image_find(IMAGE_MACHINE, local, NULL); + r = image_find(IMAGE_MACHINE, local, NULL, NULL); if (r < 0) { if (r != -ENOENT) return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local); @@ -164,7 +164,7 @@ static int pull_raw(int argc, char *argv[], void *userdata) { local); if (!arg_force) { - r = image_find(IMAGE_MACHINE, local, NULL); + r = image_find(IMAGE_MACHINE, local, NULL, NULL); if (r < 0) { if (r != -ENOENT) return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local); diff --git a/src/machine/image-dbus.c b/src/machine/image-dbus.c index c157aaf33cb..4c4f900527a 100644 --- a/src/machine/image-dbus.c +++ b/src/machine/image-dbus.c @@ -408,7 +408,7 @@ static int image_object_find(sd_bus *bus, const char *path, const char *interfac if (r < 0) return r; - r = image_find(IMAGE_MACHINE, e, &image); + r = image_find(IMAGE_MACHINE, e, NULL, &image); if (r == -ENOENT) return 0; if (r < 0) @@ -452,7 +452,7 @@ static int image_node_enumerator(sd_bus *bus, const char *path, void *userdata, if (!images) return -ENOMEM; - r = image_discover(IMAGE_MACHINE, images); + r = image_discover(IMAGE_MACHINE, NULL, images); if (r < 0) return r; diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index 781686c1048..a65f9b6a8e5 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -124,7 +124,7 @@ static int method_get_image(sd_bus_message *message, void *userdata, sd_bus_erro if (r < 0) return r; - r = image_find(IMAGE_MACHINE, name, NULL); + r = image_find(IMAGE_MACHINE, name, NULL, NULL); if (r == -ENOENT) return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name); if (r < 0) @@ -480,7 +480,7 @@ static int method_list_images(sd_bus_message *message, void *userdata, sd_bus_er if (!images) return -ENOMEM; - r = image_discover(IMAGE_MACHINE, images); + r = image_discover(IMAGE_MACHINE, NULL, images); if (r < 0) return r; @@ -562,7 +562,7 @@ static int redirect_method_to_image(sd_bus_message *message, Manager *m, sd_bus_ if (!image_name_is_valid(name)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name); - r = image_find(IMAGE_MACHINE, name, &i); + r = image_find(IMAGE_MACHINE, name, NULL, &i); if (r == -ENOENT) return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name); if (r < 0) @@ -755,7 +755,7 @@ static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_err goto child_fail; } - r = image_discover(IMAGE_MACHINE, images); + r = image_discover(IMAGE_MACHINE, NULL, images); if (r < 0) goto child_fail; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index e68f0cebf0f..75cefe84142 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -2940,7 +2940,7 @@ static int determine_names(void) { if (arg_machine) { _cleanup_(image_unrefp) Image *i = NULL; - r = image_find(IMAGE_MACHINE, arg_machine, &i); + r = image_find(IMAGE_MACHINE, arg_machine, NULL, &i); if (r == -ENOENT) return log_error_errno(r, "No image for machine '%s'.", arg_machine); if (r < 0) diff --git a/src/portable/portable.c b/src/portable/portable.c index a96a944ad1a..d74e498d596 100644 --- a/src/portable/portable.c +++ b/src/portable/portable.c @@ -495,7 +495,7 @@ int portable_extract( assert(name_or_path); - r = image_find_harder(IMAGE_PORTABLE, name_or_path, &image); + r = image_find_harder(IMAGE_PORTABLE, name_or_path, NULL, &image); if (r < 0) return r; @@ -953,7 +953,7 @@ static int install_image_symlink( /* If the image is outside of the image search also link it into it, so that it can be found with short image * names and is listed among the images. */ - if (image_in_search_path(IMAGE_PORTABLE, image_path)) + if (image_in_search_path(IMAGE_PORTABLE, NULL, image_path)) return 0; r = image_symlink(image_path, flags, &sl); @@ -987,7 +987,7 @@ int portable_attach( assert(name_or_path); - r = image_find_harder(IMAGE_PORTABLE, name_or_path, &image); + r = image_find_harder(IMAGE_PORTABLE, name_or_path, NULL, &image); if (r < 0) return r; @@ -1193,7 +1193,7 @@ int portable_detach( return log_debug_errno(r, "Failed to add unit name '%s' to set: %m", de->d_name); if (path_is_absolute(marker) && - !image_in_search_path(IMAGE_PORTABLE, marker)) { + !image_in_search_path(IMAGE_PORTABLE, NULL, marker)) { r = set_ensure_consume(&markers, &path_hash_ops_free, TAKE_PTR(marker)); if (r < 0) diff --git a/src/portable/portabled-image-bus.c b/src/portable/portabled-image-bus.c index eb0786e4bb0..76b6ddebde3 100644 --- a/src/portable/portabled-image-bus.c +++ b/src/portable/portabled-image-bus.c @@ -606,7 +606,7 @@ int bus_image_acquire( if (image_name_is_valid(name_or_path)) { /* If it's a short name, let's search for it */ - r = image_find(IMAGE_PORTABLE, name_or_path, &loaded); + r = image_find(IMAGE_PORTABLE, name_or_path, NULL, &loaded); if (r == -ENOENT) return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PORTABLE_IMAGE, "No image '%s' found.", name_or_path); diff --git a/src/portable/portabled-image.c b/src/portable/portabled-image.c index b025c205490..40548fb6556 100644 --- a/src/portable/portabled-image.c +++ b/src/portable/portabled-image.c @@ -92,7 +92,7 @@ int manager_image_cache_discover(Manager *m, Hashmap *images, sd_bus_error *erro /* A wrapper around image_discover() (for finding images in search path) and portable_discover_attached() (for * finding attached images). */ - r = image_discover(IMAGE_PORTABLE, images); + r = image_discover(IMAGE_PORTABLE, NULL, images); if (r < 0) return r; diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c index f7b1f90c6f1..d2b726efc4c 100644 --- a/src/shared/machine-image.c +++ b/src/shared/machine-image.c @@ -421,7 +421,11 @@ static int image_make( return -EMEDIUMTYPE; } -int image_find(ImageClass class, const char *name, Image **ret) { +int image_find(ImageClass class, + const char *name, + const char *root, + Image **ret) { + const char *path; int r; @@ -434,20 +438,22 @@ int image_find(ImageClass class, const char *name, Image **ret) { return -ENOENT; NULSTR_FOREACH(path, image_search_path[class]) { + _cleanup_free_ char *resolved = NULL; _cleanup_closedir_ DIR *d = NULL; struct stat st; + int flags; - d = opendir(path); - if (!d) { - if (errno == ENOENT) - continue; - - return -errno; - } + r = chase_symlinks_and_opendir(path, root, CHASE_PREFIX_ROOT, &resolved, &d); + if (r == -ENOENT) + continue; + if (r < 0) + return r; - /* As mentioned above, we follow symlinks on this fstatat(), because we want to permit people to - * symlink block devices into the search path */ - if (fstatat(dirfd(d), name, &st, 0) < 0) { + /* As mentioned above, we follow symlinks on this fstatat(), because we want to permit people + * to symlink block devices into the search path. (For now, we disable that when operating + * relative to some root directory.) */ + flags = root ? AT_SYMLINK_NOFOLLOW : 0; + if (fstatat(dirfd(d), name, &st, flags) < 0) { _cleanup_free_ char *raw = NULL; if (errno != ENOENT) @@ -457,8 +463,7 @@ int image_find(ImageClass class, const char *name, Image **ret) { if (!raw) return -ENOMEM; - if (fstatat(dirfd(d), raw, &st, 0) < 0) { - + if (fstatat(dirfd(d), raw, &st, flags) < 0) { if (errno == ENOENT) continue; @@ -468,13 +473,13 @@ int image_find(ImageClass class, const char *name, Image **ret) { if (!S_ISREG(st.st_mode)) continue; - r = image_make(name, dirfd(d), path, raw, &st, ret); + r = image_make(name, dirfd(d), resolved, raw, &st, ret); } else { if (!S_ISDIR(st.st_mode) && !S_ISBLK(st.st_mode)) continue; - r = image_make(name, dirfd(d), path, name, &st, ret); + r = image_make(name, dirfd(d), resolved, name, &st, ret); } if (IN_SET(r, -ENOENT, -EMEDIUMTYPE)) continue; @@ -488,7 +493,7 @@ int image_find(ImageClass class, const char *name, Image **ret) { } if (class == IMAGE_MACHINE && streq(name, ".host")) { - r = image_make(".host", AT_FDCWD, NULL, "/", NULL, ret); + r = image_make(".host", AT_FDCWD, NULL, empty_to_root(root), NULL, ret); if (r < 0) return r; @@ -513,14 +518,18 @@ int image_from_path(const char *path, Image **ret) { return image_make(NULL, AT_FDCWD, NULL, path, NULL, ret); } -int image_find_harder(ImageClass class, const char *name_or_path, Image **ret) { +int image_find_harder(ImageClass class, const char *name_or_path, const char *root, Image **ret) { if (image_name_is_valid(name_or_path)) - return image_find(class, name_or_path, ret); + return image_find(class, name_or_path, root, ret); return image_from_path(name_or_path, ret); } -int image_discover(ImageClass class, Hashmap *h) { +int image_discover( + ImageClass class, + const char *root, + Hashmap *h) { + const char *path; int r; @@ -529,29 +538,30 @@ int image_discover(ImageClass class, Hashmap *h) { assert(h); NULSTR_FOREACH(path, image_search_path[class]) { + _cleanup_free_ char *resolved = NULL; _cleanup_closedir_ DIR *d = NULL; struct dirent *de; - d = opendir(path); - if (!d) { - if (errno == ENOENT) - continue; - - return -errno; - } + r = chase_symlinks_and_opendir(path, root, CHASE_PREFIX_ROOT, &resolved, &d); + if (r == -ENOENT) + continue; + if (r < 0) + return r; FOREACH_DIRENT_ALL(de, d, return -errno) { _cleanup_(image_unrefp) Image *image = NULL; _cleanup_free_ char *truncated = NULL; const char *pretty; struct stat st; + int flags; if (dot_or_dot_dot(de->d_name)) continue; - /* As mentioned above, we follow symlinks on this fstatat(), because we want to permit people - * to symlink block devices into the search path */ - if (fstatat(dirfd(d), de->d_name, &st, 0) < 0) { + /* As mentioned above, we follow symlinks on this fstatat(), because we want to + * permit people to symlink block devices into the search path. */ + flags = root ? AT_SYMLINK_NOFOLLOW : 0; + if (fstatat(dirfd(d), de->d_name, &st, flags) < 0) { if (errno == ENOENT) continue; @@ -581,7 +591,7 @@ int image_discover(ImageClass class, Hashmap *h) { if (hashmap_contains(h, pretty)) continue; - r = image_make(pretty, dirfd(d), path, de->d_name, &st, &image); + r = image_make(pretty, dirfd(d), resolved, de->d_name, &st, &image); if (IN_SET(r, -ENOENT, -EMEDIUMTYPE)) continue; if (r < 0) @@ -600,7 +610,7 @@ int image_discover(ImageClass class, Hashmap *h) { if (class == IMAGE_MACHINE && !hashmap_contains(h, ".host")) { _cleanup_(image_unrefp) Image *image = NULL; - r = image_make(".host", AT_FDCWD, NULL, "/", NULL, &image); + r = image_make(".host", AT_FDCWD, NULL, empty_to_root("/"), NULL, &image); if (r < 0) return r; @@ -743,7 +753,7 @@ int image_rename(Image *i, const char *new_name) { if (r < 0) return r; - r = image_find(IMAGE_MACHINE, new_name, NULL); + r = image_find(IMAGE_MACHINE, new_name, NULL, NULL); if (r >= 0) return -EEXIST; if (r != -ENOENT) @@ -856,7 +866,7 @@ int image_clone(Image *i, const char *new_name, bool read_only) { if (r < 0) return r; - r = image_find(IMAGE_MACHINE, new_name, NULL); + r = image_find(IMAGE_MACHINE, new_name, NULL, NULL); if (r >= 0) return -EEXIST; if (r != -ENOENT) @@ -1248,16 +1258,27 @@ bool image_name_is_valid(const char *s) { return true; } -bool image_in_search_path(ImageClass class, const char *image) { +bool image_in_search_path( + ImageClass class, + const char *root, + const char *image) { + const char *path; assert(image); NULSTR_FOREACH(path, image_search_path[class]) { - const char *p; + const char *p, *q; size_t k; - p = path_startswith(image, path); + if (!empty_or_root(root)) { + q = path_startswith(path, root); + if (!q) + continue; + } else + q = path; + + p = path_startswith(q, path); if (!p) continue; diff --git a/src/shared/machine-image.h b/src/shared/machine-image.h index eea94e0324b..c568fff751b 100644 --- a/src/shared/machine-image.h +++ b/src/shared/machine-image.h @@ -62,10 +62,10 @@ Image *image_ref(Image *i); DEFINE_TRIVIAL_CLEANUP_FUNC(Image*, image_unref); -int image_find(ImageClass class, const char *name, Image **ret); +int image_find(ImageClass class, const char *root, const char *name, Image **ret); int image_from_path(const char *path, Image **ret); -int image_find_harder(ImageClass class, const char *name_or_path, Image **ret); -int image_discover(ImageClass class, Hashmap *map); +int image_find_harder(ImageClass class, const char *root, const char *name_or_path, Image **ret); +int image_discover(ImageClass class, const char *root, Hashmap *map); int image_remove(Image *i); int image_rename(Image *i, const char *new_name); @@ -84,7 +84,7 @@ int image_set_limit(Image *i, uint64_t referenced_max); int image_read_metadata(Image *i); -bool image_in_search_path(ImageClass class, const char *image); +bool image_in_search_path(ImageClass class, const char *root, const char *image); static inline bool IMAGE_IS_HIDDEN(const struct Image *i) { assert(i); diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c index 4f92d563af1..ea307dc1d69 100644 --- a/src/sysext/sysext.c +++ b/src/sysext/sysext.c @@ -897,7 +897,7 @@ static int run(int argc, char *argv[]) { if (!images) return log_oom(); - r = image_discover(IMAGE_EXTENSION, images); + r = image_discover(IMAGE_EXTENSION, arg_root, images); if (r < 0) return log_error_errno(r, "Failed to discover extension images: %m"); -- 2.47.3