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/process.c | |
| 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/process.c')
| -rw-r--r-- | src/process.c | 91 |
1 files changed, 38 insertions, 53 deletions
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. */) |