Commit 7c3370d4fe3fa6cda8655f109e4659afc8ca4269

Authored by Jan Kiszka
Committed by Mark McLoughlin
1 parent c27ff608

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>
Showing 2 changed files with 45 additions and 28 deletions
... ... @@ -1134,38 +1134,46 @@ static int tap_open(char *ifname, int ifname_size)
1134 1134  
1135 1135 static int launch_script(const char *setup_script, const char *ifname, int fd)
1136 1136 {
  1137 + sigset_t oldmask, mask;
1137 1138 int pid, status;
1138 1139 char *args[3];
1139 1140 char **parg;
1140 1141  
1141   - /* try to launch network script */
1142   - pid = fork();
1143   - if (pid >= 0) {
1144   - if (pid == 0) {
1145   - int open_max = sysconf (_SC_OPEN_MAX), i;
1146   - for (i = 0; i < open_max; i++)
1147   - if (i != STDIN_FILENO &&
1148   - i != STDOUT_FILENO &&
1149   - i != STDERR_FILENO &&
1150   - i != fd)
1151   - close(i);
1152   -
1153   - parg = args;
1154   - *parg++ = (char *)setup_script;
1155   - *parg++ = (char *)ifname;
1156   - *parg++ = NULL;
1157   - execv(setup_script, args);
1158   - _exit(1);
1159   - }
1160   - while (waitpid(pid, &status, 0) != pid);
1161   - if (!WIFEXITED(status) ||
1162   - WEXITSTATUS(status) != 0) {
1163   - fprintf(stderr, "%s: could not launch network script\n",
1164   - setup_script);
1165   - return -1;
  1142 + sigemptyset(&mask);
  1143 + sigaddset(&mask, SIGCHLD);
  1144 + sigprocmask(SIG_BLOCK, &mask, &oldmask);
  1145 +
  1146 + /* try to launch network script */
  1147 + pid = fork();
  1148 + if (pid == 0) {
  1149 + int open_max = sysconf(_SC_OPEN_MAX), i;
  1150 +
  1151 + for (i = 0; i < open_max; i++) {
  1152 + if (i != STDIN_FILENO &&
  1153 + i != STDOUT_FILENO &&
  1154 + i != STDERR_FILENO &&
  1155 + i != fd) {
  1156 + close(i);
1166 1157 }
1167 1158 }
1168   - return 0;
  1159 + parg = args;
  1160 + *parg++ = (char *)setup_script;
  1161 + *parg++ = (char *)ifname;
  1162 + *parg++ = NULL;
  1163 + execv(setup_script, args);
  1164 + _exit(1);
  1165 + } else if (pid > 0) {
  1166 + while (waitpid(pid, &status, 0) != pid) {
  1167 + /* loop */
  1168 + }
  1169 + sigprocmask(SIG_SETMASK, &oldmask, NULL);
  1170 +
  1171 + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
  1172 + return 0;
  1173 + }
  1174 + }
  1175 + fprintf(stderr, "%s: could not launch network script\n", setup_script);
  1176 + return -1;
1169 1177 }
1170 1178  
1171 1179 static int net_tap_init(VLANState *vlan, const char *model,
... ...
... ... @@ -4783,7 +4783,12 @@ static void termsig_handler(int signal)
4783 4783 qemu_system_shutdown_request();
4784 4784 }
4785 4785  
4786   -static void termsig_setup(void)
  4786 +static void sigchld_handler(int signal)
  4787 +{
  4788 + waitpid(-1, NULL, WNOHANG);
  4789 +}
  4790 +
  4791 +static void sighandler_setup(void)
4787 4792 {
4788 4793 struct sigaction act;
4789 4794  
... ... @@ -4792,6 +4797,10 @@ static void termsig_setup(void)
4792 4797 sigaction(SIGINT, &act, NULL);
4793 4798 sigaction(SIGHUP, &act, NULL);
4794 4799 sigaction(SIGTERM, &act, NULL);
  4800 +
  4801 + act.sa_handler = sigchld_handler;
  4802 + act.sa_flags = SA_NOCLDSTOP;
  4803 + sigaction(SIGCHLD, &act, NULL);
4795 4804 }
4796 4805  
4797 4806 #endif
... ... @@ -5918,7 +5927,7 @@ int main(int argc, char **argv, char **envp)
5918 5927  
5919 5928 #ifndef _WIN32
5920 5929 /* must be after terminal init, SDL library changes signal handlers */
5921   - termsig_setup();
  5930 + sighandler_setup();
5922 5931 #endif
5923 5932  
5924 5933 /* Maintain compatibility with multiple stdio monitors */
... ...