v23i047: SPS, a PS replacement, Part01/04

Rich Salz rsalz at bbn.com
Tue Nov 27 06:05:21 AEST 1990


Submitted-by: Robert Ward <olsen!robert at uunet.uu.net>
Posting-number: Volume 23, Issue 47
Archive-name: sps2/part01

[ I renamed the Makefiles so that SystemV sites would have less trouble.
  --r$ ]

Introduction:
    SPS is a intended to be used as a replacement for the standard
    ps(1) program. Its advantages over ps(1) are that it shows more
    useful information, that the displayed information is more
    comprehensible and that it is faster.


    SPS is currently implemented for the following operating systems and
    architectures.  The corresponding Makefiles are also shown here:

	Makefile.4.1		Standard 4.1bsd for Vax
	Makefile.4.2		Standard 4.2bsd, Ultrix 1.x for Vax
	Makefile.4.3		Standard 4.3bsd (or 4.3-tahoe) for Vax
	Makefile.4.3+NFS	4.3bsd+NFS from Wisconsin (Mt. Xinu?, others?)
	Makefile.dec3100	DECStation 3100 + Ultrix 3.0 (incomplete)
	Makefile.sun.2.0	Sun 4.2 UNIX Release 2.0 - 2.2 for Sun-2
	Makefile.sun.3.0	Sun 4.2 UNIX Release 3.0 for Sun-2, Sun-3
	Makefile.sun.3.2	Sun 4.2 UNIX Release 3.2 for Sun-2, Sun-3
	Makefile.sun.4.0	SunOS 4.0 for Sun-2, Sun-3, Sun-4
	Makefile.sun.4.0+386i	SunOS 4.0 for Sun 386i
	Makefile.sun.4.1	SunOS 4.1 for Sun-2, Sun-3, Sun-4
	Makefile.sun4.3.2	SunOS Sys 4-3.2 for Sun-4
	Makefile.ultrix.2.0	DEC Ultrix 2.0 - 2.2
	Makefile.ultrix.3.0	DEC Ultrix 3.0

    (I also have a somewhat ancient implementation for V7 on a PDP-11 as well
    as Unisoft Version 1.3 on a MC68000 if anyone is interested).


#! /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:  README getcmd.c printproc.c sps.l ttystatus.c waitingfor.c
# Wrapped by rsalz at papaya.bbn.com on Mon Nov 26 14:03:21 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 1 (of 4)."'
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
  echo shar: Extracting \"'README'\" \(4769 characters\)
  sed "s/^X//" >'README' <<'END_OF_FILE'
X		SPS  -  Show Process Status
X		===========================
X
X
XIntroduction:
X    SPS is a intended to be used as a replacement for the standard
X    ps(1) program. Its advantages over ps(1) are that it shows more
X    useful information, that the displayed information is more
X    comprehensible and that it is faster.
X
X
X    SPS is currently implemented for the following operating systems and
X    architectures.  The corresponding Makefiles are also shown here:
X
X	Makefile.4.1		Standard 4.1bsd for Vax
X	Makefile.4.2		Standard 4.2bsd, Ultrix 1.x for Vax
X	Makefile.4.3		Standard 4.3bsd (or 4.3-tahoe) for Vax
X	Makefile.4.3+NFS	4.3bsd+NFS from Wisconsin (Mt. Xinu?, others?)
X	Makefile.dec3100	DECStation 3100 + Ultrix 3.0 (incomplete)
X	Makefile.sun.2.0	Sun 4.2 UNIX Release 2.0 - 2.2 for Sun-2
X	Makefile.sun.3.0	Sun 4.2 UNIX Release 3.0 for Sun-2, Sun-3
X	Makefile.sun.3.2	Sun 4.2 UNIX Release 3.2 for Sun-2, Sun-3
X	Makefile.sun.4.0	SunOS 4.0 for Sun-2, Sun-3, Sun-4
X	Makefile.sun.4.0+386i	SunOS 4.0 for Sun 386i
X	Makefile.sun.4.1	SunOS 4.1 for Sun-2, Sun-3, Sun-4
X	Makefile.sun4.3.2	SunOS Sys 4-3.2 for Sun-4
X	Makefile.ultrix.2.0	DEC Ultrix 2.0 - 2.2
X	Makefile.ultrix.3.0	DEC Ultrix 3.0
X
X    (I also have a somewhat ancient implementation for V7 on a PDP-11 as well
X    as Unisoft Version 1.3 on a MC68000 if anyone is interested).
X
X
XWhat SPS does:
X    SPS displays wait channels symbolically, rather than as hexadecimal
X    addresses.  (If you wish to teach SPS about a new sort of device,
X    you must add an entry in the symbol table (globals2.c) as well as
X    increasing the size of that table (NWAITSTATE in sps.h)).
X
X    SPS sorts processes before listing them, the order reflecting the
X    relationship of the processes.  A child process is listed
X    underneath its corresponding parent and is indented to depict the
X    exact relationship.  SPS also indicates setuid processes.
X
X    SPS displays such values as the resident and virtual sizes of
X    system processes.  It accepts a whole range of options to control
X    the output.  By default, SPS lists information about one's own
X    processes.  Other options instruct it to be verbose (the "v"
X    option), to list all the command arguments of a process (the "w"
X    option) or to list the environment strings of that process (the "e"
X    option).  Similarly, there are options to control which processes
X    are to be displayed.  The "a" option tells it to describe all
X    processes and the "b" option tells it to describe "busy" processes;
X    the latter is useful if you wish to find out what is loading your
X    system.  There are also options to select the output according to
X    user, controlling tty or process number.
X
X    SPS keeps its information in an information file; by default, this
X    is /tmp/.spsinfo. This means that it can avoid having to do an
X    expensive nlist() operation each time it is run.  It must be
X    reinitialised (with the "i" option) if new users are added to
X    /etc/passwd or if a new version of /vmunix is installed.
X
X
XHow to build SPS:
X    1. In order to compile and install SPS, first unbundle the four shell
X       archive files.
X    2. Check that the define statements in sps.h are large enough for
X       your system.  In particular, you may need to increase MAXTTYS
X       to reflect the number of tty devices in /dev.  The parameter
X       MAXUSERS defines the maximum number of users defined in the
X       password file (or through the Yellow Pages).  Because the
X       user-ids are held in an internal hash table, this should
X       probably be at least double the number of actual users.
X    3. Choose an appropriate Makefile from the table above and compile
X       the source files.  For example:
X	   % make -f Makefile.sun.3.2
X    4. Try running SPS.  First, a suitable information file must be
X       initialised.  It should then be able to display information
X       concerning running processes on your system:
X	     # Initialise SPS.  Ignore any error messages at this stage.
X	   % sps i
X	     # Instruct SPS to list all active processes in verbose format.
X	   % sps va
X    5. If this all works, install SPS with the appropriate Makefile
X       and reinitialise it:
X	   % make -f Makefile.sun.3.2 install
X	   % sps -i
X
X
XBug reports:
X    Send all bug reports, fixes, comments and suggestions to Robert Ward at -
X
X~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
X    J. Robert Ward,
X    Olsen & Associates, Seefeldstrasse 233, CH-8008 Zuerich, Switzerland
X
XTel.:   +41 1 552224     Fax: +41 1 552282    Telex: 816656
XEmail:  robert at olsen.uu.ch              Uucp:  uunet!chx400!olsen!robert
XX.400:  s=robert/ou=olsen/o=uucp/p=switch/a=arcom/c=ch
X~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
END_OF_FILE
  if test 4769 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
  fi
  # end of 'README'
