home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / perl / scripts-convex / skill < prev    next >
Encoding:
Text File  |  1991-08-09  |  7.5 KB  |  337 lines

  1. #!/usr/local/bin/perl
  2. #
  3. # zap  -- blow away (or renice) processes
  4. # tom christiansen -- tchrist@convex.com
  5. #
  6. # currently configured for BSD
  7. #
  8. # Patterned after an idea from K&P, an old script
  9. # of mine, and Jeff Forys's humungous C program, skill. :-)
  10. #
  11. #
  12. # some defaults... look out for the first one!
  13.  
  14. ($PRIO_MIN, $PRIO_MAX) = (-64, 64);     # from sys/resource.h
  15. $signal   = 'TERM';
  16. $priority = +4;
  17.  
  18. ###############################################################
  19.  
  20. setpriority(0, $$, $PRIO_MIN);      # faster faster faster
  21. $SIG{HUP} = IGNORE;
  22.  
  23. $| = 1;
  24.  
  25. &init;
  26. &parse_args;
  27. &usage unless @cmd || @tty || @pid || @regexp || @user;
  28. &dump_values if $flag{'d'};
  29. &start_ps;
  30. &kill_procs;
  31. exit $status;
  32.  
  33. #####################################################################
  34.  
  35. sub parse_args {
  36.     local($numarg, $type, $signals);  # include *targets and die
  37.  
  38.     while ($_ = shift @ARGV) {
  39.     if (/^[-+](\d+)$/) { 
  40.         $numarg = $_;   # signal or numeric
  41.     } 
  42.     elsif (s/^-//) {
  43.         if (defined $signame{$_}) { 
  44.         if ($mode eq 'nice') {
  45.             warn "$0: can't mix signals with niceties, ignoring -$_\n";
  46.         } else {
  47.             $signal = $_; 
  48.         }
  49.         } 
  50.         elsif (s/^([cputr])(.*)//) {
  51.         *targets = $targptr{$type = $abbrev{$1}};
  52.         $_ = $2 || shift @ARGV;
  53.         unless (&targets($_)) {
  54.             die "$0: $_: invalid $type" unless $type eq 'regexp';
  55.             die "$0: $@\n";
  56.         }
  57.         push(@targets, $_);
  58.         } 
  59.         else {     # these can be anywhere
  60.         $flag{$1}++ while s/^([ildvNna])//; 
  61.         if (/[cputr]/) { s/^/-/; redo; }   # bad hack
  62.         if ($_ ne '') {
  63.             warn "$0: unknown option -$_\n";
  64.             &usage;
  65.         }
  66.         if ($flag{'l'}) {
  67.             $signals = "@signum";
  68.             write; # see format at end of file
  69.             exit;
  70.         } 
  71.         } 
  72.     } 
  73.     else {                     # time to guess
  74.         if ( s!^/dev/!! || &tty($_)) {
  75.         *targets = $targptr{'tty'};
  76.         } elsif (&user($_)) {
  77.         *targets = $targptr{'user'};
  78.         } elsif (&pid($_)) {
  79.         *targets = $targptr{'pid'};
  80.         } elsif (s!^/(.*)/?$!$1!) {
  81.         die "$0: $@\n" unless ®exp($_);
  82.         *targets = $targptr{'regexp'};
  83.         } else {
  84.         *targets = $targptr{'cmd'};
  85.         } 
  86.         push(@targets,$_);
  87.     } 
  88.     } 
  89.  
  90.     $mode = 'nice' if $flag{'N'};
  91.  
  92.     if (defined $numarg) {
  93.     if ($mode eq 'kill') {
  94.         $numarg =~ s/^[-+]//;
  95.         $signal = $numarg ? $signum[$numarg] : 0; #  perl hates 'ZERO'
  96.     } else {
  97.         undef $signal;
  98.         $priority = $numarg;
  99.         $priority = $PRIO_MIN     if $priority < $PRIO_MIN;
  100.         $priority = $PRIO_MAX     if $priority > $PRIO_MAX;
  101.     } 
  102.     }
  103.  
  104.  
  105.  
  106. #####################################################################
  107.  
  108. sub uid2name {
  109.     local($uid) = @_;
  110.     unless (defined $name{$uid}) {
  111.     local($name) = (getpwuid($uid))[0];
  112.     $uid{$name} = $uid;
  113.     $name{$uid} = $name;
  114.     }
  115.     $name{$uid};
  116.  
  117. sub name2uid {
  118.     local($name) = @_;
  119.     unless (defined $uid{$name}) {
  120.     local($uid) = (getpwnam($name))[2];
  121.     $uid{$name} = $uid;
  122.     $name{$uid} = $name;
  123.     }
  124.     $uid{$name};
  125.  
  126. ######################################################################
  127. # magic names here -- touch these and you are apt to be surprised
  128.  
  129. sub pid {
  130.     local($pid) = @_;
  131.     $pid =~ /^\d+$/;
  132. }
  133.  
  134. sub tty {
  135.     local($tty) = @_;
  136.     $tty =~ /^tty/ && -c "/dev/$tty";
  137.  
  138. sub user { 
  139.     local($who) = @_;
  140.     local($ok) = &name2uid($who); 
  141.     defined $ok;
  142.  
  143. sub cmd {
  144.     1;   
  145.  
  146. sub regexp {
  147.     local($pat) = @_;
  148.     eval "m$pat";
  149.     $@ =~ s/at \(eval\).*\n//;
  150.     $@ eq '';
  151.  
  152. ######################################################################
  153.  
  154. sub init {
  155.  
  156. #    run either as skill or as snice; this tells whether -5 is a 
  157. #    signal or a priority
  158.  
  159.     $mode = 'kill';
  160.     $mode = 'nice' if $0 =~ /nice/;
  161.  
  162. #   generate signal names ; comment out signames assignment
  163. #   to run kill -l instead to figure it out
  164.  
  165.     $signames = <<__EOLIST__;  # comment out for dynamic determination
  166.     HUP INT QUIT ILL TRAP IOT EMT FPE KILL BUS SEGV SYS PIPE ALRM
  167.     TERM URG STOP TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ VTALRM PROF
  168.     WINCH LOST USR1 USR2
  169. __EOLIST__
  170.  
  171.     local($signal);
  172.     $signum[0] = 'ZERO';
  173.     for (split(' ', $signames ? $signames : `kill -l`)) { 
  174.     $signame{$_} = ++$signal; 
  175.     $signum[$signal] = $_;
  176.     }
  177.  
  178. #   set up pointers and single-char abbrev for our 4 target arrays
  179. #   if you change one of strings, all idents of this name, including
  180. #   the subroutines, must change also.  be VERY CAREFUL.
  181.  
  182.     for ('cmd', 'pid', 'user', 'tty', 'regexp') {
  183.     $abbrev{(/^(.)/)[0]} = $_;
  184.     $targptr{$_} = eval "*$_";
  185.     } 
  186.  
  187. #   some defaults
  188.  
  189. }
  190.  
  191. #####################################################################
  192.  
  193. sub dump_values {
  194.     print "signal is $signal -$signame{$signal}\n" if $mode eq 'kill';
  195.     print "will renice targets to $priority\n" if $mode eq 'nice';
  196.  
  197.     for (keys %targptr) {
  198.     *targ = $targptr{$_};
  199.     next unless defined @targ;
  200.     print "$_ targets are ", join(', ', @targ), "\n";
  201.     } 
  202.  
  203.     @flags = keys %flag;
  204.     grep(s/^/-/, @flags);
  205.     print "option flags are @flags\n";
  206. }
  207.  
  208. #####################################################################
  209.  
  210. sub usage {
  211.      die <<EOF;
  212. Usage:
  213.      skill [-signal] [-Nildvna] {tty user command pid regexp}
  214.      snice [(-|+)priority] [-Nildvna] {tty user command pid regexp}
  215.  
  216.      -i    interactive
  217.      -v    show candidates
  218.      -n    like -v but don't really do it
  219.      -a    all procs are candidates
  220.      -N    nice mode 
  221.      -d    enable debugging
  222.  
  223.      Uniquely identify {...} args with leading -t, -u, -c, -p, -r
  224.      Or use a leading slash for a regexp.
  225. EOF
  226.     exit 1;
  227.  
  228. ######################################################################
  229.  
  230. sub start_ps {
  231.     $ps = 'ps l';
  232.     $ps .= 'w';
  233.  
  234.     grep($pid{$_}++, @pid);
  235.     grep($user{&name2uid($_)}++, @user);
  236.     grep($tty{$_}++, @tty);
  237.     grep($cmd{$_}++, @cmd);
  238.     $regexp = join('|', @regexp);
  239.  
  240.     $ps .= 'w' if $regexp;
  241.     $ps .= 'ax' if  $> == 0      ||
  242.             $flag{'a'}  ||
  243.             @user > 1     || 
  244.             (@user == 1 && &name2uid($user[0]) != $>);
  245.     
  246.     if (! $pattern && @cmd && !grep(m!^/!, @cmd)) { $ps .= 'c'; } 
  247.  
  248.     if (@tty == 1) {  # faster
  249.     $tty[0] =~ /^tty(..)/;
  250.     $ps .= "t$1";
  251.     } 
  252.  
  253.     print "ps command is $ps\n" if $flag{'d'};
  254.  
  255.     defined($kid_pid = open(PS, "$ps |")) ||   die  "can't run ps: $!";
  256.     if (<PS> !~ /UID/) {
  257.     warn "Something's wrong with ps";
  258.     kill 'TERM', $kid_pid;
  259.     exit 2;
  260.     } 
  261.  
  262.     $dad_pid = getppid();
  263.  
  264. ######################################################################
  265.  
  266. sub kill_procs {
  267.     while (<PS>) {
  268.     ($user, $pid) = /^\s*[a-f\d]+\s+(\d+)\s*(\d+)/i;
  269.  
  270.     next if $pid == $$;
  271.     next if $pid == $kid_pid;
  272.     next if $pid == $dad_pid && $mode eq 'kill';
  273.     
  274.     next if @user && !$user{$user};
  275.     next if @pid  && !$pid{$pid};
  276.  
  277.     ($tty, $cmd) = /\s*(\S*)\s*\d+:\d+\s+(.*)$/;
  278.     $tty = "tty$tty" unless $tty =~ /\?/;
  279.  
  280.     next if @tty  && !$tty{$tty};
  281.     next if @regexp && $cmd !~ m$regexpo;
  282.  
  283.     if (@cmd) {
  284.         ($cmdname) = ($cmd =~ /^(\S+)/);
  285.         $cmdname =~ s!.*/!!;
  286.         next if !$cmd{$cmd} && !$cmd{$cmdname};
  287.     }
  288.  
  289.     printf "%5d  %-8s %-5s  %s ", $pid, &uid2name($user), $tty, $cmd
  290.         if $flag{'v'} || $flag{'i'} || $flag{'n'};
  291.  
  292.     if ($flag{'i'}) {
  293.         $_ = <STDIN>;
  294.         defined     || exit;
  295.         /^\s*y/i     || next;
  296.     }
  297.  
  298.     $hits++;
  299.  
  300.     unless ($flag{'n'}) {
  301.         $! = 0;
  302.         if ($mode eq 'kill') {
  303.         kill $signal, $pid;
  304.         } else {
  305.         setpriority(0, $pid, $priority);
  306.         } 
  307.         if ($!) { 
  308.         warn (($mode eq 'kill' ? 'kill' : 'setpriority')
  309.             .   " $pid: $!\n");
  310.         $status = 1;
  311.         next;
  312.         }
  313.     }
  314.  
  315.     print "\n" if $flag{'v'} || $flag{'n'};
  316.     } 
  317.     close PS || die "something happened to your $ps";
  318.     warn "$0: no target processes found\n" unless $hits;
  319.  
  320. ######################################################################
  321.  
  322. format STDOUT = 
  323. Any of the following signals are valid, or their numeric equivalents:
  324. ~~   ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  325.       $signals
  326. .
  327.