[comp.sources.unix] v10i063: Top users display, 2.1 with Symmetric changes, Part01/02

rs@uunet.UU.NET (Rich Salz) (07/23/87)

Submitted-by: hoptoad!vixie!paul (Paul Vixie Esq)
Posting-Number: Volume 10, Issue 63
Archive-name: top_s375/Part01

Rich--  I've had this floating around for a while now.  I got it from the
net, at which time it ran on Vax, Sun, and Pyramid systems.  It still does,
but I've added a bunch of #ifdef and #ifndef to make it work on the Symmetric
375.  I recently recompiled for a Vax, and it seems still to work quite well
there -- so I don't think I screwed anything up.

This is Stable Code -- it has run on three Symmetric 375s for five months or
so now, with no changes.  You can bypass your usual policy of waiting a while
for the author (or in my case, sender) of sources to change their mind and
send in last-minute updates or whatever...

I tried to send mail to the author, but he did not respond.  Perhaps he'll
see this and integrate my changes into 2.2 (if such there be).

#! /bin/sh
##  This is a shell archive.  Remove anything before this line, then unpack
##  it by saving it into a file and typing "sh file".  To overwrite existing
##  files, type "sh file -c".  You can also feed this as standard input via
##  unshar, or by typing "sh <file".  If this archive is complete, you will
##  see the following message at the end:
#		"End of archive 1 (of 2)."
# Contents:  CHANGES.scs Changes MANIFEST Makefile Manifest README
#   boolean.h bzero.c commands.c getopt.c kernel.c layout.h screen.c
#   screen.h sigconv.awk sigdesc.h top.h top.local.h top.man
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f CHANGES.scs -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"CHANGES.scs\"
else
echo shar: Extracting \"CHANGES.scs\" \(1514 characters\)
sed "s/^X//" >CHANGES.scs <<'END_OF_CHANGES.scs'
XChanges for Symmetric Computer Systems s/375 (preprocessor constant: scs).
X
XThese changes were not made at, by, or for SCS proper.  SCS would probably
Xbe interested in them, but so far only the users' group has them.  They were
Xmade in February, 1987, to version 2.1 of the program, by Paul Vixie
X(dual!ptsfa!vixie!paul@ucbvax.Berkeley.EDU).
X
XSome code cleanup was done, some for appearance sake, some (e.g., fmt_proc() in
Xdisplay.c) actually structural improvements.
X
XThe SCS kernel is basically 4.2, but with a number of differences -- some I
Xlike, others I don't.  The list:
X
X	all page counts are in kilobytes (all the ones I had to use, anyway);
X	PGSHIFT is defined as 9 in <machine/param.h>, this may be an error;
X	the physical page size is 512, but the kernel pages are 1024. sigh...
X
X	in the proc structure, there is no p_rssize; p_tsize and p_dsize are
X	also missing, though combined in p_tdsize (whose value is in BYTES,
X	NOT PAGES).  p_ssize has either 0 or 16MB as its value, and is there-
X	fore useless.  p_addr is missing...
X
X	...however, there is a field p_spti which indexes into the page table
X	table.  each spt has a value telling how many pages are used (total
X	reference code), and how many are actually in memory.  these were used
X	for the "SIZE" and "RES" fields on the display...
X
X	...the lack of p_addr made it hard to find the U area for a proc, but
X	since SCS put the process name and CPU time into the proc structure
X	for use when ^T (info) is pressed, the U area wasn't needed anyway...
END_OF_CHANGES.scs
if test 1514 -ne `wc -c <CHANGES.scs`; then
    echo shar: \"CHANGES.scs\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f Changes -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"Changes\"
else
echo shar: Extracting \"Changes\" \(7151 characters\)
sed "s/^X//" >Changes <<'END_OF_Changes'
XMon Oct  6 1986 - wnl (2.1)
X	A bug with the kill command was pointed out by "dciem!tim"---
X	specifying a signal by name did not work correctly.  This bug has
X	been fixed with a simple change to commands.c.  Another bug made
X	the cpu state percentages incorrect the first time they were
X	displayed.  This bug has also been fixed (changed top.c).
X
XThu Sep  4 1986 - wnl (2.0, at last)
X	This is the version that will (hopefully) get released to the
X	world as top 2.0.
X	Added the "r" and "k" commands for renice and kill, respectively.
X	This required adding a way to handle system call errors, and the
X	addition of the "e" command.  Help screen and manual page were
X	changed to reflect this change.  Changed all "#ifdef SUN" directives
X	to "#ifdef sun", and changed all "#ifdef PYRAMID" directives to
X	"#ifdef pyr".  As much as I hate those choices of preprocessor
X	names (they too easily conflict with real variable names), it does
X	make automatic compilation possible---people don't have to change
X	the Makefile anymore for specific machines.  The manual page was
X	changed to automatically incorporate the defaults as set in the
X	Makefile (including an infinite value for TOPN) and the way the
X	manual page is generated by the Makefile was changed to make
X	maintenance of this information automatic.
X
XMon Jul 28 1986 - wnl (still pre 2.0)
X	Real close now.  I put in a new definition for the macro "pagetok"
X	that does an explicit shift of a constant expression involving
X	PGSHIFT.  Appropriate checks are made if PGSHIFT is to small.
X	"pagetok" is now used exclusively everywhere to convert kernel
X	clicks to kilobytes.  I added a full blown interactive mode with
X	the ability to change some of the runtime parameters (how many to
X	display, time delay, etc.) while top is running.  I also
X	incorporated a few ideas from the net:  control characters in the
X	command name are replaced with '?'; the '-S' option makes the
X	swapper and pager visible; options have been added to control the
X	number of displays produced (this makes it easier to make
X	performance snapshots with top).  I have also added the notion of
X	"infinite" values for number of processes and number of displays.
X	I fixed a long-standing bug in the uid to username mapping code
X	that was only aggravated on the pyramids:  it was an ill-defined
X	expression (akin to i = i++).  I tweaked the proc_compar routine
X	for qsort slightly so that stopped processes were more likely to
X	show up.  Manual page was updated to reflect all changes
X	noticeable to the user.
X
XTue Jul  1 1986 - wnl (pre 2.0 -- 1.9999?)
X	In the process of major revamping on the way to version 2.0.
X	I have completely done away with curses by adding my own screen
X	management routines in a separate file (screen.c).  The rationale
X	for this is that top knows a whole lot more about what is and is
X	not redundant on the screen and can compare simple integer values
X	where curses would have to compare strings.  This has turned out
X	to be a very big win speed-wise.  The proc_compar routine for
X	sorting has been rewritten to include several more keys.  I
X	decided this was necessary when I noticed that the "top" process
X	itself kept disappearing off the top 10 list on a Sun-3.  All the
X	processes had the same percentage (0%) and the sort wasn't really
X	doing anything worthwhile.  I changed the expression that computes
X	memory usage to use the ctob macro instead of just assuming that
X	pages were 512 bytes.  More work still needs to be done before
X	this version is usable.  I changed options-processing to use
X	getopt and added appropriate incantations to the Makefile.
X
XWed Feb 20 1985 - wnl (still 1.8)
X	Put in the ifdef FOUR_ONE statements to make top still compilable
X	on a 4.1 system.  Apparently, there are some users out there that
X	need this functionality.  Oh well.  I don't guarantee any of it,
X	since I can't test it.  Made appropriate changes to README and
X	final installation related changes to Makefile.
X
XSat Feb  2 1985 - wnl (1.8)
X	Removed all the ifdef FOUR_TWO statements and made "top" into a
X	4.2 only program.  If someone really wants to still run it on 4.1,
X	then they can do all the work.  We don't have a 4.1 machine
X	anymore, so I don't even know if the thing still works under 4.1.
X	Cleaned up the Makefile and the README.  Added installation rules
X	to the Makefile, as requested by several sites.  Fixed a very
X	obscure divide-by-zero bug.  Added a second "key" to the qsort
X	comparison function (proc_compar) so that comparisons are based on
X	cpu ticks if the percentages are equal (provided by Jonathon
X	Feiber at Sun).
X
XTue Dec 11 1984 - wnl (1.7)
X	Added the virtual and real memory status line to the header area
X	(provided by Jonathon Feiber at Sun)
X
XTue Nov 20 1984 - wnl (1.6)
X	Added an "exit" if sbrk's fail.  Added changes from Jonathon
X	Feiber at Sun:  ifdef SUN to make top work on Suns (they don't use
X	doubles in the proc structure), register declarations, check for
X	getting a user structure that has disappeared since the proc array
X	was read (it used to die, now it just shows the process as swapped).
X
XTue Nov 13 1984 - wnl (1.5)
X	If the number of displayable processes ("active_procs") was less
X	than the number of requested processes ("topn"), top would
X	segmentation fault.  This bug has been fixed.  Thanks to Prentiss
X	Riddle at ut-sally for pointing out the existence of this bug.
X
XTue Oct 23 1984 - wnl (1.4)
X	Finally fixed the hash table bug that caused processes owned by
X	root to sometimes appear with either no name or a different name
X	that had UID 0 (such as "operator").  Removed all the ifdef DEBUG
X	blocks to make top ready for distribution to the real world.
X
XSun Apr  8 1984 - wnl (still 1.3)
X	Made some slight changes to the display format.  It now looks more
X	aesthetically pleasing.  Added some preprocessor constants so that
X	the two defaults (number of processes and seconds of delay) easier
X	to change.
X
XThu Apr  5 1984 - wnl (1.3)
X	Changed the order in which things are done at initialization time.
X	This way, if an error occurs before starting the main loop, curses
X	will never get started.  Also changed other error handlers so that
X	endwin() is called before any flavor of exit.  Specifying a number
X	of processes that is more than the screen can handle is no longer
X	fatal.  It displays a warning message and pretends the user
X	specified the maximum for the screen.  Finally cured all the TSTP
X	blues (well, almost all).  I removed my TSTP handler and convinced
X	the system to always use the one that curses sets up.  Turns out
X	that "sleep" was stepping all over it during a pause.  So, I don't
X	use sleep anymore.  The only problem that remains with it now is
X	redrawing the old display before updating it after a pause.
X
XTue Apr  3 1984 - wnl (from 1.0 to 1.2)
X	I changed the format of the TIME column from just "seconds" to
X	"minutes:seconds".  I also made pausing work correctly.  Screen
X	redraws with an up to date display.  For compatibility with 4.2, I
X	changed the name of the "zero" function to "bzero".  The makefile
X	has been altered to handle versions for 4.1 and 4.2, and README
X	has been updated to reflect these recent changes.
END_OF_Changes
if test 7151 -ne `wc -c <Changes`; then
    echo shar: \"Changes\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f MANIFEST -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"MANIFEST\"
