dup2: work around a Linux bug.
authorBruno Haible <bruno@clisp.org>
Tue, 25 Aug 2009 08:52:51 +0000 (10:52 +0200)
committerBruno Haible <bruno@clisp.org>
Tue, 25 Aug 2009 08:52:51 +0000 (10:52 +0200)
ChangeLog
doc/posix-functions/dup2.texi
lib/dup2.c
m4/dup2.m4

index cd6a1e6..952e5c8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2009-08-25  Bruno Haible  <bruno@clisp.org>
+
+       dup2: work around a Linux bug.
+       * m4/dup2.m4 (gl_FUNC_DUP2): Test for the Linux bug.
+       * lib/dup2.c (rpl_dup2): Correct the return value if it is -EBADF.
+       * doc/posix-functions/dup2.texi: Mention the Linux bug.
+       Reported by Simon Josefsson.
+
 2009-08-25  Jim Meyering  <meyering@redhat.com>
 
        libguestfs uses gnulib
index c8f2ca1..6509f0e 100644 (file)
@@ -17,10 +17,14 @@ This function can hang when duplicating an fd to itself on some platforms:
 mingw.
 
 @item
-This function returns 0 for dup2 (1, 1) on some platforms:
+This function returns 0 for @code(dup2 (1, 1)} on some platforms:
 Cygwin 1.5.x.
 
 @item
+This function may return @code{-EBADF} instead of @code{-1} on some platforms:
+Linux releases between July 2008 and May 2009.
+
+@item
 This function is missing on some older platforms.
 @end itemize
 
index 6b6f45d..fb3ffb0 100644 (file)
@@ -55,6 +55,16 @@ rpl_dup2 (int fd, int desired_fd)
     }
 # endif
   result = dup2 (fd, desired_fd);
+# ifdef __linux__
+  /* Correct a Linux return value.
+     <http://git.kernel.org/?p=linux/kernel/git/stable/linux-2.6.30.y.git;a=commitdiff;h=2b79bc4f7ebbd5af3c8b867968f9f15602d5f802>
+   */
+  if (fd == desired_fd && result == (unsigned int) -EBADF)
+    {
+      errno = EBADF;
+      result = -1;
+    }
+# endif
   if (result == 0)
     result = desired_fd;
   /* Correct a cygwin 1.5.x errno value.  */
index 2abc74c..2e846c0 100644 (file)
@@ -1,4 +1,4 @@
-#serial 6
+#serial 7
 dnl Copyright (C) 2002, 2005, 2007, 2009 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -14,17 +14,28 @@ AC_DEFUN([gl_FUNC_DUP2],
     AC_LIBOBJ([dup2])
   else
     AC_CACHE_CHECK([whether dup2 works], [gl_cv_func_dup2_works],
-      [AC_RUN_IFELSE([AC_LANG_PROGRAM([[
-#include <unistd.h>
-]], [return 1 - dup2 (1, 1);])],
+      [AC_RUN_IFELSE([
+         AC_LANG_PROGRAM([[#include <unistd.h>]],
+           [if (dup2 (1, 1) == 0)
+              return 1;
+            close (0);
+            if (dup2 (0, 0) != -1)
+              return 1;
+            return 0;
+           ])
+        ],
        [gl_cv_func_dup2_works=yes], [gl_cv_func_dup2_works=no],
        [case "$host_os" in
           mingw*) # on this platform, dup2 always returns 0 for success
             gl_cv_func_dup2_works=no;;
           cygwin*) # on cygwin 1.5.x, dup2(1,1) returns 0
             gl_cv_func_dup2_works=no;;
+          linux*) # On linux between 2008-07-27 and 2009-05-11, dup2 of a
+                  # closed fd may yield -EBADF instead of -1 / errno=EBADF.
+            gl_cv_func_dup2_works=no;;
           *) gl_cv_func_dup2_works=yes;;
-        esac])])
+        esac])
+      ])
     if test "$gl_cv_func_dup2_works" = no; then
       REPLACE_DUP2=1
       AC_LIBOBJ([dup2])