systemd-sysext supports --root= for everything but the image discovery.
Fix that.
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)
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)
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);
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);
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);
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);
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);
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)
if (!images)
return -ENOMEM;
- r = image_discover(IMAGE_MACHINE, images);
+ r = image_discover(IMAGE_MACHINE, NULL, images);
if (r < 0)
return r;
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)
if (!images)
return -ENOMEM;
- r = image_discover(IMAGE_MACHINE, images);
+ r = image_discover(IMAGE_MACHINE, NULL, images);
if (r < 0)
return r;
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)
goto child_fail;
}
- r = image_discover(IMAGE_MACHINE, images);
+ r = image_discover(IMAGE_MACHINE, NULL, images);
if (r < 0)
goto child_fail;
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)
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;
/* 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);
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;
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)
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);
/* 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;
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;
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)
if (!raw)
return -ENOMEM;
- if (fstatat(dirfd(d), raw, &st, 0) < 0) {
-
+ if (fstatat(dirfd(d), raw, &st, flags) < 0) {
if (errno == ENOENT)
continue;
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;
}
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;
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;
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;
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)
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;
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)
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)
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;
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);
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);
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");