[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

yesno module consumes too much input

From: Eric Blake-1
Subject: yesno module consumes too much input
Date: Fri, 17 Aug 2007 13:01:42 -0700 (PDT)

The yesno module has a problem on platforms where exit()
does not implicitly flush seekable input streams (this behavior
of exit() is contrary to POSIX, but glibc behaves this way,
and Ulrich was unwilling to fix the glibc bug [1]).  Basically,
because the yesno module consumes input from stdin, if
the application does not restore the offset of the underlying
fd to the next unread byte prior to a successful exit, then
data is lost from subsequent applications that also read
from the file descriptor.

For an example of the bug, try this on Linux (tested
with glibc 2.3):

$ touch a b
$ echo 'n
y' > blah
$ (export LC_ALL=C; mv -vi a b; mv -vi a b) < blah
mv: overwrite `b'? mv: overwrite `b'? 
$ echo $?
$ ls ?
a  b

contrasted to Solaris or cygwin (where exit() already
takes care of flushing seekable stdin):

$ touch a b
$ echo 'n
y' > blah
$ (export LC_ALL=C; mv -vi a b; mv -vi a b) < blah
mv: overwrite `b'? mv: overwrite `b'? `a' -> `b'
$ echo $?
$ ls ?

Basically, on buggy platforms, the first mv did not reset
the file pointer to the unread line "y", so the second mv
saw EOF instead of the affirmative response.  The end
result was a violation of POSIX semantics on Linux.

The closein module is capable of resolving this problem.
However, rather than fix all of the affected applications
one-by-one (the list includes, but is not limited to,
coreutils' cp, ln, mv, rm, and remove; and findutils' find),
it would be nicer to fix this just once in yesno.  OK to
apply the patch below?

[1] http://sources.redhat.com/bugzilla/show_bug.cgi?id=3746

2007-08-17  Eric Blake  <address@hidden>

        Don't consume too much input when stdin is seekable.
        * lib/yesno.c (yesno): Flush seekable stdin.
        * modules/yesno (Depends-on): Add fflush.

Index: modules/yesno
RCS file: /sources/gnulib/gnulib/modules/yesno,v
retrieving revision 1.13
diff -u -p -r1.13 yesno
--- modules/yesno       13 Oct 2006 12:40:23 -0000      1.13
+++ modules/yesno       17 Aug 2007 19:56:38 -0000
@@ -8,6 +8,7 @@ lib/yesno.h
Index: lib/yesno.c
RCS file: /sources/gnulib/gnulib/lib/yesno.c,v
retrieving revision 1.17
diff -u -p -r1.17 yesno.c
--- lib/yesno.c 14 Dec 2006 18:47:36 -0000      1.17
+++ lib/yesno.c 17 Aug 2007 19:56:38 -0000
@@ -1,6 +1,6 @@
 /* yesno.c -- read a yes/no response from stdin
-   Copyright (C) 1990, 1998, 2001, 2003, 2004, 2005, 2006 Free
+   Copyright (C) 1990, 1998, 2001, 2003, 2004, 2005, 2006, 2007 Free
    Software Foundation, Inc.
    This program is free software; you can redistribute it and/or modify
@@ -23,6 +23,7 @@
 #include <stdlib.h>
 #include <stdio.h>
+#include <unistd.h>
 # include "getline.h"
@@ -60,5 +61,18 @@ yesno (void)
     c = getchar ();
+  /* POSIX requires that if stdin was seekable, that the application
+     leave the underlying fd positioned at the next unread byte.
+     glibc is a notorious offender of not doing this automatically at
+     exit() [glibc bug 3746], even though that is also required by
+     POSIX.  But rather than make applications use the closein module,
+     we just flush seekable input streams here.  gnulib's fflush
+     module is undefined when doing fflush on non-seekable files,
+     hence the use of lseek to figure out whether we can do the seek.
+     The sequence fflush/fseeko is guaranteed by POSIX and by gnulib
+     to do what we want, even though it is undefined in C99.  */
+  if (lseek (STDIN_FILENO, 0, SEEK_CUR) >= 0 && fflush (stdin) == 0)
+    fseeko (stdin, 0, SEEK_CUR);
   return yes;

View this message in context: 
Sent from the Gnulib mailing list archive at Nabble.com.

reply via email to

[Prev in Thread] Current Thread [Next in Thread]