emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] trunk r113315: Make file descriptors close-on-exec when po


From: Paul Eggert
Subject: [Emacs-diffs] trunk r113315: Make file descriptors close-on-exec when possible.
Date: Sun, 07 Jul 2013 18:00:50 +0000
User-agent: Bazaar (2.6b2)

------------------------------------------------------------
revno: 113315
revision-id: address@hidden
parent: address@hidden
fixes bug: http://debbugs.gnu.org/14803
committer: Paul Eggert <address@hidden>
branch nick: trunk
timestamp: Sun 2013-07-07 11:00:14 -0700
message:
  Make file descriptors close-on-exec when possible.
  
  This simplifies Emacs a bit, since it no longer needs to worry
  about closing file descriptors by hand in some cases.
  It also fixes some unlikely races.  Not all such races, as
  libraries often open files internally without setting
  close-on-exec, but it's an improvement.
  * admin/merge-gnulib (GNULIB_MODULES): Add fcntl, pipe2.
  (GNULIB_TOOL_FLAGS): Avoid binary-io, close.  Do not avoid fcntl.
  * configure.ac (mkostemp): New function to check for.
  (PTY_OPEN): Pass O_CLOEXEC to posix_openpt.
  * lib/fcntl.c, lib/getdtablesize.c, lib/pipe2.c, m4/fcntl.m4:
  * m4/getdtablesize.m4, m4/pipe2.m4: New files, taken from gnulib.
  * lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate.
  * nt/gnulib.mk: Remove empty gl_GNULIB_ENABLED_verify section;
  otherwise, gnulib-tool complains given close-on-exec changes.
  * nt/inc/ms-w32.h (pipe): Remove.
  * nt/mingw-cfg.site (ac_cv_func_fcntl, gl_cv_func_fcntl_f_dupfd_cloexec)
  (gl_cv_func_fcntl_f_dupfd_works, ac_cv_func_pipe2): New vars.
  * src/alloc.c (valid_pointer_p) [!WINDOWSNT]:
  * src/callproc.c (Fcall_process) [!MSDOS]:
  * src/emacs.c (main) [!DOS_NT]:
  * src/nsterm.m (ns_term_init):
  * src/process.c (create_process):
  Use 'pipe2' with O_CLOEXEC instead of 'pipe'.
  * src/emacs.c (Fcall_process_region) [HAVE_MKOSTEMP]:
  * src/filelock.c (create_lock_file) [HAVE_MKOSTEMP]:
  Prefer mkostemp with O_CLOEXEC to mkstemp.
  * src/callproc.c (relocate_fd) [!WINDOWSNT]:
  * src/emacs.c (main): Use F_DUPFD_CLOEXEC, not plain F_DUPFD.
  No need to use fcntl (..., F_SETFD, FD_CLOEXEC), since we're
  now using pipe2.
  * src/filelock.c (create_lock_file) [! HAVE_MKOSTEMP]:
  Make the resulting file descriptor close-on-exec.
  * src/lisp.h, src/lread.c, src/process.c (close_load_descs, 
close_process_descs):
  * src/lread.c (load_descriptor_list, load_descriptor_unwind):
  Remove; no longer needed.  All uses removed.
  * src/process.c (SOCK_CLOEXEC): Define to 0 if not supplied by system.
  (close_on_exec, accept4, process_socket) [!SOCK_CLOEXEC]:
  New functions.
  (socket) [!SOCK_CLOEXEC]: Supply a substitute.
  (Fmake_network_process, Fnetwork_interface_list):
  (Fnetwork_interface_info, server_accept_connection):
  Make newly-created socket close-on-exec.
  * src/sysdep.c (emacs_open, emacs_fopen):
  Make new-created descriptor close-on-exec.
  * src/w32.c (fcntl): Support F_DUPFD_CLOEXEC well enough for Emacs.
  * src/w32.c, src/w32.h (pipe2): Rename from 'pipe', with new flags arg.
added:
  lib/fcntl.c                    fcntl.c-20130707175726-ax31vjqobh17obwz-1
  lib/getdtablesize.c            
getdtablesize.c-20130707175726-ax31vjqobh17obwz-2
  lib/pipe2.c                    pipe2.c-20130707175726-ax31vjqobh17obwz-3
  m4/fcntl.m4                    fcntl.m4-20130707175726-ax31vjqobh17obwz-4
  m4/getdtablesize.m4            
getdtablesize.m4-20130707175726-ax31vjqobh17obwz-5
  m4/pipe2.m4                    pipe2.m4-20130707175726-ax31vjqobh17obwz-6
modified:
  ChangeLog                      changelog-20091113204419-o5vbwnq5f7feedwu-1538
  admin/ChangeLog                changelog-20091113204419-o5vbwnq5f7feedwu-2226
  admin/merge-gnulib             mergegnulib-20120521022411-ndnoaiok33j6dn0g-1
  configure.ac                   
configure.in-20091113204419-o5vbwnq5f7feedwu-783
  lib/gnulib.mk                  gnulib.mk-20110108211121-3ig4un4ogtyyca3s-7
  m4/gnulib-comp.m4              glcomp.m4-20110127072028-6mkjqxjzdsx0wp15-1
  nt/ChangeLog                   changelog-20091113204419-o5vbwnq5f7feedwu-1545
  nt/gnulib.mk                   gnulib.mk-20130331140345-sdcxubmlur6jjs1e-1
  nt/inc/ms-w32.h                msw32.h-20091113204419-o5vbwnq5f7feedwu-807
  nt/mingw-cfg.site              mingwcfg.site-20130329112849-w6zo8bvz3ddvox05-1
  src/ChangeLog                  changelog-20091113204419-o5vbwnq5f7feedwu-1438
  src/alloc.c                    alloc.c-20091113204419-o5vbwnq5f7feedwu-252
  src/callproc.c                 callproc.c-20091113204419-o5vbwnq5f7feedwu-248
  src/emacs.c                    emacs.c-20091113204419-o5vbwnq5f7feedwu-241
  src/filelock.c                 filelock.c-20091113204419-o5vbwnq5f7feedwu-179
  src/lisp.h                     lisp.h-20091113204419-o5vbwnq5f7feedwu-253
  src/lread.c                    lread.c-20091113204419-o5vbwnq5f7feedwu-266
  src/nsterm.m                   nsterm.m-20091113204419-o5vbwnq5f7feedwu-8747
  src/process.c                  process.c-20091113204419-o5vbwnq5f7feedwu-462
  src/sysdep.c                   sysdep.c-20091113204419-o5vbwnq5f7feedwu-448
  src/w32.c                      w32.c-20091113204419-o5vbwnq5f7feedwu-808
  src/w32.h                      w32.h-20091113204419-o5vbwnq5f7feedwu-809
