changeset 8872:dfee3b4fd46c

Fix lseek on mingw. * modules/lseek: New module. * m4/lseek.m4: New file. * lib/lseek.c: New file. * modules/lseek-tests: New file. * tests/test-lseek.c: New file. * tests/test-lseek.sh: New file. * MODULES.html.sh: Document lseek module. * modules/fflush (Depends-on): Add lseek, fseeko. * modules/fseeko (Depends-on): Likewise. * modules/ftello (Depends-on): Likewise. * m4/fseeko.m4 (gl_FUNC_FSEEKO): Replace fseek[o] if lseek is broken. * m4/ftello.m4 (gl_FUNC_FTELLO): Replace ftell[o] if lseek is broken. * m4/fflush.m4 (gl_REPLACE_FFLUSH): Trigger fseeko module. * lib/fseeko.c (rpl_fseeko): Quit early on non-seekable files. * lib/ftello.c (rpl_ftello): Likewise. * tests/test-fseeko.c (main): Test this. * tests/test-fseeko.sh: Likewise. * tests/test-ftello.c (main): Likewise. * tests/test-ftello.sh: Likewise. * lib/stdio_.h (fseek, ftell): Simplify, since missing fseeko now implies replacing fseek. * modules/stdio (Makefile.am): No longer need HAVE_FSEEKO, HAVE_FTELLO. * m4/unistd_h.m4 (gl_UNISTD_H_DEFAULTS): Add lseek info. * modules/unistd (Makefile.am): Likewise. * lib/unistd_.h (lseek): Declare a replacement. * doc/functions/lseek.texi (lseek): Document this fix. * doc/functions/fseek.texi (fseek): Likewise. * doc/functions/ftell.texi (ftell): Likewise.
author Eric Blake <ebb9@byu.net>
date Thu, 24 May 2007 16:59:20 +0000
parents 8015a071250c
children 25ee90a28a16
files ChangeLog MODULES.html.sh doc/functions/fseek.texi doc/functions/ftell.texi doc/functions/lseek.texi lib/fseeko.c lib/ftello.c lib/lseek.c lib/stdio_.h lib/unistd_.h m4/fflush.m4 m4/fseeko.m4 m4/ftello.m4 m4/lseek.m4 m4/unistd_h.m4 modules/fflush modules/fseeko modules/ftello modules/lseek modules/lseek-tests modules/stdio modules/unistd tests/test-fseeko.c tests/test-fseeko.sh tests/test-ftello.c tests/test-ftello.sh tests/test-lseek.c tests/test-lseek.sh
diffstat 28 files changed, 280 insertions(+), 43 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,38 @@
+2007-05-24  Eric Blake  <ebb9@byu.net>
+
+	Fix lseek on mingw.
+	* modules/lseek: New module.
+	* m4/lseek.m4: New file.
+	* lib/lseek.c: New file.
+	* modules/lseek-tests: New file.
+	* tests/test-lseek.c: New file.
+	* tests/test-lseek.sh: New file.
+	* MODULES.html.sh: Document lseek module.
+	* modules/fflush (Depends-on): Add lseek, fseeko.
+	* modules/fseeko (Depends-on): Likewise.
+	* modules/ftello (Depends-on): Likewise.
+	* m4/fseeko.m4 (gl_FUNC_FSEEKO): Replace fseek[o] if lseek is
+	broken.
+	* m4/ftello.m4 (gl_FUNC_FTELLO): Replace ftell[o] if lseek is
+	broken.
+	* m4/fflush.m4 (gl_REPLACE_FFLUSH): Trigger fseeko module.
+	* lib/fseeko.c (rpl_fseeko): Quit early on non-seekable files.
+	* lib/ftello.c (rpl_ftello): Likewise.
+	* tests/test-fseeko.c (main): Test this.
+	* tests/test-fseeko.sh: Likewise.
+	* tests/test-ftello.c (main): Likewise.
+	* tests/test-ftello.sh: Likewise.
+	* lib/stdio_.h (fseek, ftell): Simplify, since missing fseeko now
+	implies replacing fseek.
+	* modules/stdio (Makefile.am): No longer need HAVE_FSEEKO,
+	HAVE_FTELLO.
+	* m4/unistd_h.m4 (gl_UNISTD_H_DEFAULTS): Add lseek info.
+	* modules/unistd (Makefile.am): Likewise.
+	* lib/unistd_.h (lseek): Declare a replacement.
+	* doc/functions/lseek.texi (lseek): Document this fix.
+	* doc/functions/fseek.texi (fseek): Likewise.
+	* doc/functions/ftell.texi (ftell): Likewise.
+
 2007-05-24  Bruno Haible  <bruno@clisp.org>
 
 	* tests/test-vasnprintf-posix.c (test_function): Allow up to 50 bytes