fi
if test -f 'getcmd.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'getcmd.c'\"
else
  echo shar: Extracting \"'getcmd.c'\" \(6872 characters\)
  sed "s/^X//" >'getcmd.c' <<'END_OF_FILE'
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 at 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_FILE
  if test 6872 -ne `wc -c <'getcmd.c'`; then
    echo shar: \"'getcmd.c'\" unpacked with wrong size!
  fi
  # end of 'getcmd.c'
fi
if test -f 'printproc.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'printproc.c'\"
else
  echo shar: Extracting \"'printproc.c'\" \(6875 characters\)
  sed "s/^X//" >'printproc.c' <<'END_OF_FILE'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)printproc.c	1.2\t8/2/90" ;
X# endif
X
X# include       "sps.h"
X# include       "flags.h"
X# ifndef SUNOS40
X# include       <h/text.h>
X# endif
X
X# ifdef SUNOS40
X#  ifdef OLDSTATS
X#   define OFFSET 8
X#  else
X#   define OFFSET 3
X#  endif
X# else
X#   define OFFSET 0
X# endif
X
X/* PRINTPROC - Pretty print a process according to the switches. */
Xprintproc ( p, md )
X
Xregister struct process         *p ;            
Xint                             md ;            
X
X{
X	register char           *chp ;
X# ifndef SUNOS40
X	register struct text    *tp ;
X# endif
X	register struct hashtab *hp ;
X	char                    chbuf[10] ;
X	time_t                  time ;
X	time_t                  chtime ;
X# ifdef BSD42
X	time_t                  utime ;
X	time_t                  uchtime ;
X# endif
X	extern short            Lastuid, Lastpgrp ;
X	extern struct flags     Flg ;
X	char                    *waitingfor() ;
X	struct hashtab          *hashuid() ;
X	double                  percentmem() ;
X
X	/* List tty name and foreground/background/detached information */
X	printf( "%2.2s%c", p->pr_tty->l_name,
X# ifdef SDETACH
X		!p->pr_p.p_pgrp ? ' ' : p->pr_p.p_flag & SDETACH ? '_' :
X		p->pr_p.p_pgrp == p->pr_tty->l_pgrp ? '.' : ' ' ) ;
X# else
X		!p->pr_p.p_pgrp || p->pr_p.p_pgrp != p->pr_tty->l_pgrp ?
X# ifdef SPGLDR
X		p->pr_p.p_flag & SPGLDR ? '-' :
X# endif
X	       ' ' :
X# ifdef SPGLDR
X		p->pr_p.p_flag & SPGLDR ? '+' :
X# endif
X	       '.' ) ;
X# endif
X	hp = hashuid( (int)p->pr_p.p_uid ) ;
X	if ( !md  )                             
X	{       /* If a top-level process, list the user name */
X		if ( hp )
X			printf( "%-8.8s ", hp->h_uname ) ;
X		else
X			printf( "user%-4.4d ", p->pr_p.p_uid ) ;
X	}
X	else                                    
X	{       /* Usually list an asterisk for a child process */
X		md = md > 8 ? 8 : md ;
X		printf( "%*s%c", md, "",
X			p->pr_p.p_pgrp == Lastpgrp ? '|' : '*' ) ;      
X		/* But beware of setuid processes */
X		md = 8 - md ;
X		if ( p->pr_p.p_uid == Lastuid )
X			printf( "%-*.*s", md, md, "" ) ;
X		else if ( hp )
X			printf( "%-*.*s", md, md, hp->h_uname ) ;
X		else
X		{
X			md -= 4 ;
X			printf( "user%-*.*d", md, md, p->pr_p.p_uid ) ;
X		}
X	}
X	Lastuid = p->pr_p.p_uid ;
X	Lastpgrp = p->pr_p.p_pgrp ;
X	if ( Flg.flg_d )                        
X	{       /* List disc I/O and paging information */
X		if ( !p->pr_upag || p->pr_p.p_stat == SZOMB )
X		{
X			prcmd( p, 49, -63 ) ;
X			return ;
X		}
X		printf( "%2d %8d+%8d %4d %8d %8D ",
X			p->pr_files,
X# ifdef BSD42
X			p->pr_rself.ru_majflt,
X			p->pr_rself.ru_minflt,
X			p->pr_rself.ru_nswap,
X			p->pr_rself.ru_inblock + p->pr_rself.ru_oublock,
X			KBYTES( p->pr_rself.ru_idrss + p->pr_rself.ru_isrss
X				+ p->pr_rself.ru_ixrss ) ) ;
X# else
X			p->pr_vself.vm_majflt,
X			p->pr_vself.vm_minflt,
X			p->pr_vself.vm_nswap,
X			p->pr_vself.vm_inblk + p->pr_vself.vm_oublk,
X			KBYTES( (p->pr_vself.vm_idsrss
X				+ p->pr_vself.vm_ixrss) / Info.i_hz ) ) ;
X# endif
X		prcmd( p, 5, -63 ) ;
X		return ;
X	}
X	if ( !Flg.flg_v )                       
X	{       /* Not verbose so just list command arguments */
X		prcmd( p, 5, -19 ) ;
X		return ;
X	}
X	/* Arrive here if being verbose ; list cpu information */
X	switch ( p->pr_p.p_stat )               
X	{                                       
X		case SSLEEP :
X		case SWAIT :
X		case SIDL :
X			/* Determine why a process should be in a wait state */
X			chp = waitingfor( p ) ;
X			break ;
X		case SRUN :
X			chp = "run" ;
X			break ;
X		case SZOMB :
X			chp = "exit" ;
X			break ;
X		case SSTOP :
X			chp = "stop" ;
X			break ;
X	}
X	/* If the process is loaded, list the status information in capitals */
X	printf( "%-6.6s ", p->pr_p.p_flag & SLOAD ?
X		(capitals( chp, chbuf ), chbuf) : chp ) ;
X	/* List process flags */
X	printf( "%c%c%c", p->pr_p.p_flag & SSYS ? 'U' :
X		p->pr_p.p_flag & STRC ? 'T' : ' ',
X		p->pr_p.p_flag & SVFORK ? 'V' :
X		p->pr_p.p_flag & SPHYSIO ? 'I' : ' ',
X		p->pr_p.p_flag & SUANOM ? 'A' :
X		p->pr_p.p_flag & SSEQL ? 'S' : ' ' ) ;
X	/* List process niceness */
X	if ( p->pr_p.p_nice != NZERO )          
X		printf( "%3d ", p->pr_p.p_nice - NZERO ) ;
X	else
X		printf( "    " ) ;
X	if ( p->pr_p.p_stat == SZOMB )
X	{
X		prcmd( p, 41 - OFFSET, OFFSET - 69 ) ;
X		return ;
X	}                                       
X# ifdef SUNOS40
X#  ifdef OLDSTATS
X	/* List process virtual and real sizes */
X	printf( "%4d", KBYTES( p->pr_p.p_dsize + p->pr_p.p_ssize ) ) ;
X#  else
X	/* List process private and shared virtual and real sizes */
X        printf("%4d", KBYTES( p->pr_private ) ) ;
X        printf("+%4d", KBYTES( p->pr_shared ) ) ;
X#  endif
X	printf( " %4d", KBYTES( p->pr_p.p_rssize ) ) ;
X# else
X	/* List process and text virtual sizes */
X	printf( "%4d", KBYTES( p->pr_p.p_dsize + p->pr_p.p_ssize ) ) ;
X	if ( tp = p->pr_p.p_textp )
X		printf( "+%3d ", KBYTES( tp->x_size ) ) ;
X	else
X		printf( "     " ) ;
X	/* List process and text real sizes */
X	printf( "%4d", KBYTES( p->pr_p.p_rssize ) ) ;
X	if ( tp )
X		printf( "+%3d", KBYTES( tp->x_rssize ) ) ;
X	else
X		printf( "    " ) ;
X# endif
X	printf( " %2.0f ", percentmem( p ) ) ;
X	/* List information obtained from the upage. This includes the process
X	   times and command arguments. */
X	if ( !p->pr_upag )
X	{
X		prcmd( p, 20, OFFSET - 69 ) ;
X		return ;
X	}                                       
X	/* List process time information */
X# ifdef BSD42
X	time   = Flg.flg_q ? p->pr_rself.ru_utime.tv_sec :
X		 p->pr_rself.ru_utime.tv_sec + p->pr_rself.ru_stime.tv_sec ;
X	utime  = Flg.flg_q ? p->pr_rself.ru_utime.tv_usec :
X		 p->pr_rself.ru_utime.tv_usec + p->pr_rself.ru_stime.tv_usec ;
X	chtime = Flg.flg_q ? p->pr_rchild.ru_utime.tv_sec :
X		 p->pr_rchild.ru_utime.tv_sec + p->pr_rchild.ru_stime.tv_sec ;
X	uchtime = Flg.flg_q ? p->pr_rchild.ru_utime.tv_usec :
X		 p->pr_rchild.ru_utime.tv_usec + p->pr_rchild.ru_stime.tv_usec ;
X	prcpu( time, utime ) ;
X	if ( chtime != 0L )
X	{
X		printf( "+" ) ;
X		prcpu( chtime, uchtime ) ;
X	}
X# else
X	time   = Flg.flg_q ? p->pr_vself.vm_utime :
X		 p->pr_vself.vm_utime + p->pr_vself.vm_stime ;
X	chtime = Flg.flg_q ? p->pr_vchild.vm_utime :
X		 p->pr_vchild.vm_utime + p->pr_vchild.vm_stime ;
X	prcpu( time ) ;
X	if ( chtime != 0L )
X	{
X		printf( "+" ) ;
X		prcpu( chtime ) ;
X	}
X# endif
X	else
X		printf( "      " ) ;
X# ifdef BSD42
X	if ( time || utime )
X# else
X	if ( time )
X# endif
X# ifdef SUN
X		printf( " %2.0f ", (double)p->pr_p.p_pctcpu * 100.0/FSCALE ) ;
X# else
X#  ifdef DEC3100
X		printf( " %2.0f ", p->pr_p.p_pctcpu ) ;
X#  else
X		printf( " %2.0f ", p->pr_p.p_pctcpu * 100.0 ) ;
X#  endif DEC3100
X# endif SUN
X	else
X		printf( "    " ) ;
X	/* Finally, list the process command arguments. */
X	prcmd( p, 5, OFFSET - 69 ) ;                    
X}
X
X/* CAPITALS - Converts letters in `chp' to upper-case in buffer `buf'. */
Xcapitals ( chp, buf )
X
Xregister char                   *chp ;
Xregister char                   *buf ;
X
X{
X	while ( *buf = *chp++ )
X	{
X		if ( 'a' <= *buf && *buf <= 'z' )
X			*buf -= 'a' - 'A' ;
X		buf++ ;
X	}
X}
END_OF_FILE
  if test 6875 -ne `wc -c <'printproc.c'`; then
    echo shar: \"'printproc.c'\" unpacked with wrong size!
  fi
  # end of 'printproc.c'