=== modified file 'ChangeLog'
--- a/ChangeLog 2013-07-03 03:20:04 +0000
+++ b/ChangeLog 2013-07-07 18:00:14 +0000
@@ -1,3 +1,12 @@
+2013-07-07  Paul Eggert  <address@hidden>
+
+       Make file descriptors close-on-exec when possible (Bug#14803).
+       * configure.ac (mkostemp): New function to check for.
+       (PTY_OPEN): Pass O_CLOEXEC to posix_openpt.
+       * lib/fcntl.c, lib/getdtablesize.c, lib/pipe2.c, m4/fcntl.m4:
+       * m4/getdtablesize.m4, m4/pipe2.m4: New files, taken from gnulib.
+       * lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate.
+
 2013-07-03  Christoph Egger  <address@hidden>  (tiny change)
 
        * configure.ac (emacs_broken_SIGIO): Set on gnu-kfreebsd to avoid hang.

=== modified file 'admin/ChangeLog'
--- a/admin/ChangeLog   2013-07-06 18:28:54 +0000
+++ b/admin/ChangeLog   2013-07-07 18:00:14 +0000
@@ -1,3 +1,9 @@
+2013-07-07  Paul Eggert  <address@hidden>
+
+       Make file descriptors close-on-exec when possible (Bug#14803).
+       * merge-gnulib (GNULIB_MODULES): Add fcntl, pipe2.
+       (GNULIB_TOOL_FLAGS): Avoid binary-io, close.  Do not avoid fcntl.
+
 2013-07-06  Glenn Morris  <address@hidden>
 
        * admin.el (manual-misc-manuals): New function.

=== modified file 'admin/merge-gnulib'
--- a/admin/merge-gnulib        2013-05-07 21:34:03 +0000
+++ b/admin/merge-gnulib        2013-07-07 18:00:14 +0000
@@ -29,11 +29,11 @@
   alloca-opt c-ctype c-strcase
   careadlinkat close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512
   dtoastr dtotimespec dup2 environ execinfo faccessat
-  fcntl-h fdatasync fdopendir filemode fstatat fsync
+  fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync
   getloadavg getopt-gnu gettime gettimeofday
   ignore-value intprops largefile lstat
   manywarnings memrchr mktime
-  pselect pthread_sigmask putenv qacl readlink readlinkat
+  pipe2 pselect pthread_sigmask putenv qacl readlink readlinkat
   sig2str socklen stat-time stdalign stdarg stdbool stdio
   strftime strtoimax strtoumax symlink sys_stat
   sys_time time timer-time timespec-add timespec-sub unsetenv utimens
@@ -41,8 +41,8 @@
 '
 
 GNULIB_TOOL_FLAGS='
-  --avoid=dup
-  --avoid=fchdir --avoid=fcntl --avoid=fstat
+  --avoid=binary-io --avoid=close --avoid=dup
+  --avoid=fchdir --avoid=fstat
   --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow
   --avoid=open --avoid=openat-die --avoid=opendir
   --avoid=raise

=== modified file 'configure.ac'
--- a/configure.ac      2013-07-03 03:20:04 +0000
+++ b/configure.ac      2013-07-07 18:00:14 +0000
@@ -3244,7 +3244,7 @@
 getrlimit setrlimit shutdown getaddrinfo \
 strsignal setitimer \
 sendto recvfrom getsockname getpeername getifaddrs freeifaddrs \
-gai_strerror mkstemp getline getdelim sync \
+gai_strerror mkostemp mkstemp getline getdelim sync \
 difftime posix_memalign \
 getpwent endpwent getgrent endgrent \
 touchlock \
@@ -3934,7 +3934,7 @@
       AC_DEFINE(PTY_TTY_NAME_SPRINTF, [{ char *ptyname = 0; sigset_t blocked; 
sigemptyset (&blocked); sigaddset (&blocked, SIGCHLD); pthread_sigmask 
(SIG_BLOCK, &blocked, 0); if (grantpt (fd) != -1 && unlockpt (fd) != -1) 
ptyname = ptsname(fd); pthread_sigmask (SIG_UNBLOCK, &blocked, 0); if 
(!ptyname) { close (fd); return -1; } snprintf (pty_name, sizeof pty_name, 
"%s", ptyname); }])
       dnl if HAVE_POSIX_OPENPT
       if test "x$ac_cv_func_posix_openpt" = xyes; then
-        AC_DEFINE(PTY_OPEN, [fd = posix_openpt (O_RDWR | O_NOCTTY)])
+        AC_DEFINE(PTY_OPEN, [fd = posix_openpt (O_RDWR | O_CLOEXEC | 
O_NOCTTY)])
         AC_DEFINE(PTY_NAME_SPRINTF, [])
       dnl if HAVE_GETPT
       elif test "x$ac_cv_func_getpt" = xyes; then

=== added file 'lib/fcntl.c'
--- a/lib/fcntl.c       1970-01-01 00:00:00 +0000
+++ b/lib/fcntl.c       2013-07-07 18:00:14 +0000
@@ -0,0 +1,311 @@
+/* Provide file descriptor control.
+
+   Copyright (C) 2009-2013 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Written by Eric Blake <address@hidden>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <fcntl.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#if !HAVE_FCNTL
+# define rpl_fcntl fcntl
+#endif
+#undef fcntl
+
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+/* Get declarations of the native Windows API functions.  */
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+
+/* Get _get_osfhandle.  */
+# include "msvc-nothrow.h"
+
+/* Upper bound on getdtablesize().  See lib/getdtablesize.c.  */
+# define OPEN_MAX_MAX 0x10000
+
+/* Duplicate OLDFD into the first available slot of at least NEWFD,
+   which must be positive, with FLAGS determining whether the duplicate
+   will be inheritable.  */
+static int
+dupfd (int oldfd, int newfd, int flags)
+{
+  /* Mingw has no way to create an arbitrary fd.  Iterate until all
+     file descriptors less than newfd are filled up.  */
+  HANDLE curr_process = GetCurrentProcess ();
+  HANDLE old_handle = (HANDLE) _get_osfhandle (oldfd);
+  unsigned char fds_to_close[OPEN_MAX_MAX / CHAR_BIT];
+  unsigned int fds_to_close_bound = 0;
+  int result;
+  BOOL inherit = flags & O_CLOEXEC ? FALSE : TRUE;
+  int mode;
+
+  if (newfd < 0 || getdtablesize () <= newfd)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+  if (old_handle == INVALID_HANDLE_VALUE
+      || (mode = setmode (oldfd, O_BINARY)) == -1)
+    {
+      /* oldfd is not open, or is an unassigned standard file
+         descriptor.  */
+      errno = EBADF;
+      return -1;
+    }
+  setmode (oldfd, mode);
+  flags |= mode;
+
+  for (;;)
+    {
+      HANDLE new_handle;
+      int duplicated_fd;
+      unsigned int index;
+
+      if (!DuplicateHandle (curr_process,           /* SourceProcessHandle */
+                            old_handle,             /* SourceHandle */
+                            curr_process,           /* TargetProcessHandle */
+                            (PHANDLE) &new_handle,  /* TargetHandle */
+                            (DWORD) 0,              /* DesiredAccess */
+                            inherit,                /* InheritHandle */
+                            DUPLICATE_SAME_ACCESS)) /* Options */
+        {
+          /* TODO: Translate GetLastError () into errno.  */
+          errno = EMFILE;
+          result = -1;
+          break;
+        }
+      duplicated_fd = _open_osfhandle ((intptr_t) new_handle, flags);
+      if (duplicated_fd < 0)
+        {
+          CloseHandle (new_handle);
+          errno = EMFILE;
+          result = -1;
+          break;
+        }
+      if (newfd <= duplicated_fd)
+        {
+          result = duplicated_fd;
+          break;
+        }
+
+      /* Set the bit duplicated_fd in fds_to_close[].  */
+      index = (unsigned int) duplicated_fd / CHAR_BIT;
+      if (fds_to_close_bound <= index)
+        {
+          if (sizeof fds_to_close <= index)
+            /* Need to increase OPEN_MAX_MAX.  */
+            abort ();
+          memset (fds_to_close + fds_to_close_bound, '\0',
+                  index + 1 - fds_to_close_bound);
+          fds_to_close_bound = index + 1;
+        }
+      fds_to_close[index] |= 1 << ((unsigned int) duplicated_fd % CHAR_BIT);
+    }
+
+  /* Close the previous fds that turned out to be too small.  */
+  {
+    int saved_errno = errno;
+    unsigned int duplicated_fd;
+
+    for (duplicated_fd = 0;
+         duplicated_fd < fds_to_close_bound * CHAR_BIT;
+         duplicated_fd++)
+      if ((fds_to_close[duplicated_fd / CHAR_BIT]
+           >> (duplicated_fd % CHAR_BIT))
+          & 1)
+        close (duplicated_fd);
+
+    errno = saved_errno;
+  }
+
+# if REPLACE_FCHDIR
+  if (0 <= result)
+    result = _gl_register_dup (oldfd, result);
+# endif
+  return result;
+}
+#endif /* W32 */
+
+/* Perform the specified ACTION on the file descriptor FD, possibly
+   using the argument ARG further described below.  This replacement
+   handles the following actions, and forwards all others on to the
+   native fcntl.  An unrecognized ACTION returns -1 with errno set to
+   EINVAL.
+
+   F_DUPFD - duplicate FD, with int ARG being the minimum target fd.
+   If successful, return the duplicate, which will be inheritable;
+   otherwise return -1 and set errno.
+
+   F_DUPFD_CLOEXEC - duplicate FD, with int ARG being the minimum
+   target fd.  If successful, return the duplicate, which will not be
+   inheritable; otherwise return -1 and set errno.
+
+   F_GETFD - ARG need not be present.  If successful, return a
+   non-negative value containing the descriptor flags of FD (only
+   FD_CLOEXEC is portable, but other flags may be present); otherwise
+   return -1 and set errno.  */
+
+int
+rpl_fcntl (int fd, int action, /* arg */...)
+{
+  va_list arg;
+  int result = -1;
+  va_start (arg, action);
+  switch (action)
+    {
+
+#if !HAVE_FCNTL
+    case F_DUPFD:
+      {
+        int target = va_arg (arg, int);
+        result = dupfd (fd, target, 0);
+        break;
+      }
+#elif FCNTL_DUPFD_BUGGY || REPLACE_FCHDIR
+    case F_DUPFD:
+      {
+        int target = va_arg (arg, int);
+        /* Detect invalid target; needed for cygwin 1.5.x.  */
+        if (target < 0 || getdtablesize () <= target)
+          errno = EINVAL;
+        else
+          {
+            /* Haiku alpha 2 loses fd flags on original.  */
+            int flags = fcntl (fd, F_GETFD);
+            if (flags < 0)
+              {
+                result = -1;
+                break;
+              }
+            result = fcntl (fd, action, target);
+            if (0 <= result && fcntl (fd, F_SETFD, flags) == -1)
+              {
+                int saved_errno = errno;
+                close (result);
+                result = -1;
+                errno = saved_errno;
+              }
+# if REPLACE_FCHDIR
+            if (0 <= result)
+              result = _gl_register_dup (fd, result);
+# endif
+          }
+        break;
+      } /* F_DUPFD */
+#endif /* FCNTL_DUPFD_BUGGY || REPLACE_FCHDIR */
+
+    case F_DUPFD_CLOEXEC:
+      {
+        int target = va_arg (arg, int);
+
+#if !HAVE_FCNTL
+        result = dupfd (fd, target, O_CLOEXEC);
+        break;
+#else /* HAVE_FCNTL */
+        /* Try the system call first, if the headers claim it exists
+           (that is, if GNULIB_defined_F_DUPFD_CLOEXEC is 0), since we
+           may be running with a glibc that has the macro but with an
+           older kernel that does not support it.  Cache the
+           information on whether the system call really works, but
+           avoid caching failure if the corresponding F_DUPFD fails
+           for any reason.  0 = unknown, 1 = yes, -1 = no.  */
+        static int have_dupfd_cloexec = GNULIB_defined_F_DUPFD_CLOEXEC ? -1 : 
0;
+        if (0 <= have_dupfd_cloexec)
+          {
+            result = fcntl (fd, action, target);
+            if (0 <= result || errno != EINVAL)
+              {
+                have_dupfd_cloexec = 1;
+# if REPLACE_FCHDIR
+                if (0 <= result)
+                  result = _gl_register_dup (fd, result);
+# endif
+              }
+            else
+              {
+                result = rpl_fcntl (fd, F_DUPFD, target);
+                if (result < 0)
+                  break;
+                have_dupfd_cloexec = -1;
+              }
+          }
+        else
+          result = rpl_fcntl (fd, F_DUPFD, target);
+        if (0 <= result && have_dupfd_cloexec == -1)
+          {
+            int flags = fcntl (result, F_GETFD);
+            if (flags < 0 || fcntl (result, F_SETFD, flags | FD_CLOEXEC) == -1)
+              {
+                int saved_errno = errno;
+                close (result);
+                errno = saved_errno;
+                result = -1;
+              }
+          }
+        break;
+#endif /* HAVE_FCNTL */
+      } /* F_DUPFD_CLOEXEC */
+
+#if !HAVE_FCNTL
+    case F_GETFD:
+      {
+# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+        HANDLE handle = (HANDLE) _get_osfhandle (fd);
+        DWORD flags;
+        if (handle == INVALID_HANDLE_VALUE
+            || GetHandleInformation (handle, &flags) == 0)
+          errno = EBADF;
+        else
+          result = (flags & HANDLE_FLAG_INHERIT) ? 0 : FD_CLOEXEC;
+# else /* !W32 */
+        /* Use dup2 to reject invalid file descriptors.  No way to
+           access this information, so punt.  */
+        if (0 <= dup2 (fd, fd))
+          result = 0;
+# endif /* !W32 */
+        break;
+      } /* F_GETFD */
+#endif /* !HAVE_FCNTL */
+
+      /* Implementing F_SETFD on mingw is not trivial - there is no
+         API for changing the O_NOINHERIT bit on an fd, and merely
+         changing the HANDLE_FLAG_INHERIT bit on the underlying handle
+         can lead to odd state.  It may be possible by duplicating the
+         handle, using _open_osfhandle with the right flags, then
+         using dup2 to move the duplicate onto the original, but that
+         is not supported for now.  */
+
+    default:
+      {
+#if HAVE_FCNTL
+        void *p = va_arg (arg, void *);
+        result = fcntl (fd, action, p);
+#else
+        errno = EINVAL;
+#endif
+        break;
+      }
+    }
+  va_end (arg);
+  return result;
+}

=== added file 'lib/getdtablesize.c'
--- a/lib/getdtablesize.c       1970-01-01 00:00:00 +0000
+++ b/lib/getdtablesize.c       2013-07-07 18:00:14 +0000
@@ -0,0 +1,86 @@
+/* getdtablesize() function for platforms that don't have it.
+   Copyright (C) 2008-2013 Free Software Foundation, Inc.
+   Written by Bruno Haible <address@hidden>, 2008.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <unistd.h>
+
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+
+#include <stdio.h>
+
+#include "msvc-inval.h"
+
+#if HAVE_MSVC_INVALID_PARAMETER_HANDLER
+static int
+_setmaxstdio_nothrow (int newmax)
+{
+  int result;
+
+  TRY_MSVC_INVAL
+    {
+      result = _setmaxstdio (newmax);
+    }
+  CATCH_MSVC_INVAL
+    {
+      result = -1;
+    }
+  DONE_MSVC_INVAL;
+
+  return result;
+}
+# define _setmaxstdio _setmaxstdio_nothrow
+#endif
+
+/* Cache for the previous getdtablesize () result.  */
+static int dtablesize;
+
+int
+getdtablesize (void)
+{
+  if (dtablesize == 0)
+    {
+      /* We are looking for the number N such that the valid file descriptors
+         are 0..N-1.  It can be obtained through a loop as follows:
+           {
+             int fd;
+             for (fd = 3; fd < 65536; fd++)
+               if (dup2 (0, fd) == -1)
+                 break;
+             return fd;
+           }
+         On Windows XP, the result is 2048.
+         The drawback of this loop is that it allocates memory for a libc
+         internal array that is never freed.
+
+         The number N can also be obtained as the upper bound for
+         _getmaxstdio ().  _getmaxstdio () returns the maximum number of open
+         FILE objects.  The sanity check in _setmaxstdio reveals the maximum
+         number of file descriptors.  This too allocates memory, but it is
+         freed when we call _setmaxstdio with the original value.  */
+      int orig_max_stdio = _getmaxstdio ();
+      unsigned int bound;
+      for (bound = 0x10000; _setmaxstdio (bound) < 0; bound = bound / 2)
+        ;
+      _setmaxstdio (orig_max_stdio);
+      dtablesize = bound;
+    }
+  return dtablesize;
+}
+
+#endif

=== modified file 'lib/gnulib.mk'
--- a/lib/gnulib.mk     2013-05-07 21:34:03 +0000
+++ b/lib/gnulib.mk     2013-07-07 18:00:14 +0000
@@ -21,7 +21,7 @@
 # the same distribution terms as the rest of that program.
 #
 # Generated by gnulib-tool.
-# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib 
--m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=dup 
--avoid=fchdir --avoid=fcntl --avoid=fstat --avoid=malloc-posix 
--avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die 
--avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select 
--avoid=sigprocmask --avoid=sys_types --avoid=threadlib 
--makefile-name=gnulib.mk --conditional-dependencies --no-libtool 
--macro-prefix=gl --no-vc-files alloca-opt c-ctype c-strcase careadlinkat 
close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr 
dtotimespec dup2 environ execinfo faccessat fcntl-h fdatasync fdopendir 
filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday ignore-value 
intprops largefile lstat manywarnings memrchr mktime pselect pthread_sigmask 
putenv qacl readlink readlinkat sig2str socklen stat-time stdalign stdarg 
stdbool stdio strftime strtoimax strtoumax symlink sys_stat sys_time time 
timer-time timespec-add timespec-sub unsetenv utimens warnings
+# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib 
--m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux 
--avoid=binary-io --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat 
--avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open 
--avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd 
--avoid=select --avoid=sigprocmask --avoid=sys_types --avoid=threadlib 
--makefile-name=gnulib.mk --conditional-dependencies --no-libtool 
--macro-prefix=gl --no-vc-files alloca-opt c-ctype c-strcase careadlinkat 
close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr 
dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir 
filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday ignore-value 
intprops largefile lstat manywarnings memrchr mktime pipe2 pselect 
pthread_sigmask putenv qacl readlink readlinkat sig2str socklen stat-time 
stdalign stdarg stdbool stdio strftime strtoimax strtoumax symlink sys_stat 
sys_time time timer-time timespec-add timespec-sub unsetenv utimens warnings
 
 
 MOSTLYCLEANFILES += core *.stackdump
@@ -296,6 +296,15 @@
 
 ## end   gnulib module faccessat
 
+## begin gnulib module fcntl
+
+
+EXTRA_DIST += fcntl.c
+
+EXTRA_libgnu_a_SOURCES += fcntl.c
+
+## end   gnulib module fcntl
+
 ## begin gnulib module fcntl-h
 
 BUILT_SOURCES += fcntl.h
@@ -384,6 +393,17 @@
 
 ## end   gnulib module fsync
 
+## begin gnulib module getdtablesize
+
+if gl_GNULIB_ENABLED_getdtablesize
+
+endif
+EXTRA_DIST += getdtablesize.c
+
+EXTRA_libgnu_a_SOURCES += getdtablesize.c
+
+## end   gnulib module getdtablesize
+
 ## begin gnulib module getgroups
 
 if gl_GNULIB_ENABLED_getgroups
@@ -568,6 +588,12 @@
 
 ## end   gnulib module pathmax
 
+## begin gnulib module pipe2
+
+libgnu_a_SOURCES += pipe2.c
+
+## end   gnulib module pipe2
+
 ## begin gnulib module pselect
 
 
@@ -1704,9 +1730,7 @@
 
 ## begin gnulib module verify
 
-if gl_GNULIB_ENABLED_verify
 
-endif
 EXTRA_DIST += verify.h
 
 ## end   gnulib module verify

=== added file 'lib/pipe2.c'
--- a/lib/pipe2.c       1970-01-01 00:00:00 +0000
+++ b/lib/pipe2.c       2013-07-07 18:00:14 +0000
@@ -0,0 +1,171 @@
+/* Create a pipe, with specific opening flags.
+   Copyright (C) 2009-2013 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with this program; if not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <unistd.h>
+
+#include <errno.h>
+#include <fcntl.h>
+
+#if GNULIB_BINARY_IO
+# include "binary-io.h"
+#endif
+
+#include "verify.h"
+
+#if GNULIB_defined_O_NONBLOCK
+# include "nonblocking.h"
+#endif
+
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+/* Native Windows API.  */
+
+# include <io.h>
+
+#endif
+
+int
+pipe2 (int fd[2], int flags)
+{
+  /* Mingw _pipe() corrupts fd on failure; also, if we succeed at
+     creating the pipe but later fail at changing fcntl, we want
+     to leave fd unchanged: http://austingroupbugs.net/view.php?id=467  */
+  int tmp[2];
+  tmp[0] = fd[0];
+  tmp[1] = fd[1];
+
+#if HAVE_PIPE2
+# undef pipe2
+  /* Try the system call first, if it exists.  (We may be running with a glibc
+     that has the function but with an older kernel that lacks it.)  */
+  {
+    /* Cache the information whether the system call really exists.  */
+    static int have_pipe2_really; /* 0 = unknown, 1 = yes, -1 = no */
+    if (have_pipe2_really >= 0)
+      {
+        int result = pipe2 (fd, flags);
+        if (!(result < 0 && errno == ENOSYS))
+          {
+            have_pipe2_really = 1;
+            return result;
+          }
+        have_pipe2_really = -1;
+      }
+  }
+#endif
+
+  /* Check the supported flags.  */
+  if ((flags & ~(O_CLOEXEC | O_NONBLOCK | O_BINARY | O_TEXT)) != 0)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+/* Native Windows API.  */
+
+  if (_pipe (fd, 4096, flags & ~O_NONBLOCK) < 0)
+    {
+      fd[0] = tmp[0];
+      fd[1] = tmp[1];
+      return -1;
+    }
+
+  /* O_NONBLOCK handling.
+     On native Windows platforms, O_NONBLOCK is defined by gnulib.  Use the
+     functions defined by the gnulib module 'nonblocking'.  */
+# if GNULIB_defined_O_NONBLOCK
+  if (flags & O_NONBLOCK)
+    {
+      if (set_nonblocking_flag (fd[0], true) != 0
+          || set_nonblocking_flag (fd[1], true) != 0)
+        goto fail;
+    }
+# else
+  {
+    verify (O_NONBLOCK == 0);
+  }
+# endif
+
+  return 0;
+
+#else
+/* Unix API.  */
+
+  if (pipe (fd) < 0)
+    return -1;
+
+  /* POSIX <http://www.opengroup.org/onlinepubs/9699919799/functions/pipe.html>
+     says that initially, the O_NONBLOCK and FD_CLOEXEC flags are cleared on
+     both fd[0] and fd[1].  */
+
+  /* O_NONBLOCK handling.
+     On Unix platforms, O_NONBLOCK is defined by the system.  Use fcntl().  */
+  if (flags & O_NONBLOCK)
+    {
+      int fcntl_flags;
+
+      if ((fcntl_flags = fcntl (fd[1], F_GETFL, 0)) < 0
+          || fcntl (fd[1], F_SETFL, fcntl_flags | O_NONBLOCK) == -1
+          || (fcntl_flags = fcntl (fd[0], F_GETFL, 0)) < 0
+          || fcntl (fd[0], F_SETFL, fcntl_flags | O_NONBLOCK) == -1)
+        goto fail;
+    }
+
+  if (flags & O_CLOEXEC)
+    {
+      int fcntl_flags;
+
+      if ((fcntl_flags = fcntl (fd[1], F_GETFD, 0)) < 0
+          || fcntl (fd[1], F_SETFD, fcntl_flags | FD_CLOEXEC) == -1
+          || (fcntl_flags = fcntl (fd[0], F_GETFD, 0)) < 0
+          || fcntl (fd[0], F_SETFD, fcntl_flags | FD_CLOEXEC) == -1)
+        goto fail;
+    }
+
+# if O_BINARY
+  if (flags & O_BINARY)
+    {
+      setmode (fd[1], O_BINARY);
+      setmode (fd[0], O_BINARY);
+    }
+  else if (flags & O_TEXT)
+    {
+      setmode (fd[1], O_TEXT);
+      setmode (fd[0], O_TEXT);
+    }
+# endif
+
+  return 0;
+
+#endif
+
+#if GNULIB_defined_O_NONBLOCK || \
+  !((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__)
+ fail:
+  {
+    int saved_errno = errno;
+    close (fd[0]);
+    close (fd[1]);
+    fd[0] = tmp[0];
+    fd[1] = tmp[1];
+    errno = saved_errno;
+    return -1;
+  }
+#endif
+}

=== added file 'm4/fcntl.m4'
--- a/m4/fcntl.m4       1970-01-01 00:00:00 +0000
+++ b/m4/fcntl.m4       2013-07-07 18:00:14 +0000
@@ -0,0 +1,95 @@
+# fcntl.m4 serial 5
+dnl Copyright (C) 2009-2013 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+# For now, this module ensures that fcntl()
+# - supports F_DUPFD correctly
+# - supports or emulates F_DUPFD_CLOEXEC
+# - supports F_GETFD
+# Still to be ported to mingw:
+# - F_SETFD
+# - F_GETFL, F_SETFL
+# - F_GETOWN, F_SETOWN
+# - F_GETLK, F_SETLK, F_SETLKW
+AC_DEFUN([gl_FUNC_FCNTL],
+[
+  dnl Persuade glibc to expose F_DUPFD_CLOEXEC.
+  AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+  AC_REQUIRE([gl_FCNTL_H_DEFAULTS])
+  AC_REQUIRE([AC_CANONICAL_HOST])
+  AC_CHECK_FUNCS_ONCE([fcntl])
+  if test $ac_cv_func_fcntl = no; then
+    gl_REPLACE_FCNTL
+  else
+    dnl cygwin 1.5.x F_DUPFD has wrong errno, and allows negative target
+    dnl haiku alpha 2 F_DUPFD has wrong errno
+    AC_CACHE_CHECK([whether fcntl handles F_DUPFD correctly],
+      [gl_cv_func_fcntl_f_dupfd_works],
+      [AC_RUN_IFELSE([AC_LANG_PROGRAM([[
+#include <fcntl.h>
+#include <errno.h>
+]], [[int result = 0;
+      if (fcntl (0, F_DUPFD, -1) != -1) result |= 1;
+      if (errno != EINVAL) result |= 2;
+      return result;
+         ]])],
+         [gl_cv_func_fcntl_f_dupfd_works=yes],
+         [gl_cv_func_fcntl_f_dupfd_works=no],
+         [# Guess that it works on glibc systems
+          case $host_os in #((
+            *-gnu*) gl_cv_func_fcntl_f_dupfd_works="guessing yes";;
+            *)      gl_cv_func_fcntl_f_dupfd_works="guessing no";;
+          esac])])
+    case $gl_cv_func_fcntl_f_dupfd_works in
+      *yes) ;;
+      *) gl_REPLACE_FCNTL
+        AC_DEFINE([FCNTL_DUPFD_BUGGY], [1], [Define this to 1 if F_DUPFD
+          behavior does not match POSIX]) ;;
+    esac
+
+    dnl Many systems lack F_DUPFD_CLOEXEC
+    AC_CACHE_CHECK([whether fcntl understands F_DUPFD_CLOEXEC],
+      [gl_cv_func_fcntl_f_dupfd_cloexec],
+      [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <fcntl.h>
+#ifndef F_DUPFD_CLOEXEC
+choke me
+#endif
+         ]])],
+         [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#ifdef __linux__
+/* The Linux kernel only added F_DUPFD_CLOEXEC in 2.6.24, so we always replace
+   it to support the semantics on older kernels that failed with EINVAL.  */
+choke me
+#endif
+           ]])],
+           [gl_cv_func_fcntl_f_dupfd_cloexec=yes],
+           [gl_cv_func_fcntl_f_dupfd_cloexec="needs runtime check"])],
+         [gl_cv_func_fcntl_f_dupfd_cloexec=no])])
+    if test "$gl_cv_func_fcntl_f_dupfd_cloexec" != yes; then
+      gl_REPLACE_FCNTL
+      dnl No witness macro needed for this bug.
+    fi
+  fi
+  dnl Replace fcntl() for supporting the gnulib-defined fchdir() function,
+  dnl to keep fchdir's bookkeeping up-to-date.
+  m4_ifdef([gl_FUNC_FCHDIR], [
+    gl_TEST_FCHDIR
+    if test $HAVE_FCHDIR = 0; then
+      gl_REPLACE_FCNTL
+    fi
+  ])
+])
+
+AC_DEFUN([gl_REPLACE_FCNTL],
+[
+  AC_REQUIRE([gl_FCNTL_H_DEFAULTS])
+  AC_CHECK_FUNCS_ONCE([fcntl])
+  if test $ac_cv_func_fcntl = no; then
+    HAVE_FCNTL=0
+  else
+    REPLACE_FCNTL=1
+  fi
+])

