[mod.sources] SPS

sources-request@panda.UUCP (12/03/85)

Mod.sources:  Volume 3, Issue 55
Submitted by: seismo!mcvax!cernvax!hslrswi!robert (Robert Ward)


#! /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:
#	README2
#	README
#	Makefile.4.1
#	Makefile.4.2
#	Makefile.sun
#	filecount.c
#	findtty.c
#	flagdecode.c
#	flags.h
#	flagsetup.c
#	getcmd.c
#	getupage.c
#	globals1.c
#	globals2.c
#	hashuid.c
#	initialise.c
#	initsymbols.c
#	inittty.c
# This archive created: Mon Dec  2 18:40:56 1985
export PATH; PATH=/bin:$PATH
echo shar: extracting "'README2'" '(3050 characters)'
if test -f 'README2'
then
	echo shar: will not over-write existing file "'README2'"
else
sed 's/^X//' << \SHAR_EOF > 'README2'
		SPS  -  Show Process Status
		===========================

XSPS is a intended to be used as a replacement for the standard ps(1)
program. Its advantages over ps(1) are that it shows more useful
information and that it is faster.

XSPS is currently implemented for 4.1 and 4.2bsd Unix on Vaxen and for
XSun's 4.2bsd/Release 2. (I also have a somewhat older implementation
for V7 on a PDP-11 as well as Unisoft Version 1.3 on a MC68000 if you
are interested).

XSPS displays wait channels symbolically, rather than as hexadecimal
addresses. If you wish to teach sps about a new sort of device, you
must add an entry in the symbol table (globals2.c) as well as
increasing the size of that table (NWAITSTATE in sps.h).

XSPS sorts processes before listing them. The order reflects the
relationship of the processes. A child process is listed underneath its
corresponding parent and is indented to depict the exact relationship.
XSPS also indicates setuid processes.

XSPS displays such values as the resident and virtual sizes of system
processes.  It accepts a whole range of options to control the output.
By default, SPS lists information about one's own processes. Other
options instruct it to be verbose (the "v" option), to list all the
command arguments of a process (the "w" option) or to list the
environment strings of that process (the "e" option). Similarly, there
are options to control which processes are to be displayed. The "a"
option tells it to describe all processes and the "b" option tells it
to describe "busy" processes, which is useful if you wish to find out
what is loading your system. There are also options to select the
output according to user, controlling tty or process number.

XSPS keeps its information in an information file. By default, this is
/etc/spsinfo. This means that it can avoid having to do an expensive
nlist() operation each time it is run. It must be reinitialised (with
the "i" option) if new users are added to /etc/passwd or if a new
version of /vmunix is installed.

To compile SPS, unbundle the four shell archive files.  Check that the
define statements in sps.h are large enough for your system (You may
need to alter MAXTTYS).  Then compile it using the appropriate
Makefile. Initialise it by typing "sps i" (ignore any error messages at
this stage) and then test it out by typing "sps va". That should make
XSPS list verbose information about every process currently active. If
that works, use the appropriate Makefile to install it.

XSend all bug reports, fixes, comments and suggestions to Robert Ward at -

******************************************************************************
    Robert Ward,
    Hasler AG, Murtenstrasse 137a, CH-3008 Bern, Switzerland

Tel.:	    (031) - 65 23 19
Uucp:	    ... {seismo,decvax,ukc, ... }!mcvax!cernvax!hslrswi!robert
Bitnet:	    hslrswi!robert@cernvax.bitnet
Arpa:	    hslrswi!robert%cernvax.bitnet@WISCVM.ARPA
Edunet:	    hslrswi!robert%cernvax.bitnet@UCBJADE.Berkeley.EDU
******************************************************************************
SHAR_EOF
if test 3050 -ne "`wc -c < 'README2'`"
then
	echo shar: error transmitting "'README2'" '(should have been 3050 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'README'" '(1226 characters)'
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
sed 's/^X//' << \SHAR_EOF > 'README'
		SPS - Show Process Status
		=========================
To compile, install and test, type the following commands (as super-user):
	% make                  # Compile SPS
	% make install          # Install SPS into /bin/sps
	% sps i                 # Initialise SPS
	% sps va                # Run SPS
********************************************************************************
The files in this directory are for the 4.[12]BSD / VAX-11 version of SPS.
Compiler options are as follows -
	-DCHAOS         if the Chaos network is incorporated into 4.xbsd
	-DTRACE         for testing/debugging purposes
	-DBSD42         compile SPS for 4.2bsd.
			Otherwise, SPS is compiled for 4.1bsd.
********************************************************************************
If you want to tell SPS about a new type of device, then add a new line to
the symbol table (see globals2.c),after ensuring that there is sufficient
room in the `info' structure. (NWAITSTATE may need to be increased in sps.h).
********************************************************************************
XSPS understands if the size of internal kernel tables are changed under VMUNIX,
but must be recompiled if major modifications are made to the kernel.
SHAR_EOF
if test 1226 -ne "`wc -c < 'README'`"
then
	echo shar: error transmitting "'README'" '(should have been 1226 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Makefile.4.1'" '(882 characters)'
if test -f 'Makefile.4.1'
then
	echo shar: will not over-write existing file "'Makefile.4.1'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile.4.1'
# Makefile for SPS (4.1BSD UNIX Version)

PROG    =       sps
OBJS    =       filecount.o findtty.o flagdecode.o flagsetup.o \
		getcmd.o getupage.o globals1.o globals2.o hashuid.o \
		initialise.o initsymbols.o inittty.o main.o mktree.o \
		needed.o openfiles.o percentmem.o prcmd.o prcpu.o \
		prheader.o printall.o printproc.o prsummary.o readstatus.o \
		selectproc.o selecttty.o termwidth.o ttystatus.o waitingfor.o

INCS    =       sps.h
LIBS    =       -ltermlib
CFLAGS  =       -I/usr/src/sys -DCHAOS

all:            $(PROG)
X.c.o:
		cc $(CFLAGS) -c -O -R $<
globals1.o waitingfor.o:
		cc $(CFLAGS) -c -O $<

$(OBJS):        $(INCS)

$(PROG):        $(OBJS)
		cc -o $@ $(OBJS) $(LIBS)

install:        $(PROG)
		strip $(PROG)
		mv $(PROG) /bin/$(PROG)
		/etc/chown root /bin/$(PROG)
		chmod 4711 /bin/$(PROG)

lint:
		lint -x -b $(CFLAGS) *.c
clean:
		rm -f $(OBJS) $(PROG)
SHAR_EOF
if test 882 -ne "`wc -c < 'Makefile.4.1'`"
then
	echo shar: error transmitting "'Makefile.4.1'" '(should have been 882 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Makefile.4.2'" '(853 characters)'
if test -f 'Makefile.4.2'
then
	echo shar: will not over-write existing file "'Makefile.4.2'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile.4.2'
# Makefile for SPS (4.2BSD UNIX Version)

PROG    =       sps
OBJS    =       filecount.o findtty.o flagdecode.o flagsetup.o \
		getcmd.o getupage.o globals1.o globals2.o hashuid.o \
		initialise.o initsymbols.o inittty.o main.o mktree.o \
		needed.o openfiles.o percentmem.o prcmd.o prcpu.o \
		prheader.o printall.o printproc.o prsummary.o readstatus.o \
		selectproc.o selecttty.o termwidth.o ttystatus.o waitingfor.o
INCS    =       sps.h
CC      =       cc
CFLAGS  =       -DBSD42 -I/sys
LIBS    =       -ltermlib

all:		    $(PROG)
X.c.o:
		$(CC) $(CFLAGS) -c -O -R $<
	
globals1.o waitingfor.o:
		$(CC) $(CFLAGS) -c -O $<

$(OBJS):		$(INCS)

$(PROG):		$(OBJS)
		$(CC) -o $@ $(OBJS) $(LIBS)

install:		$(PROG)
		strip $(PROG)
		mv $(PROG) /bin/$(PROG)
		/etc/chown root /bin/$(PROG)

lint:
		lint -x -b $(CFLAGS) *.c
clean:
		rm -f $(OBJS) $(PROG)
SHAR_EOF
if test 853 -ne "`wc -c < 'Makefile.4.2'`"
then
	echo shar: error transmitting "'Makefile.4.2'" '(should have been 853 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Makefile.sun'" '(863 characters)'
if test -f 'Makefile.sun'
then
	echo shar: will not over-write existing file "'Makefile.sun'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile.sun'
# Makefile for SPS (Sun 4.2BSD UNIX Version)

PROG    =       sps
OBJS    =       filecount.o findtty.o flagdecode.o flagsetup.o \
		getcmd.o getupage.o globals1.o globals2.o hashuid.o \
		initialise.o initsymbols.o inittty.o main.o mktree.o \
		needed.o openfiles.o percentmem.o prcmd.o prcpu.o \
		prheader.o printall.o printproc.o prsummary.o readstatus.o \
		selectproc.o selecttty.o termwidth.o ttystatus.o waitingfor.o
INCS    =       sps.h
CC      =       cc
CFLAGS  =       -DSUN -DBSD42 -I/sys
LIBS    =       -ltermlib

all:		    $(PROG)
X.c.o:
		$(CC) $(CFLAGS) -c -O -R $<
	
globals1.o waitingfor.o:
		$(CC) $(CFLAGS) -c -O $<

$(OBJS):		$(INCS)

$(PROG):		$(OBJS)
		$(CC) -o $@ $(OBJS) $(LIBS)

install:		$(PROG)
		strip $(PROG)
		mv $(PROG) /bin/$(PROG)
		/etc/chown root /bin/$(PROG)

lint:
		lint -x -b $(CFLAGS) *.c
clean:
		rm -f $(OBJS) $(PROG)
SHAR_EOF
if test 863 -ne "`wc -c < 'Makefile.sun'`"
then
	echo shar: error transmitting "'Makefile.sun'" '(should have been 863 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'filecount.c'" '(351 characters)'
if test -f 'filecount.c'
then
	echo shar: will not over-write existing file "'filecount.c'"
else
sed 's/^X//' << \SHAR_EOF > 'filecount.c'
# include       "sps.h"

/* FILECOUNT - Counts the # open files for the current process */
filecount ()
{
	register int            i ;
	register struct file    **f ;
	register int            count ;
	extern union userstate  User ;

	count = 0 ;
	for ( i = 0, f = User.u_us.u_ofile ; i < NOFILE ; i++ )
		if ( *f++ )
			count++ ;
	return ( count ) ;
}
SHAR_EOF
if test 351 -ne "`wc -c < 'filecount.c'`"
then
	echo shar: error transmitting "'filecount.c'" '(should have been 351 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'findtty.c'" '(505 characters)'
if test -f 'findtty.c'
then
	echo shar: will not over-write existing file "'findtty.c'"
else
sed 's/^X//' << \SHAR_EOF > 'findtty.c'
# include       "sps.h"
# include       <h/tty.h>

/* FINDTTY - Attempts to determine to which tty a process is connected */
struct ttyline  *findtty ( p )

register struct process         *p ;

{
	register struct ttyline *lp ;
	extern struct info      Info ;
	extern struct ttyline   Notty ;
	extern union userstate  User ;

	if ( !p->pr_p.p_pgrp )
		return ( &Notty ) ;
	for ( lp = Info.i_ttyline ; lp->l_name[0] ; lp++ )
		if ( lp->l_dev == User.u_us.u_ttyd )
			return ( lp ) ;
	return ( &Notty ) ;
}
SHAR_EOF
if test 505 -ne "`wc -c < 'findtty.c'`"
then
	echo shar: error transmitting "'findtty.c'" '(should have been 505 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'flagdecode.c'" '(5436 characters)'
if test -f 'flagdecode.c'
then
	echo shar: will not over-write existing file "'flagdecode.c'"
else
sed 's/^X//' << \SHAR_EOF > 'flagdecode.c'
# include       "sps.h"
# include       "flags.h"

/* FLAGDECODE - Looks at the argument list and sets various internal switches */
flagdecode ( argc, argv )

register int                    argc ;
register char                   **argv ;

{
	register char           *chp ;
	union flaglist          *plist ;
	union flaglist          *tlist ;
	union flaglist          *ulist ;
	static char             usage[] =
	"sps - Unknown option %s\nUsage - sps [ -defgijkoqrsvwyABFNPSTUWZ ][ process|tty|user ] ...\n";
	union flaglist          *getflgsp() ;
	extern struct flags     Flg ;

	plist = tlist = ulist = (union flaglist*)0 ;
	for ( argv++ ; --argc ; argv++ )
	{
		chp = *argv ;
		while ( *chp )
			switch ( *chp++ )
			{
				case '-' :
					/* Separation character */
					continue ;
				case 'd' :
				case 'D' :
					/* List disc orientated information */
					Flg.flg_d = 1 ;
					Flg.flg_v = 0 ;
					continue ;
				case 'e' :
				case 'E' :
					/* List environment strings */
					Flg.flg_e = 1 ;
					continue ;
				case 'f' :
					/* List the father's process id */
					Flg.flg_f = 1 ;
					continue ;
				case 'g' :
				case 'G' :
					/* List the process group id */
					Flg.flg_g = 1 ;
					continue ;
				case 'i' :
				case 'I' :
					/* Initialise (super-user only) */
					Flg.flg_i = 1 ;
					continue ;
				case 'j' :
				case 'J' :
					/* The next argument specifies the
					   name of the information file */
					if ( argc <= 1 )
						prexit(
	      "sps - Name of an information file expected after `-j' flag\n" ) ;
					argc-- ;
					Flg.flg_j = *++argv ;
					continue ;
				case 'k' :
				case 'K' :
					/* Use a disc file such as /vmcore
					   rather than /dev/{k}mem for
					   accessing kernel data. The next
					   argument specifies the file name. */
					if ( argc <= 1 )
						prexit(
	       "sps - Name of a memory dump file expected after `-k' flag\n" ) ;
					argc-- ;
					Flg.flg_k = *++argv ;
					Flg.flg_o = 1 ;
					continue ;
				case 'l' :
				case 'v' :
				case 'L' :
				case 'V' :
					/* Verbose output */
					Flg.flg_d = 0 ;
					Flg.flg_v = 1 ;
					continue ;
				case 'o' :
				case 'O' :
					/* Avoid looking at the swap device */
					Flg.flg_o = 1 ;
					continue ;
				case 'q' :
				case 'Q' :
					/* Show only the user time, not the
					   user + system times together. */
					Flg.flg_q = 1 ;
					continue ;
				case 'r' :
				case 'R' :
					/* Repeat output every n seconds.
					   The next argument specifies n which
					   defaults to 5 if omitted. */
					Flg.flg_r = 1 ;
					if ( argc > 1 )
					{
						if ( **++argv >= '0'
						&& **argv <= '9' )
						{
							argc-- ;
							Flg.flg_rdelay
							       = atoi( *argv ) ;
							continue ;
						}
						argv-- ;
					}
					Flg.flg_rdelay = 0 ;
					continue ;
				case 's' :
					/* Next argument specifies a symbol
					   file rather than the default
					   /vmunix. */
					if ( argc <= 1 )
						prexit(
		    "sps - Name of a symbol file expected after `-s' flag\n" ) ;
					argc-- ;
					Flg.flg_s = *++argv ;
					continue ;
				case 'w' :
					/* Wide output, exceeding 79 columns */
					Flg.flg_w = 1 ;
					continue ;
				case 'y' :
				case 'Y' :
					/* List current tty information */
					Flg.flg_y = 1 ;
					continue ;
				case 'a' :
				case 'A' :
					/* List all processes */
					Flg.flg_AZ = 1 ;
					Flg.flg_A = 1 ;
					continue ;
				case 'b' :
				case 'B' :
					/* List only busy processes */
					Flg.flg_AZ = 1 ;
					Flg.flg_B = 1 ;
					continue ;
				case 'F' :
					/* List only foreground processes */
					Flg.flg_AZ = 1 ;
					Flg.flg_F = 1 ;
					continue ;
				case 'n' :
				case 'N' :
					/* No processes, just the summary line*/
					Flg.flg_AZ = 1 ;
					Flg.flg_N = 1 ;
					continue ;
				case 'p' :
				case 'P' :
					/* List only the given process ids */
					Flg.flg_AZ = 1 ;
					Flg.flg_P = 1 ;
					if ( !plist )
					   plist=Flg.flg_Plist=getflgsp( argc );
					while ( argc > 1 )
					{
						if ( **++argv == '-' )
						{
							--argv ;
							break ;
						}
						--argc ;
						plist->f_chp = *argv ;
						(++plist)->f_chp = (char*)0 ;
					}
					continue ;
				case 'S' :
					/* List only stopped processes */
					Flg.flg_AZ = 1 ;
					Flg.flg_S = 1 ;
					continue ;
				case 't' :
				case 'T' :
					/* List only processes attached to the
					   specified terminals */
					Flg.flg_AZ = 1 ;
					Flg.flg_T = 1 ;
					if ( !tlist )
					   tlist=Flg.flg_Tlist=getflgsp( argc );
					while ( argc > 1 )
					{
						if ( **++argv == '-' )
						{
							--argv ;
							break ;
						}
						--argc ;
						tlist->f_chp = *argv ;
						(++tlist)->f_chp = (char*)0 ;
					}
					continue ;
				case 'u' :
				case 'U' :
					/* List only processes belonging to the
					   specified users */
					Flg.flg_AZ = 1 ;
					Flg.flg_U = 1 ;
					if ( !ulist )
					   ulist=Flg.flg_Ulist=getflgsp( argc );
					while ( argc > 1 )
					{
						if ( **++argv == '-' )
						{
							--argv ;
							break ;
						}
						--argc ;
						ulist->f_chp = *argv ;
						(++ulist)->f_chp = (char*)0 ;
					}
					continue ;
				case 'W' :
					/* List only waiting processes */
					Flg.flg_AZ = 1 ;
					Flg.flg_W = 1 ;
					continue ;
				case 'z' :
				case 'Z' :
					/* List only zombie processes */
					Flg.flg_AZ = 1 ;
					Flg.flg_Z = 1 ;
					continue ;
				default :
					prexit( usage, *argv ) ;
					/* NOTREACHED */
			}
	}
}
SHAR_EOF
if test 5436 -ne "`wc -c < 'flagdecode.c'`"
then
	echo shar: error transmitting "'flagdecode.c'" '(should have been 5436 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'flags.h'" '(2488 characters)'
