home *** CD-ROM | disk | FTP | other *** search
- #
- # pt -- print process tree
- # Tom Christiansen <tchrist@convex.com>
- # version 1.0, Tuesday Jun 30 18:29:49 CDT 1992
- #
- # Modification History
- # version 1.1, Wed Jul 1 14:58:54 CDT 1992
- # Chop long lines to winsize unless -w supplied
- # Add -a for all procs irrespective of platform
- # Changed parse bailout to warning
- # Added Configure script
- # Numerous hacks to deal with various braindead
- # vendors garbled ps output
- #
- #
- # run ps and display process hierarchy indented
- # under parents.
- #
- # Options:
- # [-l level] limits level of children printed
- # [-i indent] change indent level from default
- # [-w] allow lines to be as long as you want.
- #
- #
-
-
- # don't use require so that it runs on ancient versions of perl
- # require 'getopts.pl';
- $file = 'getopts.pl';
- $return = do $file;
- die "couldn't parse $file: $@" if $@;
- die "couldn't do $file: $!" unless defined $return;
- die "couldn't run $file" unless $return;
-
- $VERSION = '1.1';
- $AUTHOR = 'tchrist@convex.com';
-
- $| = 1;
-
- #$$# $PS = "ps"; # a path to ps, usually /bin
- #$$# $TIOCGWINSZ = 0x40087468; # should be require sys/ioctl.ph
- #$$# $DEATH_STAR = 0; # ARGS: ps -el, not ps wwaxl
- #$$# $FLAG_WIDTH = 7;
- #$$# $FIRST_SPLIT = '^(\s*[\da-fA-F]+)\s*([\-\d]+)\s+(\d+)\s+(\d+)';
-
- die "Didn't you run Configure?"
- unless 4 == grep(defined,$PS,$TIOCGWINSZ,$DEATH_STAR,$FLAG_WIDTH);
-
- $indent = 2; # reset via -i switch
-
- $debug = 0;
-
-
- ########################################################
-
- if ($DEATH_STAR) {
- $PS_ARGS = "-l";
- $EVERYBODY = "e";
- } else {
- $PS_ARGS = "xlww";
- $EVERYBODY = "a";
- }
-
- ########################################################
-
- $maxlevel = 10_000_000; # reset via -l switch
-
- sub usage {
- local($msg) = shift;
- print STDERR "$0: $msg\n" if $msg;
- die <<EOF;
- usage: $0 [-a] [-d] [-w] [ps args] [pid list]
- (version: $VERSION author: $AUTHOR)
-
- -w wide output (don't trunc at winsize)
- -a all processes, not just mine
- -d print out debugging information
- EOF
- }
-
- &Getopts('dl:i:wa') || &usage();
-
- $maxlevel = $opt_l if $opt_l;
- $indent = $opt_i if $opt_i;
- $wide = $opt_w;
- $debug = $opt_d;
-
- while (defined($_ = shift)) { # curse pid 0
- if (/^(\d+)$/) {
- $pids{$1}++;
- $pids++; # needed for ancient perl, who can't do if %pids
- } else {
- $PS_ARGS .= "$_ ";
- }
- }
-
- $wide || &getwin;
-
- $PS_ARGS =~ s/^(-?)/${1}${EVERYBODY}/ if $pids || $opt_a;
-
- $ps = "$PS $PS_ARGS";
-
- print "opening pipe to $ps\n" if $debug;
-
- open(PS, "$ps |") || die "can't fork: $!";
- <PS>; # header
-
- printf("%-8s %5s %8s %7s %s\n", 'USER', "PID", "TTY", "TIME","COMMAND");
-
- while (<PS>) {
- ($flags, $uid, $pid, $ppid) = /$FIRST_SPLIT/o;
- ($tty, $time, $secs, $command) = /(\S+)\s*(\d+:\d+(\.\d\d)?)\s+(.*)/;
-
- unless (grep(defined,$uid,$pid,$ppid,$tty,$time,$command) == 6) {
- warn "skipping unparsable line from ps:\n$_";
- $oops++;
- next;
- }
-
- if ($debug) {
- print <<EOF;
- flags are <$flags>, uid is <$uid>, pid is <$pid>, ppid is <$ppid>
- tty is <$tty>, time is <$time>, command is <$command>
-
- EOF
- }
-
- # incredibly disgusting hack should FLAGS and UID collide
- # why oh why must vendors be so damn sysadmin-hostile?
- # don't they understand we have to parse this stuff??
- # maybe should try $flags =~ /^\s/ here as well?
- # i give no guarantees that this works.
- if (!$DEATH_STAR && length($flags) > $FLAG_WIDTH &&
- (($ppid == 0 && $pid > 10 && $uid)
- ||
- length($flags) > 2+$FLAG_WIDTH))
- {
- print "hack 1\n" if $debug;
- $ppid = $pid;
- $pid = $uid;
- $uid = substr($flags,
- $FLAG_WIDTH + 1 - (substr($flags,0,1) eq ' ' ||
- length($flags > $FLAG_WIDTH + 2)),
- 10);
- substr($flags, -length($uid), 10) = '';
-
- # hold on to your lunch, folks...
- if (!defined $id{$uid}) {
- $extra = substr($flags,-1,1);
- $uid = $extra . $uid if defined $id{$extra.$uid};
- }
- }
-
- # stupid hack should PPID and CP collide
- if ($ppid > 32_000 && $pid < 32_000) {
- print "hack 2\n" if $debug;
- $ppid = substr($ppid,0,length($pid));
- }
-
- # stupid hack should TT and TIME collide
- if (length($tty) > 2 && $tty =~ /:/) {
- print "hack 3\n" if $debug;
- $time = substr($tty, 2, 10) . $time;
- $tty = substr($tty,0,2);
- }
-
- $lines{$pid} = sprintf("%-8s %5d %8s %7s#%s\n",
- &id($uid), $pid, $tty, $time, $command);
- unless ($pid == $ppid) {
- $parent{$pid} = $ppid;
- $children{$ppid} .= "$pid ";
- }
- }
- if (!close(PS)) {
- warn "\"$ps\" exited badly!\n";
- $oops++;
- }
-
- @pids = keys %pids;
- if (@pids) {
- foreach $pid (@pids) {
- &save_the_children($pid);
- &save_our_parent($pid);
- }
- %lines = %nlines;
- }
-
- sub bynum { $a - $b; }
-
- # find the heads of the chains...
- @pids = grep(!defined $lines{$parent{$_}},keys %lines);
-
- for $pid (sort bynum @pids) {
- &children($pid);
- }
-
- exit($oops != 0);
-
- sub children {
- local($pid) = $_[0];
- local($_) = $lines{$pid};
- substr($_, index($_, '#'), 1) = ' ' x (1+ $indent * $level);
- if (!$wide && length() > $cols) {
- substr($_, $cols, 10_000) = "\n";
- }
- print;
- if ($level++ < $maxlevel) {
- local(@kids) = split(' ',$children{$pid});
- for $pid (@kids) {
- &children($pid);
- }
- }
- $level--;
- }
-
- sub id {
- local($id) = shift;
- $id{$id} = (getpwuid($id))[0] || "($id)" unless defined $id{$id};
- $id{$id};
- }
-
- sub save_the_children {
- local($parent) = shift;
- foreach $kid (split(' ',$children{$parent})) {
- &save_the_children($kid);
- }
- &keepline($parent);
- }
-
- sub save_our_parent {
- local($kid) = shift;
- local($dad) = $parent{$kid};
-
- &keepline($kid);
-
- if ($dad || $dad eq '0') { # beware $dad == 0
- &save_our_parent($dad);
- }
- }
-
- sub keepline {
- $nlines{$_[0]} = $lines{$_[0]}
- unless defined $nlines{$_[0]};
- }
-
-
- sub getwin {
- local($winsize);
- # is someone can get SS_DC_TIOCSWINSZ on MIPS working, tell me
- if ($TIOCGWINSZ && ioctl(STDERR, $TIOCGWINSZ, $winsize)) {
- ($rows, $cols) = unpack('S4', $winsize);
- } else {
- $cols = $ENV{'COLUMNS'} || ($ENV{'TERMCAP'} =~ /:co#(\d+):/)[0];
- }
- $cols = 80 unless $cols;
- print "cols are $cols\n" if $debug;
- }
-