summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS5
-rw-r--r--bootstrap.conf3
-rw-r--r--src/main.c26
-rw-r--r--src/system.h42
4 files changed, 74 insertions, 2 deletions
diff --git a/NEWS b/NEWS
index 6e5d38b9..8578e821 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,11 @@ GNU grep NEWS -*- outline -*-
* Noteworthy changes in release ?.? (????-??-??) [?]
+ grep now rejects a command like "grep -r pattern . > out",
+ in which the output file is also one of the inputs,
+ because it can result in an "infinite" disk-filling loop.
+ [bug present since "the beginning"]
+
* Noteworthy changes in release 2.9 (2011-06-21) [stable]
diff --git a/bootstrap.conf b/bootstrap.conf
index 143d7b5c..66c239e2 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -57,10 +57,11 @@ obstack
open
progname
propername
-quotearg
+quote
readme-release
realloc-gnu
regex
+same-inode
ssize_t
stddef
stdlib
diff --git a/src/main.c b/src/main.c
index 4e01a177..fd9f662e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -44,6 +44,7 @@
#include "isdir.h"
#include "progname.h"
#include "propername.h"
+#include "quote.h"
#include "savedir.h"
#include "version-etc.h"
#include "xalloc.h"
@@ -59,6 +60,11 @@
proper_name ("Mike Haertel"), \
_("others, see <http://git.sv.gnu.org/cgit/grep.git/tree/AUTHORS>")
+/* When stdout is connected to a regular file, save its stat
+ information here, so that we can automatically skip it, thus
+ avoiding a potential (racy) infinite loop. */
+static struct stat out_stat;
+
struct stats
{
struct stats const *parent;
@@ -1212,6 +1218,22 @@ grepfile (char const *file, struct stats *stats)
|| S_ISSOCK (stats->stat.st_mode)
|| S_ISFIFO (stats->stat.st_mode)))
return 1;
+
+ /* If there's 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. */
+ if (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));
+ errseen = 1;
+ return 1;
+ }
+
while ((desc = open (file, O_RDONLY)) < 0 && errno == EINTR)
continue;
@@ -2121,6 +2143,10 @@ main (int argc, char **argv)
if (show_help)
usage (EXIT_SUCCESS);
+ struct stat tmp_stat;
+ if (fstat (STDOUT_FILENO, &tmp_stat) == 0 && S_ISREG (tmp_stat.st_mode))
+ out_stat = tmp_stat;
+
if (keys)
{
if (keycc == 0)
diff --git a/src/system.h b/src/system.h
index 199b4853..e7afc46d 100644
--- a/src/system.h
+++ b/src/system.h
@@ -27,6 +27,7 @@
#include "configmake.h"
#include "dirname.h"
#include "minmax.h"
+#include "same-inode.h"
#if O_BINARY
# define HAVE_DOS_FILE_CONTENTS 1
@@ -53,8 +54,47 @@ enum { EXIT_TROUBLE = 2 };
#include <locale.h>
#ifndef initialize_main
-#define initialize_main(argcp, argvp)
+# define initialize_main(argcp, argvp)
#endif
+/* Do struct stat *S, *T have the same file attributes?
+
+ POSIX says that two files are identical if st_ino and st_dev are
+ the same, but many file systems incorrectly assign the same (device,
+ inode) pair to two distinct files, including:
+
+ - GNU/Linux NFS servers that export all local file systems as a
+ single NFS file system, if a local device number (st_dev) exceeds
+ 255, or if a local inode number (st_ino) exceeds 16777215.
+
+ - Network Appliance NFS servers in snapshot directories; see
+ Network Appliance bug #195.
+
+ - ClearCase MVFS; see bug id ATRia04618.
+
+ Check whether two files that purport to be the same have the same
+ attributes, to work around instances of this common bug. Do not
+ inspect all attributes, only attributes useful in checking for this
+ bug.
+
+ It's possible for two distinct files on a buggy file system to have
+ the same attributes, but it's not worth slowing down all
+ implementations (or complicating the configuration) to cater to
+ these rare cases in buggy implementations. */
+
+#ifndef same_file_attributes
+# define same_file_attributes(s, t) \
+ ((s)->st_mode == (t)->st_mode \
+ && (s)->st_nlink == (t)->st_nlink \
+ && (s)->st_uid == (t)->st_uid \
+ && (s)->st_gid == (t)->st_gid \
+ && (s)->st_size == (t)->st_size \
+ && (s)->st_mtime == (t)->st_mtime \
+ && (s)->st_ctime == (t)->st_ctime)
+#endif
+
+#define SAME_REGULAR_FILE(s, t) \
+ (SAME_INODE (s, t) && same_file_attributes (&s, &t))
+
#include "unlocked-io.h"
#endif