--- a/MODULES.html.sh
+++ b/MODULES.html.sh
@@ -2029,13 +2029,14 @@
   func_module gettimeofday
   func_module inet_ntop
   func_module inet_pton
+  func_module lseek
+  func_module lstat
   func_module mkdir
   func_module mkdtemp
   func_module mkstemp
   func_module poll
+  func_module printf-posix
   func_module readlink
-  func_module lstat
-  func_module printf-posix
   func_module snprintf-posix
   func_module sprintf-posix
   func_module string
--- a/doc/functions/fseek.texi
+++ b/doc/functions/fseek.texi
@@ -4,10 +4,12 @@
 
 POSIX specification: @url{http://www.opengroup.org/susv3xsh/fseek.html}
 
-Gnulib module: ---
+Gnulib module: fseeko
 
 Portability problems fixed by Gnulib:
 @itemize
+@item
+This function mistakenly succeeds on non-seekable files: mingw.
 @end itemize
 
 Portability problems not fixed by Gnulib:
@@ -15,4 +17,7 @@
 @item
 On Windows platforms (excluding Cygwin), this function does not set @code{errno}
 upon failure.
+@item
+On platforms where @code{off_t} is a 32-bit type, @code{fseek} does not work
+correctly with files larger than 2 GB.  The fix is to use fseeko instead.
 @end itemize
--- a/doc/functions/ftell.texi
+++ b/doc/functions/ftell.texi
@@ -4,10 +4,12 @@
 
 POSIX specification: @url{http://www.opengroup.org/susv3xsh/ftell.html}
 
-Gnulib module: ---
+Gnulib module: ftello
 
 Portability problems fixed by Gnulib:
 @itemize
+@item
+This function mistakenly succeeds on non-seekable files: mingw.
 @end itemize
 
 Portability problems not fixed by Gnulib:
@@ -16,4 +18,7 @@
 @code{fflush}, @code{ftell}, @code{ftello}, @code{fgetpos} behave incorrectly
 on input streams that are opened in @code{O_TEXT} mode and whose contents
 contains Unix line terminators (LF), on some platforms: mingw.
+@item
+On platforms where @code{off_t} is a 32-bit type, @code{ftell} does not work
+correctly with files larger than 2 GB.  The fix is to use ftello instead.
 @end itemize
--- a/doc/functions/lseek.texi
+++ b/doc/functions/lseek.texi
@@ -4,10 +4,12 @@
 
 POSIX specification: @url{http://www.opengroup.org/susv3xsh/lseek.html}
 
-Gnulib module: ---
+Gnulib module: lseek
 
 Portability problems fixed by Gnulib:
 @itemize
+@item
+This function mistakenly succeeds on non-seekable files: mingw.
 @end itemize
 
 Portability problems not fixed by Gnulib:
--- a/lib/fseeko.c
+++ b/lib/fseeko.c
@@ -25,12 +25,19 @@
 
 #undef fseeko
 #if !HAVE_FSEEKO
+# undef fseek
 # define fseeko fseek
 #endif
 
 int
 rpl_fseeko (FILE *fp, off_t offset, int whence)
 {
+#if LSEEK_PIPE_BROKEN
+  /* mingw gives bogus answers rather than failure on non-seekable files.  */
+  if (lseek (fileno (fp), 0, SEEK_CUR) == -1)
+    return EOF;
+#endif
+
   /* These tests are based on fpurge.c.  */
 #if defined _IO_ferror_unlocked     /* GNU libc, BeOS */
   if (fp->_IO_read_end == fp->_IO_read_ptr
--- a/lib/ftello.c
+++ b/lib/ftello.c
@@ -20,14 +20,24 @@
 /* Specification.  */
 #include <stdio.h>
 
+/* Get lseek.  */
+#include <unistd.h>
+
 #undef ftello
 #if !HAVE_FTELLO
+# undef ftell
 # define ftello ftell
 #endif
 
 off_t
 rpl_ftello (FILE *fp)
 {
+#if LSEEK_PIPE_BROKEN
+  /* mingw gives bogus answers rather than failure on non-seekable files.  */
+  if (lseek (fileno (fp), 0, SEEK_CUR) == -1)
+    return -1;
+#endif
+
 #if defined __SL64 && defined __SCLE /* Cygwin */
   if ((fp->_flags & __SL64) == 0)
     {
new file mode 100644
--- /dev/null
+++ b/lib/lseek.c
@@ -0,0 +1,40 @@
+/* An lseek() function that detects pipes.
+   Copyright (C) 2007 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <unistd.h>
+
+/* Get GetFileType.  The replacement lseek is only used on mingw, so
+   this include can be unconditional.  */
+#include <windows.h>
+#include <errno.h>
+
+#undef lseek
+
+off_t
+rpl_lseek (int fd, off_t offset, int whence)
+{
+  /* mingw lseek mistakenly succeeds on pipes, sockets, and terminals.  */
+  if (GetFileType ((HANDLE) _get_osfhandle (fd)) != FILE_TYPE_DISK)
+    {
+      errno = ESPIPE;
+      return -1;
+    }
+  return lseek (fd, offset, whence);
+}
--- a/lib/stdio_.h
+++ b/lib/stdio_.h
@@ -42,9 +42,7 @@
 #include <stdarg.h>
 #include <stddef.h>
 
-#if (@GNULIB_FFLUSH@ && @REPLACE_FFLUSH@)                               \
-  || (@GNULIB_FSEEKO@ && (!@HAVE_FSEEKO@ || @REPLACE_FSEEKO@))          \
-  || (@GNULIB_FTELLO@ && (!@HAVE_FTELLO@ || @REPLACE_FTELLO@))
+#if (@GNULIB_FSEEKO@ && @REPLACE_FSEEKO@) || (@GNULIB_FTELLO@ && @REPLACE_FTELLO@)
 /* Get off_t.  */
 # include <sys/types.h>
 #endif
@@ -218,16 +216,13 @@
 # endif
 #endif
 
-#if (@GNULIB_FFLUSH@ && @REPLACE_FFLUSH@) || (@GNULIB_FSEEKO@ && @REPLACE_FSEEKO@)
-/* Provide fseek, fseeko functions that are aware of a preceding fflush().  */
-# define fseeko rpl_fseeko
+#if @GNULIB_FSEEKO@
+# if @REPLACE_FSEEKO@
+/* Provide fseek, fseeko functions that are aware of a preceding
+   fflush(), and which detect pipes.  */
+#  define fseeko rpl_fseeko
 extern int fseeko (FILE *fp, off_t offset, int whence);
-# define fseek(fp, offset, whence) fseeko (fp, (off_t)(offset), whence)
-#elif @GNULIB_FSEEKO@
-# if !@HAVE_FSEEKO@
-/* Assume 'off_t' is the same type as 'long'.  */
-typedef int verify_fseeko_types[2 * (sizeof (off_t) == sizeof (long)) - 1];
-#  define fseeko fseek
+#  define fseek(fp, offset, whence) fseeko (fp, (off_t)(offset), whence)
 # endif
 #elif defined GNULIB_POSIXCHECK
 # undef fseeko
@@ -248,13 +243,10 @@
 #endif
 
 #if @GNULIB_FTELLO@
-# if !@HAVE_FTELLO@
-/* Assume 'off_t' is the same type as 'long'.  */
-typedef int verify_ftello_types[2 * (sizeof (off_t) == sizeof (long)) - 1];
-#  define ftello ftell
-# elif @REPLACE_FTELLO@
+# if @REPLACE_FTELLO@
 #  define ftello rpl_ftello
 extern off_t ftello (FILE *fp);
+#  define ftell(fp) ftello (fp)
 # endif
 #elif defined GNULIB_POSIXCHECK
 # undef ftello
--- a/lib/unistd_.h
+++ b/lib/unistd_.h
@@ -176,6 +176,25 @@
 #endif
 
 
+#if @GNULIB_LSEEK@
+# if @REPLACE_LSEEK@
+/* Set the offset of FD relative to SEEK_SET, SEEK_CUR, or SEEK_END.
+   Return the new offset if successful, otherwise -1 and errno set.
+   See the POSIX:2001 specification
+   <http://www.opengroup.org/susv3xsh/lseek.html>.  */
+#  define lseek rpl_lseek
+   extern off_t lseek (int fd, off_t offset, int whence);
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef lseek
+# define lseek(f,o,w) \
+    (GL_LINK_WARNING ("lseek does not fail with ESPIPE on non-seekable " \
+                      "files on some systems - " \
+                      "use gnulib module lseek for portability"), \
+     lseek (f, o, w))
+#endif
+
+
 #if @GNULIB_READLINK@
 /* Read the contents of the symbolic link FILE and place the first BUFSIZE
    bytes of it into BUF.  Return the number of bytes placed into BUF if
--- a/m4/fflush.m4
+++ b/m4/fflush.m4
@@ -1,4 +1,4 @@
-#serial 3
+# fflush.m4 serial 4
 
 # Copyright (C) 2007 Free Software Foundation, Inc.
 # This file is free software; the Free Software Foundation
@@ -20,9 +20,9 @@
 #include <stdio.h>
 #include <unistd.h>
        ]], [[FILE *f = fopen ("conftest.txt", "r");
-         char buffer[10];
+	 char buffer[10];
 	 int fd = fileno (f);
-         if (!f || 0 > fd || fread (buffer, 1, 5, f) != 5)
+	 if (!f || 0 > fd || fread (buffer, 1, 5, f) != 5)
 	   return 2;
 	 /* For deterministic results, ensure f read a bigger buffer.  */
 	 if (lseek (fd, 0, SEEK_CUR) == 5)
@@ -48,4 +48,5 @@
   AC_LIBOBJ([fseeko])
   AC_REQUIRE([gl_STDIO_H_DEFAULTS])
   REPLACE_FFLUSH=1
+  REPLACE_FSEEKO=1
 ])
--- a/m4/fseeko.m4
+++ b/m4/fseeko.m4
@@ -1,4 +1,4 @@
-# fseeko.m4 serial 2
+# fseeko.m4 serial 3
 dnl Copyright (C) 2007 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -12,10 +12,11 @@
   AC_CACHE_CHECK([for fseeko], [gl_cv_func_fseeko],
     [
       AC_TRY_LINK([#include <stdio.h>], [fseeko (stdin, 0, 0);],
-        [gl_cv_func_fseeko=yes], [gl_cv_func_fseeko=no])
+	[gl_cv_func_fseeko=yes], [gl_cv_func_fseeko=no])
     ])
   if test $gl_cv_func_fseeko = no; then
     HAVE_FSEEKO=0
+    gl_REPLACE_FSEEKO
   elif test $gl_cv_var_stdin_large_offset = no; then
     gl_REPLACE_FSEEKO
   fi
--- a/m4/ftello.m4
+++ b/m4/ftello.m4
@@ -1,4 +1,4 @@
-# ftello.m4 serial 2
+# ftello.m4 serial 3
 dnl Copyright (C) 2007 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -12,10 +12,11 @@
   AC_CACHE_CHECK([for ftello], [gl_cv_func_ftello],
     [
       AC_TRY_LINK([#include <stdio.h>], [ftello (stdin);],
-        [gl_cv_func_ftello=yes], [gl_cv_func_ftello=no])
+	[gl_cv_func_ftello=yes], [gl_cv_func_ftello=no])
     ])
   if test $gl_cv_func_ftello = no; then
     HAVE_FTELLO=0
+    gl_REPLACE_FTELLO
   elif test $gl_cv_var_stdin_large_offset = no; then
     gl_REPLACE_FTELLO
   fi
new file mode 100644
--- /dev/null
+++ b/m4/lseek.m4
@@ -0,0 +1,30 @@
+# lseek.m4 serial 1
+dnl Copyright (C) 2007 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_LSEEK],
+[
+  AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
+  AC_REQUIRE([AC_PROG_CC])
+  AC_CACHE_CHECK([whether lseek detects pipes], [gl_cv_func_lseek_pipe],
+    [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include <unistd.h>],
+[#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+/* mingw mistakenly returns 0 when trying to seek on pipes.  */
+  Choke me.
+#endif])],
+      [gl_cv_func_lseek_pipe=yes], [gl_cv_func_lseek_pipe=no])])
+  if test $gl_cv_func_lseek_pipe = no; then
+    gl_REPLACE_LSEEK
+  fi
+])
+
+AC_DEFUN([gl_REPLACE_LSEEK],
+[
+  AC_LIBOBJ([lseek])
+  AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
+  REPLACE_LSEEK=1
+  AC_DEFINE([LSEEK_PIPE_BROKEN], [1],
+	    [Define to 1 if lseek does not detect pipes.])
+])
--- a/m4/unistd_h.m4
+++ b/m4/unistd_h.m4
@@ -1,4 +1,4 @@
-# unistd_h.m4 serial 6
+# unistd_h.m4 serial 7
 dnl Copyright (C) 2006-2007 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -39,6 +39,7 @@
   GNULIB_FTRUNCATE=0;     AC_SUBST([GNULIB_FTRUNCATE])
   GNULIB_GETCWD=0;        AC_SUBST([GNULIB_GETCWD])
   GNULIB_GETLOGIN_R=0;    AC_SUBST([GNULIB_GETLOGIN_R])
+  GNULIB_LSEEK=0;         AC_SUBST([GNULIB_LSEEK])
   GNULIB_READLINK=0;      AC_SUBST([GNULIB_READLINK])
   GNULIB_SLEEP=0;         AC_SUBST([GNULIB_SLEEP])
   dnl Assume proper GNU behavior unless another module says otherwise.
@@ -50,4 +51,5 @@
   REPLACE_CHOWN=0;        AC_SUBST([REPLACE_CHOWN])
   REPLACE_FCHDIR=0;       AC_SUBST([REPLACE_FCHDIR])
   REPLACE_GETCWD=0;       AC_SUBST([REPLACE_GETCWD])
+  REPLACE_LSEEK=0;        AC_SUBST([REPLACE_LSEEK])
 ])
