Newsgroups: comp.sources.unix
From: robert@olsen.ch (Robert Ward)
Subject: v26i026: sps3 - show process status, Part03/03
Sender: unix-sources-moderator@pa.dec.com
Approved: vixie@pa.dec.com

Submitted-By: robert@olsen.ch (Robert Ward)
Posting-Number: Volume 26, Issue 26
Archive-Name: sps3/part03

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 3 (of 3)."
# Contents:  getcmd.c printproc.c sps.1 waitingfor.c
# Wrapped by vixie@cognition.pa.dec.com on Sat May  9 22:30:50 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'getcmd.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'getcmd.c'\"
else
echo shar: Extracting \"'getcmd.c'\" \(7639 characters\)
sed "s/^X//" >'getcmd.c' <<'END_OF_FILE'
X# ifndef lint
static char SccsId[] =  "@(#)getcmd.c	1.8\t6/26/91" ;
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*/
char    *getcmd ( p )
X
register struct process         *p ;
X
X{
X# ifdef KVM
X	char                    **ap ;
X	char                    *cp ;
X	char                    *sp ;
X	int			spsize ;
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# ifdef ULTRIX40
X	if ( !(p->pr_p.p_sched & SLOAD) && Flg.flg_o )
X# else
X	if ( !(p->pr_p.p_flag & SLOAD) && Flg.flg_o )
X# endif
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# ifdef ULTRIX40
X	if ( p->pr_p.p_type & SSYS )            
X# else
X	if ( p->pr_p.p_flag & SSYS )            
X# endif
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 ULTRIX40
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 ULTRIX40
X	if ( Flg.flg_c )
X# endif ULTRIX40
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	
X
X# ifdef KVM
X	spsize = sizeof( argbuf ) - 2 ;
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	while ( ap && *ap )
X	{
X		/* Copy one string from argv or env */
X		cp = *ap++ ;
X		while ( cp && *cp )
X			if ( isprint( *cp ) )
X				/* Be careful not to overrun allocated array.
X				   Fix provided by Matti E Aarnio
X				   <mea@nic.funet.fi> */
X				if ( --spsize > 0 )
X					*sp++ = *cp++ ;
X				else
X					++cp ;
X			else
X			{
X				/* Replace control characters with ?'s */
X				if ( ++nbad > 5 )
X				{
X					if ( --spsize > 0 )
X	  					*sp++ = ' ' ;
X  					break ;
X  				}
X				if ( --spsize > 0 )
X					*sp++ = '?' ;
X				cp++ ;
X			}
X		if (--spsize > 0)
X			*sp++ = ' ' ;
X		/* Check if at end of argv and user wants to see env */
X		if ( ap && *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	}
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# ifdef ULTRIX40
X	if ( (p->pr_p.p_sched & SLOAD)
X# else
X	if ( (p->pr_p.p_flag & SLOAD)
X# endif
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# ifdef ULTRIX40
X		vstodb( 0, ctod( CLSIZE ),&p->pr_p.p_smap, &db, 1 ) ;
X# else
X		vstodb( 0, ctod( CLSIZE ), &User.u_us.u_smap, &db, 1 ) ;
X# endif
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, (char *)argbuf.a_argc, CLSIZE*NBPG )
X		!= 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
getsysargs :
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*/
vstodb ( vsbase, vssize, dmp, dbp, rev )
X
register int                    vsbase ;
register int                    vssize;
struct dmap                     *dmp ;
register struct dblock          *dbp ;
int                             rev ;
X
X{
X	register int            blk ;
X	register swblk_t        *ip ;
X# ifdef BSD42
X	extern struct info      Info ;
X# endif
X# ifndef ULTRIX40
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# else ULTRIX40
X	blk = Info.i_swapfrag ;
X	ip =  dmp->dm_map ;
X	ip += (vsbase/blk) ;
X        vsbase %= blk;
X# endif ULTRIX40
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 7639 -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'\" \(7216 characters\)
sed "s/^X//" >'printproc.c' <<'END_OF_FILE'
X# ifndef lint
static char SccsId[] =  "@(#)printproc.c	1.4\t12/4/91" ;
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. */
printproc ( p, md )
X
register struct process         *p ;            
int                             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# ifdef ULTRIX40
X	printf( "%-6.6s ", p->pr_p.p_sched & SLOAD ?
X# else
X	printf( "%-6.6s ", p->pr_p.p_flag & SLOAD ?
X# endif
X		(capitals( chp, chbuf ), chbuf) : chp ) ;
X	/* List process flags */
X# ifdef ULTRIX40
X	printf( "%c%c%c", p->pr_p.p_type & SSYS ? 'U' :
X		p->pr_p.p_trace & STRC ? 'T' : ' ',
X		p->pr_p.p_vm & SVFORK ? 'V' :
X		p->pr_p.p_vm & SPHYSIO ? 'I' : ' ',
X		p->pr_p.p_vm & SUANOM ? 'A' :
X		p->pr_p.p_vm & SSEQL ? 'S' : ' ' ) ;
X# else
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# endif
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 ULTRIX40
X		printf( " %2.0f ", p->pr_p.p_pctcpu ) ;
X#  else
X		printf( " %2.0f ", p->pr_p.p_pctcpu * 100.0 ) ;
X#  endif ULTRIX40
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'. */
capitals ( chp, buf )
X
register char                   *chp ;
register 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 7216 -ne `wc -c <'printproc.c'`; then
    echo shar: \"'printproc.c'\" unpacked with wrong size!
fi
# end of 'printproc.c'
fi
if test -f 'sps.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'sps.1'\"
else
echo shar: Extracting \"'sps.1'\" \(15346 characters\)
sed "s/^X//" >'sps.1' <<'END_OF_FILE'
X.if n .pl 66
X.TH SPS 1
X.SH NAME
sps \ \ \-\ \ \ 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.
It shows the current state of any process by
listing information such as ownership, CPU time usage, memory usage
and disc activity.
X.PP
X\fISps\fP should be used in preference to \fIps\fP(1)
because it is faster and the output is more comprehensive and more
comprehensible.
X.SH OPTIONS
By default, \fIsps\fP prints basic information about one's own processes.
The various options described below select other processes or make
X\fIsps\fP more verbose.
X.PP
Upper case options select processes to be described.
Lower case options specify the format of the output.
XFor instance, the options \fBBv\fP specify that \fIsps\fP
should list ``busy'' processes in a verbose format.
Unless there is any conflict, lower case options may be used
instead of upper case options, and vice versa.
X.PP
The following options specify the format of the listed output \-
X.TP 8
X\fB\-c\fP
Use the system's idea of the command, rather than getting the arguments
from user space.  While somewhat less informative, this is faster and
more reliable.
X.TP
X\fB\-d\fP
List output reflecting how each process affects the
disc and paging activity of the system.
X.TP
X\fB\-e\fP
List the environment passed to each process.
X.TP
X\fB\-f\fP
Include the process\-id of the parent of each process.
X.TP
X\fB\-g\fP
Include the process group of each process.
X.TP
X\fB\-o\fP
Avoid looking at the swap device (\fB/dev/drum\fP). This tends to make \fIsps\fP
run faster, although no information concerning swapped processes
can be obtained.
X.TP
X\fB\-q\fP
By default, \fIsps\fP
lists the sum of the user plus system times under the
X\fITime\fP and \fIChild\fP fields.  This option forces \fIsps\fP
to list only the user times.
X.TP
X\fB\-r\fP
Repeat the output indefinitely.
If the next argument is numeric, \fIsps\fP repeats the output with that
many seconds delay between each repetition.
Otherwise the output is repeated with no delay.
X.TP
X\fB\-l\fP
X.br
X.ns
X.TP
X\fB\-v\fP
List additional information in a verbose format. See below.
X.TP
X\fB\-w\fP
List output in a wide format.  This option forces \fIsps\fP
to print all the command arguments, even if doing so extends the output
beyond one line.
X.TP
X\fB\-y\fP
Show the status of each terminal line.
X.PP
The following options specify which processes are to be described \-
X.TP 8
X\fB\-A\fP
List all processes.
X.TP
X\fB\-B\fP
List busy processes.  A process is considered to be busy
if it is immediately runnable or awaiting a fast event such as disc I/O.
X.TP
X\fB\-D\fP
List detached processes.
X.TP
X\fB\-F\fP
List foreground processes.
X.TP
X\fB\-N\fP
Show no processes at all. Only the summary line is printed.
X.TP
X\fB\-P\fP
List only processes whose identifiers are specified in the following arguments.
X.TP
X\fB\-S\fP
List stopped processes.
X.TP
X\fB\-T\fP
List only processes attached to the following specified terminals.
X.TP
X\fB\-U\fP
List only processes belonging to the following specified users.
X.TP
X\fB\-W\fP
List waiting processes.
X.TP
X\fB\-Z\fP
List zomby (exiting) processes.
X.PP
The following are miscellaneous options \-
X.TP 8
X\fB\-i\fP
Initialise \fIsps\fP.
This is necessary if new users are added to the password file,
or if a new version of UNIX is installed.
Sps builds a new information file summarising pertinent information
read 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).
See also the \fB\-j\fP and \fB\-s\fP options.
X.TP
X\fB\-j\fP
Specify an information file other than the default (\fB/etc/spsinfo\fP).
The next argument is taken to be the name of a suitable information file.
If the \fB\-i\fP flag is also specified, \fIsps\fP builds a
new information file with the given name.
Otherwise, \fBsps\fP reads previously created summarising information
from that file.
X.TP
X\fB\-k\fP
Use a specific disc file rather than the default physical
memory (\fB/dev/mem\fP)
and kernel virtual memory (\fB/dev/kmem\fP) files. The next argument is taken
to be the name of a suitable memory dump file.
This flag automatically sets the \fB\-o\fP flag.
X.TP
X\fB\-s\fP
This option is used in conjunction with the \fB\-i\fP option.
The next argument is taken to be the name of a suitable kernel executable
file, rather than the default (\fB/vmunix\fP).
X\fISps\fP looks at the symbol table of this file to determine
the virtual addresses of various kernel structures.
X.SH OUTPUT
X\fISps\fP produces output in the following fields \-
X.TP 8
X\fITy\fP
The terminal identifier to which the process is attached.
X.IP
If this is followed by an underscore, the process is detached.
If it is followed by a period, the process is running in the foreground.
Otherwise the process is running in the background but is still
attached to a terminal.
X.TP
X\fIUser\fP
The symbolic name of the process' effective user-id (see \fIexec\fP(2)
and \fIsetuid\fP(2)).
This name is defined by the system password file (\fB/etc/passwd\fP)
when \fIsps\fP was last initialised.
Otherwise, an asterisk (\fB*\fP) or vertical bar (\fB|\fP) appearing in this
column denotes that the process is an immediate relative of the
preceding process.
A bar is listed, rather than an asterisk, if both processes belong
to the same process group.
A user name is listed only if the effective user-id
differs from that of the preceding process or if it is a top-level
process (immediate offspring of process 1).
X.TP
X\fIProc#\fP
The unique process identifier.
X.TP
X\fIPpid#\fP
The process-id of the process' parent.
X.TP
X\fIPgrp#\fP
The process group to which the process belongs.
X.TP
X\fICommand\fP
The command arguments obtained from the process' own address space.
X(If the command name appears in parentheses, \fIsps\fP
was unable to locate the arguments in user space and so reports
the system's idea of the command name.)
X.PP
The following additional fields are listed when \fIsps\fP
is invoked with one of the \fB\-l\fP or \fB\-v\fP options \-
X.TP 8
X\fIStatus\fP
The process' current state.
If this field is listed in upper-case letters, the process is currently
loaded in real memory space ; otherwise it has been swapped out.
The status field may contain one of the following descriptions \-
X.RS 8
X.TP 16
X\fIrun\fP
The process can be run immediately.
X.TP
X\fIstop\fP
The process is stopped. See \fIsigvec\fP(2).
X.TP
X\fIexit\fP
The process is a zomby.
X.RE
X.IP
Any other entry in the status field indicates the process is
waiting for some external event to occur.
This is usually for one of the reasons listed below.
X(If \fIsps\fP does not know why a process is waiting, it lists
the hexadecimal address of the process' wait channel,
with the initial 80000000 trimmed off.)
A process may be waiting for one of the following reasons \-
X.RS 8
X.TP 16
X\fIchild\fP
The process is waiting for a child to terminate. See \fIwait\fP(2).
X.TP
X\fIpause\fP
Waiting for a signal to be received. See \fIsigpause\fP(2).
X.TP
X\fIswap\fP
Waiting for a page to be swapped in.
X.TP
X\fIrswbuf\fP
Waiting for a read from the swap device \fB/dev/drum.\fP
X.TP
X\fIdiscio\fP
Waiting for a disc read or write operation.
X(Actually, this means that the process is waiting for an operation
through the kernel's I/O buffering mechanism to complete, but \fIdiscio\fP
is what is generally meant here).
X.TP
X\fIrpipe\fP
X.br
X.ns
X.TP
X\fIwpipe\fP
Waiting for a read from an empty pipe.  Alternatively, the process
is 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
Waiting for a read from an empty socket.
Alternatively, the process is waiting to write to a full socket (4.[2\-]bsd only).
X.TP
X\fIaccept\fP
Waiting to accept a stream-based socket connection (4.[2\-]bsd only).
See \fIaccept\fP(2).
X.TP
X\fIconnct\fP
Waiting to establish a connection through a stream-based socket to a
remote process (4.[2\-]bsd only). See \fIconnect\fP(2).
X.TP
X\fIsocket\fP
Waiting for some other time-out event on a socket (4.[2\-]bsd only).
X.TP
X\fIselect\fP
Blocked by a \fIselect\fP(2) system call (4.[2\-]bsd only).
X.TP
X\fIrmux\fP
Waiting for a read from a multiplexor file (4.1bsd only).
X.TP
X\fIinode\fP
Waiting for an inode to be allocated or unlocked.
X.TP
X\fIexlock\fP
X.br
X.ns
X.TP
X\fIshlock\fP
Waiting 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
Waiting for a read or write to the specified terminal, or for the terminal
to be switched on. See \fItty\fP(4).
Alternatively, waiting for a read or write to the
specified slave pty device. See \fIpty\fP(4).
X.TP
X\fIitty??\fP
X.br
X.ns
Under SunOS, waiting perform I/O to an iconified window.
X.TP
X\fIrpty??\fP
X.br
X.ns
X.TP
X\fIwpty??\fP
Waiting for a read or write to the specified master pty device.
See \fIpty\fP(4).
X.TP
X\fIptrace\fP
This is a parent process tracing its child.
X.TP
X\fIvfork\fP
This is a vforking parent process waiting for its child to relinquish
memory 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
Waiting 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.
These flags may be any of the following \-
X.RS 8
X.TP 16
X\fIU\fP
The process is a UNIX system process.
X.TP
X\fIT\fP
The process is being traced or debugged.
X.TP
X\fIV\fP
The process is a child currently being vforked. See \fIvfork\fP(2).
X.TP
X\fII\fP
The process is undergoing physical I/O.
X.TP
X\fIA\fP
The system has detected, or the user has warned of
anomalous paging behaviour. See \fIvadvise\fP(2).
X.RE
X.TP 8
X\fINice\fP
The ``niceness'' of the process. See \fInice\fP(2).
X.TP
X\fIVirtual\fP
The virtual memory size of the process in kilobytes.
The first figure indicates the sum of the data and stack segments,
the second figure that of the text segment.
X.TP
X\fIResident\fP
The resident memory size of the process in kilobytes, representing
the real memory devoted to the process.
X.TP
X\fI%M\fP
The percentage of available real memory allocated to this process.
X.TP
X\fITime\fP
The total CPU time accumulated by this process.
X(This is the sum of the system plus user times, unless the \fB\-q\fP
flag is specified in which case only the user time is listed.)
X.TP
X\fIChild\fP
The total CPU time accumulated by the process' children.
X(This is the sum of the system plus user times, unless the \fB\-q\fP
flag is specified.)
X.TP
X\fI%C\fP
The percentage of available CPU time devoted to the process.
This figure is a decaying average, computed over the past second.
X.PP
The following fields are listed when \fIsps\fP is invoked with the
X\fB\-d\fP option \-
X.TP 8
X\fIFiles\fP
The number of open files for this process.
X.TP
X\fIPageFaults\fP
The number of major and minor page faults incurred by the process.
X.TP
X\fISwap\fP
The number of swaps incurred by the process.
X.TP
X\fIBlockI/O\fP
The number of block read or write operations performed
on behalf of the process.
X.TP
X\fIKbytesecs\fP
The integral of real memory usage over time.
Thus, if a process uses 60 kilobytes of real memory for 3 seconds,
this figure is incremented by 180.
X.PP
The following fields are listed when \fIsps\fP is invoked with the
X\fB\-y\fP option \-
X.TP 8
X\fIDev\fP
The major and minor device numbers of the terminal.
X.TP
X\fIAddr\fP
The 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
The number of characters in the terminal I/O queues.
These refer to the raw input queue, the canonical input queue
and the output queue.
X.TP
X\fIPgrp\fP
The process group associated with the terminal.
X.PP
After listing the requested output, \fIsps\fP prints a summary line.
This indicates the number and total virtual memory size of all processes,
the number and total virtual size of busy processes,
the number and real memory size of loaded processes
and the number and real size of swapped processes.
X.SH DIAGNOSTICS
X\fISps\fP reports a self-explanatory message if it is given an
invalid argument list.
The program also complains if it cannot find necessary system information.
X.PP
At initialisation, \fIsps\fP complains if it cannot find the addresses of
requisite system structures in the kernel symbol file.
This is usually the case because the system is rarely configured to support
all known devices.
X\fISps\fP also complains if more than one user shares the same user-id
in 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.
The output reflects the disc activity caused by these processes.
The 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.
It lists the environment as well as all the command arguments in a wide format.
The output is produced indefinitely, with a delay of two seconds between
each listing.
X.PP
X\fBsps is /vmunix.new\fP
X.PP
X\fISps\fP is initialised. It reads its symbol information from the
specified 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
Several. In particular, J. E. Kulp and J. Robert Ward,
X\fB<robert@olsen.uucp>\fP.
X.LP
NFS changes incorporated by Alexander Dupuy,
X\fB<dupuy@amsterdam.columbia.edu>\fP
X.LP
SunOS 4.0 implementation by Alexander Dupuy and
Charlie Kim \fB<cck@cunixc.cc.columbia.edu>\fP.
X.LP
Ultrix 2.\fIx\fP additions incorporated by Rob Lehman at CUUCA.
X.LP
SunOS 4.1 additions incorporated by Sakari Jalovaara, \fB<sja@sirius.hut.fi>\fP.
X.LP
Ultrix 4.0 additions incorporated by Stefano Diomedi,
X\fB<sdiomedi@tecsiel.it>\fP.
X.LP
Currently maintained by J. Robert Ward, \fB<robert@olsen.uu.ch>\fP
X.SH BUGS
Because the system is continually changing, the information reported by
X\fIsps\fP is only an approximation to reality.
If invoked by root, \fIsps\fP renices itself to \-20 in an attempt to run as
fast as possible.
X.PP
X\fISps\fP recognises the sizes and addresses of internal kernel
tables whenever it is invoked. However, it must be recompiled
if major modifications are made to the kernel.
X.PP
X\fISps\fP does not list all the detailed information shown by \fIps\fP(1).
Nor are all the options supported by \fIps\fP(1) available from \fIsps\fP.
X.PP
X\fISps\fP does not understand all the possible
reasons why a process may be sleeping.
X.PP
The code of \fIsps\fP is inherently machine-dependent and non-portable.
X.PP
The number of options to \fIsps\fP is ridiculous.
END_OF_FILE
if test 15346 -ne `wc -c <'sps.1'`; then
    echo shar: \"'sps.1'\" unpacked with wrong size!
fi
# end of 'sps.1'
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'\" \(10012 characters\)
sed "s/^X//" >'waitingfor.c' <<'END_OF_FILE'
X# ifndef lint
static char SccsId[] =  "@(#)waitingfor.c	1.7\t12/4/91" ;
X# endif
X
X# include		"sps.h"
X# ifndef SUNOS40
X# include		<h/text.h>
X# endif SUNOS40
X
X# ifdef NFS
X#  ifdef ULTRIX40
X#   include		<h/gnode.h>
X#   include		<h/inode.h>
X#  else ULTRIX40
X#   include		<h/vnode.h>
X#   include		<ufs/inode.h>
X# endif ULTRIX40
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 ULTRIX40
X#     include		<h/quota.h>
X#    else
X#     include		<ufs/quota.h>
X#    endif ULTRIX40
X#   endif NOQUOTA
X#  else NFS
X#   include		<h/quota.h>
X#  endif NFS
X# include		<h/mbuf.h>
X# include		<h/socket.h>
X# include		<h/socketvar.h>
X# endif BSD42
X
X/* 1 if `w' is in the address range defined by `a1' and `a2' ... */
X# define        INRANGE( w, a1, a2 ) \
X			( (caddr_t)(a1) <= (w) && (w) < (caddr_t)(a2) )
X
X/* NFS changes incorporated by Alexander Dupuy <dupuy@amsterdam.columbia.edu> */
X
X/* WAITINGFOR - Determine what a process is waiting for and describe it. */
char    *waitingfor ( p )
X
struct 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# ifdef ULTRIX40
X		return ( p->pr_p.p_vm & SNOVM ? "vfork" : "child" ) ;
X# else
X		return ( p->pr_p.p_flag & SNOVM ? "vfork" : "child" ) ;
X# endif ULTRIX40
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 ULTRIX40
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 ULTRIX40
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 ULTRIX40
X			/* Cretinous DEC compiler can't handle case
X			   constructs like the following ... */
X			cp = "?tty??" ;
X#  else ULTRIX40
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 ULTRIX40
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*/
getsocket ( ks, s )
X
struct socket                   *ks ;
struct 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 10012 -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 3 \(of 3\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 3 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
