[PATCH v3 3/3] selftests/nolibc: Add test for dirfd()

From: Daniel Palmer

Date: Sat Oct 31 2026 - 00:30:56 EST


Test that open() and dirfd() use the same fd and then use dirfd()
with fstatat() to stat one of its children.

The test only runs for the nolibc build because it uses readdir_r()
which is overridden to force a failure in the libc build.

Signed-off-by: Daniel Palmer <daniel@xxxxxxxxx>
---
tools/testing/selftests/nolibc/nolibc-test.c | 40 ++++++++++++++++++++
1 file changed, 40 insertions(+)

diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
index f3d0d27cdbe1..648a539fb42a 100644
--- a/tools/testing/selftests/nolibc/nolibc-test.c
+++ b/tools/testing/selftests/nolibc/nolibc-test.c
@@ -859,6 +859,45 @@ static int test_dirent(void)
return 0;
}

+static int test_dirfd(void)
+{
+ struct dirent dirent, *result;
+ int ret = 0, fd;
+ struct stat st;
+ DIR *dir;
+
+ fd = open("/", O_RDONLY | O_DIRECTORY);
+ if (fd < 0)
+ return __LINE__;
+
+ dir = fdopendir(fd);
+ if (!dir) {
+ close(fd);
+ return __LINE__;
+ }
+
+ /* Check that dirfd() gives the same fd as open() */
+ if (dirfd(dir) != fd) {
+ ret = __LINE__;
+ goto out;
+ }
+
+ /* Get the name of a child of dir */
+ if (readdir_r(dir, &dirent, &result) != 0 || !result) {
+ ret = __LINE__;
+ goto out;
+ }
+
+ /* stat the child relative to dir */
+ if (fstatat(dirfd(dir), dirent.d_name, &st, AT_SYMLINK_NOFOLLOW) != 0)
+ ret = __LINE__;
+
+out:
+ closedir(dir);
+
+ return ret;
+}
+
int test_getcwd(void)
{
char cwd_syscall[PATH_MAX];
@@ -1764,6 +1803,7 @@ int run_syscall(int min, int max)
CASE_TEST(getdents64_root); EXPECT_SYSNE(1, test_getdents64("/"), -1); break;
CASE_TEST(getdents64_null); EXPECT_SYSER(1, test_getdents64("/dev/null"), -1, ENOTDIR); break;
CASE_TEST(directories); EXPECT_SYSZR(is_nolibc && proc, test_dirent()); break;
+ CASE_TEST(dirfd); EXPECT_SYSZR(is_nolibc, test_dirfd()); break;
CASE_TEST(getrandom); EXPECT_SYSZR(1, test_getrandom()); break;
CASE_TEST(gettimeofday_tv); EXPECT_SYSZR(1, gettimeofday(&tv, NULL)); break;
CASE_TEST(gettimeofday_tv_tz);EXPECT_SYSZR(1, gettimeofday(&tv, &tz)); break;
--
2.53.0