sob@soma.UUCP (Stan Barber) (09/30/86)
#! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # README # Changes # top.man # sigconv.awk # Makefile # getopt.c # This archive created: Mon Sep 29 16:14:15 1986 export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'README'" '(5259 characters)' if test -f 'README' then echo shar: "will not over-write existing file 'README'" else cat << \SHAR_EOF > 'README' This file contains a few comments about "top", version 2.0 "top" is a program that will give continual reports about the state of the system, including a list of the top cpu using processes. It requires read access to the memory files "/dev/kmem" and "/dev/mem" as well as the system image "/vmunix". Some installations have these files protected from general access. These sites would have to install this program in the same way that programs such as "ps" are installed. CAVEAT: version 2.0 of top has internal commands that kill and renice processes. DO NOT INSTALL TOP AS A SETUID PROGRAM, or you will open up a big security hole since top makes no process ownership checks on its own. Note that it is still safe to install top as a set group-id program, since group-id has no bearing on who can renice or send signals to what processes. There are a few things that need to be checked before compiling the program: The most important item is the internal hash table size. This size is defined in the program with the preprocessor variable "Table_size". This constant MUST be larger than the number of lines in the file /etc/passwd. It is advisable that this number be about twice the number of lines, and that it be a prime number (since it dictates the size of the hash table). Make sure this is checked before compilation. Its definition exists in the file "top.local.h", but it is also settable in the Makefile. Several other things are set in "top.local.h", including the file names used for certain system files ("/vmunix", "/dev/kmem", etc.). Although I don't expect those to vary much, they are put there for convenience. Another parameter in this file is "Nominal_TOPN". This will be discussed in the next paragraph. There are two preprocessor variables that are defined at compile time by the makefile. These are "Default_TOPN" and "Default_DELAY". Their values are the defaults used for the top number of processes to be displayed and the number of seconds to delay between displays, respectively. They are set by the Makefile variables "TOPN" and "DELAY", respectively. These constants are preset as follows: TOPN=10, DELAY=5. These can be overridden by either changing the Makefile or by specifying the change on the make command line (with something like "make TOPN=15"). Version 2 of top understands an "infinite" value for the number of processes to display. Such a value indicates that top should display as much as will fill the screen. To specify a Default_TOPN of infinity, set TOPN equal to -1. Version 2 also understands the difference between an intelligent terminal and a dumb terminal (such as a hardcopy device or a file). Typically, a default of infinity would not be desirable on a dumb terminal, so the value of "Nominal_TOPN" is used when (1) Default_TOPN is infinity and (2) the output device is a dumb terminal or a file. The value for this preprocessor variable is set in "top.local.h" and can also be set from the "make" command line. In the distribution, it is set to 18. By default, the makefile will make a "top" for one of the following systems: Berkeley 4.2, Sun Unix (version 1.1 and higher), and Pyramid Unix. Previous versions of top fully supported Berkeley 4.1 Unix. This support has waned in version 2, and is not guaranteed to even work. If you really must give it a try, you can change the makefile variable "CFLAGS" to make a 4.1 "top". Instructions for doing this can be found in "Makefile". The file "bzero.c" contains a function that will zero a block of memory on a VAX. This is only needed for Berkeley 4.1, since 4.2 has a bzero defined in the C run time library. If you are strange enough to be running 4.1 on something besides a VAX, you will have to replace this routine with one that will work on your machine. If you don't know a quick way to do it, then writing a simple loop will suffice. "Bzero" takes two arguments: a pointer to the buffer to zero, and the number of bytes to zero. There are also several parameters in the makefile that control installation. These should be altered to suit the desires and needs of individual sites. Version 2.0 still only supports standard 4.2 and Sun and Pyramid architectures. I attempted to add sufficient changes to make top work on a Masscomp, but found the number of required changes to be overwhelming. Feel free to alter top to make it run on whatever funny architecture you have. I also encourage you to send those changes back to me at the address below. But, if the number of changes is high, I will be reluctant to include the changes in the next version of top. As an example, there were only 10 modifications required for the Sun version (and all changes were trivial), and just 4 changes were needed for the Pyramid. If you make any kind of change to "top" that you feel would be beneficial to others who use this program, or if you find and fix a bug, please send me the change. Enjoy! William LeFebvre Department of Computer Science Rice University ARPANet address: <phil@Rice.edu> U.S. Mail address: William LeFebvre P.O. Box 1892 Department of Computer Science Houston, TX 77251 SHAR_EOF fi echo shar: "extracting 'Changes'" '(6805 characters)' if test -f 'Changes' then echo shar: "will not over-write existing file 'Changes'" else cat << \SHAR_EOF > 'Changes' Thu Sep 4 1986 - wnl (2.0, at last) This is the version that will (hopefully) get released to the world as top 2.0. Added the "r" and "k" commands for renice and kill, respectively. This required adding a way to handle system call errors, and the addition of the "e" command. Help screen and manual page were changed to reflect this change. Changed all "#ifdef SUN" directives to "#ifdef sun", and changed all "#ifdef PYRAMID" directives to "#ifdef pyr". As much as I hate those choices of preprocessor names (they too easily conflict with real variable names), it does make automatic compilation possible---people don't have to change the Makefile anymore for specific machines. The manual page was changed to automatically incorporate the defaults as set in the Makefile (including an infinite value for TOPN) and the way the manual page is generated by the Makefile was changed to make maintenance of this information automatic. Mon Jul 28 1986 - wnl (still pre 2.0) Real close now. I put in a new definition for the macro "pagetok" that does an explicit shift of a constant expression involving PGSHIFT. Appropriate checks are made if PGSHIFT is to small. "pagetok" is now used exclusively everywhere to convert kernel clicks to kilobytes. I added a full blown interactive mode with the ability to change some of the runtime parameters (how many to display, time delay, etc.) while top is running. I also incorporated a few ideas from the net: control characters in the command name are replaced with '?'; the '-S' option makes the swapper and pager visible; options have been added to control the number of displays produced (this makes it easier to make performance snapshots with top). I have also added the notion of "infinite" values for number of processes and number of displays. I fixed a long-standing bug in the uid to username mapping code that was only aggravated on the pyramids: it was an ill-defined expression (akin to i = i++). I tweaked the proc_compar routine for qsort slightly so that stopped processes were more likely to show up. Manual page was updated to reflect all changes noticeable to the user. Tue Jul 1 1986 - wnl (pre 2.0 -- 1.9999?) In the process of major revamping on the way to version 2.0. I have completely done away with curses by adding my own screen management routines in a separate file (screen.c). The rationale for this is that top knows a whole lot more about what is and is not redundant on the screen and can compare simple integer values where curses would have to compare strings. This has turned out to be a very big win speed-wise. The proc_compar routine for sorting has been rewritten to include several more keys. I decided this was necessary when I noticed that the "top" process itself kept disappearing off the top 10 list on a Sun-3. All the processes had the same percentage (0%) and the sort wasn't really doing anything worthwhile. I changed the expression that computes memory usage to use the ctob macro instead of just assuming that pages were 512 bytes. More work still needs to be done before this version is usable. I changed options-processing to use getopt and added appropriate incantations to the Makefile. Wed Feb 20 1985 - wnl (still 1.8) Put in the ifdef FOUR_ONE statements to make top still compilable on a 4.1 system. Apparently, there are some users out there that need this functionality. Oh well. I don't guarantee any of it, since I can't test it. Made appropriate changes to README and final installation related changes to Makefile. Sat Feb 2 1985 - wnl (1.8) Removed all the ifdef FOUR_TWO statements and made "top" into a 4.2 only program. If someone really wants to still run it on 4.1, then they can do all the work. We don't have a 4.1 machine anymore, so I don't even know if the thing still works under 4.1. Cleaned up the Makefile and the README. Added installation rules to the Makefile, as requested by several sites. Fixed a very obscure divide-by-zero bug. Added a second "key" to the qsort comparison function (proc_compar) so that comparisons are based on cpu ticks if the percentages are equal (provided by Jonathon Feiber at Sun). Tue Dec 11 1984 - wnl (1.7) Added the virtual and real memory status line to the header area (provided by Jonathon Feiber at Sun) Tue Nov 20 1984 - wnl (1.6) Added an "exit" if sbrk's fail. Added changes from Jonathon Feiber at Sun: ifdef SUN to make top work on Suns (they don't use doubles in the proc structure), register declarations, check for getting a user structure that has disappeared since the proc array was read (it used to die, now it just shows the process as swapped). Tue Nov 13 1984 - wnl (1.5) If the number of displayable processes ("active_procs") was less than the number of requested processes ("topn"), top would segmentation fault. This bug has been fixed. Thanks to Prentiss Riddle at ut-sally for pointing out the existence of this bug. Tue Oct 23 1984 - wnl (1.4) Finally fixed the hash table bug that caused processes owned by root to sometimes appear with either no name or a different name that had UID 0 (such as "operator"). Removed all the ifdef DEBUG blocks to make top ready for distribution to the real world. Sun Apr 8 1984 - wnl (still 1.3) Made some slight changes to the display format. It now looks more aesthetically pleasing. Added some preprocessor constants so that the two defaults (number of processes and seconds of delay) easier to change. Thu Apr 5 1984 - wnl (1.3) Changed the order in which things are done at initialization time. This way, if an error occurs before starting the main loop, curses will never get started. Also changed other error handlers so that endwin() is called before any flavor of exit. Specifying a number of processes that is more than the screen can handle is no longer fatal. It displays a warning message and pretends the user specified the maximum for the screen. Finally cured all the TSTP blues (well, almost all). I removed my TSTP handler and convinced the system to always use the one that curses sets up. Turns out that "sleep" was stepping all over it during a pause. So, I don't use sleep anymore. The only problem that remains with it now is redrawing the old display before updating it after a pause. Tue Apr 3 1984 - wnl (from 1.0 to 1.2) I changed the format of the TIME column from just "seconds" to "minutes:seconds". I also made pausing work correctly. Screen redraws with an up to date display. For compatibility with 4.2, I changed the name of the "zero" function to "bzero". The makefile has been altered to handle versions for 4.1 and 4.2, and README has been updated to reflect these recent changes. SHAR_EOF fi echo shar: "extracting 'top.man'" '(7861 characters)' if test -f 'top.man' then echo shar: "will not over-write existing file 'top.man'" else cat << \SHAR_EOF > 'top.man' .\" NOTE: changes to the manual page for "top" should be made in the .\" file "top.man" and NOT in the file "top.1". .TH TOP 1 Local .UC 4 .SH NAME top \- display and update information about the top cpu processes .SH SYNOPSIS .B top [ .B \-Sbinu ] [ .BI \-d count ] [ .BI \-s time ] [ .I number ] .SH DESCRIPTION .\" This defines appropriate quote strings for nroff and troff .ds lq \&" .ds rq \&" .if t .ds lq `` .if t .ds rq '' .\" Just in case these number registers aren't set yet... .if \nN==0 .nr N 10 .if \nD==0 .nr D 5 .I Top displays the top .if !\nN==-1 \nN processes on the system and periodically updates this information. .if \nN==-1 \ \{\ If standard output is an intelligent terminal (see below) then as many processes as will fit on the terminal screen are displayed by default. Otherwise, a good number of them are shown (around 20). .\} Raw cpu percentage is used to rank the processes. If .I number is given, then the top .I number processes will be displayed instead of the default. .PP .I Top makes a distinction between terminals that support advanced capabilities and those that do not. This distinction affects the choice of defaults for certain options. In the remainder of this document, an \*(lqintelligent\*(rq terminal is one that supports cursor addressing, clear screen, and clear to end of line. Conversely, a \*(lqdumb\*(rq terminal is one that does not support such features. If the output of .I top is redirected to a file, it acts as if it were being run on a dumb terminal. .SH OPTIONS .TP .B \-S Show system processes in the display. Normally, system processes such as the pager and the swapper are not shown. This option makes them visible. .TP .B \-b Use \*(lqbatch\*(rq mode. In this mode, all input from the terminal is ignored. Interrupt characters (such as ^C and ^\e) still have an effect. This is the default on a dumb terminal, or when the output is not a terminal. .TP .B \-i Use \*(lqinteractive\*(rq mode. In this mode, any input is immediately read for processing. See the section on \*(lqInteractive Mode\*(rq for an explanation of which keys perform what functions. After the command is processed, the screen will immediately be updated, even if the command was not understood. This mode is the default when standard output is an intelligent terminal. .TP .B \-n Use \*(lqnon-interactive\*(rq mode. This is indentical to \*(lqbatch\*(rq mode. .TP .B \-u Do not take the time to map uid numbers to usernames. Normally, .I top will read as much of the file \*(lq/etc/passwd\*(rq as is necessary to map all the user id numbers it encounters into login names. This option disables all that, while possibly decreasing execution time. The uid numbers are displayed instead of the names. .TP .BI \-d count Show only .I count displays, then exit. A display is considered to be one update of the screen. This option allows the user to select the number of displays he wants to see before .I top automatically exits. For intelligent terminals, no upper limit is set. The default is 1 for dumb terminals. .TP .BI \-s time Set the delay between screen updates to .I time seconds. The default delay between updates is \nD seconds. .PP Both .I count and .I number fields can be specified as \*(lqinfinite\*(rq, indicating that they can stretch as far as possible. This is accomplished by using any proper prefix of the keywords \*(lqinfinity\*(rq, \*(lqmaximum\*(rq, or \*(lqall\*(rq. The default for .I count on an intelligent terminal is, in fact, .BI infinity . .SH "INTERACTIVE MODE" When .I top is running in \*(lqinteractive mode\*(rq, it reads commands from the terminal and acts upon them accordingly. In this mode, the terminal is put in \*(lqCBREAK\*(rq, so that a character will be processed as soon as it is typed. Almost always, a key will be pressed when .I top is between displays; that is, while it is waiting for .I time seconds to elapse. If this is the case, the command will be processed and the display will be updated immediately thereafter (reflecting any changes that the command may have specified). This happens even if the command was incorrect. If a key is pressed while .I top is in the middle of updating the display, it will finish the update and then process the command. Some commands require additional information, and the user will be prompted accordingly. While typing this information in, the user's erase and kill keys (as set up by the command .IR stty ) are recognized, and a newline terminates the input. .PP These commands are currently recognized (^L refers to control-L): .TP .B ^L Redraw the screen. .IP "\fBh\fP\ or\ \fB?\fP" Display a summary of the commands (help screen). .TP .B q Quit .IR top. .TP .B d Change the number of displays to show (prompt for new number). Remember that the next display counts as one, so typing .B d1 will make .I top show one final display and then immediately exit. .TP .B n or # Change the number of processes to display (prompt for new number). .TP .B s Change the number of seconds to delay between displays (prompt for new number). .TP .B k Send a signal (\*(lqkill\*(rq by default) to a list of processes. This acts similarly to the command .IR kill (1)). .TP .B r Change the priority (the \*(lqnice\*(rq) of a list of processes. This acts similarly to the command .IR renice (8)). .TP .B e Display a list of system errors (if any) generated by the last .BR k ill or .BR r enice command. .SH "THE DISPLAY" The top few lines of the display show general information about the state of the system, including the last process id assigned to a process, the three load averages, the current time, the number of existing processes, the number of processes in each state (sleeping, ABANDONED, running, starting, zombies, and stopped), and a percentage of time spent in each of the processor states (user, nice, system, and idle). It also includes the amount of virtual and real memory in use (with the amount of memory considered \*(lqactive\*(rq in parentheses) and the amount of free memory. .PP The remainder of the screen displays information about individual processes. This display is similar in spirit to .IR ps (1) but it is not exactly the same. PID is the process id, USERNAME is the name of the process's owner (if .B \-u is specified, a UID column will be substituted for USERNAME), PRI is the current priority of the process, NICE is the nice amount (in the range \-20 to 20), SIZE is the total size of the process (text, data, and stack), RES is the current amount of resident memory (both SIZE and RES are given in kilobytes), STATE is the current state (one of \*(lqsleep\*(rq, \*(lqWAIT\*(rq, \*(lqrun\*(rq, \*(lqidl\*(rq, \*(lqzomb\*(rq, or \*(lqstop\*(rq), TIME is the number of system and user cpu seconds that the process has used, WCPU is the weighted cpu percentage (this is the same value that .IR ps (1) displays as CPU), CPU is the raw percentage and is the field that is sorted to determine the order of the processes, and COMMAND is the name of the command that the process is currently running (if the process is swapped out, this column is marked \*(lq<swapped>\*(rq). .SH NOTES The \*(lqABANDONED\*(rq state (known in the kernel as \*(lqSWAIT\*(rq) was abandoned, thus the name. A process should never end up in this state. .SH AUTHOR William LeFebvre, Rice University graduate student .SH FILES .DT /dev/kmem kernel memory .br /dev/mem physical memory .br /etc/passwd used to map uid numbers to user names .br /vmunix system image .SH BUGS The command name for swapped processes should be tracked down, but this would make the program run slower. .PP As with .IR ps (1), things can change while .I top is collecting information for an update. The picture it gives is only a close approximation to reality. .SH "SEE ALSO" kill(1), ps(1), stty(1), mem(4), renice(8) SHAR_EOF fi echo shar: "extracting 'sigconv.awk'" '(439 characters)' if test -f 'sigconv.awk' then echo shar: "will not over-write existing file 'sigconv.awk'" else cat << \SHAR_EOF > 'sigconv.awk' BEGIN { print "/* This file was automatically generated */" print "/* by the awk script \"sigconv.awk\". */\n" print "struct sigdesc {" print " char *name;" print " int number;" print "};\n" print "struct sigdesc sigdesc[] = {" } /^#define[ \t][ \t]*SIG[A-Z]/ { printf " \"%s\",\t%2d,\n", \ substr($2, 4), $3 } END { print " NULL,\t 0\n};" } SHAR_EOF fi echo shar: "extracting 'Makefile'" '(3194 characters)' if test -f 'Makefile' then echo shar: "will not over-write existing file 'Makefile'" else cat << \SHAR_EOF > 'Makefile' # Makefile for "top", a top 10 process display for Unix # # This makefile is for top, version 2.0 # # Written by William LeFebvre, Rice University graduate student # installation information: # OWNER - name (or uid) for the installed executable's owner # GROUP - group name (or gid) for the installed executable's group # MODE - mode for the installed executable (should start with a 0) # BINDIR - directory where the executable should live # MANDIR - directory where the manual page should live # MAN - troff macros for manual pages # TROFF - most appropriate troff command OWNER = phil GROUP = staff MODE = 755 BINDIR = /usr/local MANDIR = /usr/man/manl MAN = man TROFF = troff # Values for the two defaults in "top": # TOPN - default number of processes to display # DELAY - default delay between updates # # set TOPN to -1 to indicate infinity (so that top will display as many # as the screen will hold). TOPN = 10 DELAY = 5 TABLE = # Top maintains an internal hash table for translating uid to username. # This hash table must be big enough to hold every name in /etc/passwd. # It is possible, but not necessary, to specify the hash table size in # this Makefile. Just uncomment the following line and provide a number. #TABLE = -DTable_size= HEADERFILES = boolean.h layout.h screen.h top.h top.local.h masscomp.h bzero.c DOCFILES = README Changes top.man sigconv.awk Makefile getopt.c SRCFILES = top.c commands.c display.c kernel.c screen.c TARFILES = $(HEADERFILES) $(DOCFILES) $(SRCFILES) OBJS = top.o commands.o display.o kernel.o screen.o getopt.o # Top uses the preprocessor variables "sun" and "pyr" for specific changes # required by Suns and Pyramids. No changes to "CFLAGS" are required for # these architectres. CFLAGS = -O # To make a version for 4.1, comment out the previous line and # uncomment the following two lines: #CFLAGS = -DFOUR_ONE -O #OBJS = top.o commands.o display.o kernel.o screen.o getopt.o bzero.o # use this definition of cc on pyramid or masscomp CC = ucb cc all: top top.1 top: $(OBJS) $(CC) $(CFLAGS) -o top $(OBJS) -ltermcap -lm top.o: top.c Makefile $(CC) -c $(CFLAGS) $(TABLE) -DDefault_TOPN=$(TOPN) -DDefault_DELAY=$(DELAY) top.c # include file dependencies top.o: boolean.h layout.h screen.h top.h top.local.h masscomp.h commands.o: sigdesc.h display.o: boolean.h layout.h screen.h top.h masscomp.h kernel.o: top.local.h masscomp.h screen.o: boolean.h screen.h # automatically built include file sigdesc.h: sigconv.awk /usr/include/signal.h awk -f sigconv.awk /usr/include/signal.h >sigdesc.h # top.1 is built by combining the actual text with the default information top.1: top.man Makefile echo '.nr N' $(TOPN) > top.1 echo '.nr D' $(DELAY) >>top.1 cat top.man >>top.1 top.cat: top.1 nroff -$(MAN) top.1 | cat -s >top.cat troff: top.1 $(TROFF) -man top.1 tar: rm -f top.tar tar cvf top.tar $(TARFILES) shar: rm -f top1.shar top2.shar top3.shar shar -v $(HEADERFILES) > top1.shar shar -v $(SRCFILES) > top2.shar shar -v $(DOCFILES) > top3.shar clean: rm -f *.o top top.cat top.tar top.1 core install: top top.1 install -s -o $(OWNER) -m $(MODE) -g $(GROUP) top $(BINDIR) install -c top.1 $(MANDIR) SHAR_EOF fi echo shar: "extracting 'getopt.c'" '(1259 characters)' if test -f 'getopt.c' then echo shar: "will not over-write existing file 'getopt.c'" else cat << \SHAR_EOF > 'getopt.c' /*LINTLIBRARY*/ #define NULL 0 #define EOF (-1) #define ERR(s, c) if(opterr){\ extern int strlen(), write();\ char errbuf[2];\ errbuf[0] = c; errbuf[1] = '\n';\ (void) write(2, argv[0], (unsigned)strlen(argv[0]));\ (void) write(2, s, (unsigned)strlen(s));\ (void) write(2, errbuf, 2);} #define strchr index extern int strcmp(); extern char *strchr(); int opterr = 1; int optind = 1; int optopt; char *optarg; int getopt(argc, argv, opts) int argc; char **argv, *opts; { static int sp = 1; register int c; register char *cp; if(sp == 1) if(optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0') return(EOF); else if(strcmp(argv[optind], "--") == NULL) { optind++; return(EOF); } optopt = c = argv[optind][sp]; if(c == ':' || (cp=strchr(opts, c)) == NULL) { ERR(": unknown option, -", c); if(argv[optind][++sp] == '\0') { optind++; sp = 1; } return('?'); } if(*++cp == ':') { if(argv[optind][sp+1] != '\0') optarg = &argv[optind++][sp+1]; else if(++optind >= argc) { ERR(": argument missing for -", c); sp = 1; return('?'); } else optarg = argv[optind++]; sp = 1; } else { if(argv[optind][++sp] == '\0') { sp = 1; optind++; } optarg = NULL; } return(c); } SHAR_EOF fi exit 0 # End of shell archive