[net.sources] Reposting of SPS for 4.[12]bsd Vaxen - Shar 4 of 4

robert@hslrswi.UUCP (Robert Ward) (07/11/85)

Send comments, suggestions, bug reports, bug fixes, etc. to -

Robert Ward, Hasler AG, Abt. 34, Belpstrasse 23, CH-3000 Bern 14, Switzerland.
(... mcvax!cernvax!hslrswi!robert).

*******************************************************************************

This is a sh(1) archive.
In order to extract the contents of this shar, use an editor to place
the contents of this file from the dotted line onwards into a second,
temporary file. Then run sh on that second file.

--------------------------------- C U T --- H E R E ---------------------------
#! /bin/sh
echo Extracting printproc.c
cat > printproc.c << '---END-OF-printproc.c---'
# include	"sps.h"
# include	"flags.h"
# include	<h/text.h>

/* PRINTPROC - Pretty print a process according to the switches. */
printproc ( p, md )

register struct process		*p ;		
int				md ;		

{
	register char		*chp ;
	register struct text	*tp ;
	register struct hashtab	*hp ;
	char			chbuf[10] ;
	time_t			time ;
	time_t			chtime ;
# ifdef BSD42
	time_t			utime ;
	time_t			uchtime ;
# endif
	extern short		Lastuid, Lastpgrp ;
	extern struct flags	Flg ;
	char			*waitingfor() ;
	struct hashtab		*hashuid() ;
	double			percentmem() ;

	/* List tty name and foreground/background/detached information */
	printf( "%2.2s%c", p->pr_tty->l_name,
		!p->pr_p.p_pgrp ? ' ' :
# ifdef SDETACH
		p->pr_p.p_flag & SDETACH ? '_' :
# endif
		p->pr_p.p_pgrp == p->pr_tty->l_pgrp ? '.' : ' ' ) ;
	hp = hashuid( p->pr_p.p_uid ) ;
	if ( !md  )				
	{	/* If a top-level process, list the user name */
		if ( hp )
			printf( "%-8.8s ", hp->h_uname ) ;
		else
			printf( "user%-4.4d ", p->pr_p.p_uid ) ;
	}
	else					
	{	/* Usually list an asterisk for a child process */
		md = md > 8 ? 8 : md ;
		printf( "%*s%c", md, "",
			p->pr_p.p_pgrp == Lastpgrp ? '|' : '*' ) ;	
		/* But beware of setuid processes */
		md = 8 - md ;
		if ( p->pr_p.p_uid == Lastuid )
			printf( "%-*.*s", md, md, "" ) ;
		else if ( hp )
			printf( "%-*.*s", md, md, hp->h_uname ) ;
		else
		{
			md -= 4 ;
			printf( "user%-*.*d", md, md, p->pr_p.p_uid ) ;
		}
	}
	Lastuid = p->pr_p.p_uid ;
	Lastpgrp = p->pr_p.p_pgrp ;
	if ( Flg.flg_d )			
	{	/* List disc I/O and paging information */
		if ( !p->pr_upag || p->pr_p.p_stat == SZOMB )
		{
			prcmd( p, 49, -63 ) ;
			return ;
		}
		printf( "%2d %8d+%8d %4d %8d %8D ",
			p->pr_files,
# ifdef BSD42
			p->pr_rself.ru_majflt,
			p->pr_rself.ru_minflt,
			p->pr_rself.ru_nswap,
			p->pr_rself.ru_inblock + p->pr_rself.ru_oublock,
			KBYTES( p->pr_rself.ru_idrss + p->pr_rself.ru_isrss
				+ p->pr_rself.ru_ixrss ) ) ;
# else
			p->pr_vself.vm_majflt,
			p->pr_vself.vm_minflt,
			p->pr_vself.vm_nswap,
			p->pr_vself.vm_inblk + p->pr_vself.vm_oublk,
			KBYTES( (p->pr_vself.vm_idsrss
				+ p->pr_vself.vm_ixrss) / Info.i_hz ) ) ;
# endif
		prcmd( p, 5, -63 ) ;
		return ;
	}
	if ( !Flg.flg_v )			
	{	/* Not verbose so just list command arguments */
		prcmd( p, 5, -19 ) ;
		return ;
	}
	/* Arrive here if being verbose ; list cpu information */
	switch ( p->pr_p.p_stat )		
	{					
		case SSLEEP :
		case SWAIT :
		case SIDL :
			/* Determine why a process should be in a wait state */
			chp = waitingfor( p ) ;
			break ;
		case SRUN :
			chp = "run" ;
			break ;
		case SZOMB :
			chp = "exit" ;
			break ;
		case SSTOP :
			chp = "stop" ;
			break ;
	}
	/* If the process is loaded, list the status information in capitals */
	printf( "%-6.6s ", p->pr_p.p_flag & SLOAD ?
		(capitals( chp, chbuf ), chbuf) : chp ) ;
	/* List process flags */
	printf( "%c%c%c", p->pr_p.p_flag & SSYS ? 'U' :
		p->pr_p.p_flag & STRC ? 'T' : ' ',
		p->pr_p.p_flag & SVFORK ? 'V' :
		p->pr_p.p_flag & SPHYSIO ? 'I' : ' ',
		p->pr_p.p_flag & SUANOM ? 'A' : ' ' ) ;
	/* List process niceness */
	if ( p->pr_p.p_nice != NZERO )		
		printf( "%3d ", p->pr_p.p_nice - NZERO ) ;
	else
		printf( "    " ) ;
	if ( p->pr_p.p_stat == SZOMB )
	{
		prcmd( p, 41, -69 ) ;
		return ;
	}					
	/* List process and text virtual sizes */
	printf( "%4d", KBYTES( p->pr_p.p_dsize + p->pr_p.p_ssize ) ) ;
	if ( tp = p->pr_p.p_textp )
		printf( "+%3d ", KBYTES( tp->x_size ) ) ;
	else
		printf( "     " ) ;
	/* List process and text real sizes */
	printf( "%4d", KBYTES( p->pr_p.p_rssize ) ) ;
	if ( tp )
		printf( "+%3d %2.0f ", KBYTES( tp->x_rssize ),
			percentmem( p ) );
	else
		printf( "        " ) ;
	/* List information obtained from the upage. This includes the process
	   times and command arguments. */
	if ( !p->pr_upag )
	{
		prcmd( p, 20, -69 ) ;
		return ;
	}					
	/* List process time information */
