home *** CD-ROM | disk | FTP | other *** search
- Subject: v07i030: Top users display for 4.2BSD, Version 2.0, Part01/02
- Newsgroups: mod.sources
- Approved: mirror!rs
-
- Submitted by: William LeFebvre <phil@rice.edu>
- Mod.sources: Volume 7, Issue 30
- Archive-name: top2/Part01
-
- Well, here it is at last: top, version 2.0.
-
- This is a new version of a top users display for Berkeley 4.2 Unix. It
- uses termcap (but not curses) to periodically update the screen with
- information about the top so-many processes that are using CPU cycles.
-
- This distribution will work on the following Unix systems: standard
- Berkeley 4.2 (i.e.: for a VAX), Sun Unix (both 2.0 and 3.0), and
- Pyramid Unix. I received copies of top programs that were modified to
- run on a Masscomp and a Sequent, but in both cases the number of
- changes that were necessary were too high. For comparison, the number
- of #ifdef lines necessary for the two current variants are: 8 for the
- Sun and 3 for the Pyramid. And none of these changes made the display
- look any different. In contrast, the number of changes that would be
- required for the Masscomp was somewhere in the area of 40, and several
- changes to the display were necessary. Similar comments hold for the
- Sequent. For these reasons, I am reluctant to add support for these
- machines. It would be just as easy to maintain completely different
- source files for these architectures. After so many ifdef's, code
- becomes unreadable.
-
- There is important information in the README. Please read it even if
- you are intimately familiar with top. Some individuals will also be
- interested in reading the Changes file.
-
- Several suggestions that I received through the net were incorporated
- in 2.0. My thanks to all those who made recommendations. Some day, I
- should add acknowledgements, but not today. Feel free to send me
- changes and especially bug fixes. If you succeed in getting top to run
- on an unsupported architecture, and the number of changes is not too
- high, then please send me the code (or at least a diff). I will try to
- include it in future versions.
-
- William LeFebvre
- Department of Computer Science
- Rice University
- <phil@Rice.edu>
-
- -----cut here ----- -----cut here ----- -----cut here ----- -----cut here -----
- #!/bin/sh
- # This is a shell archive. Remove anything before this line,
- # then unpack it by saving it in a file and typing "sh file".
- # If all goes well, you will see the message "No problems found."
-
- # Exit status; set to 1 on "wc" errors or if would overwrite.
- STATUS=0
- # Contents: Changes Makefile Manifest README boolean.h bzero.c
- # commands.c display.c getopt.c kernel.c layout.h screen.c screen.h
- # sigconv.awk top.h
-
- echo x - Changes
- if test -f Changes ; then
- echo Changes exists, putting output in $$Changes
- OUT=$$Changes
- STATUS=1
- else
- OUT=Changes
- fi
- sed 's/^X//' > $OUT <<'@//E*O*F Changes//'
- 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.
-
- 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.
-
- 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.
-
- 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.
-
- 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).
-
- 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)
-
- 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).
-
- 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.
-
- 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.
-
- 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.
-
- 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.
-
- 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.
- @//E*O*F Changes//
- chmod u=rw,g=rw,o=rw $OUT
-
- echo x - Makefile
- if test -f Makefile ; then
- echo Makefile exists, putting output in $$Makefile
- OUT=$$Makefile
- STATUS=1
- else
- OUT=Makefile
- fi
- sed 's/^X//' > $OUT <<'@//E*O*F Makefile//'
- X# Makefile for "top", a top 10 process display for Unix
- X#
- X# This makefile is for top, version 2.0
- X#
- X# Written by William LeFebvre, Rice University graduate student
-
- 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
-
- XOWNER = phil
- XGROUP = staff
- XMODE = 755
- XBINDIR = /usr/local
- XMANDIR = /usr/man/manl
- XMAN = man
- XTROFF = troff
-
- 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).
-
- XTOPN = 10
- XDELAY = 5
-
- 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=
-
- 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# Top uses the preprocessor variables "sun" and "pyr" for specific changes
- X# required by Suns and Pyramids. No changes to "CFLAGS" are required for
- X# 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
-
- Xall: top top.1
-
- Xtop: $(OBJS)
- X cc $(CFLAGS) -o top $(OBJS) -ltermcap -lm
-
- Xtop.o: top.c Makefile
- X cc -c $(CFLAGS) $(TABLE) -DDefault_TOPN=$(TOPN) -DDefault_DELAY=$(DELAY) top.c
-
- 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# automatically built include file
- Xsigdesc.h: sigconv.awk /usr/include/signal.h
- X awk -f sigconv.awk /usr/include/signal.h >sigdesc.h
-
- 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
-
- Xtop.cat: top.1
- X nroff -$(MAN) top.1 | cat -s >top.cat
-
- Xtroff: top.1
- X $(TROFF) -man top.1
-
- Xtar:
- X rm -f top.tar
- X tar cvf top.tar $(TARFILES)
-
- Xclean:
- X rm -f *.o top top.cat top.tar top.1 core
-
- Xinstall: top top.1
- X install -s -o $(OWNER) -m $(MODE) -g $(GROUP) top $(BINDIR)
- X install -c top.1 $(MANDIR)
- @//E*O*F Makefile//
- chmod u=rw,g=rw,o=rw $OUT
-
- echo x - Manifest
- if test -f Manifest ; then
- echo Manifest exists, putting output in $$Manifest
- OUT=$$Manifest
- STATUS=1
- else
- OUT=Manifest
- fi
- sed 's/^X//' > $OUT <<'@//E*O*F 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
- @//E*O*F Manifest//
- chmod u=rw,g=rw,o=rw $OUT
-
- echo x - README
- if test -f README ; then
- echo README exists, putting output in $$README
- OUT=$$README
- STATUS=1
- else
- OUT=README
- fi
- sed 's/^X//' > $OUT <<'@//E*O*F README//'
- XThis file contains a few comments about "top", version 2.0
-
- 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.
-
- 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.
-
- XThere are a few things that need to be checked before compiling the program:
-
- 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.
-
- 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.
-
- 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.
-
- 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".
-
- 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.
-
- XThere are also several parameters in the makefile that control
- Xinstallation. These should be altered to suit the desires and needs of
- Xindividual sites.
-
- 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.
-
- 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.
-
- XEnjoy!
-
- X William LeFebvre
- X Department of Computer Science
- X Rice University
- X ARPANet address: <phil@Rice.edu>
-
- X U.S. Mail address:
- X William LeFebvre
- X P.O. Box 1892
- X Department of Computer Science
- X Houston, TX 77251
- @//E*O*F README//
- chmod u=rw,g=rw,o=rw $OUT
-
- echo x - boolean.h
- if test -f boolean.h ; then
- echo boolean.h exists, putting output in $$boolean.h
- OUT=$$boolean.h
- STATUS=1
- else
- OUT=boolean.h
- fi
- sed 's/^X//' > $OUT <<'@//E*O*F 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 */
-
- @//E*O*F boolean.h//
- chmod u=rw,g=rw,o=rw $OUT
-
- echo x - bzero.c
- if test -f bzero.c ; then
- echo bzero.c exists, putting output in $$bzero.c
- OUT=$$bzero.c
- STATUS=1
- else
- OUT=bzero.c
- fi
- sed 's/^X//' > $OUT <<'@//E*O*F 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# define K 1024
-
- X/*
- X * bzero(memory, amount) - set "amount" bytes starting at "memory" to the
- X * value 0.
- X */
-
- Xbzero(memory, amount)
-
- Xchar *memory;
- Xint amount;
-
- 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_bzero64(memory, amount)
-
- Xchar *memory;
- Xint amount;
-
- X{
- X asm(" movc5 $0, (sp), $0, 8(ap), *4(ap)");
- X}
- @//E*O*F bzero.c//
- chmod u=rw,g=rw,o=rw $OUT
-
- echo x - commands.c
- if test -f commands.c ; then
- echo commands.c exists, putting output in $$commands.c
- OUT=$$commands.c
- STATUS=1
- else
- OUT=commands.c
- fi
- sed 's/^X//' > $OUT <<'@//E*O*F 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#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"
-
- Xextern int errno;
- Xextern int sys_nerr;
- Xextern char *sys_errlist[];
-
- Xextern char *copyright;
-
- Xint err_compar();
- Xchar *err_string();
- Xchar *index();
-
- X/*
- X * show_help() - display the help screen; invoked in response to
- X * either 'h' or '?'.
- X */
-
- Xshow_help()
-
- 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 * Utility routines that help with some of the commands.
- X */
-
- Xchar *next_field(str)
-
- Xregister char *str;
-
- X{
- X register char *temp;
-
- X if ((str = index(str, ' ')) == NULL)
- X {
- X return(NULL);
- X }
- X *str = '\0';
- X while (*++str == ' ') /* loop */;
- X return(str);
- X}
-
- Xscanint(str, intp)
-
- Xchar *str;
- Xint *intp;
-
- X{
- X register int val = 0;
- X register char ch;
-
- 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 * 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#define ERRMAX 20
-
- 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};
-
- 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/* 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 * 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#define STRMAX 80
-
- Xchar *err_string()
-
- 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 /* if there are no errors, return NULL */
- X if (errcnt == 0)
- X {
- X return(NULL);
- X }
-
- X /* sort the errors */
- X qsort(errs, errcnt, sizeof(struct errs), err_compar);
-
- X /* need a space at the from of the error string */
- X string[0] = ' ';
- X string[1] = '\0';
- X stringlen = STRMAX - 2;
-
- 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 /* add final message */
- X stringlen = str_adderr(string, stringlen, currerr);
-
- X /* return the error string */
- X return(stringlen == 0 ? err_listem : string);
- X}
-
- X/*
- X * str_adderr(str, len, err) - add an explanation of error "err" to
- X * the string "str".
- X */
-
- Xstr_adderr(str, len, err)
-
- Xchar *str;
- Xint len;
- Xint err;
-
- X{
- X register char *msg;
- X register int msglen;
-
- 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 * 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 */
-
- Xstr_addarg(str, len, arg, first)
-
- Xchar *str;
- Xint len;
- Xchar *arg;
- Xint first;
-
- X{
- X register int arglen;
-
- 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 * err_compar(p1, p2) - comparison routine used by "qsort"
- X * for sorting errors.
- X */
-
- Xerr_compar(p1, p2)
-
- Xregister struct errs *p1, *p2;
-
- X{
- X register int result;
-
- X if ((result = p1->errno - p2->errno) == 0)
- X {
- X return(strcmp(p1->arg, p2->arg));
- X }
- X return(result);
- X}
-
- X/*
- X * error_count() - return the number of errors currently logged.
- X */
-
- Xerror_count()
-
- X{
- X return(errcnt);
- X}
-
- X/*
- X * show_errors() - display on stdout the current log of errors.
- X */
-
- Xshow_errors()
-
- X{
- X register int cnt = 0;
- X register struct errs *errp = errs;
-
- 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 * kill_procs(str) - send signals to processes, much like the "kill"
- X * command does; invoked in response to 'k'.
- X */
-
- Xchar *kill_procs(str)
-
- Xchar *str;
-
- 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 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 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 /* terminate the end of the signal name */
- X while (*--optr == ' ');
- X *++optr = '\0';
-
- 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 /* 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 /* 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 /* return appropriate error string */
- X return(err_string());
- X}
-
- X/*
- X * renice_procs(str) - change the "nice" of processes, much like the
- X * "renice" command does; invoked in response to 'r'.
- X */
-
- Xchar *renice_procs(str)
-
- Xchar *str;
-
- X{
- X register char negate;
- X int prio;
- X int procnum;
-
- X ERR_RESET;
-
- X /* allow for negative priority values */
- X if ((negate = *str == '-'))
- X {
- X /* move past the minus sign */
- X str++;
- X }
-
- X /* use procnum as a temporary holding place and get the number */
- X procnum = scanint(str, &prio);
-
- X /* negate if necessary */
- X if (negate)
- X {
- X prio = -prio;
- X }
-
- X /* check for validity */
- X if (procnum == -1 || prio <= PRIO_MIN || prio >= PRIO_MAX)
- X {
- X return(" bad priority value");
- X }
-
- X /* move to the first process number */
- X if ((str = next_field(str)) == NULL)
- X {
- X return(" no processes specified");
- 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 /* return appropriate error string */
- X return(err_string());
- X}
-
- @//E*O*F commands.c//
- chmod u=rw,g=rw,o=rw $OUT
-
- echo x - display.c
- if test -f display.c ; then
- echo display.c exists, putting output in $$display.c
- OUT=$$display.c
- STATUS=1
- else
- OUT=display.c
- fi
- sed 's/^X//' > $OUT <<'@//E*O*F display.c//'
- X/*
- X * Top - a top users display for Berkeley Unix
- X *
- X * This file contains the routines that display information on the screen.
- X * Each section of the screen has two routines: one for initially writing
- X * all constant and dynamic text, and one for only updating the text that
- X * changes. The prefix "i_" is used on all the "initial" routines and the
- X * prefix "u_" is used for all the "updating" routines. NOTE: it is
- X * assumed that none of the "i_" routines use any of the termcap
- X * capabilities. In this way, those routines can be safely used on
- X * terminals that have minimal (or nonexistant) terminal capabilities.
- X */
-
- X#include <stdio.h>
- X#include <ctype.h>
- X#include <sys/param.h>
- X#include <sys/dir.h>
- X#include <sys/user.h>
- X#include <sys/proc.h>
- X#include <sys/dk.h>
- X#include "screen.h" /* interface to screen package */
- X#include "layout.h" /* defines for screen position layout */
- X#include "top.h"
- X#include "boolean.h"
-
- Xstatic int lmpid = 0;
- Xstatic struct user u;
-
- Xchar *printable();
-
- X/* Verbose process state names */
-
- Xchar *state_name[] =
- X{
- X "", "sleeping", "ABANDONED", "running", "starting", "zombie", "stopped"
- X};
-
- X/* process state names for the "STATE" column of the display */
-
- Xchar *state_abbrev[] =
- X{
- X "", "sleep", "WAIT", "run", "start", "zomb", "stop"
- X};
-
- X/* cpu state names for percentages */
-
- Xchar *cpu_state[] =
- X{
- X "user", "nice", "system", "idle"
- X};
-
- X/* screen positions for cpustate figures */
- Xchar x_cpustates[] = { 12, 24, 36, 50 };
-
- Xi_loadave(mpid, avenrun)
-
- Xint mpid;
- X#ifdef sun
- Xlong *avenrun;
- X#else
- Xdouble *avenrun;
- X#endif sun
-
- X{
- X register int i;
-
- X printf("last pid: %5d; load averages", mpid);
-
- X for (i = 0; i < 3; i++)
- X {
- X printf("%c %4.2f",
- X i == 0 ? ':' : ',',
- X#ifdef sun
- X (double)avenrun[i] / FSCALE);
- X#else
- X avenrun[i]);
- X#endif
- X }
- X lmpid = mpid;
- X}
-
- Xu_loadave(mpid, avenrun)
-
- Xint mpid;
- X#ifdef sun
- Xlong *avenrun;
- X#else
- Xdouble *avenrun;
- X#endif sun
-
- X{
- X register int i;
-
- X if (mpid != lmpid);
- X {
- X Move_to(x_lastpid, y_lastpid);
- X printf("%5d", mpid);
- X lmpid = mpid;
- X }
-
- X Move_to(x_loadave, y_loadave);
- X for (i = 0; i < 3; i++)
- X {
- X printf("%s%4.2f",
- X i == 0 ? "" : ", ",
- X#ifdef sun
- X (double)avenrun[i] / FSCALE);
- X#else
- X avenrun[i]);
- X#endif
- X }
- X}
-
- Xstatic int ltotal = 0;
- Xstatic int lbrkdn[7];
-
- Xi_procstates(total, brkdn)
-
- Xint total;
- Xint *brkdn;
-
- X{
- X register int i;
-
- X printf("%2d processes", total); /* ??? */
- X ltotal = total;
- X for (i = 1; i < 7; i++)
- X {
- X if (brkdn[i] != 0)
- X {
- X printf("%c %d %s%s",
- X i == 1 ? ':' : ',',
- X brkdn[i],
- X state_name[i],
- X (i == SZOMB) && (brkdn[i] > 1) ? "s" : "");
- X }
- X }
- X bcopy(brkdn, lbrkdn, sizeof(lbrkdn));
- X}
-
- Xu_procstates(total, brkdn)
-
- Xint total;
- Xint *brkdn;
-
- X{
- X register int i;
-
- X if (ltotal != total)
- X {
- X Move_to(x_procstate, y_procstate);
- X printf("%d ", total);
- X ltotal = total;
- X }
- X else if (bcmp(brkdn, lbrkdn, sizeof(lbrkdn)) == 0)
- X {
- X return;
- X }
-
- X Move_to(x_brkdn, y_brkdn);
- X for (i = 1; i < 7; i++)
- X {
- X if (brkdn[i] != 0)
- X {
- X printf("%s%d %s%s",
- X i == 1 ? "" : ", ",
- X brkdn[i],
- X state_name[i],
- X (i == SZOMB) && (brkdn[i] > 1) ? "s" : "");
- X }
- X }
- X putcap(clear_line);
- X bcopy(brkdn, lbrkdn, sizeof(lbrkdn));
- X}
-
- Xi_cpustates(changes, total)
-
- Xint *changes;
- Xint total;
-
- X{
- X register int i;
-
- X printf("\nCpu states: ");
- X for (i = 0; i < CPUSTATES; i++)
- X {
- X printf("%s%4.1f%% %s",
- X i == 0 ? "" : ", ",
- X ((float)changes[i] / (float)total) * 100.0,
- X cpu_state[i]);
- X }
- X printf("\n");
- X}
-
- Xu_cpustates(changes, total)
-
- Xint *changes;
- Xint total;
-
- X{
- X register int i;
-
- X for (i = 0; i < CPUSTATES; i++)
- X {
- X Move_to(x_cpustates[i], y_cpustates);
- X printf("%4.1f",
- X ((float)changes[i] / (float)total) * 100.0);
- X }
- X}
-
- Xz_cpustates()
-
- X{
- X register int i;
-
- X printf("\nCpu states: ");
- X for (i = 0; i < CPUSTATES; i++)
- X {
- X printf("%s %% %s", i == 0 ? "" : ", ", cpu_state[i]);
- X }
- X printf("\n");
- X}
-
- Xi_memory(i1, i2, i3, i4, i5)
-
- Xint i1, i2, i3, i4, i5;
-
- X{
- X printf("Memory: %4dK (%4dK) real, %4dK (%4dK) virtual, %4dK free",
- X i1, i2, i3, i4, i5);
- X}
-
- Xu_memory(i1, i2, i3, i4, i5)
-
- Xint i1, i2, i3, i4, i5;
-
- X{
- X Move_to(x_realmem, y_mem);
- X printf("%4dK (%4d", i1, i2);
- X Move_to(x_virtmem, y_mem);
- X printf("%4dK (%4d", i3, i4);
- X Move_to(x_free, y_mem);
- X printf("%4d", i5);
- X}
-
- Xi_header(f2)
-
- Xchar *f2;
-
- X{
- X printf(
- X "\n\n PID %s PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND",
- X f2);
- X}
-
- Xu_header()
-
- X{
- X Move_to(0, y_header);
- X}
-
- X#ifdef sun
- X#define percent_cpu(pp) ((double)(pp)->p_pctcpu / FSCALE)
- X#else
- X#define percent_cpu(pp) ((pp)->p_pctcpu)
- X#endif
-
- X#define weighted_cpu(pct, pp) ((pp)->p_time == 0 ? 0.0 : \
- X ((pct) / (1.0 - exp((pp)->p_time * logcpu))))
-
- X#define Proc_format "%5d %-8.8s %3d %4d%6dK %4dK %-5s%4d:%02d %5.2f%% %5.2f%% %.14s"
-
- X#ifdef DEBUG
- XFILE *debug;
- X#endif
-
- Xi_process(line, pp, get_userid)
-
- Xint line;
- Xstruct proc *pp;
- Xchar *(*get_userid)();
-
- X{
- X register long cputime;
- X register double pctcpu;
- X register char *thisline;
- X int len;
-
- X#ifdef DEBUG
- X debug = fopen("debug", "w");
- X#endif
- X /* calculate a pointer to the buffer for this line */
- X thisline = screenbuf[line];
-
- X /* get the cpu usage and calculate the cpu percentages */
- X cputime = get_ucpu(pp);
- X pctcpu = percent_cpu(pp);
-
- X /* format the line */
- X sprintf(thisline, Proc_format,
- X pp->p_pid,
- X (*get_userid)(pp->p_uid),
- X pp->p_pri - PZERO,
- X pp->p_nice - NZERO,
- X#ifdef pyr
- X pagetok(pp->p_tsize + pp->p_dsize + pp->p_cssize + pp->p_ussize),
- X#else
- X pagetok(pp->p_tsize + pp->p_dsize + pp->p_ssize),
- X#endif
- X pagetok(pp->p_rssize),
- X state_abbrev[pp->p_stat],
- X cputime / 60l,
- X cputime % 60l,
- X 100.0 * weighted_cpu(pctcpu, pp),
- X 100.0 * pctcpu,
- X printable(u.u_comm));
-
- X /* write the line out */
- X putchar('\n');
- X fputs(thisline, stdout);
-
- X /* zero fill the rest of it */
- X len = strlen(thisline);
- X bzero(thisline + len, Display_width - len);
- X}
-
- Xstatic int lastline = 0;
-
- Xu_process(line, pp, get_userid)
-
- Xint line;
- Xstruct proc *pp;
- Xchar *(*get_userid)();
-
- X{
- X register char *optr;
- X register char *nptr;
- X register int ch;
- X register int diff;
- X register int newcol = 1;
- X register int lastcol = 0;
- X register long cputime;
- X register double pctcpu;
- X char cursor_on_line = No;
- X char *thisline;
- X int screen_line = line + Header_lines;
- X static char newline[Display_width];
-
- X /* get a pointer to the old text for this line */
- X optr = thisline = screenbuf[line];
-
- X /* get the cpu usage and calculate the cpu percentages */
- X cputime = get_ucpu(pp);
- X pctcpu = percent_cpu(pp);
-
- X /* format the line */
- X sprintf(newline, Proc_format,
- X pp->p_pid,
- X (*get_userid)(pp->p_uid),
- X pp->p_pri - PZERO,
- X pp->p_nice - NZERO,
- X#ifdef pyr
- X pagetok(pp->p_tsize + pp->p_dsize + pp->p_cssize + pp->p_ussize),
- X#else
- X pagetok(pp->p_tsize + pp->p_dsize + pp->p_ssize),
- X#endif
- X pagetok(pp->p_rssize),
- X state_abbrev[pp->p_stat],
- X cputime / 60l,
- X cputime % 60l,
- X 100.0 * weighted_cpu(pctcpu, pp),
- X 100.0 * pctcpu,
- X printable(u.u_comm));
-
- X /* compare the two strings and only rewrite what has changed */
- X nptr = newline;
- X#ifdef DEBUG
- X fputs(optr, debug);
- X fputc('\n', debug);
- X fputs(nptr, debug);
- X fputs("\n-\n", debug);
- X#endif
-
- X /* start things off on the right foot */
- X /* this is to make sure the invariants get set up right */
- X if ((ch = *nptr++) != *optr)
- X {
- X if (screen_line - lastline == 1)
- X {
- X putchar('\n');
- X }
- X else
- X {
- X Move_to(0, screen_line);
- X }
- X cursor_on_line = Yes;
- X putchar(ch);
- X *optr = ch;
- X lastcol = 1;
- X }
- X optr++;
-
- X /*
- X * main loop -- check each character. If the old and new aren't the
- X * same, then update the display. When the distance from the current
- X * cursor position to the new change is small enough, the characters
- X * that belong there are written to move the cursor over.
- X *
- X * Invariants:
- X * lastcol is the column where the cursor currently is sitting
- X * (always one beyond the end of the last mismatch).
- X */
- X do /* yes, a do...while */
- X {
- X if ((ch = *nptr++) != *optr)
- X {
- X /* new character is different from old */
- X /* put the new character in the screen buffer */
- X *optr = ch;
-
- X /* make sure the cursor is on top of this character */
- X diff = newcol - lastcol;
- X if (diff > 0)
- X {
- X /* some motion is required--figure out which is shorter */
- X if (diff < 6 && cursor_on_line)
- X {
- X /* overwrite old stuff--get it out of the screen buffer */
- X printf("%.*s", diff, &thisline[lastcol]);
- X }
- X else
- X {
- X /* use cursor addressing */
- X Move_to(newcol, screen_line);
- X cursor_on_line = Yes;
- X }
- X /* remember where the cursor is */
- X lastcol = newcol + 1;
- X }
- X else
- X {
- X /* already there, update position */
- X lastcol++;
- X }
-
- X /* write what we need to */
- X if (ch == '\0')
- X {
- X /* at the end--terminate with a clear-to-end-of-line */
- X putcap(clear_line);
- X }
- X else
- X {
- X /* write the new character */
- X putchar(ch);
- X }
- X }
-
- X /* update working column and screen buffer pointer */
- X newcol++;
- X optr++;
-
- X } while (ch != '\0');
-
- X /* zero out the rest of the line buffer -- MUST BE DONE! */
- X bzero(optr, Display_width - newcol);
-
- X /* remember where the current line is */
- X if (cursor_on_line)
- X {
- X lastline = screen_line;
- X }
- X}
-
- Xstatic int last_hi = 0;
-
- Xu_endscreen(hi)
-
- Xregister int hi;
-
- X{
- X register int screen_line = hi + Header_lines;
-
- X if (smart_terminal)
- X {
- X if (hi < last_hi)
- X {
- X if (hi == 0)
- X {
- X putchar('\n');
- X putchar('\n');
- X putcap(clear_line);
- X putchar('\n');
- X }
- X else if (screen_line - lastline == 1)
- X {
- X putchar('\n');
- X }
- X else
- X {
- X Move_to(0, screen_line);
- X }
- X
- X while (--last_hi > hi)
- X {
- X putcap(clear_line);
- X putchar('\n');
- X }
- X putcap(clear_line);
- X }
- X else
- X {
- X last_hi = hi;
- X }
-
- X /* move the cursor to a pleasant place */
- X Move_to(x_idlecursor, y_idlecursor);
- X }
- X else
- X {
- X /* separate this display from the next with some vertical room */
- X fputs("\n\n", stdout);
- X }
- X}
-
- X/*
- X * get_ucpu(pp) - retrieve the user structure associated with the proc
- X * structure pointed to by pp and return the cpu usage. The user
- X * structure is stored in the global structure "u" for later use.
- X */
-
- Xget_ucpu(pp)
-
- Xstruct proc *pp;
-
- X{
- X if (getu(pp, &u) == -1)
- X {
- X strcpy(u.u_comm, "<swapped>");
- X return(0);
- X }
- X else
- X {
- X /* set u_comm for system processes */
- X if (u.u_comm[0] == '\0')
- X {
- X if (pp->p_pid == 0)
- X {
- X strcpy(u.u_comm, "Swapper");
- X }
- X else if (pp->p_pid == 2)
- X {
- X strcpy(u.u_comm, "Pager");
- X }
- X }
-
- X#ifdef FOUR_ONE
- X return((int)((float)(u.u_vm.vm_utime + u.u_vm.vm_stime)/hz));
- X#else
- X return(u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec);
- X#endif
- X }
- X}
-
- X/*
- X * printable(str) - make the string pointed to by "str" into one that is
- X * printable (i.e.: all ascii), by converting all non-printable
- X * characters into '?'. Replacements are done in place and a pointer
- X * to the original buffer is returned.
- X */
-
- Xchar *printable(str)
-
- Xchar *str;
-
- X{
- X register char *ptr;
- X register char ch;
-
- X ptr = str;
- X while ((ch = *ptr) != '\0')
- X {
- X if (!isprint(ch))
- X {
- X *ptr = '?';
- X }
- X ptr++;
- X }
- X return(str);
- X}
- @//E*O*F display.c//
- chmod u=rw,g=rw,o=rw $OUT
-
- echo x - getopt.c
- if test -f getopt.c ; then
- echo getopt.c exists, putting output in $$getopt.c
- OUT=$$getopt.c
- STATUS=1
- else
- OUT=getopt.c
- fi
- sed 's/^X//' > $OUT <<'@//E*O*F 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#define strchr index
-
- Xextern int strcmp();
- Xextern char *strchr();
-
- Xint opterr = 1;
- Xint optind = 1;
- Xint optopt;
- Xchar *optarg;
-
- 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 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}
- @//E*O*F getopt.c//
- chmod u=rw,g=rw,o=rw $OUT
-
- echo x - kernel.c
- if test -f kernel.c ; then
- echo kernel.c exists, putting output in $$kernel.c
- OUT=$$kernel.c
- STATUS=1
- else
- OUT=kernel.c
- fi
- sed 's/^X//' > $OUT <<'@//E*O*F 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#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#include <sys/proc.h>
-
- X#include "top.local.h"
-
- X/* useful externals */
- Xextern int errno;
- Xextern char *sys_errlist[];
-
- Xstatic int kmem = -1;
- Xstatic int mem = -1;
-
- 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 * 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 */
-
- Xgetu(p, u)
-
- Xregister struct proc *p;
- Xstruct user *u;
-
- X{
- X struct pte uptes[UPAGES];
- X register caddr_t upage;
- X register struct pte *pte;
- X register nbytes, n;
-
- 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) == 0)
- X {
- X return(-1);
- 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/*
- 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 */
-
- Xgetkval(offset, ptr, size, refstr)
-
- Xlong offset;
- Xint *ptr;
- Xint size;
- Xchar *refstr;
-
- 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}
- @//E*O*F kernel.c//
- chmod u=rw,g=rw,o=rw $OUT
-
- echo x - layout.h
- if test -f layout.h ; then
- echo layout.h exists, putting output in $$layout.h
- OUT=$$layout.h
- STATUS=1
- else
- OUT=layout.h
- fi
- sed 's/^X//' > $OUT <<'@//E*O*F 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#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#define y_cpustates 2
- @//E*O*F layout.h//
- chmod u=rw,g=rw,o=rw $OUT
-
- echo x - screen.c
- if test -f screen.c ; then
- echo screen.c exists, putting output in $$screen.c
- OUT=$$screen.c
- STATUS=1
- else
- OUT=screen.c
- fi
- sed 's/^X//' > $OUT <<'@//E*O*F 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#include <stdio.h>
- X#include <sgtty.h>
- X#include "screen.h"
- X#include "boolean.h"
-
- Xextern char *myname;
-
- Xint putstdout();
-
- 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;
-
- Xstatic struct sgttyb old_settings;
- Xstatic struct sgttyb new_settings;
- Xstatic char is_a_terminal = No;
-
- Xinit_termcap()
-
- X{
- X char *bufptr;
- X char *PCptr;
- X char *term_name;
- X char *temp_ptr;
- X char *getenv();
- X int status;
-
- X /* assume we have a smart terminal until proven otherwise */
- X smart_terminal = Yes;
-
- 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 /* pretend it's dumb and proceed */
- X smart_terminal = No;
- X return;
- X }
-
- X /* these immediately indicate a very stupid terminal */
- X if (tgetflag("hc") || tgetflag("os"))
- X {
- X smart_terminal = No;
- X return;
- 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 /* 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 /* initialize the pointer into the termcap string buffer */
- X bufptr = string_buffer;
-
- 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 /* 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 /* pad character */
- X PC = (PCptr = tgetstr("pc", &bufptr)) ? *PCptr : 0;
-
- X /* set convenience strings */
- X strcpy(home, tgoto(cursor_motion, 0, 0));
- X strcpy(lower_left, tgoto(cursor_motion, 0, screen_length - 1));
-
- X /* if stdout is not a terminal, pretend we are a dumb terminal */
- X if (gtty(1, &old_settings) == -1)
- X {
- X smart_terminal = No;
- X }
- X}
-
- Xinit_screen()
-
- X{
- X /* get the old settings for safe keeping */
- X if (gtty(1, &old_settings) == 0)
- X {
- X /* copy the settings so we can modify them */
- X new_settings = old_settings;
-
- 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 stty(1, &new_settings);
-
- X /* remember the erase and kill characters */
- X ch_erase = old_settings.sg_erase;
- X ch_kill = old_settings.sg_kill;
-
- X /* remember that it really is a terminal */
- X is_a_terminal = Yes;
-
- 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}
-
- Xend_screen()
-
- 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 /* if we have settings to reset, then do so */
- X if (is_a_terminal)
- X {
- X stty(1, &old_settings);
- X }
- X}
-
- Xreinit_screen()
-
- X{
- X /* install our settings if it is a terminal */
- X if (is_a_terminal)
- X {
- X stty(1, &new_settings);
- X }
-
- X /* send init string */
- X if (smart_terminal)
- X {
- X putcap(terminal_init);
- X }
- X}
-
- Xstandout(fmt, a1, a2, a3)
-
- Xchar *fmt;
- Xint a1, a2, a3;
-
- 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}
-
- Xclear()
-
- X{
- X if (smart_terminal)
- X {
- X putcap(clear_screen);
- X }
- X}
-
- X/* This has to be defined as a subroutine for tputs (instead of a macro) */
-
- Xputstdout(ch)
-
- Xchar ch;
-
- X{
- X putchar(ch);
- X}
-
- @//E*O*F screen.c//
- chmod u=rw,g=rw,o=rw $OUT
-
- echo x - screen.h
- if test -f screen.h ; then
- echo screen.h exists, putting output in $$screen.h
- OUT=$$screen.h
- STATUS=1
- else
- OUT=screen.h
- fi
- sed 's/^X//' > $OUT <<'@//E*O*F 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#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))
-
- 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/* These aresome termcap strings for use outside of "screen.c" */
- Xextern char *cursor_motion;
- Xextern char *clear_line;
-
- X/* rows and columns on the screen according to termcap */
- Xextern int screen_length;
- Xextern int screen_width;
-
- X/* a function that puts a single character on stdout */
- Xint putstdout();
- @//E*O*F screen.h//
- chmod u=rw,g=rw,o=rw $OUT
-
- echo x - sigconv.awk
- if test -f sigconv.awk ; then
- echo sigconv.awk exists, putting output in $$sigconv.awk
- OUT=$$sigconv.awk
- STATUS=1
- else
- OUT=sigconv.awk
- fi
- sed 's/^X//' > $OUT <<'@//E*O*F 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/^#define[ \t][ \t]*SIG[A-Z]/ {
- X printf " \"%s\",\t%2d,\n", \
- X substr($2, 4), $3
- X }
-
- XEND {
- X print " NULL,\t 0\n};"
- X }
- @//E*O*F sigconv.awk//
- chmod u=rw,g=rw,o=rw $OUT
-
- echo x - top.h
- if test -f top.h ; then
- echo top.h exists, putting output in $$top.h
- OUT=$$top.h
- STATUS=1
- else
- OUT=top.h
- fi
- sed 's/^X//' > $OUT <<'@//E*O*F top.h//'
- X/*
- X * Top - a top users display for Berkeley Unix
- X *
- X * General (global) definitions
- X */
-
- X/* Number of lines of header information on the standard screen */
- X#define Header_lines 6
-
- X/* Number of columns needed for display */
- X#define Display_width 80
-
- X/* Log base 2 of 1024 is 10 (2^10 == 1024) */
- X#define LOG1024 10
-
- 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#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
-
- Xextern double logcpu;
-
- Xdouble log();
- Xdouble exp();
-
- Xextern char (* screenbuf)[Display_width];
- @//E*O*F top.h//
- chmod u=rw,g=rw,o=rw $OUT
-
- echo Inspecting for damage in transit...
- temp=/tmp/sharin$$; dtemp=/tmp/sharout$$
- trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
- cat > $temp <<\!!!
- 125 1165 6805 Changes
- 96 461 2875 Makefile
- 18 18 161 Manifest
- 97 888 5259 README
- 5 22 125 boolean.h
- 43 131 789 bzero.c
- 449 1382 8905 commands.c
- 590 1631 11346 display.c
- 66 182 1259 getopt.c
- 141 497 3092 kernel.c
- 38 129 845 layout.h
- 233 604 4485 screen.c
- 26 135 874 screen.h
- 18 58 439 sigconv.awk
- 34 132 794 top.h
- 1979 7435 48053 total
- !!!
- wc Changes Makefile Manifest README boolean.h bzero.c commands.c display.c getopt.c kernel.c layout.h screen.c screen.h sigconv.awk top.h | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
- if test -s $dtemp ; then
- echo "Ouch [diff of wc output]:"
- cat $dtemp
- STATUS=1
- elif test $STATUS = 0 ; then
- echo "No problems found."
- else
- echo "WARNING -- PROBLEMS WERE FOUND..."
- fi
- exit $STATUS
-