Blame gl/fcntl.c

Packit Service 991b93
/* Provide file descriptor control.
Packit Service 991b93
Packit Service 991b93
   Copyright (C) 2009-2020 Free Software Foundation, Inc.
Packit Service 991b93
Packit Service 991b93
   This program is free software: you can redistribute it and/or modify
Packit Service 991b93
   it under the terms of the GNU Lesser General Public License as published by
Packit Service 991b93
   the Free Software Foundation; either version 2.1 of the License, or
Packit Service 991b93
   (at your option) any later version.
Packit Service 991b93
Packit Service 991b93
   This program is distributed in the hope that it will be useful,
Packit Service 991b93
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 991b93
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 991b93
   GNU Lesser General Public License for more details.
Packit Service 991b93
Packit Service 991b93
   You should have received a copy of the GNU Lesser General Public License
Packit Service 991b93
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
Packit Service 991b93
Packit Service 991b93
/* Written by Eric Blake <ebb9@byu.net>.  */
Packit Service 991b93
Packit Service 991b93
#include <config.h>
Packit Service 991b93
Packit Service 991b93
/* Specification.  */
Packit Service 991b93
#include <fcntl.h>
Packit Service 991b93
Packit Service 991b93
#include <errno.h>
Packit Service 991b93
#include <limits.h>
Packit Service 991b93
#include <stdarg.h>
Packit Service 991b93
#include <stdlib.h>
Packit Service 991b93
#include <unistd.h>
Packit Service 991b93
Packit Service 991b93
#ifdef __KLIBC__
Packit Service 991b93
# define INCL_DOS
Packit Service 991b93
# include <os2.h>
Packit Service 991b93
#endif
Packit Service 991b93
Packit Service 991b93
#if defined _WIN32 && ! defined __CYGWIN__
Packit Service 991b93
/* Get declarations of the native Windows API functions.  */
Packit Service 991b93
# define WIN32_LEAN_AND_MEAN
Packit Service 991b93
# include <windows.h>
Packit Service 991b93
Packit Service 991b93
/* Get _get_osfhandle.  */
Packit Service 991b93
# if GNULIB_MSVC_NOTHROW
Packit Service 991b93
#  include "msvc-nothrow.h"
Packit Service 991b93
# else
Packit Service 991b93
#  include <io.h>
Packit Service 991b93
# endif
Packit Service 991b93
Packit Service 991b93
/* Upper bound on getdtablesize().  See lib/getdtablesize.c.  */
Packit Service 991b93
# define OPEN_MAX_MAX 0x10000
Packit Service 991b93
Packit Service 991b93
/* Duplicate OLDFD into the first available slot of at least NEWFD,
Packit Service 991b93
   which must be positive, with FLAGS determining whether the duplicate
Packit Service 991b93
   will be inheritable.  */
