[alt.sources] SPS for SunOS4.1 and DEC 3100's - Shar 3 of 3

robert@olsen.UUCP (Robert Ward) (11/19/90)

#!/bin/sh
#
# This is a shar (shell archive) file.
# In order to extract the contents of this archive, remove everything
# above the "#!/bin/sh" line.  Then execute the remaining file with
# /bin/sh.  The following file(s) will be extracted:
#    percentmem.c
#    prcmd.c
#    prcpu.c
#    prheader.c
#    printall.c
#    printproc.c
#    prsummary.c
#    readstatus.c
#    selectproc.c
#    selecttty.c
#    sps.h
#    sps.l
#    stream.c
#    termwidth.c
#    ttystatus.c
#    vmstat.c
#    waitingfor.c
#
#
# This archive was generated on Mon Aug  6 17:54:08 MET DST 1990
#
#
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if [ -f 'percentmem.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "percentmem.c"
    exit 2
fi
echo x - percentmem.c
sed -e 's/^X//' > percentmem.c << '---END-OF-percentmem.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)percentmem.c	1.1\t10/1/88" ;
X# endif
X
X# include       "sps.h"
X# ifndef SUNOS40
X# include       <h/text.h>
X# endif
X# ifdef BSD42
X# include	<machine/pte.h>
X# else
X# include       <h/pte.h>
X# include       <h/vmparam.h>
X# endif
X# include       <h/vmmac.h>
X
X/* PERCENTMEM - Returns the percentage of real memory used by this process */
Xdouble  percentmem ( p )
X
Xregister struct process         *p ;
X
X{
X# ifndef SUNOS40
X	register struct text    *tp ;
X# endif
X	int                     szptudot ;
X	double                  fracmem ;
X	extern struct info      Info ;
X
X# ifdef SUNOS40
X	if ( !(p->pr_p.p_flag & SLOAD) )
X		return ( 0.0 ) ;
X	szptudot = UPAGES ;
X	fracmem = ( (double)p->pr_p.p_rssize + szptudot ) ;
X# else
X	tp = p->pr_p.p_textp ;
X	if ( !(p->pr_p.p_flag & SLOAD) || !tp )
X		return ( 0.0 ) ;
X	szptudot = UPAGES + clrnd( ctopt( p->pr_p.p_dsize + p->pr_p.p_ssize ) );
X	fracmem = ( (double)p->pr_p.p_rssize + szptudot ) / CLSIZE ;
X	if ( tp->x_ccount )
X		fracmem += ((double)tp->x_rssize)/CLSIZE/tp->x_ccount ;
X# endif
X	return ( 100.0 * fracmem / (double)Info.i_ecmx ) ;
X}
---END-OF-percentmem.c---
LEN=`wc -c < percentmem.c`
if [ $LEN !=  1112 ] ; then
    echo shar: File "percentmem.c" was $LEN, should have been 1112 bytes
fi
if [ -f 'prcmd.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "prcmd.c"
    exit 2
fi
echo x - prcmd.c
sed -e 's/^X//' > prcmd.c << '---END-OF-prcmd.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)prcmd.c	1.1\t10/1/88" ;
X# endif
X
X# include       "sps.h"
X# include       "flags.h"
X
X/* PRCMD - Prints the command arguments according to the switches */
Xprcmd ( p, lpad, width )
X
Xregister struct process         *p ;
Xint                             lpad ;
Xint                             width ;
X
X{
X	extern struct flags     Flg ;
X	extern unsigned         Termwidth ;
X
X	printf( "%*d ", lpad, p->pr_p.p_pid ) ;
X	if ( Flg.flg_f )
X	{
X		printf( "%5d ", p->pr_p.p_ppid ) ;
X		width -= 6 ;
X	}
X	if ( Flg.flg_g )
X	{
X		printf( "%5d ", p->pr_p.p_pgrp ) ;
X		width -= 6 ;
X	}
X	width += Termwidth ;
X	if ( Flg.flg_w )
X		printf( "%s\n", p->pr_cmd ) ;
X	else if ( width > 0 )
X		printf( "%-.*s\n", width, p->pr_cmd ) ;
X	if ( p->pr_csaved )
X		free( p->pr_cmd ) ;
X}
---END-OF-prcmd.c---
LEN=`wc -c < prcmd.c`
if [ $LEN !=  785 ] ; then
    echo shar: File "prcmd.c" was $LEN, should have been 785 bytes
fi
if [ -f 'prcpu.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "prcpu.c"
    exit 2
fi
echo x - prcpu.c
sed -e 's/^X//' > prcpu.c << '---END-OF-prcpu.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)prcpu.c	1.1\t10/1/88" ;
X# endif
X
X# include       "sps.h"
X
X# ifdef BSD42
X
X/* PRCPU - Print cpu time */
Xprcpu ( time, utime )
X
Xregister time_t                 time ;
Xtime_t                          utime ;
X
X{
X	time += utime / 1000000 ;
X	utime %= 1000000 ;
X	if ( time < 0L )
X	{       /* Ignore negative times */
X		printf( "     " ) ;     
X		return ;
X	}
X	if ( time < 60L*10L )
X	{       /* Print as seconds if less than 1000 seconds */
X		printf( "%3d.%1d", (int)time, (int)utime/100000 ) ;
X		return ;
X	}
X	/* Print as minutes if less than 10 hours ; print as hours if less than
X	   10 days, else print as days. */
X	if ( time < 60L*60L*10L )               
X		printf( "%3D M", time/60L ) ;
X	else if ( time < 24L*60L*60L*10L )
X		printf( "%3D H", time/60L/60L ) ;
X	else
X		printf( "%3D D", time/60L/60L/24L ) ;
X}
X
X# else
X
X/* PRCPU - Print cpu time */
Xprcpu ( time )
X
Xregister time_t                 time ;
X
X{
X	extern struct info      Info ;
X
X	if ( time < 0L )
X	{       /* Ignore negative times */
X		printf( "     " ) ;     
X		return ;
X	}
X	if ( time < Info.i_hz*60L*10L )
X	{       /* Less than 10 minutes */
X		printf( "%3D.%1D", time/Info.i_hz,
X			(time % Info.i_hz / (Info.i_hz/10L)) ) ;
X		return ;
X	}
X	/* If less than 10 hours, print as minutes */
X	time /= Info.i_hz ;
X	/* Print as minutes if less than 10 hours ; print as hours if less than
X	   10 days, else print as days. */
X	if ( time < 60L*60L*10L )               
X		printf( "%3D M", time/60L ) ;
X	else if ( time < 24L*60L*60L*10L )
X		printf( "%3D H", time/60L/60L ) ;
X	else
X		printf( "%3D D", time/60L/60L/24L ) ;
X}
X
X# endif
---END-OF-prcpu.c---
LEN=`wc -c < prcpu.c`
if [ $LEN !=  1614 ] ; then
    echo shar: File "prcpu.c" was $LEN, should have been 1614 bytes
fi
if [ -f 'prheader.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "prheader.c"
    exit 2
fi
echo x - prheader.c
sed -e 's/^X//' > prheader.c << '---END-OF-prheader.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)prheader.c	1.1\t10/1/88" ;
X# endif
X
X# include       "sps.h"
X# include       "flags.h"
X
X/* PRHEADER - Print a header according to the switches */
Xprheader ()
X{
X	extern struct flags     Flg ;
X
X	printf( "Ty User    %s Proc#", Flg.flg_v ?
X# ifdef SUNOS40
X# ifdef OLDSTATS
X		" Status Fl Nice Virt Res %M  Time Child %C" :
X# else
X		" Status Fl Nice Prv  Shr  Res %M  Time Child %C" :
X# endif
X# else
X		" Status Fl Nice Virtual Resident %M  Time Child %C" :
X# endif
X		Flg.flg_d ?
X		"  Files    PageFaults Swap BlockI/O Kbytsecs" : "" ) ;
X	if ( Flg.flg_f )
X		printf( " Ppid#" ) ;
X	if ( Flg.flg_g )
X		printf( " Pgrp#" ) ;
X	printf( " Command\n" ) ;
X}
---END-OF-prheader.c---
LEN=`wc -c < prheader.c`
if [ $LEN !=  683 ] ; then
    echo shar: File "prheader.c" was $LEN, should have been 683 bytes
fi
if [ -f 'printall.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "printall.c"
    exit 2
fi
echo x - printall.c
sed -e 's/^X//' > printall.c << '---END-OF-printall.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)printall.c	1.1\t10/1/88" ;
X# endif
X
X# include       <stdio.h>
X# include       "sps.h"
X
X/* PRINTALL - Recursively print the process tree. */
Xprintall ( p, md )
X
Xregister struct process         *p ;
Xregister int                    md ;
X
X{
X	while ( p )
X	{       /* Print this process */
X		printproc( p, md ) ;    
X		(void)fflush( stdout ) ;
X		/* Print child processes */
X		printall( p->pr_child, md+1 ) ;
X		/* Print brother processes */
X		p = p->pr_sibling ;     
X	}
X}
---END-OF-printall.c---
LEN=`wc -c < printall.c`
if [ $LEN !=  509 ] ; then
    echo shar: File "printall.c" was $LEN, should have been 509 bytes
fi
if [ -f 'printproc.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "printproc.c"
    exit 2
fi
echo x - printproc.c
sed -e 's/^X//' > printproc.c << '---END-OF-printproc.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)printproc.c	1.2\t8/2/90" ;
X# endif
X
X# include       "sps.h"
X# include       "flags.h"
X# ifndef SUNOS40
X# include       <h/text.h>
X# endif
X
X# ifdef SUNOS40
X#  ifdef OLDSTATS
X#   define OFFSET 8
X#  else
X#   define OFFSET 3
X#  endif
X# else
X#   define OFFSET 0
X# endif
X
X/* PRINTPROC - Pretty print a process according to the switches. */
Xprintproc ( p, md )
X
Xregister struct process         *p ;            
Xint                             md ;            
X
X{
X	register char           *chp ;
X# ifndef SUNOS40
X	register struct text    *tp ;
X# endif
X	register struct hashtab *hp ;
X	char                    chbuf[10] ;
X	time_t                  time ;
X	time_t                  chtime ;
X# ifdef BSD42
X	time_t                  utime ;
X	time_t                  uchtime ;
X# endif
X	extern short            Lastuid, Lastpgrp ;
X	extern struct flags     Flg ;
X	char                    *waitingfor() ;
X	struct hashtab          *hashuid() ;
X	double                  percentmem() ;
X
X	/* List tty name and foreground/background/detached information */
X	printf( "%2.2s%c", p->pr_tty->l_name,
X# ifdef SDETACH
X		!p->pr_p.p_pgrp ? ' ' : p->pr_p.p_flag & SDETACH ? '_' :
X		p->pr_p.p_pgrp == p->pr_tty->l_pgrp ? '.' : ' ' ) ;
X# else
X		!p->pr_p.p_pgrp || p->pr_p.p_pgrp != p->pr_tty->l_pgrp ?
X# ifdef SPGLDR
X		p->pr_p.p_flag & SPGLDR ? '-' :
X# endif
X	       ' ' :
X# ifdef SPGLDR
X		p->pr_p.p_flag & SPGLDR ? '+' :
X# endif
X	       '.' ) ;
X# endif
X	hp = hashuid( (int)p->pr_p.p_uid ) ;
X	if ( !md  )                             
X	{       /* If a top-level process, list the user name */
X		if ( hp )
X			printf( "%-8.8s ", hp->h_uname ) ;
X		else
X			printf( "user%-4.4d ", p->pr_p.p_uid ) ;
X	}
X	else                                    
X	{       /* Usually list an asterisk for a child process */
X		md = md > 8 ? 8 : md ;
X		printf( "%*s%c", md, "",
X			p->pr_p.p_pgrp == Lastpgrp ? '|' : '*' ) ;      
X		/* But beware of setuid processes */
X		md = 8 - md ;
X		if ( p->pr_p.p_uid == Lastuid )
X			printf( "%-*.*s", md, md, "" ) ;
X		else if ( hp )
X			printf( "%-*.*s", md, md, hp->h_uname ) ;
X		else
X		{
X			md -= 4 ;
X			printf( "user%-*.*d", md, md, p->pr_p.p_uid ) ;
X		}
X	}
X	Lastuid = p->pr_p.p_uid ;
X	Lastpgrp = p->pr_p.p_pgrp ;
X	if ( Flg.flg_d )                        
X	{       /* List disc I/O and paging information */
X		if ( !p->pr_upag || p->pr_p.p_stat == SZOMB )
X		{
X			prcmd( p, 49, -63 ) ;
X			return ;
X		}
X		printf( "%2d %8d+%8d %4d %8d %8D ",
X			p->pr_files,
X# ifdef BSD42
X			p->pr_rself.ru_majflt,
X			p->pr_rself.ru_minflt,
X			p->pr_rself.ru_nswap,
X			p->pr_rself.ru_inblock + p->pr_rself.ru_oublock,
X			KBYTES( p->pr_rself.ru_idrss + p->pr_rself.ru_isrss
X				+ p->pr_rself.ru_ixrss ) ) ;
X# else
X			p->pr_vself.vm_majflt,
X			p->pr_vself.vm_minflt,
X			p->pr_vself.vm_nswap,
X			p->pr_vself.vm_inblk + p->pr_vself.vm_oublk,
X			KBYTES( (p->pr_vself.vm_idsrss
X				+ p->pr_vself.vm_ixrss) / Info.i_hz ) ) ;
X# endif
X		prcmd( p, 5, -63 ) ;
X		return ;
X	}
X	if ( !Flg.flg_v )                       
X	{       /* Not verbose so just list command arguments */
X		prcmd( p, 5, -19 ) ;
X		return ;
X	}
X	/* Arrive here if being verbose ; list cpu information */
X	switch ( p->pr_p.p_stat )               
X	{                                       
X		case SSLEEP :
X		case SWAIT :
X		case SIDL :
X			/* Determine why a process should be in a wait state */
X			chp = waitingfor( p ) ;
X			break ;
X		case SRUN :
X			chp = "run" ;
X			break ;
X		case SZOMB :
X			chp = "exit" ;
X			break ;
X		case SSTOP :
X			chp = "stop" ;
X			break ;
X	}
X	/* If the process is loaded, list the status information in capitals */
X	printf( "%-6.6s ", p->pr_p.p_flag & SLOAD ?
X		(capitals( chp, chbuf ), chbuf) : chp ) ;
X	/* List process flags */
X	printf( "%c%c%c", p->pr_p.p_flag & SSYS ? 'U' :
X		p->pr_p.p_flag & STRC ? 'T' : ' ',
X		p->pr_p.p_flag & SVFORK ? 'V' :
X		p->pr_p.p_flag & SPHYSIO ? 'I' : ' ',
X		p->pr_p.p_flag & SUANOM ? 'A' :
X		p->pr_p.p_flag & SSEQL ? 'S' : ' ' ) ;
X	/* List process niceness */
X	if ( p->pr_p.p_nice != NZERO )          
X		printf( "%3d ", p->pr_p.p_nice - NZERO ) ;
X	else
X		printf( "    " ) ;
X	if ( p->pr_p.p_stat == SZOMB )
X	{
X		prcmd( p, 41 - OFFSET, OFFSET - 69 ) ;
X		return ;
X	}                                       
X# ifdef SUNOS40
X#  ifdef OLDSTATS
X	/* List process virtual and real sizes */
X	printf( "%4d", KBYTES( p->pr_p.p_dsize + p->pr_p.p_ssize ) ) ;
X#  else
X	/* List process private and shared virtual and real sizes */
X        printf("%4d", KBYTES( p->pr_private ) ) ;
X        printf("+%4d", KBYTES( p->pr_shared ) ) ;
X#  endif
X	printf( " %4d", KBYTES( p->pr_p.p_rssize ) ) ;
X# else
X	/* List process and text virtual sizes */
X	printf( "%4d", KBYTES( p->pr_p.p_dsize + p->pr_p.p_ssize ) ) ;
X	if ( tp = p->pr_p.p_textp )
X		printf( "+%3d ", KBYTES( tp->x_size ) ) ;
X	else
X		printf( "     " ) ;
X	/* List process and text real sizes */
X	printf( "%4d", KBYTES( p->pr_p.p_rssize ) ) ;
X	if ( tp )
X		printf( "+%3d", KBYTES( tp->x_rssize ) ) ;
X	else
X		printf( "    " ) ;
X# endif
X	printf( " %2.0f ", percentmem( p ) ) ;
X	/* List information obtained from the upage. This includes the process
X	   times and command arguments. */
X	if ( !p->pr_upag )
X	{
X		prcmd( p, 20, OFFSET - 69 ) ;
X		return ;
X	}                                       
X	/* List process time information */
X# ifdef BSD42
X	time   = Flg.flg_q ? p->pr_rself.ru_utime.tv_sec :
X		 p->pr_rself.ru_utime.tv_sec + p->pr_rself.ru_stime.tv_sec ;
X	utime  = Flg.flg_q ? p->pr_rself.ru_utime.tv_usec :
X		 p->pr_rself.ru_utime.tv_usec + p->pr_rself.ru_stime.tv_usec ;
X	chtime = Flg.flg_q ? p->pr_rchild.ru_utime.tv_sec :
X		 p->pr_rchild.ru_utime.tv_sec + p->pr_rchild.ru_stime.tv_sec ;
X	uchtime = Flg.flg_q ? p->pr_rchild.ru_utime.tv_usec :
X		 p->pr_rchild.ru_utime.tv_usec + p->pr_rchild.ru_stime.tv_usec ;
X	prcpu( time, utime ) ;
X	if ( chtime != 0L )
X	{
X		printf( "+" ) ;
X		prcpu( chtime, uchtime ) ;
X	}
X# else
X	time   = Flg.flg_q ? p->pr_vself.vm_utime :
X		 p->pr_vself.vm_utime + p->pr_vself.vm_stime ;
X	chtime = Flg.flg_q ? p->pr_vchild.vm_utime :
X		 p->pr_vchild.vm_utime + p->pr_vchild.vm_stime ;
X	prcpu( time ) ;
X	if ( chtime != 0L )
X	{
X		printf( "+" ) ;
X		prcpu( chtime ) ;
X	}
X# endif
X	else
X		printf( "      " ) ;
X# ifdef BSD42
X	if ( time || utime )
X# else
X	if ( time )
X# endif
X# ifdef SUN
X		printf( " %2.0f ", (double)p->pr_p.p_pctcpu * 100.0/FSCALE ) ;
X# else
X#  ifdef DEC3100
X		printf( " %2.0f ", p->pr_p.p_pctcpu ) ;
X#  else
X		printf( " %2.0f ", p->pr_p.p_pctcpu * 100.0 ) ;
X#  endif DEC3100
X# endif SUN
X	else
X		printf( "    " ) ;
X	/* Finally, list the process command arguments. */
X	prcmd( p, 5, OFFSET - 69 ) ;                    
X}
X
X/* CAPITALS - Converts letters in `chp' to upper-case in buffer `buf'. */
Xcapitals ( chp, buf )
X
Xregister char                   *chp ;
Xregister char                   *buf ;
X
X{
X	while ( *buf = *chp++ )
X	{
X		if ( 'a' <= *buf && *buf <= 'z' )
X			*buf -= 'a' - 'A' ;
X		buf++ ;
X	}
X}
---END-OF-printproc.c---
LEN=`wc -c < printproc.c`
if [ $LEN !=  6875 ] ; then
    echo shar: File "printproc.c" was $LEN, should have been 6875 bytes
fi
if [ -f 'prsummary.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "prsummary.c"
    exit 2
fi
echo x - prsummary.c
sed -e 's/^X//' > prsummary.c << '---END-OF-prsummary.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)prsummary.c	1.1\t10/1/88" ;
X# endif
X
X# include       "sps.h"
X
X/* PRSUMMARY - Print the summarising information */
Xprsummary ()
X{
X	extern struct summary   Summary ;
X
X	printf(
X"%D (%Dk) processes, %D (%Dk) busy, %D (%Dk) loaded, %D (%Dk) swapped\n",
X		Summary.sm_ntotal, KBYTES( Summary.sm_ktotal ),
X		Summary.sm_nbusy, KBYTES( Summary.sm_kbusy ),
X		Summary.sm_nloaded, KBYTES( Summary.sm_kloaded ),
X		Summary.sm_nswapped, KBYTES( Summary.sm_kswapped ) ) ;
X	Summary.sm_ntotal = 0L ;
X	Summary.sm_ktotal = 0L ;
X	Summary.sm_nbusy = 0L ;
X	Summary.sm_kbusy = 0L ;
X	Summary.sm_nloaded = 0L ;
X	Summary.sm_kloaded = 0L ;
X	Summary.sm_nswapped = 0L ;
X	Summary.sm_kswapped = 0L ;
X}
---END-OF-prsummary.c---
LEN=`wc -c < prsummary.c`
if [ $LEN !=  712 ] ; then
    echo shar: File "prsummary.c" was $LEN, should have been 712 bytes
fi
if [ -f 'readstatus.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "readstatus.c"
    exit 2
fi
echo x - readstatus.c
sed -e 's/^X//' > readstatus.c << '---END-OF-readstatus.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)readstatus.c	1.1\t10/1/88" ;
X# endif
X
X# include       "sps.h"
X# ifndef SUNOS40
X# include       <h/text.h>
X# endif
X
X/* READSTATUS - Reads the kernel memory for current processes and texts */
X# ifdef SUNOS40
Xreadstatus ( process )
X
Xregister struct process         *process ;
X
X# else
X
Xreadstatus ( process, text )
X
Xregister struct process         *process ;
Xstruct text                     *text ;
X
X# endif
X{
X	register struct proc    *p ;
X	register struct proc    *p0 ;
X	register struct process *pr ;
X	int                     size ;
X	extern struct info      Info ;
X	char                    *getcore() ;
X
X# ifndef SUNOS40
X	/* Read current text information */
X	size = Info.i_ntext * sizeof( struct text ) ;
X	if ( getkmem( (long)Info.i_text0, (char*)text, size ) != size )
X		prexit( "sps - Can't read system text table\n" ) ;
X# endif
X	/* Read current process information */
X	size = Info.i_nproc * sizeof( struct proc ) ;
X	p0 = (struct proc*)getcore( size ) ;
X	if ( getkmem( (long)Info.i_proc0, (char*)p0, size ) != size )
X		prexit( "sps - Can't read system process table\n" ) ;
X	/* Copy process information into our own array */
X	for ( p = p0, pr = process ; pr < &process[ Info.i_nproc ] ; p++, pr++ )
X		pr->pr_p = *p ;
X	free( (char*)p0 ) ;
X}
---END-OF-readstatus.c---
LEN=`wc -c < readstatus.c`
if [ $LEN !=  1281 ] ; then
    echo shar: File "readstatus.c" was $LEN, should have been 1281 bytes
fi
if [ -f 'selectproc.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "selectproc.c"
    exit 2
fi
echo x - selectproc.c
sed -e 's/^X//' > selectproc.c << '---END-OF-selectproc.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)selectproc.c	1.2\t6/15/90" ;
X# endif
X
X# include       "sps.h"
X# include       "flags.h"
X# ifdef USELOGINUID
X# include	<pwd.h>
X# endif USELOGINUID
X
X/*
X** SELECTPROC - Given a process structure, this procedure decides whether
X** the process is a candidate for printing.
X*/
Xselectproc ( p, process, thisuid )
X
Xregister struct process         *p ;            
Xregister struct process         *process ;      
Xint				thisuid ;
X
X{
X	register union flaglist *fp ;
X	register struct process *pp ;
X#ifdef USELOGINUID
X	char			*username ;
X	struct passwd		*pw ;
X	char			*getlogin() ;
X	struct passwd		*getpwnam() ;
X#endif USELOGINUID
X	extern struct flags     Flg ;
X
X	/* Flg.flg_AZ is an internal flag set if one of flags `A' to `Z'
X	   was specified. If this is not set, a process is listed only
X	   if it or one of its ancestors belongs to the invoking user. */
X	if ( !Flg.flg_AZ )
X	{
X#ifdef USELOGINUID
X		thisuid = (username = getlogin())
X			&& (pw = getpwnam( username )) ? pw->pw_uid : getuid() ;
X#endif USELOGINUID
X		for ( pp = p ; pp > &process[1] ; pp = pp->pr_pptr )
X			if ( thisuid == pp->pr_p.p_uid )
X				return ( 1 ) ;
X	}
X	if ( Flg.flg_A )
X		return ( 1 ) ;
X	if ( Flg.flg_P )
X		for ( fp = Flg.flg_Plist ; fp->f_pid >= 0 ; fp++ )
X			if ( fp->f_pid == p->pr_p.p_pid )
X				return ( 1 ) ;
X	if ( Flg.flg_U )
X		for ( pp = p ; pp > &process[1] ; pp = pp->pr_pptr )
X			for ( fp = Flg.flg_Ulist ; fp->f_uid >= 0 ; fp++ )
X				if ( fp->f_uid == pp->pr_p.p_uid )
X					return ( 1 ) ;
X	switch ( p->pr_p.p_stat )
X	{
X		case SRUN :
X			if ( Flg.flg_B )
X# ifdef SUNOS40
X				/* Ignore the idle processes */
X				return ( p->pr_p.p_pid != 3
X				    && p->pr_p.p_pid != 4 ) ;
X# else
X				return ( 1 ) ;
X# endif SUNOS40
X			break ;
X		case SSLEEP :
X			if ( Flg.flg_B
X			&&   p->pr_p.p_pri < PZERO && p->pr_p.p_pid > MSPID )
X# ifdef SUNOS40
X				/* Ignore the idle processes */
X				return ( p->pr_p.p_pid != 3
X				    && p->pr_p.p_pid != 4 ) ;
X# else
X				return ( 1 ) ;
X# endif SUNOS40
X		case SWAIT :
X		case SIDL :
X			if ( Flg.flg_W )
X				return ( 1 ) ;
X			break ;
X		case SSTOP :
X			if ( Flg.flg_S )
X				return ( 1 ) ;
X			break ;
X		case SZOMB :
X			if ( Flg.flg_Z )
X				return ( 1 ) ;
X			break ;
X		default :
X			break ;
X	}
X	return ( 0 ) ;
X}
---END-OF-selectproc.c---
LEN=`wc -c < selectproc.c`
if [ $LEN !=  2248 ] ; then
    echo shar: File "selectproc.c" was $LEN, should have been 2248 bytes
fi
if [ -f 'selecttty.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "selecttty.c"
    exit 2
fi
echo x - selecttty.c
sed -e 's/^X//' > selecttty.c << '---END-OF-selecttty.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)selecttty.c	1.1\t10/1/88" ;
X# endif
X
X# include       "sps.h"
X# include       "flags.h"
X
X/* SELECTTTY - Decides whether this process is interesting for its tty */
Xselecttty ( p )
X
Xregister struct process         *p ;
X
X{
X	register union flaglist *fp ;
X	extern struct flags     Flg ;
X
X	for ( fp = Flg.flg_Tlist ; fp->f_ttyline ; fp++ )
X		if ( fp->f_ttyline == p->pr_tty )
X			return ( 1 ) ;
X	return ( 0 ) ;
X}
---END-OF-selecttty.c---
LEN=`wc -c < selecttty.c`
if [ $LEN !=  448 ] ; then
    echo shar: File "selecttty.c" was $LEN, should have been 448 bytes
fi
if [ -f 'sps.h' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "sps.h"
    exit 2
fi
echo x - sps.h
sed -e 's/^X//' > sps.h << '---END-OF-sps.h---'
X# ifndef lint
Xstatic char SpsHId[] =  "@(#)sps.h	1.3\t7/4/90" ;
X# endif
X
X# ifdef SUNOS40
X#  define KERNEL
X# endif SUNOS40
X# include	<h/param.h>
X# undef KERNEL
X# include	<h/dir.h>
X# include	<h/user.h>
X# include	<h/proc.h>
X
X# ifdef SUNOS40
X#  ifndef BSD43
X#   define BSD43
X# endif BSD43
X# endif SUNOS40
X
X/*
X** Maximum # of users to be considered. (Because user names are stored
X** in a hash table, this should probably be at least double the number
X** of actual users defined in /etc/passwd or by the Yellow Pages.)
X*/
X# define	MAXUSERS	100
X/* Maximum # ttys to be considered, plus 1 for the console ... */
X# define	MAXTTYS		97
X
X
X/* Maximum user name length ... */
X# define	UNAMELEN	8
X/* Maximum process-id not to be considered busy ... */
X# define	MSPID		2
X/* # of wait states defined in the `struct info' ... */
X# ifdef NFS
X#  ifdef SUN
X#   define	NWAITSTATE	16
X#  else
X#   define	NWAITSTATE	36
X#  endif SUN
X# else NFS
X#  ifdef ULTRIX20
X#   define	NWAITSTATE	36
X#  else ULTRIX20
X#   define	NWAITSTATE	35
X#  endif ULTRIX20
X# endif NFS
X
X/* Convert clicks to kbytes ... */
X# ifndef PGSHIFT
X#  define	KBYTES( size )	((size) << 1)
X# else PGSHIFT
X#  if PGSHIFT > 10
X#   define        KBYTES( size )  ((size) << (PGSHIFT - 10))
X#  else
X#   define	KBYTES( size )	((size) >> (10 - PGSHIFT))
X#  endif
X# endif PGSHIFT
X
X/* Standard files to be examined ... */
X# define	FILE_MEM	"/dev/mem"	/* System physical memory */
X# define	FILE_KMEM	"/dev/kmem"	/* Kernel virtual memory */
X# define	FILE_SWAP	"/dev/drum"	/* Swap/paging device */
X# define	FILE_DEV	"/dev"		/* Directory of tty entries */
X# define	FILE_SYMBOL	"/vmunix"	/* Symbol file for nlist() */
X# define	FILE_INFO	"/tmp/.spsinfo"	/* Sps information file */
X# define	FILE_PASSWD	"/etc/passwd"	/* User database */
X
X/* Structure to hold necessary information concerning a tty ... */
Xstruct ttyline
X{
X	char			l_name[2] ;	/* Tty character name */
X	unsigned short		l_pgrp ;	/* Tty process group */
X# ifdef SUNOS40
X	struct streamtab	*l_addr ;	/* Ptr to streamtab in kmem */
X	struct stdata		*l_stdata ;	/* Ptr to stdata at runtime */
X# else SUNOS40
X	struct tty		*l_addr ;	/* Ptr to tty struct in kmem */
X# endif SUNOS40
X	dev_t			l_dev ;		/* Tty device # */
X} ;
X
X/* Structure holding a single hash table entry ... */
Xstruct hashtab
X{
X	short			h_uid ;		/* Uid of user entry */
X	char			h_uname[ UNAMELEN ] ; /* Corresponding name */
X} ;
X
X/*
X** Format of the standard information file maintained by sps.
X** This structure is filled in at initialisation time and then is read back
X** in whenever sps is invoked.
X** Note that the pointer variables in this structure refer to
X** kernel virtual addresses, not addresses within sps.
X** These variable are typed as such so that pointer arithmetic
X** on the kernel addresses will work correctly.
X*/
Xstruct info
X{	/* Kernel values determining process, tty and upage info ... */
X	struct proc		*i_proc0 ;	/* address of process table */
X	int			i_nproc ;	/* length of process table */
X# ifndef SUNOS40
X	struct text		*i_text0 ;	/* address of text table */
X# endif SUNOS40
X	int			i_ntext ;	/* length of text table */
X# ifdef ULTRIX20
X	struct gnode		*i_inode0 ;	/* address of inode table */
X# else ULTRIX20
X	struct inode		*i_inode0 ;	/* address of inode table */
X# endif ULTRIX20
X	int			i_ninode ;	/* length of inode table */
X	int			i_ecmx ;	/* max physical memory address*/
X# ifndef SUNOS40
X	struct buf		*i_swbuf0 ;	/* address of swap buffers */
X	int			i_nswbuf ;	/* # swap buffers */
X	struct buf		*i_buf0 ;	/* address of i/o buffers */
X	int			i_nbuf ;	/* # i/o buffers */
X	struct pte		*i_usrptmap ;	/* page table map */
X	struct pte		*i_usrpt ;	/* page table map */
X# endif SUNOS40
X	struct cdevsw		*i_cdevsw ;	/* device switch to find ttys */
X# ifdef BSD42
X#  ifdef NFS
X	struct dquot		*i_quota0 ;	/* disc quota structures */
X#  else NFS
X	struct quota		*i_quota0 ;	/* disc quota structures */
X#  endif NFS
X	int			i_nquota ;	/* # quota structures */
X	int			i_dmmin ;	/* The start of the disc map */
X	int			i_dmmax ;	/* The end of the disc map */
X	struct mbuf		*i_mbutl ;	/* Start of mbuf area */
X# else BSD42
X	int			i_hz ;		/* Clock rate */
X# endif BSD42
X# ifdef CHAOS
X	caddr_t			i_Chconntab ;	/* Chaos connection table */
X# endif
X	/* Kernel addresses are associated with process wait states ... */
X	caddr_t			i_waitstate[ NWAITSTATE ] ;
X	/* User names, stored in a hash table ... */
X	struct hashtab		i_hnames[ MAXUSERS ] ;
X	/* Tty device info ... */
X	struct ttyline		i_ttyline[ MAXTTYS ] ;
X# ifdef SUNOS40
X	struct seg_ops		*i_segvn_ops ;	/* ptr to vnode segment ops */
X	struct pty		*i_ptybase ;
X	int			i_npty ;
X#  ifdef SUNOS41
X	struct strstat		*i_strst;
X	struct stdata		*i_allstream;
X#  else SUNOS41
X	struct stdata		*i_streams ;	/* streams list */
X	struct stdata		*i_streamsNSTREAMS ;
X#  endif SUNOS41
X	caddr_t			i_sysbase ;
X# endif SUNOS40
X} ;
X
X/*
X** The symbol structure cross-references values read from the kernel with
X** their place in the info structure, and if such a value is associated with
X** a process wait state or not.
X*/
Xstruct symbol
X{
X	char			*s_kname ;	/* Kernel symbol name */
X	char			s_indirect ;	/* Value requires indirection */
X	caddr_t			*s_info ;	/* Corresponding info address */
X	char			*s_wait ;	/* Reason for wait, if any */
X} ;
X
X/* The `user' structure obtained from /dev/mem or /dev/swap ... */
Xunion userstate
X{
X	struct user		u_us ;
X	char			u_pg[ UPAGES ][ NBPG ] ;
X} ;
X
X/* Information concerning each process filled from /dev/kmem ... */
Xstruct process
X{
X	struct proc		pr_p ;		/* struct proc from /dev/kmem */
X	struct process		*pr_plink ;	/* Normalised ptrs from above */
X	struct process		*pr_sibling ;	/* Ptr to sibling process */
X	struct process		*pr_child ;	/* Ptr to child process */
X	struct process		*pr_pptr ;	/* Ptr to parent process */
X# ifdef BSD42
X	struct rusage		pr_rself ;	/* Read from upage for self */
X	struct rusage		pr_rchild ;	/* ... and the children */
X# else BSD42
X	struct vtimes		pr_vself ;	/* Read from upage for self */
X	struct vtimes		pr_vchild ;	/* ... and the children */
X# endif BSD42
X	int			pr_files ;	/* # open files */
X	struct ttyline		*pr_tty ;	/* Associated tty information */
X	char			*pr_cmd ;	/* Command args, from upage */
X	int			pr_upag:1 ;	/* Upage was obtained */
X	int			pr_csaved:1 ;	/* Cmd args saved by malloc() */
X# ifdef SUNOS40
X	unsigned		pr_private ;	/* private pages */
X	unsigned		pr_shared ;	/* shared pages */
X# endif SUNOS40
X} ;
X
X/* Structure to hold summarising information ... */
Xstruct summary
X{
X	long			sm_ntotal ;	/* Total # processes */
X	long			sm_ktotal ;	/* Total virtual memory */
X	long			sm_nbusy ;	/* # busy processes */
X	long			sm_kbusy ;	/* Busy virtual memory */
X	long			sm_nloaded ;	/* # loaded processes */
X	long			sm_kloaded ;	/* Active resident memory */
X	long			sm_nswapped ;	/* # swapped processes */
X	long			sm_kswapped ;	/* Size totally swapped out */
X} ;
---END-OF-sps.h---
LEN=`wc -c < sps.h`
if [ $LEN !=  6824 ] ; then
    echo shar: File "sps.h" was $LEN, should have been 6824 bytes
fi
if [ -f 'sps.l' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "sps.l"
    exit 2
fi
echo x - sps.l
sed -e 's/^X//' > sps.l << '---END-OF-sps.l---'
X.if n .pl 66
X.TH SPS 1
X.SH NAME
Xsps \ \ \-\ \ \ show process status
X.SH SYNOPSIS
X\fBsps\ \fP \ [ \fB\-cdefgijkoqrslvwyABDFNPSTUWZ\fP ]\ \ [
X\fIprocess\ .\ .\ .\ | tty\ .\ .\ .\ | user\ .\ .\ .\fP ]
X.SH DESCRIPTION
X\fISps\fP reports information concerning system processes.
XIt shows the current state of any process by
Xlisting information such as ownership, CPU time usage, memory usage
Xand disc activity.
X.PP
X\fISps\fP should be used in preference to \fIps\fP(1)
Xbecause it is faster and the output is more comprehensive and more
Xcomprehensible.
X.SH OPTIONS
XBy default, \fIsps\fP prints basic information about one's own processes.
XThe various options described below select other processes or make
X\fIsps\fP more verbose.
X.PP
XUpper case options select processes to be described.
XLower case options specify the format of the output.
XFor instance, the options \fBBv\fP specify that \fIsps\fP
Xshould list ``busy'' processes in a verbose format.
XUnless there is any conflict, lower case options may be used
Xinstead of upper case options, and vice versa.
X.PP
XThe following options specify the format of the listed output \-
X.TP 8
X\fB\-c\fP
XUse the system's idea of the command, rather than getting the arguments
Xfrom user space.  While somewhat less informative, this is faster and
Xmore reliable.
X.TP
X\fB\-d\fP
XList output reflecting how each process affects the
Xdisc and paging activity of the system.
X.TP
X\fB\-e\fP
XList the environment passed to each process.
X.TP
X\fB\-f\fP
XInclude the process\-id of the parent of each process.
X.TP
X\fB\-g\fP
XInclude the process group of each process.
X.TP
X\fB\-o\fP
XAvoid looking at the swap device (\fB/dev/drum\fP). This tends to make \fIsps\fP
Xrun faster, although no information concerning swapped processes
Xcan be obtained.
X.TP
X\fB\-q\fP
XBy default, \fIsps\fP
Xlists the sum of the user plus system times under the
X\fITime\fP and \fIChild\fP fields.  This option forces \fIsps\fP
Xto list only the user times.
X.TP
X\fB\-r\fP
XRepeat the output indefinitely.
XIf the next argument is numeric, \fIsps\fP repeats the output with that
Xmany seconds delay between each repetition.
XOtherwise the output is repeated with no delay.
X.TP
X\fB\-l\fP
X.br
X.ns
X.TP
X\fB\-v\fP
XList additional information in a verbose format. See below.
X.TP
X\fB\-w\fP
XList output in a wide format.  This option forces \fIsps\fP
Xto print all the command arguments, even if doing so extends the output
Xbeyond one line.
X.TP
X\fB\-y\fP
XShow the status of each terminal line.
X.PP
XThe following options specify which processes are to be described \-
X.TP 8
X\fB\-A\fP
XList all processes.
X.TP
X\fB\-B\fP
XList busy processes.  A process is considered to be busy
Xif it is immediately runnable or awaiting a fast event such as disc I/O.
X.TP
X\fB\-D\fP
XList detached processes.
X.TP
X\fB\-F\fP
XList foreground processes.
X.TP
X\fB\-N\fP
XShow no processes at all. Only the summary line is printed.
X.TP
X\fB\-P\fP
XList only processes whose identifiers are specified in the following arguments.
X.TP
X\fB\-S\fP
XList stopped processes.
X.TP
X\fB\-T\fP
XList only processes attached to the following specified terminals.
X.TP
X\fB\-U\fP
XList only processes belonging to the following specified users.
X.TP
X\fB\-W\fP
XList waiting processes.
X.TP
X\fB\-Z\fP
XList zomby (exiting) processes.
X.PP
XThe following are miscellaneous options \-
X.TP 8
X\fB\-i\fP
XInitialise \fIsps\fP.
XThis is necessary if new users are added to the password file,
Xor if a new version of UNIX is installed.
XSps builds a new information file summarising pertinent information
Xread from the password file (\fB/etc/passwd\fP), the executable kernel image
X(\fB/vmunix\fP) and the directory of tty devices (\fB/dev\fP).
XSee also the \fB\-j\fP and \fB\-s\fP options.
X.TP
X\fB\-j\fP
XSpecify an information file other than the default (\fB/etc/spsinfo\fP).
XThe next argument is taken to be the name of a suitable information file.
XIf the \fB\-i\fP flag is also specified, \fIsps\fP builds a
Xnew information file with the given name.
XOtherwise, \fBsps\fP reads previously created summarising information
Xfrom that file.
X.TP
X\fB\-k\fP
XUse a specific disc file rather than the default physical
Xmemory (\fB/dev/mem\fP)
Xand kernel virtual memory (\fB/dev/kmem\fP) files. The next argument is taken
Xto be the name of a suitable memory dump file.
XThis flag automatically sets the \fB\-o\fP flag.
X.TP
X\fB\-s\fP
XThis option is used in conjunction with the \fB\-i\fP option.
XThe next argument is taken to be the name of a suitable kernel executable
Xfile, rather than the default (\fB/vmunix\fP).
X\fISps\fP looks at the symbol table of this file to determine
Xthe virtual addresses of various kernel structures.
X.SH OUTPUT
X\fISps\fP produces output in the following fields \-
X.TP 8
X\fITy\fP
XThe terminal identifier to which the process is attached.
X.IP
XIf this is followed by an underscore, the process is detached.
XIf it is followed by a period, the process is running in the foreground.
XOtherwise the process is running in the background but is still
Xattached to a terminal.
X.TP
X\fIUser\fP
XThe symbolic name of the process' effective user-id (see \fIexec\fP(2)
Xand \fIsetuid\fP(2)).
XThis name is defined by the system password file (\fB/etc/passwd\fP)
Xwhen \fIsps\fP was last initialised.
XOtherwise, an asterisk (\fB*\fP) or vertical bar (\fB|\fP) appearing in this
Xcolumn denotes that the process is an immediate relative of the
Xpreceding process.
XA bar is listed, rather than an asterisk, if both processes belong
Xto the same process group.
XA user name is listed only if the effective user-id
Xdiffers from that of the preceding process or if it is a top-level
Xprocess (immediate offspring of process 1).
X.TP
X\fIProc#\fP
XThe unique process identifier.
X.TP
X\fIPpid#\fP
XThe process-id of the process' parent.
X.TP
X\fIPgrp#\fP
XThe process group to which the process belongs.
X.TP
X\fICommand\fP
XThe command arguments obtained from the process' own address space.
X(If the command name appears in parentheses, \fIsps\fP
Xwas unable to locate the arguments in user space and so reports
Xthe system's idea of the command name.)
X.PP
XThe following additional fields are listed when \fIsps\fP
Xis invoked with one of the \fB\-l\fP or \fB\-v\fP options \-
X.TP 8
X\fIStatus\fP
XThe process' current state.
XIf this field is listed in upper-case letters, the process is currently
Xloaded in real memory space ; otherwise it has been swapped out.
XThe status field may contain one of the following descriptions \-
X.RS 8
X.TP 16
X\fIrun\fP
XThe process can be run immediately.
X.TP
X\fIstop\fP
XThe process is stopped. See \fIsigvec\fP(2).
X.TP
X\fIexit\fP
XThe process is a zomby.
X.RE
X.IP
XAny other entry in the status field indicates the process is
Xwaiting for some external event to occur.
XThis is usually for one of the reasons listed below.
X(If \fIsps\fP does not know why a process is waiting, it lists
Xthe hexadecimal address of the process' wait channel,
Xwith the initial 80000000 trimmed off.)
XA process may be waiting for one of the following reasons \-
X.RS 8
X.TP 16
X\fIchild\fP
XThe process is waiting for a child to terminate. See \fIwait\fP(2).
X.TP
X\fIpause\fP
XWaiting for a signal to be received. See \fIsigpause\fP(2).
X.TP
X\fIswap\fP
XWaiting for a page to be swapped in.
X.TP
X\fIrswbuf\fP
XWaiting for a read from the swap device \fB/dev/drum.\fP
X.TP
X\fIdiscio\fP
XWaiting for a disc read or write operation.
X(Actually, this means that the process is waiting for an operation
Xthrough the kernel's I/O buffering mechanism to complete, but \fIdiscio\fP
Xis what is generally meant here).
X.TP
X\fIrpipe\fP
X.br
X.ns
X.TP
X\fIwpipe\fP
XWaiting for a read from an empty pipe.  Alternatively, the process
Xis waiting to write to a full pipe. See \fIpipe\fP(2).
X.TP
X\fIrsockt\fP
X.br
X.ns
X.TP
X\fIwsockt\fP
XWaiting for a read from an empty socket.
XAlternatively, the process is waiting to write to a full socket (4.[2\-]bsd only).
X.TP
X\fIaccept\fP
XWaiting to accept a stream-based socket connection (4.[2\-]bsd only).
XSee \fIaccept\fP(2).
X.TP
X\fIconnct\fP
XWaiting to establish a connection through a stream-based socket to a
Xremote process (4.[2\-]bsd only). See \fIconnect\fP(2).
X.TP
X\fIsocket\fP
XWaiting for some other time-out event on a socket (4.[2\-]bsd only).
X.TP
X\fIselect\fP
XBlocked by a \fIselect\fP(2) system call (4.[2\-]bsd only).
X.TP
X\fIrmux\fP
XWaiting for a read from a multiplexor file (4.1bsd only).
X.TP
X\fIinode\fP
XWaiting for an inode to be allocated or unlocked.
X.TP
X\fIexlock\fP
X.br
X.ns
X.TP
X\fIshlock\fP
XWaiting for a file to become unlocked. See \fIflock\fP(2).
X.TP
X\fIrtty??\fP
X.br
X.ns
X.TP
X\fIwtty??\fP
X.br
X.ns
X.TP
X\fIotty??\fP
XWaiting for a read or write to the specified terminal, or for the terminal
Xto be switched on. See \fItty\fP(4).
XAlternatively, waiting for a read or write to the
Xspecified slave pty device. See \fIpty\fP(4).
X.TP
X\fIitty??\fP
X.br
X.ns
XUnder SunOS, waiting perform I/O to an iconified window.
X.TP
X\fIrpty??\fP
X.br
X.ns
X.TP
X\fIwpty??\fP
XWaiting for a read or write to the specified master pty device.
XSee \fIpty\fP(4).
X.TP
X\fIptrace\fP
XThis is a parent process tracing its child.
X.TP
X\fIvfork\fP
XThis is a vforking parent process waiting for its child to relinquish
Xmemory resources. See \fIvfork\fP(2).
X.TP
X\fIfloppy\fP
X.br
X.ns
X.TP
X\fIprintr\fP
X.br
X.ns
X.TP
X\fIr??buf\fP
XWaiting for the specified device to complete an I/O operation.
X.RE
X.TP 8
X\fIFl\fP
XFlags associated with the current state of the process.
XThese flags may be any of the following \-
X.RS 8
X.TP 16
X\fIU\fP
XThe process is a UNIX system process.
X.TP
X\fIT\fP
XThe process is being traced or debugged.
X.TP
X\fIV\fP
XThe process is a child currently being vforked. See \fIvfork\fP(2).
X.TP
X\fII\fP
XThe process is undergoing physical I/O.
X.TP
X\fIA\fP
XThe system has detected, or the user has warned of
Xanomalous paging behaviour. See \fIvadvise\fP(2).
X.RE
X.TP 8
X\fINice\fP
XThe ``niceness'' of the process. See \fInice\fP(2).
X.TP
X\fIVirtual\fP
XThe virtual memory size of the process in kilobytes.
XThe first figure indicates the sum of the data and stack segments,
Xthe second figure that of the text segment.
X.TP
X\fIResident\fP
XThe resident memory size of the process in kilobytes, representing
Xthe real memory devoted to the process.
X.TP
X\fI%M\fP
XThe percentage of available real memory allocated to this process.
X.TP
X\fITime\fP
XThe total CPU time accumulated by this process.
X(This is the sum of the system plus user times, unless the \fB\-q\fP
Xflag is specified in which case only the user time is listed.)
X.TP
X\fIChild\fP
XThe total CPU time accumulated by the process' children.
X(This is the sum of the system plus user times, unless the \fB\-q\fP
Xflag is specified.)
X.TP
X\fI%C\fP
XThe percentage of available CPU time devoted to the process.
XThis figure is a decaying average, computed over the past second.
X.PP
XThe following fields are listed when \fIsps\fP is invoked with the
X\fB\-d\fP option \-
X.TP 8
X\fIFiles\fP
XThe number of open files for this process.
X.TP
X\fIPageFaults\fP
XThe number of major and minor page faults incurred by the process.
X.TP
X\fISwap\fP
XThe number of swaps incurred by the process.
X.TP
X\fIBlockI/O\fP
XThe number of block read or write operations performed
Xon behalf of the process.
X.TP
X\fIKbytesecs\fP
XThe integral of real memory usage over time.
XThus, if a process uses 60 kilobytes of real memory for 3 seconds,
Xthis figure is incremented by 180.
X.PP
XThe following fields are listed when \fIsps\fP is invoked with the
X\fB\-y\fP option \-
X.TP 8
X\fIDev\fP
XThe major and minor device numbers of the terminal.
X.TP
X\fIAddr\fP
XThe virtual address of the associated \fBstruct tty\fP in \fB/dev/kmem\fP.
X.TP
X\fIRawq\fP
X.br
X.ns
X.TP
X\fICanq\fP
X.br
X.ns
X.TP
X\fIOutq\fP
XThe number of characters in the terminal I/O queues.
XThese refer to the raw input queue, the canonical input queue
Xand the output queue.
X.TP
X\fIPgrp\fP
XThe process group associated with the terminal.
X.PP
XAfter listing the requested output, \fIsps\fP prints a summary line.
XThis indicates the number and total virtual memory size of all processes,
Xthe number and total virtual size of busy processes,
Xthe number and real memory size of loaded processes
Xand the number and real size of swapped processes.
X.SH DIAGNOSTICS
X\fISps\fP reports a self-explanatory message if it is given an
Xinvalid argument list.
XThe program also complains if it cannot find necessary system information.
X.PP
XAt initialisation, \fIsps\fP complains if it cannot find the addresses of
Xrequisite system structures in the kernel symbol file.
XThis is usually the case because the system is rarely configured to support
Xall known devices.
X\fISps\fP also complains if more than one user shares the same user-id
Xin the password file (\fB/etc/passwd\fP).
X.SH EXAMPLES
X\fBsps vb\fP
X.PP
X\fISps\fP describes all busy processes in a verbose manner.
X.PP
X\fBsps dtg 9 h1 co\fP
X.PP
X\fISps\fP lists processes associated with terminals \fB9\fP,
X\fBh1\fP and the \fBconsole\fP.
XThe output reflects the disc activity caused by these processes.
XThe process group of each process is also included in the output.
X.PP
X\fBsps weu robert fred \-r 2\fP
X.PP
X\fISps\fP reports processes belonging to the specified users.
XIt lists the environment as well as all the command arguments in a wide format.
XThe output is produced indefinitely, with a delay of two seconds between
Xeach listing.
X.PP
X\fBsps is /vmunix.new\fP
X.PP
X\fISps\fP is initialised. It reads its symbol information from the
Xspecified file.
X.SH FILES
X.ta 2.5i
X.nf
X\fB/dev/console\fP	Console
X\fB/dev/tty??\fP	Terminal and pty devices
X\fB/dev/kmem\fP	Kernel virtual memory
X\fB/dev/mem\fP	Physical memory
X\fB/dev/drum\fP	Paging and swap device
X\fB/etc/passwd\fP	Password file
X\fB/etc/spsinfo\fP	Information file
X\fB/vmunix\fP	Symbol file of \fB/dev/kmem\fP addresses
X\fB/etc/termcap\fP	To determine the output terminal width
X.fi
X.ta
X.SH SEE ALSO
X\fIiostat\fP(1), \fIkill\fP(1), \fIps\fP(1),
X\fIvmstat\fP(1), \fIexec\fP(2),
X\fIflock\fP(2), \fInice\fP(2), \fIpause\fP(2), \fIselect\fP(2), \fIsetuid\fP(2),
X\fIsigvec\fP(2), \fIvadvise\fP(2), \fIvfork\fP(2), \fIwait\fP(2),
X\fIpty\fP(4),\fItty\fP(4), \fIpstat\fP(8).
X.SH AUTHORS
XSeveral. In particular, J. E. Kulp and J. Robert Ward,
X\fB<robert@olsen.uucp>\fP.
X.LP
XNFS changes incorporated by Alexander Dupuy,
X\fB<dupuy@amsterdam.columbia.edu>\fP
X.LP
XSunOS 4.0 implementation by Alexander Dupuy and
XCharlie Kim \fB<cck@cunixc.cc.columbia.edu>\fP.
X.LP
XUltrix 2.\fIx\fP additions incorporated by Rob Lehman at CUUCA.
X.LP
XSunOS 4.1 additions incorporated by Sakari Jalovaara, \fB<sja@sirius.hut.fi>\fP.
X.LP
XCurrently maintained by J. Robert Ward, \fB<robert@olsen.uu.ch>\fP
X.SH BUGS
XBecause the system is continually changing, the information reported by
X\fIsps\fP is only an approximation to reality.
XIf invoked by root, \fIsps\fP renices itself to \-20 in an attempt to run as
Xfast as possible.
X.PP
X\fISps\fP recognises the sizes and addresses of internal kernel
Xtables whenever it is invoked. However, it must be recompiled
Xif major modifications are made to the kernel.
X.PP
X\fISps\fP does not list all the detailed information shown by \fIps\fP(1).
XNor are all the options supported by \fIps\fP(1) available from \fIsps\fP.
X.PP
X\fISps\fP does not understand all the possible
Xreasons why a process may be sleeping.
X.PP
XThe code of \fIsps\fP is inherently machine-dependent and non-portable.
X.PP
XThe number of options to \fIsps\fP is ridiculous.
---END-OF-sps.l---
LEN=`wc -c < sps.l`
if [ $LEN !=  15259 ] ; then
    echo shar: File "sps.l" was $LEN, should have been 15259 bytes
fi
if [ -f 'stream.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "stream.c"
    exit 2
fi
echo x - stream.c
sed -e 's/^X//' > stream.c << '---END-OF-stream.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)stream.c	1.2\t7/4/90" ;
X# endif
X
X# ifdef SUNOS40
X#  include		"sps.h"
X#  include		<h/stream.h>
X#  include		<h/vnode.h>
X#  ifdef SUNOS41
X#   include		<h/strstat.h>
X#  endif
X
Xstatic struct stdata    *pstreams ;
Xstatic struct stdata    *pstreamsNSTREAMS ;
X
Xinit_streams_tab()
X{
X	int			len ;
X	extern struct info	Info ;
X	register struct stdata	*s ;
X	struct vnode		*v ;
X	char			*getcore() ;
X
X	if ( pstreams )
X		/* reinitializing */
X		for ( s = pstreams ; s <= pstreamsNSTREAMS ; s++ )
X			if ( s->sd_vnode != 0 )
X				free( (char*)s->sd_vnode ) ;
X		free( (char*)pstreams ) ;
X#  ifdef SUNOS41
X	/*
X	 * In SunOS 4.1, the stream heads are in a linked list.  A
X	 * `struct strstat' contains the number of active streams; the
X	 * variable `allstream' points to an apparently random
X	 * position in a doubly linked `struct stdata' chain.
X	 *
X	 * To find all streams we'll have to scan the chain forwards
X	 * AND backwards from `allstream'.  `int going_forwards' below
X	 * tells which direction we are currently going.  Weird.
X	 *
X	 */
X
X	{
X		struct strstat		strst ;
X		int			n ;
X		long			addr ;
X		struct stdata		*this_stream ;
X		int			going_forwards = 1 ;
X    
X		if ( getkmem ((long) Info.i_strst, (char *) &strst,
X		    sizeof ( struct strstat )) != sizeof ( struct strstat ))
X			return 0 ;
X		len = strst.stream.use * sizeof( struct stdata ) ;
X		pstreams = (struct stdata *)getcore (len ) ;
X		addr = (long)Info.i_allstream ;
X		this_stream = pstreams ;
X		pstreamsNSTREAMS = pstreams - 1 ;
X		for (n = 0 ; n < strst.stream.use ; n++)
X		{
X			if ( getkmem ( addr, (char *) this_stream,
X			    sizeof ( struct stdata ))
X			    != sizeof ( struct stdata ))
X			{
X				/*
X				 * If we are following the `sd_next' chain we'll
X				 * have to start over from the stream pointed to
X				 * by Info.i_allstream and scan `sd_prev'
X				 * backwards.
X				 */
X				if ( going_forwards && n > 0 )
X				{
X					going_forwards = 0 ;
X					addr = (long) pstreams[0].sd_prev ;
X					n--;
X					continue ;
X				}
X				if ( pstreamsNSTREAMS < pstreams )
X					return 0 ;
X				break ;
X			}
X			addr = going_forwards ? (long) this_stream->sd_next :
X				(long) this_stream->sd_prev ;
X			this_stream++ ;
X			pstreamsNSTREAMS++ ;
X		}
X	}
X#  else SUNOS41
X	len = ((Info.i_streamsNSTREAMS - Info.i_streams) + 1)
X		* sizeof( struct stdata ) ;
X	pstreams = (struct stdata *)getcore( len ) ;
X	pstreamsNSTREAMS = pstreams + (len / sizeof( struct stdata ) ) ;
X	if ( getkmem( (long)Info.i_streams, (char *)pstreams, len ) != len )
X		return( 0 ) ;
X#  endif SUNOS41
X
X	for ( s = pstreams ; s <= pstreamsNSTREAMS ; s++ )
X		if ( s->sd_vnode != 0 )
X		{
X			if ( ( v = (struct vnode*)getcore( sizeof( *v ) ) )
X			&& getkmem( (long)s->sd_vnode, (char*)v, sizeof( *v ) )
X			== sizeof( *v ) )
X			{
X				s->sd_vnode = v ;
X				continue ;
X			}
X
X			s->sd_vnode = 0 ;
X		}
X	return( 1 ) ;
X}
X
X
X#  ifdef SUNOS41
Xstruct sess *find_session ( addr )
X
Xstruct sess			*addr ;
X
X{
X	/*
X	 * SunOS 4.1 seems to store controlling tty's in a "struct
X	 * sess" which is accessible as p->p_sessp.  Another layer
X	 * of indirection to wade through...
X	 *
X	 * To make this a tiny bit faster, I'll store sessions in a
X	 * linked list as I read them in with getkmem; subsequent
X	 * calls to find_session() check the cache.
X	 */
X
X	struct sps_sess {
X		struct sess		sess ;
X		struct sess		*addr ;
X		struct sps_sess		*next ;
X	};
X
X	static struct sps_sess		*sessions ; /* Cache of known sessions*/
X	register struct sps_sess	*s ;
X
X	/* Try to find the session in the cache */
X	for ( s = sessions ; s ; s = s->next )
X		if ( s->addr == addr )
X			return &s->sess ;
X	/* Not found; get it from kmem and put it in the cache */
X	s = (struct sps_sess *)getcore( sizeof ( struct sps_sess ) ) ;
X	if ( getkmem ((long) addr, (char *) &s->sess,
X		    sizeof ( struct sess )) != sizeof ( struct sess ) )
X		return 0 ;
X	s->addr = addr ;
X	s->next = sessions ;
X	sessions = s ;
X	return &s->sess ;
X}
X#  endif SUNOS41
X
Xstruct stdata *getstdata ( st, dev )
X
Xstruct streamtab                *st ;
Xdev_t                            dev ;
X
X{
X	register struct stdata  *s ;
X
X	for ( s = pstreams ; s <= pstreamsNSTREAMS ; s++ )
X		if ( s->sd_strtab == st && s->sd_vnode
X		&& s->sd_vnode->v_rdev == dev )
X			return( s ) ;
X	return( 0 ) ;
X}
X
X/* 1 if `w' is in the address range defined by `a1' and `a2' ... */
X# define        INRANGE( w, a1, a2 ) \
X			( (caddr_t)(a1) <= (w) && (w) < (caddr_t)(a2) )
X
Xchar *gettty ( lp, w )
X
Xregister struct ttyline         *lp ;
Xcaddr_t                         w ;
X
X{
X	struct stdata           *s ;
X	struct queue            *q ;
X	struct queue            qq[2] ;
X	char                    *cp = 0 ;
X
X	if ( ( s = lp->l_stdata ) == 0 )
X		return( 0 ) ;
X
X	q = s->sd_wrq ;		/* get write queue (only queue_t in stdata) */
X	do
X	{
X		if ( INRANGE( w, RD( q ), q ) )
X		{			/* check read queue */
X			cp = "rtty??" ;
X			break ;
X		}
X		if ( INRANGE( w, q, WR ( q ) ) )
X		{			/* check write queue */
X			cp = "wtty??" ;
X			break ;
X		}
X		/* check queue private data structures - useful??? */
X		if ( getkmem( (long)RD( q ), (char*)qq, sizeof( qq ) )
X		!= sizeof( qq ) )
X			break ;
X		if ( INRANGE( w, qq[0].q_ptr, qq[0].q_ptr + 1 ) )
X		{
X			cp = "r?ty??" ;
X		}
X		if ( INRANGE( w, qq[1].q_ptr, qq[1].q_ptr + 1 ) )
X		{
X			cp = "w?ty??" ;
X		}
X		q = qq[1].q_next ;
X	}
X	while ( q ) ;
X	if ( cp )
X	{
X		cp[4] = lp->l_name[0] ;
X		cp[5] = lp->l_name[1] ;
X		return( cp ) ;
X	}
X	return( 0 ) ;			/* chain down list? */
X}
X# endif SUNOS40
X
---END-OF-stream.c---
LEN=`wc -c < stream.c`
if [ $LEN !=  5425 ] ; then
    echo shar: File "stream.c" was $LEN, should have been 5425 bytes
fi
if [ -f 'termwidth.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "termwidth.c"
    exit 2
fi
echo x - termwidth.c
sed -e 's/^X//' > termwidth.c << '---END-OF-termwidth.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)termwidth.c	1.3\t8/6/90" ;
X# endif
X
X# include	<sys/ioctl.h>
X
X/*
X** TERMWIDTH - Sets the external variable `Termwidth' to the # of columns
X** on the terminal.
X*/
Xtermwidth ()
X{
X	register char           *termtype ;
X	register int            twidth ;
X# ifdef TIOCGWINSZ
X	struct winsize		w ;
X# else
X# ifdef TIOCGSIZE
X	struct ttysize          w ;
X# endif
X# endif
X	char                    buf[ 1025 ] ;
X	extern unsigned         Termwidth ;
X	char                    *getenv() ;
X
X# ifdef TIOCGWINSZ
X	w.ws_col = 0 ;
X	if ( !ioctl( 0, TIOCGWINSZ, &w ) && w.ws_col )
X	{
X		Termwidth = w.ws_col ;
X		return ;
X	}
X# else
X# ifdef TIOCGSIZE
X	w.ts_cols = 0 ;
X	if ( !ioctl( 0, TIOCGSIZE, &w ) && w.ts_cols )
X	{
X		Termwidth = w.ts_cols ;
X		return ;
X	}
X# endif
X# endif
X	Termwidth = 80 ;
X	if ( !(termtype = getenv( "TERM" )) )
X		return ;
X	if ( tgetent( buf, termtype ) != 1 )
X		return ;
X	twidth = tgetnum( "co" ) ;
X	if ( twidth > 40 )
X		Termwidth = twidth ;
X}
---END-OF-termwidth.c---
LEN=`wc -c < termwidth.c`
if [ $LEN !=  978 ] ; then
    echo shar: File "termwidth.c" was $LEN, should have been 978 bytes
fi
if [ -f 'ttystatus.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "ttystatus.c"
    exit 2
fi
echo x - ttystatus.c
sed -e 's/^X//' > ttystatus.c << '---END-OF-ttystatus.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)ttystatus.c	1.1\t10/1/88" ;
X# endif
X
X# include       "sps.h"
X# include       "flags.h"
X# include       <stdio.h>
X# include       <h/ioctl.h>
X# ifdef SUNOS40
X# include       <h/stream.h>
X# else
X# include       <h/tty.h>
X# endif
X# ifdef CHAOS
X# include       <chunix/chsys.h>
X# include       <chaos/chaos.h>
X# endif
X
X/*
X** TTYSTATUS - Reads the kernel memory for tty structures of active processes.
X** The addresses of the associated struct ttys of /dev/kmem are kept in the
X** info structure. Here we use those addresses to access the structures.
X** Actually, we are mostly interested just in the process group of each tty.
X*/
Xttystatus ()
X{
X	register struct ttyline *lp ;
X# ifdef SUNOS40
X	struct stdata           *stdata ;
X	extern struct stdata    *getstdata() ;
X# else
X	struct tty              tty ;
X# endif
X	extern struct flags     Flg ;
X	extern struct info      Info ;
X# ifndef KVM
X	extern int              Flkmem ;
X# endif
X
X# ifdef SUNOS40
X	if ( !init_streams_tab() )
X		fprintf( stderr, "can't read streams table\n" ) ;
X# endif
X
X	if ( Flg.flg_y )
X# ifdef SUNOS40
X		printf( "Ty   Dev       Addr  Pgrp\n" ) ;
X# else
X		printf( "Ty   Dev       Addr Rawq Canq Outq  Pgrp\n" ) ;
X# endif
X	lp = Info.i_ttyline ;
X# ifdef CHAOS
X	while ( lp->l_name[0] && lp->l_name[0] != 'C' )
X# else
X	while ( lp->l_name[0] )
X# endif
X	{
X# ifdef SUNOS40 
X		if ( stdata = getstdata ( lp->l_addr, lp->l_dev ) )
X		{
X			lp->l_stdata = stdata ;
X			lp->l_pgrp = stdata->sd_pgrp ;
X			prstr( lp, stdata ) ;
X		}
X		else
X			lp->l_pgrp = 0 ;
X		lp++ ;
X# else
X		if ( getkmem( (long)lp->l_addr, (char*)&tty, sizeof( tty ) )
X		!= sizeof( struct tty ) )
X		{
X			fprintf( stderr,
X				"sps - Can't read struct tty for tty%.2s\n",
X				lp->l_name ) ;
X			lp->l_pgrp = 0 ;
X			lp++ ;
X			continue ;
X		}
X		lp->l_pgrp = tty.t_pgrp ;
X		prtty( lp, &tty ) ;
X		lp++ ;
X# endif
X	}
X# ifdef CHAOS
X	chaosttys( lp ) ;               
X# endif
X}
X
X# ifdef SUNOS40
X
X/* PRSTR - Print out the stdata structure */
Xprstr ( lp, stdata )
X
Xregister struct ttyline         *lp ;
Xregister struct stdata          *stdata ;
X
X{
X	extern struct flags     Flg ;
X
X	if ( !Flg.flg_y )
X		return ;
X	printf( "%-2.2s %2d,%2d 0x%08x %5d\n",
X		lp->l_name,
X		major( lp->l_dev ),
X		minor( lp->l_dev ),
X		lp->l_addr,
X		stdata->sd_pgrp ) ;
X}
X
X# else
X
X/* PRTTY - Print out the tty structure */
Xprtty ( lp, tty )
X
Xregister struct ttyline         *lp ;
Xregister struct tty             *tty ;
X
X{
X	extern struct flags     Flg ;
X
X	if ( !Flg.flg_y )
X		return ;
X	printf( "%-2.2s %2d,%2d 0x%08x %4d %4d %4d %5d\n",
X		lp->l_name,
X		major( lp->l_dev ),
X		minor( lp->l_dev ),
X		lp->l_addr,
X		tty->t_rawq.c_cc,
X		tty->t_canq.c_cc,
X		tty->t_outq.c_cc,
X		tty->t_pgrp ) ;
X}
X
X# endif
X
X# ifdef CHAOS
X
X/* CHAOSTTYS - Finds ttys attached to the Chaos net */
Xchaosttys ( lp )
X
Xregister struct ttyline         *lp ;
X
X{
X	register struct connection      **cnp ;
X	register int                    i ;
X	struct tty                      tty ;
X	struct connection               *conntab[CHNCONNS] ;
X	struct connection               conn ;
X	extern struct info              Info ;
X	extern int                      Flkmem ;
X
X	(void)getkmem( (long)Info.i_Chconntab, (char*)conntab,
X		sizeof( conntab ) ) ;
X	for ( i = 0, cnp = conntab ; cnp < &conntab[CHNCONNS] ; i++, cnp++ )
X	{
X		if ( !*cnp )
X			continue ;
X		(void)getkmem( (long)*cnp, (char*)&conn, sizeof( conn ) ) ;
X		if ( !(conn.cn_flags & CHTTY) )
X			continue ;
X		(void)getkmem( (long)conn.cn_ttyp, (char*)&tty, sizeof( tty ) ) ;
X		if ( lp >= &Info.i_ttyline[MAXTTYS] )
X			prexit( "sps - Too many chaos ttys\n" ) ;
X		lp->l_addr = conn.cn_ttyp ;
X		lp->l_pgrp = tty.t_pgrp ;
X		lp->l_dev = tty.t_dev ;
X		lp->l_name[0] = 'C' ;
X		lp->l_name[1] = i < 10 ? '0'+i : i-10 <= 'z'-'a' ? i-10+'a' :
X				i-10-('z'-'a')+'A' ;
X		prtty( lp, &tty ) ;
X		lp++ ;
X	}
X}
X
X# endif
---END-OF-ttystatus.c---
LEN=`wc -c < ttystatus.c`
if [ $LEN !=  3826 ] ; then
    echo shar: File "ttystatus.c" was $LEN, should have been 3826 bytes
fi
if [ -f 'vmstat.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "vmstat.c"
    exit 2
fi
echo x - vmstat.c
sed -e 's/^X//' > vmstat.c << '---END-OF-vmstat.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)vmstat.c	1.1\t10/1/88" ;
X# endif
X
X# ifdef SUNOS40
X# ifndef OLDSTATS
X# include "sps.h"
X# include <h/mman.h>
X# include <vm/hat.h>
X# include <vm/as.h>
X# include <vm/seg.h>
X# include <vm/seg_vn.h>
X
Xseg_count ( p )
X
Xstruct process                  *p ;
X
X{
X	extern struct info      Info ;
X	struct as               as ;		/* address space */
X	struct seg              seg ;		/* segment in addr space */
X	struct segvn_data       vn_data ;
X	unsigned                private = 0 ;
X	unsigned                shared = 0 ;
X
X	p->pr_private = 0 ;
X	p->pr_shared = 0 ;
X
X	if ( getkmem( (long)p->pr_p.p_as, &as, sizeof( as ) ) != sizeof( as ) )
X		return( -1 ) ;
X	seg.s_next = as.a_segs ;	/* setup for loop */
X	do
X	{
X		if ( ( getkmem( seg.s_next, &seg, sizeof( seg ) ) )
X		!= sizeof( seg ) )
X			break ;
X		if ( seg.s_as != p->pr_p.p_as )
X			continue ;	/* invalid segment */
X		if ( seg.s_ops != Info.i_segvn_ops )
X		{			/* mapped device is "shared" */
X			shared += seg.s_size ;
X			continue ;
X		}
X		if ( getkmem( (long)seg.s_data, &vn_data, sizeof( vn_data ) )
X		!= sizeof( vn_data ) )
X			continue ;
X		/*
X		 * If a segment has an anonymous mapping, it is in the swap
X		 * area.  If it is also MAP_PRIVATE, we consider it "private"
X		 * (even though it may be shared between parent and child after
X		 * a fork() call).  Segments without an anonymous mapping are
X		 * considered to be "shared".  [Should we worry about swap
X		 * space reserved for copy-on-write shared segments?]
X		 */
X
X		if ( vn_data.amp && (vn_data.type & MAP_TYPE) == MAP_PRIVATE )
X			private += seg.s_size ;
X		else
X			shared += seg.s_size ;
X	}
X	while ( seg.s_next != as.a_segs ) ;
X
X# define BYTETOPAGE(x) (((x)+(PAGESIZE-1))>>PGSHIFT)
X
X	p->pr_private = BYTETOPAGE( private ) ;
X	p->pr_shared = BYTETOPAGE( shared ) ;
X	p->pr_p.p_rssize = as.a_rss ;	/* update count of resident pages */
X	return( 0 ) ;
X}
X# endif
X# endif
---END-OF-vmstat.c---
LEN=`wc -c < vmstat.c`
if [ $LEN !=  1902 ] ; then
    echo shar: File "vmstat.c" was $LEN, should have been 1902 bytes
fi
if [ -f 'waitingfor.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "waitingfor.c"
    exit 2
fi
echo x - waitingfor.c
sed -e 's/^X//' > waitingfor.c << '---END-OF-waitingfor.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)waitingfor.c	1.5\t8/6/90" ;
X# endif
X
X# include		"sps.h"
X# ifndef SUNOS40
X# include		<h/text.h>
X# endif SUNOS40
X
X# ifdef NFS
X#  ifdef DEC3100
X#   include		<h/gnode.h>
X#   include		<h/inode.h>
X#  else DEC3100
X#   include		<h/vnode.h>
X#   include		<ufs/inode.h>
X# endif DEC3100
X# else
X#  include		<h/inode.h>
X# endif NFS
X
X# include		<h/ioctl.h>
X# ifdef SUNOS40
X#  include		<h/stream.h>
X#  include		<h/tty.h>
X#  include		<h/ptyvar.h>
X# else SUNOS40
X#  include		<h/tty.h>
X# endif SUNOS40
X
X# include		<h/buf.h>
X# ifdef BSD42
X#  ifdef NFS
X#   ifndef NOQUOTA
X#    ifdef DEC3100
X#     include		<h/quota.h>
X#    else
X#     include		<ufs/quota.h>
X#    endif DEC3100
X#   endif NOQUOTA
X#  else NFS
X#   include		<h/quota.h>
X#  endif NFS
X# include		<h/mbuf.h>
X# include		<h/socket.h>
X# include		<h/socketvar.h>
X# endif BSD42
X
X/* 1 if `w' is in the address range defined by `a1' and `a2' ... */
X# define        INRANGE( w, a1, a2 ) \
X			( (caddr_t)(a1) <= (w) && (w) < (caddr_t)(a2) )
X
X/* NFS changes incorporated by Alexander Dupuy <dupuy@amsterdam.columbia.edu> */
X
X/* WAITINGFOR - Determine what a process is waiting for and describe it. */
Xchar    *waitingfor ( p )
X
Xstruct process                  *p ;
X
X{
X	register caddr_t        w ;
X	register struct ttyline *lp ;
X	register struct symbol  *s ;
X	register char           *cp ;
X# ifdef BSD42
X	struct socket           sc ;
X# endif
X	int			rc ;
X	static char             wbuf[ 8 ] ;
X	extern struct info      Info ;
X	extern struct symbol    Symbollist[] ;
X	char                    *sprintf() ;
X# ifdef SUNOS40
X	char                    *gettty() ;
X# endif
X
X	w = p->pr_p.p_wchan ;
X	if ( !w )
X		return ( "null" ) ;
X	/* Waiting for a child process, alternatively in a vfork() ? */
X	if ( INRANGE( w, Info.i_proc0, &Info.i_proc0[ Info.i_nproc ] ) )
X		return ( p->pr_p.p_flag & SNOVM ? "vfork" : "child" ) ;
X# ifndef SUNOS40
X	/* Waiting for a page to be brought in ? */
X	if ( INRANGE( w, Info.i_swbuf0, &Info.i_swbuf0[ Info.i_nswbuf ] ) )
X		return ( "swap" ) ;
X	/* Waiting for discio through a block device to complete ? */
X	if ( INRANGE( w, Info.i_buf0, &Info.i_buf0[ Info.i_nbuf ] ) )
X		/* SHOULD ACTUALLY READ AS "blkio" BUT "discio" IS WHAT
X		   IS GENERALLY MEANT HERE. */
X		return ( "discio" ) ;
X	/* Waiting for a text page to be brought in ? */
X	if ( INRANGE( w, Info.i_text0, &Info.i_text0[ Info.i_ntext ] ) )
X		return ( "swtext" ) ;
X# endif SUNOS40
X
X# ifdef BSD42
X#  ifndef NOQUOTA
X	/* Waiting for an event associated with the quota system ? */
X	if ( INRANGE( w, Info.i_quota0, &Info.i_quota0[ Info.i_nquota ] ) )
X		return ( "quota" ) ;
X#  endif NOQUOTA
X# endif BSD42
X
X# ifndef SUNOS41
X		 /* Sorry, I don't know how to do this...
X		  * I kinda think that SunOS 4.1 allocates inode
X		  * buffer entries dynamically.  Maybe it could be
X		  * possible to read in all "struct file"s and
X		  * compare each file.f_data to the wait channel.	++sja
X		  */
X	/* Waiting for an inode ? */
X	if ( INRANGE( w, Info.i_inode0, &Info.i_inode0[ Info.i_ninode ] ) )
X#  ifdef ULTRIX20
X		switch ( ((int)w - (int)Info.i_inode0) % sizeof( struct gnode ))
X#  else
X		switch ( ((int)w - (int)Info.i_inode0) % sizeof( struct inode ))
X#  endif ULTRIX20
X		{
X#  ifdef BSD42
X#   ifdef NFS
X			case (int)&((struct inode*)0)->i_vnode.v_exlockc :
X				/* Exclusive lock on this inode */
X				return ( "exlock" ) ;
X			case (int)&((struct inode*)0)->i_vnode.v_shlockc :
X				/* Shared lock on this inode */
X				return ( "shlock" ) ;
X#   else NFS
X#    ifdef ULTRIX20
X#     ifndef DEC3100
X			/* Compile this code with gcc if you want to run it
X			   properly.  The DEC compiler can't handle this. */
X			case (int)&((struct gnode*)0)->g_exlockc :
X				/* Exclusive lock on this inode */
X				return ( "exlock" ) ;
X			case (int)&((struct gnode*)0)->g_shlockc :
X				/* Shared lock on this inode */
X				return ( "shlock" ) ;
X			case (int)&((struct gnode*)0)->g_frcnt :
X				/* Open fifo with no readers */
X				return ( "wfifo" ) ;
X			case (int)&((struct gnode*)0)->g_fwcnt :
X				/* Open fifo with no writers */
X				return ( "rfifo" ) ;
X#     endif DEC3100
X#    else ULTRIX20
X			case (int)&((struct inode*)0)->i_exlockc :
X				/* Exclusive lock on this inode */
X				return ( "exlock" ) ;
X			case (int)&((struct inode*)0)->i_shlockc :
X				/* Shared lock on this inode */
X				return ( "shlock" ) ;
X#    endif ULTRIX20
X#   endif NFS
X#  else BSD42 
X			case 1 :
X				return ( "wpipe" ) ;
X			case 2 :
X				return ( "rpipe" ) ;
X			case (int)&((struct inode*)0)->i_un.i_group.g_datq :
X				return ( "rmux" ) ;
X#  endif BSD42
X			default :
X				/* Inode probably locked */
X				return ( "inode" ) ;
X		}
X# endif SUNOS41
X
X# if defined(BSD42) && (defined(SUNOS40) || defined(NMBCLUSTERS))
X	/* Waiting for a structure inside an mbuf ? If so, try to find why */
X#  ifdef SUNOS40
X	if ( INRANGE( w, Info.i_mbutl,
X	&Info.i_mbutl[ MBPOOLBYTES / sizeof( struct mbuf ) ] ) )
X#  else
X	if ( INRANGE( w, Info.i_mbutl,
X	&Info.i_mbutl[ NMBCLUSTERS * CLBYTES / sizeof( struct mbuf ) ] ) )
X#  endif SUNOS40
X		switch ( ((int)w - (int)Info.i_mbutl) % sizeof( struct mbuf )
X			- (int)&((struct mbuf*)0)->m_dat[0] )
X		{
X			case (int)&((struct socket*)0)->so_timeo :
X				/* Socket timeout event - Guess why */
X				rc = getsocket( (struct socket*)(w
X				    - (int)&((struct socket*)0)->so_timeo),
X						&sc ) ;
X				return ( rc && (sc.so_state & SS_ISCONNECTING)
X					? "connct" 
X					: rc && ((sc.so_options & SO_ACCEPTCONN)
X					  && !sc.so_qlen)
X					? "accept" : "socket" ) ;
X			case (int)&((struct socket*)0)->so_rcv.sb_cc :
X				/* Read from an empty socket. Here we actually
X				   attempt to determine whether the socket
X				   structure in question really does refer to
X				   a socket, or whether it is in fact a pipe
X				   in disguise. */
X				return ( getsocket( (struct socket*)(w
X				    - (int)&((struct socket*)0)->so_rcv.sb_cc),
X						&sc )
X					&& sc.so_type == SOCK_STREAM
X#  ifdef BSD43
X					&& ((sc.so_state
X					    & (SS_ISCONNECTED|SS_CANTSENDMORE))
X					    == (SS_ISCONNECTED|SS_CANTSENDMORE))
X#  else
X					&& !sc.so_rcv.sb_hiwat
X					&& !sc.so_rcv.sb_mbmax
X					&& (sc.so_state
X					    & (SS_ISCONNECTED|SS_CANTRCVMORE))
X#  endif BSD43
X					? "rpipe" : "rsockt" ) ;
X			case (int)&((struct socket*)0)->so_snd.sb_cc :
X				/* Write to a full socket. Again, we try
X				   to determine whether or not this is a
X				   real socket or a pipe. */
X				return ( getsocket( (struct socket*)(w
X				    - (int)&((struct socket*)0)->so_snd.sb_cc),
X						&sc )
X#  ifdef BSD43
X					&& sc.so_type == SOCK_STREAM
X					&& ((sc.so_state
X					    & (SS_ISCONNECTED|SS_CANTRCVMORE))
X					    == (SS_ISCONNECTED|SS_CANTRCVMORE))
X#  else
X					&& sc.so_rcv.sb_hiwat == 2048
X					&& sc.so_rcv.sb_mbmax == 4096
X					&& (sc.so_state
X					    & (SS_ISCONNECTED|SS_CANTSENDMORE))
X#  endif BSD43
X					? "wpipe" : "wsockt" ) ;
X			default :
X				/* Other mbuf event */
X				return ( "mbuf" ) ;
X		}
X# endif BSD42
X
X# ifdef SUNOS41
X	if  ( w == (caddr_t)p->pr_p.p_uarea )
X		return ( "pause" ) ;
X# endif SUNOS41
X	/* Look in the symbol table for known wait addresses. */
X	for ( s = Symbollist ; s->s_kname ; s++ )
X		if ( s->s_wait && w == *s->s_info )
X			return ( s->s_wait ) ;
X
X# ifdef SUNOS40
X	/* Have to check for ptys in a funny sort of way */
X	if ( INRANGE( w, Info.i_ptybase, &Info.i_ptybase[ Info.i_npty ] ) )
X	{
X		switch ( ((int)w - (int)Info.i_ptybase) % sizeof( struct pty ) )
X		{
X			case (int)&((struct pty*)0)->pt_flags :
X				cp = "opty??" ;
X				break ;
X			case (int)&((struct pty*)0)->pt_ttycommon.t_writeq :
X				cp = "spty??" ;
X				break ;
X			default :
X				cp = "?pty??" ;
X		}
X		/* by the conventional naming, anyhow */
X		cp[4] = 'p' + (((int)w - (int)Info.i_ptybase)
X			/ sizeof( struct pty )) / 16 ;
X		if ( ( cp[5] = '0' + (((int) w - (int)Info.i_ptybase)
X			/ sizeof( struct pty )) % 16 ) > '9' )
X			cp[5] += 'a' - '9' - 1 ;
X		return( cp ) ;
X	}
X	/* Check for ttys last, since there may be a lot of them. */
X	if ( p->pr_tty != 0 )
X		if ( cp = gettty( p->pr_tty, w ) )
X			return( cp ) ;
X	for ( lp = Info.i_ttyline ; lp->l_name[0] ; lp++ )
X		if ( cp = gettty( lp, w ) )
X			return( cp ) ;
X# else SUNOS40
X	/* Waiting for tty I/O ? If so, find which tty it is */
X	for ( lp = Info.i_ttyline ; lp->l_name[0] ; lp++ )
X		if ( INRANGE( w, &lp->l_addr[0], &lp->l_addr[1] ) )
X		{
X#  ifdef DEC3100
X			/* Cretinous DEC compiler can't handle case
X			   constructs like the following ... */
X			cp = "?tty??" ;
X#  else DEC3100
X			switch ( (int)w - (int)lp->l_addr )
X			{
X				case (int)&((struct tty*)0)->t_rawq :
X					/* Read from a tty or slave pty */
X					cp = "rtty??" ;
X					break ;
X				case (int)&((struct tty*)0)->t_outq :
X					/* Write to a tty or slave pty */
X					cp = "wtty??" ;
X					break ;
X				case (int)&((struct tty*)0)->t_canq :
X					/* Waiting for icon to be opened */
X					cp = "itty??" ;
X					break ;
X				case (int)&((struct tty*)0)->t_state :
X					/* Tty not open */
X					cp = "otty??" ;
X					break ;
X				case (int)&((struct tty*)0)->t_outq.c_cf :
X					/* Read from a controller pty */
X					cp = "rpty??" ;
X					break ;
X				case (int)&((struct tty*)0)->t_rawq.c_cf :
X					/* Write to a controller pty */
X					cp = "wpty??" ;
X					break ;
X				default :
X					cp = "?tty??" ;
X					break ;
X			}
X#  endif DEC3100
X			cp[4] = lp->l_name[0] ;
X			cp[5] = lp->l_name[1] ;
X			return ( cp ) ;
X		}
X# endif SUNOS40
X
X	/* No reason for the wait state has been found.
X	   Return the wait channel as a hexadecimal address. */
X# ifdef SUN
X	(void)sprintf( wbuf, "x%05x", w - KERNELBASE ) ;
X# else
X	(void)sprintf( wbuf, "x%05x", w - 0x80000000 ) ;
X# endif
X	return ( wbuf ) ;
X}
X
X
X# ifdef BSD42
X/*
X** GETSOCKET - Reads a `struct socket' from the kernel virtual memory address
X** identified by `ks' into the buffer `s'.
X*/
Xgetsocket ( ks, s )
X
Xstruct socket                   *ks ;
Xstruct socket                   *s ;
X
X{
X	return ( getkmem( (long)ks, (char*)s, sizeof( struct socket ) )
X		== sizeof( struct socket ) ) ;
X}
X# endif BSD42
---END-OF-waitingfor.c---
LEN=`wc -c < waitingfor.c`
if [ $LEN !=  9904 ] ; then
    echo shar: File "waitingfor.c" was $LEN, should have been 9904 bytes
fi
exit 0