else
echo shar: Extracting \"MANIFEST\" \(589 characters\)
sed "s/^X//" >MANIFEST <<'END_OF_MANIFEST'
XChanges                      1
XMANIFEST                     2
XMakefile                     1
XManifest                     1
XREADME                       1
Xboolean.h                    1
Xbzero.c                      1
Xcommands.c                   1
Xdisplay.c                    1
Xgetopt.c                     1
Xkernel.c                     1
Xlayout.h                     1
Xscreen.c                     1
Xscreen.h                     1
Xsigconv.awk                  1
Xtop.c                        2
Xtop.h                        1
Xtop.local.h                  2
Xtop.man                      2
END_OF_MANIFEST
if test 589 -ne `wc -c <MANIFEST`; then
    echo shar: \"MANIFEST\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f Makefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"Makefile\"
else
echo shar: Extracting \"Makefile\" \(2899 characters\)
sed "s/^X//" >Makefile <<'END_OF_Makefile'
X# Makefile for "top", a top 10 process display for Unix
X#
X# This makefile is for top, version 2.1
X#
X# Written by William LeFebvre, Rice University graduate student
X
X# installation information:
X#	OWNER	- name (or uid) for the installed executable's owner
X#	GROUP	- group name (or gid) for the installed executable's group
X#	MODE	- mode for the installed executable (should start with a 0)
X#	BINDIR	- directory where the executable should live
X#	MANDIR	- directory where the manual page should live
X#	MAN	- troff macros for manual pages
X#	TROFF	- most appropriate troff command
X
XOWNER  = root
XGROUP  = daemon
XMODE   = 755
XBINDIR = /usr/local/bin
XMANDIR = /usr/man/manl
XMAN    = man
XTROFF  = nroff
X
X# Values for the two defaults in "top":
X#	TOPN	- default number of processes to display
X#	DELAY	- default delay between updates
X#
X# set TOPN to -1 to indicate infinity (so that top will display as many
X# as the screen will hold).
X
XTOPN = -1
XDELAY = 5
X
XTABLE =
X# Top maintains an internal hash table for translating uid to username.
X# This hash table must be big enough to hold every name in /etc/passwd.
X# It is possible, but not necessary, to specify the hash table size in
X# this Makefile.  Just uncomment the following line and provide a number.
X#TABLE = -DTable_size=
X
XTARFILES = README Changes Makefile top.c commands.c display.c kernel.c \
X	   screen.c getopt.c \
X	   boolean.h layout.h screen.h top.h top.local.h bzero.c \
X	   sigconv.awk top.man
XOBJS = top.o commands.o display.o kernel.o screen.o getopt.o
X
X# Top uses the preprocessor variables "sun", "pyr" and "scs" for specific
X# changes required by Suns, Pyramids and Symmetrics.  No changes to "CFLAGS"
X# are required for these architectres.
XCFLAGS = -O
X# To make a version for 4.1, comment out the previous line and
X# uncomment the following two lines:
X#CFLAGS = -DFOUR_ONE -O
X#OBJS = top.o commands.o display.o kernel.o screen.o getopt.o bzero.o
X
Xall: top top.1
X
Xtop: $(OBJS)
X	cc $(CFLAGS) -o top $(OBJS) -ltermlib -lm
X
Xtop.o: top.c Makefile
X	cc $(CFLAGS) -c $(TABLE) -DDefault_TOPN=$(TOPN) -DDefault_DELAY=$(DELAY) top.c
X
X# include file dependencies
Xtop.o: boolean.h layout.h screen.h top.h top.local.h
Xcommands.o: sigdesc.h
Xdisplay.o: boolean.h layout.h screen.h top.h
Xkernel.o: top.local.h
Xscreen.o: boolean.h screen.h
X
X# automatically built include file
Xsigdesc.h: sigconv.awk /usr/include/signal.h
X	awk -f sigconv.awk /usr/include/signal.h >sigdesc.h
X
X# top.1 is built by combining the actual text with the default information
Xtop.1: top.man Makefile
X	echo '.nr N' $(TOPN) > top.1
X	echo '.nr D' $(DELAY) >>top.1
X	cat top.man >>top.1
X
Xtop.cat: top.1
X	nroff -$(MAN) top.1 | cat -s >top.cat
X
Xtroff: top.1
X	$(TROFF) -man top.1
X
Xtar:
X	rm -f top.tar
X	tar cvf top.tar $(TARFILES)
X
Xclean:
X	rm -f *.o top top.cat top.tar top.1 core
X
Xinstall: top top.1
X	install -s -o $(OWNER) -m $(MODE) -g $(GROUP) top $(BINDIR)
X	install -c top.1 $(MANDIR)
END_OF_Makefile
if test 2899 -ne `wc -c <Makefile`; then
    echo shar: \"Makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f Manifest -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"Manifest\"
else
echo shar: Extracting \"Manifest\" \(161 characters\)
sed "s/^X//" >Manifest <<'END_OF_Manifest'
XChanges
XMakefile
XManifest
XREADME
Xboolean.h
Xbzero.c
Xcommands.c
Xdisplay.c
Xgetopt.c
Xkernel.c
Xlayout.h
Xscreen.c
Xscreen.h
Xsigconv.awk
Xtop.c
Xtop.h
Xtop.local.h
Xtop.man
END_OF_Manifest
if test 161 -ne `wc -c <Manifest`; then
    echo shar: \"Manifest\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f README -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"README\"
