On 2024-11-01 06:10, Jan Černohorský wrote:

when the `-q` option is detected (grep.c:2697), the `exit_failure` variable is set to 0. This causes any error, when not specially handled, to exit with 0, even before any match is found.

Yes, that's a mistake. I can't reproduce your bug but I can see other consequences of the mistake. Fixed in the attached patch (with a test case that's unlike your problem); please give it a try.

That being said, the lower levels of your OS appear to be buggy, as 'close' should not fail with EACCES. I wouldn't be surprised if other software breaks because of this issue. So I suggest also reporting a bug to whoever maintains the NFS client code that you're using.

I'm boldly closing this bug report; we can reopen it if the patch doesn't work for you.
From fce28c4a5eac89e13a992fb54ce4c0e7502f4415 Mon Sep 17 00:00:00 2001
From: Paul Eggert <egg...@cs.ucla.edu>
Date: Fri, 1 Nov 2024 22:38:54 -0700
Subject: [PATCH] grep: fix -q suppression of diagnostics
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Problem reported by Jan Černohorský (Bug#74159).
* src/grep.c (grepbuf): If exit_on_match, set stdout_errno to
avoid screwups on buggy OSes.  Also, ignore errseen since it
cannot be true here.
(main): Do not clear exit_failure if -q is given, as exit status
should be zero only if an input line is selected.
* tests/write-error-msg: Check that -q suppresses diagnostics
of output errors only if a match is found.
---
 src/grep.c            | 12 +++++++++---
 tests/write-error-msg | 11 ++++++++---
 2 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/src/grep.c b/src/grep.c
index 912bce4..042433a 100644
--- a/src/grep.c
+++ b/src/grep.c
@@ -436,7 +436,11 @@ static const struct color_cap color_dict[] =
     { nullptr, nullptr,            nullptr }
   };
 
-/* Saved errno value from failed output functions on stdout.  */
+/* Saved errno value from failed output functions on stdout.
+   prline polls this to decide whether to die.
+   Setting it to nonzero just before exiting can prevent clean_up_stdout
+   from misbehaving on a buggy OS where 'close (STDOUT_FILENO)' fails
+   with EACCES.  */
 static int stdout_errno;
 
 static void
@@ -1490,7 +1494,10 @@ grepbuf (char *beg, char const *lim)
           if (!outleft || done_on_match)
             {
               if (exit_on_match)
-                exit (errseen ? exit_failure : EXIT_SUCCESS);
+                {
+                  stdout_errno = -1;
+                  exit (EXIT_SUCCESS);
+                }
               break;
             }
         }
@@ -2696,7 +2703,6 @@ main (int argc, char **argv)
 
       case 'q':
         exit_on_match = true;
-        exit_failure = 0;
         break;
 
       case 'R':
diff --git a/tests/write-error-msg b/tests/write-error-msg
index c6644e3..351e32c 100755
--- a/tests/write-error-msg
+++ b/tests/write-error-msg
@@ -37,8 +37,11 @@ returns_ 2 grep --line-buffered -v '^$' <in >/dev/full 2>err1 \
 returns_ 2 grep -v '^$' <in >/dev/full 2>err2 \
     || framework_failure_
 
+# disk-full error with -q and --help
+returns_ 2 grep -q --help >/dev/full 2>err3 || fail=1
+
 # ensure each error message file contains a 'write error' with additional text
-for f in err1 err2 ;
+for f in err1 err2 err3 ;
 do
     grep -Eiq '^[^:]*: write error: [a-z]+' $f \
         || {
@@ -49,7 +52,9 @@ do
 done
 
 # These messages should be identical
-compare err1 err2 \
-    || { warn_ "err1,err2 contain different error messages" ; fail=1 ; }
+for f in err2 err3; do
+  compare err1 $f \
+    || { warn_ "err1,$f contain different error messages" ; fail=1 ; }
+done
 
 Exit $fail
-- 
2.47.0

Reply via email to