Home | History | Annotate | Line # | Download | only in import
dup2.c revision 1.1.1.1.2.1
      1 /* Duplicate an open file descriptor to a specified file descriptor.
      2 
      3    Copyright (C) 1999, 2004-2007, 2009-2022 Free Software Foundation, Inc.
      4 
      5    This file is free software: you can redistribute it and/or modify
      6    it under the terms of the GNU Lesser General Public License as
      7    published by the Free Software Foundation; either version 2.1 of the
      8    License, or (at your option) any later version.
      9 
     10    This file 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 Lesser General Public License for more details.
     14 
     15    You should have received a copy of the GNU Lesser General Public License
     16    along with this program.  If not, see <https://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 #undef dup2
     29 
     30 #if defined _WIN32 && ! defined __CYGWIN__
     31 
     32 /* Get declarations of the native Windows API functions.  */
     33 # define WIN32_LEAN_AND_MEAN
     34 # include <windows.h>
     35 
     36 # if HAVE_MSVC_INVALID_PARAMETER_HANDLER
     37 #  include "msvc-inval.h"
     38 # endif
     39 
     40 /* Get _get_osfhandle.  */
     41 # if GNULIB_MSVC_NOTHROW
     42 #  include "msvc-nothrow.h"
     43 # else
     44 #  include <io.h>
     45 # endif
     46 
     47 # if HAVE_MSVC_INVALID_PARAMETER_HANDLER
     48 static int
     49 dup2_nothrow (int fd, int desired_fd)
     50 {
     51   int result;
     52 
     53   TRY_MSVC_INVAL
     54     {
     55       result = _dup2 (fd, desired_fd);
     56     }
     57   CATCH_MSVC_INVAL
     58     {
     59       errno = EBADF;
     60       result = -1;
     61     }
     62   DONE_MSVC_INVAL;
     63 
     64   return result;
     65 }
     66 # else
     67 #  define dup2_nothrow _dup2
     68 # endif
     69 
     70 static int
     71 ms_windows_dup2 (int fd, int desired_fd)
     72 {
     73   int result;
     74 
     75   /* If fd is closed, mingw hangs on dup2 (fd, fd).  If fd is open,
     76      dup2 (fd, fd) returns 0, but all further attempts to use fd in
     77      future dup2 calls will hang.  */
     78   if (fd == desired_fd)
     79     {
     80       if ((HANDLE) _get_osfhandle (fd) == INVALID_HANDLE_VALUE)
     81         {
     82           errno = EBADF;
     83           return -1;
     84         }
     85       return fd;
     86     }
     87 
     88   /* Wine 1.0.1 return 0 when desired_fd is negative but not -1:
     89      https://bugs.winehq.org/show_bug.cgi?id=21289 */
     90   if (desired_fd < 0)
     91     {
     92       errno = EBADF;
     93       return -1;
     94     }
     95 
     96   result = dup2_nothrow (fd, desired_fd);
     97 
     98   if (result == 0)
     99     result = desired_fd;
    100 
    101   return result;
    102 }
    103 
    104 # define dup2 ms_windows_dup2
    105 
    106 #elif defined __KLIBC__
    107 
    108 # include <InnoTekLIBC/backend.h>
    109 
    110 static int
    111 klibc_dup2dirfd (int fd, int desired_fd)
    112 {
    113   int tempfd;
    114   int dupfd;
    115 
    116   tempfd = open ("NUL", O_RDONLY);
    117   if (tempfd == -1)
    118     return -1;
    119 
    120   if (tempfd == desired_fd)
    121     {
    122       close (tempfd);
    123 
    124       char path[_MAX_PATH];
    125       if (__libc_Back_ioFHToPath (fd, path, sizeof (path)))
    126         return -1;
    127 
    128       return open(path, O_RDONLY);
    129     }
    130 
    131   dupfd = klibc_dup2dirfd (fd, desired_fd);
    132 
    133   close (tempfd);
    134 
    135   return dupfd;
    136 }
    137 
    138 static int
    139 klibc_dup2 (int fd, int desired_fd)
    140 {
    141   int dupfd;
    142   struct stat sbuf;
    143 
    144   dupfd = dup2 (fd, desired_fd);
    145   if (dupfd == -1 && errno == ENOTSUP \
    146       && !fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode))
    147     {
    148       close (desired_fd);
    149 
    150       return klibc_dup2dirfd (fd, desired_fd);
    151     }
    152 
    153   return dupfd;
    154 }
    155 
    156 # define dup2 klibc_dup2
    157 #endif
    158 
    159 int
    160 rpl_dup2 (int fd, int desired_fd)
    161 {
    162   int result;
    163 
    164 #ifdef F_GETFL
    165   /* On Linux kernels 2.6.26-2.6.29, dup2 (fd, fd) returns -EBADF.
    166      On Cygwin 1.5.x, dup2 (1, 1) returns 0.
    167      On Cygwin 1.7.17, dup2 (1, -1) dumps core.
    168      On Cygwin 1.7.25, dup2 (1, 256) can dump core.
    169      On Haiku, dup2 (fd, fd) mistakenly clears FD_CLOEXEC.  */
    170 # if HAVE_SETDTABLESIZE
    171   setdtablesize (desired_fd + 1);
    172 # endif
    173   if (desired_fd < 0)
    174     fd = desired_fd;
    175   if (fd == desired_fd)
    176     return fcntl (fd, F_GETFL) == -1 ? -1 : fd;
    177 #endif
    178 
    179   result = dup2 (fd, desired_fd);
    180 
    181   /* Correct an errno value on FreeBSD 6.1 and Cygwin 1.5.x.  */
    182   if (result == -1 && errno == EMFILE)
    183     errno = EBADF;
    184 #if REPLACE_FCHDIR
    185   if (fd != desired_fd && result != -1)
    186     result = _gl_register_dup (fd, result);
    187 #endif
    188   return result;
    189 }
    190