[alt.sources] SPS for SunOS4.1 and DEC 3100's - Shar 2 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:
#    filecount.c
#    findtty.c
#    flagdecode.c
#    flags.h
#    flagsetup.c
#    getcmd.c
#    getupage.c
#    globals1.c
#    globals2.c
#    hashuid.c
#    initialise.c
#    initsymbols.c
#    inittty.c
#    main.c
#    mktree.c
#    needed.c
#    openfiles.c
#
#
# This archive was generated on Mon Aug  6 17:53:37 MET DST 1990
#
#
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if [ -f 'filecount.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "filecount.c"
    exit 2
fi
echo x - filecount.c
sed -e 's/^X//' > filecount.c << '---END-OF-filecount.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)filecount.c	1.2\t7/4/90" ;
X# endif
X
X# include       "sps.h"
X
X/* FILECOUNT - Counts the # open files for the current process */
Xfilecount ( p )
X
Xstruct process         *p ;
X
X{
X	register int            i ;
X	register struct file    **f ;
X	register int            count ;
X	extern union userstate  User ;
X# ifdef SUNOS41
X	/*
X	 * The open file list is in User.u_us.u_ofile_arr
X	 * if User.u_us.u_ofile points to it; otherwise we'll have
X	 * do it the hard way by reading the list from kmem.
X	 *
X	 * Read the comment to u_ofile in /usr/include/sys/user.h.
X	 */
X
X	int			len ;
X	static char		*files = 0 ;
X	static int		 files_len = 0 ;
X	extern char		*getcore () ;
X# endif SUNOS41
X
X
X# ifdef SUNOS41
X
X#  ifndef offsetof
X#   define offsetof(type,member)	((long) &(((type *) 0)->member))
X#  endif offsetof
X
X	if ( (long) User.u_us.u_ofile ==
X	    (long) p->pr_p.p_uarea + offsetof(struct user, u_ofile_arr[0]) )
X		f = &User.u_us.u_ofile_arr[ 0 ] ;
X	else
X	{
X		len = User.u_us.u_lastfile * sizeof (struct file *) ;
X		if (len <= 0)
X			return 0;
X		if (files == 0 || len < files_len)
X		{
X			if (files != 0)
X				free (files) ;
X			files = (char *) getcore(len) ;
X			files_len = len ;
X		}
X		if ( getkmem( (long)User.u_us.u_ofile, (char *)files, len)
X		!= len )
X			return 0 ;
X		f = (struct file **)files ;
X	}
X	count = 0 ;
X	for ( i = 0 ; i < User.u_us.u_lastfile ; i++ )
X		if ( *f++ )
X			count++ ;
X	return ( count ) ;
X# else SUNOS41
X	count = 0 ;
X	for ( i = 0, f = User.u_us.u_ofile ; i < NOFILE ; i++ )
X		if ( *f++ )
X			count++ ;
X	return ( count ) ;
X# endif SUNOS41
X}
---END-OF-filecount.c---
LEN=`wc -c < filecount.c`
if [ $LEN !=  1585 ] ; then
    echo shar: File "filecount.c" was $LEN, should have been 1585 bytes
fi
if [ -f 'findtty.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "findtty.c"
    exit 2
fi
echo x - findtty.c
sed -e 's/^X//' > findtty.c << '---END-OF-findtty.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)findtty.c	1.4\t8/6/90" ;
X# endif
X
X# include       "sps.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 SUNOS41
X# include	<h/session.h>
X# endif
X
X/* FINDTTY - Attempts to determine to which tty a process is connected */
Xstruct ttyline  *findtty ( p )
X
Xregister struct process         *p ;
X
X{
X	register struct ttyline *lp ;
X	extern struct info      Info ;
X	extern struct ttyline   Notty ;
X# ifdef SUNOS41
X	struct sess		*s ;
X	extern struct sess	*find_session () ;
X# else
X	extern union userstate  User ;
X# endif SUNOS41
X
X
X# ifdef SUNOS41
X	if ( !p->pr_p.p_pgrp || !p->pr_p.p_sessp )
X		return ( &Notty ) ;
X	s = find_session( p->pr_p.p_sessp ) ;
X	if ( s == 0 || s->s_ttyp == 0 )
X		return &Notty;
X	for ( lp = Info.i_ttyline ; lp->l_name[0] ; lp++ )
X		if ( lp->l_dev == s->s_ttyd )
X			return ( lp ) ;
X	/* Kludge from outer space	++sja */
X	if ( s->s_ttyd == 256 )
X		return &Info.i_ttyline[0] ;
X	return ( &Notty ) ;
X# else
X#  ifdef ULTRIX30
X	if ( !p->pr_p.p_pgrp || !p->pr_p.p_ttyp )
X#  else
X	if ( !p->pr_p.p_pgrp || !User.u_us.u_ttyp )
X#  endif
X		return ( &Notty ) ;
X	for ( lp = Info.i_ttyline ; lp->l_name[0] ; lp++ )
X		if ( lp->l_dev == User.u_us.u_ttyd )
X			return ( lp ) ;
X	return ( &Notty ) ;
X#endif SUNOS41
X}
---END-OF-findtty.c---
LEN=`wc -c < findtty.c`
if [ $LEN !=  1324 ] ; then
    echo shar: File "findtty.c" was $LEN, should have been 1324 bytes
fi
if [ -f 'flagdecode.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "flagdecode.c"
    exit 2
fi
echo x - flagdecode.c
sed -e 's/^X//' > flagdecode.c << '---END-OF-flagdecode.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)flagdecode.c	1.1\t10/1/88" ;
X# endif
X
X# include       "sps.h"
X# include       "flags.h"
X
X/* FLAGDECODE - Looks at the argument list and sets various internal switches */
Xflagdecode ( argc, argv )
X
Xregister int                    argc ;
Xregister char                   **argv ;
X
X{
X	register char           *chp ;
X	union flaglist          *plist ;
X	union flaglist          *tlist ;
X	union flaglist          *ulist ;
X	static char             usage[] =
X	"sps - Unknown option %s\nUsage - sps [ -dcefgijkoqrsvwyABFNPSTUWZ ][ process|tty|user ] ...\n";
X	union flaglist          *getflgsp() ;
X	extern struct flags     Flg ;
X
X	plist = tlist = ulist = (union flaglist*)0 ;
X	for ( argv++ ; --argc ; argv++ )
X	{
X		chp = *argv ;
X		while ( *chp )
X			switch ( *chp++ )
X			{
X				case '-' :
X					/* Separation character */
X					continue ;
X				case 'c' :
X				case 'C' :
X					/* Print stored command, not args */
X					Flg.flg_c = 1 ;
X					continue ;
X				case 'd' :
X				case 'D' :
X					/* List disc orientated information */
X					Flg.flg_d = 1 ;
X					Flg.flg_v = 0 ;
X					continue ;
X				case 'e' :
X				case 'E' :
X					/* List environment strings */
X					Flg.flg_e = 1 ;
X					continue ;
X				case 'f' :
X					/* List the father's process id */
X					Flg.flg_f = 1 ;
X					continue ;
X				case 'g' :
X				case 'G' :
X					/* List the process group id */
X					Flg.flg_g = 1 ;
X					continue ;
X				case 'i' :
X				case 'I' :
X					/* Initialise (super-user only) */
X					Flg.flg_i = 1 ;
X					continue ;
X				case 'j' :
X				case 'J' :
X					/* The next argument specifies the
X					   name of the information file */
X					if ( argc <= 1 )
X						prexit(
X	      "sps - Name of an information file expected after `-j' flag\n" ) ;
X					argc-- ;
X					Flg.flg_j = *++argv ;
X					continue ;
X				case 'k' :
X				case 'K' :
X					/* Use a disc file such as /vmcore
X					   rather than /dev/{k}mem for
X					   accessing kernel data. The next
X					   argument specifies the file name. */
X					if ( argc <= 1 )
X						prexit(
X	       "sps - Name of a memory dump file expected after `-k' flag\n" ) ;
X					argc-- ;
X					Flg.flg_k = *++argv ;
X					Flg.flg_o = 1 ;
X					continue ;
X				case 'l' :
X				case 'v' :
X				case 'L' :
X				case 'V' :
X					/* Verbose output */
X					Flg.flg_d = 0 ;
X					Flg.flg_v = 1 ;
X					continue ;
X				case 'o' :
X				case 'O' :
X					/* Avoid looking at the swap device */
X					Flg.flg_o = 1 ;
X					continue ;
X				case 'q' :
X				case 'Q' :
X					/* Show only the user time, not the
X					   user + system times together. */
X					Flg.flg_q = 1 ;
X					continue ;
X				case 'r' :
X				case 'R' :
X					/* Repeat output every n seconds.
X					   The next argument specifies n which
X					   defaults to 5 if omitted. */
X					Flg.flg_r = 1 ;
X					if ( argc > 1 )
X					{
X						if ( **++argv >= '0'
X						&& **argv <= '9' )
X						{
X							argc-- ;
X							Flg.flg_rdelay
X							       = atoi( *argv ) ;
X							continue ;
X						}
X						argv-- ;
X					}
X					Flg.flg_rdelay = 0 ;
X					continue ;
X				case 's' :
X					/* Next argument specifies a symbol
X					   file rather than the default
X					   /vmunix. */
X					if ( argc <= 1 )
X						prexit(
X		    "sps - Name of a symbol file expected after `-s' flag\n" ) ;
X					argc-- ;
X					Flg.flg_s = *++argv ;
X					continue ;
X				case 'w' :
X					/* Wide output, exceeding 79 columns */
X					Flg.flg_w = 1 ;
X					continue ;
X				case 'y' :
X				case 'Y' :
X					/* List current tty information */
X					Flg.flg_y = 1 ;
X					continue ;
X				case 'a' :
X				case 'A' :
X					/* List all processes */
X					Flg.flg_AZ = 1 ;
X					Flg.flg_A = 1 ;
X					continue ;
X				case 'b' :
X				case 'B' :
X					/* List only busy processes */
X					Flg.flg_AZ = 1 ;
X					Flg.flg_B = 1 ;
X					continue ;
X				case 'F' :
X					/* List only foreground processes */
X					Flg.flg_AZ = 1 ;
X					Flg.flg_F = 1 ;
X					continue ;
X				case 'n' :
X				case 'N' :
X					/* No processes, just the summary line*/
X					Flg.flg_AZ = 1 ;
X					Flg.flg_N = 1 ;
X					continue ;
X				case 'p' :
X				case 'P' :
X					/* List only the given process ids */
X					Flg.flg_AZ = 1 ;
X					Flg.flg_P = 1 ;
X					if ( !plist )
X					   plist=Flg.flg_Plist=getflgsp( argc );
X					while ( argc > 1 )
X					{
X						if ( **++argv == '-' )
X						{
X							--argv ;
X							break ;
X						}
X						--argc ;
X						plist->f_chp = *argv ;
X						(++plist)->f_chp = (char*)0 ;
X					}
X					continue ;
X				case 'S' :
X					/* List only stopped processes */
X					Flg.flg_AZ = 1 ;
X					Flg.flg_S = 1 ;
X					continue ;
X				case 't' :
X				case 'T' :
X					/* List only processes attached to the
X					   specified terminals */
X					Flg.flg_AZ = 1 ;
X					Flg.flg_T = 1 ;
X					if ( !tlist )
X					   tlist=Flg.flg_Tlist=getflgsp( argc );
X					while ( argc > 1 )
X					{
X						if ( **++argv == '-' )
X						{
X							--argv ;
X							break ;
X						}
X						--argc ;
X						tlist->f_chp = *argv ;
X						(++tlist)->f_chp = (char*)0 ;
X					}
X					continue ;
X				case 'u' :
X				case 'U' :
X					/* List only processes belonging to the
X					   specified users */
X					Flg.flg_AZ = 1 ;
X					Flg.flg_U = 1 ;
X					if ( !ulist )
X					   ulist=Flg.flg_Ulist=getflgsp( argc );
X					while ( argc > 1 )
X					{
X						if ( **++argv == '-' )
X						{
X							--argv ;
X							break ;
X						}
X						--argc ;
X						ulist->f_chp = *argv ;
X						(++ulist)->f_chp = (char*)0 ;
X					}
X					continue ;
X				case 'W' :
X					/* List only waiting processes */
X					Flg.flg_AZ = 1 ;
X					Flg.flg_W = 1 ;
X					continue ;
X				case 'z' :
X				case 'Z' :
X					/* List only zombie processes */
X					Flg.flg_AZ = 1 ;
X					Flg.flg_Z = 1 ;
X					continue ;
X				default :
X					prexit( usage, *argv ) ;
X					/* NOTREACHED */
X			}
X	}
X}
---END-OF-flagdecode.c---
LEN=`wc -c < flagdecode.c`
if [ $LEN !=  5627 ] ; then
    echo shar: File "flagdecode.c" was $LEN, should have been 5627 bytes
fi
if [ -f 'flags.h' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "flags.h"
    exit 2
fi
echo x - flags.h
sed -e 's/^X//' > flags.h << '---END-OF-flags.h---'
X# ifndef lint
Xstatic char FlagsHId[] =  "@(#)flags.h	1.1\t10/1/88" ;
X# endif
X
X/* Structure holding information specified in the option list ... */
Xunion flaglist
X{
X	char                    *f_chp ;        /* Option specified as string */
X	int                     f_uid ;         /* Numerical user id */
X	int                     f_pid ;         /* Numerical process id */
X	struct ttyline          *f_ttyline ;    /* Specified tty */
X} ;
X
X/* Structure holding global information specifed by arg list options ... */
Xstruct flags
X{
X	int                     flg_c:1 ;       /* print command from upage */
X	int                     flg_d:1 ;       /* disc orientated output */
X	int                     flg_e:1 ;       /* print environment string */
X	int                     flg_f:1 ;       /* print process father # */
X	int                     flg_g:1 ;       /* print process group # */
X	int                     flg_i:1 ;       /* initialise sps */
X	char                    *flg_j ;        /* Use this as the info file */
X	char                    *flg_k ;        /* Use this as the {k}mem file*/
X	int                     flg_o:1 ;       /* avoid the swap device */
X	int                     flg_q:1 ;       /* show user time only */
X	int                     flg_r:1 ;       /* repeat output */
X	unsigned                flg_rdelay ;    /* ... with this much delay */
X	char                    *flg_s ;        /* Use this as the symbol file*/
X	int                     flg_v:1 ;       /* print verbose listing */
X	int                     flg_w:1 ;       /* print wide output */
X	int                     flg_y:1 ;       /* print tty information */
X	int                     flg_A:1 ;       /* print all processes */
X	int                     flg_B:1 ;       /* print busy processes */
X	int                     flg_F:1 ;       /* print foreground processes */
X	int                     flg_N:1 ;       /* print no processes */
X	int                     flg_P:1 ;       /* print specified process #'s*/
X	int                     flg_S:1 ;       /* print stopped processes */
X	int                     flg_T:1 ;       /* print procs for given ttys */
X	int                     flg_U:1 ;       /* print procs for given users*/
X	int                     flg_W:1 ;       /* print waiting processes */
X	int                     flg_Z:1 ;       /* print zombie processes */
X	int                     flg_AZ:1 ;      /* One of A to Z was specified*/
X	union flaglist          *flg_Plist ;    /* List of specified processes*/
X	union flaglist          *flg_Tlist ;    /* List of specified ttys */
X	union flaglist          *flg_Ulist ;    /* List of specified users */
X} ;
---END-OF-flags.h---
LEN=`wc -c < flags.h`
if [ $LEN !=  2638 ] ; then
    echo shar: File "flags.h" was $LEN, should have been 2638 bytes
fi
if [ -f 'flagsetup.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "flagsetup.c"
    exit 2
fi
echo x - flagsetup.c
sed -e 's/^X//' > flagsetup.c << '---END-OF-flagsetup.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)flagsetup.c	1.1\t10/1/88" ;
X# endif
X
X# include       "sps.h"
X# include       "flags.h"
X# include       <h/ioctl.h>
X# ifdef SUNOS40
X# include       <h/stream.h>
X# endif
X# include       <h/tty.h>
X
X/*
X** FLAGSETUP - Replaces any users or processes specified by flagdecode()
X** with numerical equivalents. The lists are terminated by negative values.
X** or null pointers. Ttystatus() must have been previously called to
X** initialise the Info structure with chaos tty values.
X*/
Xflagsetup ()
X{
X	register union flaglist *fp ;
X	register char           *chp ;
X	register int            i ;
X	register struct ttyline *lp ;
X	int                     found ;
X	extern struct flags     Flg ;
X	extern struct info      Info ;
X
X	/* Look for specified users */
X	if ( Flg.flg_U )                
X	{
X		if ( !Flg.flg_Ulist->f_chp )
X			prexit( "sps - User name was expected after -u flag\n");
X		for ( fp = Flg.flg_Ulist ; chp = fp->f_chp ; fp++ )
X		{
X			found = 0 ;
X			for ( i = 0 ; i < MAXUSERS ; i++ )
X				if ( !strncmp( chp, Info.i_hnames[i].h_uname,
X					UNAMELEN ) )
X				{
X					fp->f_uid = Info.i_hnames[i].h_uid ;
X					found = 1 ;
X					break ;
X				}
X			if ( !found )
X				prexit( "sps - Unknown user: %s\n", chp ) ;
X		}
X		fp->f_uid = -1 ;
X	}
X	/* Look for specified process ids */
X	if ( Flg.flg_P )                
X	{
X		if ( !Flg.flg_Plist->f_chp )
X			prexit(
X			     "sps - Process id was expected after -p flag\n" ) ;
X		for ( fp = Flg.flg_Plist ; chp = fp->f_chp ; fp++ )
X		{
X			if ( chp[0] < '0' || chp[0] > '9' )
X				prexit( "sps - Bad process id: %s\n", chp ) ;
X			fp->f_pid = atoi( chp ) ;
X		}
X		fp->f_pid = -1 ;
X	}
X	/* Look for specified ttys */
X	if ( !Flg.flg_T )               
X		return ;
X	if ( !Flg.flg_Tlist->f_chp )
X		prexit( "sps - Tty name was expected after -t flag\n" ) ;
X	for ( fp = Flg.flg_Tlist ; chp = fp->f_chp ; fp++ )
X	{       /* Under VMUNIX, all ttys have two character names.
X		   Thus, a flag of the form `t 8' should be expanded to
X		   become `t 08'. */
X		if ( !chp[1] )
X			chp[1] = chp[0], chp[0] = '0' ;
X		found = 0 ;
X		for ( lp = Info.i_ttyline ; lp->l_name[0] ; lp++ )
X			if ( !strncmp( chp, lp->l_name, 2 ) )
X			{
X				fp->f_ttyline = lp ;
X				found = 1 ;
X				break ;
X			}
X		if ( !found )
X			prexit( "sps - Unknown tty name: %.2s\n", chp ) ;
X	}
X	fp->f_ttyline = (struct ttyline*)0 ;
X}
---END-OF-flagsetup.c---
LEN=`wc -c < flagsetup.c`
if [ $LEN !=  2342 ] ; then
    echo shar: File "flagsetup.c" was $LEN, should have been 2342 bytes
fi
if [ -f 'getcmd.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "getcmd.c"
    exit 2
fi
echo x - getcmd.c
sed -e 's/^X//' > getcmd.c << '---END-OF-getcmd.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)getcmd.c	1.7\t8/6/90" ;
X# endif
X
X# include       "sps.h"
X# include       "flags.h"
X# ifdef KVM
X#  include      <kvm.h>
X#  include      <ctype.h>
X# else
X#  include      <h/vm.h>
X#  ifdef BSD42
X#   include	<machine/pte.h>
X#  else BSD42
X#   include      <h/pte.h>
X#  endif BSD42
X# endif KVM
X
X/*
X** GETCMD - Returns a character string read from a process' upage.
X** This character string should represent the arguments to the current process.
X*/
Xchar    *getcmd ( p )
X
Xregister struct process         *p ;
X
X{
X# ifdef KVM
X	char                    **ap ;
X	char                    *cp ;
X	char                    *sp ;
X	char                    **argv ;
X	char                    **env ;
X	extern kvm_t            *Flkvm ;
X# else
X	register int            *ip ;
X	register char           *cp ;
X	register char           *cp0 ;
X	struct dblock           db ;
X	struct pte              ptetbl[ UPAGES + CLSIZE ] ;
X	extern int              Flmem, Flswap ;
X# endif
X	unsigned                nbad ;
X	union
X	{
X		char            a_argc[ CLSIZE * NBPG ] ;
X		int             a_argi[ CLSIZE * NBPG / sizeof( int ) ] ;
X	} argbuf ;
X	extern struct flags     Flg ;
X	extern union userstate  User ;
X	char                    *strcat(), *strncpy(), *strsave() ;
X
X	p->pr_csaved = 0 ;
X	p->pr_upag = 0 ;
X	if ( p->pr_p.p_stat == SZOMB )
X		return ( "** Exit **" ) ;
X	if ( !(p->pr_p.p_flag & SLOAD) && Flg.flg_o )
X		return ( "** Swapped out **" ) ;
X	/* Find the process' upage */
X# ifdef KVM
X	if ( !getupage( p ) )           
X# else
X	if ( !getupage( p, ptetbl ) )           
X# endif
X		return ( "** No upage **" ) ;
X	p->pr_upag = 1 ;
X	/* Is this a system process ? */
X	if ( p->pr_p.p_flag & SSYS )            
X		switch ( p->pr_p.p_pid )
X		{
X			case 0 :
X				return ( "Unix Swapper" ) ;
X			case 2 :
X				return ( "Unix Pager" ) ;
X# ifdef SUNOS40
X			case 3 :
X			case 4 :
X				return ( "Unix Idle" ) ;
X# endif
X			default :
X				break ;
X		}
X# ifdef DEC3100
X	/* Reading the command arguments doesn't work on the DEC 3100 so
X	   we resort to this kludge until one day it does. */
X	if ( 1 )
X# else DEC3100
X	if ( Flg.flg_c )
X# endif DEC3100
X	{
X		p->pr_csaved = 1 ;
X		(void)strncpy( argbuf.a_argc, User.u_us.u_comm,
X			sizeof( User.u_us.u_comm ) ) ;
X		argbuf.a_argc[ sizeof ( User.u_us.u_comm ) ] = '\0' ;
X		return ( strsave( argbuf.a_argc ) ) ;
X	}
X# ifdef KVM
X	if ( kvm_getcmd( Flkvm, &p->pr_p, &User.u_us, &argv,
X		Flg.flg_e ? &env : (char ***)NULL ) < 0 || argv == NULL )
X	        goto getsysargs ;
X	p->pr_csaved = 1 ;
X	sp = argbuf.a_argc ;
X	nbad = 0 ;
X	ap = argv ;
X	do {
X		/* Copy one string from argv or env */
X		for ( cp = *ap++; *cp; )
X			if ( isprint( *cp ) )
X				*sp++ = *cp++ ;
X			else
X			{
X				/* Replace control characters with ?'s */
X				if ( ++nbad > 5 )
X				{
X  					*sp++ = ' ' ;
X  					break ;
X  				}
X				*sp++ = '?' ;
X				cp++ ;
X			}
X		*sp++ = ' ' ;
X		/* Check if at end of argv and user wants to see env */
X		if ( *ap == 0 && Flg.flg_e && argv != 0 )
X		{
X			free( (char *) argv ) ;
X			argv = NULL ;
X			ap = env ;
X			if ( ap == NULL )
X				break ;
X		}
X	} while ( *ap ) ;
X 	if ( Flg.flg_e )
X                free( (char*)env ) ;
X	while ( *--sp == ' ' )
X		*sp = '\0' ;
X	return ( strsave( argbuf.a_argc ) ) ;
X# else
X	/* Fix by Alexander Dupuy <dupuy@amsterdam.columbia.edu> */
X	/* Check for lack of stack, jack! (Sun 3.0 biod's) */
X	if (User.u_us.u_ssize == 0)
X		goto getsysargs ;
X	/* Look at the top of the upage to locate the command arguments.
X	   The page is loaded if the process itself is loaded and the pte
X	   contains is marked as valid. */
X	if ( (p->pr_p.p_flag & SLOAD)
X	&& !ptetbl[0].pg_fod && ptetbl[0].pg_pfnum )
X	{       /* If the page is loaded, read the arguments from
X		   physical memory. */
X		memseek( Flmem, (long)ctob( ptetbl[0].pg_pfnum ) ) ;
X		if ( read( Flmem, argbuf.a_argc, CLSIZE*NBPG ) != CLSIZE*NBPG )
X			return ( "** Memory read error **" ) ;
X	}
X	else                            
X	{       /* Otherwise the page is on the swap device */
X		vstodb( 0, ctod( CLSIZE ), &User.u_us.u_smap, &db, 1 ) ;
X#  ifdef BSD42
X		swseek( (long)dtob( db.db_base ) ) ;
X#  else
X		swseek( (long)ctob( db.db_base ) ) ;
X#  endif
X		if ( Flg.flg_o )
X			return ( "** Swapped page **" ) ;
X		if ( read( Flswap, argbuf.a_argc, CLSIZE*NBPG ) != CLSIZE*NBPG )
X			return ( "** Swap device read error **" ) ;
X	}
X	/* Look down until the end of command arguments is found. */
X	ip = &argbuf.a_argi[ CLSIZE*NBPG / sizeof( int ) ] ;
X	ip -= 2 ;
X	while ( *--ip )
X		if ( ip == &argbuf.a_argi[0] )
X			goto getsysargs ;
X	p->pr_csaved = 1 ;
X	/* Process the command arguments, looking for nulls and unprintable
X	   characters. */
X	cp0 = (char*)(ip + 1) ;
X	if ( !*cp0 )                    
X		cp0++ ;                 
X	if ( *cp0 )
X	{
X		nbad = 0 ;                      
X		for ( cp = cp0 ; cp < &argbuf.a_argc[ CLSIZE*NBPG ] ; cp++ )
X		{
X			*cp &= 0177 ;
X			if ( !*cp )             
X			{       /* Replace nulls with spaces */
X				*cp = ' ' ;
X				continue ;
X			}
X			if ( *cp < ' ' || *cp == 0177 )
X			{       /* Replace control characters with ?'s */
X				if ( ++nbad > 5 )
X				{
X					*cp++ = ' ' ;
X					break ;
X				}
X				*cp = '?' ;
X				continue ;
X			}
X			if ( !Flg.flg_e && *cp == '=' )
X			{       /* Break on an `=' if we are not interested
X				   in the environment strings. */
X				*cp = '\0' ;
X				while ( cp > cp0 && *--cp != ' ' )
X					*cp = '\0' ;
X				break ;
X			}
X		}
X		while ( *--cp == ' ' )
X			*cp = '\0' ;
X		return ( strsave( cp0 ) ) ;
X	}
X# endif KVM
Xgetsysargs :
X	/* If the command arguments cannot be accessed from the user's memory
X	   space, get the command name from the system's idea of what the
X	   name should be. */
X	p->pr_csaved = 1 ;
X	argbuf.a_argc[0] = '(' ;
X	(void)strncpy( &argbuf.a_argc[1], User.u_us.u_comm,
X		sizeof( User.u_us.u_comm ) ) ;
X	argbuf.a_argc[ sizeof ( User.u_us.u_comm ) + 1 ] = '\0' ;
X	(void)strcat( &argbuf.a_argc[0], ")" ) ;
X	return ( strsave( argbuf.a_argc ) ) ;
X}
X
X# ifndef KVM
X/*
X** VSTODB - Given a base/size pair in virtual swap area,
X** return a physical base/size pair which is the
X** (largest) initial, physically contiguous block.
X/* This code is stolen from the kernel file /sys/sys/vm_drum.c.
X*/
Xvstodb ( vsbase, vssize, dmp, dbp, rev )
X
Xregister int                    vsbase ;
Xregister int                    vssize;
Xstruct dmap                     *dmp ;
Xregister struct dblock          *dbp ;
Xint                             rev ;
X
X{
X	register int            blk ;
X	register swblk_t        *ip ;
X# ifdef BSD42
X	extern struct info      Info ;
X# endif
X
X# ifdef BSD42
X	blk = Info.i_dmmin ;
X# else
X	blk = DMMIN ;
X# endif
X	ip = dmp->dm_map ;
X	while ( vsbase >= blk )
X	{
X		vsbase -= blk ;
X# ifdef BSD42
X		if ( blk < Info.i_dmmax )
X# else
X		if ( blk < DMMAX )
X# endif
X			blk *= 2 ;
X		ip++ ;
X	}
X	dbp->db_size = vssize < blk - vsbase ? vssize : blk - vsbase ;
X	dbp->db_base = *ip + (rev ? blk - (vsbase + dbp->db_size) : vsbase);
X}
X# endif
---END-OF-getcmd.c---
LEN=`wc -c < getcmd.c`
if [ $LEN !=  6872 ] ; then
    echo shar: File "getcmd.c" was $LEN, should have been 6872 bytes
fi
if [ -f 'getupage.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "getupage.c"
    exit 2
fi
echo x - getupage.c
sed -e 's/^X//' > getupage.c << '---END-OF-getupage.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)getupage.c	1.3\t8/2/90" ;
X# endif
X
X# include       "sps.h"
X# ifdef KVM
X#  include      <kvm.h>
X# else
X#  include      <h/vm.h>
X#  ifdef BSD42
X#  include	<machine/pte.h>
X#  else
X#  include      <h/pte.h>
X#  endif
X# endif
X# include       <stdio.h>
X
X/*
X** GETUPAGE - Reads the upage for the specified process as well as sufficient
X** page tables entries for reading the command arguments. The pte's are read
X** into the argument `ptetbl'. The upage is read into the external variable
X** `User'. This procedure returns 1 if the upage was successfully read.
X*/
X
X# ifndef KVM
X
X# define        usrpt           (Info.i_usrpt)
X
Xgetupage ( p, ptetbl )
X
Xregister struct process         *p ;
Xregister struct pte             *ptetbl ;
X
X{
X	register int            i ;
X	register int            ncl ;
X	struct pte              pte ;
X	extern struct info      Info ;
X	extern union userstate  User ;
X	extern int              Flmem, Flkmem, Flswap ;
X
X	/* If the process is not loaded, look for the upage on the swap device*/
X	if ( !(p->pr_p.p_flag & SLOAD) )
X	{                               
X# ifdef BSD42
X		swseek( (long)dtob( p->pr_p.p_swaddr ) ) ;
X# else BSD42
X		swseek( (long)ctob( p->pr_p.p_swaddr ) ) ;
X# endif BSD42
X# ifdef SUN
X		if ( read( Flswap, (char*)&User.u_us, sizeof( union userstate ))
X		!= sizeof( union userstate ) )
X# else SUN
X		if ( read( Flswap, (char*)&User.u_us, sizeof( struct user ) )
X		!= sizeof( struct user ) )
X# endif SUN
X		{
X			fprintf( stderr,
X				"sps - Can't read upage of process %d\n",
X			    p->pr_p.p_pid ) ;
X			return ( 0 ) ;
X		}
X		return ( 1 ) ;          
X	}                               
X	/* The process is loaded. Locate the process pte's by reading
X	   the pte of their base address from system virtual address space. */
X# ifdef DEC3100
X	/* This method of accessing the upage suffices on the DEC Station
X	   but only provides sufficient pte's to read the upage, leaving the
X	   command arguments inaccessible. */
X	memseek( Flkmem, (long)p->pr_p.p_addr ) ;
X	if ( read( Flkmem, (char*)ptetbl, (UPAGES+CLSIZE)*sizeof( struct pte ) )
X	!= (UPAGES+CLSIZE)*sizeof( struct pte ) )
X	{
X		fprintf( stderr, "sps - Can't read page table of process %d\n",
X			p->pr_p.p_pid ) ;
X		return ( 0 ) ;
X	}
X# else DEC3100
X	memseek( Flkmem, (long)&Info.i_usrptmap[ btokmx(p->pr_p.p_p0br)
X		+ p->pr_p.p_szpt-1 ] ) ;
X	if ( read( Flkmem, (char*)&pte, sizeof( struct pte ) )
X	!= sizeof( struct pte ) )
X	{
X		fprintf( stderr,
X		      "sps - Can't read indir pte for upage of process %d\n",
X		    p->pr_p.p_pid ) ;
X		return ( 0 ) ;
X	}                               
X	/* Now read the process' pte's from physical memory. We need to access
X	   sufficient pte's for the upage and for the command arguments. */
X	memseek( Flmem, (long)ctob( pte.pg_pfnum+1 )
X		- (UPAGES+CLSIZE)*sizeof( struct pte ) ) ;
X	if ( read( Flmem, (char*)ptetbl, (UPAGES+CLSIZE)*sizeof( struct pte ) )
X	!= (UPAGES+CLSIZE)*sizeof( struct pte ) )
X	{
X		fprintf( stderr, "sps - Can't read page table of process %d\n",
X			p->pr_p.p_pid ) ;
X		return ( 0 ) ;
X	}
X# endif DEC3100
X	/* Now we can read the pages belonging to the upage.
X	   Here we read in an entire click at one go. */
X	ncl = (sizeof( struct user ) + NBPG*CLSIZE - 1) / (NBPG*CLSIZE) ;
X	while ( --ncl >= 0 )            
X	{                               
X		i = ncl * CLSIZE ;
X# ifdef DEC3100
X		memseek( Flmem, (long)ctob( ptetbl[ i ].pg_pfnum ) ) ;
X# else DEC3100
X		memseek( Flmem, (long)ctob( ptetbl[ CLSIZE+i ].pg_pfnum ) ) ;
X# endif DEC3100
X		if ( read( Flmem, User.u_pg[i], CLSIZE*NBPG ) != CLSIZE*NBPG )
X		{
X			fprintf( stderr,
X				"sps - Can't read page 0x%x of process %d\n",
X				ptetbl[ CLSIZE+i ].pg_pfnum, p->pr_p.p_pid ) ;
X			return ( 0 ) ;
X		}
X	}
X	return ( 1 ) ;
X}
X
X# else KVM
X
Xgetupage ( p )
X
Xregister struct process         *p ;
X
X{
X        struct user            *upage ;
X	extern union userstate  User ;
X	extern kvm_t           *Flkvm ;
X
X	if (upage = kvm_getu( Flkvm, &p->pr_p ) )
X	{
X	        bcopy( (char *)upage, User.u_pg[0], sizeof( struct user ) ) ;
X		return ( 1 ) ;
X	}
X	fprintf( stderr, "sps - Can't read upage of process %d\n",
X	    p->pr_p.p_pid ) ;
X	return ( 0 ) ;
X}
X
X# endif KVM
---END-OF-getupage.c---
LEN=`wc -c < getupage.c`
if [ $LEN !=  4161 ] ; then
    echo shar: File "getupage.c" was $LEN, should have been 4161 bytes
fi
if [ -f 'globals1.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "globals1.c"
    exit 2
fi
echo x - globals1.c
sed -e 's/^X//' > globals1.c << '---END-OF-globals1.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)globals1.c	1.1\t10/1/88" ;
X# endif
X
X# include       "sps.h"
X# include       "flags.h"
X# ifdef KVM
X# include       <kvm.h>
X# endif
X
X/* Read/Write Variables global to the code of sps */
X
Xstruct info                     Info ;          /* Information structure */
X
Xstruct flags                    Flg ;           /* Flag options */
X
Xstruct summary                  Summary ;       /* Summary of processes */
X
Xunion  userstate                User ;          /* Upage of one process */
X
X# ifdef KVM
Xkvm_t                          *Flkvm ;         /* Kernel VM descriptor */
X# else
Xint                             Flmem, Flkmem, Flswap ; /* File descriptors */
X# endif
X
Xunsigned                        Termwidth ;     /* Width of output device */
X
Xshort                           Lastpgrp ;      /* Last process pgrp printed */
X
Xshort                           Lastuid ;       /* Last process uid printed */
---END-OF-globals1.c---
LEN=`wc -c < globals1.c`
if [ $LEN !=  945 ] ; then
    echo shar: File "globals1.c" was $LEN, should have been 945 bytes
fi
if [ -f 'globals2.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "globals2.c"
    exit 2
fi
echo x - globals2.c
sed -e 's/^X//' > globals2.c << '---END-OF-globals2.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)globals2.c	1.2\t7/4/90" ;
X# endif
X
X# include       "sps.h"
X
X/* Read Only variables, global to the code of sps ... */
X
X/* Null ttyline device ... */
Xstruct ttyline                  Notty = { "  " } ;
X
X/*
X** The symbol table. For each address read from the kernel during
X** initialisation, this table shows the following:
X**      i.   the name of that symbol within the kernel ;
X**      ii.  whether an extra indirection is needed through the kernel,
X**           i.e. whether the value of that symbol should be obtained
X**           rather than its address.
X**      iii. where the obtained value/address is placed in the Info structure ;
X**      iv.  whether the obtained value is associated with a reason for
X**           a process wait state.
X*/
X/* The order of entries in this table is unimportant. */
X
Xextern struct info              Info ;
X
Xstruct symbol   Symbollist[] =
X{       
X	/* Kernel addresses required in order to access process,
X	   tty and upage information. All these addresses should be
X	   located in the symbol file during initialisation. */
X	{ "_proc",      1,  (caddr_t*)&Info.i_proc0,    (char*)0        },
X	{ "_nproc",     1,  (caddr_t*)&Info.i_nproc,    (char*)0        },
X# ifdef ULTRIX20
X	{ "_gnode",     1,  (caddr_t*)&Info.i_inode0,   (char*)0        },
X	{ "_ngnode",    1,  (caddr_t*)&Info.i_ninode,   (char*)0        },
X# else
X#  ifndef SUNOS41
X	{ "_inode",     1,  (caddr_t*)&Info.i_inode0,   (char*)0        },
X#  endif SUNOS41
X	{ "_ninode",    1,  (caddr_t*)&Info.i_ninode,   (char*)0        },
X# endif ULTRIX20
X
X# ifndef SUNOS40
X	{ "_text",      1,  (caddr_t*)&Info.i_text0,    (char*)0        },
X	{ "_ntext",     1,  (caddr_t*)&Info.i_ntext,    (char*)0        },
X	{ "_swbuf",     1,  (caddr_t*)&Info.i_swbuf0,   (char*)0        },
X	{ "_nswbuf",    1,  (caddr_t*)&Info.i_nswbuf,   (char*)0        },
X	{ "_buf",       1,  (caddr_t*)&Info.i_buf0,     (char*)0        },
X	{ "_nbuf",      1,  (caddr_t*)&Info.i_nbuf,     (char*)0        },
X	{ "_ecmx",      1,  (caddr_t*)&Info.i_ecmx,     (char*)0        },
X	{ "_Usrptmap",  0,  (caddr_t*)&Info.i_usrptmap, (char*)0        },
X	{ "_usrpt",     0,  (caddr_t*)&Info.i_usrpt,    (char*)0        },
X	{ "_dmmin",     1,  (caddr_t*)&Info.i_dmmin,    (char*)0        },
X	{ "_dmmax",     1,  (caddr_t*)&Info.i_dmmax,    (char*)0        },
X# endif SUNOS40
X
X	{ "_cdevsw",    0,  (caddr_t*)&Info.i_cdevsw,   (char*)0        },
X# ifdef BSD42
X#  ifdef NFS
X#   ifndef NOQUOTA
X	{ "_dquot",     1,  (caddr_t*)&Info.i_quota0,   (char*)0        },
X	{ "_ndquot",    1,  (caddr_t*)&Info.i_nquota,   (char*)0        },
X#   endif NOQUOTA
X#  else NFS
X	{ "_quota",     1,  (caddr_t*)&Info.i_quota0,   (char*)0        },
X	{ "_nquota",    1,  (caddr_t*)&Info.i_nquota,   (char*)0        },
X#  endif NFS
X	{ "_mbutl",     0,  (caddr_t*)&Info.i_mbutl,    (char*)0        },
X# else BSD42
X	{ "_hz",        1,  (caddr_t*)&Info.i_hz,       (char*)0        },
X# endif BSD42
X
X# ifdef CHAOS
X	{ "_Chconntab", 0,  &Info.i_Chconntab,          (char*)0        },
X# endif CHAOS
X
X# ifdef SUNOS40
X	{ "_maxmem",	1,  (caddr_t*)&Info.i_ecmx,	(char*)0	},
X	{ "_segvn_ops",	0,  (caddr_t*)&Info.i_segvn_ops,(char*)0	},
X	{ "_pty_softc",	0,  (caddr_t*)&Info.i_ptybase,	(char*)0	},
X	{ "_npty",	1,  (caddr_t*)&Info.i_npty,	(char*)0	},
X#  ifdef SUNOS41
X	{ "_strst",	0,  (caddr_t*)&Info.i_strst,	(char*)0	},
X	{ "_allstream",	1,  (caddr_t*)&Info.i_allstream, (char*)0	},
X#  else SUNOS41
X	{ "_streams",	0,  (caddr_t*)&Info.i_streams,	(char*)0	},
X	{ "_streamsNSTREAMS", 1, (caddr_t*)&Info.i_streamsNSTREAMS ,(char*)0 },
X#  endif SUNOS41
X	{ "_Sysbase",	1,  (caddr_t*)&Info.i_sysbase,	(char*)0	},
X# endif SUNOS40
X
X	/* Kernel addresses associated with process wait states.
X	   It is not important if some of these addresses are unresolved
X	   at initialisation. */
X# ifndef SUN
X	{ "_fltab",     0,  &Info.i_waitstate[0],       "floppy"        },
X	{ "_tu",        0,  &Info.i_waitstate[1],       "tu58"          },
X	{ "_lp_softc",  0,  &Info.i_waitstate[3],       "printr"        },
X# endif SUN
X	{ "_bfreelist", 0,  &Info.i_waitstate[2],       "buffer"        },
X	{ "_lbolt",     0,  &Info.i_waitstate[4],       "lbolt"         },
X	{ "_runin",     0,  &Info.i_waitstate[5],       "runin"         },
X	{ "_runout",    0,  &Info.i_waitstate[6],       "runout"        },
X	{ "_ipc",       0,  &Info.i_waitstate[7],       "ptrace"        },
X# ifdef SUNOS41
X	{ "_uunix",     0,  &Info.i_waitstate[8],       "pause"         },
X# else SUNOS41
X	{ "_u",         0,  &Info.i_waitstate[8],       "pause"         },
X# endif SUNOS41
X	{ "_freemem",   0,  &Info.i_waitstate[9],       "freemm"        },
X	{ "_kernelmap", 0,  &Info.i_waitstate[10],      "kermap"        },
X	{ "_cwaiting",  0,  &Info.i_waitstate[11],      "cwait"         },
X# ifdef BSD42
X	{ "_selwait",   0,  &Info.i_waitstate[12],      "select"        },
X# endif BSD42
X# ifdef CHAOS
X	{ "_Chrfclist", 0,  &Info.i_waitstate[13],      "chrfc"         },
X# endif CHAOS
X# ifndef SUN
X	{ "_rhpbuf",    0,  &Info.i_waitstate[14],      "rhpbuf"        },
X	{ "_rhtbuf",    0,  &Info.i_waitstate[15],      "rhtbuf"        },
X	{ "_ridcbuf",   0,  &Info.i_waitstate[16],      "ridcbf"        },
X	{ "_rikbuf",    0,  &Info.i_waitstate[17],      "rikbuf"        },
X	{ "_rmtbuf",    0,  &Info.i_waitstate[18],      "rmtbuf"        },
X	{ "_rrkbuf",    0,  &Info.i_waitstate[19],      "rrkbuf"        },
X	{ "_rrlbuf",    0,  &Info.i_waitstate[20],      "rrlbuf"        },
X	{ "_rrxbuf",    0,  &Info.i_waitstate[21],      "rrxbuf"        },
X	{ "_rswbuf",    0,  &Info.i_waitstate[22],      "rswbuf"        },
X	{ "_rtmbuf",    0,  &Info.i_waitstate[23],      "rtmbuf"        },
X	{ "_rtsbuf",    0,  &Info.i_waitstate[24],      "rtsbuf"        },
X	{ "_rudbuf",    0,  &Info.i_waitstate[25],      "rudbuf"        },
X	{ "_rupbuf",    0,  &Info.i_waitstate[26],      "rupbuf"        },
X	{ "_rutbuf",    0,  &Info.i_waitstate[27],      "rutbuf"        },
X	{ "_rvabuf",    0,  &Info.i_waitstate[28],      "rvabuf"        },
X	{ "_rvpbuf",    0,  &Info.i_waitstate[29],      "rvpbuf"        },
X	{ "_chtbuf",    0,  &Info.i_waitstate[30],      "chtbuf"        },
X	{ "_cmtbuf",    0,  &Info.i_waitstate[31],      "cmtbuf"        },
X	{ "_ctmbuf",    0,  &Info.i_waitstate[32],      "ctmbuf"        },
X	{ "_ctsbuf",    0,  &Info.i_waitstate[33],      "ctsbuf"        },
X	{ "_cutbuf",    0,  &Info.i_waitstate[34],      "cutbuf"        },
X#  ifdef NFS
X	{ "_async_bufhead", 0,  &Info.i_waitstate[35],  "async"		},
X#  endif NFS
X# else SUN
X	{ "_async_bufhead", 0,  &Info.i_waitstate[14],  "async"		},
X	{ "_desktops",	0,  &Info.i_waitstate[15],	"dtops"		},
X# endif SUN
X# ifdef ULTRIX20
X	{ "_async_bufhead", 0,  &Info.i_waitstate[35],  "async"		},
X# endif ULTRIX20
X	{ (char*)0,     0,  (caddr_t*)0,                (char*)0        }
X} ;
---END-OF-globals2.c---
LEN=`wc -c < globals2.c`
if [ $LEN !=  6807 ] ; then
    echo shar: File "globals2.c" was $LEN, should have been 6807 bytes
fi
if [ -f 'hashuid.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "hashuid.c"
    exit 2
fi
echo x - hashuid.c
sed -e 's/^X//' > hashuid.c << '---END-OF-hashuid.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)hashuid.c	1.1\t10/1/88" ;
X# endif
X
X# include       "sps.h"
X
X/* The hashing functions themselves ... */
X# define        HASHFN1( a )            (((unsigned)(a)*91 + 17) % MAXUSERS)
X# define        HASHFN2( a )            (((unsigned)(a) + 47) % MAXUSERS)
X
X/*
X** HASHUID - Returns a pointer to a slot in the hash table that corresponds
X** to the hash table entry for `uid'. It returns a null pointer if there is
X** no such slot.
X*/
Xstruct hashtab  *hashuid ( uid )
X
Xint                             uid ;
X
X{
X	register struct hashtab *hp ;
X	register int            i ;
X	register int            j ;
X	extern struct info      Info ;
X
X	j = HASHFN1( uid ) ;
X	for ( i = 0 ; i < MAXUSERS ; i++ )
X	{
X		hp = &Info.i_hnames[ j ] ;
X		if ( !hp->h_uname[0] )
X			return ( (struct hashtab*)0 ) ;
X		if ( hp->h_uid == uid )
X			return ( hp ) ;
X		j = HASHFN2( j ) ;
X	}
X	return ( (struct hashtab*)0 ) ;
X}
X
X/*
X** HASHNEXT - Returns a pointer to the next slot in the hash table that
X** may be use for storing information for `uid'. It returns a null pointer
X** if there are no more free slots available.
X*/
Xstruct hashtab  *hashnext ( uid )
X
Xint                             uid ;
X
X{
X	register struct hashtab *hp ;
X	register int            i ;
X	register int            j ;
X	extern struct info      Info ;
X
X	j = HASHFN1( uid ) ;
X	for ( i = 0 ; i < MAXUSERS ; i++ )
X	{
X		hp = &Info.i_hnames[ j ] ;
X		if ( !hp->h_uname[0] )
X			return ( hp ) ;
X		j = HASHFN2( j ) ;
X	}
X	return ( (struct hashtab*)0 ) ;
X}
---END-OF-hashuid.c---
LEN=`wc -c < hashuid.c`
if [ $LEN !=  1515 ] ; then
    echo shar: File "hashuid.c" was $LEN, should have been 1515 bytes
fi
if [ -f 'initialise.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "initialise.c"
    exit 2
fi
echo x - initialise.c
sed -e 's/^X//' > initialise.c << '---END-OF-initialise.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)initialise.c	1.1\t10/1/88" ;
X# endif
X
X# include       "sps.h"
X# include       "flags.h"
X# include       <pwd.h>
X# include       <stdio.h>
X
X/*
X** INITIALISE - Called to reset the `Info' structure with new kernel
X** addresses and user and tty information.
X*/
Xinitialise ()
X{
X	register FILE           *fd ;
X	char                    *fileinfo ;
X	extern struct flags     Flg ;
X	extern struct info      Info ;
X	FILE                    *fopen() ;
X
X	fileinfo = Flg.flg_j ? Flg.flg_j : FILE_INFO ;
X	/* Read kernel addresses */
X	initsymbols() ;                 
X	/* Read user names */
X	initusers() ;                   
X	(void)umask( ~0644 ) ;          
X	if ( !(fd = fopen( fileinfo, "w" )) )
X	{
X		fprintf( stderr, "sps - Can't create info file %s", fileinfo ) ;
X		sysperror() ;
X	}
X	/* Find tty addresses */
X	inittty() ;                     
X	if ( fwrite( (char*)&Info, sizeof( struct info ), 1, fd ) != 1 )
X	{
X		fprintf( stderr, "sps - Can't write info file %s", fileinfo ) ;
X		sysperror() ;
X		exit( 1 ) ;
X	}
X	(void)fclose( fd ) ;
X	printf( "sps is initialised\n" ) ;
X}
X
X/* INITUSERS - Read the passwd file and fill in the user name arrays */
Xinitusers ()
X{
X	register struct passwd  *pw ;
X	register struct hashtab *hp ;
X	struct passwd           *getpwent() ;
X	char                    *strncpy() ;
X	struct hashtab          *hashuid(), *hashnext() ;
X
X	while ( pw = getpwent() )
X	{       /* For each user in the passwd file, first see if that uid
X		   has been already allocated in the hash table. */
X		if ( hp = hashuid( pw->pw_uid ) )
X		{
X			fprintf( stderr,
X		   "sps - Names %s and %s conflict in passwd file for uid %d\n",
X				hp->h_uname, pw->pw_name, pw->pw_uid ) ;
X			continue ;
X		}
X		/* Try to find a free slot in the hash table and fill it. */
X		if ( !(hp = hashnext( pw->pw_uid )) )
X			prexit( "sps - Too many users in passwd file\n" ) ;
X		hp->h_uid = pw->pw_uid ;
X		(void)strncpy( hp->h_uname, pw->pw_name, UNAMELEN ) ;
X	}
X	(void)endpwent() ;
X}
---END-OF-initialise.c---
LEN=`wc -c < initialise.c`
if [ $LEN !=  1986 ] ; then
    echo shar: File "initialise.c" was $LEN, should have been 1986 bytes
fi
if [ -f 'initsymbols.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "initsymbols.c"
    exit 2
fi
echo x - initsymbols.c
sed -e 's/^X//' > initsymbols.c << '---END-OF-initsymbols.c---'
X# ifndef lint
Xstatic char SccsId[] =	"@(#)initsymbols.c	1.4\t8/6/90" ;
X# endif lint
X
X# include       "sps.h"
X# include       "flags.h"
X# ifdef BSD42
X#  include       <sys/file.h>
X# endif BSD42
X# ifdef KVM
X#  include       <kvm.h>
X# endif KVM
X# include       <nlist.h>
X# include       <stdio.h>
X
X/* INITSYMBOLS - Reads kmem values into the Info structure */
X/*
X** THIS CODE COPIES KMEM VALUES INTO THE INFO STRUCTURE ASSUMING THAT
X** VALUES READ FROM THE KERNEL HAVE TYPE CADDR_T. THEREFORE, WE ARE
X** MAKING THE DUBIOUS ASSUMPTION THAT INTS, POINTERS AND CADDR_T's
X** HAVE IDENTICAL SIZES.
X*/
Xinitsymbols ()
X{
X	register struct nlist   *np ;
X	register struct symbol  *s ;
X	register struct nlist   *np0 ;
X	char                    *filesymbol ;
X# ifdef KVM
X	extern kvm_t           *Flkvm ;
X# endif
X	extern struct flags     Flg ;
X	extern struct symbol    Symbollist[] ;
X	extern struct info      Info ;
X	char                    *getcore() ;
X	char                    *strncpy() ;
X
X	filesymbol = Flg.flg_s ? Flg.flg_s : FILE_SYMBOL ;
X	/* Find the length of the symbol table */
X	for ( s = Symbollist ; s->s_kname ; s++ )
X		;
X	/* Construct an nlist structure by copying names from the symbol table*/
X	np0 = (struct nlist*)getcore( (s-Symbollist+1)*sizeof( struct nlist ) );
X	for ( s = Symbollist, np = np0 ; s->s_kname ; s++, np++ )
X	{
X# ifdef SUN386I
X		/* Remove '_' prefix because 386i uses COFF format -
X		   Provided by Martin Reed <mr@ritd.co.uk> */
X		np->n_name = &s->s_kname[1] ;       
X# else SUN386I
X                                     
X		np->n_name = s->s_kname ; 
X# endif SUN386I     
X		np[1].n_name = (char*)0 ;       
X		np->n_value = 0 ;
X	}
X# ifdef KVM
X	if ( kvm_nlist( Flkvm, np0 ) == -1 )
X	{
X		fprintf( stderr, "sps - Can't read symbol file %s", filesymbol);
X		sysperror() ;
X	}
X              
X# else KVM
X#  ifdef BSD42
X	if ( access( filesymbol, R_OK ) < 0 )
X#  else BSD42
X	if ( access( filesymbol, 4 ) < 0 )
X#  endif BSD42
X	{
X		fprintf( stderr, "sps - Can't open symbol file %s", filesymbol);
X		sysperror() ;
X	}
X	/* Get kernel addresses */
X	(void)nlist( filesymbol, np0 ) ;              
X	if ( np0[0].n_value == -1 )
X	{
X		fprintf( stderr, "sps - Can't read symbol file %s", filesymbol);
X		sysperror() ;
X	}
X# endif KVM
X	for ( s = Symbollist, np = np0 ; s->s_kname ; s++, np++ )
X	{                                       
X		if ( !np->n_value )             
X		{
X			fprintf( stderr, "sps - Can't find symbol %s in %s",
X				np->n_name, filesymbol ) ;
X			/* Assume this error to be unimportant if the address
X			   is only associated with a process wait state.
X			   This may happen if the system has been configured
X			   without a particular device. */
X			fprintf( stderr, &Info.i_waitstate[ 0 ] <= s->s_info
X				&& s->s_info < &Info.i_waitstate[ NWAITSTATE ]
X				? " (error is not serious)\n"
X				: " (ERROR MAY BE SERIOUS)\n" ) ;
X			*s->s_info = (caddr_t)0 ;
X			continue ;
X		}
X		/* If no indirection is required, just copy the obtained value
X		   into the `Info' structure. */
X		if ( !s->s_indirect )           
X		{                               
X		/* DUBIOUS ASSUMPTION THAT KMEM VALUE HAS SIZE OF A CADDR_T */
X			*s->s_info = (caddr_t)np->n_value ;
X			continue ;              
X		}                               
X		/* Otherwise one level of indirection is required. Using the
X		   obtained address, look again in the kernel for the value */
X		/* DUBIOUS ASSUMPTION THAT KMEM VALUE HAS SIZE OF A CADDR_T */
X		(void)getkmem( (long)np->n_value, (char*)s->s_info,
X			sizeof(caddr_t) ) ;
X	}
X	free( (char*)np0 ) ;
X}
---END-OF-initsymbols.c---
LEN=`wc -c < initsymbols.c`
if [ $LEN !=  3515 ] ; then
    echo shar: File "initsymbols.c" was $LEN, should have been 3515 bytes
fi
if [ -f 'inittty.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "inittty.c"
    exit 2
fi
echo x - inittty.c
sed -e 's/^X//' > inittty.c << '---END-OF-inittty.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)inittty.c	1.1\t10/1/88" ;
X# endif
X
X# include       "sps.h"
X# include       <h/conf.h>
X# include       <h/ioctl.h>
X# ifdef SUNOS40
X# include       <h/stream.h>
X# else
X# include       <h/tty.h>
X# endif
X# include       <sys/stat.h>
X# include       <stdio.h>
X
X/* INITTTY - Initialise the tty part of the info structure */
Xinittty ()
X{
X	register struct ttyline *lp ;
X# ifdef BSD42
X	register struct direct  *dp ;
X	DIR                     *dfd ;
X# else
X	struct direct           dir ;
X	FILE                    *dfd ;
X# endif
X	struct stat             statbuf ;
X	static char             filedev[] = FILE_DEV ;
X	extern struct info      Info ;
X# ifdef BSD42
X	DIR                     *opendir() ;
X	struct direct           *readdir() ;
X# else
X	FILE                    *fopen() ;
X# endif
X
X	lp = Info.i_ttyline ;
X# ifdef BSD42
X	if ( !(dfd = opendir( filedev )) )
X# else
X	if ( !(dfd = fopen( filedev, "r" )) )
X# endif
X		prexit( "Can't open %s\n", filedev ) ;
X	if ( chdir( filedev ) < 0 )
X		prexit( "sps - Can't chdir to %s\n", filedev ) ;
X# ifdef BSD42
X	/* Read all entries in the device directory, looking for ttys */
X	while ( dp = readdir( dfd ) )
X	{       /* Skip entries that do not match "tty" or "console" */
X		if ( strncmp( "tty", dp->d_name, 3 )
X		&&   strcmp( "console", dp->d_name ) )
X			continue ;
X		/* Skip "tty" itself */
X		if ( dp->d_namlen == 3 )
X			continue ;
X# ifdef CHAOS
X		/* Skip chaos ttys ; they are accessed during ttystatus() */
X		if ( dp->d_namelen > 3 &&
X		dp->d_name[ sizeof( "tty" ) - 1 ] == 'C' )
X			continue ;
X# endif
X		if ( lp >= &Info.i_ttyline[ MAXTTYS ] )
X			prexit( "sps - Too many ttys in %s\n", filedev ) ;
X		/* Copy the tty name into the information entry */
X		if ( !strcmp( dp->d_name, "console" ) )
X		{
X			lp->l_name[0] = 'c' ;
X			lp->l_name[1] = 'o' ;
X		}
X		else
X		{
X			lp->l_name[0] = dp->d_name[3] ;
X			lp->l_name[1] = dp->d_name[4] ;
X		}
X		/* Ensure that this tty is actually a valid character device */
X		if ( stat( dp->d_name, &statbuf ) < 0 )
X			continue ;
X# else
X	/* Read all entries in the device directory, looking for ttys */
X	while ( fread( (char*)&dir, sizeof( struct direct ), 1, dfd ) == 1 )
X	{       /* Skip entries that do not match "tty" or "console" */
X		if ( strncmp( "tty", dir.d_name, 3 )
X		&&   strcmp( "console", dir.d_name ) )
X			continue ;
X		/* Skip "tty" itself */
X		if ( dir.d_name[3] == '\0' )
X			continue ;
X# ifdef CHAOS
X		/* Skip chaos ttys ; they are accessed during ttystatus() */
X		if ( dir.d_name[ sizeof( "tty" ) - 1 ] == 'C' )
X			continue ;
X# endif
X		if ( lp >= &Info.i_ttyline[ MAXTTYS ] )
X			prexit( "sps - Too many ttys in %s\n", filedev ) ;
X		/* Copy the tty name into the information entry */
X		if ( !strcmp( dir.d_name, "console" ) )
X		{
X			lp->l_name[0] = 'c' ;
X			lp->l_name[1] = 'o' ;
X		}
X		else
X		{
X			lp->l_name[0] = dir.d_name[3] ;
X			lp->l_name[1] = dir.d_name[4] ;
X		}
X		/* Ensure that this tty is actually a valid character device */
X		if ( stat( dir.d_name, &statbuf ) < 0 )
X			continue ;
X# endif
X		if ( (statbuf.st_mode & S_IFMT) != S_IFCHR )
X			continue ;
X		/* Find the device # of the tty and the address of its
X		   associated struct tty in /dev/kmem. */
X		lp->l_dev = statbuf.st_rdev ;
X		if ( getkmem ( (long)&Info.i_cdevsw[ major( statbuf.st_rdev ) ]
X# ifdef SUNOS40
X			.d_str,
X# else
X			.d_ttys,
X# endif
X		(char*)&lp->l_addr, sizeof( lp->l_addr ) )
X		!= sizeof( lp->l_addr ) )
X		{
X			fprintf( stderr, "sps - Can't read struct tty for %s\n",
X# ifdef BSD42
X				dp->d_name ) ;
X# else
X				dir.d_name ) ;
X# endif
X			continue ;
X		}
X# ifndef SUNOS40
X		lp->l_addr += (int)minor( statbuf.st_rdev ) ;
X# endif
X		lp++ ;
X	}
X# ifdef BSD42
X	(void)closedir( dfd ) ;
X# else
X	(void)fclose( dfd ) ;
X# endif
X}
---END-OF-inittty.c---
LEN=`wc -c < inittty.c`
if [ $LEN !=  3716 ] ; then
    echo shar: File "inittty.c" was $LEN, should have been 3716 bytes
fi
if [ -f 'main.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "main.c"
    exit 2
fi
echo x - main.c
sed -e 's/^X//' > main.c << '---END-OF-main.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)main.c	1.1\t10/1/88" ;
X# endif
X
X# include       "sps.h"
X# include       "flags.h"
X# ifdef KVM
X# include       <kvm.h>
X# include       <fcntl.h>
X# endif KVM
X# ifndef SUNOS40
X# include       <h/text.h>
X# endif
X# include       <sys/stat.h>
X# include       <stdio.h>
X
X
X/* SPS - Show Process Status */
X
X/* J. R. Ward - Hasler AG, Bern, Switzerland		 - 24 May 1985 */
X/*				     			 - 26 Nov 1986 */
X/* J. R. Ward - Olsen & Associates, Zuerich, Switzerland -  1 Oct 1988 */
X/* <robert@olsen.uucp> */
X
X/* NFS additions and SunOS4.0 support by Alexander Dupuy
X   <dupuy@ncs.columbia.edu> and Charlie Kim <cck@cunixc.cc.columbia.edu>.
X   Ultrix 2.x support by Rob Lehman at CUCCA. */
X
Xmain ( argc,argv )
X
Xint                             argc ;
Xchar                            **argv ;
X
X{
X	register struct process *plist ;
X	register struct process *process ;
X# ifndef SUNOS40
X	register struct text    *text ;
X# endif
X	int                     flinfo ;
X	char			*fileinfo, *filesymbol ;
X	struct stat		sinfo, ssymbol ;
X# ifdef WARNPASSWD
X	struct stat		spasswd ;
X# endif
X	extern struct flags     Flg ;
X	extern struct info      Info ;
X# ifdef KVM
X	extern kvm_t           *Flkvm ;
X# else
X	extern int              Flmem ;
X	extern int              Flkmem ;
X	extern int              Flswap ;
X# endif
X	char                    *getcore() ;
X	struct process          *needed(), *mktree() ;
X
X	/* Renice as fast as possible for root only (Suggested by Jeff Mogul,
X	   gregorio!mogul) */
X	if ( !getuid() )
X		(void)nice( -40 ) ;
X	/* Decode the flag arguments */
X	flagdecode( argc, argv ) ;      
X	/* Determine the terminal width */
X	if ( !Flg.flg_w && !Flg.flg_N && !Flg.flg_i )
X		termwidth() ;
X	/* Open the cpu physical memory, kernel virtual memory and swap device*/
X# ifdef KVM
X	Flkvm = kvm_open( Flg.flg_s, Flg.flg_k, NULL, O_RDONLY, "sps" ) ;
X# else
X	if ( Flg.flg_k )
X	{
X		Flmem = openfile( Flg.flg_k ) ;
X		Flkmem = Flmem ;
X	}
X	else
X	{
X		Flmem = openfile( FILE_MEM ) ;
X		Flkmem = openfile( FILE_KMEM ) ;
X		if ( !Flg.flg_o )
X			Flswap = openfile( FILE_SWAP ) ;
X	}
X# endif
X	if ( Flg.flg_i )
X	{       /* -i flag for info file initialisation */
X		initialise() ;          
X		exit( 0 ) ;
X	}
X	/* Check that the information file is newer than the symbol and
X	   password files, suggested by gregorio!mogul */
X	fileinfo = Flg.flg_j ? Flg.flg_j : FILE_INFO ;
X	filesymbol = Flg.flg_s ? Flg.flg_s : FILE_SYMBOL ;
X	flinfo = openfile( fileinfo ) ;
X	(void)fstat( flinfo, &sinfo ) ;
X	if ( !stat( filesymbol, &ssymbol ) &&
X		sinfo.st_mtime < ssymbol.st_mtime )
X		fprintf( stderr,
X	       "sps - WARNING: Info file `%s' is older than symbol file `%s'\n",
X			fileinfo, filesymbol ) ;
X# ifdef WARNPASSWD
X	if ( !stat( FILE_PASSWD, &spasswd ) &&
X		sinfo.st_mtime < spasswd.st_mtime )
X		fprintf( stderr,
X	       "sps - WARNING: Info file `%s' is older than passwd file `%s'\n",
X			fileinfo, FILE_PASSWD ) ;
X# endif
X	/* Read the information file */
X	if ( read( flinfo, (char*)&Info, sizeof( struct info ) )
X	!= sizeof( struct info ) )
X	{
X		fprintf( stderr, "sps - Can't read info file `%s'", fileinfo ) ;
X		sysperror() ;
X	}
X	(void)close( flinfo ) ;
X	/* Find current tty status */
X	ttystatus() ;                   
X	/* Now that we know the available ttys, decode the flags */
X	flagsetup() ;                   
X	process = (struct process*)getcore(Info.i_nproc*sizeof(struct process));
X# ifndef SUNOS40
X	text = (struct text*)getcore( Info.i_ntext * sizeof( struct text ) ) ;
X# endif
X	do
X	{       /* Read current process status */
X# ifdef SUNOS40
X		readstatus( process ) ;
X		/* Select those processes to be listed */
X		plist = needed( process ) ;
X# else
X		readstatus( process, text ) ;
X		/* Select those processes to be listed */
X		plist = needed( process, text ) ;
X# endif
X		/* Form a tree of listed processes */
X		plist = mktree( process, plist ) ;
X		if ( !Flg.flg_N )
X		{       /* Print the processes */
X			prheader() ;
X			printall( plist, 0 ) ;
X		}
X		prsummary() ;
X		(void)fflush( stdout ) ;
X		if ( Flg.flg_r )        
X		{       /* If repeating, again get tty status */
X			ttystatus() ;
X			if ( Flg.flg_rdelay )
X# ifdef BSD42
X				sleep( Flg.flg_rdelay ) ;
X# else
X				sleep( (int)Flg.flg_rdelay ) ;
X# endif
X		}
X	} while ( Flg.flg_r ) ;
X	exit( 0 ) ;
X}
---END-OF-main.c---
LEN=`wc -c < main.c`
if [ $LEN !=  4246 ] ; then
    echo shar: File "main.c" was $LEN, should have been 4246 bytes
fi
if [ -f 'mktree.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "mktree.c"
    exit 2
fi
echo x - mktree.c
sed -e 's/^X//' > mktree.c << '---END-OF-mktree.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)mktree.c	1.1\t10/1/88" ;
X# endif
X
X# include       "sps.h"
X
X/*
X** MKTREE - Sort the needed processes by subtree and at the top by user.
X** This procedure takes a list of processes (as returned by needed())
X** and returnes a pointer to a sorted list.
X*/
Xstruct process  *mktree ( process, plist )
X
Xstruct process                  *process ;
Xstruct process                  *plist ;
X
X{
X	register struct process *p ;
X	register struct process *pp ;
X	register struct process *lp ;
X	struct process          *op ;
X	struct process          proot ;
X
X	proot.pr_sibling = (struct process*)0 ;
X	for ( p = plist ; p ; p = p->pr_plink )
X	{
X		if ( p->pr_pptr > &process[1] )
X		{
X			for ( pp = plist ; pp ; pp = pp->pr_plink )
X			{
X				if ( pp != p->pr_pptr )
X					continue ;
X				if ( lp = pp->pr_child )
X				{       /* Does process have children ? */
X					op = (struct process*)0 ;
X					while (lp &&
X					lp->pr_p.p_pid < p->pr_p.p_pid )
X					{
X						op = lp ;
X						lp=lp->pr_sibling ;
X					}
X					if ( op )
X					{
X						p->pr_sibling = lp ;
X						op->pr_sibling = p ;
X						break ;
X					}
X				}       
X				p->pr_sibling = lp ;
X				pp->pr_child = p ;
X				break ;
X			}
X			if ( pp )
X				continue ;
X		}
X		/* We have a top level process, sort into top level list.
X		   The top level is sorted firstly by user-id and then
X		   by process-id. */
X		lp = &proot ;
X		pp = lp->pr_sibling ;
X		while ( pp )
X		{
X			if ( p->pr_p.p_uid < pp->pr_p.p_uid )
X				break ;
X			if ( p->pr_p.p_uid == pp->pr_p.p_uid
X			&& p->pr_p.p_pid < pp->pr_p.p_pid )
X				break ;
X			lp = pp, pp = pp->pr_sibling ;
X		}
X		p->pr_sibling = lp->pr_sibling ;
X		lp->pr_sibling = p ;
X	}
X	return ( proot.pr_sibling ) ;
X}
---END-OF-mktree.c---
LEN=`wc -c < mktree.c`
if [ $LEN !=  1703 ] ; then
    echo shar: File "mktree.c" was $LEN, should have been 1703 bytes
fi
if [ -f 'needed.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "needed.c"
    exit 2
fi
echo x - needed.c
sed -e 's/^X//' > needed.c << '---END-OF-needed.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)needed.c	1.3\t7/4/90" ;
X# endif
X
X# include       "sps.h"
X# include       "flags.h"
X# ifndef SUNOS40
X# include       <h/text.h>
X# endif
X# include       <stdio.h>
X
X/*
X** NEEDED - Determine which processes are needed for the printout
X** and add these to a list of needed processes.
X*/
X# ifdef SUNOS40
Xstruct process  *needed ( process )
X
Xregister struct process         *process ;
X
X# else
X
Xstruct process  *needed ( process, text )
X
Xregister struct process         *process ;
Xstruct text                     *text ;
X
X# endif
X{
X	register struct process *p ;
X	register struct process *plist ;
X	struct process          *lastp ;
X	int                     uid ;
X	extern struct flags     Flg ;
X	extern union userstate  User ;
X	extern struct info      Info ;
X	extern struct ttyline   Notty ;
X	struct ttyline          *findtty() ;
X	char                    *getcmd() ;
X
X	plist = (struct process*)0 ;
X	lastp = &process[ Info.i_nproc ] ;
X	/* Normalise internal pointers from kernel addresses. For each kmem
X	   address in the `proc' and `text' structures, we convert that
X	   address for our own internal use. */
X	for ( p = process ; p < lastp ; p++ )
X	{                               
X		if ( !p->pr_p.p_stat )  
X			continue ;
X# ifndef SUNOS40
X		/* Normalise internal text pointers */
X		if ( p->pr_p.p_textp )
X			p->pr_p.p_textp = &text[p->pr_p.p_textp - Info.i_text0];
X# endif
X		/* Normalise internal linked list of processes */
X		p->pr_plink = p->pr_p.p_link ?
X			&process[ p->pr_p.p_link  - Info.i_proc0 ] :
X			(struct process*)0 ;
X		/* Normalise internal parent pointers */
X		p->pr_pptr = p->pr_p.p_pptr ?
X			&process[ p->pr_p.p_pptr - Info.i_proc0 ] :
X			(struct process*)0 ;
X		/* Check for valid parent pointers */
X		if ( !p->pr_pptr )
X		{
X			p->pr_pptr = process ;
X			continue ;
X		}
X		if ( p->pr_pptr < process || p->pr_pptr >= lastp )
X		{
X			fprintf( stderr, "sps - process %d has bad pptr\n",
X				p->pr_p.p_pid ) ;
X			p->pr_pptr = process ;
X		}
X	}
X	/* For each process, see if it is a candidate for selection.
X	   If so, retrieve its command arguments and upage information. */
X	uid = getuid() ;
X	for ( p = process ; p < lastp ; p++ )
X	{                               
X		if ( !p->pr_p.p_stat )
X			continue ;
X		/* Count processes and sizes */
X		summarise( p ) ;
X		/* Select the given processes. Bear in mind that selection
X		   of processes based on the `F' and `T' flags must be
X		   postponed until the upage is accessed. */
X		if ( !Flg.flg_F && !Flg.flg_T && !selectproc( p, process, uid ))
X			continue ;
X		/* Try to find the process' command arguments. Accessing the
X		   arguments also involves retrieving the upage. */
X		p->pr_cmd = getcmd( p ) ;
X		/* If the upage was found successfully, use this information */
X		if ( p->pr_upag )       
X		{
X# ifdef BSD42
X			p->pr_rself = User.u_us.u_ru ;
X			p->pr_rchild = User.u_us.u_cru ;
X# else
X			p->pr_vself = User.u_us.u_vm ;
X			p->pr_vchild = User.u_us.u_cvm ;
X# endif
X			p->pr_tty = findtty( p ) ;
X			p->pr_files = filecount( p ) ;
X		}
X		else
X			p->pr_tty = &Notty ;
X		/* Select on the basis of the `F' and `T' flags */
X		if ( Flg.flg_F          
X		&& !(p->pr_p.p_pgrp && p->pr_p.p_pgrp == p->pr_tty->l_pgrp) )
X			continue ;
X		if ( Flg.flg_T && !selecttty( p ) )
X			continue ;
X		/* Arrive here with a selected process. Add this to the
X		   linked list of needed processes. */
X		p->pr_plink = plist ;   
X		plist = p ;
X		p->pr_child = (struct process*)0 ;
X		p->pr_sibling = (struct process*)0 ;
X	}
X	return ( plist ) ;
X}
X
X/* SUMMARISE - Summarises the given process into the `Summary' structure */
X/*
X** SHOULD ACCOUNT HERE FOR THE SIZE OF LOADED PAGE TABLES, BUT WE DON'T REALLY
X** KNOW THEIR RESIDENT SIZES.
X*/
Xsummarise ( p )
X
Xregister struct process         *p ;
X
X{
X# ifndef SUNOS40
X	register struct text    *tp ;
X# endif
X	int                     busy ;
X	extern struct summary   Summary ;
X
X	Summary.sm_ntotal++ ;
X	if ( p->pr_p.p_stat == SZOMB )
X		return ;
X	/* Firstly, account for processes */
X# if defined(OLDSTATS) || !defined(SUNOS40)
X	Summary.sm_ktotal += p->pr_p.p_dsize + p->pr_p.p_ssize ;
X# else
X	seg_count( p ) ;		/* count up process pages */
X	
X	Summary.sm_ktotal += p->pr_private + p->pr_shared ;
X# endif
X	Summary.sm_kloaded += p->pr_p.p_rssize ;
X	Summary.sm_kswapped += p->pr_p.p_swrss ;
X	if ( p->pr_p.p_flag & SLOAD )
X		Summary.sm_nloaded++ ;
X	else
X		Summary.sm_nswapped++ ;
X	busy = (p->pr_p.p_stat == SRUN) || (p->pr_p.p_stat==SSLEEP
X	     && (p->pr_p.p_pri<PZERO && p->pr_p.p_pid > MSPID) ) ;
X# ifdef SUNOS40
X	/* Ignore the idle processes */
X	if ( p->pr_p.p_pid == 3 || p->pr_p.p_pid == 4 )
X	    busy = 0 ;
X# endif SUNOS40
X	if ( busy )
X	{
X		Summary.sm_nbusy++ ;
X# if defined(OLDSTATS) || !defined(SUNOS40)
X		Summary.sm_kbusy += p->pr_p.p_dsize + p->pr_p.p_ssize ;
X# else
X		Summary.sm_kbusy += p->pr_private + p->pr_shared ;
X# endif
X	}
X# ifndef SUNOS40
X	/* Now account for their texts */
X	if ( !(tp = p->pr_p.p_textp) || !tp->x_count )
X		return ;                
X	Summary.sm_ktotal += tp->x_size ;
X	Summary.sm_kloaded += tp->x_rssize ;
X	Summary.sm_kswapped += tp->x_swrss ;
X	if ( busy )
X		Summary.sm_kbusy += tp->x_size ;
X	tp->x_count = 0 ;
X# endif
X}
---END-OF-needed.c---
LEN=`wc -c < needed.c`
if [ $LEN !=  5151 ] ; then
    echo shar: File "needed.c" was $LEN, should have been 5151 bytes
fi
if [ -f 'openfiles.c' -a "${1}" != "-c" ] ; then
    echo shar: Won\'t overwrite existing file "openfiles.c"
    exit 2
fi
echo x - openfiles.c
sed -e 's/^X//' > openfiles.c << '---END-OF-openfiles.c---'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)openfiles.c	1.1\t10/1/88" ;
X# endif
X
X# include       <stdio.h>
X# include       "sps.h"
X# include       "flags.h"
X# include       <varargs.h>
X# ifdef KVM
X# include       <kvm.h>
X# endif
X
X/* Miscellaneous procedures */
X
X/* OPENFILE - Opens the named file */
Xopenfile ( name )
X
Xchar                            *name ;
X
X{
X	register int            fd ;
X
X	if ( (fd = open( name, 0 )) >= 0 )
X		return ( fd ) ;
X	fprintf( stderr, "sps - Can't open %s", name ) ;
X	sysperror() ;
X	/* NOTREACHED */
X}
X
X# ifdef KVM
X
Xgetkmem ( addr, buf, bufsize )
X
Xlong                            addr ;
Xchar                            *buf ;
Xint                             bufsize ;
X{
X	extern kvm_t            *Flkvm ;
X
X	return( kvm_read( Flkvm, (long)addr, buf, bufsize ) ) ;
X}
X
X# else
X
Xgetkmem ( addr, buf, bufsize )
X
Xlong                            addr ;
Xchar                            *buf ;
Xint                             bufsize ;
X{
X	extern int              Flkmem ;
X
X	memseek( Flkmem, (long)addr ) ;
X	return( read( Flkmem, buf, bufsize ) ) ;
X}
X
X/* MEMSEEK - Seek on a special file */
Xmemseek ( fd, pos )
X
Xint                             fd ;
Xlong                            pos ;
X
X{
X	extern int              errno ;
X	extern struct flags     Flg ;
X	long                    lseek() ;
X
X	errno = 0 ;
X	if ( Flg.flg_k )
X# ifdef SUN
X		pos &= KERNELBASE - 1 ;
X# else
X		pos &= 0x7fffffff ;
X# endif
X	(void)lseek( fd, pos, 0 ) ;
X	if ( errno )
X	{
X		fprintf( stderr, "sps - Seek failed" ) ;
X		sysperror() ;
X	}
X}
X
X/* SWSEEK - Seek on the swap device */
Xswseek ( pos )
X
Xlong                            pos ;
X
X{
X	extern int              Flswap ;
X	extern int              errno ;
X	long                    lseek() ;
X
X	errno = 0 ;
X	(void)lseek( Flswap, pos, 0 ) ;
X	if ( errno )
X	{
X		fprintf( stderr, "sps - Seek failed" ) ;
X		sysperror() ;
X	}
X}
X
X# endif
X
X# ifdef lint
Xint                             errno ;
Xint                             sys_nerr ;
Xchar                            *sys_errlist[] ;
X# endif
X
X/* SYSPERROR - Reports a system defined error msg and then exits gracefully */
Xsysperror ()
X{
X	extern int              errno ;
X	extern int              sys_nerr ;
X	extern char             *sys_errlist[] ;
X
X	if ( 0 < errno && errno < sys_nerr )
X		fprintf( stderr, " : %s", sys_errlist[errno] ) ;
X	(void)fputc( '\n', stderr ) ;
X	exit( 1 ) ;
X}
X
X/* STRSAVE - Store a string in core for later use. */
Xchar    *strsave ( cp )
X
Xregister char                   *cp ;
X
X{
X	register char           *chp ;
X	char                    *getcore(), *strcpy() ;
X
X	chp = getcore( strlen( cp ) + 1 ) ;
X	(void)strcpy( chp, cp ) ;
X	return ( chp ) ;
X}
X
X/* GETCORE - Allocate and return a pointer to the asked for amount of core */
Xchar    *getcore ( size )
X
Xregister int                    size ;
X
X{
X	register char           *chp ;
X	char                    *malloc() ;
X
X	if ( chp = malloc( (unsigned)size ) )
X		return ( chp ) ;
X	fprintf( stderr, "sps - Out of core" ) ;
X	sysperror() ;
X	/* NOTREACHED */
X}
X
Xunion flaglist  *getflgsp ( argc )
X
Xregister int                    argc ;
X
X{
X	char                    *getcore() ;
X
X	return ( (union flaglist*)getcore( sizeof( union flaglist )*argc ) ) ;
X}
X
X/* PREXIT - Print an error message and exit */
X/* VARARGS */
X/* ARGSUSED */
Xprexit ( va_alist )
X
Xva_dcl
X
X{
X	char                    *fmt ;
X	va_list                  args ;
X
X	va_start( args ) ;
X	fmt = va_arg( args, char * ) ;
X
X	vfprintf( stderr, fmt, args ) ;
X	exit( 1 ) ;
X}
X
X# ifndef VPRINTF
X
Xint vfprintf ( filep, fmt, args )
X
XFILE	                        *filep ;
Xchar                            *fmt ;
Xva_list                          args ;
X
X{
X	_doprnt( fmt, args, filep ) ;	
X	return( ferror( filep ) ? EOF : 0 ) ;
X}
X
X# endif
---END-OF-openfiles.c---
LEN=`wc -c < openfiles.c`
if [ $LEN !=  3718 ] ; then
    echo shar: File "openfiles.c" was $LEN, should have been 3718 bytes
fi
exit 0