Packit Service 991b93
static int
Packit Service 991b93
dupfd (int oldfd, int newfd, int flags)
Packit Service 991b93
{
Packit Service 991b93
  /* Mingw has no way to create an arbitrary fd.  Iterate until all
Packit Service 991b93
     file descriptors less than newfd are filled up.  */
Packit Service 991b93
  HANDLE curr_process = GetCurrentProcess ();
Packit Service 991b93
  HANDLE old_handle = (HANDLE) _get_osfhandle (oldfd);
Packit Service 991b93
  unsigned char fds_to_close[OPEN_MAX_MAX / CHAR_BIT];
Packit Service 991b93
  unsigned int fds_to_close_bound = 0;
Packit Service 991b93
  int result;
Packit Service 991b93
  BOOL inherit = flags & O_CLOEXEC ? FALSE : TRUE;
Packit Service 991b93
  int mode;
Packit Service 991b93
Packit Service 991b93
  if (newfd < 0 || getdtablesize () <= newfd)
Packit Service 991b93
    {
Packit Service 991b93
      errno = EINVAL;
Packit Service 991b93
      return -1;
Packit Service 991b93
    }
Packit Service 991b93
  if (old_handle == INVALID_HANDLE_VALUE
Packit Service 991b93
      || (mode = setmode (oldfd, O_BINARY)) == -1)
Packit Service 991b93
    {
Packit Service 991b93
      /* oldfd is not open, or is an unassigned standard file
Packit Service 991b93
         descriptor.  */
Packit Service 991b93
      errno = EBADF;
Packit Service 991b93
      return -1;
Packit Service 991b93
    }
Packit Service 991b93
  setmode (oldfd, mode);
Packit Service 991b93
  flags |= mode;
Packit Service 991b93
Packit Service 991b93
  for (;;)
Packit Service 991b93
    {
Packit Service 991b93
      HANDLE new_handle;
Packit Service 991b93
      int duplicated_fd;
Packit Service 991b93
      unsigned int index;
Packit Service 991b93
Packit Service 991b93
      if (!DuplicateHandle (curr_process,           /* SourceProcessHandle */
Packit Service 991b93
                            old_handle,             /* SourceHandle */
Packit Service 991b93
                            curr_process,           /* TargetProcessHandle */
Packit Service 991b93
                            (PHANDLE) &new_handle,  /* TargetHandle */
Packit Service 991b93
                            (DWORD) 0,              /* DesiredAccess */
Packit Service 991b93
                            inherit,                /* InheritHandle */
Packit Service 991b93
                            DUPLICATE_SAME_ACCESS)) /* Options */
Packit Service 991b93
        {
Packit Service 991b93
          switch (GetLastError ())
Packit Service 991b93
            {
Packit Service 991b93
              case ERROR_TOO_MANY_OPEN_FILES:
Packit Service 991b93
                errno = EMFILE;
Packit Service 991b93
                break;
Packit Service 991b93
              case ERROR_INVALID_HANDLE:
Packit Service 991b93
              case ERROR_INVALID_TARGET_HANDLE:
Packit Service 991b93
              case ERROR_DIRECT_ACCESS_HANDLE:
Packit Service 991b93
                errno = EBADF;
Packit Service 991b93
                break;
Packit Service 991b93
              case ERROR_INVALID_PARAMETER:
Packit Service 991b93
              case ERROR_INVALID_FUNCTION:
Packit Service 991b93
              case ERROR_INVALID_ACCESS:
Packit Service 991b93
                errno = EINVAL;
Packit Service 991b93
                break;
Packit Service 991b93
              default:
Packit Service 991b93
                errno = EACCES;
Packit Service 991b93
                break;
Packit Service 991b93
            }
Packit Service 991b93
          result = -1;
Packit Service 991b93
          break;
Packit Service 991b93
        }
Packit Service 991b93
      duplicated_fd = _open_osfhandle ((intptr_t) new_handle, flags);
Packit Service 991b93
      if (duplicated_fd < 0)
Packit Service 991b93
        {
Packit Service 991b93
          CloseHandle (new_handle);
Packit Service 991b93
          result = -1;
Packit Service 991b93
          break;
Packit Service 991b93
        }
Packit Service 991b93
      if (newfd <= duplicated_fd)
Packit Service 991b93
        {
Packit Service 991b93
          result = duplicated_fd;
Packit Service 991b93
          break;
Packit Service 991b93
        }
Packit Service 991b93
Packit Service 991b93
      /* Set the bit duplicated_fd in fds_to_close[].  */
Packit Service 991b93
      index = (unsigned int) duplicated_fd / CHAR_BIT;
Packit Service 991b93
      if (fds_to_close_bound <= index)
Packit Service 991b93
        {
Packit Service 991b93
          if (sizeof fds_to_close <= index)
Packit Service 991b93
            /* Need to increase OPEN_MAX_MAX.  */
Packit Service 991b93
            abort ();
Packit Service 991b93
          memset (fds_to_close + fds_to_close_bound, '\0',
Packit Service 991b93
                  index + 1 - fds_to_close_bound);
Packit Service 991b93
          fds_to_close_bound = index + 1;
Packit Service 991b93
        }
Packit Service 991b93
      fds_to_close[index] |= 1 << ((unsigned int) duplicated_fd % CHAR_BIT);
Packit Service 991b93
    }
Packit Service 991b93
Packit Service 991b93
  /* Close the previous fds that turned out to be too small.  */
Packit Service 991b93
  {
Packit Service 991b93
    int saved_errno = errno;
Packit Service 991b93
    unsigned int duplicated_fd;
Packit Service 991b93
Packit Service 991b93
    for (duplicated_fd = 0;
Packit Service 991b93
         duplicated_fd < fds_to_close_bound * CHAR_BIT;
Packit Service 991b93
         duplicated_fd++)
Packit Service 991b93
      if ((fds_to_close[duplicated_fd / CHAR_BIT]
Packit Service 991b93
           >> (duplicated_fd % CHAR_BIT))
Packit Service 991b93
          & 1)
Packit Service 991b93
        close (duplicated_fd);
Packit Service 991b93
Packit Service 991b93
    errno = saved_errno;
Packit Service 991b93
  }
Packit Service 991b93
Packit Service 991b93
# if REPLACE_FCHDIR
Packit Service 991b93
  if (0 <= result)
Packit Service 991b93
    result = _gl_register_dup (oldfd, result);
Packit Service 991b93
# endif
Packit Service 991b93
  return result;
Packit Service 991b93
}
Packit Service 991b93
#endif /* W32 */
Packit Service 991b93
Packit Service 991b93
/* Forward declarations, because we '#undef fcntl' in the middle of this
Packit Service 991b93
   compilation unit.  */
