slirp: Avoid zombie processes after fork_exec

Slirp uses fork_exec for spawning service processes, and QEMU uses this
for running smbd. As SIGCHLD is not handled, these processes become
zombies on termination. Fix this by installing a proper signal handler,
but also make sure we disable the signal while waiting on forked network
setup/shutdown scripts.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Mark McLoughlin <markmc@redhat.com>
This commit is contained in:
Jan Kiszka 2009-05-08 12:34:17 +02:00 committed by Mark McLoughlin
parent c27ff60871
commit 7c3370d4fe
2 changed files with 44 additions and 27 deletions

58
net.c
View File

@ -1134,38 +1134,46 @@ static int tap_open(char *ifname, int ifname_size)
static int launch_script(const char *setup_script, const char *ifname, int fd) static int launch_script(const char *setup_script, const char *ifname, int fd)
{ {
sigset_t oldmask, mask;
int pid, status; int pid, status;
char *args[3]; char *args[3];
char **parg; char **parg;
/* try to launch network script */ sigemptyset(&mask);
pid = fork(); sigaddset(&mask, SIGCHLD);
if (pid >= 0) { sigprocmask(SIG_BLOCK, &mask, &oldmask);
if (pid == 0) {
int open_max = sysconf (_SC_OPEN_MAX), i;
for (i = 0; i < open_max; i++)
if (i != STDIN_FILENO &&
i != STDOUT_FILENO &&
i != STDERR_FILENO &&
i != fd)
close(i);
parg = args; /* try to launch network script */
*parg++ = (char *)setup_script; pid = fork();
*parg++ = (char *)ifname; if (pid == 0) {
*parg++ = NULL; int open_max = sysconf(_SC_OPEN_MAX), i;
execv(setup_script, args);
_exit(1); for (i = 0; i < open_max; i++) {
} if (i != STDIN_FILENO &&
while (waitpid(pid, &status, 0) != pid); i != STDOUT_FILENO &&
if (!WIFEXITED(status) || i != STDERR_FILENO &&
WEXITSTATUS(status) != 0) { i != fd) {
fprintf(stderr, "%s: could not launch network script\n", close(i);
setup_script);
return -1;
} }
} }
return 0; parg = args;
*parg++ = (char *)setup_script;
*parg++ = (char *)ifname;
*parg++ = NULL;
execv(setup_script, args);
_exit(1);
} else if (pid > 0) {
while (waitpid(pid, &status, 0) != pid) {
/* loop */
}
sigprocmask(SIG_SETMASK, &oldmask, NULL);
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
return 0;
}
}
fprintf(stderr, "%s: could not launch network script\n", setup_script);
return -1;
} }
static int net_tap_init(VLANState *vlan, const char *model, static int net_tap_init(VLANState *vlan, const char *model,

13
vl.c
View File

@ -4783,7 +4783,12 @@ static void termsig_handler(int signal)
qemu_system_shutdown_request(); qemu_system_shutdown_request();
} }
static void termsig_setup(void) static void sigchld_handler(int signal)
{
waitpid(-1, NULL, WNOHANG);
}
static void sighandler_setup(void)
{ {
struct sigaction act; struct sigaction act;
@ -4792,6 +4797,10 @@ static void termsig_setup(void)
sigaction(SIGINT, &act, NULL); sigaction(SIGINT, &act, NULL);
sigaction(SIGHUP, &act, NULL); sigaction(SIGHUP, &act, NULL);
sigaction(SIGTERM, &act, NULL); sigaction(SIGTERM, &act, NULL);
act.sa_handler = sigchld_handler;
act.sa_flags = SA_NOCLDSTOP;
sigaction(SIGCHLD, &act, NULL);
} }
#endif #endif
@ -5918,7 +5927,7 @@ int main(int argc, char **argv, char **envp)
#ifndef _WIN32 #ifndef _WIN32
/* must be after terminal init, SDL library changes signal handlers */ /* must be after terminal init, SDL library changes signal handlers */
termsig_setup(); sighandler_setup();
#endif #endif
/* Maintain compatibility with multiple stdio monitors */ /* Maintain compatibility with multiple stdio monitors */