[comp.sources.misc] v05i084: submission to comp.sources.misc

lew@gsg.UUCP (Paul Lew) (12/19/88)

Posting-number: Volume 5, Issue 84
Submitted-by: "Paul Lew" <lew@gsg.UUCP>
Archive-name: pt.bsd

Newsgroups: comp.sources.misc
Keywords: ps BSD process tree
Message-ID: <290@gsg.UUCP>
Date: 16 Dec 88 17:39:57 GMT
Organization: General Systems Group, Inc., Salem, NH
Lines: 511

	ptree,pt: BSD ps backend filter to display process tree

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	README
#	ptree.c
#	Kill
# This archive created: Fri Dec 16 12:22:07 1988
export PATH; PATH=/bin:$PATH
echo shar: extracting "'README'" '(2009 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
sed 's/^	X//' << \SHAR_EOF > 'README'
	X			Ptree Version 1.0  05/24/88
	X
	XIntroduction:
	X
	X    ptree is  a backend filter  for  BSD  'ps' command.  It  reads the
	X    output from  ps and produces  process tree  graph on the  standard
	X    output with each process indented under its  parent.  This program
	X    was inspired by  the 'utree' program  for  system V  from  Brandon
	X    Allbery.  The following is an example:
	X
	X      $ ptree ag | grep -v getty
	X	  USER STAT TTY  TIME COMMAND
	X	   lew I    i14  0:09 -Tcsh (Tcsh)
	X	   lew I    i14  0:31 |  emacs
	X	   lew I    p0   0:00 |  |  /usr/local/emacs/etc/loadst -n 60
	X	 alice I    i17  0:03 -csh (csh)
	X	   lew I    i18  0:08 -Tcsh (Tcsh)
	X	   lew S    i18  0:09 |  screen -e?]
	X	   lew I    p1   0:06 |  |  -bin/Tcsh (Tcsh)
	X	   lew S    p2   0:07 |  |  -bin/Tcsh (Tcsh)
	X	domino S    i26  0:05 -csh (csh)
	X	domino S    i26  0:00 |  lprint -f /usr/local/bin/lprint -n BigBucks
	X	domino S    i26  0:00 |  |  dcat -d 3 -b 128
	X	   mxt I    i27  0:02 -csh (csh)
	X	   mxt I    i27  0:03 |  mail -f
	X	   mxt I    i27  0:00 |  |  sh -c /usr/ucb/more
	X	   mxt I    i27  0:00 |  |  |  /usr/ucb/more
	X
	X    This is not 'yet another setuid program'.  You dont have to be the
	X    root to use it.  This is the main reason  to write it as a filter.
	X    May be BSD can incorporate this into real 'ps' on future release.
	X
	X    Kill is a script which uses 'sf' (shell form in comp.sources.unix)
	X    to allow one to send signals to processes by context.
	X
	XManual:
	X
	X    There is no man page to it, type: 'pt H' will give you simple help
	X    message.  If you know how 'ps' works then you  dont need a manual,
	X    if you dont, this might not be useful to you.
	X
	XBuild:
	X
	X    cc -o ptree ptree.c
	X    ln ptree pt
	X
	XCopyright:
	X
	X    No copyright, complete in public domain. Do whatever you like with
	X    it.  If you can make money from it, great for you.
	X
	X----------------------------------------------------------------------
	XPaul Lew			{olivea,harvard,decvax}!gsg!lew	(UUCP)
	XGeneral Systems Group, 5 Manor Parkway, Salem, NH 03079	(603) 893-1000
SHAR_EOF
if test 2009 -ne "`wc -c < 'README'`"
then
	echo shar: error transmitting "'README'" '(should have been 2009 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'ptree.c'" '(8883 characters)'
