From 488e1398da6a15b70399d52346b05d9770db4732 Mon Sep 17 00:00:00 2001 From: Carl Edquist Date: Sat, 10 Dec 2022 09:31:03 -0600 Subject: [PATCH] tee: only do iopoll for pipe outputs We can skip the broken-pipe detection for file types other than pipes. Sockets behave similarly to pipes in some ways, but the semantics appear to be different in important ways, such that poll() doesn't detect when the remote read end is closed. * src/tee.c (is_pipe): add helper function detecting if fd is a pipe. * (tee_files): populate out_is_pipe bool array corresponding to whether items in descriptors array are pipes, only do pipe_check/iopoll() logic for a given output if it is a pipe. --- src/tee.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/tee.c b/src/tee.c index b254466..482967a 100644 --- a/src/tee.c +++ b/src/tee.c @@ -276,6 +276,15 @@ fail_output(FILE **descriptors, char **files, int i) return fail; } +/* Return true if fd refers to a pipe */ + +static bool +is_pipe(int fd) +{ + struct stat st; + return fstat (fd, &st) == 0 && S_ISFIFO(st.st_mode); +} + /* Copy the standard input into each of the NFILES files in FILES and into the standard output. As a side effect, modify FILES[-1]. Return true if successful. */ @@ -285,6 +294,7 @@ tee_files (int nfiles, char **files) { size_t n_outputs = 0; FILE **descriptors; + bool *out_is_pipe; char buffer[BUFSIZ]; ssize_t bytes_read = 0; int i; @@ -303,8 +313,10 @@ tee_files (int nfiles, char **files) In both arrays, entry 0 corresponds to standard output. */ descriptors = xnmalloc (nfiles + 1, sizeof *descriptors); + out_is_pipe = xnmalloc (nfiles + 1, sizeof *out_is_pipe); files--; descriptors[0] = stdout; + out_is_pipe[0] = is_pipe (fileno (descriptors[0])); files[0] = bad_cast (_("standard output")); setvbuf (stdout, NULL, _IONBF, 0); n_outputs++; @@ -313,6 +325,7 @@ tee_files (int nfiles, char **files) { /* Do not treat "-" specially - as mandated by POSIX. */ descriptors[i] = fopen (files[i], mode_string); + out_is_pipe[i] = is_pipe (fileno (descriptors[i])); if (descriptors[i] == NULL) { error (output_error == output_error_exit @@ -329,7 +342,7 @@ tee_files (int nfiles, char **files) while (n_outputs) { - if (pipe_check) + if (pipe_check && out_is_pipe[first_out]) { int err = iopoll (STDIN_FILENO, fileno (descriptors[first_out])); @@ -384,6 +397,7 @@ tee_files (int nfiles, char **files) } free (descriptors); + free (out_is_pipe); return ok; } -- 2.9.0