wez Wed Jan 15 13:54:04 2003 EDT Added files: /php4/ext/standard proc_open.h
Modified files: /php4/ext/standard basic_functions.c exec.h proc_open.c /php4/ext/standard/tests/general_functions proc_open.phpt Log: Relieve scripts of the burden of ensuring that all pipes are closed prior to calling proc_close(). Implement proc_get_status(resource $process) which returns an array of information about a process created with proc_open(). The information includes: array( "command" => string "name of the command", "pid" => long process identifier, "running" => bool true if the process is still running "exitcode" => long exitcode if the process exited "signaled" => bool true if the process was signaled "termsig" => long signal number if signaled "stopped" => bool true if the process is stopped "stopsig" => long signal number if stopped );
Index: php4/ext/standard/basic_functions.c diff -u php4/ext/standard/basic_functions.c:1.561 php4/ext/standard/basic_functions.c:1.562 --- php4/ext/standard/basic_functions.c:1.561 Wed Jan 15 11:29:00 2003 +++ php4/ext/standard/basic_functions.c Wed Jan 15 13:54:02 2003 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: basic_functions.c,v 1.561 2003/01/15 16:29:00 wez Exp $ */ +/* $Id: basic_functions.c,v 1.562 2003/01/15 18:54:02 wez Exp $ */ #include "php.h" #include "php_streams.h" @@ -414,6 +414,7 @@ #ifdef PHP_CAN_SUPPORT_PROC_OPEN PHP_FE(proc_open, third_arg_force_ref) PHP_FE(proc_close, NULL) + PHP_FE(proc_get_status, + NULL) #endif PHP_FE(rand, NULL) Index: php4/ext/standard/exec.h diff -u php4/ext/standard/exec.h:1.16 php4/ext/standard/exec.h:1.17 --- php4/ext/standard/exec.h:1.16 Tue Dec 31 11:07:38 2002 +++ php4/ext/standard/exec.h Wed Jan 15 13:54:03 2003 @@ -16,7 +16,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: exec.h,v 1.16 2002/12/31 16:07:38 sebastian Exp $ */ +/* $Id: exec.h,v 1.17 2003/01/15 18:54:03 wez Exp $ */ #ifndef EXEC_H #define EXEC_H @@ -28,6 +28,7 @@ PHP_FUNCTION(passthru); PHP_FUNCTION(shell_exec); PHP_FUNCTION(proc_open); +PHP_FUNCTION(proc_get_status); PHP_FUNCTION(proc_close); PHP_MINIT_FUNCTION(proc_open); Index: php4/ext/standard/proc_open.c diff -u php4/ext/standard/proc_open.c:1.1 php4/ext/standard/proc_open.c:1.2 --- php4/ext/standard/proc_open.c:1.1 Wed Jan 15 11:29:00 2003 +++ php4/ext/standard/proc_open.c Wed Jan 15 13:54:03 2003 @@ -12,10 +12,10 @@ | obtain it through the world-wide-web, please send a note to | | [EMAIL PROTECTED] so we can mail you a copy immediately. | +----------------------------------------------------------------------+ - | Author: Wez Furlong | + | Author: Wez Furlong <[EMAIL PROTECTED]> | +----------------------------------------------------------------------+ */ -/* $Id: proc_open.c,v 1.1 2003/01/15 16:29:00 wez Exp $ */ +/* $Id: proc_open.c,v 1.2 2003/01/15 18:54:03 wez Exp $ */ #include <stdio.h> #include "php.h" @@ -52,27 +52,39 @@ * */ #ifdef PHP_CAN_SUPPORT_PROC_OPEN +#include "proc_open.h" + static int le_proc_open; static void proc_open_rsrc_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) { + struct php_process_handle *proc = (struct php_process_handle*)rsrc->ptr; + int i; #ifdef PHP_WIN32 - HANDLE child; DWORD wstatus; +#elif HAVE_SYS_WAIT_H + int wstatus; + pid_t wait_pid; +#endif + + /* Close all handles to avoid a deadlock */ + for (i = 0; i < proc->npipes; i++) { + if (proc->pipes[i] != 0) { + zend_list_delete(proc->pipes[i]); + proc->pipes[i] = 0; + } + } - child = (HANDLE)rsrc->ptr; - WaitForSingleObject(child, INFINITE); - GetExitCodeProcess(child, &wstatus); +#ifdef PHP_WIN32 + + WaitForSingleObject(proc->child, INFINITE); + GetExitCodeProcess(proc->child, &wstatus); FG(pclose_ret) = wstatus; -#else -# if HAVE_SYS_WAIT_H - int wstatus; - pid_t child, wait_pid; - child = (pid_t)rsrc->ptr; - +#elif HAVE_SYS_WAIT_H + do { - wait_pid = waitpid(child, &wstatus, 0); + wait_pid = waitpid(proc->child, &wstatus, 0); } while (wait_pid == -1 && errno == EINTR); if (wait_pid == -1) @@ -83,20 +95,23 @@ FG(pclose_ret) = wstatus; } -# else +#else FG(pclose_ret) = -1; -# endif #endif + + pefree(proc->command, proc->is_persistent); + pefree(proc, proc->is_persistent); + } /* {{{ php_make_safe_mode_command */ -static int php_make_safe_mode_command(char *cmd, char **safecmd TSRMLS_DC) +static int php_make_safe_mode_command(char *cmd, char **safecmd, int is_persistent +TSRMLS_DC) { int lcmd, larg0, ldir, len, overflow_limit; char *space, *sep, *arg0; if (!PG(safe_mode)) { - *safecmd = estrdup(cmd); + *safecmd = pestrdup(cmd, is_persistent); return SUCCESS; } @@ -140,7 +155,12 @@ efree(arg0); arg0 = php_escape_shell_cmd(*safecmd); efree(*safecmd); - *safecmd = arg0; + if (is_persistent) { + *safecmd = pestrdup(arg0, 1); + efree(arg0); + } else { + *safecmd = arg0; + } return SUCCESS; } @@ -158,23 +178,85 @@ close a process opened by proc_open */ PHP_FUNCTION(proc_close) { - zval *proc; - void *child; + zval *zproc; + struct php_process_handle *proc; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &proc) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zproc) == FAILURE) { RETURN_FALSE; } - ZEND_FETCH_RESOURCE(child, void *, &proc, -1, "process", le_proc_open); + ZEND_FETCH_RESOURCE(proc, struct php_process_handle *, &zproc, -1, "process", +le_proc_open); - zend_list_delete(Z_LVAL_P(proc)); + zend_list_delete(Z_LVAL_P(zproc)); RETURN_LONG(FG(pclose_ret)); } /* }}} */ +/* {{{ proto array proc_get_status(resource process) + get information about a process opened by proc_open */ +PHP_FUNCTION(proc_get_status) +{ + zval *zproc; + struct php_process_handle *proc; +#ifdef PHP_WIN32 + DWORD wstatus; +#elif HAVE_SYS_WAIT_H + int wstatus; + pid_t wait_pid; +#endif + int running = 1, signaled = 0, stopped = 0; + int exitcode = -1, termsig = 0, stopsig = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zproc) == FAILURE) { + RETURN_FALSE; + } + + ZEND_FETCH_RESOURCE(proc, struct php_process_handle *, &zproc, -1, "process", +le_proc_open); + + array_init(return_value); + + add_assoc_string(return_value, "command", proc->command, 1); + add_assoc_long(return_value, "pid", proc->child); + +#ifdef PHP_WIN32 + + GetExitCodeProcess(proc->child, &wstatus); + + running = wstatus == STILL_ACTIVE; + exitcode == STILL_ACTIVE ? -1 : wstatus; + +#elif HAVE_SYS_WAIT_H + + errno = 0; + wait_pid = waitpid(proc->child, &wstatus, WNOHANG|WUNTRACED); + + if (wait_pid == proc->child) { + if (WIFEXITED(wstatus)) { + running = 0; + exitcode = WEXITSTATUS(wstatus); + } + if (WIFSIGNALED(wstatus)) { + signaled = 1; + termsig = WTERMSIG(wstatus); + } + if (WIFSTOPPED(wstatus)) { + stopped = 1; + stopsig = WSTOPSIG(wstatus); + } + } +#endif + + add_assoc_bool(return_value, "running", running); + add_assoc_bool(return_value, "signaled", signaled); + add_assoc_bool(return_value, "stopped", stopped); + add_assoc_long(return_value, "exitcode", exitcode); + add_assoc_long(return_value, "termsig", termsig); + add_assoc_long(return_value, "stopsig", stopsig); +} +/* }}} */ + /* {{{ handy definitions for portability/readability */ #ifdef PHP_WIN32 -typedef HANDLE descriptor_t; # define pipe(pair) (CreatePipe(&pair[0], &pair[1], &security, 2048L) ? 0 : -1) # define COMSPEC_NT "cmd.exe" @@ -197,9 +279,7 @@ # define close_descriptor(fd) CloseHandle(fd) #else -typedef int descriptor_t; # define close_descriptor(fd) close(fd) - #endif #define DESC_PIPE 1 @@ -208,7 +288,7 @@ struct php_proc_open_descriptor_item { int index; /* desired fd number in child process */ - descriptor_t parentend, childend; /* fds for pipes in parent/child */ + php_file_descriptor_t parentend, childend; /* fds for pipes in +parent/child */ int mode; /* mode for proc_open code */ int mode_flags; /* mode flags for opening fds */ }; @@ -218,7 +298,6 @@ Run a process with more control over it's file descriptors */ PHP_FUNCTION(proc_open) { -#define MAX_DESCRIPTORS 16 char *command; long command_len; @@ -228,24 +307,24 @@ int i; zval **descitem = NULL; HashPosition pos; - struct php_proc_open_descriptor_item descriptors[MAX_DESCRIPTORS]; + struct php_proc_open_descriptor_item +descriptors[PHP_PROC_OPEN_MAX_DESCRIPTORS]; #ifdef PHP_WIN32 PROCESS_INFORMATION pi; STARTUPINFO si; BOOL newprocok; - HANDLE child; SECURITY_ATTRIBUTES security; char *command_with_cmd; -#else - pid_t child; #endif + php_process_id_t child; + struct php_process_handle *proc; + int is_persistent = 0; /* TODO: ensure that persistent procs will work */ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "saz/", &command, &command_len, &descriptorspec, &pipes) == FAILURE) { RETURN_FALSE; } - if (FAILURE == php_make_safe_mode_command(command, &command TSRMLS_CC)) { + if (FAILURE == php_make_safe_mode_command(command, &command, is_persistent +TSRMLS_CC)) { RETURN_FALSE; } @@ -317,7 +396,7 @@ } if (strcmp(Z_STRVAL_PP(ztype), "pipe") == 0) { - descriptor_t newpipe[2]; + php_file_descriptor_t newpipe[2]; zval **zmode; if (zend_hash_index_find(Z_ARRVAL_PP(descitem), 1, (void **)&zmode) == SUCCESS) { @@ -358,7 +437,6 @@ zval **zfile, **zmode; int fd; php_stream *stream; - size_t old_size = FG(def_chunk_size); descriptors[ndesc].mode = DESC_FILE; @@ -377,11 +455,8 @@ } /* try a wrapper */ - - FG(def_chunk_size) = 1; stream = php_stream_open_wrapper(Z_STRVAL_PP(zfile), Z_STRVAL_PP(zmode), - ENFORCE_SAFE_MODE|REPORT_ERRORS, NULL); - FG(def_chunk_size) = old_size; + +ENFORCE_SAFE_MODE|REPORT_ERRORS|STREAM_WILL_CAST, NULL); /* force into an fd */ if (stream == NULL || FAILURE == php_stream_cast(stream, @@ -403,7 +478,7 @@ } zend_hash_move_forward_ex(Z_ARRVAL_P(descriptorspec), &pos); - if (++ndesc == MAX_DESCRIPTORS) + if (++ndesc == PHP_PROC_OPEN_MAX_DESCRIPTORS) break; } @@ -447,7 +522,7 @@ child = pi.hProcess; CloseHandle(pi.hThread); -#else +#elif HAVE_FORK /* the unix way */ child = fork(); @@ -487,10 +562,17 @@ goto exit_fail; } +#else +# error You lose (configure should not have let you get here) #endif /* we forked/spawned and this is the parent */ - efree(command); + proc = (struct php_process_handle*)pemalloc(sizeof(struct php_process_handle), +is_persistent); + proc->is_persistent = is_persistent; + proc->command = command; + proc->npipes = ndesc; + proc->child = child; + array_init(pipes); /* clean up all the child ends and then open streams on the parent @@ -534,17 +616,21 @@ MAKE_STD_ZVAL(retfp); php_stream_to_zval(stream, retfp); add_index_zval(pipes, descriptors[i].index, retfp); + + proc->pipes[i] = Z_LVAL_P(retfp); } } break; + default: + proc->pipes[i] = 0; } } - ZEND_REGISTER_RESOURCE(return_value, (void*)child, le_proc_open); + ZEND_REGISTER_RESOURCE(return_value, proc, le_proc_open); return; exit_fail: - efree(command); + pefree(command, is_persistent); RETURN_FALSE; } Index: php4/ext/standard/tests/general_functions/proc_open.phpt diff -u php4/ext/standard/tests/general_functions/proc_open.phpt:1.2 php4/ext/standard/tests/general_functions/proc_open.phpt:1.3 --- php4/ext/standard/tests/general_functions/proc_open.phpt:1.2 Sat Aug 3 10:54:30 2002 +++ php4/ext/standard/tests/general_functions/proc_open.phpt Wed Jan 15 13:54:03 +2003 @@ -20,12 +20,6 @@ $pipes ); -/* As per manual: avoid deadlock */ -for ($i = 0; $i < count($pipes); $i++) -{ - fclose($pipes[$i]); -} - proc_close($cat); echo "I didn't segfault!\n"; Index: php4/ext/standard/proc_open.h +++ php4/ext/standard/proc_open.h /* +----------------------------------------------------------------------+ | PHP Version 4 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2003 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 2.02 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available at through the world-wide-web at | | http://www.php.net/license/2_02.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | [EMAIL PROTECTED] so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Wez Furlong <[EMAIL PROTECTED]> | +----------------------------------------------------------------------+ */ /* $Id: proc_open.h,v 1.1 2003/01/15 18:54:03 wez Exp $ */ #ifdef PHP_WIN32 typedef HANDLE php_file_descriptor_t; typedef HANDLE php_process_id_t; #else typedef int php_file_descriptor_t; typedef pid_t php_process_id_t; #endif #define PHP_PROC_OPEN_MAX_DESCRIPTORS 16 struct php_process_handle { php_process_id_t child; int npipes; long pipes[PHP_PROC_OPEN_MAX_DESCRIPTORS]; char *command; int is_persistent; };
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php