if test -f 'ptree.c'
then
	echo shar: will not over-write existing file "'ptree.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'ptree.c'
	Xstatic	char	*Sccsid = "(File: %M%  Ver: %I%  Update: %G% %U%)";
	X/*+F***********************************************************************
	X*
	X* File name:	ptree.c
	X*
	X* Author:	Paul Lew, General Systems Group, Inc. Salem, NH
	X* Created at:	05/22/88  16:10 PM
	X* Last update:	05/24/88  08:54 PM  (Edition: 26)
	X*
	X* Description:	This program will parse output of 'ps' command and display
	X*		the output with process indented under their parents for
	X*		the easy identification.
	X*	
	X* Environment:	4.2 BSD Unix (Pyramid OSx 4.1)
	X*
	X* Usage:	ptree [HPacgxt#]
	X*
	X* Update History:
	X*
	X*      Date		Description					By
	X*    --------	------------------------------------------------	---
	X*    05/22/88	Initial version						Lew
	X*
	X* Routines included:
	X*
	X*	build_offset	build offset from 1st line of ps output	
	X*	save_addr	return addr of Save array with pid = pid	
	X*	add_child	add child to parent, if exists, add to end of sibling
	X*	print_result	display result
	X*	print_process	print a given process sub-tree
	X*	dump_save	dump save structure for debugging
	X*	procarg		return command argument for ps command
	X*	usage		display help message
	X*
	X* Build:	cc -o ptree ptree.c <CR>
	X*
	X**-F**********************************************************************/
	X
	X#include	<stdio.h>
	X#include	<pwd.h>
	X
	X#define	YES		1
	X#define	NO		0
	X
	X#define	MAXLINE		200
	X
	Xstruct	save	{
	X	struct	save	*so_parent;	/* pointer to parent */
	X	struct	save	*so_sibling;	/* pointer to 1st sibling */
	X	struct	save	*so_child;	/* pointer to 1st child */
	X	int		so_uid;		/* user ID */
	X	char		so_name[9];	/* user name */
	X	int		so_pid;		/* pid */
	X	int		so_ppid;	/* parent pid */
	X	char		*so_buffer;	/* pointer to ps output */
	X	} Save [MAXLINE];
	X
	Xchar	*Version = "Version 1.0  05/24/88  00:51 AM";
	Xchar	*Author = "Paul Lew, lew@gsg.uucp";
	X
	Xint	Line;				/* # of output line from ps */
	Xint	Print_me = NO;			/* if NO, dont print my processes */
	Xint	Print_pid = NO;			/* if YES, output PID */
	Xchar	Command [80];
	Xint	My_pid;				/* my process id */
	X
	Xint	Uid_offset;
	Xint	Pid_offset;
	Xint	Ppid_offset;
	Xint	End_ppid;
	Xint	Stat_offset;
	Xint	Tyy_offset;
	Xint	Command_offset;
	X
	Xstruct	save	*save_addr ();
	Xchar		*procarg ();
	X
	Xextern	FILE	*popen ();
	Xextern	char	*malloc (), *calloc ();
	X
	X/*-------------------------------------------------------------05/23/88-+
	X|									|
	X|	  M a i n     R o u t i n e     S t a r t s     H e r e		|
	X|									|
	X+----------------------------------------------------------------------*/
	Xmain (argc, argv)
	Xint	argc;
	Xchar	**argv;
	X	{
	X	FILE			*pfd;	/* file descriptor for popen() */
	X	char			*p;	/* temp pointer to malloced buffer */
	X	register int		i;	/* loop index */
	X	register struct	save	*svp;
	X
	X	p = procarg (argc, argv);
	X	sprintf (Command, "ps lw%s", p);
	X	if ((pfd = popen (Command, "r")) == NULL) {
	X		fprintf (stderr, "can not execture ps\n");
	X		exit (1);
	X		}
	X	for (Line=0; Line<MAXLINE; Line++) {
	X		p = malloc (BUFSIZ);
	X		if (p == NULL) {
	X			perror ("malloc");
	X			exit (1);
	X			}
	X		if (fgets (p, BUFSIZ, pfd) == NULL) break;
	X		Save[Line].so_buffer = p;
	X		if (Line == 0) build_offset (p);
	X		else			/* prevent CP data being processed */
	X			p[End_ppid] = '\0';
	X		}
	X	pclose (pfd);
	X	for (i=1; i<Line; i++) {
	X		struct	passwd	*pwp;
	X		svp = &Save[i];
	X		svp->so_pid  = atoi (&svp->so_buffer[Pid_offset]);
	X		svp->so_ppid = atoi (&svp->so_buffer[Ppid_offset]);
	X		svp->so_uid  = atoi (&svp->so_buffer[Uid_offset]);
	X		pwp = getpwuid (svp->so_uid);
	X		strncpy (svp->so_name, pwp->pw_name, 8);
	X		}
	X	for (i=1; i<Line; i++) {
	X		struct	save	*p;
	X		svp = &Save[i];
	X		svp->so_parent = p = save_addr (svp->so_ppid);
	X		if (p) {
	X			add_child (p, svp);
	X			}
	X		}
	X	print_result ();
	X#ifdef	DEBUG
	X	dump_save ();	
	X#endif
	X	exit (0);
	X	}
	X
	X/*-------------------------------------------------------------05/23/88-+
	X|									|
	X|	 build_offset : build offset from 1st line of ps output		|
	X|									|
	X+----------------------------------------------------------------------*/
	Xbuild_offset (buf)
	Xchar	*buf;				/* header line */
	X	{
	X	char		*p = buf;
	X	for (p=buf; *p != '\0'; p++) {
	X		if      (strncmp ("UID",    p, 3) == 0) Uid_offset     = p-buf;
	X		else if (strncmp ("  PID ", p, 6) == 0) Pid_offset     = p-buf;
	X		else if (strncmp (" PPID ", p, 6) == 0) Ppid_offset    = p-buf;
	X		else if (strncmp ("STAT",   p, 4) == 0) Stat_offset    = p-buf;
	X		else if (strncmp ("TTY",    p, 3) == 0) Tyy_offset     = p-buf;
	X		else if (strncmp ("COMMAND",p, 7) == 0) Command_offset = p-buf;
	X		}
	X	End_ppid = Ppid_offset + 5;
	X	}
	X
	X/*-------------------------------------------------------------05/23/88-+
	X|									|
	X|	   save_addr : return addr of Save array with pid = pid		|
	X|									|
	X+----------------------------------------------------------------------*/
	Xstruct	save	*
	Xsave_addr (pid)
	Xint	pid;
	X	{
	X	register int	i;
	X	for (i=1; i<Line; i++) {
	X		if (Save[i].so_pid == pid) return (&Save[i]);
	X		}
	X	return (NULL);			/* not found */
	X	}
	X
	X/*-------------------------------------------------------------05/23/88-+
	X|									|
	X|  add_child : add child to parent, if exists, add to end of sibling	|
	X|									|
	X+----------------------------------------------------------------------*/
	Xadd_child (parent, child)
	Xstruct	save	*parent;
	Xstruct	save	*child;
	X	{
	X	if (parent->so_child == NULL) {
	X		parent->so_child = child;
	X		}
	X	else	{
	X		struct	save	*tp = parent->so_child;
	X		while (tp->so_sibling != NULL) tp = tp->so_sibling;
	X		tp->so_sibling = child;
	X		}
	X	child->so_sibling = NULL;
	X	}
	X
	X/*-------------------------------------------------------------05/23/88-+
	X|									|
	X|		      print_result : display result			|
	X|									|
	X+----------------------------------------------------------------------*/
	Xprint_result ()
	X	{
	X	register int	i;
	X	struct	save	*svp;
	X
	X	My_pid = getpid ();
	X	printf ("%s    USER %s", Print_pid ? "  PID " : "",
	X		&Save[0].so_buffer[Stat_offset]);
	X	for (i=1; i<Line; i++) {
	X		svp = &Save[i];
	X		if (svp->so_parent != NULL) {
	X			if (svp->so_pid != 0)
	X			  continue;
	X			}
	X		print_process (0, svp);
	X		}
	X	}
	X
	X/*-------------------------------------------------------------05/23/88-+
	X|									|
	X|	      print_process : print a given process sub-tree		|
	X|									|
	X+----------------------------------------------------------------------*/
	Xprint_process (level, svp)
	Xint		level;
	Xstruct	save	*svp;
	X	{
	X	struct	save	*tp;
	X	register int	i;
	X
	X	if (!Print_me && svp->so_pid == My_pid) return;
	X	if (Print_pid) printf ("%5d ", svp->so_pid);
	X	printf ("%8s %.*s", svp->so_name, Command_offset - Stat_offset,
	X		&svp->so_buffer[Stat_offset]);
	X	for (i=0; i<level; i++) printf ("|  ");
	X	printf ("%s", &svp->so_buffer[Command_offset]);
	X	if ((tp = svp->so_child) != NULL) {
	X		while (tp != NULL) {
	X			if (tp != svp)		/* avoid infinit recursion */
	X				print_process (level+1, tp);
	X			tp = tp->so_sibling;
	X			}
	X		}
	X	}
	X
	X/*-------------------------------------------------------------05/23/88-+
	X|									|
	X|	      dump_save : dump save structure for debugging		|
	X|									|
	X+----------------------------------------------------------------------*/
	X#ifdef	DEBUG
	Xdump_save ()
	X	{
	X	register int		i;
	X	register struct	save	*tp;
	X
	X	for (i=1; i<Line; i++) {
	X		tp = &Save[i];
	X		printf ("parent=%08x(x) ", tp->so_parent);
	X		printf ("sibling=%08x(x) ", tp->so_sibling);
	X		printf ("child=%08x(x) ", tp->so_child);
	X		printf ("PID=%05d PPID=%05d\n", tp->so_pid, tp->so_ppid);
	X		}
	X	printf ("command: [%s]\n", Command);
	X	}
	X#endif
	X
	X/*------------------------------------------------------------05/24/88--+
	X|									|
	X|	   procarg : return command argument for ps command		|
	X|									|
	X+----------------------------------------------------------------------*/
	Xchar	*
	Xprocarg (argc, argv)
	Xint	argc;
	Xchar	**argv;
	X	{
	X	static	char	buf [20] = "";
	X	register char	c;
	X	register char	*p = argv[1];
	X	int		i = 0;
	X
	X	if (argc == 1) return (buf);
	X	while ((c = *p++) != '\0') {
	X		switch (c) {
	X			case 'P':	Print_me = YES;		break;
	X			case 'p':	Print_pid = YES;	break;
	X			case 'H':	usage (argv[0]);	exit (0);
	X			case 'a': case 'c': case 'e': case 'g':
	X			case 'x':	buf[i++] = c;		break;
	X			case 't':	strcpy (&buf[i], p-1);	return (buf);
	X			default:	usage (argv[0]); exit (1);
	X			}
	X		}
	X	buf [i] = '\0';
	X	return (buf);
	X	}
	X
	X/*-------------------------------------------------------------07/01/86-+
	X|									|
	X|		    usage : display help message			|
	X|									|
	X+----------------------------------------------------------------------*/
	Xstatic usage (pname)
	Xchar	*pname;			/* program name */
	X	{
	X	fprintf (stderr, "%s  %s  %s\n", pname, Version, Author);
	X	fprintf (stderr, "Usage: %s [acepgtxHP]\n", pname);
	X	fprintf (stderr, "where options:\n");
	X	fprintf (stderr, "  H              display this help message\n");
	X	fprintf (stderr, "  P              print processes created by me\n");
	X	fprintf (stderr, "  p              output PID\n");
	X	fprintf (stderr, "  a,c,e,g,t,x    will be passed to ps, if t is\n");
	X	fprintf (stderr, "                 specified, all the rest char in\n");
	X	fprintf (stderr, "                 the argument will be copied\n");
	X	}
