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