--- a/modules/fflush
+++ b/modules/fflush
@@ -3,16 +3,16 @@
 
 Files:
 lib/fflush.c
-lib/fseeko.c
 m4/fflush.m4
-m4/fseeko.m4
 
 Depends-on:
 fpurge
 ftello
 freading
+lseek
 stdio
 unistd
+fseeko
 
 configure.ac-early:
 AC_REQUIRE([AC_FUNC_FSEEKO])
--- a/modules/fseeko
+++ b/modules/fseeko
@@ -6,6 +6,7 @@
 m4/fseeko.m4
 
 Depends-on:
+lseek
 stdio
 
 configure.ac-early:
--- a/modules/ftello
+++ b/modules/ftello
@@ -6,6 +6,7 @@
 m4/ftello.m4
 
 Depends-on:
+lseek
 stdio
 
 configure.ac-early:
new file mode 100644
--- /dev/null
+++ b/modules/lseek
@@ -0,0 +1,24 @@
+Description:
+lseek() function: Reposition a file descriptor.
+
+Files:
+lib/lseek.c
+m4/lseek.m4
+
+Depends-on:
+unistd
+
+configure.ac:
+gl_FUNC_LSEEK
+gl_UNISTD_MODULE_INDICATOR([lseek])
+
+Makefile.am:
+
+Include:
+<unistd.h>
+
+License:
+LGPL
+
+Maintainer:
+Eric Blake
new file mode 100644
--- /dev/null
+++ b/modules/lseek-tests
@@ -0,0 +1,13 @@
+Files:
+tests/test-lseek.c
+tests/test-lseek.sh
+
+Depends-on:
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-lseek.sh
+TESTS_ENVIRONMENT += EXEEXT='@EXEEXT@' srcdir='$(srcdir)'
+check_PROGRAMS += test-lseek
+EXTRA_DIST += test-lseek.sh
--- a/modules/stdio
+++ b/modules/stdio
@@ -46,9 +46,7 @@
 	      -e 's|@''REPLACE_VSPRINTF''@|$(REPLACE_VSPRINTF)|g' \
 	      -e 's|@''HAVE_VASPRINTF''@|$(HAVE_VASPRINTF)|g' \
 	      -e 's|@''REPLACE_VASPRINTF''@|$(REPLACE_VASPRINTF)|g' \
