summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorPádraig Brady <P@draigBrady.com>2023-03-05 15:51:32 +0000
committerPádraig Brady <P@draigBrady.com>2023-03-08 18:32:05 +0000
commit16000805eb1bcdf25360471b8bbc8ec3f025e035 (patch)
tree62f3c3de4d34462cac20967433b827bc4cf9cb1e /tests
parent176b74f0e7360d94450c5aa3cf7db2ab86ed28c8 (diff)
downloadcoreutils-16000805eb1bcdf25360471b8bbc8ec3f025e035.tar.gz
tee: support non blocking outputs
Non blocking outputs can be seen for example when piping telnet through tee to a terminal. In that case telnet sets its input to nonblocking mode, which results in tee's output being nonblocking, in which case in may receive an EAGAIN error upon write(). The same issue was seen with mpirun. The following can be used to reproduce this locally at a terminal (in most invocations): $ { dd iflag=nonblock count=0 status=none; dd bs=10K count=10 if=/dev/zero status=none; } | tee || echo fail >/dev/tty * src/iopoll.c (iopoll_internal): A new function refactored from iopoll(), to also support a mode where we check the output descriptor is writeable. (iopoll): Now refactored to just call iopoll_internal(). (fwait_for_nonblocking_write): A new internal function which uses iopoll_internal() to wait for writeable output if an EAGAIN or EWOULDBLOCK was received. (fwrite_nonblock): An fwrite() wrapper which uses fwait_for_nonblocking_write() to handle EAGAIN. (fclose_nonblock): Likewise. src/iopoll.h: Add fclose_nonblock, fwrite_nonblock. src/tee.c: Call fclose_nonblock() and fwrite_nonblock wrappers, instead of the standard functions. * tests/misc/tee.sh: Add a test case. * NEWS: Mention the improvement. The idea was suggested by Kamil Dudka in https://bugzilla.redhat.com/1615467
Diffstat (limited to 'tests')
-rwxr-xr-xtests/misc/tee.sh17
1 files changed, 16 insertions, 1 deletions
diff --git a/tests/misc/tee.sh b/tests/misc/tee.sh
index 63e7524c0..ce0cfd41d 100755
--- a/tests/misc/tee.sh
+++ b/tests/misc/tee.sh
@@ -79,8 +79,23 @@ touch file.ro || framework_failure_
chmod a-w file.ro || framework_failure_
returns_ 1 tee -p </dev/null file.ro || fail=1
-# Ensure tee honors --output-error modes
mkfifo_or_skip_ fifo
+
+# Ensure tee handles nonblocking output correctly
+# Terminate any background processes
+cleanup_() { kill $pid 2>/dev/null && wait $pid; }
+read_fifo_delayed() {
+ { sleep .1; timeout 10 dd of=/dev/null status=none; } <fifo
+}
+read_fifo_delayed & pid=$!
+dd count=20 bs=100K if=/dev/zero status=none |
+{
+ dd count=0 oflag=nonblock status=none
+ tee || { cleanup_; touch tee.fail; }
+} >fifo
+test -f tee.fail && fail=1
+
+# Ensure tee honors --output-error modes
read_fifo() { timeout 10 dd count=1 if=fifo of=/dev/null status=none & }
# Determine platform sigpipe exit status