Subject: Re: bug#24903: "tail -f - foo" does not terminate when stdin is closed and foo is ignored
From: Pádraig Brady <[email-masked]>
To: Julian Büning <[email-masked]>, [email-masked]
Cc: Oscar Soria Dustmann <[email-masked]>, Daniel Schemmel <[email-masked]>
Date: Tue, 8 Nov 2016 17:47:15 +0000
List-Id: <debbugs-submit.debbugs.gnu.org>

On 08/11/16 16:39, Julian Büning wrote:
> We observed another behavior possibly related to bug #24495:

Similar yes.

> $ mkdir foo
> $ echo "bar" | tail -f - foo &
> [1] 16386
> ==> standard input <==
> bar
> 
> ==> foo <==
> tail: error reading 'foo': Is a directory
> tail: foo: cannot follow end of this type of file; giving up on this name
> $ jobs
> [1]+  Running                 echo "bar" | tail -f - foo &

Yes we should exit here.

> $ readlink /proc/16386/fd/0
> pipe:[162156]
> $ lsof | grep 162156
> tail      16386          user    0r     FIFO       0,10       0t0
> 162156 pipe
> 
> Only the reading end of the pipe is still open, thus tail should not be
> able to read any more bytes from it.

Right we're not blocked on read()

The attached should fix it up.

thanks,
Pádraig.

p.s. These Symbolic Execution techniques are intriguing.
Have you any more details.
From a6207bdacee615ad6e19e24911aad7ae8364f6f9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <[email-masked]>
Date: Tue, 8 Nov 2016 17:34:44 +0000
Subject: [PATCH] tail: terminate when following pipes and untailable non pipes

* src/tail.c (ignore_pipe_or_fifo): Mark the descriptor as -1
for pipes so that any_live_files() detects correctly that
the entry is no longer live.
* tests/tail-2/pipe-f.sh: Add a test case.
Fixes http://bugs.gnu.org/24903 which was detected
using Symbolic Execution techniques developed in
the course of the SYMBIOSYS research project at
COMSYS, RWTH Aachen University.
---
 src/tail.c             |  5 ++++-
 tests/tail-2/pipe-f.sh | 11 ++++++++++-
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/src/tail.c b/src/tail.c
index 718fc8a..96982ed 100644
--- a/src/tail.c
+++ b/src/tail.c
@@ -2212,7 +2212,10 @@ ignore_fifo_and_pipe (struct File_spec *f, size_t n_files)
          && (S_ISFIFO (f[i].mode)
              || (HAVE_FIFO_PIPES != 1 && isapipe (f[i].fd))));
       if (is_a_fifo_or_pipe)
-        f[i].ignore = true;
+        {
+          f[i].fd = -1;
+          f[i].ignore = true;
+        }
       else
         ++n_viable;
     }
diff --git a/tests/tail-2/pipe-f.sh b/tests/tail-2/pipe-f.sh
index 7abb7d6..82364da 100755
--- a/tests/tail-2/pipe-f.sh
+++ b/tests/tail-2/pipe-f.sh
@@ -19,9 +19,18 @@
 . "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
 print_ver_ tail
 
+echo oo > exp || framework_failure_
 echo foo | timeout 10 tail -f -c3 > out || fail=1
-echo oo > exp || fail=1
+compare exp out || fail=1
+
+cat <<\EOF > exp
+==> standard input <==
+ar
 
+==> missing <==
+EOF
+mkdir missing || framework_failure_
+echo bar | returns_ 1 timeout 10 tail -f -c3 - missing > out || fail=1
 compare exp out || fail=1
 
 Exit $fail
-- 
2.5.5