home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume7 / top2 / part01 next >
Encoding:
Internet Message Format  |  1986-11-30  |  55.8 KB

  1. Subject:  v07i030:  Top users display for 4.2BSD, Version 2.0, Part01/02
  2. Newsgroups: mod.sources
  3. Approved: mirror!rs
  4.  
  5. Submitted by: William LeFebvre <phil@rice.edu>
  6. Mod.sources: Volume 7, Issue 30
  7. Archive-name: top2/Part01
  8.  
  9. Well, here it is at last:  top, version 2.0.
  10.  
  11. This is a new version of a top users display for Berkeley 4.2 Unix.  It
  12. uses termcap (but not curses) to periodically update the screen with
  13. information about the top so-many processes that are using CPU cycles.
  14.  
  15. This distribution will work on the following Unix systems:  standard
  16. Berkeley 4.2 (i.e.: for a VAX), Sun Unix (both 2.0 and 3.0), and
  17. Pyramid Unix.  I received copies of top programs that were modified to
  18. run on a Masscomp and a Sequent, but in both cases the number of
  19. changes that were necessary were too high.  For comparison, the number
  20. of #ifdef lines necessary for the two current variants are:  8 for the
  21. Sun and 3 for the Pyramid.  And none of these changes made the display
  22. look any different.  In contrast, the number of changes that would be
  23. required for the Masscomp was somewhere in the area of 40, and several
  24. changes to the display were necessary.  Similar comments hold for the
  25. Sequent.  For these reasons, I am reluctant to add support for these
  26. machines.  It would be just as easy to maintain completely different
  27. source files for these architectures.  After so many ifdef's, code
  28. becomes unreadable.
  29.  
  30. There is important information in the README.  Please read it even if
  31. you are intimately familiar with top.  Some individuals will also be
  32. interested in reading the Changes file.
  33.  
  34. Several suggestions that I received through the net were incorporated
  35. in 2.0.  My thanks to all those who made recommendations.  Some day, I
  36. should add acknowledgements, but not today.  Feel free to send me
  37. changes and especially bug fixes.  If you succeed in getting top to run
  38. on an unsupported architecture, and the number of changes is not too
  39. high, then please send me the code (or at least a diff).  I will try to
  40. include it in future versions.
  41.  
  42.             William LeFebvre
  43.             Department of Computer Science
  44.             Rice University
  45.             <phil@Rice.edu>
  46.  
  47. -----cut here ----- -----cut here ----- -----cut here ----- -----cut here -----
  48. #!/bin/sh
  49. # This is a shell archive.  Remove anything before this line,
  50. # then unpack it by saving it in a file and typing "sh file".
  51. # If all goes well, you will see the message "No problems found."
  52.  
  53. # Exit status; set to 1 on "wc" errors or if would overwrite.
  54. STATUS=0
  55. # Contents:  Changes Makefile Manifest README boolean.h bzero.c
  56. #    commands.c display.c getopt.c kernel.c layout.h screen.c screen.h
  57. #    sigconv.awk top.h
  58.  
  59. echo x - Changes
  60. if test -f Changes ; then
  61.     echo Changes exists, putting output in $$Changes
  62.     OUT=$$Changes
  63.     STATUS=1
  64. else
  65.     OUT=Changes
  66. fi
  67. sed 's/^X//' > $OUT <<'@//E*O*F Changes//'
  68. XThu Sep  4 1986 - wnl (2.0, at last)
  69. X    This is the version that will (hopefully) get released to the
  70. X    world as top 2.0.
  71. X    Added the "r" and "k" commands for renice and kill, respectively.
  72. X    This required adding a way to handle system call errors, and the
  73. X    addition of the "e" command.  Help screen and manual page were
  74. X    changed to reflect this change.  Changed all "#ifdef SUN" directives
  75. X    to "#ifdef sun", and changed all "#ifdef PYRAMID" directives to
  76. X    "#ifdef pyr".  As much as I hate those choices of preprocessor
  77. X    names (they too easily conflict with real variable names), it does
  78. X    make automatic compilation possible---people don't have to change
  79. X    the Makefile anymore for specific machines.  The manual page was
  80. X    changed to automatically incorporate the defaults as set in the
  81. X    Makefile (including an infinite value for TOPN) and the way the
  82. X    manual page is generated by the Makefile was changed to make
  83. X    maintenance of this information automatic.
  84.  
  85. XMon Jul 28 1986 - wnl (still pre 2.0)
  86. X    Real close now.  I put in a new definition for the macro "pagetok"
  87. X    that does an explicit shift of a constant expression involving
  88. X    PGSHIFT.  Appropriate checks are made if PGSHIFT is to small.
  89. X    "pagetok" is now used exclusively everywhere to convert kernel
  90. X    clicks to kilobytes.  I added a full blown interactive mode with
  91. X    the ability to change some of the runtime parameters (how many to
  92. X    display, time delay, etc.) while top is running.  I also
  93. X    incorporated a few ideas from the net:  control characters in the
  94. X    command name are replaced with '?'; the '-S' option makes the
  95. X    swapper and pager visible; options have been added to control the
  96. X    number of displays produced (this makes it easier to make
  97. X    performance snapshots with top).  I have also added the notion of
  98. X    "infinite" values for number of processes and number of displays.
  99. X    I fixed a long-standing bug in the uid to username mapping code
  100. X    that was only aggravated on the pyramids:  it was an ill-defined
  101. X    expression (akin to i = i++).  I tweaked the proc_compar routine
  102. X    for qsort slightly so that stopped processes were more likely to
  103. X    show up.  Manual page was updated to reflect all changes
  104. X    noticeable to the user.
  105.  
  106. XTue Jul  1 1986 - wnl (pre 2.0 -- 1.9999?)
  107. X    In the process of major revamping on the way to version 2.0.
  108. X    I have completely done away with curses by adding my own screen
  109. X    management routines in a separate file (screen.c).  The rationale
  110. X    for this is that top knows a whole lot more about what is and is
  111. X    not redundant on the screen and can compare simple integer values
  112. X    where curses would have to compare strings.  This has turned out
  113. X    to be a very big win speed-wise.  The proc_compar routine for
  114. X    sorting has been rewritten to include several more keys.  I
  115. X    decided this was necessary when I noticed that the "top" process
  116. X    itself kept disappearing off the top 10 list on a Sun-3.  All the
  117. X    processes had the same percentage (0%) and the sort wasn't really
  118. X    doing anything worthwhile.  I changed the expression that computes
  119. X    memory usage to use the ctob macro instead of just assuming that
  120. X    pages were 512 bytes.  More work still needs to be done before
  121. X    this version is usable.  I changed options-processing to use
  122. X    getopt and added appropriate incantations to the Makefile.
  123.  
  124. XWed Feb 20 1985 - wnl (still 1.8)
  125. X    Put in the ifdef FOUR_ONE statements to make top still compilable
  126. X    on a 4.1 system.  Apparently, there are some users out there that
  127. X    need this functionality.  Oh well.  I don't guarantee any of it,
  128. X    since I can't test it.  Made appropriate changes to README and
  129. X    final installation related changes to Makefile.
  130.  
  131. XSat Feb  2 1985 - wnl (1.8)
  132. X    Removed all the ifdef FOUR_TWO statements and made "top" into a
  133. X    4.2 only program.  If someone really wants to still run it on 4.1,
  134. X    then they can do all the work.  We don't have a 4.1 machine
  135. X    anymore, so I don't even know if the thing still works under 4.1.
  136. X    Cleaned up the Makefile and the README.  Added installation rules
  137. X    to the Makefile, as requested by several sites.  Fixed a very
  138. X    obscure divide-by-zero bug.  Added a second "key" to the qsort
  139. X    comparison function (proc_compar) so that comparisons are based on
  140. X    cpu ticks if the percentages are equal (provided by Jonathon
  141. X    Feiber at Sun).
  142.  
  143. XTue Dec 11 1984 - wnl (1.7)
  144. X    Added the virtual and real memory status line to the header area
  145. X    (provided by Jonathon Feiber at Sun)
  146.  
  147. XTue Nov 20 1984 - wnl (1.6)
  148. X    Added an "exit" if sbrk's fail.  Added changes from Jonathon
  149. X    Feiber at Sun:  ifdef SUN to make top work on Suns (they don't use
  150. X    doubles in the proc structure), register declarations, check for
  151. X    getting a user structure that has disappeared since the proc array
  152. X    was read (it used to die, now it just shows the process as swapped).
  153.  
  154. XTue Nov 13 1984 - wnl (1.5)
  155. X    If the number of displayable processes ("active_procs") was less
  156. X    than the number of requested processes ("topn"), top would
  157. X    segmentation fault.  This bug has been fixed.  Thanks to Prentiss
  158. X    Riddle at ut-sally for pointing out the existence of this bug.
  159.  
  160. XTue Oct 23 1984 - wnl (1.4)
  161. X    Finally fixed the hash table bug that caused processes owned by
  162. X    root to sometimes appear with either no name or a different name
  163. X    that had UID 0 (such as "operator").  Removed all the ifdef DEBUG
  164. X    blocks to make top ready for distribution to the real world.
  165.  
  166. XSun Apr  8 1984 - wnl (still 1.3)
  167. X    Made some slight changes to the display format.  It now looks more
  168. X    aesthetically pleasing.  Added some preprocessor constants so that
  169. X    the two defaults (number of processes and seconds of delay) easier
  170. X    to change.
  171.  
  172. XThu Apr  5 1984 - wnl (1.3)
  173. X    Changed the order in which things are done at initialization time.
  174. X    This way, if an error occurs before starting the main loop, curses
  175. X    will never get started.  Also changed other error handlers so that
  176. X    endwin() is called before any flavor of exit.  Specifying a number
  177. X    of processes that is more than the screen can handle is no longer
  178. X    fatal.  It displays a warning message and pretends the user
  179. X    specified the maximum for the screen.  Finally cured all the TSTP
  180. X    blues (well, almost all).  I removed my TSTP handler and convinced
  181. X    the system to always use the one that curses sets up.  Turns out
  182. X    that "sleep" was stepping all over it during a pause.  So, I don't
  183. X    use sleep anymore.  The only problem that remains with it now is
  184. X    redrawing the old display before updating it after a pause.
  185.  
  186. XTue Apr  3 1984 - wnl (from 1.0 to 1.2)
  187. X    I changed the format of the TIME column from just "seconds" to
  188. X    "minutes:seconds".  I also made pausing work correctly.  Screen
  189. X    redraws with an up to date display.  For compatibility with 4.2, I
  190. X    changed the name of the "zero" function to "bzero".  The makefile
  191. X    has been altered to handle versions for 4.1 and 4.2, and README
  192. X    has been updated to reflect these recent changes.
  193. @//E*O*F Changes//
  194. chmod u=rw,g=rw,o=rw $OUT
  195.  
  196. echo x - Makefile
  197. if test -f Makefile ; then
  198.     echo Makefile exists, putting output in $$Makefile
  199.     OUT=$$Makefile
  200.     STATUS=1
  201. else
  202.     OUT=Makefile
  203. fi
  204. sed 's/^X//' > $OUT <<'@//E*O*F Makefile//'
  205. X# Makefile for "top", a top 10 process display for Unix
  206. X#
  207. X# This makefile is for top, version 2.0
  208. X#
  209. X# Written by William LeFebvre, Rice University graduate student
  210.  
  211. X# installation information:
  212. X#    OWNER    - name (or uid) for the installed executable's owner
  213. X#    GROUP    - group name (or gid) for the installed executable's group
  214. X#    MODE    - mode for the installed executable (should start with a 0)
  215. X#    BINDIR    - directory where the executable should live
  216. X#    MANDIR    - directory where the manual page should live
  217. X#    MAN    - troff macros for manual pages
  218. X#    TROFF    - most appropriate troff command
  219.  
  220. XOWNER  = phil
  221. XGROUP  = staff
  222. XMODE   = 755
  223. XBINDIR = /usr/local
  224. XMANDIR = /usr/man/manl
  225. XMAN    = man
  226. XTROFF  = troff
  227.  
  228. X# Values for the two defaults in "top":
  229. X#    TOPN    - default number of processes to display
  230. X#    DELAY    - default delay between updates
  231. X#
  232. X# set TOPN to -1 to indicate infinity (so that top will display as many
  233. X# as the screen will hold).
  234.  
  235. XTOPN = 10
  236. XDELAY = 5
  237.  
  238. XTABLE =
  239. X# Top maintains an internal hash table for translating uid to username.
  240. X# This hash table must be big enough to hold every name in /etc/passwd.
  241. X# It is possible, but not necessary, to specify the hash table size in
  242. X# this Makefile.  Just uncomment the following line and provide a number.
  243. X#TABLE = -DTable_size=
  244.  
  245. XTARFILES = README Changes Makefile top.c commands.c display.c kernel.c \
  246. X       screen.c getopt.c \
  247. X       boolean.h layout.h screen.h top.h top.local.h bzero.c \
  248. X       sigconv.awk top.man
  249. XOBJS = top.o commands.o display.o kernel.o screen.o getopt.o
  250.  
  251. X# Top uses the preprocessor variables "sun" and "pyr" for specific changes
  252. X# required by Suns and Pyramids.  No changes to "CFLAGS" are required for
  253. X# these architectres.
  254. XCFLAGS = -O
  255. X# To make a version for 4.1, comment out the previous line and
  256. X# uncomment the following two lines:
  257. X#CFLAGS = -DFOUR_ONE -O
  258. X#OBJS = top.o commands.o display.o kernel.o screen.o getopt.o bzero.o
  259.  
  260. Xall: top top.1
  261.  
  262. Xtop: $(OBJS)
  263. X    cc $(CFLAGS) -o top $(OBJS) -ltermcap -lm
  264.  
  265. Xtop.o: top.c Makefile
  266. X    cc -c $(CFLAGS) $(TABLE) -DDefault_TOPN=$(TOPN) -DDefault_DELAY=$(DELAY) top.c
  267.  
  268. X# include file dependencies
  269. Xtop.o: boolean.h layout.h screen.h top.h top.local.h
  270. Xcommands.o: sigdesc.h
  271. Xdisplay.o: boolean.h layout.h screen.h top.h
  272. Xkernel.o: top.local.h
  273. Xscreen.o: boolean.h screen.h
  274.  
  275. X# automatically built include file
  276. Xsigdesc.h: sigconv.awk /usr/include/signal.h
  277. X    awk -f sigconv.awk /usr/include/signal.h >sigdesc.h
  278.  
  279. X# top.1 is built by combining the actual text with the default information
  280. Xtop.1: top.man Makefile
  281. X    echo '.nr N' $(TOPN) > top.1
  282. X    echo '.nr D' $(DELAY) >>top.1
  283. X    cat top.man >>top.1
  284.  
  285. Xtop.cat: top.1
  286. X    nroff -$(MAN) top.1 | cat -s >top.cat
  287.  
  288. Xtroff: top.1
  289. X    $(TROFF) -man top.1
  290.  
  291. Xtar:
  292. X    rm -f top.tar
  293. X    tar cvf top.tar $(TARFILES)
  294.  
  295. Xclean:
  296. X    rm -f *.o top top.cat top.tar top.1 core
  297.  
  298. Xinstall: top top.1
  299. X    install -s -o $(OWNER) -m $(MODE) -g $(GROUP) top $(BINDIR)
  300. X    install -c top.1 $(MANDIR)
  301. @//E*O*F Makefile//
  302. chmod u=rw,g=rw,o=rw $OUT
  303.  
  304. echo x - Manifest
  305. if test -f Manifest ; then
  306.     echo Manifest exists, putting output in $$Manifest
  307.     OUT=$$Manifest
  308.     STATUS=1
  309. else
  310.     OUT=Manifest
  311. fi
  312. sed 's/^X//' > $OUT <<'@//E*O*F Manifest//'
  313. XChanges
  314. XMakefile
  315. XManifest
  316. XREADME
  317. Xboolean.h
  318. Xbzero.c
  319. Xcommands.c
  320. Xdisplay.c
  321. Xgetopt.c
  322. Xkernel.c
  323. Xlayout.h
  324. Xscreen.c
  325. Xscreen.h
  326. Xsigconv.awk
  327. Xtop.c
  328. Xtop.h
  329. Xtop.local.h
  330. Xtop.man
  331. @//E*O*F Manifest//
  332. chmod u=rw,g=rw,o=rw $OUT
  333.  
  334. echo x - README
  335. if test -f README ; then
  336.     echo README exists, putting output in $$README
  337.     OUT=$$README
  338.     STATUS=1
  339. else
  340.     OUT=README
  341. fi
  342. sed 's/^X//' > $OUT <<'@//E*O*F README//'
  343. XThis file contains a few comments about "top", version 2.0
  344.  
  345. X"top" is a program that will give continual reports about the state of the
  346. Xsystem, including a list of the top cpu using processes.  It requires read
  347. Xaccess to the memory files "/dev/kmem" and "/dev/mem" as well as the system
  348. Ximage "/vmunix".  Some installations have these files protected from general
  349. Xaccess.  These sites would have to install this program in the same way that
  350. Xprograms such as "ps" are installed.
  351.  
  352. XCAVEAT:  version 2.0 of top has internal commands that kill and renice
  353. Xprocesses.  DO NOT INSTALL TOP AS A SETUID PROGRAM, or you will open up a
  354. Xbig security hole since top makes no process ownership checks on its own.
  355. XNote that it is still safe to install top as a set group-id program, since
  356. Xgroup-id has no bearing on who can renice or send signals to what processes.
  357.  
  358. XThere are a few things that need to be checked before compiling the program:
  359.  
  360. XThe most important item is the internal hash table size.  This size is
  361. Xdefined in the program with the preprocessor variable "Table_size".  This
  362. Xconstant MUST be larger than the number of lines in the file /etc/passwd.
  363. XIt is advisable that this number be about twice the number of lines, and
  364. Xthat it be a prime number (since it dictates the size of the hash table).
  365. XMake sure this is checked before compilation.  Its definition exists in
  366. Xthe file "top.local.h", but it is also settable in the Makefile.
  367.  
  368. XSeveral other things are set in "top.local.h", including the file names
  369. Xused for certain system files ("/vmunix", "/dev/kmem", etc.).  Although I
  370. Xdon't expect those to vary much, they are put there for convenience.
  371. XAnother parameter in this file is "Nominal_TOPN".  This will be discussed
  372. Xin the next paragraph.
  373.  
  374. XThere are two preprocessor variables that are defined at compile time by
  375. Xthe makefile.  These are "Default_TOPN" and "Default_DELAY".  Their values
  376. Xare the defaults used for the top number of processes to be displayed and
  377. Xthe number of seconds to delay between displays, respectively.  They are
  378. Xset by the Makefile variables "TOPN" and "DELAY", respectively.  These
  379. Xconstants are preset as follows:  TOPN=10, DELAY=5.  These can be
  380. Xoverridden by either changing the Makefile or by specifying the change on
  381. Xthe make command line (with something like "make TOPN=15").  Version 2 of
  382. Xtop understands an "infinite" value for the number of processes to
  383. Xdisplay.  Such a value indicates that top should display as much as will
  384. Xfill the screen.  To specify a Default_TOPN of infinity, set TOPN equal
  385. Xto -1.  Version 2 also understands the difference between an intelligent
  386. Xterminal and a dumb terminal (such as a hardcopy device or a file).
  387. XTypically, a default of infinity would not be desirable on a dumb
  388. Xterminal, so the value of "Nominal_TOPN" is used when (1) Default_TOPN is
  389. Xinfinity and (2) the output device is a dumb terminal or a file.  The
  390. Xvalue for this preprocessor variable is set in "top.local.h" and can also
  391. Xbe set from the "make" command line.  In the distribution, it is set to 18.
  392.  
  393. XBy default, the makefile will make a "top" for one of the following
  394. Xsystems:  Berkeley 4.2, Sun Unix (version 1.1 and higher), and Pyramid
  395. XUnix.  Previous versions of top fully supported Berkeley 4.1 Unix.  This
  396. Xsupport has waned in version 2, and is not guaranteed to even work.  If
  397. Xyou really must give it a try, you can change the makefile variable
  398. X"CFLAGS" to make a 4.1 "top".  Instructions for doing this can be found in
  399. X"Makefile".
  400.  
  401. XThe file "bzero.c" contains a function that will zero a block of memory on
  402. Xa VAX.  This is only needed for Berkeley 4.1, since 4.2 has a bzero
  403. Xdefined in the C run time library.  If you are strange enough to be
  404. Xrunning 4.1 on something besides a VAX, you will have to replace this
  405. Xroutine with one that will work on your machine.  If you don't know a
  406. Xquick way to do it, then writing a simple loop will suffice.  "Bzero"
  407. Xtakes two arguments:  a pointer to the buffer to zero, and the number of
  408. Xbytes to zero.
  409.  
  410. XThere are also several parameters in the makefile that control
  411. Xinstallation.  These should be altered to suit the desires and needs of
  412. Xindividual sites.
  413.  
  414. XVersion 2.0 still only supports standard 4.2 and Sun and Pyramid
  415. Xarchitectures.  I attempted to add sufficient changes to make top work on
  416. Xa Masscomp, but found the number of required changes to be overwhelming.
  417. XFeel free to alter top to make it run on whatever funny architecture you
  418. Xhave.  I also encourage you to send those changes back to me at the
  419. Xaddress below.  But, if the number of changes is high, I will be reluctant
  420. Xto include the changes in the next version of top.  As an example, there
  421. Xwere only 10 modifications required for the Sun version (and all changes
  422. Xwere trivial), and just 4 changes were needed for the Pyramid.
  423.  
  424. XIf you make any kind of change to "top" that you feel would be beneficial
  425. Xto others who use this program, or if you find and fix a bug, please send
  426. Xme the change.
  427.  
  428. XEnjoy!
  429.  
  430. X                                William LeFebvre
  431. X                Department of Computer Science
  432. X                Rice University
  433. X                                ARPANet address: <phil@Rice.edu>
  434.  
  435. X                U.S. Mail address:
  436. X                    William LeFebvre
  437. X                    P.O. Box 1892
  438. X                    Department of Computer Science
  439. X                    Houston, TX  77251
  440. @//E*O*F README//
  441. chmod u=rw,g=rw,o=rw $OUT
  442.  
  443. echo x - boolean.h
  444. if test -f boolean.h ; then
  445.     echo boolean.h exists, putting output in $$boolean.h
  446.     OUT=$$boolean.h
  447.     STATUS=1
  448. else
  449.     OUT=boolean.h
  450. fi
  451. sed 's/^X//' > $OUT <<'@//E*O*F boolean.h//'
  452. X/* My favorite names for boolean values */
  453. X#define  No    0
  454. X#define  Yes    1
  455. X#define  Maybe    2        /* tri-state boolean, actually */
  456.  
  457. @//E*O*F boolean.h//
  458. chmod u=rw,g=rw,o=rw $OUT
  459.  
  460. echo x - bzero.c
  461. if test -f bzero.c ; then
  462.     echo bzero.c exists, putting output in $$bzero.c
  463.     OUT=$$bzero.c
  464.     STATUS=1
  465. else
  466.     OUT=bzero.c
  467. fi
  468. sed 's/^X//' > $OUT <<'@//E*O*F bzero.c//'
  469. X/*
  470. X *  Fast, sleazy, and ugly zero function.
  471. X *
  472. X *  Note that this will only work on a VAX, but it is real easy to write a
  473. X *  similar function for whatever machine you may need.  If nothing else,
  474. X *  just a simple loop in C will suffice.
  475. X *
  476. X *  Dave Johnson, Rice University.
  477. X *
  478. X *  Enhanced by William LeFebvre of Rice University to handle zeroing more
  479. X *  than 64K.
  480. X */
  481.  
  482. X# define   K    1024
  483.  
  484. X/*
  485. X *  bzero(memory, amount) - set "amount" bytes starting at "memory" to the
  486. X *                value 0.
  487. X */
  488.  
  489. Xbzero(memory, amount)
  490.  
  491. Xchar *memory;
  492. Xint  amount;
  493.  
  494. X{
  495. X    while (amount >= 64*K)
  496. X    {
  497. X    _bzero64(memory, 64*K-1);
  498. X    memory += 64*K-1;
  499. X    amount -= 64*K-1;
  500. X    }
  501. X    _bzero64(memory, amount);
  502. X}
  503.  
  504. X_bzero64(memory, amount)
  505.  
  506. Xchar *memory;
  507. Xint  amount;
  508.  
  509. X{
  510. X    asm("    movc5    $0, (sp), $0, 8(ap), *4(ap)");
  511. X}
  512. @//E*O*F bzero.c//
  513. chmod u=rw,g=rw,o=rw $OUT
  514.  
  515. echo x - commands.c
  516. if test -f commands.c ; then
  517.     echo commands.c exists, putting output in $$commands.c
  518.     OUT=$$commands.c
  519.     STATUS=1
  520. else
  521.     OUT=commands.c
  522. fi
  523. sed 's/^X//' > $OUT <<'@//E*O*F commands.c//'
  524. X/*
  525. X *  Top users display for Berkeley Unix
  526. X *
  527. X *  This file contains the routines that implement some of the interactive
  528. X *  mode commands.  Note that some of the commands are implemented in-line
  529. X *  in "main".  This is necessary because they change the global state of
  530. X *  "top" (i.e.:  changing the number of processes to display).
  531. X */
  532.  
  533. X#include <stdio.h>
  534. X#include <ctype.h>
  535. X#include <signal.h>
  536. X#include <sys/time.h>
  537. X#include <sys/resource.h>
  538. X#include "sigdesc.h"        /* generated automatically */
  539. X#include "boolean.h"
  540.  
  541. Xextern int  errno;
  542. Xextern int  sys_nerr;
  543. Xextern char *sys_errlist[];
  544.  
  545. Xextern char *copyright;
  546.  
  547. Xint err_compar();
  548. Xchar *err_string();
  549. Xchar *index();
  550.  
  551. X/*
  552. X *  show_help() - display the help screen; invoked in response to
  553. X *        either 'h' or '?'.
  554. X */
  555.  
  556. Xshow_help()
  557.  
  558. X{
  559. X    fputs(copyright, stdout);
  560. X    fputs("\n\n\
  561. XA top users display for Unix\n\
  562. X\n\
  563. XThese single-character commands are available:\n\
  564. X\n\
  565. X^L      - redraw screen\n\
  566. Xq       - quit\n\
  567. Xh or ?  - help; show this text\n\
  568. Xd       - change number of displays to show\n\
  569. Xe       - list errors generated by last \"kill\" or \"renice\" command\n\
  570. Xk       - kill processes; send a signal to a list of processes\n\
  571. Xn or #  - change number of processes to display\n\
  572. Xr       - renice a process\n\
  573. Xs       - change number of seconds to delay between updates\n\
  574. X\n\
  575. X\n", stdout);
  576. X}
  577.  
  578. X/*
  579. X *  Utility routines that help with some of the commands.
  580. X */
  581.  
  582. Xchar *next_field(str)
  583.  
  584. Xregister char *str;
  585.  
  586. X{
  587. X    register char *temp;
  588.  
  589. X    if ((str = index(str, ' ')) == NULL)
  590. X    {
  591. X    return(NULL);
  592. X    }
  593. X    *str = '\0';
  594. X    while (*++str == ' ') /* loop */;
  595. X    return(str);
  596. X}
  597.  
  598. Xscanint(str, intp)
  599.  
  600. Xchar *str;
  601. Xint  *intp;
  602.  
  603. X{
  604. X    register int val = 0;
  605. X    register char ch;
  606.  
  607. X    while ((ch = *str++) != '\0')
  608. X    {
  609. X    if (isdigit(ch))
  610. X    {
  611. X        val = val * 10 + (ch - '0');
  612. X    }
  613. X    else if (isspace(ch))
  614. X    {
  615. X        break;
  616. X    }
  617. X    else
  618. X    {
  619. X        return(-1);
  620. X    }
  621. X    }
  622. X    *intp = val;
  623. X    return(0);
  624. X}
  625.  
  626. X/*
  627. X *  Some of the commands make system calls that could generate errors.
  628. X *  These errors are collected up in an array of structures for later
  629. X *  contemplation and display.  Such routines return a string containing an
  630. X *  error message, or NULL if no errors occurred.  The next few routines are
  631. X *  for manipulating and displaying these errors.  We need an upper limit on
  632. X *  the number of errors, so we arbitrarily choose 20.
  633. X */
  634.  
  635. X#define ERRMAX 20
  636.  
  637. Xstruct errs        /* structure for a system-call error */
  638. X{
  639. X    int  errno;        /* value of errno (that is, the actual error) */
  640. X    char *arg;        /* argument that caused the error */
  641. X};
  642.  
  643. Xstatic struct errs errs[ERRMAX];
  644. Xstatic int errcnt;
  645. Xstatic char *err_toomany = " too many errors occurred";
  646. Xstatic char *err_listem = 
  647. X    " Many errors occurred.  Press `e' to display the list of errors.";
  648.  
  649. X/* These macros get used to reset and log the errors */
  650. X#define ERR_RESET   errcnt = 0
  651. X#define ERROR(p, e) if (errcnt >= ERRMAX) \
  652. X            { \
  653. X            return(err_toomany); \
  654. X            } \
  655. X            else \
  656. X            { \
  657. X            errs[errcnt].arg = (p); \
  658. X            errs[errcnt++].errno = (e); \
  659. X            }
  660.  
  661. X/*
  662. X *  err_string() - return an appropriate error string.  This is what the
  663. X *    command will return for displaying.  If no errors were logged, then
  664. X *    return NULL.  The maximum length of the error string is defined by
  665. X *    "STRMAX".
  666. X */
  667.  
  668. X#define STRMAX 80
  669.  
  670. Xchar *err_string()
  671.  
  672. X{
  673. X    register char *ptr;
  674. X    register struct errs *errp;
  675. X    register int  cnt = 0;
  676. X    register int  first = Yes;
  677. X    register int  currerr = -1;
  678. X    int stringlen;        /* characters still available in "string" */
  679. X    char string[STRMAX];
  680.  
  681. X    /* if there are no errors, return NULL */
  682. X    if (errcnt == 0)
  683. X    {
  684. X    return(NULL);
  685. X    }
  686.  
  687. X    /* sort the errors */
  688. X    qsort(errs, errcnt, sizeof(struct errs), err_compar);
  689.  
  690. X    /* need a space at the from of the error string */
  691. X    string[0] = ' ';
  692. X    string[1] = '\0';
  693. X    stringlen = STRMAX - 2;
  694.  
  695. X    /* loop thru the sorted list, building an error string */
  696. X    ptr = string;
  697. X    while (cnt < errcnt)
  698. X    {
  699. X    errp = &(errs[cnt++]);
  700. X    if (errp->errno != currerr)
  701. X    {
  702. X        if (currerr != -1)
  703. X        {
  704. X        if ((stringlen = str_adderr(string, stringlen, currerr)) < 2)
  705. X        {
  706. X            return(err_listem);
  707. X        }
  708. X        strcat(string, "; ");        /* we know there's more */
  709. X        }
  710. X        currerr = errp->errno;
  711. X        first = Yes;
  712. X    }
  713. X    if ((stringlen = str_addarg(string, stringlen, errp->arg, first)) ==0)
  714. X    {
  715. X        return(err_listem);
  716. X    }
  717. X    first = No;
  718. X    }
  719.  
  720. X    /* add final message */
  721. X    stringlen = str_adderr(string, stringlen, currerr);
  722.  
  723. X    /* return the error string */
  724. X    return(stringlen == 0 ? err_listem : string);
  725. X}
  726.  
  727. X/*
  728. X *  str_adderr(str, len, err) - add an explanation of error "err" to
  729. X *    the string "str".
  730. X */
  731.  
  732. Xstr_adderr(str, len, err)
  733.  
  734. Xchar *str;
  735. Xint len;
  736. Xint err;
  737.  
  738. X{
  739. X    register char *msg;
  740. X    register int  msglen;
  741.  
  742. X    msg = err == 0 ? "Not a number" : sys_errlist[err];
  743. X    msglen = strlen(msg) + 2;
  744. X    if (len <= msglen)
  745. X    {
  746. X    return(0);
  747. X    }
  748. X    strcat(str, ": ");
  749. X    strcat(str, msg);
  750. X    return(len - msglen);
  751. X}
  752.  
  753. X/*
  754. X *  str_addarg(str, len, arg, first) - add the string argument "arg" to
  755. X *    the string "str".  This is the first in the group when "first"
  756. X *    is set (indicating that a comma should NOT be added to the front).
  757. X */
  758.  
  759. Xstr_addarg(str, len, arg, first)
  760.  
  761. Xchar *str;
  762. Xint  len;
  763. Xchar *arg;
  764. Xint  first;
  765.  
  766. X{
  767. X    register int arglen;
  768.  
  769. X    arglen = strlen(arg);
  770. X    if (!first)
  771. X    {
  772. X    arglen += 2;
  773. X    }
  774. X    if (len <= arglen)
  775. X    {
  776. X    return(0);
  777. X    }
  778. X    if (!first)
  779. X    {
  780. X    strcat(str, ", ");
  781. X    }
  782. X    strcat(str, arg);
  783. X    return(len - arglen);
  784. X}
  785.  
  786. X/*
  787. X *  err_compar(p1, p2) - comparison routine used by "qsort"
  788. X *    for sorting errors.
  789. X */
  790.  
  791. Xerr_compar(p1, p2)
  792.  
  793. Xregister struct errs *p1, *p2;
  794.  
  795. X{
  796. X    register int result;
  797.  
  798. X    if ((result = p1->errno - p2->errno) == 0)
  799. X    {
  800. X    return(strcmp(p1->arg, p2->arg));
  801. X    }
  802. X    return(result);
  803. X}
  804.  
  805. X/*
  806. X *  error_count() - return the number of errors currently logged.
  807. X */
  808.  
  809. Xerror_count()
  810.  
  811. X{
  812. X    return(errcnt);
  813. X}
  814.  
  815. X/*
  816. X *  show_errors() - display on stdout the current log of errors.
  817. X */
  818.  
  819. Xshow_errors()
  820.  
  821. X{
  822. X    register int cnt = 0;
  823. X    register struct errs *errp = errs;
  824.  
  825. X    printf("%d error%s:\n\n", errcnt, errcnt == 1 ? "" : "s");
  826. X    while (cnt++ < errcnt)
  827. X    {
  828. X    printf("%5s: %s\n", errp->arg,
  829. X        errp->errno == 0 ? "Not a number" : sys_errlist[errp->errno]);
  830. X    errp++;
  831. X    }
  832. X}
  833.  
  834. X/*
  835. X *  kill_procs(str) - send signals to processes, much like the "kill"
  836. X *        command does; invoked in response to 'k'.
  837. X */
  838.  
  839. Xchar *kill_procs(str)
  840.  
  841. Xchar *str;
  842.  
  843. X{
  844. X    register char *nptr;
  845. X    register char *optr;
  846. X    int signum = SIGTERM;    /* default */
  847. X    int procnum;
  848. X    char badnum = 0;
  849. X    struct sigdesc *sigp;
  850.  
  851. X    ERR_RESET;
  852. X    if (str[0] == '-')
  853. X    {
  854. X    /* explicit signal specified */
  855. X    if ((optr = nptr = next_field(str)) == NULL)
  856. X    {
  857. X        return(" kill: no processes specified");
  858. X    }
  859.  
  860. X    if (isdigit(str[1]))
  861. X    {
  862. X        scanint(str + 1, &signum);
  863. X        if (signum <= 0 || signum >= NSIG)
  864. X        {
  865. X        return(" invalid signal number");
  866. X        }
  867. X    }
  868. X    else 
  869. X    {
  870. X        /* terminate the end of the signal name */
  871. X        while (*--optr == ' ');
  872. X        *++optr = '\0';
  873.  
  874. X        /* translate the name into a number */
  875. X        for (sigp = sigdesc; sigp->name != NULL; sigp++)
  876. X        {
  877. X        if (strcmp(sigp->name, str + 1) == 0)
  878. X        {
  879. X            signum = sigp->number;
  880. X            break;
  881. X        }
  882. X        }
  883.  
  884. X        /* was it ever found */
  885. X        if (sigp->name == NULL)
  886. X        {
  887. X        return(" bad signal name");
  888. X        }
  889. X    }
  890. X    /* put the new pointer in place */
  891. X    str = nptr;
  892. X    }
  893.  
  894. X    /* loop thru the string, killing processes */
  895. X    do
  896. X    {
  897. X    if (scanint(str, &procnum) == -1)
  898. X    {
  899. X        ERROR(str, 0);
  900. X    }
  901. X    else if (kill(procnum, signum) == -1)
  902. X    {
  903. X        /* chalk up an error */
  904. X        ERROR(str, errno);
  905. X    }
  906. X    } while ((str = next_field(str)) != NULL);
  907.  
  908. X    /* return appropriate error string */
  909. X    return(err_string());
  910. X}
  911.  
  912. X/*
  913. X *  renice_procs(str) - change the "nice" of processes, much like the
  914. X *        "renice" command does; invoked in response to 'r'.
  915. X */
  916.  
  917. Xchar *renice_procs(str)
  918.  
  919. Xchar *str;
  920.  
  921. X{
  922. X    register char negate;
  923. X    int prio;
  924. X    int procnum;
  925.  
  926. X    ERR_RESET;
  927.  
  928. X    /* allow for negative priority values */
  929. X    if ((negate = *str == '-'))
  930. X    {
  931. X    /* move past the minus sign */
  932. X    str++;
  933. X    }
  934.  
  935. X    /* use procnum as a temporary holding place and get the number */
  936. X    procnum = scanint(str, &prio);
  937.  
  938. X    /* negate if necessary */
  939. X    if (negate)
  940. X    {
  941. X    prio = -prio;
  942. X    }
  943.  
  944. X    /* check for validity */
  945. X    if (procnum == -1 || prio <= PRIO_MIN || prio >= PRIO_MAX)
  946. X    {
  947. X    return(" bad priority value");
  948. X    }
  949.  
  950. X    /* move to the first process number */
  951. X    if ((str = next_field(str)) == NULL)
  952. X    {
  953. X    return(" no processes specified");
  954. X    }
  955.  
  956. X    /* loop thru the process numbers, renicing each one */
  957. X    do
  958. X    {
  959. X    if (scanint(str, &procnum) == -1)
  960. X    {
  961. X        ERROR(str, 0);
  962. X    }
  963. X    else if (setpriority(PRIO_PROCESS, procnum, prio) == -1)
  964. X    {
  965. X        ERROR(str, errno);
  966. X    }
  967. X    } while ((str = next_field(str)) != NULL);
  968.  
  969. X    /* return appropriate error string */
  970. X    return(err_string());
  971. X}
  972.  
  973. @//E*O*F commands.c//
  974. chmod u=rw,g=rw,o=rw $OUT
  975.  
  976. echo x - display.c
  977. if test -f display.c ; then
  978.     echo display.c exists, putting output in $$display.c
  979.     OUT=$$display.c
  980.     STATUS=1
  981. else
  982.     OUT=display.c
  983. fi
  984. sed 's/^X//' > $OUT <<'@//E*O*F display.c//'
  985. X/*
  986. X *  Top - a top users display for Berkeley Unix
  987. X *
  988. X *  This file contains the routines that display information on the screen.
  989. X *  Each section of the screen has two routines:  one for initially writing
  990. X *  all constant and dynamic text, and one for only updating the text that
  991. X *  changes.  The prefix "i_" is used on all the "initial" routines and the
  992. X *  prefix "u_" is used for all the "updating" routines.  NOTE:  it is
  993. X *  assumed that none of the "i_" routines use any of the termcap
  994. X *  capabilities.  In this way, those routines can be safely used on
  995. X *  terminals that have minimal (or nonexistant) terminal capabilities.
  996. X */
  997.  
  998. X#include <stdio.h>
  999. X#include <ctype.h>
  1000. X#include <sys/param.h>
  1001. X#include <sys/dir.h>
  1002. X#include <sys/user.h>
  1003. X#include <sys/proc.h>
  1004. X#include <sys/dk.h>
  1005. X#include "screen.h"        /* interface to screen package */
  1006. X#include "layout.h"        /* defines for screen position layout */
  1007. X#include "top.h"
  1008. X#include "boolean.h"
  1009.  
  1010. Xstatic int lmpid = 0;
  1011. Xstatic struct user u;
  1012.  
  1013. Xchar *printable();
  1014.  
  1015. X/* Verbose process state names */
  1016.  
  1017. Xchar *state_name[] =
  1018. X{
  1019. X    "", "sleeping", "ABANDONED", "running", "starting", "zombie", "stopped"
  1020. X};
  1021.  
  1022. X/* process state names for the "STATE" column of the display */
  1023.  
  1024. Xchar *state_abbrev[] =
  1025. X{
  1026. X    "", "sleep", "WAIT", "run", "start", "zomb", "stop"
  1027. X};
  1028.  
  1029. X/* cpu state names for percentages */
  1030.  
  1031. Xchar *cpu_state[] =
  1032. X{
  1033. X    "user", "nice", "system", "idle"
  1034. X};
  1035.  
  1036. X/* screen positions for cpustate figures */
  1037. Xchar x_cpustates[] = { 12, 24, 36, 50 };
  1038.  
  1039. Xi_loadave(mpid, avenrun)
  1040.  
  1041. Xint mpid;
  1042. X#ifdef sun
  1043. Xlong *avenrun;
  1044. X#else
  1045. Xdouble *avenrun;
  1046. X#endif sun
  1047.  
  1048. X{
  1049. X    register int i;
  1050.  
  1051. X    printf("last pid: %5d;  load averages", mpid);
  1052.  
  1053. X    for (i = 0; i < 3; i++)
  1054. X    {
  1055. X    printf("%c %4.2f",
  1056. X        i == 0 ? ':' : ',',
  1057. X#ifdef sun
  1058. X        (double)avenrun[i] / FSCALE);
  1059. X#else
  1060. X        avenrun[i]);
  1061. X#endif
  1062. X    }
  1063. X    lmpid = mpid;
  1064. X}
  1065.  
  1066. Xu_loadave(mpid, avenrun)
  1067.  
  1068. Xint mpid;
  1069. X#ifdef sun
  1070. Xlong *avenrun;
  1071. X#else
  1072. Xdouble *avenrun;
  1073. X#endif sun
  1074.  
  1075. X{
  1076. X    register int i;
  1077.  
  1078. X    if (mpid != lmpid);
  1079. X    {
  1080. X    Move_to(x_lastpid, y_lastpid);
  1081. X    printf("%5d", mpid);
  1082. X    lmpid = mpid;
  1083. X    }
  1084.  
  1085. X    Move_to(x_loadave, y_loadave);
  1086. X    for (i = 0; i < 3; i++)
  1087. X    {
  1088. X    printf("%s%4.2f",
  1089. X        i == 0 ? "" : ", ",
  1090. X#ifdef sun
  1091. X        (double)avenrun[i] / FSCALE);
  1092. X#else
  1093. X        avenrun[i]);
  1094. X#endif
  1095. X    }
  1096. X}
  1097.  
  1098. Xstatic int ltotal = 0;
  1099. Xstatic int lbrkdn[7];
  1100.  
  1101. Xi_procstates(total, brkdn)
  1102.  
  1103. Xint total;
  1104. Xint *brkdn;
  1105.  
  1106. X{
  1107. X    register int i;
  1108.  
  1109. X    printf("%2d processes", total);    /* ??? */
  1110. X    ltotal = total;
  1111. X    for (i = 1; i < 7; i++)
  1112. X    {
  1113. X    if (brkdn[i] != 0)
  1114. X    {
  1115. X        printf("%c %d %s%s",
  1116. X            i == 1 ? ':' : ',',
  1117. X            brkdn[i],
  1118. X            state_name[i],
  1119. X            (i == SZOMB) && (brkdn[i] > 1) ? "s" : "");
  1120. X    }
  1121. X    }
  1122. X    bcopy(brkdn, lbrkdn, sizeof(lbrkdn));
  1123. X}
  1124.  
  1125. Xu_procstates(total, brkdn)
  1126.  
  1127. Xint total;
  1128. Xint *brkdn;
  1129.  
  1130. X{
  1131. X    register int i;
  1132.  
  1133. X    if (ltotal != total)
  1134. X    {
  1135. X    Move_to(x_procstate, y_procstate);
  1136. X    printf("%d ", total);
  1137. X    ltotal = total;
  1138. X    }
  1139. X    else if (bcmp(brkdn, lbrkdn, sizeof(lbrkdn)) == 0)
  1140. X    {
  1141. X    return;
  1142. X    }
  1143.  
  1144. X    Move_to(x_brkdn, y_brkdn);
  1145. X    for (i = 1; i < 7; i++)
  1146. X    {
  1147. X    if (brkdn[i] != 0)
  1148. X    {
  1149. X        printf("%s%d %s%s",
  1150. X            i == 1 ? "" : ", ",
  1151. X            brkdn[i],
  1152. X            state_name[i],
  1153. X            (i == SZOMB) && (brkdn[i] > 1) ? "s" : "");
  1154. X    }
  1155. X    }
  1156. X    putcap(clear_line);
  1157. X    bcopy(brkdn, lbrkdn, sizeof(lbrkdn));
  1158. X}
  1159.  
  1160. Xi_cpustates(changes, total)
  1161.  
  1162. Xint *changes;
  1163. Xint total;
  1164.  
  1165. X{
  1166. X    register int i;
  1167.  
  1168. X    printf("\nCpu states: ");
  1169. X    for (i = 0; i < CPUSTATES; i++)
  1170. X    {
  1171. X    printf("%s%4.1f%% %s",
  1172. X        i == 0 ? "" : ", ",
  1173. X        ((float)changes[i] / (float)total) * 100.0,
  1174. X        cpu_state[i]);
  1175. X    }
  1176. X    printf("\n");
  1177. X}
  1178.  
  1179. Xu_cpustates(changes, total)
  1180.  
  1181. Xint *changes;
  1182. Xint total;
  1183.  
  1184. X{
  1185. X    register int i;
  1186.  
  1187. X    for (i = 0; i < CPUSTATES; i++)
  1188. X    {
  1189. X    Move_to(x_cpustates[i], y_cpustates);
  1190. X    printf("%4.1f",
  1191. X        ((float)changes[i] / (float)total) * 100.0);
  1192. X    }
  1193. X}
  1194.  
  1195. Xz_cpustates()
  1196.  
  1197. X{
  1198. X    register int i;
  1199.  
  1200. X    printf("\nCpu states: ");
  1201. X    for (i = 0; i < CPUSTATES; i++)
  1202. X    {
  1203. X    printf("%s    %% %s", i == 0 ? "" : ", ", cpu_state[i]);
  1204. X    }
  1205. X    printf("\n");
  1206. X}
  1207.  
  1208. Xi_memory(i1, i2, i3, i4, i5)
  1209.  
  1210. Xint i1, i2, i3, i4, i5;
  1211.  
  1212. X{
  1213. X    printf("Memory: %4dK (%4dK) real, %4dK (%4dK) virtual, %4dK free",
  1214. X    i1, i2, i3, i4, i5);
  1215. X}
  1216.  
  1217. Xu_memory(i1, i2, i3, i4, i5)
  1218.  
  1219. Xint i1, i2, i3, i4, i5;
  1220.  
  1221. X{
  1222. X    Move_to(x_realmem, y_mem);
  1223. X    printf("%4dK (%4d", i1, i2);
  1224. X    Move_to(x_virtmem, y_mem);
  1225. X    printf("%4dK (%4d", i3, i4);
  1226. X    Move_to(x_free, y_mem);
  1227. X    printf("%4d", i5);
  1228. X}
  1229.  
  1230. Xi_header(f2)
  1231.  
  1232. Xchar *f2;
  1233.  
  1234. X{
  1235. X    printf(
  1236. X      "\n\n  PID %s PRI NICE   SIZE   RES STATE   TIME   WCPU    CPU COMMAND", 
  1237. X      f2);
  1238. X}
  1239.  
  1240. Xu_header()
  1241.  
  1242. X{
  1243. X    Move_to(0, y_header);
  1244. X}
  1245.  
  1246. X#ifdef sun
  1247. X#define percent_cpu(pp) ((double)(pp)->p_pctcpu / FSCALE)
  1248. X#else
  1249. X#define percent_cpu(pp) ((pp)->p_pctcpu)
  1250. X#endif
  1251.  
  1252. X#define weighted_cpu(pct, pp) ((pp)->p_time == 0 ? 0.0 : \
  1253. X             ((pct) / (1.0 - exp((pp)->p_time * logcpu))))
  1254.  
  1255. X#define Proc_format "%5d %-8.8s %3d %4d%6dK %4dK %-5s%4d:%02d %5.2f%% %5.2f%% %.14s"
  1256.  
  1257. X#ifdef DEBUG
  1258. XFILE *debug;
  1259. X#endif
  1260.  
  1261. Xi_process(line, pp, get_userid)
  1262.  
  1263. Xint line;
  1264. Xstruct proc *pp;
  1265. Xchar *(*get_userid)();
  1266.  
  1267. X{
  1268. X    register long cputime;
  1269. X    register double pctcpu;
  1270. X    register char *thisline;
  1271. X    int len;
  1272.  
  1273. X#ifdef DEBUG
  1274. X    debug = fopen("debug", "w");
  1275. X#endif
  1276. X    /* calculate a pointer to the buffer for this line */
  1277. X    thisline = screenbuf[line];
  1278.  
  1279. X    /* get the cpu usage and calculate the cpu percentages */
  1280. X    cputime = get_ucpu(pp);
  1281. X    pctcpu = percent_cpu(pp);
  1282.  
  1283. X    /* format the line */
  1284. X    sprintf(thisline, Proc_format,
  1285. X    pp->p_pid,
  1286. X    (*get_userid)(pp->p_uid),
  1287. X    pp->p_pri - PZERO,
  1288. X    pp->p_nice - NZERO,
  1289. X#ifdef pyr
  1290. X    pagetok(pp->p_tsize + pp->p_dsize + pp->p_cssize + pp->p_ussize),
  1291. X#else
  1292. X    pagetok(pp->p_tsize + pp->p_dsize + pp->p_ssize),
  1293. X#endif
  1294. X    pagetok(pp->p_rssize),
  1295. X    state_abbrev[pp->p_stat],
  1296. X    cputime / 60l,
  1297. X    cputime % 60l,
  1298. X    100.0 * weighted_cpu(pctcpu, pp),
  1299. X    100.0 * pctcpu,
  1300. X    printable(u.u_comm));
  1301.  
  1302. X    /* write the line out */
  1303. X    putchar('\n');
  1304. X    fputs(thisline, stdout);
  1305.  
  1306. X    /* zero fill the rest of it */
  1307. X    len = strlen(thisline);
  1308. X    bzero(thisline + len, Display_width - len);
  1309. X}
  1310.  
  1311. Xstatic int lastline = 0;
  1312.  
  1313. Xu_process(line, pp, get_userid)
  1314.  
  1315. Xint line;
  1316. Xstruct proc *pp;
  1317. Xchar *(*get_userid)();
  1318.  
  1319. X{
  1320. X    register char *optr;
  1321. X    register char *nptr;
  1322. X    register int ch;
  1323. X    register int diff;
  1324. X    register int newcol = 1;
  1325. X    register int lastcol = 0;
  1326. X    register long cputime;
  1327. X    register double pctcpu;
  1328. X    char cursor_on_line = No;
  1329. X    char *thisline;
  1330. X    int screen_line = line + Header_lines;
  1331. X    static char newline[Display_width];
  1332.  
  1333. X    /* get a pointer to the old text for this line */
  1334. X    optr = thisline = screenbuf[line];
  1335.  
  1336. X    /* get the cpu usage and calculate the cpu percentages */
  1337. X    cputime = get_ucpu(pp);
  1338. X    pctcpu = percent_cpu(pp);
  1339.  
  1340. X    /* format the line */
  1341. X    sprintf(newline, Proc_format,
  1342. X    pp->p_pid,
  1343. X    (*get_userid)(pp->p_uid),
  1344. X    pp->p_pri - PZERO,
  1345. X    pp->p_nice - NZERO,
  1346. X#ifdef pyr
  1347. X    pagetok(pp->p_tsize + pp->p_dsize + pp->p_cssize + pp->p_ussize),
  1348. X#else
  1349. X    pagetok(pp->p_tsize + pp->p_dsize + pp->p_ssize),
  1350. X#endif
  1351. X    pagetok(pp->p_rssize),
  1352. X    state_abbrev[pp->p_stat],
  1353. X    cputime / 60l,
  1354. X    cputime % 60l,
  1355. X    100.0 * weighted_cpu(pctcpu, pp),
  1356. X    100.0 * pctcpu,
  1357. X    printable(u.u_comm));
  1358.  
  1359. X    /* compare the two strings and only rewrite what has changed */
  1360. X    nptr = newline;
  1361. X#ifdef DEBUG
  1362. X    fputs(optr, debug);
  1363. X    fputc('\n', debug);
  1364. X    fputs(nptr, debug);
  1365. X    fputs("\n-\n", debug);
  1366. X#endif
  1367.  
  1368. X    /* start things off on the right foot            */
  1369. X    /* this is to make sure the invariants get set up right */
  1370. X    if ((ch = *nptr++) != *optr)
  1371. X    {
  1372. X    if (screen_line - lastline == 1)
  1373. X    {
  1374. X        putchar('\n');
  1375. X    }
  1376. X    else
  1377. X    {
  1378. X        Move_to(0, screen_line);
  1379. X    }
  1380. X    cursor_on_line = Yes;
  1381. X    putchar(ch);
  1382. X    *optr = ch;
  1383. X    lastcol = 1;
  1384. X    }
  1385. X    optr++;
  1386.  
  1387. X    /*
  1388. X     *  main loop -- check each character.  If the old and new aren't the
  1389. X     *    same, then update the display.  When the distance from the current
  1390. X     *    cursor position to the new change is small enough, the characters
  1391. X     *    that belong there are written to move the cursor over.
  1392. X     *
  1393. X     *    Invariants:
  1394. X     *        lastcol is the column where the cursor currently is sitting
  1395. X     *        (always one beyond the end of the last mismatch).
  1396. X     */
  1397. X    do        /* yes, a do...while */
  1398. X    {
  1399. X    if ((ch = *nptr++) != *optr)
  1400. X    {
  1401. X        /* new character is different from old      */
  1402. X        /* put the new character in the screen buffer */
  1403. X        *optr = ch;
  1404.  
  1405. X        /* make sure the cursor is on top of this character */
  1406. X        diff = newcol - lastcol;
  1407. X        if (diff > 0)
  1408. X        {
  1409. X        /* some motion is required--figure out which is shorter */
  1410. X        if (diff < 6 && cursor_on_line)
  1411. X        {
  1412. X            /* overwrite old stuff--get it out of the screen buffer */
  1413. X            printf("%.*s", diff, &thisline[lastcol]);
  1414. X        }
  1415. X        else
  1416. X        {
  1417. X            /* use cursor addressing */
  1418. X            Move_to(newcol, screen_line);
  1419. X            cursor_on_line = Yes;
  1420. X        }
  1421. X        /* remember where the cursor is */
  1422. X        lastcol = newcol + 1;
  1423. X        }
  1424. X        else
  1425. X        {
  1426. X        /* already there, update position */
  1427. X        lastcol++;
  1428. X        }
  1429.  
  1430. X        /* write what we need to */
  1431. X        if (ch == '\0')
  1432. X        {
  1433. X        /* at the end--terminate with a clear-to-end-of-line */
  1434. X        putcap(clear_line);
  1435. X        }
  1436. X        else
  1437. X        {
  1438. X        /* write the new character */
  1439. X        putchar(ch);
  1440. X        }
  1441. X    }
  1442.  
  1443. X    /* update working column and screen buffer pointer */
  1444. X    newcol++;
  1445. X    optr++;
  1446.  
  1447. X    } while (ch != '\0');
  1448.  
  1449. X    /* zero out the rest of the line buffer -- MUST BE DONE! */
  1450. X    bzero(optr, Display_width - newcol);
  1451.  
  1452. X    /* remember where the current line is */
  1453. X    if (cursor_on_line)
  1454. X    {
  1455. X    lastline = screen_line;
  1456. X    }
  1457. X}
  1458.  
  1459. Xstatic int last_hi = 0;
  1460.  
  1461. Xu_endscreen(hi)
  1462.  
  1463. Xregister int hi;
  1464.  
  1465. X{
  1466. X    register int screen_line = hi + Header_lines;
  1467.  
  1468. X    if (smart_terminal)
  1469. X    {
  1470. X    if (hi < last_hi)
  1471. X    {
  1472. X        if (hi == 0)
  1473. X        {
  1474. X        putchar('\n');
  1475. X        putchar('\n');
  1476. X        putcap(clear_line);
  1477. X        putchar('\n');
  1478. X        }
  1479. X        else if (screen_line - lastline == 1)
  1480. X        {
  1481. X        putchar('\n');
  1482. X        }
  1483. X        else
  1484. X        {
  1485. X        Move_to(0, screen_line);
  1486. X        }
  1487. X    
  1488. X        while (--last_hi > hi)
  1489. X        {
  1490. X        putcap(clear_line);
  1491. X        putchar('\n');
  1492. X        }
  1493. X        putcap(clear_line);
  1494. X    }
  1495. X    else
  1496. X    {
  1497. X        last_hi = hi;
  1498. X    }
  1499.  
  1500. X    /* move the cursor to a pleasant place */
  1501. X    Move_to(x_idlecursor, y_idlecursor);
  1502. X    }
  1503. X    else
  1504. X    {
  1505. X    /* separate this display from the next with some vertical room */
  1506. X    fputs("\n\n", stdout);
  1507. X    }
  1508. X}
  1509.  
  1510. X/*
  1511. X *  get_ucpu(pp) - retrieve the user structure associated with the proc
  1512. X *    structure pointed to by pp and return the cpu usage.  The user
  1513. X *    structure is stored in the global structure "u" for later use.
  1514. X */
  1515.  
  1516. Xget_ucpu(pp)
  1517.  
  1518. Xstruct proc *pp;
  1519.  
  1520. X{
  1521. X    if (getu(pp, &u) == -1)
  1522. X    {
  1523. X    strcpy(u.u_comm, "<swapped>");
  1524. X    return(0);
  1525. X    }
  1526. X    else
  1527. X    {
  1528. X    /* set u_comm for system processes */
  1529. X    if (u.u_comm[0] == '\0')
  1530. X    {
  1531. X        if (pp->p_pid == 0)
  1532. X        {
  1533. X        strcpy(u.u_comm, "Swapper");
  1534. X        }
  1535. X        else if (pp->p_pid == 2)
  1536. X        {
  1537. X        strcpy(u.u_comm, "Pager");
  1538. X        }
  1539. X    }
  1540.  
  1541. X#ifdef FOUR_ONE
  1542. X    return((int)((float)(u.u_vm.vm_utime + u.u_vm.vm_stime)/hz));
  1543. X#else
  1544. X    return(u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec);
  1545. X#endif
  1546. X    }
  1547. X}
  1548.  
  1549. X/*
  1550. X *  printable(str) - make the string pointed to by "str" into one that is
  1551. X *    printable (i.e.: all ascii), by converting all non-printable
  1552. X *    characters into '?'.  Replacements are done in place and a pointer
  1553. X *    to the original buffer is returned.
  1554. X */
  1555.  
  1556. Xchar *printable(str)
  1557.  
  1558. Xchar *str;
  1559.  
  1560. X{
  1561. X    register char *ptr;
  1562. X    register char ch;
  1563.  
  1564. X    ptr = str;
  1565. X    while ((ch = *ptr) != '\0')
  1566. X    {
  1567. X    if (!isprint(ch))
  1568. X    {
  1569. X        *ptr = '?';
  1570. X    }
  1571. X    ptr++;
  1572. X    }
  1573. X    return(str);
  1574. X}
  1575. @//E*O*F display.c//
  1576. chmod u=rw,g=rw,o=rw $OUT
  1577.  
  1578. echo x - getopt.c
  1579. if test -f getopt.c ; then
  1580.     echo getopt.c exists, putting output in $$getopt.c
  1581.     OUT=$$getopt.c
  1582.     STATUS=1
  1583. else
  1584.     OUT=getopt.c
  1585. fi
  1586. sed 's/^X//' > $OUT <<'@//E*O*F getopt.c//'
  1587. X/*LINTLIBRARY*/
  1588. X#define NULL    0
  1589. X#define EOF    (-1)
  1590. X#define ERR(s, c)    if(opterr){\
  1591. X    extern int strlen(), write();\
  1592. X    char errbuf[2];\
  1593. X    errbuf[0] = c; errbuf[1] = '\n';\
  1594. X    (void) write(2, argv[0], (unsigned)strlen(argv[0]));\
  1595. X    (void) write(2, s, (unsigned)strlen(s));\
  1596. X    (void) write(2, errbuf, 2);}
  1597.  
  1598. X#define strchr index
  1599.  
  1600. Xextern int strcmp();
  1601. Xextern char *strchr();
  1602.  
  1603. Xint    opterr = 1;
  1604. Xint    optind = 1;
  1605. Xint    optopt;
  1606. Xchar    *optarg;
  1607.  
  1608. Xint
  1609. Xgetopt(argc, argv, opts)
  1610. Xint    argc;
  1611. Xchar    **argv, *opts;
  1612. X{
  1613. X    static int sp = 1;
  1614. X    register int c;
  1615. X    register char *cp;
  1616.  
  1617. X    if(sp == 1)
  1618. X        if(optind >= argc ||
  1619. X           argv[optind][0] != '-' || argv[optind][1] == '\0')
  1620. X            return(EOF);
  1621. X        else if(strcmp(argv[optind], "--") == NULL) {
  1622. X            optind++;
  1623. X            return(EOF);
  1624. X        }
  1625. X    optopt = c = argv[optind][sp];
  1626. X    if(c == ':' || (cp=strchr(opts, c)) == NULL) {
  1627. X        ERR(": unknown option, -", c);
  1628. X        if(argv[optind][++sp] == '\0') {
  1629. X            optind++;
  1630. X            sp = 1;
  1631. X        }
  1632. X        return('?');
  1633. X    }
  1634. X    if(*++cp == ':') {
  1635. X        if(argv[optind][sp+1] != '\0')
  1636. X            optarg = &argv[optind++][sp+1];
  1637. X        else if(++optind >= argc) {
  1638. X            ERR(": argument missing for -", c);
  1639. X            sp = 1;
  1640. X            return('?');
  1641. X        } else
  1642. X            optarg = argv[optind++];
  1643. X        sp = 1;
  1644. X    } else {
  1645. X        if(argv[optind][++sp] == '\0') {
  1646. X            sp = 1;
  1647. X            optind++;
  1648. X        }
  1649. X        optarg = NULL;
  1650. X    }
  1651. X    return(c);
  1652. X}
  1653. @//E*O*F getopt.c//
  1654. chmod u=rw,g=rw,o=rw $OUT
  1655.  
  1656. echo x - kernel.c
  1657. if test -f kernel.c ; then
  1658.     echo kernel.c exists, putting output in $$kernel.c
  1659.     OUT=$$kernel.c
  1660.     STATUS=1
  1661. else
  1662.     OUT=kernel.c
  1663. fi
  1664. sed 's/^X//' > $OUT <<'@//E*O*F kernel.c//'
  1665. X/*
  1666. X *  Top - a top users display for Berkeley Unix
  1667. X *  
  1668. X *  This file contains all the routines that retrieve values from
  1669. X *  kernel and user memory.
  1670. X */
  1671.  
  1672. X#include <stdio.h>
  1673. X#if defined(FOUR_ONE) || defined(pyr)
  1674. X#include <sys/pte.h>
  1675. X#else
  1676. X#include <machine/pte.h>
  1677. X#endif
  1678. X#include <sys/param.h>
  1679. X#include <sys/dir.h>
  1680. X#include <sys/user.h>
  1681. X#include <sys/proc.h>
  1682.  
  1683. X#include "top.local.h"
  1684.  
  1685. X/* useful externals */
  1686. Xextern int errno;
  1687. Xextern char *sys_errlist[];
  1688.  
  1689. Xstatic int kmem = -1;
  1690. Xstatic int mem = -1;
  1691.  
  1692. Xinit_kernel()
  1693. X{
  1694. X    /* open kmem and mem */
  1695. X    if ((kmem = open(KMEM, 0)) < 0)
  1696. X    {
  1697. X    perror(KMEM);
  1698. X    exit(20);
  1699. X    }
  1700. X    if ((mem = open(MEM, 0)) < 0)
  1701. X    {
  1702. X    perror(MEM);
  1703. X    exit(21);
  1704. X    }
  1705.  
  1706. X}
  1707.  
  1708. X/*
  1709. X *  getu(p, u) - get the user structure for the process whose proc structure
  1710. X *    is pointed to by p.  The user structure is put in the buffer pointed
  1711. X *    to by u.  Return 0 if successful, -1 on failure (such as the process
  1712. X *    being swapped out).
  1713. X */
  1714.  
  1715. Xgetu(p, u)
  1716.  
  1717. Xregister struct proc *p;
  1718. Xstruct user *u;
  1719.  
  1720. X{
  1721. X    struct pte uptes[UPAGES];
  1722. X    register caddr_t upage;
  1723. X    register struct pte *pte;
  1724. X    register nbytes, n;
  1725.  
  1726. X    /*
  1727. X     *  Check if the process is currently loaded or swapped out.  The way we
  1728. X     *  get the u area is totally different for the two cases.  For this
  1729. X     *  application, we just don't bother if the process is swapped out.
  1730. X     */
  1731. X    if ((p->p_flag & SLOAD) == 0)
  1732. X    {
  1733. X    return(-1);
  1734. X    }
  1735.  
  1736. X    /*
  1737. X     *  Process is currently in memory, we hope!
  1738. X     */
  1739. X    if (!getkval(p->p_addr, uptes, sizeof(uptes), "!p->p_addr"))
  1740. X    {
  1741. X    /* we can't seem to get to it, so pretend it's swapped out */
  1742. X    return(-1);
  1743. X    } 
  1744. X    upage = (caddr_t)u;
  1745. X    pte = uptes;
  1746. X    for (nbytes = sizeof(struct user); nbytes > 0; nbytes -= NBPG)
  1747. X    {
  1748. X        lseek(mem, pte++->pg_pfnum * NBPG, 0);
  1749. X    n = MIN(nbytes, NBPG);
  1750. X    if (read(mem, upage, n) != n)
  1751. X    {
  1752. X        /* we can't seem to get to it, so pretend it's swapped out */
  1753. X        return(-1);
  1754. X    }
  1755. X    upage += n;
  1756. X    }
  1757. X    return(0);
  1758. X}
  1759.  
  1760. X/*
  1761. X *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
  1762. X *    "offset" is the byte offset into the kernel for the desired value,
  1763. X *      "ptr" points to a buffer into which the value is retrieved,
  1764. X *      "size" is the size of the buffer (and the object to retrieve),
  1765. X *      "refstr" is a reference string used when printing error meessages,
  1766. X *        if "refstr" starts with a '!', then a failure on read will not
  1767. X *          be fatal (this may seem like a silly way to do things, but I
  1768. X *          really didn't want the overhead of another argument).
  1769. X *      
  1770. X */
  1771.  
  1772. Xgetkval(offset, ptr, size, refstr)
  1773.  
  1774. Xlong offset;
  1775. Xint *ptr;
  1776. Xint size;
  1777. Xchar *refstr;
  1778.  
  1779. X{
  1780. X    if (lseek(kmem, offset, 0) == -1)
  1781. X    {
  1782. X    if (*refstr == '!')
  1783. X    {
  1784. X        refstr++;
  1785. X    }
  1786. X    fprintf(stderr, "%s: lseek to %s: %s\n",
  1787. X        KMEM, refstr, sys_errlist[errno]);
  1788. X    quit(22);
  1789. X    }
  1790. X    if (read(kmem, ptr, size) == -1)
  1791. X    {
  1792. X    if (*refstr == '!')
  1793. X    {
  1794. X        /* we lost the race with the kernel, process isn't in memory */
  1795. X        return(0);
  1796. X    } 
  1797. X    else 
  1798. X    {
  1799. X        fprintf(stderr, "%s: reading %s: %s\n",
  1800. X        KMEM, refstr, sys_errlist[errno]);
  1801. X        quit(23);
  1802. X    }
  1803. X    }
  1804. X    return(1);
  1805. X}
  1806. @//E*O*F kernel.c//
  1807. chmod u=rw,g=rw,o=rw $OUT
  1808.  
  1809. echo x - layout.h
  1810. if test -f layout.h ; then
  1811.     echo layout.h exists, putting output in $$layout.h
  1812.     OUT=$$layout.h
  1813.     STATUS=1
  1814. else
  1815.     OUT=layout.h
  1816. fi
  1817. sed 's/^X//' > $OUT <<'@//E*O*F layout.h//'
  1818. X/*
  1819. X *  Top - a top users display for Berkeley Unix
  1820. X *
  1821. X *  This file defines the locations on tne screen for various parts of the
  1822. X *  display.  These definitions are used by the routines in "display.c" for
  1823. X *  cursor addressing.
  1824. X */
  1825.  
  1826. X#define  x_lastpid    10
  1827. X#define  y_lastpid    0
  1828. X#define  x_loadave    33
  1829. X#define  y_loadave    0
  1830. X#define  x_procstate    0
  1831. X#define  y_procstate    1
  1832. X#define  x_brkdn    14
  1833. X#define  y_brkdn    1
  1834. X#define  x_realmem    8
  1835. X#define  x_virtmem    28
  1836. X#define  x_free        51
  1837. X#define  y_mem        3
  1838. X#define  x_header    0
  1839. X#define  y_header    5
  1840. X#define  x_idlecursor    0
  1841. X#define  y_idlecursor    4
  1842. X#define  y_procs    6
  1843. X#define  x_p_pid    0
  1844. X#define  x_p_user    6
  1845. X#define  x_p_pri    15
  1846. X#define  x_p_nice    20
  1847. X#define  x_p_size    25
  1848. X#define  x_p_res    31
  1849. X#define  x_p_state    37
  1850. X#define  x_p_time    43
  1851. X#define  x_p_wcpu    50
  1852. X#define  x_p_cpu    57
  1853. X#define  x_p_command    64
  1854.  
  1855. X#define  y_cpustates    2
  1856. @//E*O*F layout.h//
  1857. chmod u=rw,g=rw,o=rw $OUT
  1858.  
  1859. echo x - screen.c
  1860. if test -f screen.c ; then
  1861.     echo screen.c exists, putting output in $$screen.c
  1862.     OUT=$$screen.c
  1863.     STATUS=1
  1864. else
  1865.     OUT=screen.c
  1866. fi
  1867. sed 's/^X//' > $OUT <<'@//E*O*F screen.c//'
  1868. X/*
  1869. X *  Top - a top users display for Berkeley Unix
  1870. X *
  1871. X *  This file contains the routines that interface to termcap and stty/gtty.
  1872. X */
  1873.  
  1874. X#include <stdio.h>
  1875. X#include <sgtty.h>
  1876. X#include "screen.h"
  1877. X#include "boolean.h"
  1878.  
  1879. Xextern char *myname;
  1880.  
  1881. Xint putstdout();
  1882.  
  1883. Xint  scrolls;
  1884. Xint  hardcopy;
  1885. Xint  screen_length;
  1886. Xint  screen_width;
  1887. Xchar ch_erase;
  1888. Xchar ch_kill;
  1889. Xchar smart_terminal;
  1890. Xchar PC;
  1891. Xchar *tgetstr();
  1892. Xchar *tgoto();
  1893. Xchar termcap_buf[1024];
  1894. Xchar init_buf[1024];
  1895. Xchar string_buffer[1024];
  1896. Xchar home[15];
  1897. Xchar lower_left[15];
  1898. Xchar *clear_line;
  1899. Xchar *clear_screen;
  1900. Xchar *cursor_motion;
  1901. Xchar *start_standout;
  1902. Xchar *end_standout;
  1903. Xchar *terminal_init;
  1904. Xchar *terminal_end;
  1905. Xshort ospeed;
  1906.  
  1907. Xstatic struct sgttyb old_settings;
  1908. Xstatic struct sgttyb new_settings;
  1909. Xstatic char is_a_terminal = No;
  1910.  
  1911. Xinit_termcap()
  1912.  
  1913. X{
  1914. X    char *bufptr;
  1915. X    char *PCptr;
  1916. X    char *term_name;
  1917. X    char *temp_ptr;
  1918. X    char *getenv();
  1919. X    int status;
  1920.  
  1921. X    /* assume we have a smart terminal until proven otherwise */
  1922. X    smart_terminal = Yes;
  1923.  
  1924. X    /* now get terminal name and termcap entry */
  1925. X    term_name = getenv("TERM");
  1926. X    if ((status = tgetent(termcap_buf, term_name)) != 1)
  1927. X    {
  1928. X    if (status == -1)
  1929. X    {
  1930. X        fprintf(stderr, "%s: can't open termcap file\n", myname);
  1931. X    }
  1932. X    else
  1933. X    {
  1934. X        fprintf(stderr, "%s: no termcap entry for a `%s' terminal\n",
  1935. X            myname, getenv("TERM"));
  1936. X    }
  1937.  
  1938. X    /* pretend it's dumb and proceed */
  1939. X    smart_terminal = No;
  1940. X    return;
  1941. X    }
  1942.  
  1943. X    /* these immediately indicate a very stupid terminal */
  1944. X    if (tgetflag("hc") || tgetflag("os"))
  1945. X    {
  1946. X    smart_terminal = No;
  1947. X    return;
  1948. X    }
  1949.  
  1950. X    /* set up common terminal capabilities */
  1951. X    if ((screen_length = tgetnum("li")) <= 0)
  1952. X    {
  1953. X    screen_length = smart_terminal = 0;
  1954. X    return;
  1955. X    }
  1956.  
  1957. X    /* screen_width is a little different */
  1958. X    if ((screen_width = tgetnum("co")) == -1)
  1959. X    {
  1960. X    screen_width = 79;
  1961. X    }
  1962. X    else
  1963. X    {
  1964. X    screen_width -= 1;
  1965. X    }
  1966.  
  1967. X    /* initialize the pointer into the termcap string buffer */
  1968. X    bufptr = string_buffer;
  1969.  
  1970. X    /* get necessary capabilities */
  1971. X    if ((clear_line    = tgetstr("ce", &bufptr)) == NULL ||
  1972. X    (clear_screen  = tgetstr("cl", &bufptr)) == NULL ||
  1973. X    (cursor_motion = tgetstr("cm", &bufptr)) == NULL)
  1974. X    {
  1975. X    smart_terminal = No;
  1976. X    return;
  1977. X    }
  1978.  
  1979. X    /* get some more sophisticated stuff -- these are optional */
  1980. X    terminal_init  = tgetstr("ti", &bufptr);
  1981. X    terminal_end   = tgetstr("te", &bufptr);
  1982. X    start_standout = tgetstr("so", &bufptr);
  1983. X    end_standout   = tgetstr("se", &bufptr);
  1984.  
  1985. X    /* pad character */
  1986. X    PC = (PCptr = tgetstr("pc", &bufptr)) ? *PCptr : 0;
  1987.  
  1988. X    /* set convenience strings */
  1989. X    strcpy(home, tgoto(cursor_motion, 0, 0));
  1990. X    strcpy(lower_left, tgoto(cursor_motion, 0, screen_length - 1));
  1991.  
  1992. X    /* if stdout is not a terminal, pretend we are a dumb terminal */
  1993. X    if (gtty(1, &old_settings) == -1)
  1994. X    {
  1995. X    smart_terminal = No;
  1996. X    }
  1997. X}
  1998.  
  1999. Xinit_screen()
  2000.  
  2001. X{
  2002. X    /* get the old settings for safe keeping */
  2003. X    if (gtty(1, &old_settings) == 0)
  2004. X    {
  2005. X    /* copy the settings so we can modify them */
  2006. X    new_settings = old_settings;
  2007.  
  2008. X    /* turn on CBREAK and turn off character echo and tab expansion */
  2009. X    new_settings.sg_flags |= CBREAK;
  2010. X    new_settings.sg_flags &= ~(ECHO|XTABS);
  2011. X    stty(1, &new_settings);
  2012.  
  2013. X    /* remember the erase and kill characters */
  2014. X    ch_erase = old_settings.sg_erase;
  2015. X    ch_kill  = old_settings.sg_kill;
  2016.  
  2017. X    /* remember that it really is a terminal */
  2018. X    is_a_terminal = Yes;
  2019.  
  2020. X    /* send the termcap initialization string */
  2021. X    putcap(terminal_init);
  2022. X    }
  2023. X    else
  2024. X    {
  2025. X    /* not a terminal at all---consider it dumb */
  2026. X    smart_terminal = No;
  2027. X    }
  2028. X}
  2029.  
  2030. Xend_screen()
  2031.  
  2032. X{
  2033. X    /* move to the lower left, clear the line and send "te" */
  2034. X    if (smart_terminal)
  2035. X    {
  2036. X    putcap(lower_left);
  2037. X    putcap(clear_line);
  2038. X    putcap(terminal_end);
  2039. X    }
  2040.  
  2041. X    /* if we have settings to reset, then do so */
  2042. X    if (is_a_terminal)
  2043. X    {
  2044. X    stty(1, &old_settings);
  2045. X    }
  2046. X}
  2047.  
  2048. Xreinit_screen()
  2049.  
  2050. X{
  2051. X    /* install our settings if it is a terminal */
  2052. X    if (is_a_terminal)
  2053. X    {
  2054. X    stty(1, &new_settings);
  2055. X    }
  2056.  
  2057. X    /* send init string */
  2058. X    if (smart_terminal)
  2059. X    {
  2060. X    putcap(terminal_init);
  2061. X    }
  2062. X}
  2063.  
  2064. Xstandout(fmt, a1, a2, a3)
  2065.  
  2066. Xchar *fmt;
  2067. Xint a1, a2, a3;
  2068.  
  2069. X{
  2070. X    if (smart_terminal)
  2071. X    {
  2072. X    putcap(start_standout);
  2073. X    printf(fmt, a1, a2, a3);
  2074. X    putcap(end_standout);
  2075. X    }
  2076. X    else
  2077. X    {
  2078. X    printf(fmt, a1, a2, a3);
  2079. X    }
  2080. X}
  2081.  
  2082. Xclear()
  2083.  
  2084. X{
  2085. X    if (smart_terminal)
  2086. X    {
  2087. X    putcap(clear_screen);
  2088. X    }
  2089. X}
  2090.  
  2091. X/* This has to be defined as a subroutine for tputs (instead of a macro) */
  2092.  
  2093. Xputstdout(ch)
  2094.  
  2095. Xchar ch;
  2096.  
  2097. X{
  2098. X    putchar(ch);
  2099. X}
  2100.  
  2101. @//E*O*F screen.c//
  2102. chmod u=rw,g=rw,o=rw $OUT
  2103.  
  2104. echo x - screen.h
  2105. if test -f screen.h ; then
  2106.     echo screen.h exists, putting output in $$screen.h
  2107.     OUT=$$screen.h
  2108.     STATUS=1
  2109. else
  2110.     OUT=screen.h
  2111. fi
  2112. sed 's/^X//' > $OUT <<'@//E*O*F screen.h//'
  2113. X/*
  2114. X *  top - a top users display for Unix 4.2
  2115. X *
  2116. X *  This file contains all the definitions necessary to use the hand-written
  2117. X *  screen package in "screen.c"
  2118. X */
  2119.  
  2120. X#define TCputs(str)    tputs(str, 1, putstdout)
  2121. X#define putcap(str)    ((str) != NULL ? TCputs(str) : 0)
  2122. X#define Move_to(x, y)    TCputs(tgoto(cursor_motion, x, y))
  2123.  
  2124. Xextern char ch_erase;        /* set to the user's erase character */
  2125. Xextern char ch_kill;        /* set to the user's kill  character */
  2126. Xextern char smart_terminal;     /* set if the terminal has sufficient termcap
  2127. X                   capabilities for normal operation */
  2128.  
  2129. X/* These aresome termcap strings for use outside of "screen.c" */
  2130. Xextern char *cursor_motion;
  2131. Xextern char *clear_line;
  2132.  
  2133. X/* rows and columns on the screen according to termcap */
  2134. Xextern int  screen_length;
  2135. Xextern int  screen_width;
  2136.  
  2137. X/* a function that puts a single character on stdout */
  2138. Xint putstdout();
  2139. @//E*O*F screen.h//
  2140. chmod u=rw,g=rw,o=rw $OUT
  2141.  
  2142. echo x - sigconv.awk
  2143. if test -f sigconv.awk ; then
  2144.     echo sigconv.awk exists, putting output in $$sigconv.awk
  2145.     OUT=$$sigconv.awk
  2146.     STATUS=1
  2147. else
  2148.     OUT=sigconv.awk
  2149. fi
  2150. sed 's/^X//' > $OUT <<'@//E*O*F sigconv.awk//'
  2151. XBEGIN        {
  2152. X            print "/* This file was automatically generated */"
  2153. X            print "/* by the awk script \"sigconv.awk\".      */\n"
  2154. X            print "struct sigdesc {"
  2155. X            print "    char *name;"
  2156. X            print "    int  number;"
  2157. X            print "};\n"
  2158. X            print "struct sigdesc sigdesc[] = {"
  2159. X        }
  2160.  
  2161. X/^#define[ \t][ \t]*SIG[A-Z]/    {
  2162. X                    printf "    \"%s\",\t%2d,\n", \
  2163. X                    substr($2, 4), $3
  2164. X                }
  2165.  
  2166. XEND                {
  2167. X                    print "    NULL,\t 0\n};"
  2168. X                }
  2169. @//E*O*F sigconv.awk//
  2170. chmod u=rw,g=rw,o=rw $OUT
  2171.  
  2172. echo x - top.h
  2173. if test -f top.h ; then
  2174.     echo top.h exists, putting output in $$top.h
  2175.     OUT=$$top.h
  2176.     STATUS=1
  2177. else
  2178.     OUT=top.h
  2179. fi
  2180. sed 's/^X//' > $OUT <<'@//E*O*F top.h//'
  2181. X/*
  2182. X *  Top - a top users display for Berkeley Unix
  2183. X *
  2184. X *  General (global) definitions
  2185. X */
  2186.  
  2187. X/* Number of lines of header information on the standard screen */
  2188. X#define Header_lines    6
  2189.  
  2190. X/* Number of columns needed for display */
  2191. X#define Display_width    80
  2192.  
  2193. X/* Log base 2 of 1024 is 10 (2^10 == 1024) */
  2194. X#define LOG1024        10
  2195.  
  2196. X/* Convert clicks (kernel pages) to kbytes ... */
  2197. X/* If there is no PGSHIFT defined, assume it is 11 */
  2198. X/* Is this needed for compatability with some old flavor of 4.2 or 4.1? */
  2199. X#ifndef PGSHIFT
  2200. X#define pagetok(size)    ((size) << 1)
  2201. X#else
  2202. X#if PGSHIFT>10
  2203. X#define pagetok(size)    ((size) << (PGSHIFT - LOG1024))
  2204. X#else
  2205. X#define pagetok(size)    ((size) >> (LOG1024 - PGSHIFT))
  2206. X#endif
  2207. X#endif
  2208.  
  2209. Xextern double logcpu;
  2210.  
  2211. Xdouble log();
  2212. Xdouble exp();
  2213.  
  2214. Xextern char (* screenbuf)[Display_width];
  2215. @//E*O*F top.h//
  2216. chmod u=rw,g=rw,o=rw $OUT
  2217.  
  2218. echo Inspecting for damage in transit...
  2219. temp=/tmp/sharin$$; dtemp=/tmp/sharout$$
  2220. trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
  2221. cat > $temp <<\!!!
  2222.      125    1165    6805 Changes
  2223.       96     461    2875 Makefile
  2224.       18      18     161 Manifest
  2225.       97     888    5259 README
  2226.        5      22     125 boolean.h
  2227.       43     131     789 bzero.c
  2228.      449    1382    8905 commands.c
  2229.      590    1631   11346 display.c
  2230.       66     182    1259 getopt.c
  2231.      141     497    3092 kernel.c
  2232.       38     129     845 layout.h
  2233.      233     604    4485 screen.c
  2234.       26     135     874 screen.h
  2235.       18      58     439 sigconv.awk
  2236.       34     132     794 top.h
  2237.     1979    7435   48053 total
  2238. !!!
  2239. 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
  2240. if test -s $dtemp ; then
  2241.     echo "Ouch [diff of wc output]:"
  2242.     cat $dtemp
  2243.     STATUS=1
  2244. elif test $STATUS = 0 ; then
  2245.     echo "No problems found."
  2246. else
  2247.     echo "WARNING -- PROBLEMS WERE FOUND..."
  2248. fi
  2249. exit $STATUS
  2250.