All of lore.kernel.org
 help / color / mirror / Atom feed
* [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.