105436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Provide file descriptor control.
205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
305436638acc7c010349a69c3395f1a57c642dc62Ying Wang   Copyright (C) 2009-2012 Free Software Foundation, Inc.
405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   This program is free software: you can redistribute it and/or modify
605436638acc7c010349a69c3395f1a57c642dc62Ying Wang   it under the terms of the GNU General Public License as published by
705436638acc7c010349a69c3395f1a57c642dc62Ying Wang   the Free Software Foundation; either version 3 of the License, or
805436638acc7c010349a69c3395f1a57c642dc62Ying Wang   (at your option) any later version.
905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1005436638acc7c010349a69c3395f1a57c642dc62Ying Wang   This program is distributed in the hope that it will be useful,
1105436638acc7c010349a69c3395f1a57c642dc62Ying Wang   but WITHOUT ANY WARRANTY; without even the implied warranty of
1205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1305436638acc7c010349a69c3395f1a57c642dc62Ying Wang   GNU General Public License for more details.
1405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   You should have received a copy of the GNU General Public License
1605436638acc7c010349a69c3395f1a57c642dc62Ying Wang   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
1705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1805436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Written by Eric Blake <ebb9@byu.net>.  */
1905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <config.h>
2105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2205436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Specification.  */
2305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <fcntl.h>
2405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <errno.h>
2605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <limits.h>
2705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <stdarg.h>
2805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <unistd.h>
2905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
3005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if !HAVE_FCNTL
3105436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define rpl_fcntl fcntl
3205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
3305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#undef fcntl
3405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
3505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
3605436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Get declarations of the native Windows API functions.  */
3705436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define WIN32_LEAN_AND_MEAN
3805436638acc7c010349a69c3395f1a57c642dc62Ying Wang# include <windows.h>
3905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
4005436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Get _get_osfhandle.  */
4105436638acc7c010349a69c3395f1a57c642dc62Ying Wang# include "msvc-nothrow.h"
4205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
4305436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Upper bound on getdtablesize().  See lib/getdtablesize.c.  */
4405436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define OPEN_MAX_MAX 0x10000
4505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
4605436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Duplicate OLDFD into the first available slot of at least NEWFD,
4705436638acc7c010349a69c3395f1a57c642dc62Ying Wang   which must be positive, with FLAGS determining whether the duplicate
4805436638acc7c010349a69c3395f1a57c642dc62Ying Wang   will be inheritable.  */
4905436638acc7c010349a69c3395f1a57c642dc62Ying Wangstatic int
5005436638acc7c010349a69c3395f1a57c642dc62Ying Wangdupfd (int oldfd, int newfd, int flags)
5105436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
5205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Mingw has no way to create an arbitrary fd.  Iterate until all
5305436638acc7c010349a69c3395f1a57c642dc62Ying Wang     file descriptors less than newfd are filled up.  */
5405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  HANDLE curr_process = GetCurrentProcess ();
5505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  HANDLE old_handle = (HANDLE) _get_osfhandle (oldfd);
5605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  unsigned char fds_to_close[OPEN_MAX_MAX / CHAR_BIT];
5705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  unsigned int fds_to_close_bound = 0;
5805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int result;
5905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  BOOL inherit = flags & O_CLOEXEC ? FALSE : TRUE;
6005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int mode;
6105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
6205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (newfd < 0 || getdtablesize () <= newfd)
6305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
6405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      errno = EINVAL;
6505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      return -1;
6605436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
6705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (old_handle == INVALID_HANDLE_VALUE
6805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      || (mode = setmode (oldfd, O_BINARY)) == -1)
6905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
7005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* oldfd is not open, or is an unassigned standard file
7105436638acc7c010349a69c3395f1a57c642dc62Ying Wang         descriptor.  */
7205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      errno = EBADF;
7305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      return -1;
7405436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
7505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  setmode (oldfd, mode);
7605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  flags |= mode;
7705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
7805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  for (;;)
7905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
8005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      HANDLE new_handle;
8105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      int duplicated_fd;
8205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      unsigned int index;
8305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
8405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (!DuplicateHandle (curr_process,           /* SourceProcessHandle */
8505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                            old_handle,             /* SourceHandle */
8605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                            curr_process,           /* TargetProcessHandle */
8705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                            (PHANDLE) &new_handle,  /* TargetHandle */
8805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                            (DWORD) 0,              /* DesiredAccess */
8905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                            inherit,                /* InheritHandle */
9005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                            DUPLICATE_SAME_ACCESS)) /* Options */
9105436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
9205436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* TODO: Translate GetLastError () into errno.  */
9305436638acc7c010349a69c3395f1a57c642dc62Ying Wang          errno = EMFILE;
9405436638acc7c010349a69c3395f1a57c642dc62Ying Wang          result = -1;
9505436638acc7c010349a69c3395f1a57c642dc62Ying Wang          break;
9605436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
9705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      duplicated_fd = _open_osfhandle ((intptr_t) new_handle, flags);
9805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (duplicated_fd < 0)
9905436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
10005436638acc7c010349a69c3395f1a57c642dc62Ying Wang          CloseHandle (new_handle);
10105436638acc7c010349a69c3395f1a57c642dc62Ying Wang          errno = EMFILE;
10205436638acc7c010349a69c3395f1a57c642dc62Ying Wang          result = -1;
10305436638acc7c010349a69c3395f1a57c642dc62Ying Wang          break;
10405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
10505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (newfd <= duplicated_fd)
10605436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
10705436638acc7c010349a69c3395f1a57c642dc62Ying Wang          result = duplicated_fd;
10805436638acc7c010349a69c3395f1a57c642dc62Ying Wang          break;
10905436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
11005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
11105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* Set the bit duplicated_fd in fds_to_close[].  */
11205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      index = (unsigned int) duplicated_fd / CHAR_BIT;
11305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (fds_to_close_bound <= index)
11405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
11505436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (sizeof fds_to_close <= index)
11605436638acc7c010349a69c3395f1a57c642dc62Ying Wang            /* Need to increase OPEN_MAX_MAX.  */
11705436638acc7c010349a69c3395f1a57c642dc62Ying Wang            abort ();
11805436638acc7c010349a69c3395f1a57c642dc62Ying Wang          memset (fds_to_close + fds_to_close_bound, '\0',
11905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  index + 1 - fds_to_close_bound);
12005436638acc7c010349a69c3395f1a57c642dc62Ying Wang          fds_to_close_bound = index + 1;
12105436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
12205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      fds_to_close[index] |= 1 << ((unsigned int) duplicated_fd % CHAR_BIT);
12305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
12405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
12505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Close the previous fds that turned out to be too small.  */
12605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  {
12705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    int saved_errno = errno;
12805436638acc7c010349a69c3395f1a57c642dc62Ying Wang    unsigned int duplicated_fd;
12905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
13005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    for (duplicated_fd = 0;
13105436638acc7c010349a69c3395f1a57c642dc62Ying Wang         duplicated_fd < fds_to_close_bound * CHAR_BIT;
13205436638acc7c010349a69c3395f1a57c642dc62Ying Wang         duplicated_fd++)
13305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if ((fds_to_close[duplicated_fd / CHAR_BIT]
13405436638acc7c010349a69c3395f1a57c642dc62Ying Wang           >> (duplicated_fd % CHAR_BIT))
13505436638acc7c010349a69c3395f1a57c642dc62Ying Wang          & 1)
13605436638acc7c010349a69c3395f1a57c642dc62Ying Wang        close (duplicated_fd);
13705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
13805436638acc7c010349a69c3395f1a57c642dc62Ying Wang    errno = saved_errno;
13905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  }
14005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
14105436638acc7c010349a69c3395f1a57c642dc62Ying Wang# if REPLACE_FCHDIR
14205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (0 <= result)
14305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    result = _gl_register_dup (oldfd, result);
14405436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif
14505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return result;
14605436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
14705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif /* W32 */
14805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
14905436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Perform the specified ACTION on the file descriptor FD, possibly
15005436638acc7c010349a69c3395f1a57c642dc62Ying Wang   using the argument ARG further described below.  This replacement
15105436638acc7c010349a69c3395f1a57c642dc62Ying Wang   handles the following actions, and forwards all others on to the
15205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   native fcntl.  An unrecognized ACTION returns -1 with errno set to
15305436638acc7c010349a69c3395f1a57c642dc62Ying Wang   EINVAL.
15405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
15505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   F_DUPFD - duplicate FD, with int ARG being the minimum target fd.
15605436638acc7c010349a69c3395f1a57c642dc62Ying Wang   If successful, return the duplicate, which will be inheritable;
15705436638acc7c010349a69c3395f1a57c642dc62Ying Wang   otherwise return -1 and set errno.
15805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
15905436638acc7c010349a69c3395f1a57c642dc62Ying Wang   F_DUPFD_CLOEXEC - duplicate FD, with int ARG being the minimum
16005436638acc7c010349a69c3395f1a57c642dc62Ying Wang   target fd.  If successful, return the duplicate, which will not be
16105436638acc7c010349a69c3395f1a57c642dc62Ying Wang   inheritable; otherwise return -1 and set errno.
16205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
16305436638acc7c010349a69c3395f1a57c642dc62Ying Wang   F_GETFD - ARG need not be present.  If successful, return a
16405436638acc7c010349a69c3395f1a57c642dc62Ying Wang   non-negative value containing the descriptor flags of FD (only
16505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   FD_CLOEXEC is portable, but other flags may be present); otherwise
16605436638acc7c010349a69c3395f1a57c642dc62Ying Wang   return -1 and set errno.  */
16705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
16805436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
16905436638acc7c010349a69c3395f1a57c642dc62Ying Wangrpl_fcntl (int fd, int action, /* arg */...)
17005436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
17105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  va_list arg;
17205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int result = -1;
17305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  va_start (arg, action);
17405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  switch (action)
17505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
17605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
17705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if !HAVE_FCNTL
17805436638acc7c010349a69c3395f1a57c642dc62Ying Wang    case F_DUPFD:
17905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      {
18005436638acc7c010349a69c3395f1a57c642dc62Ying Wang        int target = va_arg (arg, int);
18105436638acc7c010349a69c3395f1a57c642dc62Ying Wang        result = dupfd (fd, target, 0);
18205436638acc7c010349a69c3395f1a57c642dc62Ying Wang        break;
18305436638acc7c010349a69c3395f1a57c642dc62Ying Wang      }
18405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#elif FCNTL_DUPFD_BUGGY || REPLACE_FCHDIR
18505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    case F_DUPFD:
18605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      {
18705436638acc7c010349a69c3395f1a57c642dc62Ying Wang        int target = va_arg (arg, int);
18805436638acc7c010349a69c3395f1a57c642dc62Ying Wang        /* Detect invalid target; needed for cygwin 1.5.x.  */
18905436638acc7c010349a69c3395f1a57c642dc62Ying Wang        if (target < 0 || getdtablesize () <= target)
19005436638acc7c010349a69c3395f1a57c642dc62Ying Wang          errno = EINVAL;
19105436638acc7c010349a69c3395f1a57c642dc62Ying Wang        else
19205436638acc7c010349a69c3395f1a57c642dc62Ying Wang          {
19305436638acc7c010349a69c3395f1a57c642dc62Ying Wang            /* Haiku alpha 2 loses fd flags on original.  */
19405436638acc7c010349a69c3395f1a57c642dc62Ying Wang            int flags = fcntl (fd, F_GETFD);
19505436638acc7c010349a69c3395f1a57c642dc62Ying Wang            if (flags < 0)
19605436638acc7c010349a69c3395f1a57c642dc62Ying Wang              {
19705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                result = -1;
19805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                break;
19905436638acc7c010349a69c3395f1a57c642dc62Ying Wang              }
20005436638acc7c010349a69c3395f1a57c642dc62Ying Wang            result = fcntl (fd, action, target);
20105436638acc7c010349a69c3395f1a57c642dc62Ying Wang            if (0 <= result && fcntl (fd, F_SETFD, flags) == -1)
20205436638acc7c010349a69c3395f1a57c642dc62Ying Wang              {
20305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                int saved_errno = errno;
20405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                close (result);
20505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                result = -1;
20605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                errno = saved_errno;
20705436638acc7c010349a69c3395f1a57c642dc62Ying Wang              }
20805436638acc7c010349a69c3395f1a57c642dc62Ying Wang# if REPLACE_FCHDIR
20905436638acc7c010349a69c3395f1a57c642dc62Ying Wang            if (0 <= result)
21005436638acc7c010349a69c3395f1a57c642dc62Ying Wang              result = _gl_register_dup (fd, result);
21105436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif
21205436638acc7c010349a69c3395f1a57c642dc62Ying Wang          }
21305436638acc7c010349a69c3395f1a57c642dc62Ying Wang        break;
21405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      } /* F_DUPFD */
21505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif /* FCNTL_DUPFD_BUGGY || REPLACE_FCHDIR */
21605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
21705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    case F_DUPFD_CLOEXEC:
21805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      {
21905436638acc7c010349a69c3395f1a57c642dc62Ying Wang        int target = va_arg (arg, int);
22005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
22105436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if !HAVE_FCNTL
22205436638acc7c010349a69c3395f1a57c642dc62Ying Wang        result = dupfd (fd, target, O_CLOEXEC);
22305436638acc7c010349a69c3395f1a57c642dc62Ying Wang        break;
22405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#else /* HAVE_FCNTL */
22505436638acc7c010349a69c3395f1a57c642dc62Ying Wang        /* Try the system call first, if the headers claim it exists
22605436638acc7c010349a69c3395f1a57c642dc62Ying Wang           (that is, if GNULIB_defined_F_DUPFD_CLOEXEC is 0), since we
22705436638acc7c010349a69c3395f1a57c642dc62Ying Wang           may be running with a glibc that has the macro but with an
22805436638acc7c010349a69c3395f1a57c642dc62Ying Wang           older kernel that does not support it.  Cache the
22905436638acc7c010349a69c3395f1a57c642dc62Ying Wang           information on whether the system call really works, but
23005436638acc7c010349a69c3395f1a57c642dc62Ying Wang           avoid caching failure if the corresponding F_DUPFD fails
23105436638acc7c010349a69c3395f1a57c642dc62Ying Wang           for any reason.  0 = unknown, 1 = yes, -1 = no.  */
23205436638acc7c010349a69c3395f1a57c642dc62Ying Wang        static int have_dupfd_cloexec = GNULIB_defined_F_DUPFD_CLOEXEC ? -1 : 0;
23305436638acc7c010349a69c3395f1a57c642dc62Ying Wang        if (0 <= have_dupfd_cloexec)
23405436638acc7c010349a69c3395f1a57c642dc62Ying Wang          {
23505436638acc7c010349a69c3395f1a57c642dc62Ying Wang            result = fcntl (fd, action, target);
23605436638acc7c010349a69c3395f1a57c642dc62Ying Wang            if (0 <= result || errno != EINVAL)
23705436638acc7c010349a69c3395f1a57c642dc62Ying Wang              {
23805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                have_dupfd_cloexec = 1;
23905436638acc7c010349a69c3395f1a57c642dc62Ying Wang# if REPLACE_FCHDIR
24005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                if (0 <= result)
24105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  result = _gl_register_dup (fd, result);
24205436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif
24305436638acc7c010349a69c3395f1a57c642dc62Ying Wang              }
24405436638acc7c010349a69c3395f1a57c642dc62Ying Wang            else
24505436638acc7c010349a69c3395f1a57c642dc62Ying Wang              {
24605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                result = rpl_fcntl (fd, F_DUPFD, target);
24705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                if (result < 0)
24805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  break;
24905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                have_dupfd_cloexec = -1;
25005436638acc7c010349a69c3395f1a57c642dc62Ying Wang              }
25105436638acc7c010349a69c3395f1a57c642dc62Ying Wang          }
25205436638acc7c010349a69c3395f1a57c642dc62Ying Wang        else
25305436638acc7c010349a69c3395f1a57c642dc62Ying Wang          result = rpl_fcntl (fd, F_DUPFD, target);
25405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        if (0 <= result && have_dupfd_cloexec == -1)
25505436638acc7c010349a69c3395f1a57c642dc62Ying Wang          {
25605436638acc7c010349a69c3395f1a57c642dc62Ying Wang            int flags = fcntl (result, F_GETFD);
25705436638acc7c010349a69c3395f1a57c642dc62Ying Wang            if (flags < 0 || fcntl (result, F_SETFD, flags | FD_CLOEXEC) == -1)
25805436638acc7c010349a69c3395f1a57c642dc62Ying Wang              {
25905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                int saved_errno = errno;
26005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                close (result);
26105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                errno = saved_errno;
26205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                result = -1;
26305436638acc7c010349a69c3395f1a57c642dc62Ying Wang              }
26405436638acc7c010349a69c3395f1a57c642dc62Ying Wang          }
26505436638acc7c010349a69c3395f1a57c642dc62Ying Wang        break;
26605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif /* HAVE_FCNTL */
26705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      } /* F_DUPFD_CLOEXEC */
26805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
26905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if !HAVE_FCNTL
27005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    case F_GETFD:
27105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      {
27205436638acc7c010349a69c3395f1a57c642dc62Ying Wang# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
27305436638acc7c010349a69c3395f1a57c642dc62Ying Wang        HANDLE handle = (HANDLE) _get_osfhandle (fd);
27405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        DWORD flags;
27505436638acc7c010349a69c3395f1a57c642dc62Ying Wang        if (handle == INVALID_HANDLE_VALUE
27605436638acc7c010349a69c3395f1a57c642dc62Ying Wang            || GetHandleInformation (handle, &flags) == 0)
27705436638acc7c010349a69c3395f1a57c642dc62Ying Wang          errno = EBADF;
27805436638acc7c010349a69c3395f1a57c642dc62Ying Wang        else
27905436638acc7c010349a69c3395f1a57c642dc62Ying Wang          result = (flags & HANDLE_FLAG_INHERIT) ? 0 : FD_CLOEXEC;
28005436638acc7c010349a69c3395f1a57c642dc62Ying Wang# else /* !W32 */
28105436638acc7c010349a69c3395f1a57c642dc62Ying Wang        /* Use dup2 to reject invalid file descriptors.  No way to
28205436638acc7c010349a69c3395f1a57c642dc62Ying Wang           access this information, so punt.  */
28305436638acc7c010349a69c3395f1a57c642dc62Ying Wang        if (0 <= dup2 (fd, fd))
28405436638acc7c010349a69c3395f1a57c642dc62Ying Wang          result = 0;
28505436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif /* !W32 */
28605436638acc7c010349a69c3395f1a57c642dc62Ying Wang        break;
28705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      } /* F_GETFD */
28805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif /* !HAVE_FCNTL */
28905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
29005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* Implementing F_SETFD on mingw is not trivial - there is no
29105436638acc7c010349a69c3395f1a57c642dc62Ying Wang         API for changing the O_NOINHERIT bit on an fd, and merely
29205436638acc7c010349a69c3395f1a57c642dc62Ying Wang         changing the HANDLE_FLAG_INHERIT bit on the underlying handle
29305436638acc7c010349a69c3395f1a57c642dc62Ying Wang         can lead to odd state.  It may be possible by duplicating the
29405436638acc7c010349a69c3395f1a57c642dc62Ying Wang         handle, using _open_osfhandle with the right flags, then
29505436638acc7c010349a69c3395f1a57c642dc62Ying Wang         using dup2 to move the duplicate onto the original, but that
29605436638acc7c010349a69c3395f1a57c642dc62Ying Wang         is not supported for now.  */
29705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
29805436638acc7c010349a69c3395f1a57c642dc62Ying Wang    default:
29905436638acc7c010349a69c3395f1a57c642dc62Ying Wang      {
30005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if HAVE_FCNTL
30105436638acc7c010349a69c3395f1a57c642dc62Ying Wang        void *p = va_arg (arg, void *);
30205436638acc7c010349a69c3395f1a57c642dc62Ying Wang        result = fcntl (fd, action, p);
30305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#else
30405436638acc7c010349a69c3395f1a57c642dc62Ying Wang        errno = EINVAL;
30505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
30605436638acc7c010349a69c3395f1a57c642dc62Ying Wang        break;
30705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      }
30805436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
30905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  va_end (arg);
31005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return result;
31105436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
312