Subject: Re: bug#25283: grep: (standard input): invalid argument when run from make
From: Paul Eggert <[email-masked]>
To: Benno Fünfstück <[email-masked]>
Cc: [email-masked]
Date: Tue, 27 Dec 2016 11:23:32 -0800
List-Id: <debbugs-submit.debbugs.gnu.org>

Thanks for reporting that problem. I wonder why GNU 'make' sets stdout to append 
mode? That surprises me, and I don't see where POSIX allows it. Anyway, it's 
clearly a bug in 'grep' no matter what 'make' is doing. I wrote up a test case 
for the bug and installed the attached, which is a bit more conservative than 
the patch you submitted.
From 8f0974b6315c71a5160c62f7147ff890bda90179 Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email-masked]>
Date: Tue, 27 Dec 2016 11:16:32 -0800
Subject: [PATCH] grep: fix bug with '... | grep pat >> /dev/null'
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Problem reported by Benno Fünfstück (Bug#25283).
* NEWS: Document this.
* src/grep.c (drain_input) [SPLICE_F_MOVE]:
Don't assume /dev/null is always acceptable output to splice.
* tests/grep-dev-null-out: Test for the bug.
---
 NEWS                    |  7 ++++---
 src/grep.c              | 14 +++++++++-----
 tests/grep-dev-null-out |  2 ++
 3 files changed, 15 insertions(+), 8 deletions(-)

diff --git a/NEWS b/NEWS
index 2e7d1ae..8830582 100644
--- a/NEWS
+++ b/NEWS
@@ -4,9 +4,10 @@ GNU grep NEWS                                    -*- outline -*-
 
 ** Bug fixes
 
-  grep no longer fails when standard input is a file in the Linux
-  /proc file system and standard output is /dev/null.
-  [bug introduced in grep-2.27]
+  When standard output is /dev/null, grep no longer fails when
+  standard input is a file in the Linux /proc file system, or when
+  standard input is a pipe and standard output is in append mdoe.
+  [bugs introduced in grep-2.27]
 
 ** Bug fixes
 
diff --git a/src/grep.c b/src/grep.c
index f28f3c2..aebab20 100644
--- a/src/grep.c
+++ b/src/grep.c
@@ -1728,11 +1728,15 @@ drain_input (int fd, struct stat const *st)
     {
 #ifdef SPLICE_F_MOVE
       /* Should be faster, since it need not copy data to user space.  */
-      while ((nbytes = splice (fd, NULL, STDOUT_FILENO, NULL,
-                               INITIAL_BUFSIZE, SPLICE_F_MOVE)))
-        if (nbytes < 0)
-          return false;
-      return true;
+      nbytes = splice (fd, NULL, STDOUT_FILENO, NULL,
+                       INITIAL_BUFSIZE, SPLICE_F_MOVE);
+      if (0 <= nbytes || errno != EINVAL)
+        {
+          while (0 < nbytes)
+            nbytes = splice (fd, NULL, STDOUT_FILENO, NULL,
+                             INITIAL_BUFSIZE, SPLICE_F_MOVE);
+          return nbytes == 0;
+        }
 #endif
     }
   while ((nbytes = safe_read (fd, buffer, bufalloc)))
diff --git a/tests/grep-dev-null-out b/tests/grep-dev-null-out
index 13a4843..c8128d5 100755
--- a/tests/grep-dev-null-out
+++ b/tests/grep-dev-null-out
@@ -8,4 +8,6 @@ require_timeout_
 ${AWK-awk} 'BEGIN {while (1) print "x"}' </dev/null |
   returns_ 124 timeout 1 grep x >/dev/null || fail=1
 
+echo abc | grep b >>/dev/null || fail=1
+
 Exit $fail
-- 
2.7.4