fi
if test -f 'sps.l' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'sps.l'\"
else
  echo shar: Extracting \"'sps.l'\" \(15259 characters\)
  sed "s/^X//" >'sps.l' <<'END_OF_FILE'
X.if n .pl 66
X.TH SPS 1
X.SH NAME
Xsps \ \ \-\ \ \ show process status
X.SH SYNOPSIS
X\fBsps\ \fP \ [ \fB\-cdefgijkoqrslvwyABDFNPSTUWZ\fP ]\ \ [
X\fIprocess\ .\ .\ .\ | tty\ .\ .\ .\ | user\ .\ .\ .\fP ]
X.SH DESCRIPTION
X\fISps\fP reports information concerning system processes.
XIt shows the current state of any process by
Xlisting information such as ownership, CPU time usage, memory usage
Xand disc activity.
X.PP
X\fISps\fP should be used in preference to \fIps\fP(1)
Xbecause it is faster and the output is more comprehensive and more
Xcomprehensible.
X.SH OPTIONS
XBy default, \fIsps\fP prints basic information about one's own processes.
XThe various options described below select other processes or make
X\fIsps\fP more verbose.
X.PP
XUpper case options select processes to be described.
XLower case options specify the format of the output.
XFor instance, the options \fBBv\fP specify that \fIsps\fP
Xshould list ``busy'' processes in a verbose format.
XUnless there is any conflict, lower case options may be used
Xinstead of upper case options, and vice versa.
X.PP
XThe following options specify the format of the listed output \-
X.TP 8
X\fB\-c\fP
XUse the system's idea of the command, rather than getting the arguments
Xfrom user space.  While somewhat less informative, this is faster and
Xmore reliable.
X.TP
X\fB\-d\fP
XList output reflecting how each process affects the
Xdisc and paging activity of the system.
X.TP
X\fB\-e\fP
XList the environment passed to each process.
X.TP
X\fB\-f\fP
XInclude the process\-id of the parent of each process.
X.TP
X\fB\-g\fP
XInclude the process group of each process.
X.TP
X\fB\-o\fP
XAvoid looking at the swap device (\fB/dev/drum\fP). This tends to make \fIsps\fP
Xrun faster, although no information concerning swapped processes
Xcan be obtained.
X.TP
X\fB\-q\fP
XBy default, \fIsps\fP
Xlists the sum of the user plus system times under the
X\fITime\fP and \fIChild\fP fields.  This option forces \fIsps\fP
Xto list only the user times.
X.TP
X\fB\-r\fP
XRepeat the output indefinitely.
XIf the next argument is numeric, \fIsps\fP repeats the output with that
Xmany seconds delay between each repetition.
XOtherwise the output is repeated with no delay.
X.TP
X\fB\-l\fP
X.br
X.ns
X.TP
X\fB\-v\fP
XList additional information in a verbose format. See below.
X.TP
X\fB\-w\fP
XList output in a wide format.  This option forces \fIsps\fP
Xto print all the command arguments, even if doing so extends the output
Xbeyond one line.
X.TP
X\fB\-y\fP
XShow the status of each terminal line.
X.PP
XThe following options specify which processes are to be described \-
X.TP 8
X\fB\-A\fP
XList all processes.
X.TP
X\fB\-B\fP
XList busy processes.  A process is considered to be busy
Xif it is immediately runnable or awaiting a fast event such as disc I/O.
X.TP
X\fB\-D\fP
XList detached processes.
X.TP
X\fB\-F\fP
XList foreground processes.
X.TP
X\fB\-N\fP
XShow no processes at all. Only the summary line is printed.
X.TP
X\fB\-P\fP
XList only processes whose identifiers are specified in the following arguments.
X.TP
X\fB\-S\fP
XList stopped processes.
X.TP
X\fB\-T\fP
XList only processes attached to the following specified terminals.
X.TP
X\fB\-U\fP
XList only processes belonging to the following specified users.
X.TP
X\fB\-W\fP
XList waiting processes.
X.TP
X\fB\-Z\fP
XList zomby (exiting) processes.
X.PP
XThe following are miscellaneous options \-
X.TP 8
X\fB\-i\fP
XInitialise \fIsps\fP.
XThis is necessary if new users are added to the password file,
Xor if a new version of UNIX is installed.
XSps builds a new information file summarising pertinent information
Xread from the password file (\fB/etc/passwd\fP), the executable kernel image
X(\fB/vmunix\fP) and the directory of tty devices (\fB/dev\fP).
XSee also the \fB\-j\fP and \fB\-s\fP options.
X.TP
X\fB\-j\fP
XSpecify an information file other than the default (\fB/etc/spsinfo\fP).
XThe next argument is taken to be the name of a suitable information file.
XIf the \fB\-i\fP flag is also specified, \fIsps\fP builds a
Xnew information file with the given name.
XOtherwise, \fBsps\fP reads previously created summarising information
Xfrom that file.
X.TP
X\fB\-k\fP
XUse a specific disc file rather than the default physical
Xmemory (\fB/dev/mem\fP)
Xand kernel virtual memory (\fB/dev/kmem\fP) files. The next argument is taken
Xto be the name of a suitable memory dump file.
XThis flag automatically sets the \fB\-o\fP flag.
X.TP
X\fB\-s\fP
XThis option is used in conjunction with the \fB\-i\fP option.
XThe next argument is taken to be the name of a suitable kernel executable
Xfile, rather than the default (\fB/vmunix\fP).
X\fISps\fP looks at the symbol table of this file to determine
Xthe virtual addresses of various kernel structures.
X.SH OUTPUT
X\fISps\fP produces output in the following fields \-
X.TP 8
X\fITy\fP
XThe terminal identifier to which the process is attached.
X.IP
XIf this is followed by an underscore, the process is detached.
XIf it is followed by a period, the process is running in the foreground.
XOtherwise the process is running in the background but is still
Xattached to a terminal.
X.TP
X\fIUser\fP
XThe symbolic name of the process' effective user-id (see \fIexec\fP(2)
Xand \fIsetuid\fP(2)).
XThis name is defined by the system password file (\fB/etc/passwd\fP)
Xwhen \fIsps\fP was last initialised.
XOtherwise, an asterisk (\fB*\fP) or vertical bar (\fB|\fP) appearing in this
Xcolumn denotes that the process is an immediate relative of the
Xpreceding process.
XA bar is listed, rather than an asterisk, if both processes belong
Xto the same process group.
XA user name is listed only if the effective user-id
Xdiffers from that of the preceding process or if it is a top-level
Xprocess (immediate offspring of process 1).
X.TP
X\fIProc#\fP
XThe unique process identifier.
X.TP
X\fIPpid#\fP
XThe process-id of the process' parent.
X.TP
X\fIPgrp#\fP
XThe process group to which the process belongs.
X.TP
X\fICommand\fP
XThe command arguments obtained from the process' own address space.
X(If the command name appears in parentheses, \fIsps\fP
Xwas unable to locate the arguments in user space and so reports
Xthe system's idea of the command name.)
X.PP
XThe following additional fields are listed when \fIsps\fP
Xis invoked with one of the \fB\-l\fP or \fB\-v\fP options \-
X.TP 8
X\fIStatus\fP
XThe process' current state.
XIf this field is listed in upper-case letters, the process is currently
Xloaded in real memory space ; otherwise it has been swapped out.
XThe status field may contain one of the following descriptions \-
X.RS 8
X.TP 16
X\fIrun\fP
XThe process can be run immediately.
X.TP
X\fIstop\fP
XThe process is stopped. See \fIsigvec\fP(2).
X.TP
X\fIexit\fP
XThe process is a zomby.
X.RE
X.IP
XAny other entry in the status field indicates the process is
Xwaiting for some external event to occur.
XThis is usually for one of the reasons listed below.
X(If \fIsps\fP does not know why a process is waiting, it lists
Xthe hexadecimal address of the process' wait channel,
Xwith the initial 80000000 trimmed off.)
XA process may be waiting for one of the following reasons \-
X.RS 8
X.TP 16
X\fIchild\fP
XThe process is waiting for a child to terminate. See \fIwait\fP(2).
X.TP
X\fIpause\fP
XWaiting for a signal to be received. See \fIsigpause\fP(2).
X.TP
X\fIswap\fP
XWaiting for a page to be swapped in.
X.TP
X\fIrswbuf\fP
XWaiting for a read from the swap device \fB/dev/drum.\fP
X.TP
X\fIdiscio\fP
XWaiting for a disc read or write operation.
X(Actually, this means that the process is waiting for an operation
Xthrough the kernel's I/O buffering mechanism to complete, but \fIdiscio\fP
Xis what is generally meant here).
X.TP
X\fIrpipe\fP
X.br
X.ns
X.TP
X\fIwpipe\fP
XWaiting for a read from an empty pipe.  Alternatively, the process
Xis waiting to write to a full pipe. See \fIpipe\fP(2).
X.TP
X\fIrsockt\fP
X.br
X.ns
X.TP
X\fIwsockt\fP
XWaiting for a read from an empty socket.
XAlternatively, the process is waiting to write to a full socket (4.[2\-]bsd only).
X.TP
X\fIaccept\fP
XWaiting to accept a stream-based socket connection (4.[2\-]bsd only).
XSee \fIaccept\fP(2).
X.TP
X\fIconnct\fP
XWaiting to establish a connection through a stream-based socket to a
Xremote process (4.[2\-]bsd only). See \fIconnect\fP(2).
X.TP
X\fIsocket\fP
XWaiting for some other time-out event on a socket (4.[2\-]bsd only).
X.TP
X\fIselect\fP
XBlocked by a \fIselect\fP(2) system call (4.[2\-]bsd only).
X.TP
X\fIrmux\fP
XWaiting for a read from a multiplexor file (4.1bsd only).
X.TP
X\fIinode\fP
XWaiting for an inode to be allocated or unlocked.
X.TP
X\fIexlock\fP
X.br
X.ns
X.TP
X\fIshlock\fP
XWaiting for a file to become unlocked. See \fIflock\fP(2).
X.TP
X\fIrtty??\fP
X.br
X.ns
X.TP
X\fIwtty??\fP
X.br
X.ns
X.TP
X\fIotty??\fP
XWaiting for a read or write to the specified terminal, or for the terminal
Xto be switched on. See \fItty\fP(4).
XAlternatively, waiting for a read or write to the
Xspecified slave pty device. See \fIpty\fP(4).
X.TP
X\fIitty??\fP
X.br
X.ns
XUnder SunOS, waiting perform I/O to an iconified window.
X.TP
X\fIrpty??\fP
X.br
X.ns
X.TP
X\fIwpty??\fP
XWaiting for a read or write to the specified master pty device.
XSee \fIpty\fP(4).
X.TP
X\fIptrace\fP
XThis is a parent process tracing its child.
X.TP
X\fIvfork\fP
XThis is a vforking parent process waiting for its child to relinquish
Xmemory resources. See \fIvfork\fP(2).
X.TP
X\fIfloppy\fP
X.br
X.ns
X.TP
X\fIprintr\fP
X.br
X.ns
X.TP
X\fIr??buf\fP
XWaiting for the specified device to complete an I/O operation.
X.RE
X.TP 8
X\fIFl\fP
XFlags associated with the current state of the process.
XThese flags may be any of the following \-
X.RS 8
X.TP 16
X\fIU\fP
XThe process is a UNIX system process.
X.TP
X\fIT\fP
XThe process is being traced or debugged.
X.TP
X\fIV\fP
XThe process is a child currently being vforked. See \fIvfork\fP(2).
X.TP
X\fII\fP
XThe process is undergoing physical I/O.
X.TP
X\fIA\fP
XThe system has detected, or the user has warned of
Xanomalous paging behaviour. See \fIvadvise\fP(2).
X.RE
X.TP 8
X\fINice\fP
XThe ``niceness'' of the process. See \fInice\fP(2).
X.TP
X\fIVirtual\fP
XThe virtual memory size of the process in kilobytes.
XThe first figure indicates the sum of the data and stack segments,
Xthe second figure that of the text segment.
X.TP
X\fIResident\fP
XThe resident memory size of the process in kilobytes, representing
Xthe real memory devoted to the process.
X.TP
X\fI%M\fP
XThe percentage of available real memory allocated to this process.
X.TP
X\fITime\fP
XThe total CPU time accumulated by this process.
X(This is the sum of the system plus user times, unless the \fB\-q\fP
Xflag is specified in which case only the user time is listed.)
X.TP
X\fIChild\fP
XThe total CPU time accumulated by the process' children.
X(This is the sum of the system plus user times, unless the \fB\-q\fP
Xflag is specified.)
X.TP
X\fI%C\fP
XThe percentage of available CPU time devoted to the process.
XThis figure is a decaying average, computed over the past second.
X.PP
XThe following fields are listed when \fIsps\fP is invoked with the
X\fB\-d\fP option \-
X.TP 8
X\fIFiles\fP
XThe number of open files for this process.
X.TP
X\fIPageFaults\fP
XThe number of major and minor page faults incurred by the process.
X.TP
X\fISwap\fP
XThe number of swaps incurred by the process.
X.TP
X\fIBlockI/O\fP
XThe number of block read or write operations performed
Xon behalf of the process.
X.TP
X\fIKbytesecs\fP
XThe integral of real memory usage over time.
XThus, if a process uses 60 kilobytes of real memory for 3 seconds,
Xthis figure is incremented by 180.
X.PP
XThe following fields are listed when \fIsps\fP is invoked with the
X\fB\-y\fP option \-
X.TP 8
X\fIDev\fP
XThe major and minor device numbers of the terminal.
X.TP
X\fIAddr\fP
XThe virtual address of the associated \fBstruct tty\fP in \fB/dev/kmem\fP.
X.TP
X\fIRawq\fP
X.br
X.ns
X.TP
X\fICanq\fP
X.br
X.ns
X.TP
X\fIOutq\fP
XThe number of characters in the terminal I/O queues.
XThese refer to the raw input queue, the canonical input queue
Xand the output queue.
X.TP
X\fIPgrp\fP
XThe process group associated with the terminal.
X.PP
XAfter listing the requested output, \fIsps\fP prints a summary line.
XThis indicates the number and total virtual memory size of all processes,
Xthe number and total virtual size of busy processes,
Xthe number and real memory size of loaded processes
Xand the number and real size of swapped processes.
X.SH DIAGNOSTICS
X\fISps\fP reports a self-explanatory message if it is given an
Xinvalid argument list.
XThe program also complains if it cannot find necessary system information.
X.PP
XAt initialisation, \fIsps\fP complains if it cannot find the addresses of
Xrequisite system structures in the kernel symbol file.
XThis is usually the case because the system is rarely configured to support
Xall known devices.
X\fISps\fP also complains if more than one user shares the same user-id
Xin the password file (\fB/etc/passwd\fP).
X.SH EXAMPLES
X\fBsps vb\fP
X.PP
X\fISps\fP describes all busy processes in a verbose manner.
X.PP
X\fBsps dtg 9 h1 co\fP
X.PP
X\fISps\fP lists processes associated with terminals \fB9\fP,
X\fBh1\fP and the \fBconsole\fP.
XThe output reflects the disc activity caused by these processes.
XThe process group of each process is also included in the output.
X.PP
X\fBsps weu robert fred \-r 2\fP
X.PP
X\fISps\fP reports processes belonging to the specified users.
XIt lists the environment as well as all the command arguments in a wide format.
XThe output is produced indefinitely, with a delay of two seconds between
Xeach listing.
X.PP
X\fBsps is /vmunix.new\fP
X.PP
X\fISps\fP is initialised. It reads its symbol information from the
Xspecified file.
X.SH FILES
X.ta 2.5i
X.nf
X\fB/dev/console\fP	Console
X\fB/dev/tty??\fP	Terminal and pty devices
X\fB/dev/kmem\fP	Kernel virtual memory
X\fB/dev/mem\fP	Physical memory
X\fB/dev/drum\fP	Paging and swap device
X\fB/etc/passwd\fP	Password file
X\fB/etc/spsinfo\fP	Information file
X\fB/vmunix\fP	Symbol file of \fB/dev/kmem\fP addresses
X\fB/etc/termcap\fP	To determine the output terminal width
X.fi
X.ta
X.SH SEE ALSO
X\fIiostat\fP(1), \fIkill\fP(1), \fIps\fP(1),
X\fIvmstat\fP(1), \fIexec\fP(2),
X\fIflock\fP(2), \fInice\fP(2), \fIpause\fP(2), \fIselect\fP(2), \fIsetuid\fP(2),
X\fIsigvec\fP(2), \fIvadvise\fP(2), \fIvfork\fP(2), \fIwait\fP(2),
X\fIpty\fP(4),\fItty\fP(4), \fIpstat\fP(8).
X.SH AUTHORS
XSeveral. In particular, J. E. Kulp and J. Robert Ward,
X\fB<robert at olsen.uucp>\fP.
X.LP
XNFS changes incorporated by Alexander Dupuy,
X\fB<dupuy at amsterdam.columbia.edu>\fP
X.LP
XSunOS 4.0 implementation by Alexander Dupuy and
XCharlie Kim \fB<cck at cunixc.cc.columbia.edu>\fP.
X.LP
XUltrix 2.\fIx\fP additions incorporated by Rob Lehman at CUUCA.
X.LP
XSunOS 4.1 additions incorporated by Sakari Jalovaara, \fB<sja at sirius.hut.fi>\fP.
X.LP
XCurrently maintained by J. Robert Ward, \fB<robert at olsen.uu.ch>\fP
X.SH BUGS
XBecause the system is continually changing, the information reported by
X\fIsps\fP is only an approximation to reality.
XIf invoked by root, \fIsps\fP renices itself to \-20 in an attempt to run as
Xfast as possible.
X.PP
X\fISps\fP recognises the sizes and addresses of internal kernel
Xtables whenever it is invoked. However, it must be recompiled
Xif major modifications are made to the kernel.
X.PP
X\fISps\fP does not list all the detailed information shown by \fIps\fP(1).
XNor are all the options supported by \fIps\fP(1) available from \fIsps\fP.
X.PP
X\fISps\fP does not understand all the possible
Xreasons why a process may be sleeping.
X.PP
XThe code of \fIsps\fP is inherently machine-dependent and non-portable.
X.PP
XThe number of options to \fIsps\fP is ridiculous.
END_OF_FILE
  if test 15259 -ne `wc -c <'sps.l'`; then
    echo shar: \"'sps.l'\" unpacked with wrong size!
  fi
  # end of 'sps.l'
fi
if test -f 'ttystatus.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'ttystatus.c'\"
else
  echo shar: Extracting \"'ttystatus.c'\" \(3826 characters\)
  sed "s/^X//" >'ttystatus.c' <<'END_OF_FILE'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)ttystatus.c	1.1\t10/1/88" ;
