From 1360a2c5dad6eec56a1dcb975f07d705f58b00b8 Mon Sep 17 00:00:00 2001
From: Brad King <brad.king@kitware.com>
Date: Fri, 2 Jul 2004 16:39:29 -0400
Subject: [PATCH] BUG#392: Implementation of process tree killing for systems
 with /proc filesystem.

---
 ProcessUNIX.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 74 insertions(+), 2 deletions(-)

diff --git a/ProcessUNIX.c b/ProcessUNIX.c
index c8a3d1d..4e31af7 100644
--- a/ProcessUNIX.c
+++ b/ProcessUNIX.c
@@ -53,6 +53,7 @@ do.
 #include <errno.h>     /* errno */
 #include <time.h>      /* gettimeofday */
 #include <signal.h>    /* sigaction */
+#include <dirent.h>    /* DIR, dirent */
 
 /* The number of pipes for the child's output.  The standard stdout
    and stderr pipes are the first two.  One more pipe is used to
@@ -98,6 +99,7 @@ static kwsysProcessTime kwsysProcessTimeSubtract(kwsysProcessTime in1, kwsysProc
 static void kwsysProcessSetExitException(kwsysProcess* cp, int sig);
 static void kwsysProcessChildErrorExit(int errorPipe);
 static void kwsysProcessRestoreDefaultSignalHandlers(void);
+static void kwsysProcessKill(pid_t process_id);
 
 /*--------------------------------------------------------------------------*/
 /* Structure containing data used to implement the child's execution.  */
@@ -992,7 +994,7 @@ void kwsysProcess_Kill(kwsysProcess* cp)
     {
     if(cp->ForkPIDs[i])
       {
-      kill(cp->ForkPIDs[i], SIGKILL);
+      kwsysProcessKill(cp->ForkPIDs[i]);
       }
     }
 }
@@ -1090,7 +1092,7 @@ static void kwsysProcessCleanup(kwsysProcess* cp, int error)
         {
         if(cp->ForkPIDs[i])
           {
-          kill(cp->ForkPIDs[i], SIGKILL);
+          kwsysProcessKill(cp->ForkPIDs[i]);
           }
         }
       }
@@ -1716,3 +1718,73 @@ static void kwsysProcessRestoreDefaultSignalHandlers(void)
   sigaction(SIGUNUSED, &act, 0);
 #endif
 }
+
+/*--------------------------------------------------------------------------*/
+static void kwsysProcessKill(pid_t process_id)
+{
+  DIR* procdir;
+
+  /* Suspend the process to be sure it will not create more children.  */
+  kill(process_id, SIGSTOP);
+
+  /* Kill all children if we can find them.  Currently this works only
+     on systems that support the proc filesystem.  */
+  if((procdir = opendir("/proc")) != NULL)
+    {
+#if defined(MAXPATHLEN)
+    char fname[MAXPATHLEN];
+#elif defined(PATH_MAX)
+    char fname[PATH_MAX];
+#else
+    char fname[4096];
+#endif
+    const int bufferSize = 1024;
+    char buffer[bufferSize+1];
+    struct dirent* d;
+
+    /* Each process has a directory in /proc whose name is the pid.
+       Within this directory is a file called stat that has the
+       following format:
+
+         pid (command line) status ppid ...
+
+       We want to get the ppid for all processes.  Those that have
+       process_id as their parent should be recursively killed.  */
+    for(d = readdir(procdir); d; d = readdir(procdir))
+      {
+      int pid;
+      if(sscanf(d->d_name, "%d", &pid) == 1 && pid != 0)
+        {
+        struct stat finfo;
+        sprintf(fname, "/proc/%d/stat", pid);
+        if(stat(fname, &finfo) == 0)
+          {
+          FILE* f = fopen(fname, "r");
+          if(f)
+            {
+            int nread = fread(buffer, 1, bufferSize, f);
+            buffer[nread] = '\0';
+            if(nread > 0)
+              {
+              const char* rparen = strrchr(buffer, ')');
+              int ppid;
+              if(rparen && (sscanf(rparen+1, "%*s %d", &ppid) == 1))
+                {
+                if(ppid == process_id)
+                  {
+                  /* Recursively kill this child and its children.  */
+                  kwsysProcessKill(pid);
+                  }
+                }
+              }
+            fclose(f);
+            }
+          }
+        }
+      }
+    closedir(procdir);
+    }
+
+  /* Kill the process.  */
+  kill(process_id, SIGKILL);
+}
-- 
GitLab