if test -f 'flags.h'
then
	echo shar: will not over-write existing file "'flags.h'"
else
sed 's/^X//' << \SHAR_EOF > 'flags.h'
/* Structure holding information specified in the option list ... */
union flaglist
{
	char                    *f_chp ;        /* Option specified as string */
	int                     f_uid ;         /* Numerical user id */
	int                     f_pid ;         /* Numerical process id */
	struct ttyline          *f_ttyline ;    /* Specified tty */
} ;

/* Structure holding global information specifed by arg list options ... */
struct flags
{
	int                     flg_d:1 ;       /* disc orientated output */
	int                     flg_e:1 ;       /* print environment string */
	int                     flg_f:1 ;       /* print process father # */
	int                     flg_g:1 ;       /* print process group # */
	int                     flg_i:1 ;       /* initialise sps */
	char                    *flg_j ;        /* Use this as the info file */
	char                    *flg_k ;        /* Use this as the {k}mem file*/
	int                     flg_o:1 ;       /* avoid the swap device */
	int                     flg_q:1 ;       /* show user time only */
	int                     flg_r:1 ;       /* repeat output */
	unsigned                flg_rdelay ;    /* ... with this much delay */
	char                    *flg_s ;        /* Use this as the symbol file*/
	int                     flg_v:1 ;       /* print verbose listing */
	int                     flg_w:1 ;       /* print wide output */
	int                     flg_y:1 ;       /* print tty information */
	int                     flg_A:1 ;       /* print all processes */
	int                     flg_B:1 ;       /* print busy processes */
	int                     flg_F:1 ;       /* print foreground processes */
	int                     flg_N:1 ;       /* print no processes */
	int                     flg_P:1 ;       /* print specified process #'s*/
	int                     flg_S:1 ;       /* print stopped processes */
	int                     flg_T:1 ;       /* print procs for given ttys */
	int                     flg_U:1 ;       /* print procs for given users*/
	int                     flg_W:1 ;       /* print waiting processes */
	int                     flg_Z:1 ;       /* print zombie processes */
	int                     flg_AZ:1 ;      /* One of A to Z was specified*/
	union flaglist          *flg_Plist ;    /* List of specified processes*/
	union flaglist          *flg_Tlist ;    /* List of specified ttys */
	union flaglist          *flg_Ulist ;    /* List of specified users */
} ;
SHAR_EOF
if test 2488 -ne "`wc -c < 'flags.h'`"
then
	echo shar: error transmitting "'flags.h'" '(should have been 2488 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'flagsetup.c'" '(2182 characters)'
if test -f 'flagsetup.c'
then
	echo shar: will not over-write existing file "'flagsetup.c'"
else
sed 's/^X//' << \SHAR_EOF > 'flagsetup.c'
# include       "sps.h"
# include       "flags.h"
# include       <h/tty.h>

/*
** FLAGSETUP - Replaces any users or processes specified by flagdecode()
** with numerical equivalents. The lists are terminated by negative values.
** or null pointers. Ttystatus() must have been previously called to
** initialise the Info structure with chaos tty values.
*/
flagsetup ()
{
	register union flaglist *fp ;
	register char           *chp ;
	register int            i ;
	register struct ttyline *lp ;
	int                     found ;
	extern struct flags     Flg ;
	extern struct info      Info ;

	/* Look for specified users */
	if ( Flg.flg_U )                
	{
		if ( !Flg.flg_Ulist->f_chp )
			prexit( "sps - User name was expected after -u flag\n");
		for ( fp = Flg.flg_Ulist ; chp = fp->f_chp ; fp++ )
		{
			found = 0 ;
			for ( i = 0 ; i < MAXUSERID ; i++ )
				if ( !strncmp( chp, Info.i_hnames[i].h_uname,
					UNAMELEN ) )
				{
					fp->f_uid = Info.i_hnames[i].h_uid ;
					found = 1 ;
					break ;
				}
			if ( !found )
				prexit( "sps - Unknown user: %s\n", chp ) ;
		}
		fp->f_uid = -1 ;
	}
	/* Look for specified process ids */
	if ( Flg.flg_P )                
	{
		if ( !Flg.flg_Plist->f_chp )
			prexit(
			     "sps - Process id was expected after -p flag\n" ) ;
		for ( fp = Flg.flg_Plist ; chp = fp->f_chp ; fp++ )
		{
			if ( chp[0] < '0' || chp[0] > '9' )
				prexit( "sps - Bad process id: %s\n", chp ) ;
			fp->f_pid = atoi( chp ) ;
		}
		fp->f_pid = -1 ;
	}
	/* Look for specified ttys */
	if ( !Flg.flg_T )               
		return ;
	if ( !Flg.flg_Tlist->f_chp )
		prexit( "sps - Tty name was expected after -t flag\n" ) ;
	for ( fp = Flg.flg_Tlist ; chp = fp->f_chp ; fp++ )
	{       /* Under VMUNIX, all ttys have two character names.
		   Thus, a flag of the form `t 8' should be expanded to
		   become `t 08'. */
		if ( !chp[1] )
			chp[1] = chp[0], chp[0] = '0' ;
		found = 0 ;
		for ( lp = Info.i_ttyline ; lp->l_name[0] ; lp++ )
			if ( !strncmp( chp, lp->l_name, 2 ) )
			{
				fp->f_ttyline = lp ;
				found = 1 ;
				break ;
			}
		if ( !found )
			prexit( "sps - Unknown tty name: %.2s\n", chp ) ;
	}
	fp->f_ttyline = (struct ttyline*)0 ;
}
SHAR_EOF
if test 2182 -ne "`wc -c < 'flagsetup.c'`"
then
	echo shar: error transmitting "'flagsetup.c'" '(should have been 2182 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'getcmd.c'" '(4815 characters)'
if test -f 'getcmd.c'
then
	echo shar: will not over-write existing file "'getcmd.c'"
else
sed 's/^X//' << \SHAR_EOF > 'getcmd.c'
# include       "sps.h"
# include       "flags.h"
# include       <h/vm.h>
# ifdef BSD42
# include	<machine/pte.h>
# else
# include       <h/pte.h>
# endif

/*
** GETCMD - Returns a character string read from a process' upage.
** This character string should represent the arguments to the current process.
*/
char    *getcmd ( p )

register struct process         *p ;

{
	register int            *ip ;
	register char           *cp ;
	register char           *cp0 ;
	unsigned                nbad ;
	struct dblock           db ;
	struct pte              ptetbl[ UPAGES + CLSIZE ] ;
	union
	{
		char            a_argc[ CLSIZE * NBPG ] ;
		int             a_argi[ CLSIZE * NBPG / sizeof( int ) ] ;
	} argbuf ;
	extern struct flags     Flg ;
	extern union userstate  User ;
	extern int              Flmem, Flswap ;
	char                    *strcat(), *strncpy(), *strsave() ;

	p->pr_csaved = 0 ;
	p->pr_upag = 0 ;
	if ( p->pr_p.p_stat == SZOMB )
		return ( "** Exit **" ) ;
	if ( !(p->pr_p.p_flag & SLOAD) && Flg.flg_o )
		return ( "** Swapped out **" ) ;
	/* Find the process' upage */
	if ( !getupage( p, ptetbl ) )           
		return ( "** No upage **" ) ;
	/* Is this a system process ? */
	if ( p->pr_p.p_flag & SSYS )            
		switch ( p->pr_p.p_pid )
		{
			case 0 :
				p->pr_upag = 1 ;
				return ( "Unix Swapper" ) ;
			case 2 :
				p->pr_upag = 1 ;
				return ( "Unix Pager" ) ;
			default :
				break ;
		}
	/* Look at the top of the upage to locate the command arguments.
	   The page is loaded if the process itself is loaded and the pte
	   contains is marked as valid. */
	if ( (p->pr_p.p_flag & SLOAD)
	&& !ptetbl[0].pg_fod && ptetbl[0].pg_pfnum )
	{       /* If the page is loaded, read the arguments from
		   physical memory. */
		memseek( Flmem, (long)ctob( ptetbl[0].pg_pfnum ) ) ;
		if ( read( Flmem, argbuf.a_argc, CLSIZE*NBPG ) != CLSIZE*NBPG )
			return ( "** Memory read error **" ) ;
	}
	else                            
	{       /* Otherwise the page is on the swap device */
		vstodb( 0, ctod( CLSIZE ), &User.u_us.u_smap, &db, 1 ) ;
# ifdef BSD42
		swseek( (long)dtob( db.db_base ) ) ;
# else
		swseek( (long)ctob( db.db_base ) ) ;
# endif
		if ( Flg.flg_o )
			return ( "** Swapped page **" ) ;
		if ( read( Flswap, argbuf.a_argc, CLSIZE*NBPG ) != CLSIZE*NBPG )
			return ( "** Swap device read error **" ) ;
	}
	/* Look down until the end of command arguments is found. */
	p->pr_upag = 1 ;
	p->pr_csaved = 1 ;
	ip = &argbuf.a_argi[ CLSIZE*NBPG / sizeof( int ) ] ;
	ip -= 2 ;
	while ( *--ip )
		if ( ip == &argbuf.a_argi[0] )
			goto getsysargs ;
	/* Process the command arguments, looking for nulls and unprintable
	   characters. */
	cp0 = (char*)(ip + 1) ;
	if ( !*cp0 )                    
		cp0++ ;                 
	if ( *cp0 )
	{
		nbad = 0 ;                      
		for ( cp = cp0 ; cp < &argbuf.a_argc[ CLSIZE*NBPG ] ; cp++ )
		{
			*cp &= 0177 ;
			if ( !*cp )             
			{       /* Replace nulls with spaces */
				*cp = ' ' ;
				continue ;
			}
			if ( *cp < ' ' || *cp == 0177 )
			{       /* Replace control characters with ?'s */
				if ( ++nbad > 5 )
				{
					*cp++ = ' ' ;
					break ;
				}
				*cp = '?' ;
				continue ;
			}
			if ( !Flg.flg_e && *cp == '=' )
			{       /* Break on an `=' if we are not interested
				   in the environment strings. */
				*cp = '\0' ;
				while ( cp > cp0 && *--cp != ' ' )
					*cp = '\0' ;
				break ;
			}
		}
		while ( *--cp == ' ' )
			*cp = '\0' ;
		return ( strsave( cp0 ) ) ;
	}
getsysargs :
	/* If the command arguments cannot be accessed from the user's memory
	   space, get the command name from the system's idea of what the
	   name should be. */
	argbuf.a_argc[0] = '(' ;
	(void)strncpy( &argbuf.a_argc[1], User.u_us.u_comm,
		sizeof( User.u_us.u_comm ) ) ;
	(void)strcat( &argbuf.a_argc[0], ")" ) ;
	return ( strsave( argbuf.a_argc ) ) ;
}

