PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LTP GCOV extension - code coverage report
Current view: directory - standard - proc_open.c
Test: PHP Code Coverage
Date: 2009-11-23 Instrumented lines: 342
Code covered: 76.6 % Executed lines: 262
Legend: not executed executed

       1                 : /*
       2                 :    +----------------------------------------------------------------------+
       3                 :    | PHP Version 6                                                        |
       4                 :    +----------------------------------------------------------------------+
       5                 :    | Copyright (c) 1997-2009 The PHP Group                                |
       6                 :    +----------------------------------------------------------------------+
       7                 :    | This source file is subject to version 3.01 of the PHP license,      |
       8                 :    | that is bundled with this package in the file LICENSE, and is        |
       9                 :    | available through the world-wide-web at the following url:           |
      10                 :    | http://www.php.net/license/3_01.txt                                  |
      11                 :    | If you did not receive a copy of the PHP license and are unable to   |
      12                 :    | obtain it through the world-wide-web, please send a note to          |
      13                 :    | license@php.net so we can mail you a copy immediately.               |
      14                 :    +----------------------------------------------------------------------+
      15                 :    | Author: Wez Furlong <wez@thebrainroom.com>                           |
      16                 :    +----------------------------------------------------------------------+
      17                 :  */
      18                 : /* $Id: proc_open.c 288605 2009-09-23 13:51:50Z dmitry $ */
      19                 : 
      20                 : #if 0 && (defined(__linux__) || defined(sun) || defined(__IRIX__))
      21                 : # define _BSD_SOURCE            /* linux wants this when XOPEN mode is on */
      22                 : # define _BSD_COMPAT            /* irix: uint */
      23                 : # define _XOPEN_SOURCE 500  /* turn on Unix98 */
      24                 : # define __EXTENSIONS__ 1       /* Solaris: uint */
      25                 : #endif
      26                 : 
      27                 : #include "php.h"
      28                 : #include <stdio.h>
      29                 : #include <ctype.h>
      30                 : #include "php_string.h"
      31                 : #include "ext/standard/head.h"
      32                 : #include "ext/standard/file.h"
      33                 : #include "exec.h"
      34                 : #include "php_globals.h"
      35                 : #include "SAPI.h"
      36                 : 
      37                 : #ifdef NETWARE
      38                 : #include <proc.h>
      39                 : #include <library.h>
      40                 : #endif
      41                 : 
      42                 : #if HAVE_SYS_WAIT_H
      43                 : #include <sys/wait.h>
      44                 : #endif
      45                 : #if HAVE_SIGNAL_H
      46                 : #include <signal.h>
      47                 : #endif
      48                 : 
      49                 : #if HAVE_SYS_STAT_H
      50                 : #include <sys/stat.h>
      51                 : #endif
      52                 : #if HAVE_FCNTL_H
      53                 : #include <fcntl.h>
      54                 : #endif
      55                 : 
      56                 : /* This symbol is defined in ext/standard/config.m4.
      57                 :  * Essentially, it is set if you HAVE_FORK || PHP_WIN32
      58                 :  * Otherplatforms may modify that configure check and add suitable #ifdefs
      59                 :  * around the alternate code.
      60                 :  * */
      61                 : #ifdef PHP_CAN_SUPPORT_PROC_OPEN
      62                 : 
      63                 : #if 0 && HAVE_PTSNAME && HAVE_GRANTPT && HAVE_UNLOCKPT && HAVE_SYS_IOCTL_H && HAVE_TERMIOS_H
      64                 : # include <sys/ioctl.h>
      65                 : # include <termios.h>
      66                 : # define PHP_CAN_DO_PTS 1
      67                 : #endif
      68                 : 
      69                 : #include "proc_open.h"
      70                 : 
      71                 : static int le_proc_open;
      72                 : 
      73                 : #if !defined(PHP_WIN32) && !defined(NETWARE)
      74                 : /* {{{ _php_array_to_argv */
      75                 : static char **_php_array_to_argv(zval *arg_array, int is_persistent)
      76               5 : {
      77                 :         zval **element, temp;
      78                 :         char **c_argv, **ap;
      79                 :         HashTable *target_hash;
      80                 :         HashPosition pos;
      81                 : 
      82               5 :         target_hash = Z_ARRVAL_P(arg_array);
      83               5 :         ap = c_argv = (char **)pecalloc(zend_hash_num_elements(target_hash) + 1, sizeof(char *), is_persistent);
      84                 :         
      85                 :         /* skip first element */
      86               5 :         zend_hash_internal_pointer_reset_ex(target_hash, &pos);
      87               5 :         zend_hash_move_forward_ex(target_hash, &pos);
      88                 :         for (   ;
      89              19 :                         zend_hash_get_current_data_ex(target_hash, (void **) &element, &pos) == SUCCESS;
      90               9 :                         zend_hash_move_forward_ex(target_hash, &pos)) {
      91                 : 
      92               9 :                 temp = **element;
      93               9 :                 if (Z_TYPE_PP(element) != IS_STRING) {
      94               9 :                         zval_copy_ctor(&temp);
      95               9 :                         convert_to_string(&temp);
      96                 :                 }
      97               9 :                 *ap++ = pestrndup(Z_STRVAL(temp), Z_STRLEN(temp), is_persistent);
      98               9 :                 if (Z_TYPE_PP(element) != IS_STRING) {
      99               9 :                         zval_dtor(&temp);
     100                 :                 }
     101                 :         }
     102                 : 
     103               5 :         return c_argv;
     104                 : }
     105                 : /* }}} */
     106                 : 
     107                 : /* {{{ _php_free_argv */
     108                 : static void _php_free_argv(char **argv, int is_persistent)
     109           16906 : {
     110           16906 :         if (argv) {
     111               5 :                 char **ap = NULL;
     112                 : 
     113              14 :                 for (ap = argv; *ap; ap++) {
     114               9 :                         pefree(*ap, is_persistent);
     115                 :                 }
     116               5 :                 pefree(argv, is_persistent);
     117                 :         }
     118           16906 : }
     119                 : /* }}} */
     120                 : 
     121                 : #endif
     122                 : 
     123                 : /* {{{ _php_array_to_envp */
     124                 : static php_process_env_t _php_array_to_envp(zval *environment, int is_persistent TSRMLS_DC)
     125           16896 : {
     126                 :         zval **element;
     127                 :         php_process_env_t env;
     128                 :         zstr string_key;
     129                 :         char *data;
     130                 : #ifndef PHP_WIN32
     131                 :         char **ep;
     132                 : #endif
     133                 :         char *p;
     134           16896 :         uint string_length, cnt, l, sizeenv=0, el_len;
     135                 :         ulong num_key;
     136                 :         HashTable *target_hash;
     137                 :         HashPosition pos;
     138                 : 
     139           16896 :         memset(&env, 0, sizeof(env));
     140                 :         
     141           16896 :         if (!environment) {
     142               0 :                 return env;
     143                 :         }
     144                 :         
     145           16896 :         cnt = zend_hash_num_elements(Z_ARRVAL_P(environment));
     146                 :         
     147           16896 :         if (cnt < 1) {
     148                 : #ifndef PHP_WIN32
     149               3 :                 env.envarray = (char **) pecalloc(1, sizeof(char *), is_persistent);
     150                 : #endif
     151               3 :                 env.envp = (char *) pecalloc(4, 1, is_persistent);
     152               3 :                 return env;
     153                 :         }
     154                 : 
     155           16893 :         target_hash = HASH_OF(environment);
     156           16893 :         if (!target_hash) {
     157               0 :                 return env;
     158                 :         }
     159                 : 
     160                 :         /* first, we have to get the size of all the elements in the hash */
     161           16893 :         for (zend_hash_internal_pointer_reset_ex(target_hash, &pos);
     162          925936 :                         zend_hash_get_current_data_ex(target_hash, (void **) &element, &pos) == SUCCESS;
     163          892150 :                         zend_hash_move_forward_ex(target_hash, &pos)) {
     164                 :                 
     165          892150 :                 convert_to_string_ex(element);
     166          892150 :                 el_len = Z_STRLEN_PP(element);
     167          892150 :                 if (el_len == 0) {
     168          134962 :                         continue;
     169                 :                 }
     170                 :                 
     171          757188 :                 sizeenv += el_len+1;
     172                 :                 
     173          757188 :                 switch (zend_hash_get_current_key_ex(target_hash, &string_key, &string_length, &num_key, 0, &pos)) {
     174                 :                         case HASH_KEY_IS_STRING:
     175          757186 :                                 if (string_length == 0) {
     176               0 :                                         continue;
     177                 :                                 }
     178          757186 :                                 sizeenv += string_length+1;
     179                 :                                 break;
     180                 :                 }
     181                 :         }
     182                 : 
     183                 : #ifndef PHP_WIN32
     184           16893 :         ep = env.envarray = (char **) pecalloc(cnt + 1, sizeof(char *), is_persistent);
     185                 : #endif
     186           16893 :         p = env.envp = (char *) pecalloc(sizeenv + 4, 1, is_persistent);
     187                 : 
     188           16893 :         for (zend_hash_internal_pointer_reset_ex(target_hash, &pos);
     189          925936 :                         zend_hash_get_current_data_ex(target_hash, (void **) &element, &pos) == SUCCESS;
     190          892150 :                         zend_hash_move_forward_ex(target_hash, &pos)) {
     191                 :                 
     192          892150 :                 convert_to_string_ex(element);
     193          892150 :                 el_len = Z_STRLEN_PP(element);
     194                 :                 
     195          892150 :                 if (el_len == 0) {
     196          134962 :                         continue;
     197                 :                 }
     198                 :                 
     199          757188 :                 data = Z_STRVAL_PP(element);
     200          757188 :                 switch (zend_hash_get_current_key_ex(target_hash, &string_key, &string_length, &num_key, 0, &pos)) {
     201                 :                         case HASH_KEY_IS_STRING:
     202          757186 :                                 if (string_length == 0) {
     203               0 :                                         continue;
     204                 :                                 }
     205          757186 :                                 l = string_length + el_len + 1;
     206          757186 :                                 memcpy(p, string_key.s, string_length);
     207          757186 :                                 strcat(p, "=");
     208          757186 :                                 strcat(p, data);
     209                 :                                 
     210                 : #ifndef PHP_WIN32
     211          757186 :                                 *ep = p;
     212          757186 :                                 ++ep;
     213                 : #endif
     214          757186 :                                 p += l;
     215          757186 :                                 break;
     216                 :                         case HASH_KEY_IS_LONG:
     217               0 :                                 memcpy(p,data,el_len);
     218                 : #ifndef PHP_WIN32
     219               0 :                                 *ep = p;
     220               0 :                                 ++ep;
     221                 : #endif
     222               0 :                                 p += el_len + 1;
     223                 :                                 break;
     224                 :                         case HASH_KEY_NON_EXISTANT:
     225                 :                                 break;
     226                 :                 }
     227                 :         }       
     228                 : 
     229                 :         assert(p - env.envp <= sizeenv);
     230                 : 
     231           16893 :         return env;
     232                 : }
     233                 : /* }}} */
     234                 : 
     235                 : /* {{{ _php_free_envp */
     236                 : static void _php_free_envp(php_process_env_t env, int is_persistent)
     237           16906 : {
     238                 : #ifndef PHP_WIN32
     239           16906 :         if (env.envarray) {
     240           16896 :                 pefree(env.envarray, is_persistent);
     241                 :         }
     242                 : #endif
     243           16906 :         if (env.envp) {
     244           16896 :                 pefree(env.envp, is_persistent);
     245                 :         }
     246           16906 : }
     247                 : /* }}} */
     248                 : 
     249                 : /* {{{ proc_open_rsrc_dtor */
     250                 : static void proc_open_rsrc_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
     251           16906 : {
     252           16906 :         struct php_process_handle *proc = (struct php_process_handle*)rsrc->ptr;
     253                 :         int i;
     254                 : #ifdef PHP_WIN32
     255                 :         DWORD wstatus;
     256                 : #elif HAVE_SYS_WAIT_H
     257                 :         int wstatus;
     258                 :         pid_t wait_pid;
     259                 : #endif
     260                 : 
     261                 :         /* Close all handles to avoid a deadlock */
     262           67617 :         for (i = 0; i < proc->npipes; i++) {
     263           50711 :                 if (proc->pipes[i] != 0) {
     264           50708 :                         zend_list_delete(proc->pipes[i]);
     265           50708 :                         proc->pipes[i] = 0;
     266                 :                 }
     267                 :         }
     268                 :         
     269                 : #ifdef PHP_WIN32
     270                 :         
     271                 :         WaitForSingleObject(proc->childHandle, INFINITE);
     272                 :         GetExitCodeProcess(proc->childHandle, &wstatus);
     273                 :         FG(pclose_ret) = wstatus;
     274                 :         CloseHandle(proc->childHandle);
     275                 :         
     276                 : #elif HAVE_SYS_WAIT_H
     277                 :         
     278                 :         do {
     279           16906 :                 wait_pid = waitpid(proc->child, &wstatus, 0);
     280           16906 :         } while (wait_pid == -1 && errno == EINTR);
     281                 :         
     282           16906 :         if (wait_pid == -1)
     283           16874 :                 FG(pclose_ret) = -1;
     284                 :         else {
     285              32 :                 if (WIFEXITED(wstatus))
     286              28 :                         wstatus = WEXITSTATUS(wstatus);
     287              32 :                 FG(pclose_ret) = wstatus;
     288                 :         }
     289                 :         
     290                 : #else
     291                 :         FG(pclose_ret) = -1;
     292                 : #endif
     293           16906 :         _php_free_envp(proc->env, proc->is_persistent);
     294                 : #if !defined(PHP_WIN32) && !defined(NETWARE)
     295           16906 :         _php_free_argv(proc->argv, proc->is_persistent);
     296                 : #endif
     297           16906 :         pefree(proc->command, proc->is_persistent);
     298           16906 :         pefree(proc, proc->is_persistent);
     299                 :         
     300           16906 : }
     301                 : /* }}} */
     302                 : 
     303                 : /* {{{ PHP_MINIT_FUNCTION(proc_open) */
     304                 : PHP_MINIT_FUNCTION(proc_open)
     305           17007 : {
     306           17007 :         le_proc_open = zend_register_list_destructors_ex(proc_open_rsrc_dtor, NULL, "process", module_number);
     307           17007 :         return SUCCESS;
     308                 : }
     309                 : /* }}} */
     310                 : 
     311                 : /* {{{ proto bool proc_terminate(resource process [, long signal]) U
     312                 :    kill a process opened by proc_open */
     313                 : PHP_FUNCTION(proc_terminate)
     314               8 : {
     315                 :         zval *zproc;
     316                 :         struct php_process_handle *proc;
     317               8 :         long sig_no = SIGTERM;
     318                 :         
     319               8 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &zproc, &sig_no) == FAILURE) {
     320               0 :                 RETURN_FALSE;
     321                 :         }
     322                 : 
     323               8 :         ZEND_FETCH_RESOURCE(proc, struct php_process_handle *, &zproc, -1, "process", le_proc_open);
     324                 :         
     325                 : #ifdef PHP_WIN32
     326                 :         if (TerminateProcess(proc->childHandle, 255)) {
     327                 :                 RETURN_TRUE;
     328                 :         } else {
     329                 :                 RETURN_FALSE;
     330                 :         }
     331                 : #else
     332               8 :         if (kill(proc->child, sig_no) == 0) {
     333               7 :                 RETURN_TRUE;
     334                 :         } else {
     335               1 :                 RETURN_FALSE;
     336                 :         }
     337                 : #endif
     338                 : }
     339                 : /* }}} */
     340                 : 
     341                 : /* {{{ proto int proc_close(resource process) U
     342                 :    close a process opened by proc_open */
     343                 : PHP_FUNCTION(proc_close)
     344           16903 : {
     345                 :         zval *zproc;
     346                 :         struct php_process_handle *proc;
     347                 :         
     348           16903 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zproc) == FAILURE) {
     349               0 :                 RETURN_FALSE;
     350                 :         }
     351                 : 
     352           16903 :         ZEND_FETCH_RESOURCE(proc, struct php_process_handle *, &zproc, -1, "process", le_proc_open);
     353                 :         
     354           16903 :         zend_list_delete(Z_LVAL_P(zproc));
     355           16903 :         RETURN_LONG(FG(pclose_ret));
     356                 : }
     357                 : /* }}} */
     358                 : 
     359                 : /* {{{ proto array proc_get_status(resource process) U
     360                 :    get information about a process opened by proc_open */
     361                 : PHP_FUNCTION(proc_get_status)
     362           16893 : {
     363                 :         zval *zproc;
     364                 :         struct php_process_handle *proc;
     365                 : #ifdef PHP_WIN32
     366                 :         DWORD wstatus;
     367                 : #elif HAVE_SYS_WAIT_H
     368                 :         int wstatus;
     369                 :         pid_t wait_pid;
     370                 : #endif
     371                 :         UChar *ucmd;
     372                 :         int ucmd_len;
     373           16893 :         int running = 1, signaled = 0, stopped = 0;
     374           16893 :         int exitcode = -1, termsig = 0, stopsig = 0;
     375                 :         
     376           16893 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zproc) == FAILURE) {
     377               0 :                 RETURN_FALSE;
     378                 :         }
     379                 : 
     380           16893 :         ZEND_FETCH_RESOURCE(proc, struct php_process_handle *, &zproc, -1, "process", le_proc_open);
     381                 : 
     382           16893 :         array_init(return_value);
     383                 : 
     384           16893 :         if (SUCCESS == php_stream_path_decode(&php_plain_files_wrapper, &ucmd, &ucmd_len, proc->command, strlen(proc->command), REPORT_ERRORS, FG(default_context))) {
     385           16893 :                 add_ascii_assoc_unicodel(return_value, "command", ucmd, ucmd_len, 0);
     386                 :         } else {
     387                 :                 /* Fallback on original binary string */
     388               0 :                 add_ascii_assoc_string(return_value, "command", proc->command, 1);
     389                 :         }
     390           16893 :         add_ascii_assoc_long(return_value, "pid", (long) proc->child);
     391                 :         
     392                 : #ifdef PHP_WIN32
     393                 :         
     394                 :         GetExitCodeProcess(proc->childHandle, &wstatus);
     395                 : 
     396                 :         running = wstatus == STILL_ACTIVE;
     397                 :         exitcode = running ? -1 : wstatus;
     398                 :         
     399                 : #elif HAVE_SYS_WAIT_H
     400                 :         
     401           16893 :         errno = 0;
     402           16893 :         wait_pid = waitpid(proc->child, &wstatus, WNOHANG|WUNTRACED);
     403                 :         
     404           16893 :         if (wait_pid == proc->child) {
     405           16874 :                 if (WIFEXITED(wstatus)) {
     406           16872 :                         running = 0;
     407           16872 :                         exitcode = WEXITSTATUS(wstatus);
     408                 :                 }
     409           16874 :                 if (WIFSIGNALED(wstatus)) {
     410               2 :                         running = 0;
     411               2 :                         signaled = 1;
     412                 : #ifdef NETWARE
     413                 :                         termsig = WIFTERMSIG(wstatus);
     414                 : #else
     415               2 :                         termsig = WTERMSIG(wstatus);
     416                 : #endif
     417                 :                 }
     418           16874 :                 if (WIFSTOPPED(wstatus)) {
     419               0 :                         stopped = 1;
     420               0 :                         stopsig = WSTOPSIG(wstatus);
     421                 :                 }
     422              19 :         } else if (wait_pid == -1) {
     423               1 :                 running = 0;
     424                 :         }
     425                 : #endif
     426                 : 
     427           16893 :         add_ascii_assoc_bool(return_value, "running", running);
     428           16893 :         add_ascii_assoc_bool(return_value, "signaled", signaled);
     429           16893 :         add_ascii_assoc_bool(return_value, "stopped", stopped);
     430           16893 :         add_ascii_assoc_long(return_value, "exitcode", exitcode);
     431           16893 :         add_ascii_assoc_long(return_value, "termsig", termsig);
     432           16893 :         add_ascii_assoc_long(return_value, "stopsig", stopsig);
     433                 : }
     434                 : /* }}} */
     435                 : 
     436                 : /* {{{ handy definitions for portability/readability */
     437                 : #ifdef PHP_WIN32
     438                 : # define pipe(pair)             (CreatePipe(&pair[0], &pair[1], &security, 2048L) ? 0 : -1)
     439                 : 
     440                 : # define COMSPEC_NT     "cmd.exe"
     441                 : # define COMSPEC_9X     "command.com"
     442                 : 
     443                 : static inline HANDLE dup_handle(HANDLE src, BOOL inherit, BOOL closeorig)
     444                 : {
     445                 :         HANDLE copy, self = GetCurrentProcess();
     446                 :         
     447                 :         if (!DuplicateHandle(self, src, self, &copy, 0, inherit, DUPLICATE_SAME_ACCESS |
     448                 :                                 (closeorig ? DUPLICATE_CLOSE_SOURCE : 0)))
     449                 :                 return NULL;
     450                 :         return copy;
     451                 : }
     452                 : 
     453                 : static inline HANDLE dup_fd_as_handle(int fd)
     454                 : {
     455                 :         return dup_handle((HANDLE)_get_osfhandle(fd), TRUE, FALSE);
     456                 : }
     457                 : 
     458                 : # define close_descriptor(fd)   CloseHandle(fd)
     459                 : #else
     460                 : # define close_descriptor(fd)   close(fd)
     461                 : #endif
     462                 : 
     463                 : #define DESC_PIPE               1
     464                 : #define DESC_FILE               2
     465                 : #define DESC_PARENT_MODE_WRITE  8
     466                 : 
     467                 : struct php_proc_open_descriptor_item {
     468                 :         int index;                                                      /* desired fd number in child process */
     469                 :         php_file_descriptor_t parentend, childend;      /* fds for pipes in parent/child */
     470                 :         int mode;                                                       /* mode for proc_open code */
     471                 :         int mode_flags;                                         /* mode flags for opening fds */
     472                 : };
     473                 : /* }}} */
     474                 : 
     475                 : /* {{{ proto resource proc_open(string command, array descriptorspec, array &pipes [, string cwd [, array env [, array other_options]]]) U
     476                 :    Run a process with more control over it's file descriptors */
     477                 : PHP_FUNCTION(proc_open)
     478           16907 : {
     479           16907 :         zval **ppcommand, **ppcwd = NULL;
     480                 :         zval **command_with_args;
     481           16907 :         char *command, *cwd=NULL;
     482           16907 :         int command_len, cwd_len = 0;
     483                 :         zval *descriptorspec;
     484                 :         zval *pipes;
     485           16907 :         zval *environment = NULL;
     486           16907 :         zval *other_options = NULL;
     487                 :         php_process_env_t env;
     488           16907 :         int ndesc = 0;
     489                 :         int i;
     490           16907 :         zval **descitem = NULL;
     491                 :         HashPosition pos;
     492                 :         struct php_proc_open_descriptor_item descriptors[PHP_PROC_OPEN_MAX_DESCRIPTORS];
     493           16907 :         char** child_argv = NULL;
     494                 : #ifdef PHP_WIN32
     495                 :         PROCESS_INFORMATION pi;
     496                 :         HANDLE childHandle;
     497                 :         STARTUPINFO si;
     498                 :         BOOL newprocok;
     499                 :         SECURITY_ATTRIBUTES security;
     500                 :         DWORD dwCreateFlags = 0;
     501                 :         char *command_with_cmd;
     502                 :         UINT old_error_mode;
     503                 : #endif
     504                 : #ifdef NETWARE
     505                 :         char* command_dup = NULL;
     506                 :         char* orig_cwd = NULL;
     507                 :         int command_num_args = 0;
     508                 :         wiring_t channel;
     509                 : #endif
     510                 :         php_process_id_t child;
     511                 :         struct php_process_handle *proc;
     512           16907 :         int is_persistent = 0; /* TODO: ensure that persistent procs will work */
     513                 : #ifdef PHP_WIN32
     514                 :         int suppress_errors = 0;
     515                 : #endif
     516           16907 :         int bypass_shell = 0;
     517                 : #if PHP_CAN_DO_PTS
     518                 :         php_file_descriptor_t dev_ptmx = -1;    /* master */
     519                 :         php_file_descriptor_t slave_pty = -1;
     520                 : #endif
     521           16907 :         php_stream_context *context = FG(default_context);
     522           16907 :         zend_uchar binary_pipes = 0;
     523                 : 
     524           16907 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zaz|Z!a!a!", &command_with_args, &descriptorspec, &pipes, &ppcwd, &environment, &other_options) == FAILURE) {
     525               0 :                 RETURN_FALSE;
     526                 :         }
     527                 : 
     528           16907 :         if (ppcwd && php_stream_path_param_encode(ppcwd, &cwd, &cwd_len, REPORT_ERRORS, FG(default_context)) == FAILURE) {
     529               0 :                 RETURN_FALSE;
     530                 :         }
     531                 : 
     532           16907 :         if (other_options) {
     533                 :                 zval **item;
     534                 : #ifdef PHP_WIN32
     535                 :                 if (SUCCESS == zend_ascii_hash_find(Z_ARRVAL_P(other_options), "suppress_errors", sizeof("suppress_errors"), (void**)&item)) {
     536                 :                         if ((Z_TYPE_PP(item) == IS_BOOL || Z_TYPE_PP(item) == IS_LONG) &&
     537                 :                             Z_LVAL_PP(item)) {
     538                 :                                 suppress_errors = 1;
     539                 :                         }
     540                 :                 }
     541                 : #endif
     542           16900 :                 if (SUCCESS == zend_ascii_hash_find(Z_ARRVAL_P(other_options), "bypass_shell", sizeof("bypass_shell"), (void**)&item)) {
     543               6 :                         if ((Z_TYPE_PP(item) == IS_BOOL || Z_TYPE_PP(item) == IS_LONG) &&
     544                 :                             Z_LVAL_PP(item)) {
     545               6 :                                 bypass_shell = 1;
     546                 :                         }
     547                 :                 }
     548                 :                 /* Suppresses automatic application of unicode filters when unicode.semantics=on */
     549           16900 :                 if (SUCCESS == zend_ascii_hash_find(Z_ARRVAL_P(other_options), "binary_pipes", sizeof("binary_pipes"), (void**)&item)) {
     550           16894 :                         if (Z_TYPE_PP(item) == IS_BOOL && Z_BVAL_PP(item)) {
     551           16894 :                                 binary_pipes = 1;
     552                 :                         }
     553                 :                 }
     554                 : 
     555                 :                 /* Override FG(default_context) */
     556           16900 :                 if (SUCCESS == zend_ascii_hash_find(Z_ARRVAL_P(other_options), "context", sizeof("context"), (void**)&item)) {
     557               0 :                         context = php_stream_context_from_zval(*item, 0);
     558                 :                 }
     559                 :         }
     560                 : 
     561                 : #if !defined(PHP_WIN32) && !defined(NETWARE)
     562           16907 :         if (bypass_shell) {
     563                 :                 zval **item;
     564                 :                 
     565               6 :                 if (Z_TYPE_PP(command_with_args) != IS_ARRAY) {
     566               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "first parameter must be array when bypass_shell is on");
     567               0 :                         RETURN_FALSE;
     568                 :                 }
     569               6 :                 if (zend_hash_num_elements(Z_ARRVAL_PP(command_with_args)) < 1) {
     570               1 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "arguments array must have at least one element");
     571               1 :                         RETURN_FALSE;
     572                 :                 }
     573                 :                 
     574               5 :                 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(command_with_args), &pos);
     575               5 :                 if (zend_hash_get_current_data_ex(Z_ARRVAL_PP(command_with_args), (void **)&item, &pos) == SUCCESS) {
     576               5 :                         if (Z_TYPE_PP(item) == IS_STRING || Z_TYPE_PP(item) == IS_UNICODE) {
     577               5 :                                 ppcommand = item;
     578                 :                         } else {
     579               0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "first argument must be a nonempty string");
     580               0 :                                 RETURN_FALSE;
     581                 :                         }
     582                 :                 } else {
     583               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "first argument must be at index 0");
     584               0 :                         RETURN_FALSE;
     585                 :                 }
     586                 :         } else {
     587                 : #endif
     588           16901 :                 if (Z_TYPE_PP(command_with_args) != IS_STRING && Z_TYPE_PP(command_with_args) != IS_UNICODE) {
     589               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s() expects parameter 1 to be string, %s given", get_active_function_name(TSRMLS_C),
     590                 :                                 zend_zval_type_name(*command_with_args));
     591               0 :                         RETURN_FALSE;
     592                 :                 }
     593           16901 :                 ppcommand = command_with_args;
     594                 :                 /* command_len will be set below */
     595                 : #if !defined(PHP_WIN32) && !defined(NETWARE)
     596                 :         }
     597                 : #endif
     598                 : 
     599           16906 :         if (php_stream_path_param_encode(ppcommand, &command, &command_len, REPORT_ERRORS, FG(default_context)) == FAILURE) {
     600               0 :                 RETURN_FALSE;
     601                 :         }
     602                 : 
     603                 : #if !defined(PHP_WIN32) && !defined(NETWARE)
     604           16906 :         if (bypass_shell) {
     605               5 :                 child_argv = _php_array_to_argv(*command_with_args, is_persistent);
     606                 :         }
     607                 : #endif
     608                 : 
     609           16906 :         if (environment) {
     610           16896 :                 env = _php_array_to_envp(environment, is_persistent TSRMLS_CC);
     611                 :         } else {
     612              10 :                 memset(&env, 0, sizeof(env));
     613                 :         }
     614                 : 
     615           16906 :         memset(descriptors, 0, sizeof(descriptors));
     616                 : 
     617                 : #ifdef PHP_WIN32
     618                 :         /* we use this to allow the child to inherit handles */
     619                 :         memset(&security, 0, sizeof(security));
     620                 :         security.nLength = sizeof(security);
     621                 :         security.bInheritHandle = TRUE;
     622                 :         security.lpSecurityDescriptor = NULL;
     623                 : #endif
     624                 :         
     625                 :         /* walk the descriptor spec and set up files/pipes */
     626           16906 :         zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(descriptorspec), &pos);
     627           84523 :         while (zend_hash_get_current_data_ex(Z_ARRVAL_P(descriptorspec), (void **)&descitem, &pos) == SUCCESS) {
     628                 :                 zstr str_index;
     629                 :                 ulong nindex;
     630                 :                 zval **ztype;
     631                 : 
     632           50711 :                 str_index.v = NULL;
     633           50711 :                 zend_hash_get_current_key_ex(Z_ARRVAL_P(descriptorspec), &str_index, NULL, &nindex, 0, &pos);
     634                 : 
     635           50711 :                 if (str_index.v) {
     636               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "descriptor spec must be an integer indexed array");
     637               0 :                         goto exit_fail;
     638                 :                 }
     639                 : 
     640           50711 :                 descriptors[ndesc].index = nindex;
     641                 : 
     642           50711 :                 if (Z_TYPE_PP(descitem) == IS_RESOURCE) {
     643                 :                         /* should be a stream - try and dup the descriptor */
     644                 :                         php_stream *stream;
     645                 :                         int fd;
     646                 : 
     647               3 :                         php_stream_from_zval(stream, descitem);
     648                 : 
     649               3 :                         if (FAILURE == php_stream_cast(stream, PHP_STREAM_AS_FD, (void **)&fd, REPORT_ERRORS)) {
     650               0 :                                 goto exit_fail;
     651                 :                         }
     652                 : 
     653                 : #ifdef PHP_WIN32
     654                 :                         descriptors[ndesc].childend = dup_fd_as_handle(fd);
     655                 :                         if (descriptors[ndesc].childend == NULL) {
     656                 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to dup File-Handle for descriptor %d", nindex);
     657                 :                                 goto exit_fail;
     658                 :                         }
     659                 : #else
     660               3 :                         descriptors[ndesc].childend = dup(fd);
     661               3 :                         if (descriptors[ndesc].childend < 0) {
     662               0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to dup File-Handle for descriptor %ld - %s", nindex, strerror(errno));
     663               0 :                                 goto exit_fail;
     664                 :                         }
     665                 : #endif
     666               3 :                         descriptors[ndesc].mode = DESC_FILE;
     667                 : 
     668           50708 :                 } else if (Z_TYPE_PP(descitem) != IS_ARRAY) {
     669               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Descriptor item must be either an array or a File-Handle");
     670               0 :                         goto exit_fail;
     671                 :                 } else {
     672                 : 
     673           50708 :                         if (zend_hash_index_find(Z_ARRVAL_PP(descitem), 0, (void **)&ztype) == SUCCESS) {
     674           50708 :                                 convert_to_string_ex(ztype);
     675                 :                         } else {
     676               0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Missing handle qualifier in array");
     677               0 :                                 goto exit_fail;
     678                 :                         }
     679                 : 
     680           50708 :                         if (strcmp(Z_STRVAL_PP(ztype), "pipe") == 0) {
     681                 :                                 php_file_descriptor_t newpipe[2];
     682                 :                                 zval **zmode;
     683                 : 
     684           50708 :                                 if (zend_hash_index_find(Z_ARRVAL_PP(descitem), 1, (void **)&zmode) == SUCCESS) {
     685           50708 :                                         convert_to_string_ex(zmode);
     686                 :                                 } else {
     687               0 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Missing mode parameter for 'pipe'");
     688               0 :                                         goto exit_fail;
     689                 :                                 }
     690                 : 
     691           50708 :                                 descriptors[ndesc].mode = DESC_PIPE;
     692                 : 
     693           50708 :                                 if (0 != pipe(newpipe)) {
     694               0 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to create pipe %s", strerror(errno));
     695               0 :                                         goto exit_fail;
     696                 :                                 }
     697                 : 
     698           50708 :                                 if (strncmp(Z_STRVAL_PP(zmode), "w", 1) != 0) {
     699           16907 :                                         descriptors[ndesc].parentend = newpipe[1];
     700           16907 :                                         descriptors[ndesc].childend = newpipe[0];
     701           16907 :                                         descriptors[ndesc].mode |= DESC_PARENT_MODE_WRITE;
     702                 :                                 } else {
     703           33801 :                                         descriptors[ndesc].parentend = newpipe[0];
     704           33801 :                                         descriptors[ndesc].childend = newpipe[1];
     705                 :                                 }
     706                 : #ifdef PHP_WIN32
     707                 :                                 /* don't let the child inherit the parent side of the pipe */
     708                 :                                 descriptors[ndesc].parentend = dup_handle(descriptors[ndesc].parentend, FALSE, TRUE);
     709                 : #endif
     710           50708 :                                 descriptors[ndesc].mode_flags = descriptors[ndesc].mode & DESC_PARENT_MODE_WRITE ? O_WRONLY : O_RDONLY;
     711                 : #ifdef PHP_WIN32
     712                 :                                 if (Z_STRLEN_PP(zmode) >= 2 && Z_STRVAL_PP(zmode)[1] == 'b') {
     713                 :                                         descriptors[ndesc].mode_flags |= O_BINARY;
     714                 :                                 }
     715                 : #endif
     716                 : 
     717               0 :                         } else if (strcmp(Z_STRVAL_PP(ztype), "file") == 0) {
     718                 :                                 zval **zfile, **zmode;
     719                 :                                 char *filename;
     720                 :                                 int filename_len;
     721               0 :                                 zend_uchar free_filename = 0;
     722                 :                                 int fd;
     723                 :                                 php_stream *stream;
     724                 : 
     725               0 :                                 descriptors[ndesc].mode = DESC_FILE;
     726                 : 
     727               0 :                                 if (zend_hash_index_find(Z_ARRVAL_PP(descitem), 2, (void **)&zmode) == SUCCESS) {
     728               0 :                                         convert_to_string_ex(zmode);
     729                 :                                 } else {
     730               0 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Missing mode parameter for 'file'");
     731               0 :                                         goto exit_fail;
     732                 :                                 }
     733                 : 
     734               0 :                                 if (zend_hash_index_find(Z_ARRVAL_PP(descitem), 1, (void **)&zfile) == SUCCESS) {
     735               0 :                                         if (Z_TYPE_PP(zfile) == IS_UNICODE &&
     736                 :                                                 php_stream_path_encode(NULL, &filename, &filename_len,
     737                 :                                                                         Z_USTRVAL_PP(zfile), Z_USTRLEN_PP(zfile), REPORT_ERRORS, context) == SUCCESS) {
     738               0 :                                                 free_filename = 1;
     739                 :                                         } else {
     740               0 :                                                 convert_to_string_ex(zfile);
     741               0 :                                                 filename = Z_STRVAL_PP(zfile);
     742               0 :                                                 filename_len = Z_STRLEN_PP(zfile);
     743                 :                                         }
     744                 :                                 } else {
     745               0 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Missing file name parameter for 'file'");
     746               0 :                                         goto exit_fail;
     747                 :                                 }
     748                 : 
     749                 : 
     750                 :                                 /* try a wrapper */
     751               0 :                                 stream = php_stream_open_wrapper_ex(filename, Z_STRVAL_PP(zmode),
     752                 :                                                 REPORT_ERRORS|STREAM_WILL_CAST, NULL, context);
     753               0 :                                 if (free_filename) {
     754               0 :                                         efree(filename);
     755                 :                                 }
     756                 : 
     757                 :                                 /* force into an fd */
     758               0 :                                 if (stream == NULL || FAILURE == php_stream_cast(stream,
     759                 :                                                         PHP_STREAM_CAST_RELEASE|PHP_STREAM_AS_FD,
     760                 :                                                         (void **)&fd, REPORT_ERRORS)) {
     761                 :                                         goto exit_fail;
     762                 :                                 }
     763                 : 
     764                 : #ifdef PHP_WIN32
     765                 :                                 descriptors[ndesc].childend = dup_fd_as_handle(fd);
     766                 :                                 _close(fd);
     767                 : 
     768                 :                                 /* simulate the append mode by fseeking to the end of the file
     769                 :                                 this introduces a potential race-condition, but it is the best we can do, though */
     770                 :                                 if (strchr(Z_STRVAL_PP(zmode), 'a')) {
     771                 :                                         SetFilePointer(descriptors[ndesc].childend, 0, NULL, FILE_END);
     772                 :                                 }
     773                 : #else
     774               0 :                                 descriptors[ndesc].childend = fd;
     775                 : #endif
     776               0 :                         } else if (strcmp(Z_STRVAL_PP(ztype), "pty") == 0) {
     777                 : #if PHP_CAN_DO_PTS
     778                 :                                 if (dev_ptmx == -1) {
     779                 :                                         /* open things up */
     780                 :                                         dev_ptmx = open("/dev/ptmx", O_RDWR);
     781                 :                                         if (dev_ptmx == -1) {
     782                 :                                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to open /dev/ptmx, errno %d", errno);
     783                 :                                                 goto exit_fail;
     784                 :                                         }
     785                 :                                         grantpt(dev_ptmx);
     786                 :                                         unlockpt(dev_ptmx);
     787                 :                                         slave_pty = open(ptsname(dev_ptmx), O_RDWR);
     788                 : 
     789                 :                                         if (slave_pty == -1) {
     790                 :                                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to open slave pty, errno %d", errno);
     791                 :                                                 goto exit_fail;
     792                 :                                         }
     793                 :                                 }
     794                 :                                 descriptors[ndesc].mode = DESC_PIPE;
     795                 :                                 descriptors[ndesc].childend = dup(slave_pty);
     796                 :                                 descriptors[ndesc].parentend = dup(dev_ptmx);
     797                 :                                 descriptors[ndesc].mode_flags = O_RDWR;
     798                 : #else
     799               0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "pty pseudo terminal not supported on this system");
     800               0 :                                 goto exit_fail;
     801                 : #endif
     802                 :                         } else {
     803               0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s is not a valid descriptor spec/mode", Z_STRVAL_PP(ztype));
     804               0 :                                 goto exit_fail;
     805                 :                         }
     806                 :                 }
     807                 : 
     808           50711 :                 zend_hash_move_forward_ex(Z_ARRVAL_P(descriptorspec), &pos);
     809           50711 :                 if (++ndesc == PHP_PROC_OPEN_MAX_DESCRIPTORS) {
     810               0 :                         break;
     811                 :                 }
     812                 :         }
     813                 : 
     814                 : #ifdef PHP_WIN32
     815                 :         memset(&si, 0, sizeof(si));
     816                 :         si.cb = sizeof(si);
     817                 :         si.dwFlags = STARTF_USESTDHANDLES;
     818                 :         
     819                 :         si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
     820                 :         si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
     821                 :         si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
     822                 :         
     823                 :         /* redirect stdin/stdout/stderr if requested */
     824                 :         for (i = 0; i < ndesc; i++) {
     825                 :                 switch(descriptors[i].index) {
     826                 :                         case 0:
     827                 :                                 si.hStdInput = descriptors[i].childend;
     828                 :                                 break;
     829                 :                         case 1:
     830                 :                                 si.hStdOutput = descriptors[i].childend;
     831                 :                                 break;
     832                 :                         case 2:
     833                 :                                 si.hStdError = descriptors[i].childend;
     834                 :                                 break;
     835                 :                 }
     836                 :         }
     837                 : 
     838                 :         
     839                 :         memset(&pi, 0, sizeof(pi));
     840                 :         
     841                 :         if (suppress_errors) {
     842                 :                 old_error_mode = SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOGPFAULTERRORBOX);
     843                 :         }
     844                 :         
     845                 :         dwCreateFlags = NORMAL_PRIORITY_CLASS;
     846                 :         if(strcmp(sapi_module.name, "cli") != 0) {
     847                 :                 dwCreateFlags |= CREATE_NO_WINDOW;
     848                 :         }
     849                 : 
     850                 :         if (bypass_shell) {
     851                 :                 newprocok = CreateProcess(NULL, command, &security, &security, TRUE, dwCreateFlags, env.envp, cwd, &si, &pi);
     852                 :         } else {
     853                 :                 spprintf(&command_with_cmd, 0, "%s /c %s", GetVersion() < 0x80000000 ? COMSPEC_NT : COMSPEC_9X, command);
     854                 : 
     855                 :                 newprocok = CreateProcess(NULL, command_with_cmd, &security, &security, TRUE, dwCreateFlags, env.envp, cwd, &si, &pi);
     856                 :                 
     857                 :                 efree(command_with_cmd);
     858                 :         }
     859                 : 
     860                 :         if (suppress_errors) {
     861                 :                 SetErrorMode(old_error_mode);
     862                 :         }
     863                 :         
     864                 :         if (FALSE == newprocok) {
     865                 :                 DWORD dw = GetLastError();
     866                 : 
     867                 :                 /* clean up all the descriptors */
     868                 :                 for (i = 0; i < ndesc; i++) {
     869                 :                         CloseHandle(descriptors[i].childend);
     870                 :                         if (descriptors[i].parentend) {
     871                 :                                 CloseHandle(descriptors[i].parentend);
     872                 :                         }
     873                 :                 }
     874                 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "CreateProcess failed, error code - %u", dw);
     875                 :                 goto exit_fail;
     876                 :         }
     877                 : 
     878                 :         childHandle = pi.hProcess;
     879                 :         child       = pi.dwProcessId;
     880                 :         CloseHandle(pi.hThread);
     881                 : 
     882                 : #elif defined(NETWARE)
     883                 :         if (cwd) {
     884                 :                 orig_cwd = getcwd(NULL, PATH_MAX);
     885                 :                 chdir2(cwd);
     886                 :         }
     887                 :         channel.infd = descriptors[0].childend;
     888                 :         channel.outfd = descriptors[1].childend;
     889                 :         channel.errfd = -1;
     890                 :         /* Duplicate the command as processing downwards will modify it*/
     891                 :         command_dup = strdup(command);
     892                 :         if (!command_dup) {
     893                 :                 goto exit_fail;
     894                 :         }
     895                 :         /* get a number of args */
     896                 :         construct_argc_argv(command_dup, NULL, &command_num_args, NULL);
     897                 :         child_argv = (char**) malloc((command_num_args + 1) * sizeof(char*));
     898                 :         if(!child_argv) {
     899                 :                 free(command_dup);
     900                 :                 if (cwd && orig_cwd) {
     901                 :                         chdir2(orig_cwd);
     902                 :                         free(orig_cwd);
     903                 :                 }
     904                 :         }
     905                 :         /* fill the child arg vector */
     906                 :         construct_argc_argv(command_dup, NULL, &command_num_args, child_argv);
     907                 :         child_argv[command_num_args] = NULL;
     908                 :         child = procve(child_argv[0], PROC_DETACHED|PROC_INHERIT_CWD, NULL, &channel, NULL, NULL, 0, NULL, (const char**)child_argv);
     909                 :         free(child_argv);
     910                 :         free(command_dup);
     911                 :         if (cwd && orig_cwd) {
     912                 :                 chdir2(orig_cwd);
     913                 :                 free(orig_cwd);
     914                 :         }
     915                 :         if (child < 0) {
     916                 :                 /* failed to fork() */
     917                 :                 /* clean up all the descriptors */
     918                 :                 for (i = 0; i < ndesc; i++) {
     919                 :                         close(descriptors[i].childend);
     920                 :                         if (descriptors[i].parentend)
     921                 :                                 close(descriptors[i].parentend);
     922                 :                 }
     923                 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "procve failed - %s", strerror(errno));
     924                 :                 goto exit_fail;
     925                 :         }
     926                 : #elif HAVE_FORK
     927                 :         /* the unix way */
     928           16906 :         child = fork();
     929                 : 
     930           33810 :         if (child == 0) {
     931                 :                 /* this is the child process */
     932                 : 
     933                 : #if PHP_CAN_DO_PTS
     934                 :                 if (dev_ptmx >= 0) {
     935                 :                         int my_pid = getpid();
     936                 : 
     937                 : #ifdef TIOCNOTTY
     938                 :                         /* detach from original tty. Might only need this if isatty(0) is true */
     939                 :                         ioctl(0,TIOCNOTTY,NULL);
     940                 : #else
     941                 :                         setsid();
     942                 : #endif
     943                 :                         /* become process group leader */
     944                 :                         setpgid(my_pid, my_pid);
     945                 :                         tcsetpgrp(0, my_pid);
     946                 :                 }
     947                 : #endif
     948                 :                 
     949                 :                 /* close those descriptors that we just opened for the parent stuff,
     950                 :                  * dup new descriptors into required descriptors and close the original
     951                 :                  * cruft */
     952           67611 :                 for (i = 0; i < ndesc; i++) {
     953           50707 :                         switch (descriptors[i].mode & ~DESC_PARENT_MODE_WRITE) {
     954                 :                                 case DESC_PIPE:
     955           50704 :                                         close(descriptors[i].parentend);
     956                 :                                         break;
     957                 :                         }
     958           50707 :                         if (dup2(descriptors[i].childend, descriptors[i].index) < 0) {
     959               0 :                                 perror("dup2");
     960                 :                         }
     961           50707 :                         if (descriptors[i].childend != descriptors[i].index) {
     962           50707 :                                 close(descriptors[i].childend);
     963                 :                         }
     964                 :                 }
     965                 : 
     966                 : #if PHP_CAN_DO_PTS
     967                 :                 if (dev_ptmx >= 0) {
     968                 :                         close(dev_ptmx);
     969                 :                         close(slave_pty);
     970                 :                 }
     971                 : #endif
     972                 :                 
     973           16904 :                 if (cwd) {
     974           16894 :                         chdir(cwd);
     975                 :                 }
     976                 :                 
     977           16904 :                 if (bypass_shell && env.envarray) {
     978               2 :                         execve(command, child_argv, env.envarray);
     979           16902 :                 } else if (bypass_shell) {
     980               3 :                         execv(command, child_argv);
     981           16899 :                 } else if (env.envarray) {
     982           16894 :                         execle("/bin/sh", "sh", "-c", command, NULL, env.envarray);
     983                 :                 } else {
     984               5 :                         execl("/bin/sh", "sh", "-c", command, NULL);
     985                 :                 }
     986               0 :                 _exit(127);
     987                 : 
     988           16906 :         } else if (child < 0) {
     989                 :                 /* failed to fork() */
     990                 : 
     991                 :                 /* clean up all the descriptors */
     992               0 :                 for (i = 0; i < ndesc; i++) {
     993               0 :                         close(descriptors[i].childend);
     994               0 :                         if (descriptors[i].parentend)
     995               0 :                                 close(descriptors[i].parentend);
     996                 :                 }
     997                 : 
     998               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "fork failed - %s", strerror(errno));
     999                 : 
    1000               0 :                 goto exit_fail;
    1001                 : 
    1002                 :         }
    1003                 : #else
    1004                 : # error You lose (configure should not have let you get here)
    1005                 : #endif
    1006                 :         /* we forked/spawned and this is the parent */
    1007                 : 
    1008           16906 :         proc = (struct php_process_handle*)pemalloc(sizeof(struct php_process_handle), is_persistent);
    1009           16906 :         proc->is_persistent = is_persistent;
    1010           16906 :         proc->command = pestrdup(command, is_persistent);
    1011           16906 :         proc->npipes = ndesc;
    1012           16906 :         proc->child = child;
    1013                 : #ifdef PHP_WIN32
    1014                 :         proc->childHandle = childHandle;
    1015                 : #endif
    1016           16906 :         proc->env = env;
    1017                 : #if !defined(PHP_WIN32) && !defined(NETWARE)
    1018           16906 :         proc->argv = child_argv;
    1019                 : #endif
    1020                 : 
    1021           16906 :         if (pipes != NULL) {
    1022           16906 :                 zval_dtor(pipes);
    1023                 :         }
    1024           16906 :         array_init(pipes);
    1025                 : 
    1026                 : #if PHP_CAN_DO_PTS
    1027                 :         if (dev_ptmx >= 0) {
    1028                 :                 close(dev_ptmx);
    1029                 :                 close(slave_pty);
    1030                 :         }
    1031                 : #endif
    1032                 : 
    1033                 :         /* clean up all the child ends and then open streams on the parent
    1034                 :          * ends, where appropriate */
    1035           67617 :         for (i = 0; i < ndesc; i++) {
    1036           50711 :                 char *mode_string=NULL;
    1037           50711 :                 php_stream *stream = NULL;
    1038           50711 :                 zend_uchar read_stream = 0, write_stream = 0;
    1039                 : 
    1040           50711 :                 close_descriptor(descriptors[i].childend);
    1041                 : 
    1042           50711 :                 switch (descriptors[i].mode & ~DESC_PARENT_MODE_WRITE) {
    1043                 :                         case DESC_PIPE:
    1044           50708 :                                 switch(descriptors[i].mode_flags) {
    1045                 : #ifdef PHP_WIN32
    1046                 :                                         case O_WRONLY|O_BINARY:
    1047                 :                                                 mode_string = "wb";
    1048                 :                                                 write_stream = 1;
    1049                 :                                                 break;
    1050                 :                                         case O_RDONLY|O_BINARY:
    1051                 :                                                 mode_string = "rb";
    1052                 :                                                 read_stream = 1;
    1053                 :                                                 break;
    1054                 : #endif
    1055                 :                                         case O_WRONLY:
    1056           16907 :                                                 mode_string = "w";
    1057           16907 :                                                 write_stream = 1;
    1058           16907 :                                                 break;
    1059                 :                                         case O_RDONLY:
    1060           33801 :                                                 mode_string = "r";
    1061           33801 :                                                 read_stream = 1;
    1062           33801 :                                                 break;
    1063                 :                                         case O_RDWR:
    1064               0 :                                                 mode_string = "r+";
    1065               0 :                                                 write_stream = 1;
    1066               0 :                                                 read_stream = 1;
    1067                 :                                                 break;
    1068                 :                                 }
    1069                 : #ifdef PHP_WIN32
    1070                 :                                 stream = php_stream_fopen_from_fd(_open_osfhandle((zend_intptr_t)descriptors[i].parentend,
    1071                 :                                                         descriptors[i].mode_flags), mode_string, NULL);
    1072                 : #else
    1073           50708 :                                 stream = php_stream_fopen_from_fd(descriptors[i].parentend, mode_string, NULL);
    1074                 : # if defined(F_SETFD) && defined(FD_CLOEXEC)
    1075                 :                                 /* mark the descriptor close-on-exec, so that it won't be inherited by potential other children */
    1076           50708 :                                 fcntl(descriptors[i].parentend, F_SETFD, FD_CLOEXEC);
    1077                 : # endif
    1078                 : #endif
    1079           50708 :                                 if (stream) {
    1080                 :                                         zval *retfp;
    1081                 : 
    1082                 :                                         /* nasty hack; don't copy it */
    1083           50708 :                                         stream->flags |= PHP_STREAM_FLAG_NO_SEEK;
    1084                 : 
    1085           50708 :                                         if (!binary_pipes) {
    1086              28 :                                                 if (write_stream) {
    1087              13 :                                                         char *encoding = (context && context->output_encoding) ? context->output_encoding : UG(stream_encoding);
    1088                 : 
    1089              13 :                                                         php_stream_encoding_apply(stream, 1, encoding, UG(from_error_mode), UG(from_subst_char));
    1090                 :                                                 }
    1091              28 :                                                 if (read_stream) {
    1092              15 :                                                         char *encoding = (context && context->output_encoding) ? context->output_encoding : UG(stream_encoding);
    1093                 : 
    1094              15 :                                                         php_stream_encoding_apply(stream, 0, encoding, UG(to_error_mode), NULL);
    1095                 :                                                 }
    1096                 :                                         }
    1097                 :                                         
    1098           50708 :                                         MAKE_STD_ZVAL(retfp);
    1099           50708 :                                         php_stream_to_zval(stream, retfp);
    1100           50708 :                                         add_index_zval(pipes, descriptors[i].index, retfp);
    1101                 : 
    1102           50708 :                                         proc->pipes[i] = Z_LVAL_P(retfp);
    1103                 :                                 }
    1104           50708 :                                 break;
    1105                 :                         default:
    1106               3 :                                 proc->pipes[i] = 0;
    1107                 :                 }
    1108                 :         }
    1109                 : 
    1110           16906 :         ZEND_REGISTER_RESOURCE(return_value, proc, le_proc_open);
    1111           16906 :         return;
    1112                 : 
    1113               0 : exit_fail:
    1114                 : #if !defined(PHP_WIN32) && !defined(NETWARE)
    1115               0 :         _php_free_argv(child_argv, is_persistent);
    1116                 : #endif
    1117               0 :         _php_free_envp(env, is_persistent);
    1118                 : #if PHP_CAN_DO_PTS
    1119                 :         if (dev_ptmx >= 0) {
    1120                 :                 close(dev_ptmx);
    1121                 :         }
    1122                 :         if (slave_pty >= 0) {
    1123                 :                 close(slave_pty);
    1124                 :         }
    1125                 : #endif
    1126               0 :         RETURN_FALSE;
    1127                 : 
    1128                 : }
    1129                 : /* }}} */
    1130                 : 
    1131                 : #endif /* PHP_CAN_SUPPORT_PROC_OPEN */
    1132                 : 
    1133                 : /*
    1134                 :  * Local variables:
    1135                 :  * tab-width: 4
    1136                 :  * c-basic-offset: 4
    1137                 :  * End:
    1138                 :  * vim600: sw=4 ts=4 fdm=marker
    1139                 :  * vim<600: sw=4 ts=4
    1140                 :  */

Generated by: LTP GCOV extension version 1.5

Generated at Mon, 23 Nov 2009 17:39:42 +0000 (33 hours ago)

Copyright © 2005-2009 The PHP Group
All rights reserved.