logo

utils-std

Collection of commonly available Unix tools git clone https://anongit.hacktivis.me/git/utils-std.git/
commit: 69cbb114a926327ac256e2007d4208ba734e1fad
parent 51df2fb18fab83c6ccae6e4ddeb9e00b40740e64
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Thu,  5 Feb 2026 11:37:55 +0100

cmd/tee: Use read/write instead of fgetc/fputc

Prevents buffering of the output (short read means immediate write)
and potentially increase performance (reduced processing,
better buffer size).

Diffstat:

Mcmd/tee.c43+++++++++++++++++++++++++++----------------
1 file changed, 27 insertions(+), 16 deletions(-)

diff --git a/cmd/tee.c b/cmd/tee.c @@ -8,8 +8,9 @@ #include <assert.h> /* assert() */ #include <errno.h> /* errno */ +#include <fcntl.h> #include <signal.h> /* signal() */ -#include <stdio.h> /* fprintf(), fgetc(), fputc(), fclose(), fopen() */ +#include <stdio.h> /* fprintf() */ #include <stdlib.h> /* calloc(), free(), abort() */ #include <string.h> /* strerror() */ #include <unistd.h> /* getopt(), opt… */ @@ -20,19 +21,16 @@ const char *argv0 = "tee"; static void -cleanup(FILE **fds) +cleanup(int *fds) { - if(fds != NULL) - { - free(fds); - } + free(fds); } int main(int argc, char *argv[]) { - const char *mode = "w"; - FILE **fds = {NULL}; // Shut up GCC + mode_t mode = O_WRONLY | O_NOCTTY | O_CREAT; + int *fds = NULL; int c; #ifdef HAS_GETOPT_LONG @@ -54,7 +52,7 @@ main(int argc, char *argv[]) switch(c) { case 'a': - mode = "a"; + mode |= O_APPEND; break; case 'i': /* ignore SIGINT */; signal(SIGINT, SIG_IGN); @@ -88,9 +86,9 @@ main(int argc, char *argv[]) assert(argv[argi]); // POSIX: implementations shouldn't treat '-' as stdin - fds[argi] = fopen(argv[argi], mode); + fds[argi] = open(argv[argi], mode); - if(fds[argi] == NULL) + if(fds[argi] < 0) { fprintf(stderr, "tee: error: Failed opening file ‘%s’: %s\n", argv[argi], strerror(errno)); cleanup(fds); @@ -101,9 +99,21 @@ main(int argc, char *argv[]) // main loop, note that failed writes shouldn't make tee exit int err = 0; - while((c = fgetc(stdin)) != EOF) + while(true) { - if(fputc(c, stdout) == EOF) + static char buf[BUFSIZ]; + ssize_t sread = read(STDIN_FILENO, buf, sizeof(buf)); + if(sread == 0) break; + if(sread < 0) + { + fprintf(stderr, "tee: error: Failed reading from stdin: %s\n", strerror(errno)); + cleanup(fds); + return 1; + } + + size_t nread = (size_t)sread; + + if(write(STDOUT_FILENO, buf, nread) < 0) { fprintf(stderr, "tee: error: Failed writing to stdout: %s\n", strerror(errno)); err = 1; @@ -112,9 +122,10 @@ main(int argc, char *argv[]) for(int argi = 0; argi < argc; argi++) { - if(fputc(c, fds[argi]) == EOF) + if(write(fds[argi], buf, nread) < 0) { - fprintf(stderr, "tee: error: Failed writing to argument %d: %s\n", argi, strerror(errno)); + fprintf( + stderr, "tee: error: Failed writing to file '%s': %s\n", argv[argi], strerror(errno)); err = 1; errno = 0; } @@ -124,7 +135,7 @@ main(int argc, char *argv[]) // cleanup for(int argi = 0; argi < argc; argi++) { - if(fclose(fds[argi]) != 0) + if(close(fds[argi]) != 0) { fprintf(stderr, "tee: error: Failed closing file '%s': %s\n", argv[argi], strerror(errno)); err++;