-	      -e 's|@''HAVE_FSEEKO''@|$(HAVE_FSEEKO)|g' \
 	      -e 's|@''REPLACE_FSEEKO''@|$(REPLACE_FSEEKO)|g' \
-	      -e 's|@''HAVE_FTELLO''@|$(HAVE_FTELLO)|g' \
 	      -e 's|@''REPLACE_FTELLO''@|$(REPLACE_FTELLO)|g' \
 	      -e 's|@''REPLACE_FFLUSH''@|$(REPLACE_FFLUSH)|g' \
 	      -e '/definition of GL_LINK_WARNING/r $(LINK_WARNING_H)' \
--- a/modules/unistd
+++ b/modules/unistd
@@ -29,6 +29,7 @@
 	      -e 's|@''GNULIB_FTRUNCATE''@|$(GNULIB_FTRUNCATE)|g' \
 	      -e 's|@''GNULIB_GETCWD''@|$(GNULIB_GETCWD)|g' \
 	      -e 's|@''GNULIB_GETLOGIN_R''@|$(GNULIB_GETLOGIN_R)|g' \
+	      -e 's|@''GNULIB_LSEEK''@|$(GNULIB_LSEEK)|g' \
 	      -e 's|@''GNULIB_READLINK''@|$(GNULIB_READLINK)|g' \
 	      -e 's|@''GNULIB_SLEEP''@|$(GNULIB_SLEEP)|g' \
 	      -e 's|@''HAVE_DUP2''@|$(HAVE_DUP2)|g' \
