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