X# endif
X
X# include       "sps.h"
X# include       "flags.h"
X# include       <stdio.h>
X# include       <h/ioctl.h>
X# ifdef SUNOS40
X# include       <h/stream.h>
X# else
X# include       <h/tty.h>
X# endif
X# ifdef CHAOS
X# include       <chunix/chsys.h>
X# include       <chaos/chaos.h>
X# endif
X
X/*
X** TTYSTATUS - Reads the kernel memory for tty structures of active processes.
X** The addresses of the associated struct ttys of /dev/kmem are kept in the
X** info structure. Here we use those addresses to access the structures.
X** Actually, we are mostly interested just in the process group of each tty.
X*/
Xttystatus ()
X{
X	register struct ttyline *lp ;
X# ifdef SUNOS40
X	struct stdata           *stdata ;
X	extern struct stdata    *getstdata() ;
X# else
X	struct tty              tty ;
X# endif
X	extern struct flags     Flg ;
X	extern struct info      Info ;
X# ifndef KVM
X	extern int              Flkmem ;
X# endif
X
X# ifdef SUNOS40
X	if ( !init_streams_tab() )
X		fprintf( stderr, "can't read streams table\n" ) ;
X# endif
X
X	if ( Flg.flg_y )
X# ifdef SUNOS40
X		printf( "Ty   Dev       Addr  Pgrp\n" ) ;
X# else
X		printf( "Ty   Dev       Addr Rawq Canq Outq  Pgrp\n" ) ;
X# endif
X	lp = Info.i_ttyline ;
X# ifdef CHAOS
X	while ( lp->l_name[0] && lp->l_name[0] != 'C' )
X# else
X	while ( lp->l_name[0] )
X# endif
X	{
X# ifdef SUNOS40 
X		if ( stdata = getstdata ( lp->l_addr, lp->l_dev ) )
X		{
X			lp->l_stdata = stdata ;
X			lp->l_pgrp = stdata->sd_pgrp ;
X			prstr( lp, stdata ) ;
X		}
X		else
X			lp->l_pgrp = 0 ;
X		lp++ ;
X# else
X		if ( getkmem( (long)lp->l_addr, (char*)&tty, sizeof( tty ) )
X		!= sizeof( struct tty ) )
X		{
X			fprintf( stderr,
X				"sps - Can't read struct tty for tty%.2s\n",
X				lp->l_name ) ;
X			lp->l_pgrp = 0 ;
X			lp++ ;
X			continue ;
X		}
X		lp->l_pgrp = tty.t_pgrp ;
X		prtty( lp, &tty ) ;
X		lp++ ;
X# endif
X	}
X# ifdef CHAOS
X	chaosttys( lp ) ;               
X# endif
X}
X
X# ifdef SUNOS40
X
X/* PRSTR - Print out the stdata structure */
Xprstr ( lp, stdata )
X
Xregister struct ttyline         *lp ;
Xregister struct stdata          *stdata ;
X
X{
X	extern struct flags     Flg ;
X
X	if ( !Flg.flg_y )
X		return ;
X	printf( "%-2.2s %2d,%2d 0x%08x %5d\n",
X		lp->l_name,
X		major( lp->l_dev ),
X		minor( lp->l_dev ),
X		lp->l_addr,
X		stdata->sd_pgrp ) ;
X}
X
X# else
X
X/* PRTTY - Print out the tty structure */
Xprtty ( lp, tty )
X
Xregister struct ttyline         *lp ;
Xregister struct tty             *tty ;
X
X{
X	extern struct flags     Flg ;
X
X	if ( !Flg.flg_y )
X		return ;
X	printf( "%-2.2s %2d,%2d 0x%08x %4d %4d %4d %5d\n",
X		lp->l_name,
X		major( lp->l_dev ),
X		minor( lp->l_dev ),
X		lp->l_addr,
X		tty->t_rawq.c_cc,
X		tty->t_canq.c_cc,
X		tty->t_outq.c_cc,
X		tty->t_pgrp ) ;
X}
X
X# endif
X
X# ifdef CHAOS
X
X/* CHAOSTTYS - Finds ttys attached to the Chaos net */
Xchaosttys ( lp )
X
Xregister struct ttyline         *lp ;
X
X{
X	register struct connection      **cnp ;
X	register int                    i ;
X	struct tty                      tty ;
X	struct connection               *conntab[CHNCONNS] ;
X	struct connection               conn ;
X	extern struct info              Info ;
X	extern int                      Flkmem ;
X
X	(void)getkmem( (long)Info.i_Chconntab, (char*)conntab,
X		sizeof( conntab ) ) ;
X	for ( i = 0, cnp = conntab ; cnp < &conntab[CHNCONNS] ; i++, cnp++ )
X	{
X		if ( !*cnp )
X			continue ;
X		(void)getkmem( (long)*cnp, (char*)&conn, sizeof( conn ) ) ;
X		if ( !(conn.cn_flags & CHTTY) )
X			continue ;
X		(void)getkmem( (long)conn.cn_ttyp, (char*)&tty, sizeof( tty ) ) ;
X		if ( lp >= &Info.i_ttyline[MAXTTYS] )
X			prexit( "sps - Too many chaos ttys\n" ) ;
X		lp->l_addr = conn.cn_ttyp ;
X		lp->l_pgrp = tty.t_pgrp ;
X		lp->l_dev = tty.t_dev ;
X		lp->l_name[0] = 'C' ;
X		lp->l_name[1] = i < 10 ? '0'+i : i-10 <= 'z'-'a' ? i-10+'a' :
X				i-10-('z'-'a')+'A' ;
X		prtty( lp, &tty ) ;
X		lp++ ;
X	}
X}
X
X# endif
END_OF_FILE
  if test 3826 -ne `wc -c <'ttystatus.c'`; then
    echo shar: \"'ttystatus.c'\" unpacked with wrong size!
  fi
  # end of 'ttystatus.c'
