=== modified file 'ChangeLog' --- ChangeLog 2013-07-03 03:20:04 +0000 +++ ChangeLog 2013-07-07 06:02:44 +0000 @@ -1,3 +1,12 @@ +2013-07-07 Paul Eggert + + 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 (tiny change) * configure.ac (emacs_broken_SIGIO): Set on gnu-kfreebsd to avoid hang. === modified file 'admin/ChangeLog' --- admin/ChangeLog 2013-07-06 18:28:54 +0000 +++ admin/ChangeLog 2013-07-07 05:52:09 +0000 @@ -1,3 +1,9 @@ +2013-07-07 Paul Eggert + + 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 * admin.el (manual-misc-manuals): New function. === modified file 'admin/merge-gnulib' --- admin/merge-gnulib 2013-05-07 21:34:03 +0000 +++ admin/merge-gnulib 2013-07-05 22:03:36 +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' --- configure.ac 2013-07-03 03:20:04 +0000 +++ configure.ac 2013-07-07 05:53:12 +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' --- lib/fcntl.c 1970-01-01 00:00:00 +0000 +++ lib/fcntl.c 2013-07-05 22:44:07 +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 . */ + +/* Written by Eric Blake . */ + +#include + +/* Specification. */ +#include + +#include +#include +#include +#include + +#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 + +/* 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' --- lib/getdtablesize.c 1970-01-01 00:00:00 +0000 +++ lib/getdtablesize.c 2013-07-05 22:44:07 +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 , 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 . */ + +#include + +/* Specification. */ +#include + +#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ + +#include + +#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' --- lib/gnulib.mk 2013-05-07 21:34:03 +0000 +++ lib/gnulib.mk 2013-07-05 22:03:36 +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' --- lib/pipe2.c 1970-01-01 00:00:00 +0000 +++ lib/pipe2.c 2013-07-05 22:44:07 +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 . */ + +#include + +/* Specification. */ +#include + +#include +#include + +#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 + +#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 + 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' --- m4/fcntl.m4 1970-01-01 00:00:00 +0000 +++ m4/fcntl.m4 2013-07-05 22:44:08 +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 +#include +]], [[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 +#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' --- m4/getdtablesize.m4 1970-01-01 00:00:00 +0000 +++ m4/getdtablesize.m4 2013-07-05 22:44:08 +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' --- m4/gnulib-comp.m4 2013-05-07 21:34:03 +0000 +++ m4/gnulib-comp.m4 2013-07-05 22:03:36 +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' --- m4/pipe2.m4 1970-01-01 00:00:00 +0000 +++ m4/pipe2.m4 2013-07-05 22:44:08 +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 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' --- nt/ChangeLog 2013-06-25 15:08:47 +0000 +++ nt/ChangeLog 2013-07-07 06:24:50 +0000 @@ -1,3 +1,12 @@ +2013-07-07 Paul Eggert + + 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 * configure.bat: Add warning to the help text about using the === modified file 'nt/gnulib.mk' --- nt/gnulib.mk 2013-05-16 05:51:39 +0000 +++ nt/gnulib.mk 2013-07-05 22:03:36 +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' --- nt/inc/ms-w32.h 2013-05-15 17:06:26 +0000 +++ nt/inc/ms-w32.h 2013-07-07 06:01:09 +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' --- nt/mingw-cfg.site 2013-05-18 07:17:03 +0000 +++ nt/mingw-cfg.site 2013-07-07 06:01:42 +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' --- src/ChangeLog 2013-07-06 17:58:41 +0000 +++ src/ChangeLog 2013-07-07 06:00:57 +0000 @@ -1,3 +1,41 @@ +2013-07-07 Paul Eggert + + 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-06 Jan Djärv * nsterm.m (sendEvent:): Handle NSAPP_DATA2_RUNFILEDIALOG. === modified file 'src/alloc.c' --- src/alloc.c 2013-07-05 16:58:01 +0000 +++ src/alloc.c 2013-07-06 00:10:22 +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' --- src/callproc.c 2013-07-06 02:40:50 +0000 +++ src/callproc.c 2013-07-07 01:37:23 +0000 @@ -517,7 +517,7 @@ { #ifndef MSDOS int fd[2]; - if (pipe (fd) == -1) + if (pipe2 (fd, O_CLOEXEC) != 0) { int pipe_errno = errno; emacs_close (filefd); @@ -1034,12 +1034,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", @@ -1182,15 +1186,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 @@ -1352,9 +1347,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); @@ -1392,7 +1389,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' --- src/emacs.c 2013-07-06 02:40:50 +0000 +++ src/emacs.c 2013-07-07 01:37:23 +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' --- src/filelock.c 2013-05-05 00:51:49 +0000 +++ src/filelock.c 2013-07-06 02:14:57 +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' --- src/lisp.h 2013-07-04 09:29:28 +0000 +++ src/lisp.h 2013-07-05 22:03:45 +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' --- src/lread.c 2013-07-06 02:40:50 +0000 +++ src/lread.c 2013-07-05 22:34:56 +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) @@ -4349,9 +4322,6 @@ load_in_progress = 0; Vload_file_name = Qnil; - - load_descriptor_list = Qnil; - Vstandard_input = Qt; Vloads_in_progress = Qnil; } @@ -4624,9 +4594,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' --- src/nsterm.m 2013-07-06 17:58:41 +0000 +++ src/nsterm.m 2013-07-06 19:12:39 +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' --- src/process.c 2013-07-05 16:58:01 +0000 +++ src/process.c 2013-07-06 09:06:26 +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 . 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' --- src/sysdep.c 2013-07-06 02:40:50 +0000 +++ src/sysdep.c 2013-07-06 07:05:41 +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' --- src/w32.c 2013-06-21 20:11:44 +0000 +++ src/w32.c 2013-07-07 06:00:02 +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' --- src/w32.h 2013-03-05 22:35:41 +0000 +++ src/w32.h 2013-07-07 06:00:18 +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 **);