home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #19 / NN_1992_19.iso / spool / comp / unix / shell / 3700 < prev    next >
Encoding:
Internet Message Format  |  1992-08-30  |  8.6 KB

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