Blame lib/dup2.c

Packit 8f70b4
/* Duplicate an open file descriptor to a specified file descriptor.
Packit 8f70b4
Packit 8f70b4
   Copyright (C) 1999, 2004-2007, 2009-2018 Free Software Foundation, Inc.
Packit 8f70b4
Packit 8f70b4
   This program is free software: you can redistribute it and/or modify
Packit 8f70b4
   it under the terms of the GNU General Public License as published by
Packit 8f70b4
   the Free Software Foundation; either version 3 of the License, or
Packit 8f70b4
   (at your option) any later version.
Packit 8f70b4
Packit 8f70b4
   This program is distributed in the hope that it will be useful,
Packit 8f70b4
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 8f70b4
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 8f70b4
   GNU General Public License for more details.
Packit 8f70b4
Packit 8f70b4
   You should have received a copy of the GNU General Public License
Packit 8f70b4
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
Packit 8f70b4
Packit 8f70b4
/* written by Paul Eggert */
Packit 8f70b4
Packit 8f70b4
#include <config.h>
Packit 8f70b4
Packit 8f70b4
/* Specification.  */
Packit 8f70b4
#include <unistd.h>
Packit 8f70b4
Packit 8f70b4
#include <errno.h>
Packit 8f70b4
#include <fcntl.h>
Packit 8f70b4
Packit 8f70b4
#if HAVE_DUP2
Packit 8f70b4
Packit 8f70b4
# undef dup2
Packit 8f70b4
Packit 8f70b4
# if defined _WIN32 && ! defined __CYGWIN__
Packit 8f70b4
Packit 8f70b4
/* Get declarations of the native Windows API functions.  */
Packit 8f70b4
#  define WIN32_LEAN_AND_MEAN
Packit 8f70b4
#  include <windows.h>
Packit 8f70b4
Packit 8f70b4
#  if HAVE_MSVC_INVALID_PARAMETER_HANDLER
Packit 8f70b4
#   include "msvc-inval.h"
Packit 8f70b4
#  endif
Packit 8f70b4
Packit 8f70b4
/* Get _get_osfhandle.  */
Packit 8f70b4
#  if GNULIB_MSVC_NOTHROW
Packit 8f70b4
#   include "msvc-nothrow.h"
Packit 8f70b4
#  else
Packit 8f70b4
#   include <io.h>
Packit 8f70b4
#  endif
Packit 8f70b4
Packit 8f70b4
#  if HAVE_MSVC_INVALID_PARAMETER_HANDLER
Packit 8f70b4
static int
Packit 8f70b4
dup2_nothrow (int fd, int desired_fd)
Packit 8f70b4
{
Packit 8f70b4
  int result;
Packit 8f70b4
Packit 8f70b4
  TRY_MSVC_INVAL
Packit 8f70b4
    {
Packit 8f70b4
      result = dup2 (fd, desired_fd);
Packit 8f70b4
    }
Packit 8f70b4
  CATCH_MSVC_INVAL
Packit 8f70b4
    {
Packit 8f70b4
      errno = EBADF;
Packit 8f70b4
      result = -1;
Packit 8f70b4
    }
Packit 8f70b4
  DONE_MSVC_INVAL;
Packit 8f70b4
Packit 8f70b4
  return result;
Packit 8f70b4
}
Packit 8f70b4
#  else
Packit 8f70b4
#   define dup2_nothrow dup2
Packit 8f70b4
#  endif
Packit 8f70b4
Packit 8f70b4
static int
Packit 8f70b4
ms_windows_dup2 (int fd, int desired_fd)
Packit 8f70b4
{
Packit 8f70b4
  int result;
Packit 8f70b4
Packit 8f70b4
  /* If fd is closed, mingw hangs on dup2 (fd, fd).  If fd is open,
Packit 8f70b4
     dup2 (fd, fd) returns 0, but all further attempts to use fd in
Packit 8f70b4
     future dup2 calls will hang.  */
Packit 8f70b4
  if (fd == desired_fd)
Packit 8f70b4
    {
Packit 8f70b4
      if ((HANDLE) _get_osfhandle (fd) == INVALID_HANDLE_VALUE)
Packit 8f70b4
        {
Packit 8f70b4
          errno = EBADF;
Packit 8f70b4
          return -1;
Packit 8f70b4
        }
Packit 8f70b4
      return fd;
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
  /* Wine 1.0.1 return 0 when desired_fd is negative but not -1:
Packit 8f70b4
     https://bugs.winehq.org/show_bug.cgi?id=21289 */
Packit 8f70b4
  if (desired_fd < 0)
Packit 8f70b4
    {
Packit 8f70b4
      errno = EBADF;
Packit 8f70b4
      return -1;
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
  result = dup2_nothrow (fd, desired_fd);
Packit 8f70b4
Packit 8f70b4
  if (result == 0)
Packit 8f70b4
    result = desired_fd;
Packit 8f70b4
Packit 8f70b4
  return result;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
#  define dup2 ms_windows_dup2
Packit 8f70b4
Packit 8f70b4
# elif defined __KLIBC__
Packit 8f70b4
Packit 8f70b4
#  include <InnoTekLIBC/backend.h>
Packit 8f70b4
Packit 8f70b4
static int
Packit 8f70b4
klibc_dup2dirfd (int fd, int desired_fd)
Packit 8f70b4
{
Packit 8f70b4
  int tempfd;
Packit 8f70b4
  int dupfd;
Packit 8f70b4
Packit 8f70b4
  tempfd = open ("NUL", O_RDONLY);
Packit 8f70b4
  if (tempfd == -1)
Packit 8f70b4
    return -1;
Packit 8f70b4
Packit 8f70b4
  if (tempfd == desired_fd)
Packit 8f70b4
    {
Packit 8f70b4
      close (tempfd);
Packit 8f70b4
Packit 8f70b4
      char path[_MAX_PATH];
Packit 8f70b4
      if (__libc_Back_ioFHToPath (fd, path, sizeof (path)))
Packit 8f70b4
        return -1;
Packit 8f70b4
Packit 8f70b4
      return open(path, O_RDONLY);
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
  dupfd = klibc_dup2dirfd (fd, desired_fd);
Packit 8f70b4
Packit 8f70b4
  close (tempfd);
Packit 8f70b4
Packit 8f70b4
  return dupfd;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
static int
Packit 8f70b4
klibc_dup2 (int fd, int desired_fd)
Packit 8f70b4
{
Packit 8f70b4
  int dupfd;
Packit 8f70b4
  struct stat sbuf;
Packit 8f70b4
Packit 8f70b4
  dupfd = dup2 (fd, desired_fd);
Packit 8f70b4
  if (dupfd == -1 && errno == ENOTSUP \
Packit 8f70b4
      && !fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode))
Packit 8f70b4
    {
Packit 8f70b4
      close (desired_fd);
Packit 8f70b4
Packit 8f70b4
      return klibc_dup2dirfd (fd, desired_fd);
Packit 8f70b4
    }
Packit 8f70b4
Packit 8f70b4
  return dupfd;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
#  define dup2 klibc_dup2
Packit 8f70b4
# endif
Packit 8f70b4
Packit 8f70b4
int
Packit 8f70b4
rpl_dup2 (int fd, int desired_fd)
Packit 8f70b4
{
Packit 8f70b4
  int result;
Packit 8f70b4
Packit 8f70b4
# ifdef F_GETFL
Packit 8f70b4
  /* On Linux kernels 2.6.26-2.6.29, dup2 (fd, fd) returns -EBADF.
Packit 8f70b4
     On Cygwin 1.5.x, dup2 (1, 1) returns 0.
Packit 8f70b4
     On Cygwin 1.7.17, dup2 (1, -1) dumps core.
Packit 8f70b4
     On Cygwin 1.7.25, dup2 (1, 256) can dump core.
Packit 8f70b4
     On Haiku, dup2 (fd, fd) mistakenly clears FD_CLOEXEC.  */
Packit 8f70b4
#  if HAVE_SETDTABLESIZE
Packit 8f70b4
  setdtablesize (desired_fd + 1);
Packit 8f70b4
#  endif
Packit 8f70b4
  if (desired_fd < 0)
Packit 8f70b4
    fd = desired_fd;
Packit 8f70b4
  if (fd == desired_fd)
Packit 8f70b4
    return fcntl (fd, F_GETFL) == -1 ? -1 : fd;
Packit 8f70b4
# endif
Packit 8f70b4
Packit 8f70b4
  result = dup2 (fd, desired_fd);
Packit 8f70b4
Packit 8f70b4
  /* Correct an errno value on FreeBSD 6.1 and Cygwin 1.5.x.  */
Packit 8f70b4
  if (result == -1 && errno == EMFILE)
Packit 8f70b4
    errno = EBADF;
Packit 8f70b4
# if REPLACE_FCHDIR
Packit 8f70b4
  if (fd != desired_fd && result != -1)
Packit 8f70b4
    result = _gl_register_dup (fd, result);
Packit 8f70b4
# endif
Packit 8f70b4
  return result;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
#else /* !HAVE_DUP2 */
Packit 8f70b4
Packit 8f70b4
/* On older platforms, dup2 did not exist.  */
Packit 8f70b4
Packit 8f70b4
# ifndef F_DUPFD
Packit 8f70b4
static int
Packit 8f70b4
dupfd (int fd, int desired_fd)
Packit 8f70b4
{
Packit 8f70b4
  int duplicated_fd = dup (fd);
Packit 8f70b4
  if (duplicated_fd < 0 || duplicated_fd == desired_fd)
Packit 8f70b4
    return duplicated_fd;
Packit 8f70b4
  else
Packit 8f70b4
    {
Packit 8f70b4
      int r = dupfd (fd, desired_fd);
Packit 8f70b4
      int e = errno;
Packit 8f70b4
      close (duplicated_fd);
Packit 8f70b4
      errno = e;
Packit 8f70b4
      return r;
Packit 8f70b4
    }
Packit 8f70b4
}
Packit 8f70b4
# endif
Packit 8f70b4
Packit 8f70b4
int
Packit 8f70b4
dup2 (int fd, int desired_fd)
Packit 8f70b4
{
Packit 8f70b4
  int result = fcntl (fd, F_GETFL) < 0 ? -1 : fd;
Packit 8f70b4
  if (result == -1 || fd == desired_fd)
Packit 8f70b4
    return result;
Packit 8f70b4
  close (desired_fd);
Packit 8f70b4
# ifdef F_DUPFD
Packit 8f70b4
  result = fcntl (fd, F_DUPFD, desired_fd);
Packit 8f70b4
#  if REPLACE_FCHDIR
Packit 8f70b4
  if (0 <= result)
Packit 8f70b4
    result = _gl_register_dup (fd, result);
Packit 8f70b4
#  endif
Packit 8f70b4
# else
Packit 8f70b4
  result = dupfd (fd, desired_fd);
Packit 8f70b4
# endif
Packit 8f70b4
  if (result == -1 && (errno == EMFILE || errno == EINVAL))
Packit 8f70b4
    errno = EBADF;
Packit 8f70b4
  return result;
Packit 8f70b4
}
Packit 8f70b4
#endif /* !HAVE_DUP2 */