Packit Service 991b93
/* Our implementation of fcntl (fd, F_DUPFD, target).  */
Packit Service 991b93
static int rpl_fcntl_DUPFD (int fd, int target);
Packit Service 991b93
/* Our implementation of fcntl (fd, F_DUPFD_CLOEXEC, target).  */
Packit Service 991b93
static int rpl_fcntl_DUPFD_CLOEXEC (int fd, int target);
Packit Service 991b93
#ifdef __KLIBC__
Packit Service 991b93
/* Adds support for fcntl on directories.  */
Packit Service 991b93
static int klibc_fcntl (int fd, int action, /* arg */...);
Packit Service 991b93
#endif
Packit Service 991b93
Packit Service 991b93
Packit Service 991b93
/* Perform the specified ACTION on the file descriptor FD, possibly
Packit Service 991b93
   using the argument ARG further described below.  This replacement
Packit Service 991b93
   handles the following actions, and forwards all others on to the
Packit Service 991b93
   native fcntl.  An unrecognized ACTION returns -1 with errno set to
Packit Service 991b93
   EINVAL.
Packit Service 991b93
Packit Service 991b93
   F_DUPFD - duplicate FD, with int ARG being the minimum target fd.
Packit Service 991b93
   If successful, return the duplicate, which will be inheritable;
Packit Service 991b93
   otherwise return -1 and set errno.
Packit Service 991b93
Packit Service 991b93
   F_DUPFD_CLOEXEC - duplicate FD, with int ARG being the minimum
Packit Service 991b93
   target fd.  If successful, return the duplicate, which will not be
Packit Service 991b93
   inheritable; otherwise return -1 and set errno.
Packit Service 991b93
Packit Service 991b93
   F_GETFD - ARG need not be present.  If successful, return a
Packit Service 991b93
   non-negative value containing the descriptor flags of FD (only
Packit Service 991b93
   FD_CLOEXEC is portable, but other flags may be present); otherwise
Packit Service 991b93
   return -1 and set errno.  */
