1 /* Duplicate an open file descriptor to a specified file descriptor. 2 3 Copyright (C) 1999, 2004-2007, 2009-2011 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 (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ 29 /* Get declarations of the Win32 API functions. */ 30 # define WIN32_LEAN_AND_MEAN 31 # include <windows.h> 32 #endif 33 34 #if HAVE_DUP2 35 36 # undef dup2 37 38 int 39 rpl_dup2 (int fd, int desired_fd) 40 { 41 int result; 42 # if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ 43 /* If fd is closed, mingw hangs on dup2 (fd, fd). If fd is open, 44 dup2 (fd, fd) returns 0, but all further attempts to use fd in 45 future dup2 calls will hang. */ 46 if (fd == desired_fd) 47 { 48 if ((HANDLE) _get_osfhandle (fd) == INVALID_HANDLE_VALUE) 49 { 50 errno = EBADF; 51 return -1; 52 } 53 return fd; 54 } 55 /* Wine 1.0.1 return 0 when desired_fd is negative but not -1: 56 http://bugs.winehq.org/show_bug.cgi?id=21289 */ 57 if (desired_fd < 0) 58 { 59 errno = EBADF; 60 return -1; 61 } 62 # elif !defined __linux__ 63 /* On Haiku, dup2 (fd, fd) mistakenly clears FD_CLOEXEC. */ 64 if (fd == desired_fd) 65 return fcntl (fd, F_GETFL) == -1 ? -1 : fd; 66 # endif 67 result = dup2 (fd, desired_fd); 68 # ifdef __linux__ 69 /* Correct a Linux return value. 70 <http://git.kernel.org/?p=linux/kernel/git/stable/linux-2.6.30.y.git;a=commitdiff;h=2b79bc4f7ebbd5af3c8b867968f9f15602d5f802> 71 */ 72 if (fd == desired_fd && result == (unsigned int) -EBADF) 73 { 74 errno = EBADF; 75 result = -1; 76 } 77 # endif 78 if (result == 0) 79 result = desired_fd; 80 /* Correct a cygwin 1.5.x errno value. */ 81 else if (result == -1 && errno == EMFILE) 82 errno = EBADF; 83 # if REPLACE_FCHDIR 84 if (fd != desired_fd && result != -1) 85 result = _gl_register_dup (fd, result); 86 # endif 87 return result; 88 } 89 90 #else /* !HAVE_DUP2 */ 91 92 /* On older platforms, dup2 did not exist. */ 93 94 # ifndef F_DUPFD 95 static int 96 dupfd (int fd, int desired_fd) 97 { 98 int duplicated_fd = dup (fd); 99 if (duplicated_fd < 0 || duplicated_fd == desired_fd) 100 return duplicated_fd; 101 else 102 { 103 int r = dupfd (fd, desired_fd); 104 int e = errno; 105 close (duplicated_fd); 106 errno = e; 107 return r; 108 } 109 } 110 # endif 111 112 int 113 dup2 (int fd, int desired_fd) 114 { 115 int result = fcntl (fd, F_GETFL) < 0 ? -1 : fd; 116 if (result == -1 || fd == desired_fd) 117 return result; 118 close (desired_fd); 119 # ifdef F_DUPFD 120 result = fcntl (fd, F_DUPFD, desired_fd); 121 # if REPLACE_FCHDIR 122 if (0 <= result) 123 result = _gl_register_dup (fd, result); 124 # endif 125 # else 126 result = dupfd (fd, desired_fd); 127 # endif 128 if (result == -1 && (errno == EMFILE || errno == EINVAL)) 129 errno = EBADF; 130 return result; 131 } 132 #endif /* !HAVE_DUP2 */ 133