/*
** VSTODB - Given a base/size pair in virtual swap area,
** return a physical base/size pair which is the
** (largest) initial, physically contiguous block.
/* This code is stolen from the kernel file /sys/sys/vm_drum.c.
*/
vstodb ( vsbase, vssize, dmp, dbp, rev )

register int                    vsbase ;
register int                    vssize;
struct dmap                     *dmp ;
register struct dblock          *dbp ;
int                             rev ;

{
	register int            blk ;
	register swblk_t        *ip ;
# ifdef BSD42
	extern struct info      Info ;
# endif

# ifdef BSD42
	blk = Info.i_dmmin ;
# else
	blk = DMMIN ;
# endif
	ip = dmp->dm_map ;
	while ( vsbase >= blk )
	{
		vsbase -= blk ;
# ifdef BSD42
		if ( blk < Info.i_dmmax )
# else
		if ( blk < DMMAX )
# endif
			blk *= 2 ;
		ip++ ;
	}
	dbp->db_size = vssize < blk - vsbase ? vssize : blk - vsbase ;
	dbp->db_base = *ip + (rev ? blk - (vsbase + dbp->db_size) : vsbase);
}
SHAR_EOF
if test 4815 -ne "`wc -c < 'getcmd.c'`"
then
	echo shar: error transmitting "'getcmd.c'" '(should have been 4815 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'getupage.c'" '(2971 characters)'
if test -f 'getupage.c'
then
	echo shar: will not over-write existing file "'getupage.c'"
else
sed 's/^X//' << \SHAR_EOF > 'getupage.c'
# include       "sps.h"
# include       <h/vm.h>
# ifdef BSD42
# include	<machine/pte.h>
# else
# include       <h/pte.h>
# endif
# include       <stdio.h>

/*
** GETUPAGE - Reads the upage for the specified process as well as sufficient
** page tables entries for reading the command arguments. The pte's are read
** into the argument `ptetbl'. The upage is read into the external variable
** `User'. This procedure returns 1 if the upage was successfully read.
*/

# define        usrpt           (Info.i_usrpt)

getupage ( p, ptetbl )

register struct process         *p ;
register struct pte             *ptetbl ;

{
	register int            i ;
	register int            ncl ;
	struct pte              pte ;
	extern struct info      Info ;
	extern union userstate  User ;
	extern int              Flmem, Flkmem, Flswap ;

	/* If the process is not loaded, look for the upage on the swap device*/
	if ( !(p->pr_p.p_flag & SLOAD) )
	{                               
# ifdef BSD42
		swseek( (long)dtob( p->pr_p.p_swaddr ) ) ;
# else
		swseek( (long)ctob( p->pr_p.p_swaddr ) ) ;
# endif
# ifdef SUN
		if ( read( Flswap, (char*)&User.u_us, sizeof( union userstate ))
		!= sizeof( union userstate ) )
# else
		if ( read( Flswap, (char*)&User.u_us, sizeof( struct user ) )
		!= sizeof( struct user ) )
# endif
		{
			fprintf( stderr,
				"sps - Can't read upage of process %d\n",
			    p->pr_p.p_pid ) ;
			return ( 0 ) ;
		}
		return ( 1 ) ;          
	}                               
	/* The process is loaded. Locate the process pte's by reading
	   the pte of their base address from system virtual address space. */
	memseek( Flkmem, (long)&Info.i_usrptmap[ btokmx(p->pr_p.p_p0br)
		+ p->pr_p.p_szpt-1 ] ) ;
	if ( read( Flkmem, (char*)&pte, sizeof( struct pte ) )
	!= sizeof( struct pte ) )
	{
		fprintf( stderr,
		      "sps - Can't read indir pte for upage of process %d\n",
		    p->pr_p.p_pid ) ;
		return ( 0 ) ;
	}                               
	/* Now read the process' pte's from physical memory. We need to access
	   sufficient pte's for the upage and for the command arguments. */
	memseek( Flmem, (long)ctob( pte.pg_pfnum+1 )
		- (UPAGES+CLSIZE)*sizeof( struct pte ) ) ;
	if ( read( Flmem, (char*)ptetbl, (UPAGES+CLSIZE)*sizeof( struct pte ) )
	!= (UPAGES+CLSIZE)*sizeof( struct pte ) )
	{
		fprintf( stderr, "sps - Can't read page table of process %d\n",
			p->pr_p.p_pid ) ;
		return ( 0 ) ;
	}
	/* Now we can read the pages belonging to the upage.
	   Here we read in an entire click at one go. */
	ncl = (sizeof( struct user ) + NBPG*CLSIZE - 1) / (NBPG*CLSIZE) ;
	while ( --ncl >= 0 )            
	{                               
		i = ncl * CLSIZE ;
		memseek( Flmem, (long)ctob( ptetbl[ CLSIZE+i ].pg_pfnum ) ) ;
		if ( read( Flmem, User.u_pg[i], CLSIZE*NBPG ) != CLSIZE*NBPG )
		{
			fprintf( stderr,
				"sps - Can't read page 0x%x of process %d\n",
				ptetbl[ CLSIZE+i ].pg_pfnum, p->pr_p.p_pid ) ;
			return ( 0 ) ;
		}
	}
	return ( 1 ) ;
}
SHAR_EOF
if test 2971 -ne "`wc -c < 'getupage.c'`"
then
	echo shar: error transmitting "'getupage.c'" '(should have been 2971 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'globals1.c'" '(720 characters)'
if test -f 'globals1.c'
then
	echo shar: will not over-write existing file "'globals1.c'"
else
sed 's/^X//' << \SHAR_EOF > 'globals1.c'
# include       "sps.h"
# include       "flags.h"

/* Read/Write Variables global to the code of sps */

struct info                     Info ;          /* Information structure */

struct flags                    Flg ;           /* Flag options */

struct summary                  Summary ;       /* Summary of processes */

union  userstate                User ;          /* Upage of one process */

int                             Flmem, Flkmem, Flswap ; /* File descriptors */

unsigned                        Termwidth ;     /* Width of output device */

short                           Lastpgrp ;      /* Last process pgrp printed */

short                           Lastuid ;       /* Last process uid printed */
SHAR_EOF
if test 720 -ne "`wc -c < 'globals1.c'`"
then
	echo shar: error transmitting "'globals1.c'" '(should have been 720 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'globals2.c'" '(5240 characters)'
if test -f 'globals2.c'
then
	echo shar: will not over-write existing file "'globals2.c'"
else
sed 's/^X//' << \SHAR_EOF > 'globals2.c'
# include       "sps.h"

/* Read Only variables, global to the code of sps ... */

/* Null ttyline device ... */
struct ttyline                  Notty = { 0, 0, "  ", 0 } ;

/*
** The symbol table. For each address read from the kernel during
** initialisation, this table shows the following:
**      i.   the name of that symbol within the kernel ;
**      ii.  whether an extra indirection is needed through the kernel,
**           i.e. whether the value of that symbol should be obtained
**           rather than its address.
**      iii. where the obtained value/address is placed in the Info structure ;
**      iv.  whether the obtained value is associated with a reason for
**           a process wait state.
*/
/* The order of entries in this table is unimportant. */

extern struct info              Info ;

struct symbol   Symbollist[] =
{       
	/* Kernel addresses required in order to access process,
	   tty and upage information. All these addresses should be
	   located in the symbol file during initialisation. */
	{ "_proc",      1,  (caddr_t*)&Info.i_proc0,    (char*)0        },
	{ "_nproc",     1,  (caddr_t*)&Info.i_nproc,    (char*)0        },
	{ "_text",      1,  (caddr_t*)&Info.i_text0,    (char*)0        },
	{ "_ntext",     1,  (caddr_t*)&Info.i_ntext,    (char*)0        },
	{ "_inode",     1,  (caddr_t*)&Info.i_inode0,   (char*)0        },
	{ "_ninode",    1,  (caddr_t*)&Info.i_ninode,   (char*)0        },
	{ "_swbuf",     1,  (caddr_t*)&Info.i_swbuf0,   (char*)0        },
	{ "_nswbuf",    1,  (caddr_t*)&Info.i_nswbuf,   (char*)0        },
	{ "_buf",       1,  (caddr_t*)&Info.i_buf0,     (char*)0        },
	{ "_nbuf",      1,  (caddr_t*)&Info.i_nbuf,     (char*)0        },
	{ "_ecmx",      1,  (caddr_t*)&Info.i_ecmx,     (char*)0        },
	{ "_Usrptmap",  0,  (caddr_t*)&Info.i_usrptmap, (char*)0        },
	{ "_usrpt",     0,  (caddr_t*)&Info.i_usrpt,    (char*)0        },
	{ "_cdevsw",    0,  (caddr_t*)&Info.i_cdevsw,   (char*)0        },
# ifdef BSD42
	{ "_quota",     1,  (caddr_t*)&Info.i_quota0,   (char*)0        },
	{ "_nquota",    1,  (caddr_t*)&Info.i_nquota,   (char*)0        },
	{ "_dmmin",     1,  (caddr_t*)&Info.i_dmmin,    (char*)0        },
	{ "_dmmax",     1,  (caddr_t*)&Info.i_dmmax,    (char*)0        },
	{ "_mbutl",     0,  (caddr_t*)&Info.i_mbutl,    (char*)0        },
# else
	{ "_hz",        1,  (caddr_t*)&Info.i_hz,       (char*)0        },
# endif
# ifdef CHAOS
	{ "_Chconntab", 0,  &Info.i_Chconntab,          (char*)0        },
# endif
	/* Kernel addresses associated with process wait states.
	   It is not important if some of these addresses are unresolved
	   at initialisation. */
	{ "_fltab",     0,  &Info.i_waitstate[0],       "floppy"        },
	{ "_tu",        0,  &Info.i_waitstate[1],       "tu58"          },
	{ "_bfreelist", 0,  &Info.i_waitstate[2],       "buffer"        },
	{ "_lp_softc",  0,  &Info.i_waitstate[3],       "printr"        },
	{ "_lbolt",     0,  &Info.i_waitstate[4],       "lbolt"         },
	{ "_runin",     0,  &Info.i_waitstate[5],       "runin"         },
	{ "_runout",    0,  &Info.i_waitstate[6],       "runout"        },
	{ "_ipc",       0,  &Info.i_waitstate[7],       "ptrace"        },
	{ "_u",         0,  &Info.i_waitstate[8],       "pause"         },
	{ "_freemem",   0,  &Info.i_waitstate[9],       "freemm"        },
	{ "_kernelmap", 0,  &Info.i_waitstate[10],      "kermap"        },
	{ "_cwaiting",  0,  &Info.i_waitstate[11],      "cwait"         },
	{ "_rhpbuf",    0,  &Info.i_waitstate[12],      "rhpbuf"        },
	{ "_rhtbuf",    0,  &Info.i_waitstate[13],      "rhtbuf"        },
	{ "_ridcbuf",   0,  &Info.i_waitstate[14],      "ridcbf"        },
	{ "_rikbuf",    0,  &Info.i_waitstate[15],      "rikbuf"        },
	{ "_rmtbuf",    0,  &Info.i_waitstate[16],      "rmtbuf"        },
	{ "_rrkbuf",    0,  &Info.i_waitstate[17],      "rrkbuf"        },
	{ "_rrlbuf",    0,  &Info.i_waitstate[18],      "rrlbuf"        },
	{ "_rrxbuf",    0,  &Info.i_waitstate[19],      "rrxbuf"        },
	{ "_rswbuf",    0,  &Info.i_waitstate[20],      "rswbuf"        },
	{ "_rtmbuf",    0,  &Info.i_waitstate[21],      "rtmbuf"        },
	{ "_rtsbuf",    0,  &Info.i_waitstate[22],      "rtsbuf"        },
	{ "_rudbuf",    0,  &Info.i_waitstate[23],      "rudbuf"        },
	{ "_rupbuf",    0,  &Info.i_waitstate[24],      "rupbuf"        },
	{ "_rutbuf",    0,  &Info.i_waitstate[25],      "rutbuf"        },
	{ "_rvabuf",    0,  &Info.i_waitstate[26],      "rvabuf"        },
	{ "_rvpbuf",    0,  &Info.i_waitstate[27],      "rvpbuf"        },
	{ "_chtbuf",    0,  &Info.i_waitstate[28],      "chtbuf"        },
	{ "_cmtbuf",    0,  &Info.i_waitstate[29],      "cmtbuf"        },
	{ "_ctmbuf",    0,  &Info.i_waitstate[30],      "ctmbuf"        },
	{ "_ctsbuf",    0,  &Info.i_waitstate[31],      "ctsbuf"        },
	{ "_cutbuf",    0,  &Info.i_waitstate[32],      "cutbuf"        },
# ifdef BSD42
	{ "_selwait",   0,  &Info.i_waitstate[33],      "select"        },
# endif
# ifdef CHAOS
	{ "_Chrfclist", 0,  &Info.i_waitstate[34],      "chrfc"         },
# endif
# ifdef SUN
	{ "_async_bufhead", 0,  &Info.i_waitstate[35],  "async"		},
# endif
	{ (char*)0,     0,  (caddr_t*)0,                (char*)0        }
} ;
SHAR_EOF
if test 5240 -ne "`wc -c < 'globals2.c'`"
then
	echo shar: error transmitting "'globals2.c'" '(should have been 5240 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'hashuid.c'" '(1421 characters)'