else
echo shar: Extracting \"README\" \(5259 characters\)
sed "s/^X//" >README <<'END_OF_README'
XThis file contains a few comments about "top", version 2.0
X
X"top" is a program that will give continual reports about the state of the
Xsystem, including a list of the top cpu using processes.  It requires read
Xaccess to the memory files "/dev/kmem" and "/dev/mem" as well as the system
Ximage "/vmunix".  Some installations have these files protected from general
Xaccess.  These sites would have to install this program in the same way that
Xprograms such as "ps" are installed.
X
XCAVEAT:  version 2.0 of top has internal commands that kill and renice
Xprocesses.  DO NOT INSTALL TOP AS A SETUID PROGRAM, or you will open up a
Xbig security hole since top makes no process ownership checks on its own.
XNote that it is still safe to install top as a set group-id program, since
Xgroup-id has no bearing on who can renice or send signals to what processes.
X
XThere are a few things that need to be checked before compiling the program:
X
XThe most important item is the internal hash table size.  This size is
Xdefined in the program with the preprocessor variable "Table_size".  This
Xconstant MUST be larger than the number of lines in the file /etc/passwd.
XIt is advisable that this number be about twice the number of lines, and
Xthat it be a prime number (since it dictates the size of the hash table).
XMake sure this is checked before compilation.  Its definition exists in
Xthe file "top.local.h", but it is also settable in the Makefile.
X
XSeveral other things are set in "top.local.h", including the file names
Xused for certain system files ("/vmunix", "/dev/kmem", etc.).  Although I
Xdon't expect those to vary much, they are put there for convenience.
XAnother parameter in this file is "Nominal_TOPN".  This will be discussed
Xin the next paragraph.
X
XThere are two preprocessor variables that are defined at compile time by
Xthe makefile.  These are "Default_TOPN" and "Default_DELAY".  Their values
Xare the defaults used for the top number of processes to be displayed and
Xthe number of seconds to delay between displays, respectively.  They are
Xset by the Makefile variables "TOPN" and "DELAY", respectively.  These
Xconstants are preset as follows:  TOPN=10, DELAY=5.  These can be
Xoverridden by either changing the Makefile or by specifying the change on
Xthe make command line (with something like "make TOPN=15").  Version 2 of
Xtop understands an "infinite" value for the number of processes to
Xdisplay.  Such a value indicates that top should display as much as will
Xfill the screen.  To specify a Default_TOPN of infinity, set TOPN equal
Xto -1.  Version 2 also understands the difference between an intelligent
Xterminal and a dumb terminal (such as a hardcopy device or a file).
XTypically, a default of infinity would not be desirable on a dumb
Xterminal, so the value of "Nominal_TOPN" is used when (1) Default_TOPN is
Xinfinity and (2) the output device is a dumb terminal or a file.  The
Xvalue for this preprocessor variable is set in "top.local.h" and can also
Xbe set from the "make" command line.  In the distribution, it is set to 18.
X
XBy default, the makefile will make a "top" for one of the following
Xsystems:  Berkeley 4.2, Sun Unix (version 1.1 and higher), and Pyramid
XUnix.  Previous versions of top fully supported Berkeley 4.1 Unix.  This
Xsupport has waned in version 2, and is not guaranteed to even work.  If
Xyou really must give it a try, you can change the makefile variable
X"CFLAGS" to make a 4.1 "top".  Instructions for doing this can be found in
X"Makefile".
X
XThe file "bzero.c" contains a function that will zero a block of memory on
Xa VAX.  This is only needed for Berkeley 4.1, since 4.2 has a bzero
Xdefined in the C run time library.  If you are strange enough to be
Xrunning 4.1 on something besides a VAX, you will have to replace this
Xroutine with one that will work on your machine.  If you don't know a
Xquick way to do it, then writing a simple loop will suffice.  "Bzero"
Xtakes two arguments:  a pointer to the buffer to zero, and the number of
Xbytes to zero.
X
XThere are also several parameters in the makefile that control
Xinstallation.  These should be altered to suit the desires and needs of
Xindividual sites.
X
XVersion 2.0 still only supports standard 4.2 and Sun and Pyramid
Xarchitectures.  I attempted to add sufficient changes to make top work on
Xa Masscomp, but found the number of required changes to be overwhelming.
XFeel free to alter top to make it run on whatever funny architecture you
Xhave.  I also encourage you to send those changes back to me at the
Xaddress below.  But, if the number of changes is high, I will be reluctant
Xto include the changes in the next version of top.  As an example, there
Xwere only 10 modifications required for the Sun version (and all changes
Xwere trivial), and just 4 changes were needed for the Pyramid.
X
XIf you make any kind of change to "top" that you feel would be beneficial
Xto others who use this program, or if you find and fix a bug, please send
Xme the change.
X
XEnjoy!
X
X                                William LeFebvre
X				Department of Computer Science
X				Rice University
X                                ARPANet address: <phil@Rice.edu>
X
X				U.S. Mail address:
X				    William LeFebvre
X				    P.O. Box 1892
X				    Department of Computer Science
X				    Houston, TX  77251
END_OF_README
if test 5259 -ne `wc -c <README`; then
    echo shar: \"README\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f boolean.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"boolean.h\"
else
echo shar: Extracting \"boolean.h\" \(125 characters\)
sed "s/^X//" >boolean.h <<'END_OF_boolean.h'
X/* My favorite names for boolean values */
X#define  No	0
X#define  Yes	1
X#define  Maybe	2		/* tri-state boolean, actually */
X
END_OF_boolean.h
if test 125 -ne `wc -c <boolean.h`; then
    echo shar: \"boolean.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f bzero.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"bzero.c\"
else
echo shar: Extracting \"bzero.c\" \(789 characters\)
sed "s/^X//" >bzero.c <<'END_OF_bzero.c'
X/*
X *  Fast, sleazy, and ugly zero function.
X *
X *  Note that this will only work on a VAX, but it is real easy to write a
X *  similar function for whatever machine you may need.  If nothing else,
X *  just a simple loop in C will suffice.
X *
X *  Dave Johnson, Rice University.
X *
X *  Enhanced by William LeFebvre of Rice University to handle zeroing more
X *  than 64K.
X */
X
X# define   K	1024
X
X/*
X *  bzero(memory, amount) - set "amount" bytes starting at "memory" to the
X *			    value 0.
X */
X
Xbzero(memory, amount)
X
Xchar *memory;
Xint  amount;
X
X{
X    while (amount >= 64*K)
X    {
X	_bzero64(memory, 64*K-1);
X	memory += 64*K-1;
X	amount -= 64*K-1;
X    }
X    _bzero64(memory, amount);
X}
X
X_bzero64(memory, amount)
X
Xchar *memory;
Xint  amount;
X
X{
X    asm("	movc5	$0, (sp), $0, 8(ap), *4(ap)");
X}
END_OF_bzero.c
if test 789 -ne `wc -c <bzero.c`; then
    echo shar: \"bzero.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f commands.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"commands.c\"
