Repository: nickodell/pact Branch: master Commit: 9bb7d2e981d1 Files: 6 Total size: 4.6 KB Directory structure: gitextract_7arvnqt5/ ├── .gitignore ├── COPYING-WTFPL ├── Makefile ├── README.md ├── pact.c └── test.sh ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ pact ================================================ FILE: COPYING-WTFPL ================================================ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE Version 2, December 2004 Copyright (C) 2004 Sam Hocevar Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long as the name is changed. DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. You just DO WHAT THE FUCK YOU WANT TO. ================================================ FILE: Makefile ================================================ CFLAGS = -O2 -Wall -Werror -std=c99 ifeq ($(debug),1) CFLAGS += -DPRINT_DEBUG=1 endif pact: pact.c gcc pact.c ${CFLAGS} -o pact install: pact cp pact /bin/pact clean: rm -f pact ================================================ FILE: README.md ================================================ # pact Give pact several process IDs. When one process ID dies, pact will kill all provided PIDs. Example usage: #!/bin/bash cmd1 & PID1=$! cmd2 --some-arg & PID2=$! ./pact $PID1 $PID2 ##Advanced usage pact also accepts a one character modifier before the process ID. It can be either M or K. M monitors the process without killing it, and K will not monitor the process, but it will kill the process if another monitored process dies. Example: #!/bin/bash (sleep 5)& PID1=$! (sleep 24h)& PID2=$! # If the shell dies, kill the other processes. If one of the # processes die, don't kill the shell. ./pact $PID1 $PID2 M$$ # Pause, because otherwise the shell will immediately die and pact # will kill the subprocesses. pause ================================================ FILE: pact.c ================================================ #define _POSIX_SOURCE #define _POSIX_C_SOURCE 199309L #include #include #include #include //#include #include #include #include #include #include #include #ifdef PRINT_DEBUG #define DEBUG(...) fprintf(stdout, __VA_ARGS__) #else #define DEBUG(...) #endif #define ERROR(...) fprintf(stderr, __VA_ARGS__) struct child_proc { pid_t pid; bool monitorProc; bool killProc; bool procChanged; }; bool killAll = false; void on_SIGTERM(int signal) { killAll = true; } int main(int argc, char *argv[]) { // Trap SIGTERM struct sigaction action; memset(&action, 0, sizeof(struct sigaction)); action.sa_handler = on_SIGTERM; sigaction(SIGTERM, &action, NULL); int numProcs = argc - 1; // Check the arguments are sane and that every argument corresponds // to a process if(argc < 2) { ERROR("You must give pact some PID's!\n"); ERROR("Usage: %s [K/M]PID ...\n", argv[0]); return 42; } struct child_proc procs[numProcs]; memset(&procs, 0, sizeof(procs)); for(int i = 0; i < numProcs; i++) { char* currentArg = argv[i + 1]; int pid; char modifier; int ret; bool hasModifier = !isdigit(currentArg[0]); if(hasModifier) { DEBUG("Arg has modifier\n"); modifier = currentArg[0]; currentArg++; ret = sscanf(currentArg, "%d", &pid); switch (modifier) { case 'K': procs[i].monitorProc = false; procs[i].killProc = true; break; case 'M': procs[i].monitorProc = true; procs[i].killProc = false; break; default: ERROR("Unrecognized modifier %c\n", modifier); break; } } else { DEBUG("Arg has no modifier\n"); ret = sscanf(currentArg, "%d", &pid); procs[i].monitorProc = true; procs[i].killProc = true; } if(ret != 1) { ERROR("Error - \"%s\" is not a valid argument.\n", currentArg); killAll = true; } else { procs[i].pid = pid; } } // Fork and let the child handle the work int ret = fork(); if(ret > 0) { exit(0); } else if(ret < 0) { ERROR("Cannot fork()\n"); } else if(ret == 0) { // We're the child, continue with the program } // Wait for one of those processes to die while(!killAll) { for(int i = 0; i < numProcs; i++) { pid_t pid = procs[i].pid; if(kill(pid, 0) == -1) { // Process no longer exists, don't kill it // later procs[i].procChanged = true; // Don't start killing processes if we got // the K modifier for this process if(procs[i].monitorProc) { killAll = true; break; } } } if(!killAll) { DEBUG("Sleeping\n"); struct timespec ts; ts.tv_sec = 1; ts.tv_nsec = 0; nanosleep(&ts, NULL); } } // Kill all other processes for(int i = 0; i < numProcs; i++) { pid_t pid = procs[i].pid; if(!procs[i].killProc || procs[i].procChanged || pid == 0) { continue; } DEBUG("Killing %d\n", pid); kill(pid, SIGTERM); } return 0; } ================================================ FILE: test.sh ================================================ #!/bin/bash echo "shell at $$" (sleep 24h)& PID1=$! echo "sleep1 at $PID1" (sleep 1)& PID2=$! echo "sleep2 at $PID2" ./pact $PID1 $PID2 ps -A | grep $PID1 ps -A | grep $PID2 #read #ps -A | grep $PID1 #ps -A | grep $PID2