# ifdef BSD42
	time   = Flg.flg_q ? p->pr_rself.ru_utime.tv_sec :
		 p->pr_rself.ru_utime.tv_sec + p->pr_rself.ru_stime.tv_sec ;
	utime  = Flg.flg_q ? p->pr_rself.ru_utime.tv_usec :
		 p->pr_rself.ru_utime.tv_usec + p->pr_rself.ru_stime.tv_usec ;
	chtime = Flg.flg_q ? p->pr_rchild.ru_utime.tv_sec :
		 p->pr_rchild.ru_utime.tv_sec + p->pr_rchild.ru_stime.tv_sec ;
	uchtime = Flg.flg_q ? p->pr_rchild.ru_utime.tv_usec :
		 p->pr_rchild.ru_utime.tv_usec + p->pr_rchild.ru_stime.tv_usec ;
	prcpu( time, utime ) ;
	if ( chtime != 0L )
	{
		printf( "+" ) ;
		prcpu( chtime, uchtime ) ;
	}
# else
	time   = Flg.flg_q ? p->pr_vself.vm_utime :
		 p->pr_vself.vm_utime + p->pr_vself.vm_stime ;
	chtime = Flg.flg_q ? p->pr_vchild.vm_utime :
		 p->pr_vchild.vm_utime + p->pr_vchild.vm_stime ;
	prcpu( time ) ;
	if ( chtime != 0L )
	{
		printf( "+" ) ;
		prcpu( chtime ) ;
	}
# endif
	else
		printf( "      " ) ;
# ifdef BSD42
	if ( time || utime )
# else
	if ( time )
