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