[net.sources] System Monitoring Program

mike@brl-tgr.ARPA (Michael John Muuss <mike>) (12/04/84)

echo 'sh - Makefile'
sed 's/^X//' <<'________This_Is_The_END________' >>Makefile
X
X# mon makefile
X#
X#  Beware dependencies on mon.h are not properly stated.
X#
XOBJS = mon.o io.o vm.o netif.o display.o readnames.o
X
Xall: mon
X
Xmon: $(OBJS) mon.h
X	cc -o mon $(OBJS) -lcurses -ltermlib
X
Xclean:
X	rm -f core *.o mon a.out
X
Xprint:
X	qpr mon.h mon.c io.c vm.c netif.c readnames.c display.c
________This_Is_The_END________
echo 'sh - display.c'
sed 's/^X//' <<'________This_Is_The_END________' >>display.c
X/*
X *			D I S P L A Y . C
X *
X *  This section handles the display initialization and updates for "mon"
X */
X#include "mon.h"
X#include <curses.h>
X
X#define	HOSTLEN	40		/* Length of hostname */
X
X/* Screen Positions */
X#define	LEFT	0
X#define	PROCY	2
X#define	CPUY	5
X#define	TIMEY	8
X#define	PAGEY	11
X#define	CHARY	5
X#define	CHARX	37
X#define	NETIFY	17
X#define	DISKY	2
X#define	DISKX	55
X
X/*
X * DISPINIT - clears the screen, puts up the info labels, and
X *   displays the initial information (device names).
X */
Xdispinit()
X{
X	char	hname[HOSTLEN];
X	register int i;
X
X	clear();			/* clear screen */
X	gethostname(hname, HOSTLEN);	/* host name in upper left */
X	printw(hname);
X
X	/* Put up the labels */
X        mvprintw(PROCY,LEFT,"Procs: r d p s sl  Mem: real  ract  virt  vact  free");
X        mvprintw(DISKY,DISKX,"Disks: Kbps tps msps");
X        mvprintw(CPUY,LEFT,"Cpu: ints  scall  csw");
X	if (dualcpu)
X	        mvprintw(CPUY,LEFT+25,"Cpu2: csw");
X        mvprintw(TIMEY,LEFT,"Time: user nice sys idle");
X	if (dualcpu)
X	        mvprintw(TIMEY,LEFT+26,"Time2: user nice sys idle");
X        mvprintw(PAGEY,LEFT,"Paging: re  at pin pout  oprs  fr  def   sr");
X	mvprintw(PAGEY+3,LEFT,"       nxf  xf  nzf  zf  nrf  rf  prf  swi swo");
X        mvprintw(CHARY,CHARX,"Char: in   out");
X        mvprintw(NETIFY,LEFT,"Name   Ipkts  Ierrs  Opkts  Oerrs  Collis Oqueue");
X
X	/* add the disk drive names to the screen */
X        for(i = 0; i < DK_NDRIVE; i++) {
X		if (*dr_name[i])
X	                mvprintw(DISKY+1+i,DISKX,dr_name[i]);
X		else
X			break;
X        }
X	mvprintw(DISKY+1+i,DISKX,"--------------------");
X	mvprintw(DISKY+2+i,DISKX,"Total:");
X
X	/* put up the network interface names */
X	for (i = 0; i < numif; i++)
X		mvprintw(NETIFY+1+i,LEFT,nifinfo[i].name);
X}
X
X/*
X * DISPUPDATE - updates the dynamic data on the screen.
X */
Xdispupdate()
X{
X	int	i;
X
X	for (i = 0; i < numif; i++)
X		mvprintw(NETIFY+1+i,LEFT+7,"%5d  %5d  %5d  %5d  %5d  %5d",
X			nifdat[i].ipackets, nifdat[i].ierrors,
X			nifdat[i].opackets, nifdat[i].oerrors,
X			nifdat[i].collisions, nifinfo[i].outqlen);
X}
________This_Is_The_END________
echo 'sh - io.c'
sed 's/^X//' <<'________This_Is_The_END________' >>io.c
X/*
X *      I O
X *
X * Purpose: Read the kernel's I/O statistics and display selected
X *      parameters about terminals and disks.
X *
X */
X
X#include "mon.h"
X
Xdouble	kbps, tps;	/* Kbytes/sec and xfers/sec */
Xint	lasty;		/* Last disk y location */
X
X/* Temporary Defines - All output should be moved to dispinfo */
X#include <curses.h>
X#define CHARX   37
X#define	CHARY	5
X#define	DISKX	55
X#define	DISKY	2
X#define	DISKOFF	6
X#define	DISKWDS	DISKOFF
X#define	DISKXFER DISKOFF+4
X#define	DISKSEEK DISKOFF+8
X
Xio()
X{
X        int y;
X        register i;
X	long	t;
X	double	tkbps, ttps;	/* Totals for all drives */
X
X        lseek(kmem, (long)namelist[X_DK_TIME].n_value, 0);
X        read(kmem, s.dk_time, sizeof s.dk_time);
X        lseek(kmem, (long)namelist[X_DK_XFER].n_value, 0);
X        read(kmem, s.dk_xfer, sizeof s.dk_xfer);
X        lseek(kmem, (long)namelist[X_DK_WDS].n_value, 0);
X        read(kmem, s.dk_wds, sizeof s.dk_wds);
X        lseek(kmem, (long)namelist[X_TK_NIN].n_value, 0);
X        read(kmem, &s.tk_nin, sizeof s.tk_nin);
X        lseek(kmem, (long)namelist[X_TK_NOUT].n_value, 0);
X        read(kmem, &s.tk_nout, sizeof s.tk_nout);
X        lseek(kmem, (long)namelist[X_DK_SEEK].n_value, 0);
X        read(kmem, s.dk_seek, sizeof s.dk_seek);
X        lseek(kmem, (long)namelist[X_DK_MSPW].n_value, 0);
X        read(kmem, s.dk_mspw, sizeof s.dk_mspw);
X        lseek(kmem, (long)namelist[X_HZ].n_value, 0);
X        read(kmem, &hz, sizeof hz);
X        for (i = 0; i < DK_NDRIVE; i++) {
X#define X(fld)  t = s.fld[i]; s.fld[i] -= s1.fld[i]; s1.fld[i] = t
X                X(dk_xfer); X(dk_seek); X(dk_wds); X(dk_time);
X        }
X        t = s.tk_nin; s.tk_nin -= s1.tk_nin; s1.tk_nin = t;
X        t = s.tk_nout; s.tk_nout -= s1.tk_nout; s1.tk_nout = t;
X
X	/* output character I/O counts */
X        mvprintw(CHARY+1,CHARX+4,"%4.0f %5.0f", s.tk_nin/etime, s.tk_nout/etime);
X
X	/* Display Drive statistics */
X	tkbps = ttps = 0;
X        for (i=0; i<DK_NDRIVE; i++) {
X                if (stats(i)) {
X	        	tkbps += kbps;
X        		ttps += tps;
X                }
X        }
X	/* Display Totals */
X	mvprintw(lasty+2, DISKX+DISKOFF, "%4.0f%4.0f", tkbps, ttps);
X}
X
X/*
X * Display statistics for dk drive number dn.
X *  Returns 1 if totals should be updated.
X */
Xstats(dn)
X{
X        int y;
X        register i;
X        double atime, words, xtime, itime;
X
X	/* only display info for named (real) devices */
X	if (!*dr_name[dn])
X		return(0);
X
X        y = dn + DISKY+1;
X	lasty = y;
X        if (s.dk_mspw[dn] == 0.0) {
X                mvprintw(y,DISKX+DISKOFF,"%4.0f%4.0f%6.1f ", 0.0, 0.0, 0.0);
X                return(0);
X        }
X        atime = s.dk_time[dn];
X        atime /= (float) hz;
X        words = s.dk_wds[dn]*32.0;      /* number of 16 bit words transferred */
X        xtime = s.dk_mspw[dn]*words;    /* transfer time */
X        itime = atime - xtime;          /* time not transferring (seek time) */
X
X        if (xtime < 0)
X                itime += xtime, xtime = 0;
X        if (itime < 0)
X                xtime += itime, itime = 0;
X
X	/* Avg Kbps, transfers/sec, avg seek time (in msec) */
X	kbps = words/512/etime;
X	tps = s.dk_xfer[dn]/etime;
X        mvprintw(y,DISKX+DISKWDS,"%4.0f", kbps);
X        mvprintw(y,DISKX+DISKXFER,"%4.0f", tps);
X        mvprintw(y,DISKX+DISKSEEK,"%6.1f ",
X            s.dk_seek[dn] ? itime*1000./s.dk_seek[dn] : 0.0);
X
X	return(1);	/* Update totals */
X}
X
X
________This_Is_The_END________
echo 'sh - mon.8b'
sed 's/^X//' <<'________This_Is_The_END________' >>mon.8b
X.TH MON 8 "26 April 1981"
X.de s1
X.if n .sp
X.if t .sp .1i
X..
X.de t1
X.if n .ta 5n
X.if t .ta 1i
X..
X.UC 4
X.SH NAME
Xmon \- display system activity
X.SH SYNOPSIS
X.B mon
X[ interval ]
X.SH DESCRIPTION
X.I Mon
Xprovides a screen oriented display of system activity.
XIt updates the display every second unless
X.I interval
Xis specified, then successive updates occur every
X.I interval
Xseconds.
X.PP
XThe format fields are:
X.PP
XTop Line: host name, load averages for 5 seconds, 1, 5, and 15 minutes,
Xand date.
X.PP
XProcs: information about numbers of processes in various states.
X.s1
X.t1
X.nf
Xr       on run queue (does not include the running job, i.e. mon)
Xd       waiting for "disk" i/o (sleeping with priority < PZERO)
Xp       page wait
Xs       runnable or short sleeper (< 20 secs) but swapped
Xsl      sleeping in core.
X.fi
X.s1
XMem: information about the usage of virtual and real memory.
XVirtual pages are considered active if they belong to processes which
Xare running or have run in the last 20 seconds.
XA ``page'' here is 1024 bytes.
X.s1
X.t1
X.nf
Xreal    total real pages used
Xract    active real pages
Xvirt    total virtual pages used
Xvact    active virtual pages
Xfree    size of the free list
X.fi
X.s1
XCpu: trap/interrupt rate averages per second
X.s1
X.t1
X.nf
Xints    (non clock) device interrupts per second
Xscall   system calls per second
Xcsw     cpu context switch rate (switches/sec)
X.fi
X.s1
XTime: breakdown of percentage usage of CPU time
X.s1
X.nf
Xuser    user time for normal and low priority processes
Xnice    running "nice" jobs
Xsys     system time
Xidle    cpu idle
X.fi
X.s1
XPaging: information about page faults and paging activity.
XThese are averaged each second, and given in units per second.
X.s1
X.t1
X.nf
Xre      page reclaims (simulating reference bits)
Xat      pages attached (found in free list rather than swapdev
X        or filsys)
Xpin     pages paged in
Xpout    pages paged out
Xoprs    calls to paging routine
Xfr      pages freed by daemon per second
Xdef     anticipated short term memory shortfall
Xsr      pages scanned by clock algorithm, per-second
Xnxf     number of executable filled on demand (exfod) pages
X        created
Xxf      number of exfod's filled
Xnzf     number of zero filled on demand (zfod) pages created
Xzf      number of zfod's filled
Xnrf     number of fill on demand pages mapped by vread (vrfod)
X        created
Xrf      number of vrfod's filled
Xprf     pages reclaimed from free list
Xswi     number of swapin operations
Xswo     number of swapout operations
X.fi
X.s1
XChars: Number of chars from and to terminals during the interval.
X.fi
X.s1
XNetwork Interfaces: The name of the interface is given along with the
Xnumber of packets sent and received during the interval, the number of
Xinput and output errors, collisions (for ethernet type networks), and
Xthe output queue length.
X.fi
X.s1
XDisks: For each "alive" disk monitored.
X.s1
X.t1
X.nf
XKbps    average Kbyte per second transfer rate during interval
Xtps     transfers per second
Xmsps    average milliseconds per seek during the interval
X.nf
X.s1
XCommands:
X   ^L   repaints the screen.
X    q   exits the program.
X    Any other character will cause the screen to be updated (thus
X        you can for example run "mon 100" and type single characters
X        to take "snapshots" of the system).
X.s1
X.SH FILES
X/dev/kmem, /vmunix
X.SH SEE ALSO
XThe sections starting with ``Interpreting system activity'' in
X.IR "Installing and Operating 4.2bsd" .
X.SH AUTHOR
XPhillip Dykstra
________This_Is_The_END________
echo 'sh - mon.c'
sed 's/^X//' <<'________This_Is_The_END________' >>mon.c
X/*
X *			M O N . C
X *
X *  A program to moniter system activity.
X *   Rework of earlier mon program.  17 Aug 84 - Phillip Dykstra
X *
X */
X
X#include "mon.h"
X#include <curses.h>
X#include <signal.h>
X
Xstruct	sgttyb ttyb;
Xint done();
X
X/*
X *  The namelist array.  Uses to get the kernal variables needed
X *  by all the MON routines.  The order of this list MUST correspond
X *  to the order of the definitions in mon.h
X */
Xstruct nlist namelist[] = {
X	{ "_dk_busy" },
X	{ "_dk_mspw" },
X	{ "_hz" },
X	{ "_cp_time" },
X	{ "_rate" },
X	{ "_total" },
X	{ "_deficit" },
X	{ "_dk_xfer" },
X	{ "_mbdinit" },
X	{ "_ubdinit" },
X	{ "_ifnet" },
X	{ "_dk_time" },
X	{ "_dk_wds" },
X	{ "_dk_seek" },
X	{ "_tk_nin" },
X	{ "_tk_nout" },
X	{ "_avenrun" },
X	{ "_cp2_time" },	/* 2nd CPU stats */
X	{ "_slavestart" },	/* Used to detect 2nd CPU */
X	{ 0 }
X};
X
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
X        register i;
X        double f1, f2;
X        extern char *ctime();
X
X/*
X * fill the namelist and open /dev/kmem
X */
X        nlist("/vmunix", namelist);
X        if(namelist[X_DK_BUSY].n_type == 0) {
X                printf("dk_busy not found in /vmunix namelist\n");
X                exit(1);
X        }
X        kmem = open("/dev/kmem", 0);
X        if(kmem < 0) {
X                printf("cannot open /dev/kmem\n");
X                exit(1);
X        }
X        if(argc > 1)
X                intv = (atoi(argv[1]));
X        else intv = 1;
X
X/* 
X * do all things that need to be done only once
X */
X        lseek(kmem, (long)namelist[X_DK_MSPW].n_value, 0);
X        read(kmem, s.dk_mspw, sizeof s.dk_mspw);
X        lseek(kmem, (long)namelist[X_HZ].n_value, 0);
X        read(kmem, &hz, sizeof hz);
X	read_names();
X	dualcpu = 0;
X	if (namelist[X_SLAVESTART].n_type)
X		dualcpu++;        
X/*
X * monitor parameters forever
X */
X        worker();
X        /* NOTREACHED */
X}
X
Xchar obuf[BUFSIZ];	/* Output buffer */
X
Xworker()
X{
X        long clock;
X	struct timeval tintv;
X	int i, tin;
X
X	/* set up signals */
X	signal(SIGINT, done);
X	signal(SIGQUIT, done);
X
X	/* set CBREAK mode with no buffering on stdin */
X	setbuf(stdin, 0);
X	setbuf(stdout, obuf);
X	ioctl(0, TIOCGETP, &ttyb);
X	ttyb.sg_flags |= CBREAK;
X	ioctl(fileno(stdin), TIOCSETP, (char *)&ttyb);
X
X	tintv.tv_sec = intv;
X	tintv.tv_usec = 0;
X	initscr();	/* init curses package */
X	nifinit();	/* get initial net interfaces data */
X        dispinit();     /* initialize display */
X        for(;;){
X                vm();
X                io();
X        	nifupdate();
X        	/* get load average */
X		lseek(kmem, (long)namelist[LOADAV].n_value, 0);
X		read(kmem, &loadavg[0], sizeof loadavg);
X        	mvprintw(0,13,"%4.2f %4.2f %4.2f %4.2f", loadavg[3], loadavg[0], loadavg[1], loadavg[2]);
X                time(&clock);
X                mvprintw(0,40,ctime(&clock));
X        	dispupdate();
X        	mvprintw(23, 0, "CMD> ");
X                refresh();
X        	tin = 1;
X        	i = select(2, &tin, (int *)0, (int *)0, &tintv);
X        	if (i && tin) {
X        		i = getchar();
X        		if (i == 12)
X				dispinit();
X        		else if (i == 'q')
X        			done();
X        	}
X        }
X}
X
X/*
X * DONE - put the term back in non CBREAK mode and exit.
X */
Xdone()
X{
X	ioctl(0, TIOCGETP, &ttyb);
X	ttyb.sg_flags &= ~CBREAK;
X	ioctl(fileno(stdin), TIOCSETP, (char *)&ttyb);
X	mvprintw(23,0,"\n");
X	refresh();
X	exit(1);
X}
________This_Is_The_END________
echo 'sh - mon.h'
sed 's/^X//' <<'________This_Is_The_END________' >>mon.h
X/*
X *		M O N . H
X *
X *  Contains all includes and global defines/data needed by "mon"
X */
X#include <stdio.h>
X#include <ctype.h>
X#include <nlist.h>
X#include <sys/types.h>
X#include <sys/vm.h>		/* virtual memory info struct */
X#include <sys/dk.h>		/* disk info struct */
X#include <sys/time.h>
X
X/*
X * The main namelist entries.  This order MUST correspond to the
X *  definition of namelist in main.
X */
X#define	X_DK_BUSY	0
X#define	X_DK_MSPW	1
X#define	X_HZ		2
X#define	X_CP_TIME	3
X#define	X_RATE		4
X#define	X_TOTAL		5
X#define	X_DEFICIT	6
X#define	X_DK_XFER	7
X#define X_MBDINIT	8
X#define	X_UBDINIT	9
X#define	N_IFNET		10
X#define X_DK_TIME	11
X#define	X_DK_WDS	12
X#define	X_DK_SEEK	13
X#define	X_TK_NIN	14
X#define	X_TK_NOUT	15
X#define	LOADAV		16
X#define X_CP_TIME2	17	/* 2nd CPU stats */
X#define	X_SLAVESTART	18	/* 2nd cpu existance test */
X
Xextern struct nlist namelist[];
Xint intv;			/* interval time */
Xint numif;			/* number of interfaces */
Xint dualcpu;			/* flag to indicate dual CPU */
Xint kmem, hz;
Xint deficit;
Xdouble etime;
Xdouble loadavg[4];
X
X/* drive names and numbers */
Xchar dr_name[DK_NDRIVE][10];
Xchar dr_unit[DK_NDRIVE];
X
X/*
X *  Net Interfaces Data - consists of two structures:
X *
X *	nifinfo		contains the "static" data (names, addresses)
X *			and iterative data which does not consist
X *			of "running totals".
X *
X *	nifdata		The "dynamic" running total data.  Two copies,
X *			a "total" and "interval" are kept.
X *
X */
X#define	MAXIF	10		/* ten interfaces maximum */
X
Xstruct	nifinfo {
X	char	name[16];	/* interface name */
X	int	outqlen;	/* output queue length */
X	/* add address, netname, etc. eventually */
X	/* also non totaling data */
X} nifinfo[MAXIF];
X
Xstruct	nifdata	{
X	int	ipackets;	/* input packets */
X	int	ierrors;	/* input errors */
X	int	opackets;	/* output packets */
X	int	oerrors;	/* output errors */
X	int	collisions;
X} nifdat[MAXIF], niftot[MAXIF];
X
X/* state info */
Xstruct state {
X        long    cp_time[CPUSTATES];
X	long	cp_time2[CPUSTATES];	/* 2nd CPU */
X        long    dk_time[DK_NDRIVE];
X        long    dk_wds[DK_NDRIVE];
X        long    dk_seek[DK_NDRIVE];
X        long    dk_xfer[DK_NDRIVE];
X        float   dk_mspw[DK_NDRIVE];
X        long    tk_nin;
X        long    tk_nout;
X        struct  vmmeter Rate;
X        struct  vmtotal Total;
X} s, s1;
X
X#define rate            s.Rate
X#define total           s.Total
________This_Is_The_END________
echo 'sh - netif.c'
sed 's/^X//' <<'________This_Is_The_END________' >>netif.c
X/*
X *			N E T I F . C
X *
X *  This section of mon handles the network interfaces.
X *
X *	nifinit()	initializes "static" info on interfaces.
X *	nifupdate()	gets "dynamic" info on net interfaces.
X */
X#include "mon.h"
X#include <sys/socket.h>
X#include <net/if.h>
X#include <netinet/in.h>
X
Xchar	*index();
X
X/*
X * NIFINIT - initialize the static network interfaces info such
X *   as device names, addresses, etc.  Also calls nifupdate() once
X *   to set up initial values for data with running totals.
X */
Xnifinit()
X{
X	off_t	firstifnet;		/* offset to first ifnet struct */
X	off_t	ifnetp;			/* points to ifnet struct in kmem */
X	struct ifnet ifnet;
X	struct nifinfo *nifip;
X
X	/* check for valid kernal offset */
X	if (namelist[N_IFNET].n_type == NULL) {
X		fprintf(stderr, "mon: ifnet symbol not defined!\n");
X		return;
X	}
X
X	/* get starting address of ifnet structure chain */
X	lseek(kmem, namelist[N_IFNET].n_value, 0);
X	read(kmem, &firstifnet, sizeof(firstifnet));
X
X	/* get info for each interface in chain */
X	numif = 0;			/* count number of interfaces */
X	ifnetp = firstifnet;
X	nifip = &nifinfo[0];
X	while (ifnetp) {
X		char	*cp;
X
X		numif++;
X		/* get an ifnet entry */
X		lseek(kmem, (long)ifnetp, 0);
X		read(kmem, &ifnet, sizeof(ifnet));
X
X		/* build its interface name */
X		lseek(kmem, (long)ifnet.if_name, 0);
X		read(kmem, nifip->name, 15);
X		nifip->name[15] = '\0';
X		cp = index(nifip->name, '\0');
X		sprintf(cp, "%d", ifnet.if_unit);
X
X		/* other info comes here */
X
X		if (++nifip >= &nifinfo[MAXIF])
X			break;		/* no more room for interfaces */
X
X		ifnetp = (off_t)ifnet.if_next;	/* link to next ifnet struct */
X	}
X
X	nifupdate();	/* init running totals */
X}
X
X/*
X * NIFUPDATE - gets the "dynamic" info about the network interfaces.
X */
Xnifupdate()
X{
X	off_t	ifnetp;		/* pointer to ifnet struct in kmem */
X	struct	ifnet	ifnet;
X	int	i;
X
X	if (namelist[N_IFNET].n_type == NULL)
X		return;		/* no net interfaces */
X
X	/* get info from ifnet struct chain */
X	lseek(kmem, namelist[N_IFNET].n_value, 0);
X	read(kmem, &ifnetp, sizeof(ifnetp));
X	i = 0;
X	while (ifnetp) {
X		lseek(kmem, (long)ifnetp, 0);
X		read (kmem, &ifnet, sizeof(ifnet));
X
X		/* extract interval data from ifnet and update totals */
X		nifdat[i].ipackets = ifnet.if_ipackets - niftot[i].ipackets;
X		niftot[i].ipackets = ifnet.if_ipackets;
X		nifdat[i].ierrors = ifnet.if_ierrors - niftot[i].ierrors;
X		niftot[i].ierrors = ifnet.if_ierrors;
X		nifdat[i].opackets = ifnet.if_opackets - niftot[i].opackets;
X		niftot[i].opackets = ifnet.if_opackets;
X		nifdat[i].oerrors = ifnet.if_oerrors - niftot[i].oerrors;
X		niftot[i].oerrors = ifnet.if_oerrors;
X		nifdat[i].collisions = ifnet.if_collisions - niftot[i].collisions;
X		niftot[i].collisions = ifnet.if_collisions;
X		/* extract nifinfo (other stuff) data from ifnet */
X		/* OTHER STUFF OF INTEREST HERE */
X		nifinfo[i].outqlen = ifnet.if_snd.ifq_len;
X
X		if (++i >= MAXIF)
X			break;		/* no more room for interfaces */
X
X		ifnetp = (off_t)ifnet.if_next;	/* link to next ifnet struct */
X	}
X}
________This_Is_The_END________
echo 'sh - readnames.c'
sed 's/^X//' <<'________This_Is_The_END________' >>readnames.c
X/*
X *      R E A D N A M E S
X * 
X * purpose: Reads the names of the disks from kernel space
X *
X */
X#include "mon.h"
X#include <sys/buf.h>		/* needed by following two includes */
X#include <vaxuba/ubavar.h>	/* unibus adapters */
X#include <vaxmba/mbavar.h>	/* massbus adapters */
X
X#define steal(where, var) lseek(kmem, where, 0); read(kmem, &var, sizeof var);
X
Xread_names()
X{
X        struct mba_device mdev;
X        register struct mba_device *mp;
X        struct mba_driver mdrv;
X        short two_char;
X        char *cp = (char *) &two_char;
X        struct uba_device udev, *up;
X        struct uba_driver udrv;
X
X        mp = (struct mba_device *) namelist[X_MBDINIT].n_value;
X        up = (struct uba_device *) namelist[X_UBDINIT].n_value;
X        if (mp) for (;;) {
X                steal(mp++, mdev);
X                if (mdev.mi_driver == 0)
X                        break;
X                if (mdev.mi_dk < 0 || mdev.mi_alive == 0)
X                        continue;
X                steal(mdev.mi_driver, mdrv);
X                steal(mdrv.md_dname, two_char);
X                sprintf(dr_name[mdev.mi_dk], "%c%c%d", cp[0], cp[1], mdev.mi_unit);
X                dr_unit[mdev.mi_dk] = mdev.mi_unit;
X        }
X        if (up) for (;;) {
X                steal(up++, udev);
X                if (udev.ui_driver == 0)
X                        break;
X                if (udev.ui_dk < 0 || udev.ui_alive == 0)
X                        continue;
X                steal(udev.ui_driver, udrv);
X                steal(udrv.ud_dname, two_char);
X                sprintf(dr_name[udev.ui_dk], "%c%c%d", cp[0], cp[1], udev.ui_unit);
X                dr_unit[udev.ui_dk] = udev.ui_unit;
X        }
X}
________This_Is_The_END________
echo 'sh - vm.c'
sed 's/^X//' <<'________This_Is_The_END________' >>vm.c
X/*
X *      V M
X *
X * Purpose:  Read the system virtual memory status info from kernel
X *      space and write it onto the virtual screen used by curses(3).
X *
X * Bugs:  This routime (like the others) it does its own
X *      printing.  This makes it very difficult to change the screen
X *      format.  A better solution would be to move all the prints
X *      into a screen update function.
X */
X
X#include "mon.h"
X#include <machine/param.h>	/* defines bytes/page */
X
X/* Temporary defines */
X#define	PROCS	2
X#define	CPUY	5
X#define	TIMEY	8
X#define	PAGE	11
X
Xvm()
X{
X        register i,j;
X	long	t;		/* temporary */
X
X        lseek(kmem, (long)namelist[X_CP_TIME].n_value, 0);
X        read(kmem, s.cp_time, sizeof s.cp_time);
X	/* Check for 2nd CPU stats */
X	if (dualcpu) {
X	        lseek(kmem, (long)namelist[X_CP_TIME2].n_value, 0);
X	        read(kmem, s.cp_time2, sizeof s.cp_time2);
X	}
X        lseek(kmem, (long)namelist[X_DK_XFER].n_value, 0);
X        read(kmem, s.dk_xfer, sizeof s.dk_xfer);
X        lseek(kmem, (long)namelist[X_RATE].n_value, 0);
X        read(kmem, &rate, sizeof rate);
X        lseek(kmem, (long)namelist[X_TOTAL].n_value, 0);
X        read(kmem, &total, sizeof total);
X        lseek(kmem, (long)namelist[X_DEFICIT].n_value, 0);
X        read(kmem, &deficit, sizeof deficit);
X        etime = 0;
X        for (i=0; i < CPUSTATES; i++) {
X                t = s.cp_time[i];
X                s.cp_time[i] -= s1.cp_time[i];
X                s1.cp_time[i] = t;
X        	if (dualcpu) {
X	                t = s.cp_time2[i];
X        	        s.cp_time2[i] -= s1.cp_time2[i];
X                	s1.cp_time2[i] = t;
X        	}
X                etime += s.cp_time[i];	/* interval must count 1 CPU only */
X        }
X        if(etime == 0.)
X                etime = 1.;
X        etime /= (float) hz;
X
X	/* Display the procs line */
X        mvprintw(PROCS+1,6,"%2d%2d%2d%2d %2d", total.t_rq, total.t_dw, total.t_pw, total.t_sw, total.t_sl);
X#define pgtok(a) ((a)*NBPG/1024)
X        mvprintw(PROCS+1,23,"%5d %5d", pgtok(total.t_rm), pgtok(total.t_arm) );
X        mvprintw(PROCS+1,34,"%6d %5d", pgtok(total.t_vm), pgtok(total.t_avm) );
X        mvprintw(PROCS+1,47,"%5d", pgtok(total.t_free));
X
X	/* Display paging info */
X        mvprintw(PAGE+1,6,"%4d %3d",
X                (rate.v_pgrec - (rate.v_xsfrec+rate.v_xifrec)),
X                (rate.v_xsfrec+rate.v_xifrec));
X        mvprintw(PAGE+1,14,"%4d %4d", pgtok(rate.v_pgpgin),
X                pgtok(rate.v_pgpgout));
X	/* operations per time is (pgin + pgout)  */
X        mvprintw(PAGE+1,24,"%4d", (pgtok(rate.v_pgin)+
X                pgtok(rate.v_pgout)));
X        mvprintw(PAGE+1,29,"%4d %4d %4d", pgtok(rate.v_dfree)
X                , pgtok(deficit), rate.v_scan);
X
X	/* Display CPU info */
X        mvprintw(CPUY+1,4,"%4d  %4d", (rate.v_intr) - hz, rate.v_syscall);
X        mvprintw(CPUY+1,17,"%4d", rate.v_swtch);
X	if (dualcpu)
X	        mvprintw(CPUY+1,30,"%4d", rate.v_swtch2);
X        cputime();
X
X	/* Display additional stuff */
X	mvprintw(PAGE+4,6,"%4d%4d %4d%4d %4d%4d %4d %4d%4d",
X		rate.v_nexfod, rate.v_exfod,
X		rate.v_nzfod, rate.v_zfod,
X		rate.v_nvrfod, rate.v_vrfod,
X		rate.v_pgfrec,
X		rate.v_swpin, rate.v_swpout);
X}
X
X
X/*
X * Display cpu time info (%time in each state)
X */
Xcputime()
X{
X        int x;
X        double t, t2;
X        register i;
X
X        t = t2 = 0;
X        for(i=0; i<CPUSTATES; i++) {
X                t += s.cp_time[i];
X                t2 += s.cp_time2[i];
X        }
X	if(t == 0.)
X		t = 1.;
X	if (t2 == 0.)
X		t2 = 1.;
X        x = 6;
X        for(i=0; i<CPUSTATES; i++){
X                mvprintw(TIMEY+1,x,"%3.0f", 100 * s.cp_time[i]/t);
X        	if (dualcpu)
X	                mvprintw(TIMEY+1,x+27,"%3.0f", 100 * s.cp_time2[i]/t2);
X                x += 5;
X        }
X}
________This_Is_The_END________