if test -f 'hashuid.c'
then
	echo shar: will not over-write existing file "'hashuid.c'"
else
sed 's/^X//' << \SHAR_EOF > 'hashuid.c'
# include       "sps.h"

/* The hashing functions themselves ... */
# define        HASHFN1( a )            (((a)*91 + 17) % MAXUSERID)
# define        HASHFN2( a )            (((a) + 47) % MAXUSERID)

/*
** HASHUID - Returns a pointer to a slot in the hash table that corresponds
** to the hash table entry for `uid'. It returns a null pointer if there is
** no such slot.
*/
struct hashtab  *hashuid ( uid )

int                             uid ;

{
	register struct hashtab *hp ;
	register int            i ;
	register int            j ;
	extern struct info      Info ;

	j = HASHFN1( uid ) ;
	for ( i = 0 ; i < MAXUSERID ; i++ )
	{
		hp = &Info.i_hnames[ j ] ;
		if ( !hp->h_uname[0] )
			return ( (struct hashtab*)0 ) ;
		if ( hp->h_uid == uid )
			return ( hp ) ;
		j = HASHFN2( j ) ;
	}
	return ( (struct hashtab*)0 ) ;
}

/*
** HASHNEXT - Returns a pointer to the next slot in the hash table that
** may be use for storing information for `uid'. It returns a null pointer
** if there are no more free slots available.
*/
struct hashtab  *hashnext ( uid )

int                             uid ;

{
	register struct hashtab *hp ;
	register int            i ;
	register int            j ;
	extern struct info      Info ;

	j = HASHFN1( uid ) ;
	for ( i = 0 ; i < MAXUSERID ; i++ )
	{
		hp = &Info.i_hnames[ j ] ;
		if ( !hp->h_uname[0] )
			return ( hp ) ;
		j = HASHFN2( j ) ;
	}
	return ( (struct hashtab*)0 ) ;
}
SHAR_EOF
if test 1421 -ne "`wc -c < 'hashuid.c'`"
then
	echo shar: error transmitting "'hashuid.c'" '(should have been 1421 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'initialise.c'" '(1905 characters)'
if test -f 'initialise.c'
then
	echo shar: will not over-write existing file "'initialise.c'"
else
sed 's/^X//' << \SHAR_EOF > 'initialise.c'
# include       "sps.h"
# include       "flags.h"
# include       <pwd.h>
# include       <stdio.h>

/*
** INITIALISE - Called to reset the `Info' structure with new kernel
** addresses and user and tty information.
*/
initialise ()
{
	register FILE           *fd ;
	char                    *fileinfo ;
	extern struct flags     Flg ;
	extern struct info      Info ;
	FILE                    *fopen() ;

	fileinfo = Flg.flg_j ? Flg.flg_j : FILE_INFO ;
	/* Read kernel addresses */
	initsymbols() ;                 
	/* Read user names */
	initusers() ;                   
	(void)umask( ~0644 ) ;          
	if ( !(fd = fopen( fileinfo, "w" )) )
	{
		fprintf( stderr, "sps - Can't create info file %s", fileinfo ) ;
		sysperror() ;
	}
	/* Find tty addresses */
	inittty() ;                     
	if ( fwrite( (char*)&Info, sizeof( struct info ), 1, fd ) != 1 )
	{
		fprintf( stderr, "sps - Can't write info file %s", fileinfo ) ;
		sysperror() ;
		exit( 1 ) ;
	}
	(void)fclose( fd ) ;
	printf( "sps is initialised\n" ) ;
}

/* INITUSERS - Read the passwd file and fill in the user name arrays */
initusers ()
{
	register struct passwd  *pw ;
	register struct hashtab *hp ;
	struct passwd           *getpwent() ;
	char                    *strncpy() ;
	struct hashtab          *hashuid(), *hashnext() ;

	while ( pw = getpwent() )
	{       /* For each user in the passwd file, first see if that uid
		   has been already allocated in the hash table. */
		if ( hp = hashuid( pw->pw_uid ) )
		{
			fprintf( stderr,
		   "sps - Names %s and %s conflict in passwd file for uid %d\n",
				hp->h_uname, pw->pw_name, pw->pw_uid ) ;
			continue ;
		}
		/* Try to find a free slot in the hash table and fill it. */
		if ( !(hp = hashnext( pw->pw_uid )) )
			prexit( "sps - Too many users in passwd file\n" ) ;
		hp->h_uid = pw->pw_uid ;
		(void)strncpy( hp->h_uname, pw->pw_name, UNAMELEN ) ;
	}
	(void)endpwent() ;
}
SHAR_EOF
if test 1905 -ne "`wc -c < 'initialise.c'`"
then
	echo shar: error transmitting "'initialise.c'" '(should have been 1905 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'initsymbols.c'" '(2994 characters)'
if test -f 'initsymbols.c'
then
	echo shar: will not over-write existing file "'initsymbols.c'"
else
sed 's/^X//' << \SHAR_EOF > 'initsymbols.c'
# include       "sps.h"
# include       "flags.h"
# ifdef BSD42
# include       <sys/file.h>
# endif
# include       <nlist.h>
# include       <stdio.h>

/* INITSYMBOLS - Reads kmem values into the Info structure */
/*
** THIS CODE COPIES KMEM VALUES INTO THE INFO STRUCTURE ASSUMING THAT
** VALUES READ FROM THE KERNEL HAVE TYPE CADDR_T. THEREFORE, WE ARE
** MAKING THE DUBIOUS ASSUMPTION THAT INTS, POINTERS AND CADDR_T's
** HAVE IDENTICAL SIZES.
*/
initsymbols ()
{
	register struct nlist   *np ;
	register struct symbol  *s ;
	register struct nlist   *np0 ;
	char                    *filesymbol ;
	extern int              Flkmem ;
	extern struct flags     Flg ;
	extern struct symbol    Symbollist[] ;
	extern struct info      Info ;
	char                    *getcore() ;
	char                    *strncpy() ;

	filesymbol = Flg.flg_s ? Flg.flg_s : FILE_SYMBOL ;
	/* Find the length of the symbol table */
	for ( s = Symbollist ; s->s_kname ; s++ )
		;
	/* Construct an nlist structure by copying names from the symbol table*/
	np0 = (struct nlist*)getcore( (s-Symbollist+1)*sizeof( struct nlist ) );
	for ( s = Symbollist, np = np0 ; s->s_kname ; s++, np++ )
	{                                       
		np->n_name = s->s_kname ;       
		np[1].n_name = (char*)0 ;       
		np->n_value = 0 ;
	}
# ifdef BSD42
	if ( access( filesymbol, R_OK ) < 0 )
# else
	if ( access( filesymbol, 4 ) < 0 )
# endif
	{
		fprintf( stderr, "sps - Can't open symbol file %s", filesymbol);
		sysperror() ;
	}
	/* Get kernel addresses */
	nlist( filesymbol, np0 ) ;              
	if ( np0[0].n_value == -1 )
	{
		fprintf( stderr, "sps - Can't read symbol file %s", filesymbol);
		sysperror() ;
	}
	for ( s = Symbollist, np = np0 ; s->s_kname ; s++, np++ )
	{                                       
		if ( !np->n_value )             
		{
			fprintf( stderr, "sps - Can't find symbol %s in %s",
				np->n_name, filesymbol ) ;
			/* Assume this error to be unimportant if the address
			   is only associated with a process wait state.
			   This may happen if the system has been configured
			   without a particular device. */
			fprintf( stderr, &Info.i_waitstate[ 0 ] <= s->s_info
				&& s->s_info < &Info.i_waitstate[ NWAITSTATE ]
				? " (error is not serious)\n"
				: " (ERROR MAY BE SERIOUS)\n" ) ;
			*s->s_info = (caddr_t)0 ;
			continue ;
		}
		/* If no indirection is required, just copy the obtained value
		   into the `Info' structure. */
		if ( !s->s_indirect )           
		{                               
		/* DUBIOUS ASSUMPTION THAT KMEM VALUE HAS SIZE OF A CADDR_T */
			*s->s_info = (caddr_t)np->n_value ;
			continue ;              
		}                               
		/* Otherwise one level of indirection is required. Using the
		   obtained address, look again in the kernel for the value */
		memseek( Flkmem, (long)np->n_value ) ;
		/* DUBIOUS ASSUMPTION THAT KMEM VALUE HAS SIZE OF A CADDR_T */
		(void)read( Flkmem, (char*)s->s_info, sizeof(caddr_t) ) ;
	}
	free( (char*)np0 ) ;
}
SHAR_EOF
if test 2994 -ne "`wc -c < 'initsymbols.c'`"
then
	echo shar: error transmitting "'initsymbols.c'" '(should have been 2994 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'inittty.c'" '(3544 characters)'
if test -f 'inittty.c'
then
	echo shar: will not over-write existing file "'inittty.c'"
else
sed 's/^X//' << \SHAR_EOF > 'inittty.c'
# include       "sps.h"
# include       <h/conf.h>
# include       <h/tty.h>
# include       <sys/stat.h>
# include       <stdio.h>

/* INITTTY - Initialise the tty part of the info structure */
inittty ()
{
	register struct ttyline *lp ;
# ifdef BSD42
	register struct direct  *dp ;
	DIR                     *dfd ;
# else
	struct direct           dir ;
	FILE                    *dfd ;
# endif
	struct stat             statbuf ;
	static char             filedev[] = FILE_DEV ;
	extern struct info      Info ;
	extern int              Flkmem ;
# ifdef BSD42
	DIR                     *opendir() ;
	struct direct           *readdir() ;
# else
	FILE                    *fopen() ;
# endif

	lp = Info.i_ttyline ;
# ifdef BSD42
	if ( !(dfd = opendir( filedev )) )
# else
	if ( !(dfd = fopen( filedev, "r" )) )
# endif
		prexit( "Can't open %s\n", filedev ) ;
	if ( chdir( filedev ) < 0 )
		prexit( "sps - Can't chdir to %s\n", filedev ) ;
# ifdef BSD42
	/* Read all entries in the device directory, looking for ttys */
	while ( dp = readdir( dfd ) )
	{       /* Skip entries that do not match "tty" or "console" */
		if ( strncmp( "tty", dp->d_name, 3 )
		&&   strcmp( "console", dp->d_name ) )
			continue ;
		/* Skip "tty" itself */
		if ( dp->d_namlen == 3 )
			continue ;
# ifdef CHAOS
		/* Skip chaos ttys ; they are accessed during ttystatus() */
		if ( dp->d_namelen > 3 &&
		dp->d_name[ sizeof( "tty" ) - 1 ] == 'C' )
			continue ;
# endif
		if ( lp >= &Info.i_ttyline[ MAXTTYS ] )
			prexit( "sps - Too many ttys in %s\n", filedev ) ;
		/* Copy the tty name into the information entry */
		if ( !strcmp( dp->d_name, "console" ) )
		{
			lp->l_name[0] = 'c' ;
			lp->l_name[1] = 'o' ;
		}
		else
		{
			lp->l_name[0] = dp->d_name[3] ;
			lp->l_name[1] = dp->d_name[4] ;
		}
		/* Ensure that this tty is actually a valid character device */
		if ( stat( dp->d_name, &statbuf ) < 0 )
			continue ;
# else
	/* Read all entries in the device directory, looking for ttys */
	while ( fread( (char*)&dir, sizeof( struct direct ), 1, dfd ) == 1 )
	{       /* Skip entries that do not match "tty" or "console" */
		if ( strncmp( "tty", dir.d_name, 3 )
		&&   strcmp( "console", dir.d_name ) )
			continue ;
		/* Skip "tty" itself */
		if ( dir.d_name[3] == '\0' )
			continue ;
# ifdef CHAOS
		/* Skip chaos ttys ; they are accessed during ttystatus() */
		if ( dir.d_name[ sizeof( "tty" ) - 1 ] == 'C' )
			continue ;
# endif
		if ( lp >= &Info.i_ttyline[ MAXTTYS ] )
			prexit( "sps - Too many ttys in %s\n", filedev ) ;
		/* Copy the tty name into the information entry */
		if ( !strcmp( dir.d_name, "console" ) )
		{
			lp->l_name[0] = 'c' ;
			lp->l_name[1] = 'o' ;
		}
		else
		{
			lp->l_name[0] = dir.d_name[3] ;
			lp->l_name[1] = dir.d_name[4] ;
		}
		/* Ensure that this tty is actually a valid character device */
		if ( stat( dir.d_name, &statbuf ) < 0 )
			continue ;
# endif
		if ( (statbuf.st_mode & S_IFMT) != S_IFCHR )
			continue ;
		/* Find the device # of the tty and the address of its
		   associated struct tty in /dev/kmem. */
		lp->l_dev = statbuf.st_rdev ;
		memseek( Flkmem,
		     (long)&Info.i_cdevsw[ major( statbuf.st_rdev ) ].d_ttys ) ;
		if ( read( Flkmem, (char*)&lp->l_addr, sizeof( lp->l_addr ) )
		!= sizeof( lp->l_addr ) )
		{
			fprintf( stderr, "sps - Can't read struct tty for %s\n",
# ifdef BSD42
				dp->d_name ) ;
# else
				dir.d_name ) ;
# endif
			continue ;
		}
		lp->l_addr += (int)minor( statbuf.st_rdev ) ;
		lp++ ;
	}
# ifdef BSD42
	(void)closedir( dfd ) ;
# else
	(void)fclose( dfd ) ;
# endif
}
SHAR_EOF
if test 3544 -ne "`wc -c < 'inittty.c'`"
then
	echo shar: error transmitting "'inittty.c'" '(should have been 3544 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0

sources-request@panda.UUCP (12/03/85)

Mod.sources:  Volume 3, Issue 56
Submitted by: seismo!mcvax!cernvax!hslrswi!robert (Robert Ward)


