diff options
| author | Paul Eggert | 2013-07-07 11:00:14 -0700 |
|---|---|---|
| committer | Paul Eggert | 2013-07-07 11:00:14 -0700 |
| commit | 067428c1717acd28f205c2cff93f0583eb347f4c (patch) | |
| tree | 5937b119187f9900840e2c1174b408e86bb8d12b /src | |
| parent | 9aff9b3864085addb02b699f9648e547a8c00e54 (diff) | |
| download | emacs-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
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 38 | ||||
| -rw-r--r-- | src/alloc.c | 2 | ||||
| -rw-r--r-- | src/callproc.c | 21 | ||||
| -rw-r--r-- | src/emacs.c | 7 | ||||
| -rw-r--r-- | src/filelock.c | 15 | ||||
| -rw-r--r-- | src/lisp.h | 2 | ||||
| -rw-r--r-- | src/lread.c | 33 | ||||
| -rw-r--r-- | src/nsterm.m | 2 | ||||
| -rw-r--r-- | src/process.c | 91 | ||||
| -rw-r--r-- | src/sysdep.c | 34 | ||||
| -rw-r--r-- | src/w32.c | 13 | ||||
| -rw-r--r-- | src/w32.h | 2 |
12 files changed, 140 insertions, 120 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 069d39ce6be..07285d564b2 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,41 @@ | |||
| 1 | 2013-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 | |||
| 1 | 2013-07-07 Jan Djärv <jan.h.d@swipnet.se> | 39 | 2013-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); | |||
| 3668 | extern void map_obarray (Lisp_Object, void (*) (Lisp_Object, Lisp_Object), | 3668 | extern void map_obarray (Lisp_Object, void (*) (Lisp_Object, Lisp_Object), |
| 3669 | Lisp_Object); | 3669 | Lisp_Object); |
| 3670 | extern void dir_warning (const char *, Lisp_Object); | 3670 | extern void dir_warning (const char *, Lisp_Object); |
| 3671 | extern void close_load_descs (void); | ||
| 3672 | extern void init_obarray (void); | 3671 | extern void init_obarray (void); |
| 3673 | extern void init_lread (void); | 3672 | extern void init_lread (void); |
| 3674 | extern void syms_of_lread (void); | 3673 | extern void syms_of_lread (void); |
| @@ -3995,7 +3994,6 @@ extern void delete_keyboard_wait_descriptor (int); | |||
| 3995 | extern void add_gpm_wait_descriptor (int); | 3994 | extern void add_gpm_wait_descriptor (int); |
| 3996 | extern void delete_gpm_wait_descriptor (int); | 3995 | extern void delete_gpm_wait_descriptor (int); |
| 3997 | #endif | 3996 | #endif |
| 3998 | extern void close_process_descs (void); | ||
| 3999 | extern void init_process_emacs (void); | 3997 | extern void init_process_emacs (void); |
| 4000 | extern void syms_of_process (void); | 3998 | extern void syms_of_process (void); |
| 4001 | extern void setup_process_coding_systems (Lisp_Object); | 3999 | extern 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. */ |
| 96 | static Lisp_Object read_objects; | 96 | static Lisp_Object read_objects; |
| 97 | 97 | ||
| 98 | /* List of descriptors now open for Fload. */ | ||
| 99 | static 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. */ |
| 102 | static FILE *instream; | 99 | static 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); |
| 151 | static Lisp_Object load_unwind (Lisp_Object); | 148 | static Lisp_Object load_unwind (Lisp_Object); |
| 152 | static 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 | |||
| 1399 | static Lisp_Object | ||
| 1400 | load_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 | |||
| 1409 | void | ||
| 1410 | close_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 | ||
| 1419 | static bool | 1392 | static bool |
| 1420 | complete_filename_p (Lisp_Object pathname) | 1393 | complete_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 | |||
| 143 | static int | ||
| 144 | close_on_exec (int fd) | ||
| 145 | { | ||
| 146 | if (0 <= fd) | ||
| 147 | fcntl (fd, F_SETFD, FD_CLOEXEC); | ||
| 148 | return fd; | ||
| 149 | } | ||
| 150 | |||
| 151 | static int | ||
| 152 | accept4 (int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) | ||
| 153 | { | ||
| 154 | return close_on_exec (accept (sockfd, addr, addrlen)); | ||
| 155 | } | ||
| 156 | |||
| 157 | static int | ||
| 158 | process_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 | |||
| 6865 | void | ||
| 6866 | close_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 | |||
| 6887 | DEFUN ("get-buffer-process", Fget_buffer_process, Sget_buffer_process, 1, 1, 0, | 6872 | DEFUN ("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. |
| 6889 | BUFFER may be a buffer or the name of one. */) | 6874 | BUFFER 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 | |||
| 2159 | emacs_open (const char *file, int oflags, int mode) | 2159 | emacs_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) | |||
| 2170 | FILE * | 2173 | FILE * |
| 2171 | emacs_fopen (char const *file, char const *mode) | 2174 | emacs_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 | ||
| 2179 | int | 2201 | int |
| @@ -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. */ |
| 6723 | int | 6723 | int |
| 6724 | fcntl (int s, int cmd, int options) | 6724 | fcntl (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 */ | ||
| 6868 | int | 6873 | int |
| 6869 | sys_pipe (int * phandles) | 6874 | pipe2 (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 |
| @@ -188,7 +188,7 @@ extern int random (void); | |||
| 188 | 188 | ||
| 189 | extern int fchmod (int, mode_t); | 189 | extern int fchmod (int, mode_t); |
| 190 | extern int sys_rename_replace (char const *, char const *, BOOL); | 190 | extern int sys_rename_replace (char const *, char const *, BOOL); |
| 191 | extern int sys_pipe (int *); | 191 | extern int pipe2 (int *, int); |
| 192 | 192 | ||
| 193 | extern void set_process_dir (char *); | 193 | extern void set_process_dir (char *); |
| 194 | extern int sys_spawnve (int, char *, char **, char **); | 194 | extern int sys_spawnve (int, char *, char **, char **); |