From 73dcdb9f30cb94a3183db54d9b463370c3978d4d Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 13 Nov 2012 20:55:41 -0800 Subject: Use faccessat, not access, when checking file permissions. This fixes a bug that has been present in Emacs since its creation. It was reported by Chris Torek in 1983 even before GNU Emacs existed, which must set some sort of record. (Torek's bug report was against a predecessor of GNU Emacs, but GNU Emacs happened to have the same common flaw.) See Torek's Usenet posting "setuid/setgid programs & Emacs" Article-I.D.: sri-arpa.858 Posted: Fri Apr 8 14:18:56 1983. * .bzrignore: Add lib/fcntl.h. * configure.ac (euidaccess): Remove check; gnulib does this for us now. (gl_FCNTL_O_FLAGS): Define a dummy version. * lib/at-func.c, lib/euidaccess.c, lib/faccessat.c, lib/fcntl.in.h: * lib/getgroups.c, lib/group-member.c, lib/root-uid.h: * lib/xalloc-oversized.h, m4/euidaccess.m4, m4/faccessat.m4: * m4/fcntl_h.m4, m4/getgroups.m4, m4/group-member.m4: New files, from gnulib. * lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate. * admin/merge-gnulib (GNULIB_MODULES): Add faccessat. (GNULIB_TOOL_FLAGS): Avoid at-internal, fchdir, malloc-posix, openat-die, openat-h, save-cwd. Do not avoid fcntl-h. Omit gnulib's m4/fcntl-o.m4. * nt/inc/ms-w32.h (AT_FDCWD, AT_EACCESS): New symbols. (access): Remove. (faccessat): New macro. * src/Makefile.in (LIB_EACCESS): New macro. (LIBES): Use it. * src/callproc.c (init_callproc): * src/charset.c (init_charset): * src/fileio.c (check_existing, check_executable, check_writable) (Ffile_readable_p): * src/lread.c (openp, load_path_check): * src/process.c (allocate_pty): * src/xrdb.c (file_p): Use effective UID when checking permissions, not real UID. * src/callproc.c (init_callproc): * src/charset.c (init_charset): * src/lread.c (load_path_check, init_lread): Test whether directories are accessible, not merely whether they exist. * src/conf_post.h (GNULIB_SUPPORT_ONLY_AT_FDCWD): New macro. * src/fileio.c (check_existing, check_executable, check_writable) (Ffile_readable_p): Use symbolic names instead of integers for the flags, as they're portable now. (check_writable): New arg AMODE. All uses changed. Set errno on failure. (Ffile_readable_p): Use faccessat, not stat + open + close. (Ffile_writable_p): No need to call check_existing + check_writable. Just call check_writable and then look at errno. This saves a syscall. dir should never be nil; replace an unnecessary runtime check with an eassert. When checking the parent directory of a nonexistent file, check that the directory is searchable as well as writable, as we can't create files in unsearchable directories. (file_directory_p): New function, which uses 'stat' on most platforms but faccessat with D_OK (for efficiency) if WINDOWSNT. (Ffile_directory_p, Fset_file_times): Use it. (file_accessible_directory_p): New function, which uses a single syscall for efficiency. (Ffile_accessible_directory_p): Use it. * src/xrdb.c (file_p): Use file_directory_p. * src/lisp.h (file_directory_p, file_accessible_directory_p): New decls. * src/lread.c (openp): When opening a file, use fstat rather than stat, as that avoids a permissions race. When not opening a file, use file_directory_p rather than stat. (dir_warning): First arg is now a usage string, not a format. Use errno. All uses changed. * src/nsterm.m (ns_term_init): Remove unnecessary call to file-readable that merely introduced a race. * src/process.c, src/sysdep.c, src/term.c: All uses of '#ifdef O_NONBLOCK' changed to '#if O_NONBLOCK', to accommodate gnulib O_* style, and similarly for the other O_* flags. * src/w32.c (sys_faccessat): Rename from sys_access and switch to faccessat's API. All uses changed. * src/xrdb.c: Do not include ; no longer needed. (magic_db): Rename from magic_file_p. (magic_db, search_magic_path): Return an XrmDatabase rather than a char *, so that we don't have to test for file existence separately from opening the file for reading. This removes a race fixes a permission-checking problem, and simplifies the code. All uses changed. (file_p): Remove; no longer needed. Fixes: debbugs:12632 --- src/process.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'src/process.c') diff --git a/src/process.c b/src/process.c index 43f0239d301..728abebe758 100644 --- a/src/process.c +++ b/src/process.c @@ -208,7 +208,7 @@ static EMACS_INT update_tick; #ifndef NON_BLOCKING_CONNECT #ifdef HAVE_SELECT #if defined (HAVE_GETPEERNAME) || defined (GNU_LINUX) -#if defined (O_NONBLOCK) || defined (O_NDELAY) +#if O_NONBLOCK || O_NDELAY #if defined (EWOULDBLOCK) || defined (EINPROGRESS) #define NON_BLOCKING_CONNECT #endif /* EWOULDBLOCK || EINPROGRESS */ @@ -655,7 +655,7 @@ allocate_pty (void) PTY_OPEN; #else /* no PTY_OPEN */ { -# ifdef O_NONBLOCK +# if O_NONBLOCK fd = emacs_open (pty_name, O_RDWR | O_NONBLOCK, 0); # else fd = emacs_open (pty_name, O_RDWR | O_NDELAY, 0); @@ -672,7 +672,7 @@ allocate_pty (void) #else sprintf (pty_name, "/dev/tty%c%x", c, i); #endif /* no PTY_TTY_NAME_SPRINTF */ - if (access (pty_name, 6) != 0) + if (faccessat (AT_FDCWD, pty_name, R_OK | W_OK, AT_EACCESS) != 0) { emacs_close (fd); # ifndef __sgi @@ -1624,7 +1624,7 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) #if ! defined (USG) || defined (USG_SUBTTY_WORKS) /* On most USG systems it does not work to open the pty's tty here, then close it and reopen it in the child. */ -#ifdef O_NOCTTY +#if O_NOCTTY /* Don't let this terminal become our controlling terminal (in case we don't have one). */ forkout = forkin = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0); @@ -1678,11 +1678,11 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir) } #endif -#ifdef O_NONBLOCK +#if O_NONBLOCK fcntl (inchannel, F_SETFL, O_NONBLOCK); fcntl (outchannel, F_SETFL, O_NONBLOCK); #else -#ifdef O_NDELAY +#if O_NDELAY fcntl (inchannel, F_SETFL, O_NDELAY); fcntl (outchannel, F_SETFL, O_NDELAY); #endif @@ -1943,7 +1943,7 @@ create_pty (Lisp_Object process) #if ! defined (USG) || defined (USG_SUBTTY_WORKS) /* On most USG systems it does not work to open the pty's tty here, then close it and reopen it in the child. */ -#ifdef O_NOCTTY +#if O_NOCTTY /* Don't let this terminal become our controlling terminal (in case we don't have one). */ int forkout = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0); @@ -1963,11 +1963,11 @@ create_pty (Lisp_Object process) } #endif /* HAVE_PTYS */ -#ifdef O_NONBLOCK +#if O_NONBLOCK fcntl (inchannel, F_SETFL, O_NONBLOCK); fcntl (outchannel, F_SETFL, O_NONBLOCK); #else -#ifdef O_NDELAY +#if O_NDELAY fcntl (inchannel, F_SETFL, O_NDELAY); fcntl (outchannel, F_SETFL, O_NDELAY); #endif @@ -2927,7 +2927,7 @@ usage: (make-network-process &rest ARGS) */) { /* Don't support network sockets when non-blocking mode is not available, since a blocked Emacs is not useful. */ -#if !defined (O_NONBLOCK) && !defined (O_NDELAY) +#if !O_NONBLOCK && !O_NDELAY error ("Network servers not supported"); #else is_server = 1; @@ -3193,7 +3193,7 @@ usage: (make-network-process &rest ARGS) */) #ifdef NON_BLOCKING_CONNECT if (is_non_blocking_client) { -#ifdef O_NONBLOCK +#if O_NONBLOCK ret = fcntl (s, F_SETFL, O_NONBLOCK); #else ret = fcntl (s, F_SETFL, O_NDELAY); @@ -3410,10 +3410,10 @@ usage: (make-network-process &rest ARGS) */) chan_process[inch] = proc; -#ifdef O_NONBLOCK +#if O_NONBLOCK fcntl (inch, F_SETFL, O_NONBLOCK); #else -#ifdef O_NDELAY +#if O_NDELAY fcntl (inch, F_SETFL, O_NDELAY); #endif #endif @@ -4145,10 +4145,10 @@ server_accept_connection (Lisp_Object server, int channel) chan_process[s] = proc; -#ifdef O_NONBLOCK +#if O_NONBLOCK fcntl (s, F_SETFL, O_NONBLOCK); #else -#ifdef O_NDELAY +#if O_NDELAY fcntl (s, F_SETFL, O_NDELAY); #endif #endif @@ -4849,11 +4849,11 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, #endif /* ISC 4.1 defines both EWOULDBLOCK and O_NONBLOCK, and Emacs uses O_NONBLOCK, so what we get is EAGAIN. */ -#ifdef O_NONBLOCK +#if O_NONBLOCK else if (nread == -1 && errno == EAGAIN) ; #else -#ifdef O_NDELAY +#if O_NDELAY else if (nread == -1 && errno == EAGAIN) ; /* Note that we cannot distinguish between no input @@ -7348,7 +7348,7 @@ init_process_emacs (void) #ifdef HAVE_GETSOCKNAME ADD_SUBFEATURE (QCservice, Qt); #endif -#if defined (O_NONBLOCK) || defined (O_NDELAY) +#if O_NONBLOCK || O_NDELAY ADD_SUBFEATURE (QCserver, Qt); #endif -- cgit v1.3 From 3d082a269ece18058ed82957f8a056822b39789e Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Fri, 16 Nov 2012 07:29:22 -0800 Subject: Remove no-longer-used pty_max_bytes variable. * configure.ac (fpathconf): Remove unnecessary check. * admin/CPP-DEFINES (HAVE_FPATHCONF): Remove. * src/process.c (pty_max_bytes): Remove; unused. (send_process): Do not set it. --- ChangeLog | 5 +++++ admin/CPP-DEFINES | 1 - admin/ChangeLog | 5 +++++ configure.ac | 2 +- src/ChangeLog | 6 ++++++ src/process.c | 16 ---------------- 6 files changed, 17 insertions(+), 18 deletions(-) (limited to 'src/process.c') diff --git a/ChangeLog b/ChangeLog index f5f649aae6d..1e5bf54a897 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-11-16 Paul Eggert + + Remove no-longer-used pty_max_bytes variable. + * configure.ac (fpathconf): Remove unnecessary check. + 2012-11-14 Paul Eggert Use faccessat, not access, when checking file permissions (Bug#12632). diff --git a/admin/CPP-DEFINES b/admin/CPP-DEFINES index 0a4c14cb95c..17c56dc7e9e 100644 --- a/admin/CPP-DEFINES +++ b/admin/CPP-DEFINES @@ -152,7 +152,6 @@ HAVE_ENVIRON_DECL HAVE_EUIDACCESS HAVE_FCNTL_H HAVE_FORK -HAVE_FPATHCONF HAVE_FREEIFADDRS HAVE_FREETYPE HAVE_FSEEKO diff --git a/admin/ChangeLog b/admin/ChangeLog index fd28bf1228f..4eb413e948f 100644 --- a/admin/ChangeLog +++ b/admin/ChangeLog @@ -1,3 +1,8 @@ +2012-11-16 Paul Eggert + + Remove no-longer-used pty_max_bytes variable. + * CPP-DEFINES (HAVE_FPATHCONF): Remove. + 2012-11-14 Paul Eggert Use faccessat, not access, when checking file permissions (Bug#12632). diff --git a/configure.ac b/configure.ac index b0c81a23f8a..937c645bb58 100644 --- a/configure.ac +++ b/configure.ac @@ -2874,7 +2874,7 @@ AC_SUBST(BLESSMAIL_TARGET) AC_CHECK_FUNCS(gethostname \ closedir getrusage get_current_dir_name \ lrand48 \ -fpathconf select getpagesize setlocale \ +select getpagesize setlocale \ utimes getrlimit setrlimit getcwd shutdown getaddrinfo \ strsignal setitimer \ sendto recvfrom getsockname getpeername getifaddrs freeifaddrs \ diff --git a/src/ChangeLog b/src/ChangeLog index 8caaa2f68e0..c9c754f8677 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,9 @@ +2012-11-16 Paul Eggert + + Remove no-longer-used pty_max_bytes variable. + * process.c (pty_max_bytes): Remove; unused. + (send_process): Do not set it. + 2012-11-15 Juanma Barranquero * makefile.w32-in ($(BLD)/dispnew.$(O), $(BLD)/emacs.$(O)): diff --git a/src/process.c b/src/process.c index 728abebe758..785282fba36 100644 --- a/src/process.c +++ b/src/process.c @@ -340,9 +340,6 @@ static struct sockaddr_and_len { #define DATAGRAM_CONN_P(proc) (0) #endif -/* Maximum number of bytes to send to a pty without an eof. */ -static int pty_max_bytes; - /* These setters are used only in this file, so they can be private. */ static void pset_buffer (struct Lisp_Process *p, Lisp_Object val) @@ -5532,19 +5529,6 @@ send_process (Lisp_Object proc, const char *buf, ptrdiff_t len, buf = SSDATA (object); } - if (pty_max_bytes == 0) - { -#if defined (HAVE_FPATHCONF) && defined (_PC_MAX_CANON) - pty_max_bytes = fpathconf (p->outfd, _PC_MAX_CANON); - if (pty_max_bytes < 0) - pty_max_bytes = 250; -#else - pty_max_bytes = 250; -#endif - /* Deduct one, to leave space for the eof. */ - pty_max_bytes--; - } - /* If there is already data in the write_queue, put the new data in the back of queue. Otherwise, ignore it. */ if (!NILP (p->write_queue)) -- cgit v1.3 From 22bae83fa8c432780fe20202a660aa8c84f3087a Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 17 Nov 2012 18:46:45 +0200 Subject: Fix bug #12829 with aborts on MS-Windows when several child processes die. nt/inc/sys/wait.h: New file, with prototype of waitpid and definitions of macros it needs. nt/inc/ms-w32.h (wait): Don't define, 'wait' is not used anymore. (sys_wait): Remove prototype. nt/config.nt (HAVE_SYS_WAIT_H): Define to 1. src/w32proc.c (create_child): Don't clip the PID of the child process to fit into an Emacs integer, as this is no longer a restriction. (waitpid): Rename from sys_wait. Emulate a Posix 'waitpid' by reaping only the process specified by PID argument, if that is positive. Use PID instead of dead_child to know which process to reap. Wait for the child to die only if WNOHANG is not in OPTIONS. (sys_select): Don't set dead_child. src/sysdep.c (wait_for_termination_1): Remove the WINDOWSNT portion, as it is no longer needed. src/process.c (waitpid, WUNTRACED) [!WNOHANG]: Remove definitions, no longer needed. (record_child_status_change): Remove the setting of record_at_most_one_child for the !WNOHANG case. --- nt/ChangeLog | 10 +++++ nt/config.nt | 2 +- nt/inc/ms-w32.h | 3 -- nt/inc/sys/wait.h | 33 ++++++++++++++ src/ChangeLog | 20 +++++++++ src/process.c | 20 --------- src/sysdep.c | 7 +-- src/w32proc.c | 127 ++++++++++++++++++++++++++++++++++++++---------------- 8 files changed, 156 insertions(+), 66 deletions(-) create mode 100644 nt/inc/sys/wait.h (limited to 'src/process.c') diff --git a/nt/ChangeLog b/nt/ChangeLog index aa690e5d75f..b24acae8be5 100644 --- a/nt/ChangeLog +++ b/nt/ChangeLog @@ -1,3 +1,13 @@ +2012-11-17 Eli Zaretskii + + * inc/sys/wait.h: New file, with prototype of waitpid and + definitions of macros it needs. + + * inc/ms-w32.h (wait): Don't define, 'wait' is not used anymore. + (sys_wait): Remove prototype. + + * config.nt (HAVE_SYS_WAIT_H): Define to 1. + 2012-11-17 Dani Moncayo * zipdist.bat (ZIP_CHECK): Remove unused label. When invoking 7z diff --git a/nt/config.nt b/nt/config.nt index 69549fb2087..638f0a7461b 100644 --- a/nt/config.nt +++ b/nt/config.nt @@ -986,7 +986,7 @@ along with GNU Emacs. If not, see . */ #undef HAVE_SYS_VLIMIT_H /* Define to 1 if you have that is POSIX.1 compatible. */ -#undef HAVE_SYS_WAIT_H +#define HAVE_SYS_WAIT_H 1 /* Define to 1 if you have the header file. */ #undef HAVE_TERM_H diff --git a/nt/inc/ms-w32.h b/nt/inc/ms-w32.h index 1b2a309e1be..7b16ccab069 100644 --- a/nt/inc/ms-w32.h +++ b/nt/inc/ms-w32.h @@ -183,15 +183,12 @@ extern char *getenv (); /* Subprocess calls that are emulated. */ #define spawnve sys_spawnve -#define wait sys_wait #define kill sys_kill #define signal sys_signal /* Internal signals. */ #define emacs_raise(sig) emacs_abort() -extern int sys_wait (int *); - /* termcap.c calls that are emulated. */ #define tputs sys_tputs #define tgetstr sys_tgetstr diff --git a/nt/inc/sys/wait.h b/nt/inc/sys/wait.h new file mode 100644 index 00000000000..8d890c9e175 --- /dev/null +++ b/nt/inc/sys/wait.h @@ -0,0 +1,33 @@ +/* A limited emulation of sys/wait.h on Posix systems. + +Copyright (C) 2012 Free Software Foundation, Inc. + +This file is part of GNU Emacs. + +GNU Emacs is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs. If not, see . */ + +#ifndef INC_SYS_WAIT_H_ +#define INC_SYS_WAIT_H_ + +#define WNOHANG 1 +#define WUNTRACED 2 +#define WSTOPPED 2 /* same as WUNTRACED */ +#define WEXITED 4 +#define WCONTINUED 8 + +/* The various WIF* macros are defined in src/syswait.h. */ + +extern pid_t waitpid (pid_t, int *, int); + +#endif /* INC_SYS_WAIT_H_ */ diff --git a/src/ChangeLog b/src/ChangeLog index 1194fe099fa..45d48ba41cc 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,23 @@ +2012-11-17 Eli Zaretskii + + * w32proc.c (create_child): Don't clip the PID of the child + process to fit into an Emacs integer, as this is no longer a + restriction. + (waitpid): Rename from sys_wait. Emulate a Posix 'waitpid' by + reaping only the process specified by PID argument, if that is + positive. Use PID instead of dead_child to know which process to + reap. Wait for the child to die only if WNOHANG is not in + OPTIONS. + (sys_select): Don't set dead_child. + + * sysdep.c (wait_for_termination_1): Remove the WINDOWSNT portion, + as it is no longer needed. + + * process.c (waitpid, WUNTRACED) [!WNOHANG]: Remove definitions, + no longer needed. + (record_child_status_change): Remove the setting of + record_at_most_one_child for the !WNOHANG case. + 2012-11-17 Paul Eggert Fix problems in ns port found by static checking. diff --git a/src/process.c b/src/process.c index 785282fba36..5fe6a6540f3 100644 --- a/src/process.c +++ b/src/process.c @@ -130,18 +130,6 @@ extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *, EMACS_TIME *, void *); #endif -/* This is for DOS_NT ports. FIXME: Remove this old portability cruft - by having DOS_NT ports implement waitpid instead of wait. Nowadays - POSIXish hosts all define waitpid, WNOHANG, and WUNTRACED, as these - have been standard since POSIX.1-1988. */ -#ifndef WNOHANG -# undef waitpid -# define waitpid(pid, status, options) wait (status) -#endif -#ifndef WUNTRACED -# define WUNTRACED 0 -#endif - /* Work around GCC 4.7.0 bug with strict overflow checking; see . These lines can be removed once the GCC bug is fixed. */ @@ -6295,17 +6283,9 @@ record_child_status_change (pid_t pid, int w) { #ifdef SIGCHLD -# ifdef WNOHANG /* On POSIXish hosts, record at most one child only if we already know one child that has exited. */ bool record_at_most_one_child = 0 <= pid; -# else - /* On DOS_NT (the only porting target that lacks WNOHANG), - record the status of at most one child process, since the SIGCHLD - handler must return right away. If any more processes want to - signal us, we will get another signal. */ - bool record_at_most_one_child = 1; -# endif Lisp_Object tail; diff --git a/src/sysdep.c b/src/sysdep.c index a7f3de2f1b1..06dc41b511e 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -289,10 +289,6 @@ wait_for_termination_1 (pid_t pid, int interruptible) { while (1) { -#ifdef WINDOWSNT - wait (0); - break; -#else /* not WINDOWSNT */ int status; int wait_result = waitpid (pid, &status, 0); if (wait_result < 0) @@ -306,7 +302,8 @@ wait_for_termination_1 (pid_t pid, int interruptible) break; } -#endif /* not WINDOWSNT */ + /* Note: the MS-Windows emulation of waitpid calls QUIT + internally. */ if (interruptible) QUIT; } diff --git a/src/w32proc.c b/src/w32proc.c index 10dd23003b8..fd6a498290a 100644 --- a/src/w32proc.c +++ b/src/w32proc.c @@ -789,7 +789,6 @@ alarm (int seconds) /* Child process management list. */ int child_proc_count = 0; child_process child_procs[ MAX_CHILDREN ]; -child_process *dead_child = NULL; static DWORD WINAPI reader_thread (void *arg); @@ -1042,9 +1041,6 @@ create_child (char *exe, char *cmdline, char *env, int is_gui_app, if (cp->pid < 0) cp->pid = -cp->pid; - /* pid must fit in a Lisp_Int */ - cp->pid = cp->pid & INTMASK; - *pPid = cp->pid; return TRUE; @@ -1120,55 +1116,110 @@ reap_subprocess (child_process *cp) delete_child (cp); } -/* Wait for any of our existing child processes to die - When it does, close its handle - Return the pid and fill in the status if non-NULL. */ +/* Wait for a child process specified by PID, or for any of our + existing child processes (if PID is nonpositive) to die. When it + does, close its handle. Return the pid of the process that died + and fill in STATUS if non-NULL. */ -int -sys_wait (int *status) +pid_t +waitpid (pid_t pid, int *status, int options) { DWORD active, retval; int nh; - int pid; child_process *cp, *cps[MAX_CHILDREN]; HANDLE wait_hnd[MAX_CHILDREN]; + DWORD timeout_ms; + int dont_wait = (options & WNOHANG) != 0; nh = 0; - if (dead_child != NULL) + /* According to Posix: + + PID = -1 means status is requested for any child process. + + PID > 0 means status is requested for a single child process + whose pid is PID. + + PID = 0 means status is requested for any child process whose + process group ID is equal to that of the calling process. But + since Windows has only a limited support for process groups (only + for console processes and only for the purposes of passing + Ctrl-BREAK signal to them), and since we have no documented way + of determining whether a given process belongs to our group, we + treat 0 as -1. + + PID < -1 means status is requested for any child process whose + process group ID is equal to the absolute value of PID. Again, + since we don't support process groups, we treat that as -1. */ + if (pid > 0) { - /* We want to wait for a specific child */ - wait_hnd[nh] = dead_child->procinfo.hProcess; - cps[nh] = dead_child; - if (!wait_hnd[nh]) emacs_abort (); - nh++; - active = 0; - goto get_result; + int our_child = 0; + + /* We are requested to wait for a specific child. */ + for (cp = child_procs + (child_proc_count-1); cp >= child_procs; cp--) + { + /* Some child_procs might be sockets; ignore them. Also + ignore subprocesses whose output is not yet completely + read. */ + if (CHILD_ACTIVE (cp) + && cp->procinfo.hProcess + && cp->pid == pid) + { + our_child = 1; + break; + } + } + if (our_child) + { + if (cp->fd < 0 || (fd_info[cp->fd].flags & FILE_AT_EOF) != 0) + { + wait_hnd[nh] = cp->procinfo.hProcess; + cps[nh] = cp; + nh++; + } + else if (dont_wait) + { + /* PID specifies our subprocess, but its status is not + yet available. */ + return 0; + } + } + if (nh == 0) + { + /* No such child process, or nothing to wait for, so fail. */ + errno = ECHILD; + return -1; + } } else { for (cp = child_procs + (child_proc_count-1); cp >= child_procs; cp--) - /* some child_procs might be sockets; ignore them */ - if (CHILD_ACTIVE (cp) && cp->procinfo.hProcess - && (cp->fd < 0 || (fd_info[cp->fd].flags & FILE_AT_EOF) != 0)) - { - wait_hnd[nh] = cp->procinfo.hProcess; - cps[nh] = cp; - nh++; - } + { + if (CHILD_ACTIVE (cp) + && cp->procinfo.hProcess + && (cp->fd < 0 || (fd_info[cp->fd].flags & FILE_AT_EOF) != 0)) + { + wait_hnd[nh] = cp->procinfo.hProcess; + cps[nh] = cp; + nh++; + } + } + if (nh == 0) + { + /* Nothing to wait on, so fail. */ + errno = ECHILD; + return -1; + } } - if (nh == 0) - { - /* Nothing to wait on, so fail */ - errno = ECHILD; - return -1; - } + if (dont_wait) + timeout_ms = 0; + else + timeout_ms = 1000; /* check for quit about once a second. */ do { - /* Check for quit about once a second. */ QUIT; - active = WaitForMultipleObjects (nh, wait_hnd, FALSE, 1000); + active = WaitForMultipleObjects (nh, wait_hnd, FALSE, timeout_ms); } while (active == WAIT_TIMEOUT); if (active == WAIT_FAILED) @@ -1198,8 +1249,10 @@ get_result: } if (retval == STILL_ACTIVE) { - /* Should never happen */ + /* Should never happen. */ DebPrint (("Wait.WaitForMultipleObjects returned an active process\n")); + if (pid > 0 && dont_wait) + return 0; errno = EINVAL; return -1; } @@ -1213,6 +1266,8 @@ get_result: else retval <<= 8; + if (pid > 0 && active != 0) + emacs_abort (); cp = cps[active]; pid = cp->pid; #ifdef FULL_DEBUG @@ -2001,9 +2056,7 @@ count_children: DebPrint (("select calling SIGCHLD handler for pid %d\n", cp->pid)); #endif - dead_child = cp; sig_handlers[SIGCHLD] (SIGCHLD); - dead_child = NULL; } } else if (fdindex[active] == -1) -- cgit v1.3