1: #!/bin/ksh
2: #
3: ## sh code translated to ksh, with some additional optimizations
4: ## RB Oct 2002
5: #---------------------------------------------------------------
6:
7: #
8: # Copyright 1995, by Hewlett-Packard Company
9: #
10: # The code in this file is from the book "Shell Programming
11: # Examples" by Bruce Blinn, published by Prentice Hall.
12: # This file may be copied free of charge for personal,
13: # non-commercial use provided that this notice appears in
14: # all copies of the file. There is no warranty, either
15: # expressed or implied, supplied with this code.
16: #
17: # NAME
18: # ptree - print a process tree
19: #
20: # SYNOPSIS
21: # ptree [-n] [pid]
22: # ptree [-n] [pid] [level] [datafile]
23: #
24: # DESCRIPTION
25: # This command will print the process tree for the
26: # process identified by pid. When called by the user,
27: # only the first format shown should be used. If the
28: # process ID (pid) is not passed, process 1 is assumed.
29: #
30: # The second format of this command is only used when
31: # this command calls itself recursively to print the next
32: # level of the process tree.
33: #
34: # -n Do not recurse
35: #
36: # RETURN VALUE
37: # 0 Successful completion
38: # 1 Usage error
39: #
40: ############################################################
41: ## Put our own directory in the PATH, since we use recursion
42: ## ksh lets us avoid using `dirname`
43: ## Also, make sure /usr/bin/ps is ahead of any other version of ps (/usr/ucb etc.)
44: PATH=/usr/bin:$PATH:${0%/*}
45:
46: ## Don't even import this function if we've already used it
47: if [[ -z "$SYSTEM" ]]; then
48: . SystemType.sh
49: fi
50:
51: integer INDENT LEVEL
52:
53: CMDNAME=${0##*/}
54: USAGE="Usage: $CMDNAME [-n] [pid]"
55: RECURSIVE=TRUE # List processes recursively
56: PROCESS= # PID of the starting process
57: LEVEL= # Indentation level (num parents)
58: DATAFILE= # Reformatted output from ps
59: PS_OPTS= # Options for the ps command
60: OLD_IFS=$IFS # Original value of IFS variable
61:
62: ## Setting SYSTEM is expensive - don't do it more than once
63: SYSTEM=${SYSTEM:=`SystemType`}; export SYSTEM
64: # SYSTEM=`SystemType` # String identifying the system
65:
66: #
67: # Temporaries
68: #
69: PID= # Process ID
70: PPID= # Process ID of the parent process
71: OWNER= # Owner of the process
72: NAME= # Name of the process
73: LINE= # Line from the data file
74: OUTLINE= # Line of output
75: INDENT= # Column number where line begins
76:
77: trap 'rm -f /tmp/*.$$; exit 1' 1 2 3 15
78:
79: FillLine() {
80: #
81: # SYNOPSIS
82: # FillLine line column
83: #
84: integer _COLUMN _LEN
85: _LINE="$1"
86: _COLUMN=$2
87: ## Using ksh lets us do this arithmetic internally
88: ## otherwise `expr` is needed potentially thousands of times
89: _LEN=${#_LINE}
90: while [[ $_LEN -lt $_COLUMN ]]
91: do
92: _LINE="$_LINE "
93: _COLUMN=$(($_COLUMN - 1))
94: done
95:
96: print "$_LINE"
97: }
98:
99: while :
100: do
101: case $1 in
102: -n) RECURSIVE=FALSE
103: shift
104: ;;
105: --) shift
106: break
107: ;;
108: -*) print "$USAGE" 1>&2
109: exit 1
110: ;;
111: *) break
112: ;;
113: esac
114: done
115:
116: #
117: # Make sure the number of parameters is reasonable.
118: #
119: if [[ $# -eq 0 ]] then
120: PROCESS=1
121: LEVEL=0
122: DATAFILE=/tmp/ptree.$$
123: elif [[ $# -eq 1 ]]; then
124: PROCESS=$1
125: LEVEL=0
126: DATAFILE=/tmp/ptree.$$
127: elif [[ $# -eq 3 ]]; then
128: PROCESS=$1
129: LEVEL=$2
130: DATAFILE=$3
131: else
132: print "$USAGE" 1>&2
133: exit 1
134: fi
135:
136: if [[ "$LEVEL" = 0 ]]; then
137: #
138: # Determine which options to use with the ps command.
139: #
140: case $SYSTEM in
141: SUNBSD | ULTRIX ) PS_OPTS="-auwx" ;;
142: * ) PS_OPTS="-ef" ;;
143: esac
144:
145: #
146: # Build the data file.
147: #
148: rm -f $DATAFILE
149:
150: ## Fragile programming! - depends closely on the exact output of ps
151: case $SYSTEM in
152: SGI62 ) COL=47 ;;
153: AIX | HP | SGI | SOLARIS ) COL=48 ;;
154: SUNBSD | DECOSF | SGI65 ) COL=57 ;;
155: ULTRIX ) COL=51 ;;
156: * ) print "Unexpected system type." 1>&2
157: exit 1 ;;
158: esac
159:
160: ## Original code used a scratch file and loop to generate $DATAFILE
161: ## Replaced by piping through awk.
162: ps $PS_OPTS | sed '1d' | sort | awk '{print $2,$3,$1,substr($0,'$COL')}' > $DATAFILE
163: fi
164:
165: #
166: # Print the current process.
167: #
168: ## Use internal arithmetic again, instead of calling 'expr'
169: INDENT=$(( $LEVEL * 2 ))
170: OUTLINE=`FillLine "" $INDENT`
171:
172: LINE=`grep "^$PROCESS " $DATAFILE`
173: set $LINE
174: OUTLINE="$OUTLINE $1"
175: OUTLINE=`FillLine "$OUTLINE" 30`
176: OUTLINE="$OUTLINE $3 $4"
177: print "$OUTLINE"
178:
179: if [[ "$RECURSIVE" = "TRUE" ]];then
180: LEVEL=$(($LEVEL + 1))
181: while read LINE
182: do
183: set $LINE
184: #
185: # For every process that is a child of the
186: # current process, invoke this command ($0)
187: # recursively.
188: #
189: if [[ "$2" = "$PROCESS" ]]; then
190: $0 $1 $LEVEL $DATAFILE
191: fi
192: done <$DATAFILE
193: fi
194:
195: rm -f /tmp/*.$$
196: exit 0
| last modified 09/02/2006 | Introduction | Table of Contents (frame/no frame) |
Printable (single file) |
© Dartmouth College |