dup2.c revision 1.1.1.2 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