aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggert2013-07-07 11:00:14 -0700
committerPaul Eggert2013-07-07 11:00:14 -0700
commit067428c1717acd28f205c2cff93f0583eb347f4c (patch)
tree5937b119187f9900840e2c1174b408e86bb8d12b
parent9aff9b3864085addb02b699f9648e547a8c00e54 (diff)
downloademacs-067428c1717acd28f205c2cff93f0583eb347f4c.tar.gz
emacs-067428c1717acd28f205c2cff93f0583eb347f4c.zip
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. Fixes: debbugs:14803
-rw-r--r--ChangeLog9
-rw-r--r--admin/ChangeLog6
-rwxr-xr-xadmin/merge-gnulib8
-rw-r--r--configure.ac4
-rw-r--r--lib/fcntl.c311
-rw-r--r--lib/getdtablesize.c86
-rw-r--r--lib/gnulib.mk30
-rw-r--r--lib/pipe2.c171
-rw-r--r--m4/fcntl.m495
-rw-r--r--m4/getdtablesize.m417
-rw-r--r--m4/gnulib-comp.m450
-rw-r--r--m4/pipe2.m418
-rw-r--r--nt/ChangeLog9
-rw-r--r--nt/gnulib.mk3
-rw-r--r--nt/inc/ms-w32.h1
-rw-r--r--nt/mingw-cfg.site5
-rw-r--r--src/ChangeLog38
-rw-r--r--src/alloc.c2
-rw-r--r--src/callproc.c21
-rw-r--r--src/emacs.c7
-rw-r--r--src/filelock.c15
-rw-r--r--src/lisp.h2
-rw-r--r--src/lread.c33
-rw-r--r--src/nsterm.m2
-rw-r--r--src/process.c91
-rw-r--r--src/sysdep.c34
-rw-r--r--src/w32.c13
-rw-r--r--src/w32.h2
28 files changed, 933 insertions, 150 deletions
diff --git a/ChangeLog b/ChangeLog
index bd938539421..33e739c9173 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
12013-07-07 Paul Eggert <eggert@cs.ucla.edu>
2
3 Make file descriptors close-on-exec when possible (Bug#14803).
4 * configure.ac (mkostemp): New function to check for.
5 (PTY_OPEN): Pass O_CLOEXEC to posix_openpt.
6 * lib/fcntl.c, lib/getdtablesize.c, lib/pipe2.c, m4/fcntl.m4:
7 * m4/getdtablesize.m4, m4/pipe2.m4: New files, taken from gnulib.
8 * lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate.
9
12013-07-03 Christoph Egger <christoph@debian.org> (tiny change) 102013-07-03 Christoph Egger <christoph@debian.org> (tiny change)
2 11
3 * configure.ac (emacs_broken_SIGIO): Set on gnu-kfreebsd to avoid hang. 12 * configure.ac (emacs_broken_SIGIO): Set on gnu-kfreebsd to avoid hang.
diff --git a/admin/ChangeLog b/admin/ChangeLog
index 592a41968db..f7d7cbb55d2 100644
--- a/admin/ChangeLog
+++ b/admin/ChangeLog
@@ -1,3 +1,9 @@
12013-07-07 Paul Eggert <eggert@cs.ucla.edu>
2
3 Make file descriptors close-on-exec when possible (Bug#14803).
4 * merge-gnulib (GNULIB_MODULES): Add fcntl, pipe2.
5 (GNULIB_TOOL_FLAGS): Avoid binary-io, close. Do not avoid fcntl.
6
12013-07-06 Glenn Morris <rgm@gnu.org> 72013-07-06 Glenn Morris <rgm@gnu.org>
2 8
3 * admin.el (manual-misc-manuals): New function. 9 * admin.el (manual-misc-manuals): New function.
diff --git a/admin/merge-gnulib b/admin/merge-gnulib
index c8bfe0dacc3..f89fe7959fd 100755
--- a/admin/merge-gnulib
+++ b/admin/merge-gnulib
@@ -29,11 +29,11 @@ GNULIB_MODULES='
29 alloca-opt c-ctype c-strcase 29 alloca-opt c-ctype c-strcase
30 careadlinkat close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 30 careadlinkat close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512
31 dtoastr dtotimespec dup2 environ execinfo faccessat 31 dtoastr dtotimespec dup2 environ execinfo faccessat
32 fcntl-h fdatasync fdopendir filemode fstatat fsync 32 fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync
33 getloadavg getopt-gnu gettime gettimeofday 33 getloadavg getopt-gnu gettime gettimeofday
34 ignore-value intprops largefile lstat 34 ignore-value intprops largefile lstat
35 manywarnings memrchr mktime 35 manywarnings memrchr mktime
36 pselect pthread_sigmask putenv qacl readlink readlinkat 36 pipe2 pselect pthread_sigmask putenv qacl readlink readlinkat
37 sig2str socklen stat-time stdalign stdarg stdbool stdio 37 sig2str socklen stat-time stdalign stdarg stdbool stdio
38 strftime strtoimax strtoumax symlink sys_stat 38 strftime strtoimax strtoumax symlink sys_stat
39 sys_time time timer-time timespec-add timespec-sub unsetenv utimens 39 sys_time time timer-time timespec-add timespec-sub unsetenv utimens
@@ -41,8 +41,8 @@ GNULIB_MODULES='
41' 41'
42 42
43GNULIB_TOOL_FLAGS=' 43GNULIB_TOOL_FLAGS='
44 --avoid=dup 44 --avoid=binary-io --avoid=close --avoid=dup
45 --avoid=fchdir --avoid=fcntl --avoid=fstat 45 --avoid=fchdir --avoid=fstat
46 --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow 46 --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow
47 --avoid=open --avoid=openat-die --avoid=opendir 47 --avoid=open --avoid=openat-die --avoid=opendir
48 --avoid=raise 48 --avoid=raise
diff --git a/configure.ac b/configure.ac
index baf8aab1406..bbaa02820ab 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3244,7 +3244,7 @@ select getpagesize setlocale \
3244getrlimit setrlimit shutdown getaddrinfo \ 3244getrlimit setrlimit shutdown getaddrinfo \
3245strsignal setitimer \ 3245strsignal setitimer \
3246sendto recvfrom getsockname getpeername getifaddrs freeifaddrs \ 3246sendto recvfrom getsockname getpeername getifaddrs freeifaddrs \
3247gai_strerror mkstemp getline getdelim sync \ 3247gai_strerror mkostemp mkstemp getline getdelim sync \
3248difftime posix_memalign \ 3248difftime posix_memalign \
3249getpwent endpwent getgrent endgrent \ 3249getpwent endpwent getgrent endgrent \
3250touchlock \ 3250touchlock \
@@ -3934,7 +3934,7 @@ case $opsys in
3934 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); }]) 3934 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); }])
3935 dnl if HAVE_POSIX_OPENPT 3935 dnl if HAVE_POSIX_OPENPT
3936 if test "x$ac_cv_func_posix_openpt" = xyes; then 3936 if test "x$ac_cv_func_posix_openpt" = xyes; then
3937 AC_DEFINE(PTY_OPEN, [fd = posix_openpt (O_RDWR | O_NOCTTY)]) 3937 AC_DEFINE(PTY_OPEN, [fd = posix_openpt (O_RDWR | O_CLOEXEC | O_NOCTTY)])
3938 AC_DEFINE(PTY_NAME_SPRINTF, []) 3938 AC_DEFINE(PTY_NAME_SPRINTF, [])
3939 dnl if HAVE_GETPT 3939 dnl if HAVE_GETPT
3940 elif test "x$ac_cv_func_getpt" = xyes; then 3940 elif test "x$ac_cv_func_getpt" = xyes; then
diff --git a/lib/fcntl.c b/lib/fcntl.c
new file mode 100644
index 00000000000..735fa66f4d7
--- /dev/null
+++ b/lib/fcntl.c
@@ -0,0 +1,311 @@
1/* Provide file descriptor control.
2
3 Copyright (C) 2009-2013 Free Software Foundation, Inc.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17
18/* Written by Eric Blake <ebb9@byu.net>. */
19
20#include <config.h>
21
22/* Specification. */
23#include <fcntl.h>
24
25#include <errno.h>
26#include <limits.h>
27#include <stdarg.h>
28#include <unistd.h>
29
30#if !HAVE_FCNTL
31# define rpl_fcntl fcntl
32#endif
33#undef fcntl
34
35#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
36/* Get declarations of the native Windows API functions. */
37# define WIN32_LEAN_AND_MEAN
38# include <windows.h>
39
40/* Get _get_osfhandle. */
41# include "msvc-nothrow.h"
42
43/* Upper bound on getdtablesize(). See lib/getdtablesize.c. */
44# define OPEN_MAX_MAX 0x10000
45
46/* Duplicate OLDFD into the first available slot of at least NEWFD,
47 which must be positive, with FLAGS determining whether the duplicate
48 will be inheritable. */
49static int
50dupfd (int oldfd, int newfd, int flags)
51{
52 /* Mingw has no way to create an arbitrary fd. Iterate until all
53 file descriptors less than newfd are filled up. */
54 HANDLE curr_process = GetCurrentProcess ();
55 HANDLE old_handle = (HANDLE) _get_osfhandle (oldfd);
56 unsigned char fds_to_close[OPEN_MAX_MAX / CHAR_BIT];
57 unsigned int fds_to_close_bound = 0;
58 int result;
59 BOOL inherit = flags & O_CLOEXEC ? FALSE : TRUE;
60 int mode;
61
62 if (newfd < 0 || getdtablesize () <= newfd)
63 {
64 errno = EINVAL;
65 return -1;
66 }
67 if (old_handle == INVALID_HANDLE_VALUE
68 || (mode = setmode (oldfd, O_BINARY)) == -1)
69 {
70 /* oldfd is not open, or is an unassigned standard file
71 descriptor. */
72 errno = EBADF;
73 return -1;
74 }
75 setmode (oldfd, mode);
76 flags |= mode;
77
78 for (;;)
79 {
80 HANDLE new_handle;
81 int duplicated_fd;
82 unsigned int index;
83
84 if (!DuplicateHandle (curr_process, /* SourceProcessHandle */
85 old_handle, /* SourceHandle */
86 curr_process, /* TargetProcessHandle */
87 (PHANDLE) &new_handle, /* TargetHandle */
88 (DWORD) 0, /* DesiredAccess */
89 inherit, /* InheritHandle */
90 DUPLICATE_SAME_ACCESS)) /* Options */
91 {
92 /* TODO: Translate GetLastError () into errno. */
93 errno = EMFILE;
94 result = -1;
95 break;
96 }
97 duplicated_fd = _open_osfhandle ((intptr_t) new_handle, flags);
98 if (duplicated_fd < 0)
99 {
100 CloseHandle (new_handle);
101 errno = EMFILE;
102 result = -1;
103 break;
104 }
105 if (newfd <= duplicated_fd)
106 {
107 result = duplicated_fd;
108 break;
109 }
110
111 /* Set the bit duplicated_fd in fds_to_close[]. */
112 index = (unsigned int) duplicated_fd / CHAR_BIT;
113 if (fds_to_close_bound <= index)
114 {
115 if (sizeof fds_to_close <= index)
116 /* Need to increase OPEN_MAX_MAX. */
117 abort ();
118 memset (fds_to_close + fds_to_close_bound, '\0',
119 index + 1 - fds_to_close_bound);
120 fds_to_close_bound = index + 1;
121 }
122 fds_to_close[index] |= 1 << ((unsigned int) duplicated_fd % CHAR_BIT);
123 }
124
125 /* Close the previous fds that turned out to be too small. */
126 {
127 int saved_errno = errno;
128 unsigned int duplicated_fd;
129
130 for (duplicated_fd = 0;
131 duplicated_fd < fds_to_close_bound * CHAR_BIT;
132 duplicated_fd++)
133 if ((fds_to_close[duplicated_fd / CHAR_BIT]
134 >> (duplicated_fd % CHAR_BIT))
135 & 1)
136 close (duplicated_fd);
137
138 errno = saved_errno;
139 }
140
141# if REPLACE_FCHDIR
142 if (0 <= result)
143 result = _gl_register_dup (oldfd, result);
144# endif
145 return result;
146}
147#endif /* W32 */
148
149/* Perform the specified ACTION on the file descriptor FD, possibly
150 using the argument ARG further described below. This replacement
151 handles the following actions, and forwards all others on to the
152 native fcntl. An unrecognized ACTION returns -1 with errno set to
153 EINVAL.
154
155 F_DUPFD - duplicate FD, with int ARG being the minimum target fd.
156 If successful, return the duplicate, which will be inheritable;
157 otherwise return -1 and set errno.
158
159 F_DUPFD_CLOEXEC - duplicate FD, with int ARG being the minimum
160 target fd. If successful, return the duplicate, which will not be
161 inheritable; otherwise return -1 and set errno.
162
163 F_GETFD - ARG need not be present. If successful, return a
164 non-negative value containing the descriptor flags of FD (only
165 FD_CLOEXEC is portable, but other flags may be present); otherwise
166 return -1 and set errno. */
167
168int
169rpl_fcntl (int fd, int action, /* arg */...)
170{
171 va_list arg;
172 int result = -1;
173 va_start (arg, action);
174 switch (action)
175 {
176
177#if !HAVE_FCNTL
178 case F_DUPFD:
179 {
180 int target = va_arg (arg, int);
181 result = dupfd (fd, target, 0);
182 break;
183 }
184#elif FCNTL_DUPFD_BUGGY || REPLACE_FCHDIR
185 case F_DUPFD:
186 {
187 int target = va_arg (arg, int);
188 /* Detect invalid target; needed for cygwin 1.5.x. */
189 if (target < 0 || getdtablesize () <= target)
190 errno = EINVAL;
191 else
192 {
193 /* Haiku alpha 2 loses fd flags on original. */
194 int flags = fcntl (fd, F_GETFD);
195 if (flags < 0)
196 {
197 result = -1;
198 break;
199 }
200 result = fcntl (fd, action, target);
201 if (0 <= result && fcntl (fd, F_SETFD, flags) == -1)
202 {
203 int saved_errno = errno;
204 close (result);
205 result = -1;
206 errno = saved_errno;
207 }
208# if REPLACE_FCHDIR
209 if (0 <= result)
210 result = _gl_register_dup (fd, result);
211# endif
212 }
213 break;
214 } /* F_DUPFD */
215#endif /* FCNTL_DUPFD_BUGGY || REPLACE_FCHDIR */
216
217 case F_DUPFD_CLOEXEC:
218 {
219 int target = va_arg (arg, int);
220
221#if !HAVE_FCNTL
222 result = dupfd (fd, target, O_CLOEXEC);
223 break;
224#else /* HAVE_FCNTL */
225 /* Try the system call first, if the headers claim it exists
226 (that is, if GNULIB_defined_F_DUPFD_CLOEXEC is 0), since we
227 may be running with a glibc that has the macro but with an
228 older kernel that does not support it. Cache the
229 information on whether the system call really works, but
230 avoid caching failure if the corresponding F_DUPFD fails
231 for any reason. 0 = unknown, 1 = yes, -1 = no. */
232 static int have_dupfd_cloexec = GNULIB_defined_F_DUPFD_CLOEXEC ? -1 : 0;
233 if (0 <= have_dupfd_cloexec)
234 {
235 result = fcntl (fd, action, target);
236 if (0 <= result || errno != EINVAL)
237 {
238 have_dupfd_cloexec = 1;
239# if REPLACE_FCHDIR
240 if (0 <= result)
241 result = _gl_register_dup (fd, result);
242# endif
243 }
244 else
245 {
246 result = rpl_fcntl (fd, F_DUPFD, target);
247 if (result < 0)
248 break;
249 have_dupfd_cloexec = -1;
250 }
251 }
252 else
253 result = rpl_fcntl (fd, F_DUPFD, target);
254 if (0 <= result && have_dupfd_cloexec == -1)
255 {
256 int flags = fcntl (result, F_GETFD);
257 if (flags < 0 || fcntl (result, F_SETFD, flags | FD_CLOEXEC) == -1)
258 {
259 int saved_errno = errno;
260 close (result);
261 errno = saved_errno;
262 result = -1;
263 }
264 }
265 break;
266#endif /* HAVE_FCNTL */
267 } /* F_DUPFD_CLOEXEC */
268
269#if !HAVE_FCNTL
270 case F_GETFD:
271 {
272# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
273 HANDLE handle = (HANDLE) _get_osfhandle (fd);
274 DWORD flags;
275 if (handle == INVALID_HANDLE_VALUE
276 || GetHandleInformation (handle, &flags) == 0)
277 errno = EBADF;
278 else
279 result = (flags & HANDLE_FLAG_INHERIT) ? 0 : FD_CLOEXEC;
280# else /* !W32 */
281 /* Use dup2 to reject invalid file descriptors. No way to
282 access this information, so punt. */
283 if (0 <= dup2 (fd, fd))
284 result = 0;
285# endif /* !W32 */
286 break;
287 } /* F_GETFD */
288#endif /* !HAVE_FCNTL */
289
290 /* Implementing F_SETFD on mingw is not trivial - there is no
291 API for changing the O_NOINHERIT bit on an fd, and merely
292 changing the HANDLE_FLAG_INHERIT bit on the underlying handle
293 can lead to odd state. It may be possible by duplicating the
294 handle, using _open_osfhandle with the right flags, then
295 using dup2 to move the duplicate onto the original, but that
296 is not supported for now. */
297
298 default:
299 {
300#if HAVE_FCNTL
301 void *p = va_arg (arg, void *);
302 result = fcntl (fd, action, p);
303#else
304 errno = EINVAL;
305#endif
306 break;
307 }
308 }
309 va_end (arg);
310 return result;
311}
diff --git a/lib/getdtablesize.c b/lib/getdtablesize.c
new file mode 100644
index 00000000000..9947405af61
--- /dev/null
+++ b/lib/getdtablesize.c
@@ -0,0 +1,86 @@
1/* getdtablesize() function for platforms that don't have it.
2 Copyright (C) 2008-2013 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2008.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17
18#include <config.h>
19
20/* Specification. */
21#include <unistd.h>
22
23#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
24
25#include <stdio.h>
26
27#include "msvc-inval.h"
28
29#if HAVE_MSVC_INVALID_PARAMETER_HANDLER
30static int
31_setmaxstdio_nothrow (int newmax)
32{
33 int result;
34
35 TRY_MSVC_INVAL
36 {
37 result = _setmaxstdio (newmax);
38 }
39 CATCH_MSVC_INVAL
40 {
41 result = -1;
42 }
43 DONE_MSVC_INVAL;
44
45 return result;
46}
47# define _setmaxstdio _setmaxstdio_nothrow
48#endif
49
50/* Cache for the previous getdtablesize () result. */
51static int dtablesize;
52
53int
54getdtablesize (void)
55{
56 if (dtablesize == 0)
57 {
58 /* We are looking for the number N such that the valid file descriptors
59 are 0..N-1. It can be obtained through a loop as follows:
60 {
61 int fd;
62 for (fd = 3; fd < 65536; fd++)
63 if (dup2 (0, fd) == -1)
64 break;
65 return fd;
66 }
67 On Windows XP, the result is 2048.
68 The drawback of this loop is that it allocates memory for a libc
69 internal array that is never freed.
70
71 The number N can also be obtained as the upper bound for
72 _getmaxstdio (). _getmaxstdio () returns the maximum number of open
73 FILE objects. The sanity check in _setmaxstdio reveals the maximum
74 number of file descriptors. This too allocates memory, but it is
75 freed when we call _setmaxstdio with the original value. */
76 int orig_max_stdio = _getmaxstdio ();
77 unsigned int bound;
78 for (bound = 0x10000; _setmaxstdio (bound) < 0; bound = bound / 2)
79 ;
80 _setmaxstdio (orig_max_stdio);
81 dtablesize = bound;
82 }
83 return dtablesize;
84}
85
86#endif
diff --git a/lib/gnulib.mk b/lib/gnulib.mk
index 4a84b1db261..9f9ac6c0583 100644
--- a/lib/gnulib.mk
+++ b/lib/gnulib.mk
@@ -21,7 +21,7 @@
21# the same distribution terms as the rest of that program. 21# the same distribution terms as the rest of that program.
22# 22#
23# Generated by gnulib-tool. 23# Generated by gnulib-tool.
24# 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 24# 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
25 25
26 26
27MOSTLYCLEANFILES += core *.stackdump 27MOSTLYCLEANFILES += core *.stackdump
@@ -296,6 +296,15 @@ EXTRA_libgnu_a_SOURCES += at-func.c faccessat.c
296 296
297## end gnulib module faccessat 297## end gnulib module faccessat
298 298
299## begin gnulib module fcntl
300
301
302EXTRA_DIST += fcntl.c
303
304EXTRA_libgnu_a_SOURCES += fcntl.c
305
306## end gnulib module fcntl
307
299## begin gnulib module fcntl-h 308## begin gnulib module fcntl-h
300 309
301BUILT_SOURCES += fcntl.h 310BUILT_SOURCES += fcntl.h
@@ -384,6 +393,17 @@ EXTRA_libgnu_a_SOURCES += fsync.c
384 393
385## end gnulib module fsync 394## end gnulib module fsync
386 395
396## begin gnulib module getdtablesize
397
398if gl_GNULIB_ENABLED_getdtablesize
399
400endif
401EXTRA_DIST += getdtablesize.c
402
403EXTRA_libgnu_a_SOURCES += getdtablesize.c
404
405## end gnulib module getdtablesize
406
387## begin gnulib module getgroups 407## begin gnulib module getgroups
388 408
389if gl_GNULIB_ENABLED_getgroups 409if gl_GNULIB_ENABLED_getgroups
@@ -568,6 +588,12 @@ EXTRA_DIST += pathmax.h
568 588
569## end gnulib module pathmax 589## end gnulib module pathmax
570 590
591## begin gnulib module pipe2
592
593libgnu_a_SOURCES += pipe2.c
594
595## end gnulib module pipe2
596
571## begin gnulib module pselect 597## begin gnulib module pselect
572 598
573 599
@@ -1704,9 +1730,7 @@ EXTRA_DIST += utimens.h
1704 1730
1705## begin gnulib module verify 1731## begin gnulib module verify
1706 1732
1707if gl_GNULIB_ENABLED_verify
1708 1733
1709endif
1710EXTRA_DIST += verify.h 1734EXTRA_DIST += verify.h
1711 1735
1712## end gnulib module verify 1736## end gnulib module verify
diff --git a/lib/pipe2.c b/lib/pipe2.c
new file mode 100644
index 00000000000..3858c328f76
--- /dev/null
+++ b/lib/pipe2.c
@@ -0,0 +1,171 @@
1/* Create a pipe, with specific opening flags.
2 Copyright (C) 2009-2013 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, see <http://www.gnu.org/licenses/>. */
16
17#include <config.h>
18
19/* Specification. */
20#include <unistd.h>
21
22#include <errno.h>
23#include <fcntl.h>
24
25#if GNULIB_BINARY_IO
26# include "binary-io.h"
27#endif
28
29#include "verify.h"
30
31#if GNULIB_defined_O_NONBLOCK
32# include "nonblocking.h"
33#endif
34
35#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
36/* Native Windows API. */
37
38# include <io.h>
39
40#endif
41
42int
43pipe2 (int fd[2], int flags)
44{
45 /* Mingw _pipe() corrupts fd on failure; also, if we succeed at
46 creating the pipe but later fail at changing fcntl, we want
47 to leave fd unchanged: http://austingroupbugs.net/view.php?id=467 */
48 int tmp[2];
49 tmp[0] = fd[0];
50 tmp[1] = fd[1];
51
52#if HAVE_PIPE2
53# undef pipe2
54 /* Try the system call first, if it exists. (We may be running with a glibc
55 that has the function but with an older kernel that lacks it.) */
56 {
57 /* Cache the information whether the system call really exists. */
58 static int have_pipe2_really; /* 0 = unknown, 1 = yes, -1 = no */
59 if (have_pipe2_really >= 0)
60 {
61 int result = pipe2 (fd, flags);
62 if (!(result < 0 && errno == ENOSYS))
63 {
64 have_pipe2_really = 1;
65 return result;
66 }
67 have_pipe2_really = -1;
68 }
69 }
70#endif
71
72 /* Check the supported flags. */
73 if ((flags & ~(O_CLOEXEC | O_NONBLOCK | O_BINARY | O_TEXT)) != 0)
74 {
75 errno = EINVAL;
76 return -1;
77 }
78
79#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
80/* Native Windows API. */
81
82 if (_pipe (fd, 4096, flags & ~O_NONBLOCK) < 0)
83 {
84 fd[0] = tmp[0];
85 fd[1] = tmp[1];
86 return -1;
87 }
88
89 /* O_NONBLOCK handling.
90 On native Windows platforms, O_NONBLOCK is defined by gnulib. Use the
91 functions defined by the gnulib module 'nonblocking'. */
92# if GNULIB_defined_O_NONBLOCK
93 if (flags & O_NONBLOCK)
94 {
95 if (set_nonblocking_flag (fd[0], true) != 0
96 || set_nonblocking_flag (fd[1], true) != 0)
97 goto fail;
98 }
99# else
100 {
101 verify (O_NONBLOCK == 0);
102 }
103# endif
104
105 return 0;
106
107#else
108/* Unix API. */
109
110 if (pipe (fd) < 0)
111 return -1;
112
113 /* POSIX <http://www.opengroup.org/onlinepubs/9699919799/functions/pipe.html>
114 says that initially, the O_NONBLOCK and FD_CLOEXEC flags are cleared on
115 both fd[0] and fd[1]. */
116
117 /* O_NONBLOCK handling.
118 On Unix platforms, O_NONBLOCK is defined by the system. Use fcntl(). */
119 if (flags & O_NONBLOCK)
120 {
121 int fcntl_flags;
122
123 if ((fcntl_flags = fcntl (fd[1], F_GETFL, 0)) < 0
124 || fcntl (fd[1], F_SETFL, fcntl_flags | O_NONBLOCK) == -1
125 || (fcntl_flags = fcntl (fd[0], F_GETFL, 0)) < 0
126 || fcntl (fd[0], F_SETFL, fcntl_flags | O_NONBLOCK) == -1)
127 goto fail;
128 }
129
130 if (flags & O_CLOEXEC)
131 {
132 int fcntl_flags;
133
134 if ((fcntl_flags = fcntl (fd[1], F_GETFD, 0)) < 0
135 || fcntl (fd[1], F_SETFD, fcntl_flags | FD_CLOEXEC) == -1
136 || (fcntl_flags = fcntl (fd[0], F_GETFD, 0)) < 0
137 || fcntl (fd[0], F_SETFD, fcntl_flags | FD_CLOEXEC) == -1)
138 goto fail;
139 }
140
141# if O_BINARY
142 if (flags & O_BINARY)
143 {
144 setmode (fd[1], O_BINARY);
145 setmode (fd[0], O_BINARY);
146 }
147 else if (flags & O_TEXT)
148 {
149 setmode (fd[1], O_TEXT);
150 setmode (fd[0], O_TEXT);
151 }
152# endif
153
154 return 0;
155
156#endif
157
158#if GNULIB_defined_O_NONBLOCK || \
159 !((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__)
160 fail:
161 {
162 int saved_errno = errno;
163 close (fd[0]);
164 close (fd[1]);
165 fd[0] = tmp[0];
166 fd[1] = tmp[1];
167 errno = saved_errno;
168 return -1;
169 }
170#endif
171}
diff --git a/m4/fcntl.m4 b/m4/fcntl.m4
new file mode 100644
index 00000000000..5481cae4d80
--- /dev/null
+++ b/m4/fcntl.m4
@@ -0,0 +1,95 @@
1# fcntl.m4 serial 5
2dnl Copyright (C) 2009-2013 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved.
6
7# For now, this module ensures that fcntl()
8# - supports F_DUPFD correctly
9# - supports or emulates F_DUPFD_CLOEXEC
10# - supports F_GETFD
11# Still to be ported to mingw:
12# - F_SETFD
13# - F_GETFL, F_SETFL
14# - F_GETOWN, F_SETOWN
15# - F_GETLK, F_SETLK, F_SETLKW
16AC_DEFUN([gl_FUNC_FCNTL],
17[
18 dnl Persuade glibc to expose F_DUPFD_CLOEXEC.
19 AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
20 AC_REQUIRE([gl_FCNTL_H_DEFAULTS])
21 AC_REQUIRE([AC_CANONICAL_HOST])
22 AC_CHECK_FUNCS_ONCE([fcntl])
23 if test $ac_cv_func_fcntl = no; then
24 gl_REPLACE_FCNTL
25 else
26 dnl cygwin 1.5.x F_DUPFD has wrong errno, and allows negative target
27 dnl haiku alpha 2 F_DUPFD has wrong errno
28 AC_CACHE_CHECK([whether fcntl handles F_DUPFD correctly],
29 [gl_cv_func_fcntl_f_dupfd_works],
30 [AC_RUN_IFELSE([AC_LANG_PROGRAM([[
31#include <fcntl.h>
32#include <errno.h>
33]], [[int result = 0;
34 if (fcntl (0, F_DUPFD, -1) != -1) result |= 1;
35 if (errno != EINVAL) result |= 2;
36 return result;
37 ]])],
38 [gl_cv_func_fcntl_f_dupfd_works=yes],
39 [gl_cv_func_fcntl_f_dupfd_works=no],
40 [# Guess that it works on glibc systems
41 case $host_os in #((
42 *-gnu*) gl_cv_func_fcntl_f_dupfd_works="guessing yes";;
43 *) gl_cv_func_fcntl_f_dupfd_works="guessing no";;
44 esac])])
45 case $gl_cv_func_fcntl_f_dupfd_works in
46 *yes) ;;
47 *) gl_REPLACE_FCNTL
48 AC_DEFINE([FCNTL_DUPFD_BUGGY], [1], [Define this to 1 if F_DUPFD
49 behavior does not match POSIX]) ;;
50 esac
51
52 dnl Many systems lack F_DUPFD_CLOEXEC
53 AC_CACHE_CHECK([whether fcntl understands F_DUPFD_CLOEXEC],
54 [gl_cv_func_fcntl_f_dupfd_cloexec],
55 [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
56#include <fcntl.h>
57#ifndef F_DUPFD_CLOEXEC
58choke me
59#endif
60 ]])],
61 [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
62#ifdef __linux__
63/* The Linux kernel only added F_DUPFD_CLOEXEC in 2.6.24, so we always replace
64 it to support the semantics on older kernels that failed with EINVAL. */
65choke me
66#endif
67 ]])],
68 [gl_cv_func_fcntl_f_dupfd_cloexec=yes],
69 [gl_cv_func_fcntl_f_dupfd_cloexec="needs runtime check"])],
70 [gl_cv_func_fcntl_f_dupfd_cloexec=no])])
71 if test "$gl_cv_func_fcntl_f_dupfd_cloexec" != yes; then
72 gl_REPLACE_FCNTL
73 dnl No witness macro needed for this bug.
74 fi
75 fi
76 dnl Replace fcntl() for supporting the gnulib-defined fchdir() function,
77 dnl to keep fchdir's bookkeeping up-to-date.
78 m4_ifdef([gl_FUNC_FCHDIR], [
79 gl_TEST_FCHDIR
80 if test $HAVE_FCHDIR = 0; then
81 gl_REPLACE_FCNTL
82 fi
83 ])
84])
85
86AC_DEFUN([gl_REPLACE_FCNTL],
87[
88 AC_REQUIRE([gl_FCNTL_H_DEFAULTS])
89 AC_CHECK_FUNCS_ONCE([fcntl])
90 if test $ac_cv_func_fcntl = no; then
91 HAVE_FCNTL=0
92 else
93 REPLACE_FCNTL=1
94 fi
95])
diff --git a/m4/getdtablesize.m4 b/m4/getdtablesize.m4
new file mode 100644
index 00000000000..8f04b3b8c2a
--- /dev/null
+++ b/m4/getdtablesize.m4
@@ -0,0 +1,17 @@
1# getdtablesize.m4 serial 4
2dnl Copyright (C) 2008-2013 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved.
6
7AC_DEFUN([gl_FUNC_GETDTABLESIZE],
8[
9 AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
10 AC_CHECK_FUNCS_ONCE([getdtablesize])
11 if test $ac_cv_func_getdtablesize != yes; then
12 HAVE_GETDTABLESIZE=0
13 fi
14])
15
16# Prerequisites of lib/getdtablesize.c.
17AC_DEFUN([gl_PREREQ_GETDTABLESIZE], [:])
diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4
index 344b77642b9..e813692aeaf 100644
--- a/m4/gnulib-comp.m4
+++ b/m4/gnulib-comp.m4
@@ -63,6 +63,7 @@ AC_DEFUN([gl_EARLY],
63 AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) 63 AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
64 # Code from module extern-inline: 64 # Code from module extern-inline:
65 # Code from module faccessat: 65 # Code from module faccessat:
66 # Code from module fcntl:
66 # Code from module fcntl-h: 67 # Code from module fcntl-h:
67 # Code from module fdatasync: 68 # Code from module fdatasync:
68 # Code from module fdopendir: 69 # Code from module fdopendir:
@@ -70,6 +71,7 @@ AC_DEFUN([gl_EARLY],
70 # Code from module fpending: 71 # Code from module fpending:
71 # Code from module fstatat: 72 # Code from module fstatat:
72 # Code from module fsync: 73 # Code from module fsync:
74 # Code from module getdtablesize:
73 # Code from module getgroups: 75 # Code from module getgroups:
74 # Code from module getloadavg: 76 # Code from module getloadavg:
75 # Code from module getopt-gnu: 77 # Code from module getopt-gnu:
@@ -92,6 +94,7 @@ AC_DEFUN([gl_EARLY],
92 # Code from module nocrash: 94 # Code from module nocrash:
93 # Code from module openat-h: 95 # Code from module openat-h:
94 # Code from module pathmax: 96 # Code from module pathmax:
97 # Code from module pipe2:
95 # Code from module pselect: 98 # Code from module pselect:
96 # Code from module pthread_sigmask: 99 # Code from module pthread_sigmask:
97 # Code from module putenv: 100 # Code from module putenv:
@@ -191,6 +194,11 @@ AC_DEFUN([gl_INIT],
191 fi 194 fi
192 gl_MODULE_INDICATOR([faccessat]) 195 gl_MODULE_INDICATOR([faccessat])
193 gl_UNISTD_MODULE_INDICATOR([faccessat]) 196 gl_UNISTD_MODULE_INDICATOR([faccessat])
197 gl_FUNC_FCNTL
198 if test $HAVE_FCNTL = 0 || test $REPLACE_FCNTL = 1; then
199 AC_LIBOBJ([fcntl])
200 fi
201 gl_FCNTL_MODULE_INDICATOR([fcntl])
194 gl_FCNTL_H 202 gl_FCNTL_H
195 gl_FUNC_FDATASYNC 203 gl_FUNC_FDATASYNC
196 if test $HAVE_FDATASYNC = 0; then 204 if test $HAVE_FDATASYNC = 0; then
@@ -273,6 +281,8 @@ AC_DEFUN([gl_INIT],
273 fi 281 fi
274 gl_TIME_MODULE_INDICATOR([mktime]) 282 gl_TIME_MODULE_INDICATOR([mktime])
275 gl_MULTIARCH 283 gl_MULTIARCH
284 gl_FUNC_PIPE2
285 gl_UNISTD_MODULE_INDICATOR([pipe2])
276 gl_FUNC_PSELECT 286 gl_FUNC_PSELECT
277 if test $HAVE_PSELECT = 0 || test $REPLACE_PSELECT = 1; then 287 if test $HAVE_PSELECT = 0 || test $REPLACE_PSELECT = 1; then
278 AC_LIBOBJ([pselect]) 288 AC_LIBOBJ([pselect])
@@ -364,6 +374,7 @@ AC_DEFUN([gl_INIT],
364 gl_gnulib_enabled_260941c0e5dc67ec9e87d1fb321c300b=false 374 gl_gnulib_enabled_260941c0e5dc67ec9e87d1fb321c300b=false
365 gl_gnulib_enabled_dosname=false 375 gl_gnulib_enabled_dosname=false
366 gl_gnulib_enabled_euidaccess=false 376 gl_gnulib_enabled_euidaccess=false
377 gl_gnulib_enabled_getdtablesize=false
367 gl_gnulib_enabled_getgroups=false 378 gl_gnulib_enabled_getgroups=false
368 gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36=false 379 gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36=false
369 gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1=false 380 gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1=false
@@ -373,7 +384,6 @@ AC_DEFUN([gl_INIT],
373 gl_gnulib_enabled_stat=false 384 gl_gnulib_enabled_stat=false
374 gl_gnulib_enabled_strtoll=false 385 gl_gnulib_enabled_strtoll=false
375 gl_gnulib_enabled_strtoull=false 386 gl_gnulib_enabled_strtoull=false
376 gl_gnulib_enabled_verify=false
377 gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec=false 387 gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec=false
378 func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b () 388 func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b ()
379 { 389 {
@@ -407,6 +417,18 @@ AC_DEFUN([gl_INIT],
407 fi 417 fi
408 fi 418 fi
409 } 419 }
420 func_gl_gnulib_m4code_getdtablesize ()
421 {
422 if ! $gl_gnulib_enabled_getdtablesize; then
423 gl_FUNC_GETDTABLESIZE
424 if test $HAVE_GETDTABLESIZE = 0; then
425 AC_LIBOBJ([getdtablesize])
426 gl_PREREQ_GETDTABLESIZE
427 fi
428 gl_UNISTD_MODULE_INDICATOR([getdtablesize])
429 gl_gnulib_enabled_getdtablesize=true
430 fi
431 }
410 func_gl_gnulib_m4code_getgroups () 432 func_gl_gnulib_m4code_getgroups ()
411 { 433 {
412 if ! $gl_gnulib_enabled_getgroups; then 434 if ! $gl_gnulib_enabled_getgroups; then
@@ -479,9 +501,6 @@ AC_DEFUN([gl_INIT],
479 if test $REPLACE_STAT = 1; then 501 if test $REPLACE_STAT = 1; then
480 func_gl_gnulib_m4code_pathmax 502 func_gl_gnulib_m4code_pathmax
481 fi 503 fi
482 if test $REPLACE_STAT = 1; then
483 func_gl_gnulib_m4code_verify
484 fi
485 fi 504 fi
486 } 505 }
487 func_gl_gnulib_m4code_strtoll () 506 func_gl_gnulib_m4code_strtoll ()
@@ -508,12 +527,6 @@ AC_DEFUN([gl_INIT],
508 gl_gnulib_enabled_strtoull=true 527 gl_gnulib_enabled_strtoull=true
509 fi 528 fi
510 } 529 }
511 func_gl_gnulib_m4code_verify ()
512 {
513 if ! $gl_gnulib_enabled_verify; then
514 gl_gnulib_enabled_verify=true
515 fi
516 }
517 func_gl_gnulib_m4code_682e609604ccaac6be382e4ee3a4eaec () 530 func_gl_gnulib_m4code_682e609604ccaac6be382e4ee3a4eaec ()
518 { 531 {
519 if ! $gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec; then 532 if ! $gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec; then
@@ -532,6 +545,9 @@ AC_DEFUN([gl_INIT],
532 if test $HAVE_FACCESSAT = 0; then 545 if test $HAVE_FACCESSAT = 0; then
533 func_gl_gnulib_m4code_03e0aaad4cb89ca757653bd367a6ccb7 546 func_gl_gnulib_m4code_03e0aaad4cb89ca757653bd367a6ccb7
534 fi 547 fi
548 if test $HAVE_FCNTL = 0 || test $REPLACE_FCNTL = 1; then
549 func_gl_gnulib_m4code_getdtablesize
550 fi
535 if test $HAVE_FDOPENDIR = 0; then 551 if test $HAVE_FDOPENDIR = 0; then
536 func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b 552 func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b
537 fi 553 fi
@@ -568,19 +584,14 @@ AC_DEFUN([gl_INIT],
568 if { test $HAVE_STRTOIMAX = 0 || test $REPLACE_STRTOIMAX = 1; } && test $ac_cv_type_long_long_int = yes; then 584 if { test $HAVE_STRTOIMAX = 0 || test $REPLACE_STRTOIMAX = 1; } && test $ac_cv_type_long_long_int = yes; then
569 func_gl_gnulib_m4code_strtoll 585 func_gl_gnulib_m4code_strtoll
570 fi 586 fi
571 if test $HAVE_STRTOIMAX = 0 || test $REPLACE_STRTOIMAX = 1; then
572 func_gl_gnulib_m4code_verify
573 fi
574 if test $ac_cv_func_strtoumax = no && test $ac_cv_type_unsigned_long_long_int = yes; then 587 if test $ac_cv_func_strtoumax = no && test $ac_cv_type_unsigned_long_long_int = yes; then
575 func_gl_gnulib_m4code_strtoull 588 func_gl_gnulib_m4code_strtoull
576 fi 589 fi
577 if test $ac_cv_func_strtoumax = no; then
578 func_gl_gnulib_m4code_verify
579 fi
580 m4_pattern_allow([^gl_GNULIB_ENABLED_]) 590 m4_pattern_allow([^gl_GNULIB_ENABLED_])
581 AM_CONDITIONAL([gl_GNULIB_ENABLED_260941c0e5dc67ec9e87d1fb321c300b], [$gl_gnulib_enabled_260941c0e5dc67ec9e87d1fb321c300b]) 591 AM_CONDITIONAL([gl_GNULIB_ENABLED_260941c0e5dc67ec9e87d1fb321c300b], [$gl_gnulib_enabled_260941c0e5dc67ec9e87d1fb321c300b])
582 AM_CONDITIONAL([gl_GNULIB_ENABLED_dosname], [$gl_gnulib_enabled_dosname]) 592 AM_CONDITIONAL([gl_GNULIB_ENABLED_dosname], [$gl_gnulib_enabled_dosname])
583 AM_CONDITIONAL([gl_GNULIB_ENABLED_euidaccess], [$gl_gnulib_enabled_euidaccess]) 593 AM_CONDITIONAL([gl_GNULIB_ENABLED_euidaccess], [$gl_gnulib_enabled_euidaccess])
594 AM_CONDITIONAL([gl_GNULIB_ENABLED_getdtablesize], [$gl_gnulib_enabled_getdtablesize])
584 AM_CONDITIONAL([gl_GNULIB_ENABLED_getgroups], [$gl_gnulib_enabled_getgroups]) 595 AM_CONDITIONAL([gl_GNULIB_ENABLED_getgroups], [$gl_gnulib_enabled_getgroups])
585 AM_CONDITIONAL([gl_GNULIB_ENABLED_be453cec5eecf5731a274f2de7f2db36], [$gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36]) 596 AM_CONDITIONAL([gl_GNULIB_ENABLED_be453cec5eecf5731a274f2de7f2db36], [$gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36])
586 AM_CONDITIONAL([gl_GNULIB_ENABLED_a9786850e999ae65a836a6041e8e5ed1], [$gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1]) 597 AM_CONDITIONAL([gl_GNULIB_ENABLED_a9786850e999ae65a836a6041e8e5ed1], [$gl_gnulib_enabled_a9786850e999ae65a836a6041e8e5ed1])
@@ -590,7 +601,6 @@ AC_DEFUN([gl_INIT],
590 AM_CONDITIONAL([gl_GNULIB_ENABLED_stat], [$gl_gnulib_enabled_stat]) 601 AM_CONDITIONAL([gl_GNULIB_ENABLED_stat], [$gl_gnulib_enabled_stat])
591 AM_CONDITIONAL([gl_GNULIB_ENABLED_strtoll], [$gl_gnulib_enabled_strtoll]) 602 AM_CONDITIONAL([gl_GNULIB_ENABLED_strtoll], [$gl_gnulib_enabled_strtoll])
592 AM_CONDITIONAL([gl_GNULIB_ENABLED_strtoull], [$gl_gnulib_enabled_strtoull]) 603 AM_CONDITIONAL([gl_GNULIB_ENABLED_strtoull], [$gl_gnulib_enabled_strtoull])
593 AM_CONDITIONAL([gl_GNULIB_ENABLED_verify], [$gl_gnulib_enabled_verify])
594 AM_CONDITIONAL([gl_GNULIB_ENABLED_682e609604ccaac6be382e4ee3a4eaec], [$gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec]) 604 AM_CONDITIONAL([gl_GNULIB_ENABLED_682e609604ccaac6be382e4ee3a4eaec], [$gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec])
595 # End of code from modules 605 # End of code from modules
596 m4_ifval(gl_LIBSOURCES_LIST, [ 606 m4_ifval(gl_LIBSOURCES_LIST, [
@@ -764,6 +774,7 @@ AC_DEFUN([gl_FILE_LIST], [
764 lib/execinfo.c 774 lib/execinfo.c
765 lib/execinfo.in.h 775 lib/execinfo.in.h
766 lib/faccessat.c 776 lib/faccessat.c
777 lib/fcntl.c
767 lib/fcntl.in.h 778 lib/fcntl.in.h
768 lib/fdatasync.c 779 lib/fdatasync.c
769 lib/fdopendir.c 780 lib/fdopendir.c
@@ -776,6 +787,7 @@ AC_DEFUN([gl_FILE_LIST], [
776 lib/fsync.c 787 lib/fsync.c
777 lib/ftoastr.c 788 lib/ftoastr.c
778 lib/ftoastr.h 789 lib/ftoastr.h
790 lib/getdtablesize.c
779 lib/getgroups.c 791 lib/getgroups.c
780 lib/getloadavg.c 792 lib/getloadavg.c
781 lib/getopt.c 793 lib/getopt.c
@@ -799,6 +811,7 @@ AC_DEFUN([gl_FILE_LIST], [
799 lib/openat-proc.c 811 lib/openat-proc.c
800 lib/openat.h 812 lib/openat.h
801 lib/pathmax.h 813 lib/pathmax.h
814 lib/pipe2.c
802 lib/pselect.c 815 lib/pselect.c
803 lib/pthread_sigmask.c 816 lib/pthread_sigmask.c
804 lib/putenv.c 817 lib/putenv.c
@@ -870,6 +883,7 @@ AC_DEFUN([gl_FILE_LIST], [
870 m4/extern-inline.m4 883 m4/extern-inline.m4
871 m4/faccessat.m4 884 m4/faccessat.m4
872 m4/fcntl-o.m4 885 m4/fcntl-o.m4
886 m4/fcntl.m4
873 m4/fcntl_h.m4 887 m4/fcntl_h.m4
874 m4/fdatasync.m4 888 m4/fdatasync.m4
875 m4/fdopendir.m4 889 m4/fdopendir.m4
@@ -877,6 +891,7 @@ AC_DEFUN([gl_FILE_LIST], [
877 m4/fpending.m4 891 m4/fpending.m4
878 m4/fstatat.m4 892 m4/fstatat.m4
879 m4/fsync.m4 893 m4/fsync.m4
894 m4/getdtablesize.m4
880 m4/getgroups.m4 895 m4/getgroups.m4
881 m4/getloadavg.m4 896 m4/getloadavg.m4
882 m4/getopt.m4 897 m4/getopt.m4
@@ -897,6 +912,7 @@ AC_DEFUN([gl_FILE_LIST], [
897 m4/nocrash.m4 912 m4/nocrash.m4
898 m4/off_t.m4 913 m4/off_t.m4
899 m4/pathmax.m4 914 m4/pathmax.m4
915 m4/pipe2.m4
900 m4/pselect.m4 916 m4/pselect.m4
901 m4/pthread_sigmask.m4 917 m4/pthread_sigmask.m4
902 m4/putenv.m4 918 m4/putenv.m4
diff --git a/m4/pipe2.m4 b/m4/pipe2.m4
new file mode 100644
index 00000000000..6ccee105239
--- /dev/null
+++ b/m4/pipe2.m4
@@ -0,0 +1,18 @@
1# pipe2.m4 serial 2
2dnl Copyright (C) 2009-2013 Free Software Foundation, Inc.
3dnl This file is free software; the Free Software Foundation
4dnl gives unlimited permission to copy and/or distribute it,
5dnl with or without modifications, as long as this notice is preserved.
6
7AC_DEFUN([gl_FUNC_PIPE2],
8[
9 AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
10
11 dnl Persuade glibc <unistd.h> to declare pipe2().
12 AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
13
14 AC_CHECK_FUNCS_ONCE([pipe2])
15 if test $ac_cv_func_pipe2 != yes; then
16 HAVE_PIPE2=0
17 fi
18])
diff --git a/nt/ChangeLog b/nt/ChangeLog
index 1a0746b3181..a9b4f836644 100644
--- a/nt/ChangeLog
+++ b/nt/ChangeLog
@@ -1,3 +1,12 @@
12013-07-07 Paul Eggert <eggert@cs.ucla.edu>
2
3 Make file descriptors close-on-exec when possible (Bug#14803).
4 * gnulib.mk: Remove empty gl_GNULIB_ENABLED_verify section;
5 otherwise, gnulib-tool complains given close-on-exec changes.
6 * inc/ms-w32.h (pipe): Remove.
7 * mingw-cfg.site (ac_cv_func_fcntl, gl_cv_func_fcntl_f_dupfd_cloexec)
8 (gl_cv_func_fcntl_f_dupfd_works, ac_cv_func_pipe2): New vars.
9
12013-06-25 Juanma Barranquero <lekktu@gmail.com> 102013-06-25 Juanma Barranquero <lekktu@gmail.com>
2 11
3 * configure.bat: Add warning to the help text about using the 12 * configure.bat: Add warning to the help text about using the
diff --git a/nt/gnulib.mk b/nt/gnulib.mk
index ac4fc2768d9..df27dcf610c 100644
--- a/nt/gnulib.mk
+++ b/nt/gnulib.mk
@@ -876,9 +876,6 @@ EXTRA_DIST += utimens.h
876 876
877## begin gnulib module verify 877## begin gnulib module verify
878 878
879if gl_GNULIB_ENABLED_verify
880
881endif
882EXTRA_DIST += verify.h 879EXTRA_DIST += verify.h
883 880
884## end gnulib module verify 881## end gnulib module verify
diff --git a/nt/inc/ms-w32.h b/nt/inc/ms-w32.h
index 29c8e383893..3e50c78f145 100644
--- a/nt/inc/ms-w32.h
+++ b/nt/inc/ms-w32.h
@@ -211,7 +211,6 @@ extern struct tm * sys_localtime (const time_t *);
211#define mktemp sys_mktemp 211#define mktemp sys_mktemp
212#undef open 212#undef open
213#define open sys_open 213#define open sys_open
214#define pipe sys_pipe
215#undef read 214#undef read
216#define read sys_read 215#define read sys_read
217#define rename sys_rename 216#define rename sys_rename
diff --git a/nt/mingw-cfg.site b/nt/mingw-cfg.site
index 41e4f23784e..cf55fe04ed8 100644
--- a/nt/mingw-cfg.site
+++ b/nt/mingw-cfg.site
@@ -67,6 +67,10 @@ gl_cv_func_readlink_works=yes
67gl_cv_func_symlink_works=yes 67gl_cv_func_symlink_works=yes
68ac_cv_func_readlinkat=yes 68ac_cv_func_readlinkat=yes
69ac_cv_func_faccessat=yes 69ac_cv_func_faccessat=yes
70# Implemented in w32.c
71ac_cv_func_fcntl=yes
72gl_cv_func_fcntl_f_dupfd_cloexec=yes
73gl_cv_func_fcntl_f_dupfd_works=yes
70# We don't need fdopendir 74# We don't need fdopendir
71ac_cv_func_fdopendir="not-needed" 75ac_cv_func_fdopendir="not-needed"
72gl_cv_func_fdopendir_works="no-but-not-needed-so-yes" 76gl_cv_func_fdopendir_works="no-but-not-needed-so-yes"
@@ -95,6 +99,7 @@ ac_cv_func_getloadavg=yes
95# Avoid compiling gnulib mktime 99# Avoid compiling gnulib mktime
96gl_cv_func_working_mktime=yes 100gl_cv_func_working_mktime=yes
97# Implemented in w32.c 101# Implemented in w32.c
102ac_cv_func_pipe2=yes
98ac_cv_have_decl_unsetenv=yes 103ac_cv_have_decl_unsetenv=yes
99ac_cv_func_unsetenv=yes 104ac_cv_func_unsetenv=yes
100gt_cv_func_unsetenv_ret='int' 105gt_cv_func_unsetenv_ret='int'
diff --git a/src/ChangeLog b/src/ChangeLog
index 069d39ce6be..07285d564b2 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,41 @@
12013-07-07 Paul Eggert <eggert@cs.ucla.edu>
2
3 Make file descriptors close-on-exec when possible (Bug#14803).
4 This simplifies Emacs a bit, since it no longer needs to worry
5 about closing file descriptors by hand in some cases.
6 It also fixes some unlikely races. Not all such races, as
7 libraries often open files internally without setting
8 close-on-exec, but it's an improvement.
9 * alloc.c (valid_pointer_p) [!WINDOWSNT]:
10 * callproc.c (Fcall_process) [!MSDOS]:
11 * emacs.c (main) [!DOS_NT]:
12 * nsterm.m (ns_term_init):
13 * process.c (create_process):
14 Use 'pipe2' with O_CLOEXEC instead of 'pipe'.
15 * emacs.c (Fcall_process_region) [HAVE_MKOSTEMP]:
16 * filelock.c (create_lock_file) [HAVE_MKOSTEMP]:
17 Prefer mkostemp with O_CLOEXEC to mkstemp.
18 * callproc.c (relocate_fd) [!WINDOWSNT]:
19 * emacs.c (main): Use F_DUPFD_CLOEXEC, not plain F_DUPFD.
20 No need to use fcntl (..., F_SETFD, FD_CLOEXEC), since we're
21 now using pipe2.
22 * filelock.c (create_lock_file) [! HAVE_MKOSTEMP]:
23 Make the resulting file descriptor close-on-exec.
24 * lisp.h, lread.c, process.c (close_load_descs, close_process_descs):
25 * lread.c (load_descriptor_list, load_descriptor_unwind):
26 Remove; no longer needed. All uses removed.
27 * process.c (SOCK_CLOEXEC): Define to 0 if not supplied by system.
28 (close_on_exec, accept4, process_socket) [!SOCK_CLOEXEC]:
29 New functions.
30 (socket) [!SOCK_CLOEXEC]: Supply a substitute.
31 (Fmake_network_process, Fnetwork_interface_list):
32 (Fnetwork_interface_info, server_accept_connection):
33 Make newly-created socket close-on-exec.
34 * sysdep.c (emacs_open, emacs_fopen):
35 Make new-created descriptor close-on-exec.
36 * w32.c (fcntl): Support F_DUPFD_CLOEXEC well enough for Emacs.
37 * w32.c, w32.h (pipe2): Rename from 'pipe', with new flags arg.
38
12013-07-07 Jan Djärv <jan.h.d@swipnet.se> 392013-07-07 Jan Djärv <jan.h.d@swipnet.se>
2 40
3 * nsterm.m (sendEvent:): Propagate keyboard events to modal windows 41 * nsterm.m (sendEvent:): Propagate keyboard events to modal windows
diff --git a/src/alloc.c b/src/alloc.c
index a31a176caa7..b71cdb98d78 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -4741,7 +4741,7 @@ valid_pointer_p (void *p)
4741 Unfortunately, we cannot use NULL_DEVICE here, as emacs_write may 4741 Unfortunately, we cannot use NULL_DEVICE here, as emacs_write may
4742 not validate p in that case. */ 4742 not validate p in that case. */
4743 4743
4744 if (pipe (fd) == 0) 4744 if (pipe2 (fd, O_CLOEXEC) == 0)
4745 { 4745 {
4746 bool valid = emacs_write (fd[1], (char *) p, 16) == 16; 4746 bool valid = emacs_write (fd[1], (char *) p, 16) == 16;
4747 emacs_close (fd[1]); 4747 emacs_close (fd[1]);
diff --git a/src/callproc.c b/src/callproc.c
index 185dc9a493e..3e70b1c2e49 100644
--- a/src/callproc.c
+++ b/src/callproc.c
@@ -519,7 +519,7 @@ usage: (call-process PROGRAM &optional INFILE DESTINATION DISPLAY &rest ARGS) *
519 { 519 {
520#ifndef MSDOS 520#ifndef MSDOS
521 int fd[2]; 521 int fd[2];
522 if (pipe (fd) == -1) 522 if (pipe2 (fd, O_CLOEXEC) != 0)
523 { 523 {
524 int pipe_errno = errno; 524 int pipe_errno = errno;
525 emacs_close (filefd); 525 emacs_close (filefd);
@@ -1036,12 +1036,16 @@ usage: (call-process-region START END PROGRAM &optional DELETE BUFFER DISPLAY &r
1036 memcpy (tempfile, SDATA (encoded_tem), SBYTES (encoded_tem) + 1); 1036 memcpy (tempfile, SDATA (encoded_tem), SBYTES (encoded_tem) + 1);
1037 coding_systems = Qt; 1037 coding_systems = Qt;
1038 1038
1039#ifdef HAVE_MKSTEMP 1039#if defined HAVE_MKOSTEMP || defined HAVE_MKSTEMP
1040 { 1040 {
1041 int fd; 1041 int fd;
1042 1042
1043 block_input (); 1043 block_input ();
1044# ifdef HAVE_MKOSTEMP
1045 fd = mkostemp (tempfile, O_CLOEXEC);
1046# else
1044 fd = mkstemp (tempfile); 1047 fd = mkstemp (tempfile);
1048# endif
1045 unblock_input (); 1049 unblock_input ();
1046 if (fd == -1) 1050 if (fd == -1)
1047 report_file_error ("Failed to open temporary file", 1051 report_file_error ("Failed to open temporary file",
@@ -1184,15 +1188,6 @@ child_setup (int in, int out, int err, char **new_argv, bool set_pgrp,
1184 1188
1185 pid_t pid = getpid (); 1189 pid_t pid = getpid ();
1186 1190
1187 /* Close Emacs's descriptors that this process should not have. */
1188 close_process_descs ();
1189
1190 /* DOS_NT isn't in a vfork, so if we are in the middle of load-file,
1191 we will lose if we call close_load_descs here. */
1192#ifndef DOS_NT
1193 close_load_descs ();
1194#endif
1195
1196 /* Note that use of alloca is always safe here. It's obvious for systems 1191 /* Note that use of alloca is always safe here. It's obvious for systems
1197 that do not have true vfork or that have true (stack) alloca. 1192 that do not have true vfork or that have true (stack) alloca.
1198 If using vfork and C_ALLOCA (when Emacs used to include 1193 If using vfork and C_ALLOCA (when Emacs used to include
@@ -1354,9 +1349,11 @@ child_setup (int in, int out, int err, char **new_argv, bool set_pgrp,
1354 emacs_close (1); 1349 emacs_close (1);
1355 emacs_close (2); 1350 emacs_close (2);
1356 1351
1352 /* Redirect file descriptors and clear FD_CLOEXEC on the redirected ones. */
1357 dup2 (in, 0); 1353 dup2 (in, 0);
1358 dup2 (out, 1); 1354 dup2 (out, 1);
1359 dup2 (err, 2); 1355 dup2 (err, 2);
1356
1360 emacs_close (in); 1357 emacs_close (in);
1361 if (out != in) 1358 if (out != in)
1362 emacs_close (out); 1359 emacs_close (out);
@@ -1394,7 +1391,7 @@ relocate_fd (int fd, int minfd)
1394 return fd; 1391 return fd;
1395 else 1392 else
1396 { 1393 {
1397 int new = fcntl (fd, F_DUPFD, minfd); 1394 int new = fcntl (fd, F_DUPFD_CLOEXEC, minfd);
1398 if (new == -1) 1395 if (new == -1)
1399 { 1396 {
1400 const char *message_1 = "Error while setting up child: "; 1397 const char *message_1 = "Error while setting up child: ";
diff --git a/src/emacs.c b/src/emacs.c
index 6ba01d1a443..e4412e2ea1a 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -889,7 +889,7 @@ main (int argc, char **argv)
889 emacs_close (0); 889 emacs_close (0);
890 emacs_close (1); 890 emacs_close (1);
891 result = emacs_open (term, O_RDWR, 0); 891 result = emacs_open (term, O_RDWR, 0);
892 if (result < 0 || dup (0) < 0) 892 if (result < 0 || fcntl (0, F_DUPFD_CLOEXEC, 1) < 0)
893 { 893 {
894 char *errstring = strerror (errno); 894 char *errstring = strerror (errno);
895 fprintf (stderr, "%s: %s: %s\n", argv[0], term, errstring); 895 fprintf (stderr, "%s: %s: %s\n", argv[0], term, errstring);
@@ -969,7 +969,7 @@ main (int argc, char **argv)
969 use a pipe for synchronization. The parent waits for the child 969 use a pipe for synchronization. The parent waits for the child
970 to close its end of the pipe (using `daemon-initialized') 970 to close its end of the pipe (using `daemon-initialized')
971 before exiting. */ 971 before exiting. */
972 if (pipe (daemon_pipe) == -1) 972 if (pipe2 (daemon_pipe, O_CLOEXEC) != 0)
973 { 973 {
974 fprintf (stderr, "Cannot pipe!\n"); 974 fprintf (stderr, "Cannot pipe!\n");
975 exit (1); 975 exit (1);
@@ -1065,9 +1065,6 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
1065 daemon_name = xstrdup (dname_arg); 1065 daemon_name = xstrdup (dname_arg);
1066 /* Close unused reading end of the pipe. */ 1066 /* Close unused reading end of the pipe. */
1067 close (daemon_pipe[0]); 1067 close (daemon_pipe[0]);
1068 /* Make sure that the used end of the pipe is closed on exec, so
1069 that it is not accessible to programs started from .emacs. */
1070 fcntl (daemon_pipe[1], F_SETFD, FD_CLOEXEC);
1071 1068
1072 setsid (); 1069 setsid ();
1073#else /* DOS_NT */ 1070#else /* DOS_NT */
diff --git a/src/filelock.c b/src/filelock.c
index de6aba8385c..1fcd2432484 100644
--- a/src/filelock.c
+++ b/src/filelock.c
@@ -416,8 +416,13 @@ create_lock_file (char *lfname, char *lock_info_str, bool force)
416 memcpy (nonce, lfname, lfdirlen); 416 memcpy (nonce, lfname, lfdirlen);
417 strcpy (nonce + lfdirlen, nonce_base); 417 strcpy (nonce + lfdirlen, nonce_base);
418 418
419#if HAVE_MKSTEMP 419#if HAVE_MKOSTEMP
420 /* Prefer mkstemp if available, as it avoids a race between 420 /* Prefer mkostemp to mkstemp, as it avoids a window where FD is
421 temporarily open without close-on-exec. */
422 fd = mkostemp (nonce, O_BINARY | O_CLOEXEC);
423 need_fchmod = 1;
424#elif HAVE_MKSTEMP
425 /* Prefer mkstemp to mktemp, as it avoids a race between
421 mktemp and emacs_open. */ 426 mktemp and emacs_open. */
422 fd = mkstemp (nonce); 427 fd = mkstemp (nonce);
423 need_fchmod = 1; 428 need_fchmod = 1;
@@ -432,7 +437,11 @@ create_lock_file (char *lfname, char *lock_info_str, bool force)
432 err = errno; 437 err = errno;
433 else 438 else
434 { 439 {
435 ptrdiff_t lock_info_len = strlen (lock_info_str); 440 ptrdiff_t lock_info_len;
441#if ! HAVE_MKOSTEMP
442 fcntl (fd, F_SETFD, FD_CLOEXEC);
443#endif
444 lock_info_len = strlen (lock_info_str);
436 err = 0; 445 err = 0;
437 if (emacs_write (fd, lock_info_str, lock_info_len) != lock_info_len 446 if (emacs_write (fd, lock_info_str, lock_info_len) != lock_info_len
438 || (need_fchmod && fchmod (fd, world_readable) != 0)) 447 || (need_fchmod && fchmod (fd, world_readable) != 0))
diff --git a/src/lisp.h b/src/lisp.h
index 5d6fa760108..692f73cdbc3 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -3668,7 +3668,6 @@ extern Lisp_Object string_to_number (char const *, int, bool);
3668extern void map_obarray (Lisp_Object, void (*) (Lisp_Object, Lisp_Object), 3668extern void map_obarray (Lisp_Object, void (*) (Lisp_Object, Lisp_Object),
3669 Lisp_Object); 3669 Lisp_Object);
3670extern void dir_warning (const char *, Lisp_Object); 3670extern void dir_warning (const char *, Lisp_Object);
3671extern void close_load_descs (void);
3672extern void init_obarray (void); 3671extern void init_obarray (void);
3673extern void init_lread (void); 3672extern void init_lread (void);
3674extern void syms_of_lread (void); 3673extern void syms_of_lread (void);
@@ -3995,7 +3994,6 @@ extern void delete_keyboard_wait_descriptor (int);
3995extern void add_gpm_wait_descriptor (int); 3994extern void add_gpm_wait_descriptor (int);
3996extern void delete_gpm_wait_descriptor (int); 3995extern void delete_gpm_wait_descriptor (int);
3997#endif 3996#endif
3998extern void close_process_descs (void);
3999extern void init_process_emacs (void); 3997extern void init_process_emacs (void);
4000extern void syms_of_process (void); 3998extern void syms_of_process (void);
4001extern void setup_process_coding_systems (Lisp_Object); 3999extern void setup_process_coding_systems (Lisp_Object);
diff --git a/src/lread.c b/src/lread.c
index 2ceeb106653..83d2e8d954a 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -95,9 +95,6 @@ static Lisp_Object Qload_in_progress;
95 It must be set to nil before all top-level calls to read0. */ 95 It must be set to nil before all top-level calls to read0. */
96static Lisp_Object read_objects; 96static Lisp_Object read_objects;
97 97
98/* List of descriptors now open for Fload. */
99static Lisp_Object load_descriptor_list;
100
101/* File for get_file_char to read from. Use by load. */ 98/* File for get_file_char to read from. Use by load. */
102static FILE *instream; 99static FILE *instream;
103 100
@@ -149,7 +146,6 @@ static void readevalloop (Lisp_Object, FILE *, Lisp_Object, bool,
149 Lisp_Object, Lisp_Object, 146 Lisp_Object, Lisp_Object,
150 Lisp_Object, Lisp_Object); 147 Lisp_Object, Lisp_Object);
151static Lisp_Object load_unwind (Lisp_Object); 148static Lisp_Object load_unwind (Lisp_Object);
152static Lisp_Object load_descriptor_unwind (Lisp_Object);
153 149
154/* Functions that read one byte from the current source READCHARFUN 150/* Functions that read one byte from the current source READCHARFUN
155 or unreads one byte. If the integer argument C is -1, it returns 151 or unreads one byte. If the integer argument C is -1, it returns
@@ -1328,11 +1324,8 @@ Return t if the file exists and loads successfully. */)
1328 } 1324 }
1329 1325
1330 record_unwind_protect (load_unwind, make_save_pointer (stream)); 1326 record_unwind_protect (load_unwind, make_save_pointer (stream));
1331 record_unwind_protect (load_descriptor_unwind, load_descriptor_list);
1332 specbind (Qload_file_name, found); 1327 specbind (Qload_file_name, found);
1333 specbind (Qinhibit_file_name_operation, Qnil); 1328 specbind (Qinhibit_file_name_operation, Qnil);
1334 load_descriptor_list
1335 = Fcons (make_number (fileno (stream)), load_descriptor_list);
1336 specbind (Qload_in_progress, Qt); 1329 specbind (Qload_in_progress, Qt);
1337 1330
1338 instream = stream; 1331 instream = stream;
@@ -1395,26 +1388,6 @@ load_unwind (Lisp_Object arg) /* Used as unwind-protect function in load. */
1395 } 1388 }
1396 return Qnil; 1389 return Qnil;
1397} 1390}
1398
1399static Lisp_Object
1400load_descriptor_unwind (Lisp_Object oldlist)
1401{
1402 load_descriptor_list = oldlist;
1403 return Qnil;
1404}
1405
1406/* Close all descriptors in use for Floads.
1407 This is used when starting a subprocess. */
1408
1409void
1410close_load_descs (void)
1411{
1412#ifndef WINDOWSNT
1413 Lisp_Object tail;
1414 for (tail = load_descriptor_list; CONSP (tail); tail = XCDR (tail))
1415 emacs_close (XFASTINT (XCAR (tail)));
1416#endif
1417}
1418 1391
1419static bool 1392static bool
1420complete_filename_p (Lisp_Object pathname) 1393complete_filename_p (Lisp_Object pathname)
@@ -4376,9 +4349,6 @@ init_lread (void)
4376 4349
4377 load_in_progress = 0; 4350 load_in_progress = 0;
4378 Vload_file_name = Qnil; 4351 Vload_file_name = Qnil;
4379
4380 load_descriptor_list = Qnil;
4381
4382 Vstandard_input = Qt; 4352 Vstandard_input = Qt;
4383 Vloads_in_progress = Qnil; 4353 Vloads_in_progress = Qnil;
4384} 4354}
@@ -4651,9 +4621,6 @@ variables, this must be set in the first line of a file. */);
4651 4621
4652 /* Vsource_directory was initialized in init_lread. */ 4622 /* Vsource_directory was initialized in init_lread. */
4653 4623
4654 load_descriptor_list = Qnil;
4655 staticpro (&load_descriptor_list);
4656
4657 DEFSYM (Qcurrent_load_list, "current-load-list"); 4624 DEFSYM (Qcurrent_load_list, "current-load-list");
4658 DEFSYM (Qstandard_input, "standard-input"); 4625 DEFSYM (Qstandard_input, "standard-input");
4659 DEFSYM (Qread_char, "read-char"); 4626 DEFSYM (Qread_char, "read-char");
diff --git a/src/nsterm.m b/src/nsterm.m
index dfb82edd738..074a5adf78c 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -4142,7 +4142,7 @@ ns_term_init (Lisp_Object display_name)
4142 4142
4143 if (selfds[0] == -1) 4143 if (selfds[0] == -1)
4144 { 4144 {
4145 if (pipe (selfds) == -1) 4145 if (pipe2 (selfds, O_CLOEXEC) != 0)
4146 { 4146 {
4147 fprintf (stderr, "Failed to create pipe: %s\n", 4147 fprintf (stderr, "Failed to create pipe: %s\n",
4148 emacs_strerror (errno)); 4148 emacs_strerror (errno));
diff --git a/src/process.c b/src/process.c
index b77fb97168a..cad42470bc1 100644
--- a/src/process.c
+++ b/src/process.c
@@ -135,6 +135,34 @@ extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
135 EMACS_TIME *, void *); 135 EMACS_TIME *, void *);
136#endif 136#endif
137 137
138#ifndef SOCK_CLOEXEC
139# define SOCK_CLOEXEC 0
140
141/* Emulate GNU/Linux accept4 and socket well enough for this module. */
142
143static int
144close_on_exec (int fd)
145{
146 if (0 <= fd)
147 fcntl (fd, F_SETFD, FD_CLOEXEC);
148 return fd;
149}
150
151static int
152accept4 (int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags)
153{
154 return close_on_exec (accept (sockfd, addr, addrlen));
155}
156
157static int
158process_socket (int domain, int type, int protocol)
159{
160 return close_on_exec (socket (domain, type, protocol));
161}
162# undef socket
163# define socket(domain, type, protocol) process_socket (domain, type, protocol)
164#endif
165
138/* Work around GCC 4.7.0 bug with strict overflow checking; see 166/* Work around GCC 4.7.0 bug with strict overflow checking; see
139 <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52904>. 167 <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52904>.
140 These lines can be removed once the GCC bug is fixed. */ 168 These lines can be removed once the GCC bug is fixed. */
@@ -1619,14 +1647,11 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
1619 else 1647 else
1620#endif /* HAVE_PTYS */ 1648#endif /* HAVE_PTYS */
1621 { 1649 {
1622 int tem; 1650 if (pipe2 (sv, O_CLOEXEC) != 0)
1623 tem = pipe (sv);
1624 if (tem < 0)
1625 report_file_error ("Creating pipe", Qnil); 1651 report_file_error ("Creating pipe", Qnil);
1626 inchannel = sv[0]; 1652 inchannel = sv[0];
1627 forkout = sv[1]; 1653 forkout = sv[1];
1628 tem = pipe (sv); 1654 if (pipe2 (sv, O_CLOEXEC) != 0)
1629 if (tem < 0)
1630 { 1655 {
1631 emacs_close (inchannel); 1656 emacs_close (inchannel);
1632 emacs_close (forkout); 1657 emacs_close (forkout);
@@ -1637,29 +1662,14 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
1637 } 1662 }
1638 1663
1639#ifndef WINDOWSNT 1664#ifndef WINDOWSNT
1640 { 1665 if (pipe2 (wait_child_setup, O_CLOEXEC) != 0)
1641 int tem; 1666 report_file_error ("Creating pipe", Qnil);
1642
1643 tem = pipe (wait_child_setup);
1644 if (tem < 0)
1645 report_file_error ("Creating pipe", Qnil);
1646 tem = fcntl (wait_child_setup[1], F_GETFD, 0);
1647 if (tem >= 0)
1648 tem = fcntl (wait_child_setup[1], F_SETFD, tem | FD_CLOEXEC);
1649 if (tem < 0)
1650 {
1651 emacs_close (wait_child_setup[0]);
1652 emacs_close (wait_child_setup[1]);
1653 report_file_error ("Setting file descriptor flags", Qnil);
1654 }
1655 }
1656#endif 1667#endif
1657 1668
1658 fcntl (inchannel, F_SETFL, O_NONBLOCK); 1669 fcntl (inchannel, F_SETFL, O_NONBLOCK);
1659 fcntl (outchannel, F_SETFL, O_NONBLOCK); 1670 fcntl (outchannel, F_SETFL, O_NONBLOCK);
1660 1671
1661 /* Record this as an active process, with its channels. 1672 /* Record this as an active process, with its channels. */
1662 As a result, child_setup will close Emacs's side of the pipes. */
1663 chan_process[inchannel] = process; 1673 chan_process[inchannel] = process;
1664 XPROCESS (process)->infd = inchannel; 1674 XPROCESS (process)->infd = inchannel;
1665 XPROCESS (process)->outfd = outchannel; 1675 XPROCESS (process)->outfd = outchannel;
@@ -3135,7 +3145,8 @@ usage: (make-network-process &rest ARGS) */)
3135 retry_connect: 3145 retry_connect:
3136#endif 3146#endif
3137 3147
3138 s = socket (lres->ai_family, lres->ai_socktype, lres->ai_protocol); 3148 s = socket (lres->ai_family, lres->ai_socktype | SOCK_CLOEXEC,
3149 lres->ai_protocol);
3139 if (s < 0) 3150 if (s < 0)
3140 { 3151 {
3141 xerrno = errno; 3152 xerrno = errno;
@@ -3532,7 +3543,7 @@ format; see the description of ADDRESS in `make-network-process'. */)
3532 int s; 3543 int s;
3533 Lisp_Object res; 3544 Lisp_Object res;
3534 3545
3535 s = socket (AF_INET, SOCK_STREAM, 0); 3546 s = socket (AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
3536 if (s < 0) 3547 if (s < 0)
3537 return Qnil; 3548 return Qnil;
3538 3549
@@ -3688,7 +3699,7 @@ FLAGS is the current flags of the interface. */)
3688 error ("interface name too long"); 3699 error ("interface name too long");
3689 strcpy (rq.ifr_name, SSDATA (ifname)); 3700 strcpy (rq.ifr_name, SSDATA (ifname));
3690 3701
3691 s = socket (AF_INET, SOCK_STREAM, 0); 3702 s = socket (AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
3692 if (s < 0) 3703 if (s < 0)
3693 return Qnil; 3704 return Qnil;
3694 3705
@@ -3984,7 +3995,7 @@ server_accept_connection (Lisp_Object server, int channel)
3984 } saddr; 3995 } saddr;
3985 socklen_t len = sizeof saddr; 3996 socklen_t len = sizeof saddr;
3986 3997
3987 s = accept (channel, &saddr.sa, &len); 3998 s = accept4 (channel, &saddr.sa, &len, SOCK_CLOEXEC);
3988 3999
3989 if (s < 0) 4000 if (s < 0)
3990 { 4001 {
@@ -6858,32 +6869,6 @@ setup_process_coding_systems (Lisp_Object process)
6858#endif 6869#endif
6859} 6870}
6860 6871
6861/* Close all descriptors currently in use for communication
6862 with subprocess. This is used in a newly-forked subprocess
6863 to get rid of irrelevant descriptors. */
6864
6865void
6866close_process_descs (void)
6867{
6868#ifndef DOS_NT
6869 int i;
6870 for (i = 0; i < MAXDESC; i++)
6871 {
6872 Lisp_Object process;
6873 process = chan_process[i];
6874 if (!NILP (process))
6875 {
6876 int in = XPROCESS (process)->infd;
6877 int out = XPROCESS (process)->outfd;
6878 if (in >= 0)
6879 emacs_close (in);
6880 if (out >= 0 && in != out)
6881 emacs_close (out);
6882 }
6883 }
6884#endif
6885}
6886
6887DEFUN ("get-buffer-process", Fget_buffer_process, Sget_buffer_process, 1, 1, 0, 6872DEFUN ("get-buffer-process", Fget_buffer_process, Sget_buffer_process, 1, 1, 0,
6888 doc: /* Return the (or a) process associated with BUFFER. 6873 doc: /* Return the (or a) process associated with BUFFER.
6889BUFFER may be a buffer or the name of one. */) 6874BUFFER may be a buffer or the name of one. */)
diff --git a/src/sysdep.c b/src/sysdep.c
index 91e941a2050..faca7fae461 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -543,8 +543,6 @@ sys_subshell (void)
543#endif 543#endif
544 } 544 }
545 545
546 close_process_descs (); /* Close Emacs's pipes/ptys */
547
548#ifdef MSDOS /* Demacs 1.1.2 91/10/20 Manabu Higashida */ 546#ifdef MSDOS /* Demacs 1.1.2 91/10/20 Manabu Higashida */
549 { 547 {
550 char *epwd = getenv ("PWD"); 548 char *epwd = getenv ("PWD");
@@ -2152,6 +2150,8 @@ emacs_abort (void)
2152#endif 2150#endif
2153 2151
2154/* Open FILE for Emacs use, using open flags OFLAG and mode MODE. 2152/* Open FILE for Emacs use, using open flags OFLAG and mode MODE.
2153 Arrange for subprograms to not inherit the file descriptor.
2154 Prefer a method that is multithread-safe, if available.
2155 Do not fail merely because the open was interrupted by a signal. 2155 Do not fail merely because the open was interrupted by a signal.
2156 Allow the user to quit. */ 2156 Allow the user to quit. */
2157 2157
@@ -2159,8 +2159,11 @@ int
2159emacs_open (const char *file, int oflags, int mode) 2159emacs_open (const char *file, int oflags, int mode)
2160{ 2160{
2161 int fd; 2161 int fd;
2162 oflags |= O_CLOEXEC;
2162 while ((fd = open (file, oflags, mode)) < 0 && errno == EINTR) 2163 while ((fd = open (file, oflags, mode)) < 0 && errno == EINTR)
2163 QUIT; 2164 QUIT;
2165 if (! O_CLOEXEC && 0 <= fd)
2166 fcntl (fd, F_SETFD, FD_CLOEXEC);
2164 return fd; 2167 return fd;
2165} 2168}
2166 2169
@@ -2170,10 +2173,29 @@ emacs_open (const char *file, int oflags, int mode)
2170FILE * 2173FILE *
2171emacs_fopen (char const *file, char const *mode) 2174emacs_fopen (char const *file, char const *mode)
2172{ 2175{
2173 FILE *fp; 2176 int fd, omode, oflags;
2174 while (! (fp = fopen (file, mode)) && errno == EINTR) 2177 int bflag = 0;
2175 QUIT; 2178 char const *m = mode;
2176 return fp; 2179
2180 switch (*m++)
2181 {
2182 case 'r': omode = O_RDONLY; oflags = 0; break;
2183 case 'w': omode = O_WRONLY; oflags = O_CREAT | O_TRUNC; break;
2184 case 'a': omode = O_WRONLY; oflags = O_CREAT | O_APPEND; break;
2185 default: emacs_abort ();
2186 }
2187
2188 while (*m)
2189 switch (*m++)
2190 {
2191 case '+': omode = O_RDWR; break;
2192 case 'b': bflag = O_BINARY; break;
2193 case 't': bflag = O_TEXT; break;
2194 default: /* Ignore. */ break;
2195 }
2196
2197 fd = emacs_open (file, omode | oflags | bflag, 0666);
2198 return fd < 0 ? 0 : fdopen (fd, mode);
2177} 2199}
2178 2200
2179int 2201int
diff --git a/src/w32.c b/src/w32.c
index 230479cd61a..46aebe8b634 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -6719,10 +6719,16 @@ sys_sendto (int s, const char * buf, int len, int flags,
6719} 6719}
6720 6720
6721/* Windows does not have an fcntl function. Provide an implementation 6721/* Windows does not have an fcntl function. Provide an implementation
6722 solely for making sockets non-blocking. */ 6722 good enough for Emacs. */
6723int 6723int
6724fcntl (int s, int cmd, int options) 6724fcntl (int s, int cmd, int options)
6725{ 6725{
6726 /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
6727 invoked in a context where fd1 is closed and all descriptors less
6728 than fd1 are open, so sys_dup is an adequate implementation. */
6729 if (cmd == F_DUPFD_CLOEXEC)
6730 return sys_dup (s);
6731
6726 if (winsock_lib == NULL) 6732 if (winsock_lib == NULL)
6727 { 6733 {
6728 errno = ENETDOWN; 6734 errno = ENETDOWN;
@@ -6864,13 +6870,14 @@ sys_dup2 (int src, int dst)
6864 return rc; 6870 return rc;
6865} 6871}
6866 6872
6867/* Unix pipe() has only one arg */
6868int 6873int
6869sys_pipe (int * phandles) 6874pipe2 (int * phandles, int pipe2_flags)
6870{ 6875{
6871 int rc; 6876 int rc;
6872 unsigned flags; 6877 unsigned flags;
6873 6878
6879 eassert (pipe2_flags == O_CLOEXEC);
6880
6874 /* make pipe handles non-inheritable; when we spawn a child, we 6881 /* make pipe handles non-inheritable; when we spawn a child, we
6875 replace the relevant handle with an inheritable one. Also put 6882 replace the relevant handle with an inheritable one. Also put
6876 pipes into binary mode; we will do text mode translation ourselves 6883 pipes into binary mode; we will do text mode translation ourselves
diff --git a/src/w32.h b/src/w32.h
index 17da0778db1..9c1f1efa699 100644
--- a/src/w32.h
+++ b/src/w32.h
@@ -188,7 +188,7 @@ extern int random (void);
188 188
189extern int fchmod (int, mode_t); 189extern int fchmod (int, mode_t);
190extern int sys_rename_replace (char const *, char const *, BOOL); 190extern int sys_rename_replace (char const *, char const *, BOOL);
191extern int sys_pipe (int *); 191extern int pipe2 (int *, int);
192 192
193extern void set_process_dir (char *); 193extern void set_process_dir (char *);
194extern int sys_spawnve (int, char *, char **, char **); 194extern int sys_spawnve (int, char *, char **, char **);