# endif
		printf( " %2.0f ", p->pr_p.p_pctcpu * 100.0 ) ;
	else
		printf( "    " ) ;
	/* Finally, list the process command arguments. */
	prcmd( p, 5, -69 ) ;			
}

/* CAPITALS - Converts letters in `chp' to upper-case in buffer `buf'. */
capitals ( chp, buf )

register char			*chp ;
register char			*buf ;

{
	while ( *buf = *chp++ )
	{
		if ( 'a' <= *buf && *buf <= 'z' )
			*buf -= 'a' - 'A' ;
		buf++ ;
	}
}
---END-OF-printproc.c---
echo Extracting prsummary.c
cat > prsummary.c << '---END-OF-prsummary.c---'
# include	"sps.h"

/* PRSUMMARY - Print the summarising information */
prsummary ()
{
	extern struct summary	Summary ;

	printf(
"%D (%Dk) processes, %D (%Dk) busy, %D (%Dk) loaded, %D (%Dk) swapped\n",
		Summary.sm_ntotal, KBYTES( Summary.sm_ktotal ),
		Summary.sm_nbusy, KBYTES( Summary.sm_kbusy ),
		Summary.sm_nloaded, KBYTES( Summary.sm_kloaded ),
		Summary.sm_nswapped, KBYTES( Summary.sm_kswapped ) ) ;
	Summary.sm_ntotal = 0L ;
	Summary.sm_ktotal = 0L ;
	Summary.sm_nbusy = 0L ;
	Summary.sm_kbusy = 0L ;
	Summary.sm_nloaded = 0L ;
	Summary.sm_kloaded = 0L ;
	Summary.sm_nswapped = 0L ;
	Summary.sm_kswapped = 0L ;
}
---END-OF-prsummary.c---
echo Extracting readstatus.c
cat > readstatus.c << '---END-OF-readstatus.c---'
# include	"sps.h"
# include	<h/text.h>

/* READSTATUS - Reads the kernel memory for current processes and texts */
readstatus ( process, text )

register struct process		*process ;
struct text			*text ;

{
	register struct proc	*p ;
	register struct proc	*p0 ;
	register struct process	*pr ;
	extern struct info	Info ;
	extern int		Flkmem ;
	char			*getcore() ;

	/* Read current text information */
	memseek( Flkmem, (long)Info.i_text0 ) ;
	if ( read( Flkmem, (char*)text, Info.i_ntext * sizeof( struct text ) )
	!= Info.i_ntext * sizeof( struct text ) )
		prexit( "sps - Can't read system text table\n" ) ;
	/* Read current process information */
	p0 = (struct proc*)getcore( sizeof( struct proc )*Info.i_nproc ) ;
	memseek( Flkmem, (long)Info.i_proc0 ) ;
	if ( read( Flkmem, (char*)p0, Info.i_nproc * sizeof( struct proc ) )
	!= Info.i_nproc * sizeof( struct proc ) )
		prexit( "sps - Can't read system process table\n" ) ;
	/* Copy process information into our own array */
	for ( p = p0, pr = process ; pr < &process[ Info.i_nproc ] ; p++, pr++ )
		pr->pr_p = *p ;
	free( (char*)p0 ) ;
}
---END-OF-readstatus.c---
echo Extracting selectproc.c
cat > selectproc.c << '---END-OF-selectproc.c---'
# include	"sps.h"
# include	"flags.h"

/*
** SELECTPROC - Given a process structure, this procedure decides whether
** the process is a candidate for printing.
*/
selectproc ( p, process, thisuid )

register struct process		*p ;		
register struct process		*process ;	
int				thisuid ;	

