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