]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
tools/nolibc: add fopen()
authorThomas Weißschuh <thomas.weissschuh@linutronix.de>
Mon, 28 Apr 2025 12:40:14 +0000 (14:40 +0200)
committerThomas Weißschuh <linux@weissschuh.net>
Wed, 21 May 2025 13:32:14 +0000 (15:32 +0200)
This is used in various selftests and will be handy when integrating
those with nolibc.

Only the standard POSIX modes are supported.
No extensions nor the (noop) "b" from ISO C are accepted.

Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
Acked-by: Willy Tarreau <w@1wt.eu>
Link: https://lore.kernel.org/r/20250428-nolibc-misc-v2-13-3c043eeab06c@linutronix.de
Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
tools/include/nolibc/stdio.h
tools/testing/selftests/nolibc/nolibc-test.c

index df5717d591826c8468e3473581ac0d6e76629aa3..c470d334ef3f410d0584e01045d380347d61ad95 100644 (file)
@@ -13,6 +13,7 @@
 #include "std.h"
 #include "arch.h"
 #include "errno.h"
+#include "fcntl.h"
 #include "types.h"
 #include "sys.h"
 #include "stdarg.h"
@@ -55,6 +56,32 @@ FILE *fdopen(int fd, const char *mode __attribute__((unused)))
        return (FILE*)(intptr_t)~fd;
 }
 
+static __attribute__((unused))
+FILE *fopen(const char *pathname, const char *mode)
+{
+       int flags, fd;
+
+       switch (*mode) {
+       case 'r':
+               flags = O_RDONLY;
+               break;
+       case 'w':
+               flags = O_WRONLY | O_CREAT | O_TRUNC;
+               break;
+       case 'a':
+               flags = O_WRONLY | O_CREAT | O_APPEND;
+               break;
+       default:
+               SET_ERRNO(EINVAL); return NULL;
+       }
+
+       if (mode[1] == '+')
+               flags = (flags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
+
+       fd = open(pathname, flags, 0666);
+       return fdopen(fd, mode);
+}
+
 /* provides the fd of stream. */
 static __attribute__((unused))
 int fileno(FILE *stream)
index d1157319b5d715dbc94ff9203b1d2a2e932aabcf..0391c7d01380ea2f20d1d07497ea1964bcb6a9f4 100644 (file)
@@ -859,6 +859,29 @@ int test_getpagesize(void)
        return !c;
 }
 
+int test_file_stream(void)
+{
+       FILE *f;
+       int r;
+
+       f = fopen("/dev/null", "r");
+       if (!f)
+               return -1;
+
+       errno = 0;
+       r = fwrite("foo", 1, 3, f);
+       if (r != 0 || errno != EBADF) {
+               fclose(f);
+               return -1;
+       }
+
+       r = fclose(f);
+       if (r == EOF)
+               return -1;
+
+       return 0;
+}
+
 int test_fork(void)
 {
        int status;
@@ -1311,6 +1334,7 @@ int run_syscall(int min, int max)
                CASE_TEST(dup3_0);            tmp = dup3(0, 100, 0);  EXPECT_SYSNE(1, tmp, -1); close(tmp); break;
                CASE_TEST(dup3_m1);           tmp = dup3(-1, 100, 0); EXPECT_SYSER(1, tmp, -1, EBADF); if (tmp != -1) close(tmp); break;
                CASE_TEST(execve_root);       EXPECT_SYSER(1, execve("/", (char*[]){ [0] = "/", [1] = NULL }, NULL), -1, EACCES); break;
+               CASE_TEST(file_stream);       EXPECT_SYSZR(1, test_file_stream()); break;
                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;