else
echo shar: Extracting \"commands.c\" \(8806 characters\)
sed "s/^X//" >commands.c <<'END_OF_commands.c'
X/*
X *  Top users display for Berkeley Unix
X *
X *  This file contains the routines that implement some of the interactive
X *  mode commands.  Note that some of the commands are implemented in-line
X *  in "main".  This is necessary because they change the global state of
X *  "top" (i.e.:  changing the number of processes to display).
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <signal.h>
X#include <sys/time.h>
X#include <sys/resource.h>
X#include "sigdesc.h"		/* generated automatically */
X#include "boolean.h"
X
Xextern int  errno;
Xextern int  sys_nerr;
Xextern char *sys_errlist[];
X
Xextern char *copyright;
X
Xint err_compar();
Xchar *err_string();
Xchar *index();
X
X/*
X *  show_help() - display the help screen; invoked in response to
X *		either 'h' or '?'.
X */
X
Xshow_help()
X
X{
X    fputs(copyright, stdout);
X    fputs("\n\n\
XA top users display for Unix\n\
X\n\
XThese single-character commands are available:\n\
X\n\
X^L      - redraw screen\n\
Xq       - quit\n\
Xh or ?  - help; show this text\n\
Xd       - change number of displays to show\n\
Xe       - list errors generated by last \"kill\" or \"renice\" command\n\
Xk       - kill processes; send a signal to a list of processes\n\
Xn or #  - change number of processes to display\n\
Xr       - renice a process\n\
Xs       - change number of seconds to delay between updates\n\
X\n\
X\n", stdout);
X}
X
X/*
X *  Utility routines that help with some of the commands.
X */
X
Xchar *next_field(str)
X
Xregister char *str;
X
X{
X    register char *temp;
X
X    if ((str = index(str, ' ')) == NULL)
X    {
X	return(NULL);
X    }
X    *str = '\0';
X    while (*++str == ' ') /* loop */;
X    return(str);
X}
X
Xscanint(str, intp)
X
Xchar *str;
Xint  *intp;
X
X{
X    register int val = 0;
X    register char ch;
X
X    while ((ch = *str++) != '\0')
X    {
X	if (isdigit(ch))
X	{
X	    val = val * 10 + (ch - '0');
X	}
X	else if (isspace(ch))
X	{
X	    break;
X	}
X	else
X	{
X	    return(-1);
X	}
X    }
X    *intp = val;
X    return(0);
X}
X
X/*
X *  Some of the commands make system calls that could generate errors.
X *  These errors are collected up in an array of structures for later
X *  contemplation and display.  Such routines return a string containing an
X *  error message, or NULL if no errors occurred.  The next few routines are
X *  for manipulating and displaying these errors.  We need an upper limit on
X *  the number of errors, so we arbitrarily choose 20.
X */
X
X#define ERRMAX 20
X
Xstruct errs		/* structure for a system-call error */
X{
X    int  errno;		/* value of errno (that is, the actual error) */
X    char *arg;		/* argument that caused the error */
X};
X
Xstatic struct errs errs[ERRMAX];
Xstatic int errcnt;
Xstatic char *err_toomany = " too many errors occurred";
Xstatic char *err_listem = 
X	" Many errors occurred.  Press `e' to display the list of errors.";
X
X/* These macros get used to reset and log the errors */
X#define ERR_RESET   errcnt = 0
X#define ERROR(p, e) if (errcnt >= ERRMAX) \
X		    { \
X			return(err_toomany); \
X		    } \
X		    else \
X		    { \
X			errs[errcnt].arg = (p); \
X			errs[errcnt++].errno = (e); \
X		    }
X
X/*
X *  err_string() - return an appropriate error string.  This is what the
X *	command will return for displaying.  If no errors were logged, then
X *	return NULL.  The maximum length of the error string is defined by
X *	"STRMAX".
X */
X
X#define STRMAX 80
X
Xchar *err_string()
X
X{
X    register char *ptr;
X    register struct errs *errp;
X    register int  cnt = 0;
X    register int  first = Yes;
X    register int  currerr = -1;
X    int stringlen;		/* characters still available in "string" */
X    char string[STRMAX];
X
X    /* if there are no errors, return NULL */
X    if (errcnt == 0)
X    {
X	return(NULL);
X    }
X
X    /* sort the errors */
X    qsort(errs, errcnt, sizeof(struct errs), err_compar);
X
X    /* need a space at the from of the error string */
X    string[0] = ' ';
X    string[1] = '\0';
X    stringlen = STRMAX - 2;
X
X    /* loop thru the sorted list, building an error string */
X    ptr = string;
X    while (cnt < errcnt)
X    {
X	errp = &(errs[cnt++]);
X	if (errp->errno != currerr)
X	{
X	    if (currerr != -1)
X	    {
X		if ((stringlen = str_adderr(string, stringlen, currerr)) < 2)
X		{
X		    return(err_listem);
X		}
X		strcat(string, "; ");		/* we know there's more */
X	    }
X	    currerr = errp->errno;
X	    first = Yes;
X	}
X	if ((stringlen = str_addarg(string, stringlen, errp->arg, first)) ==0)
X	{
X	    return(err_listem);
X	}
X	first = No;
X    }
X
X    /* add final message */
X    stringlen = str_adderr(string, stringlen, currerr);
X
X    /* return the error string */
X    return(stringlen == 0 ? err_listem : string);
X}
X
X/*
X *  str_adderr(str, len, err) - add an explanation of error "err" to
X *	the string "str".
X */
X
Xstr_adderr(str, len, err)
X
Xchar *str;
Xint len;
Xint err;
X
X{
X    register char *msg;
X    register int  msglen;
X
X    msg = err == 0 ? "Not a number" : sys_errlist[err];
X    msglen = strlen(msg) + 2;
X    if (len <= msglen)
X    {
X	return(0);
X    }
X    strcat(str, ": ");
X    strcat(str, msg);
X    return(len - msglen);
X}
X
X/*
X *  str_addarg(str, len, arg, first) - add the string argument "arg" to
X *	the string "str".  This is the first in the group when "first"
X *	is set (indicating that a comma should NOT be added to the front).
X */
X
Xstr_addarg(str, len, arg, first)
X
Xchar *str;
Xint  len;
Xchar *arg;
Xint  first;
X
X{
X    register int arglen;
X
X    arglen = strlen(arg);
X    if (!first)
X    {
X	arglen += 2;
X    }
X    if (len <= arglen)
X    {
X	return(0);
X    }
X    if (!first)
X    {
X	strcat(str, ", ");
X    }
X    strcat(str, arg);
X    return(len - arglen);
X}
X
X/*
X *  err_compar(p1, p2) - comparison routine used by "qsort"
X *	for sorting errors.
X */
X
Xerr_compar(p1, p2)
X
Xregister struct errs *p1, *p2;
X
X{
X    register int result;
X
X    if ((result = p1->errno - p2->errno) == 0)
X    {
X	return(strcmp(p1->arg, p2->arg));
X    }
X    return(result);
X}
X
X/*
X *  error_count() - return the number of errors currently logged.
X */
X
Xerror_count()
X
X{
X    return(errcnt);
X}
X
X/*
X *  show_errors() - display on stdout the current log of errors.
X */
X
Xshow_errors()
X
X{
X    register int cnt = 0;
X    register struct errs *errp = errs;
X
X    printf("%d error%s:\n\n", errcnt, errcnt == 1 ? "" : "s");
X    while (cnt++ < errcnt)
X    {
X	printf("%5s: %s\n", errp->arg,
X	    errp->errno == 0 ? "Not a number" : sys_errlist[errp->errno]);
X	errp++;
X    }
X}
X
X/*
X *  kill_procs(str) - send signals to processes, much like the "kill"
X *		command does; invoked in response to 'k'.
X */
X
Xchar *kill_procs(str)
X
Xchar *str;
X
X{
X    register char *nptr;
X    register char *optr;
X    int signum = SIGTERM;	/* default */
X    int procnum;
X    char badnum = 0;
X    struct sigdesc *sigp;
X
X    ERR_RESET;
X    if (str[0] == '-')
X    {
X	/* explicit signal specified */
X	if ((optr = nptr = next_field(str)) == NULL)
X	{
X	    return(" kill: no processes specified");
X	}
X
X	if (isdigit(str[1]))
X	{
X	    scanint(str + 1, &signum);
X	    if (signum <= 0 || signum >= NSIG)
X	    {
X		return(" invalid signal number");
X	    }
X	}
X	else 
X	{
X	    /* translate the name into a number */
X	    for (sigp = sigdesc; sigp->name != NULL; sigp++)
X	    {
X		if (strcmp(sigp->name, str + 1) == 0)
X		{
X		    signum = sigp->number;
X		    break;
X		}
X	    }
X
X	    /* was it ever found */
X	    if (sigp->name == NULL)
X	    {
X		return(" bad signal name");
X	    }
X	}
X	/* put the new pointer in place */
X	str = nptr;
X    }
X
X    /* loop thru the string, killing processes */
X    do
X    {
X	if (scanint(str, &procnum) == -1)
X	{
X	    ERROR(str, 0);
X	}
X	else if (kill(procnum, signum) == -1)
X	{
X	    /* chalk up an error */
X	    ERROR(str, errno);
X	}
X    } while ((str = next_field(str)) != NULL);
X
X    /* return appropriate error string */
X    return(err_string());
X}
X
X/*
X *  renice_procs(str) - change the "nice" of processes, much like the
X *		"renice" command does; invoked in response to 'r'.
X */
X
Xchar *renice_procs(str)
X
Xchar *str;
X
X{
X    register char negate;
X    int prio;
X    int procnum;
X
X    ERR_RESET;
X
X    /* allow for negative priority values */
X    if ((negate = *str == '-'))
X    {
X	/* move past the minus sign */
X	str++;
X    }
X
X    /* use procnum as a temporary holding place and get the number */
X    procnum = scanint(str, &prio);
X
X    /* negate if necessary */
X    if (negate)
X    {
X	prio = -prio;
X    }
X
X    /* check for validity */
X    if (procnum == -1 || prio <= PRIO_MIN || prio >= PRIO_MAX)
X    {
X	return(" bad priority value");
X    }
X
X    /* move to the first process number */
X    if ((str = next_field(str)) == NULL)
X    {
X	return(" no processes specified");
X    }
X
X    /* loop thru the process numbers, renicing each one */
X    do
X    {
X	if (scanint(str, &procnum) == -1)
X	{
X	    ERROR(str, 0);
X	}
X	else if (setpriority(PRIO_PROCESS, procnum, prio) == -1)
X	{
X	    ERROR(str, errno);
X	}
X    } while ((str = next_field(str)) != NULL);
X
X    /* return appropriate error string */
X    return(err_string());
X}
X
END_OF_commands.c
if test 8806 -ne `wc -c <commands.c`; then
    echo shar: \"commands.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f getopt.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"getopt.c\"
