summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Meyering <meyering@redhat.com>2011-12-11 19:26:38 +0100
committerJim Meyering <meyering@redhat.com>2011-12-12 14:09:51 +0100
commited071726be5758b1422d7972450a1867655268b4 (patch)
treeb8445db49b05cc80b20b1e200c0d5dc5de59bdfe
parent979592944f06bddb108458073239d2ff52d2c475 (diff)
downloadgrep-ed071726be5758b1422d7972450a1867655268b4.tar.gz
disable the new input==output guard for additional options
* src/main.c (grepfile): Do not reject input == output also when using a few other options. * tests/in-eq-out-infloop: Test these new cases. * NEWS (Bug fixes): Mention it
-rw-r--r--NEWS12
-rw-r--r--src/main.c18
-rwxr-xr-xtests/in-eq-out-infloop9
3 files changed, 35 insertions, 4 deletions
diff --git a/NEWS b/NEWS
index 6bdeb221..5e187f8a 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,18 @@ GNU grep NEWS -*- outline -*-
* Noteworthy changes in release ?.? (????-??-??) [?]
+** Bug fixes
+
+ grep no longer rejects "grep -qr . > out", i.e., when run with -q
+ and an input file is the same as the output file, since with -q
+ grep generates no output, so there is no risk of infinite loop or
+ of an output-affecting race condition. Thus, the use of the following
+ options also disables the input-equals-output failure:
+ --max-count=N (-m) (for N >= 2)
+ --files-with-matches (-l)
+ --files-without-match (-L)
+ [bug introduced in grep-2.10]
+
* Noteworthy changes in release 2.10 (2011-11-16) [stable]
diff --git a/src/main.c b/src/main.c
index c81342fe..afd77c5c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1219,16 +1219,26 @@ grepfile (char const *file, struct stats *stats)
|| S_ISFIFO (stats->stat.st_mode)))
return 1;
- /* If there's a regular file on stdout and the current file refers
+ /* If there is a regular file on stdout and the current file refers
to the same i-node, we have to report the problem and skip it.
Otherwise when matching lines from some other input reach the
disk before we open this file, we can end up reading and matching
those lines and appending them to the file from which we're reading.
Then we'd have what appears to be an infinite loop that'd terminate
only upon filling the output file system or reaching a quota.
- However, there is no risk of an infinite loop when we know that
- grep will generate no output (-q). */
- if (!out_quiet && S_ISREG (stats->stat.st_mode) && out_stat.st_ino
+ However, there is no risk of an infinite loop if grep is generating
+ no output, i.e., with --silent, --quiet, -q.
+ Similarly, with any of these:
+ --max-count=N (-m) (for N >= 2)
+ --files-with-matches (-l)
+ --files-without-match (-L)
+ there is no risk of trouble.
+ For --max-count=1, grep stops after printing the first match,
+ so there is no risk of malfunction. But even --max-count=2, with
+ input==output, while there is no risk of infloop, there is a race
+ condition that could result in "alternate" output. */
+ if (!out_quiet && list_files == 0 && 1 < max_count
+ && S_ISREG (stats->stat.st_mode) && out_stat.st_ino
&& SAME_REGULAR_FILE (stats->stat, out_stat))
{
error (0, 0, _("input file %s is also the output"), quote (file));
diff --git a/tests/in-eq-out-infloop b/tests/in-eq-out-infloop
index 726accba..dcb7ac05 100755
--- a/tests/in-eq-out-infloop
+++ b/tests/in-eq-out-infloop
@@ -23,4 +23,13 @@ test $st = 2 || fail=1
compare err.exp err || fail=1
+# But with each of the following options it must not exit-2.
+for i in -q -m1 -l -L; do
+ timeout 10 grep $i 0 out >> out 2> err; st=$?
+ test $st = 2 && fail=1
+done
+
+timeout 10 grep -2 0 out >> out 2> err; st=$?
+test $st = 2 || fail=1
+
Exit $fail