Home | History | Annotate | Line # | Download | only in import
dup2.c revision 1.1
      1  1.1  christos /* Duplicate an open file descriptor to a specified file descriptor.
      2  1.1  christos 
      3  1.1  christos    Copyright (C) 1999, 2004-2007, 2009-2020 Free Software Foundation, Inc.
      4  1.1  christos 
      5  1.1  christos    This program is free software: you can redistribute it and/or modify
      6  1.1  christos    it under the terms of the GNU General Public License as published by
      7  1.1  christos    the Free Software Foundation; either version 3 of the License, or
      8  1.1  christos    (at your option) any later version.
      9  1.1  christos 
     10  1.1  christos    This program is distributed in the hope that it will be useful,
     11  1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  1.1  christos    GNU General Public License for more details.
     14  1.1  christos 
     15  1.1  christos    You should have received a copy of the GNU General Public License
     16  1.1  christos    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
     17  1.1  christos 
     18  1.1  christos /* written by Paul Eggert */
     19  1.1  christos 
     20  1.1  christos #include <config.h>
     21  1.1  christos 
     22  1.1  christos /* Specification.  */
     23  1.1  christos #include <unistd.h>
     24  1.1  christos 
     25  1.1  christos #include <errno.h>
     26  1.1  christos #include <fcntl.h>
     27  1.1  christos 
     28  1.1  christos #if HAVE_DUP2
     29  1.1  christos 
     30  1.1  christos # undef dup2
     31  1.1  christos 
     32  1.1  christos # if defined _WIN32 && ! defined __CYGWIN__
     33  1.1  christos 
     34  1.1  christos /* Get declarations of the native Windows API functions.  */
     35  1.1  christos #  define WIN32_LEAN_AND_MEAN
     36  1.1  christos #  include <windows.h>
     37  1.1  christos 
     38  1.1  christos #  if HAVE_MSVC_INVALID_PARAMETER_HANDLER
     39  1.1  christos #   include "msvc-inval.h"
     40  1.1  christos #  endif
     41  1.1  christos 
     42  1.1  christos /* Get _get_osfhandle.  */
     43  1.1  christos #  if GNULIB_MSVC_NOTHROW
     44  1.1  christos #   include "msvc-nothrow.h"
     45  1.1  christos #  else
     46  1.1  christos #   include <io.h>
     47  1.1  christos #  endif
     48  1.1  christos 
     49  1.1  christos #  if HAVE_MSVC_INVALID_PARAMETER_HANDLER
     50  1.1  christos static int
     51  1.1  christos dup2_nothrow (int fd, int desired_fd)
     52  1.1  christos {
     53  1.1  christos   int result;
     54  1.1  christos 
     55  1.1  christos   TRY_MSVC_INVAL
     56  1.1  christos     {
     57  1.1  christos       result = dup2 (fd, desired_fd);
     58  1.1  christos     }
     59  1.1  christos   CATCH_MSVC_INVAL
     60  1.1  christos     {
     61  1.1  christos       errno = EBADF;
     62  1.1  christos       result = -1;
     63  1.1  christos     }
     64  1.1  christos   DONE_MSVC_INVAL;
     65  1.1  christos 
     66  1.1  christos   return result;
     67  1.1  christos }
     68  1.1  christos #  else
     69  1.1  christos #   define dup2_nothrow dup2
     70  1.1  christos #  endif
     71  1.1  christos 
     72  1.1  christos static int
     73  1.1  christos ms_windows_dup2 (int fd, int desired_fd)
     74  1.1  christos {
     75  1.1  christos   int result;
     76  1.1  christos 
     77  1.1  christos   /* If fd is closed, mingw hangs on dup2 (fd, fd).  If fd is open,
     78  1.1  christos      dup2 (fd, fd) returns 0, but all further attempts to use fd in
     79  1.1  christos      future dup2 calls will hang.  */
     80  1.1  christos   if (fd == desired_fd)
     81  1.1  christos     {
     82  1.1  christos       if ((HANDLE) _get_osfhandle (fd) == INVALID_HANDLE_VALUE)
     83  1.1  christos         {
     84  1.1  christos           errno = EBADF;
     85  1.1  christos           return -1;
     86  1.1  christos         }
     87  1.1  christos       return fd;
     88  1.1  christos     }
     89  1.1  christos 
     90  1.1  christos   /* Wine 1.0.1 return 0 when desired_fd is negative but not -1:
     91  1.1  christos      https://bugs.winehq.org/show_bug.cgi?id=21289 */
     92  1.1  christos   if (desired_fd < 0)
     93  1.1  christos     {
     94  1.1  christos       errno = EBADF;
     95  1.1  christos       return -1;
     96  1.1  christos     }
     97  1.1  christos 
     98  1.1  christos   result = dup2_nothrow (fd, desired_fd);
     99  1.1  christos 
    100  1.1  christos   if (result == 0)
    101  1.1  christos     result = desired_fd;
    102  1.1  christos 
    103  1.1  christos   return result;
    104  1.1  christos }
    105  1.1  christos 
    106  1.1  christos #  define dup2 ms_windows_dup2
    107  1.1  christos 
    108  1.1  christos # elif defined __KLIBC__
    109  1.1  christos 
    110  1.1  christos #  include <InnoTekLIBC/backend.h>
    111  1.1  christos 
    112  1.1  christos static int
    113  1.1  christos klibc_dup2dirfd (int fd, int desired_fd)
    114  1.1  christos {
    115  1.1  christos   int tempfd;
    116  1.1  christos   int dupfd;
    117  1.1  christos 
    118  1.1  christos   tempfd = open ("NUL", O_RDONLY);
    119  1.1  christos   if (tempfd == -1)
    120  1.1  christos     return -1;
    121  1.1  christos 
    122  1.1  christos   if (tempfd == desired_fd)
    123  1.1  christos     {
    124  1.1  christos       close (tempfd);
    125  1.1  christos 
    126  1.1  christos       char path[_MAX_PATH];
    127  1.1  christos       if (__libc_Back_ioFHToPath (fd, path, sizeof (path)))
    128  1.1  christos         return -1;
    129  1.1  christos 
    130  1.1  christos       return open(path, O_RDONLY);
    131  1.1  christos     }
    132  1.1  christos 
    133  1.1  christos   dupfd = klibc_dup2dirfd (fd, desired_fd);
    134  1.1  christos 
    135  1.1  christos   close (tempfd);
    136  1.1  christos 
    137  1.1  christos   return dupfd;
    138  1.1  christos }
    139  1.1  christos 
    140  1.1  christos static int
    141  1.1  christos klibc_dup2 (int fd, int desired_fd)
    142  1.1  christos {
    143  1.1  christos   int dupfd;
    144  1.1  christos   struct stat sbuf;
    145  1.1  christos 
    146  1.1  christos   dupfd = dup2 (fd, desired_fd);
    147  1.1  christos   if (dupfd == -1 && errno == ENOTSUP \
    148  1.1  christos       && !fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode))
    149  1.1  christos     {
    150  1.1  christos       close (desired_fd);
    151  1.1  christos 
    152  1.1  christos       return klibc_dup2dirfd (fd, desired_fd);
    153  1.1  christos     }
    154  1.1  christos 
    155  1.1  christos   return dupfd;
    156  1.1  christos }
    157  1.1  christos 
    158  1.1  christos #  define dup2 klibc_dup2
    159  1.1  christos # endif
    160  1.1  christos 
    161  1.1  christos int
    162  1.1  christos rpl_dup2 (int fd, int desired_fd)
    163  1.1  christos {
    164  1.1  christos   int result;
    165  1.1  christos 
    166  1.1  christos # ifdef F_GETFL
    167  1.1  christos   /* On Linux kernels 2.6.26-2.6.29, dup2 (fd, fd) returns -EBADF.
    168  1.1  christos      On Cygwin 1.5.x, dup2 (1, 1) returns 0.
    169  1.1  christos      On Cygwin 1.7.17, dup2 (1, -1) dumps core.
    170  1.1  christos      On Cygwin 1.7.25, dup2 (1, 256) can dump core.
    171  1.1  christos      On Haiku, dup2 (fd, fd) mistakenly clears FD_CLOEXEC.  */
    172  1.1  christos #  if HAVE_SETDTABLESIZE
    173  1.1  christos   setdtablesize (desired_fd + 1);
    174  1.1  christos #  endif
    175  1.1  christos   if (desired_fd < 0)
    176  1.1  christos     fd = desired_fd;
    177  1.1  christos   if (fd == desired_fd)
    178  1.1  christos     return fcntl (fd, F_GETFL) == -1 ? -1 : fd;
    179  1.1  christos # endif
    180  1.1  christos 
    181  1.1  christos   result = dup2 (fd, desired_fd);
    182  1.1  christos 
    183  1.1  christos   /* Correct an errno value on FreeBSD 6.1 and Cygwin 1.5.x.  */
    184  1.1  christos   if (result == -1 && errno == EMFILE)
    185  1.1  christos     errno = EBADF;
    186  1.1  christos # if REPLACE_FCHDIR
    187  1.1  christos   if (fd != desired_fd && result != -1)
    188  1.1  christos     result = _gl_register_dup (fd, result);
    189  1.1  christos # endif
    190  1.1  christos   return result;
    191  1.1  christos }
    192  1.1  christos 
    193  1.1  christos #else /* !HAVE_DUP2 */
    194  1.1  christos 
    195  1.1  christos /* On older platforms, dup2 did not exist.  */
    196  1.1  christos 
    197  1.1  christos # ifndef F_DUPFD
    198  1.1  christos static int
    199  1.1  christos dupfd (int fd, int desired_fd)
    200  1.1  christos {
    201  1.1  christos   int duplicated_fd = dup (fd);
    202  1.1  christos   if (duplicated_fd < 0 || duplicated_fd == desired_fd)
    203  1.1  christos     return duplicated_fd;
    204  1.1  christos   else
    205  1.1  christos     {
    206  1.1  christos       int r = dupfd (fd, desired_fd);
    207  1.1  christos       int e = errno;
    208  1.1  christos       close (duplicated_fd);
    209  1.1  christos       errno = e;
    210  1.1  christos       return r;
    211  1.1  christos     }
    212  1.1  christos }
    213  1.1  christos # endif
    214  1.1  christos 
    215  1.1  christos int
    216  1.1  christos dup2 (int fd, int desired_fd)
    217  1.1  christos {
    218  1.1  christos   int result = fcntl (fd, F_GETFL) < 0 ? -1 : fd;
    219  1.1  christos   if (result == -1 || fd == desired_fd)
    220  1.1  christos     return result;
    221  1.1  christos   close (desired_fd);
    222  1.1  christos # ifdef F_DUPFD
    223  1.1  christos   result = fcntl (fd, F_DUPFD, desired_fd);
    224  1.1  christos #  if REPLACE_FCHDIR
    225  1.1  christos   if (0 <= result)
    226  1.1  christos     result = _gl_register_dup (fd, result);
    227  1.1  christos #  endif
    228  1.1  christos # else
    229  1.1  christos   result = dupfd (fd, desired_fd);
    230  1.1  christos # endif
    231  1.1  christos   if (result == -1 && (errno == EMFILE || errno == EINVAL))
    232  1.1  christos     errno = EBADF;
    233  1.1  christos   return result;
    234  1.1  christos }
    235  1.1  christos #endif /* !HAVE_DUP2 */
    236