18dffb485Schristos /* Duplicate an open file descriptor to a specified file descriptor.
28dffb485Schristos
3*4b169a6bSchristos Copyright (C) 1999, 2004-2007, 2009-2022 Free Software Foundation, Inc.
48dffb485Schristos
5*4b169a6bSchristos This file is free software: you can redistribute it and/or modify
6*4b169a6bSchristos it under the terms of the GNU Lesser General Public License as
7*4b169a6bSchristos published by the Free Software Foundation; either version 2.1 of the
8*4b169a6bSchristos License, or (at your option) any later version.
98dffb485Schristos
10*4b169a6bSchristos This file is distributed in the hope that it will be useful,
118dffb485Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
128dffb485Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13*4b169a6bSchristos GNU Lesser General Public License for more details.
148dffb485Schristos
15*4b169a6bSchristos You should have received a copy of the GNU Lesser General Public License
168dffb485Schristos along with this program. If not, see <https://www.gnu.org/licenses/>. */
178dffb485Schristos
188dffb485Schristos /* written by Paul Eggert */
198dffb485Schristos
208dffb485Schristos #include <config.h>
218dffb485Schristos
228dffb485Schristos /* Specification. */
238dffb485Schristos #include <unistd.h>
248dffb485Schristos
258dffb485Schristos #include <errno.h>
268dffb485Schristos #include <fcntl.h>
278dffb485Schristos
288dffb485Schristos #undef dup2
298dffb485Schristos
308dffb485Schristos #if defined _WIN32 && ! defined __CYGWIN__
318dffb485Schristos
328dffb485Schristos /* Get declarations of the native Windows API functions. */
338dffb485Schristos # define WIN32_LEAN_AND_MEAN
348dffb485Schristos # include <windows.h>
358dffb485Schristos
368dffb485Schristos # if HAVE_MSVC_INVALID_PARAMETER_HANDLER
378dffb485Schristos # include "msvc-inval.h"
388dffb485Schristos # endif
398dffb485Schristos
408dffb485Schristos /* Get _get_osfhandle. */
418dffb485Schristos # if GNULIB_MSVC_NOTHROW
428dffb485Schristos # include "msvc-nothrow.h"
438dffb485Schristos # else
448dffb485Schristos # include <io.h>
458dffb485Schristos # endif
468dffb485Schristos
478dffb485Schristos # if HAVE_MSVC_INVALID_PARAMETER_HANDLER
488dffb485Schristos static int
dup2_nothrow(int fd,int desired_fd)498dffb485Schristos dup2_nothrow (int fd, int desired_fd)
508dffb485Schristos {
518dffb485Schristos int result;
528dffb485Schristos
538dffb485Schristos TRY_MSVC_INVAL
548dffb485Schristos {
55*4b169a6bSchristos result = _dup2 (fd, desired_fd);
568dffb485Schristos }
578dffb485Schristos CATCH_MSVC_INVAL
588dffb485Schristos {
598dffb485Schristos errno = EBADF;
608dffb485Schristos result = -1;
618dffb485Schristos }
628dffb485Schristos DONE_MSVC_INVAL;
638dffb485Schristos
648dffb485Schristos return result;
658dffb485Schristos }
668dffb485Schristos # else
67*4b169a6bSchristos # define dup2_nothrow _dup2
688dffb485Schristos # endif
698dffb485Schristos
708dffb485Schristos static int
ms_windows_dup2(int fd,int desired_fd)718dffb485Schristos ms_windows_dup2 (int fd, int desired_fd)
728dffb485Schristos {
738dffb485Schristos int result;
748dffb485Schristos
758dffb485Schristos /* If fd is closed, mingw hangs on dup2 (fd, fd). If fd is open,
768dffb485Schristos dup2 (fd, fd) returns 0, but all further attempts to use fd in
778dffb485Schristos future dup2 calls will hang. */
788dffb485Schristos if (fd == desired_fd)
798dffb485Schristos {
808dffb485Schristos if ((HANDLE) _get_osfhandle (fd) == INVALID_HANDLE_VALUE)
818dffb485Schristos {
828dffb485Schristos errno = EBADF;
838dffb485Schristos return -1;
848dffb485Schristos }
858dffb485Schristos return fd;
868dffb485Schristos }
878dffb485Schristos
888dffb485Schristos /* Wine 1.0.1 return 0 when desired_fd is negative but not -1:
898dffb485Schristos https://bugs.winehq.org/show_bug.cgi?id=21289 */
908dffb485Schristos if (desired_fd < 0)
918dffb485Schristos {
928dffb485Schristos errno = EBADF;
938dffb485Schristos return -1;
948dffb485Schristos }
958dffb485Schristos
968dffb485Schristos result = dup2_nothrow (fd, desired_fd);
978dffb485Schristos
988dffb485Schristos if (result == 0)
998dffb485Schristos result = desired_fd;
1008dffb485Schristos
1018dffb485Schristos return result;
1028dffb485Schristos }
1038dffb485Schristos
1048dffb485Schristos # define dup2 ms_windows_dup2
1058dffb485Schristos
1068dffb485Schristos #elif defined __KLIBC__
1078dffb485Schristos
1088dffb485Schristos # include <InnoTekLIBC/backend.h>
1098dffb485Schristos
1108dffb485Schristos static int
klibc_dup2dirfd(int fd,int desired_fd)1118dffb485Schristos klibc_dup2dirfd (int fd, int desired_fd)
1128dffb485Schristos {
1138dffb485Schristos int tempfd;
1148dffb485Schristos int dupfd;
1158dffb485Schristos
1168dffb485Schristos tempfd = open ("NUL", O_RDONLY);
1178dffb485Schristos if (tempfd == -1)
1188dffb485Schristos return -1;
1198dffb485Schristos
1208dffb485Schristos if (tempfd == desired_fd)
1218dffb485Schristos {
1228dffb485Schristos close (tempfd);
1238dffb485Schristos
1248dffb485Schristos char path[_MAX_PATH];
1258dffb485Schristos if (__libc_Back_ioFHToPath (fd, path, sizeof (path)))
1268dffb485Schristos return -1;
1278dffb485Schristos
1288dffb485Schristos return open(path, O_RDONLY);
1298dffb485Schristos }
1308dffb485Schristos
1318dffb485Schristos dupfd = klibc_dup2dirfd (fd, desired_fd);
1328dffb485Schristos
1338dffb485Schristos close (tempfd);
1348dffb485Schristos
1358dffb485Schristos return dupfd;
1368dffb485Schristos }
1378dffb485Schristos
1388dffb485Schristos static int
klibc_dup2(int fd,int desired_fd)1398dffb485Schristos klibc_dup2 (int fd, int desired_fd)
1408dffb485Schristos {
1418dffb485Schristos int dupfd;
1428dffb485Schristos struct stat sbuf;
1438dffb485Schristos
1448dffb485Schristos dupfd = dup2 (fd, desired_fd);
1458dffb485Schristos if (dupfd == -1 && errno == ENOTSUP \
1468dffb485Schristos && !fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode))
1478dffb485Schristos {
1488dffb485Schristos close (desired_fd);
1498dffb485Schristos
1508dffb485Schristos return klibc_dup2dirfd (fd, desired_fd);
1518dffb485Schristos }
1528dffb485Schristos
1538dffb485Schristos return dupfd;
1548dffb485Schristos }
1558dffb485Schristos
1568dffb485Schristos # define dup2 klibc_dup2
1578dffb485Schristos #endif
1588dffb485Schristos
1598dffb485Schristos int
rpl_dup2(int fd,int desired_fd)1608dffb485Schristos rpl_dup2 (int fd, int desired_fd)
1618dffb485Schristos {
1628dffb485Schristos int result;
1638dffb485Schristos
1648dffb485Schristos #ifdef F_GETFL
1658dffb485Schristos /* On Linux kernels 2.6.26-2.6.29, dup2 (fd, fd) returns -EBADF.
1668dffb485Schristos On Cygwin 1.5.x, dup2 (1, 1) returns 0.
1678dffb485Schristos On Cygwin 1.7.17, dup2 (1, -1) dumps core.
1688dffb485Schristos On Cygwin 1.7.25, dup2 (1, 256) can dump core.
1698dffb485Schristos On Haiku, dup2 (fd, fd) mistakenly clears FD_CLOEXEC. */
1708dffb485Schristos # if HAVE_SETDTABLESIZE
1718dffb485Schristos setdtablesize (desired_fd + 1);
1728dffb485Schristos # endif
1738dffb485Schristos if (desired_fd < 0)
1748dffb485Schristos fd = desired_fd;
1758dffb485Schristos if (fd == desired_fd)
1768dffb485Schristos return fcntl (fd, F_GETFL) == -1 ? -1 : fd;
1778dffb485Schristos #endif
1788dffb485Schristos
1798dffb485Schristos result = dup2 (fd, desired_fd);
1808dffb485Schristos
1818dffb485Schristos /* Correct an errno value on FreeBSD 6.1 and Cygwin 1.5.x. */
1828dffb485Schristos if (result == -1 && errno == EMFILE)
1838dffb485Schristos errno = EBADF;
1848dffb485Schristos #if REPLACE_FCHDIR
1858dffb485Schristos if (fd != desired_fd && result != -1)
1868dffb485Schristos result = _gl_register_dup (fd, result);
1878dffb485Schristos #endif
1888dffb485Schristos return result;
1898dffb485Schristos }
190