16acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn/* Duplicate an open file descriptor to a specified file descriptor.
26acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
36acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn   Copyright (C) 1999, 2004-2007, 2009-2012 Free Software Foundation, Inc.
46acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
56acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn   This program is free software: you can redistribute it and/or modify
66acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn   it under the terms of the GNU General Public License as published by
76acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn   the Free Software Foundation; either version 3 of the License, or
86acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn   (at your option) any later version.
96acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn   This program is distributed in the hope that it will be useful,
116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn   but WITHOUT ANY WARRANTY; without even the implied warranty of
126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn   GNU General Public License for more details.
146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn   You should have received a copy of the GNU General Public License
166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn/* written by Paul Eggert */
196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#include <config.h>
216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn/* Specification.  */
236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#include <unistd.h>
246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#include <errno.h>
266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#include <fcntl.h>
276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#if HAVE_DUP2
296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn# undef dup2
316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn/* Get declarations of the native Windows API functions.  */
356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#  define WIN32_LEAN_AND_MEAN
366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#  include <windows.h>
376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#  include "msvc-inval.h"
396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn/* Get _get_osfhandle.  */
416acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#  include "msvc-nothrow.h"
426acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstatic int
446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennms_windows_dup2 (int fd, int desired_fd)
456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  int result;
476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  /* If fd is closed, mingw hangs on dup2 (fd, fd).  If fd is open,
496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn     dup2 (fd, fd) returns 0, but all further attempts to use fd in
506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn     future dup2 calls will hang.  */
516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  if (fd == desired_fd)
526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn      if ((HANDLE) _get_osfhandle (fd) == INVALID_HANDLE_VALUE)
546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        {
556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn          errno = EBADF;
566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn          return -1;
576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn        }
586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn      return fd;
596acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
606acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
616acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  /* Wine 1.0.1 return 0 when desired_fd is negative but not -1:
626acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn     http://bugs.winehq.org/show_bug.cgi?id=21289 */
636acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  if (desired_fd < 0)
646acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
656acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn      errno = EBADF;
666acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn      return -1;
676acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
686acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
696acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  TRY_MSVC_INVAL
706acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
716acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn      result = dup2 (fd, desired_fd);
726acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
736acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  CATCH_MSVC_INVAL
746acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
756acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn      errno = EBADF;
766acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn      result = -1;
776acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
786acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  DONE_MSVC_INVAL;
796acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
806acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  if (result == 0)
816acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    result = desired_fd;
826acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
836acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  return result;
846acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
856acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
866acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#  define dup2 ms_windows_dup2
876acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
886acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn# endif
896acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
906acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennint
916acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennrpl_dup2 (int fd, int desired_fd)
926acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
936acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  int result;
946acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
956acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn# ifdef F_GETFL
966acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  /* On Linux kernels 2.6.26-2.6.29, dup2 (fd, fd) returns -EBADF.
976acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn     On Cygwin 1.5.x, dup2 (1, 1) returns 0.
986acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn     On Haiku, dup2 (fd, fd) mistakenly clears FD_CLOEXEC.  */
996acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  if (fd == desired_fd)
1006acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    return fcntl (fd, F_GETFL) == -1 ? -1 : fd;
1016acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn# endif
1026acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1036acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  result = dup2 (fd, desired_fd);
1046acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1056acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  /* Correct an errno value on FreeBSD 6.1 and Cygwin 1.5.x.  */
1066acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  if (result == -1 && errno == EMFILE)
1076acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    errno = EBADF;
1086acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn# if REPLACE_FCHDIR
1096acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  if (fd != desired_fd && result != -1)
1106acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    result = _gl_register_dup (fd, result);
1116acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn# endif
1126acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  return result;
1136acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
1146acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1156acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#else /* !HAVE_DUP2 */
1166acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1176acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn/* On older platforms, dup2 did not exist.  */
1186acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1196acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn# ifndef F_DUPFD
1206acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennstatic int
1216acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renndupfd (int fd, int desired_fd)
1226acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
1236acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  int duplicated_fd = dup (fd);
1246acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  if (duplicated_fd < 0 || duplicated_fd == desired_fd)
1256acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    return duplicated_fd;
1266acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  else
1276acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    {
1286acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn      int r = dupfd (fd, desired_fd);
1296acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn      int e = errno;
1306acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn      close (duplicated_fd);
1316acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn      errno = e;
1326acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn      return r;
1336acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    }
1346acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
1356acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn# endif
1366acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn
1376acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Rennint
1386acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renndup2 (int fd, int desired_fd)
1396acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn{
1406acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  int result = fcntl (fd, F_GETFL) < 0 ? -1 : fd;
1416acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  if (result == -1 || fd == desired_fd)
1426acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    return result;
1436acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  close (desired_fd);
1446acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn# ifdef F_DUPFD
1456acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  result = fcntl (fd, F_DUPFD, desired_fd);
1466acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#  if REPLACE_FCHDIR
1476acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  if (0 <= result)
1486acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    result = _gl_register_dup (fd, result);
1496acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#  endif
1506acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn# else
1516acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  result = dupfd (fd, desired_fd);
1526acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn# endif
1536acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  if (result == -1 && (errno == EMFILE || errno == EINVAL))
1546acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn    errno = EBADF;
1556acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn  return result;
1566acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn}
1576acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn#endif /* !HAVE_DUP2 */
1586acb9a7ea3d7564944e12cbc73a857b88c1301eeMarius Renn