#! /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:
#	main.c
#	mktree.c
#	needed.c
#	openfiles.c
#	percentmem.c
#	prcmd.c
#	prcpu.c
#	prheader.c
#	printall.c
#	printproc.c
#	prsummary.c
#	readstatus.c
#	selectproc.c
#	selecttty.c
#	sps.h
#	termwidth.c
#	ttystatus.c
#	waitingfor.c
# This archive created: Mon Dec  2 18:41:14 1985
export PATH; PATH=/bin:$PATH
echo shar: extracting "'main.c'" '(2626 characters)'
if test -f 'main.c'
then
	echo shar: will not over-write existing file "'main.c'"
else
sed 's/^X//' << \SHAR_EOF > 'main.c'
# include       "sps.h"
# include       "flags.h"
# include       <h/text.h>
# include       <stdio.h>

/* SPS - Show Process Status */
/* J. R. Ward - Hasler AG Bern - 24 May 1985 */
main ( argc,argv )

int                             argc ;
char                            **argv ;

{
	register struct process *plist ;
	register struct process *process ;
	register struct text    *text ;
	int                     flinfo ;
	extern struct flags     Flg ;
	extern struct info      Info ;
	extern int              Flmem ;
	extern int              Flkmem ;
	extern int              Flswap ;
	char                    *getcore() ;
	struct process          *needed(), *mktree() ;

	/* Renice as fast as possible for root (Suggested by Gregorio!mogul) */
	if ( !getuid() )
		(void)nice( -40 ) ;
	/* Decode the flag arguments */
	flagdecode( argc, argv ) ;      
	/* Determine the terminal width */
	if ( !Flg.flg_w && !Flg.flg_N && !Flg.flg_i )
		termwidth() ;
	/* Open the cpu physical memory, kernel virtual memory and swap device*/
	if ( Flg.flg_k )
	{
		Flmem = openfile( Flg.flg_k ) ;
		Flkmem = Flmem ;
	}
	else
	{
		Flmem = openfile( FILE_MEM ) ;
		Flkmem = openfile( FILE_KMEM ) ;
		if ( !Flg.flg_o )
			Flswap = openfile( FILE_SWAP ) ;
	}
	if ( Flg.flg_i )
	{       /* -i flag for info file initialisation */
		initialise() ;          
		exit( 0 ) ;
	}
	/* Read the information file */
	flinfo = openfile( Flg.flg_j ? Flg.flg_j : FILE_INFO ) ;
	if ( read( flinfo, (char*)&Info, sizeof( struct info ) )
	!= sizeof( struct info ) )
	{
		fprintf( stderr, "sps - Can't read info file %s",
			Flg.flg_j ? Flg.flg_j : FILE_INFO ) ;
		sysperror() ;
	}
	(void)close( flinfo ) ;
	/* Find current tty status */
	ttystatus() ;                   
	/* Now that we know the available ttys, decode the flags */
	flagsetup() ;                   
	process = (struct process*)getcore(Info.i_nproc*sizeof(struct process));
	text = (struct text*)getcore( Info.i_ntext * sizeof( struct text ) ) ;
	do
	{       /* Read current process and text status */
		readstatus( process, text ) ;
		/* Select those processes to be listed */
		plist = needed( process, text ) ;
		/* Form a tree of listed processes */
		plist = mktree( process, plist ) ;
		if ( !Flg.flg_N )
		{       /* Print the processes */
			prheader() ;
			printall( plist, 0 ) ;
		}
		prsummary() ;
		(void)fflush( stdout ) ;
		if ( Flg.flg_r )        
		{       /* If repeating, again get tty status */
			ttystatus() ;
			if ( Flg.flg_rdelay )
# ifdef BSD42
				sleep( Flg.flg_rdelay ) ;
# else
				sleep( (int)Flg.flg_rdelay ) ;
# endif
		}
	} while ( Flg.flg_r ) ;
	exit( 0 ) ;
}
SHAR_EOF
if test 2626 -ne "`wc -c < 'main.c'`"
then
	echo shar: error transmitting "'main.c'" '(should have been 2626 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'mktree.c'" '(1626 characters)'
if test -f 'mktree.c'
then
	echo shar: will not over-write existing file "'mktree.c'"
else
sed 's/^X//' << \SHAR_EOF > 'mktree.c'
# include       "sps.h"

/*
** MKTREE - Sort the needed processes by subtree and at the top by user.
** This procedure takes a list of processes (as returned by needed())
** and returnes a pointer to a sorted list.
*/
struct process  *mktree ( process, plist )

struct process                  *process ;
struct process                  *plist ;

{
	register struct process *p ;
	register struct process *pp ;
	register struct process *lp ;
	struct process          *op ;
	struct process          proot ;

	proot.pr_sibling = (struct process*)0 ;
	for ( p = plist ; p ; p = p->pr_plink )
	{
		if ( p->pr_pptr > &process[1] )
		{
			for ( pp = plist ; pp ; pp = pp->pr_plink )
			{
				if ( pp != p->pr_pptr )
					continue ;
				if ( lp = pp->pr_child )
				{       /* Does process have children ? */
					op = (struct process*)0 ;
					while (lp &&
					lp->pr_p.p_pid < p->pr_p.p_pid )
					{
						op = lp ;
						lp=lp->pr_sibling ;
					}
					if ( op )
					{
						p->pr_sibling = lp ;
						op->pr_sibling = p ;
						break ;
					}
				}       
				p->pr_sibling = lp ;
				pp->pr_child = p ;
				break ;
			}
			if ( pp )
				continue ;
		}
		/* We have a top level process, sort into top level list.
		   The top level is sorted firstly by user-id and then
		   by process-id. */
		lp = &proot ;
		pp = lp->pr_sibling ;
		while ( pp )
		{
			if ( p->pr_p.p_uid < pp->pr_p.p_uid )
				break ;
			if ( p->pr_p.p_uid == pp->pr_p.p_uid
			&& p->pr_p.p_pid < pp->pr_p.p_pid )
				break ;
			lp = pp, pp = pp->pr_sibling ;
		}
		p->pr_sibling = lp->pr_sibling ;
		lp->pr_sibling = p ;
	}
	return ( proot.pr_sibling ) ;
}
SHAR_EOF
if test 1626 -ne "`wc -c < 'mktree.c'`"
then
	echo shar: error transmitting "'mktree.c'" '(should have been 1626 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'needed.c'" '(4455 characters)'
if test -f 'needed.c'
then
	echo shar: will not over-write existing file "'needed.c'"
else
sed 's/^X//' << \SHAR_EOF > 'needed.c'
# include       "sps.h"
# include       "flags.h"
# include       <h/text.h>
# include       <stdio.h>

/*
** NEEDED - Determine which processes are needed for the printout
** and add these to a list of needed processes.
*/
struct process  *needed ( process, text )

register struct process         *process ;
struct text                     *text ;

{
	register struct process *p ;
	register struct process *plist ;
	struct process          *lastp ;
	int                     uid ;
	extern struct flags     Flg ;
	extern union userstate  User ;
	extern struct info      Info ;
	extern struct ttyline   Notty ;
	struct ttyline          *findtty() ;
	char                    *getcmd() ;

	plist = (struct process*)0 ;
	lastp = &process[ Info.i_nproc ] ;
	/* Normalise internal pointers from kernel addresses. For each kmem
	   address in the `proc' and `text' structures, we convert that
	   address for our own internal use. */
	for ( p = process ; p < lastp ; p++ )
	{                               
		if ( !p->pr_p.p_stat )  
			continue ;
		/* Normalise internal text pointers */
		if ( p->pr_p.p_textp )
			p->pr_p.p_textp = &text[p->pr_p.p_textp - Info.i_text0];
		/* Normalise internal linked list of processes */
		p->pr_plink = p->pr_p.p_link ?
			&process[ p->pr_p.p_link  - Info.i_proc0 ] :
			(struct process*)0 ;
		/* Normalise internal parent pointers */
		p->pr_pptr = p->pr_p.p_pptr ?
			&process[ p->pr_p.p_pptr - Info.i_proc0 ] :
			(struct process*)0 ;
		/* Check for valid parent pointers */
		if ( !p->pr_pptr )
		{
			p->pr_pptr = process ;
			continue ;
		}
		if ( p->pr_pptr < process || p->pr_pptr >= lastp )
		{
			fprintf( stderr, "sps - process %d has bad pptr\n",
				p->pr_p.p_pid ) ;
			p->pr_pptr = process ;
		}
	}
	/* For each process, see if it is a candidate for selection.
	   If so, retrieve its command arguments and upage information. */
	uid = getuid() ;
	for ( p = process ; p < lastp ; p++ )
	{                               
		if ( !p->pr_p.p_stat )
			continue ;
		/* Count processes and sizes */
		summarise( p ) ;
		/* Select the given processes. Bear in mind that selection
		   of processes based on the `F' and `T' flags must be
		   postponed until the upage is accessed. */
		if ( !Flg.flg_F && !Flg.flg_T && !selectproc( p, process, uid ))
			continue ;
		/* Try to find the process' command arguments. Accessing the
		   arguments also involves retrieving the upage. */
		p->pr_cmd = getcmd( p ) ;
		/* If the upage was found successfully, use this information */
		if ( p->pr_upag )       
		{
# ifdef BSD42
			p->pr_rself = User.u_us.u_ru ;
			p->pr_rchild = User.u_us.u_cru ;
# else
			p->pr_vself = User.u_us.u_vm ;
			p->pr_vchild = User.u_us.u_cvm ;
# endif
			p->pr_tty = findtty( p ) ;
			p->pr_files = filecount() ;
		}
		else
			p->pr_tty = &Notty ;
		/* Select on the basis of the `F' and `T' flags */
		if ( Flg.flg_F          
		&& !(p->pr_p.p_pgrp && p->pr_p.p_pgrp == p->pr_tty->l_pgrp) )
			continue ;
		if ( Flg.flg_T && !selecttty( p ) )
			continue ;
		/* Arrive here with a selected process. Add this to the
		   linked list of needed processes. */
		p->pr_plink = plist ;   
		plist = p ;
		p->pr_child = (struct process*)0 ;
		p->pr_sibling = (struct process*)0 ;
	}
	return ( plist ) ;
}

/* SUMMARISE - Summarises the given process into the `Summary' structure */
/*
** SHOULD ACCOUNT HERE FOR THE SIZE OF LOADED PAGE TABLES, BUT WE DON'T REALLY
** KNOW THEIR RESIDENT SIZES.
*/
summarise ( p )

register struct process         *p ;

{
	register struct text    *tp ;
	int                     busy ;
	extern struct summary   Summary ;

	Summary.sm_ntotal++ ;
	if ( p->pr_p.p_stat == SZOMB )
		return ;
	/* Firstly, account for processes */
	Summary.sm_ktotal += p->pr_p.p_dsize + p->pr_p.p_ssize ;
	Summary.sm_kloaded += p->pr_p.p_rssize ;
	Summary.sm_kswapped += p->pr_p.p_swrss ;
	if ( p->pr_p.p_flag & SLOAD )
		Summary.sm_nloaded++ ;
	else
		Summary.sm_nswapped++ ;
	busy = (p->pr_p.p_stat == SRUN) || (p->pr_p.p_stat==SSLEEP
	     && (p->pr_p.p_pri<PZERO && p->pr_p.p_pid > MSPID) ) ;
	if ( busy )
	{
		Summary.sm_nbusy++ ;
		Summary.sm_kbusy += p->pr_p.p_dsize + p->pr_p.p_ssize ;
	}
	/* Now account for their texts */
	if ( !(tp = p->pr_p.p_textp) || !tp->x_count )
		return ;                
	Summary.sm_ktotal += tp->x_size ;
	Summary.sm_kloaded += tp->x_rssize ;
	Summary.sm_kswapped += tp->x_swrss ;
	if ( busy )
		Summary.sm_kbusy += tp->x_size ;
	tp->x_count = 0 ;
}
SHAR_EOF
if test 4455 -ne "`wc -c < 'needed.c'`"
then
	echo shar: error transmitting "'needed.c'" '(should have been 4455 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'openfiles.c'" '(2626 characters)'
if test -f 'openfiles.c'
then
	echo shar: will not over-write existing file "'openfiles.c'"
else
sed 's/^X//' << \SHAR_EOF > 'openfiles.c'
# include       <stdio.h>
# include       "sps.h"
# include       "flags.h"

/* Miscellaneous procedures */

/* OPENFILE - Opens the named file */
openfile ( name )

char                            *name ;

{
	register int            fd ;

	if ( (fd = open( name, 0 )) >= 0 )
		return ( fd ) ;
	fprintf( stderr, "sps - Can't open %s", name ) ;
	sysperror() ;
	/* NOTREACHED */
}

/* MEMSEEK - Seek on a special file */
memseek ( fd, pos )

int                             fd ;
long                            pos ;

{
	extern int              errno ;
	extern struct flags     Flg ;
	long                    lseek() ;

	errno = 0 ;
	if ( Flg.flg_k )
		pos &= 0x7fffffff ;
	(void)lseek( fd, pos, 0 ) ;
	if ( errno )
	{
		fprintf( stderr, "sps - Seek failed" ) ;
		sysperror() ;
	}
}

/* SWSEEK - Seek on the swap device */
swseek ( pos )

long                            pos ;

{
	extern int              Flswap ;
	extern int              errno ;
	long                    lseek() ;

	errno = 0 ;
	(void)lseek( Flswap, pos, 0 ) ;
	if ( errno )
	{
		fprintf( stderr, "sps - Seek failed" ) ;
		sysperror() ;
	}
}

# ifdef lint
int                             errno ;
int                             sys_nerr ;
char                            *sys_errlist[] ;
# endif

/* SYSPERROR - Reports a system defined error msg and then exits gracefully */
sysperror ()
{
	extern int              errno ;
	extern int              sys_nerr ;
	extern char             *sys_errlist[] ;

	if ( 0 < errno && errno < sys_nerr )
		fprintf( stderr, " : %s", sys_errlist[errno] ) ;
	(void)fputc( '\n', stderr ) ;
	exit( 1 ) ;
}