=== added file 'm4/getdtablesize.m4'
--- a/m4/getdtablesize.m4       1970-01-01 00:00:00 +0000
+++ b/m4/getdtablesize.m4       2013-07-07 18:00:14 +0000
@@ -0,0 +1,17 @@
+# getdtablesize.m4 serial 4
+dnl Copyright (C) 2008-2013 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_GETDTABLESIZE],
+[
+  AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
+  AC_CHECK_FUNCS_ONCE([getdtablesize])
+  if test $ac_cv_func_getdtablesize != yes; then
+    HAVE_GETDTABLESIZE=0
+  fi
+])
+
+# Prerequisites of lib/getdtablesize.c.
+AC_DEFUN([gl_PREREQ_GETDTABLESIZE], [:])

=== modified file 'm4/gnulib-comp.m4'
--- a/m4/gnulib-comp.m4 2013-05-07 21:34:03 +0000
+++ b/m4/gnulib-comp.m4 2013-07-07 18:00:14 +0000
@@ -63,6 +63,7 @@
   AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
   # Code from module extern-inline:
   # Code from module faccessat:
+  # Code from module fcntl:
   # Code from module fcntl-h:
   # Code from module fdatasync:
   # Code from module fdopendir:
@@ -70,6 +71,7 @@
   # Code from module fpending:
   # Code from module fstatat:
   # Code from module fsync:
+  # Code from module getdtablesize:
   # Code from module getgroups:
   # Code from module getloadavg:
   # Code from module getopt-gnu:
@@ -92,6 +94,7 @@
   # Code from module nocrash:
   # Code from module openat-h:
   # Code from module pathmax:
+  # Code from module pipe2:
   # Code from module pselect:
   # Code from module pthread_sigmask:
   # Code from module putenv:
@@ -191,6 +194,11 @@
   fi
   gl_MODULE_INDICATOR([faccessat])
   gl_UNISTD_MODULE_INDICATOR([faccessat])
+  gl_FUNC_FCNTL
+  if test $HAVE_FCNTL = 0 || test $REPLACE_FCNTL = 1; then
+    AC_LIBOBJ([fcntl])
+  fi
+  gl_FCNTL_MODULE_INDICATOR([fcntl])
   gl_FCNTL_H
   gl_FUNC_FDATASYNC
   if test $HAVE_FDATASYNC = 0; then
@@ -273,6 +281,8 @@
   fi
   gl_TIME_MODULE_INDICATOR([mktime])
   gl_MULTIARCH
+  gl_FUNC_PIPE2
+  gl_UNISTD_MODULE_INDICATOR([pipe2])
   gl_FUNC_PSELECT
   if test $HAVE_PSELECT = 0 || test $REPLACE_PSELECT = 1; then
     AC_LIBOBJ([pselect])
