#/usr/bin/perl

$BSD = -f '/vmunix';

$_ = $0;
if ($_ =~ /KILL$/) {
    if ($#ARGV >= 0) {
	$_ .= ' ' . shift;
    }
    else {
	$_ .= ' appl';
    }
}

$ENV{'IFS'} = '' if $ENV{'IFS'};        # plug sh security hole
$applbin = '/appl/bin';
$ENV{'PATH'} = "$applbin:/bin:/usr/bin:/usr/local/bin";

if (/xyz/) {
    do killsys('xyz');
}
elsif (/def/) {
    do killsys('def');
}
elsif (/abc/) {
    do killsys('abc');
}
elsif (/appl/) {
    @ARGV = ();
    do killsys('xyz');
    do killsys('def');
    do killsys('abc');
    do killipc();
    do killall();
    sleep 1;                    # give them a chance to die
    if (&count_attached()) {
	sleep 5;                # give them a longer chance
	if (&count_attached()) {
	    die <<CURTAINS;
WARNING: I can't find all the processes with shared memory.
CURTAINS
	}
    }
}
else {
    die "Usage: KILL subsystem [pids]";
}
exit 0;

sub killsys {
    $sys = shift(@_);
    if ($sys =~ /xyz/) {
	$pat1 = ' xyzzy$| plugh$| plover$';
	$pat2 = 'xyzzy|plugh';
    }
    elsif ($sys =~ /def/) {
	$pat1 = ' def$| [a-zA-Z].def$';
	$pat2 = 'def';
    }
    elsif ($sys =~ /abc/) {
	$pat1 = ' abcdaemon$';
	$pat2 = 'abc';
    }
    else {
	die "Internal error, stopped";
    }

# If no pids specified, make up our own list

    if ($#ARGV < 0) {
	if ($BSD) {
	    open(PS, '/bin/ps axc|') || warn "Can't run ps\n";
	}
	else {
	    open(PS, '/bin/ps -ef|') || warn "Can't run ps\n";
	}

	while (<PS>) {
	    if ($BSD) {
		$pid = $_ + 0;
	    }
	    else {
		$pid = substr($_,9,6) + 0;
		$COMMAND = index($_,"COMMAND") if $COMMAND < 1;
		$_ = substr($_,$COMMAND);
		@ary = split;
		$_ = shift(@ary);
		s|.*/||;
		$_ = ' ' . $_;
	    }
	    push(ARGV,$pid) if $_ =~ $pat1;
	}
	warn "No $sys processes found.\n" unless @ARGV;
	close(PS);
	$checking = 0;
    }
    else {
	$checking++;    # we'll need to check propriety
    }

    # now get info necessary for logging

    chop($date = `date`);
    $date =~ s/ [A-Z][DS]T 19[89][0-9]//;
    chop($whoami = `who am i`);
    $whoami =~ s/[ \t]+/ /g;
    $whoami =~ s/^[a-z]*!//;

    while ($pid = shift) {
	open(KILLLOG,">>/local/tmp/${sys}_kill_log");
	if ($checking && `/bin/ps -p$pid` !~ $pat2) {
	    print KILLLOG $date, ' ', $whoami,
	      " not allowed to kill ",$pid,"\n";
	    print "$pid is not a $sys process!\n";
	}
	else {
	    print KILLLOG $date, ' ', $whoami,
	      ' killed ',$pid,"\n";
	    $pid =~ /(.*)/;
	    $pid = $1;
	    kill 15, $pid;    # Give 'em a shot across the bow.
	    sleep(5);         # I hope this is long enough...
	    kill 9, $pid;     # Deep six 'em.
	}
	close(KILLLOG);
    }
}

