From e6145d6878d0733d9ec39a2690a5fd7e4978ebd8 Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 2 Jul 2004 16:39:29 -0400 Subject: BUG#392: Implementation of process tree killing for systems with /proc filesystem. --- Source/kwsys/ProcessUNIX.c | 76 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 2 deletions(-) diff --git a/Source/kwsys/ProcessUNIX.c b/Source/kwsys/ProcessUNIX.c index b5c1e19..d05213c 100644 --- a/Source/kwsys/ProcessUNIX.c +++ b/Source/kwsys/ProcessUNIX.c @@ -53,6 +53,7 @@ do. #include /* errno */ #include /* gettimeofday */ #include /* sigaction */ +#include /* 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); +} -- cgit v0.12