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