tail: fix handling of broken pipes with SIGPIPE ignored

* init.cfg (trap_sigpipe_or_skip_): A new function refactored from...
* tests/misc/printf-surprise.sh: ...here.
* tests/misc/seq-epipe.sh. Likewise.
* src/tail.c (die_pipe): Ensure we exit upon sending SIGPIPE.
* tests/tail-2/pipe-f.sh: Ensure we exit even if SIGPIPE is ignored.
* NEWS: Mention the bug fix.
This commit is contained in:
Pádraig Brady 2019-01-20 00:13:15 -08:00
parent 17983b2cb3
commit fa50623394
6 changed files with 37 additions and 14 deletions

4
NEWS
View File

@ -27,6 +27,10 @@ GNU coreutils NEWS -*- outline -*-
'tail -f file | filter' no longer exits immediately on AIX.
[bug introduced in coreutils-8.28]
'tail -f file | filter' no longer goes into an infinite loop
if filter exits and SIGPIPE is ignored.
[bug introduced in coreutils-8.28]
** Changes in behavior
echo now always processes backslash escapes when the POSIXLY_CORRECT

View File

@ -610,6 +610,12 @@ mkfifo_or_skip_()
fi
}
trap_sigpipe_or_skip_()
{
(trap '' PIPE && yes | :) 2>&1 | grep -qF 'Broken pipe' ||
skip_ 'trapping SIGPIPE is not supported'
}
# Disable the current test if the working directory seems to have
# the setgid bit set.
skip_if_setgid_()

View File

@ -334,6 +334,14 @@ named file in a way that accommodates renaming, removal and creation.\n\
exit (status);
}
/* Ensure exit, either with SIGPIPE or EXIT_FAILURE status. */
static void ATTRIBUTE_NORETURN
die_pipe (void)
{
raise (SIGPIPE);
exit (EXIT_FAILURE);
}
/* If the output has gone away, then terminate
as we would if we had written to this output. */
static void
@ -349,7 +357,7 @@ check_output_alive (void)
pfd.events = POLLERR;
if (poll (&pfd, 1, 0) >= 0 && (pfd.revents & POLLERR))
raise (SIGPIPE);
die_pipe ();
#else
struct timeval delay;
delay.tv_sec = delay.tv_usec = 0;
@ -361,7 +369,7 @@ check_output_alive (void)
/* readable event on STDOUT is equivalent to POLLERR,
and implies an error condition on output like broken pipe. */
if (select (STDOUT_FILENO + 1, &rfd, NULL, NULL, &delay) == 1)
raise (SIGPIPE);
die_pipe ();
#endif
}
@ -1659,7 +1667,7 @@ tail_forever_inotify (int wd, struct File_spec *f, size_t n_files,
{
/* readable event on STDOUT is equivalent to POLLERR,
and implies an error on output like broken pipe. */
raise (SIGPIPE);
die_pipe ();
}
else
break;

View File

@ -49,9 +49,7 @@ vm=$(get_min_ulimit_v_ env $prog %20f 0) \
# triggering the printf(3) misbehavior -- which, btw, is required by ISO C99.
mkfifo_or_skip_ fifo
(trap '' PIPE && yes | :) 2>&1 | grep -qF 'Broken pipe' ||
skip_ 'trapping SIGPIPE is not supported'
trap_sigpipe_or_skip_
# Disable MALLOC_PERTURB_, to avoid triggering this bug
# https://bugs.debian.org/481543#77

View File

@ -18,9 +18,7 @@
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
print_ver_ seq
(trap '' PIPE && yes | :) 2>&1 | grep -qF 'Broken pipe' ||
skip_ 'trapping SIGPIPE is not supported'
trap_sigpipe_or_skip_
# upon EPIPE with signals ignored, 'seq' should exit with an error.
timeout 10 sh -c \

View File

@ -18,6 +18,7 @@
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
print_ver_ tail
trap_sigpipe_or_skip_
# Speedup the non inotify case
fastpoll='-s.1 --max-unchanged-stats=1'
@ -36,11 +37,19 @@ echo bar | returns_ 1 \
compare exp out || fail=1
# This would wait indefinitely before v8.28 due to no EPIPE being
# generated due to no data written after the first small amount
(returns_ 124 timeout 10 tail -n2 -f $mode $fastpoll out && touch timed_out) |
sed 2q > out2
test -e timed_out && fail=1
compare exp out2 || fail=1
# generated due to no data written after the first small amount.
# Also check tail exits if SIGPIPE is being ignored.
# Note 'trap - SIGPIPE' is ineffective if the initiating shell
# has ignored SIGPIPE, but that's not the normal case.
for disposition in '' '-'; do
(trap "$disposition" PIPE;
returns_ 124 timeout 10 \
tail -n2 -f $mode $fastpoll out && touch timed_out) |
sed 2q > out2
test -e timed_out && fail=1
compare exp out2 || fail=1
rm -f timed_out
done
# This would wait indefinitely before v8.28 (until first write)
(returns_ 1 timeout 10 tail -f $mode $fastpoll /dev/null >&-) || fail=1