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