fi
if test -f 'waitingfor.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'waitingfor.c'\"
else
  echo shar: Extracting \"'waitingfor.c'\" \(9904 characters\)
  sed "s/^X//" >'waitingfor.c' <<'END_OF_FILE'
X# ifndef lint
Xstatic char SccsId[] =  "@(#)waitingfor.c	1.5\t8/6/90" ;
X# endif
X
X# include		"sps.h"
X# ifndef SUNOS40
X# include		<h/text.h>
X# endif SUNOS40
X
X# ifdef NFS
X#  ifdef DEC3100
X#   include		<h/gnode.h>
X#   include		<h/inode.h>
X#  else DEC3100
X#   include		<h/vnode.h>
X#   include		<ufs/inode.h>
X# endif DEC3100
X# else
X#  include		<h/inode.h>
X# endif NFS
X
X# include		<h/ioctl.h>
X# ifdef SUNOS40
X#  include		<h/stream.h>
X#  include		<h/tty.h>
X#  include		<h/ptyvar.h>
X# else SUNOS40
X#  include		<h/tty.h>
X# endif SUNOS40
X
X# include		<h/buf.h>
X# ifdef BSD42
X#  ifdef NFS
X#   ifndef NOQUOTA
X#    ifdef DEC3100
X#     include		<h/quota.h>
X#    else
X#     include		<ufs/quota.h>
X#    endif DEC3100
X#   endif NOQUOTA
X#  else NFS
X#   include		<h/quota.h>
X#  endif NFS
X# include		<h/mbuf.h>
X# include		<h/socket.h>
X# include		<h/socketvar.h>
X# endif BSD42
X
X/* 1 if `w' is in the address range defined by `a1' and `a2' ... */
X# define        INRANGE( w, a1, a2 ) \
X			( (caddr_t)(a1) <= (w) && (w) < (caddr_t)(a2) )
X
X/* NFS changes incorporated by Alexander Dupuy <dupuy at amsterdam.columbia.edu> */
X
X/* WAITINGFOR - Determine what a process is waiting for and describe it. */
Xchar    *waitingfor ( p )
X
Xstruct process                  *p ;
X
X{
X	register caddr_t        w ;
X	register struct ttyline *lp ;
X	register struct symbol  *s ;
X	register char           *cp ;
X# ifdef BSD42
X	struct socket           sc ;
X# endif
X	int			rc ;
X	static char             wbuf[ 8 ] ;
X	extern struct info      Info ;
X	extern struct symbol    Symbollist[] ;
X	char                    *sprintf() ;
X# ifdef SUNOS40
X	char                    *gettty() ;
X# endif
X
X	w = p->pr_p.p_wchan ;
X	if ( !w )
X		return ( "null" ) ;
X	/* Waiting for a child process, alternatively in a vfork() ? */
X	if ( INRANGE( w, Info.i_proc0, &Info.i_proc0[ Info.i_nproc ] ) )
X		return ( p->pr_p.p_flag & SNOVM ? "vfork" : "child" ) ;
X# ifndef SUNOS40
X	/* Waiting for a page to be brought in ? */
X	if ( INRANGE( w, Info.i_swbuf0, &Info.i_swbuf0[ Info.i_nswbuf ] ) )
X		return ( "swap" ) ;
X	/* Waiting for discio through a block device to complete ? */
X	if ( INRANGE( w, Info.i_buf0, &Info.i_buf0[ Info.i_nbuf ] ) )
X		/* SHOULD ACTUALLY READ AS "blkio" BUT "discio" IS WHAT
X		   IS GENERALLY MEANT HERE. */
X		return ( "discio" ) ;
X	/* Waiting for a text page to be brought in ? */
X	if ( INRANGE( w, Info.i_text0, &Info.i_text0[ Info.i_ntext ] ) )
X		return ( "swtext" ) ;
X# endif SUNOS40
X
X# ifdef BSD42
X#  ifndef NOQUOTA
X	/* Waiting for an event associated with the quota system ? */
X	if ( INRANGE( w, Info.i_quota0, &Info.i_quota0[ Info.i_nquota ] ) )
X		return ( "quota" ) ;
X#  endif NOQUOTA
X# endif BSD42
X
X# ifndef SUNOS41
X		 /* Sorry, I don't know how to do this...
X		  * I kinda think that SunOS 4.1 allocates inode
X		  * buffer entries dynamically.  Maybe it could be
X		  * possible to read in all "struct file"s and
X		  * compare each file.f_data to the wait channel.	++sja
X		  */
X	/* Waiting for an inode ? */
X	if ( INRANGE( w, Info.i_inode0, &Info.i_inode0[ Info.i_ninode ] ) )
X#  ifdef ULTRIX20
X		switch ( ((int)w - (int)Info.i_inode0) % sizeof( struct gnode ))
X#  else
X		switch ( ((int)w - (int)Info.i_inode0) % sizeof( struct inode ))
X#  endif ULTRIX20
X		{
X#  ifdef BSD42
X#   ifdef NFS
X			case (int)&((struct inode*)0)->i_vnode.v_exlockc :
X				/* Exclusive lock on this inode */
X				return ( "exlock" ) ;
X			case (int)&((struct inode*)0)->i_vnode.v_shlockc :
X				/* Shared lock on this inode */
X				return ( "shlock" ) ;
X#   else NFS
X#    ifdef ULTRIX20
X#     ifndef DEC3100
X			/* Compile this code with gcc if you want to run it
X			   properly.  The DEC compiler can't handle this. */
X			case (int)&((struct gnode*)0)->g_exlockc :
X				/* Exclusive lock on this inode */
X				return ( "exlock" ) ;
X			case (int)&((struct gnode*)0)->g_shlockc :
X				/* Shared lock on this inode */
X				return ( "shlock" ) ;
X			case (int)&((struct gnode*)0)->g_frcnt :
X				/* Open fifo with no readers */
X				return ( "wfifo" ) ;
X			case (int)&((struct gnode*)0)->g_fwcnt :
X				/* Open fifo with no writers */
X				return ( "rfifo" ) ;
X#     endif DEC3100
X#    else ULTRIX20
X			case (int)&((struct inode*)0)->i_exlockc :
X				/* Exclusive lock on this inode */
X				return ( "exlock" ) ;
X			case (int)&((struct inode*)0)->i_shlockc :
X				/* Shared lock on this inode */
X				return ( "shlock" ) ;
X#    endif ULTRIX20
X#   endif NFS
X#  else BSD42 
X			case 1 :
X				return ( "wpipe" ) ;
X			case 2 :
X				return ( "rpipe" ) ;
X			case (int)&((struct inode*)0)->i_un.i_group.g_datq :
X				return ( "rmux" ) ;
X#  endif BSD42
X			default :
X				/* Inode probably locked */
X				return ( "inode" ) ;
X		}
X# endif SUNOS41
X
X# if defined(BSD42) && (defined(SUNOS40) || defined(NMBCLUSTERS))
X	/* Waiting for a structure inside an mbuf ? If so, try to find why */
X#  ifdef SUNOS40
X	if ( INRANGE( w, Info.i_mbutl,
X	&Info.i_mbutl[ MBPOOLBYTES / sizeof( struct mbuf ) ] ) )
X#  else
X	if ( INRANGE( w, Info.i_mbutl,
X	&Info.i_mbutl[ NMBCLUSTERS * CLBYTES / sizeof( struct mbuf ) ] ) )
X#  endif SUNOS40
X		switch ( ((int)w - (int)Info.i_mbutl) % sizeof( struct mbuf )
X			- (int)&((struct mbuf*)0)->m_dat[0] )
X		{
X			case (int)&((struct socket*)0)->so_timeo :
X				/* Socket timeout event - Guess why */
X				rc = getsocket( (struct socket*)(w
X				    - (int)&((struct socket*)0)->so_timeo),
X						&sc ) ;
X				return ( rc && (sc.so_state & SS_ISCONNECTING)
X					? "connct" 
X					: rc && ((sc.so_options & SO_ACCEPTCONN)
X					  && !sc.so_qlen)
X					? "accept" : "socket" ) ;
X			case (int)&((struct socket*)0)->so_rcv.sb_cc :
X				/* Read from an empty socket. Here we actually
X				   attempt to determine whether the socket
X				   structure in question really does refer to
X				   a socket, or whether it is in fact a pipe
X				   in disguise. */
X				return ( getsocket( (struct socket*)(w
X				    - (int)&((struct socket*)0)->so_rcv.sb_cc),
X						&sc )
X					&& sc.so_type == SOCK_STREAM
X#  ifdef BSD43
X					&& ((sc.so_state
X					    & (SS_ISCONNECTED|SS_CANTSENDMORE))
X					    == (SS_ISCONNECTED|SS_CANTSENDMORE))
X#  else
X					&& !sc.so_rcv.sb_hiwat
X					&& !sc.so_rcv.sb_mbmax
X					&& (sc.so_state
X					    & (SS_ISCONNECTED|SS_CANTRCVMORE))
X#  endif BSD43
X					? "rpipe" : "rsockt" ) ;
X			case (int)&((struct socket*)0)->so_snd.sb_cc :
X				/* Write to a full socket. Again, we try
X				   to determine whether or not this is a
X				   real socket or a pipe. */
X				return ( getsocket( (struct socket*)(w
X				    - (int)&((struct socket*)0)->so_snd.sb_cc),
X						&sc )
X#  ifdef BSD43
X					&& sc.so_type == SOCK_STREAM
X					&& ((sc.so_state
X					    & (SS_ISCONNECTED|SS_CANTRCVMORE))
X					    == (SS_ISCONNECTED|SS_CANTRCVMORE))
X#  else
X					&& sc.so_rcv.sb_hiwat == 2048
X					&& sc.so_rcv.sb_mbmax == 4096
X					&& (sc.so_state
X					    & (SS_ISCONNECTED|SS_CANTSENDMORE))
X#  endif BSD43
X					? "wpipe" : "wsockt" ) ;
X			default :
X				/* Other mbuf event */
X				return ( "mbuf" ) ;
X		}
X# endif BSD42
X
X# ifdef SUNOS41
X	if  ( w == (caddr_t)p->pr_p.p_uarea )
X		return ( "pause" ) ;
X# endif SUNOS41
X	/* Look in the symbol table for known wait addresses. */
X	for ( s = Symbollist ; s->s_kname ; s++ )
X		if ( s->s_wait && w == *s->s_info )
X			return ( s->s_wait ) ;
X
X# ifdef SUNOS40
X	/* Have to check for ptys in a funny sort of way */
X	if ( INRANGE( w, Info.i_ptybase, &Info.i_ptybase[ Info.i_npty ] ) )
X	{
X		switch ( ((int)w - (int)Info.i_ptybase) % sizeof( struct pty ) )
X		{
X			case (int)&((struct pty*)0)->pt_flags :
X				cp = "opty??" ;
X				break ;
X			case (int)&((struct pty*)0)->pt_ttycommon.t_writeq :
X				cp = "spty??" ;
X				break ;
X			default :
X				cp = "?pty??" ;
X		}
X		/* by the conventional naming, anyhow */
X		cp[4] = 'p' + (((int)w - (int)Info.i_ptybase)
X			/ sizeof( struct pty )) / 16 ;
X		if ( ( cp[5] = '0' + (((int) w - (int)Info.i_ptybase)
X			/ sizeof( struct pty )) % 16 ) > '9' )
X			cp[5] += 'a' - '9' - 1 ;
X		return( cp ) ;
X	}
X	/* Check for ttys last, since there may be a lot of them. */
X	if ( p->pr_tty != 0 )
X		if ( cp = gettty( p->pr_tty, w ) )
X			return( cp ) ;
X	for ( lp = Info.i_ttyline ; lp->l_name[0] ; lp++ )
X		if ( cp = gettty( lp, w ) )
X			return( cp ) ;
X# else SUNOS40
X	/* Waiting for tty I/O ? If so, find which tty it is */
X	for ( lp = Info.i_ttyline ; lp->l_name[0] ; lp++ )
X		if ( INRANGE( w, &lp->l_addr[0], &lp->l_addr[1] ) )
X		{
X#  ifdef DEC3100
X			/* Cretinous DEC compiler can't handle case
X			   constructs like the following ... */
X			cp = "?tty??" ;
X#  else DEC3100
X			switch ( (int)w - (int)lp->l_addr )
X			{
X				case (int)&((struct tty*)0)->t_rawq :
X					/* Read from a tty or slave pty */
X					cp = "rtty??" ;
X					break ;
X				case (int)&((struct tty*)0)->t_outq :
X					/* Write to a tty or slave pty */
X					cp = "wtty??" ;
X					break ;
X				case (int)&((struct tty*)0)->t_canq :
X					/* Waiting for icon to be opened */
X					cp = "itty??" ;
X					break ;
X				case (int)&((struct tty*)0)->t_state :
X					/* Tty not open */
X					cp = "otty??" ;
X					break ;
X				case (int)&((struct tty*)0)->t_outq.c_cf :
X					/* Read from a controller pty */
X					cp = "rpty??" ;
X					break ;
X				case (int)&((struct tty*)0)->t_rawq.c_cf :
X					/* Write to a controller pty */
X					cp = "wpty??" ;
X					break ;
X				default :
X					cp = "?tty??" ;
X					break ;
X			}
X#  endif DEC3100
X			cp[4] = lp->l_name[0] ;
X			cp[5] = lp->l_name[1] ;
X			return ( cp ) ;
X		}
X# endif SUNOS40
X
X	/* No reason for the wait state has been found.
X	   Return the wait channel as a hexadecimal address. */
X# ifdef SUN
X	(void)sprintf( wbuf, "x%05x", w - KERNELBASE ) ;
X# else
X	(void)sprintf( wbuf, "x%05x", w - 0x80000000 ) ;
X# endif
X	return ( wbuf ) ;
X}
X
X
X# ifdef BSD42
X/*
X** GETSOCKET - Reads a `struct socket' from the kernel virtual memory address
X** identified by `ks' into the buffer `s'.
X*/
Xgetsocket ( ks, s )
X
Xstruct socket                   *ks ;
Xstruct socket                   *s ;
X
X{
X	return ( getkmem( (long)ks, (char*)s, sizeof( struct socket ) )
X		== sizeof( struct socket ) ) ;
X}
X# endif BSD42
END_OF_FILE
  if test 9904 -ne `wc -c <'waitingfor.c'`; then
    echo shar: \"'waitingfor.c'\" unpacked with wrong size!
  fi
  # end of 'waitingfor.c'
fi
echo shar: End of archive 1 \(of 4\).
cp /dev/null ark1isdone
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