* [PATCH v2 0/2] tools/nolibc: add support for directory access
@ 2025-02-09 13:25 Thomas Weißschuh
2025-02-09 13:25 ` [PATCH v2 1/2] tools/nolibc: add support for sys_llseek() Thomas Weißschuh
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Thomas Weißschuh @ 2025-02-09 13:25 UTC (permalink / raw)
To: Willy Tarreau, Shuah Khan
Cc: linux-kernel, linux-kselftest, Thomas Weißschuh,
Thomas Weißschuh
Add support opendir(), readdir_r(), closedir() and friends.
Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
---
Changes in v2:
- Move definitions to dirent.h
- Reserve space for the trailing NULL byte of d_name
- Implement readdir_r() instead of readdir()
- Expand commit message
- Link to v1: https://lore.kernel.org/r/20250130-nolibc-dir-v1-0-ea9950b52e29@weissschuh.net
---
Thomas Weißschuh (2):
tools/nolibc: add support for sys_llseek()
tools/nolibc: add support for directory access
tools/include/nolibc/Makefile | 1 +
tools/include/nolibc/dirent.h | 98 ++++++++++++++++++++++++++++
tools/include/nolibc/nolibc.h | 1 +
tools/include/nolibc/sys.h | 29 +++++++-
tools/testing/selftests/nolibc/nolibc-test.c | 39 +++++++++++
5 files changed, 167 insertions(+), 1 deletion(-)
---
base-commit: c1f4a7a84037249d086a4114c0c4332a260e9091
change-id: 20250130-nolibc-dir-980c2e2b661a
Best regards,
--
Thomas Weißschuh <linux@weissschuh.net>
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 1/2] tools/nolibc: add support for sys_llseek()
2025-02-09 13:25 [PATCH v2 0/2] tools/nolibc: add support for directory access Thomas Weißschuh
@ 2025-02-09 13:25 ` Thomas Weißschuh
2025-02-09 13:25 ` [PATCH v2 2/2] tools/nolibc: add support for directory access Thomas Weißschuh
2025-02-09 15:43 ` [PATCH v2 0/2] " Willy Tarreau
2 siblings, 0 replies; 4+ messages in thread
From: Thomas Weißschuh @ 2025-02-09 13:25 UTC (permalink / raw)
To: Willy Tarreau, Shuah Khan
Cc: linux-kernel, linux-kselftest, Thomas Weißschuh,
Thomas Weißschuh
From: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
Not all architectures have the old sys_lseek(), notably riscv32.
Implement lseek() in terms of sys_llseek() in that case.
Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
---
tools/include/nolibc/sys.h | 29 ++++++++++++++++++++++++++++-
1 file changed, 28 insertions(+), 1 deletion(-)
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h
index 8c0a55bc9dc3aacd110db0195975fe4f85480fc5..8f44c33b121300e80b41c971019484007d050b17 100644
--- a/tools/include/nolibc/sys.h
+++ b/tools/include/nolibc/sys.h
@@ -597,10 +597,37 @@ off_t sys_lseek(int fd, off_t offset, int whence)
#endif
}
+static __attribute__((unused))
+int sys_llseek(int fd, unsigned long offset_high, unsigned long offset_low,
+ __kernel_loff_t *result, int whence)
+{
+#ifdef __NR_llseek
+ return my_syscall5(__NR_llseek, fd, offset_high, offset_low, result, whence);
+#else
+ return __nolibc_enosys(__func__, fd, offset_high, offset_low, result, whence);
+#endif
+}
+
static __attribute__((unused))
off_t lseek(int fd, off_t offset, int whence)
{
- return __sysret(sys_lseek(fd, offset, whence));
+ __kernel_loff_t loff = 0;
+ off_t result;
+ int ret;
+
+ result = sys_lseek(fd, offset, whence);
+ if (result == -ENOSYS) {
+ /* Only exists on 32bit where nolibc off_t is also 32bit */
+ ret = sys_llseek(fd, 0, offset, &loff, whence);
+ if (ret < 0)
+ result = ret;
+ else if (loff != (off_t)loff)
+ result = -EOVERFLOW;
+ else
+ result = loff;
+ }
+
+ return __sysret(result);
}
--
2.48.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v2 2/2] tools/nolibc: add support for directory access
2025-02-09 13:25 [PATCH v2 0/2] tools/nolibc: add support for directory access Thomas Weißschuh
2025-02-09 13:25 ` [PATCH v2 1/2] tools/nolibc: add support for sys_llseek() Thomas Weißschuh
@ 2025-02-09 13:25 ` Thomas Weißschuh
2025-02-09 15:43 ` [PATCH v2 0/2] " Willy Tarreau
2 siblings, 0 replies; 4+ messages in thread
From: Thomas Weißschuh @ 2025-02-09 13:25 UTC (permalink / raw)
To: Willy Tarreau, Shuah Khan
Cc: linux-kernel, linux-kselftest, Thomas Weißschuh,
Thomas Weißschuh
From: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
Add an implementation for directory access operations.
To keep nolibc itself allocation-free, a "DIR *" does not point to any
data, but directly encodes a filedescriptor number, equivalent to "FILE *".
Without any per-directory storage it is not possible to implement
readdir() POSIX confirming. Instead only readdir_r() is provided.
While readdir_r() is deprecated in glibc, the reasons for that are
not applicable to nolibc.
Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
---
tools/include/nolibc/Makefile | 1 +
tools/include/nolibc/dirent.h | 98 ++++++++++++++++++++++++++++
tools/include/nolibc/nolibc.h | 1 +
tools/testing/selftests/nolibc/nolibc-test.c | 39 +++++++++++
4 files changed, 139 insertions(+)
diff --git a/tools/include/nolibc/Makefile b/tools/include/nolibc/Makefile
index a1f55fb24bb38c1f49c653af5825e8bcc569a56d..dceec0e1a135119108d6f4dcb3d2ec57c002ffd3 100644
--- a/tools/include/nolibc/Makefile
+++ b/tools/include/nolibc/Makefile
@@ -29,6 +29,7 @@ all_files := \
compiler.h \
crt.h \
ctype.h \
+ dirent.h \
errno.h \
nolibc.h \
signal.h \
diff --git a/tools/include/nolibc/dirent.h b/tools/include/nolibc/dirent.h
new file mode 100644
index 0000000000000000000000000000000000000000..c5c30d0dd6806b1bec2fa8120a3df29aaa201393
--- /dev/null
+++ b/tools/include/nolibc/dirent.h
@@ -0,0 +1,98 @@
+/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
+/*
+ * Directory access for NOLIBC
+ * Copyright (C) 2025 Thomas Weißschuh <linux@weissschuh.net>
+ */
+
+#ifndef _NOLIBC_DIRENT_H
+#define _NOLIBC_DIRENT_H
+
+#include "stdint.h"
+#include "types.h"
+
+#include <linux/limits.h>
+
+struct dirent {
+ ino_t d_ino;
+ char d_name[NAME_MAX + 1];
+};
+
+/* See comment of FILE in stdio.h */
+typedef struct {
+ char dummy[1];
+} DIR;
+
+static __attribute__((unused))
+DIR *fdopendir(int fd)
+{
+ if (fd < 0) {
+ SET_ERRNO(EBADF);
+ return NULL;
+ }
+ return (DIR *)(intptr_t)~fd;
+}
+
+static __attribute__((unused))
+DIR *opendir(const char *name)
+{
+ int fd;
+
+ fd = open(name, O_RDONLY);
+ if (fd == -1)
+ return NULL;
+ return fdopendir(fd);
+}
+
+static __attribute__((unused))
+int closedir(DIR *dirp)
+{
+ intptr_t i = (intptr_t)dirp;
+
+ if (i >= 0) {
+ SET_ERRNO(EBADF);
+ return -1;
+ }
+ return close(~i);
+}
+
+static __attribute__((unused))
+int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
+{
+ char buf[sizeof(struct linux_dirent64) + NAME_MAX + 1];
+ struct linux_dirent64 *ldir = (void *)buf;
+ intptr_t i = (intptr_t)dirp;
+ int fd, ret;
+
+ if (i >= 0)
+ return EBADF;
+
+ fd = ~i;
+
+ ret = sys_getdents64(fd, ldir, sizeof(buf));
+ if (ret < 0)
+ return -ret;
+ if (ret == 0) {
+ *result = NULL;
+ return 0;
+ }
+
+ /*
+ * getdents64() returns as many entries as fit the buffer.
+ * readdir() can only return one entry at a time.
+ * Make sure the non-returned ones are not skipped.
+ */
+ ret = lseek(fd, ldir->d_off, SEEK_SET);
+ if (ret == -1)
+ return errno;
+
+ entry->d_ino = ldir->d_ino;
+ /* the destination should always be big enough */
+ strlcpy(entry->d_name, ldir->d_name, sizeof(entry->d_name));
+ *result = entry;
+ return 0;
+}
+
+/* make sure to include all global symbols */
+#include "nolibc.h"
+
+#endif /* _NOLIBC_DIRENT_H */
diff --git a/tools/include/nolibc/nolibc.h b/tools/include/nolibc/nolibc.h
index 92436b1e44413e659b3cca592930aad8b458cb74..05d92afedb7258f0e3c311bf6f12be68b25d6e9a 100644
--- a/tools/include/nolibc/nolibc.h
+++ b/tools/include/nolibc/nolibc.h
@@ -105,6 +105,7 @@
#include "string.h"
#include "time.h"
#include "stackprotector.h"
+#include "dirent.h"
/* Used by programs to avoid std includes */
#define NOLIBC
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
index f162793b162f9b1ec687098b9094a6d247a53e99..798fbdcd3ff8c36b514feb3fa1c7b8d7701cccd7 100644
--- a/tools/testing/selftests/nolibc/nolibc-test.c
+++ b/tools/testing/selftests/nolibc/nolibc-test.c
@@ -769,6 +769,44 @@ int test_getdents64(const char *dir)
return ret;
}
+static int test_dirent(void)
+{
+ int comm = 0, cmdline = 0;
+ struct dirent dirent, *result;
+ DIR *dir;
+ int ret;
+
+ dir = opendir("/proc/self");
+ if (!dir)
+ return 1;
+
+ while (1) {
+ errno = 0;
+ ret = readdir_r(dir, &dirent, &result);
+ if (ret != 0)
+ return 1;
+ if (!result)
+ break;
+
+ if (strcmp(dirent.d_name, "comm") == 0)
+ comm++;
+ else if (strcmp(dirent.d_name, "cmdline") == 0)
+ cmdline++;
+ }
+
+ if (errno)
+ return 1;
+
+ ret = closedir(dir);
+ if (ret)
+ return 1;
+
+ if (comm != 1 || cmdline != 1)
+ return 1;
+
+ return 0;
+}
+
int test_getpagesize(void)
{
int x = getpagesize();
@@ -1061,6 +1099,7 @@ int run_syscall(int min, int max)
CASE_TEST(fork); EXPECT_SYSZR(1, test_fork()); break;
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(proc, test_dirent()); break;
CASE_TEST(gettimeofday_tv); EXPECT_SYSZR(1, gettimeofday(&tv, NULL)); break;
CASE_TEST(gettimeofday_tv_tz);EXPECT_SYSZR(1, gettimeofday(&tv, &tz)); break;
CASE_TEST(getpagesize); EXPECT_SYSZR(1, test_getpagesize()); break;
--
2.48.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v2 0/2] tools/nolibc: add support for directory access
2025-02-09 13:25 [PATCH v2 0/2] tools/nolibc: add support for directory access Thomas Weißschuh
2025-02-09 13:25 ` [PATCH v2 1/2] tools/nolibc: add support for sys_llseek() Thomas Weißschuh
2025-02-09 13:25 ` [PATCH v2 2/2] tools/nolibc: add support for directory access Thomas Weißschuh
@ 2025-02-09 15:43 ` Willy Tarreau
2 siblings, 0 replies; 4+ messages in thread
From: Willy Tarreau @ 2025-02-09 15:43 UTC (permalink / raw)
To: Thomas Weißschuh
Cc: Shuah Khan, linux-kernel, linux-kselftest, Thomas Weißschuh
On Sun, Feb 09, 2025 at 02:25:44PM +0100, Thomas Weißschuh wrote:
> Add support opendir(), readdir_r(), closedir() and friends.
>
> Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
> ---
> Changes in v2:
> - Move definitions to dirent.h
> - Reserve space for the trailing NULL byte of d_name
> - Implement readdir_r() instead of readdir()
> - Expand commit message
> - Link to v1: https://lore.kernel.org/r/20250130-nolibc-dir-v1-0-ea9950b52e29@weissschuh.net
Nice!
Acked-by: Willy Tarreau <w@1wt.eu>
Willy
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2025-02-09 15:55 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-09 13:25 [PATCH v2 0/2] tools/nolibc: add support for directory access Thomas Weißschuh
2025-02-09 13:25 ` [PATCH v2 1/2] tools/nolibc: add support for sys_llseek() Thomas Weißschuh
2025-02-09 13:25 ` [PATCH v2 2/2] tools/nolibc: add support for directory access Thomas Weißschuh
2025-02-09 15:43 ` [PATCH v2 0/2] " Willy Tarreau
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.