{
	register union flaglist	*fp ;
	register struct process	*pp ;
	extern struct flags	Flg ;

	/* Flg.flg_AZ is an internal flag set if one of flags `A' to `Z'
	   was specified. If this is not set, a process is listed only
	   if it or one of its ancestors belongs to the invoking user. */
	if ( !Flg.flg_AZ )
		for ( pp = p ; pp > &process[1] ; pp = pp->pr_pptr )
			if ( thisuid == pp->pr_p.p_uid )
				return ( 1 ) ;
	if ( Flg.flg_A )
		return ( 1 ) ;
	if ( Flg.flg_P )
		for ( fp = Flg.flg_Plist ; fp->f_pid >= 0 ; fp++ )
			if ( fp->f_pid == p->pr_p.p_pid )
				return ( 1 ) ;
	if ( Flg.flg_U )
		for ( pp = p ; pp > &process[1] ; pp = pp->pr_pptr )
			for ( fp = Flg.flg_Ulist ; fp->f_uid >= 0 ; fp++ )
				if ( fp->f_uid == pp->pr_p.p_uid )
					return ( 1 ) ;
	switch ( p->pr_p.p_stat )
	{
		case SRUN :
			if ( Flg.flg_B )
				return ( 1 ) ;
			break ;
		case SSLEEP :
			if ( Flg.flg_B
			&&   p->pr_p.p_pri < PZERO && p->pr_p.p_pid > MSPID )
				return ( 1 ) ;
		case SWAIT :
		case SIDL :
			if ( Flg.flg_W )
				return ( 1 ) ;
			break ;
		case SSTOP :
			if ( Flg.flg_S )
				return ( 1 ) ;
			break ;
		case SZOMB :
			if ( Flg.flg_Z )
				return ( 1 ) ;
			break ;
		default :
			break ;
	}
	return ( 0 ) ;
}
---END-OF-selectproc.c---
echo Extracting selecttty.c
cat > selecttty.c << '---END-OF-selecttty.c---'
# include	"sps.h"
# include	"flags.h"

/* SELECTTTY - Decides whether this process is interesting for its tty */
selecttty ( p )

register struct process		*p ;

{
	register union flaglist	*fp ;
	extern struct flags	Flg ;

	for ( fp = Flg.flg_Tlist ; fp->f_ttyline ; fp++ )
		if ( fp->f_ttyline == p->pr_tty )
			return ( 1 ) ;
	return ( 0 ) ;
}
---END-OF-selecttty.c---
echo Extracting sps.h
cat > sps.h << '---END-OF-sps.h---'
# include	<h/param.h>
# include	<h/dir.h>
# include	<h/user.h>
# include	<h/proc.h>

/*
** Maximum # of users to be considered. (Should probably be
** approximately double the # of users in /etc/passwd.)
*/
# define	MAXUSERID	100
/* Maximum # ttys to be considered ... */
# define	MAXTTYS		50
/* Maximum user name length ... */
# define	UNAMELEN	8
/* Maximum process-id not to be considered busy ... */
# define	MSPID		2
/* # of wait states defined in the `struct info' ... */
# define	NWAITSTATE	35

/* Convert clicks to kbytes ... */
# define	KBYTES( size )	((size) >> (10 - PGSHIFT))

/* Standard files to be examined ... */
# define	FILE_MEM	"/dev/mem"	/* System physical memory */
# define	FILE_KMEM	"/dev/kmem"	/* Kernel virtual memory */
# define	FILE_SWAP	"/dev/drum"	/* Swap/paging device */
# define	FILE_DEV	"/dev"		/* Directory of tty entries */
# define	FILE_SYMBOL	"/vmunix"	/* Symbol file for nlist() */
# define	FILE_INFO	"/etc/spsinfo"	/* Sps information file */

/* Structure to hold necessary information concerning a tty ... */
struct ttyline
{
	struct tty		*l_addr ;	/* Ptr to tty struct in kmem */
	unsigned short		l_pgrp ;	/* Tty process group */
	char			l_name[2] ;	/* Tty character name */
	dev_t			l_dev ;		/* Tty device # */
} ;

/* Structure holding a single hash table entry ... */
struct hashtab
{
	unsigned short		h_uid ;		/* Uid of user entry */
	char			h_uname[ UNAMELEN ] ; /* Corresponding name */
} ;