@@ -364,6 +374,7 @@
   gl_gnulib_enabled_260941c0e5dc67ec9e87d1fb321c300b=false
   gl_gnulib_enabled_dosname=false
   gl_gnulib_enabled_euidaccess=false
+  gl_gnulib_enabled_getdtablesize=false
   gl_gnulib_enabled_getgroups=false
   gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36=false
   gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1=false
@@ -373,7 +384,6 @@
   gl_gnulib_enabled_stat=false
   gl_gnulib_enabled_strtoll=false
   gl_gnulib_enabled_strtoull=false
-  gl_gnulib_enabled_verify=false
   gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec=false
   func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b ()
   {
@@ -407,6 +417,18 @@
       fi
     fi
   }
+  func_gl_gnulib_m4code_getdtablesize ()
+  {
+    if ! $gl_gnulib_enabled_getdtablesize; then
+      gl_FUNC_GETDTABLESIZE
+      if test $HAVE_GETDTABLESIZE = 0; then
+        AC_LIBOBJ([getdtablesize])
+        gl_PREREQ_GETDTABLESIZE
+      fi
+      gl_UNISTD_MODULE_INDICATOR([getdtablesize])
+      gl_gnulib_enabled_getdtablesize=true
+    fi
+  }
   func_gl_gnulib_m4code_getgroups ()
   {
     if ! $gl_gnulib_enabled_getgroups; then
@@ -479,9 +501,6 @@
       if test $REPLACE_STAT = 1; then
         func_gl_gnulib_m4code_pathmax
       fi
-      if test $REPLACE_STAT = 1; then
-        func_gl_gnulib_m4code_verify
-      fi
     fi
   }
   func_gl_gnulib_m4code_strtoll ()
@@ -508,12 +527,6 @@
       gl_gnulib_enabled_strtoull=true
     fi
   }
-  func_gl_gnulib_m4code_verify ()
-  {
-    if ! $gl_gnulib_enabled_verify; then
-      gl_gnulib_enabled_verify=true
-    fi
-  }
   func_gl_gnulib_m4code_682e609604ccaac6be382e4ee3a4eaec ()
   {
     if ! $gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec; then
@@ -532,6 +545,9 @@
   if test $HAVE_FACCESSAT = 0; then
     func_gl_gnulib_m4code_03e0aaad4cb89ca757653bd367a6ccb7
   fi
+  if test $HAVE_FCNTL = 0 || test $REPLACE_FCNTL = 1; then
+    func_gl_gnulib_m4code_getdtablesize
+  fi
   if test $HAVE_FDOPENDIR = 0; then
     func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b
   fi
@@ -568,19 +584,14 @@
   if { test $HAVE_STRTOIMAX = 0 || test $REPLACE_STRTOIMAX = 1; } && test 
$ac_cv_type_long_long_int = yes; then
     func_gl_gnulib_m4code_strtoll
   fi
-  if test $HAVE_STRTOIMAX = 0 || test $REPLACE_STRTOIMAX = 1; then
-    func_gl_gnulib_m4code_verify
-  fi
   if test $ac_cv_func_strtoumax = no && test 
$ac_cv_type_unsigned_long_long_int = yes; then
     func_gl_gnulib_m4code_strtoull
   fi
-  if test $ac_cv_func_strtoumax = no; then
-    func_gl_gnulib_m4code_verify
-  fi
   m4_pattern_allow([^gl_GNULIB_ENABLED_])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_260941c0e5dc67ec9e87d1fb321c300b], 
[$gl_gnulib_enabled_260941c0e5dc67ec9e87d1fb321c300b])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_dosname], [$gl_gnulib_enabled_dosname])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_euidaccess], 
[$gl_gnulib_enabled_euidaccess])
+  AM_CONDITIONAL([gl_GNULIB_ENABLED_getdtablesize], 
[$gl_gnulib_enabled_getdtablesize])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_getgroups], [$gl_gnulib_enabled_getgroups])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_be453cec5eecf5731a274f2de7f2db36], 
[$gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_a9786850e999ae65a836a6041e8e5ed1], 
[$gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1])
@@ -590,7 +601,6 @@
   AM_CONDITIONAL([gl_GNULIB_ENABLED_stat], [$gl_gnulib_enabled_stat])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_strtoll], [$gl_gnulib_enabled_strtoll])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_strtoull], [$gl_gnulib_enabled_strtoull])
