Hi,
I logged "Bug #17538 proc_close() doesn't return exit value of process"
a little while a ago, full details are at
http://bugs.php.net/bug.php?id=17538 obviously, but the short summary is
that proc_close() doesn't return the exit value of the process, like
it's meant to. The bug I logged has an example script and stuff.
Anyway, I needed a fix soon, so I've had a poke around in the PHP source
myself, and I have basically got pretty close to a fix. I deliberated
for a little bit about whether I should try and make a patch, or log
more info on the bug, but I decided that posting to the list was best,
because I don't have a magic wand fix, rather some *very* relevant info
that a PHP developer will be able to use to create a proper fix.
Ok, so, all the problems I found are in ext/standard/exec.c (CVS version
of course).
This is the offending code:
# if HAVE_SYS_WAIT
int wstatus;
pid_t child, wait_pid;
child = (pid_t)rsrc->ptr;
do {
wait_pid = waitpid(child, &wstatus, 0);
} while (wait_pid == -1 && errno = EINTR);
if (wait_pid == -1)
FG(pclose_ret) = -1;
else
FG(pclose_ret) = wstatus;
# else
FG(pclose_ret) = -1;
# endif
Firstly, the gdb was showing me that code inside here wasn't getting
executed (waitpid() wasn't getting run). It turns out that there is no
HAVE_SYS_WAIT in php_config.h, but there is a HAVE_SYS_WAIT_H. I
imagine that perhaps it should be HAVE_SYS_WAIT_H?
Anyway, that was what was causing the code not to be run. So, for the
purposes of my experimentation, I just deleted the # if # else and #
endif lines (and the FG() line between else and endif) so that the code
could run, since clearly this is the code that sets pclose_ret, which is
in turn the number returned by proc_close().
That was the first problem. I'm sure someone more knowledgeable about
the PHP source will know if it's actually meant to be HAVE_SYS_WAIT_H,
or something else.
So, with that removed, I tried to compile, and the
} while (wait_pid == -1 && errno = EINTR);
line gave me an "invalid lvalue in assignment" compiler error. Changing
to "errno == EINTR" fixed that, but I'm not sure if it's meant to be ==
or not, or what's meant to be happening. But, I took a punt at ==, and
it compiled.
Then, I tried running some programs through proc_open() and
proc_close(), but php was mangling the return values.
The line:
FG(pclose_ret) = wstatus;
should be
FG(pclose_ret) = WEXITSTATUS(wstatus);
see "man waitpid" for details, basically wstatus contains more than just
the exit code, and WEXITSTATUS() returns the relevant exit status
number.
So, I compiled again, and it worked! I ended up with:
int wstatus;
pid_t child, wait_pid;
child = (pid_t)rsrc->ptr;
do {
wait_pid = waitpid(child, &wstatus, 0);
} while (wait_pid == -1 && errno == EINTR);
if (wait_pid == -1)
FG(pclose_ret) = -1;
else
FG(pclose_ret) = WEXITSTATUS(wstatus);
Now, it would be great if a PHP developer could apply this, or something
along these lines, to the source tree to make proc_close() work (and
close my bug!). As I say, I'm no PHP developer, nor even a particularly
good C programmer, so there may well be other things to consider when
applying a fix that I've missed, but this worked for me :)
Thanks,
KimS
--
PHP Development Mailing List <http://www.php.net/>
To unsubscribe, visit: http://www.php.net/unsub.php