/* STRSAVE - Store a string in core for later use. */
char    *strsave ( cp )

register char                   *cp ;

{
	register char           *chp ;
	char                    *getcore(), *strcpy() ;

	chp = getcore( strlen( cp ) + 1 ) ;
	(void)strcpy( chp, cp ) ;
	return ( chp ) ;
}

/* GETCORE - Allocate and return a pointer to the asked for amount of core */
char    *getcore ( size )

register int                    size ;

{
	register char           *chp ;
	char                    *malloc() ;

	if ( chp = malloc( (unsigned)size ) )
		return ( chp ) ;
	fprintf( stderr, "sps - Out of core" ) ;
	sysperror() ;
	/* NOTREACHED */
}

union flaglist  *getflgsp ( argc )

register int                    argc ;

{
	char                    *getcore() ;

	return ( (union flaglist*)getcore( sizeof( union flaglist )*argc ) ) ;
}

/* PREXIT - Print an error message and exit */
/* VARARGS1 */
/* ARGSUSED */
prexit ( fmt, args )

char                            *fmt ;

{
	_doprnt( fmt, &args, stderr ) ;
	exit( 1 ) ;
}
SHAR_EOF
if test 2626 -ne "`wc -c < 'openfiles.c'`"
then
	echo shar: error transmitting "'openfiles.c'" '(should have been 2626 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'percentmem.c'" '(823 characters)'
if test -f 'percentmem.c'
then
	echo shar: will not over-write existing file "'percentmem.c'"
else
sed 's/^X//' << \SHAR_EOF > 'percentmem.c'
# include       "sps.h"
# include       <h/text.h>
# ifdef BSD42
# include	<machine/pte.h>
# else
# include       <h/pte.h>
# include       <h/vmparam.h>
# endif
# include       <h/vmmac.h>

/* PERCENTMEM - Returns the percentage of real memory used by this process */
double  percentmem ( p )

register struct process         *p ;

{
	register struct text    *tp ;
	int                     szptudot ;
	double                  fracmem ;
	extern struct info      Info ;

	tp = p->pr_p.p_textp ;
	if ( !(p->pr_p.p_flag & SLOAD) || !tp )
		return ( 0.0 ) ;
	szptudot = UPAGES + clrnd( ctopt( p->pr_p.p_dsize + p->pr_p.p_ssize ) );
	fracmem = ( (double)p->pr_p.p_rssize + szptudot ) / CLSIZE ;
	if ( tp->x_ccount )
		fracmem += ((double)tp->x_rssize)/CLSIZE/tp->x_ccount ;
	return ( 100.0 * fracmem / (double)Info.i_ecmx ) ;
}
SHAR_EOF
if test 823 -ne "`wc -c < 'percentmem.c'`"
then
	echo shar: error transmitting "'percentmem.c'" '(should have been 823 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'prcmd.c'" '(709 characters)'
if test -f 'prcmd.c'
then
	echo shar: will not over-write existing file "'prcmd.c'"
else
sed 's/^X//' << \SHAR_EOF > 'prcmd.c'
# include       "sps.h"
# include       "flags.h"

/* PRCMD - Prints the command arguments according to the switches */
prcmd ( p, lpad, width )

register struct process         *p ;
int                             lpad ;
int                             width ;

{
	extern struct flags     Flg ;
	extern unsigned         Termwidth ;

	printf( "%*d ", lpad, p->pr_p.p_pid ) ;
	if ( Flg.flg_f )
	{
		printf( "%5d ", p->pr_p.p_ppid ) ;
		width -= 6 ;
	}
	if ( Flg.flg_g )
	{
		printf( "%5d ", p->pr_p.p_pgrp ) ;
		width -= 6 ;
	}
	width += Termwidth ;
	if ( Flg.flg_w )
		printf( "%s\n", p->pr_cmd ) ;
	else if ( width > 0 )
		printf( "%-.*s\n", width, p->pr_cmd ) ;
	if ( p->pr_csaved )
		free( p->pr_cmd ) ;
}
SHAR_EOF
if test 709 -ne "`wc -c < 'prcmd.c'`"
then
	echo shar: error transmitting "'prcmd.c'" '(should have been 709 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'prcpu.c'" '(1538 characters)'
if test -f 'prcpu.c'
then
	echo shar: will not over-write existing file "'prcpu.c'"
else
sed 's/^X//' << \SHAR_EOF > 'prcpu.c'
# include       "sps.h"

# ifdef BSD42

/* PRCPU - Print cpu time */
prcpu ( time, utime )

register time_t                 time ;
time_t                          utime ;

{
	time += utime / 1000000 ;
	utime %= 1000000 ;
	if ( time < 0L )
	{       /* Ignore negative times */
		printf( "     " ) ;     
		return ;
	}
	if ( time < 60L*10L )
	{       /* Print as seconds if less than 1000 seconds */
		printf( "%3d.%1d", (int)time, (int)utime/100000 ) ;
		return ;
	}
	/* Print as minutes if less than 10 hours ; print as hours if less than
	   10 days, else print as days. */
	if ( time < 60L*60L*10L )               
		printf( "%3D M", time/60L ) ;
	else if ( time < 24L*60L*60L*10L )
		printf( "%3D H", time/60L/60L ) ;
	else
		printf( "%3D D", time/60L/60L/24L ) ;
}

# else

/* PRCPU - Print cpu time */
prcpu ( time )

register time_t                 time ;

{
	extern struct info      Info ;

	if ( time < 0L )
	{       /* Ignore negative times */
		printf( "     " ) ;     
		return ;
	}
	if ( time < Info.i_hz*60L*10L )
	{       /* Less than 10 minutes */
		printf( "%3D.%1D", time/Info.i_hz,
			(time % Info.i_hz / (Info.i_hz/10L)) ) ;
		return ;
	}
	/* If less than 10 hours, print as minutes */
	time /= Info.i_hz ;
	/* Print as minutes if less than 10 hours ; print as hours if less than
	   10 days, else print as days. */
	if ( time < 60L*60L*10L )               
		printf( "%3D M", time/60L ) ;
	else if ( time < 24L*60L*60L*10L )
		printf( "%3D H", time/60L/60L ) ;
	else
		printf( "%3D D", time/60L/60L/24L ) ;
}

# endif
SHAR_EOF
if test 1538 -ne "`wc -c < 'prcpu.c'`"
then
	echo shar: error transmitting "'prcpu.c'" '(should have been 1538 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'prheader.c'" '(438 characters)'
if test -f 'prheader.c'
then
	echo shar: will not over-write existing file "'prheader.c'"
else
sed 's/^X//' << \SHAR_EOF > 'prheader.c'
# include       "sps.h"
# include       "flags.h"

/* PRHEADER - Print a header according to the switches */
prheader ()
{
	extern struct flags     Flg ;

	printf( "Ty User    %s Proc#", Flg.flg_v ?
		" Status Fl Nice Virtual Resident %M  Time Child %C" :
		Flg.flg_d ?
		"  Files    PageFaults Swap BlockI/O Kbytsecs" : "" ) ;
	if ( Flg.flg_f )
		printf( " Ppid#" ) ;
	if ( Flg.flg_g )
		printf( " Pgrp#" ) ;
	printf( " Command\n" ) ;
}
SHAR_EOF
if test 438 -ne "`wc -c < 'prheader.c'`"
then
	echo shar: error transmitting "'prheader.c'" '(should have been 438 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'printall.c'" '(430 characters)'
if test -f 'printall.c'
then
	echo shar: will not over-write existing file "'printall.c'"
else
sed 's/^X//' << \SHAR_EOF > 'printall.c'
# include       <stdio.h>
# include       "sps.h"

/* PRINTALL - Recursively print the process tree. */
printall ( p, md )

register struct process         *p ;
register int                    md ;

{
	while ( p )
	{       /* Print this process */
		printproc( p, md ) ;    
		(void)fflush( stdout ) ;
		/* Print child processes */
		printall( p->pr_child, md+1 ) ;
		/* Print brother processes */
		p = p->pr_sibling ;     
	}
}
SHAR_EOF
if test 430 -ne "`wc -c < 'printall.c'`"
then
	echo shar: error transmitting "'printall.c'" '(should have been 430 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'printproc.c'" '(5844 characters)'
if test -f 'printproc.c'
then
	echo shar: will not over-write existing file "'printproc.c'"
else
sed 's/^X//' << \SHAR_EOF > 'printproc.c'
# include       "sps.h"
# include       "flags.h"
# include       <h/text.h>

/* PRINTPROC - Pretty print a process according to the switches. */
printproc ( p, md )

register struct process         *p ;            
int                             md ;            

{
	register char           *chp ;
	register struct text    *tp ;
	register struct hashtab *hp ;
	char                    chbuf[10] ;
	time_t                  time ;
	time_t                  chtime ;
# ifdef BSD42
	time_t                  utime ;
	time_t                  uchtime ;
# endif
	extern short            Lastuid, Lastpgrp ;
	extern struct flags     Flg ;
	char                    *waitingfor() ;
	struct hashtab          *hashuid() ;
	double                  percentmem() ;

	/* List tty name and foreground/background/detached information */
	printf( "%2.2s%c", p->pr_tty->l_name,
		!p->pr_p.p_pgrp ? ' ' :
# ifdef SDETACH
		p->pr_p.p_flag & SDETACH ? '_' :
# endif
		p->pr_p.p_pgrp == p->pr_tty->l_pgrp ? '.' : ' ' ) ;
	hp = hashuid( p->pr_p.p_uid ) ;
	if ( !md  )                             
	{       /* If a top-level process, list the user name */
		if ( hp )
			printf( "%-8.8s ", hp->h_uname ) ;
		else
			printf( "user%-4.4d ", p->pr_p.p_uid ) ;
	}
	else                                    
	{       /* Usually list an asterisk for a child process */
		md = md > 8 ? 8 : md ;
		printf( "%*s%c", md, "",
			p->pr_p.p_pgrp == Lastpgrp ? '|' : '*' ) ;      
		/* But beware of setuid processes */
		md = 8 - md ;
		if ( p->pr_p.p_uid == Lastuid )
			printf( "%-*.*s", md, md, "" ) ;
		else if ( hp )
			printf( "%-*.*s", md, md, hp->h_uname ) ;
		else
		{
			md -= 4 ;
			printf( "user%-*.*d", md, md, p->pr_p.p_uid ) ;
		}
	}
	Lastuid = p->pr_p.p_uid ;
	Lastpgrp = p->pr_p.p_pgrp ;
	if ( Flg.flg_d )                        
	{       /* List disc I/O and paging information */
		if ( !p->pr_upag || p->pr_p.p_stat == SZOMB )
		{
			prcmd( p, 49, -63 ) ;
			return ;
		}
		printf( "%2d %8d+%8d %4d %8d %8D ",
			p->pr_files,
# ifdef BSD42
			p->pr_rself.ru_majflt,
			p->pr_rself.ru_minflt,
			p->pr_rself.ru_nswap,
			p->pr_rself.ru_inblock + p->pr_rself.ru_oublock,
			KBYTES( p->pr_rself.ru_idrss + p->pr_rself.ru_isrss
				+ p->pr_rself.ru_ixrss ) ) ;
# else
			p->pr_vself.vm_majflt,
			p->pr_vself.vm_minflt,
			p->pr_vself.vm_nswap,
			p->pr_vself.vm_inblk + p->pr_vself.vm_oublk,
			KBYTES( (p->pr_vself.vm_idsrss
				+ p->pr_vself.vm_ixrss) / Info.i_hz ) ) ;
# endif
		prcmd( p, 5, -63 ) ;
		return ;
	}
	if ( !Flg.flg_v )                       
	{       /* Not verbose so just list command arguments */
		prcmd( p, 5, -19 ) ;
		return ;
	}
	/* Arrive here if being verbose ; list cpu information */
	switch ( p->pr_p.p_stat )               
	{                                       
		case SSLEEP :
		case SWAIT :
		case SIDL :
			/* Determine why a process should be in a wait state */
			chp = waitingfor( p ) ;
			break ;
		case SRUN :
			chp = "run" ;
			break ;
		case SZOMB :
			chp = "exit" ;
			break ;
		case SSTOP :
			chp = "stop" ;
			break ;
	}
	/* If the process is loaded, list the status information in capitals */
	printf( "%-6.6s ", p->pr_p.p_flag & SLOAD ?
		(capitals( chp, chbuf ), chbuf) : chp ) ;
	/* List process flags */
	printf( "%c%c%c", p->pr_p.p_flag & SSYS ? 'U' :
		p->pr_p.p_flag & STRC ? 'T' : ' ',
		p->pr_p.p_flag & SVFORK ? 'V' :
		p->pr_p.p_flag & SPHYSIO ? 'I' : ' ',
		p->pr_p.p_flag & SUANOM ? 'A' : ' ' ) ;
	/* List process niceness */
	if ( p->pr_p.p_nice != NZERO )          
		printf( "%3d ", p->pr_p.p_nice - NZERO ) ;
	else
		printf( "    " ) ;
	if ( p->pr_p.p_stat == SZOMB )
	{
		prcmd( p, 41, -69 ) ;
		return ;
	}                                       
	/* List process and text virtual sizes */
	printf( "%4d", KBYTES( p->pr_p.p_dsize + p->pr_p.p_ssize ) ) ;
	if ( tp = p->pr_p.p_textp )
		printf( "+%3d ", KBYTES( tp->x_size ) ) ;
	else
		printf( "     " ) ;
	/* List process and text real sizes */
	printf( "%4d", KBYTES( p->pr_p.p_rssize ) ) ;
	if ( tp )
		printf( "+%3d %2.0f ", KBYTES( tp->x_rssize ),
			percentmem( p ) );
	else
		printf( "        " ) ;
	/* List information obtained from the upage. This includes the process
	   times and command arguments. */
	if ( !p->pr_upag )
	{
		prcmd( p, 20, -69 ) ;
		return ;
	}                                       
	/* List process time information */
