I am using the following code in order to run some commands using parent/child:
int nStatus = 0;
int nRet = 0;
pid_t pid = -1;
char *envp[] =
{
"LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/tmp",
0
};
if(pnChildExitStatus == NULL || pcBuf == NULL)
{
nRet = -EINVAL;
goto returnHandler;
}
*pnChildExitStatus = 0;
pid = fork();
switch(pid)
{
case -1:
nRet = -errno; //can't fork
break;
case 0: //child
nRet = execl("/bin/sh","sh","-c", pcBuf, envp,NULL);
if (-1 == nRet) {
nRet = -errno;
goto returnHandler;
}
break;
default: //parent
/*After this call 'nStatus' is an encoded exit value. WIF macros will extract how it exited*/
if( waitpid(pid, &nStatus, 0) < 0 )
{
nRet = -errno;
*pnChildExitStatus = errno;
}
if(WIFEXITED(nStatus))
{
nRet = EXIT_SUCCESS;
*pnChildExitStatus = WEXITSTATUS(nStatus);
}
goto returnHandler;
break;
}
returnHandler:
return nRet;
}
My problem is as follows:
In some cases, Parent receives WEXITSTATUS(nStatus) != 0, although my child process always return 0 (I verified it with debug prints).
Can someone offer any idea on how is this possible?
Thank you all in advance.
Your use of waitpid() is flawed.
If waitpid() is interrupted it will return -1,
however the value in nStatus may be undefined,
thus if (WIFEXITED(nStatus)) could still be true
and WEXITSTATUS(nStatus) could be anything.
What can interrupt a syscall, (like waitpid)?
A signal, like, SIGCHLD, for an exiting child.
The normal pattern is something like:
while ((wpid = waitpid(pid, &nStatus, 0)) != pid) {
if (wpid == -1) { /* see below */
if (errno == EINTR) continue;
/* else handle the other error (pretty unlikely) */
/* probably by returning something */
}
}
if (wpid == -1) { /* error */ } /* if you choose to `break' from the loop on error */
else { /* process exited */ } /* you need to check the situation here */
The if (wpid == -1) is a bit superfluous here, as the only value wpid could have inside this loop is -1, but other variants of this pattern do not constrain wpid so tightly, so it's defensive programming against a change.
Similarly with if (errno == EINTR) as the only 3 errnos from most (all?) waitpids are: EINTR, ECHILD (no children), and EFAULT (you got the 2nd arg wrong). But, again, defensive programming.