Return to BSD News archive
Path: euryale.cc.adfa.oz.au!newshost.carno.net.au!harbinger.cc.monash.edu.au!munnari.OZ.AU!news.ecn.uoknor.edu!news.wildstar.net!news.ececs.uc.edu!newsxfer.itd.umich.edu!newsxfer3.itd.umich.edu!su-news-hub1.bbnplanet.com!cpk-news-hub1.bbnplanet.com!news.bbnplanet.com!ais.net!news.idt.net!out2.nntp.cais.net!news2.cais.com!news
From: Vivek Khera <khera@kciLink.com>
Newsgroups: comp.unix.bsd.bsdi.misc
Subject: Re: BSDI3.0 and Skill (superkill)
Date: 07 Apr 1997 00:12:16 -0400
Organization: Khera Communications, Inc., Rockville, MD
Lines: 385
Message-ID: <x7wwqfii8v.fsf@kci.kciLink.com>
References: <3347c498.0@news.nucleus.com>
NNTP-Posting-Host: 204.117.82.1
Mime-Version: 1.0 (generated by tm-edit 7.106)
Content-Type: text/plain; charset=US-ASCII
X-Newsreader: Gnus v5.4.37/XEmacs 19.15
Xref: euryale.cc.adfa.oz.au comp.unix.bsd.bsdi.misc:6605
I use a perl version of skill that has worked fine since BSD/OS 2.1.
It seems to work on BSD/OS 3.0 also, since it only relies on the
output of the ps program to be the same.
#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.1).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
# Made on 1997-04-07 00:12 EDT by <khera@kci.kciLink.com>.
# Source directory was `/usr/local/bin'.
#
# Existing files will *not* be overwritten unless `-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 7808 -rwxr-xr-x skill
#
touch -am 1231235999 $$.touch >/dev/null 2>&1
if test ! -f 1231235999 && test -f $$.touch; then
shar_touch=touch
else
shar_touch=:
echo
echo 'WARNING: not restoring timestamps. Consider getting and'
echo "installing GNU \`touch', distributed in GNU File Utilities..."
echo
fi
rm -f 1231235999 $$.touch
#
# ============= skill ==============
if test -f 'skill' && test X"$1" != X"-c"; then
echo 'x - skipping skill (file already exists)'
else
echo 'x - extracting skill (text)'
sed 's/^X//' << 'SHAR_EOF' > 'skill' &&
#!/usr/bin/perl
# zap -- blow away (or renice) processes
# tom christiansen -- tchrist@usenix.org
#
# currently configured for BSD
#
# Patterned after an idea from K&P, an old script
# of mine, and Jeff Forys's humungous C program, skill. :-)
#
#
# some defaults... look out for the first one!
X
($PRIO_MIN, $PRIO_MAX) = (-64, 64); # from sys/resource.h
$signal = 'TERM';
$priority = +4;
X
###############################################################
X
setpriority(0, $$, $PRIO_MIN); # faster faster faster
$SIG{HUP} = IGNORE;
X
$| = 1;
X
&init;
&parse_args;
&usage unless @cmd || @tty || @pid || @regexp || @user;
&dump_values if $flag{'d'};
&start_ps;
&kill_procs;
exit $status;
X
#####################################################################
X
sub parse_args {
X local($numarg, $type, $signals); # include *targets and die
X
X while ($_ = shift @ARGV) {
X if (/^[-+](\d+)$/) {
X $numarg = $_; # signal or numeric
X }
X elsif (s/^-//) {
X if (defined $signame{$_}) {
X if ($mode eq 'nice') {
X warn "$0: can't mix signals with niceties, ignoring -$_\n";
X } else {
X $signal = $_;
X }
X }
X elsif (s/^([cputr])(.*)//) {
X *targets = $targptr{$type = $abbrev{$1}};
X $_ = $2 || shift @ARGV;
X unless (&targets($_)) {
X die "$0: $_: invalid $type" unless $type eq 'regexp';
X die "$0: $@\n";
X }
X push(@targets, $_);
X }
X else { # these can be anywhere
X $flag{$1}++ while s/^([ildvNna])//;
X if (/[cputr]/) { s/^/-/; redo; } # bad hack
X if ($_ ne '') {
X warn "$0: unknown option -$_\n";
X &usage;
X }
X if ($flag{'l'}) {
X $signals = "\@signum";
X write; # see format at end of file
X exit;
X }
X }
X }
X else { # time to guess
X if ( s!^/dev/!! || &tty($_)) {
X *targets = $targptr{'tty'};
X } elsif (&user($_)) {
X *targets = $targptr{'user'};
X } elsif (&pid($_)) {
X *targets = $targptr{'pid'};
X } elsif (s!^/(.*)/?$!$1!) {
X die "$0: $@\n" unless ®exp($_);
X *targets = $targptr{'regexp'};
X } else {
X *targets = $targptr{'cmd'};
X }
X push(@targets,$_);
X }
X }
X
X $mode = 'nice' if $flag{'N'};
X
X if (defined $numarg) {
X if ($mode eq 'kill') {
X $numarg =~ s/^[-+]//;
X $signal = $numarg ? $signum[$numarg] : 0; # perl hates 'ZERO'
X } else {
X undef $signal;
X $priority = $numarg;
X $priority = $PRIO_MIN if $priority < $PRIO_MIN;
X $priority = $PRIO_MAX if $priority > $PRIO_MAX;
X }
X }
X
}
X
X
#####################################################################
X
sub uid2name {
X local($uid) = @_;
X unless (defined $name{$uid}) {
X local($name) = (getpwuid($uid))[0];
X $uid{$name} = $uid;
X $name{$uid} = $name;
X }
X $name{$uid};
}
X
sub name2uid {
X local($name) = @_;
X unless (defined $uid{$name}) {
X local($uid) = (getpwnam($name))[2];
X $uid{$name} = $uid;
X $name{$uid} = $name;
X }
X $uid{$name};
}
X
######################################################################
# magic names here -- touch these and you are apt to be surprised
X
sub pid {
X local($pid) = @_;
X $pid =~ /^\d+$/;
}
X
sub tty {
X local($tty) = @_;
X $tty =~ /^tty/ && -c "/dev/$tty";
}
X
sub user {
X local($who) = @_;
X local($ok) = &name2uid($who);
X defined $ok;
}
X
sub cmd {
X 1;
}
X
sub regexp {
X local($pat) = @_;
X eval '/$pat/';
X $@ =~ s/at \(eval\).*\n//;
X $@ eq '';
}
X
######################################################################
X
sub init {
X
# run either as skill or as snice; this tells whether -5 is a
# signal or a priority
X
X $mode = 'kill';
X $mode = 'nice' if $0 =~ /nice/;
X
# generate signal names ; comment out signames assignment
# to run kill -l instead to figure it out
X
X $signames = <<__EOLIST__; # comment out for dynamic determination
X HUP INT QUIT ILL TRAP IOT EMT FPE KILL BUS SEGV SYS PIPE ALRM
X TERM URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ VTALRM PROF
X WINCH INFO USR1 USR2
__EOLIST__
X
X local($signal);
X $signum[0] = 'ZERO';
X for (split(' ', $signames ? $signames : `kill -l`)) {
X $signame{$_} = ++$signal;
X $signum[$signal] = $_;
X }
X
# set up pointers and single-char abbrev for our 4 target arrays
# if you change one of strings, all idents of this name, including
# the subroutines, must change also. be VERY CAREFUL.
X
X for ('cmd', 'pid', 'user', 'tty', 'regexp') {
X $abbrev{(/^(.)/)[0]} = $_;
X $targptr{$_} = eval "*$_";
X }
X
# some defaults
X
}
X
#####################################################################
X
sub dump_values {
X print "signal is $signal -$signame{$signal}\n" if $mode eq 'kill';
X print "will renice targets to $priority\n" if $mode eq 'nice';
X
X for (keys %targptr) {
X *targ = $targptr{$_};
X next unless defined @targ;
X print "$_ targets are ", join(', ', @targ), "\n";
X }
X
X @flags = keys %flag;
X grep(s/^/-/, @flags);
X print "option flags are @flags\n";
}
X
#####################################################################
X
sub usage {
X die <<EOF;
Usage:
X skill [-signal] [-Nildvna] {tty user command pid regexp}
X snice [(-|+)priority] [-Nildvna] {tty user command pid regexp}
X
X -i interactive
X -v show candidates
X -n like -v but do not really do it
X -a all procs are candidates
X -N nice mode
X -d enable debugging
X
X -l list signals and exit
X
X Uniquely identify {...} args with leading -t, -u, -c, -p, -r
X Or use a leading slash for a regexp.
EOF
X exit 1;
}
X
######################################################################
X
sub start_ps {
X $ps = 'ps xl';
X $ps .= 'w';
X
X grep($pid{$_}++, @pid);
X grep($user{&name2uid($_)}++, @user);
X grep($tty{$_}++, @tty);
X grep($cmd{$_}++, @cmd);
X $regexp = join('|', @regexp);
X
X $ps .= 'w' if $regexp;
X $ps .= 'a' if $> == 0 ||
X $flag{'a'} ||
X @user > 1 ||
X (@user == 1 && &name2uid($user[0]) != $>);
X
# if (! $pattern && @cmd && !grep(m!^/!, @cmd)) { $ps .= 'c'; }
X
X if (@tty == 1) { # faster
X $tty[0] =~ /^tty(..)/;
X $ps .= "t$1";
X }
X
X print "ps command is $ps\n" if $flag{'d'};
X
X defined($kid_pid = open(PS, "$ps |")) || die "can't run ps: $!";
X if (<PS> !~ /UID/) {
X warn "Something's wrong with ps";
X kill 'TERM', $kid_pid;
X exit 2;
X }
X
X $dad_pid = getppid();
}
X
######################################################################
X
sub kill_procs {
X while (<PS>) {
X # first two fields on BSDi
X ($user, $pid) = /^\s*(\d+)\s*(\d+)/i;
X
X next if $pid == $$;
X next if $pid == $kid_pid;
X next if $pid == $dad_pid && $mode eq 'kill';
X
X next if @user && !$user{$user};
X next if @pid && !$pid{$pid};
X
X # time is in dd:dd.dd format on BSDi
X ($tty, $cmd) = /\s*(\S*)\s*\d+:\d+\.\d+\s+(.*)$/;
X $tty = "tty$tty" unless $tty =~ /\?/;
X
X next if @tty && !$tty{$tty};
X next if @regexp && $cmd !~ /$regexp/o;
X
X if (@cmd) {
X ($cmdname) = ($cmd =~ /^(\S+)/);
X $cmdname =~ s!.*/!!;
X next if !$cmd{$cmd} && !$cmd{$cmdname};
X }
X
X printf "%5d %-8s %-5s %s ", $pid, &uid2name($user), $tty, $cmd
X if $flag{'v'} || $flag{'i'} || $flag{'n'};
X
X if ($flag{'i'}) {
X $_ = <STDIN>;
X defined || exit;
X /^\s*y/i || next;
X }
X
X $hits++;
X
X unless ($flag{'n'}) {
X $! = 0;
X if ($mode eq 'kill') {
X kill $signal, $pid;
X } else {
X setpriority(0, $pid, $priority);
X }
X if ($!) {
X warn (($mode eq 'kill' ? 'kill' : 'setpriority')
X . " $pid: $!\n");
X $status = 1;
X next;
X }
X }
X
X print "\n" if $flag{'v'} || $flag{'n'};
X }
X close PS || die "something happened to your $ps";
X warn "$0: no target processes found\n" unless $hits;
}
X
######################################################################
X
format STDOUT =
Any of the following signals are valid, or their numeric equivalents:
X~~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
X $signals
X.
SHAR_EOF
$shar_touch -am 0204173396 'skill' &&
chmod 0755 'skill' ||
echo 'restore of skill failed'
shar_count="`wc -c < 'skill'`"
test 7808 -eq "$shar_count" ||
echo "skill: original size 7808, current size $shar_count"
fi
exit 0