/*
** Format of the standard information file maintained by sps.
** This structure is filled in at initialisation time and then is read back
** in whenever sps is invoked.
** Note that the pointer variables in this structure refer to
** kernel virtual addresses, not addresses within sps.
** These variable are typed as such so that pointer arithmetic
** on the kernel addresses will work correctly.
*/
struct info
{	/* Kernel values determining process, tty and upage info ... */
	struct proc		*i_proc0 ;	/* address of process table */
	int			i_nproc ;	/* length of process table */
	struct text		*i_text0 ;	/* address of text table */
	int			i_ntext ;	/* length of text table */
	struct inode		*i_inode0 ;	/* address of inode table */
	int			i_ninode ;	/* length of inode table */
	struct buf		*i_swbuf0 ;	/* address of swap buffers */
	int			i_nswbuf ;	/* # swap buffers */
	struct buf		*i_buf0 ;	/* address of i/o buffers */
	int			i_nbuf ;	/* # i/o buffers */
	int			i_ecmx ;	/* max physical memory address*/
	struct pte		*i_usrptmap ;	/* page table map */
	struct pte		*i_usrpt ;	/* page table map */
	struct cdevsw		*i_cdevsw ;	/* device switch to find ttys */
# ifdef BSD42
	struct quota		*i_quota0 ;	/* disc quota structures */
	int			i_nquota ;	/* # quota structures */
	int			i_dmmin ;	/* The start of the disc map */
	int			i_dmmax ;	/* The end of the disc map */
	struct mbuf		*i_mbutl ;	/* Start of mbuf area */
# else
	int			i_hz ;		/* Clock rate */
# endif
# ifdef	CHAOS
	caddr_t			i_Chconntab ;	/* Chaos connection table */
# endif
	/* Kernel addresses are associated with process wait states ... */
	caddr_t			i_waitstate[ NWAITSTATE ] ;
	/* User names, stored in a hash table ... */
	struct hashtab		i_hnames[ MAXUSERID ] ;
	/* Tty device info ... */
	struct ttyline		i_ttyline[ MAXTTYS ] ;
} ;

/*
** The symbol structure cross-references values read from the kernel with
** their place in the info structure, and if such a value is associated with
** a process wait state or not.
*/
struct symbol
{
	char			*s_kname ;	/* Kernel symbol name */
	char			s_indirect ;	/* Value requires indirection */
	caddr_t			*s_info ;	/* Corresponding info address */
	char			*s_wait ;	/* Reason for wait, if any */
} ;

/* The `user' structure obtained from /dev/mem or /dev/swap ... */
union userstate
{
	struct user		u_us ;
	char			u_pg[ UPAGES ][ NBPG ] ;
} ;

/* Information concerning each process filled from /dev/kmem ... */
struct process
{
	struct proc		pr_p ;		/* struct proc from /dev/kmem */
	struct process		*pr_plink ;	/* Normalised ptrs from above */
	struct process		*pr_sibling ;	/* Ptr to sibling process */
	struct process		*pr_child ;	/* Ptr to child process */
	struct process		*pr_pptr ;	/* Ptr to parent process */
# ifdef BSD42
	struct rusage		pr_rself ;	/* Read from upage for self */
	struct rusage		pr_rchild ;	/* ... and the children */
# else
	struct vtimes		pr_vself ;	/* Read from upage for self */
	struct vtimes		pr_vchild ;	/* ... and the children */
# endif
	int			pr_files ;	/* # open files */
	struct ttyline		*pr_tty ;	/* Associated tty information */
	char			*pr_cmd ;	/* Command args, from upage */
	int			pr_upag:1 ;	/* Upage was obtained */
	int			pr_csaved:1 ;	/* Cmd args saved by malloc() */
} ;

