]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
vpick: take separate root_fd and dir_fd arguments
authorLennart Poettering <lennart@amutable.com>
Thu, 28 May 2026 10:37:39 +0000 (12:37 +0200)
committerLennart Poettering <lennart@amutable.com>
Wed, 24 Jun 2026 10:59:55 +0000 (12:59 +0200)
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.

src/core/exec-invoke.c
src/core/namespace.c
src/portable/portable.c
src/shared/discover-image.c
src/shared/mstack.c
src/shared/vpick.c
src/shared/vpick.h
src/test/test-vpick.c
src/vpick/vpick-tool.c

index a06852a6b5ffafeff2cf9ae93fadbb0e9ade2e7f..c45c807198d6b9ed1d138d315063cc6fe656a504 100644 (file)
@@ -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,
index a6ba2659e429056ee9b2525dceb9b0f3d14c3ff0..3fc0a8652db7a008ca3bc5bd1f4ddb63a745446b 100644 (file)
@@ -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),
index a98c1162d95e78545968ddfb300e1e4e1b8ccf2d..9d510118be284030f2d6fa7297832e1e9529b148 100644 (file)
@@ -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),
index 0410b523baafd678ff11935e9cae2f6559f42065..9994ff5da451e781ce881ba12005584fc27336e8 100644 (file)
@@ -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,
index cc3cb9a75f7cbae5a4eb0b20c7ff486fab5712f5..65f38ba3b3df2a16da2362a871f1beb8e9dfd6a8 100644 (file)
@@ -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)
index 7890fb1708830b2db3b5feb4fdcd99684b43eab1..c661f92fafc95d25628cee9f16baebbc7bc8dfff 100644 (file)
@@ -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,
index 55596d24dfe0fe1980307d5d36ed696250681e68..de67cbe35384d2fa24f5c506af47cf9d0da77c23 100644 (file)
@@ -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,
index 400380b5754f39f45b96c7d420a3e466850f8e6c..6fea29e594ca644dd42fb230430daa2c3894c09f 100644 (file)
@@ -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"));
index f0b5ef44dfb67ddd9342b335072a827fba1c402f..85f2b5c1cbb379d546a81b6fcdd706a97dc746b4 100644 (file)
@@ -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,