else
echo shar: Extracting \"getopt.c\" \(1259 characters\)
sed "s/^X//" >getopt.c <<'END_OF_getopt.c'
X/*LINTLIBRARY*/
X#define NULL	0
X#define EOF	(-1)
X#define ERR(s, c)	if(opterr){\
X	extern int strlen(), write();\
X	char errbuf[2];\
X	errbuf[0] = c; errbuf[1] = '\n';\
X	(void) write(2, argv[0], (unsigned)strlen(argv[0]));\
X	(void) write(2, s, (unsigned)strlen(s));\
X	(void) write(2, errbuf, 2);}
X
X#define strchr index
X
Xextern int strcmp();
Xextern char *strchr();
X
Xint	opterr = 1;
Xint	optind = 1;
Xint	optopt;
Xchar	*optarg;
X
Xint
Xgetopt(argc, argv, opts)
Xint	argc;
Xchar	**argv, *opts;
X{
X	static int sp = 1;
X	register int c;
X	register char *cp;
X
X	if(sp == 1)
X		if(optind >= argc ||
X		   argv[optind][0] != '-' || argv[optind][1] == '\0')
X			return(EOF);
X		else if(strcmp(argv[optind], "--") == NULL) {
X			optind++;
X			return(EOF);
X		}
X	optopt = c = argv[optind][sp];
X	if(c == ':' || (cp=strchr(opts, c)) == NULL) {
X		ERR(": unknown option, -", c);
X		if(argv[optind][++sp] == '\0') {
X			optind++;
X			sp = 1;
X		}
X		return('?');
X	}
X	if(*++cp == ':') {
X		if(argv[optind][sp+1] != '\0')
X			optarg = &argv[optind++][sp+1];
X		else if(++optind >= argc) {
X			ERR(": argument missing for -", c);
X			sp = 1;
X			return('?');
X		} else
X			optarg = argv[optind++];
X		sp = 1;
X	} else {
X		if(argv[optind][++sp] == '\0') {
X			sp = 1;
X			optind++;
X		}
X		optarg = NULL;
X	}
X	return(c);
X}
END_OF_getopt.c
if test 1259 -ne `wc -c <getopt.c`; then
    echo shar: \"getopt.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f kernel.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"kernel.c\"
else
echo shar: Extracting \"kernel.c\" \(3693 characters\)
sed "s/^X//" >kernel.c <<'END_OF_kernel.c'
X/*
X *  Top - a top users display for Berkeley Unix
X *  
X *  This file contains all the routines that retrieve values from
X *  kernel and user memory.
X */
X
X#include <stdio.h>
X#if defined(FOUR_ONE) || defined(pyr)
X#include <sys/pte.h>
X#else
X#include <machine/pte.h>
X#endif
X#include <sys/param.h>
X#include <sys/dir.h>
X#include <sys/user.h>
X#if defined(scs)
X# define FLOAT		/* for pcrcpu in proc.h */
X# include <sys/vm.h>	/* for struct spt */
X#endif
X#include <sys/proc.h>
X
X#include "top.local.h"
X
X/* useful externals */
Xextern int errno;
Xextern char *sys_errlist[];
X
Xstatic int kmem = -1;
Xstatic int mem = -1;
X
Xinit_kernel()
X{
X    /* open kmem and mem */
X    if ((kmem = open(KMEM, 0)) < 0)
X    {
X	perror(KMEM);
X	exit(20);
X    }
X    if ((mem = open(MEM, 0)) < 0)
X    {
X	perror(MEM);
X	exit(21);
X    }
X}
X
X#if !defined(scs)
X
X/*
X *  getu(p, u) - get the user structure for the process whose proc structure
X *	is pointed to by p.  The user structure is put in the buffer pointed
X *	to by u.  Return 0 if successful, -1 on failure (such as the process
X *	being swapped out).
X */
X
Xgetu(p, u)
X
Xregister struct proc *p;
Xstruct user *u;
X
X{
X    struct pte uptes[UPAGES];
X    register caddr_t upage;
X    register struct pte *pte;
X    register nbytes, n;
X
X    /*
X     *  Check if the process is currently loaded or swapped out.  The way we
X     *  get the u area is totally different for the two cases.  For this
X     *  application, we just don't bother if the process is swapped out.
X     */
X    if (!(p->p_flag & SLOAD))
X    {
X	return(-1);
X    }
X
X    /*
X     *  Process is currently in memory, we hope!
X     */
X    if (!getkval(p->p_addr, uptes, sizeof(uptes), "!p->p_addr"))
X    {
X	/* we can't seem to get to it, so pretend it's swapped out */
X	return(-1);
X    } 
X    upage = (caddr_t)u;
X    pte = uptes;
X    for (nbytes = sizeof(struct user); nbytes > 0; nbytes -= NBPG)
X    {
X    	lseek(mem, pte++->pg_pfnum * NBPG, 0);
X	n = MIN(nbytes, NBPG);
X	if (read(mem, upage, n) != n)
X	{
X	    /* we can't seem to get to it, so pretend it's swapped out */
X	    return(-1);
X	}
X	upage += n;
X    }
X    return(0);
X}
X#endif !scs
X
X/*
X *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
X *	"offset" is the byte offset into the kernel for the desired value,
X *  	"ptr" points to a buffer into which the value is retrieved,
X *  	"size" is the size of the buffer (and the object to retrieve),
X *  	"refstr" is a reference string used when printing error meessages,
X *	    if "refstr" starts with a '!', then a failure on read will not
X *  	    be fatal (this may seem like a silly way to do things, but I
X *  	    really didn't want the overhead of another argument).
X *  	
X */
X
Xgetkval(offset, ptr, size, refstr)
X
Xlong offset;
Xint *ptr;
Xint size;
Xchar *refstr;
X
X{
X    if (lseek(kmem, offset, 0) == -1)
X    {
X	if (*refstr == '!')
X	{
X	    refstr++;
X	}
X	fprintf(stderr, "%s: lseek to %s: %s\n",
X	    KMEM, refstr, sys_errlist[errno]);
X	quit(22);
X    }
X    if (read(kmem, ptr, size) == -1)
X    {
X	if (*refstr == '!')
X	{
X	    /* we lost the race with the kernel, process isn't in memory */
X	    return(0);
X	} 
X	else 
X	{
X	    fprintf(stderr, "%s: reading %s: %s\n",
X		KMEM, refstr, sys_errlist[errno]);
X	    quit(23);
X	}
X    }
X    return(1);
X}
X
X#if defined(scs)
Xvoid
Xget_spt(spti, sptp)
X	int		spti;
X	struct spt	*sptp;
X{
X	extern struct spt	*spt;		/* defined in top.c */
X
X	/* Let's get tricky, shall we?  *spt is a pointer in kernel space;
X	 * we can use it in a getkval() call, but we can't dereference it
X	 * directly.  However, C's pointer arithmetic will still work, even
X	 * though we aren't going to use the pointer as a pointer...
X	 */
X
X	getkval(spt + spti, sptp, sizeof(struct spt), "spt");
X}
X#endif scs
END_OF_kernel.c
if test 3693 -ne `wc -c <kernel.c`; then
    echo shar: \"kernel.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f layout.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"layout.h\"
