*BSD News Article 93008


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 &regexp($_);
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