Packit Service 991b93
Packit Service 991b93
int
Packit Service 991b93
fcntl (int fd, int action, /* arg */...)
Packit Service 991b93
#undef fcntl
Packit Service 991b93
#ifdef __KLIBC__
Packit Service 991b93
# define fcntl klibc_fcntl
Packit Service 991b93
#endif
Packit Service 991b93
{
Packit Service 991b93
  va_list arg;
Packit Service 991b93
  int result = -1;
Packit Service 991b93
  va_start (arg, action);
Packit Service 991b93
  switch (action)
Packit Service 991b93
    {
Packit Service 991b93
    case F_DUPFD:
Packit Service 991b93
      {
Packit Service 991b93
        int target = va_arg (arg, int);
Packit Service 991b93
        result = rpl_fcntl_DUPFD (fd, target);
Packit Service 991b93
        break;
Packit Service 991b93
      }
Packit Service 991b93
Packit Service 991b93
    case F_DUPFD_CLOEXEC:
Packit Service 991b93
      {
Packit Service 991b93
        int target = va_arg (arg, int);
Packit Service 991b93
        result = rpl_fcntl_DUPFD_CLOEXEC (fd, target);
Packit Service 991b93
        break;
Packit Service 991b93
      }
Packit Service 991b93
Packit Service 991b93
#if !HAVE_FCNTL
Packit Service 991b93
    case F_GETFD:
Packit Service 991b93
      {
Packit Service 991b93
# if defined _WIN32 && ! defined __CYGWIN__
Packit Service 991b93
        HANDLE handle = (HANDLE) _get_osfhandle (fd);
Packit Service 991b93
        DWORD flags;
Packit Service 991b93
        if (handle == INVALID_HANDLE_VALUE
Packit Service 991b93
            || GetHandleInformation (handle, &flags) == 0)
Packit Service 991b93
          errno = EBADF;
Packit Service 991b93
        else
Packit Service 991b93
          result = (flags & HANDLE_FLAG_INHERIT) ? 0 : FD_CLOEXEC;
Packit Service 991b93
# else /* !W32 */
Packit Service 991b93
        /* Use dup2 to reject invalid file descriptors.  No way to
Packit Service 991b93
           access this information, so punt.  */
Packit Service 991b93
        if (0 <= dup2 (fd, fd))
Packit Service 991b93
          result = 0;
Packit Service 991b93
# endif /* !W32 */
Packit Service 991b93
        break;
Packit Service 991b93
      } /* F_GETFD */
Packit Service 991b93
#endif /* !HAVE_FCNTL */
Packit Service 991b93
Packit Service 991b93
      /* Implementing F_SETFD on mingw is not trivial - there is no
Packit Service 991b93
         API for changing the O_NOINHERIT bit on an fd, and merely
Packit Service 991b93
         changing the HANDLE_FLAG_INHERIT bit on the underlying handle
Packit Service 991b93
         can lead to odd state.  It may be possible by duplicating the
Packit Service 991b93
         handle, using _open_osfhandle with the right flags, then
Packit Service 991b93
         using dup2 to move the duplicate onto the original, but that
Packit Service 991b93
         is not supported for now.  */
Packit Service 991b93
Packit Service 991b93
    default:
Packit Service 991b93
      {
Packit Service 991b93
#if HAVE_FCNTL
Packit Service 991b93
        switch (action)
Packit Service 991b93
          {
Packit Service 991b93
          #ifdef F_BARRIERFSYNC                  /* macOS */
Packit Service 991b93
          case F_BARRIERFSYNC:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_CHKCLEAN                      /* macOS */
Packit Service 991b93
          case F_CHKCLEAN:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_CLOSEM                        /* NetBSD, HP-UX */
Packit Service 991b93
          case F_CLOSEM:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_FLUSH_DATA                    /* macOS */
Packit Service 991b93
          case F_FLUSH_DATA:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_FREEZE_FS                     /* macOS */
Packit Service 991b93
          case F_FREEZE_FS:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_FULLFSYNC                     /* macOS */
Packit Service 991b93
          case F_FULLFSYNC:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_GETCONFINED                   /* macOS */
Packit Service 991b93
          case F_GETCONFINED:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_GETDEFAULTPROTLEVEL           /* macOS */
Packit Service 991b93
          case F_GETDEFAULTPROTLEVEL:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_GETFD                         /* POSIX */
Packit Service 991b93
          case F_GETFD:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_GETFL                         /* POSIX */
Packit Service 991b93
          case F_GETFL:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_GETLEASE                      /* Linux */
Packit Service 991b93
          case F_GETLEASE:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_GETNOSIGPIPE                  /* macOS */
Packit Service 991b93
          case F_GETNOSIGPIPE:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_GETOWN                        /* POSIX */
Packit Service 991b93
          case F_GETOWN:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_GETPIPE_SZ                    /* Linux */
Packit Service 991b93
          case F_GETPIPE_SZ:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_GETPROTECTIONCLASS            /* macOS */
Packit Service 991b93
          case F_GETPROTECTIONCLASS:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_GETPROTECTIONLEVEL            /* macOS */
Packit Service 991b93
          case F_GETPROTECTIONLEVEL:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_GET_SEALS                     /* Linux */
Packit Service 991b93
          case F_GET_SEALS:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_GETSIG                        /* Linux */
Packit Service 991b93
          case F_GETSIG:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_MAXFD                         /* NetBSD */
Packit Service 991b93
          case F_MAXFD:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_RECYCLE                       /* macOS */
Packit Service 991b93
          case F_RECYCLE:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_SETFIFOENH                    /* HP-UX */
Packit Service 991b93
          case F_SETFIFOENH:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_THAW_FS                       /* macOS */
Packit Service 991b93
          case F_THAW_FS:
Packit Service 991b93
          #endif
Packit Service 991b93
            /* These actions take no argument.  */
Packit Service 991b93
            result = fcntl (fd, action);
Packit Service 991b93
            break;
Packit Service 991b93
Packit Service 991b93
          #ifdef F_ADD_SEALS                     /* Linux */
Packit Service 991b93
          case F_ADD_SEALS:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_BADFD                         /* Solaris */
Packit Service 991b93
          case F_BADFD:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_CHECK_OPENEVT                 /* macOS */
Packit Service 991b93
          case F_CHECK_OPENEVT:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_DUP2FD                        /* FreeBSD, AIX, Solaris */
Packit Service 991b93
          case F_DUP2FD:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_DUP2FD_CLOEXEC                /* FreeBSD, Solaris */
Packit Service 991b93
          case F_DUP2FD_CLOEXEC:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_DUP2FD_CLOFORK                /* Solaris */
Packit Service 991b93
          case F_DUP2FD_CLOFORK:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_DUPFD                         /* POSIX */
Packit Service 991b93
          case F_DUPFD:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_DUPFD_CLOEXEC                 /* POSIX */
Packit Service 991b93
          case F_DUPFD_CLOEXEC:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_DUPFD_CLOFORK                 /* Solaris */
Packit Service 991b93
          case F_DUPFD_CLOFORK:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_GETXFL                        /* Solaris */
Packit Service 991b93
          case F_GETXFL:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_GLOBAL_NOCACHE                /* macOS */
Packit Service 991b93
          case F_GLOBAL_NOCACHE:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_MAKECOMPRESSED                /* macOS */
Packit Service 991b93
          case F_MAKECOMPRESSED:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_MOVEDATAEXTENTS               /* macOS */
Packit Service 991b93
          case F_MOVEDATAEXTENTS:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_NOCACHE                       /* macOS */
Packit Service 991b93
          case F_NOCACHE:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_NODIRECT                      /* macOS */
Packit Service 991b93
          case F_NODIRECT:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_NOTIFY                        /* Linux */
Packit Service 991b93
          case F_NOTIFY:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_OPLKACK                       /* IRIX */
Packit Service 991b93
          case F_OPLKACK:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_OPLKREG                       /* IRIX */
Packit Service 991b93
          case F_OPLKREG:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_RDAHEAD                       /* macOS */
Packit Service 991b93
          case F_RDAHEAD:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_SETBACKINGSTORE               /* macOS */
Packit Service 991b93
          case F_SETBACKINGSTORE:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_SETCONFINED                   /* macOS */
Packit Service 991b93
          case F_SETCONFINED:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_SETFD                         /* POSIX */
Packit Service 991b93
          case F_SETFD:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_SETFL                         /* POSIX */
Packit Service 991b93
          case F_SETFL:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_SETLEASE                      /* Linux */
Packit Service 991b93
          case F_SETLEASE:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_SETNOSIGPIPE                  /* macOS */
Packit Service 991b93
          case F_SETNOSIGPIPE:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_SETOWN                        /* POSIX */
Packit Service 991b93
          case F_SETOWN:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_SETPIPE_SZ                    /* Linux */
Packit Service 991b93
          case F_SETPIPE_SZ:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_SETPROTECTIONCLASS            /* macOS */
Packit Service 991b93
          case F_SETPROTECTIONCLASS:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_SETSIG                        /* Linux */
Packit Service 991b93
          case F_SETSIG:
Packit Service 991b93
          #endif
Packit Service 991b93
          #ifdef F_SINGLE_WRITER                 /* macOS */
Packit Service 991b93
          case F_SINGLE_WRITER:
Packit Service 991b93
          #endif
Packit Service 991b93
            /* These actions take an 'int' argument.  */
Packit Service 991b93
            {
Packit Service 991b93
              int x = va_arg (arg, int);
Packit Service 991b93
              result = fcntl (fd, action, x);
Packit Service 991b93
            }
Packit Service 991b93
            break;
Packit Service 991b93
Packit Service 991b93
          default:
Packit Service 991b93
            /* Other actions take a pointer argument.  */
Packit Service 991b93
            {
Packit Service 991b93
              void *p = va_arg (arg, void *);
Packit Service 991b93
              result = fcntl (fd, action, p);
Packit Service 991b93
            }
Packit Service 991b93
            break;
Packit Service 991b93
          }
Packit Service 991b93
#else
Packit Service 991b93
        errno = EINVAL;
Packit Service 991b93
#endif
Packit Service 991b93
        break;
Packit Service 991b93
      }
Packit Service 991b93
    }
Packit Service 991b93
  va_end (arg);
Packit Service 991b93
  return result;
Packit Service 991b93
}
Packit Service 991b93
Packit Service 991b93
static int
Packit Service 991b93
rpl_fcntl_DUPFD (int fd, int target)
Packit Service 991b93
{
Packit Service 991b93
  int result;
Packit Service 991b93
#if !HAVE_FCNTL
Packit Service 991b93
  result = dupfd (fd, target, 0);
Packit Service 991b93
#elif FCNTL_DUPFD_BUGGY || REPLACE_FCHDIR
Packit Service 991b93
  /* Detect invalid target; needed for cygwin 1.5.x.  */
Packit Service 991b93
  if (target < 0 || getdtablesize () <= target)
Packit Service 991b93
    {
Packit Service 991b93
      result = -1;
Packit Service 991b93
      errno = EINVAL;
Packit Service 991b93
    }
Packit Service 991b93
  else
Packit Service 991b93
    {
Packit Service 991b93
      /* Haiku alpha 2 loses fd flags on original.  */
Packit Service 991b93
      int flags = fcntl (fd, F_GETFD);
Packit Service 991b93
      if (flags < 0)
Packit Service 991b93
        result = -1;
Packit Service 991b93
      else
Packit Service 991b93
        {
Packit Service 991b93
          result = fcntl (fd, F_DUPFD, target);
Packit Service 991b93
          if (0 <= result && fcntl (fd, F_SETFD, flags) == -1)
Packit Service 991b93
            {
Packit Service 991b93
              int saved_errno = errno;
Packit Service 991b93
              close (result);
Packit Service 991b93
              result = -1;
Packit Service 991b93
              errno = saved_errno;
Packit Service 991b93
            }
Packit Service 991b93
# if REPLACE_FCHDIR
Packit Service 991b93
          if (0 <= result)
Packit Service 991b93
            result = _gl_register_dup (fd, result);
Packit Service 991b93
# endif
Packit Service 991b93
        }
Packit Service 991b93
    }
Packit Service 991b93
#else
Packit Service 991b93
  result = fcntl (fd, F_DUPFD, target);
Packit Service 991b93
#endif
Packit Service 991b93
  return result;
Packit Service 991b93
}
Packit Service 991b93
Packit Service 991b93
static int
Packit Service 991b93
rpl_fcntl_DUPFD_CLOEXEC (int fd, int target)
Packit Service 991b93
{
Packit Service 991b93
  int result;
Packit Service 991b93
#if !HAVE_FCNTL
Packit Service 991b93
  result = dupfd (fd, target, O_CLOEXEC);
Packit Service 991b93
#else /* HAVE_FCNTL */
Packit Service 991b93
# if defined __HAIKU__
Packit Service 991b93
  /* On Haiku, the system fcntl (fd, F_DUPFD_CLOEXEC, target) sets
Packit Service 991b93
     the FD_CLOEXEC flag on fd, not on target.  Therefore avoid the
Packit Service 991b93
     system fcntl in this case.  */
Packit Service 991b93
#  define have_dupfd_cloexec -1
Packit Service 991b93
# else
Packit Service 991b93
  /* Try the system call first, if the headers claim it exists
Packit Service 991b93
     (that is, if GNULIB_defined_F_DUPFD_CLOEXEC is 0), since we
Packit Service 991b93
     may be running with a glibc that has the macro but with an
Packit Service 991b93
     older kernel that does not support it.  Cache the
Packit Service 991b93
     information on whether the system call really works, but
Packit Service 991b93
     avoid caching failure if the corresponding F_DUPFD fails
Packit Service 991b93
     for any reason.  0 = unknown, 1 = yes, -1 = no.  */
Packit Service 991b93
  static int have_dupfd_cloexec = GNULIB_defined_F_DUPFD_CLOEXEC ? -1 : 0;
Packit Service 991b93
  if (0 <= have_dupfd_cloexec)
Packit Service 991b93
    {
Packit Service 991b93
      result = fcntl (fd, F_DUPFD_CLOEXEC, target);
Packit Service 991b93
      if (0 <= result || errno != EINVAL)
Packit Service 991b93
        {
Packit Service 991b93
          have_dupfd_cloexec = 1;
Packit Service 991b93
#  if REPLACE_FCHDIR
Packit Service 991b93
          if (0 <= result)
Packit Service 991b93
            result = _gl_register_dup (fd, result);
Packit Service 991b93
#  endif
Packit Service 991b93
        }
Packit Service 991b93
      else
Packit Service 991b93
        {
Packit Service 991b93
          result = rpl_fcntl_DUPFD (fd, target);
Packit Service 991b93
          if (result >= 0)
Packit Service 991b93
            have_dupfd_cloexec = -1;
Packit Service 991b93
        }
Packit Service 991b93
    }
Packit Service 991b93
  else
Packit Service 991b93
# endif
Packit Service 991b93
    result = rpl_fcntl_DUPFD (fd, target);
Packit Service 991b93
  if (0 <= result && have_dupfd_cloexec == -1)
Packit Service 991b93
    {
Packit Service 991b93
      int flags = fcntl (result, F_GETFD);
Packit Service 991b93
      if (flags < 0 || fcntl (result, F_SETFD, flags | FD_CLOEXEC) == -1)
Packit Service 991b93
        {
Packit Service 991b93
          int saved_errno = errno;
Packit Service 991b93
          close (result);
Packit Service 991b93
          errno = saved_errno;
Packit Service 991b93
          result = -1;
Packit Service 991b93
        }
Packit Service 991b93
    }
Packit Service 991b93
#endif /* HAVE_FCNTL */
Packit Service 991b93
  return result;
Packit Service 991b93
}
Packit Service 991b93
Packit Service 991b93
#undef fcntl
Packit Service 991b93
Packit Service 991b93
#ifdef __KLIBC__
Packit Service 991b93
Packit Service 991b93
static int
Packit Service 991b93
klibc_fcntl (int fd, int action, /* arg */...)
Packit Service 991b93
{
Packit Service 991b93
  va_list arg_ptr;
Packit Service 991b93
  int arg;
Packit Service 991b93
  struct stat sbuf;
Packit Service 991b93
  int result;
Packit Service 991b93
Packit Service 991b93
  va_start (arg_ptr, action);
Packit Service 991b93
  arg = va_arg (arg_ptr, int);
Packit Service 991b93
  result = fcntl (fd, action, arg);
Packit Service 991b93
  /* EPERM for F_DUPFD, ENOTSUP for others */
Packit Service 991b93
  if (result == -1 && (errno == EPERM || errno == ENOTSUP)
Packit Service 991b93
      && !fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode))
