Attempt to keep running if a child process dies.
authorSimon Kelley <simon@thekelleys.org.uk>
Mon, 13 Jan 2025 10:56:19 +0000 (10:56 +0000)
committerSimon Kelley <simon@thekelleys.org.uk>
Mon, 13 Jan 2025 10:56:19 +0000 (10:56 +0000)
If a child process dies unexpectedly, log the error and
try and tidy up so the main process continues to run and
doesn't block awaiting the dead child.

src/dnsmasq.c

index fc35018..5b89455 100644 (file)
@@ -1484,7 +1484,7 @@ static void async_event(int pipe, time_t now)
 {
   pid_t p;
   struct event_desc ev;
-  int i, check = 0;
+  int wstatus, i, check = 0;
   char *msg;
   
   /* NOTE: the memory used to return msg is leaked: use msgs in events only
@@ -1547,7 +1547,7 @@ static void async_event(int pipe, time_t now)
                
       case EVENT_CHILD:
        /* See Stevens 5.10 */
-       while ((p = waitpid(-1, NULL, WNOHANG)) != 0)
+       while ((p = waitpid(-1, &wstatus, WNOHANG)) != 0)
          if (p == -1)
            {
              if (errno != EINTR)
@@ -1558,6 +1558,20 @@ static void async_event(int pipe, time_t now)
              if (daemon->tcp_pids[i] == p)
                {
                  daemon->tcp_pids[i] = 0;
+
+                 if (!WIFEXITED(wstatus))
+                   {
+                     /* If a helper process dies, (eg with SIGSEV)
+                        log that and attempt to patch things up so that the 
+                        parent can continue to function. */
+                     my_syslog(LOG_WARNING, _("TCP helper process %u died unexpectedly"), (unsigned int)p);
+                     if (daemon->tcp_pipes[i] != -1)
+                       {
+                         close(daemon->tcp_pipes[i]);
+                         daemon->tcp_pipes[i] = -1;
+                       }
+                   }
+                 
                  /* tcp_pipes == -1 && tcp_pids == 0 required to free slot */
                  if (daemon->tcp_pipes[i] == -1)
                    daemon->metrics[METRIC_TCP_CONNECTIONS]--;
@@ -2092,7 +2106,7 @@ static void do_tcp_connection(struct listener *listener, time_t now, int slot)
      Reset that here. */
   if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
     while(retry_send(fcntl(confd, F_SETFL, flags & ~O_NONBLOCK)));
-  
+
   buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
              
   if (buff)