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,38 +1134,46 @@ static int tap_open(char *ifname, int ifname_size)
1134 1134
1135 static int launch_script(const char *setup_script, const char *ifname, int fd) 1135 static int launch_script(const char *setup_script, const char *ifname, int fd)
1136 { 1136 {
  1137 + sigset_t oldmask, mask;
1137 int pid, status; 1138 int pid, status;
1138 char *args[3]; 1139 char *args[3];
1139 char **parg; 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 static int net_tap_init(VLANState *vlan, const char *model, 1179 static int net_tap_init(VLANState *vlan, const char *model,
@@ -4783,7 +4783,12 @@ static void termsig_handler(int signal) @@ -4783,7 +4783,12 @@ static void termsig_handler(int signal)
4783 qemu_system_shutdown_request(); 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 struct sigaction act; 4793 struct sigaction act;
4789 4794
@@ -4792,6 +4797,10 @@ static void termsig_setup(void) @@ -4792,6 +4797,10 @@ static void termsig_setup(void)
4792 sigaction(SIGINT, &act, NULL); 4797 sigaction(SIGINT, &act, NULL);
4793 sigaction(SIGHUP, &act, NULL); 4798 sigaction(SIGHUP, &act, NULL);
4794 sigaction(SIGTERM, &act, NULL); 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 #endif 4806 #endif
@@ -5918,7 +5927,7 @@ int main(int argc, char **argv, char **envp) @@ -5918,7 +5927,7 @@ int main(int argc, char **argv, char **envp)
5918 5927
5919 #ifndef _WIN32 5928 #ifndef _WIN32
5920 /* must be after terminal init, SDL library changes signal handlers */ 5929 /* must be after terminal init, SDL library changes signal handlers */
5921 - termsig_setup(); 5930 + sighandler_setup();
5922 #endif 5931 #endif
5923 5932
5924 /* Maintain compatibility with multiple stdio monitors */ 5933 /* Maintain compatibility with multiple stdio monitors */