v23i048: SPS, a PS replacement, Part02/04
Rich Salz
rsalz at bbn.com
Tue Nov 27 06:05:40 AEST 1990
Submitted-by: Robert Ward <olsen!robert at uunet.uu.net>
Posting-number: Volume 23, Issue 48
Archive-name: sps2/part02
#! /bin/sh
# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix at uunet.uu.net if you want that tool.
# Contents: flagdecode.c flags.h getupage.c globals2.c inittty.c
# main.c needed.c openfiles.c sps.h stream.c
# Wrapped by rsalz at papaya.bbn.com on Mon Nov 26 14:03:22 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:
echo ' "shar: End of archive 2 (of 4)."'
if test -f 'flagdecode.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'flagdecode.c'\"
else
echo shar: Extracting \"'flagdecode.c'\" \(5627 characters\)
sed "s/^X//" >'flagdecode.c' <<'END_OF_FILE'
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_FILE
if test 5627 -ne `wc -c <'flagdecode.c'`; then
echo shar: \"'flagdecode.c'\" unpacked with wrong size!
fi
# end of 'flagdecode.c'
fi
if test -f 'flags.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'flags.h'\"
else
echo shar: Extracting \"'flags.h'\" \(2638 characters\)
sed "s/^X//" >'flags.h' <<'END_OF_FILE'
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_FILE
if test 2638 -ne `wc -c <'flags.h'`; then
echo shar: \"'flags.h'\" unpacked with wrong size!
fi
# end of 'flags.h'
fi
if test -f 'getupage.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'getupage.c'\"
else
echo shar: Extracting \"'getupage.c'\" \(4161 characters\)
sed "s/^X//" >'getupage.c' <<'END_OF_FILE'
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_FILE
if test 4161 -ne `wc -c <'getupage.c'`; then
echo shar: \"'getupage.c'\" unpacked with wrong size!
fi
# end of 'getupage.c'
fi
if test -f 'globals2.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'globals2.c'\"
else
echo shar: Extracting \"'globals2.c'\" \(6807 characters\)
sed "s/^X//" >'globals2.c' <<'END_OF_FILE'
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_FILE
if test 6807 -ne `wc -c <'globals2.c'`; then
echo shar: \"'globals2.c'\" unpacked with wrong size!
fi
# end of 'globals2.c'
fi
if test -f 'inittty.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'inittty.c'\"
else
echo shar: Extracting \"'inittty.c'\" \(3716 characters\)
sed "s/^X//" >'inittty.c' <<'END_OF_FILE'
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_FILE
if test 3716 -ne `wc -c <'inittty.c'`; then
echo shar: \"'inittty.c'\" unpacked with wrong size!
fi
# end of 'inittty.c'
fi
if test -f 'main.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'main.c'\"
else
echo shar: Extracting \"'main.c'\" \(4246 characters\)
sed "s/^X//" >'main.c' <<'END_OF_FILE'
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 at olsen.uucp> */
X
X/* NFS additions and SunOS4.0 support by Alexander Dupuy
X <dupuy at ncs.columbia.edu> and Charlie Kim <cck at 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_FILE
if test 4246 -ne `wc -c <'main.c'`; then
echo shar: \"'main.c'\" unpacked with wrong size!
fi
# end of 'main.c'
fi
if test -f 'needed.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'needed.c'\"
else
echo shar: Extracting \"'needed.c'\" \(5151 characters\)
sed "s/^X//" >'needed.c' <<'END_OF_FILE'
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_FILE
if test 5151 -ne `wc -c <'needed.c'`; then
echo shar: \"'needed.c'\" unpacked with wrong size!
fi
# end of 'needed.c'
fi
if test -f 'openfiles.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'openfiles.c'\"
else
echo shar: Extracting \"'openfiles.c'\" \(3718 characters\)
sed "s/^X//" >'openfiles.c' <<'END_OF_FILE'
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_FILE
if test 3718 -ne `wc -c <'openfiles.c'`; then
echo shar: \"'openfiles.c'\" unpacked with wrong size!
fi
# end of 'openfiles.c'
fi
if test -f 'sps.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'sps.h'\"
else
echo shar: Extracting \"'sps.h'\" \(6824 characters\)
sed "s/^X//" >'sps.h' <<'END_OF_FILE'
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_FILE
if test 6824 -ne `wc -c <'sps.h'`; then
echo shar: \"'sps.h'\" unpacked with wrong size!
fi
# end of 'sps.h'
fi
if test -f 'stream.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'stream.c'\"
else
echo shar: Extracting \"'stream.c'\" \(5425 characters\)
sed "s/^X//" >'stream.c' <<'END_OF_FILE'
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_FILE
if test 5425 -ne `wc -c <'stream.c'`; then
echo shar: \"'stream.c'\" unpacked with wrong size!
fi
# end of 'stream.c'
fi
echo shar: End of archive 2 \(of 4\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 4 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 4 archives.
rm -f ark[1-9]isdone
else
echo You still must unpack the following archives:
echo " " ${MISSING}
fi
exit 0
exit 0 # Just in case...
--
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.
More information about the Comp.sources.unix
mailing list