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

Reply via email to