Edit report at https://bugs.php.net/bug.php?id=41003&edit=1

 ID:                 41003
 Comment by:         arto at bendiken dot net
 Reported by:        andy dot shellam at mailnetwork dot co dot uk
 Summary:            proc_get_status - PID is -1 out
 Status:             Open
 Type:               Feature/Change Request
 Package:            Feature/Change Request
 Operating System:   Unix (FreeBSD)
 PHP Version:        5.2.1
 Block user comment: N
 Private report:     N

 New Comment:

Note that a very simple user-level workaround on Unix systems is to call 
proc_open("exec /usr/bin/myprogram") instead of 
proc_open("/usr/bin/myprogram"), 
in which case the shell is replaced by the program being executed and 
proc_get_status() thus returns the program's PID instead of the shell's.

Similarly, the very simplest (though not most efficient) way to have the 
"bypass_shell" option work on Unix as well would be to simply prepend "exec " 
to 
the command string automatically in the implementation of proc_open().

It seems to me that proc_get_status() works correctly, and that indeed this bug 
report is really about "bypass_shell" not being honored on Unix, so perhaps the 
bug report could be retitled accordingly.


Previous Comments:
------------------------------------------------------------------------
[2009-03-17 07:55:31] vdovin_m at mail dot ru

I have w/changes for FreeBSD. W/pacth you can use "bypass_shell" to start 
binary executable file w/o /bin/sh process. To compile w/patch, modification in 
Makefile are needed (add "-lpopt" to EXTRA_LIBS parameter line).

-----proc_open.patch start----
{{{
19c19,21
< 
---
> #ifndef PHP_WIN32
> #include <popt.h>
> #endif
469a472,474
>       char *param_str = NULL;
>       char *param_dup = NULL;
>       char *const *av = NULL;
501d505
<       int bypass_shell = 0;
502a507
>       int bypass_shell = 0;
517a523,524
>       command_len = strlen(command);
> 
533a541,552
> #else
>       if (other_options) {
>               zval **item;
>               if (SUCCESS == zend_hash_find(Z_ARRVAL_P(other_options), 
> "bypass_shell", sizeof("bypass_shell"), (void**)&item)) {
>                       if ((Z_TYPE_PP(item) == IS_BOOL || Z_TYPE_PP(item) == 
> IS_LONG) &&
>                           Z_LVAL_PP(item)) {
>                               param_dup = pemalloc(command_len+1, 
> is_persistent);
>                               memcpy(param_dup, command, command_len+1);
>                               bypass_shell = 1;
>                       }
>               }
>       }
536,537d554
<       command_len = strlen(command);
< 
881c898,915
<                       execle("/bin/sh", "sh", "-c", command, NULL, 
env.envarray);
---
>                       if (bypass_shell) {
>                               int rc;                                 
>                               if ((param_str = strchr(command, ' '))) {
>                                       rc = poptParseArgvString(command, NULL, 
> (const char ***)&av);
>                                       *param_str = '\0';
>                                       if (!rc && av != NULL){
>                                               execve(command, (char * const 
> *) av, env.envarray);
>                                               free((void*)av);
>                                       } else {
>                                               param_str++;
>                                               execle(command, command, 
> param_str, NULL, env.envarray);
>                                       }
>                               } else {
>                                       execlp(command, NULL);
>                               }
>                       } else {
>                               execle("/bin/sh", "sh", "-c", command, NULL, 
> env.envarray);
>                       }
883c917,934
<                       execl("/bin/sh", "sh", "-c", command, NULL);
---
>                       if (bypass_shell) {
>                               int rc;                                 
>                               if ((param_str = strchr(command, ' '))) {
>                                       rc = poptParseArgvString(command, NULL, 
> (const char ***)&av);
>                                       *param_str = '\0';
>                                       if (!rc && av != NULL){
>                                               execvp(command, (char * const 
> *) av);
>                                               free((void*)av);
>                                       } else {
>                                               param_str++;
>                                               execlp(command, command, 
> param_str, NULL);
>                                       }
>                               } else {
>                                       execlp(command, NULL);
>                               }
>                       } else {
>                               execl("/bin/sh", "sh", "-c", command, NULL);
>                       }
909c960,965
<       proc->command = command;
---
>       if (bypass_shell) {
>               pefree(command, is_persistent);
>               proc->command = param_dup;
>       } else {
>               proc->command = command;
>       }
991a1048
>       pefree(param_dup, is_persistent);
}}}
-----proc_open.patch end------