SHAR_EOF
if test 8883 -ne "`wc -c < 'ptree.c'`"
then
	echo shar: error transmitting "'ptree.c'" '(should have been 8883 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Kill'" '(2925 characters)'
if test -f 'Kill'
then
	echo shar: will not over-write existing file "'Kill'"
else
sed 's/^	X//' << \SHAR_EOF > 'Kill'
	X#! /bin/csh -f
	X#
	X#-	Kill - kill process with shell form interface
	X#-
	X#-	This  program will use  shell form to   display current user's
	X#-	process  generated by  ptree command.    You  can  tab to  the
	X#-	desired process  and select proper signal to  be  sent  to the
	X#-	process.  Press return will trigger the action.
	X#-
	X#	Author:		Paul Lew, General Systems Group, Inc.
	X#	Created at:	05/12/88  07:56 PM
	X#	Last update:	07/26/88  10:56 AM  (Edition: 32)
	X#
	X#-	Usage:		Kill [string]
	X#-	where option:
	X#-		string	if specified, will do 'ptree ax | grep string'
	X#-			and display only matched process.
	X#
	Xset tmpfile = "/tmp/tmpfile.$$"
	Xset sofile = "/tmp/sofile.$$"
	Xset ptfile = "/tmp/ptfile.$$"
	X#---------------------------------------------------------------#
	X#	      Display help if requested by user			#
	X#---------------------------------------------------------------#
	Xswitch ( "$1" )
	X	case -H[xX]:
	X		set echo; set verbose; shift
	X		breaksw
	X	case -H*:
	X		show_help `which $0` $1
	X		goto end
	X	default:
	X	endsw
	X#---------------------------------------------------------------#
	X#			Process Arguments			#
	X#---------------------------------------------------------------#
	Xset greparg = '.'
	Xset ptflag = 'x'
	Xif ( "$1" != '' ) then
	X	set greparg = $1
	X	set ptflag = 'ax'
	X	endif
	X#---------------------------------------------------------------#
	X#		  Create sf description file			#
	X#---------------------------------------------------------------#
	Xpt p$ptflag > $tmpfile
	Xtr '~' '?' < $tmpfile | sed -n \
	X   -e '1s/COMMAND/SIGNAL &/p;1d' \
	X   -e  '/Kill/d' \
	X   -e "/$greparg/"'{;s/^\(..............................\)\(.*\)$/\1~~~~~~ \2/p;}' \
	X   > $ptfile
	Xsed 's/^......//' $ptfile | colrm 80 > $tmpfile
	X@ lcount = `cat $tmpfile | wc -l`
	X@ lcount--
	Xif ( $lcount == 0 ) then
	X	echo "...Pattern $greparg not found in pt list, aborted..."
	X	goto end
	X	endif
	Xcat << cat_eof >> $tmpfile
	X
	X[TAB (next process), SPACE (next signal), - (no signal), RETURN (execute)]
	X
	Xcat_eof
	X@ i = 0
	Xset sig = "/-     /HUP/INT/QUIT/ILL/TRAP/ABRT/EMT/FPE/KILL/BUS/SEGV/SYS"
	Xset sig = "$sig/PIPE/ALRM/TERM/URG/STOP/TSTP/CONT/CHLD/TTIN/TTOU/IO/XCPU"
	Xset sig = "$sig/XFSZ/VTALRM/PROF/USR1/USR2/PWR/LOST/"
	Xwhile ( $i < $lcount )
	X	@ i++
	X	echo ".v=var$i.s=$sig." >> $tmpfile
	X	end
	X#---------------------------------------------------------------#
	X#		   run sf to get user input			#
	X#---------------------------------------------------------------#
	Xsf -u -o $sofile < $tmpfile
	Xif ( ! -e $sofile ) goto end
	Xsource $sofile
	X@ i = 0
	Xwhile ( $i < $lcount )
	X	@ i++
	X	set var = `eval echo \$var$i`
	X	if ( "$var" != '-' ) then
	X		@ line = $i + 1
	X		kill -$var `sed -n "$line"'s/^ *\([0-9]*\).*$/\1/p' $ptfile`
	X		endif
	X	end
	X#---------------------------------------------------------------#
	X#		Clean up and exit here...			#
	X#---------------------------------------------------------------#
	Xend:
	X	/bin/rm -f $tmpfile $sofile $ptfile
	X	unset tmpfile sofile ptfile i lcount var line greparg ptflag
SHAR_EOF
if test 2925 -ne "`wc -c < 'Kill'`"
then
	echo shar: error transmitting "'Kill'" '(should have been 2925 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0