V7 and MC68000 version of SPS
Robert Ward
robert at hslrswi.UUCP
Sat Jun 29 12:12:45 AEST 1985
Here is the version of SPS for Bell Labs V7 (PDP-11) Unix and Unisoft 1.3
MC68000 Unix for those who have expressed interest in it. It is almost
functionally equivalent of the 4.xbsd version that was posted a few days
ago to net.sources.
This is a somewhat older version than the 4.[12]bsd version of SPS and
hence lacks a few of the fancier features such as hashing of user-ids
as well as some miscellaneous options. However, it shouldn't be too
difficult to update the code to incorporate these additions.
The following notes apply to anyone who is interested in trying to port SPS
to a new machine or system. The majority of the code of SPS is suprisingly
portable to most systems (at least it has been so far). The difficulty
invariably lies in the part of the code that fetches a process' upage
(getcmd11.c) and the code which attempts to locate the base of the command
argument stack in the user address space. If you have the code for ps(1),
you can always rip the relevant sections out of there. Otherwise it means
having to use guesswork and adb(1) and a lot of time.
The code enclosed in "#ifdef VMUNIX" lines below refers to an older version
of SPS for a 4.1bsd Vax only. It is largely obselete and should be ignored.
The code for this and the 4.xbsd versions should, of course, really be combined
together but then the ifdefing becomes a severe headache and makes the code
even more unreadable.
Please send any comments, suggestions, bug fixes and reports to me.
Robert Ward.
Hasler AG (Abt. 34)
Belpstrasse 23
CH-3000 Bern 14
Switzerland.
*******************************************************************************
This is a sh(1) archive.
To extract, cut after the following dotted line and run sh on that file.
--------------------------------- C U T --- H E R E ---------------------------
#! /bin/sh
echo Extracting Makefile.11
cat > Makefile.11 << '---END-OF-Makefile.11---'
# Makefile for SPS (IIASA PDP-11/70 Version)
PROG = sps
OBJS = findtty.o flagdecode.o flagsetup.o \
getcmd11.o globals1.o globals2.o \
initialise.o main.o mktree.o needed.o openfiles.o \
prcmd.o prcpu.o prheader.o printall.o \
printproc.o prsummary.o readstatus.o readsymbols.o \
select.o select_tty.o ttyinit.o ttystatus.o waitingfor.o
SRCS = findtty.c flagdecode.c flagsetup.c \
getcmd11.c globals1.c globals2.c \
initialise.c main.c mktree.c needed.c openfiles.c \
prcmd.c prcpu.c prheader.c printall.c \
printproc.c prsummary.c readstatus.c readsymbols.c \
select.c select_tty.c ttyinit.c ttystatus.c waitingfor.c
INCS = sps.h
CC = cc11
CFLAGS = -I/usr/include/local/pdp11/sys
all: $(PROG)
.c.o:
$(CC) $(CFLAGS) -c -O $<
$(OBJS): $(INCS)
$(PROG): $(OBJS)
$(CC) -o $@ $(OBJS)
install: $(PROG)
strip $(PROG)
mv $(PROG) /bin/$(PROG)
/etc/chown root /bin/$(PROG)
chmod 4711 /bin/$(PROG)
lint:
lint -x -b $(CFLAGS) $(SRCS)
clean:
rm -f $(OBJS) $(PROG)
---END-OF-Makefile.11---
echo Extracting Makefile.4.1
cat > Makefile.4.1 << '---END-OF-Makefile.4.1---'
# Makefile for SPS (4.1BSD UNIX Version, with or without Chaos network)
PROG = sps
OBJS = filecount.o findtty.o flagdecode.o flagsetup.o \
getcmd.o getupage.o globals1.o globals2.o \
initialise.o main.o mktree.o needed.o openfiles.o \
percentmem.o prcmd.o prcpu.o prheader.o printall.o \
printproc.o prsummary.o readstatus.o readsymbols.o \
select.o select_tty.o ttyinit.o ttystatus.o waitingfor.o
SRCS = filecount.c findtty.c flagdecode.c flagsetup.c \
getcmd.c getupage.c globals1.c globals2.c \
initialise.c main.c mktree.c needed.c openfiles.c \
percentmem.c prcmd.c prcpu.c prheader.c printall.c \
printproc.c prsummary.c readstatus.c readsymbols.c \
select.c select_tty.c ttyinit.c ttystatus.c waitingfor.c
INCS = sps.h
CFLAGS = -I/usr/src/sys -DVMUNIX -DCHAOS
all: $(PROG)
.c.o:
cc $(CFLAGS) -c -O -R $<
getcmd.o globals1.o waitingfor.o:
cc $(CFLAGS) -c -O $<
$(OBJS): $(INCS)
$(PROG): $(OBJS)
cc -o $@ $(OBJS)
install: $(PROG)
strip $(PROG)
mv $(PROG) /usr/local/$(PROG)
/etc/chown root /usr/local/$(PROG)
chmod 4711 /usr/local/$(PROG)
lint:
lint -x -b $(CFLAGS) $(SRCS)
clean:
rm -f $(OBJS) $(PROG)
---END-OF-Makefile.4.1---
echo Extracting Makefile.68000
cat > Makefile.68000 << '---END-OF-Makefile.68000---'
# Makefile for SPS (Unisoft Version 1.3 UNIX)
PROG = sps
OBJS = findtty.o flagdecode.o flagsetup.o \
getcmd11.o globals1.o globals2.o \
initialise.o main.o mktree.o needed.o openfiles.o \
prcmd.o prcpu.o prheader.o printall.o \
printproc.o prsummary.o readstatus.o readsymbols.o \
select.o select_tty.o ttyinit.o ttystatus.o waitingfor.o
SRCS = findtty.c flagdecode.c flagsetup.c \
getcmd11.c globals1.c globals2.c \
initialise.c main.c mktree.c needed.c openfiles.c \
prcmd.c prcpu.c prheader.c printall.c \
printproc.c prsummary.c readstatus.c readsymbols.c \
select.c select_tty.c ttyinit.c ttystatus.c waitingfor.c
INCS = sps.h
CFLAGS = -c -DV7 -DM68000 -I/usr/include/sys
CC = cc
all: $(PROG)
.c.o:
$(CC) -O $(CFLAGS) $<
openfiles.o:
$(CC) $(CFLAGS) $<
$(OBJS): $(INCS)
$(PROG): $(OBJS)
$(CC) -o $@ $(OBJS)
install: $(PROG)
strip $(PROG)
mv $(PROG) /bin/$(PROG)
chown root /bin/$(PROG)
chmod 4711 /bin/$(PROG)
lint:
lint -x -b $(CFLAGS) $(SRCS)
clean:
rm -f $(OBJS) $(PROG)
---END-OF-Makefile.68000---
echo Extracting Makefile.v7
cat > Makefile.v7 << '---END-OF-Makefile.v7---'
# Makefile for SPS (Bell Labs PDP-11 Version 7 Unix)
PROG = sps
OBJS = findtty.o flagdecode.o flagsetup.o \
getcmd11.o globals1.o globals2.o \
initialise.o main.o mktree.o needed.o openfiles.o \
prcmd.o prcpu.o prheader.o printall.o \
printproc.o prsummary.o readstatus.o readsymbols.o \
select.o select_tty.o ttyinit.o ttystatus.o waitingfor.o
SRCS = findtty.c flagdecode.c flagsetup.c \
getcmd11.c globals1.c globals2.c \
initialise.c main.c mktree.c needed.c openfiles.c \
prcmd.c prcpu.c prheader.c printall.c \
printproc.c prsummary.c readstatus.c readsymbols.c \
select.c select_tty.c ttyinit.c ttystatus.c waitingfor.c
INCS = sps.h
CFLAGS = -DV7 -Dvoid=int -I/v7/usr/include/sys
CC = /v7/bin/cc
all: $(PROG)
.c.o:
$(CC) $(CFLAGS) -c -O $<
$(OBJS): $(INCS)
$(PROG): $(OBJS)
$(CC) -o $@ $(OBJS)
install: $(PROG)
strip $(PROG)
mv $(PROG) /bin/$(PROG)
/etc/chown root /bin/$(PROG)
chmod 4711 /bin/$(PROG)
lint:
lint -x -b $(CFLAGS) $(SRCS)
clean:
rm -f $(OBJS) $(PROG)
---END-OF-Makefile.v7---
echo Extracting README
cat > README << '---END-OF-README---'
SPS - Show Process Status
=========================
SPS currently runs under four different Unix systems :
Bells Labs PDP-11 Unix,
Berkeley 4.1BSD VAX Unix (VAX-11/780 and VAX-11/750),
IIASA PDP-11/70 Unix,
Unisoft Version 1.3 Unix (PSI-9068).
Compiler options are as follows -
-DVMUNIX for 4.1bsd
-DCHAOS if the Chaos network is incorporated into 4.1bsd
-DV7 for V7 Unix, IIASA PDP-11/70 and Unisoft
-DM68000 for Unisoft
-DTRACE for testing/debugging purposes
********************************************************************************
When porting SPS to a new machine, the things to watch out for are the
way in which a process' upage is accessed (see pread() in getcmd11.c)
and the way in which command arguments are set up on the user stack
(see getcmd()). Command arguments are generally set up differently on each
machine ; the difficulty lies in trying to locate the base of the argument
list.
Some versions of Unix also seem to be incorrectly compiled : the `d_ttys'
field of the entries in the `cdevsw' table that refer to tty devices is
sometimes null. The kernel must then be patched so that these fields refer
to the corresponding `struct tty' inside the kernel.
********************************************************************************
If you want to tell SPS about a new type of device, then add make a new
entry in the `struct info' (see sps.h) and add a new line in the symbol
table (see globals2.c).
********************************************************************************
SPS understands if the size of internal kernel tables are changed under VMUNIX,
but not under any other system. It must be recompiled if major modifications
are made to the kernel.
---END-OF-README---
echo Extracting filecount.c
cat > filecount.c << '---END-OF-filecount.c---'
# ifdef VMUNIX
# include "sps.h"
/* FILECOUNT - Counts the # open files for the current process */
filecount ()
{
register int i ;
register struct file **f ;
register int count ;
extern union userstate User ;
count = 0 ;
for ( i = 0, f = User.u_us.u_ofile ; i < NOFILE ; i++ )
if ( *f++ )
count++ ;
return ( count ) ;
}
# endif
---END-OF-filecount.c---
echo Extracting findtty.c
cat > findtty.c << '---END-OF-findtty.c---'
# include "sps.h"
/* FINDTTY - Attempts to determine to which tty a process is connected */
struct ttyline *findtty ( p )
register struct process *p ;
{
register struct ttyline *lp ;
extern struct info Info ;
extern struct ttyline Notty ;
# ifdef VMUNIX
extern union userstate User ;
# endif
if ( !p->pr_p.p_pgrp )
return ( &Notty ) ;
for ( lp = Info.i_ttyline ; lp->l_name[0] ; lp++ )
# ifdef VMUNIX
if ( lp->l_dev == User.u_us.u_ttyd )
# else
if ( lp->l_dev == p->pr_ttyd )
# endif
return ( lp ) ;
return ( &Notty ) ;
}
---END-OF-findtty.c---
echo Extracting flagdecode.c
cat > flagdecode.c << '---END-OF-flagdecode.c---'
# include "sps.h"
/* FLAGDECODE - Looks at the argument list and sets various internal switches */
/* Note that the `d' and `D' switches are only implemented under VMUNIX */
flagdecode ( argc, argv )
register int argc ;
register char **argv ;
{
register char *chp ;
union flaglist *plist ;
union flaglist *tlist ;
union flaglist *ulist ;
static char usage[] =
# ifdef VMUNIX
"sps - Unknown option %s\nUsage - sps [ -defgiqrvwyABDFNPSTUWZ ][ process|tty|user ] ...\n";
# else
"sps - Unknown option %s\nUsage - sps [ -efgiqrvwyABFNPSTUWZ ][ process|tty|user ] ...\n";
# endif
union flaglist *getflgsp() ;
extern struct flags Flg ;
plist = tlist = ulist = (union flaglist*)0 ;
for ( argv++ ; --argc ; argv++ )
{
chp = *argv ;
while ( *chp )
switch ( *chp++ )
{
case '-' :
/* Separation character */
continue ;
# ifdef VMUNIX
case 'd' :
/* List disc orientated information */
Flg.flg_d = 1 ;
Flg.flg_v = 0 ;
continue ;
# endif
case 'e' :
case 'E' :
/* List environment strings */
Flg.flg_e = 1 ;
continue ;
case 'f' :
/* List the father's process id */
Flg.flg_f = 1 ;
Flg.flg_g = 0 ;
continue ;
case 'g' :
case 'G' :
/* List the process group id */
Flg.flg_f = 0 ;
Flg.flg_g = 1 ;
continue ;
case 'i' :
case 'I' :
/* Initialise (super-user only) */
Flg.flg_i = 1 ;
continue ;
case 'l' :
case 'v' :
case 'L' :
case 'V' :
/* Verbose output */
# ifdef VMUNIX
Flg.flg_d = 0 ;
# endif
Flg.flg_v = 1 ;
continue ;
case 'q' :
case 'Q' :
/* Show only the user time, not the
user + system times together. */
Flg.flg_q = 1 ;
continue ;
case 'r' :
case 'R' :
/* Repeat output every 5 seconds */
Flg.flg_r = 1 ;
continue ;
case 'w' :
/* Wide output, exceeding 79 columns */
Flg.flg_w = 1 ;
continue ;
case 'y' :
case 'Y' :
/* List current tty information */
Flg.flg_y = 1 ;
continue ;
case 'a' :
case 'A' :
/* List all processes */
Flg.flg_AZ = 1 ;
Flg.flg_A = 1 ;
continue ;
case 'b' :
case 'B' :
/* List only busy processes */
Flg.flg_AZ = 1 ;
Flg.flg_B = 1 ;
continue ;
# ifdef VMUNIX
case 'D' :
/* List only detached processes */
Flg.flg_AZ = 1 ;
Flg.flg_D = 1 ;
continue ;
# endif
case 'F' :
/* List only foreground processes */
Flg.flg_AZ = 1 ;
Flg.flg_F = 1 ;
continue ;
case 'n' :
case 'N' :
/* No processes, just the summary line*/
Flg.flg_AZ = 1 ;
Flg.flg_N = 1 ;
continue ;
case 'p' :
case 'P' :
/* List only the given process ids */
Flg.flg_AZ = 1 ;
Flg.flg_P = 1 ;
if ( !plist )
plist=Flg.flg_Plist=getflgsp( argc );
while ( argc > 1 )
{
if ( **++argv == '-' )
{
--argv ;
break ;
}
--argc ;
plist->f_chp = *argv ;
(++plist)->f_chp = (char*)0 ;
}
continue ;
case 's' :
case 'S' :
/* List only stopped processes */
Flg.flg_AZ = 1 ;
Flg.flg_S = 1 ;
continue ;
case 't' :
case 'T' :
/* List only processes attached to the
specified terminals */
Flg.flg_AZ = 1 ;
Flg.flg_T = 1 ;
if ( !tlist )
tlist=Flg.flg_Tlist=getflgsp( argc );
while ( argc > 1 )
{
if ( **++argv == '-' )
{
--argv ;
break ;
}
--argc ;
tlist->f_chp = *argv ;
(++tlist)->f_chp = (char*)0 ;
}
continue ;
case 'u' :
case 'U' :
/* List only processes belonging to the
specified users */
Flg.flg_AZ = 1 ;
Flg.flg_U = 1 ;
if ( !ulist )
ulist=Flg.flg_Ulist=getflgsp( argc );
while ( argc > 1 )
{
if ( **++argv == '-' )
{
--argv ;
break ;
}
--argc ;
ulist->f_chp = *argv ;
(++ulist)->f_chp = (char*)0 ;
}
continue ;
case 'W' :
/* List only waiting processes */
Flg.flg_AZ = 1 ;
Flg.flg_W = 1 ;
continue ;
case 'z' :
case 'Z' :
/* List only zombie processes */
Flg.flg_AZ = 1 ;
Flg.flg_Z = 1 ;
continue ;
default :
prexit( usage, *argv ) ;
/* NOTREACHED */
}
}
}
---END-OF-flagdecode.c---
echo Extracting flagsetup.c
cat > flagsetup.c << '---END-OF-flagsetup.c---'
# include "sps.h"
/*
** FLAGSETUP - Replaces any users or processes specified by flagdecode()
** with numerical equivalents. The lists are terminated by negative values.
** or null pointers. Ttystatus() must have been previously called to
** initialise the Info structure with chaos tty values.
*/
flagsetup ()
{
register union flaglist *fp ;
register char *chp ;
register int i ;
register struct ttyline *lp ;
int found ;
extern struct flags Flg ;
extern struct info Info ;
/* Look for specified users */
if ( Flg.flg_U )
{
if ( !Flg.flg_Ulist->f_chp )
prexit( "sps - User name was expected after -u flag\n");
for ( fp = Flg.flg_Ulist ; chp = fp->f_chp ; fp++ )
{
found = 0 ;
for ( i = 0 ; i < MAXUSERS ; i++ )
if ( !strncmp( chp, Info.i_unames[i], UNAMELEN))
{
fp->f_uid = i, found = 1 ;
break ;
}
if ( !found )
prexit( "sps - Unknown user: %s\n", chp ) ;
}
fp->f_uid = -1 ;
}
/* Look for specified process ids */
if ( Flg.flg_P )
{
if ( !Flg.flg_Plist->f_chp )
prexit(
"sps - Process id was expected after -p flag\n" ) ;
for ( fp = Flg.flg_Plist ; chp = fp->f_chp ; fp++ )
{
if ( chp[0] < '0' || chp[0] > '9' )
prexit( "sps - Bad process id: %s\n", chp ) ;
fp->f_pid = atoi( chp ) ;
}
fp->f_pid = -1 ;
}
/* Look for specified ttys */
if ( !Flg.flg_T )
return ;
if ( !Flg.flg_Tlist->f_chp )
prexit( "sps - Tty name was expected after -t flag\n" ) ;
for ( fp = Flg.flg_Tlist ; chp = fp->f_chp ; fp++ )
{
# ifdef VMUNIX
/* Under VMUNIX, all ttys have two character names.
Thus, a flag of the form `t 8' should be expanded to
become `t 08'. */
if ( !chp[1] )
chp[1] = chp[0], chp[0] = '0' ;
# endif
found = 0 ;
for ( lp = Info.i_ttyline ; lp->l_name[0] ; lp++ )
if ( !strncmp( chp, lp->l_name, 2 ) )
{
fp->f_ttyline = lp ;
found = 1 ;
break ;
}
if ( !found )
prexit( "sps - Unknown tty name: %.2s\n", chp ) ;
}
fp->f_ttyline = (struct ttyline*)0 ;
}
---END-OF-flagsetup.c---
echo Extracting getcmd.c
cat > getcmd.c << '---END-OF-getcmd.c---'
# ifdef VMUNIX
# include "sps.h"
/*
** GETCMD - Returns a character string read from a process' upage.
** This character string should represent the arguments to the current process.
*/
char *getcmd ( p )
register struct process *p ;
{
register int *ip ;
register char *cp ;
register char *cp0 ;
struct pte pte ;
char *argptr ;
int nbad, i ;
static char argbuf[ MAXARGPG * NBPG ] ;
static struct pte ptetable[ PAGETABLESIZE ] ;
extern struct flags Flg ;
extern union userstate User ;
extern int Flmem ;
extern int Flswap ;
char *strcat(), *strsave() ;
long lseek() ;
p->pr_csaved = 0 ;
p->pr_upag = 0 ;
if ( p->pr_p.p_stat == SZOMB )
return ( "** Defunct **" ) ;
/* Find the process' upage */
if ( !getupage( p, ptetable ) )
return ( "** No upage **" ) ;
/* Is this a system process ? */
if ( p->pr_p.p_flag & SSYS )
switch ( p->pr_p.p_pid )
{
case 0 :
p->pr_upag = 1 ;
return ( "Unix Swapper" ) ;
case 2 :
p->pr_upag = 1 ;
return ( "Unix Pager" ) ;
default :
break ;
}
/* Look at the top of the upage to locate the command arguments.
To locate each user page, we must access the page table entries
to find the physical locations. */
for ( i = 0 ; i < MAXARGPG ; i++ )
{
argptr = &argbuf[( MAXARGPG - 1 - i ) * NBPG] ;
pte = ptetable[MAXARGPG - 1 - i] ;
if ( (p->pr_p.p_flag & SLOAD) && !pte.pg_fod && pte.pg_pfnum )
{ /* If the page is loaded, read the arguments from
physical memory. */
(void)lseek( Flmem, (long)ctob( pte.pg_pfnum ), 0 ) ;
if ( read( Flmem, argptr, NBPG ) != NBPG )
return ( "** Mem read error **" ) ;
}
else
{ /* Otherwise the page is on the swap device */
(void)lseek( Flswap,
(long)ctob( User.u_us.u_smap.dm_map[0]+DMMIN-1-i), 0 ) ;
if ( read( Flswap, argptr, NBPG ) != NBPG )
return ( "** Swap read error **" ) ;
}
/* Arrive here with `argptr' pointing to the top of the
upage. Look down until the end of command arguments
is found. */
ip = (int*)&argptr[NBPG] ;
if ( i == 0 )
{
*--ip = 0 ;
ip-- ;
}
while ( ip > (int*)argptr && *--ip )
;
if ( ip > (int*)argptr || !*ip )
break ;
/* If no command arguments were found on this page, then
access the next. */
}
p->pr_upag = 1 ;
p->pr_csaved = 1 ;
/* If the command arguments could not be accessed from the user's
memory space, get the command name from the system's idea
of what the name should be. */
if ( i >= MAXARGPG )
{
argbuf[0] = '(' ;
(void)strncpy( &argbuf[1], User.u_us.u_comm,
sizeof( User.u_us.u_comm ) ) ;
(void)strcat( argbuf, ")" ) ;
return ( strsave( argbuf ) ) ;
}
/* Process the command arguments, looking for nulls and unprintable
characters. */
cp0 = (char*)(ip + 1) ;
if ( !*cp0 )
cp0++ ;
nbad = 0 ;
for ( cp = cp0 ; cp < &argbuf[MAXARGPG*NBPG] ; cp++ )
{
*cp &= 0177 ;
if ( !*cp )
{ /* Replace nulls with spaces */
*cp = ' ' ;
continue ;
}
if ( *cp < ' ' || *cp == 0177 )
{ /* Replace control characters with ?'s */
if ( ++nbad > 5 )
{
*cp++ = ' ' ;
break ;
}
*cp = '?' ;
continue ;
}
if ( !Flg.flg_e && *cp == '=' )
{ /* Break on an `=' if we are not interested in the
environment strings. */
*cp = '\0' ;
while ( cp > cp0 && *--cp != ' ' )
*cp = '\0' ;
break ;
}
}
while ( *--cp == ' ' )
*cp = '\0' ;
return ( strsave( cp0 ) ) ;
}
# endif
---END-OF-getcmd.c---
echo Extracting getcmd11.c
cat > getcmd11.c << '---END-OF-getcmd11.c---'
# ifndef VMUNIX
# include "sps.h"
/* The effective `page' size for a PDP-11/70 ... */
# ifndef NBPG
# define NBPG 512
# endif
/* For the benefit of Unisoft Unix ... */
# ifdef M68000
# ifndef UBASE
# define UBASE 0x1ff000
# endif
# endif
/*
** GETCMD - Returns a character string read from system memory.
** This character string should represent the arguments to the current process.
** This is functionally similar to the VAX version of getcmd(). Notice, however,
** that, in the interests of speed, only one page is ever accessed to
** determine the command arguments. If the combined arguments plus
** environment span across more than one page, an attempt is made to locate
** the command name from system space.
*/
char *getcmd ( p )
register struct process *p ;
{
register char *cp ;
register char *cp0 ;
# ifdef M68000
register int *cpi ;
# endif
int nbad ;
static char argbuf[ NBPG ] ;
extern struct flags Flg ;
extern struct info Info ;
char *strsave() ;
p->pr_csaved = 0 ;
p->pr_upag = 0 ;
if ( p->pr_p.p_stat == SZOMB )
return ( "** Defunct **" ) ;
if ( p->pr_p.p_flag & SSYS )
{
p->pr_upag = 1 ;
return ( "UNIX Swapper" ) ;
}
if ( !(p->pr_p.p_flag & SLOAD) && p->pr_p.p_addr > Info.i_nswap )
return ( "** Swap address error **" ) ;
if ( pread( p, NBPG, argbuf, sizeof( argbuf ), 1 ) == -1 )
return ( "** Read error **" ) ;
p->pr_upag = 1 ;
# ifdef M68000
cpi = (int*)&argbuf[NBPG] ;
while ( cpi > (int*)argbuf && !*--cpi )
;
if ( cpi <= (int*)&argbuf[0] )
goto notfound ;
while ( cpi > (int*)argbuf && *--cpi )
;
if ( cpi <= (int*)&argbuf[0] )
goto notfound ;
cp0 = (char*)(cpi+1) ;
# else
/* Locate the start and end of the command arguments in the buffer.
The start is determined by locating a byte containing 0377,
searching from the end of the buffer. */
cp = &argbuf[NBPG] ;
while ( cp > &argbuf[0] && (int)*--cp != -1 )
;
if ( cp <= &argbuf[0] )
goto notfound ;
/* If the command arguments were successfully accessed,
we arrive here with `cp' pointing just before a byte containing
0377, followed (possibly) by a series of non-null bytes,
followed by a series of nulls.
Now increment `cp' until it points to the first byte
past the nulls. This, hopefully, represents the beginning
of the command arguments. */
cp += 2 ;
while ( cp < &argbuf[NBPG] && *cp++ )
;
if ( cp >= &argbuf[NBPG] )
goto notfound ;
cp-- ;
while ( cp < &argbuf[NBPG] && !*cp++ )
;
if ( cp >= &argbuf[NBPG] )
goto notfound ;
cp0 = cp-1 ;
# endif
p->pr_csaved = 1 ;
/* Process the command arguments, looking for nulls and unprintable
characters. */
nbad = 0 ;
for ( cp = cp0 ; cp < &argbuf[ NBPG ] ; cp++ )
{
*cp &= 0177 ;
if ( !*cp )
{ /* Replace nulls with spaces */
*cp = ' ' ;
continue ;
}
if ( *cp < ' ' || *cp == 0177 )
{ /* Replace control characters with ?'s */
if ( ++nbad > 5 )
{
*cp++ = ' ' ;
break ;
}
*cp = '?' ;
continue ;
}
if ( !Flg.flg_e && *cp == '=' )
{ /* Break on an '=' if we are not interested in the
environment strings. */
*cp = '\0' ;
while ( cp > cp0 && *--cp != ' ' )
*cp = '\0' ;
break ;
}
}
while ( *--cp == ' ' )
*cp = '\0' ;
return ( strsave( cp0 ) ) ;
notfound :
/* We arrive here if the page of command arguments is full,
in other words, if we have not found the beginning of the
command. Now try to determine the name of the command
by accessing the system's idea of what the name is. */
if ( pread( p, (int)((struct user*)0)->u_comm, &argbuf[1],
DIRSIZ, 0 ) == -1 )
return ( "** Too many arguments **" ) ;
argbuf[0] = '(' ;
argbuf[DIRSIZ+1] = '\0' ;
for ( cp = &argbuf[1] ; cp <= &argbuf[DIRSIZ+1] ; cp++ )
{
*cp &= 0177 ;
if ( !*cp )
{
*cp++ = ')' ;
*cp = '\0' ;
break ;
}
if ( *cp < ' ' || *cp == 0177 )
*cp = '?' ;
}
p->pr_csaved = 1 ;
return ( strsave( &argbuf[0] ) ) ;
}
/* PREAD - Read process information */
pread ( p, addr, buf, nbytes, flag )
register struct process *p ;
register unsigned addr ;
register char *buf ;
int nbytes ;
int flag ;
{
long seekaddr ;
long saddr1, saddr2 ;
char *cp ;
static char localbuf[ NBPG ] ;
extern int Flmem ;
extern int Flswap ;
extern struct info Info ;
long lseek() ;
/* `Flag' indicates whether the search is to be from the top
of the process address space, or the upage area. */
seekaddr = flag ? (long)ctob( p->pr_p.p_size ) - addr :
addr + (int)Info.i_u - UBASE ;
/* If the process is loaded, look in its address space. */
if ( p->pr_p.p_flag & SLOAD )
{
(void)lseek( Flmem, seekaddr + (long)ctob( p->pr_p.p_addr), 0 );
return ( read( Flmem, buf, nbytes ) ) ;
}
/* Otherwise the process is swapped out. Look on the swap device.
The code here seems to be because /dev/swap is a block device
and therefore must be accessed one block at a time. */
seekaddr += ((long)(unsigned)p->pr_p.p_addr + Info.i_swplo) << 9 ;
saddr1 = seekaddr / 512L * 512L ;
(void)lseek( Flswap, saddr1, 0 ) ;
saddr2 = seekaddr % 512L ;
if ( !saddr2 )
return ( read( Flswap, buf, nbytes ) ) ;
(void)read( Flswap, localbuf, sizeof( localbuf ) ) ;
cp = &localbuf[ (int)saddr2 ] ;
while ( cp < &localbuf[ sizeof( localbuf ) ] && nbytes-- )
*buf++ = *cp++ ;
if ( nbytes > 0 )
return ( read( Flswap, buf, nbytes ) ) ;
return ( 0 ) ;
}
/* GETUINFO - Read information from the process' upage */
getuinfo ( p )
register struct process *p ;
{
/* NOTE THAT THE STRUCTURE SHOWN BELOW SHOULD MIMIC HOW
THE TIME INFORMATION IS STORED IN A PROCESS' UPAGE. */
struct
{
time_t t_utime ;
time_t t_stime ;
time_t t_cutime ;
time_t t_cstime ;
} t ;
/* Firstly, read the process cpu times from the upage */
if ( pread( p, (int)&((struct user*)0)->u_utime, (char*)&t,
sizeof( t ), 0 ) == -1 )
{
p->pr_utime = 0L ;
p->pr_stime = 0L ;
p->pr_cutime = 0L ;
p->pr_cstime = 0L ;
}
else
{
p->pr_utime = t.t_utime ;
p->pr_stime = t.t_stime ;
p->pr_cutime = t.t_cutime ;
p->pr_cstime = t.t_cstime ;
}
/* Now determine to which tty the process is connected */
if ( pread( p, (int)&((struct user*)0)->u_ttyd, (char*)&p->pr_ttyd,
sizeof( dev_t ), 0 ) == -1 )
p->pr_ttyd = (dev_t)0 ;
}
---END-OF-getcmd11.c---
echo Extracting getupage.c
cat > getupage.c << '---END-OF-getupage.c---'
# ifdef VMUNIX
# include "sps.h"
# include <stdio.h>
/* GETUPAGE - Reads the upage for the specified process */
# define usrpt (Info.i_usrpt)
getupage ( p, ptetable )
register struct process *p ;
struct pte *ptetable ;
{
struct pte *pteaddr ;
struct pte pte ;
register int i ;
int ncl ;
extern struct info Info ;
extern union userstate User ;
extern int Flmem ;
extern int Flkmem ;
extern int Flswap ;
long lseek() ;
/* If the process is not loaded, look for the upage on the swap device*/
if ( !(p->pr_p.p_flag & SLOAD) )
{
(void)lseek( Flswap, (long)ctob( p->pr_p.p_swaddr ), 0 ) ;
if ( read( Flswap, (char*)&User.u_us, sizeof( struct user ) )
!= sizeof( struct user ) )
{
fprintf( stderr,
"sps - Can't read upage of process %d\n",
p->pr_p.p_pid ) ;
return ( 0 ) ;
}
return ( 1 ) ;
}
/* The process is loaded. Find where its pte's are kept */
pteaddr = &Info.i_usrptmap[ btokmx(p->pr_p.p_p0br) + p->pr_p.p_szpt-1 ];
(void)lseek( Flkmem, (long)pteaddr, 0 );
if ( read( Flkmem, (char*)&pte, sizeof( struct pte ) )
!= sizeof( struct pte ) )
{
fprintf ( stderr,
"sps - cant read indir pte to get upage for process %d\n",
p->pr_p.p_pid ) ;
return ( 0 ) ;
}
/* Now get sufficient pte's to be able to read the upage */
(void)lseek( Flmem, (long)
(ctob(pte.pg_pfnum+1) - PAGETABLESIZE*sizeof( struct pte )), 0 ) ;
if ( read( Flmem, (char*)ptetable, PAGETABLESIZE*sizeof( struct pte ) )
!= PAGETABLESIZE * sizeof( struct pte ) )
{
fprintf( stderr, "sps - cant read page table of process %d\n",
p->pr_p.p_pid ) ;
return ( 0 ) ;
}
/* Now we can read the pages belonging to the upage */
ncl = ( sizeof( struct user ) + NBPG*CLSIZE - 1 ) / ( NBPG*CLSIZE ) ;
while ( --ncl >= 0 )
{
i = ncl * CLSIZE ;
(void)lseek(Flmem,(long)ctob(ptetable[MAXARGPG+i].pg_pfnum),0);
if ( read( Flmem, User.u_pg[i], CLSIZE*NBPG ) != CLSIZE*NBPG )
{
fprintf( stderr,
"sps - cant read page %d of process %d\n",
ptetable[MAXARGPG+i].pg_pfnum, p->pr_p.p_pid ) ;
return( 0 ) ;
}
}
return ( 1 ) ;
}
# endif
---END-OF-getupage.c---
echo Extracting globals1.c
cat > globals1.c << '---END-OF-globals1.c---'
# include "sps.h"
# ifndef VMUNIX
# include <stdio.h>
# endif
/* Read/Write Variables global to the code of sps */
struct info Info ; /* Information structure */
struct flags Flg ; /* Flag options */
struct summary Summary ; /* Summary of processes */
# ifdef VMUNIX
union userstate User ; /* Upage of one process */
# endif
int Flmem, Flkmem, Flswap ; /* File descriptors */
short Lastuid ; /* Last process uid printed */
# ifndef VMUNIX
char Sobuf[ BUFSIZ ] ; /* Stdout buffer */
# endif
---END-OF-globals1.c---
echo Extracting globals2.c
cat > globals2.c << '---END-OF-globals2.c---'
# include "sps.h"
/* Read Only variables, global to the code of sps ... */
/* Null ttyline device ... */
struct ttyline Notty = { 0, 0, " ", 0 } ;
/*
** The symbol table. For each address read from the kernel during
** initialisation, this table shows the following:
** i. the name of that symbol inside the kernel ;
** ii. whether an extra indirection is needed through the kernel
** to obtain the value of that symbol ;
** iii. where the obtained value/address is placed in the Info structure ;
** iv. whether the obtained value is associated with a reason for
** a process wait state.
*/
/* The order of entries in this table is unimportant. */
extern struct info Info ;
struct symbol Symbollist[] =
{
/* Kernel addresses required in order to access process,
tty and upage information. */
# ifdef VMUNIX
{ "_nproc", 1, (caddr_t*)&Info.i_nproc, (char*)0 },
{ "_ntext", 1, (caddr_t*)&Info.i_ntext, (char*)0 },
{ "_ninode", 1, (caddr_t*)&Info.i_ninode, (char*)0 },
{ "_nswbuf", 1, (caddr_t*)&Info.i_nswbuf, (char*)0 },
{ "_nbuf", 1, (caddr_t*)&Info.i_nbuf, (char*)0 },
{ "_hz", 1, (caddr_t*)&Info.i_hz, (char*)0 },
{ "_ecmx", 1, (caddr_t*)&Info.i_ecmx, (char*)0 },
{ "_pt_tty", 0, (caddr_t*)&Info.i_pt_tty, (char*)0 },
{ "_Usrptmap", 0, (caddr_t*)&Info.i_usrptmap, (char*)0 },
{ "_usrpt", 0, (caddr_t*)&Info.i_usrpt, (char*)0 },
{ "_swbuf", 1, (caddr_t*)&Info.i_swbuf0, (char*)0 },
{ "_proc", 1, (caddr_t*)&Info.i_proc0, (char*)0 },
{ "_text", 1, (caddr_t*)&Info.i_text0, (char*)0 },
{ "_inode", 1, (caddr_t*)&Info.i_inode0, (char*)0 },
{ "_buf", 1, (caddr_t*)&Info.i_buf0, (char*)0 },
{ "_cdevsw", 0, (caddr_t*)&Info.i_cdevsw, (char*)0 },
# ifdef CHAOS
{ "_Chconntab", 0, &Info.i_Chconntab, (char*)0 },
# endif
# else
{ "_nswap", 1, (caddr_t*)&Info.i_nswap, (char*)0 },
{ "_swplo", 1, (caddr_t*)&Info.i_swplo, (char*)0 },
{ "_proc", 0, (caddr_t*)&Info.i_proc0, (char*)0 },
{ "_text", 0, (caddr_t*)&Info.i_text0, (char*)0 },
{ "_inode", 0, (caddr_t*)&Info.i_inode0, (char*)0 },
{ "_buf", 0, (caddr_t*)&Info.i_buf0, (char*)0 },
{ "_cdevsw", 0, (caddr_t*)&Info.i_cdevsw, (char*)0 },
# endif
/* Kernel addresses associated with process wait states. */
# ifdef VMUNIX
{ "_fltab", 0, &Info.i_fltab, "floppy" },
{ "_va_softc", 0, &Info.i_va_softc, "varian" },
{ "_bfreelist", 0, &Info.i_bfreeli, "buffer" },
{ "_lp_softc", 0, &Info.i_lpdt, "printr" },
{ "_rswbuf", 0, &Info.i_rswbuf, "rswap" },
# ifdef CHAOS
{ "_Chrfclist", 0, &Info.i_chrfclist, "chrfc" },
# endif
# else
{ "_vn11", 0, &Info.i_va_softc, "varian" },
{ "_bfreeli", 0, &Info.i_bfreeli, "buffer" },
{ "_lp_dt", 0, &Info.i_lpdt, "printr" },
{ "_swbuf1", 0, &Info.i_swap1, "swap1" },
{ "_swbuf2", 0, &Info.i_swap2, "swap2" },
# endif
{ "_u", 0, &Info.i_u, "pause" },
{ "_chtbuf", 0, &Info.i_chtbuf, "tapecn" },
{ "_rhtbuf", 0, &Info.i_rhtbuf, "tapeio" },
{ "_lbolt", 0, &Info.i_lbolt, "lbolt" },
{ "_runin", 0, &Info.i_runin, "runin" },
{ "_runout", 0, &Info.i_runout, "runout" },
{ "_ipc", 0, &Info.i_ipc, "ptrace" },
{ (char*)0, 0, (caddr_t*)0, (char*)0 }
} ;
---END-OF-globals2.c---
echo Extracting initialise.c
cat > initialise.c << '---END-OF-initialise.c---'
# include "sps.h"
# include <pwd.h>
# include <stdio.h>
/*
** INITIALISE - Called to reset the `Info' structure with new kernel
** addresses and user and tty information.
*/
initialise ()
{
register FILE *fd ;
static char file_info[] = FILE_INFO ;
extern struct info Info ;
FILE *fopen() ;
# ifndef TRACE
if ( getuid() )
prexit( "sps - You are not the super-user\n" ) ;
# endif
/* Read kernel addresses */
readsymbols() ;
/* Read user names */
readusers() ;
(void)umask( ~0644 ) ;
if ( !(fd = fopen( file_info, "w" )) )
{
fprintf( stderr, "sps - Can't create info file %s", file_info );
sysperror() ;
}
/* Find tty addresses */
ttyinit() ;
if ( fwrite( (char*)&Info, sizeof( struct info ), 1, fd ) != 1 )
{
fprintf( stderr, "sps - can't write info file %s", file_info ) ;
sysperror() ;
exit( 1 ) ;
}
(void)fclose( fd ) ;
printf( "Sps is initialised\n" ) ;
}
/* READUSERS - Read the passwd file and fill in the user name arrays */
readusers ()
{
register struct passwd *pw ;
struct passwd *getpwent() ;
char *strncpy() ;
extern struct info Info ;
while ( pw = getpwent() )
{
if ( pw->pw_uid >= MAXUSERS )
{
fprintf( stderr,
"sps - User %s has uid %d exceeding maximum %d\n",
pw->pw_name, pw->pw_uid, MAXUSERS ) ;
continue ;
}
if ( !Info.i_unames[ pw->pw_uid ][0] )
(void)strncpy( &Info.i_unames[ pw->pw_uid ][0],
pw->pw_name, UNAMELEN ) ;
}
endpwent() ;
}
---END-OF-initialise.c---
echo Extracting main.c
cat > main.c << '---END-OF-main.c---'
# include "sps.h"
# include <stdio.h>
/* SPS - Show Process Status */
/* J. R. Ward - IIASA - 31 March 1983 */
main ( argc,argv )
int argc ;
char **argv ;
{
register struct process *plist ;
# ifdef VMUNIX
register struct process *process ;
register struct text *text ;
# else
static struct process process[ NPROC ] ;
static struct text text[ NTEXT ] ;
# endif
int flinfo ;
extern struct flags Flg ;
extern struct info Info ;
extern int Flmem ;
extern int Flkmem ;
extern int Flswap ;
# ifndef VMUNIX
extern char Sobuf[] ;
# endif
# ifdef VMUNIX
char *getcore() ;
# endif
struct process *needed(), *mktree() ;
# ifndef TRACE
(void)nice( -40 ) ;
(void)setuid( getuid() ) ;
# endif
# ifndef VMUNIX
setbuf( stdout, Sobuf ) ;
# endif
/* Decode the flag arguments */
flagdecode( argc, argv ) ;
/* Open the cpu physical memory, kernel virtual memory and swap device*/
Flmem = openfile( FILE_MEM ) ;
Flkmem = openfile( FILE_KMEM ) ;
Flswap = openfile( FILE_SWAP ) ;
if ( Flg.flg_i )
{ /* -i flag for info file initialisation */
initialise() ;
exit( 0 ) ;
}
/* Read the information file */
flinfo = openfile( FILE_INFO ) ;
if ( read( flinfo, (char*)&Info, sizeof( struct info ) )
!= sizeof( struct info ) )
{
fprintf( stderr, "sps - Can't read info file %s", FILE_INFO ) ;
sysperror() ;
}
(void)close( flinfo ) ;
/* Find current tty status */
ttystatus() ;
/* Now that we know the available ttys, decode the flags */
flagsetup() ;
# ifdef VMUNIX
process = (struct process*)getcore(Info.i_nproc*sizeof(struct process));
text = (struct text*)getcore( Info.i_ntext * sizeof( struct text ) ) ;
# endif
do
{ /* Read current process and text status */
readstatus( process, text ) ;
/* Select those processes to be listed */
plist = needed( getuid(), process, text ) ;
/* Form a tree of listed processes */
plist = mktree( process, plist ) ;
if ( !Flg.flg_N )
{ /* Print the processes */
prheader() ;
printall( plist, 0 ) ;
}
prsummary() ;
(void)fflush( stdout ) ;
if ( Flg.flg_r )
{ /* If repeating, again get tty status */
ttystatus() ;
sleep( 5 ) ;
}
} while ( Flg.flg_r ) ;
exit( 0 ) ;
}
---END-OF-main.c---
echo Extracting mktree.c
cat > mktree.c << '---END-OF-mktree.c---'
# include "sps.h"
/*
** MKTREE - Sort the needed processes by subtree and at the top by user.
** This procedure takes a list of processes (as returned by needed())
** and returnes a pointer to a sorted list.
*/
struct process *mktree ( process, plist )
struct process *process ;
struct process *plist ;
{
register struct process *p ;
register struct process *pp ;
register struct process *lp ;
struct process *op ;
struct process proot ;
proot.pr_sibling = (struct process*)0 ;
for ( p = plist ; p ; p = p->pr_plink )
{
if ( p->pr_pptr > &process[1] )
{
for ( pp = plist ; pp ; pp = pp->pr_plink )
{
if ( pp != p->pr_pptr )
continue ;
if ( lp = pp->pr_child )
{ /* Does process have children ? */
op = (struct process*)0 ;
while (lp &&
lp->pr_p.p_pid < p->pr_p.p_pid )
{
op = lp ;
lp=lp->pr_sibling ;
}
if ( op )
{
p->pr_sibling = lp ;
op->pr_sibling = p ;
break ;
}
}
p->pr_sibling = lp ;
pp->pr_child = p ;
break ;
}
if ( pp )
continue ;
}
/* We have a top level process, sort into top level list.
The top level is sorted firstly by user-id and then
by process-id. */
lp = &proot ;
pp = lp->pr_sibling ;
while ( pp )
{
if ( p->pr_p.p_uid < pp->pr_p.p_uid )
break ;
if ( p->pr_p.p_uid == pp->pr_p.p_uid
&& p->pr_p.p_pid < pp->pr_p.p_pid )
break ;
lp = pp, pp = pp->pr_sibling ;
}
p->pr_sibling = lp->pr_sibling ;
lp->pr_sibling = p ;
}
return ( proot.pr_sibling ) ;
}
---END-OF-mktree.c---
echo Extracting needed.c
cat > needed.c << '---END-OF-needed.c---'
# include "sps.h"
# include <stdio.h>
/*
** NEEDED - Determine which processes are needed for the printout
** and add these to a list of needed processes.
*/
struct process *needed ( thisuid, process, text )
int thisuid ;
register struct process *process ;
struct text *text ;
{
register struct process *p ;
# ifdef V7
register struct process *pp ;
# endif
register struct process *plist ;
struct process *lastp ;
extern struct flags Flg ;
# ifdef VMUNIX
extern union userstate User ;
# endif
extern struct info Info ;
extern struct ttyline Notty ;
struct ttyline *findtty() ;
char *getcmd() ;
plist = (struct process*)0 ;
# ifdef VMUNIX
lastp = &process[Info.i_nproc] ;
# else
lastp = &process[NPROC] ;
# endif
/* Normalise internal pointers from kernel addresses. For each kmem
address in the `proc' and `text' structures, we convert that
address for our own internal use. */
for ( p = process ; p < lastp ; p++ )
{
if ( !p->pr_p.p_stat )
continue ;
/* Normalise internal text pointers */
if ( p->pr_p.p_textp )
p->pr_p.p_textp = &text[p->pr_p.p_textp - Info.i_text0];
/* Normalise internal linked list of processes */
p->pr_plink = p->pr_p.p_link ?
&process[ p->pr_p.p_link - Info.i_proc0 ] :
(struct process*)0 ;
# ifdef V7
/* Compensate for the lack of a parent pointer in the
standard V7 proc structure ; here we go through the
proc array searching for a process that has the same
id as that of the current parent. */
p->pr_pptr = (struct process*)0 ;
for ( pp = process ; pp < lastp ; pp++ )
if ( pp->pr_p.p_pid == p->pr_p.p_ppid )
{
p->pr_pptr = pp ;
break ;
}
# else
/* Normalise internal process parent pointers */
p->pr_pptr = p->pr_p.p_pptr ?
&process[ p->pr_p.p_pptr - Info.i_proc0 ] :
(struct process*)0 ;
# endif
/* Check for valid parent pointers */
if ( !p->pr_pptr )
{
p->pr_pptr = process ;
continue ;
}
if ( p->pr_pptr < process || p->pr_pptr >= lastp )
{
fprintf( stderr, "sps - process %d has bad pptr\n",
p->pr_p.p_pid ) ;
p->pr_pptr = process ;
}
}
/* For each process, see if it is a candidate for selection.
If so, retrieve its command arguments and upage information. */
for ( p = process ; p < lastp ; p++ )
{
if ( !p->pr_p.p_stat )
continue ;
/* Count processes and sizes */
summarise( p ) ;
/* Select the given processes. Bear in mind that selection
of processes based on the `F' and `T' flags must be
postponed until the upage is accessed. */
if ( !Flg.flg_F && !Flg.flg_T && !select( p, process, thisuid ))
continue ;
/* Try to find the process' command arguments. Accessing the
arguments also involves retrieving the upage. */
p->pr_cmd = getcmd( p ) ;
/* If the upage was found successfully, use this information */
if ( p->pr_upag )
{
# ifdef VMUNIX
p->pr_vself = User.u_us.u_vm ;
p->pr_vchild = User.u_us.u_cvm ;
p->pr_tty = findtty( p ) ;
p->pr_files = filecount() ;
# else
getuinfo( p ) ;
p->pr_tty = findtty( p ) ;
# ifndef V7
/* Here we simulate the missing SDETACH bit from the
proc structure. A process is detached if its parent
is detached, or if its parent is process 1 and it
is running in the background. */
p->pr_detach = p->pr_pptr->pr_detach
|| (p->pr_pptr->pr_p.p_pid == 1
&& (p->pr_p.p_flag & SBGRND)) ;
# endif
# endif
}
else
p->pr_tty = &Notty ;
/* Select on the basis of the `F' and `T' flags */
if ( Flg.flg_F
&& !(p->pr_p.p_pgrp && p->pr_p.p_pgrp == p->pr_tty->l_pgrp) )
continue ;
if ( Flg.flg_T && !select_tty( p ) )
continue ;
/* Arrive here with a selected process. Add this to the
linked list of needed processes. */
p->pr_plink = plist ;
plist = p ;
p->pr_child = (struct process*)0 ;
p->pr_sibling = (struct process*)0 ;
/* Check for valid process user-id */
if ( p->pr_p.p_uid >= MAXUSERS )
{
fprintf( stderr,
"sps - Process %d has uid %d exceeding maximum %d\n",
p->pr_p.p_pid, p->pr_p.p_uid, MAXUSERS ) ;
p->pr_p.p_uid %= MAXUSERS ;
}
}
return ( plist ) ;
}
/* SUMMARISE - Summarises the given process into the `Summary' structure */
/*
** SHOULD ACCOUNT HERE FOR THE SIZE OF LOADED PAGE TABLES, BUT WE DON'T REALLY
** KNOW THEIR RESIDENT SIZES.
*/
summarise ( p )
register struct process *p ;
{
register struct text *tp ;
int busy ;
extern struct summary Summary ;
Summary.sm_ntotal++ ;
if ( p->pr_p.p_stat == SZOMB )
return ;
/* Firstly, account for processes */
# ifdef VMUNIX
Summary.sm_ktotal += p->pr_p.p_dsize + p->pr_p.p_ssize ;
Summary.sm_kloaded += p->pr_p.p_rssize ;
Summary.sm_kswapped += p->pr_p.p_swrss ;
# else
Summary.sm_ktotal += p->pr_p.p_size ;
if ( p->pr_p.p_flag & SLOAD )
Summary.sm_kloaded += p->pr_p.p_size ;
# endif
if ( p->pr_p.p_flag & SLOAD )
Summary.sm_nloaded++ ;
else
Summary.sm_nswapped++ ;
busy = (p->pr_p.p_stat == SRUN) || (p->pr_p.p_stat==SSLEEP
&& (p->pr_p.p_pri<PZERO && p->pr_p.p_pid > MSPID) ) ;
if ( busy )
{
Summary.sm_nbusy++ ;
# ifdef VMUNIX
Summary.sm_kbusy += p->pr_p.p_dsize + p->pr_p.p_ssize ;
# else
Summary.sm_kbusy += p->pr_p.p_size ;
# endif
}
/* Now account for their texts */
if ( !(tp = p->pr_p.p_textp) || !tp->x_count )
return ;
Summary.sm_ktotal += tp->x_size ;
# ifdef VMUNIX
Summary.sm_kloaded += tp->x_rssize ;
Summary.sm_kswapped += tp->x_swrss ;
# else
if ( p->pr_p.p_flag & SLOAD )
Summary.sm_kloaded += tp->x_size ;
# endif
if ( busy )
Summary.sm_kbusy += tp->x_size ;
tp->x_count = 0 ;
}
---END-OF-needed.c---
echo Extracting openfiles.c
cat > openfiles.c << '---END-OF-openfiles.c---'
# include <stdio.h>
# include "sps.h"
/* Miscellaneous procedures */
/* OPENFILE - Opens the named file */
openfile ( name )
char *name ;
{
register int fd ;
if ( (fd = open( name, 0 )) >= 0 )
return ( fd ) ;
fprintf( stderr, "sps - Can't open %s", name ) ;
sysperror() ;
/* NOTREACHED */
}
# ifdef lint
int errno ;
int sys_nerr ;
char *sys_errlist[] ;
# endif
/* SYSPERROR - Reports a system defined error msg and then exits gracefully */
sysperror ()
{
extern int errno ;
extern int sys_nerr ;
extern char *sys_errlist[] ;
if ( 0 < errno && errno < sys_nerr )
fprintf( stderr, " : %s", sys_errlist[errno] ) ;
fputc( '\n', stderr ) ;
exit( 1 ) ;
}
/* STRSAVE - Store a string in core for later use. */
char *strsave ( cp )
register char *cp ;
{
register char *chp ;
char *getcore(), *strcpy() ;
chp = getcore( strlen( cp ) + 1 ) ;
(void)strcpy( chp, cp ) ;
return ( chp ) ;
}
/* GETCORE - Allocate and return a pointer to the asked for amount of core */
char *getcore ( size )
register int size ;
{
register char *chp ;
char *malloc() ;
if ( chp = malloc( (unsigned)size ) )
return ( chp ) ;
fprintf( stderr, "sps - Out of core" ) ;
sysperror() ;
/* NOTREACHED */
}
union flaglist *getflgsp ( argc )
register int argc ;
{
char *getcore() ;
return ( (union flaglist*)getcore( sizeof( union flaglist )*argc ) ) ;
}
/* PREXIT - Print an error message and exit */
/* VARARGS1 */
/* ARGSUSED */
prexit ( fmt, args )
char *fmt ;
{
_doprnt( fmt, &args, stderr ) ;
exit( 1 ) ;
}
---END-OF-openfiles.c---
echo Extracting percentmem.c
cat > percentmem.c << '---END-OF-percentmem.c---'
# ifdef VMUNIX
# include "sps.h"
/* PERCENTMEM - Returns the percentage of real memory used by this process */
double percentmem ( p )
register struct process *p ;
{
register struct text *tp ;
double fracmem ;
int szptudot ;
extern struct info Info ;
tp = p->pr_p.p_textp ;
if ( !(p->pr_p.p_flag & SLOAD) || !tp )
return ( 0.0 ) ;
szptudot = UPAGES + clrnd( ctopt( p->pr_p.p_dsize + p->pr_p.p_ssize ) );
fracmem = ( (double)p->pr_p.p_rssize+szptudot ) / CLSIZE ;
if ( tp->x_ccount )
fracmem += ((double)tp->x_rssize)/CLSIZE/tp->x_ccount ;
return ( 100.0 * fracmem / (double)Info.i_ecmx ) ;
}
# endif
---END-OF-percentmem.c---
echo Extracting prcmd.c
cat > prcmd.c << '---END-OF-prcmd.c---'
# include "sps.h"
/* PRCMD - Prints the command arguments according to the switches */
prcmd ( p, lpad, width )
register struct process *p ;
int lpad ;
int width ;
{
extern struct flags Flg ;
# ifdef VMUNIX
printf( "%*d ", lpad+5, Flg.flg_f ? p->pr_p.p_ppid :
# else
printf( "%*d ", lpad+5, Flg.flg_f ? p->pr_pptr->pr_p.p_pid :
# endif
Flg.flg_g ? p->pr_p.p_pgrp : p->pr_p.p_pid ) ;
if ( Flg.flg_w )
printf( "%s\n", p->pr_cmd ) ;
else
printf( "%-.*s\n", width, p->pr_cmd ) ;
if ( p->pr_csaved )
free( p->pr_cmd ) ;
}
---END-OF-prcmd.c---
echo Extracting prcpu.c
cat > prcpu.c << '---END-OF-prcpu.c---'
# include "sps.h"
# ifdef VMUNIX
# define HERTZ (Info.i_hz)
# else
# define HERTZ HZ
# endif
/* PRCPU - Print cpu time */
prcpu ( time )
register time_t time ;
{
extern struct info Info ;
/* Assume more than 1000 hours is in error */
if ( time < 0 || time > HERTZ*1000L*60L*60L )
{
printf( " " ) ;
return ;
}
if ( time < HERTZ*60L*10L )
{ /* Less than 10 minutes */
printf( "%3d.%1d", (int)(time/HERTZ),
(int)(time % HERTZ / (HERTZ/10L)) ) ;
return ;
}
time /= HERTZ ;
/* If less than 10 hours, print as minutes */
if ( time < 60L*60L*10L )
printf( "%3D M", time/60L ) ;
else
printf( "%3D H", time/60L/60L ) ;
}
---END-OF-prcpu.c---
echo Extracting prheader.c
cat > prheader.c << '---END-OF-prheader.c---'
# include "sps.h"
/* PRHEADER - Print a header according to the switches */
prheader ()
{
# ifdef VMUNIX
static char vhdr[] =
"Status Fl Nice Virtual Resident %M Time Child %C Proc# Command\n" ;
static char dhdr[] =
" Files PageFaults Swap BlockI/O Kbytsecs Proc# Command\n" ;
# else
static char vhdr[] =
"Status Fl Nice Memory Time Child Proc# Command\n" ;
# endif
static char hdr[] =
"Proc# Command\n" ;
extern struct flags Flg ;
printf( "Ty User " ) ;
# ifdef VMUNIX
printf( "%s", Flg.flg_v ? vhdr : Flg.flg_d ? dhdr : hdr ) ;
# else
printf( "%s", Flg.flg_v ? vhdr : hdr ) ;
# endif
}
---END-OF-prheader.c---
echo Extracting printall.c
cat > printall.c << '---END-OF-printall.c---'
# include <stdio.h>
# include "sps.h"
/* PRINTALL - Recursively print the process tree. */
printall ( p, md )
register struct process *p ;
register int md ;
{
while ( p )
{ /* Print this process */
printproc( p, md ) ;
(void)fflush( stdout ) ;
/* Print child processes */
printall( p->pr_child, md+1 ) ;
/* Print brother processes */
p = p->pr_sibling ;
}
}
---END-OF-printall.c---
echo Extracting printproc.c
cat > printproc.c << '---END-OF-printproc.c---'
# include "sps.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 ;
char chbuf[10] ;
time_t time ;
time_t chtime ;
extern short Lastuid ;
extern struct flags Flg ;
extern struct info Info ;
char *waitingfor() ;
# ifdef VMUNIX
double percentmem() ;
# endif
/* List tty name and foreground/background/detached information */
printf( "%2.2s%c", p->pr_tty->l_name,
!p->pr_p.p_pgrp ? ' ' :
# ifdef VMUNIX
p->pr_p.p_flag & SDETACH ? '_' :
# else
# ifndef V7
p->pr_detach ? '_' :
# endif
# endif
p->pr_p.p_pgrp == p->pr_tty->l_pgrp ? '.' : ' ' ) ;
if ( !md )
{ /* If a top-level process, list the user name */
if ( Info.i_unames[ p->pr_p.p_uid ][0] )
printf( "%-8.8s ", Info.i_unames[ p->pr_p.p_uid ] ) ;
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*", md, "" ) ;
/* But beware of setuid processes */
chp = p->pr_p.p_uid == Lastuid ? "" :
Info.i_unames[ p->pr_p.p_uid ] ;
md = 8 - md ;
printf( "%-*.*s", md, md, chp ) ;
}
Lastuid = p->pr_p.p_uid ;
# ifdef VMUNIX
if ( Flg.flg_d )
{ /* List disc I/O and paging information */
if ( !p->pr_upag || p->pr_p.p_stat == SZOMB )
{
prcmd( p, 44, 17 ) ;
return ;
}
printf( "%2d %8d+%8d %4d %8d %8D ",
p->pr_files,
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,
MSIZE( ( p->pr_vself.vm_idsrss
+ p->pr_vself.vm_ixrss )/Info.i_hz ) ) ;
prcmd( p, 0, 17 ) ;
return ;
}
# endif
if ( !Flg.flg_v )
{ /* Not verbose so just list command arguments */
prcmd( p, 0, 61 ) ;
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 */
# ifdef VMUNIX
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 & (SANOM|SUANOM) ? 'A' : ' ' ) ;
# else
printf( "%c%c%c", p->pr_p.p_flag & SSYS ? 'U' :
p->pr_p.p_flag & STRC ? 'T' : ' ',
p->pr_p.p_flag & SSWAP ? 'S' : ' ',
p->pr_p.p_flag & SULOCK ? 'L' : ' ' ) ;
# endif
/* 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 )
{
# ifdef VMUNIX
prcmd( p, 36, 11 ) ;
# else
prcmd( p, 23, 13 ) ;
# endif
return ;
}
/* List process and text virtual sizes */
# ifdef VMUNIX
printf( "%4d", MSIZE( p->pr_p.p_dsize + p->pr_p.p_ssize ) ) ;
if ( tp = p->pr_p.p_textp )
printf( "+%3d ", MSIZE( tp->x_size ) ) ;
else
printf( " " ) ;
/* List process and text real sizes */
printf( "%4d", MSIZE( p->pr_p.p_rssize ) ) ;
if ( tp )
printf( "+%3d %2.0f ", MSIZE( tp->x_rssize ), percentmem( p ) );
else
printf( " " ) ;
# else
printf( " " ) ;
prmem( p->pr_p.p_size ) ;
if ( tp = p->pr_p.p_textp )
{
printf( "+" ) ;
prmem( tp->x_size ) ;
}
else
printf( " " ) ;
printf( " " ) ;
# endif
/* List information obtained from the upage. This includes the process
times and command arguments. */
if ( !p->pr_upag )
{
# ifdef VMUNIX
prcmd( p, 15, 11 ) ;
# else
prcmd( p, 12, 24 ) ;
# endif
return ;
}
/* List process time information */
# ifdef VMUNIX
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 ;
# else
time = Flg.flg_q ? p->pr_utime : p->pr_utime + p->pr_stime ;
chtime = Flg.flg_q ? p->pr_cutime : p->pr_cutime + p->pr_cstime ;
# endif
prcpu( time ) ;
if ( chtime != 0L )
{
printf( "+" ) ;
prcpu( chtime ) ;
}
else
printf( " " ) ;
# ifdef VMUNIX
if ( time )
printf( " %2.0f ", p->pr_p.p_pctcpu * 100.0 ) ;
else
printf( " " ) ;
# endif
/* Finally, list the process command arguments. */
# ifdef VMUNIX
prcmd( p, 0, 11 ) ;
# else
prcmd( p, 1, 24 ) ;
# endif
}
/* 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++ ;
}
}
# ifndef VMUNIX
/* PRMEM - List the memory size of a given process */
prmem ( size )
register int size ;
{
# ifdef M68000
printf( "%4d", MSIZE( size ) ) ;
# else
printf( "%2d.%1d", (size / 16) & 07777, (size % 16) * 10/64 ) ;
# endif
}
# endif
---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(
# ifdef VMUNIX
"%D (%Dk) processes, %D (%Dk) busy, %D (%Dk) loaded, %D (%Dk) swapped\n",
# else
"%D (%Dk) processes, %D (%Dk) busy, %D (%Dk) loaded, %D swapped\n",
# endif
Summary.sm_ntotal, MSIZE( Summary.sm_ktotal ),
Summary.sm_nbusy, MSIZE( Summary.sm_kbusy ),
Summary.sm_nloaded, MSIZE( Summary.sm_kloaded ),
# ifdef VMUNIX
Summary.sm_nswapped, MSIZE( Summary.sm_kswapped ) ) ;
# else
Summary.sm_nswapped ) ;
# endif
Summary.sm_ntotal = Summary.sm_ktotal = 0L ;
Summary.sm_nbusy = Summary.sm_kbusy = 0L ;
Summary.sm_nloaded = Summary.sm_kloaded = 0L ;
# ifdef VMUNIX
Summary.sm_nswapped = Summary.sm_kswapped = 0L ;
# else
Summary.sm_nswapped = 0L ;
# endif
}
---END-OF-prsummary.c---
echo Extracting readstatus.c
cat > readstatus.c << '---END-OF-readstatus.c---'
# include "sps.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 ;
# ifdef VMUNIX
register struct proc *p0 ;
# else
static struct proc p0[ NPROC ] ;
# endif
register struct process *pr ;
extern struct info Info ;
extern int Flkmem ;
long lseek() ;
# ifdef VMUNIX
char *getcore() ;
# endif
/* Read current text information */
(void)lseek( Flkmem, (long)Info.i_text0, 0 ) ;
# ifdef VMUNIX
(void)read( Flkmem, (char*)text, Info.i_ntext * sizeof( struct text ) );
# else
(void)read( Flkmem, (char*)text, NTEXT * sizeof( struct text ) );
# endif
/* Read current process information */
# ifdef VMUNIX
p0 = (struct proc*)getcore( sizeof( struct proc )*Info.i_nproc ) ;
# endif
(void)lseek( Flkmem, (long)Info.i_proc0, 0 ) ;
# ifdef VMUNIX
(void)read( Flkmem, (char*)p0, Info.i_nproc * sizeof( struct proc ) ) ;
/* 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 ) ;
# else
(void)read( Flkmem, (char*)p0, NPROC * sizeof( struct proc ) ) ;
for ( p = p0, pr = process ; pr < &process[NPROC] ; p++, pr++ )
pr->pr_p = *p ;
# endif
}
---END-OF-readstatus.c---
echo Extracting readsymbols.c
cat > readsymbols.c << '---END-OF-readsymbols.c---'
# include "sps.h"
# ifdef VMUNIX
# include <nlist.h>
# else
# include <a.out.h>
# endif
# include <stdio.h>
# ifndef NCPS
# define NCPS 8
# endif
/* READSYMBOLS - Reads kmem values into the Info structure */
/*
** THIS CODE COPIES KMEM VALUES INTO THE INFO STRUCTURE ASSUMING THAT
** VALUES READ FROM THE KERNEL HAVE TYPE CADDR_T. THEREFORE, WE ARE
** MAKING THE DUBIOUS ASSUMPTION THAT INTS, POINTERS AND CADDR_T's
** HAVE IDENTICAL SIZES.
*/
readsymbols ()
{
register struct nlist *np ;
register struct symbol *s ;
register struct nlist *np0 ;
static char file_symbol[] = FILE_SYMBOL ;
extern struct symbol Symbollist[] ;
extern int Flkmem ;
char *getcore() ;
long lseek() ;
# ifndef VMUNIX
char *strncpy() ;
# endif
/* Find the length of the symbol table */
for ( s = Symbollist ; s->s_kname ; s++ )
;
/* Construct an nlist structure by copying names from the symbol table*/
np0 = (struct nlist*)getcore( (s-Symbollist+1)*sizeof( struct nlist ) );
for ( s = Symbollist, np = np0 ; s->s_kname ; s++, np++ )
{
# ifdef VMUNIX
np->n_name = s->s_kname ;
np[1].n_name = (char*)0 ;
# else
(void)strncpy( np->n_name, s->s_kname, NCPS ) ;
np[1].n_name[0] = '\0' ;
# endif
np->n_value = 0 ;
}
/* Get kernel addresses */
nlist( file_symbol, np0 ) ;
# ifdef VMUNIX
if ( np0[0].n_value == -1 )
{
fprintf( stderr,
"sps - Can't read symbol file %s", file_symbol ) ;
sysperror() ;
}
# endif
/* Copy addresses and values into the `Info' structure */
for ( s = Symbollist, np = np0 ; s->s_kname ; s++, np++ )
{
if ( !np->n_value )
{
# ifdef VMUNIX
fprintf( stderr, "sps - Can't find symbol %s in %s\n",
np->n_name, file_symbol ) ;
# else
fprintf( stderr,
"sps - Can't find symbol %*.*s in %s\n",
NCPS, NCPS, np->n_name, file_symbol ) ;
# endif
*s->s_info = (caddr_t)0 ;
continue ;
}
/* If no indirection is required, just copy the obtained value
into the `Info' structure. */
if ( !s->s_indirect )
{
/* DUBIOUS ASSUMPTION THAT KMEM VALUE HAS SIZE OF A CADDR_T */
*s->s_info = (caddr_t)np->n_value ;
continue ;
}
/* Otherwise one level of indirection is required. Using the
obtained address, look again in the kernel for the value */
(void)lseek( Flkmem, (long)np->n_value, 0 ) ;
/* DUBIOUS ASSUMPTION THAT KMEM VALUE HAS SIZE OF A CADDR_T */
(void)read( Flkmem, (char*)s->s_info, sizeof(caddr_t) ) ;
}
free( (char*)np0 ) ;
}
---END-OF-readsymbols.c---
echo Extracting select.c
cat > select.c << '---END-OF-select.c---'
# include "sps.h"
/*
** SELECT - Given a process structure, this procedure decides whether
** the process is a candidate for printing.
*/
select ( 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 ;
}
# ifdef VMUNIX
if ( Flg.flg_D && p->pr_p.p_pgrp && (p->pr_p.p_flag & SDETACH) )
return ( 1 ) ;
# endif
return ( 0 ) ;
}
---END-OF-select.c---
echo Extracting select_tty.c
cat > select_tty.c << '---END-OF-select_tty.c---'
# include "sps.h"
/* SELECT_TTY - Decides whether this process is interesting for its tty */
select_tty ( 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-select_tty.c---
echo Extracting sps.h
cat > sps.h << '---END-OF-sps.h---'
# ifdef VMUNIX
# include <h/param.h>
# include <h/dir.h>
# include <h/user.h>
# include <h/proc.h>
# include <h/pte.h>
# include <h/vm.h>
# include <h/inode.h>
# include <h/file.h>
# include <h/buf.h>
# include <h/text.h>
# include <h/tty.h>
# include <h/conf.h>
# else
# include <param.h>
# include <dir.h>
# include <user.h>
# include <proc.h>
# include <inode.h>
# include <file.h>
# include <buf.h>
# include <text.h>
# include <tty.h>
# include <conf.h>
# endif
/* Max # users to be considered ... */
# define MAXUSERS 300
/* Max # ttys to be considered ... */
# define MAXTTYS 50
/* Max user name length ... */
# define UNAMELEN 8
/* Max process-id not to be considered busy ... */
# define MSPID 2
# ifdef VMUNIX
/* # process' virtual pages to be read to determine argument list ... */
# define MAXARGPG 5
/* Length of each process' page table to be obtained ... */
# define PAGETABLESIZE (UPAGES + MAXARGPG)
# endif
/* Convert clicks to kbytes ... */
# ifdef VMUNIX
# define KSHIFT 10
# define MSIZE( s ) ( (s) >> (KSHIFT - PGSHIFT) )
# else
# ifdef M68000
# define MSIZE( s ) ( (s) << 1 )
# else
# define MSIZE( s ) ( (s) >> 4 )
# endif
# endif
/* 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/swap" /* Swap/paging device */
# ifdef VMUNIX
# define FILE_SYMBOL "/vmunix" /* Symbol file for nlist() */
# else
# define FILE_SYMBOL "/unix"
# endif
# define FILE_DEV "/dev" /* Directory of tty entries */
# ifdef TRACE
# define FILE_INFO "./spsinfo" /* Information file */
# else
# define FILE_INFO "/etc/spsinfo"
# endif
/* 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 # */
} ;
/* Format of the standard information file maintained by sps ... */
/*
** This structure is filled in at initialisation time. Otherwise it
** is read in whenever sps is invoked. Keeping known kernel addresses
** in a file is much faster than accessing them every time the program
** 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 ... */
# ifdef VMUNIX
int i_nproc ; /* length of process table */
int i_ntext ; /* length of text table */
int i_ninode ; /* length of inode table */
int i_nswbuf ; /* # swap buffers */
int i_nbuf ; /* # i/o buffers */
int i_hz ; /* clock rate on this machine */
int i_ecmx ; /* max physical memory address*/
struct tty *i_pt_tty ; /* pseudo-tty device base */
struct pte *i_usrptmap ; /* page table map */
struct pte *i_usrpt ; /* page table map */
struct buf *i_swbuf0 ; /* address of swap buffers */
# ifdef CHAOS
caddr_t i_Chconntab ; /* Chaos connection table */
# endif
# else
int i_nswap ;
int i_swplo ;
# endif
struct proc *i_proc0 ; /* address of process table */
struct text *i_text0 ; /* address of text table */
struct inode *i_inode0 ; /* address of inode table */
struct buf *i_buf0 ; /* address of i/o buffers */
struct cdevsw *i_cdevsw ; /* device switch to find ttys */
/* These remaining kernel addresses are associated with
process wait states ... */
# ifdef VMUNIX
caddr_t i_fltab ;
caddr_t i_rswbuf ;
# ifdef CHAOS
caddr_t i_chrfclist ;
# endif
# else
caddr_t i_swap1 ;
caddr_t i_swap2 ;
# endif
caddr_t i_va_softc ;
caddr_t i_bfreeli ;
caddr_t i_lpdt ;
caddr_t i_lbolt ;
caddr_t i_runin ;
caddr_t i_runout ;
caddr_t i_ipc ;
caddr_t i_u ;
caddr_t i_chtbuf ;
caddr_t i_rhtbuf ;
/* User names, indexed by uid ... */
char i_unames[ MAXUSERS ][ UNAMELEN ] ;
/* Tty device info ... */
struct ttyline i_ttyline[ MAXTTYS ] ;
} ;
# ifdef VMUNIX
/* The `user' structure obtained from /dev/mem or /dev/swap ... */
union userstate
{
struct user u_us ;
char u_pg[ UPAGES ][ NBPG ] ;
} ;
# endif
/* 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 ;
# ifdef VMUNIX
struct vtimes pr_vself ; /* Read from upage for self */
struct vtimes pr_vchild ; /* ... and the children */
int pr_files ; /* # open files */
# else
time_t pr_utime ;
time_t pr_stime ;
time_t pr_cutime ;
time_t pr_cstime ;
dev_t pr_ttyd ;
# endif
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() */
# ifndef VMUNIX
# ifndef V7
int pr_detach:1 ; /* Simulate the SDETACH bit */
# endif
# endif
} ;
/* To hold information specified in the option list ... */
union flaglist
{
char *f_chp ; /* Option specified as string */
int f_uid ; /* Numerical user id */
int f_pid ; /* Numerical process id */
struct ttyline *f_ttyline ; /* Specified tty */
} ;
/* To hold global information specifed by options in the arg list ... */
struct flags
{
# ifdef VMUNIX
int flg_d:1 ; /* disc orientated output */
# endif
int flg_e:1 ; /* print environment string */
int flg_f:1 ; /* print process father # */
int flg_g:1 ; /* print process group # */
int flg_i:1 ; /* initialise sps */
int flg_q:1 ; /* show user time only */
int flg_r:1 ; /* repeat output */
int flg_v:1 ; /* print verbose listing */
int flg_w:1 ; /* print wide output */
int flg_y:1 ; /* print tty information */
int flg_A:1 ; /* print all processes */
int flg_B:1 ; /* print busy processes */
# ifdef VMUNIX
int flg_D:1 ; /* print detached processes */
# endif
int flg_F:1 ; /* print foreground processes */
int flg_N:1 ; /* print no processes */
int flg_P:1 ; /* print specified process #'s*/
int flg_S:1 ; /* print stopped processes */
int flg_T:1 ; /* print procs for given ttys */
int flg_U:1 ; /* print procs for given users*/
int flg_W:1 ; /* print waiting processes */
int flg_Z:1 ; /* print zombie processes */
int flg_AZ:1 ; /* One of A to Z was specified*/
union flaglist *flg_Plist ; /* List of specified processes*/
union flaglist *flg_Tlist ; /* List of specified ttys */
union flaglist *flg_Ulist ; /* List of specified users */
} ;
/* 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 */
# ifdef VMUNIX
long sm_kswapped ; /* Size totally swapped out */
# endif
} ;
/*
** 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 */
} ;
---END-OF-sps.h---
echo Extracting ttyinit.c
cat > ttyinit.c << '---END-OF-ttyinit.c---'
# include "sps.h"
# include <stdio.h>
# include <sys/stat.h>
/* TTYINIT - Initialise the tty part of the info structure */
ttyinit ()
{
register struct ttyline *lp ;
FILE *fd ;
struct direct dirbuf ;
struct stat statbuf ;
static char file_dev[] = FILE_DEV ;
extern struct info Info ;
extern int Flkmem ;
FILE *fdopen() ;
lp = Info.i_ttyline ;
fd = fdopen( openfile( file_dev ), "r" ) ;
if ( chdir( file_dev ) < 0 )
prexit( "sps - Can't chdir to %s\n", file_dev ) ;
/* Read all entries in the device directory, looking for ttys */
while ( fread( (char*)&dirbuf, sizeof( struct direct ), 1, fd ) == 1 )
{
if ( !dirbuf.d_ino )
continue ;
/* Skip entries that do not match "tty" or "console" */
if ( strncmp( "tty", dirbuf.d_name, 3 )
&& strcmp( "console", dirbuf.d_name ) )
continue ;
/* Skip "tty" itself */
if ( dirbuf.d_name[3] == '\0' )
continue ;
# ifdef CHAOS
/* Skip chaos ttys ; they are accessed during ttystatus() */
if ( dirbuf.d_name[ sizeof( "tty" ) - 1 ] == 'C' )
continue ;
# endif
if ( lp >= &Info.i_ttyline[ MAXTTYS ] )
prexit( "sps - Too many ttys in %s\n", file_dev ) ;
/* Copy the tty name into the information entry */
if ( !strcmp( dirbuf.d_name, "console" ) )
lp->l_name[0] = 'c', lp->l_name[1] = 'o' ;
else
{
lp->l_name[0] = dirbuf.d_name[3] ;
lp->l_name[1] = dirbuf.d_name[4] ;
}
/* Ensure that this tty is actually a valid character device */
if ( stat( dirbuf.d_name, &statbuf ) < 0 )
continue ;
if ( (statbuf.st_mode & S_IFMT) != S_IFCHR )
continue ;
/* Find the device # of the tty and the address of its
associated struct tty in /dev/kmem. */
lp->l_dev = statbuf.st_rdev ;
(void)lseek( Flkmem,
(long)&Info.i_cdevsw[ major( statbuf.st_rdev ) ].d_ttys,
0 ) ;
(void)read( Flkmem, (char*)&lp->l_addr, sizeof( lp->l_addr ) ) ;
lp->l_addr += (int)minor( statbuf.st_rdev ) ;
lp++ ;
}
(void)fclose( fd ) ;
}
---END-OF-ttyinit.c---
echo Extracting ttystatus.c
cat > ttystatus.c << '---END-OF-ttystatus.c---'
# include "sps.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 ;
long lseek() ;
if ( Flg.flg_y )
# if VMUNIX | M68000
printf( "Ty Dev Addr Rawq Canq Outq Pgrp\n" ) ;
# else
printf( "Ty Dev Addr Rawq Canq Outq Pgrp\n" ) ;
# endif
lp = Info.i_ttyline ;
# ifdef CHAOS
while ( lp->l_name[0] && lp->l_name[0] != 'C' )
# else
while ( lp->l_name[0] )
# endif
{
(void)lseek( Flkmem, (long)lp->l_addr, 0 ) ;
(void)read( Flkmem, (char*)&tty, sizeof( struct tty ) ) ;
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 ;
# if VMUNIX | M68000
printf( "%-2.2s %2d,%2d 0x%08x %4d %4d %4d %5d\n",
# else
printf( "%-2.2s %2d,%2d 0o%06o %4d %4d %4d %5d\n",
# endif
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 ;
(void)lseek( Flkmem, (long)Info.i_Chconntab, 0 ) ;
(void)read( Flkmem, (char*)conntab, sizeof( conntab ) ) ;
for ( i = 0, cnp = conntab ; cnp < &conntab[CHNCONNS] ; i++, cnp++ )
{
if ( !*cnp )
continue ;
(void)lseek( Flkmem, (long)*cnp, 0 ) ;
(void)read( Flkmem, (char*)&conn, sizeof( struct connection ) );
if ( !(conn.cn_flags & CHTTY) )
continue ;
(void)lseek( Flkmem, (long)conn.cn_ttyp, 0 ) ;
(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"
/* WAITINGFOR - Determine what a process is waiting for and describe it. */
# define INRANGE( w, a1, a2 ) \
( (caddr_t)(a1) <= (w) && (w) < (caddr_t)(a2) )
# ifdef VMUNIX
/* Max # active pty devices (this # is unobtainable from the system) ... */
# define NPTY 16
# endif
char *waitingfor ( p )
struct process *p ;
{
register caddr_t w ;
register struct ttyline *lp ;
register struct symbol *s ;
register char *cp ;
static char wbuf[ 7 ] ;
extern struct info Info ;
extern struct symbol Symbollist[] ;
char *sprintf() ;
w = p->pr_p.p_wchan ;
if ( !w )
return ( "null" ) ;
# ifdef VMUNIX
if ( INRANGE( w, Info.i_proc0, &Info.i_proc0[ Info.i_nproc ] ) )
return ( p->pr_p.p_flag & SNOVM ? "vfork" : "child" ) ;
if ( INRANGE( w, Info.i_swbuf0, &Info.i_swbuf0[ Info.i_nswbuf ] ) )
return ( "swap" ) ;
if ( INRANGE( w, Info.i_buf0, &Info.i_buf0[ Info.i_nbuf ] ) )
return ( "discio" ) ;
if ( INRANGE( w, Info.i_text0, &Info.i_text0[ Info.i_ntext ] ) )
return ( "swtext" ) ;
# else
if ( INRANGE( w, Info.i_proc0, &Info.i_proc0[ NPROC ] ) )
return ( "child" ) ;
if ( INRANGE( w, Info.i_buf0, &Info.i_buf0[ NBUF ] ) )
return ( "discio" ) ;
# endif
/* Is the process waiting for a tty ? */
for ( lp = Info.i_ttyline ; lp->l_name[0] ; lp++ )
if ( INRANGE( w, &lp->l_addr[0], &lp->l_addr[1] ) )
{
w -= (int)lp->l_addr ;
cp = w == (caddr_t)&((struct tty*)0)->t_rawq ? "rtty??"
: w == (caddr_t)&((struct tty*)0)->t_outq ? "wtty??"
: w == (caddr_t)&((struct tty*)0)->t_state ? "otty??"
: "?tty??" ;
cp[4] = lp->l_name[0] ;
cp[5] = lp->l_name[1] ;
return ( cp ) ;
}
/* Is the process waiting for an inode ? */
# ifdef VMUNIX
if ( INRANGE( w, Info.i_inode0, &Info.i_inode0[Info.i_ninode] ) )
# else
if ( INRANGE( w, Info.i_inode0, &Info.i_inode0[NINODE] ) )
# endif
switch ( ((int)w - (int)Info.i_inode0) % sizeof( struct inode ))
{
case 1 :
return ( "wpipe" ) ;
case 2 :
return ( "rpipe" ) ;
# ifdef VMUNIX
case (int)&((struct inode*)0)->i_un.i_group.g_datq :
return ( "rmux" ) ;
# endif
default :
return ( "inode" ) ;
}
# ifdef VMUNIX
# if NPTY > 0
/* Is the process waiting for a pseudo tty ? */
if ( INRANGE( w, Info.i_pt_tty, &Info.i_pt_tty[NPTY] ) )
switch ( ((int)w - (int)Info.i_pt_tty) % sizeof( struct tty ) )
{
case (int)&((struct tty*)0)->t_rawq :
return ( "rspty" ) ;
case (int)&((struct tty*)0)->t_rawq.c_cf :
return ( "wcpty" ) ;
case (int)&((struct tty*)0)->t_outq :
return ( "wspty" ) ;
case (int)&((struct tty*)0)->t_outq.c_cf :
return ( "rcpty" ) ;
default :
return ( "??pty" ) ;
}
# endif
# 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. */
# ifdef VMUNIX
(void)sprintf( wbuf, "x%05x", w - 0x80000000 ) ;
# else
(void)sprintf( wbuf, "x%05x", w ) ;
# endif
return ( wbuf ) ;
}
---END-OF-waitingfor.c---
More information about the Comp.sources.unix
mailing list