-  AM_CONDITIONAL([gl_GNULIB_ENABLED_verify], [$gl_gnulib_enabled_verify])
   AM_CONDITIONAL([gl_GNULIB_ENABLED_682e609604ccaac6be382e4ee3a4eaec], 
[$gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec])
   # End of code from modules
   m4_ifval(gl_LIBSOURCES_LIST, [
@@ -764,6 +774,7 @@
   lib/execinfo.c
   lib/execinfo.in.h
   lib/faccessat.c
+  lib/fcntl.c
   lib/fcntl.in.h
   lib/fdatasync.c
   lib/fdopendir.c
@@ -776,6 +787,7 @@
   lib/fsync.c
   lib/ftoastr.c
   lib/ftoastr.h
+  lib/getdtablesize.c
   lib/getgroups.c
   lib/getloadavg.c
   lib/getopt.c
@@ -799,6 +811,7 @@
   lib/openat-proc.c
   lib/openat.h
   lib/pathmax.h
+  lib/pipe2.c
   lib/pselect.c
   lib/pthread_sigmask.c
   lib/putenv.c
@@ -870,6 +883,7 @@
   m4/extern-inline.m4
   m4/faccessat.m4
   m4/fcntl-o.m4
+  m4/fcntl.m4
   m4/fcntl_h.m4
   m4/fdatasync.m4
   m4/fdopendir.m4
@@ -877,6 +891,7 @@
   m4/fpending.m4
   m4/fstatat.m4
   m4/fsync.m4
+  m4/getdtablesize.m4
   m4/getgroups.m4
   m4/getloadavg.m4
   m4/getopt.m4
@@ -897,6 +912,7 @@
   m4/nocrash.m4
   m4/off_t.m4
   m4/pathmax.m4
+  m4/pipe2.m4
   m4/pselect.m4
   m4/pthread_sigmask.m4
   m4/putenv.m4

=== added file 'm4/pipe2.m4'
--- a/m4/pipe2.m4       1970-01-01 00:00:00 +0000
+++ b/m4/pipe2.m4       2013-07-07 18:00:14 +0000
@@ -0,0 +1,18 @@
+# pipe2.m4 serial 2
+dnl Copyright (C) 2009-2013 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_PIPE2],
+[
+  AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
+
+  dnl Persuade glibc <unistd.h> to declare pipe2().
+  AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
+
+  AC_CHECK_FUNCS_ONCE([pipe2])
+  if test $ac_cv_func_pipe2 != yes; then
+    HAVE_PIPE2=0
+  fi
+])