# ifdef BSD42
	time   = Flg.flg_q ? p->pr_rself.ru_utime.tv_sec :
		 p->pr_rself.ru_utime.tv_sec + p->pr_rself.ru_stime.tv_sec ;
	utime  = Flg.flg_q ? p->pr_rself.ru_utime.tv_usec :
		 p->pr_rself.ru_utime.tv_usec + p->pr_rself.ru_stime.tv_usec ;
	chtime = Flg.flg_q ? p->pr_rchild.ru_utime.tv_sec :
		 p->pr_rchild.ru_utime.tv_sec + p->pr_rchild.ru_stime.tv_sec ;
	uchtime = Flg.flg_q ? p->pr_rchild.ru_utime.tv_usec :
		 p->pr_rchild.ru_utime.tv_usec + p->pr_rchild.ru_stime.tv_usec ;
	prcpu( time, utime ) ;
	if ( chtime != 0L )
	{
		printf( "+" ) ;
		prcpu( chtime, uchtime ) ;
	}
# else
	time   = Flg.flg_q ? p->pr_vself.vm_utime :
		 p->pr_vself.vm_utime + p->pr_vself.vm_stime ;
	chtime = Flg.flg_q ? p->pr_vchild.vm_utime :
		 p->pr_vchild.vm_utime + p->pr_vchild.vm_stime ;
	prcpu( time ) ;
	if ( chtime != 0L )
	{
		printf( "+" ) ;
		prcpu( chtime ) ;
	}
# endif
	else
		printf( "      " ) ;
# ifdef BSD42
	if ( time || utime )
# else
	if ( time )
# endif
# ifdef SUN
		printf( " %2.0f ", (double)p->pr_p.p_pctcpu ) ;
# else
		printf( " %2.0f ", p->pr_p.p_pctcpu * 100.0 ) ;
# endif
	else
		printf( "    " ) ;
	/* Finally, list the process command arguments. */
	prcmd( p, 5, -69 ) ;                    
}

/* CAPITALS - Converts letters in `chp' to upper-case in buffer `buf'. */
capitals ( chp, buf )

register char                   *chp ;
register char                   *buf ;

{
	while ( *buf = *chp++ )
	{
		if ( 'a' <= *buf && *buf <= 'z' )
			*buf -= 'a' - 'A' ;
		buf++ ;
	}
}
SHAR_EOF
if test 5844 -ne "`wc -c < 'printproc.c'`"
then
	echo shar: error transmitting "'printproc.c'" '(should have been 5844 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'prsummary.c'" '(632 characters)'
if test -f 'prsummary.c'
then
	echo shar: will not over-write existing file "'prsummary.c'"
else
sed 's/^X//' << \SHAR_EOF > 'prsummary.c'
# include       "sps.h"

/* PRSUMMARY - Print the summarising information */
prsummary ()
{
	extern struct summary   Summary ;

	printf(
"%D (%Dk) processes, %D (%Dk) busy, %D (%Dk) loaded, %D (%Dk) swapped\n",
		Summary.sm_ntotal, KBYTES( Summary.sm_ktotal ),
		Summary.sm_nbusy, KBYTES( Summary.sm_kbusy ),
		Summary.sm_nloaded, KBYTES( Summary.sm_kloaded ),
		Summary.sm_nswapped, KBYTES( Summary.sm_kswapped ) ) ;
	Summary.sm_ntotal = 0L ;
	Summary.sm_ktotal = 0L ;
	Summary.sm_nbusy = 0L ;
	Summary.sm_kbusy = 0L ;
	Summary.sm_nloaded = 0L ;
	Summary.sm_kloaded = 0L ;
	Summary.sm_nswapped = 0L ;
	Summary.sm_kswapped = 0L ;
}
SHAR_EOF
if test 632 -ne "`wc -c < 'prsummary.c'`"
then
	echo shar: error transmitting "'prsummary.c'" '(should have been 632 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'readstatus.c'" '(1170 characters)'
if test -f 'readstatus.c'
then
	echo shar: will not over-write existing file "'readstatus.c'"
else
sed 's/^X//' << \SHAR_EOF > 'readstatus.c'
# include       "sps.h"
# include       <h/text.h>

/* READSTATUS - Reads the kernel memory for current processes and texts */
readstatus ( process, text )

register struct process         *process ;
struct text                     *text ;

{
	register struct proc    *p ;
	register struct proc    *p0 ;
	register struct process *pr ;
	extern struct info      Info ;
	extern int              Flkmem ;
	char                    *getcore() ;

	/* Read current text information */
	memseek( Flkmem, (long)Info.i_text0 ) ;
	if ( read( Flkmem, (char*)text, Info.i_ntext * sizeof( struct text ) )
	!= Info.i_ntext * sizeof( struct text ) )
		prexit( "sps - Can't read system text table\n" ) ;
	/* Read current process information */
	p0 = (struct proc*)getcore( sizeof( struct proc )*Info.i_nproc ) ;
	memseek( Flkmem, (long)Info.i_proc0 ) ;
	if ( read( Flkmem, (char*)p0, Info.i_nproc * sizeof( struct proc ) )
	!= Info.i_nproc * sizeof( struct proc ) )
		prexit( "sps - Can't read system process table\n" ) ;
	/* Copy process information into our own array */
	for ( p = p0, pr = process ; pr < &process[ Info.i_nproc ] ; p++, pr++ )
		pr->pr_p = *p ;
	free( (char*)p0 ) ;
}
SHAR_EOF
if test 1170 -ne "`wc -c < 'readstatus.c'`"
then
	echo shar: error transmitting "'readstatus.c'" '(should have been 1170 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'selectproc.c'" '(1587 characters)'
if test -f 'selectproc.c'
then
	echo shar: will not over-write existing file "'selectproc.c'"
else
sed 's/^X//' << \SHAR_EOF > 'selectproc.c'
# include       "sps.h"
# include       "flags.h"

/*
** SELECTPROC - Given a process structure, this procedure decides whether
** the process is a candidate for printing.
*/
selectproc ( p, process, thisuid )

register struct process         *p ;            
register struct process         *process ;      
int                             thisuid ;       

{
	register union flaglist *fp ;
	register struct process *pp ;
	extern struct flags     Flg ;

	/* Flg.flg_AZ is an internal flag set if one of flags `A' to `Z'
	   was specified. If this is not set, a process is listed only
	   if it or one of its ancestors belongs to the invoking user. */
	if ( !Flg.flg_AZ )
		for ( pp = p ; pp > &process[1] ; pp = pp->pr_pptr )
			if ( thisuid == pp->pr_p.p_uid )
				return ( 1 ) ;
	if ( Flg.flg_A )
		return ( 1 ) ;
	if ( Flg.flg_P )
		for ( fp = Flg.flg_Plist ; fp->f_pid >= 0 ; fp++ )
			if ( fp->f_pid == p->pr_p.p_pid )
				return ( 1 ) ;
	if ( Flg.flg_U )
		for ( pp = p ; pp > &process[1] ; pp = pp->pr_pptr )
			for ( fp = Flg.flg_Ulist ; fp->f_uid >= 0 ; fp++ )
				if ( fp->f_uid == pp->pr_p.p_uid )
					return ( 1 ) ;
	switch ( p->pr_p.p_stat )
	{
		case SRUN :
			if ( Flg.flg_B )
				return ( 1 ) ;
			break ;
		case SSLEEP :
			if ( Flg.flg_B
			&&   p->pr_p.p_pri < PZERO && p->pr_p.p_pid > MSPID )
				return ( 1 ) ;
		case SWAIT :
		case SIDL :
			if ( Flg.flg_W )
				return ( 1 ) ;
			break ;
		case SSTOP :
			if ( Flg.flg_S )
				return ( 1 ) ;
			break ;
		case SZOMB :
			if ( Flg.flg_Z )
				return ( 1 ) ;
			break ;
		default :
			break ;
	}
	return ( 0 ) ;
}
SHAR_EOF
if test 1587 -ne "`wc -c < 'selectproc.c'`"
then
	echo shar: error transmitting "'selectproc.c'" '(should have been 1587 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'selecttty.c'" '(368 characters)'
if test -f 'selecttty.c'
then
	echo shar: will not over-write existing file "'selecttty.c'"
else
sed 's/^X//' << \SHAR_EOF > 'selecttty.c'
# include       "sps.h"
# include       "flags.h"

/* SELECTTTY - Decides whether this process is interesting for its tty */
selecttty ( p )

register struct process         *p ;

{
	register union flaglist *fp ;
	extern struct flags     Flg ;

	for ( fp = Flg.flg_Tlist ; fp->f_ttyline ; fp++ )
		if ( fp->f_ttyline == p->pr_tty )
			return ( 1 ) ;
	return ( 0 ) ;
}
SHAR_EOF
if test 368 -ne "`wc -c < 'selecttty.c'`"
then
	echo shar: error transmitting "'selecttty.c'" '(should have been 368 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'sps.h'" '(6468 characters)'
if test -f 'sps.h'
then
	echo shar: will not over-write existing file "'sps.h'"
else
sed 's/^X//' << \SHAR_EOF > 'sps.h'
# include       <h/param.h>
# include       <h/dir.h>
# include       <h/user.h>
# include       <h/proc.h>

/*
** Maximum # of users to be considered. (Should probably be
** approximately double the # of users in /etc/passwd.)
*/
# define        MAXUSERID       100
/* Maximum # ttys to be considered ... */
# define        MAXTTYS         60
/* Maximum user name length ... */
# define        UNAMELEN        8
/* Maximum process-id not to be considered busy ... */
# define        MSPID           2
/* # of wait states defined in the `struct info' ... */
# define        NWAITSTATE      36

/* Convert clicks to kbytes ... */
# ifdef SUN
# define        KBYTES( size )  ((size) << 1)
# else
# define        KBYTES( size )  ((size) >> (10 - PGSHIFT))
# endif

/* Standard files to be examined ... */
# define        FILE_MEM        "/dev/mem"      /* System physical memory */
# define        FILE_KMEM       "/dev/kmem"     /* Kernel virtual memory */
# define        FILE_SWAP       "/dev/drum"     /* Swap/paging device */
# define        FILE_DEV        "/dev"          /* Directory of tty entries */
# define        FILE_SYMBOL     "/vmunix"       /* Symbol file for nlist() */
# define        FILE_INFO       "/etc/spsinfo"  /* Sps information file */

/* Structure to hold necessary information concerning a tty ... */
struct ttyline
{
	struct tty              *l_addr ;       /* Ptr to tty struct in kmem */
	unsigned short          l_pgrp ;        /* Tty process group */
	char                    l_name[2] ;     /* Tty character name */
	dev_t                   l_dev ;         /* Tty device # */
} ;

/* Structure holding a single hash table entry ... */
struct hashtab
{
	unsigned short          h_uid ;         /* Uid of user entry */
	char                    h_uname[ UNAMELEN ] ; /* Corresponding name */
} ;

/*
** Format of the standard information file maintained by sps.
** This structure is filled in at initialisation time and then is read back
** in whenever sps is invoked.
** Note that the pointer variables in this structure refer to
** kernel virtual addresses, not addresses within sps.
** These variable are typed as such so that pointer arithmetic
** on the kernel addresses will work correctly.
*/
struct info
{       /* Kernel values determining process, tty and upage info ... */
	struct proc             *i_proc0 ;      /* address of process table */
	int                     i_nproc ;       /* length of process table */
	struct text             *i_text0 ;      /* address of text table */
	int                     i_ntext ;       /* length of text table */
	struct inode            *i_inode0 ;     /* address of inode table */
	int                     i_ninode ;      /* length of inode table */
	struct buf              *i_swbuf0 ;     /* address of swap buffers */
	int                     i_nswbuf ;      /* # swap buffers */
	struct buf              *i_buf0 ;       /* address of i/o buffers */
	int                     i_nbuf ;        /* # i/o buffers */
	int                     i_ecmx ;        /* max physical memory address*/
	struct pte              *i_usrptmap ;   /* page table map */
	struct pte              *i_usrpt ;      /* page table map */
	struct cdevsw           *i_cdevsw ;     /* device switch to find ttys */
# ifdef BSD42
	struct quota            *i_quota0 ;     /* disc quota structures */
	int                     i_nquota ;      /* # quota structures */
	int                     i_dmmin ;       /* The start of the disc map */
	int                     i_dmmax ;       /* The end of the disc map */
	struct mbuf             *i_mbutl ;      /* Start of mbuf area */
# else
	int                     i_hz ;          /* Clock rate */
# endif
# ifdef CHAOS
	caddr_t                 i_Chconntab ;   /* Chaos connection table */
# endif
	/* Kernel addresses are associated with process wait states ... */
	caddr_t                 i_waitstate[ NWAITSTATE ] ;
	/* User names, stored in a hash table ... */
	struct hashtab          i_hnames[ MAXUSERID ] ;
	/* Tty device info ... */
	struct ttyline          i_ttyline[ MAXTTYS ] ;
} ;

/*
** The symbol structure cross-references values read from the kernel with
** their place in the info structure, and if such a value is associated with
** a process wait state or not.
*/
struct symbol
{
	char                    *s_kname ;      /* Kernel symbol name */
	char                    s_indirect ;    /* Value requires indirection */
	caddr_t                 *s_info ;       /* Corresponding info address */
	char                    *s_wait ;       /* Reason for wait, if any */
} ;

/* The `user' structure obtained from /dev/mem or /dev/swap ... */
union userstate
{
	struct user             u_us ;
	char                    u_pg[ UPAGES ][ NBPG ] ;
} ;

/* Information concerning each process filled from /dev/kmem ... */
struct process
{
	struct proc             pr_p ;          /* struct proc from /dev/kmem */
	struct process          *pr_plink ;     /* Normalised ptrs from above */
	struct process          *pr_sibling ;   /* Ptr to sibling process */
	struct process          *pr_child ;     /* Ptr to child process */
	struct process          *pr_pptr ;      /* Ptr to parent process */
# ifdef BSD42
	struct rusage           pr_rself ;      /* Read from upage for self */
	struct rusage           pr_rchild ;     /* ... and the children */
# else
	struct vtimes           pr_vself ;      /* Read from upage for self */
	struct vtimes           pr_vchild ;     /* ... and the children */
# endif
	int                     pr_files ;      /* # open files */
	struct ttyline          *pr_tty ;       /* Associated tty information */
	char                    *pr_cmd ;       /* Command args, from upage */
	int                     pr_upag:1 ;     /* Upage was obtained */
	int                     pr_csaved:1 ;   /* Cmd args saved by malloc() */
} ;

