| I have a shell script (written myself) that works most of the time,
| but when the youngest processes do not have the highest PIDs of all
| existing processes (which is possible, if a system runs long
| enough and PIDs wrap around after about 30000 processes),
| it gets into trouble.
jonm@Ingres.COM (Don't Judge a book by your cover) writes:
| You could extend your current script to include a small C routine that
| provides the process group information. This will apply to all processes
| that are children of another process.
|
| main(argc, argv)
| int argc;
| char *argv[];
| {
| exit getpgrp(atoi(argv[1]))
| }
|
| Where your first argument is the pid of the process you located in your
| first step.
|
| Then let your killing fingers do the talking.
Um, why do this the hard way? I append a package for such purposes I use here.
It's all scripts. It is a trivial exercise to modify the tkill script to match
process names instead of process numbers. You will have to install the
appropriate instance of ps_ppid.*.sh as ps_ppid.
- Cameron Simpson
cameron@cs.unsw.oz.au, DoD 0743
--
"The engine purrs beneath me with a purpose,
ready for the pleasure of my hand upon the throttle." - Peter Smith
#!/bin/sh
#
# Cut here and feed through /bin/sh.
#
sed 's/^X//' > 'ps_bsd2ppid.pl' <<'EOF-ps_bsd2ppid.pl'
X#!/usr/local/bin/perl
X#
X# Convert BSD ps lagx output to ps_ppid output.
X# We produce
X# USER PID PPID TTY SZ RSS STAT TIME COMMAND
X# separated by tabs.
X#
X
X$"="\t";
Xwhile (<>)
X { if ($. == 1)
X # replace heading
X { print "UID\tPID\tPPID\tTTY\tSZ\tRSS\tSTAT\tTIME\tCOMMAND\n";
X next;
X }
X
X# F UID PID PPID CP PRI NI ADDR SZ RSS STAT TTY TIME COMMAND
X if (@f=/^\s*\d+\s+(\d+)\s+(\d+)\s+(\d+)\s+\d+\s+[- ]\d+\s*[- ]\d+\s[\s\da-f]{3}[\da-z]([\s\d]{4}\d)\s+(\d+)\s+([RTPDSIZ][W >][N< ])\s+(\S+\s*\d+:\d\d)\s+(.*\S)\s*$/o)
X { if ($f[6] =~ /(\S+)\s+(\d+:\d\d)/
X || $f[6] =~ /(\S*\D)(\d+:\d\d)/
X || $f[6] =~ /(.*)(\d+:\d\d)/)
X { @f=(@f[0,1,2],$1,@f[3,4,5],$2,@f[7]);
X print "@f\n";
X }
X else
X { print STDERR $_;
X }
X }
X elsif (/^\S/)
X { print STDERR $_;
X }
X }
EOF-ps_bsd2ppid.pl
sed 's/^X//' > 'ps_bsdw2ppid.pl' <<'EOF-ps_bsdw2ppid.pl'
X#!/usr/local/bin/perl
X#
X# Convert BSD ps lagx output to ps_ppid output.
X# We produce
X# USER PID PPID TTY SZ RSS STAT TIME COMMAND
X# separated by tabs.
X#
X
X$"="\t";
Xwhile (<>)
X { if ($. == 1)
X # replace heading
X { print "UID\tPID\tPPID\tTTY\tSZ\tRSS\tSTAT\tTIME\tCOMMAND\n";
X next;
X }
X
X# F UID PID PPID CP PRI NI ADDR SZ RSS WCHAN STAT TT TIME COMMAND
X if (@f=/^(\d{8}|\s*\d{1,7})\s*(\d+)\s+(\d+)\s+(\d+)\s+\d+\s+[- ]\d+\s*[- ]\d+\s[\s\da-f]{3}[\da-z]\s*(\d+)\s+(\d+)\s+\w*\s+([RTPDSIZ][W >][N< ][AS ][V ]?)\s+(\S+\s*\d+:\d\d)\s+(.*\S)\s*$/o)
X { shift @f;
X if ($f[6] =~ /(\S+)\s+(\d+:\d\d)/
X || $f[6] =~ /(\S*\D)(\d+:\d\d)/
X || $f[6] =~ /(.*)(\d+:\d\d)/)
X { @f=(@f[0,1,2],$1,@f[3,4,5],$2,@f[7]);
X print "@f\n";
X }
X else
X { print STDERR $_;
X }
X }
X elsif (/^\S/)
X { print STDERR $_;
X }
X }
EOF-ps_bsdw2ppid.pl
sed 's/^X//' > 'ps_ppid.bsd.sh' <<'EOF-ps_ppid.bsd.sh'
X#!/bin/sh
X#
X# Produce a ps listing containing nine fields:
X# USER PID PPID TTY SZ RSS STAT TIME COMMAND
X# from a BSD-style ps command.
X#
X
Xps lagx ${1+"$@"} | ps_bsd2ppid
EOF-ps_ppid.bsd.sh
sed 's/^X//' > 'ps_ppid.bsdw.sh' <<'EOF-ps_ppid.bsdw.sh'
X#!/bin/sh
X#
X# Produce a ps listing containing nine fields:
X# USER PID PPID TTY SZ RSS STAT TIME COMMAND
X# from a BSD-style ps command with a WCHAN column.
X#
X
Xps lagx ${1+"$@"} | ps_bsdw2ppid
EOF-ps_ppid.bsdw.sh
sed 's/^X//' > 'ps_ppid.inetd.sh' <<'EOF-ps_ppid.inetd.sh'
X#!/bin/sh
X#
X# Stub to run ps_ppid with useful PATH from inetd.
X#
X
XPATH=/usr/local/bin:$PATH
Xexport PATH
Xexec /usr/local/bin/ps_ppid ${1+"$@"}
EOF-ps_ppid.inetd.sh
sed 's/^X//' > 'ps_ppid.sysv.sh' <<'EOF-ps_ppid.sysv.sh'
X#!/bin/sh
X#
X# Produce a ps listing containing nine fields:
X# USER PID PPID TTY SZ RSS STAT TIME COMMAND
X# from a SYSV-style ps command.
X#
X
Xps -elf ${1+"$@"} | ps_sysv2ppid
EOF-ps_ppid.sysv.sh
sed 's/^X//' > 'ps_sysv2ppid.pl' <<'EOF-ps_sysv2ppid.pl'
X#!/usr/local/bin/perl
X#
X# Convert SYSV ps -elf output to ps_ppid output.
X# We produce
X# USER PID PPID TTY SZ RSS STAT TIME COMMAND
X# separated by tabs.
X#
X
Xwhile (<>)
X { if ($. == 1)
X # replace heading
X { print "UID\tPID\tPPID\tTTY\tSZ\tRSS\tSTAT\tTIME\tCOMMAND\n";
X next;
X }
X
X# F S UID PID PPID C PRI NI P SZ RSS WCHAN STIME TTY TIME COMD
X if (s/^[\da-f]{2} ([SRZTIX])\s*(\S+)\s+(\d+)\s+(\d+)\s+\d+\s*[ +]\d+\s+\d+\s\S+\s+(\d+):([ \d]{5})[ \da-f]{8} .{8}\s+(\S+)\s+(\d+:\d\d)\s+(.*)/\2\t\3\t\4\t\7\t\5\t\6\t\1\t\8\t\9/o)
X { print;
X }
X elsif (/^\S/)
X { print STDERR $_;
X }
X }
EOF-ps_sysv2ppid.pl
sed 's/^X//' > 'pt.1' <<'EOF-pt.1'
X.TH PT 1 Local
X.SH NAME
Xpt \- print process tree
X.br
Xrpt \- print remote process tree
X.br
Xtkill \- kill process tree
X.br
Xps_ppid \- print uid, pid, ppid, tty, cmd+args for use by pt
X.br
Xps_bsd2ppid \- convert Apollo ps lagx output into ps_ppid output
X.br
Xps_bsdw2ppid \- convert BSD ps lagx output into ps_ppid output
X.br
Xps_sysv2ppid \- convert SYSV ps -ef output into ps_ppid output
X.SH SYNOPSIS
X.B pt
X.RB [ - ]
X.RB [ -b ]
X.RB [ -f ]
X.RI [ subtree... ]
X.RI [ secondary-ps_ppid-arguments ]
X.br
X.B rpt
X.RB [ -b ]
X.RB [ -f ]
X.RI [ subtree... ]
X.I hosts...
X.br
X.B tkill
X.RB [ -v ]
X.RB [ -\fIsignal\fB ]
X.I subtree
X.RI [ secondary-ps-arguments ]
X.br
X.B ps_ppid
X.RI [ secondary-ps-arguments ]
X.br
X.B ps_bsd2ppid
X.RI [ files... ]
X.br
X.B ps_bsdw2ppid
X.RI [ files... ]
X.br
X.B ps_sysv2ppid
X.RI [ files... ]
X.SH DESCRIPTION
XThese programs comprise a collection of filters
Xfor producing process tree listings.
X
X.B pt
Xprints an indented process listing
Xreflecting the parent-child relationships
Xof the process tree.
XOutput consists of ten columns:
X.TP
XUSER
XEffective username.
X.TP
XUID
XEffective user id.
X.TP
XPID
XProcess id.
X.TP
XPPID
XParent process id.
X.TP
XSZ
XVirtual size of the process.
X.TP
XRSS
XReal memory (resident set) size of the process.
X.TP
XTTY
XControlling terminal.
X.TP
XSTAT
XProcess state.
X.TP
XTIME
XCPU time.
X.TP
XCOMMAND
XProcess argument list.
XThe COMMAND column is indented by two spaces for each depth of pedigree.
X.P
XAll columns are separated by white space,
Xand except for COMMAND are guarrenteed to contains no white space,
Xthus rending the list easy to parse.
X.P
XThe following arguments affect the listing:
X.TP
X.B \-
XThis causes
X.B pt
Xto read a
X.BR ps_ppid -style
Xprocess listing from standard input rather than opening a pipe to
X.B ps_ppid
Xitself.
X.TP
X.B \-b
XTake the basename of argument zero of the process.
XThis often produces a much more readable listing.
XIt is the default.
X.TP
X.B \-f
XTake the full name of argument zero of the process.
XThis produces a much more informative listing.
X.TP
X.I subtree
XAn argument consisting entirely of digits is taken
Xto be a process-id to be the root of the tree printed.
XOnly descendants of this process will be printed.
XNormally,
X.B pt
Xproduces the entire list for the current host.
X.P
XAny other arguments are passed to the internal invocation of
X.B ps_ppid
X(or ignored if the\ \fB\-\fR\ option is used).
XSince
X.B ps_ppid
Xpasses these arguments in turn to the
X.B ps
Xcommand it is possible, for example,
Xto take direct advantage of the remote capabilites of the Apollo ps, viz:
X.[]
Xpt //fuligin
X.][
X
X.B rpt
Xruns
X.B pt
Xwith a process listing obtains from a remote host.
XIt takes the\ \fB\-b\fR, \fB-f\fR and
X.I subtree
Xarguments of
X.B pt
Xand passes them to
X.BR pt .
XFollowing arguments are taken to be references to hosts.
XArguments of the form\ \fB//\fIhost\fR are taken to be Apollo hosts,
Xand passed directly to
X.BR pt .
XOther arguments are presumed to be internet host names
Xor internet numeric addresses\ (\fIn\fB.\fIn\fB.\fIn\fB.\fIn\fR),
Xand a connection to that host's
X.B ps_ppid
Xport is made and the output passed to
X.BR pt .
X
X.B tkill
Xsends the specified
X.I signal
Xto the process in the tree whose root is
X.IR subtree .
XIf the
X.B -v
Xoption is supplied,
Xthe generated kill command is printed just before execution.
X.I subtree
Xand any following arguments
Xare passed to
X.B pt
Xinternally when generating the process list.
X
X.B ps_ppid
Xgenerates nine column tab-separated output suitable for feeding to
X.BR pt .
XThese columns are:
X.IR USER ,
X.IR PID ,
X.IR PPID ,
X.IR TTY ,
X.IR SZ ,
X.IR RSS ,
X.IR STAT ,
X.IR TIME ,
Xand
X.IR COMMAND .
XThe
X.I USER
Xcolumn is either a login name or a numeric uid.
XAs this is accomplished by filtering the output of the local
X.B ps
Xcommand, any arguments supplied are passed to the ps command.
X
X.B ps_bsd2ppid
Xis a filter which converts input of the same format
Xas that output by the Apollo
X.B "ps lagx"
Xcommand into output as produced by the
X.B ps_ppid
Xcommand.
X
X.B ps_bsdw2ppid
Xis a filter which converts input of the same format
Xas that output by the BSD
X.B "ps lagx"
Xcommand into output as produced by the
X.B ps_ppid
Xcommand.
XThe input format differs from that of the Apollo
X.B ps
Xcommand through the addition of the WCHAN column.
X
X.B ps_sysv2ppid
Xis a filter which converts input of the same format
Xas that output by the System\ V
X.B "ps -elf"
Xcommand into output as produced by the
X.B ps_ppid
Xcommand.
X.SH BUGS
XThere should a way to control the degree of indent produced by
X.BR pt .
X
XThe various \fBps_\fItype\fB2ppid\fR filters can be confused
Xif various columns of the ps listing input overflow,
Xthus running into each other.
XThis is more properly a bug in various vendors' ps commands,
Xwhich should ensure at least one space between columns
Xto keep them machine parsable.
XTh filters at least recognise and accomodates the most common overlaps.
X.SH AUTHOR
XCameron Simpson
X.SH SEE ALSO
Xps(1), kill(1), tcpio(1)
EOF-pt.1
sed 's/^X//' > 'pt.pl' <<'EOF-pt.pl'
X#!/usr/local/bin/perl
X#
X# pt - print process tree
X#
X# Munges ps_ppid listing into indented process tree.