#!/usr/bin/perl

# killtree [-<SIG>] <pid>...
$sig=15;
if ($ARGV[0] =~ /-[0-9]+$/) {
	$sig=0-$ARGV[0];
	shift;
}

# program name
$prg=$0;
$prg =~ s/.*\///;

# check usage
if ($#ARGV == -1) {
	print STDERR "Usage: $prg [-<SIGNAL>] <pid>...\n";
	exit 1;
}

# run ps to work out process tree
open(PS, "ps -el|");
#F S   UID   PID  PPID  C PRI  NI ADDR    SZ WCHAN  TTY          TIME CMD
#0 S   500 28255 24532  0  82   0    -   409 rt_sig pts/6    00:00:00 ksh
#0 R   500 28258 28255  0  84   0    -   828 -      pts/6    00:00:00 ps
#0 S   500 28259 28255  0  82   0    -   376 pipe_w pts/6    00:00:00 grep
while ($l=<PS>) {
	$l =~ s/\s+/ /g;
	($pflg, $pstat, $puid, $pid, $ppid, @prest)=split(" ", $l);
	# store away each PIDs parent
	$ps{$pid}=$ppid;
}
close PS;

foreach $pid (@ARGV) {
	# set list of PIDs to kill
	if (!$ps{$pid}) {
		# no such PID
		print STDERR "$prg: $pid No such PID\n";
	} else {
		# add PID
		$tokill{$pid}=1;
		# add PIDs whose parent is pid
		&padd($pid);
	}
}

# generate a list
foreach $kpid (keys %tokill) {
	push @pall, $kpid;
}
# kill them all
if (@pall) {
	kill $sig, @pall;
	exit 0;
}
exit 1;

# recursive routine to get children of PID
sub padd() {
	(local $pp)=@_;
	(local @pl, $np, $ch);

	@pl=();
	foreach $ch (keys %ps) {
		# find PIDs whose parent is pp
		if ($ps{$ch} == $pp) {
			# add to global & short list
			$tokill{$ch}=1;
			push @pl, $ch;
		}
	}
	foreach $np (@pl) {
		# recurse on short list
		&padd($np);
	}
}
