dd: don’t trust st_size on /proc/files
[coreutils.git] / tests / misc / tee.sh
blob862ef2b9545beba49026849c0cc93d56dc4e050b
1 #!/bin/sh
2 # test for basic tee functionality.
4 # Copyright (C) 2005-2024 Free Software Foundation, Inc.
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <https://www.gnu.org/licenses/>.
19 . "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
20 print_ver_ tee
22 echo line >sample || framework_failure_
24 # POSIX says: "Processing of at least 13 file operands shall be supported."
25 for n in 0 1 2 12 13; do
26 files=$(seq $n)
27 rm -f $files
28 tee $files <sample >out || fail=1
29 for f in out $files; do
30 compare sample $f || fail=1
31 done
32 done
34 # Ensure tee treats '-' as the name of a file, as mandated by POSIX.
35 # Between v5.3.0 and v8.23, a '-' argument caused tee to send another
36 # copy of input to standard output.
37 tee - <sample >out 2>err || fail=1
38 compare sample ./- || fail=1
39 compare sample out || fail=1
40 compare /dev/null err || fail=1
42 # Ensure tee exits early if no more writable outputs
43 if test -w /dev/full && test -c /dev/full; then
44 yes | returns_ 1 timeout 10 tee /dev/full 2>err >/dev/full || fail=1
45 # Ensure an error for each of the 2 outputs
46 # (and no redundant errors for stdout).
47 test $(wc -l < err) = 2 || { cat err; fail=1; }
50 # Ensure we continue with outputs that are OK
51 seq 10000 > multi_read || framework_failure_
53 returns_ 1 tee /dev/full out2 2>err >out1 <multi_read || fail=1
54 cmp multi_read out1 || fail=1
55 cmp multi_read out2 || fail=1
56 # Ensure an error for failing output
57 test $(wc -l < err) = 1 || { cat err; fail=1; }
59 returns_ 1 tee out1 out2 2>err >/dev/full <multi_read || fail=1
60 cmp multi_read out1 || fail=1
61 cmp multi_read out2 || fail=1
62 # Ensure an error for failing output
63 test $(wc -l < err) = 1 || { cat err; fail=1; }
66 case $host_triplet in
67 *aix*) echo 'avoiding due to no way to detect closed outputs on AIX' ;;
69 # Test iopoll-powered early exit for closed pipes
70 tee_exited() { sleep $1; test -f tee.exited; }
71 # Currently this functionality is most useful with
72 # intermittent input from a terminal, but here we
73 # use an input pipe that doesn't write anything
74 # but will exit as soon as tee does, or it times out
75 retry_delay_ tee_exited .1 7 | # 12.7s (Must be > following timeout)
76 { timeout 10 tee -p 2>err && touch tee.exited; } | :
77 test $(wc -l < err) = 0 || { cat err; fail=1; }
78 test -f tee.exited || fail=1 ;;
79 esac
81 # Test with unwritable files
82 if ! uid_is_privileged_; then # root does not get EPERM.
83 touch file.ro || framework_failure_
84 chmod a-w file.ro || framework_failure_
85 returns_ 1 tee -p </dev/null file.ro || fail=1
88 mkfifo_or_skip_ fifo
90 # Ensure tee handles nonblocking output correctly
91 # Terminate any background processes
92 cleanup_() { kill $pid 2>/dev/null && wait $pid; }
93 read_fifo_delayed() {
94 { sleep .1; timeout 10 dd of=/dev/null status=none; } <fifo
96 read_fifo_delayed & pid=$!
97 dd count=20 bs=100K if=/dev/zero status=none |
99 dd count=0 oflag=nonblock status=none
100 tee || { cleanup_; touch tee.fail; }
101 } >fifo
102 test -f tee.fail && fail=1 || cleanup_
104 # Ensure tee honors --output-error modes
105 read_fifo() { timeout 10 dd count=1 if=fifo of=/dev/null status=none & }
107 # Determine platform sigpipe exit status
108 read_fifo
109 yes >fifo
110 pipe_status=$?
112 # Default operation is to continue on output errors but exit silently on SIGPIPE
113 read_fifo
114 yes | returns_ $pipe_status timeout 10 tee ./e/noent 2>err >fifo || fail=1
115 test $(wc -l < err) = 1 || { cat err; fail=1; }
117 # With -p, SIGPIPE is suppressed, exit 0 for EPIPE when all outputs finished
118 read_fifo
119 yes | timeout 10 tee -p 2>err >fifo || fail=1
120 test $(wc -l < err) = 0 || { cat err; fail=1; }
122 # With --output-error=warn, exit 1 for EPIPE when all outputs finished
123 read_fifo
124 yes | returns_ 1 timeout 10 tee --output-error=warn 2>err >fifo || fail=1
125 test $(wc -l < err) = 1 || { cat err; fail=1; }
127 # With --output-error=exit, exit 1 immediately for EPIPE
128 read_fifo
129 yes | returns_ 1 timeout 10 tee --output-error=exit /dev/null 2>err >fifo \
130 || fail=1
131 test $(wc -l < err) = 1 || { cat err; fail=1; }
133 # With --output-error=exit, exit 1 immediately on output error
134 read_fifo
135 yes | returns_ 1 timeout 10 tee --output-error=exit ./e/noent 2>err >fifo \
136 || fail=1
137 test $(wc -l < err) = 1 || { cat err; fail=1; }
139 # With --output-error=exit-nopipe, exit 0 for EPIPE
140 read_fifo
141 yes | timeout 10 tee --output-error=exit-nopipe 2>err >fifo || fail=1
142 test $(wc -l < err) = 0 || { cat err; fail=1; }
144 wait
145 Exit $fail