else
echo shar: Extracting \"layout.h\" \(845 characters\)
sed "s/^X//" >layout.h <<'END_OF_layout.h'
X/*
X *  Top - a top users display for Berkeley Unix
X *
X *  This file defines the locations on tne screen for various parts of the
X *  display.  These definitions are used by the routines in "display.c" for
X *  cursor addressing.
X */
X
X#define  x_lastpid	10
X#define  y_lastpid	0
X#define  x_loadave	33
X#define  y_loadave	0
X#define  x_procstate	0
X#define  y_procstate	1
X#define  x_brkdn	14
X#define  y_brkdn	1
X#define  x_realmem	8
X#define  x_virtmem	28
X#define  x_free		51
X#define  y_mem		3
X#define  x_header	0
X#define  y_header	5
X#define  x_idlecursor	0
X#define  y_idlecursor	4
X#define  y_procs	6
X#define  x_p_pid	0
X#define  x_p_user	6
X#define  x_p_pri	15
X#define  x_p_nice	20
X#define  x_p_size	25
X#define  x_p_res	31
X#define  x_p_state	37
X#define  x_p_time	43
X#define  x_p_wcpu	50
X#define  x_p_cpu	57
X#define  x_p_command	64
X
X#define  y_cpustates	2
END_OF_layout.h
if test 845 -ne `wc -c <layout.h`; then
    echo shar: \"layout.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f screen.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"screen.c\"
else
echo shar: Extracting \"screen.c\" \(4697 characters\)
sed "s/^X//" >screen.c <<'END_OF_screen.c'
X/*
X *  Top - a top users display for Berkeley Unix
X *
X *  This file contains the routines that interface to termcap and stty/gtty.
X *
X *  Paul Vixie, February 1987: converted to use ioctl() instead of stty/gtty.
X */
X
X#include <stdio.h>
X#include <sgtty.h>
X#include "screen.h"
X#include "boolean.h"
X
Xextern char *myname;
X
Xint putstdout();
X
Xint  scrolls;
Xint  hardcopy;
Xint  screen_length;
Xint  screen_width;
Xchar ch_erase;
Xchar ch_kill;
Xchar smart_terminal;
Xchar PC;
Xchar *tgetstr();
Xchar *tgoto();
Xchar termcap_buf[1024];
Xchar init_buf[1024];
Xchar string_buffer[1024];
Xchar home[15];
Xchar lower_left[15];
Xchar *clear_line;
Xchar *clear_screen;
Xchar *cursor_motion;
Xchar *start_standout;
Xchar *end_standout;
Xchar *terminal_init;
Xchar *terminal_end;
Xshort ospeed;
X
Xstatic struct sgttyb old_settings;
Xstatic struct sgttyb new_settings;
Xstatic char is_a_terminal = No;
X
X#define	STDIN	0
X#define	STDOUT	1
X#define	STDERR	2
X
Xinit_termcap()
X
X{
X    char *bufptr;
X    char *PCptr;
X    char *term_name;
X    char *temp_ptr;
X    char *getenv();
X    int status;
X
X    /* assume we have a smart terminal until proven otherwise */
X    smart_terminal = Yes;
X
X    /* now get terminal name and termcap entry */
X    term_name = getenv("TERM");
X    if ((status = tgetent(termcap_buf, term_name)) != 1)
X    {
X	if (status == -1)
X	{
X	    fprintf(stderr, "%s: can't open termcap file\n", myname);
X	}
X	else
X	{
X	    fprintf(stderr, "%s: no termcap entry for a `%s' terminal\n",
X		    myname, getenv("TERM"));
X	}
X
X	/* pretend it's dumb and proceed */
X	smart_terminal = No;
X	return;
X    }
X
X    /* these immediately indicate a very stupid terminal */
X    if (tgetflag("hc") || tgetflag("os"))
X    {
X	smart_terminal = No;
X	return;
X    }
X
X    /* set up common terminal capabilities */
X    if ((screen_length = tgetnum("li")) <= 0)
X    {
X	screen_length = smart_terminal = 0;
X	return;
X    }
X
X    /* screen_width is a little different */
X    if ((screen_width = tgetnum("co")) == -1)
X    {
X	screen_width = 79;
X    }
X    else
X    {
X	screen_width -= 1;
X    }
X
X    /* initialize the pointer into the termcap string buffer */
X    bufptr = string_buffer;
X
X    /* get necessary capabilities */
X    if ((clear_line    = tgetstr("ce", &bufptr)) == NULL ||
X	(clear_screen  = tgetstr("cl", &bufptr)) == NULL ||
X	(cursor_motion = tgetstr("cm", &bufptr)) == NULL)
X    {
X	smart_terminal = No;
X	return;
X    }
X
X    /* get some more sophisticated stuff -- these are optional */
X    terminal_init  = tgetstr("ti", &bufptr);
X    terminal_end   = tgetstr("te", &bufptr);
X    start_standout = tgetstr("so", &bufptr);
X    end_standout   = tgetstr("se", &bufptr);
X
X    /* pad character */
X    PC = (PCptr = tgetstr("pc", &bufptr)) ? *PCptr : 0;
X
X    /* set convenience strings */
X    strcpy(home, tgoto(cursor_motion, 0, 0));
X    strcpy(lower_left, tgoto(cursor_motion, 0, screen_length - 1));
X
X    /* if stdout is not a terminal, pretend we are a dumb terminal */
X    if (-1 == ioctl(STDOUT, TIOCGETP, &old_settings))
X    {
X	smart_terminal = No;
X    }
X}
X
Xinit_screen()
X
X{
X    /* get the old settings for safe keeping */
X    if (0 == ioctl(STDOUT, TIOCGETP, &old_settings))
X    {
X	/* copy the settings so we can modify them */
X	new_settings = old_settings;
X
X	/* turn on CBREAK and turn off character echo and tab expansion */
X	new_settings.sg_flags |= CBREAK;
X	new_settings.sg_flags &= ~(ECHO|XTABS);
X	ioctl(STDOUT, TIOCSETP, &new_settings);
X
X	/* remember the erase and kill characters */
X	ch_erase = old_settings.sg_erase;
X	ch_kill  = old_settings.sg_kill;
X
X	/* remember that it really is a terminal */
X	is_a_terminal = Yes;
X
X	/* send the termcap initialization string */
X	putcap(terminal_init);
X    }
X    else
X    {
X	/* not a terminal at all---consider it dumb */
X	smart_terminal = No;
X    }
X}
X
Xend_screen()
X
X{
X    /* move to the lower left, clear the line and send "te" */
X    if (smart_terminal)
X    {
X	putcap(lower_left);
X	putcap(clear_line);
X	putcap(terminal_end);
X    }
X
X    /* if we have settings to reset, then do so */
X    if (is_a_terminal)
X    {
X	ioctl(STDOUT, TIOCSETP, &old_settings);
X    }
X}
X
Xreinit_screen()
X
X{
X    /* install our settings if it is a terminal */
X    if (is_a_terminal)
X    {
X	ioctl(STDOUT, TIOCSETP, &new_settings);
X    }
X
X    /* send init string */
X    if (smart_terminal)
X    {
X	putcap(terminal_init);
X    }
X}
X
Xstandout(fmt, a1, a2, a3)
X
Xchar *fmt;
Xint a1, a2, a3;
X
X{
X    if (smart_terminal)
X    {
X	putcap(start_standout);
X	printf(fmt, a1, a2, a3);
X	putcap(end_standout);
X    }
X    else
X    {
X	printf(fmt, a1, a2, a3);
X    }
X}
X
Xclear()
X
X{
X    if (smart_terminal)
X    {
X	putcap(clear_screen);
X    }
X}
X
X/* This has to be defined as a subroutine for tputs (instead of a macro) */
X
Xputstdout(ch)
X
Xchar ch;
X
X{
X    putchar(ch);
X}
X
END_OF_screen.c
if test 4697 -ne `wc -c <screen.c`; then
    echo shar: \"screen.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f screen.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"screen.h\"