@@ -39,6 +40,7 @@
 	      -e 's|@''REPLACE_CHOWN''@|$(REPLACE_CHOWN)|g' \
 	      -e 's|@''REPLACE_FCHDIR''@|$(REPLACE_FCHDIR)|g' \
 	      -e 's|@''REPLACE_GETCWD''@|$(REPLACE_GETCWD)|g' \
+	      -e 's|@''REPLACE_LSEEK''@|$(REPLACE_LSEEK)|g' \
 	      < $(srcdir)/unistd_.h; \
 	} > $@-t
 	mv $@-t $@
--- a/tests/test-fseeko.c
+++ b/tests/test-fseeko.c
@@ -25,8 +25,12 @@
 #include <sys/types.h>
 
 int
-main ()
+main (int argc, char **argv)
 {
-  /* This test assumes stdin is seekable.  */
-  return fseeko (stdin, (off_t)0, SEEK_CUR) != 0;
+  /* Assume stdin is seekable iff argc > 1.  */
+  int expected = argc > 1 ? 0 : -1;
+  /* Exit with success only if fseek/fseeko agree.  */
+  int r1 = fseeko (stdin, (off_t)0, SEEK_CUR);
+  int r2 = fseek (stdin, (long)0, SEEK_CUR);
+  return ! (r1 == r2 && r1 == expected);
 }
