#!/bin/ksh # ## sh code translated to ksh, with some additional optimizations ## RB Oct 2002 #--------------------------------------------------------------- # # Copyright 1995, by Hewlett-Packard Company # # The code in this file is from the book "Shell Programming # Examples" by Bruce Blinn, published by Prentice Hall. # This file may be copied free of charge for personal, # non-commercial use provided that this notice appears in # all copies of the file. There is no warranty, either # expressed or implied, supplied with this code. # # NAME # ptree - print a process tree # # SYNOPSIS # ptree [-n] [pid] # ptree [-n] [pid] [level] [datafile] # # DESCRIPTION # This command will print the process tree for the # process identified by pid. When called by the user, # only the first format shown should be used. If the # process ID (pid) is not passed, process 1 is assumed. # # The second format of this command is only used when # this command calls itself recursively to print the next # level of the process tree. # # -n Do not recurse # # RETURN VALUE # 0 Successful completion # 1 Usage error # ############################################################ ## Put our own directory in the PATH, since we use recursion ## ksh lets us avoid using `dirname` ## Also, make sure /usr/bin/ps is ahead of any other version of ps (/usr/ucb etc.) PATH=/usr/bin:$PATH:${0%/*} ## Don't even import this function if we've already used it if [[ -z "$SYSTEM" ]]; then . SystemType.sh fi integer INDENT LEVEL CMDNAME=${0##*/} USAGE="Usage: $CMDNAME [-n] [pid]" RECURSIVE=TRUE # List processes recursively PROCESS= # PID of the starting process LEVEL= # Indentation level (num parents) DATAFILE= # Reformatted output from ps PS_OPTS= # Options for the ps command OLD_IFS=$IFS # Original value of IFS variable ## Setting SYSTEM is expensive - don't do it more than once SYSTEM=${SYSTEM:=`SystemType`}; export SYSTEM # SYSTEM=`SystemType` # String identifying the system # # Temporaries # PID= # Process ID PPID= # Process ID of the parent process OWNER= # Owner of the process NAME= # Name of the process LINE= # Line from the data file OUTLINE= # Line of output INDENT= # Column number where line begins trap 'rm -f /tmp/*.$$; exit 1' 1 2 3 15 FillLine() { # # SYNOPSIS # FillLine line column # integer _COLUMN _LEN _LINE="$1" _COLUMN=$2 ## Using ksh lets us do this arithmetic internally ## otherwise `expr` is needed potentially thousands of times _LEN=${#_LINE} while [[ $_LEN -lt $_COLUMN ]] do _LINE="$_LINE " _COLUMN=$(($_COLUMN - 1)) done print "$_LINE" } while : do case $1 in -n) RECURSIVE=FALSE shift ;; --) shift break ;; -*) print "$USAGE" 1>&2 exit 1 ;; *) break ;; esac done # # Make sure the number of parameters is reasonable. # if [[ $# -eq 0 ]] then PROCESS=1 LEVEL=0 DATAFILE=/tmp/ptree.$$ elif [[ $# -eq 1 ]]; then PROCESS=$1 LEVEL=0 DATAFILE=/tmp/ptree.$$ elif [[ $# -eq 3 ]]; then PROCESS=$1 LEVEL=$2 DATAFILE=$3 else print "$USAGE" 1>&2 exit 1 fi if [[ "$LEVEL" = 0 ]]; then # # Determine which options to use with the ps command. # case $SYSTEM in SUNBSD | ULTRIX ) PS_OPTS="-auwx" ;; * ) PS_OPTS="-ef" ;; esac # # Build the data file. # rm -f $DATAFILE ## Fragile programming! - depends closely on the exact output of ps case $SYSTEM in SGI62 ) COL=47 ;; AIX | HP | SGI | SOLARIS ) COL=48 ;; SUNBSD | DECOSF | SGI65 ) COL=57 ;; ULTRIX ) COL=51 ;; * ) print "Unexpected system type." 1>&2 exit 1 ;; esac ## Original code used a scratch file and loop to generate $DATAFILE ## Replaced by piping through awk. ps $PS_OPTS | sed '1d' | sort | awk '{print $2,$3,$1,substr($0,'$COL')}' > $DATAFILE fi # # Print the current process. # ## Use internal arithmetic again, instead of calling 'expr' INDENT=$(( $LEVEL * 2 )) OUTLINE=`FillLine "" $INDENT` LINE=`grep "^$PROCESS " $DATAFILE` set $LINE OUTLINE="$OUTLINE $1" OUTLINE=`FillLine "$OUTLINE" 30` OUTLINE="$OUTLINE $3 $4" print "$OUTLINE" if [[ "$RECURSIVE" = "TRUE" ]];then LEVEL=$(($LEVEL + 1)) while read LINE do set $LINE # # For every process that is a child of the # current process, invoke this command ($0) # recursively. # if [[ "$2" = "$PROCESS" ]]; then $0 $1 $LEVEL $DATAFILE fi done <$DATAFILE fi rm -f /tmp/*.$$ exit 0