else
echo shar: Extracting \"screen.h\" \(874 characters\)
sed "s/^X//" >screen.h <<'END_OF_screen.h'
X/*
X *  top - a top users display for Unix 4.2
X *
X *  This file contains all the definitions necessary to use the hand-written
X *  screen package in "screen.c"
X */
X
X#define TCputs(str)	tputs(str, 1, putstdout)
X#define putcap(str)	((str) != NULL ? TCputs(str) : 0)
X#define Move_to(x, y)	TCputs(tgoto(cursor_motion, x, y))
X
Xextern char ch_erase;		/* set to the user's erase character */
Xextern char ch_kill;		/* set to the user's kill  character */
Xextern char smart_terminal;     /* set if the terminal has sufficient termcap
X				   capabilities for normal operation */
X
X/* These aresome termcap strings for use outside of "screen.c" */
Xextern char *cursor_motion;
Xextern char *clear_line;
X
X/* rows and columns on the screen according to termcap */
Xextern int  screen_length;
Xextern int  screen_width;
X
X/* a function that puts a single character on stdout */
Xint putstdout();
END_OF_screen.h
if test 874 -ne `wc -c <screen.h`; then
    echo shar: \"screen.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f sigconv.awk -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"sigconv.awk\"
else
echo shar: Extracting \"sigconv.awk\" \(439 characters\)
sed "s/^X//" >sigconv.awk <<'END_OF_sigconv.awk'
XBEGIN		{
X		    print "/* This file was automatically generated */"
X		    print "/* by the awk script \"sigconv.awk\".      */\n"
X		    print "struct sigdesc {"
X		    print "    char *name;"
X		    print "    int  number;"
X		    print "};\n"
X		    print "struct sigdesc sigdesc[] = {"
X		}
X
X/^#define[ \t][ \t]*SIG[A-Z]/	{
X				    printf "    \"%s\",\t%2d,\n", \
X					substr($2, 4), $3
X				}
X
XEND				{
X				    print "    NULL,\t 0\n};"
X				}
END_OF_sigconv.awk
if test 439 -ne `wc -c <sigconv.awk`; then
    echo shar: \"sigconv.awk\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f sigdesc.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"sigdesc.h\"
else
echo shar: Extracting \"sigdesc.h\" \(696 characters\)
sed "s/^X//" >sigdesc.h <<'END_OF_sigdesc.h'
X/* This file was automatically generated */
X/* by the awk script "sigconv.awk".      */
X
Xstruct sigdesc {
X    char *name;
X    int  number;
X};
X
Xstruct sigdesc sigdesc[] = {
X    "HUP",	 1,
X    "INT",	 2,
X    "QUIT",	 3,
X    "ILL",	 4,
X    "TRAP",	 5,
X    "IOT",	 6,
X    "EMT",	 7,
X    "FPE",	 8,
X    "KILL",	 9,
X    "BUS",	10,
X    "SEGV",	11,
X    "SYS",	12,
X    "PIPE",	13,
X    "ALRM",	14,
X    "TERM",	15,
X    "URG",	16,
X    "STOP",	17,
X    "TSTP",	18,
X    "CONT",	19,
X    "CHLD",	20,
X    "TTIN",	21,
X    "TTOU",	22,
X    "IO",	23,
X    "XCPU",	24,
X    "XFSZ",	25,
X    "DVZ",	26,
X    "NMI",	27,
X    "WINCH",	28,
X    "PROF",	29,
X    "VTALRM",	30,
X    "USR1",	31,
X    "CATCHALL",	2000,
X    NULL,	 0
X};
END_OF_sigdesc.h
if test 696 -ne `wc -c <sigdesc.h`; then
    echo shar: \"sigdesc.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f top.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"top.h\"
else
echo shar: Extracting \"top.h\" \(936 characters\)
sed "s/^X//" >top.h <<'END_OF_top.h'
X/*
X *  Top - a top users display for Berkeley Unix
X *
X *  General (global) definitions
X */
X
X/* Number of lines of header information on the standard screen */
X#define Header_lines	6
X
X/* Number of columns needed for display */
X#define Display_width	80
X
X/* Log base 2 of 1024 is 10 (2^10 == 1024) */
X#define LOG1024		10
X
X/* Convert clicks (kernel pages) to kbytes ... */
X/* If there is no PGSHIFT defined, assume it is 11 */
X/* Is this needed for compatability with some old flavor of 4.2 or 4.1? */
X#if defined(scs)
X	/* the s/375 <machine/param.h> has this as 9, but it's really 10 */
X# undef PGSHIFT
X# define PGSHIFT 10
X#endif scs
X
X#ifndef PGSHIFT
X# define pagetok(size)	((size) << 1)
X#else
X# if PGSHIFT>10
X#  define pagetok(size)	((size) << (PGSHIFT - LOG1024))
X# else
X#  define pagetok(size)	((size) >> (LOG1024 - PGSHIFT))
X# endif
X#endif
X
Xextern double logcpu;
X
Xdouble log();
Xdouble exp();
X
Xextern char (* screenbuf)[Display_width];
END_OF_top.h
if test 936 -ne `wc -c <top.h`; then
    echo shar: \"top.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f top.local.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"top.local.h\"
else
echo shar: Extracting \"top.local.h\" \(1208 characters\)
sed "s/^X//" >top.local.h <<'END_OF_top.local.h'
X/*
X *  Top - a top users display for Berkeley Unix
X *
X *  Definitions for things that might vary between installations.
X */
X
X/*
X *  "Table_size" defines the size of the hash tables used to map uid to
X *  username.  The number of users in /etc/passwd CANNOT be greater than
X *  this number.  If the error message "table overflow: too many users"
X *  is printed by top, then "Table_size" needs to be increased.  Things will
X *  work best if the number is a prime number that is about twice the number
X *  of lines in /etc/passwd.
X */
X#ifndef Table_size
X#define Table_size	57
X#endif
X
X/*
X *  "Nominal_TOPN" is used as the default TOPN when Default_TOPN is Infinity
X *  and the output is a dumb terminal.  If we didn't do this, then
X *  installations who use a default TOPN of Infinity will get every
X *  process in the system when running top on a dumb terminal (or redirected
X *  to a file).  Note that Nominal_TOPN is a default:  it can still be
X *  overridden on the command line, even with the value "infinity".
X */
X#ifndef Nominal_TOPN
X#define Nominal_TOPN	18
X#endif
X
X/*
X *  File name for the system image and the memory devices.
X */
X#define VMUNIX	"/vmunix"
X#define KMEM	"/dev/kmem"
X#define MEM	"/dev/mem"
END_OF_top.local.h
if test 1208 -ne `wc -c <top.local.h`; then
    echo shar: \"top.local.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f top.man -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"top.man\"
