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 <sam@hocevar.net>
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 <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
//#include <sys/wait.h>
#include <sys/types.h>
#include <signal.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#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
gitextract_7arvnqt5/ ├── .gitignore ├── COPYING-WTFPL ├── Makefile ├── README.md ├── pact.c └── test.sh
SYMBOL INDEX (3 symbols across 1 files)
FILE: pact.c
type child_proc (line 24) | struct child_proc {
function on_SIGTERM (line 33) | void on_SIGTERM(int signal) {
function main (line 38) | int main(int argc, char *argv[]) {
Condensed preview — 6 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (5K chars).
[
{
"path": ".gitignore",
"chars": 5,
"preview": "pact\n"
},
{
"path": "COPYING-WTFPL",
"chars": 483,
"preview": " DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE\n Version 2, December 2004\n\n Copyright (C) 200"
},
{
"path": "Makefile",
"chars": 185,
"preview": "CFLAGS = -O2 -Wall -Werror -std=c99\nifeq ($(debug),1)\n\tCFLAGS += -DPRINT_DEBUG=1\nendif\n\npact: pact.c\n\tgcc pact.c ${CFLAG"
},
{
"path": "README.md",
"chars": 820,
"preview": "# pact\n\nGive pact several process IDs. When one process ID dies, pact will kill all\nprovided PIDs.\n\nExample usage:\n\n "
},
{
"path": "pact.c",
"chars": 2968,
"preview": "#define _POSIX_SOURCE\n#define _POSIX_C_SOURCE 199309L\n\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#incl"
},
{
"path": "test.sh",
"chars": 227,
"preview": "#!/bin/bash\n\necho \"shell at $$\"\n\n(sleep 24h)&\nPID1=$!\necho \"sleep1 at $PID1\"\n(sleep 1)&\nPID2=$!\necho \"sleep2 at $PID2\"\n\n"
}
]
About this extraction
This page contains the full source code of the nickodell/pact GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 6 files (4.6 KB), approximately 1.6k tokens, and a symbol index with 3 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.