=== modified file 'nt/ChangeLog'
--- a/nt/ChangeLog      2013-06-25 15:08:47 +0000
+++ b/nt/ChangeLog      2013-07-07 18:00:14 +0000
@@ -1,3 +1,12 @@
+2013-07-07  Paul Eggert  <address@hidden>
+
+       Make file descriptors close-on-exec when possible (Bug#14803).
+       * gnulib.mk: Remove empty gl_GNULIB_ENABLED_verify section;
+       otherwise, gnulib-tool complains given close-on-exec changes.
+       * inc/ms-w32.h (pipe): Remove.
+       * mingw-cfg.site (ac_cv_func_fcntl, gl_cv_func_fcntl_f_dupfd_cloexec)
+       (gl_cv_func_fcntl_f_dupfd_works, ac_cv_func_pipe2): New vars.
+
 2013-06-25  Juanma Barranquero  <address@hidden>
 
        * configure.bat: Add warning to the help text about using the

=== modified file 'nt/gnulib.mk'
--- a/nt/gnulib.mk      2013-05-16 05:51:39 +0000
+++ b/nt/gnulib.mk      2013-07-07 18:00:14 +0000
@@ -876,9 +876,6 @@
 
 ## begin gnulib module verify
 
-if gl_GNULIB_ENABLED_verify
-
-endif
 EXTRA_DIST += verify.h
 
 ## end   gnulib module verify

=== modified file 'nt/inc/ms-w32.h'
--- a/nt/inc/ms-w32.h   2013-05-15 17:06:26 +0000
+++ b/nt/inc/ms-w32.h   2013-07-07 18:00:14 +0000
@@ -211,7 +211,6 @@
 #define mktemp  sys_mktemp
 #undef open
 #define open    sys_open
-#define pipe    sys_pipe
 #undef read
 #define read    sys_read
 #define rename  sys_rename

=== modified file 'nt/mingw-cfg.site'
--- a/nt/mingw-cfg.site 2013-05-18 07:17:03 +0000
+++ b/nt/mingw-cfg.site 2013-07-07 18:00:14 +0000
@@ -67,6 +67,10 @@
 gl_cv_func_symlink_works=yes
 ac_cv_func_readlinkat=yes
 ac_cv_func_faccessat=yes
+# Implemented in w32.c
+ac_cv_func_fcntl=yes
+gl_cv_func_fcntl_f_dupfd_cloexec=yes
+gl_cv_func_fcntl_f_dupfd_works=yes
 # We don't need fdopendir
 ac_cv_func_fdopendir="not-needed"
 gl_cv_func_fdopendir_works="no-but-not-needed-so-yes"
@@ -95,6 +99,7 @@
 # Avoid compiling gnulib mktime
 gl_cv_func_working_mktime=yes
 # Implemented in w32.c
+ac_cv_func_pipe2=yes
 ac_cv_have_decl_unsetenv=yes
 ac_cv_func_unsetenv=yes
 gt_cv_func_unsetenv_ret='int'

=== modified file 'src/ChangeLog'
--- a/src/ChangeLog     2013-07-07 08:41:09 +0000
+++ b/src/ChangeLog     2013-07-07 18:00:14 +0000
@@ -1,3 +1,41 @@
+2013-07-07  Paul Eggert  <address@hidden>
+
+       Make file descriptors close-on-exec when possible (Bug#14803).
+       This simplifies Emacs a bit, since it no longer needs to worry
+       about closing file descriptors by hand in some cases.
+       It also fixes some unlikely races.  Not all such races, as
+       libraries often open files internally without setting
+       close-on-exec, but it's an improvement.
+       * alloc.c (valid_pointer_p) [!WINDOWSNT]:
+       * callproc.c (Fcall_process) [!MSDOS]:
+       * emacs.c (main) [!DOS_NT]:
+       * nsterm.m (ns_term_init):
+       * process.c (create_process):
+       Use 'pipe2' with O_CLOEXEC instead of 'pipe'.
+       * emacs.c (Fcall_process_region) [HAVE_MKOSTEMP]:
+       * filelock.c (create_lock_file) [HAVE_MKOSTEMP]:
+       Prefer mkostemp with O_CLOEXEC to mkstemp.
+       * callproc.c (relocate_fd) [!WINDOWSNT]:
+       * emacs.c (main): Use F_DUPFD_CLOEXEC, not plain F_DUPFD.
+       No need to use fcntl (..., F_SETFD, FD_CLOEXEC), since we're
+       now using pipe2.
+       * filelock.c (create_lock_file) [! HAVE_MKOSTEMP]:
+       Make the resulting file descriptor close-on-exec.
+       * lisp.h, lread.c, process.c (close_load_descs, close_process_descs):
+       * lread.c (load_descriptor_list, load_descriptor_unwind):
+       Remove; no longer needed.  All uses removed.
+       * process.c (SOCK_CLOEXEC): Define to 0 if not supplied by system.
+       (close_on_exec, accept4, process_socket) [!SOCK_CLOEXEC]:
+       New functions.
+       (socket) [!SOCK_CLOEXEC]: Supply a substitute.
+       (Fmake_network_process, Fnetwork_interface_list):
+       (Fnetwork_interface_info, server_accept_connection):
+       Make newly-created socket close-on-exec.
+       * sysdep.c (emacs_open, emacs_fopen):
+       Make new-created descriptor close-on-exec.
+       * w32.c (fcntl): Support F_DUPFD_CLOEXEC well enough for Emacs.
+       * w32.c, w32.h (pipe2): Rename from 'pipe', with new flags arg.
+
 2013-07-07  Jan Djärv  <address@hidden>
 
        * nsterm.m (sendEvent:): Propagate keyboard events to modal windows

=== modified file 'src/alloc.c'
--- a/src/alloc.c       2013-07-05 16:58:01 +0000
+++ b/src/alloc.c       2013-07-07 18:00:14 +0000
@@ -4741,7 +4741,7 @@
      Unfortunately, we cannot use NULL_DEVICE here, as emacs_write may
      not validate p in that case.  */
 
-  if (pipe (fd) == 0)
+  if (pipe2 (fd, O_CLOEXEC) == 0)
     {
       bool valid = emacs_write (fd[1], (char *) p, 16) == 16;
       emacs_close (fd[1]);

=== modified file 'src/callproc.c'
--- a/src/callproc.c    2013-07-07 07:28:29 +0000
+++ b/src/callproc.c    2013-07-07 18:00:14 +0000
@@ -519,7 +519,7 @@
     {
 #ifndef MSDOS
       int fd[2];
-      if (pipe (fd) == -1)
+      if (pipe2 (fd, O_CLOEXEC) != 0)
        {
          int pipe_errno = errno;
          emacs_close (filefd);
@@ -1036,12 +1036,16 @@
     memcpy (tempfile, SDATA (encoded_tem), SBYTES (encoded_tem) + 1);
     coding_systems = Qt;
 
-#ifdef HAVE_MKSTEMP
+#if defined HAVE_MKOSTEMP || defined HAVE_MKSTEMP
     {
       int fd;
 
       block_input ();
+# ifdef HAVE_MKOSTEMP
+      fd = mkostemp (tempfile, O_CLOEXEC);
+# else
       fd = mkstemp (tempfile);
+# endif
       unblock_input ();
       if (fd == -1)
        report_file_error ("Failed to open temporary file",
@@ -1184,15 +1188,6 @@
 
   pid_t pid = getpid ();
 
-  /* Close Emacs's descriptors that this process should not have.  */
-  close_process_descs ();
-
-  /* DOS_NT isn't in a vfork, so if we are in the middle of load-file,
-     we will lose if we call close_load_descs here.  */
-#ifndef DOS_NT
-  close_load_descs ();
-#endif
-
   /* Note that use of alloca is always safe here.  It's obvious for systems
      that do not have true vfork or that have true (stack) alloca.
      If using vfork and C_ALLOCA (when Emacs used to include
@@ -1354,9 +1349,11 @@
   emacs_close (1);
   emacs_close (2);
 
+  /* Redirect file descriptors and clear FD_CLOEXEC on the redirected ones.  */
   dup2 (in, 0);
   dup2 (out, 1);
   dup2 (err, 2);
+
   emacs_close (in);
   if (out != in)
     emacs_close (out);
@@ -1394,7 +1391,7 @@
     return fd;
   else
     {
-      int new = fcntl (fd, F_DUPFD, minfd);
+      int new = fcntl (fd, F_DUPFD_CLOEXEC, minfd);
       if (new == -1)
        {
          const char *message_1 = "Error while setting up child: ";

=== modified file 'src/emacs.c'
--- a/src/emacs.c       2013-07-06 02:40:50 +0000
+++ b/src/emacs.c       2013-07-07 18:00:14 +0000
@@ -889,7 +889,7 @@
          emacs_close (0);
          emacs_close (1);
          result = emacs_open (term, O_RDWR, 0);
-         if (result < 0 || dup (0) < 0)
+         if (result < 0 || fcntl (0, F_DUPFD_CLOEXEC, 1) < 0)
            {
              char *errstring = strerror (errno);
              fprintf (stderr, "%s: %s: %s\n", argv[0], term, errstring);
@@ -969,7 +969,7 @@
         use a pipe for synchronization.  The parent waits for the child
         to close its end of the pipe (using `daemon-initialized')
         before exiting.  */
-      if (pipe (daemon_pipe) == -1)
+      if (pipe2 (daemon_pipe, O_CLOEXEC) != 0)
        {
          fprintf (stderr, "Cannot pipe!\n");
          exit (1);
@@ -1065,9 +1065,6 @@
                daemon_name = xstrdup (dname_arg);
       /* Close unused reading end of the pipe.  */
       close (daemon_pipe[0]);
-      /* Make sure that the used end of the pipe is closed on exec, so
-        that it is not accessible to programs started from .emacs.  */
-      fcntl (daemon_pipe[1], F_SETFD, FD_CLOEXEC);
 
       setsid ();
 #else /* DOS_NT */

=== modified file 'src/filelock.c'
--- a/src/filelock.c    2013-05-05 00:51:49 +0000
+++ b/src/filelock.c    2013-07-07 18:00:14 +0000
@@ -416,8 +416,13 @@
       memcpy (nonce, lfname, lfdirlen);
       strcpy (nonce + lfdirlen, nonce_base);
 
-#if HAVE_MKSTEMP
-      /* Prefer mkstemp if available, as it avoids a race between
+#if HAVE_MKOSTEMP
+      /* Prefer mkostemp to mkstemp, as it avoids a window where FD is
+        temporarily open without close-on-exec.  */
+      fd = mkostemp (nonce, O_BINARY | O_CLOEXEC);
+      need_fchmod = 1;
+#elif HAVE_MKSTEMP
+      /* Prefer mkstemp to mktemp, as it avoids a race between
         mktemp and emacs_open.  */
       fd = mkstemp (nonce);
       need_fchmod = 1;
@@ -432,7 +437,11 @@
        err = errno;
       else
        {
-         ptrdiff_t lock_info_len = strlen (lock_info_str);
+         ptrdiff_t lock_info_len;
+#if ! HAVE_MKOSTEMP
+         fcntl (fd, F_SETFD, FD_CLOEXEC);
+#endif
+         lock_info_len = strlen (lock_info_str);
          err = 0;
          if (emacs_write (fd, lock_info_str, lock_info_len) != lock_info_len
              || (need_fchmod && fchmod (fd, world_readable) != 0))

=== modified file 'src/lisp.h'
--- a/src/lisp.h        2013-07-04 09:29:28 +0000
+++ b/src/lisp.h        2013-07-07 18:00:14 +0000
@@ -3668,7 +3668,6 @@
 extern void map_obarray (Lisp_Object, void (*) (Lisp_Object, Lisp_Object),
                          Lisp_Object);
 extern void dir_warning (const char *, Lisp_Object);
-extern void close_load_descs (void);
 extern void init_obarray (void);
 extern void init_lread (void);
 extern void syms_of_lread (void);
@@ -3995,7 +3994,6 @@
 extern void add_gpm_wait_descriptor (int);
 extern void delete_gpm_wait_descriptor (int);
 #endif
-extern void close_process_descs (void);
 extern void init_process_emacs (void);
 extern void syms_of_process (void);
 extern void setup_process_coding_systems (Lisp_Object);

=== modified file 'src/lread.c'
--- a/src/lread.c       2013-07-07 07:28:29 +0000
+++ b/src/lread.c       2013-07-07 18:00:14 +0000
@@ -95,9 +95,6 @@
    It must be set to nil before all top-level calls to read0.  */
 static Lisp_Object read_objects;
 
-/* List of descriptors now open for Fload.  */
-static Lisp_Object load_descriptor_list;
-
 /* File for get_file_char to read from.  Use by load.  */
 static FILE *instream;
 
@@ -149,7 +146,6 @@
                           Lisp_Object, Lisp_Object,
                           Lisp_Object, Lisp_Object);
 static Lisp_Object load_unwind (Lisp_Object);
-static Lisp_Object load_descriptor_unwind (Lisp_Object);
 
 /* Functions that read one byte from the current source READCHARFUN
    or unreads one byte.  If the integer argument C is -1, it returns
@@ -1328,11 +1324,8 @@
     }
 
   record_unwind_protect (load_unwind, make_save_pointer (stream));
-  record_unwind_protect (load_descriptor_unwind, load_descriptor_list);
   specbind (Qload_file_name, found);
   specbind (Qinhibit_file_name_operation, Qnil);
-  load_descriptor_list
-    = Fcons (make_number (fileno (stream)), load_descriptor_list);
   specbind (Qload_in_progress, Qt);
 
   instream = stream;
@@ -1395,26 +1388,6 @@
     }
   return Qnil;
 }
-
-static Lisp_Object
-load_descriptor_unwind (Lisp_Object oldlist)
-{
-  load_descriptor_list = oldlist;
-  return Qnil;
-}
-
-/* Close all descriptors in use for Floads.
-   This is used when starting a subprocess.  */
-
-void
-close_load_descs (void)
-{
-#ifndef WINDOWSNT
-  Lisp_Object tail;
-  for (tail = load_descriptor_list; CONSP (tail); tail = XCDR (tail))
-    emacs_close (XFASTINT (XCAR (tail)));
-#endif
-}
 
 static bool
 complete_filename_p (Lisp_Object pathname)
@@ -4376,9 +4349,6 @@
 
   load_in_progress = 0;
   Vload_file_name = Qnil;
-
-  load_descriptor_list = Qnil;
-
   Vstandard_input = Qt;
   Vloads_in_progress = Qnil;
 }
@@ -4651,9 +4621,6 @@
 
   /* Vsource_directory was initialized in init_lread.  */
 
-  load_descriptor_list = Qnil;
-  staticpro (&load_descriptor_list);
-
   DEFSYM (Qcurrent_load_list, "current-load-list");
   DEFSYM (Qstandard_input, "standard-input");
   DEFSYM (Qread_char, "read-char");

=== modified file 'src/nsterm.m'
--- a/src/nsterm.m      2013-07-07 08:41:09 +0000
+++ b/src/nsterm.m      2013-07-07 18:00:14 +0000
@@ -4142,7 +4142,7 @@
 
   if (selfds[0] == -1)
     {
-      if (pipe (selfds) == -1)
+      if (pipe2 (selfds, O_CLOEXEC) != 0)
         {
           fprintf (stderr, "Failed to create pipe: %s\n",
                    emacs_strerror (errno));

=== modified file 'src/process.c'
--- a/src/process.c     2013-07-05 16:58:01 +0000
+++ b/src/process.c     2013-07-07 18:00:14 +0000
@@ -135,6 +135,34 @@
                       EMACS_TIME *, void *);
 #endif
 
+#ifndef SOCK_CLOEXEC
+# define SOCK_CLOEXEC 0
+
+/* Emulate GNU/Linux accept4 and socket well enough for this module.  */
+
+static int
+close_on_exec (int fd)
+{
+  if (0 <= fd)
+    fcntl (fd, F_SETFD, FD_CLOEXEC);
+  return fd;
+}
+
+static int
+accept4 (int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags)
+{
+  return close_on_exec (accept (sockfd, addr, addrlen));
+}
+
+static int
+process_socket (int domain, int type, int protocol)
+{
+  return close_on_exec (socket (domain, type, protocol));
+}
+# undef socket
+# define socket(domain, type, protocol) process_socket (domain, type, protocol)
+#endif
+
 /* Work around GCC 4.7.0 bug with strict overflow checking; see
    <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52904>.
    These lines can be removed once the GCC bug is fixed.  */
@@ -1619,14 +1647,11 @@
   else
 #endif /* HAVE_PTYS */
     {
-      int tem;
-      tem = pipe (sv);
-      if (tem < 0)
+      if (pipe2 (sv, O_CLOEXEC) != 0)
        report_file_error ("Creating pipe", Qnil);
       inchannel = sv[0];
       forkout = sv[1];
-      tem = pipe (sv);
-      if (tem < 0)
+      if (pipe2 (sv, O_CLOEXEC) != 0)
        {
          emacs_close (inchannel);
          emacs_close (forkout);
@@ -1637,29 +1662,14 @@
     }
 
 #ifndef WINDOWSNT
-    {
-      int tem;
-
-      tem = pipe (wait_child_setup);
-      if (tem < 0)
-       report_file_error ("Creating pipe", Qnil);
-      tem = fcntl (wait_child_setup[1], F_GETFD, 0);
-      if (tem >= 0)
-       tem = fcntl (wait_child_setup[1], F_SETFD, tem | FD_CLOEXEC);
-      if (tem < 0)
-       {
-         emacs_close (wait_child_setup[0]);
-         emacs_close (wait_child_setup[1]);
-         report_file_error ("Setting file descriptor flags", Qnil);
-       }
-    }
+  if (pipe2 (wait_child_setup, O_CLOEXEC) != 0)
+    report_file_error ("Creating pipe", Qnil);
 #endif
 
   fcntl (inchannel, F_SETFL, O_NONBLOCK);
   fcntl (outchannel, F_SETFL, O_NONBLOCK);
 
-  /* Record this as an active process, with its channels.
-     As a result, child_setup will close Emacs's side of the pipes.  */
+  /* Record this as an active process, with its channels.  */
   chan_process[inchannel] = process;
   XPROCESS (process)->infd = inchannel;
   XPROCESS (process)->outfd = outchannel;
@@ -3135,7 +3145,8 @@
     retry_connect:
 #endif
 
-      s = socket (lres->ai_family, lres->ai_socktype, lres->ai_protocol);
+      s = socket (lres->ai_family, lres->ai_socktype | SOCK_CLOEXEC,
+                 lres->ai_protocol);
       if (s < 0)
        {
          xerrno = errno;
@@ -3532,7 +3543,7 @@
   int s;
   Lisp_Object res;
 
-  s = socket (AF_INET, SOCK_STREAM, 0);
+  s = socket (AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
   if (s < 0)
     return Qnil;
 
@@ -3688,7 +3699,7 @@
     error ("interface name too long");
   strcpy (rq.ifr_name, SSDATA (ifname));
 
-  s = socket (AF_INET, SOCK_STREAM, 0);
+  s = socket (AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
   if (s < 0)
     return Qnil;
 
@@ -3984,7 +3995,7 @@
   } saddr;
   socklen_t len = sizeof saddr;
 
-  s = accept (channel, &saddr.sa, &len);
+  s = accept4 (channel, &saddr.sa, &len, SOCK_CLOEXEC);
 
   if (s < 0)
     {
@@ -6858,32 +6869,6 @@
 #endif
 }
 
-/* Close all descriptors currently in use for communication
-   with subprocess.  This is used in a newly-forked subprocess
-   to get rid of irrelevant descriptors.  */
-
-void
-close_process_descs (void)
-{
-#ifndef DOS_NT
-  int i;
-  for (i = 0; i < MAXDESC; i++)
-    {
-      Lisp_Object process;
-      process = chan_process[i];
-      if (!NILP (process))
-       {
-         int in  = XPROCESS (process)->infd;
-         int out = XPROCESS (process)->outfd;
-         if (in >= 0)
-           emacs_close (in);
-         if (out >= 0 && in != out)
-           emacs_close (out);
-       }
-    }
-#endif
-}
-
 DEFUN ("get-buffer-process", Fget_buffer_process, Sget_buffer_process, 1, 1, 0,
        doc: /* Return the (or a) process associated with BUFFER.
 BUFFER may be a buffer or the name of one.  */)

=== modified file 'src/sysdep.c'
--- a/src/sysdep.c      2013-07-06 02:40:50 +0000
+++ b/src/sysdep.c      2013-07-07 18:00:14 +0000
@@ -543,8 +543,6 @@
 #endif
        }
 
-      close_process_descs ();  /* Close Emacs's pipes/ptys */
-
 #ifdef MSDOS    /* Demacs 1.1.2 91/10/20 Manabu Higashida */
       {
        char *epwd = getenv ("PWD");
@@ -2152,6 +2150,8 @@
 #endif
 
 /* Open FILE for Emacs use, using open flags OFLAG and mode MODE.
+   Arrange for subprograms to not inherit the file descriptor.
+   Prefer a method that is multithread-safe, if available.
    Do not fail merely because the open was interrupted by a signal.
    Allow the user to quit.  */
 
@@ -2159,8 +2159,11 @@
 emacs_open (const char *file, int oflags, int mode)
 {
   int fd;
+  oflags |= O_CLOEXEC;
   while ((fd = open (file, oflags, mode)) < 0 && errno == EINTR)
     QUIT;
+  if (! O_CLOEXEC && 0 <= fd)
+    fcntl (fd, F_SETFD, FD_CLOEXEC);
   return fd;
 }
 
@@ -2170,10 +2173,29 @@
 FILE *
 emacs_fopen (char const *file, char const *mode)
 {
-  FILE *fp;
-  while (! (fp = fopen (file, mode)) && errno == EINTR)
-    QUIT;
-  return fp;
+  int fd, omode, oflags;
+  int bflag = 0;
+  char const *m = mode;
+
+  switch (*m++)
+    {
+    case 'r': omode = O_RDONLY; oflags = 0; break;
+    case 'w': omode = O_WRONLY; oflags = O_CREAT | O_TRUNC; break;
+    case 'a': omode = O_WRONLY; oflags = O_CREAT | O_APPEND; break;
+    default: emacs_abort ();
+    }
+
+  while (*m)
+    switch (*m++)
+      {
+      case '+': omode = O_RDWR; break;
+      case 'b': bflag = O_BINARY; break;
+      case 't': bflag = O_TEXT; break;
+      default: /* Ignore.  */ break;
+      }
+
+  fd = emacs_open (file, omode | oflags | bflag, 0666);
+  return fd < 0 ? 0 : fdopen (fd, mode);
 }
 
 int

=== modified file 'src/w32.c'
--- a/src/w32.c 2013-06-21 20:11:44 +0000
+++ b/src/w32.c 2013-07-07 18:00:14 +0000
@@ -6719,10 +6719,16 @@
 }
 
 /* Windows does not have an fcntl function.  Provide an implementation
-   solely for making sockets non-blocking.  */
+   good enough for Emacs.  */
 int
 fcntl (int s, int cmd, int options)
 {
+  /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
+     invoked in a context where fd1 is closed and all descriptors less
+     than fd1 are open, so sys_dup is an adequate implementation.  */
+  if (cmd == F_DUPFD_CLOEXEC)
+    return sys_dup (s);
+
   if (winsock_lib == NULL)
     {
       errno = ENETDOWN;
@@ -6864,13 +6870,14 @@
   return rc;
 }
 
-/* Unix pipe() has only one arg */
 int
-sys_pipe (int * phandles)
+pipe2 (int * phandles, int pipe2_flags)
 {
   int rc;
   unsigned flags;
 
+  eassert (pipe2_flags == O_CLOEXEC);
+
   /* make pipe handles non-inheritable; when we spawn a child, we
      replace the relevant handle with an inheritable one.  Also put
      pipes into binary mode; we will do text mode translation ourselves

=== modified file 'src/w32.h'
--- a/src/w32.h 2013-03-05 22:35:41 +0000
+++ b/src/w32.h 2013-07-07 18:00:14 +0000
@@ -188,7 +188,7 @@
 
 extern int fchmod (int, mode_t);
 extern int sys_rename_replace (char const *, char const *, BOOL);
-extern int sys_pipe (int *);
+extern int pipe2 (int *, int);
 
 extern void set_process_dir (char *);
 extern int sys_spawnve (int, char *, char **, char **);


reply via email to

[Prev in Thread] Current Thread [Next in Thread]