------------------------------------------------------------------------
[2007-06-19 11:59:10] andy dot shellam at mailnetwork dot co dot uk

Can this be raised as a feature request, that PHP can optionally bypass the 
shell when launching a process, as in the Windows version?

------------------------------------------------------------------------
[2007-04-09 11:56:47] andy dot shellam at mailnetwork dot co dot uk

Sorry that might have been a bad example, but even without a shell script (i.e. 
an executable) a shell process is still launched to run that process.

You are correct, PHP is returning the ID of the process it launches (the 
shell.)  But can this not be changed as it is in the Windows version, so you 
can (optionally) bypass the shell and launch the process directly, as that 
would then return the correct PID of the process itself?

I.e. in Windows PHP is launching cmd.exe, in Unix it's launching sh.  In the 
Windows version there's an option to bypass cmd.exe and launch the process 
directly.  Can't you do the same for Unix?

------------------------------------------------------------------------
[2007-04-08 15:14:23] il...@php.net

Thank you for taking the time to write to us, but this is not
a bug. Please double-check the documentation available at
http://www.php.net/manual/ and the instructions on how to report
a bug at http://bugs.php.net/how-to-report.php

PHP started the ./loop.sh script, which is why its PID is returned. The 
other command was initiated by the shell script and PHP has no way of 
knowing about it.

------------------------------------------------------------------------
[2007-04-05 12:09:38] andy dot shellam at mailnetwork dot co dot uk

Description:
------------
proc_get_status when run with a proc_open'd resource returns a PID that is one 
less than shown in ps output.

E.g. to kill a process opened by proc_open, you need to add 1 to the PID 
returned by proc_get_status for it to work.

This is because proc_get_status returns the PID of the shell that then runs the 
command - not the command process itself.

Reproduce code:
---------------
Create a bash script that loops endlessly to simulate a long-running:

#!/usr/local/bin/bash

while [ 0 -eq 0 ]; do
        let 0
done

In PHP, run this script (from CLI):

#!/usr/local/php/bin/php
<?php

$descriptorspec = array(
   0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
   1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
   2 => array("file", "/tmp/error-output.txt", "a") // stderr is a file to 
write to
);

$cwd = '/tmp';
$env = array('some_option' => 'aeiou');

$process = proc_open('/tmp/loop.sh', $descriptorspec, $pipes, $cwd, $env, 
Array("bypass_shell" => TRUE));

if (is_resource($process)) {
        $procinfo = proc_get_status($process);
        echo "Opened process ID is: " . $procinfo['pid'] . "\n";
}

?>


Expected result:
----------------
Opened process ID is: 40609

(from ps output):

[NetServe@sydney ~]$ sudo ps auxwww|grep loop.sh
root       40609 48.2  0.2  3036  1672  p0  R+    1:06PM   0:05.94 
/usr/local/bin/bash /tmp/loop.sh
root       40608  0.0  0.1  1632   988  p0  S+    1:06PM   0:00.00 sh -c 
/tmp/loop.sh


Actual result:
--------------
Opened process ID is: 40608

[NetServe@sydney ~]$ sudo ps auxwww|grep loop.sh
root       40609 48.2  0.2  3036  1672  p0  R+    1:06PM   0:05.94 
/usr/local/bin/bash /tmp/loop.sh
root       40608  0.0  0.1  1632   988  p0  S+    1:06PM   0:00.00 sh -c 
/tmp/loop.sh


As you can see, the PID returned by proc_get_info is the shell that is then 
used to start the actual command - if you kill the shell's PID, the command 
carries on running.  Kill the shell PID+1, and it kills both off.

This is similar to http://bugs.php.net/bug.php?id=40070, however the 
bypass_shell does not work on Unix.


------------------------------------------------------------------------



-- 
Edit this bug report at https://bugs.php.net/bug.php?id=41003&edit=1

Reply via email to