Eric Blake wrote: > [adding bug-gnulib] > > On 03/02/2011 06:28 AM, Stefan Vargyas wrote: >> Dear maintainers, >> >> While building and running coreutils v8.9, I came across the >> following issue of 'du': >> >> $ mkdir /tmp/foo >> $ du --files0-from=/tmp/foo >> du: `/tmp/foo': read error: Is a directory >> ... >> >> The program enters an infinite loop
Thanks! That affects the latest (coreutils-8.10), too. > Thanks for the report. This is indeed a bug. > > I wonder if the better fix would be to modify the gnulib argv-iter > module to make argv_iter_init_stream to fail if fileno(fp) is a > directory, since not all platforms reliably fail with EISDIR when doing > read() on a directory (some, like BSD, successfully return EOF, and some > older systems even read raw directory contents). That's just what I've done. Here's a tentative patch, both for du.c and argv-iter.c in gnulib. A probably-identical change to the du.c part will be required for wc.c. I'll add tests and update NEWS, too. diff --git a/src/du.c b/src/du.c index 671cac7..e205cd5 100644 --- a/src/du.c +++ b/src/du.c @@ -889,6 +889,8 @@ main (int argc, char **argv) quote (files_from)); ai = argv_iter_init_stream (stdin); + if (ai == NULL && errno == EISDIR) + error (EXIT_FAILURE, errno, _("invalid file: %s"), quote (files_from)); /* It's not easy here to count the arguments, so assume the worst. */ diff --git a/lib/argv-iter.c b/lib/argv-iter.c index 340e588..f0445f1 100644 --- a/lib/argv-iter.c +++ b/lib/argv-iter.c @@ -21,6 +21,8 @@ #include <stdlib.h> #include <string.h> +#include <sys/stat.h> +#include <errno.h> struct argv_iterator { @@ -49,11 +51,21 @@ argv_iter_init_argv (char **argv) } /* Initialize to read from the stream, FP. - The input is expected to contain a list of NUL-delimited tokens. */ + The input is expected to contain a list of NUL-delimited tokens. + If FP refers to a directory, set errno to EISDIR and return NULL. */ struct argv_iterator * argv_iter_init_stream (FILE *fp) { - struct argv_iterator *ai = malloc (sizeof *ai); + struct argv_iterator *ai; + struct stat st; + + if (fstat (fileno (fp), &st) == 0 && S_ISDIR (st.st_mode)) + { + errno = EISDIR; + return NULL; + } + + ai = malloc (sizeof *ai); if (!ai) return NULL; ai->fp = fp;