diff --git a/src/shared/discover-image.c b/src/shared/discover-image.c index 37bcc26a6a..96b39683c4 100644 --- a/src/shared/discover-image.c +++ b/src/shared/discover-image.c @@ -408,6 +408,8 @@ static int image_make( /* We explicitly *do* follow symlinks here, since we want to allow symlinking trees, raw files and block * devices into /var/lib/machines/, and treat them normally. + * Note that if the caller does not want to follow symlinks (and does not care about symlink races) + * then the caller should pass in a resolved path and an fd. * * This function returns -ENOENT if we can't find the image after all, and -EMEDIUMTYPE if it's not a file we * recognize. */ @@ -744,10 +746,7 @@ int image_find(RuntimeScope scope, const char *root, Image **ret) { - /* 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.) */ - int open_flags = root ? O_NOFOLLOW : 0, r; + int r; assert(scope < _RUNTIME_SCOPE_MAX && scope != RUNTIME_SCOPE_GLOBAL); assert(class >= 0); @@ -762,32 +761,47 @@ int image_find(RuntimeScope scope, if (!names) return -ENOMEM; + _cleanup_close_ int rfd = XAT_FDROOT; /* We only expect absolute paths */ + if (root) { + rfd = open(root, O_CLOEXEC|O_DIRECTORY|O_PATH); + if (rfd < 0) + return log_debug_errno(errno, "Failed to open root directory '%s': %m", root); + } + _cleanup_strv_free_ char **search = NULL; r = pick_image_search_path(scope, class, root, &search); if (r < 0) return r; STRV_FOREACH(s, search) { - _cleanup_free_ char *resolved = NULL; _cleanup_closedir_ DIR *d = NULL; + _cleanup_free_ char *search_path = NULL; - r = chase_and_opendir(*s, root, CHASE_PREFIX_ROOT, &resolved, &d); + r = chase_and_opendirat(rfd, *s, CHASE_AT_RESOLVE_IN_ROOT, &search_path, &d); if (r == -ENOENT) continue; if (r < 0) return r; STRV_FOREACH(n, names) { - _cleanup_free_ char *fname_buf = NULL; const char *fname = *n; + _cleanup_free_ char *fname_path = NULL, *chased_path = NULL, *resolved_file = NULL; + _cleanup_close_ int fd = -EBADF; - _cleanup_close_ int fd = openat(dirfd(d), fname, O_PATH|O_CLOEXEC|open_flags); - if (fd < 0) { - if (errno != ENOENT) - return -errno; + fname_path = path_join(search_path, fname); + if (!fname_path) + return -ENOMEM; + /* Follow symlinks only inside given root */ + r = chaseat(rfd, fname_path, CHASE_AT_RESOLVE_IN_ROOT, &chased_path, &fd); + if (r == -ENOENT) continue; - } + if (r < 0) + return r; + + r = chaseat_prefix_root(chased_path, root, &resolved_file); + if (r < 0) + return r; struct stat st; if (fstat(fd, &st) < 0) @@ -813,10 +827,6 @@ int image_find(RuntimeScope scope, *ASSERT_PTR(endswith(suffix, ".v")) = 0; - _cleanup_free_ char *vp = path_join(resolved, fname); - if (!vp) - return -ENOMEM; - PickFilter filter = { .type_mask = endswith(suffix, ".raw") ? (UINT32_C(1) << DT_REG) | (UINT32_C(1) << DT_BLK) : (UINT32_C(1) << DT_DIR), .basename = name, @@ -826,48 +836,44 @@ int image_find(RuntimeScope scope, _cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL; r = path_pick(root, - /* toplevel_fd= */ AT_FDCWD, - vp, + rfd, + fname_path, /* This has to be the unresolved entry with the .v suffix */ &filter, /* n_filters= */ 1, - PICK_ARCHITECTURE|PICK_TRIES, + PICK_ARCHITECTURE|PICK_TRIES|PICK_RESOLVE, &result); if (r < 0) { - log_debug_errno(r, "Failed to pick versioned image on '%s', skipping: %m", vp); + log_debug_errno(r, "Failed to pick versioned image on '%s%s', skipping: %m", empty_to_root(root), skip_leading_slash(fname_path)); continue; } if (!result.path) { - log_debug("Found versioned directory '%s', without matching entry, skipping.", vp); + log_debug("Found versioned directory '%s%s', without matching entry, skipping.", empty_to_root(root), skip_leading_slash(fname_path)); continue; } /* Refresh the stat data for the discovered target */ st = result.st; close_and_replace(fd, result.fd); + free(resolved_file); + resolved_file = path_join(root, result.path); + if (!resolved_file) + return -ENOMEM; - _cleanup_free_ char *bn = NULL; - r = path_extract_filename(result.path, &bn); - if (r < 0) { - log_debug_errno(r, "Failed to extract basename of image path '%s', skipping: %m", result.path); - continue; - } - - fname_buf = path_join(fname, bn); - if (!fname_buf) - return log_oom(); - - fname = fname_buf; - + /* fname and fname_path are invalid now because they would need to be set + * from result.path by extracting the filename to set + * fname = path_join(fname, filename) and then + * fname_path = path_join(*s, fname) but since they are unused we don't do it */ + fname = NULL; + fname_path = mfree(fname_path); } else if (!S_ISDIR(st.st_mode) && !S_ISBLK(st.st_mode)) { log_debug("Ignoring non-directory and non-block device file '%s' without suffix.", fname); continue; } - _cleanup_free_ char *path = path_join(resolved, fname); - if (!path) - return -ENOMEM; - - r = image_make(class, name, fd, path, &st, ret); + /* Only put resolved paths into the image entry (incl. --root=). + * Defending against symlink races is not done + * and would be a TODO. */ + r = image_make(class, name, fd, resolved_file, &st, ret); if (IN_SET(r, -ENOENT, -EMEDIUMTYPE)) continue; if (r < 0) @@ -948,46 +954,58 @@ int image_discover( const char *root, Hashmap **images) { - /* 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.) */ - int open_flags = root ? O_NOFOLLOW : 0, r; + int r; assert(scope < _RUNTIME_SCOPE_MAX && scope != RUNTIME_SCOPE_GLOBAL); assert(class >= 0); assert(class < _IMAGE_CLASS_MAX); assert(images); + _cleanup_close_ int rfd = XAT_FDROOT; /* We only expect absolute paths */ + if (root) { + rfd = open(root, O_CLOEXEC|O_DIRECTORY|O_PATH); + if (rfd < 0) + return log_debug_errno(errno, "Failed to open root directory '%s': %m", root); + } + _cleanup_strv_free_ char **search = NULL; r = pick_image_search_path(scope, class, root, &search); if (r < 0) return r; STRV_FOREACH(s, search) { - _cleanup_free_ char *resolved = NULL; _cleanup_closedir_ DIR *d = NULL; + _cleanup_free_ char *search_path = NULL; - r = chase_and_opendir(*s, root, CHASE_PREFIX_ROOT, &resolved, &d); + r = chase_and_opendirat(rfd, *s, CHASE_AT_RESOLVE_IN_ROOT, &search_path, &d); if (r == -ENOENT) continue; if (r < 0) return r; FOREACH_DIRENT_ALL(de, d, return -errno) { - _cleanup_free_ char *pretty = NULL, *fname_buf = NULL; + _cleanup_free_ char *pretty = NULL, *fname_path = NULL, *chased_path = NULL, *resolved_file = NULL; _cleanup_(image_unrefp) Image *image = NULL; const char *fname = de->d_name; + _cleanup_close_ int fd = -EBADF; if (dot_or_dot_dot(fname)) continue; - _cleanup_close_ int fd = openat(dirfd(d), fname, O_PATH|O_CLOEXEC|open_flags); - if (fd < 0) { - if (errno != ENOENT) - return -errno; + fname_path = path_join(search_path, fname); + if (!fname_path) + return -ENOMEM; - continue; /* Vanished while we were looking at it */ - } + /* Follow symlinks only inside given root */ + r = chaseat(rfd, fname_path, CHASE_AT_RESOLVE_IN_ROOT, &chased_path, &fd); + if (r == -ENOENT) + continue; + if (r < 0) + return r; + + r = chaseat_prefix_root(chased_path, root, &resolved_file); + if (r < 0) + return r; struct stat st; if (fstat(fd, &st) < 0) @@ -1026,10 +1044,6 @@ int image_discover( continue; } - _cleanup_free_ char *vp = path_join(resolved, fname); - if (!vp) - return -ENOMEM; - PickFilter filter = { .type_mask = endswith(suffix, ".raw") ? (UINT32_C(1) << DT_REG) | (UINT32_C(1) << DT_BLK) : (UINT32_C(1) << DT_DIR), .basename = pretty, @@ -1039,38 +1053,36 @@ int image_discover( _cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL; r = path_pick(root, - /* toplevel_fd= */ AT_FDCWD, - vp, + rfd, + fname_path, /* This has to be the unresolved entry with the .v suffix */ &filter, /* n_filters= */ 1, - PICK_ARCHITECTURE|PICK_TRIES, + PICK_ARCHITECTURE|PICK_TRIES|PICK_RESOLVE, &result); if (r < 0) { - log_debug_errno(r, "Failed to pick versioned image on '%s', skipping: %m", vp); + log_debug_errno(r, "Failed to pick versioned image on '%s%s', skipping: %m", empty_to_root(root), skip_leading_slash(fname_path)); continue; } if (!result.path) { - log_debug("Found versioned directory '%s', without matching entry, skipping.", vp); + log_debug("Found versioned directory '%s%s', without matching entry, skipping.", empty_to_root(root), skip_leading_slash(fname_path)); continue; } /* Refresh the stat data for the discovered target */ st = result.st; close_and_replace(fd, result.fd); + free(resolved_file); + resolved_file = path_join(root, result.path); + if (!resolved_file) + return -ENOMEM; - _cleanup_free_ char *bn = NULL; - r = path_extract_filename(result.path, &bn); - if (r < 0) { - log_debug_errno(r, "Failed to extract basename of image path '%s', skipping: %m", result.path); - continue; - } - - fname_buf = path_join(fname, bn); - if (!fname_buf) - return log_oom(); - - fname = fname_buf; - + /* fname and fname_path are invalid now because they would need to + * be set from result.path by extracting the filename to set + * fname = path_join(fname, filename) and then + * fname_path = path_join(*s, fname) but since they are unused we + * don't do it */ + fname = NULL; + fname_path = mfree(fname_path); } else { r = extract_image_basename( fname, @@ -1103,11 +1115,10 @@ int image_discover( if (hashmap_contains(*images, pretty)) continue; - _cleanup_free_ char *path = path_join(resolved, fname); - if (!path) - return -ENOMEM; - - r = image_make(class, pretty, fd, path, &st, &image); + /* Only put resolved paths into the image entry. + * Defending against symlink races is not done + * and would be a TODO. */ + r = image_make(class, pretty, fd, resolved_file, &st, &image); if (IN_SET(r, -ENOENT, -EMEDIUMTYPE)) continue; if (r < 0) @@ -2148,6 +2159,11 @@ int image_read_metadata(Image *i, const char *root, const ImagePolicy *image_pol if (r < 0) return log_debug_errno(r, "Failed to decrypt image '%s': %m", i->path); + /* Do not use the image name derived from the backing file of the loop device */ + r = free_and_strdup(&m->image_name, i->name); + if (r < 0) + return r; + r = dissected_image_acquire_metadata( m, /* userns_fd= */ -EBADF, diff --git a/src/shared/vpick.c b/src/shared/vpick.c index d8fae8aa77..f3fd233e17 100644 --- a/src/shared/vpick.c +++ b/src/shared/vpick.c @@ -193,7 +193,7 @@ static int pin_choice( _cleanup_free_ char *resolved_path = NULL; int r; - assert(toplevel_fd >= 0 || toplevel_fd == AT_FDCWD); + assert(toplevel_fd >= 0 || IN_SET(toplevel_fd, AT_FDCWD, XAT_FDROOT)); assert(inode_path); assert(filter); assert(ret); @@ -324,7 +324,7 @@ static int make_choice( _cleanup_close_ int inode_fd = TAKE_FD(_inode_fd); int r; - assert(toplevel_fd >= 0 || toplevel_fd == AT_FDCWD); + assert(toplevel_fd >= 0 || IN_SET(toplevel_fd, AT_FDCWD, XAT_FDROOT)); assert(inode_path); assert(filter); assert(ret); @@ -516,7 +516,7 @@ static int path_pick_one( uint32_t filter_type_mask; int r; - assert(toplevel_fd >= 0 || toplevel_fd == AT_FDCWD); + assert(toplevel_fd >= 0 || IN_SET(toplevel_fd, AT_FDCWD, XAT_FDROOT)); assert(path); assert(filter); assert(ret); @@ -663,7 +663,7 @@ int path_pick(const char *toplevel_path, _cleanup_(pick_result_done) PickResult best = PICK_RESULT_NULL; int r; - assert(toplevel_fd >= 0 || toplevel_fd == AT_FDCWD); + assert(toplevel_fd >= 0 || IN_SET(toplevel_fd, AT_FDCWD, XAT_FDROOT)); assert(path); assert(filters || n_filters == 0); assert(ret); diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c index 340d762b13..ea3ebceab5 100644 --- a/src/sysext/sysext.c +++ b/src/sysext/sysext.c @@ -1911,6 +1911,11 @@ static int merge_subprocess( if (r < 0) return r; + /* Do not use the image name derived from the backing file of the loop device */ + r = free_and_strdup(&m->image_name, img->name); + if (r < 0) + return r; + r = dissected_image_load_verity_sig_partition( m, d->fd, diff --git a/test/units/TEST-50-DISSECT.sysext.sh b/test/units/TEST-50-DISSECT.sysext.sh index 26bec15351..0ebc115208 100755 --- a/test/units/TEST-50-DISSECT.sysext.sh +++ b/test/units/TEST-50-DISSECT.sysext.sh @@ -1307,6 +1307,286 @@ run_systemd_sysext "$fake_root" unmerge extension_verify_after_unmerge "$fake_root" "$hierarchy" -h ) +# A couple of symlink tests follow below + +( init_trap +: "Check if following a relative extension directory symlink works with and without --root=" +fake_root=${roots_dir:+"$roots_dir/follow-relative-dir-symlink"} +hierarchy=/opt + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +mv -T "$fake_root/var/lib/extensions/test-extension" "$fake_root/var/othername-extension" +ln -s "../../othername-extension" "$fake_root/var/lib/extensions/test-extension" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" + +run_systemd_sysext "$fake_root" merge +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +rm -rf "$fake_root/var/othername-extension" +) + +( init_trap +: "Check if following an absolute extension directory symlink works with and without --root=" +fake_root=${roots_dir:+"$roots_dir/follow-absolute-dir-symlink"} +hierarchy=/opt + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +mv -T "$fake_root/var/lib/extensions/test-extension" "$fake_root/var/othername-extension" +ln -s "/var/othername-extension" "$fake_root/var/lib/extensions/test-extension" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" + +run_systemd_sysext "$fake_root" merge +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +rm -rf "$fake_root/var/othername-extension" +) + +( init_trap +: "Check if following a relative extension image symlink works with and without --root=" +fake_root=${roots_dir:+"$roots_dir/follow-relative-image-symlink"} +hierarchy=/opt + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image_raw "$fake_root" "$hierarchy" +mv "$fake_root/var/lib/extensions/test-extension.raw" "$fake_root/var/othername-extension.raw" +ln -s "../../othername-extension.raw" "$fake_root/var/lib/extensions/test-extension.raw" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" + +run_systemd_sysext "$fake_root" merge +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +rm -rf "$fake_root/var/othername-extension.raw" +) + +( init_trap +: "Check if following an absolute extension image symlink works with and without --root=" +fake_root=${roots_dir:+"$roots_dir/follow-absolute-image-symlink"} +hierarchy=/opt + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image_raw "$fake_root" "$hierarchy" +mv "$fake_root/var/lib/extensions/test-extension.raw" "$fake_root/var/othername-extension.raw" +ln -s "/var/othername-extension.raw" "$fake_root/var/lib/extensions/test-extension.raw" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" + +run_systemd_sysext "$fake_root" merge +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +rm -rf "$fake_root/var/othername-extension.raw" +) + +# And now a couple of vpick tests, including following symlinks + +( init_trap +: "Check if vpick works for directory extensions" +fake_root=${roots_dir:+"$roots_dir/vpick-dir"} +hierarchy=/opt + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +mkdir -p "$fake_root/var/lib/extensions/test-extension.v" +mv -T "$fake_root/var/lib/extensions/test-extension" "$fake_root/var/lib/extensions/test-extension.v/test-extension_1.0" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" + +run_systemd_sysext "$fake_root" merge +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +rm -rf "$fake_root/var/lib/extensions/test-extension.v" +) + +( init_trap +: "Check if vpick works for image extensions" +fake_root=${roots_dir:+"$roots_dir/vpick-image"} +hierarchy=/opt + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image_raw "$fake_root" "$hierarchy" +mkdir -p "$fake_root/var/lib/extensions/test-extension.raw.v" +mv "$fake_root/var/lib/extensions/test-extension.raw" "$fake_root/var/lib/extensions/test-extension.raw.v/test-extension_1.0.raw" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" + +run_systemd_sysext "$fake_root" merge +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +rm -rf "$fake_root/var/lib/extensions/test-extension.raw.v" +) + +( init_trap +: "Check if vpick works for directory extensions if .v is a relative symlink" +fake_root=${roots_dir:+"$roots_dir/vpick-dir-relative-symlink"} +hierarchy=/opt + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +mkdir -p "$fake_root/var/test-extension-vpick" +mv -T "$fake_root/var/lib/extensions/test-extension" "$fake_root/var/test-extension-vpick/test-extension_1.0" +ln -s "../../test-extension-vpick" "$fake_root/var/lib/extensions/test-extension.v" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" + +run_systemd_sysext "$fake_root" merge +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +rm -rf "$fake_root/var/lib/extensions/test-extension.v" "$fake_root/var/test-extension-vpick" +) + +( init_trap +: "Check if vpick works for directory extensions if .v is an absolute symlink" +fake_root=${roots_dir:+"$roots_dir/vpick-dir-absolute-symlink"} +hierarchy=/opt + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +mkdir -p "$fake_root/var/test-extension-vpick" +mv -T "$fake_root/var/lib/extensions/test-extension" "$fake_root/var/test-extension-vpick/test-extension_1.0" +ln -s "/var/test-extension-vpick" "$fake_root/var/lib/extensions/test-extension.v" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" + +run_systemd_sysext "$fake_root" merge +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +rm -rf "$fake_root/var/lib/extensions/test-extension.v" "$fake_root/var/test-extension-vpick" +) + +( init_trap +: "Check if vpick works for image extensions if .v is a relative symlink" +fake_root=${roots_dir:+"$roots_dir/vpick-image-relative-symlink"} +hierarchy=/opt + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image_raw "$fake_root" "$hierarchy" +mkdir -p "$fake_root/var/test-extension-vpick" +mv "$fake_root/var/lib/extensions/test-extension.raw" "$fake_root/var/test-extension-vpick/test-extension_1.0.raw" +ln -s "../../test-extension-vpick" "$fake_root/var/lib/extensions/test-extension.raw.v" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" + +run_systemd_sysext "$fake_root" merge +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +rm -rf "$fake_root/var/lib/extensions/test-extension.raw.v" "$fake_root/var/test-extension-vpick" +) + +( init_trap +: "Check if vpick works for image extensions if .v is an absolute symlink" +fake_root=${roots_dir:+"$roots_dir/vpick-image-absolute-symlink"} +hierarchy=/opt + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image_raw "$fake_root" "$hierarchy" +mkdir -p "$fake_root/var/test-extension-vpick" +mv "$fake_root/var/lib/extensions/test-extension.raw" "$fake_root/var/test-extension-vpick/test-extension_1.0.raw" +ln -s "/var/test-extension-vpick" "$fake_root/var/lib/extensions/test-extension.raw.v" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" + +run_systemd_sysext "$fake_root" merge +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +rm -rf "$fake_root/var/lib/extensions/test-extension.raw.v" "$fake_root/var/test-extension-vpick" +) + +( init_trap +: "Check if vpick works for directory extensions if inside a .v there is a relative symlink" +fake_root=${roots_dir:+"$roots_dir/vpick-dir-relative-symlink-inside"} +hierarchy=/opt + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +mv -T "$fake_root/var/lib/extensions/test-extension" "$fake_root/var/othername-extension" +mkdir -p "$fake_root/var/lib/extensions/test-extension.v" +ln -s "../../../othername-extension" "$fake_root/var/lib/extensions/test-extension.v/test-extension_1.0" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" + +run_systemd_sysext "$fake_root" merge +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +rm -rf "$fake_root/var/lib/extensions/test-extension.v" "$fake_root/var/othername-extension" +) + +( init_trap +: "Check if vpick works for directory extensions if inside a .v there is an absolute symlink" +fake_root=${roots_dir:+"$roots_dir/vpick-dir-absolute-symlink-inside"} +hierarchy=/opt + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image "$fake_root" "$hierarchy" +mv -T "$fake_root/var/lib/extensions/test-extension" "$fake_root/var/othername-extension" +mkdir -p "$fake_root/var/lib/extensions/test-extension.v" +ln -s "/var/othername-extension" "$fake_root/var/lib/extensions/test-extension.v/test-extension_1.0" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" + +run_systemd_sysext "$fake_root" merge +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +rm -rf "$fake_root/var/lib/extensions/test-extension.v" "$fake_root/var/othername-extension" +) + +( init_trap +: "Check if vpick works for image extensions if inside a .v there is a relative symlink" +fake_root=${roots_dir:+"$roots_dir/vpick-image-relative-symlink-inside"} +hierarchy=/opt + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image_raw "$fake_root" "$hierarchy" +mv "$fake_root/var/lib/extensions/test-extension.raw" "$fake_root/var/othername-extension.raw" +mkdir -p "$fake_root/var/lib/extensions/test-extension.raw.v" +ln -s "../../../othername-extension.raw" "$fake_root/var/lib/extensions/test-extension.raw.v/test-extension_1.0.raw" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" + +run_systemd_sysext "$fake_root" merge +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +rm -rf "$fake_root/var/lib/extensions/test-extension.raw.v" "$fake_root/var/othername-extension.raw" +) + +( init_trap +: "Check if vpick works for image extensions if inside a .v there is an absolute symlink" +fake_root=${roots_dir:+"$roots_dir/vpick-image-absolute-symlink-inside"} +hierarchy=/opt + +prepare_root "$fake_root" "$hierarchy" +prepare_extension_image_raw "$fake_root" "$hierarchy" +mv "$fake_root/var/lib/extensions/test-extension.raw" "$fake_root/var/othername-extension.raw" +mkdir -p "$fake_root/var/lib/extensions/test-extension.raw.v" +ln -s "/var/othername-extension.raw" "$fake_root/var/lib/extensions/test-extension.raw.v/test-extension_1.0.raw" +prepare_read_only_hierarchy "$fake_root" "$hierarchy" + +run_systemd_sysext "$fake_root" merge +extension_verify_after_merge "$fake_root" "$hierarchy" -e -h + +run_systemd_sysext "$fake_root" unmerge +extension_verify_after_unmerge "$fake_root" "$hierarchy" -h +rm -rf "$fake_root/var/lib/extensions/test-extension.raw.v" "$fake_root/var/othername-extension.raw" +) + +# Done with the above vpick symlink tests for --root= and without + } # End of run_sysext_tests