else
echo shar: Extracting \"top.man\" \(7861 characters\)
sed "s/^X//" >top.man <<'END_OF_top.man'
X.\" NOTE:  changes to the manual page for "top" should be made in the
X.\"        file "top.man" and NOT in the file "top.1".
X.TH TOP 1 Local
X.UC 4
X.SH NAME
Xtop \- display and update information about the top cpu processes
X.SH SYNOPSIS
X.B top
X[
X.B \-Sbinu
X] [
X.BI \-d count
X] [
X.BI \-s time
X] [
X.I number
X]
X.SH DESCRIPTION
X.\" This defines appropriate quote strings for nroff and troff
X.ds lq \&"
X.ds rq \&"
X.if t .ds lq ``
X.if t .ds rq ''
X.\" Just in case these number registers aren't set yet...
X.if \nN==0 .nr N 10
X.if \nD==0 .nr D 5
X.I Top
Xdisplays the top
X.if !\nN==-1 \nN
Xprocesses on the system and periodically updates this information.
X.if \nN==-1 \
X\{\
XIf standard output is an intelligent terminal (see below) then
Xas many processes as will fit on the terminal screen are displayed
Xby default.  Otherwise, a good number of them are shown (around 20).
X.\}
XRaw cpu percentage is used to rank the processes.  If
X.I number
Xis given, then the top
X.I number
Xprocesses will be displayed instead of the default.
X.PP
X.I Top
Xmakes a distinction between terminals that support advanced capabilities
Xand those that do not.  This
Xdistinction affects the choice of defaults for certain options.  In the
Xremainder of this document, an \*(lqintelligent\*(rq terminal is one that
Xsupports cursor addressing, clear screen, and clear to end of line.
XConversely, a \*(lqdumb\*(rq terminal is one that does not support such
Xfeatures.  If the output of
X.I top
Xis redirected to a file, it acts as if it were being run on a dumb
Xterminal.
X.SH OPTIONS
X.TP
X.B \-S
XShow system processes in the display.  Normally, system processes such as
Xthe pager and the swapper are not shown.  This option makes them visible.
X.TP
X.B \-b
XUse \*(lqbatch\*(rq mode.  In this mode, all input from the terminal is
Xignored.  Interrupt characters (such as ^C and ^\e) still have an effect.
XThis is the default on a dumb terminal, or when the output is not a terminal.
X.TP
X.B \-i
XUse \*(lqinteractive\*(rq mode.  In this mode, any input is immediately
Xread for processing.  See the section on \*(lqInteractive Mode\*(rq
Xfor an explanation of
Xwhich keys perform what functions.  After the command is processed, the
Xscreen will immediately be updated, even if the command was not
Xunderstood.  This mode is the default when standard output is an
Xintelligent terminal.
X.TP
X.B \-n
XUse \*(lqnon-interactive\*(rq mode.  This is indentical to \*(lqbatch\*(rq
Xmode.
X.TP
X.B \-u
XDo not take the time to map uid numbers to usernames.  Normally,
X.I top
Xwill read as much of the file \*(lq/etc/passwd\*(rq as is necessary to map
Xall the user id numbers it encounters into login names.  This option
Xdisables all that, while possibly decreasing execution time.  The uid
Xnumbers are displayed instead of the names.
X.TP
X.BI \-d count
XShow only
X.I count
Xdisplays, then exit.  A display is considered to be one update of the
Xscreen.  This option allows the user to select the number of displays he
Xwants to see before
X.I top
Xautomatically exits.  For intelligent terminals, no upper limit
Xis set.  The default is 1 for dumb terminals.
X.TP
X.BI \-s time
XSet the delay between screen updates to
X.I time
Xseconds.  The default delay between updates is \nD seconds.
X.PP
XBoth
X.I count
Xand
X.I number
Xfields can be specified as \*(lqinfinite\*(rq, indicating that they can
Xstretch as far as possible.  This is accomplished by using any proper
Xprefix of the keywords
X\*(lqinfinity\*(rq,
X\*(lqmaximum\*(rq,
Xor
X\*(lqall\*(rq.
XThe default for
X.I count
Xon an intelligent terminal is, in fact,
X.BI infinity .
X.SH "INTERACTIVE MODE"
XWhen
X.I top
Xis running in \*(lqinteractive mode\*(rq, it reads commands from the
Xterminal and acts upon them accordingly.  In this mode, the terminal is
Xput in \*(lqCBREAK\*(rq, so that a character will be
Xprocessed as soon as it is typed.  Almost always, a key will be
Xpressed when
X.I top
Xis between displays; that is, while it is waiting for
X.I time
Xseconds to elapse.  If this is the case, the command will be
Xprocessed and the display will be updated immediately thereafter
X(reflecting any changes that the command may have specified).  This
Xhappens even if the command was incorrect.  If a key is pressed while 
X.I top
Xis in the middle of updating the display, it will finish the update and
Xthen process the command.  Some commands require additional information,
Xand the user will be prompted accordingly.  While typing this information
Xin, the user's erase and kill keys (as set up by the command
X.IR stty )
Xare recognized, and a newline terminates the input.
X.PP
XThese commands are currently recognized (^L refers to control-L):
X.TP
X.B ^L
XRedraw the screen.
X.IP "\fBh\fP\ or\ \fB?\fP"
XDisplay a summary of the commands (help screen).
X.TP
X.B q
XQuit
X.IR top.
X.TP
X.B d
XChange the number of displays to show (prompt for new number).
XRemember that the next display counts as one, so typing
X.B d1
Xwill make
X.I top
Xshow one final display and then immediately exit.
X.TP
X.B n or #
XChange the number of processes to display (prompt for new number).
X.TP
X.B s
XChange the number of seconds to delay between displays
X(prompt for new number).
X.TP
X.B k
XSend a signal (\*(lqkill\*(rq by default) to a list of processes.  This
Xacts similarly to the command
X.IR kill (1)).
X.TP
X.B r
XChange the priority (the \*(lqnice\*(rq) of a list of processes.
XThis acts similarly to the command
X.IR renice (8)).
X.TP
X.B e
XDisplay a list of system errors (if any) generated by the last
X.BR k ill
Xor
X.BR r enice
Xcommand.
X.SH "THE DISPLAY"
XThe top few lines of the display show general information
Xabout the state of the system, including
Xthe last process id assigned to a process,
Xthe three load averages,
Xthe current time,
Xthe number of existing processes,
Xthe number of processes in each state
X(sleeping, ABANDONED, running, starting, zombies, and stopped),
Xand a percentage of time spent in each of the processor states
X(user, nice, system, and idle).
XIt also includes the amount of virtual and real memory in use
X(with the amount of memory considered \*(lqactive\*(rq in parentheses) and
Xthe amount of free memory.
X.PP
XThe remainder of the screen displays information about individual
Xprocesses.  This display is similar in spirit to
X.IR ps (1)
Xbut it is not exactly the same.  PID is the process id, USERNAME is the name
Xof the process's owner (if
X.B \-u
Xis specified, a UID column will be substituted for USERNAME),
XPRI is the current priority of the process,
XNICE is the nice amount (in the range \-20 to 20),
XSIZE is the total size of the process (text, data, and stack),
XRES is the current amount of resident memory (both SIZE and RES are
Xgiven in kilobytes),
XSTATE is the current state (one of \*(lqsleep\*(rq, \*(lqWAIT\*(rq,
X\*(lqrun\*(rq, \*(lqidl\*(rq, \*(lqzomb\*(rq, or \*(lqstop\*(rq),
XTIME is the number of system and user cpu seconds that the process has used,
XWCPU is the weighted cpu percentage (this is the same value that
X.IR ps (1)
Xdisplays as CPU),
XCPU is the raw percentage and is the field that is sorted to determine
Xthe order of the processes, and
XCOMMAND is the name of the command that the process is currently running
X(if the process is swapped out, this column is marked \*(lq<swapped>\*(rq).
X.SH NOTES
XThe \*(lqABANDONED\*(rq state (known in the kernel as \*(lqSWAIT\*(rq) was
Xabandoned, thus the name.  A process should never end up in this state.
X.SH AUTHOR
XWilliam LeFebvre, Rice University graduate student
X.SH FILES
X.DT
X/dev/kmem		kernel memory
X.br
X/dev/mem		physical memory
X.br
X/etc/passwd		used to map uid numbers to user names
X.br
X/vmunix		system image
X.SH BUGS
XThe command name for swapped processes should be tracked down, but this
Xwould make the program run slower.
X.PP
XAs with
X.IR ps (1),
Xthings can change while
X.I top
Xis collecting information for an update.  The picture it gives is only a
Xclose approximation to reality.
X.SH "SEE ALSO"
Xkill(1),
Xps(1),
Xstty(1),
Xmem(4),
Xrenice(8)
END_OF_top.man
if test 7861 -ne `wc -c <top.man`; then
    echo shar: \"top.man\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 1 \(of 2\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked both archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0


-- 

Rich $alz			"Anger is an energy"
Cronus Project, BBN Labs	rsalz@bbn.com
Moderator, comp.sources.unix	sources@uunet.uu.net