Blame gl/fcntl.c

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