--- a/tests/test-fseeko.sh
+++ b/tests/test-fseeko.sh
@@ -1,3 +1,5 @@
 #!/bin/sh
 
-./test-fseeko${EXEEXT} < "$srcdir/test-fseeko.sh"
+./test-fseeko${EXEEXT} 1 < "$srcdir/test-fseeko.sh" || exit 1
+echo hi | ./test-fseeko${EXEEXT} || exit 1
+exit 0
--- a/tests/test-ftello.c
+++ b/tests/test-ftello.c
@@ -25,9 +25,12 @@
 #include <sys/types.h>
 
 int
-main ()
+main (int argc, char **argv)
 {
-  /* This test assumes stdin is seekable.  */
-  off_t pos = ftello (stdin);
-  return pos < 0;
+  /* Assume stdin is seekable iff argc > 1.  */
+  int expected = argc > 1 ? 0 : -1;
+  /* Exit with success only if ftell/ftello agree.  */
+  off_t pos1 = ftello (stdin);
+  long pos2 = ftell (stdin);
+  return ! (pos1 == pos2 && pos1 == expected);
 }
--- a/tests/test-ftello.sh
+++ b/tests/test-ftello.sh
@@ -1,3 +1,5 @@
 #!/bin/sh
 
-./test-ftello${EXEEXT} < "$srcdir/test-ftello.sh"
+./test-ftello${EXEEXT} 1 < "$srcdir/test-ftello.sh" || exit 1
+echo hi | ./test-ftello${EXEEXT} || exit 1
+exit 0
new file mode 100644
--- /dev/null
+++ b/tests/test-lseek.c
@@ -0,0 +1,29 @@
+/* Test of lseek() function.
+   Copyright (C) 2007 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+/* Written by Eric Blake, 2007.  */
+
+#include <config.h>
+
+#include <unistd.h>
+
+int
+main ()
+{
+  /* Exit with success only if stdin is seekable.  */
+  return lseek (0, (off_t)0, SEEK_CUR) < 0;
+}
new file mode 100755
--- /dev/null
+++ b/tests/test-lseek.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+# Succeed on seekable stdin
+./test-lseek${EXEEXT} < "$srcdir/test-lseek.sh" || exit 1
+# Fail on pipe stdin
+echo hi | ./test-lseek${EXEEXT} && exit 1
+exit 0