diff options
-rw-r--r-- | NEWS | 5 | ||||
-rw-r--r-- | bootstrap.conf | 3 | ||||
-rw-r--r-- | src/main.c | 26 | ||||
-rw-r--r-- | src/system.h | 42 |
4 files changed, 74 insertions, 2 deletions
@@ -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 @@ -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 |