/* Structure to hold summarising information ... */
struct summary
{
	long			sm_ntotal ;	/* Total # processes */
	long			sm_ktotal ;	/* Total virtual memory */
	long			sm_nbusy ;	/* # busy processes */
	long			sm_kbusy ;	/* Busy virtual memory */
	long			sm_nloaded ;	/* # loaded processes */
	long			sm_kloaded ;	/* Active resident memory */
	long			sm_nswapped ;	/* # swapped processes */
	long			sm_kswapped ;	/* Size totally swapped out */
} ;
---END-OF-sps.h---
echo Extracting termwidth.c
cat > termwidth.c << '---END-OF-termwidth.c---'
/*
** TERMWIDTH - Sets the external variable `Termwidth' to the # of columns
** on the terminal.
*/
termwidth ()
{
	register char		*termtype ;
	register int		twidth ;
	char			buf[ 1025 ] ;
	extern unsigned		Termwidth ;
	char			*getenv() ;

	Termwidth = 80 ;
	if ( !(termtype = getenv( "TERM" )) )
		return ;
	if ( tgetent( buf, termtype ) != 1 )
		return ;
	twidth = tgetnum( "co" ) ;
	if ( twidth > 40 )
		Termwidth = twidth ;
}
---END-OF-termwidth.c---
echo Extracting ttystatus.c
cat > ttystatus.c << '---END-OF-ttystatus.c---'
# include	"sps.h"
# include	"flags.h"
# include	<stdio.h>
# include	<h/tty.h>
# ifdef CHAOS
# include	<chunix/chsys.h>
# include	<chaos/chaos.h>
# endif

/*
** TTYSTATUS - Reads the kernel memory for tty structures of active processes.
** The addresses of the associated struct ttys of /dev/kmem are kept in the
** info structure. Here we use those addresses to access the structures.
** Actually, we are mostly interested just in the process group of each tty.
*/
ttystatus ()
{
	register struct ttyline	*lp ;
	struct tty		tty ;
	extern struct flags	Flg ;
	extern struct info	Info ;
	extern int		Flkmem ;

	if ( Flg.flg_y )
		printf( "Ty   Dev       Addr Rawq Canq Outq  Pgrp\n" ) ;
	lp = Info.i_ttyline ;
# ifdef CHAOS
	while ( lp->l_name[0] && lp->l_name[0] != 'C' )
# else
	while ( lp->l_name[0] )
# endif
	{
		memseek( Flkmem, (long)lp->l_addr ) ;
		if ( read( Flkmem, (char*)&tty, sizeof( struct tty ) )
		!= sizeof( struct tty ) )
		{
			fprintf( stderr,
				"sps - Can't read struct tty for tty%.2s\n",
				lp->l_name ) ;
			lp->l_pgrp = 0 ;
			lp++ ;
			continue ;
		}
		lp->l_pgrp = tty.t_pgrp ;
		prtty( lp, &tty ) ;
		lp++ ;
	}
# ifdef CHAOS
	chaosttys( lp ) ;		
# endif
}

/* PRTTY - Print out the tty structure */
prtty ( lp, tty )

register struct ttyline		*lp ;
register struct tty		*tty ;

{
	extern struct flags	Flg ;

	if ( !Flg.flg_y )
		return ;
	printf( "%-2.2s %2d,%2d 0x%08x %4d %4d %4d %5d\n",
		lp->l_name,
		major( lp->l_dev ),
		minor( lp->l_dev ),
		lp->l_addr,
		tty->t_rawq.c_cc,
		tty->t_canq.c_cc,
		tty->t_outq.c_cc,
		tty->t_pgrp ) ;
}

# ifdef CHAOS

/* CHAOSTTYS - Finds ttys attached to the Chaos net */
chaosttys ( lp )

register struct ttyline		*lp ;

{
	register struct connection	**cnp ;
	register int			i ;
	struct tty			tty ;
	struct connection		*conntab[CHNCONNS] ;
	struct connection		conn ;
	extern struct info		Info ;
	extern int			Flkmem ;

	memseek( Flkmem, (long)Info.i_Chconntab ) ;
	(void)read( Flkmem, (char*)conntab, sizeof( conntab ) ) ;
	for ( i = 0, cnp = conntab ; cnp < &conntab[CHNCONNS] ; i++, cnp++ )
	{
		if ( !*cnp )
			continue ;
		memseek( Flkmem, (long)*cnp ) ;
		(void)read( Flkmem, (char*)&conn, sizeof( struct connection ) );
		if ( !(conn.cn_flags & CHTTY) )
			continue ;
		memseek( Flkmem, (long)conn.cn_ttyp ) ;
		(void)read( Flkmem, (char*)&tty, sizeof( struct tty ) ) ;
		if ( lp >= &Info.i_ttyline[MAXTTYS] )
			prexit( "sps - Too many chaos ttys\n" ) ;
		lp->l_addr = conn.cn_ttyp ;
		lp->l_pgrp = tty.t_pgrp ;
		lp->l_dev = tty.t_dev ;
		lp->l_name[0] = 'C' ;
		lp->l_name[1] = i < 10 ? '0'+i : i-10 <= 'z'-'a' ? i-10+'a' :
				i-10-('z'-'a')+'A' ;
		prtty( lp, &tty ) ;
		lp++ ;
	}
}

