]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
machine-image: properly support searching for images below some --root= path
authorLennart Poettering <lennart@poettering.net>
Tue, 12 Jan 2021 16:18:53 +0000 (17:18 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 19 Jan 2021 12:41:42 +0000 (13:41 +0100)
systemd-sysext supports --root= for everything but the image discovery.
Fix that.

13 files changed:
src/import/export.c
src/import/import-fs.c
src/import/import.c
src/import/pull.c
src/machine/image-dbus.c
src/machine/machined-dbus.c
src/nspawn/nspawn.c
src/portable/portable.c
src/portable/portabled-image-bus.c
src/portable/portabled-image.c
src/shared/machine-image.c
src/shared/machine-image.h
src/sysext/sysext.c

index b8507330ac0bd962ebd5665da0bf4dddb56dc1c7..9c44fcf35cc746e19dd1dfeba31332f9a02eff73 100644 (file)
@@ -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)
index a22eef8255824815c109aba5e9121ff24be55c08..a36ab24fb8e7bf2c796849147e69a7619c5d2709 100644 (file)
@@ -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);
index 9ea8e7f16dd9b806247de905f5f6bceca9a98be3..3fd99d11603346a17f0b74d2da0c93dac6b4e09d 100644 (file)
@@ -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);
index a4cec9448e2910a96f5b366b2ba3af7e717d4540..e80d8abe6f5140a90428aea972b88fe1f5145db6 100644 (file)
@@ -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);
index c157aaf33cbc183f29480ec003bf9a3a7f326844..4c4f900527addc12fb78d4b4e26bb7d860b79d5d 100644 (file)
@@ -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;
 
index 781686c1048b40f449c0a9b53a703dee5f4ec5d1..a65f9b6a8e5628ea604504fd30c966ae2dfb6c07 100644 (file)
@@ -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;
 
index e68f0cebf0ff641011fcf90b9dfb13a371bbd245..75cefe84142aac537ae0d03da78b817f998933e2 100644 (file)
@@ -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)
index a96a944ad1ae0f0ced697ddc2828e4cd6c3f6b5f..d74e498d596d67f19e7a5c29eca892a6b0b75ee7 100644 (file)
@@ -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)
index eb0786e4bb017df80d1cf471a77fc3209b61579e..76b6ddebde374068beb41508f0b79ffd67e79abf 100644 (file)
@@ -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);
 
index b025c2054907bf3e53400ac16640c4d5907e0177..40548fb655676416fd1bf494932d1ff94c9d8a42 100644 (file)
@@ -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;
 
index f7b1f90c6f11477b49f162d821ad499048b87b42..d2b726efc4c4a6f45eaa63bc468fa8dc2d93b1a7 100644 (file)
@@ -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;
 
index eea94e0324bb3d3ea4fd39502b53b043926ee738..c568fff751bd202b18f779ccc5f1907930087315 100644 (file)
@@ -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);
index 4f92d563af187800613a2beb9a58febc18e74f04..ea307dc1d69305b251c7a5bc84579e480b8e76e8 100644 (file)
@@ -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");