libport: For spawnvp(_P_DETACH, ...), double-fork to avoid creating zombies.

This commit is contained in:
Ken Thomases 2011-11-30 16:49:37 -06:00 committed by Alexandre Julliard
parent abe6a13ff1
commit fda27ccc1b
1 changed files with 30 additions and 5 deletions

View File

@ -36,7 +36,7 @@
int spawnvp(int mode, const char *cmdname, const char *const argv[]) int spawnvp(int mode, const char *cmdname, const char *const argv[])
{ {
#ifndef HAVE__SPAWNVP #ifndef HAVE__SPAWNVP
int pid = 0, status, wret; int pid, status, wret;
if (mode == _P_OVERLAY) if (mode == _P_OVERLAY)
{ {
@ -51,20 +51,45 @@ int spawnvp(int mode, const char *cmdname, const char *const argv[])
pid = fork(); pid = fork();
if (pid == 0) if (pid == 0)
{ {
/* in child */
if (mode == _P_DETACH)
{
pid = fork();
if (pid == -1) _exit(1);
else if (pid > 0) _exit(0);
/* else in grandchild */
}
signal( SIGPIPE, SIG_DFL ); signal( SIGPIPE, SIG_DFL );
execvp(cmdname, (char **)argv); execvp(cmdname, (char **)argv);
_exit(1); _exit(1);
} }
if (pid != -1 && mode == _P_OVERLAY) exit(0); if (pid == -1)
return -1;
if (pid != -1 && mode == _P_WAIT) if (mode == _P_OVERLAY) exit(0);
if (mode == _P_WAIT || mode == _P_DETACH)
{ {
while (pid != (wret = waitpid(pid, &status, 0))) while (pid != (wret = waitpid(pid, &status, 0)))
if (wret == -1 && errno != EINTR) break; if (wret == -1 && errno != EINTR) break;
if (pid == wret && WIFEXITED(status)) pid = WEXITSTATUS(status); if (pid == wret && WIFEXITED(status))
else pid = 255; /* abnormal exit with an abort or an interrupt */ {
if (mode == _P_WAIT)
pid = WEXITSTATUS(status);
else /* mode == _P_DETACH */
if (WEXITSTATUS(status) != 0) /* child couldn't fork grandchild */
pid = -1;
}
else
{
if (mode == _P_WAIT)
pid = 255; /* abnormal exit with an abort or an interrupt */
else /* mode == _P_DETACH */
pid = -1;
}
} }
return pid; return pid;