[PATCH] input: Fix tee(2) error handling

Herbert Xu <[email protected]> Sun, 3 May 2026 12:19:16 +0800
Newsgroups org.kernel.vger.dash
Message-ID <[email protected]>
Matt Whitlock <[email protected]> wrote:
> Dash 0.5.13.3:
> 
> $ /bin/dash -c '{ echo 1; sleep 1; echo 2; } | while read -r line; do echo "${line}" & done'
> 1
> ^C

Thanks, this is a regression in the tee error handling code:

---8<---
The variable fd should only switch to the tee pipe if the tee(2)
call succeeded, otherwise the retry will read the wrong file
descriptor.

Also remove the stdin_istty check in stdin_tee as the fallback
path now requries setting errno to EINVAL.  Instead of optimising
for the rare case of a non-canonical input tty, just let the
tee(2) call fail instead.

Finally switch from pipe to sh_pipe.  The pipe(2) call should never
fail, and if it does, just abort the shell.

Fixes: 41457be81fa7 ("input: Fix EINTR handling when reading from a pipe")
Reported-by: Matt Whitlock <[email protected]>
Signed-off-by: Herbert Xu <[email protected]>

diff --git a/src/input.c b/src/input.c
index 4e30010..591f28a 100644
--- a/src/input.c
+++ b/src/input.c
@@ -166,13 +166,8 @@ static int stdin_tee(void *buf, int nr)
 {
 	int err;
 
-	if (stdin_istty)
-		return 0;
-
 	if (!stdin_state.pip[0]) {
-		err = pipe(stdin_state.pip);
-		if (err < 0)
-			return err;
+		sh_pipe(stdin_state.pip, 0);
 		if (stdin_state.pip[0] < 10)
 			stdin_state.pip[0] = savefd(stdin_state.pip[0],
 						    stdin_state.pip[0]);
@@ -276,6 +271,7 @@ preadfd(void)
 {
 	char *buf = parsefile->buf;
 	int fd = parsefile->fd;
+	bool use_tee;
 	int unget;
 	int pnr;
 	int nr;
@@ -295,6 +291,12 @@ preadfd(void)
 	if (!IS_DEFINED_SMALL && !nr)
 		return nr;
 
+	use_tee = likely(!fd) &&
+#ifndef SMALL
+		  !el &&
+#endif
+		  !stdin_bufferable();
+
 	pnr = nr;
 retry:
 	nr = pnr;
@@ -326,12 +328,13 @@ retry:
 	}
 #endif
 
-	if (!fd && !stdin_bufferable()) {
+	if (likely(use_tee)) {
 		nr = stdin_tee(buf, nr);
-		fd = stdin_state.pip[0];
-		if (nr < 0 && errno == EINVAL) {
-			fd = 0;
-			nr = 1;
+		if (nr >= 0)
+			fd = stdin_state.pip[0];
+		else if (errno == EINVAL) {
+			use_tee = false;
+			nr = pnr = 1;
 		}
 	}
 
-- 
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt