Home | History | Annotate | Download | only in lib
      1 /* Duplicate an open file descriptor to a specified file descriptor.
      2 
      3    Copyright (C) 1999, 2004-2007, 2009-2012 Free Software Foundation, Inc.
      4 
      5    This program is free software: you can redistribute it and/or modify
      6    it under the terms of the GNU General Public License as published by
      7    the Free Software Foundation; either version 3 of the License, or
      8    (at your option) any later version.
      9 
     10    This program is distributed in the hope that it will be useful,
     11    but WITHOUT ANY WARRANTY; without even the implied warranty of
     12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13    GNU General Public License for more details.
     14 
     15    You should have received a copy of the GNU General Public License
     16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     17 
     18 /* written by Paul Eggert */
     19 
     20 #include <config.h>
     21 
     22 /* Specification.  */
     23 #include <unistd.h>
     24 
     25 #include <errno.h>
     26 #include <fcntl.h>
     27 
     28 #if HAVE_DUP2
     29 
     30 # undef dup2
     31 
     32 # if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
     33 
     34 /* Get declarations of the native Windows API functions.  */
     35 #  define WIN32_LEAN_AND_MEAN
     36 #  include <windows.h>
     37 
     38 #  include "msvc-inval.h"
     39 
     40 /* Get _get_osfhandle.  */
     41 #  include "msvc-nothrow.h"
     42 
     43 static int
     44 ms_windows_dup2 (int fd, int desired_fd)
     45 {
     46   int result;
     47 
     48   /* If fd is closed, mingw hangs on dup2 (fd, fd).  If fd is open,
     49      dup2 (fd, fd) returns 0, but all further attempts to use fd in
     50      future dup2 calls will hang.  */
     51   if (fd == desired_fd)
     52     {
     53       if ((HANDLE) _get_osfhandle (fd) == INVALID_HANDLE_VALUE)
     54         {
     55           errno = EBADF;
     56           return -1;
     57         }
     58       return fd;
     59     }
     60 
     61   /* Wine 1.0.1 return 0 when desired_fd is negative but not -1:
     62      http://bugs.winehq.org/show_bug.cgi?id=21289 */
     63   if (desired_fd < 0)
     64     {
     65       errno = EBADF;
     66       return -1;
     67     }
     68 
     69   TRY_MSVC_INVAL
     70     {
     71       result = dup2 (fd, desired_fd);
     72     }
     73   CATCH_MSVC_INVAL
     74     {
     75       errno = EBADF;
     76       result = -1;
     77     }
     78   DONE_MSVC_INVAL;
     79 
     80   if (result == 0)
     81     result = desired_fd;
     82 
     83   return result;
     84 }
     85 
     86 #  define dup2 ms_windows_dup2
     87 
     88 # endif
     89 
     90 int
     91 rpl_dup2 (int fd, int desired_fd)
     92 {
     93   int result;
     94 
     95 # ifdef F_GETFL
     96   /* On Linux kernels 2.6.26-2.6.29, dup2 (fd, fd) returns -EBADF.
     97      On Cygwin 1.5.x, dup2 (1, 1) returns 0.
     98      On Haiku, dup2 (fd, fd) mistakenly clears FD_CLOEXEC.  */
     99   if (fd == desired_fd)
    100     return fcntl (fd, F_GETFL) == -1 ? -1 : fd;
    101 # endif
    102 
    103   result = dup2 (fd, desired_fd);
    104 
    105   /* Correct an errno value on FreeBSD 6.1 and Cygwin 1.5.x.  */
    106   if (result == -1 && errno == EMFILE)
    107     errno = EBADF;
    108 # if REPLACE_FCHDIR
    109   if (fd != desired_fd && result != -1)
    110     result = _gl_register_dup (fd, result);
    111 # endif
    112   return result;
    113 }
    114 
    115 #else /* !HAVE_DUP2 */
    116 
    117 /* On older platforms, dup2 did not exist.  */
    118 
    119 # ifndef F_DUPFD
    120 static int
    121 dupfd (int fd, int desired_fd)
    122 {
    123   int duplicated_fd = dup (fd);
    124   if (duplicated_fd < 0 || duplicated_fd == desired_fd)
    125     return duplicated_fd;
    126   else
    127     {
    128       int r = dupfd (fd, desired_fd);
    129       int e = errno;
    130       close (duplicated_fd);
    131       errno = e;
    132       return r;
    133     }
    134 }
    135 # endif
    136 
    137 int
    138 dup2 (int fd, int desired_fd)
    139 {
    140   int result = fcntl (fd, F_GETFL) < 0 ? -1 : fd;
    141   if (result == -1 || fd == desired_fd)
    142     return result;
    143   close (desired_fd);
    144 # ifdef F_DUPFD
    145   result = fcntl (fd, F_DUPFD, desired_fd);
    146 #  if REPLACE_FCHDIR
    147   if (0 <= result)
    148     result = _gl_register_dup (fd, result);
    149 #  endif
    150 # else
    151   result = dupfd (fd, desired_fd);
    152 # endif
    153   if (result == -1 && (errno == EMFILE || errno == EINVAL))
    154     errno = EBADF;
    155   return result;
    156 }
    157 #endif /* !HAVE_DUP2 */
    158