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