tools/nolibc: implement fd-based FILE streams
authorThomas Weißschuh <linux@weissschuh.net>
Sun, 2 Apr 2023 18:48:05 +0000 (20:48 +0200)
committerPaul E. McKenney <paulmck@kernel.org>
Fri, 9 Jun 2023 18:33:05 +0000 (11:33 -0700)
This enables the usage of the stream APIs with arbitrary filedescriptors.

It will be used by a future testcase.

Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
Signed-off-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
tools/include/nolibc/stdio.h

index 6cbbb52836a00f74286a900196c962ccaec333db..0eef91daf2898b33e2df8884cbcd22a6f238226a 100644 (file)
 #define EOF (-1)
 #endif
 
-/* just define FILE as a non-empty type */
+/* just define FILE as a non-empty type. The value of the pointer gives
+ * the FD: FILE=~fd for fd>=0 or NULL for fd<0. This way positive FILE
+ * are immediately identified as abnormal entries (i.e. possible copies
+ * of valid pointers to something else).
+ */
 typedef struct FILE {
        char dummy[1];
 } FILE;
 
-/* We define the 3 common stdio files as constant invalid pointers that
- * are easily recognized.
- */
-static __attribute__((unused)) FILE* const stdin  = (FILE*)-3;
-static __attribute__((unused)) FILE* const stdout = (FILE*)-2;
-static __attribute__((unused)) FILE* const stderr = (FILE*)-1;
+static __attribute__((unused)) FILE* const stdin  = (FILE*)(intptr_t)~STDIN_FILENO;
+static __attribute__((unused)) FILE* const stdout = (FILE*)(intptr_t)~STDOUT_FILENO;
+static __attribute__((unused)) FILE* const stderr = (FILE*)(intptr_t)~STDERR_FILENO;
+
+/* provides a FILE* equivalent of fd. The mode is ignored. */
+static __attribute__((unused))
+FILE *fdopen(int fd, const char *mode __attribute__((unused)))
+{
+       if (fd < 0) {
+               SET_ERRNO(EBADF);
+               return NULL;
+       }
+       return (FILE*)(intptr_t)~fd;
+}
+
+/* provides the fd of stream. */
+static __attribute__((unused))
+int fileno(FILE *stream)
+{
+       intptr_t i = (intptr_t)stream;
+
+       if (i >= 0) {
+               SET_ERRNO(EBADF);
+               return -1;
+       }
+       return ~i;
+}
+
+/* flush a stream. */
+static __attribute__((unused))
+int fflush(FILE *stream)
+{
+       intptr_t i = (intptr_t)stream;
+
+       /* NULL is valid here. */
+       if (i > 0) {
+               SET_ERRNO(EBADF);
+               return -1;
+       }
+
+       /* Don't do anything, nolibc does not support buffering. */
+       return 0;
+}
+
+/* flush a stream. */
+static __attribute__((unused))
+int fclose(FILE *stream)
+{
+       intptr_t i = (intptr_t)stream;
+
+       if (i >= 0) {
+               SET_ERRNO(EBADF);
+               return -1;
+       }
+
+       if (close(~i))
+               return EOF;
+
+       return 0;
+}
 
 /* getc(), fgetc(), getchar() */
 
@@ -41,14 +99,8 @@ static __attribute__((unused))
 int fgetc(FILE* stream)
 {
        unsigned char ch;
-       int fd;
 
-       if (stream < stdin || stream > stderr)
-               return EOF;
-
-       fd = 3 + (long)stream;
-
-       if (read(fd, &ch, 1) <= 0)
+       if (read(fileno(stream), &ch, 1) <= 0)
                return EOF;
        return ch;
 }
@@ -68,14 +120,8 @@ static __attribute__((unused))
 int fputc(int c, FILE* stream)
 {
        unsigned char ch = c;
-       int fd;
-
-       if (stream < stdin || stream > stderr)
-               return EOF;
-
-       fd = 3 + (long)stream;
 
-       if (write(fd, &ch, 1) <= 0)
+       if (write(fileno(stream), &ch, 1) <= 0)
                return EOF;
        return ch;
 }
@@ -96,12 +142,7 @@ static __attribute__((unused))
 int _fwrite(const void *buf, size_t size, FILE *stream)
 {
        ssize_t ret;
-       int fd;
-
-       if (stream < stdin || stream > stderr)
-               return EOF;
-
-       fd = 3 + (long)stream;
+       int fd = fileno(stream);
 
        while (size) {
                ret = write(fd, buf, size);