sub killipc {
    @goners = ();
    open(IPCS,"ipcs -a |") || warn "Can't run ipcs\n";
    while (<IPCS>) {
	$LSPID = index($_,'LSPID') unless $LSPID > 0;
	$LRPID = index($_,'LRPID') unless $LRPID > 0;
	$CPID = index($_,' CPID') unless $CPID > 0;
	$LPID = index($_,' LPID') unless $LPID > 0;
	$SEGSZ = index($_,'SEGSZ') unless $SEGSZ > 0;
	if (/^q/) {
	    if ($LSPID > 0) {
		$pid = substr($_,$LSPID,6) + 0;
		$pid =~ /^(\d+)$/;      # Untaint $pid.
		$pid = $1;
		push(@goners,$pid) if $pid > 1;
	    }
	    if ($LRPID > 0) {
		$pid = substr($_,$LSPID,6) + 0;
		$pid =~ /^(\d+)$/;      # Untaint $pid.
		$pid = $1;
		push(@goners,$pid) if $pid > 1;
	    }
	}

	elsif (/^m/) {
	    next if substr($_,$SEGSZ,6) == 4096;
	    if ($CPID > 0) {
		$pid = substr($_,$CPID,6) + 0;
		$pid =~ /^(\d+)$/;      # Untaint $pid.
		$pid = $1;
		push(@goners,$pid) if $pid > 1;
	    }
	    if ($LPID > 0) {
		$pid = substr($_,$LPID,6) + 0;
		$pid =~ /^(\d+)$/;      # Untaint $pid.
		$pid = $1;
		push(@goners,$pid) if $pid > 1;
	    }
	}
    }
    close(IPCS);

    kill 9, @goners;
}

sub killall {
    @goners = ();
    if ($BSD) {
	open(PS, '/bin/ps axww|') || warn "Can't run ps\n";
    }
    else {
	open(PS, '/bin/ps -ef|') || warn "Can't run ps\n";
    }
    $head = <PS>;
    $COMMAND = index($head,"COMMAND") if $COMMAND <= 0;
    while (<PS>) {
	if ($BSD) {
	    $pid = $_ + 0;
	}
	else {
	    $pid = substr($_,9,6) + 0;
	}
	$cmd = substr($_,$COMMAND);
	@ary = split(' ',$cmd);
	$_ = shift(@ary);
	s|.*/||;
	if (/^(perl|csh|sh|\[.*\])$/) { # Ignore 1st argument?
	    $_ = shift(@ary);
	    s|.*/||;
	}

	$prog = $_;
	if (! -f "$applbin/$prog" && $cmd =~ /\((\w+)\)/) {
	    $prog = $1;
	}
	if ($prog eq 'START'
	  || $prog eq '.START'
	  || $prog eq 'wall'
	  || ($prog =~ /KILL$/ && $pid != $$)) {
	    push(@finally,"$pid $prog");
	    next;
	}
	next if $prog =~ /KILL$/;
	if (-f "$applbin/$prog") {
	    $pid =~ /(.*)/;
	    $pid = $1;
	    push(goners,$pid);
	    print "Killing $prog, pid $pid\n";
	}
    }
    close(PS);

    kill 15,@goners;
    sleep(5);
    kill 9,@goners;

    if ($#finally >= 0) {
	sleep(6);
	for (@finally) {
	    ($pid,$prog) = split;
	    $pid =~ /(\d+)/;
	    $pid = $1;
	    print "Killing $prog, pid $pid\n" if kill 9,$pid;
	}
    }
}

sub count_attached {
    $attached = 0;
    open(IPCS,"ipcs -a |") || warn "Can't run ipcs\n";
    $ipcrm = '';
    while (<IPCS>) {
	$SEGSZ = index($_,'SEGSZ') unless $SEGSZ > 0;
	$NATTCH = index($_,'NATTCH') unless $NATTCH > 0;
	$killnum = $1 if /^[msq]\s*(\d+)/;
	if (/^m/) {
	    next if substr($_,$SEGSZ,6) == 4096;
	    $ipcrm .= " -m $killnum";
	    $attached += substr($_,$NATTCH,6) if $NATTCH > 0;
	}
	elsif (/^s/) {
	    $ipcrm .= " -s $killnum";
	}
	elsif (/^q/) {
	    $ipcrm .= " -q $killnum";
	}
    }
    close(IPCS);
    if ($ipcrm) {
	$ipcrm =~ /(.*)/;
	$ipcrm = $1;
	print "ipcrm$ipcrm\n";
	system "ipcrm$ipcrm";
    }
    $attached;
}