SPS (Show Process Status) Part 1 of 2

sources-request at panda.UUCP sources-request at panda.UUCP
Tue Dec 3 09:48:55 AEST 1985


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



More information about the Mod.sources mailing list