home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / languages / perl / scripts-convex / pt.shar / pt / pt.pl < prev    next >
Encoding:
Text File  |  1993-05-26  |  6.1 KB  |  258 lines

  1. #
  2. # pt -- print process tree
  3. #     Tom Christiansen <tchrist@convex.com>
  4. #       version 1.0, Tuesday Jun 30 18:29:49 CDT 1992
  5. #    
  6. #    Modification History
  7. #    version 1.1, Wed Jul  1 14:58:54 CDT 1992
  8. #        Chop long lines to winsize unless -w supplied
  9. #        Add -a for all procs irrespective of platform
  10. #        Changed parse bailout to warning
  11. #        Added Configure script
  12. #        Numerous hacks to deal with various braindead
  13. #        vendors garbled ps output
  14. #        
  15. #
  16. # run ps and display process hierarchy indented
  17. # under parents.
  18. #
  19. # Options:
  20. #     [-l level]    limits level of children printed
  21. #     [-i indent]    change indent level from default
  22. #    [-w]         allow lines to be as long as you want.
  23. #
  24.  
  25.  
  26. # don't use require so that it runs on ancient versions of perl
  27.     # require 'getopts.pl';
  28.     $file = 'getopts.pl';
  29.     $return = do $file;
  30.     die "couldn't parse $file: $@" if $@;
  31.     die "couldn't do $file: $!" unless defined $return;
  32.     die "couldn't run $file" unless $return;
  33.  
  34. $VERSION = '1.1';
  35. $AUTHOR = 'tchrist@convex.com';
  36.  
  37. $| = 1;
  38.  
  39. #$$# $PS = "ps";            # a path to ps, usually /bin
  40. #$$# $TIOCGWINSZ = 0x40087468;           # should be require sys/ioctl.ph
  41. #$$# $DEATH_STAR = 0;            # ARGS: ps -el, not ps wwaxl
  42. #$$# $FLAG_WIDTH = 7;
  43. #$$# $FIRST_SPLIT = '^(\s*[\da-fA-F]+)\s*([\-\d]+)\s+(\d+)\s+(\d+)';
  44.  
  45. die "Didn't you run Configure?"
  46.     unless 4 == grep(defined,$PS,$TIOCGWINSZ,$DEATH_STAR,$FLAG_WIDTH);
  47.  
  48. $indent = 2;               # reset via -i switch
  49.  
  50. $debug = 0;
  51.  
  52.  
  53. ########################################################
  54.  
  55. if ($DEATH_STAR) {
  56.     $PS_ARGS = "-l"; 
  57.     $EVERYBODY = "e";
  58. } else {
  59.     $PS_ARGS = "xlww";
  60.     $EVERYBODY = "a";
  61. }
  62.  
  63. ########################################################
  64.  
  65. $maxlevel = 10_000_000;  # reset via -l switch
  66.  
  67. sub usage {
  68.     local($msg) = shift;
  69.     print STDERR "$0: $msg\n" if $msg;
  70.     die <<EOF;
  71. usage: $0 [-a] [-d] [-w] [ps args] [pid list]
  72.         (version: $VERSION   author: $AUTHOR)
  73.  
  74.     -w     wide output (don't trunc at winsize)
  75.     -a    all processes, not just mine
  76.     -d    print out debugging information
  77. EOF
  78.  
  79. &Getopts('dl:i:wa') || &usage();
  80.  
  81. $maxlevel = $opt_l if $opt_l;
  82. $indent = $opt_i if $opt_i;
  83. $wide = $opt_w;
  84. $debug = $opt_d;
  85.  
  86. while (defined($_ = shift)) {  # curse pid 0
  87.     if (/^(\d+)$/) {
  88.     $pids{$1}++;
  89.     $pids++;  # needed for ancient perl, who can't do if %pids
  90.     } else {
  91.     $PS_ARGS .= "$_ ";
  92.     }
  93.  
  94. $wide || &getwin;
  95.  
  96. $PS_ARGS =~ s/^(-?)/${1}${EVERYBODY}/ if $pids || $opt_a;
  97.  
  98. $ps = "$PS $PS_ARGS";
  99.  
  100. print "opening pipe to $ps\n" if $debug;
  101.  
  102. open(PS, "$ps |") || die "can't fork: $!";
  103. <PS>; # header
  104.  
  105. printf("%-8s %5s %8s %7s %s\n", 'USER', "PID", "TTY", "TIME","COMMAND");
  106.  
  107. while (<PS>) {
  108.     ($flags, $uid, $pid, $ppid) = /$FIRST_SPLIT/o;
  109.     ($tty, $time, $secs, $command) = /(\S+)\s*(\d+:\d+(\.\d\d)?)\s+(.*)/;
  110.  
  111.     unless (grep(defined,$uid,$pid,$ppid,$tty,$time,$command) == 6) {
  112.     warn "skipping unparsable line from ps:\n$_";
  113.     $oops++;
  114.     next;
  115.     }
  116.  
  117.     if ($debug) {
  118.     print <<EOF;
  119. flags are <$flags>, uid is <$uid>, pid is <$pid>, ppid is <$ppid>
  120. tty is <$tty>, time is <$time>, command is <$command>
  121.  
  122. EOF
  123.     } 
  124.  
  125.     # incredibly disgusting hack should FLAGS and UID collide
  126.     # why oh why must vendors be so damn sysadmin-hostile?
  127.     # don't they understand we have to parse this stuff??
  128.     #     maybe should try $flags =~ /^\s/ here as well?
  129.     # i give no guarantees that this works.
  130.     if (!$DEATH_STAR && length($flags) > $FLAG_WIDTH  &&
  131.           (($ppid == 0 && $pid > 10 && $uid) 
  132.           || 
  133.       length($flags) > 2+$FLAG_WIDTH))
  134.     {
  135.     print "hack 1\n" if $debug;
  136.     $ppid = $pid;
  137.     $pid = $uid;
  138.     $uid = substr($flags, 
  139.                       $FLAG_WIDTH + 1 - (substr($flags,0,1) eq ' ' ||
  140.                                     length($flags > $FLAG_WIDTH + 2)),
  141.               10);
  142.     substr($flags, -length($uid), 10) = '';
  143.  
  144.     # hold on to your lunch, folks...
  145.     if (!defined $id{$uid}) {
  146.         $extra = substr($flags,-1,1);
  147.         $uid = $extra . $uid if defined $id{$extra.$uid};
  148.     } 
  149.     } 
  150.  
  151.     # stupid hack should PPID and CP collide
  152.     if ($ppid > 32_000 && $pid < 32_000) {
  153.     print "hack 2\n" if $debug;
  154.     $ppid = substr($ppid,0,length($pid));
  155.     }
  156.  
  157.     # stupid hack should TT and TIME collide
  158.     if (length($tty) > 2 && $tty =~ /:/) {
  159.     print "hack 3\n" if $debug;
  160.     $time = substr($tty, 2, 10) . $time;
  161.     $tty = substr($tty,0,2);
  162.     } 
  163.  
  164.     $lines{$pid} = sprintf("%-8s %5d %8s %7s#%s\n", 
  165.         &id($uid), $pid, $tty, $time, $command);
  166.     unless ($pid == $ppid) {
  167.     $parent{$pid} = $ppid;
  168.     $children{$ppid} .= "$pid ";
  169.     }
  170. if (!close(PS)) {
  171.     warn "\"$ps\" exited badly!\n";
  172.     $oops++;
  173. }
  174.  
  175. @pids = keys %pids;
  176. if (@pids) {
  177.     foreach $pid (@pids) {
  178.     &save_the_children($pid);
  179.     &save_our_parent($pid);
  180.     } 
  181.     %lines = %nlines;
  182.  
  183. sub bynum { $a - $b; } 
  184.  
  185. # find the heads of the chains...
  186. @pids = grep(!defined $lines{$parent{$_}},keys %lines);
  187.  
  188. for $pid (sort bynum @pids) {
  189.     &children($pid); 
  190.  
  191. exit($oops != 0);
  192.  
  193. sub children {
  194.     local($pid) = $_[0];
  195.     local($_) = $lines{$pid};
  196.     substr($_, index($_, '#'), 1) = ' ' x (1+ $indent * $level);
  197.     if (!$wide && length() > $cols) {
  198.     substr($_, $cols, 10_000) = "\n";
  199.     } 
  200.     print;
  201.     if ($level++ < $maxlevel) {
  202.     local(@kids) = split(' ',$children{$pid});
  203.     for $pid (@kids) {
  204.         &children($pid);
  205.     }
  206.     } 
  207.     $level--;
  208.  
  209. sub id {
  210.     local($id) = shift;
  211.     $id{$id} = (getpwuid($id))[0] || "($id)" unless defined $id{$id};
  212.     $id{$id};
  213.  
  214. sub save_the_children {
  215.     local($parent) = shift;
  216.     foreach $kid (split(' ',$children{$parent})) {
  217.     &save_the_children($kid);
  218.     } 
  219.     &keepline($parent);
  220.     
  221. sub save_our_parent {
  222.     local($kid) = shift;
  223.     local($dad) = $parent{$kid};
  224.  
  225.     &keepline($kid);
  226.  
  227.     if ($dad || $dad eq '0') { # beware $dad == 0
  228.     &save_our_parent($dad);
  229.     }
  230.  
  231. sub keepline {
  232.     $nlines{$_[0]}  = $lines{$_[0]} 
  233.     unless defined $nlines{$_[0]};
  234.  
  235.  
  236. sub getwin {
  237.     local($winsize);
  238.     # is someone can get SS_DC_TIOCSWINSZ on MIPS working, tell me
  239.     if ($TIOCGWINSZ && ioctl(STDERR, $TIOCGWINSZ, $winsize)) {
  240.         ($rows, $cols) = unpack('S4', $winsize);
  241.     } else {
  242.         $cols = $ENV{'COLUMNS'} || ($ENV{'TERMCAP'} =~ /:co#(\d+):/)[0];
  243.     }
  244.     $cols = 80 unless $cols;
  245.     print "cols are $cols\n" if $debug;
  246. }
  247.