Packit Service 991b93
    {
Packit Service 991b93
      ULONG ulMode;
Packit Service 991b93
Packit Service 991b93
      switch (action)
Packit Service 991b93
        {
Packit Service 991b93
        case F_DUPFD:
Packit Service 991b93
          /* Find available fd */
Packit Service 991b93
          while (fcntl (arg, F_GETFL) != -1 || errno != EBADF)
Packit Service 991b93
            arg++;
Packit Service 991b93
Packit Service 991b93
          result = dup2 (fd, arg);
Packit Service 991b93
          break;
Packit Service 991b93
Packit Service 991b93
        /* Using underlying APIs is right ? */
Packit Service 991b93
        case F_GETFD:
Packit Service 991b93
          if (DosQueryFHState (fd, &ulMode))
Packit Service 991b93
            break;
Packit Service 991b93
Packit Service 991b93
          result = (ulMode & OPEN_FLAGS_NOINHERIT) ? FD_CLOEXEC : 0;
Packit Service 991b93
          break;
Packit Service 991b93
Packit Service 991b93
        case F_SETFD:
Packit Service 991b93
          if (arg & ~FD_CLOEXEC)
Packit Service 991b93
            break;
Packit Service 991b93
Packit Service 991b93
          if (DosQueryFHState (fd, &ulMode))
Packit Service 991b93
            break;
Packit Service 991b93
Packit Service 991b93
          if (arg & FD_CLOEXEC)
Packit Service 991b93
            ulMode |= OPEN_FLAGS_NOINHERIT;
Packit Service 991b93
          else
Packit Service 991b93
            ulMode &= ~OPEN_FLAGS_NOINHERIT;
Packit Service 991b93
Packit Service 991b93
          /* Filter supported flags.  */
Packit Service 991b93
          ulMode &= (OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_FAIL_ON_ERROR
Packit Service 991b93
                     | OPEN_FLAGS_NO_CACHE | OPEN_FLAGS_NOINHERIT);
Packit Service 991b93
Packit Service 991b93
          if (DosSetFHState (fd, ulMode))
Packit Service 991b93
            break;
Packit Service 991b93
Packit Service 991b93
          result = 0;
Packit Service 991b93
          break;
Packit Service 991b93
Packit Service 991b93
        case F_GETFL:
Packit Service 991b93
          result = 0;
Packit Service 991b93
          break;
Packit Service 991b93
Packit Service 991b93
        case F_SETFL:
Packit Service 991b93
          if (arg != 0)
Packit Service 991b93
            break;
Packit Service 991b93
Packit Service 991b93
          result = 0;
Packit Service 991b93
          break;
Packit Service 991b93
Packit Service 991b93
        default:
Packit Service 991b93
          errno = EINVAL;
Packit Service 991b93
          break;
Packit Service 991b93
        }
Packit Service 991b93
    }
Packit Service 991b93
Packit Service 991b93
  va_end (arg_ptr);
Packit Service 991b93
Packit Service 991b93
  return result;
Packit Service 991b93
}
Packit Service 991b93
Packit Service 991b93
#endif