# endif
---END-OF-ttystatus.c---
echo Extracting waitingfor.c
cat > waitingfor.c << '---END-OF-waitingfor.c---'
# include	"sps.h"
# include	<h/tty.h>
# include	<h/text.h>
# include	<h/inode.h>
# include	<h/buf.h>
# ifdef BSD42
# include	<h/quota.h>
# include	<h/mbuf.h>
# include	<h/socket.h>
# include	<h/socketvar.h>
# endif

/* 1 if `w' is in the address range defined by `a1' and `a2' ... */
# define	INRANGE( w, a1, a2 ) \
			( (caddr_t)(a1) <= (w) && (w) < (caddr_t)(a2) )

/* WAITINGFOR - Determine what a process is waiting for and describe it. */
char	*waitingfor ( p )

struct process			*p ;

{
	register caddr_t	w ;
	register struct ttyline	*lp ;
	register struct symbol	*s ;
	register char		*cp ;
# ifdef BSD42
	struct socket		sc ;
# endif
	static char		wbuf[ 8 ] ;
	extern struct info	Info ;
	extern struct symbol	Symbollist[] ;
	char			*sprintf() ;

	w = p->pr_p.p_wchan ;
	if ( !w )
		return ( "null" ) ;
	/* Waiting for a child process, alternatively in a vfork() ? */
	if ( INRANGE( w, Info.i_proc0, &Info.i_proc0[ Info.i_nproc ] ) )
		return ( p->pr_p.p_flag & SNOVM ? "vfork" : "child" ) ;
	/* Waiting for a page to be brought in ? */
	if ( INRANGE( w, Info.i_swbuf0, &Info.i_swbuf0[ Info.i_nswbuf ] ) )
		return ( "swap" ) ;
	/* Waiting for discio through a block device to complete ? */
	if ( INRANGE( w, Info.i_buf0, &Info.i_buf0[ Info.i_nbuf ] ) )
		/* SHOULD ACTUALLY READ AS "blkio" BUT "discio" IS WHAT
		   IS GENERALLY MEANT HERE. */
		return ( "discio" ) ;
	/* Waiting for a text page to be brought in ? */
	if ( INRANGE( w, Info.i_text0, &Info.i_text0[ Info.i_ntext ] ) )
		return ( "swtext" ) ;
# ifdef BSD42
	/* Waiting for an event associated with the quota system ? */
	if ( INRANGE( w, Info.i_quota0, &Info.i_quota0[ Info.i_nquota ] ) )
		return ( "quota" ) ;
# endif
	/* Waiting for tty I/O ? If so, find which tty it is */
	for ( lp = Info.i_ttyline ; lp->l_name[0] ; lp++ )
		if ( INRANGE( w, &lp->l_addr[0], &lp->l_addr[1] ) )
		{
			switch ( w - (int)lp->l_addr )
			{
				case (int)&((struct tty*)0)->t_rawq :
					/* Read from a tty or slave pty */
					cp = "rtty??" ;
					break ;
				case (int)&((struct tty*)0)->t_outq :
					/* Write to a tty or slave pty */
					cp = "wtty??" ;
					break ;
				case (int)&((struct tty*)0)->t_state :
					/* Tty not open */
					cp = "otty??" ;
					break ;
				case (int)&((struct tty*)0)->t_outq.c_cf :
					/* Read from a controller pty */
					cp = "rpty??" ;
					break ;
				case (int)&((struct tty*)0)->t_rawq.c_cf :
					/* Write to a controller pty */
					cp = "wpty??" ;
					break ;
				default :
					cp = "?tty??" ;
					break ;
			}
			cp[4] = lp->l_name[0] ;
			cp[5] = lp->l_name[1] ;
			return ( cp ) ;
		}
	/* Waiting for an inode ? */
	if ( INRANGE( w, Info.i_inode0, &Info.i_inode0[ Info.i_ninode ] ) )
		switch ( ((int)w - (int)Info.i_inode0) % sizeof( struct inode ))
		{
# ifdef BSD42
			case (int)&((struct inode*)0)->i_exlockc :
				/* Exclusive lock on this inode */
				return ( "exlock" ) ;
			case (int)&((struct inode*)0)->i_shlockc :
				/* Shared lock on this inode */
				return ( "shlock" ) ;
# else
			case 1 :
				return ( "wpipe" ) ;
			case 2 :
				return ( "rpipe" ) ;
			case (int)&((struct inode*)0)->i_un.i_group.g_datq :
				return ( "rmux" ) ;
# endif
			default :
				/* Inode probably locked */
				return ( "inode" ) ;
		}
# ifdef BSD42
	/* Waiting for a structure inside an mbuf ? If so, try to find why */
	if ( INRANGE( w, Info.i_mbutl,
	&Info.i_mbutl[ NMBCLUSTERS * CLBYTES / sizeof( struct mbuf ) ] ) )
		switch ( ((int)w - (int)Info.i_mbutl) % sizeof( struct mbuf )
			- (int)&((struct mbuf*)0)->m_dat[0] )
		{
			case (int)&((struct socket*)0)->so_timeo :
				/* Socket timeout event */
				return ( "socket" ) ;
			case (int)&((struct socket*)0)->so_rcv.sb_cc :
				/* Read from an empty socket. Here we actually
				   attempt to determine whether the socket
				   structure in question really does refer to
				   a socket, or whether it is in fact a pipe
				   in disguise. */
				return ( getsocket( (struct socket*)(w
				    - (int)&((struct socket*)0)->so_rcv.sb_cc),
						&sc )
					&& sc.so_type == SOCK_STREAM
					&& !sc.so_rcv.sb_hiwat
					&& !sc.so_rcv.sb_mbmax
					&& (sc.so_state
					    & (SS_ISCONNECTED|SS_CANTRCVMORE))
					? "rpipe" : "rsockt" ) ;
			case (int)&((struct socket*)0)->so_snd.sb_cc :
				/* Write to a full socket. Again, we try
				   to determine whether or not this is a
				   real socket or a pipe. */
				return ( getsocket( (struct socket*)(w
				    - (int)&((struct socket*)0)->so_snd.sb_cc),
						&sc )
					&& sc.so_type == SOCK_STREAM
					&& sc.so_rcv.sb_hiwat == 2048
					&& sc.so_rcv.sb_mbmax == 4096
					&& (sc.so_state
					    & (SS_ISCONNECTED|SS_CANTSENDMORE))
					? "wpipe" : "wsockt" ) ;
			default :
				/* Other mbuf event */
				return ( "mbuf" ) ;
		}
# endif
	/* Look in the symbol table for known wait addresses. */
	for ( s = Symbollist ; s->s_kname ; s++ )
		if ( s->s_wait && w == *s->s_info )
			return ( s->s_wait ) ;	
	/* No reason for the wait state has been found.
	   Return the wait channel as a hexadecimal address. */
	(void)sprintf( wbuf, "x%05x", w - 0x80000000 ) ;
	return ( wbuf ) ;
}

# ifdef BSD42
/*
** GETSOCKET - Reads a `struct socket' from the kernel virtual memory address
** identified by `ks' into the buffer `s'.
*/
getsocket ( ks, s )

struct socket			*ks ;
struct socket			*s ;

{
	extern int		Flkmem ;

	memseek( Flkmem, (long)ks ) ;
	return ( read( Flkmem, (char*)s, sizeof( struct socket ) )
		== sizeof( struct socket ) ) ;
}
# endif
---END-OF-waitingfor.c---