From: Lennart Poettering Date: Thu, 28 May 2026 10:37:39 +0000 (+0200) Subject: vpick: take separate root_fd and dir_fd arguments X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=95a372a514dfe0e03d9e03b4171f87fd98ddcb14;p=thirdparty%2Fsystemd.git vpick: take separate root_fd and dir_fd arguments Mirror how chaseat() works these days: instead of a single toplevel_fd that serves as both the root (chroot) boundary and the directory that resolution starts from, path_pick() now takes a separate root_fd and dir_fd. This lets callers resolve a path relative to a specific directory fd while confining symlink and absolute-path resolution to a root directory fd. All existing callers are updated to pass the same fd for both, preserving their current behaviour. --- diff --git a/src/core/exec-invoke.c b/src/core/exec-invoke.c index a06852a6b5f..c45c807198d 100644 --- a/src/core/exec-invoke.c +++ b/src/core/exec-invoke.c @@ -3719,8 +3719,9 @@ static int pin_rootfs( if (context->root_image) { _cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL; - r = path_pick(/* toplevel_path= */ NULL, - /* toplevel_fd= */ AT_FDCWD, + r = path_pick(/* root_path= */ NULL, + /* root_fd= */ AT_FDCWD, + /* dir_fd= */ AT_FDCWD, context->root_image, pick_filter_image_raw, ELEMENTSOF(pick_filter_image_raw), @@ -3760,8 +3761,9 @@ static int pin_rootfs( if (context->root_directory) { _cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL; - r = path_pick(/* toplevel_path= */ NULL, - /* toplevel_fd= */ AT_FDCWD, + r = path_pick(/* root_path= */ NULL, + /* root_fd= */ AT_FDCWD, + /* dir_fd= */ AT_FDCWD, context->root_directory, pick_filter_image_dir, ELEMENTSOF(pick_filter_image_dir), @@ -3789,8 +3791,9 @@ static int pin_rootfs( if (context->root_mstack) { _cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL; - r = path_pick(/* toplevel_path= */ NULL, - /* toplevel_fd= */ AT_FDCWD, + r = path_pick(/* root_path= */ NULL, + /* root_fd= */ AT_FDCWD, + /* dir_fd= */ AT_FDCWD, context->root_mstack, pick_filter_image_mstack, /* n_filters= */ 1, diff --git a/src/core/namespace.c b/src/core/namespace.c index a6ba2659e42..3fc0a8652db 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -564,8 +564,9 @@ static int append_extensions( _cleanup_free_ char *mount_point = NULL; const MountImage *m = mount_images + i; - r = path_pick(/* toplevel_path= */ NULL, - /* toplevel_fd= */ AT_FDCWD, + r = path_pick(/* root_path= */ NULL, + /* root_fd= */ AT_FDCWD, + /* dir_fd= */ AT_FDCWD, m->source, pick_filter_image_raw, ELEMENTSOF(pick_filter_image_raw), @@ -636,8 +637,9 @@ static int append_extensions( if (startswith(e, "+")) e++; - r = path_pick(/* toplevel_path= */ NULL, - /* toplevel_fd= */ AT_FDCWD, + r = path_pick(/* root_path= */ NULL, + /* root_fd= */ AT_FDCWD, + /* dir_fd= */ AT_FDCWD, e, pick_filter_image_dir, ELEMENTSOF(pick_filter_image_dir), diff --git a/src/portable/portable.c b/src/portable/portable.c index a98c1162d95..9d510118be2 100644 --- a/src/portable/portable.c +++ b/src/portable/portable.c @@ -821,8 +821,9 @@ static int extract_image_and_extensions( /* If we get a path, then check if it can be resolved with vpick. We need this as we might just * get a simple image name, which would make vpick error out. */ if (path_is_absolute(name_or_path)) { - r = path_pick(/* toplevel_path= */ NULL, - /* toplevel_fd= */ AT_FDCWD, + r = path_pick(/* root_path= */ NULL, + /* root_fd= */ AT_FDCWD, + /* dir_fd= */ AT_FDCWD, name_or_path, pick_filter_image_any, ELEMENTSOF(pick_filter_image_any), @@ -860,8 +861,9 @@ static int extract_image_and_extensions( const char *path = *p; if (path_is_absolute(*p)) { - r = path_pick(/* toplevel_path= */ NULL, - /* toplevel_fd= */ AT_FDCWD, + r = path_pick(/* root_path= */ NULL, + /* root_fd= */ AT_FDCWD, + /* dir_fd= */ AT_FDCWD, *p, pick_filter_image_any, ELEMENTSOF(pick_filter_image_any), @@ -2201,8 +2203,9 @@ static bool marker_matches_images(const char *marker, const char *name_or_path, if (r < 0) return log_debug_errno(r, "Failed to extract image name from %s, ignoring: %m", image); - r = path_pick(/* toplevel_path= */ NULL, - /* toplevel_fd= */ AT_FDCWD, + r = path_pick(/* root_path= */ NULL, + /* root_fd= */ AT_FDCWD, + /* dir_fd= */ AT_FDCWD, *image_name_or_path, pick_filter_image_any, ELEMENTSOF(pick_filter_image_any), diff --git a/src/shared/discover-image.c b/src/shared/discover-image.c index 0410b523baa..9994ff5da45 100644 --- a/src/shared/discover-image.c +++ b/src/shared/discover-image.c @@ -956,6 +956,7 @@ int image_find(RuntimeScope scope, _cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL; r = path_pick(root, + rfd, rfd, fname_path, /* This has to be the unresolved entry with the .v suffix */ &filter, @@ -1177,6 +1178,7 @@ int image_discover( _cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL; r = path_pick(root, + rfd, rfd, fname_path, /* This has to be the unresolved entry with the .v suffix */ &filter, diff --git a/src/shared/mstack.c b/src/shared/mstack.c index cc3cb9a75f7..65f38ba3b3d 100644 --- a/src/shared/mstack.c +++ b/src/shared/mstack.c @@ -139,7 +139,7 @@ static int mstack_load_one(MStack *mstack, const char *dir, int dir_fd, const ch }; _cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL; - r = path_pick(dir, dir_fd, fname, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE, &result); + r = path_pick(dir, dir_fd, dir_fd, fname, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE, &result); if (r < 0) return log_debug_errno(r, "Failed to resolve '%s' directory: %m", fname); if (r == 0) diff --git a/src/shared/vpick.c b/src/shared/vpick.c index 7890fb17088..c661f92fafc 100644 --- a/src/shared/vpick.c +++ b/src/shared/vpick.c @@ -176,8 +176,9 @@ static int errno_from_mode(uint32_t type_mask, mode_t found) { } static int pin_choice( - const char *toplevel_path, - int toplevel_fd, + const char *root_path, + int root_fd, + int dir_fd, const char *inode_path, int _inode_fd, /* we always take ownership of the fd, even on failure */ unsigned tries_left, @@ -190,14 +191,15 @@ static int pin_choice( _cleanup_free_ char *resolved_path = NULL; int r; - assert(wildcard_fd_is_valid(toplevel_fd)); + assert(wildcard_fd_is_valid(root_fd)); + assert(wildcard_fd_is_valid(dir_fd)); assert(inode_path); assert(filter); assert(ret); if (inode_fd < 0 || FLAGS_SET(flags, PICK_RESOLVE)) { - r = chaseat(toplevel_fd, - toplevel_fd, + r = chaseat(root_fd, + dir_fd, inode_path, /* flags= */ 0, FLAGS_SET(flags, PICK_RESOLVE) ? &resolved_path : NULL, @@ -212,11 +214,11 @@ static int pin_choice( struct stat st; if (fstat(inode_fd, &st) < 0) return log_debug_errno(errno, "Failed to stat discovered inode '%s%s': %m", - empty_to_root(toplevel_path), skip_leading_slash(inode_path)); + empty_to_root(root_path), skip_leading_slash(inode_path)); if (filter->type_mask != 0 && !BIT_SET(filter->type_mask, IFTODT(st.st_mode))) { log_debug("Inode '%s/%s' has wrong type, found '%s'.", - empty_to_root(toplevel_path), skip_leading_slash(inode_path), + empty_to_root(root_path), skip_leading_slash(inode_path), inode_type_to_string(st.st_mode)); *ret = PICK_RESULT_NULL; return 0; @@ -311,8 +313,9 @@ static bool architecture_matches(const PickFilter *filter, Architecture a) { } static int make_choice( - const char *toplevel_path, - int toplevel_fd, + const char *root_path, + int root_fd, + int dir_fd, const char *inode_path, int _inode_fd, /* we always take ownership of the fd, even on failure */ const PickFilter *filter, @@ -322,13 +325,14 @@ static int make_choice( _cleanup_close_ int inode_fd = TAKE_FD(_inode_fd); int r; - assert(wildcard_fd_is_valid(toplevel_fd)); + assert(wildcard_fd_is_valid(root_fd)); + assert(wildcard_fd_is_valid(dir_fd)); assert(inode_path); assert(filter); assert(ret); if (inode_fd < 0) { - r = chaseat(toplevel_fd, toplevel_fd, inode_path, /* flags= */ 0, NULL, &inode_fd); + r = chaseat(root_fd, dir_fd, inode_path, /* flags= */ 0, NULL, &inode_fd); if (r < 0) return r; } @@ -345,18 +349,19 @@ static int make_choice( return log_oom_debug(); _cleanup_close_ int object_fd = -EBADF; - r = chaseat(toplevel_fd, toplevel_fd, p, /* flags= */ 0, &object_path, &object_fd); + r = chaseat(root_fd, dir_fd, p, /* flags= */ 0, &object_path, &object_fd); if (r == -ENOENT) { *ret = PICK_RESULT_NULL; return 0; } if (r < 0) return log_debug_errno(r, "Failed to open '%s/%s': %m", - empty_to_root(toplevel_path), skip_leading_slash(p)); + empty_to_root(root_path), skip_leading_slash(p)); return pin_choice( - toplevel_path, - toplevel_fd, + root_path, + root_fd, + dir_fd, FLAGS_SET(flags, PICK_RESOLVE) ? object_path : p, TAKE_FD(object_fd), /* unconditionally pass ownership of the fd */ /* tries_left= */ UINT_MAX, @@ -371,16 +376,16 @@ static int make_choice( /* Underspecified, so we do our enumeration dance */ /* Convert O_PATH to a regular directory fd */ - _cleanup_close_ int dir_fd = fd_reopen(inode_fd, O_DIRECTORY|O_RDONLY|O_CLOEXEC); - if (dir_fd < 0) - return log_debug_errno(dir_fd, "Failed to reopen '%s/%s' as directory: %m", - empty_to_root(toplevel_path), skip_leading_slash(inode_path)); + _cleanup_close_ int enumerate_fd = fd_reopen(inode_fd, O_DIRECTORY|O_RDONLY|O_CLOEXEC); + if (enumerate_fd < 0) + return log_debug_errno(enumerate_fd, "Failed to reopen '%s/%s' as directory: %m", + empty_to_root(root_path), skip_leading_slash(inode_path)); _cleanup_free_ DirectoryEntries *de = NULL; - r = readdir_all(dir_fd, 0, &de); + r = readdir_all(enumerate_fd, 0, &de); if (r < 0) return log_debug_errno(r, "Failed to read directory '%s/%s': %m", - empty_to_root(toplevel_path), skip_leading_slash(inode_path)); + empty_to_root(root_path), skip_leading_slash(inode_path)); _cleanup_(pick_result_done) PickResult best = PICK_RESULT_NULL; @@ -457,8 +462,9 @@ static int make_choice( return log_oom_debug(); _cleanup_(pick_result_done) PickResult found = PICK_RESULT_NULL; - r = pin_choice(toplevel_path, - toplevel_fd, + r = pin_choice(root_path, + root_fd, + dir_fd, p, /* _inode_fd= */ -EBADF, found_tries_left, @@ -501,8 +507,9 @@ static int make_choice( } static int path_pick_one( - const char *toplevel_path, - int toplevel_fd, + const char *root_path, + int root_fd, + int dir_fd, const char *path, const PickFilter *filter, PickFlags flags, @@ -513,7 +520,8 @@ static int path_pick_one( uint32_t filter_type_mask; int r; - assert(wildcard_fd_is_valid(toplevel_fd)); + assert(wildcard_fd_is_valid(root_fd)); + assert(wildcard_fd_is_valid(dir_fd)); assert(path); assert(filter); assert(ret); @@ -537,8 +545,9 @@ static int path_pick_one( /* Explicit basename specified, then shortcut things and do .v mode regardless of the path name. */ if (filter->basename) return make_choice( - toplevel_path, - toplevel_fd, + root_path, + root_fd, + dir_fd, path, /* inode_fd= */ -EBADF, filter, @@ -623,8 +632,9 @@ static int path_pick_one( } return make_choice( - toplevel_path, - toplevel_fd, + root_path, + root_fd, + dir_fd, enumeration_path, /* inode_fd= */ -EBADF, &(const PickFilter) { @@ -640,8 +650,9 @@ static int path_pick_one( bypass: /* Don't make any choice, but just use the passed path literally */ return pin_choice( - toplevel_path, - toplevel_fd, + root_path, + root_fd, + dir_fd, path, /* inode_fd= */ -EBADF, /* tries_left= */ UINT_MAX, @@ -651,8 +662,9 @@ bypass: ret); } -int path_pick(const char *toplevel_path, - int toplevel_fd, +int path_pick(const char *root_path, + int root_fd, + int dir_fd, const char *path, const PickFilter filters[], size_t n_filters, @@ -662,7 +674,8 @@ int path_pick(const char *toplevel_path, _cleanup_(pick_result_done) PickResult best = PICK_RESULT_NULL; int r; - assert(wildcard_fd_is_valid(toplevel_fd)); + assert(wildcard_fd_is_valid(root_fd)); + assert(wildcard_fd_is_valid(dir_fd)); assert(path); assert(filters || n_filters == 0); assert(ret); @@ -671,7 +684,7 @@ int path_pick(const char *toplevel_path, for (size_t i = 0; i < n_filters; i++) { _cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL; - r = path_pick_one(toplevel_path, toplevel_fd, path, &filters[i], flags, &result); + r = path_pick_one(root_path, root_fd, dir_fd, path, &filters[i], flags, &result); if (r < 0) return r; if (r == 0) @@ -717,8 +730,9 @@ int path_pick_update_warn( /* This updates the first argument if needed! */ - r = path_pick(/* toplevel_path= */ NULL, - /* toplevel_fd= */ AT_FDCWD, + r = path_pick(/* root_path= */ NULL, + /* root_fd= */ AT_FDCWD, + /* dir_fd= */ AT_FDCWD, *path, filters, n_filters, diff --git a/src/shared/vpick.h b/src/shared/vpick.h index 55596d24dfe..de67cbe3538 100644 --- a/src/shared/vpick.h +++ b/src/shared/vpick.h @@ -45,8 +45,9 @@ void pick_result_done(PickResult *p); int pick_result_compare(const PickResult *a, const PickResult *b, PickFlags flags); -int path_pick(const char *toplevel_path, - int toplevel_fd, +int path_pick(const char *root_path, + int root_fd, + int dir_fd, const char *path, const PickFilter filters[], size_t n_filters, diff --git a/src/test/test-vpick.c b/src/test/test-vpick.c index 400380b5754..6fea29e594c 100644 --- a/src/test/test-vpick.c +++ b/src/test/test-vpick.c @@ -48,7 +48,7 @@ TEST(path_pick) { }; if (IN_SET(native_architecture(), ARCHITECTURE_X86, ARCHITECTURE_X86_64)) { - ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result)); + ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result)); ASSERT_TRUE(S_ISREG(result.st.st_mode)); ASSERT_STREQ(result.version, "99"); ASSERT_EQ(result.architecture, ARCHITECTURE_X86); @@ -58,7 +58,7 @@ TEST(path_pick) { } filter.architecture = ARCHITECTURE_X86_64; - ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result)); + ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result)); ASSERT_TRUE(S_ISREG(result.st.st_mode)); ASSERT_STREQ(result.version, "55"); ASSERT_EQ(result.architecture, ARCHITECTURE_X86_64); @@ -66,7 +66,7 @@ TEST(path_pick) { pick_result_done(&result); filter.architecture = ARCHITECTURE_IA64; - ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result)); + ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result)); ASSERT_TRUE(S_ISREG(result.st.st_mode)); ASSERT_STREQ(result.version, "5"); ASSERT_EQ(result.architecture, ARCHITECTURE_IA64); @@ -75,7 +75,7 @@ TEST(path_pick) { filter.architecture = _ARCHITECTURE_INVALID; filter.version = "5"; - ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result)); + ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result)); ASSERT_TRUE(S_ISREG(result.st.st_mode)); ASSERT_STREQ(result.version, "5"); if (native_architecture() != ARCHITECTURE_IA64) { @@ -85,7 +85,7 @@ TEST(path_pick) { pick_result_done(&result); filter.architecture = ARCHITECTURE_IA64; - ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result)); + ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result)); ASSERT_TRUE(S_ISREG(result.st.st_mode)); ASSERT_STREQ(result.version, "5"); ASSERT_EQ(result.architecture, ARCHITECTURE_IA64); @@ -93,7 +93,7 @@ TEST(path_pick) { pick_result_done(&result); filter.architecture = ARCHITECTURE_CRIS; - ASSERT_OK_ZERO(path_pick(NULL, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result)); + ASSERT_OK_ZERO(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result)); ASSERT_EQ(result.st.st_mode, MODE_INVALID); ASSERT_NULL(result.version); ASSERT_LT(result.architecture, 0); @@ -104,7 +104,7 @@ TEST(path_pick) { filter.architecture = _ARCHITECTURE_INVALID; filter.version = NULL; if (IN_SET(native_architecture(), ARCHITECTURE_X86_64, ARCHITECTURE_X86)) { - ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result)); + ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result)); ASSERT_TRUE(S_ISREG(result.st.st_mode)); ASSERT_STREQ(result.version, "55"); @@ -123,7 +123,7 @@ TEST(path_pick) { pp = ASSERT_NOT_NULL(path_join(p, "foo.v/foo___.raw")); if (IN_SET(native_architecture(), ARCHITECTURE_X86, ARCHITECTURE_X86_64)) { - ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result)); + ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result)); ASSERT_TRUE(S_ISREG(result.st.st_mode)); ASSERT_STREQ(result.version, "55"); ASSERT_EQ(result.architecture, native_architecture()); @@ -137,10 +137,10 @@ TEST(path_pick) { pp = ASSERT_NOT_NULL(path_join(p, "foo.v/foo_5.raw")); filter.type_mask = UINT32_C(1) << DT_DIR; - ASSERT_OK_ZERO(path_pick(NULL, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result)); + ASSERT_OK_ZERO(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result)); filter.type_mask = UINT32_C(1) << DT_REG; - ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result)); + ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result)); ASSERT_TRUE(S_ISREG(result.st.st_mode)); ASSERT_NULL(result.version); ASSERT_EQ(result.architecture, _ARCHITECTURE_INVALID); @@ -153,7 +153,7 @@ TEST(path_pick) { filter.architecture = ARCHITECTURE_S390; filter.basename = "quux"; - ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result)); + ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, &filter, /* n_filters= */ 1, PICK_ARCHITECTURE|PICK_TRIES, &result)); ASSERT_TRUE(S_ISREG(result.st.st_mode)); ASSERT_STREQ(result.version, "2"); ASSERT_EQ(result.tries_left, 4U); @@ -209,7 +209,7 @@ TEST(pick_filter_image_any) { _cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL; /* Test pick_filter_image_any: should pick the highest version, which is the directory test_5 */ - ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, pick_filter_image_any, ELEMENTSOF(pick_filter_image_any), PICK_ARCHITECTURE, &result)); + ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, pick_filter_image_any, ELEMENTSOF(pick_filter_image_any), PICK_ARCHITECTURE, &result)); ASSERT_TRUE(S_ISDIR(result.st.st_mode)); ASSERT_STREQ(result.version, "5"); ASSERT_TRUE(endswith(result.path, "/test_5")); @@ -219,14 +219,14 @@ TEST(pick_filter_image_any) { ASSERT_OK(unlinkat(sub_dfd, "test_4", AT_REMOVEDIR)); ASSERT_OK(unlinkat(sub_dfd, "test_5", AT_REMOVEDIR)); - ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, pick_filter_image_any, ELEMENTSOF(pick_filter_image_any), PICK_ARCHITECTURE, &result)); + ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, pick_filter_image_any, ELEMENTSOF(pick_filter_image_any), PICK_ARCHITECTURE, &result)); ASSERT_TRUE(S_ISREG(result.st.st_mode)); ASSERT_STREQ(result.version, "3"); ASSERT_TRUE(endswith(result.path, "/test_3.raw")); pick_result_done(&result); /* Verify that pick_filter_image_raw only matches .raw files */ - ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, pick_filter_image_raw, ELEMENTSOF(pick_filter_image_raw), PICK_ARCHITECTURE, &result)); + ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, pick_filter_image_raw, ELEMENTSOF(pick_filter_image_raw), PICK_ARCHITECTURE, &result)); ASSERT_TRUE(S_ISREG(result.st.st_mode)); ASSERT_STREQ(result.version, "3"); ASSERT_TRUE(endswith(result.path, "/test_3.raw")); @@ -239,12 +239,12 @@ TEST(pick_filter_image_any) { ASSERT_OK(unlinkat(sub_dfd, "test_3.raw", 0)); /* Now only test_10.txt, test_11.img, and test_12 remain - none should match */ - ASSERT_OK_ZERO(path_pick(NULL, AT_FDCWD, pp, pick_filter_image_any, ELEMENTSOF(pick_filter_image_any), PICK_ARCHITECTURE, &result)); + ASSERT_OK_ZERO(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, pick_filter_image_any, ELEMENTSOF(pick_filter_image_any), PICK_ARCHITECTURE, &result)); /* But if we add a directory, it should be picked */ ASSERT_OK(mkdirat(sub_dfd, "test_6", 0755)); - ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, pick_filter_image_any, ELEMENTSOF(pick_filter_image_any), PICK_ARCHITECTURE, &result)); + ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, pick_filter_image_any, ELEMENTSOF(pick_filter_image_any), PICK_ARCHITECTURE, &result)); ASSERT_TRUE(S_ISDIR(result.st.st_mode)); ASSERT_STREQ(result.version, "6"); ASSERT_TRUE(endswith(result.path, "/test_6")); @@ -263,7 +263,7 @@ TEST(pick_filter_image_any) { pick_result_done(&result); - ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, pick_filter_image_dir, ELEMENTSOF(pick_filter_image_dir), PICK_ARCHITECTURE, &result)); + ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, pick_filter_image_dir, ELEMENTSOF(pick_filter_image_dir), PICK_ARCHITECTURE, &result)); ASSERT_TRUE(S_ISDIR(result.st.st_mode)); ASSERT_STREQ(result.version, "2"); ASSERT_TRUE(endswith(result.path, "/myimage_2")); @@ -273,7 +273,7 @@ TEST(pick_filter_image_any) { ASSERT_OK(unlinkat(sub_dfd, "myimage_1", AT_REMOVEDIR)); ASSERT_OK(unlinkat(sub_dfd, "myimage_2", AT_REMOVEDIR)); - ASSERT_OK_ZERO(path_pick(NULL, AT_FDCWD, pp, pick_filter_image_dir, ELEMENTSOF(pick_filter_image_dir), PICK_ARCHITECTURE, &result)); + ASSERT_OK_ZERO(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, pick_filter_image_dir, ELEMENTSOF(pick_filter_image_dir), PICK_ARCHITECTURE, &result)); } TEST(path_pick_resolve) { @@ -294,26 +294,26 @@ TEST(path_pick_resolve) { _cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL; /* Test without PICK_RESOLVE - should return the symlink path */ - ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, pick_filter_image_any, ELEMENTSOF(pick_filter_image_any), PICK_ARCHITECTURE, &result)); + ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, pick_filter_image_any, ELEMENTSOF(pick_filter_image_any), PICK_ARCHITECTURE, &result)); ASSERT_STREQ(result.version, "2"); ASSERT_TRUE(endswith(result.path, "/resolve_2.raw")); pick_result_done(&result); /* Test with PICK_RESOLVE - should return the resolved (target) path */ - ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, pick_filter_image_any, ELEMENTSOF(pick_filter_image_any), PICK_ARCHITECTURE|PICK_RESOLVE, &result)); + ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, pick_filter_image_any, ELEMENTSOF(pick_filter_image_any), PICK_ARCHITECTURE|PICK_RESOLVE, &result)); ASSERT_STREQ(result.version, "2"); ASSERT_TRUE(endswith(result.path, "/target_file.raw")); pick_result_done(&result); /* Test pick_filter_image_dir without PICK_RESOLVE */ - ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, pick_filter_image_dir, ELEMENTSOF(pick_filter_image_dir), PICK_ARCHITECTURE, &result)); + ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, pick_filter_image_dir, ELEMENTSOF(pick_filter_image_dir), PICK_ARCHITECTURE, &result)); ASSERT_TRUE(S_ISDIR(result.st.st_mode)); ASSERT_STREQ(result.version, "1"); ASSERT_TRUE(endswith(result.path, "/resolve_1")); pick_result_done(&result); /* Test pick_filter_image_dir with PICK_RESOLVE */ - ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, pick_filter_image_dir, ELEMENTSOF(pick_filter_image_dir), PICK_ARCHITECTURE|PICK_RESOLVE, &result)); + ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, pick_filter_image_dir, ELEMENTSOF(pick_filter_image_dir), PICK_ARCHITECTURE|PICK_RESOLVE, &result)); ASSERT_TRUE(S_ISDIR(result.st.st_mode)); ASSERT_STREQ(result.version, "1"); ASSERT_TRUE(endswith(result.path, "/target_dir")); @@ -323,12 +323,12 @@ TEST(path_pick_resolve) { ASSERT_OK(symlinkat("target_file.raw", dfd, "intermediate_link.raw")); ASSERT_OK(symlinkat("../intermediate_link.raw", sub_dfd, "resolve_3.raw")); - ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, pick_filter_image_raw, ELEMENTSOF(pick_filter_image_raw), PICK_ARCHITECTURE, &result)); + ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, pick_filter_image_raw, ELEMENTSOF(pick_filter_image_raw), PICK_ARCHITECTURE, &result)); ASSERT_STREQ(result.version, "3"); ASSERT_TRUE(endswith(result.path, "/resolve_3.raw")); pick_result_done(&result); - ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, pp, pick_filter_image_raw, ELEMENTSOF(pick_filter_image_raw), PICK_ARCHITECTURE|PICK_RESOLVE, &result)); + ASSERT_OK_POSITIVE(path_pick(NULL, AT_FDCWD, AT_FDCWD, pp, pick_filter_image_raw, ELEMENTSOF(pick_filter_image_raw), PICK_ARCHITECTURE|PICK_RESOLVE, &result)); ASSERT_STREQ(result.version, "3"); /* The chain should be fully resolved to target_file.raw */ ASSERT_TRUE(endswith(result.path, "/target_file.raw")); diff --git a/src/vpick/vpick-tool.c b/src/vpick/vpick-tool.c index f0b5ef44dfb..85f2b5c1cbb 100644 --- a/src/vpick/vpick-tool.c +++ b/src/vpick/vpick-tool.c @@ -237,8 +237,9 @@ static int run(int argc, char *argv[]) { return log_error_errno(r, "Failed to make path '%s' absolute: %m", *i); _cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL; - r = path_pick(/* toplevel_path= */ NULL, - /* toplevel_fd= */ AT_FDCWD, + r = path_pick(/* root_path= */ NULL, + /* root_fd= */ AT_FDCWD, + /* dir_fd= */ AT_FDCWD, p, &(PickFilter) { .basename = arg_filter_basename,