/* Structure to hold summarising information ... */
struct summary
{
	long                    sm_ntotal ;     /* Total # processes */
	long                    sm_ktotal ;     /* Total virtual memory */
	long                    sm_nbusy ;      /* # busy processes */
	long                    sm_kbusy ;      /* Busy virtual memory */
	long                    sm_nloaded ;    /* # loaded processes */
	long                    sm_kloaded ;    /* Active resident memory */
	long                    sm_nswapped ;   /* # swapped processes */
	long                    sm_kswapped ;   /* Size totally swapped out */
} ;
SHAR_EOF
if test 6468 -ne "`wc -c < 'sps.h'`"
then
	echo shar: error transmitting "'sps.h'" '(should have been 6468 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'termwidth.c'" '(490 characters)'
if test -f 'termwidth.c'
then
	echo shar: will not over-write existing file "'termwidth.c'"
else
sed 's/^X//' << \SHAR_EOF > 'termwidth.c'
/*
** TERMWIDTH - Sets the external variable `Termwidth' to the # of columns
** on the terminal.
*/
termwidth ()
{
	register char           *termtype ;
	register int            twidth ;
	char                    buf[ 1025 ] ;
	extern unsigned         Termwidth ;
	char                    *getenv() ;

	Termwidth = 80 ;
	if ( !(termtype = getenv( "TERM" )) )
		return ;
	if ( tgetent( buf, termtype ) != 1 )
		return ;
	twidth = tgetnum( "co" ) ;
	if ( twidth > 40 )
		Termwidth = twidth ;
}
SHAR_EOF
if test 490 -ne "`wc -c < 'termwidth.c'`"
then
	echo shar: error transmitting "'termwidth.c'" '(should have been 490 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'ttystatus.c'" '(2883 characters)'
if test -f 'ttystatus.c'
then
	echo shar: will not over-write existing file "'ttystatus.c'"
else
sed 's/^X//' << \SHAR_EOF > 'ttystatus.c'
# include       "sps.h"
# include       "flags.h"
# include       <stdio.h>
# include       <h/tty.h>
# ifdef CHAOS
# include       <chunix/chsys.h>
# include       <chaos/chaos.h>
# endif

/*
** TTYSTATUS - Reads the kernel memory for tty structures of active processes.
** The addresses of the associated struct ttys of /dev/kmem are kept in the
** info structure. Here we use those addresses to access the structures.
** Actually, we are mostly interested just in the process group of each tty.
*/
ttystatus ()
{
	register struct ttyline *lp ;
	struct tty              tty ;
	extern struct flags     Flg ;
	extern struct info      Info ;
	extern int              Flkmem ;

	if ( Flg.flg_y )
		printf( "Ty   Dev       Addr Rawq Canq Outq  Pgrp\n" ) ;
	lp = Info.i_ttyline ;
# ifdef CHAOS
	while ( lp->l_name[0] && lp->l_name[0] != 'C' )
# else
	while ( lp->l_name[0] )
# endif
	{
		memseek( Flkmem, (long)lp->l_addr ) ;
		if ( read( Flkmem, (char*)&tty, sizeof( struct tty ) )
		!= sizeof( struct tty ) )
		{
			fprintf( stderr,
				"sps - Can't read struct tty for tty%.2s\n",
				lp->l_name ) ;
			lp->l_pgrp = 0 ;
			lp++ ;
			continue ;
		}
		lp->l_pgrp = tty.t_pgrp ;
		prtty( lp, &tty ) ;
		lp++ ;
	}
# ifdef CHAOS
	chaosttys( lp ) ;               
# endif
}

/* PRTTY - Print out the tty structure */
prtty ( lp, tty )

register struct ttyline         *lp ;
register struct tty             *tty ;

{
	extern struct flags     Flg ;

	if ( !Flg.flg_y )
		return ;
	printf( "%-2.2s %2d,%2d 0x%08x %4d %4d %4d %5d\n",
		lp->l_name,
		major( lp->l_dev ),
		minor( lp->l_dev ),
		lp->l_addr,
		tty->t_rawq.c_cc,
		tty->t_canq.c_cc,
		tty->t_outq.c_cc,
		tty->t_pgrp ) ;
}

# ifdef CHAOS

/* CHAOSTTYS - Finds ttys attached to the Chaos net */
chaosttys ( lp )

register struct ttyline         *lp ;

{
	register struct connection      **cnp ;
	register int                    i ;
	struct tty                      tty ;
	struct connection               *conntab[CHNCONNS] ;
	struct connection               conn ;
	extern struct info              Info ;
	extern int                      Flkmem ;

	memseek( Flkmem, (long)Info.i_Chconntab ) ;
	(void)read( Flkmem, (char*)conntab, sizeof( conntab ) ) ;
	for ( i = 0, cnp = conntab ; cnp < &conntab[CHNCONNS] ; i++, cnp++ )
	{
		if ( !*cnp )
			continue ;
		memseek( Flkmem, (long)*cnp ) ;
		(void)read( Flkmem, (char*)&conn, sizeof( struct connection ) );
		if ( !(conn.cn_flags & CHTTY) )
			continue ;
		memseek( Flkmem, (long)conn.cn_ttyp ) ;
		(void)read( Flkmem, (char*)&tty, sizeof( struct tty ) ) ;
		if ( lp >= &Info.i_ttyline[MAXTTYS] )
			prexit( "sps - Too many chaos ttys\n" ) ;
		lp->l_addr = conn.cn_ttyp ;
		lp->l_pgrp = tty.t_pgrp ;
		lp->l_dev = tty.t_dev ;
		lp->l_name[0] = 'C' ;
		lp->l_name[1] = i < 10 ? '0'+i : i-10 <= 'z'-'a' ? i-10+'a' :
				i-10-('z'-'a')+'A' ;
		prtty( lp, &tty ) ;
		lp++ ;
	}
}

# endif
SHAR_EOF
if test 2883 -ne "`wc -c < 'ttystatus.c'`"
then
	echo shar: error transmitting "'ttystatus.c'" '(should have been 2883 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'waitingfor.c'" '(5822 characters)'
if test -f 'waitingfor.c'
then
	echo shar: will not over-write existing file "'waitingfor.c'"
else
sed 's/^X//' << \SHAR_EOF > 'waitingfor.c'
# include       "sps.h"
# include       <h/tty.h>
# include       <h/text.h>
# ifdef SUN
# include       <h/vnode.h>
# include       <ufs/inode.h>
# else
# include       <h/inode.h>
# endif
# include       <h/buf.h>
# ifdef BSD42
# include       <h/quota.h>
# include       <h/mbuf.h>
# include       <h/socket.h>
# include       <h/socketvar.h>
# endif

/* 1 if `w' is in the address range defined by `a1' and `a2' ... */
# define        INRANGE( w, a1, a2 ) \
			( (caddr_t)(a1) <= (w) && (w) < (caddr_t)(a2) )

/* WAITINGFOR - Determine what a process is waiting for and describe it. */
char    *waitingfor ( p )

struct process                  *p ;

{
	register caddr_t        w ;
	register struct ttyline *lp ;
	register struct symbol  *s ;
	register char           *cp ;
# ifdef BSD42
	struct socket           sc ;
# endif
	static char             wbuf[ 8 ] ;
	extern struct info      Info ;
	extern struct symbol    Symbollist[] ;
	char                    *sprintf() ;

	w = p->pr_p.p_wchan ;
	if ( !w )
		return ( "null" ) ;
	/* Waiting for a child process, alternatively in a vfork() ? */
	if ( INRANGE( w, Info.i_proc0, &Info.i_proc0[ Info.i_nproc ] ) )
		return ( p->pr_p.p_flag & SNOVM ? "vfork" : "child" ) ;
	/* Waiting for a page to be brought in ? */
	if ( INRANGE( w, Info.i_swbuf0, &Info.i_swbuf0[ Info.i_nswbuf ] ) )
		return ( "swap" ) ;
	/* Waiting for discio through a block device to complete ? */
	if ( INRANGE( w, Info.i_buf0, &Info.i_buf0[ Info.i_nbuf ] ) )
		/* SHOULD ACTUALLY READ AS "blkio" BUT "discio" IS WHAT
		   IS GENERALLY MEANT HERE. */
		return ( "discio" ) ;
	/* Waiting for a text page to be brought in ? */
	if ( INRANGE( w, Info.i_text0, &Info.i_text0[ Info.i_ntext ] ) )
		return ( "swtext" ) ;
# ifdef BSD42
	/* Waiting for an event associated with the quota system ? */
	if ( INRANGE( w, Info.i_quota0, &Info.i_quota0[ Info.i_nquota ] ) )
		return ( "quota" ) ;
# endif
	/* Waiting for tty I/O ? If so, find which tty it is */
	for ( lp = Info.i_ttyline ; lp->l_name[0] ; lp++ )
		if ( INRANGE( w, &lp->l_addr[0], &lp->l_addr[1] ) )
		{
			switch ( w - (int)lp->l_addr )
			{
				case (int)&((struct tty*)0)->t_rawq :
					/* Read from a tty or slave pty */
					cp = "rtty??" ;
					break ;
				case (int)&((struct tty*)0)->t_outq :
					/* Write to a tty or slave pty */
					cp = "wtty??" ;
					break ;
				case (int)&((struct tty*)0)->t_state :
					/* Tty not open */
					cp = "otty??" ;
					break ;
				case (int)&((struct tty*)0)->t_outq.c_cf :
					/* Read from a controller pty */
					cp = "rpty??" ;
					break ;
				case (int)&((struct tty*)0)->t_rawq.c_cf :
					/* Write to a controller pty */
					cp = "wpty??" ;
					break ;
				default :
					cp = "?tty??" ;
					break ;
			}
			cp[4] = lp->l_name[0] ;
			cp[5] = lp->l_name[1] ;
			return ( cp ) ;
		}
	/* Waiting for an inode ? */
	if ( INRANGE( w, Info.i_inode0, &Info.i_inode0[ Info.i_ninode ] ) )
		switch ( ((int)w - (int)Info.i_inode0) % sizeof( struct inode ))
		{
# ifdef BSD42
# ifndef SUN
			case (int)&((struct inode*)0)->i_exlockc :
				/* Exclusive lock on this inode */
				return ( "exlock" ) ;
			case (int)&((struct inode*)0)->i_shlockc :
				/* Shared lock on this inode */
				return ( "shlock" ) ;
# endif
# else
			case 1 :
				return ( "wpipe" ) ;
			case 2 :
				return ( "rpipe" ) ;
			case (int)&((struct inode*)0)->i_un.i_group.g_datq :
				return ( "rmux" ) ;
# endif
			default :
				/* Inode probably locked */
				return ( "inode" ) ;
		}
# ifdef BSD42
	/* Waiting for a structure inside an mbuf ? If so, try to find why */
	if ( INRANGE( w, Info.i_mbutl,
	&Info.i_mbutl[ NMBCLUSTERS * CLBYTES / sizeof( struct mbuf ) ] ) )
		switch ( ((int)w - (int)Info.i_mbutl) % sizeof( struct mbuf )
			- (int)&((struct mbuf*)0)->m_dat[0] )
		{
			case (int)&((struct socket*)0)->so_timeo :
				/* Socket timeout event */
				return ( "socket" ) ;
			case (int)&((struct socket*)0)->so_rcv.sb_cc :
				/* Read from an empty socket. Here we actually
				   attempt to determine whether the socket
				   structure in question really does refer to
				   a socket, or whether it is in fact a pipe
				   in disguise. */
				return ( getsocket( (struct socket*)(w
				    - (int)&((struct socket*)0)->so_rcv.sb_cc),
						&sc )
					&& sc.so_type == SOCK_STREAM
					&& !sc.so_rcv.sb_hiwat
					&& !sc.so_rcv.sb_mbmax
					&& (sc.so_state
					    & (SS_ISCONNECTED|SS_CANTRCVMORE))
					? "rpipe" : "rsockt" ) ;
			case (int)&((struct socket*)0)->so_snd.sb_cc :
				/* Write to a full socket. Again, we try
				   to determine whether or not this is a
				   real socket or a pipe. */
				return ( getsocket( (struct socket*)(w
				    - (int)&((struct socket*)0)->so_snd.sb_cc),
						&sc )
					&& sc.so_type == SOCK_STREAM
					&& sc.so_rcv.sb_hiwat == 2048
					&& sc.so_rcv.sb_mbmax == 4096
					&& (sc.so_state
					    & (SS_ISCONNECTED|SS_CANTSENDMORE))
					? "wpipe" : "wsockt" ) ;
			default :
				/* Other mbuf event */
				return ( "mbuf" ) ;
		}
# endif
	/* Look in the symbol table for known wait addresses. */
	for ( s = Symbollist ; s->s_kname ; s++ )
		if ( s->s_wait && w == *s->s_info )
			return ( s->s_wait ) ;  
	/* No reason for the wait state has been found.
	   Return the wait channel as a hexadecimal address. */
# ifdef SUN
	(void)sprintf( wbuf, "x%05x", w ) ;
# else
	(void)sprintf( wbuf, "x%05x", w - 0x80000000 ) ;
# endif
	return ( wbuf ) ;
}

# ifdef BSD42
/*
** GETSOCKET - Reads a `struct socket' from the kernel virtual memory address
** identified by `ks' into the buffer `s'.
*/
getsocket ( ks, s )

struct socket                   *ks ;
struct socket                   *s ;

{
	extern int              Flkmem ;

	memseek( Flkmem, (long)ks ) ;
	return ( read( Flkmem, (char*)s, sizeof( struct socket ) )
		== sizeof( struct socket ) ) ;
}
# endif
SHAR_EOF
if test 5822 -ne "`wc -c < 'waitingfor.c'`"
then
	echo shar: error transmitting "'waitingfor.c'" '(should have been 5822 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0