Index: head/contrib/top/ADVERTISEMENT =================================================================== --- head/contrib/top/ADVERTISEMENT +++ head/contrib/top/ADVERTISEMENT @@ -1,28 +0,0 @@ - William LeFebvre - Group sys Consulting - wnl@groupsys.com - +1-770-813-3224 - - -William LeFebvre is available for consulting and teaching engagements -through the company Group sys Consulting. William's specialties are: - - Unix system administration issues - Local area network design - Design of safe connections to the Internet - Domain Name Service - Threaded programming with pthreads - Netscape Server API plugins - INN news server configuration - SunOS to Solaris migration - Troubleshooting - - -Although located in the Atlanta metropolitan area, William can easily -travel to any location in the United States and Canada. Trips to -other countries can be arranged as well. - -If you are interested in having William work for your organization, -contact him at +1-770-813-3224 or via the address "wnl@groupsys.com". -You may also wish to visit the Group sys web page at www.groupsys.com. - Index: head/contrib/top/Changes =================================================================== --- head/contrib/top/Changes +++ head/contrib/top/Changes @@ -1,632 +0,0 @@ -Thu Mar 30 2000 - wnl (3.5beta12) - Updated modules: m_aix41.c, m_aix43.c, m_mtxinu.c, m_sco5.c, - and m_ultrix4.c. - Included m_irixsgi.c from some source that's been floating around - SGI. Don't yet know how it compares to m_irix62. - -Fri Mar 10 2000 - wnl (3.5beta11) - top.c: avoid potential loop if stdout gets closed, use macro - for p_active to avoid collision with system macros. - m_sunos5: widened some fields to accomodate 5.8. - m_decosf1: added ordering support - m_irix62_64: provides 64-bit module based on m_irix62. - m_irix62: skip bogus files in /proc directory - m_svr42MP and m_svr5: complete replacement with updated copies - m_mtxinu: complete replacement with updated copies - m_aix43: new module for 4.3 - getans: replaced with a Bourne shell script - -Mon Mar 6 2000 - wnl (3.5beta10) - m_sunos5.c: workaround for curses bug: ensure that TERMINFO has - a value. - -Fri Jan 15 1999 - wnl (3.5beta10) - top.c: now check return code from read to avoid looping on eof. - top.c: delay of 0 now only valid for root. - decosf1.c: patches from Rainer Orth should fix most of the - problems with this module (including the display of certain - processes and runtime errors). - sunos5.c: Rainer insisted on putting the slash back in the - state field ("run/4") and widened the field to accomodate it. - aix.c: widened PID field for 6-digit pids (shortened NICE field) - module macosx added, thanks to Andrew Townley. - -Fri Dec 18 1998 - wnl (3.5beta9) - Configure checks status of "make" and complains if it fails. - -Thu Dec 17 1998 - wnl (3.5beta9) - Added module sco5 from Mike Hopkirk. - Added module netbsd132 from moto kawasaki. - -Sun Oct 25 1998 - wnl (3.5beta9) - Added Casper's patches for sunos5 for the following: - produce same results as swap -s (5.5 and higher), - don't use system_pages kstat when /dev/kmem can be opened, - skip . and .. when reading /proc, replace use of SOLARIS24 - with OSREV. - -Fri Sep 11 1998 - wnl (3.5beta9) - Added workaround to getans for the absence of $< in SCO Unix. - -Wed Jul 1 1998 - wnl (3.5beta9) - Changed structure member "errno" to "errnum" in commands.c. - Replaced hpux10 module with one from John Haxby. - -Fri Apr 17 1998 - wnl (3.5beta8) - Moved definition of _KMEMUSER earlier in m_sunos5.c. This should - fix the compilation problem with gnu 2.7.2.3, obviating the need - for the fixinc.svr4 patch, but hopefully will not affect anything - else. - Added -DORDER to m_sunos4mp.c - -Tue Nov 18 1997 - wnl (3.5beta7) - Added gcc 2.7.2.3 patch for fixinc.svr4 and changed INSTALL and - FAQ to refer to it. - Added NetBSD HP9000 fix. Hopefully it doesn't break other - NetBSD platforms. - -Fri Oct 24 1997 - wnl (3.5beta7) - Modified m_dcosx.c to change uses of procdir to xprocdir, avoiding - a name clash with an include file (Bryn Parrott) - -Sat Oct 11 1997 - wnl (3.5beta6) - Incorporated Casper's patches for Solaris 2.6 and for the multi- - processor bug ("kstat finds too many cpus"). - -Sun Jan 20 1996 - wnl (3.5beta5) - Fixed Casper's m_sunos5 module: there was a poor interaction with - his use of OSREV and SunOS 5.5.1. - -Fri Dec 20 1996 - wnl (3.5beta4) - Replaced m_sunos5 with a reworked version by Casper Dik. This one - should work under 2.6 and may not require that top be run setuid - to root under 2.5 or 2.6. This also fixed a bug in m_sunos5 that - was introduced in beta3. - Fixed calculation of OSREV in Configure. - -Wed Nov 20 1996 - wnl (3.5beta3) - Incorporated contributed fixes to: bsdos2, irix62, freebsd20, - ultrix4, sunos5. Changed calculation of swap area in sunos5 (now - uses swapctl). sunos5 now understands idled processors. Changed - Configure to determine os revision using uname (when available) - and adding it to machine.c compiliation in Makefile as -DOSREV. - Changed calls to "exit" in modules to use "quit" instead. - -Oct 20 1996 - wnl (3.5beta3) - Removed "time" from list of ordering choices: there's no easy way - to get cpu time for all processes (it's in the u area). - -Fri Oct 18 1996 - wnl (3.5beta3) - hpux10 and hpux9: using a better means for determining when a - process is idle. - decosf1 now includes utils.h. - -Fri Sep 13 1996 - wnl (3.5beta2) - Fixed Configure to build Make.desc in such a way that doesn't - require a long argument to sed. - -Thu Sep 12 1996 - wnl (3.5beta2) - Fixed bug in display.c that affected empty cpustate names. - Created hpux1010 module - a variant of hpux10 that does not use - struct proc or struct user (suitable for HP/UX 10.10). - -Wed Sep 11 1996 - wnl (3.5beta2) - Changes to sunos5 module: Removed WCPU column since it is meaningless - on a SVR4-based system. Added THR column to show number of threads - for each process. This was not straightforward: the information is - not stored in prpsinfo but rather in prstatus. - -Tue Sep 10 1996 - wnl (3.5beta1) - Added patches for sunos4mp to provide order support. - Added irix62 module. - Changed prime.c to include stdio.h for printf prototype. - Added conditional code to os.h and utils.c to handle systems - where sys_errlist is defined in stdio.h (such as NetBSD). - -Mon Sep 09 1996 - wnl (3.5beta1) - Removed tar and shar rules from Makefile.X -- don't need them anymore. - Added -v option to display version number. Updated man page. - -Thu Aug 29 1996 - wnl (3.4) - Replaced modules (from Tim Pugh): next 32, next40. - Fixed bug in username.c: hashing negative uids. - -Thu Aug 22 1996 - wnl (3.4beta3) - Patched modules: ultrix4, sunos4, sunos5, utek, decosf1, irix5. - Added modules: next40, next32. - Fixed procstates update bug in display.c. - Fixed divide by zero bug in utils.c. - Fixed bad number in layout.h - Minor fixes to Configure. - Complete overhaul of FAQ. - -Tue Feb 13 1996 - wnl (3.4beta3) - Added convex module from Warren Vosper (originally written by - William Jones). - -Tue Feb 13 1996 - wnl (3.4beta2) - Fixed format_k in utils.c to calculate K and M values correctly. - Added check for gigabyte values ('G'). Changed sumamry_format - in display.c to use format_k where appropriate. - Changed creation of distribution tar file to place everything in - a top level directory. - -Tue Jan 30 1996 - wnl (3.4beta2) - Added m_aix41 module. Added new tag type to module comments: - TERMCAP, which defined the library to use for a termcap library. - If no TERMCAP tag is found in the module's initial comment, then - Configure will default to "-ltermcap". AIX needs this since it - put all the termcap routines in libcurses(!) - - Added m_bsdos2 (found lingering in my mailbox). - Updated m_svr4 to include support for NCR multiprocessors. - Fixed small bug in utils.c - -Thu Jan 25 1996 - wnl (3.4beta1) - Fixed m_sunos5 invocation of gettimeofday to include "NULL" as - second argument. This provides compatability with the Posix- - compliant template provided with SunOS 5.5, but doesn't hurt - previous versions since they do bother with a template for that - function. - - Made changes (recommended by net users) to hpux10, ultrix4, - netbsd10, aux3 (replaced aux31). Added module for linux. - -Fri Oct 10 1995 - wnl (3.4beta1) - Added user-contributed modules for SCO Unix, IRIX 5, HP/UX 10, - Pyramid DC/OSX. Changed Configure so that it runs in environments - whose c-shells have no 'eval'(!). Added support for multiple sort - ordering methods via the -o switch. This option requires support - from the machine dependent module: such support was added to - sunos5 (thus sunos54) and sunos4. - - display.c: Changed CPU states display line to shorten the leading - tag if the data won't fit in the current width. Fixed a divide-by- - zero bug that affected ultrasparc servers (and potentially other - systems). - - m_sunos5.c: Now asks the system for the correct pagesize rather than - assuming it is 4K. - -Thu Mar 2 1995 - wnl (3.3 RELEASE) - Added module netbsd10 and renamed netbsd to netbsd08. Changed - Configure so that it does not use an initial default module name. - Made other compatability fixes to Configure. Added comments to - decosf1 concerning optimizer bug. Other documentation changes. - Added use of "prime.c" to Configure script. - -Tue Feb 7 1995 - wnl (3.3beta6) - Still one more beta.... - Fixes for sunos5 2.4 gcc core dump (it was an alignment problem). - Fixed and improvements for decosf1 (including use of format_k - for proper SIZE column formatting). Added modules freebsd20 and - ncr3000. - -Thu Feb 2 1995 - wnl (3.3beta5) - One more beta.... - Fixed a few bugs in the sunos5 port pertaining to casting and - very large memory counts. Added "ifndef HAVE_GETOPT" to getopt.c - to provide for conditional compilation of the getopt function. - Those systems that have getopt in libc can add -DHAVE_GETOPT to - the CFLAGS line in the module to prevent the function from being - compiled. Added sunos54 module to accomodate SunOS 5.4 - peculiarities. Added module for aux3.1. - -Wed Jan 4 1995 - wnl (3.3beta4) - This is really taking too long......sigh. - Fixed SIGWINCH handling once and for all. It now remembers the - number of processes you want displayed even thru window resizes. - Fixed buffer conflict in utils.c (itoa and itoa7). - Lots of small improvements to the various modules were made over - the past month: too numberous to list here. SunOS 5 module made - more secure thru use of seteuid calls (other SVR4 modules should - be modified similarly). One final MP fix to sunos5, too. Module - for decosf1 was modified to accomodate V3.0. - -Mon Apr 18 1994 - wnl (3.3beta3) - I think I finally got a sunos5 module that will work on MP - machines. Fixed cpu states figure in osmp41a so that - percentages never exceed 100%. Added shell script "install" - since Unix vendors can't seem to make up their minds on what - options they want to use for the one that comes with the OS. - Added netbsd modules from Christos. Fixed lots of other little - things over the past few months that I have long since forgotten. - -Wed Dec 15 1993 - wnl (3.3beta2) - Added module patches from various users: hpux9, sunos5. - Fixed bug with batch mode (screen_width wasn't getting set). - Changes to accomodate 64 bit machines. - Fixed some bugs in command parsing ("renice 19 " did something - unexpected). - -Mon Aug 30 1993 - wnl (3.3beta) - Added lots of little patches from various users. - Added routines to utils.c for intelligent formatting of kilobytes - and time. These are intended to be used in the modules when - formatting a process line. Added code to "summary_format" in - display.c to do intelligent formatting of memory quantities. - Redid display.c to allow for varying line widths and dynamic - reallocation of the screen buffer. - Added a SIGWINCH handler to top.c! - Added a constant, MAX_COLS, to top.h which defines the absolute - widest line we will ever allow. Changed allocations of "char fmt" - in all machine modules to use this constant rather than an abitrary - number. - -Fri Aug 13 1993 - wnl (3.3) - Changed return value definition of time-related functions in top.c, - display.c, and m_ultrix4.c to time_t (stuart@coral.cs.jcu.edu.au). - Fixed bug in display.c: line_update when start != 0. - -Wed Aug 4 1993 - wnl (3.2 release) - Changes to Configure from Paul Vixie. Added modules for hpux9 and - bsd386. - -Tue Jul 13 1993 - wnl (3.1 release) - More small changes and minor bug fixes. Brought bsd44 up to date - and added a module for svr4.2. Changed shar packaging to use Rich - Salz's cshar stuff. - -Wed Jul 7 1993 - wnl (3.1BETA) - More changes and bug fixes to Configure. Applied some other - minor bug fixes and suggestions from the beta testers. Added - the "metatop" shell script and the "installmeta" rule to the - Makefile to make handling multiple machine models and OS versions - easier. Added INSTALL and FAQ files. - -Tue May 18 1993 - wnl (3.1BETA) - Changed Configure to be compatible with most SVR4 environments - (differing output from "ls -lg"). Also changed Configure, - Makefile.X, etc., to look for module files in the subdirectory - "machine" (thanks to Christos Zoulas). - -Tue Apr 20 1993 - wnl (3.1BETA) - Changed both occurences of "ls -1" in Configure to "ls". This - SHOULD produce the same result, and has the advantage that it - doesn't produce an error on a system 5 machine. Integrated other - changes recommended in the first round of beta testing. - -Wed Mar 10 1993 - wnl (3.1BETA) - MAJOR CHANGE: I have added a required function to all machine - dependent modules, called proc_owner. It takes a pid as an argument - and returns the uid of the process's owner. Such capability is - necessary for top to run securely as a set-uid program, something - that is needed for SVR4 implementations to read /proc. I have - retrofitted all modules except dgux with this function, but was - not able to test most of them. Top should now run securely as - a setuid program. Added 386bsd and sunos5 modules. Added sunos4mp - module for MP Suns. - -Sat Feb 20 1993 - wnl (3.1ALPHA) - Modified top.c and commands.c to compile correctly on System V - derived Unixes (especially SVR4), but in a way that doesn't rely - on an oracle-like declaration (that is, I don't use "ifdef SYSV"). - Fixed some bugs in "Configure" and "getans". Added inspection of - env variable "TOP" for options, and made -I default to showing - idle processes. Added "u" command to change username restriction - on the fly. Created shell script "suntop" for poor multi-version - SunOS folks (like myself). - -Wed Jun 3 1992 - wnl (3.0) - "max_topn" wasn't being used everywhere it was supposed to be - in top.c. Many cosmetic changes, including copyright notices in - all the .c files. Version number is now handled by version.c and - reflects the current patchlevel (which is initially set to 0). - Changed Configure and Makefile to allow configurable variables for - certain commands: shell, cc, awk, install. Updated README and - Porting. Ready to release to the world! - -Mon May 18 1992 - wnl (2.9BETA) - Added modules provided by Christos Zoulas. Replaced screen.c - with one modified by Christos and that will appropriately select - and handle the sgtty, termio, or termios system. Integrated many - other changes recommended by Christos. Fixed (I hope) the "-b" - batch mode display bug. Had to change loadavg to load_avg to avoid - a conflict with 4.4BSD. - -Mon Apr 27 1992 - wnl (2.8BETA) - Added modules provided by Daniel Trinkle. Added patchlevel.h, - but the patch level is not yet reflected in the version number. - Cleaned up m_sunos4.c a little. - -Wed Apr 22 1992 - wnl (2.8BETA) - Major internal reorganization. All of the system dependent stuff - is now really and truly separated from everything else. The - system dependent functions are contained in a separate .c file - called a "module". The Configure script knows how to find and - set up these modules, but the human installer still needs to tell - Configure which module to use (no automagic determination of - machine type---sorry). Added -U option to specify one user's - processes, but there is no corresponding command...yet. Other - changes and improvements too numerous to mention here. Currently - there are only two modules: sunos4 and umax. But after this beta - release is sent around, I expect more to be written. I just hope - that the machine-dependent abstractions don't need to change in - the process. - -Thu Mar 26 1992 - wnl (2.7BETA) - Beta release with minimal architecture support. Updated README - and added a first cut at a Porting guide. Added ioctl TIOCGWINSZ - code from top2.5+ (courtesy of David MacKenzie). I didn't even - try porting the Ultrix support since I don't have access to an - Ultrix machine. - -Fri Oct 11 1991 - wnl (2.6) - This version was not widely released. It contained many changes. - Here are the major ones: - - Put in Vixie's idle process hack. - - Enhanced type field in new_message to handle delayed messages. - - Changed u_process to automatically adjust for varying lines of - output. Management of screenbuf should now be completely contained - in display.c. Removed now extraneous code from CMD_number[12] - portion of command switch in top.c. This was the stuff that dealt - with zeroing out lines in screenbuf. - - Finally made it all work correctly on a 386i. Problems I had to - overcome: kvm_nlist doesn't return 0 on success as advertised (it - returns 1 instead); the results of a kvm_nlist are different - (n_type can be zero even for a symbol that exists). - - Serious rearrangement for processor dependent stuff. All nlists - are now in separate files with the suffix ".nlist". Most machine - specific code is in "machine.c" surrounded by appropriate ifdefs--- - the goal is to eventually have all machine specific code in this - file. Managed to find a way to detect SunOS 4.x at compile-time: - this is contained in the include file "sun.h". Completely changed - the memory display line for SunOS 4.x---it now displays a far - more appropriate report. - - Created the shell script "Configure" to aid in the configuration - step. - - Fixed a bug in init_termcap: it will now tolerate an environment - which does not have TERM defined (thanks to Sam Horrocks for - pointing this out). - -Tue Aug 9 1988 - wnl (2.5) - Added changes to make top work under version 4.0 of the Sun - operating system. Changes were provided by Scott Alexander of the - University of Pennsylvania. Thanks! Compile with "-Dsunos4" to - get them. Virtual memory statistics are not readily accessible - under 4.0, so they don't show up in the output. - -Thu Jul 31 1987 - wnl (2.4) - Fixed a problem with the 4.0 Pyramid code. The label "cp_time" - doesn't exist in the 4.0 kernel anymore. I think the code Carl - sent me wants "percpu" instead. That is what I am using and it - appears to work. 375 code is still untested (at least by me). - Also picked a great deal of lint out of the source. Lint now only - complains about a very few nitpicky things (there are far too many - calls to "printf" to put a "(void)" in front of!), at least under - SunOS. - -Tue Jul 28 1987 - wnl (2.4a) - Added changes for a Symmetrics Computer Systems s/375 machine. - Changes were provided by Paul Vixie. Thanks! According to Mr. - Vixie: "These changes were not made at, by, or for SCS proper. - SCS would probably be interested in them, but so far only the - users' group has them. They were made in February, 1987, to - version 2.1 of the program, by Paul Vixie - (dual!ptsfa!vixie!paul@ucbvax.Berkeley.EDU)." His changes were - integrated into version 2.3 to make version 2.4. - - The SCS peculiarities are summarized in Changes.scs. - -Tue Jun 9 1987 - wnl (2.3 for real) - Changed the includes for the extra code Carl sent me to only - compile on Version 4.0 Pyramid machines. This makes top still - compilable on pre-4.0 Pyramids. Specifically, this code is only - compiled when both "pyr" and "CPUFOUND" are defined. - -Wed Jun 3 1987 - wnl (2.3 with Pyramid additions) - It's been a month and I still haven't done anything about - distributing this version. However, Carl Gutekunst from Pyramid - has sent me some extra patches for some of the Pyramid code. I - just added those and will make them part of 2.3. This fixes the - following Pyramid problems: adds the inclusion of , - uses the correct size for getting the kernel value _ccpu (this bug - affected the Vax version as well), sums the elements of the percpu - array to calculate a cp_time value (for OSx 4.0). - -Fri May 1 1987 - wnl (2.3) - I have finally finished all the changes for better support of - oddbal terminals. Added the low-level routine "clear_eol" which - makes handling terminals without "ce" easy: it uses spaces - instead. All direct uses of "clear_line" outside of screen.c have - been changed to use this primitive. A terminal with "os" is now - handled in such that all situations that need overwriting are - completely avoided (including several commands). This required - some changes to the way commands are translated into action (in - "top.c"). Made several important changes to display.c to prevent - overflowing of any of the fields. Specifically, more than 99 - total processes and a cpu state that reaches 100%. Had to make a - small change to two casts in top.c, because the Sun 3.2 compiler - was giving warnings on them. Added the "-q" option which lets - root run top at a nice of -20 (in case he thinks he really needs it). - -Tue Dec 30 1986 - wnl (2.2) - I think I fixed a bug reported by Julian Onions at Nottingham. - Occasionally, top will core dump when the sprintf in either - i_process or u_process overflows due to an exceptionally - unrealistic time value. I think it highly unlikely that top can - get a bad proc structure (although I suppose it is possible), but - the process time is read from the user structure, and that can - sometimes be part garbage. So, "get_ucpu" checks the value it - returns to make sure its formatted form will not overflow the - sprintf. If this doesn't fix the bug, then more drastic measures - will be necessary. I plan to make this version the official - "top 2.2". [[ This version was never distributed very widely. ]] - -Tue Dec 2 1986 - wnl (2.2c) - Added to top.c the notion of a "failed command". When a command - produces a message (on the message line), an update does not - follow it. Before, the message was written and a new display was - shown---purposefully not overwriting the message. But the - improvements to handle overstriking terminals and terminals - without "ce" clear the screen before every display, which would - erase the message. Now, the message is displayed and top waits - another full time interval before updating the display. This - works much better all around. - -Mon Nov 24 1986 - wnl (2.2b) - Created a new file, utils.c, and made appropriate changes to - Makefile. This new file holds all utility functions that can and - may be used by more than one "module". Improved i_memory and - u_memory (display.c) so that screen updates for the values - displayed are only changed when necessary. Also made the line - look better: the last fixes made for a rather ugly display. - Added the locally defined constant "LoadMax" and added code to - top.c to send the cursor home after a space command is entered if - the load average is higher than "LoadMax". This provides visual - feedback on loaded systems. - -Mon Nov 3 1986 - wnl (2.2a) - Widened the format for memory usage so that it can display 5 - digits. This makes that line look a little ugly---maybe I'll fix - that later. Screen handling now understands "os" and a missing - "ce". It treats them identically: clear the screen between each - display. Screen handling code now uses "cd" when appropriate - (i.e.: when user has shortened the screen). Made i_loadave clear - then screen and took out most of the explicit calls to "clear" in - top.c. This method is cleaner, especially in conjunction with - "os" handling. Added preprocessor variable "RANDOM_PW" for - systems that access the passwd file randomly (Sun's yp and 4.3). - With "RANDOM_PW" set, "getpwuid" is used instead of "getpwnam", - but uid->username mappings are still hashed internally (because - that is still faster than going to disk). - -Mon Oct 6 1986 - wnl (2.1) - A bug with the kill command was pointed out by "dciem!tim"--- - specifying a signal by name did not work correctly. This bug has - been fixed with a simple change to commands.c. Another bug made - the cpu state percentages incorrect the first time they were - displayed. This bug has also been fixed (changed top.c). - -Thu Sep 4 1986 - wnl (2.0, at last) - This is the version that will (hopefully) get released to the - world as top 2.0. - Added the "r" and "k" commands for renice and kill, respectively. - This required adding a way to handle system call errors, and the - addition of the "e" command. Help screen and manual page were - changed to reflect this change. Changed all "#ifdef SUN" directives - to "#ifdef sun", and changed all "#ifdef PYRAMID" directives to - "#ifdef pyr". As much as I hate those choices of preprocessor - names (they too easily conflict with real variable names), it does - make automatic compilation possible---people don't have to change - the Makefile anymore for specific machines. The manual page was - changed to automatically incorporate the defaults as set in the - Makefile (including an infinite value for TOPN) and the way the - manual page is generated by the Makefile was changed to make - maintenance of this information automatic. - -Mon Jul 28 1986 - wnl (still pre 2.0) - Real close now. I put in a new definition for the macro "pagetok" - that does an explicit shift of a constant expression involving - PGSHIFT. Appropriate checks are made if PGSHIFT is to small. - "pagetok" is now used exclusively everywhere to convert kernel - clicks to kilobytes. I added a full blown interactive mode with - the ability to change some of the runtime parameters (how many to - display, time delay, etc.) while top is running. I also - incorporated a few ideas from the net: control characters in the - command name are replaced with '?'; the '-S' option makes the - swapper and pager visible; options have been added to control the - number of displays produced (this makes it easier to make - performance snapshots with top). I have also added the notion of - "infinite" values for number of processes and number of displays. - I fixed a long-standing bug in the uid to username mapping code - that was only aggravated on the pyramids: it was an ill-defined - expression (akin to i = i++). I tweaked the proc_compar routine - for qsort slightly so that stopped processes were more likely to - show up. Manual page was updated to reflect all changes - noticeable to the user. - -Tue Jul 1 1986 - wnl (pre 2.0 -- 1.9999?) - In the process of major revamping on the way to version 2.0. - I have completely done away with curses by adding my own screen - management routines in a separate file (screen.c). The rationale - for this is that top knows a whole lot more about what is and is - not redundant on the screen and can compare simple integer values - where curses would have to compare strings. This has turned out - to be a very big win speed-wise. The proc_compar routine for - sorting has been rewritten to include several more keys. I - decided this was necessary when I noticed that the "top" process - itself kept disappearing off the top 10 list on a Sun-3. All the - processes had the same percentage (0%) and the sort wasn't really - doing anything worthwhile. I changed the expression that computes - memory usage to use the ctob macro instead of just assuming that - pages were 512 bytes. More work still needs to be done before - this version is usable. I changed options-processing to use - getopt and added appropriate incantations to the Makefile. - -Wed Feb 20 1985 - wnl (still 1.8) - Put in the ifdef FOUR_ONE statements to make top still compilable - on a 4.1 system. Apparently, there are some users out there that - need this functionality. Oh well. I don't guarantee any of it, - since I can't test it. Made appropriate changes to README and - final installation related changes to Makefile. - -Sat Feb 2 1985 - wnl (1.8) - Removed all the ifdef FOUR_TWO statements and made "top" into a - 4.2 only program. If someone really wants to still run it on 4.1, - then they can do all the work. We don't have a 4.1 machine - anymore, so I don't even know if the thing still works under 4.1. - Cleaned up the Makefile and the README. Added installation rules - to the Makefile, as requested by several sites. Fixed a very - obscure divide-by-zero bug. Added a second "key" to the qsort - comparison function (proc_compar) so that comparisons are based on - cpu ticks if the percentages are equal (provided by Jonathon - Feiber at Sun). - -Tue Dec 11 1984 - wnl (1.7) - Added the virtual and real memory status line to the header area - (provided by Jonathon Feiber at Sun) - -Tue Nov 20 1984 - wnl (1.6) - Added an "exit" if sbrk's fail. Added changes from Jonathon - Feiber at Sun: ifdef SUN to make top work on Suns (they don't use - doubles in the proc structure), register declarations, check for - getting a user structure that has disappeared since the proc array - was read (it used to die, now it just shows the process as swapped). - -Tue Nov 13 1984 - wnl (1.5) - If the number of displayable processes ("active_procs") was less - than the number of requested processes ("topn"), top would - segmentation fault. This bug has been fixed. Thanks to Prentiss - Riddle at ut-sally for pointing out the existence of this bug. - -Tue Oct 23 1984 - wnl (1.4) - Finally fixed the hash table bug that caused processes owned by - root to sometimes appear with either no name or a different name - that had UID 0 (such as "operator"). Removed all the ifdef DEBUG - blocks to make top ready for distribution to the real world. - -Sun Apr 8 1984 - wnl (still 1.3) - Made some slight changes to the display format. It now looks more - aesthetically pleasing. Added some preprocessor constants so that - the two defaults (number of processes and seconds of delay) easier - to change. - -Thu Apr 5 1984 - wnl (1.3) - Changed the order in which things are done at initialization time. - This way, if an error occurs before starting the main loop, curses - will never get started. Also changed other error handlers so that - endwin() is called before any flavor of exit. Specifying a number - of processes that is more than the screen can handle is no longer - fatal. It displays a warning message and pretends the user - specified the maximum for the screen. Finally cured all the TSTP - blues (well, almost all). I removed my TSTP handler and convinced - the system to always use the one that curses sets up. Turns out - that "sleep" was stepping all over it during a pause. So, I don't - use sleep anymore. The only problem that remains with it now is - redrawing the old display before updating it after a pause. - -Tue Apr 3 1984 - wnl (from 1.0 to 1.2) - I changed the format of the TIME column from just "seconds" to - "minutes:seconds". I also made pausing work correctly. Screen - redraws with an up to date display. For compatibility with 4.2, I - changed the name of the "zero" function to "bzero". The makefile - has been altered to handle versions for 4.1 and 4.2, and README - has been updated to reflect these recent changes. Index: head/contrib/top/Configure =================================================================== --- head/contrib/top/Configure +++ head/contrib/top/Configure @@ -1,565 +0,0 @@ -#!/bin/csh -f -# -# Configuration script for top. -# -# Use with version 3.0 and higher. -# -set PRIME = "/usr/games/primes" -set vars = (module LoadMax topn NominalTopn delay owner group mode random \ - TableSize bindir mandir manext mansty \ - Cmdshell Cmdcc Cmdawk Cmdinstall cdefs) -set fastrack = 0 -set yesno = (no yes) - -onintr byebye - -# make sure that getans is there and ready -if (! -e getans) then - echo 'This package is not complete. The shell file "getans" is missing.' - exit 10 -endif -chmod +x getans - -if ($#argv > 0) then -# fast track configuration - set fastrack = 1 -else -cat <<'EOF' -Configuration for top, version 3.5 - -One moment.... -'EOF' -endif - -# collect file names and module names -ls machine/m_*.c >$$.f -ls machine/m_*.man >$$.m -sed -e 's@^machine/m_@@' -e 's/.c$//' $$.f >$$.n - -# build Make.desc -sed -e 's@\.c@.desc\\@' $$.f | sed -e '$s/\\//' >$$.a -sed -e "/^DESCS/r $$.a" Make.desc.X >Make.desc - -# build desc files and SYNOPSIS as needed -make -f Make.desc >/dev/null -if ($status != 0) then - echo "Unable to build the synopsis." - echo 'Make sure the command "make" is on your path and try' - echo 'running Configure again.' - exit 1 -endif - -if (-e .defaults) then - echo "" - echo "Reading configuration from last time..." - source .defaults - set nodefaults = 0 - if ($fastrack == 1) then - set module = $1 - endif -else - if ($fastrack == 1) then - echo "No previous configuration was found." - set fastrack = 0 - set module = $1 - else - set module = "" - endif - set LoadMax = 5.0 - set topn = 15 - set NominalTopn = 18 - set delay = 5 - set TableSize = 0 - set bindir = /usr/local/bin - set mandir = /usr/man/manl - set manext = l - set mansty = man - set nodefaults = 1 - set Cmdshell = /bin/sh - set Cmdawk = awk - set Cmdinstall = ./install - set Cmdcc = cc - set cdefs = -O -endif -echo "" - -if ($fastrack == 1) then - grep -s $module $$.n >/dev/null - if ($status != 0) then - echo "$module is not recognized. To see a list of available modules" - echo 'run "Configure" with no arguments.' - rm -f $$.[fmna] - exit 1 - endif - set random1 = `expr $random + 1` - cat </dev/null -if ($status != 0) then - echo "That is not a recognized module name." - goto getmod -endif - -# display a full description -sed -e '1,/DESCRIPTION:/d' -e '/^$/,$d' machine/m_${module}.desc - -# verify it -echo "" -./getans "Is this what you want to use?" yesno 1 .$$ -if (`cat .$$` == 0) then - goto getmod -endif -endif - -cat <<'EOF' - -First we need to find out a little bit about the executables needed to -compile top. - -'EOF' -./getans "What is the full path name for the Bourne shell" file "$Cmdshell" .$$ -set Cmdshell = `cat .$$` - -cat <<'EOF' - -Please supply the name of the appropriate command. It need not be a -full path name, but the named command does need to exist somewhere on -the current path. - -'EOF' -./getans "AWK Interpreter" path "$Cmdawk" .$$ -set Cmdawk = `cat .$$` -./getans "C Compiler" path "$Cmdcc" .$$ -set Cmdcc = `cat .$$` - -cat <<'EOF' - -The installer command needs to understand Berkeley-esque arguments: -"-o" for owner, "-g" for group, and "-m" for mode. A shell script -called "install" is distributed with top and is suitable for use by -top. You can specify a different program here if you like, or use -the shell script (the default). - -'EOF' -./getans "Installer" path "$Cmdinstall" .$$ -set Cmdinstall = `cat .$$` - -cat < 1) then - set rand = 1 - endif -else - ypwhich >&/dev/null - if ($status == 0 || -e /etc/passwd.dir || -e /etc/pwd.db) then - set rand = 1 - endif -endif - -if ($rand == 1) then - echo "It looks like you have a passwd file that can be accessed at random." - set pr = 'Do you want top to take advantage of this' -else - echo "It looks like you have conventional passwd file access. Top can take" - echo "advantage of a random access passwd mechanism if such exists. Do" - echo "you want top to assume that accesses to the file /etc/passwd are done" - set pr = 'with random access rather than sequential' -endif - -if ($nodefaults == 1) then - set random = $rand -endif - -./getans "${pr}?" yesno $random .$$ -set random = `cat .$$` - -echo "" -echo "Compiling prime.c" -$Cmdcc $cdefs -o prime prime.c -lm -if ($status != 0) then - echo "Oh well." - rm -f prime -endif - -echo "" - -ypcat passwd.byname >&/tmp/$$.a -if ($status == 0) then - set cnt = `wc -l &/tmp/$$.a - if ($status == 0) then - set cnt = `wc -l /tmp/$$.b - grep '^....r..r..' /tmp/$$.b >&/dev/null - if ($status == 1) then - grep '^....r..-..' /tmp/$$.b >&/dev/null - if ($status == 0) then - set t_group = `awk ' { print $4 }' /tmp/$$.b` - set t_mode = 2755 - echo "It looks like only group $t_group can read the memory devices." - else - set t_mode = 4755 - echo "It looks like only root can read the memory devices." - endif - else - set t_mode = 755 - echo "It looks like anybody can read the memory devices." - endif -else - echo "It looks like there are no memory device special files." - set t_mode = 755 -endif -if ($nodefaults) then - set owner = $t_owner - set group = $t_group - set mode = $t_mode -endif -echo "Tell me how to set the following when top is installed:" -./getans "Owner" user "$owner" .$$ -set owner = `cat .$$` -./getans "Group owner" group "$group" .$$ -set group = `cat .$$` -./getans "Mode" integer "$mode" .$$ -set mode = `cat .$$` -rm -f /tmp/$$.b - -echo "" -./getans "Install the executable in this directory" file "$bindir" .$$ -set bindir = `cat .$$` - -echo "" -./getans "Install the manual page in this directory" file "$mandir" .$$ -set mandir = `cat .$$` - -echo "" -./getans "Install the manual page with this extension" string "$manext" .$$ -set manext = `cat .$$` - -echo "" -./getans "Install the manual page as 'man' or 'catman'" string "$mansty" .$$ -set mansty = `cat .$$` - -echo "" -echo "We are done with the questions." - -# Some Unix environments are so poor that their csh doesn't even support -# the "eval" builtin. Check for this before relying on its use to save -# the current configuration. -/bin/csh -fc "eval echo foo" >&/dev/null -if ($status == 1) then - echo "Can't save configuration (nonfatal)" -else - echo "Saving configuration..." -# save settings to use as defaults the next time - rm -f .defaults - touch .defaults - foreach v ($vars) - set tmp = `eval echo \$$v` - echo set $v = "'$tmp'" >>.defaults - end -endif - -fast: - -# clean up -rm -f $$.[fmna] - -# set the link for machine.c -rm -f machine.c machine.o -ln -s machine/m_${module}.c machine.c - -# get definitions out of the module file -set libs = `grep LIBS: machine/m_${module}.desc | sed -e 's/^.[^:]*: *//'` -set cflgs = `grep CFLAGS: machine/m_${module}.desc | sed -e 's/^.[^:]*: *//'` -set tcap = `grep TERMCAP: machine/m_${module}.desc | sed -e 's/^.[^:]*: *//'` -set math = `grep MATH: machine/m_${module}.desc | sed -e 's/^.[^:]*: *//'` - -# get osrev defition, if we can -set uname="" -if (-e /usr/bin/uname) then - set uname=/usr/bin/uname -else if (-e /bin/uname) then - set uname=/bin/uname -endif - -if ("$uname" != "") then -# different versions of tr can't agree on the way to specify ranges, so -# we will have to give the range explicitly.....sigh. - set osrev="-DOSREV=`$uname -r | tr -cd ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`" -else - set osrev="" -endif - -# default for tcap (termcap) -if ("$tcap" == "") then - set tcap="-ltermcap" -else if ("$tcap" == "none") then - set tcap="" -endif - -# allow for the module to override or remove -lm -if ("$math" == "") then - set math="-lm" -else if ("$math" == "none") then - set math="" -endif - -if ( { grep -s SIGKILL /usr/include/signal.h } ) then - set signal="/usr/include/signal.h" -else - set signal="/usr/include/sys/signal.h" -endif - - -echo "Building Makefile..." -sed -e "s|%topn%|$topn|" \ - -e "s|%delay%|$delay|" \ - -e "s|%owner%|$owner|" \ - -e "s|%group%|$group|" \ - -e "s|%mode%|$mode|" \ - -e "s|%bindir%|$bindir|" \ - -e "s|%mandir%|$mandir|" \ - -e "s|%manext%|$manext|" \ - -e "s|%mansty%|$mansty|" \ - -e "s|%tablesize%|$TableSize|" \ - -e "s|%libs%|$libs|" \ - -e "s|%cflgs%|$cflgs|" \ - -e "s|%termcap%|$tcap|" \ - -e "s|%math%|$math|" \ - -e "s|%cdefs%|$cdefs|" \ - -e "s|%signal%|$signal|" \ - -e "s|%cc%|$Cmdcc|" \ - -e "s|%awk%|$Cmdawk|" \ - -e "s|%install%|$Cmdinstall|" \ - -e "s|%shell%|$Cmdshell|" \ - -e "s|%osrev%|$osrev|" \ - Makefile.X >Makefile - -echo "Building top.local.h..." -sed -e "s|%LoadMax%|$LoadMax|" \ - -e "s|%TableSize%|$TableSize|" \ - -e "s|%NominalTopn%|$NominalTopn|" \ - -e "s|%topn%|$topn|" \ - -e "s|%delay%|$delay|" \ - -e "s|%random%|$random|" \ - top.local.H >top.local.h - -echo "Building top.1..." -sed -e "s|%topn%|$topn|" \ - -e "s|%delay%|$delay|" \ - top.X >top.1 -if (-e machine/m_${module}.man ) then - cat machine/m_${module}.man >>top.1 -endif - -# clean up -rm -f .$$ - -echo 'Doing a "make clean".' -make clean - -echo 'To create the executable, type "make".' -echo 'To install the executable, type "make install".' -exit 0 - -byebye: -rm -f .$$ $$.[fmna] /tmp/$$.[ab] -exit 1 Index: head/contrib/top/DISCLAIMER =================================================================== --- head/contrib/top/DISCLAIMER +++ head/contrib/top/DISCLAIMER @@ -1,31 +0,0 @@ -DISCLAIMER - -"top" is distributed free of charge. It should not be considered an -official product of Group sys Consulting. William LeFebvre supports -"top" in his spare time and as time permits. - -NO WARRANTY: - -BECAUSE "top" IS DISTRIBUTED FREE OF CHARGE, THERE IS ABSOLUTELY NO -WARRANTY PROVIDED, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING, GROUP SYS CONSULTING, ARGONNE -NATIONAL LABORATORY, NORTHWESTERN UNIVERSITY, WILLIAM N. LeFEBVRE -AND/OR OTHER PARTIES PROVIDE "top" "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -PROGRAM IS WITH YOU. SHOULD THE "top" PROGRAM PROVE DEFECTIVE, YOU -ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - -IN NO EVENT WILL GROUP SYS CONSULTING, ARGONNE NATIONAL LABORATORY, -NORTHWESTERN UNIVERSITY, WILLIAM N. LeFEBVRE, AND/OR ANY OTHER PARTY -WHO MAY MODIFY AND REDISTRIBUTE "top", BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY LOST PROFITS, LOST MONIES, OR OTHER SPECIAL, INCIDENTAL -OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE -(INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED -INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A FAILURE OF THE -PROGRAM TO OPERATE WITH OTHER PROGRAMS) THE PROGRAM, EVEN IF YOU HAVE -BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM BY -ANY OTHER PARTY. - -So there! Index: head/contrib/top/FAQ =================================================================== --- head/contrib/top/FAQ +++ head/contrib/top/FAQ @@ -1,264 +0,0 @@ - TOP - Version 3.5 - Beta Release 11 - - William LeFebvre - with much help from others - - -FREQUENTLY ASKED QUESTIONS AND THEIR ANSWERS - -This FAQ is broken out in to several topics. - - -GENERAL - - 1. "Where do I get the latest version of top?" - -The official site for top is "ftp.groupsys.com" in the directory -"/pub/top". It is also available from the following mirror sites: -"pharos.dgim.doc.ca" in /packages/top, "uiarchive.uiuc.edu" in -/pub/packages/top, "sunsite.auc.dk" in /pub/unix/top. European -users should consider using the Denmark (dk) site. - - 2. "Is there a web page for top?" - -Yes. Point your browser at http://www.groupsys.com/top. It includes -all documentation, a nice interactive display which describes the -various components of the output of top, web-based retrieval of the -package, year 2000 information, and pointers to the mailing list. - - 3. "Is there a mailing list for top?" - -The official list for announcements is "top-announce@groupsys.com". -This list is managed by "majordomo@groupsys.com". Announcements of -importance to all top users will be sent to this list, including new -releases, availability of beta test versions, emergency revisions and -patches, etc. Anyone is welcome to join top-announce. This is a -read-only list. The list of subscribers will not (intentionally) be -made available, and postings to the list are limited. - -In addition, there is a top developers mailing list that is used by -beta testers and other people who help me port the program to various -machines. Membership to this list is solely at my discretion. If you -feel qualified to act as a beta tester, or if you are doing development -work on top (such as porting to a new platform), you may submit a -request by sending a message to "top-spinners-request@groupsys.com" -containing the word "subscribe". I will contact you within a few days, -as my schedule permits. - - 4. "What about Year 2000 compliance"? - -Top should not experience any problems with the transition to the year -2000. A full statement concerning top and the year 2000 can be found -in the file "Y2K" included with the distribution. - - - 5. "Why does it take so long for a new version of top to go through the - beta test process?" - -This is completely my fault. I have just not had the time to give top -the attention it deserves. I thank everyone for their patience, and I -hope that with the recent changes in the direction of my career that I -can spend more time on this. - - 6. "Top is not written in ANSI C. Do you ever plan to change that?" - -Top predates ANSI C by about 5 years. Yeah, it'll get "fixed" eventually. -Probably in 3.6. - - -CONFIGURING - - 7. "Configure said that it saw /proc and is recommending that I install top - setuid root. Is there any way around this? Is it safe?" - -There is no way around it. Complain to POSIX. Every effort has been made -to make top a secure setuid program. However, we cannot guarantee that -there are no security problems associated with this configuration. The -places where top is most vulnerable are the builtin kill and renice -commands. There is no internal top command that causes top to start a shell -as a subprocess. Some SVR4 systems may contain a bug that enables a user to -renice his own processes downward (to lower nice values that are more -favorable for the process). This problem has been fixed for the Solaris 2.x -modules, but may still exist in others. We will hopefully fix this up in -the next release. - - 8. "Why is Configure a c-shell script? I thought c-shell scripts were - evil?" - -They are. :-) I'll probably be rewriting the Configure script for the -next release, or switching to something like Gnu configure. - - -COMPILING - - 9. "We just upgraded our operating system to a new version and top broke. - What should we do?" - -Recompile it. Top is very sensitive to changes in internal kernel data -structures. It is not uncommon for a new version of the operating system to -include changes to kernel data structures. - - -RUNNING - -10. "I just finished compiling top and it works fine for root, but when - I try to run it as a regular user it either complains about files - it can't open or it doesn't display all the information it should. - Did I do something wrong?" - -Well, you're just not done. On many operating systems today, access to -many of the kernel memory devices and other system files is restricted to -either root or a particular group. The Configure script figures this out -(usually) and makes sure that the "intsall" rule in the Makefile will -install top so that anyone can run it successfully. However, you have to -*install* it first. Do this with the command "make install". - -11. "Top is (not) displaying idle processes and I don't (do) want it to." - -This default has only changed about a dozen times, and I finally got tired -of people whining about it. Go read the manual page for the current version -and pay special attention to the description of the "TOP" environment -variable. - -12. "We have so much memory in our machine that the memory status display - (the fourth line) ends up being longer than 80 characters. This - completely messes up top's output. Is there a patch?" - -Most modules have been changed to use new memory formatting functions which -will display large values in terms of megabytes instead of kilobytes. This -should fix all occurences of this problem. If you encounter a system where -this large memory display overflow is still occurring, please let me know -(send mail to ). Also note that newer versions of top can -use columns beyond 79, and understand window resizes. So you can always -make your window bigger. - -13. "I tried to compile top with gcc and it doesn't work. I get - compilation errors in the include files, or I get an executable that - dumps core, or top displays incorrect numbers in some of the displays. - What's wrong?" - -Gnu CC likes very much to use its own include files. Not being a gcc -expert, I can't explain why it does this. But I can tell you that if -you upgrade your operating system (say from Solaris 2.4 to Solaris -2.5) after installing gcc, then the include files that gcc uses will -be incorrect, especially those found in the "sys" directory. Your -choices are: (1) rebuild and reinstall the "standard" include files -for gcc (look for scripts in the distribution called "fixincludes" and -"fixinc.svr4"), (2) compile machine.c with "CFLAGS=-I/usr/include" -then make the rest of the object files normally, or (3) use "cc". -Solaris 2.6 users should also consult FAQ #20. - -14. "The cpu state percentages are all wrong, indicating that my machine is - using 95% system time when it is clearly idle. What's wrong?" - -This can happen if you compiled with gcc using the wrong include files. -See the previous question. - - -SUNOS PROBLEMS - -15. "I tried compiling top under SunOS version 4.1.x and it got compile time - errors. Is there a patch?" - -If you try compiling top in a "System V environment" under SunOS (that is, -/usr/5bin is before /usr/bin on your path) then the compilation may fail. -This is mostly due to the fact that top thinks its being compiled on a -System V machine when it really isn't. The only solution is to put /usr/bin -and /usr/ucb before /usr/5bin on your path and try again. - - -SVR4-derived PROBLEMS - -16. "When I run top on my SVR4-derived operating system, it displays all - the system information at the top but does not display any process - information (or only displayes process information for my own - processes). Yet when I run it as root, everything works fine." - -Your system probably uses the pseudo file system "/proc", which is by -default only accessible by root. Top needs to be installed setuid root on -such systems if it is going to function correctly for normal users. - - -SOLARIS PROBLEMS - -17. "Under Solaris 2, when I run top as root it only shows root processes, - or it only shows processes with a PID less than 1000. It refuses to - show anything else. What do I do?" - -You probably compiled it with /usr/ucb/cc instead of the real C compiler. -/usr/ucb/cc is a cc front end that compiles programs in BSD source-level -compatability mode. You do not want that. Make sure that /usr/ucb is not -on your path and try compiling top again. - -18. "Under Solaris 2, I compiled top using what I am sure is the correct - compiler but when I try to run it it complains about missing dynamic - libraries. What is wrong?" - -Check to see if you have LD_LIBRARY_PATH defined in your shell. If you do, -make sure that /usr/ucblib is not on the path anywhere. Then try compiling -top again. - -19. "Under Solaris 2, when I try to run top it complains that it can't open - the library "libucb.so.1". So I changed the LIBS line in m_sunos5.c - to include -R/usr/ucblib to make sure that the dynamic linker will look - there when top runs. I figured this was just an oversight. Was I - right?" - -No, you were not right. As distributed, top requires NO alterations -for successful compilation and operations under any release of Solaris -2. You probably compiled top with /usr/ucb/cc instead of the real C -compiler. See FAQ #10 for more details. - -20. "When I try to compile top under Solaris 2.6 using gcc I get compile - time errors. There appear to be problems with the include files, - such as 'u_rlimit has incomplete type' and/or 'u_saved_rlimit has - incomplete type'. I've already run fixinc.svr4 as per FAQ #13. - Why didn't that fix it?" - -Only top versions 3.5 and later are compatible with Solaris 2.6. Make -sure you are using the most up-to-date version. Earlier beta release -copies of version 3.5 had additional problems when compiled with gcc. -Retrieve the official version 3.5 (non-beta) release from one of the -sites listed in FAQ #1 or FAQ #2. - - -SCO PROBLEMS - -21. "When I try to run Configure, it complains about a syntax error." - -Some versions of SCO's csh do not understand the syntax "$<". Earlier -releases of top depended on this syntax to read input from the installer's -terminal during the installation process. Version 3.5 fixes this. - - -SVR42 PROBLEMS - -22. "The memory display doesn't work right. Why?" - -This is a known bug with the svr42 module. The problem has been traced down -to a potential bug in the "mem" driver. The author of the svr42 module is -working on a fix. - - -STILL STUCK - -23. I'm still stuck. To whom do I report problems with top?" - -The most common problems are caused by top's sensitivity to internal kernel -data structures. So make sure that you are using the right include files, -and make sure that you test out top on the same machine where you compiled -it. Sun's BSD Source Compatability Mode is also a common culprit. Make -sure you aren't using either /usr/ucb/cc or any of the libraries in -/usr/ucblib. Finally, make sure you are using the correct module. If there -does not appear to be one appropriate for your computer, then top probably -will not work on your system. - -If after reading all of this file and checking everything you can you are -still stuck, then send mail to "wnl@groupsys.com". I will answer your mail -when I have time. Please bear with me in that regard! If it looks like the -problem is machine-specific, I will forward the report along to the module's -author. If you would like to converse directly with the module author, the -authors' names are listed at the beginning of the module .c file in the -"machine" directory. Index: head/contrib/top/FREEBSD-upgrade =================================================================== --- head/contrib/top/FREEBSD-upgrade +++ head/contrib/top/FREEBSD-upgrade @@ -1,22 +0,0 @@ -$FreeBSD$ - -This file contains notes regarding the upgrade of top(1). See the vendor -import instructions at: - - https://www.freebsd.org/doc/en/articles/committers-guide/subversion-primer.html#svn-advanced-use-vendor-imports - -The upstream project pages for top(1) are: - - http://www.unixtop.org/ - - https://sourceforge.net/projects/unixtop/ - -contrib/top/machine.h specifies an interface that must be provided by the -target OS. That interface is implemented in usr.bin/top/machine.c - -To enable building on case-insensitive filesystems, the following files were -renamed: - - contrib/top/top.X -> contrib/top/top.xs - contrib/top/top.local.H -> contrib/top/top.local.hs - Index: head/contrib/top/INSTALL =================================================================== --- head/contrib/top/INSTALL +++ head/contrib/top/INSTALL @@ -1,166 +0,0 @@ - TOP - Version 3.5 - - William LeFebvre - and a cast of many - -INSTALLATION - -Configuration and installation of top is very straightforward. After -unpacking the sources, run the script "Configure". It will present you -with a series of questions, all of which should be explained in the -presentation. After you have answered all the questions, "Configure" will -perform all the necessary configuration. Once this is finished, type -"make install". Make will compile the sources then install the resulting -executable and manual page in the appropriate places. - -The most difficult step in the configuration is the choice of an -appropriate machine-specific module. The Configure script gives you a -list of choices complete with brief descriptions of when each choice is -appropriate. Each module is contained in a separate c file in the -directory "machine". The module contains all of the machine-specific code -that makes top work correctly on the architecture in question. All of the -code in the top-level directory is machine-independent (or at least -strives to be). Hints for some module choices that are not obvious are -given at the end of this file. - -The first comment in each c file in that directory contains the synopsis -AND a detailed description of the machines for which that module is -appropriate. It also contains a list of authors for that module. If you -are really stumped in this choice, use grep to find your machine -manufacturer's name or operating system name in machine/*.c. If you still -can't find one that is appropriate, then chances are very good that one -hasn't been written yet. If that is the case, then you are out of luck. - -HANDLING MULTIPLE ARCHITECTURES - -If you need to recompile top for a different architecture (that is, using -a different module) you need to reconfigure top. A short cut is available -to make this a little easier. If all of your previous answers to the -configuration questions (except for the module name of course) are -adequate for the new architecture, then you can just use the command -"Configure ". The configuration script will reconfigure top -using the new module and all the answers you gave last time. It will -finish with a "make clean". Once that completes, type "make install" -and make will compile the sources and do the installation. - -HANDLING MULTIPLE OS VERSIONS - -By far the most frequently received bug report for top is something like -this: "We just upgraded our operating system to version 99.9.9.9 and top -broke. What should we do?" The simple answer is "recompile". - -Top is very sensitive to changes in internal kernel data structures -(especially the proc and user structures). Some operating systems -(especially SunOS) are notorious for changing these structure in every -minor release of the OS. This means that a top executable made under one -version of the OS will not always work correctly (if even at all) under -another version. This is just one of those tough facts of life. There is -really no way around it. - -To make life even worse, some operating systems (SunOS again) will use -slightly different proc and user structures on different models. For -example, "top" built on a SparcStation 2 will not run correctly on a -SparcStation 10, even if they are both running SunOS 4.1.3. These -unfortunate circumstances make maintaining top very difficult, especially -in an environment that runs several different versions of the same -operating system. - -But there is hope. If your operating system has a properly functioning -"uname" command then you can handle this problem rather gracefully. -Included in the distribution is a shell file called "metatop". All this -shell file does is: - - exec top-`uname -m`-`uname -r` "$@" - -So when you run this script, it execs a filename that is unique to your -specific machine architecture and your OS revision number. - -To use "metatop", do the following: - - . on any machine, run Configure and choose the module that is - appropriate for the machine - . for all machines which use the same module: - . group machines according to machine architecture AND OS - revision number (i.e.: sun4-4.1.1, sun4c-4.1.1, sun4c-4.1.2, - sun4-4.1.3, sun4c-4.1.3, sun4m-4.1.3, ...) - . for each group, choose one machine from that group and on it - run "make clean; make installmeta". - - -The "installmeta" rule in the makefile will insure that top is compiled, -install the shell file "metatop" as "top", then install the executable -"top" with a name appropriate to the machine architecture and OS revision. - - -HINTS FOR CHOOSING THE CORRECT MODULE: - -SOLARIS 2.x - -All versions of Solaris will now work with the module sunos5. Version -specific modules (such as sunos54) no longer exist. - - -SUNOS 4.x AND MULTIPROCESSOR ARCHITECTURES - -First, we need to be speaking the same language: - -sun4 a regular sparc sun 4 architecture machine (sparc station 1, - sparc station 2, IPC, SLC, etc.) - -sun4m a multiprocessor sparc (Sparc 10, 4/670, 4/690) - -I intended to write the sunos4 module so that an executable compiled on a -sun4m machine would work correctly on a sun4 machine. Unfortunately my -experiments indicate that this cannot be done. It turns out that the user -structure is so different between these two architectures that nothing -short of a serious hack will make the same executable work correctly on -both machines. I recommend that you use the separate module "sunos4mp" -when making an executable for a sun4m architecture, and use "sunos4" when -making an executable for sun4 or sun4c architectures. - -DIGITAL UNIX V4.0 - -This is the successor to DECOSF/1. Use the module decosf1. - -SOLBOURNE OPERATING SYSTEM (OS/MP) - -If you are running OS/MP version 4.1A, then use the module "osmp4.1a". - -If you are running a version of OS/MP OLDER than 4.1A (that is, one -of its predecessors), use the module "sunos4". - -If you are running OS/MP 4.1B or LATER, use the module "sunos4mp". - -HP/UX OPERATING SYSTEM - -The module hpux8 works on all version 8 systems. Some say that it works -with version 9 as well, but one user did send me a separate module for -version 9. This module has only been tested on series 800 machines. I -would recommend the following for those running version 9: try hpux9 and -if it doesn't work then try hpux8. If neither work, then send mail to me -and/or the modules' authors. Another note: we have a model 730 supposedly -running version 9.01. The module hpux9 did not compile successfully, but -the module hpux8 worked fine. The module hpux10 works on all revisions of -HP/UX 10 except 10.10, where HP removed the definition of the proc structure -from the system include files. - -NET/2 386BSD SYSTEMS - -If your version of the operating system has patchkit 2.4 installed, -then you will need to modify machine/m_386bsd.c and uncomment the -definition of PATCHED_KVM. This patchkit makes what more than a few -people believe to be a wholly unnecessary patch to the way the kvm -routines work. - -A/UX SYSTEMS - -There is a module for A/UX 3.0 and 3.1. Whether or not it works for -any other version is not known. Proceed at your own risk. - -Although AUX does not generally have a renice systemcall, it can be -implemented by tweeking kernel memory. The flag IMPLEMENT_SETPRIORITY -controls the inclusion of this code. It is off be default. While -such a simple hack should not be difficult to get right, USE THIS -FEATURE AT YOUR OWN RISK! - Index: head/contrib/top/Make.desc.X =================================================================== --- head/contrib/top/Make.desc.X +++ head/contrib/top/Make.desc.X @@ -1,24 +0,0 @@ -# Makefile for .desc files - -# This makefile is the prototype for "Make.desc", which is used by -# top's Configure script to build .desc files and the SYNOPSIS file. -# Configure then uses these files to ask appropriate questions. - -# Written by William LeFebvre, Group sys Consulting -# (formerly of Northwestern University and Rice University) - -# DO NOT EDIT "Make.desc"!!! Make changes to "Make.desc.X", -# then "make veryclean", then run "Configure". - -# The list of .desc files will be inserted after this next line: -DESCS=\ - -.SUFFIXES: .desc - -.c.desc: - sed -e '/^$$/,$$d' -e 's,^[/ *]*,,' $< > $@ - -all: SYNOPSIS - -SYNOPSIS: $(DESCS) - grep SYNOPSIS: $(DESCS) | sed -e 's@^machine/m_@@' -e 's@.desc:.[^:]*: *@:@' >SYNOPSIS Index: head/contrib/top/Makefile.X =================================================================== --- head/contrib/top/Makefile.X +++ head/contrib/top/Makefile.X @@ -1,117 +0,0 @@ -# Makefile for "top", a top 10 process display for Unix -# -# This makefile is for top, version 3 -# -# Written by William LeFebvre, Group sys Consulting -# (formerly of Northwestern University and Rice University) - -# DO NOT EDIT "Makefile"!!!! Make changes to "Makefile.X" and rerun -# Configure. - -# Executables (these should be obvious): - -SHELL = %shell% -CC = %cc% -AWK = %awk% -INSTALL = %install% - -# installation information: -# OWNER - name (or uid) for the installed executable's owner -# GROUP - group name (or gid) for the installed executable's group -# MODE - mode for the installed executable (should start with a 0) -# BINDIR - directory where the executable should live -# MANDIR - directory where the manual page should live -# MANEXT - installed man pages end in .$(MANEXT) -# MANSTY - "man" or "catman" depending on what's to be installed -# SIGNAL - or ; the one with signal definitions -# TROFF - most appropriate troff command - -OWNER = %owner% -GROUP = %group% -MODE = %mode% -BINDIR = %bindir% -MANDIR = %mandir% -MANEXT = %manext% -MANSTY = %mansty% -SIGNAL = %signal% - -# Values for the two defaults in "top": -# TOPN - default number of processes to display -# DELAY - default delay between updates -# -# set TOPN to -1 to indicate infinity (so that top will display as many -# as the screen will hold). - -TOPN = %topn% -DELAY = %delay% - -CFILES = top.c commands.c display.c screen.c username.c \ - utils.c version.c getopt.c machine.c -OBJS = top.o commands.o display.o screen.o username.o \ - utils.o version.o getopt.o machine.o - -CDEFS = %cdefs% -LIBS = %libs% -TERMCAP = %termcap% -MATH = %math% - -CFLAGS = %cflgs% $(CDEFS) -LINTFLAGS = -x $(CDEFS) - -all: Makefile top.local.h top - -Makefile: Makefile.X - @echo 'You need to run the script "Configure" before running "make".' - exit 10 - -top.local.h: top.local.H - @echo 'You need to run the script "Configure" before running "make".' - exit 10 - -top: $(OBJS) - rm -f top - $(CC) $(CDEFS) -o top $(OBJS) $(TERMCAP) $(MATH) $(LIBS) - -lint: sigdesc.h - $(LINT) $(LINTFLAGS) $(CFILES) - -# include file dependencies -top.o: boolean.h display.h screen.h top.h top.local.h utils.h machine.h -commands.o: boolean.h sigdesc.h top.h utils.h -display.o: boolean.h display.h layout.h screen.h top.h top.local.h utils.h -screen.o: boolean.h screen.h -utils.o: top.h -version.o: top.h patchlevel.h -username.o: top.local.h utils.h - -# when compiling machine.c, include os revision definition -machine.o: machine.c top.h machine.h utils.h - $(CC) "%osrev%" $(CFLAGS) -c machine.c - -# automatically built include file -sigdesc.h: sigconv.awk $(SIGNAL) - $(AWK) -f sigconv.awk $(SIGNAL) >sigdesc.h - -clean: - rm -f *.o top core core.* sigdesc.h - -veryclean: clean - rm -f Make.desc machine/*.desc .defaults top.tar SYNOPSIS Makefile top.local.h top.1 machine.c prime - -install: top top.1 install-top install-$(MANSTY) - -install-top: - $(INSTALL) -o $(OWNER) -m $(MODE) -g $(GROUP) top $(BINDIR) - -install-man: - $(INSTALL) top.1 $(MANDIR)/top.$(MANEXT) - -install-catman: - tbl top.1 | nroff -man > $(MANDIR)/top.$(MANEXT) - -installmeta: top top.1 - $(INSTALL) -o $(OWNER) -m 755 -g $(GROUP) metatop $(BINDIR)/top - @echo $(INSTALL) -o $(OWNER) -m $(MODE) -g $(GROUP) top $(BINDIR)/top-`uname -m`-`uname -r` - @$(INSTALL) -o $(OWNER) -m $(MODE) -g $(GROUP) \ - top $(BINDIR)/top-`uname -m`-`uname -r` - $(INSTALL) top.1 $(MANDIR)/top.$(MANEXT) Index: head/contrib/top/Porting =================================================================== --- head/contrib/top/Porting +++ head/contrib/top/Porting @@ -1,165 +0,0 @@ -Instructions for porting top to other architectures. - -This is still a preliminary document. Suggestions for improvement are -most welcome. - -My address is now "wnl@groupsys.com". - -Before you embark on a port, please send me a mail message telling me -what platform you are porting top to. There are three reasons for -this: (1) I may already have a port, (2) module naming needs to be -centralized, (3) I want to loosely track the various porting efforts. -You do not need to wait for an "okay", but I do want to know that you -are working on it. And of course, once it is finished, please send me -the module files so that I can add them to the main distribution! - ----------- - -There is one set of functions which extract all the information that -top needs for display. These functions are collected in to one file. -To make top work on a different architecture simply requires a -different implementation of these functions. The functions for a -given architecture "foo" are stored in a file called "m_foo.c". The -Configure script looks for these files and lets the configurer choose -one of them. This file is called a "module". The idea is that making -top work on a different machine only requires one additional file and -does not require changes to any existing files. - -A module template is included in the distribution, called "m-template". -To write your own module, it is a good idea to start with this template. -If you architecture is similar to one for which a module already -exists, then you can start with that module instead. If you do so, -remember to change the "AUTHOR" section at the top! - -The first comment in a module contains information which is extracted -and used by Configure. This information is marked with words in all -capitals (such as "SYNOPSIS:" and "LIBS:"). Go look at m-template: it -is fairly self-explanatory. The text after "LIBS:" (on the same line) -is extracted and included in the LIBS definition of the Makefile so -that extra libraries which may be necessary on some machines (such as -"-lkvm") can be specified in the module. The text after "CFLAGS:" -(on the same line) is extracted and included as flags in the "CFLAGS" -definition of the Makefile (thus in every compilation step). This is -used for rare circumstances only: please don't abuse this hook. - -Some operating systems have idiosyncrasies which will affect the form -and/or content of the information top displays. You may wish to -document such anomalies in the top man page. This can be done by adding -a file called m_{modulename}.man (where {modulename} is replaced with -the name of the module). Configure will automatically add this file to -the end of the man page. See m_sunos4.man for an example. - -A module is concerned with two structures: - -The statics struct is filled in by machine_init. Each item is a -pointer to a list of character pointers. The list is terminated -with a null pointer. - -struct statics -{ - char **procstate_names; /* process state names */ - char **cpustate_names; /* cpu state names */ - char **memory_names; /* memory information names */ -}; - -The system_info struct is filled in by get_system_info and -get_process_info. - -struct system_info -{ - int last_pid; /* last pid assigned (0 means non-sequential assignment) */ - double load_avg[NUM_AVERAGES]; /* see below */ - int p_total; /* total number of processes */ - int p_active; /* number of procs considered "active" */ - int *procstates; /* array of process state counters */ - int *cpustates; /* array of cpustate counters */ - int *memory; /* memory information */ -}; - -The last three pointers each point to an array of integers. The -length of the array is determined by the length of the corresponding -_names array in the statics structure. Furthermore, if an entry in a -_names array is the empty string ("") then the corresponding value in -the value array will be skipped over. The display routine displays, -for example, the string procstate_names[0] then the number -procstates[0], then procstate_names[1], procstates[1], etc. until -procstate_names[N] == NULL. This allows for a tremendous amount of -flexibility in labeling the displayed values. - -"procstates" and "memory" are displayed as straight integer values. -Values in "cpustates" are displayed as a percentage * 10. For -example, the (integer) value 105 is displayed as 10.5%. - -These routines must be defined by the machine dependent module. - -int machine_init(struct statics *) - - returns 0 on success and -1 on failure, - prints error messages - -char *format_header(char *) - - Returns a string which should be used as the header for the - process display area. The argument is a string used to label - the username column (either "USERNAME" or "UID") and is always - 8 characters in length. - -void get_system_info(struct system_info *) - -caddr_t get_process_info(struct system_info *, int, int, int (*func)()) - - returns a handle to use with format_next_process - -char *format_next_process(caddr_t, char *(*func)()) - - returns string which describes next process - -int proc_compare(caddr_t, caddr_t) - - qsort comparison function - -uid_t proc_owner(pid_t) - - Returns the uid owner of the process specified by the pid argument. - This function is VERY IMPORTANT. If it fails to do its job, then - top may pose a security risk. - - -get_process_info is called immediately after get_system_info. In -fact, the two functions could be rolled in to one. The reason they -are not is mostly historical. - -Top relies on the existence of a function called "setpriority" to -change a process's priority. This exists as a kernel call on most 4.3 -BSD derived Unixes. If neither your operating system nor your C -library supplies such a function, then you will need to add one to the -module. It is defined as follows: - - int setpriority (int dummy, int who, int niceval) - - For the purposes of top, the first argument is meaningless. - The second is the pid and the third is the new nice value. - This function should behave just like a kernel call, setting - errno and returning -1 in case of an error. This function MUST - check to make sure that a non-root user does not specify a nice - value less than the process's current value. If it detects such - a condition, it should set errno to EACCES and return -1. - Other possible ERRNO values: ESRCH when pid "who" does not exist, - EPERM when the invoker is not root and not the same as the - process owner. - -Note that top checks process ownership and should never call setpriority -when the invoker's uid is not root and not the same as the process's owner -uid. - - -The file "machine.h" contains definitions which are useful to modules -and to top.c (such as the structure definitions). You SHOULD NOT need -to change it when porting to a new platform. - -Porting to a new platform should NOT require any changes to existing -files. You should only need to add m_ files. If you feel you need a -change in one of the existing files, please contact me so that we can -discuss the details. I want to keep such changes as general as -possible. - Index: head/contrib/top/README =================================================================== --- head/contrib/top/README +++ head/contrib/top/README @@ -1,192 +0,0 @@ - TOP - Version 3.5 - - William LeFebvre - and a cast of dozens - - -If you do not want to read this entire file, then at least read -the section at the end entitled "KNOWN PROBLEMS". - -If you are having any problems getting top to work, please read the -file "FAQ" *before* contacting me. Thank you. - -"top" is a program that will give continual reports about the state of -the system, including a list of the top cpu using processes. Version 3 -of "top" has three primary design goals: provide an accurate snapshot of -the system and process state, not be one of the top processes itself, be -as portable as possible. - -Version 3 has many bug fixes from version 2.5, and it has also been -reorganized in a major way to make it easy to port to other platforms. -All system dependent code is now contained in one file. - -Top now includes a configuration script called "Configure". It helps -the installer choose the correct parameters for this particular -installation. This script MUST be run before attempting to compile top. - -Top requires read access to the memory files "/dev/kmem" and "/dev/mem" -as well as the system image "/vmunix". Some installations have these -files protected from general access. These sites would have to install -this program in the same way that programs such as "ps" are installed. -In addition, on those Unix variants that support the proc filesystem -(such as SVR4 and Solaris 2), top requires read access to all the files -in /proc: typically dictating that top be installed setuid to root. - -CAVEAT: version 3 of top has internal commands that kill and renice -processes. Although I have taken steps to insure that top makes -appropriate checks with these commands, I cannot guarantee that these -internal commands are totally secure. IF YOU INSTALL top as a SETUID -program, you do so AT YOUR OWN RISK! I realize that some operating -systems will require top to run setuid, and I will do everything I can -to make sure that top is a secure setuid program. - -Configure will ask you to input values for certain parameters. Before -each parameter, Configure will display a description of what the -parameter does. Read the description and choose an appropriate value. -Sometimes a default will appear in brackets. Typing just return will -choose the default. - -System support now takes the form of "modules". Adding support for -a different architecture requires only adding a module. Configure -asks which module to use when it is configuring top. See the file -"Porting" for a description of how to write your own module. - -To compile and install "top", read the file "INSTALL" and follow the -directions and advice contained therein. - -Once you have created a binary for one particular type of machine, you -can reconfigure for another type with "./Configure modulename" where -"modulename" is replaced with the appropriate module name. All other -parameter values are kept the same. Note that in some cases this may -not be appropriate. - -If you make any kind of change to "top" that you feel would be -beneficial to others who use this program, or if you find and fix a bug, -please send me the change. - -Be sure to read the FAQ enclosed with the distrubution. It contains -answers to the most commonly asked questions about the configuration, -installation, and operation of top. - - -AVAILABILITY - -The latest version of "top" is now being made available via anonymous -FTP from the host "ftp.groupsys.com" in the directory "/pub/top". -Additional modules will be made available in the directory -"/pub/top/m". The site "eecs.nwu.edu" will continue to house copies -of the distribution as well. - -Here are HTML links for the four best "top" archive sites: - -Top archive (groupsys.com) -Top archive (eecs.nwu.edu) - Top mirror (dgim.doc.ca) -Top mirror (uiuc.edu) - -New releases will be posted to comp.sources.unix as they become -available. Sites which arhive that newsgroup will also contain copies -of the distribution. - -Announcements about availability will be made to the mailing list -"top-announce@groupsys.com". This is an open list maintained by -majordomo. To join the list, send a message containing the word -"subscribe" to "top-announce-request@groupsys.com". Addresses of -subscribers to this list are kept confidential and will never be used -for any purpose other than as recipients of announements concerning -this software. - - -KNOWN PROBLEMS: - -Gnu CC - -Compiling via Gnu CC continued to be the source of most of the -questions I receive. By far the most common mistake made by those -attempting to compile top with Gnu CC is out of date include files. -When the operating system is upgraded, the include files that are part -of the gcc package MUST also be updated. Gcc maintains its own -include files. Even a minor OS upgrade can involve changes to some of -the kernel's internal data structures, which are defined in include -files in "sys". Top is very sensitive to these changes. If you are -compiling with gcc and experience any sort of strange problems, please -make sure the include files you are using are up to date BEFORE -sending me a bug report. Look in the gcc source distribution for the -shell script "fixincludes". - -HP/UX 10.10 - -In their infinite wisdom, the folks at HP have decided that mere mortals -such as you and I don't need to know what the kernel's proc structure looks -like. To that end, they have removed all useful content from the include -file in version 10.10. As a result, top will not compile -under 10.10. What HP is trying to accomplish with this move is to force -iconoclasts such as myself to use "pstat" for collecting all process -information. I have no immediate solution for this problem, but hope to -obtain a sufficiently complete definition of "struct proc" at some point in -the near future. Stay tuned. - -DIGITAL UNIX 4.0 (DECOSF/1 V4.0) - -A user has reported that idle processes are not displayed regardless -of the flags used when invoking top. We have not had time to track -this problem down. - -DECOSF/1 V3.0 - -There is a bug either in the module, in utils.c, or in DEC's optimizer that -is tickled by the decosf1 module when compiled under V3.0 (and perhaps -earlier versions). Top compiled using DEC's compiler with optimization -will consistently produce a segmentation fault (in format_next_process -while calling sprintf). To work around this problem, either compile top -with gcc or turn off optimization (compile without -O). We think that -one of the bugs fixed in utils.c fixed this problem as well, but we are -not certain. - - -System V R 4.2 - -Load average and memory displays do not work. The problem has been -traced down to a potential bug in the "mem" driver. The author -of the svr42 module is working on a fix. - - - -GRATITUDE - -My perpetual thanks to all the people who have helped me support top -on so many platforms. Without these people, top would not be what it -is. Here is a partial list of contributors and other individuals. - - Robert Boucher - Marc Cohen - David Cutter - Casper Dik - Charles Hedrick - Andrew Herbert - Jeff Janvrin - Torsten Kasch - Petri Kutvonen - William L. Jones - Tim Pugh - Steve Scherf - Phillip Wu - -(My apologies if I missed anyone.) - - -AUTHOR - - William LeFebvre - Group sys Consulting - wnl@groupsys.com - - - U.S. Mail address: - William LeFebvre - Group sys Consulting - 11585 Jones Bridge Road - Suite 420-139 - Alpharetta, GA 30022 - (770) 813-3224 Index: head/contrib/top/Y2K =================================================================== --- head/contrib/top/Y2K +++ head/contrib/top/Y2K @@ -1,26 +0,0 @@ -Top and the Year 2000 - -The software package top will not be affected by years numbering -between 2000 and 2037. No portion of the top code stores dates on -disk. All date processing in top is performed with functions from the -Unix C library and Unix kernel. The specific functions are: time(2) -and ctime(3S). These functions deal exclusively with conventional -Unix time values (number of seconds since Midnight January 1, 1970 -GMT) and produce strings with a 4-digit year. At no point in the code -for top are the last two digits used to represent a year. - -Top and the Year 2038 - -In the year 2038 top will fail to represent the time of day correctly -on 32-bit Unix operating systems. This is due to a limitation in the -way Unix represents time. Top will only work on systems whose kernel -call "time" and C library call "ctime" have been adjusted to represent -time with a value greater than 32 bits. The exact date and time of -this failure is 3:14:08 January 19, 2038 GMT. Note that this failure -will only affect the display of the current time in the output from -top. - - -THERE IS ABSOLUTELY NO WARRANTY PROVIDED WITH THIS SOFTWARE. -Please see the contents of the file "DISCLAIMER" for further -information. Index: head/contrib/top/boolean.h =================================================================== --- head/contrib/top/boolean.h +++ head/contrib/top/boolean.h @@ -1,5 +0,0 @@ -/* My favorite names for boolean values */ -#define No 0 -#define Yes 1 -#define Maybe 2 /* tri-state boolean, actually */ - Index: head/contrib/top/commands.h =================================================================== --- head/contrib/top/commands.h +++ head/contrib/top/commands.h @@ -1,21 +0,0 @@ -/* - * Top users/processes display for Unix - * Version 3 - * - * This program may be freely redistributed, - * but this entire comment MUST remain intact. - * - * Copyright (c) 1984, 1989, William LeFebvre, Rice University - * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University - * Copyright (c) 2016, Randy Westlund - * - * $FreeBSD$ - */ -#ifndef COMMANDS_H -#define COMMANDS_H - -void show_errors(void); -int error_count(void); -void show_help(void); - -#endif /* COMMANDS_H */ Index: head/contrib/top/commands.c =================================================================== --- head/contrib/top/commands.c +++ head/contrib/top/commands.c @@ -1,542 +0,0 @@ -/* - * Top users/processes display for Unix - * Version 3 - * - * This program may be freely redistributed, - * but this entire comment MUST remain intact. - * - * Copyright (c) 1984, 1989, William LeFebvre, Rice University - * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University - * - * $FreeBSD$ - */ - -/* - * This file contains the routines that implement some of the interactive - * mode commands. Note that some of the commands are implemented in-line - * in "main". This is necessary because they change the global state of - * "top" (i.e.: changing the number of processes to display). - */ - -#include "os.h" - -#include -#include - -#include -#include -#include -#include - -#include "commands.h" -#include "sigdesc.h" /* generated automatically */ -#include "top.h" -#include "boolean.h" -#include "utils.h" -#include "machine.h" - -extern int errno; - -extern char *copyright; - -/* imported from screen.c */ -extern int overstrike; - -int err_compar(); -char *err_string(); -static int str_adderr(char *str, int len, int err); -static int str_addarg(char *str, int len, char *arg, int first); - -/* - * show_help() - display the help screen; invoked in response to - * either 'h' or '?'. - */ - -void -show_help() - -{ - printf("Top version %s, %s\n", version_string(), copyright); - fputs("\n\n\ -A top users display for Unix\n\ -\n\ -These single-character commands are available:\n\ -\n\ -^L - redraw screen\n\ -q - quit\n\ -h or ? - help; show this text\n", stdout); - - /* not all commands are availalbe with overstrike terminals */ - if (overstrike) - { - fputs("\n\ -Other commands are also available, but this terminal is not\n\ -sophisticated enough to handle those commands gracefully.\n\n", stdout); - } - else - { - fputs("\ -C - toggle the displaying of weighted CPU percentage\n\ -d - change number of displays to show\n\ -e - list errors generated by last \"kill\" or \"renice\" command\n\ -H - toggle the displaying of threads\n\ -i or I - toggle the displaying of idle processes\n\ -j - toggle the displaying of jail ID\n\ -J - display processes for only one jail (+ selects all jails)\n\ -k - kill processes; send a signal to a list of processes\n\ -m - toggle the display between 'cpu' and 'io' modes\n\ -n or # - change number of processes to display\n", stdout); -#ifdef ORDER - if (displaymode == DISP_CPU) - fputs("\ -o - specify sort order (pri, size, res, cpu, time, threads, jid, pid)\n", - stdout); - else - fputs("\ -o - specify sort order (vcsw, ivcsw, read, write, fault, total, jid, pid)\n", - stdout); -#endif - fputs("\ -P - toggle the displaying of per-CPU statistics\n\ -r - renice a process\n\ -s - change number of seconds to delay between updates\n\ -S - toggle the displaying of system processes\n\ -a - toggle the displaying of process titles\n\ -t - toggle the display of this process\n\ -u - display processes for only one user (+ selects all users)\n\ -w - toggle the display of swap use for each process\n\ -z - toggle the displaying of the system idle process\n\ -\n\ -\n", stdout); - } -} - -/* - * Utility routines that help with some of the commands. - */ - -char *next_field(str) - -register char *str; - -{ - if ((str = strchr(str, ' ')) == NULL) - { - return(NULL); - } - *str = '\0'; - while (*++str == ' ') /* loop */; - - /* if there is nothing left of the string, return NULL */ - /* This fix is dedicated to Greg Earle */ - return(*str == '\0' ? NULL : str); -} - -int -scanint(str, intp) - -char *str; -int *intp; - -{ - register int val = 0; - register char ch; - - /* if there is nothing left of the string, flag it as an error */ - /* This fix is dedicated to Greg Earle */ - if (*str == '\0') - { - return(-1); - } - - while ((ch = *str++) != '\0') - { - if (isdigit(ch)) - { - val = val * 10 + (ch - '0'); - } - else if (isspace(ch)) - { - break; - } - else - { - return(-1); - } - } - *intp = val; - return(0); -} - -/* - * Some of the commands make system calls that could generate errors. - * These errors are collected up in an array of structures for later - * contemplation and display. Such routines return a string containing an - * error message, or NULL if no errors occurred. The next few routines are - * for manipulating and displaying these errors. We need an upper limit on - * the number of errors, so we arbitrarily choose 20. - */ - -#define ERRMAX 20 - -struct errs /* structure for a system-call error */ -{ - int errnum; /* value of errno (that is, the actual error) */ - char *arg; /* argument that caused the error */ -}; - -static struct errs errs[ERRMAX]; -static int errcnt; -static char *err_toomany = " too many errors occurred"; -static char *err_listem = - " Many errors occurred. Press `e' to display the list of errors."; - -/* These macros get used to reset and log the errors */ -#define ERR_RESET errcnt = 0 -#define ERROR(p, e) if (errcnt >= ERRMAX) \ - { \ - return(err_toomany); \ - } \ - else \ - { \ - errs[errcnt].arg = (p); \ - errs[errcnt++].errnum = (e); \ - } - -/* - * err_string() - return an appropriate error string. This is what the - * command will return for displaying. If no errors were logged, then - * return NULL. The maximum length of the error string is defined by - * "STRMAX". - */ - -#define STRMAX 80 - -char *err_string() - -{ - register struct errs *errp; - register int cnt = 0; - register int first = Yes; - register int currerr = -1; - int stringlen; /* characters still available in "string" */ - static char string[STRMAX]; - - /* if there are no errors, return NULL */ - if (errcnt == 0) - { - return(NULL); - } - - /* sort the errors */ - qsort((char *)errs, errcnt, sizeof(struct errs), err_compar); - - /* need a space at the front of the error string */ - string[0] = ' '; - string[1] = '\0'; - stringlen = STRMAX - 2; - - /* loop thru the sorted list, building an error string */ - while (cnt < errcnt) - { - errp = &(errs[cnt++]); - if (errp->errnum != currerr) - { - if (currerr != -1) - { - if ((stringlen = str_adderr(string, stringlen, currerr)) < 2) - { - return(err_listem); - } - (void) strcat(string, "; "); /* we know there's more */ - } - currerr = errp->errnum; - first = Yes; - } - if ((stringlen = str_addarg(string, stringlen, errp->arg, first)) ==0) - { - return(err_listem); - } - first = No; - } - - /* add final message */ - stringlen = str_adderr(string, stringlen, currerr); - - /* return the error string */ - return(stringlen == 0 ? err_listem : string); -} - -/* - * str_adderr(str, len, err) - add an explanation of error "err" to - * the string "str". - */ - -static int -str_adderr(str, len, err) - -char *str; -int len; -int err; - -{ - register char *msg; - register int msglen; - - msg = err == 0 ? "Not a number" : errmsg(err); - msglen = strlen(msg) + 2; - if (len <= msglen) - { - return(0); - } - (void) strcat(str, ": "); - (void) strcat(str, msg); - return(len - msglen); -} - -/* - * str_addarg(str, len, arg, first) - add the string argument "arg" to - * the string "str". This is the first in the group when "first" - * is set (indicating that a comma should NOT be added to the front). - */ - -static int -str_addarg(str, len, arg, first) - -char *str; -int len; -char *arg; -int first; - -{ - register int arglen; - - arglen = strlen(arg); - if (!first) - { - arglen += 2; - } - if (len <= arglen) - { - return(0); - } - if (!first) - { - (void) strcat(str, ", "); - } - (void) strcat(str, arg); - return(len - arglen); -} - -/* - * err_compar(p1, p2) - comparison routine used by "qsort" - * for sorting errors. - */ - -int -err_compar(p1, p2) - -register struct errs *p1, *p2; - -{ - register int result; - - if ((result = p1->errnum - p2->errnum) == 0) - { - return(strcmp(p1->arg, p2->arg)); - } - return(result); -} - -/* - * error_count() - return the number of errors currently logged. - */ - -int -error_count() - -{ - return(errcnt); -} - -/* - * show_errors() - display on stdout the current log of errors. - */ - -void -show_errors() - -{ - register int cnt = 0; - register struct errs *errp = errs; - - printf("%d error%s:\n\n", errcnt, errcnt == 1 ? "" : "s"); - while (cnt++ < errcnt) - { - printf("%5s: %s\n", errp->arg, - errp->errnum == 0 ? "Not a number" : errmsg(errp->errnum)); - errp++; - } -} - -/* - * kill_procs(str) - send signals to processes, much like the "kill" - * command does; invoked in response to 'k'. - */ - -char *kill_procs(str) - -char *str; - -{ - register char *nptr; - int signum = SIGTERM; /* default */ - int procnum; - struct sigdesc *sigp; - int uid; - - /* reset error array */ - ERR_RESET; - - /* remember our uid */ - uid = getuid(); - - /* skip over leading white space */ - while (isspace(*str)) str++; - - if (str[0] == '-') - { - /* explicit signal specified */ - if ((nptr = next_field(str)) == NULL) - { - return(" kill: no processes specified"); - } - - if (isdigit(str[1])) - { - (void) scanint(str + 1, &signum); - if (signum <= 0 || signum >= NSIG) - { - return(" invalid signal number"); - } - } - else - { - /* translate the name into a number */ - for (sigp = sigdesc; sigp->name != NULL; sigp++) - { - if (strcmp(sigp->name, str + 1) == 0) - { - signum = sigp->number; - break; - } - } - - /* was it ever found */ - if (sigp->name == NULL) - { - return(" bad signal name"); - } - } - /* put the new pointer in place */ - str = nptr; - } - - /* loop thru the string, killing processes */ - do - { - if (scanint(str, &procnum) == -1) - { - ERROR(str, 0); - } - else - { - /* check process owner if we're not root */ - if (uid && (uid != proc_owner(procnum))) - { - ERROR(str, EACCES); - } - /* go in for the kill */ - else if (kill(procnum, signum) == -1) - { - /* chalk up an error */ - ERROR(str, errno); - } - } - } while ((str = next_field(str)) != NULL); - - /* return appropriate error string */ - return(err_string()); -} - -/* - * renice_procs(str) - change the "nice" of processes, much like the - * "renice" command does; invoked in response to 'r'. - */ - -char *renice_procs(str) - -char *str; - -{ - register char negate; - int prio; - int procnum; - int uid; - - ERR_RESET; - uid = getuid(); - - /* allow for negative priority values */ - if ((negate = (*str == '-')) != 0) - { - /* move past the minus sign */ - str++; - } - - /* use procnum as a temporary holding place and get the number */ - procnum = scanint(str, &prio); - - /* negate if necessary */ - if (negate) - { - prio = -prio; - } - -#if defined(PRIO_MIN) && defined(PRIO_MAX) - /* check for validity */ - if (procnum == -1 || prio < PRIO_MIN || prio > PRIO_MAX) - { - return(" bad priority value"); - } -#endif - - /* move to the first process number */ - if ((str = next_field(str)) == NULL) - { - return(" no processes specified"); - } - - /* loop thru the process numbers, renicing each one */ - do - { - if (scanint(str, &procnum) == -1) - { - ERROR(str, 0); - } - - /* check process owner if we're not root */ - else if (uid && (uid != proc_owner(procnum))) - { - ERROR(str, EACCES); - } - else if (setpriority(PRIO_PROCESS, procnum, prio) == -1) - { - ERROR(str, errno); - } - } while ((str = next_field(str)) != NULL); - - /* return appropriate error string */ - return(err_string()); -} - Index: head/contrib/top/display.h =================================================================== --- head/contrib/top/display.h +++ head/contrib/top/display.h @@ -1,43 +0,0 @@ -/* constants needed for display.c */ - -/* "type" argument for new_message function */ - -#define MT_standout 1 -#define MT_delayed 2 - -#include "machine.h" - -int display_updatecpus(struct statics *statics); -void clear_message(void); -int display_resize(void); -void i_header(char *text); -char *printable(char *string); -char *cpustates_tag(void); -void display_header(int t); -int display_init(struct statics *statics); -void i_arc(int *stats); -void i_carc(int *stats); -void i_cpustates(int *states); -void i_loadave(int mpid, double *avenrun); -void i_memory(int *stats); -void i_message(void); -void i_process(int line, char *thisline); -void i_procstates(int total, int *brkdn); -void i_swap(int *stats); -void i_timeofday(time_t *tod); -void i_uptime(struct timeval *bt, time_t *tod); -void new_message(); -int readline(char *buffer, int size, int numeric); -char *trim_header(char *text); -void u_arc(int *stats); -void u_carc(int *stats); -void u_cpustates(int *states); -void u_endscreen(int hi); -void u_header(char *text); -void u_loadave(int mpid, double *avenrun); -void u_memory(int *stats); -void u_message(void); -void u_process(int line, char *newline); -void u_procstates(int total, int *brkdn); -void u_swap(int *stats); -void z_cpustates(void); Index: head/contrib/top/display.c =================================================================== --- head/contrib/top/display.c +++ head/contrib/top/display.c @@ -1,1455 +0,0 @@ -/* - * Top users/processes display for Unix - * Version 3 - * - * This program may be freely redistributed, - * but this entire comment MUST remain intact. - * - * Copyright (c) 1984, 1989, William LeFebvre, Rice University - * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University - * - * $FreeBSD$ - */ - -/* - * This file contains the routines that display information on the screen. - * Each section of the screen has two routines: one for initially writing - * all constant and dynamic text, and one for only updating the text that - * changes. The prefix "i_" is used on all the "initial" routines and the - * prefix "u_" is used for all the "updating" routines. - * - * ASSUMPTIONS: - * None of the "i_" routines use any of the termcap capabilities. - * In this way, those routines can be safely used on terminals that - * have minimal (or nonexistant) terminal capabilities. - * - * The routines are called in this order: *_loadave, i_timeofday, - * *_procstates, *_cpustates, *_memory, *_message, *_header, - * *_process, u_endscreen. - */ - -#include "os.h" - -#include - -#include -#include -#include -#include -#include - -#include "screen.h" /* interface to screen package */ -#include "layout.h" /* defines for screen position layout */ -#include "display.h" -#include "top.h" -#include "top.local.h" -#include "boolean.h" -#include "machine.h" /* we should eliminate this!!! */ -#include "utils.h" - -#ifdef DEBUG -FILE *debug; -#endif - -/* imported from screen.c */ -extern int overstrike; - -static int lmpid = 0; -static int last_hi = 0; /* used in u_process and u_endscreen */ -static int lastline = 0; -static int display_width = MAX_COLS; - -#define lineindex(l) ((l)*display_width) - - -/* things initialized by display_init and used thruout */ - -/* buffer of proc information lines for display updating */ -char *screenbuf = NULL; - -static char **procstate_names; -static char **cpustate_names; -static char **memory_names; -static char **arc_names; -static char **carc_names; -static char **swap_names; - -static int num_procstates; -static int num_cpustates; -static int num_memory; -static int num_swap; - -static int *lprocstates; -static int *lcpustates; -static int *lmemory; -static int *lswap; - -static int num_cpus; -static int *cpustate_columns; -static int cpustate_total_length; -static int cpustates_column; - -static enum { OFF, ON, ERASE } header_status = ON; - -static int string_count(); -static void summary_format(); -static void line_update(); - -int x_lastpid = 10; -int y_lastpid = 0; -int x_loadave = 33; -int x_loadave_nompid = 15; -int y_loadave = 0; -int x_procstate = 0; -int y_procstate = 1; -int x_brkdn = 15; -int y_brkdn = 1; -int x_mem = 5; -int y_mem = 3; -int x_arc = 5; -int y_arc = 4; -int x_carc = 5; -int y_carc = 5; -int x_swap = 6; -int y_swap = 4; -int y_message = 5; -int x_header = 0; -int y_header = 6; -int x_idlecursor = 0; -int y_idlecursor = 5; -int y_procs = 7; - -int y_cpustates = 2; -int Header_lines = 7; - -int display_resize() - -{ - register int lines; - - /* first, deallocate any previous buffer that may have been there */ - if (screenbuf != NULL) - { - free(screenbuf); - } - - /* calculate the current dimensions */ - /* if operating in "dumb" mode, we only need one line */ - lines = smart_terminal ? screen_length - Header_lines : 1; - - if (lines < 0) - lines = 0; - /* we don't want more than MAX_COLS columns, since the machine-dependent - modules make static allocations based on MAX_COLS and we don't want - to run off the end of their buffers */ - display_width = screen_width; - if (display_width >= MAX_COLS) - { - display_width = MAX_COLS - 1; - } - - /* now, allocate space for the screen buffer */ - screenbuf = (char *)malloc(lines * display_width); - if (screenbuf == (char *)NULL) - { - /* oops! */ - return(-1); - } - - /* return number of lines available */ - /* for dumb terminals, pretend like we can show any amount */ - return(smart_terminal ? lines : Largest); -} - -int display_updatecpus(statics) - -struct statics *statics; - -{ - register int *lp; - register int lines; - register int i; - - /* call resize to do the dirty work */ - lines = display_resize(); - if (pcpu_stats) - num_cpus = statics->ncpus; - else - num_cpus = 1; - cpustates_column = 5; /* CPU: */ - if (num_cpus != 1) - cpustates_column += 2; /* CPU 0: */ - for (i = num_cpus; i > 9; i /= 10) - cpustates_column++; - - /* fill the "last" array with all -1s, to insure correct updating */ - lp = lcpustates; - i = num_cpustates * num_cpus; - while (--i >= 0) - { - *lp++ = -1; - } - - return(lines); -} - -int display_init(statics) - -struct statics *statics; - -{ - register int lines; - register char **pp; - register int *ip; - register int i; - - lines = display_updatecpus(statics); - - /* only do the rest if we need to */ - if (lines > -1) - { - /* save pointers and allocate space for names */ - procstate_names = statics->procstate_names; - num_procstates = string_count(procstate_names); - lprocstates = (int *)malloc(num_procstates * sizeof(int)); - - cpustate_names = statics->cpustate_names; - - swap_names = statics->swap_names; - num_swap = string_count(swap_names); - lswap = (int *)malloc(num_swap * sizeof(int)); - num_cpustates = string_count(cpustate_names); - lcpustates = (int *)malloc(num_cpustates * sizeof(int) * statics->ncpus); - cpustate_columns = (int *)malloc(num_cpustates * sizeof(int)); - - memory_names = statics->memory_names; - num_memory = string_count(memory_names); - lmemory = (int *)malloc(num_memory * sizeof(int)); - - arc_names = statics->arc_names; - carc_names = statics->carc_names; - - /* calculate starting columns where needed */ - cpustate_total_length = 0; - pp = cpustate_names; - ip = cpustate_columns; - while (*pp != NULL) - { - *ip++ = cpustate_total_length; - if ((i = strlen(*pp++)) > 0) - { - cpustate_total_length += i + 8; - } - } - } - - /* return number of lines available */ - return(lines); -} - -void -i_loadave(mpid, avenrun) - -int mpid; -double *avenrun; - -{ - register int i; - - /* i_loadave also clears the screen, since it is first */ - top_clear(); - - /* mpid == -1 implies this system doesn't have an _mpid */ - if (mpid != -1) - { - printf("last pid: %5d; ", mpid); - } - - printf("load averages"); - - for (i = 0; i < 3; i++) - { - printf("%c %5.2f", - i == 0 ? ':' : ',', - avenrun[i]); - } - lmpid = mpid; -} - -void -u_loadave(mpid, avenrun) - -int mpid; -double *avenrun; - -{ - register int i; - - if (mpid != -1) - { - /* change screen only when value has really changed */ - if (mpid != lmpid) - { - Move_to(x_lastpid, y_lastpid); - printf("%5d", mpid); - lmpid = mpid; - } - - /* i remembers x coordinate to move to */ - i = x_loadave; - } - else - { - i = x_loadave_nompid; - } - - /* move into position for load averages */ - Move_to(i, y_loadave); - - /* display new load averages */ - /* we should optimize this and only display changes */ - for (i = 0; i < 3; i++) - { - printf("%s%5.2f", - i == 0 ? "" : ", ", - avenrun[i]); - } -} - -void -i_timeofday(tod) - -time_t *tod; - -{ - /* - * Display the current time. - * "ctime" always returns a string that looks like this: - * - * Sun Sep 16 01:03:52 1973 - * 012345678901234567890123 - * 1 2 - * - * We want indices 11 thru 18 (length 8). - */ - - if (smart_terminal) - { - Move_to(screen_width - 8, 0); - } - else - { - fputs(" ", stdout); - } -#ifdef DEBUG - { - char *foo; - foo = ctime(tod); - fputs(foo, stdout); - } -#endif - printf("%-8.8s\n", &(ctime(tod)[11])); - lastline = 1; -} - -static int ltotal = 0; -static char procstates_buffer[MAX_COLS]; - -/* - * *_procstates(total, brkdn, names) - print the process summary line - * - * Assumptions: cursor is at the beginning of the line on entry - * lastline is valid - */ - -void -i_procstates(total, brkdn) - -int total; -int *brkdn; - -{ - register int i; - - /* write current number of processes and remember the value */ - printf("%d processes:", total); - ltotal = total; - - /* put out enough spaces to get to column 15 */ - i = digits(total); - while (i++ < 4) - { - putchar(' '); - } - - /* format and print the process state summary */ - summary_format(procstates_buffer, brkdn, procstate_names); - fputs(procstates_buffer, stdout); - - /* save the numbers for next time */ - memcpy(lprocstates, brkdn, num_procstates * sizeof(int)); -} - -void -u_procstates(total, brkdn) - -int total; -int *brkdn; - -{ - static char new[MAX_COLS]; - register int i; - - /* update number of processes only if it has changed */ - if (ltotal != total) - { - /* move and overwrite */ -#if (x_procstate == 0) - Move_to(x_procstate, y_procstate); -#else - /* cursor is already there...no motion needed */ - /* assert(lastline == 1); */ -#endif - printf("%d", total); - - /* if number of digits differs, rewrite the label */ - if (digits(total) != digits(ltotal)) - { - fputs(" processes:", stdout); - /* put out enough spaces to get to column 15 */ - i = digits(total); - while (i++ < 4) - { - putchar(' '); - } - /* cursor may end up right where we want it!!! */ - } - - /* save new total */ - ltotal = total; - } - - /* see if any of the state numbers has changed */ - if (memcmp(lprocstates, brkdn, num_procstates * sizeof(int)) != 0) - { - /* format and update the line */ - summary_format(new, brkdn, procstate_names); - line_update(procstates_buffer, new, x_brkdn, y_brkdn); - memcpy(lprocstates, brkdn, num_procstates * sizeof(int)); - } -} - -#ifdef no_more -/* - * *_cpustates(states, names) - print the cpu state percentages - * - * Assumptions: cursor is on the PREVIOUS line - */ - -/* cpustates_tag() calculates the correct tag to use to label the line */ - -char *cpustates_tag() - -{ - register char *use; - - static char *short_tag = "CPU: "; - static char *long_tag = "CPU states: "; - - /* if length + strlen(long_tag) >= screen_width, then we have to - use the shorter tag (we subtract 2 to account for ": ") */ - if (cpustate_total_length + (int)strlen(long_tag) - 2 >= screen_width) - { - use = short_tag; - } - else - { - use = long_tag; - } - - /* set cpustates_column accordingly then return result */ - cpustates_column = strlen(use); - return(use); -} -#endif - -void -i_cpustates(states) - -int *states; - -{ - register int i = 0; - register int value; - register char **names; - register char *thisname; - int cpu; - -for (cpu = 0; cpu < num_cpus; cpu++) { - names = cpustate_names; - - /* print tag and bump lastline */ - if (num_cpus == 1) - printf("\nCPU: "); - else { - value = printf("\nCPU %d: ", cpu); - while (value++ <= cpustates_column) - printf(" "); - } - lastline++; - - /* now walk thru the names and print the line */ - while ((thisname = *names++) != NULL) - { - if (*thisname != '\0') - { - /* retrieve the value and remember it */ - value = *states++; - - /* if percentage is >= 1000, print it as 100% */ - printf((value >= 1000 ? "%s%4.0f%% %s" : "%s%4.1f%% %s"), - (i++ % num_cpustates) == 0 ? "" : ", ", - ((float)value)/10., - thisname); - } - } -} - - /* copy over values into "last" array */ - memcpy(lcpustates, states, num_cpustates * sizeof(int) * num_cpus); -} - -void -u_cpustates(states) - -int *states; - -{ - register int value; - register char **names; - register char *thisname; - register int *lp; - register int *colp; - int cpu; - -for (cpu = 0; cpu < num_cpus; cpu++) { - names = cpustate_names; - - Move_to(cpustates_column, y_cpustates + cpu); - lastline = y_cpustates + cpu; - lp = lcpustates + (cpu * num_cpustates); - colp = cpustate_columns; - - /* we could be much more optimal about this */ - while ((thisname = *names++) != NULL) - { - if (*thisname != '\0') - { - /* did the value change since last time? */ - if (*lp != *states) - { - /* yes, move and change */ - Move_to(cpustates_column + *colp, y_cpustates + cpu); - lastline = y_cpustates + cpu; - - /* retrieve value and remember it */ - value = *states; - - /* if percentage is >= 1000, print it as 100% */ - printf((value >= 1000 ? "%4.0f" : "%4.1f"), - ((double)value)/10.); - - /* remember it for next time */ - *lp = value; - } - } - - /* increment and move on */ - lp++; - states++; - colp++; - } -} -} - -void -z_cpustates() - -{ - register int i = 0; - register char **names; - register char *thisname; - register int *lp; - int cpu, value; - -for (cpu = 0; cpu < num_cpus; cpu++) { - names = cpustate_names; - - /* show tag and bump lastline */ - if (num_cpus == 1) - printf("\nCPU: "); - else { - value = printf("\nCPU %d: ", cpu); - while (value++ <= cpustates_column) - printf(" "); - } - lastline++; - - while ((thisname = *names++) != NULL) - { - if (*thisname != '\0') - { - printf("%s %% %s", (i++ % num_cpustates) == 0 ? "" : ", ", thisname); - } - } -} - - /* fill the "last" array with all -1s, to insure correct updating */ - lp = lcpustates; - i = num_cpustates * num_cpus; - while (--i >= 0) - { - *lp++ = -1; - } -} - -/* - * *_memory(stats) - print "Memory: " followed by the memory summary string - * - * Assumptions: cursor is on "lastline" - * for i_memory ONLY: cursor is on the previous line - */ - -char memory_buffer[MAX_COLS]; - -void -i_memory(stats) - -int *stats; - -{ - fputs("\nMem: ", stdout); - lastline++; - - /* format and print the memory summary */ - summary_format(memory_buffer, stats, memory_names); - fputs(memory_buffer, stdout); -} - -void -u_memory(stats) - -int *stats; - -{ - static char new[MAX_COLS]; - - /* format the new line */ - summary_format(new, stats, memory_names); - line_update(memory_buffer, new, x_mem, y_mem); -} - -/* - * *_arc(stats) - print "ARC: " followed by the ARC summary string - * - * Assumptions: cursor is on "lastline" - * for i_arc ONLY: cursor is on the previous line - */ -char arc_buffer[MAX_COLS]; - -void -i_arc(stats) - -int *stats; - -{ - if (arc_names == NULL) - return; - - fputs("\nARC: ", stdout); - lastline++; - - /* format and print the memory summary */ - summary_format(arc_buffer, stats, arc_names); - fputs(arc_buffer, stdout); -} - -void -u_arc(stats) - -int *stats; - -{ - static char new[MAX_COLS]; - - if (arc_names == NULL) - return; - - /* format the new line */ - summary_format(new, stats, arc_names); - line_update(arc_buffer, new, x_arc, y_arc); -} - - -/* - * *_carc(stats) - print "Compressed ARC: " followed by the summary string - * - * Assumptions: cursor is on "lastline" - * for i_carc ONLY: cursor is on the previous line - */ -char carc_buffer[MAX_COLS]; - -void -i_carc(stats) - -int *stats; - -{ - if (carc_names == NULL) - return; - - fputs("\n ", stdout); - lastline++; - - /* format and print the memory summary */ - summary_format(carc_buffer, stats, carc_names); - fputs(carc_buffer, stdout); -} - -void -u_carc(stats) - -int *stats; - -{ - static char new[MAX_COLS]; - - if (carc_names == NULL) - return; - - /* format the new line */ - summary_format(new, stats, carc_names); - line_update(carc_buffer, new, x_carc, y_carc); -} - -/* - * *_swap(stats) - print "Swap: " followed by the swap summary string - * - * Assumptions: cursor is on "lastline" - * for i_swap ONLY: cursor is on the previous line - */ - -char swap_buffer[MAX_COLS]; - -void -i_swap(stats) - -int *stats; - -{ - fputs("\nSwap: ", stdout); - lastline++; - - /* format and print the swap summary */ - summary_format(swap_buffer, stats, swap_names); - fputs(swap_buffer, stdout); -} - -void -u_swap(stats) - -int *stats; - -{ - static char new[MAX_COLS]; - - /* format the new line */ - summary_format(new, stats, swap_names); - line_update(swap_buffer, new, x_swap, y_swap); -} - -/* - * *_message() - print the next pending message line, or erase the one - * that is there. - * - * Note that u_message is (currently) the same as i_message. - * - * Assumptions: lastline is consistent - */ - -/* - * i_message is funny because it gets its message asynchronously (with - * respect to screen updates). - */ - -static char next_msg[MAX_COLS + 5]; -static int msglen = 0; -/* Invariant: msglen is always the length of the message currently displayed - on the screen (even when next_msg doesn't contain that message). */ - -void -i_message() - -{ - while (lastline < y_message) - { - fputc('\n', stdout); - lastline++; - } - if (next_msg[0] != '\0') - { - top_standout(next_msg); - msglen = strlen(next_msg); - next_msg[0] = '\0'; - } - else if (msglen > 0) - { - (void) clear_eol(msglen); - msglen = 0; - } -} - -void -u_message() - -{ - i_message(); -} - -static int header_length; - -/* - * Trim a header string to the current display width and return a newly - * allocated area with the trimmed header. - */ - -char * -trim_header(text) - -char *text; - -{ - char *s; - int width; - - s = NULL; - width = display_width; - header_length = strlen(text); - if (header_length >= width) { - s = malloc((width + 1) * sizeof(char)); - if (s == NULL) - return (NULL); - strncpy(s, text, width); - s[width] = '\0'; - } - return (s); -} - -/* - * *_header(text) - print the header for the process area - * - * Assumptions: cursor is on the previous line and lastline is consistent - */ - -void -i_header(text) - -char *text; - -{ - char *s; - - s = trim_header(text); - if (s != NULL) - text = s; - - if (header_status == ON) - { - putchar('\n'); - fputs(text, stdout); - lastline++; - } - else if (header_status == ERASE) - { - header_status = OFF; - } - free(s); -} - -/*ARGSUSED*/ -void -u_header(text) - -char *text __unused; /* ignored */ - -{ - - if (header_status == ERASE) - { - putchar('\n'); - lastline++; - clear_eol(header_length); - header_status = OFF; - } -} - -/* - * *_process(line, thisline) - print one process line - * - * Assumptions: lastline is consistent - */ - -void -i_process(line, thisline) - -int line; -char *thisline; - -{ - register char *p; - register char *base; - - /* make sure we are on the correct line */ - while (lastline < y_procs + line) - { - putchar('\n'); - lastline++; - } - - /* truncate the line to conform to our current screen width */ - thisline[display_width] = '\0'; - - /* write the line out */ - fputs(thisline, stdout); - - /* copy it in to our buffer */ - base = smart_terminal ? screenbuf + lineindex(line) : screenbuf; - p = strecpy(base, thisline); - - /* zero fill the rest of it */ - memzero(p, display_width - (p - base)); -} - -void -u_process(line, newline) - -int line; -char *newline; - -{ - register char *optr; - register int screen_line = line + Header_lines; - register char *bufferline; - - /* remember a pointer to the current line in the screen buffer */ - bufferline = &screenbuf[lineindex(line)]; - - /* truncate the line to conform to our current screen width */ - newline[display_width] = '\0'; - - /* is line higher than we went on the last display? */ - if (line >= last_hi) - { - /* yes, just ignore screenbuf and write it out directly */ - /* get positioned on the correct line */ - if (screen_line - lastline == 1) - { - putchar('\n'); - lastline++; - } - else - { - Move_to(0, screen_line); - lastline = screen_line; - } - - /* now write the line */ - fputs(newline, stdout); - - /* copy it in to the buffer */ - optr = strecpy(bufferline, newline); - - /* zero fill the rest of it */ - memzero(optr, display_width - (optr - bufferline)); - } - else - { - line_update(bufferline, newline, 0, line + Header_lines); - } -} - -void -u_endscreen(hi) - -int hi; - -{ - register int screen_line = hi + Header_lines; - register int i; - - if (smart_terminal) - { - if (hi < last_hi) - { - /* need to blank the remainder of the screen */ - /* but only if there is any screen left below this line */ - if (lastline + 1 < screen_length) - { - /* efficiently move to the end of currently displayed info */ - if (screen_line - lastline < 5) - { - while (lastline < screen_line) - { - putchar('\n'); - lastline++; - } - } - else - { - Move_to(0, screen_line); - lastline = screen_line; - } - - if (clear_to_end) - { - /* we can do this the easy way */ - putcap(clear_to_end); - } - else - { - /* use clear_eol on each line */ - i = hi; - while ((void) clear_eol(strlen(&screenbuf[lineindex(i++)])), i < last_hi) - { - putchar('\n'); - } - } - } - } - last_hi = hi; - - /* move the cursor to a pleasant place */ - Move_to(x_idlecursor, y_idlecursor); - lastline = y_idlecursor; - } - else - { - /* separate this display from the next with some vertical room */ - fputs("\n\n", stdout); - } -} - -void -display_header(t) - -int t; - -{ - if (t) - { - header_status = ON; - } - else if (header_status == ON) - { - header_status = ERASE; - } -} - -/*VARARGS2*/ -void -new_message(type, msgfmt, a1, a2, a3) - -int type; -char *msgfmt; -caddr_t a1, a2, a3; - -{ - register int i; - - /* first, format the message */ - (void) snprintf(next_msg, sizeof(next_msg), msgfmt, a1, a2, a3); - - if (msglen > 0) - { - /* message there already -- can we clear it? */ - if (!overstrike) - { - /* yes -- write it and clear to end */ - i = strlen(next_msg); - if ((type & MT_delayed) == 0) - { - type & MT_standout ? top_standout(next_msg) : - fputs(next_msg, stdout); - (void) clear_eol(msglen - i); - msglen = i; - next_msg[0] = '\0'; - } - } - } - else - { - if ((type & MT_delayed) == 0) - { - type & MT_standout ? top_standout(next_msg) : fputs(next_msg, stdout); - msglen = strlen(next_msg); - next_msg[0] = '\0'; - } - } -} - -void -clear_message() - -{ - if (clear_eol(msglen) == 1) - { - putchar('\r'); - } -} - -int -readline(buffer, size, numeric) - -char *buffer; -int size; -int numeric; - -{ - register char *ptr = buffer; - register char ch; - register char cnt = 0; - register char maxcnt = 0; - - /* allow room for null terminator */ - size -= 1; - - /* read loop */ - while ((fflush(stdout), read(0, ptr, 1) > 0)) - { - /* newline means we are done */ - if ((ch = *ptr) == '\n' || ch == '\r') - { - break; - } - - /* handle special editing characters */ - if (ch == ch_kill) - { - /* kill line -- account for overstriking */ - if (overstrike) - { - msglen += maxcnt; - } - - /* return null string */ - *buffer = '\0'; - putchar('\r'); - return(-1); - } - else if (ch == ch_erase) - { - /* erase previous character */ - if (cnt <= 0) - { - /* none to erase! */ - putchar('\7'); - } - else - { - fputs("\b \b", stdout); - ptr--; - cnt--; - } - } - /* check for character validity and buffer overflow */ - else if (cnt == size || (numeric && !isdigit(ch)) || - !isprint(ch)) - { - /* not legal */ - putchar('\7'); - } - else - { - /* echo it and store it in the buffer */ - putchar(ch); - ptr++; - cnt++; - if (cnt > maxcnt) - { - maxcnt = cnt; - } - } - } - - /* all done -- null terminate the string */ - *ptr = '\0'; - - /* account for the extra characters in the message area */ - /* (if terminal overstrikes, remember the furthest they went) */ - msglen += overstrike ? maxcnt : cnt; - - /* return either inputted number or string length */ - putchar('\r'); - return(cnt == 0 ? -1 : numeric ? atoi(buffer) : cnt); -} - -/* internal support routines */ - -static int string_count(pp) - -register char **pp; - -{ - register int cnt; - - cnt = 0; - while (*pp++ != NULL) - { - cnt++; - } - return(cnt); -} - -static void summary_format(str, numbers, names) - -char *str; -int *numbers; -register char **names; - -{ - register char *p; - register int num; - register char *thisname; - register int useM = No; - char rbuf[6]; - - /* format each number followed by its string */ - p = str; - while ((thisname = *names++) != NULL) - { - /* get the number to format */ - num = *numbers++; - - /* display only non-zero numbers */ - if (num > 0) - { - /* is this number in kilobytes? */ - if (thisname[0] == 'K') - { - /* yes: format it as a memory value */ - p = strecpy(p, format_k(num)); - - /* skip over the K, since it was included by format_k */ - p = strecpy(p, thisname+1); - } - /* is this number a ratio? */ - else if (thisname[0] == ':') - { - (void) snprintf(rbuf, sizeof(rbuf), "%.2f", - (float)*(numbers - 2) / (float)num); - p = strecpy(p, rbuf); - p = strecpy(p, thisname); - } - else - { - p = strecpy(p, itoa(num)); - p = strecpy(p, thisname); - } - } - - /* ignore negative numbers, but display corresponding string */ - else if (num < 0) - { - p = strecpy(p, thisname); - } - } - - /* if the last two characters in the string are ", ", delete them */ - p -= 2; - if (p >= str && p[0] == ',' && p[1] == ' ') - { - *p = '\0'; - } -} - -static void line_update(old, new, start, line) - -register char *old; -register char *new; -int start; -int line; - -{ - register int ch; - register int diff; - register int newcol = start + 1; - register int lastcol = start; - char cursor_on_line = No; - char *current; - - /* compare the two strings and only rewrite what has changed */ - current = old; -#ifdef DEBUG - fprintf(debug, "line_update, starting at %d\n", start); - fputs(old, debug); - fputc('\n', debug); - fputs(new, debug); - fputs("\n-\n", debug); -#endif - - /* start things off on the right foot */ - /* this is to make sure the invariants get set up right */ - if ((ch = *new++) != *old) - { - if (line - lastline == 1 && start == 0) - { - putchar('\n'); - } - else - { - Move_to(start, line); - } - cursor_on_line = Yes; - putchar(ch); - *old = ch; - lastcol = 1; - } - old++; - - /* - * main loop -- check each character. If the old and new aren't the - * same, then update the display. When the distance from the - * current cursor position to the new change is small enough, - * the characters that belong there are written to move the - * cursor over. - * - * Invariants: - * lastcol is the column where the cursor currently is sitting - * (always one beyond the end of the last mismatch). - */ - do /* yes, a do...while */ - { - if ((ch = *new++) != *old) - { - /* new character is different from old */ - /* make sure the cursor is on top of this character */ - diff = newcol - lastcol; - if (diff > 0) - { - /* some motion is required--figure out which is shorter */ - if (diff < 6 && cursor_on_line) - { - /* overwrite old stuff--get it out of the old buffer */ - printf("%.*s", diff, ¤t[lastcol-start]); - } - else - { - /* use cursor addressing */ - Move_to(newcol, line); - cursor_on_line = Yes; - } - /* remember where the cursor is */ - lastcol = newcol + 1; - } - else - { - /* already there, update position */ - lastcol++; - } - - /* write what we need to */ - if (ch == '\0') - { - /* at the end--terminate with a clear-to-end-of-line */ - (void) clear_eol(strlen(old)); - } - else - { - /* write the new character */ - putchar(ch); - } - /* put the new character in the screen buffer */ - *old = ch; - } - - /* update working column and screen buffer pointer */ - newcol++; - old++; - - } while (ch != '\0'); - - /* zero out the rest of the line buffer -- MUST BE DONE! */ - diff = display_width - newcol; - if (diff > 0) - { - memzero(old, diff); - } - - /* remember where the current line is */ - if (cursor_on_line) - { - lastline = line; - } -} - -/* - * printable(str) - make the string pointed to by "str" into one that is - * printable (i.e.: all ascii), by converting all non-printable - * characters into '?'. Replacements are done in place and a pointer - * to the original buffer is returned. - */ - -char *printable(str) - -char *str; - -{ - register char *ptr; - register char ch; - - ptr = str; - while ((ch = *ptr) != '\0') - { - if (!isprint(ch)) - { - *ptr = '?'; - } - ptr++; - } - return(str); -} - -void -i_uptime(bt, tod) - -struct timeval* bt; -time_t *tod; - -{ - time_t uptime; - int days, hrs, mins, secs; - - if (bt->tv_sec != -1) { - uptime = *tod - bt->tv_sec; - days = uptime / 86400; - uptime %= 86400; - hrs = uptime / 3600; - uptime %= 3600; - mins = uptime / 60; - secs = uptime % 60; - - /* - * Display the uptime. - */ - - if (smart_terminal) - { - Move_to((screen_width - 24) - (days > 9 ? 1 : 0), 0); - } - else - { - fputs(" ", stdout); - } - printf(" up %d+%02d:%02d:%02d", days, hrs, mins, secs); - } -} Index: head/contrib/top/getans =================================================================== --- head/contrib/top/getans +++ head/contrib/top/getans @@ -1,118 +0,0 @@ -#!/bin/sh -# getans prompt type default results_filename -# type is one of -# number -# integer -# neginteger -# file default=default filename -# path -# yesno default=0,1 corres yes or no -# string (default) - -RAWPMPT=$1 -TYP=$2 -DFLT=$3 -OFNM=$4 - -ny0="no"; ny1="yes" -if [ ${TYP} = "yesno" ]; then - eval ny=\$ny${DFLT} - pmpt="${RAWPMPT} [$ny]: " -else - if [ -z "${DFLT}" ]; then - pmpt="${RAWPMPT}" - else - pmpt="${RAWPMPT} [${DFLT}]: " - fi -fi -if [ x"`echo -n`" = x-n ] -then - c=\\c -else - n=-n -fi - -while : -do - echo $n "$pmpt"$c - read input - case "$TYP" in - number) - tmp=`echo $input | tr -d 0123456789.` - if [ -n "$tmp" ]; then - echo "Invalid number. Please try again." - continue - fi - ;; - - integer) - tmp=`echo $input | tr -d 0123456789` - if [ -n "$tmp" ]; then - echo "Invalid integer. Please try again." - continue - fi - ;; - - neginteger) - if [ "x$input" != "x-1" ]; then - tmp=`echo $input | tr -d 0123456789` - if [ -n "$tmp" ]; then - echo "Invalid integer. Please try again." - continue - fi - fi - ;; - - file) - if [ -z "$input" ]; then - input=${DFLT} - fi - if [ ! -f "$input" -a ! -d "$input" ]; then - echo "The file $input does not exist. Please try again." - continue - fi - ;; - - path) - if [ -z "$input" ]; then - input="${DFLT}" - fi - if [ ! -f "$input" ]; then - path=`echo $PATH | sed -e s'/::/ . /g' -e 's/:/ /g'` - x= - for elt in $path; do - if [ -f "$elt/$input" ]; then x=1; break; fi - done - if [ -z "$x" ] ;then - echo "The command $input was not found. Please try again." - continue - fi - fi - ;; - - yesno) - if [ -z "$input" ]; then - input="${DFLT}" - else - case $input in - y | yes) - input=1 ;; - n | no) - input=0 ;; - *) - echo 'Please answer "yes" or "no".' - continue ;; - esac - fi - ;; - - *) ;; - esac - break -done - -if [ -z "$input" ]; then - input="${DFLT}" -fi - -echo $input > ${OFNM} Index: head/contrib/top/getopt.c =================================================================== --- head/contrib/top/getopt.c +++ head/contrib/top/getopt.c @@ -1,90 +0,0 @@ -/* - * "getopt" routine customized for top. - */ - -/* - * Many modern-day Unix implementations already have this function - * in libc. The standard "getopt" is perfectly sufficient for top's - * needs. If such a function exists in libc then you certainly don't - * need to compile this one in. To prevent this function from being - * compiled, define "HAVE_GETOPT". This is usually done in the "CFLAGS" - * line of the corresponding machine module. - */ - -/* - * This empty declaration exists solely to placate overexhuberant C - * compilers that like to warn you about content-free files. - */ -static void __empty(); - -#ifndef HAVE_GETOPT - -/*LINTLIBRARY*/ - -#include "os.h" -#ifndef NULL -#define NULL 0 -#endif -#ifndef EOF -#define EOF (-1) -#endif -#define ERR(s, c) if(opterr){\ - extern int write();\ - char errbuf[2];\ - errbuf[0] = c; errbuf[1] = '\n';\ - (void) write(2, argv[0], strlen(argv[0]));\ - (void) write(2, s, strlen(s));\ - (void) write(2, errbuf, 2);} - - -int opterr = 1; -int optind = 1; -int optopt; -char *optarg; - -int -getopt(argc, argv, opts) -int argc; -char **argv, *opts; -{ - static int sp = 1; - register int c; - register char *cp; - - if(sp == 1) - if(optind >= argc || - argv[optind][0] != '-' || argv[optind][1] == '\0') - return(EOF); - else if(strcmp(argv[optind], "--") == 0) { - optind++; - return(EOF); - } - optopt = c = argv[optind][sp]; - if(c == ':' || (cp=strchr(opts, c)) == NULL) { - ERR(": unknown option, -", c); - if(argv[optind][++sp] == '\0') { - optind++; - sp = 1; - } - return('?'); - } - if(*++cp == ':') { - if(argv[optind][sp+1] != '\0') - optarg = &argv[optind++][sp+1]; - else if(++optind >= argc) { - ERR(": argument missing for -", c); - sp = 1; - return('?'); - } else - optarg = argv[optind++]; - sp = 1; - } else { - if(argv[optind][++sp] == '\0') { - sp = 1; - optind++; - } - optarg = NULL; - } - return(c); -} -#endif /* HAVE_GETOPT */ Index: head/contrib/top/install-sh =================================================================== --- head/contrib/top/install-sh +++ head/contrib/top/install-sh @@ -1,69 +0,0 @@ -#!/bin/sh -# -# this shell script is amazingly similar to the old and lamented -# BSD "install" command. It recognized the following options: -# -# -o target file owner -# -m target file mode -# -g target file group owner -# -# -# scan the options -# -while [ $# -gt 0 ]; do - case $1 in - -o) - owner=$2 - shift ; shift - ;; - - -m) - mode=$2 - shift; shift - ;; - - -g) - group=$2 - shift ; shift - ;; - - -*) - echo "install: unknown option $1" - exit - ;; - - *) - break - ;; - esac -done -# -# we need two more: filename and destination -# -if [ $# -ne 2 ]; then - echo "Usage: install [ -o owner ] [ -m mode ] [ -g group ] file destination" - exit -fi -# -# first, copy -# -cp $1 $2 -# -# normalize the name -# -dest=$2 -if [ -d $2 ]; then - dest=$2/`basename $1` -fi -# -# do optional things -# -if [ "$owner" ]; then - chown $owner $dest -fi -if [ "$group" ]; then - chgrp $group $dest -fi -if [ "$mode" ]; then - chmod $mode $dest -fi Index: head/contrib/top/layout.h =================================================================== --- head/contrib/top/layout.h +++ head/contrib/top/layout.h @@ -1,35 +0,0 @@ -/* - * Top - a top users display for Berkeley Unix - * - * This file defines the locations on tne screen for various parts of the - * display. These definitions are used by the routines in "display.c" for - * cursor addressing. - * - * $FreeBSD$ - */ - -extern int x_lastpid; /* 10 */ -extern int y_lastpid; /* 0 */ -extern int x_loadave; /* 33 */ -extern int x_loadave_nompid; /* 15 */ -extern int y_loadave; /* 0 */ -extern int x_procstate; /* 0 */ -extern int y_procstate; /* 1 */ -extern int x_brkdn; /* 15 */ -extern int y_brkdn; /* 1 */ -extern int x_mem; /* 5 */ -extern int y_mem; /* 3 */ -extern int x_arc; /* 5 */ -extern int y_arc; /* 4 */ -extern int x_carc; /* 5 */ -extern int y_carc; /* 5 */ -extern int x_swap; /* 6 */ -extern int y_swap; /* 4 */ -extern int y_message; /* 5 */ -extern int x_header; /* 0 */ -extern int y_header; /* 6 */ -extern int x_idlecursor; /* 0 */ -extern int y_idlecursor; /* 5 */ -extern int y_procs; /* 7 */ - -extern int y_cpustates; /* 2 */ Index: head/contrib/top/loadavg.h =================================================================== --- head/contrib/top/loadavg.h +++ head/contrib/top/loadavg.h @@ -1,57 +0,0 @@ -/* - * Top - a top users display for Berkeley Unix - * - * Defines required to access load average figures. - * - * This include file sets up everything we need to access the load average - * values in the kernel in a machine independent way. First, it sets the - * typedef "load_avg" to be either double or long (depending on what is - * needed), then it defines these macros appropriately: - * - * loaddouble(la) - convert load_avg to double. - * intload(i) - convert integer to load_avg. - */ - -/* - * We assume that if FSCALE is defined, then avenrun and ccpu are type long. - * If your machine is an exception (mips, perhaps?) then make adjustments - * here. - * - * Defined types: load_avg for load averages, pctcpu for cpu percentages. - */ -#if defined(__mips__) && !(defined(__NetBSD__) || defined(__FreeBSD__)) -# include -# if defined(FBITS) && !defined(FSCALE) -# define FSCALE (1 << FBITS) /* RISC/os on mips */ -# endif -#endif - -#ifdef FSCALE -# define FIXED_LOADAVG FSCALE -# define FIXED_PCTCPU FSCALE -#endif - -#ifdef ibm032 -# undef FIXED_LOADAVG -# undef FIXED_PCTCPU -# define FIXED_PCTCPU PCT_SCALE -#endif - - -#ifdef FIXED_PCTCPU - typedef long pctcpu; -# define pctdouble(p) ((double)(p) / FIXED_PCTCPU) -#else -typedef double pctcpu; -# define pctdouble(p) (p) -#endif - -#ifdef FIXED_LOADAVG - typedef fixpt_t load_avg; -# define loaddouble(la) ((double)(la) / FIXED_LOADAVG) -# define intload(i) ((int)((i) * FIXED_LOADAVG)) -#else - typedef double load_avg; -# define loaddouble(la) (la) -# define intload(i) ((double)(i)) -#endif Index: head/contrib/top/m-template =================================================================== --- head/contrib/top/m-template +++ head/contrib/top/m-template @@ -1,241 +0,0 @@ -/* - * top - a top users display for Unix - * - * THIS IS A TEMPLATE FILE FOR A MACHINE DEPENDENT (m_...c) FILE - * - * SYNOPSIS: one line description of machine this module works with - * - * DESCRIPTION: - * Detailed description of this machine dependent module. - * It can be multiple lines, but a blank comment line (one with only an - * asterisk) is considered to end it. Place here a complete list of - * the machines and OS versions that this module works on. - * - * LIBS: list of special libraries to include at link step (REMOVE THIS LINE IF NOT NEEDED) - * - * AUTHOR: your name and - */ - -#include "top.h" -#include "machine.h" - - -/* - * These definitions control the format of the per-process area - */ - -static char header[] = - " PID X PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND"; -/* 0123456 -- field to fill in starts at header+6 */ -#define UNAME_START 6 - -#define Proc_format \ - "%5d %-8.8s %3d %4d%6dK %4dK %-5s%4d:%02d %5.2f%% %5.2f%% %.14s" - -/* these are for detailing the process states */ - -int process_states[?]; -char *procstatenames[] = { - "", " sleeping, ", " ABANDONED, ", " running, ", " starting, ", - " zombie, ", " stopped, ", - NULL -}; - -/* these are for detailing the cpu states */ - -int cpu_states[?]; -char *cpustatenames[] = { - "user", "nice", "system", "idle", - NULL -}; - -/* these are for detailing the memory statistics */ - -int memory_stats[?]; -char *memorynames[] = { - "K available, ", "K in use, ", "K free, ", "K locked", NULL -}; - -/* useful externals */ -extern int errno; -extern char *sys_errlist[]; - -long lseek(); -long time(); -long percentages(); - -machine_init(statics) - -struct statics *statics; - -{ - return(0); -} - -char *format_header(uname_field) - -register char *uname_field; - -{ - register char *ptr; - - ptr = header + UNAME_START; - while (*uname_field != '\0') - { - *ptr++ = *uname_field++; - } - - return(header); -} - -get_system_info(si) - -struct system_info *si; - -{ -} - -static struct handle handle; - -caddr_t get_process_info(si, sel, compare) - -struct system_info *si; -struct process_select *sel; -int (*compare)(); - -{ - return((caddr_t)&handle); -} - -char fmt[128]; /* static area where result is built */ - -/* define what weighted cpu is. */ -#define weighted_cpu(pct, pp) ((pp)->p_time == 0 ? 0.0 : \ - ((pct) / (1.0 - exp((pp)->p_time * logcpu)))) - -char *format_next_process(handle, get_userid) - -caddr_t handle; -char *(*get_userid)(); - -{ - return(fmt); -} - -/* - * getkval(offset, ptr, size, refstr) - get a value out of the kernel. - * "offset" is the byte offset into the kernel for the desired value, - * "ptr" points to a buffer into which the value is retrieved, - * "size" is the size of the buffer (and the object to retrieve), - * "refstr" is a reference string used when printing error meessages, - * if "refstr" starts with a '!', then a failure on read will not - * be fatal (this may seem like a silly way to do things, but I - * really didn't want the overhead of another argument). - * - */ - -getkval(offset, ptr, size, refstr) - -unsigned long offset; -int *ptr; -int size; -char *refstr; - -{ - if (kvm_read(kd, offset, ptr, size) != size) - { - if (*refstr == '!') - { - return(0); - } - else - { - fprintf(stderr, "top: kvm_read for %s: %s\n", - refstr, sys_errlist[errno]); - quit(23); - } - } - return(1); -} - -/* comparison routine for qsort */ -/* NOTE: this is specific to the BSD proc structure, but it should - give you a good place to start. */ - -/* - * proc_compare - comparison function for "qsort" - * Compares the resource consumption of two processes using five - * distinct keys. The keys (in descending order of importance) are: - * percent cpu, cpu ticks, state, resident set size, total virtual - * memory usage. The process states are ordered as follows (from least - * to most important): WAIT, zombie, sleep, stop, start, run. The - * array declaration below maps a process state index into a number - * that reflects this ordering. - */ - -static unsigned char sorted_state[] = -{ - 0, /* not used */ - 3, /* sleep */ - 1, /* ABANDONED (WAIT) */ - 6, /* run */ - 5, /* start */ - 2, /* zombie */ - 4 /* stop */ -}; - -proc_compare(pp1, pp2) - -struct proc **pp1; -struct proc **pp2; - -{ - register struct proc *p1; - register struct proc *p2; - register int result; - register pctcpu lresult; - - /* remove one level of indirection */ - p1 = *pp1; - p2 = *pp2; - - /* compare percent cpu (pctcpu) */ - if ((lresult = p2->p_pctcpu - p1->p_pctcpu) == 0) - { - /* use cpticks to break the tie */ - if ((result = p2->p_cpticks - p1->p_cpticks) == 0) - { - /* use process state to break the tie */ - if ((result = sorted_state[p2->p_stat] - - sorted_state[p1->p_stat]) == 0) - { - /* use priority to break the tie */ - if ((result = p2->p_pri - p1->p_pri) == 0) - { - /* use resident set size (rssize) to break the tie */ - if ((result = p2->p_rssize - p1->p_rssize) == 0) - { - /* use total memory to break the tie */ - result = PROCSIZE(p2) - PROCSIZE(p1); - } - } - } - } - } - else - { - result = lresult < 0 ? -1 : 1; - } - - return(result); -} - -proc_owner(pid) - -int pid; - -{ - /* returns uid of owner of process pid */ - return(uid); -} - Index: head/contrib/top/machine.h =================================================================== --- head/contrib/top/machine.h +++ head/contrib/top/machine.h @@ -1,96 +0,0 @@ -/* - * $FreeBSD$ - */ - -/* - * This file defines the interface between top and the machine-dependent - * module. It is NOT machine dependent and should not need to be changed - * for any specific machine. - */ -#ifndef MACHINE_H -#define MACHINE_H - -#include "top.h" - -/* - * the statics struct is filled in by machine_init - */ -struct statics -{ - char **procstate_names; - char **cpustate_names; - char **memory_names; - char **arc_names; - char **carc_names; - char **swap_names; -#ifdef ORDER - char **order_names; -#endif - int ncpus; -}; - -/* - * the system_info struct is filled in by a machine dependent routine. - */ - -#ifdef p_active /* uw7 define macro p_active */ -#define P_ACTIVE p_pactive -#else -#define P_ACTIVE p_active -#endif - -struct system_info -{ - int last_pid; - double load_avg[NUM_AVERAGES]; - int p_total; - int P_ACTIVE; /* number of procs considered "active" */ - int *procstates; - int *cpustates; - int *memory; - int *arc; - int *carc; - int *swap; - struct timeval boottime; - int ncpus; -}; - -/* cpu_states is an array of percentages * 10. For example, - the (integer) value 105 is 10.5% (or .105). - */ - -/* - * the process_select struct tells get_process_info what processes we - * are interested in seeing - */ - -struct process_select -{ - int idle; /* show idle processes */ - int self; /* show self */ - int system; /* show system processes */ - int thread; /* show threads */ -#define TOP_MAX_UIDS 8 - int uid[TOP_MAX_UIDS]; /* only these uids (unless uid[0] == -1) */ - int wcpu; /* show weighted cpu */ - int jid; /* only this jid (unless jid == -1) */ - int jail; /* show jail ID */ - int swap; /* show swap usage */ - int kidle; /* show per-CPU idle threads */ - char *command; /* only this command (unless == NULL) */ -}; - -/* routines defined by the machine dependent module */ - -char *format_header(char *uname_field); -char *format_next_process(caddr_t handle, char *(*get_userid)(int), - int flags); -void toggle_pcpustats(void); -void get_system_info(struct system_info *si); -int machine_init(struct statics *statics, char do_unames); -int proc_owner(int pid); - -/* non-int routines typically used by the machine dependent module */ -char *printable(char *string); - -#endif /* MACHINE_H */ Index: head/contrib/top/metatop =================================================================== --- head/contrib/top/metatop +++ head/contrib/top/metatop @@ -1,25 +0,0 @@ -#! /bin/sh -# -# Top is very sensitive to differences in the kernel, so much so that an -# executable created on one sub-architecture may not work on others. It -# is also quite common for a minor OS revision to require recompilation of -# top. Both of these problems are especially prevalent on Suns. For -# example, a top executable made under SunOS 4.1.1 will not run correctly -# under SunOS 4.1.2, and vice versa. "metatop" attempts to solve this -# problem by choosing one of several possible top executables to run then -# executing it. -# -# To use metatop your operating system needs to have the command "uname" -# as part of the standard OS release. MAKE SURE IT DOES before proceeding. -# It will try to execute the command "top-`uname -m`-`uname -r`" For -# example, on a sparcstation 1 running SunOS 4.1.1, it will try to run -# "top-sun4c-4.1.1". -# -# INSTALLATION is easy. Just compile top as normal. Then use the command -# "make metainstall" (on the same machine!) instead of the usual. "make" -# will insure that this shell script is installed correctly then will install -# the most recently made top executable with the correct name. Remember: -# you will need to "make clean" and "make metainstall" on every different -# combination of sub-architecture and OS version that you have. -# -exec $0-`uname -m`-`uname -r` "$@" Index: head/contrib/top/os.h =================================================================== --- head/contrib/top/os.h +++ head/contrib/top/os.h @@ -1,38 +0,0 @@ -#include -#include /* This defines BSD */ -#if defined(BSD) && !defined(BSD4_4) && !defined(__osf__) -# include -# include -# define strchr(a, b) index((a), (b)) -# define strrchr(a, b) rindex((a), (b)) -# define memcpy(a, b, c) bcopy((b), (a), (c)) -# define memzero(a, b) bzero((a), (b)) -# define memcmp(a, b, c) bcmp((a), (b), (c)) -#if defined(NeXT) - typedef void sigret_t; -#else - typedef int sigret_t; -#endif - -/* system routines that don't return int */ -char *getenv(); -caddr_t malloc(); - -#else -# include -# define setbuffer(f, b, s) setvbuf((f), (b), (b) ? _IOFBF : _IONBF, (s)) -# include -# include -# include -# define memzero(a, b) memset((a), 0, (b)) - typedef void sigret_t; -#endif - -/* some systems declare sys_errlist in stdio.h! */ -#if defined(__NetBSD__) || defined(__FreeBSD__) -#if !defined(__m68k__) -# if !defined(__NetBSD132__) -#define SYS_ERRLIST_DECLARED -# endif /* __NetBSD132__ */ -#endif -#endif Index: head/contrib/top/patchlevel.h =================================================================== --- head/contrib/top/patchlevel.h +++ head/contrib/top/patchlevel.h @@ -1,2 +0,0 @@ -#define PATCHLEVEL 5 -#define BETA "beta12" Index: head/contrib/top/prime.c =================================================================== --- head/contrib/top/prime.c +++ head/contrib/top/prime.c @@ -1,41 +0,0 @@ -/* - * Prime number generator. It prints on stdout the next prime number - * higher than the number specified as argv[1]. - */ - -#include -#include - -main(argc, argv) - -int argc; -char *argv[]; - -{ - double i, j; - int f; - - if (argc < 2) - { - exit(1); - } - - i = atoi(argv[1]); - while (i++) - { - f=1; - for (j=2; j -#ifdef CBREAK -# include -# define SGTTY -#else -# ifdef TCGETA -# define TERMIO -# include -# else -# define TERMIOS -# include -# endif -#endif -#if defined(TERMIO) || defined(TERMIOS) -# ifndef TAB3 -# ifdef OXTABS -# define TAB3 OXTABS -# else -# define TAB3 0 -# endif -# endif -#endif -#include -#include -#include "screen.h" -#include "boolean.h" - -extern char *myname; - - -int overstrike; -int screen_length; -int screen_width; -char ch_erase; -char ch_kill; -char smart_terminal; -char PC; -char *tgetstr(); -char *tgoto(); -char termcap_buf[1024]; -char string_buffer[1024]; -char home[15]; -char lower_left[15]; -char *clear_line; -char *clear_screen; -char *clear_to_end; -char *cursor_motion; -char *start_standout; -char *end_standout; -char *terminal_init; -char *terminal_end; - -#ifdef SGTTY -static struct sgttyb old_settings; -static struct sgttyb new_settings; -#endif -#ifdef TERMIO -static struct termio old_settings; -static struct termio new_settings; -#endif -#ifdef TERMIOS -static struct termios old_settings; -static struct termios new_settings; -#endif -static char is_a_terminal = No; -#ifdef TOStop -static int old_lword; -static int new_lword; -#endif - -#define STDIN 0 -#define STDOUT 1 -#define STDERR 2 - -void -init_termcap(interactive) - -int interactive; - -{ - char *bufptr; - char *PCptr; - char *term_name; - char *getenv(); - int status; - - /* set defaults in case we aren't smart */ - screen_width = MAX_COLS; - screen_length = 0; - - if (!interactive) - { - /* pretend we have a dumb terminal */ - smart_terminal = No; - return; - } - - /* assume we have a smart terminal until proven otherwise */ - smart_terminal = Yes; - - /* get the terminal name */ - term_name = getenv("TERM"); - - /* if there is no TERM, assume it's a dumb terminal */ - /* patch courtesy of Sam Horrocks at telegraph.ics.uci.edu */ - if (term_name == NULL) - { - smart_terminal = No; - return; - } - - /* now get the termcap entry */ - if ((status = tgetent(termcap_buf, term_name)) != 1) - { - if (status == -1) - { - fprintf(stderr, "%s: can't open termcap file\n", myname); - } - else - { - fprintf(stderr, "%s: no termcap entry for a `%s' terminal\n", - myname, term_name); - } - - /* pretend it's dumb and proceed */ - smart_terminal = No; - return; - } - - /* "hardcopy" immediately indicates a very stupid terminal */ - if (tgetflag("hc")) - { - smart_terminal = No; - return; - } - - /* set up common terminal capabilities */ - if ((screen_length = tgetnum("li")) <= 0) - { - screen_length = smart_terminal = 0; - return; - } - - /* screen_width is a little different */ - if ((screen_width = tgetnum("co")) == -1) - { - screen_width = 79; - } - else - { - screen_width -= 1; - } - - /* terminals that overstrike need special attention */ - overstrike = tgetflag("os"); - - /* initialize the pointer into the termcap string buffer */ - bufptr = string_buffer; - - /* get "ce", clear to end */ - if (!overstrike) - { - clear_line = tgetstr("ce", &bufptr); - } - - /* get necessary capabilities */ - if ((clear_screen = tgetstr("cl", &bufptr)) == NULL || - (cursor_motion = tgetstr("cm", &bufptr)) == NULL) - { - smart_terminal = No; - return; - } - - /* get some more sophisticated stuff -- these are optional */ - clear_to_end = tgetstr("cd", &bufptr); - terminal_init = tgetstr("ti", &bufptr); - terminal_end = tgetstr("te", &bufptr); - start_standout = tgetstr("so", &bufptr); - end_standout = tgetstr("se", &bufptr); - - /* pad character */ - PC = (PCptr = tgetstr("pc", &bufptr)) ? *PCptr : 0; - - /* set convenience strings */ - (void) strncpy(home, tgoto(cursor_motion, 0, 0), sizeof(home) - 1); - home[sizeof(home) - 1] = '\0'; - /* (lower_left is set in get_screensize) */ - - /* get the actual screen size with an ioctl, if needed */ - /* This may change screen_width and screen_length, and it always - sets lower_left. */ - get_screensize(); - - /* if stdout is not a terminal, pretend we are a dumb terminal */ -#ifdef SGTTY - if (ioctl(STDOUT, TIOCGETP, &old_settings) == -1) - { - smart_terminal = No; - } -#endif -#ifdef TERMIO - if (ioctl(STDOUT, TCGETA, &old_settings) == -1) - { - smart_terminal = No; - } -#endif -#ifdef TERMIOS - if (tcgetattr(STDOUT, &old_settings) == -1) - { - smart_terminal = No; - } -#endif -} - -void -init_screen() - -{ - /* get the old settings for safe keeping */ -#ifdef SGTTY - if (ioctl(STDOUT, TIOCGETP, &old_settings) != -1) - { - /* copy the settings so we can modify them */ - new_settings = old_settings; - - /* turn on CBREAK and turn off character echo and tab expansion */ - new_settings.sg_flags |= CBREAK; - new_settings.sg_flags &= ~(ECHO|XTABS); - (void) ioctl(STDOUT, TIOCSETP, &new_settings); - - /* remember the erase and kill characters */ - ch_erase = old_settings.sg_erase; - ch_kill = old_settings.sg_kill; - -#ifdef TOStop - /* get the local mode word */ - (void) ioctl(STDOUT, TIOCLGET, &old_lword); - - /* modify it */ - new_lword = old_lword | LTOSTOP; - (void) ioctl(STDOUT, TIOCLSET, &new_lword); -#endif - /* remember that it really is a terminal */ - is_a_terminal = Yes; - - /* send the termcap initialization string */ - putcap(terminal_init); - } -#endif -#ifdef TERMIO - if (ioctl(STDOUT, TCGETA, &old_settings) != -1) - { - /* copy the settings so we can modify them */ - new_settings = old_settings; - - /* turn off ICANON, character echo and tab expansion */ - new_settings.c_lflag &= ~(ICANON|ECHO); - new_settings.c_oflag &= ~(TAB3); - new_settings.c_cc[VMIN] = 1; - new_settings.c_cc[VTIME] = 0; - (void) ioctl(STDOUT, TCSETA, &new_settings); - - /* remember the erase and kill characters */ - ch_erase = old_settings.c_cc[VERASE]; - ch_kill = old_settings.c_cc[VKILL]; - - /* remember that it really is a terminal */ - is_a_terminal = Yes; - - /* send the termcap initialization string */ - putcap(terminal_init); - } -#endif -#ifdef TERMIOS - if (tcgetattr(STDOUT, &old_settings) != -1) - { - /* copy the settings so we can modify them */ - new_settings = old_settings; - - /* turn off ICANON, character echo and tab expansion */ - new_settings.c_lflag &= ~(ICANON|ECHO); - new_settings.c_oflag &= ~(TAB3); - new_settings.c_cc[VMIN] = 1; - new_settings.c_cc[VTIME] = 0; - (void) tcsetattr(STDOUT, TCSADRAIN, &new_settings); - - /* remember the erase and kill characters */ - ch_erase = old_settings.c_cc[VERASE]; - ch_kill = old_settings.c_cc[VKILL]; - - /* remember that it really is a terminal */ - is_a_terminal = Yes; - - /* send the termcap initialization string */ - putcap(terminal_init); - } -#endif - - if (!is_a_terminal) - { - /* not a terminal at all---consider it dumb */ - smart_terminal = No; - } -} - -void -end_screen() - -{ - /* move to the lower left, clear the line and send "te" */ - if (smart_terminal) - { - putcap(lower_left); - putcap(clear_line); - fflush(stdout); - putcap(terminal_end); - } - - /* if we have settings to reset, then do so */ - if (is_a_terminal) - { -#ifdef SGTTY - (void) ioctl(STDOUT, TIOCSETP, &old_settings); -#ifdef TOStop - (void) ioctl(STDOUT, TIOCLSET, &old_lword); -#endif -#endif -#ifdef TERMIO - (void) ioctl(STDOUT, TCSETA, &old_settings); -#endif -#ifdef TERMIOS - (void) tcsetattr(STDOUT, TCSADRAIN, &old_settings); -#endif - } -} - -void -reinit_screen() - -{ - /* install our settings if it is a terminal */ - if (is_a_terminal) - { -#ifdef SGTTY - (void) ioctl(STDOUT, TIOCSETP, &new_settings); -#ifdef TOStop - (void) ioctl(STDOUT, TIOCLSET, &new_lword); -#endif -#endif -#ifdef TERMIO - (void) ioctl(STDOUT, TCSETA, &new_settings); -#endif -#ifdef TERMIOS - (void) tcsetattr(STDOUT, TCSADRAIN, &new_settings); -#endif - } - - /* send init string */ - if (smart_terminal) - { - putcap(terminal_init); - } -} - -void -get_screensize() - -{ - -#ifdef TIOCGWINSZ - - struct winsize ws; - - if (ioctl (1, TIOCGWINSZ, &ws) != -1) - { - if (ws.ws_row != 0) - { - screen_length = ws.ws_row; - } - if (ws.ws_col != 0) - { - screen_width = ws.ws_col - 1; - } - } - -#else -#ifdef TIOCGSIZE - - struct ttysize ts; - - if (ioctl (1, TIOCGSIZE, &ts) != -1) - { - if (ts.ts_lines != 0) - { - screen_length = ts.ts_lines; - } - if (ts.ts_cols != 0) - { - screen_width = ts.ts_cols - 1; - } - } - -#endif /* TIOCGSIZE */ -#endif /* TIOCGWINSZ */ - - (void) strncpy(lower_left, tgoto(cursor_motion, 0, screen_length - 1), - sizeof(lower_left) - 1); - lower_left[sizeof(lower_left) - 1] = '\0'; -} - -void -top_standout(char *msg) -{ - if (smart_terminal) - { - putcap(start_standout); - fputs(msg, stdout); - putcap(end_standout); - } - else - { - fputs(msg, stdout); - } -} - -void -top_clear() -{ - if (smart_terminal) - { - putcap(clear_screen); - } -} - -int -clear_eol(int len) -{ - if (smart_terminal && !overstrike && len > 0) - { - if (clear_line) - { - putcap(clear_line); - return(0); - } - else - { - while (len-- > 0) - { - putchar(' '); - } - return(1); - } - } - return(-1); -} - -void -go_home() - -{ - if (smart_terminal) - { - putcap(home); - } -} - -/* This has to be defined as a subroutine for tputs (instead of a macro) */ - -int -putstdout(int ch) -{ - return putchar(ch); -} Index: head/contrib/top/sigconv.awk =================================================================== --- head/contrib/top/sigconv.awk +++ head/contrib/top/sigconv.awk @@ -1,55 +0,0 @@ -# $FreeBSD$ - -BEGIN { - nsig = 0; - j = 0; - print "/* This file was automatically generated */" - print "/* by the awk script \"sigconv.awk\". */\n" - print "struct sigdesc {" - print " char *name;" - print " int number;" - print "};\n" - print "struct sigdesc sigdesc[] = {" - } - -/^#define[ \t][ \t]*SIG[A-Z]+[0-9]*[ \t]/ { - - j = sprintf("%d", $3); - str = $2; - - if (nsig < j) - nsig = j; - - siglist[j] = sprintf("{ \"%s\",\t%2d },", \ - substr(str, 4), j); - } -/^#[ \t]*define[ \t][ \t]*SIG[A-Z]+[0-9]*[ \t]/ { - - j = sprintf("%d", $4); - str = $3; - - if (nsig < j) - nsig = j; - - siglist[j] = sprintf("{ \"%s\",\t%2d },", \ - substr(str, 4), j); - } -/^#[ \t]*define[ \t][ \t]*_SIG[A-Z]+[0-9]*[ \t]/ { - - j = sprintf("%d", $4); - str = $3; - - if (nsig < j) - nsig = j; - - siglist[j] = sprintf("{ \"%s\",\t%2d },", \ - substr(str, 5), j); - } - -END { - for (n = 1; n <= nsig; n++) - if (siglist[n] != "") - printf(" %s\n", siglist[n]); - - printf(" { NULL,\t 0 }\n};\n"); - } Index: head/contrib/top/top.h =================================================================== --- head/contrib/top/top.h +++ head/contrib/top/top.h @@ -1,54 +0,0 @@ -/* - * $FreeBSD$ - */ -/* - * Top - a top users display for Berkeley Unix - * - * General (global) definitions - */ - -#ifndef TOP_H -#define TOP_H - -/* Current major version number */ -#define VERSION 3 - -/* Number of lines of header information on the standard screen */ -extern int Header_lines; /* 7 */ - -/* Maximum number of columns allowed for display */ -#define MAX_COLS 512 - -/* Log base 2 of 1024 is 10 (2^10 == 1024) */ -#define LOG1024 10 - -char *itoa(); -char *itoa7(); - -char *version_string(); - -/* Special atoi routine returns either a non-negative number or one of: */ -#define Infinity -1 -#define Invalid -2 - -/* maximum number we can have */ -#define Largest 0x7fffffff - -/* - * The entire display is based on these next numbers being defined as is. - */ - -#define NUM_AVERAGES 3 - -enum displaymodes { DISP_CPU = 0, DISP_IO, DISP_MAX }; - -/* - * Format modifiers - */ -#define FMT_SHOWARGS 0x00000001 - -extern enum displaymodes displaymode; - -extern int pcpu_stats; - -#endif /* TOP_H */ Index: head/contrib/top/top.c =================================================================== --- head/contrib/top/top.c +++ head/contrib/top/top.c @@ -1,1318 +0,0 @@ -char *copyright = - "Copyright (c) 1984 through 1996, William LeFebvre"; - -/* - * Top users/processes display for Unix - * Version 3 - * - * This program may be freely redistributed, - * but this entire comment MUST remain intact. - * - * Copyright (c) 1984, 1989, William LeFebvre, Rice University - * Copyright (c) 1989 - 1994, William LeFebvre, Northwestern University - * Copyright (c) 1994, 1995, William LeFebvre, Argonne National Laboratory - * Copyright (c) 1996, William LeFebvre, Group sys Consulting - * - * $FreeBSD$ - */ - -/* - * See the file "Changes" for information on version-to-version changes. - */ - -/* - * This file contains "main" and other high-level routines. - */ - -/* - * The following preprocessor variables, when defined, are used to - * distinguish between different Unix implementations: - * - * SIGHOLD - use SVR4 sighold function when defined - * SIGRELSE - use SVR4 sigrelse function when defined - * FD_SET - macros FD_SET and FD_ZERO are used when defined - */ - -#include "os.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -/* includes specific to top */ -#include "commands.h" -#include "display.h" /* interface to display package */ -#include "screen.h" /* interface to screen package */ -#include "top.h" -#include "top.local.h" -#include "boolean.h" -#include "machine.h" -#include "utils.h" -#include "username.h" - -/* Size of the stdio buffer given to stdout */ -#define Buffersize 2048 - -/* The buffer that stdio will use */ -char stdoutbuf[Buffersize]; - -/* build Signal masks */ -#define Smask(s) (1 << ((s) - 1)) - -/* for getopt: */ -extern int optind; -extern char *optarg; - -/* imported from screen.c */ -extern int overstrike; - -static int fmt_flags = 0; -int pcpu_stats = No; - -/* signal handling routines */ -sigret_t leave(); -sigret_t tstop(); -#ifdef SIGWINCH -sigret_t top_winch(int); -#endif - -volatile sig_atomic_t leaveflag; -volatile sig_atomic_t tstopflag; -volatile sig_atomic_t winchflag; - -/* internal routines */ -void quit(); - -/* values which need to be accessed by signal handlers */ -static int max_topn; /* maximum displayable processes */ - -/* miscellaneous things */ -struct process_select ps; -char *myname = "top"; -jmp_buf jmp_int; - -/* routines that don't return int */ - -char *username(); -char *ctime(); -char *kill_procs(); -char *renice_procs(); - -#ifdef ORDER -extern int (*compares[])(); -#else -extern int proc_compare(); -extern int io_compare(); -#endif -time_t time(); - -caddr_t get_process_info(struct system_info *si, struct process_select *sel, - int (*compare)(const void *, const void *)); - -/* different routines for displaying the user's identification */ -/* (values assigned to get_userid) */ -char *username(); -char *itoa7(); - -/* pointers to display routines */ -void (*d_loadave)(int mpid, double *avenrun) = i_loadave; -void (*d_procstates)(int total, int *brkdn) = i_procstates; -void (*d_cpustates)(int *states) = i_cpustates; -void (*d_memory)(int *stats) = i_memory; -void (*d_arc)(int *stats) = i_arc; -void (*d_carc)(int *stats) = i_carc; -void (*d_swap)(int *stats) = i_swap; -void (*d_message)(void) = i_message; -void (*d_header)(char *text) = i_header; -void (*d_process)(int line, char *thisline) = i_process; - -void reset_display(void); - -static void -reset_uids() -{ - for (size_t i = 0; i < TOP_MAX_UIDS; ++i) - ps.uid[i] = -1; -} - -static int -add_uid(int uid) -{ - size_t i = 0; - - /* Add the uid if there's room */ - for (; i < TOP_MAX_UIDS; ++i) - { - if (ps.uid[i] == -1 || ps.uid[i] == uid) - { - ps.uid[i] = uid; - break; - } - } - - return (i == TOP_MAX_UIDS); -} - -static void -rem_uid(int uid) -{ - size_t i = 0; - size_t where = TOP_MAX_UIDS; - - /* Look for the user to remove - no problem if it's not there */ - for (; i < TOP_MAX_UIDS; ++i) - { - if (ps.uid[i] == -1) - break; - if (ps.uid[i] == uid) - where = i; - } - - /* Make sure we don't leave a hole in the middle */ - if (where != TOP_MAX_UIDS) - { - ps.uid[where] = ps.uid[i-1]; - ps.uid[i-1] = -1; - } -} - -static int -handle_user(char *buf, size_t buflen) -{ - int rc = 0; - int uid = -1; - char *buf2 = buf; - - new_message(MT_standout, "Username to show (+ for all): "); - if (readline(buf, buflen, No) <= 0) - { - clear_message(); - return rc; - } - - if (buf[0] == '+' || buf[0] == '-') - { - if (buf[1] == '\0') - { - reset_uids(); - goto end; - } - else - ++buf2; - } - - if ((uid = userid(buf2)) == -1) - { - new_message(MT_standout, " %s: unknown user", buf2); - rc = 1; - goto end; - } - - if (buf2 == buf) - { - reset_uids(); - ps.uid[0] = uid; - goto end; - } - - if (buf[0] == '+') - { - if (add_uid(uid)) - { - new_message(MT_standout, " too many users, reset with '+'"); - rc = 1; - goto end; - } - } - else - rem_uid(uid); - -end: - putchar('\r'); - return rc; -} - -int -main(argc, argv) - -int argc; -char *argv[]; - -{ - register int i; - register int active_procs; - register int change; - - struct system_info system_info; - struct statics statics; - caddr_t processes; - - static char tempbuf1[50]; - static char tempbuf2[50]; - int old_sigmask; /* only used for BSD-style signals */ - int topn = Default_TOPN; - int delay = Default_DELAY; - int displays = 0; /* indicates unspecified */ - int sel_ret = 0; - time_t curr_time; - char *(*get_userid)() = username; - char *uname_field = "USERNAME"; - char *header_text; - char *env_top; - char **preset_argv; - int preset_argc = 0; - char **av; - int ac; - char dostates = No; - char do_unames = Yes; - char interactive = Maybe; - char warnings = 0; -#if Default_TOPN == Infinity - char topn_specified = No; -#endif - char ch; - char *iptr; - char no_command = 1; - struct timeval timeout; -#ifdef ORDER - char *order_name = NULL; - int order_index = 0; -#endif -#ifndef FD_SET - /* FD_SET and friends are not present: fake it */ - typedef int fd_set; -#define FD_ZERO(x) (*(x) = 0) -#define FD_SET(f, x) (*(x) = 1< 0) - { - if ((myname = strrchr(argv[0], '/')) == 0) - { - myname = argv[0]; - } - else - { - myname++; - } - } - - /* initialize some selection options */ - ps.idle = Yes; - ps.self = -1; - ps.system = No; - reset_uids(); - ps.thread = No; - ps.wcpu = 1; - ps.jid = -1; - ps.jail = No; - ps.swap = No; - ps.kidle = Yes; - ps.command = NULL; - - /* get preset options from the environment */ - if ((env_top = getenv("TOP")) != NULL) - { - av = preset_argv = argparse(env_top, &preset_argc); - ac = preset_argc; - - /* set the dummy argument to an explanatory message, in case - getopt encounters a bad argument */ - preset_argv[0] = "while processing environment"; - } - - /* process options */ - do { - /* if we're done doing the presets, then process the real arguments */ - if (preset_argc == 0) - { - ac = argc; - av = argv; - - /* this should keep getopt happy... */ - optind = 1; - } - - while ((i = getopt(ac, av, "CSIHPabijJ:nquvzs:d:U:m:o:tw")) != EOF) - { - switch(i) - { - case 'v': /* show version number */ - fprintf(stderr, "%s: version %s\n", - myname, version_string()); - exit(1); - break; - - case 'u': /* toggle uid/username display */ - do_unames = !do_unames; - break; - - case 'U': /* display only username's processes */ - if ((ps.uid[0] = userid(optarg)) == -1) - { - fprintf(stderr, "%s: unknown user\n", optarg); - exit(1); - } - break; - - case 'S': /* show system processes */ - ps.system = !ps.system; - break; - - case 'I': /* show idle processes */ - ps.idle = !ps.idle; - break; - - case 'i': /* go interactive regardless */ - interactive = Yes; - break; - - case 'n': /* batch, or non-interactive */ - case 'b': - interactive = No; - break; - - case 'a': - fmt_flags ^= FMT_SHOWARGS; - break; - - case 'd': /* number of displays to show */ - if ((i = atoiwi(optarg)) == Invalid || i == 0) - { - fprintf(stderr, - "%s: warning: display count should be positive -- option ignored\n", - myname); - warnings++; - } - else - { - displays = i; - } - break; - - case 's': - if ((delay = atoi(optarg)) < 0 || (delay == 0 && getuid() != 0)) - { - fprintf(stderr, - "%s: warning: seconds delay should be positive -- using default\n", - myname); - delay = Default_DELAY; - warnings++; - } - break; - - case 'q': /* be quick about it */ - /* only allow this if user is really root */ - if (getuid() == 0) - { - /* be very un-nice! */ - (void) nice(-20); - } - else - { - fprintf(stderr, - "%s: warning: `-q' option can only be used by root\n", - myname); - warnings++; - } - break; - - case 'm': /* select display mode */ - if (strcmp(optarg, "io") == 0) { - displaymode = DISP_IO; - } else if (strcmp(optarg, "cpu") == 0) { - displaymode = DISP_CPU; - } else { - fprintf(stderr, - "%s: warning: `-m' option can only take args " - "'io' or 'cpu'\n", - myname); - exit(1); - } - break; - - case 'o': /* select sort order */ -#ifdef ORDER - order_name = optarg; -#else - fprintf(stderr, - "%s: this platform does not support arbitrary ordering. Sorry.\n", - myname); - warnings++; -#endif - break; - - case 't': - ps.self = (ps.self == -1) ? getpid() : -1; - break; - - case 'C': - ps.wcpu = !ps.wcpu; - break; - - case 'H': - ps.thread = !ps.thread; - break; - - case 'j': - ps.jail = !ps.jail; - break; - - case 'J': /* display only jail's processes */ - if ((ps.jid = jail_getid(optarg)) == -1) - { - fprintf(stderr, "%s: unknown jail\n", optarg); - exit(1); - } - ps.jail = 1; - break; - - case 'P': - pcpu_stats = !pcpu_stats; - break; - - case 'w': - ps.swap = 1; - break; - - case 'z': - ps.kidle = !ps.kidle; - break; - - default: - fprintf(stderr, -"Top version %s\n" -"Usage: %s [-abCHIijnPqStuvwz] [-d count] [-m io | cpu] [-o field] [-s time]\n" -" [-J jail] [-U username] [number]\n", - version_string(), myname); - exit(1); - } - } - - /* get count of top processes to display (if any) */ - if (optind < ac) - { - if ((topn = atoiwi(av[optind])) == Invalid) - { - fprintf(stderr, - "%s: warning: process display count should be non-negative -- using default\n", - myname); - warnings++; - } -#if Default_TOPN == Infinity - else - { - topn_specified = Yes; - } -#endif - } - - /* tricky: remember old value of preset_argc & set preset_argc = 0 */ - i = preset_argc; - preset_argc = 0; - - /* repeat only if we really did the preset arguments */ - } while (i != 0); - - /* set constants for username/uid display correctly */ - if (!do_unames) - { - uname_field = " UID "; - get_userid = itoa7; - } - - /* initialize the kernel memory interface */ - if (machine_init(&statics, do_unames) == -1) - { - exit(1); - } - -#ifdef ORDER - /* determine sorting order index, if necessary */ - if (order_name != NULL) - { - if ((order_index = string_index(order_name, statics.order_names)) == -1) - { - char **pp; - - fprintf(stderr, "%s: '%s' is not a recognized sorting order.\n", - myname, order_name); - fprintf(stderr, "\tTry one of these:"); - pp = statics.order_names; - while (*pp != NULL) - { - fprintf(stderr, " %s", *pp++); - } - fputc('\n', stderr); - exit(1); - } - } -#endif - -#ifdef no_initialization_needed - /* initialize the hashing stuff */ - if (do_unames) - { - init_hash(); - } -#endif - - /* initialize termcap */ - init_termcap(interactive); - - /* get the string to use for the process area header */ - header_text = format_header(uname_field); - - /* initialize display interface */ - if ((max_topn = display_init(&statics)) == -1) - { - fprintf(stderr, "%s: can't allocate sufficient memory\n", myname); - exit(4); - } - - /* print warning if user requested more processes than we can display */ - if (topn > max_topn) - { - fprintf(stderr, - "%s: warning: this terminal can only display %d processes.\n", - myname, max_topn); - warnings++; - } - - /* adjust for topn == Infinity */ - if (topn == Infinity) - { - /* - * For smart terminals, infinity really means everything that can - * be displayed, or Largest. - * On dumb terminals, infinity means every process in the system! - * We only really want to do that if it was explicitly specified. - * This is always the case when "Default_TOPN != Infinity". But if - * topn wasn't explicitly specified and we are on a dumb terminal - * and the default is Infinity, then (and only then) we use - * "Nominal_TOPN" instead. - */ -#if Default_TOPN == Infinity - topn = smart_terminal ? Largest : - (topn_specified ? Largest : Nominal_TOPN); -#else - topn = Largest; -#endif - } - - /* set header display accordingly */ - display_header(topn > 0); - - /* determine interactive state */ - if (interactive == Maybe) - { - interactive = smart_terminal; - } - - /* if # of displays not specified, fill it in */ - if (displays == 0) - { - displays = smart_terminal ? Infinity : 1; - } - - /* hold interrupt signals while setting up the screen and the handlers */ -#ifdef SIGHOLD - sighold(SIGINT); - sighold(SIGQUIT); - sighold(SIGTSTP); -#else - old_sigmask = sigblock(Smask(SIGINT) | Smask(SIGQUIT) | Smask(SIGTSTP)); -#endif - init_screen(); - (void) signal(SIGINT, leave); - (void) signal(SIGQUIT, leave); - (void) signal(SIGTSTP, tstop); -#ifdef SIGWINCH - (void) signal(SIGWINCH, top_winch); -#endif -#ifdef SIGRELSE - sigrelse(SIGINT); - sigrelse(SIGQUIT); - sigrelse(SIGTSTP); -#else - (void) sigsetmask(old_sigmask); -#endif - if (warnings) - { - fputs("....", stderr); - fflush(stderr); /* why must I do this? */ - sleep((unsigned)(3 * warnings)); - fputc('\n', stderr); - } - -restart: - - /* - * main loop -- repeat while display count is positive or while it - * indicates infinity (by being -1) - */ - - while ((displays == -1) || (displays-- > 0)) - { - int (*compare)(); - - - /* get the current stats */ - get_system_info(&system_info); - -#ifdef ORDER - compare = compares[order_index]; -#else - if (displaymode == DISP_CPU) - compare = proc_compare; - else - compare = io_compare; -#endif - - /* get the current set of processes */ - processes = - get_process_info(&system_info, &ps, compare); - - /* display the load averages */ - (*d_loadave)(system_info.last_pid, - system_info.load_avg); - - /* display the current time */ - /* this method of getting the time SHOULD be fairly portable */ - time(&curr_time); - i_uptime(&system_info.boottime, &curr_time); - i_timeofday(&curr_time); - - /* display process state breakdown */ - (*d_procstates)(system_info.p_total, - system_info.procstates); - - /* display the cpu state percentage breakdown */ - if (dostates) /* but not the first time */ - { - (*d_cpustates)(system_info.cpustates); - } - else - { - /* we'll do it next time */ - if (smart_terminal) - { - z_cpustates(); - } - else - { - putchar('\n'); - } - dostates = Yes; - } - - /* display memory stats */ - (*d_memory)(system_info.memory); - (*d_arc)(system_info.arc); - (*d_carc)(system_info.carc); - - /* display swap stats */ - (*d_swap)(system_info.swap); - - /* handle message area */ - (*d_message)(); - - /* update the header area */ - (*d_header)(header_text); - - if (topn > 0) - { - /* determine number of processes to actually display */ - /* this number will be the smallest of: active processes, - number user requested, number current screen accomodates */ - active_procs = system_info.P_ACTIVE; - if (active_procs > topn) - { - active_procs = topn; - } - if (active_procs > max_topn) - { - active_procs = max_topn; - } - - /* now show the top "n" processes. */ - for (i = 0; i < active_procs; i++) - { - (*d_process)(i, format_next_process(processes, get_userid, - fmt_flags)); - } - } - else - { - i = 0; - } - - /* do end-screen processing */ - u_endscreen(i); - - /* now, flush the output buffer */ - if (fflush(stdout) != 0) - { - new_message(MT_standout, " Write error on stdout"); - putchar('\r'); - quit(1); - /*NOTREACHED*/ - } - - /* only do the rest if we have more displays to show */ - if (displays) - { - /* switch out for new display on smart terminals */ - if (smart_terminal) - { - if (overstrike) - { - reset_display(); - } - else - { - d_loadave = u_loadave; - d_procstates = u_procstates; - d_cpustates = u_cpustates; - d_memory = u_memory; - d_arc = u_arc; - d_carc = u_carc; - d_swap = u_swap; - d_message = u_message; - d_header = u_header; - d_process = u_process; - } - } - - no_command = Yes; - if (!interactive) - { - sleep(delay); - if (leaveflag) { - end_screen(); - exit(0); - } - } - else while (no_command) - { - /* assume valid command unless told otherwise */ - no_command = No; - - /* set up arguments for select with timeout */ - FD_ZERO(&readfds); - FD_SET(0, &readfds); /* for standard input */ - timeout.tv_sec = delay; - timeout.tv_usec = 0; - - if (leaveflag) { - end_screen(); - exit(0); - } - - if (tstopflag) { - /* move to the lower left */ - end_screen(); - fflush(stdout); - - /* default the signal handler action */ - (void) signal(SIGTSTP, SIG_DFL); - - /* unblock the signal and send ourselves one */ -#ifdef SIGRELSE - sigrelse(SIGTSTP); -#else - (void) sigsetmask(sigblock(0) & ~(1 << (SIGTSTP - 1))); -#endif - (void) kill(0, SIGTSTP); - - /* reset the signal handler */ - (void) signal(SIGTSTP, tstop); - - /* reinit screen */ - reinit_screen(); - reset_display(); - tstopflag = 0; - goto restart; - } - - if (winchflag) { - /* reascertain the screen dimensions */ - get_screensize(); - - /* tell display to resize */ - max_topn = display_resize(); - - /* reset the signal handler */ - (void) signal(SIGWINCH, top_winch); - - reset_display(); - winchflag = 0; - goto restart; - } - - /* wait for either input or the end of the delay period */ - sel_ret = select(2, &readfds, NULL, NULL, &timeout); - if (sel_ret < 0 && errno != EINTR) - quit(0); - if (sel_ret > 0) - { - int newval; - char *errmsg; - - /* something to read -- clear the message area first */ - clear_message(); - - /* now read it and convert to command strchr */ - /* (use "change" as a temporary to hold strchr) */ - if (read(0, &ch, 1) != 1) - { - /* read error: either 0 or -1 */ - new_message(MT_standout, " Read error on stdin"); - putchar('\r'); - quit(1); - /*NOTREACHED*/ - } - if ((iptr = strchr(command_chars, ch)) == NULL) - { - if (ch != '\r' && ch != '\n') - { - /* illegal command */ - new_message(MT_standout, " Command not understood"); - } - putchar('\r'); - no_command = Yes; - } - else - { - change = iptr - command_chars; - if (overstrike && change > CMD_OSLIMIT) - { - /* error */ - new_message(MT_standout, - " Command cannot be handled by this terminal"); - putchar('\r'); - no_command = Yes; - } - else switch(change) - { - case CMD_redraw: /* redraw screen */ - reset_display(); - break; - - case CMD_update: /* merely update display */ - /* is the load average high? */ - if (system_info.load_avg[0] > LoadMax) - { - /* yes, go home for visual feedback */ - go_home(); - fflush(stdout); - } - break; - - case CMD_quit: /* quit */ - quit(0); - /*NOTREACHED*/ - break; - - case CMD_help1: /* help */ - case CMD_help2: - reset_display(); - top_clear(); - show_help(); - top_standout("Hit any key to continue: "); - fflush(stdout); - (void) read(0, &ch, 1); - break; - - case CMD_errors: /* show errors */ - if (error_count() == 0) - { - new_message(MT_standout, - " Currently no errors to report."); - putchar('\r'); - no_command = Yes; - } - else - { - reset_display(); - top_clear(); - show_errors(); - top_standout("Hit any key to continue: "); - fflush(stdout); - (void) read(0, &ch, 1); - } - break; - - case CMD_number1: /* new number */ - case CMD_number2: - new_message(MT_standout, - "Number of processes to show: "); - newval = readline(tempbuf1, 8, Yes); - if (newval > -1) - { - if (newval > max_topn) - { - new_message(MT_standout | MT_delayed, - " This terminal can only display %d processes.", - max_topn); - putchar('\r'); - } - - if (newval == 0) - { - /* inhibit the header */ - display_header(No); - } - else if (newval > topn && topn == 0) - { - /* redraw the header */ - display_header(Yes); - d_header = i_header; - } - topn = newval; - } - break; - - case CMD_delay: /* new seconds delay */ - new_message(MT_standout, "Seconds to delay: "); - if ((i = readline(tempbuf1, 8, Yes)) > -1) - { - if ((delay = i) == 0 && getuid() != 0) - { - delay = 1; - } - } - clear_message(); - break; - - case CMD_displays: /* change display count */ - new_message(MT_standout, - "Displays to show (currently %s): ", - displays == -1 ? "infinite" : - itoa(displays)); - if ((i = readline(tempbuf1, 10, Yes)) > 0) - { - displays = i; - } - else if (i == 0) - { - quit(0); - } - clear_message(); - break; - - case CMD_kill: /* kill program */ - new_message(0, "kill "); - if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) - { - if ((errmsg = kill_procs(tempbuf2)) != NULL) - { - new_message(MT_standout, "%s", errmsg); - putchar('\r'); - no_command = Yes; - } - } - else - { - clear_message(); - } - break; - - case CMD_renice: /* renice program */ - new_message(0, "renice "); - if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) - { - if ((errmsg = renice_procs(tempbuf2)) != NULL) - { - new_message(MT_standout, "%s", errmsg); - putchar('\r'); - no_command = Yes; - } - } - else - { - clear_message(); - } - break; - - case CMD_idletog: - case CMD_idletog2: - ps.idle = !ps.idle; - new_message(MT_standout | MT_delayed, - " %sisplaying idle processes.", - ps.idle ? "D" : "Not d"); - putchar('\r'); - break; - - case CMD_selftog: - ps.self = (ps.self == -1) ? getpid() : -1; - new_message(MT_standout | MT_delayed, - " %sisplaying self.", - (ps.self == -1) ? "D" : "Not d"); - putchar('\r'); - break; - - case CMD_user: - if (handle_user(tempbuf2, sizeof(tempbuf2))) - no_command = Yes; - break; - - case CMD_thrtog: - ps.thread = !ps.thread; - new_message(MT_standout | MT_delayed, - " Displaying threads %s", - ps.thread ? "separately" : "as a count"); - header_text = format_header(uname_field); - reset_display(); - putchar('\r'); - break; - case CMD_wcputog: - ps.wcpu = !ps.wcpu; - new_message(MT_standout | MT_delayed, - " Displaying %s CPU", - ps.wcpu ? "weighted" : "raw"); - header_text = format_header(uname_field); - reset_display(); - putchar('\r'); - break; - case CMD_viewtog: - if (++displaymode == DISP_MAX) - displaymode = 0; - header_text = format_header(uname_field); - display_header(Yes); - d_header = i_header; - reset_display(); - break; - case CMD_viewsys: - ps.system = !ps.system; - break; - case CMD_showargs: - fmt_flags ^= FMT_SHOWARGS; - break; -#ifdef ORDER - case CMD_order: - new_message(MT_standout, - "Order to sort: "); - if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) - { - if ((i = string_index(tempbuf2, statics.order_names)) == -1) - { - new_message(MT_standout, - " %s: unrecognized sorting order", tempbuf2); - no_command = Yes; - } - else - { - order_index = i; - } - putchar('\r'); - } - else - { - clear_message(); - } - break; -#endif - case CMD_jidtog: - ps.jail = !ps.jail; - new_message(MT_standout | MT_delayed, - " %sisplaying jail ID.", - ps.jail ? "D" : "Not d"); - header_text = format_header(uname_field); - reset_display(); - putchar('\r'); - break; - - case CMD_jail: - new_message(MT_standout, - "Jail to show (+ for all): "); - if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) - { - if (tempbuf2[0] == '+' && - tempbuf2[1] == '\0') - { - ps.jid = -1; - } - else if ((i = jail_getid(tempbuf2)) == -1) - { - new_message(MT_standout, - " %s: unknown jail", tempbuf2); - no_command = Yes; - } - else - { - ps.jid = i; - } - if (ps.jail == 0) { - ps.jail = 1; - new_message(MT_standout | - MT_delayed, " Displaying jail " - "ID."); - header_text = - format_header(uname_field); - reset_display(); - } - putchar('\r'); - } - else - { - clear_message(); - } - break; - - case CMD_kidletog: - ps.kidle = !ps.kidle; - new_message(MT_standout | MT_delayed, - " %sisplaying system idle process.", - ps.kidle ? "D" : "Not d"); - putchar('\r'); - break; - case CMD_pcputog: - pcpu_stats = !pcpu_stats; - new_message(MT_standout | MT_delayed, - " Displaying %sCPU statistics.", - pcpu_stats ? "per-" : "global "); - toggle_pcpustats(); - max_topn = display_updatecpus(&statics); - reset_display(); - putchar('\r'); - break; - case CMD_swaptog: - ps.swap = !ps.swap; - new_message(MT_standout | MT_delayed, - " %sisplaying per-process swap usage.", - ps.swap ? "D" : "Not d"); - header_text = format_header(uname_field); - reset_display(); - putchar('\r'); - break; - default: - new_message(MT_standout, " BAD CASE IN SWITCH!"); - putchar('\r'); - } - } - - /* flush out stuff that may have been written */ - fflush(stdout); - } - } - } - } - -#ifdef DEBUG - fclose(debug); -#endif - quit(0); - /*NOTREACHED*/ -} - -/* - * reset_display() - reset all the display routine pointers so that entire - * screen will get redrawn. - */ - -void -reset_display() - -{ - d_loadave = i_loadave; - d_procstates = i_procstates; - d_cpustates = i_cpustates; - d_memory = i_memory; - d_arc = i_arc; - d_carc = i_carc; - d_swap = i_swap; - d_message = i_message; - d_header = i_header; - d_process = i_process; -} - -/* - * signal handlers - */ - -sigret_t leave() /* exit under normal conditions -- INT handler */ - -{ - leaveflag = 1; -} - -sigret_t tstop(i) /* SIGTSTP handler */ - -int i; - -{ - tstopflag = 1; -} - -#ifdef SIGWINCH -sigret_t top_winch(int i) /* SIGWINCH handler */ -{ - winchflag = 1; -} -#endif - -void quit(status) /* exit under duress */ - -int status; - -{ - end_screen(); - exit(status); - /*NOTREACHED*/ -} Index: head/contrib/top/top.local.hs =================================================================== --- head/contrib/top/top.local.hs +++ head/contrib/top/top.local.hs @@ -1,68 +0,0 @@ -/* - * Top - a top users display for Berkeley Unix - * - * Definitions for things that might vary between installations. - */ - -/* - * The space command forces an immediate update. Sometimes, on loaded - * systems, this update will take a significant period of time (because all - * the output is buffered). So, if the short-term load average is above - * "LoadMax", then top will put the cursor home immediately after the space - * is pressed before the next update is attempted. This serves as a visual - * acknowledgement of the command. On Suns, "LoadMax" will get multiplied by - * "FSCALE" before being compared to avenrun[0]. Therefore, "LoadMax" - * should always be specified as a floating point number. - */ -#ifndef LoadMax -#define LoadMax %LoadMax% -#endif - -/* - * "Table_size" defines the size of the hash tables used to map uid to - * username. The number of users in /etc/passwd CANNOT be greater than - * this number. If the error message "table overflow: too many users" - * is printed by top, then "Table_size" needs to be increased. Things will - * work best if the number is a prime number that is about twice the number - * of lines in /etc/passwd. - */ -#ifndef Table_size -#define Table_size %TableSize% -#endif - -/* - * "Nominal_TOPN" is used as the default TOPN when Default_TOPN is Infinity - * and the output is a dumb terminal. If we didn't do this, then - * installations who use a default TOPN of Infinity will get every - * process in the system when running top on a dumb terminal (or redirected - * to a file). Note that Nominal_TOPN is a default: it can still be - * overridden on the command line, even with the value "infinity". - */ -#ifndef Nominal_TOPN -#define Nominal_TOPN %NominalTopn% -#endif - -#ifndef Default_TOPN -#define Default_TOPN %topn% -#endif - -#ifndef Default_DELAY -#define Default_DELAY %delay% -#endif - -/* - * If the local system's getpwnam interface uses random access to retrieve - * a record (i.e.: 4.3 systems, Sun "yellow pages"), then defining - * RANDOM_PW will take advantage of that fact. If RANDOM_PW is defined, - * then getpwnam is used and the result is cached. If not, then getpwent - * is used to read and cache the password entries sequentially until the - * desired one is found. - * - * We initially set RANDOM_PW to something which is controllable by the - * Configure script. Then if its value is 0, we undef it. - */ - -#define RANDOM_PW %random% -#if RANDOM_PW == 0 -#undef RANDOM_PW -#endif Index: head/contrib/top/top.xs =================================================================== --- head/contrib/top/top.xs +++ head/contrib/top/top.xs @@ -1,459 +0,0 @@ -.\" NOTE: changes to the manual page for "top" should be made in the -.\" file "top.X" and NOT in the file "top.1". -.\" $FreeBSD$ -.nr N %topn% -.nr D %delay% -.TH TOP 1 Local -.UC 4 -.SH NAME -top \- display and update information about the top cpu processes -.SH SYNOPSIS -.B top -[ -.B \-abCHIijnPqStuvwz -] [ -.BI \-d count -] [ -.BI \-m io | cpu -] [ -.BI \-o field -] [ -.BI \-s time -] [ -.BI \-J jail -] [ -.BI \-U username -] [ -.I number -] -.SH DESCRIPTION -.\" This defines appropriate quote strings for nroff and troff -.ds lq \&" -.ds rq \&" -.if t .ds lq `` -.if t .ds rq '' -.\" Just in case these number registers aren't set yet... -.if \nN==0 .nr N 10 -.if \nD==0 .nr D 2 -.I Top -displays the top -.if !\nN==-1 \nN -processes on the system and periodically updates this information. -.if \nN==-1 \ -\{\ -If standard output is an intelligent terminal (see below) then -as many processes as will fit on the terminal screen are displayed -by default. Otherwise, a good number of them are shown (around 20). -.\} -Raw cpu percentage is used to rank the processes. If -.I number -is given, then the top -.I number -processes will be displayed instead of the default. -.PP -.I Top -makes a distinction between terminals that support advanced capabilities -and those that do not. This -distinction affects the choice of defaults for certain options. In the -remainder of this document, an \*(lqintelligent\*(rq terminal is one that -supports cursor addressing, clear screen, and clear to end of line. -Conversely, a \*(lqdumb\*(rq terminal is one that does not support such -features. If the output of -.I top -is redirected to a file, it acts as if it were being run on a dumb -terminal. -.SH OPTIONS -.TP -.B \-C -Toggle CPU display mode. -By default top displays the weighted CPU percentage in the WCPU column -(this is the same value that -.IR ps (1) -displays as CPU). -Each time -.B \-C -flag is passed it toggles between \*(lqraw cpu\*(rq mode -and \*(lqweighted cpu\*(rq mode, showing the \*(lqCPU\*(rq or -the \*(lqWCPU\*(rq column respectively. -.TP -.B \-S -Show system processes in the display. Normally, system processes such as -the pager and the swapper are not shown. This option makes them visible. -.TP -.B \-a -Display command names derived from the argv[] vector, rather than real -executable name. It's useful when you want to watch applications, that -puts their status information there. If the real name differs from argv[0], -it will be displayed in parenthesis. -.TP -.B \-b -Use \*(lqbatch\*(rq mode. In this mode, all input from the terminal is -ignored. Interrupt characters (such as ^C and ^\e) still have an effect. -This is the default on a dumb terminal, or when the output is not a terminal. -.TP -.B \-H -Display each thread for a multithreaded process individually. -By default a single summary line is displayed for each process. -.TP -.B \-i -Use \*(lqinteractive\*(rq mode. In this mode, any input is immediately -read for processing. See the section on \*(lqInteractive Mode\*(rq -for an explanation of -which keys perform what functions. After the command is processed, the -screen will immediately be updated, even if the command was not -understood. This mode is the default when standard output is an -intelligent terminal. -.TP -.B \-I -Do not display idle processes. -By default, top displays both active and idle processes. -.TP -.B \-j -Display the -.IR jail (8) -ID. -.TP -.B \-t -Do not display the -.I top -process. -.TP -.BI \-m display -Display either 'cpu' or 'io' statistics. Default is 'cpu'. -.TP -.B \-n -Use \*(lqnon-interactive\*(rq mode. This is identical to \*(lqbatch\*(rq -mode. -.TP -.B \-P -Display per-cpu CPU usage statistics. -.TP -.B \-q -Renice -.I top -to -20 so that it will run faster. This can be used when the system is -being very sluggish to improve the possibility of discovering the problem. -This option can only be used by root. -.TP -.B \-u -Do not take the time to map uid numbers to usernames. Normally, -.I top -will read as much of the file \*(lq/etc/passwd\*(rq as is necessary to map -all the user id numbers it encounters into login names. This option -disables all that, while possibly decreasing execution time. The uid -numbers are displayed instead of the names. -.TP -.B \-v -Write version number information to stderr then exit immediately. -No other processing takes place when this option is used. To see current -revision information while top is running, use the help command \*(lq?\*(rq. -.TP -.B \-w -Display approximate swap usage for each process. -.TP -.B \-z -Do not display the system idle process. -.TP -.BI \-d count -Show only -.I count -displays, then exit. A display is considered to be one update of the -screen. This option allows the user to select the number of displays he -wants to see before -.I top -automatically exits. For intelligent terminals, no upper limit -is set. The default is 1 for dumb terminals. -.TP -.BI \-s time -Set the delay between screen updates to -.I time -seconds. The default delay between updates is \nD seconds. -.TP -.BI \-o field -Sort the process display area on the specified field. The field name -is the name of the column as seen in the output, but in lower case: -\*(lqcpu\*(lq, \*(rqsize\*(lq, \*(rqres\*(lq, \*(rqtime\*(lq, -\*(rqpri\*(lq, \*(rqthreads\*(lq, \*(lqtotal\*(lq, \*(rqread\*(lq, -\*(rqwrite\*(lq, \*(rqfault\*(lq, \*(rqvcsw\*(lq, \*(rqivcsw\*(lq, -\*(lqjid\*(lq, \*(rqswap\*(lq or \*(rqpid\*(lq. -.TP -.BI \-J jail -Show only those processes owned by -.IR jail . -This may be either the -.B jid -or -.B name -of the jail. -Use -.B 0 -to limit to host processes. -Using this option implies the -.B \-j -flag. -.PP -.BI \-U username -Show only those processes owned by -.IR username . -This option currently only accepts usernames and will not understand -uid numbers. -.PP -Both -.I count -and -.I number -fields can be specified as \*(lqinfinite\*(rq, indicating that they can -stretch as far as possible. This is accomplished by using any proper -prefix of the keywords -\*(lqinfinity\*(rq, -\*(lqmaximum\*(rq, -or -\*(lqall\*(rq. -The default for -.I count -on an intelligent terminal is, in fact, -.BI infinity . -.PP -The environment variable -.B TOP -is examined for options before the command line is scanned. This enables -a user to set his or her own defaults. The number of processes to display -can also be specified in the environment variable -.BR TOP . -The options -.BR \-a , -.BR \-C , -.BR \-H , -.BR \-I , -.BR \-j , -.BR \-P , -.BR \-S , -.BR \-t , -.BR \-u , -.BR \-w , -and -.B \-z -are actually toggles. A second specification of any of these options -will negate the first. Thus a user who has the environment variable -.B TOP -set to \*(lq\-I\*(rq may use the command \*(lqtop \-I\*(rq to see idle processes. -.SH "INTERACTIVE MODE" -When -.I top -is running in \*(lqinteractive mode\*(rq, it reads commands from the -terminal and acts upon them accordingly. In this mode, the terminal is -put in \*(lqCBREAK\*(rq, so that a character will be -processed as soon as it is typed. Almost always, a key will be -pressed when -.I top -is between displays; that is, while it is waiting for -.I time -seconds to elapse. If this is the case, the command will be -processed and the display will be updated immediately thereafter -(reflecting any changes that the command may have specified). This -happens even if the command was incorrect. If a key is pressed while -.I top -is in the middle of updating the display, it will finish the update and -then process the command. Some commands require additional information, -and the user will be prompted accordingly. While typing this information -in, the user's erase and kill keys (as set up by the command -.IR stty ) -are recognized, and a newline terminates the input. -.PP -These commands are currently recognized (^L refers to control-L): -.TP -.B ^L -Redraw the screen. -.IP "\fBh\fP\ or\ \fB?\fP" -Display a summary of the commands (help screen). Version information -is included in this display. -.TP -.B q -Quit -.IR top. -.TP -.B d -Change the number of displays to show (prompt for new number). -Remember that the next display counts as one, so typing -.B d1 -will make -.I top -show one final display and then immediately exit. -.TP -.B m -Toggle the display between 'cpu' and 'io' modes. -.TP -.B n or # -Change the number of processes to display (prompt for new number). -.TP -.B s -Change the number of seconds to delay between displays -(prompt for new number). -.TP -.B S -Toggle the display of system processes. -.TP -.B a -Toggle the display of process titles. -.TP -.B k -Send a signal (\*(lqkill\*(rq by default) to a list of processes. This -acts similarly to the command -.IR kill (1)). -.TP -.B r -Change the priority (the \*(lqnice\*(rq) of a list of processes. -This acts similarly to the command -.IR renice (8)). -.TP -.B u -Display only processes owned by a specific set of usernames (prompt for -username). If the username specified is simply \*(lq+\*(rq or \*(lq-\*(rq, -then processes belonging to all users will be displayed. Usernames can be added -to and removed from the set by prepending them with \*(lq+\*(rq and -\*(lq-\*(rq, respectively. -.TP -.B o -Change the order in which the display is sorted. This command is not -available on all systems. The sort key names vary from system to system -but usually include: \*(lqcpu\*(rq, \*(lqres\*(rq, \*(lqsize\*(rq, -\*(lqtime\*(rq. The default is cpu. -.TP -.B e -Display a list of system errors (if any) generated by the last -.BR k ill -or -.BR r enice -command. -.TP -.B H -Toggle the display of threads. -.TP -.B i -(or -.BR I ) -Toggle the display of idle processes. -.TP -.B j -Toggle the display of -.IR jail (8) -ID. -.TP -.B J -Display only processes owned by a specific jail (prompt for jail). -If the jail specified is simply \*(lq+\*(rq, then processes belonging -to all jails and the host will be displayed. -This will also enable the display of JID. -.TP -.B P -Toggle the display of per-CPU statistics. -.TP -.B t -Toggle the display of the -.I top -process. -.TP -.B w -Toggle the display of swap usage. -.TP -.B z -Toggle the display of the system idle process. -.SH "THE DISPLAY" -The actual display varies depending on the specific variant of Unix -that the machine is running. This description may not exactly match -what is seen by top running on this particular machine. Differences -are listed at the end of this manual entry. -.PP -The top few lines of the display show general information -about the state of the system, including -the last process id assigned to a process (on most systems), -the three load averages, -the current time, -the number of existing processes, -the number of processes in each state -(sleeping, running, starting, zombies, and stopped), -and a percentage of time spent in each of the processor states -(user, nice, system, and idle). -It also includes information about physical and virtual memory allocation. -.PP -The remainder of the screen displays information about individual -processes. This display is similar in spirit to -.IR ps (1) -but it is not exactly the same. PID is the process id, -JID, when displayed, is the -.IR jail (8) -ID corresponding to the process, -USERNAME is the name of the process's owner (if -.B \-u -is specified, a UID column will be substituted for USERNAME), -PRI is the current priority of the process, -NICE is the nice amount (in the range \-20 to 20), -SIZE is the total size of the process (text, data, and stack), -RES is the current amount of resident memory, -SWAP is the approximate amount of swap, if enabled -(SIZE, RES and SWAP are given in kilobytes), -STATE is the current state (one of \*(lqSTART\*(rq, \*(lqRUN\*(rq -(shown as \*(lqCPUn\*(rq on SMP systems), \*(lqSLEEP\*(rq, \*(lqSTOP\*(rq, -\*(lqZOMB\*(rq, \*(lqWAIT\*(rq, \*(lqLOCK\*(rq or the event on which the -process waits), -C is the processor number on which the process is executing -(visible only on SMP systems), -TIME is the number of system and user cpu seconds that the process has used, -WCPU, when displayed, is the weighted cpu percentage (this is the same -value that -.IR ps (1) -displays as CPU), -CPU is the raw percentage and is the field that is sorted to determine -the order of the processes, and -COMMAND is the name of the command that the process is currently running -(if the process is swapped out, this column is marked \*(lq\*(rq). -.SH NOTES -If a process is in the \*(lqSLEEP\*(rq or \*(lqLOCK\*(rq state, -the state column will report the name of the event or lock on which the -process is waiting. -Lock names are prefixed with an asterisk \*(lq*\*(rq while sleep events -are not. -.SH AUTHOR -William LeFebvre, EECS Department, Northwestern University -.SH ENVIRONMENT -.DT -TOP user-configurable defaults for options. -.SH FILES -.DT -/dev/kmem kernel memory -.br -/dev/mem physical memory -.br -/etc/passwd used to map uid numbers to user names -.br -/boot/kernel/kernel system image -.SH BUGS -Don't shoot me, but the default for -.B \-I -has changed once again. So many people were confused by the fact that -.I top -wasn't showing them all the processes that I have decided to make the -default behavior show idle processes, just like it did in version 2. -But to appease folks who can't stand that behavior, I have added the -ability to set \*(lqdefault\*(rq options in the environment variable -.B TOP -(see the OPTIONS section). Those who want the behavior that version -3.0 had need only set the environment variable -.B TOP -to \*(lq\-I\*(rq. -.PP -The command name for swapped processes should be tracked down, but this -would make the program run slower. -.PP -As with -.IR ps (1), -things can change while -.I top -is collecting information for an update. The picture it gives is only a -close approximation to reality. -.SH "SEE ALSO" -kill(1), -ps(1), -stty(1), -mem(4), -renice(8) Index: head/contrib/top/username.h =================================================================== --- head/contrib/top/username.h +++ head/contrib/top/username.h @@ -1,23 +0,0 @@ -/* - * Top users/processes display for Unix - * Version 3 - * - * This program may be freely redistributed, - * but this entire comment MUST remain intact. - * - * Copyright (c) 1984, 1989, William LeFebvre, Rice University - * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University - * Copyright (c) 2016, Randy Westlund - * - * $FreeBSD$ - */ -#ifndef USERNAME_H -#define USERNAME_H - -int enter_user(int uid, char *name, int wecare); -int get_user(int uid); -void init_hash(void); -char *username(int uid); -int userid(char *username); - -#endif /* USERNAME_H */ Index: head/contrib/top/username.c =================================================================== --- head/contrib/top/username.c +++ head/contrib/top/username.c @@ -1,195 +0,0 @@ -/* - * Top users/processes display for Unix - * Version 3 - * - * This program may be freely redistributed, - * but this entire comment MUST remain intact. - * - * Copyright (c) 1984, 1989, William LeFebvre, Rice University - * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University - * - * $FreeBSD$ - */ - -/* - * Username translation code for top. - * - * These routines handle uid to username mapping. - * They use a hashing table scheme to reduce reading overhead. - * For the time being, these are very straightforward hashing routines. - * Maybe someday I'll put in something better. But with the advent of - * "random access" password files, it might not be worth the effort. - * - * Changes to these have been provided by John Gilmore (gnu@toad.com). - * - * The hash has been simplified in this release, to avoid the - * table overflow problems of previous releases. If the value - * at the initial hash location is not right, it is replaced - * by the right value. Collisions will cause us to call getpw* - * but hey, this is a cache, not the Library of Congress. - * This makes the table size independent of the passwd file size. - */ - -#include -#include - -#include -#include -#include -#include - -#include "top.local.h" -#include "utils.h" -#include "username.h" - -struct hash_el { - int uid; - char name[MAXLOGNAME]; -}; - -#define is_empty_hash(x) (hash_table[x].name[0] == 0) - -/* simple minded hashing function */ -/* Uid "nobody" is -2 results in hashit(-2) = -2 which is out of bounds for - the hash_table. Applied abs() function to fix. 2/16/96 tpugh -*/ -#define hashit(i) (abs(i) % Table_size) - -/* K&R requires that statically declared tables be initialized to zero. */ -/* We depend on that for hash_table and YOUR compiler had BETTER do it! */ -struct hash_el hash_table[Table_size]; - - -void -init_hash() - -{ - /* - * There used to be some steps we had to take to initialize things. - * We don't need to do that anymore, but we will leave this stub in - * just in case future changes require initialization steps. - */ -} - -char *username(uid) - -int uid; - -{ - register int hashindex; - - hashindex = hashit(uid); - if (is_empty_hash(hashindex) || (hash_table[hashindex].uid != uid)) - { - /* not here or not right -- get it out of passwd */ - hashindex = get_user(uid); - } - return(hash_table[hashindex].name); -} - -int userid(username) - -char *username; - -{ - struct passwd *pwd; - - /* Eventually we want this to enter everything in the hash table, - but for now we just do it simply and remember just the result. - */ - - if ((pwd = getpwnam(username)) == NULL) - { - return(-1); - } - - /* enter the result in the hash table */ - enter_user(pwd->pw_uid, username, 1); - - /* return our result */ - return(pwd->pw_uid); -} - -int enter_user(uid, name, wecare) - -int uid; -char *name; -int wecare; /* 1 = enter it always, 0 = nice to have */ - -{ - register int hashindex; - -#ifdef DEBUG - fprintf(stderr, "enter_hash(%d, %s, %d)\n", uid, name, wecare); -#endif - - hashindex = hashit(uid); - - if (!is_empty_hash(hashindex)) - { - if (!wecare) - return 0; /* Don't clobber a slot for trash */ - if (hash_table[hashindex].uid == uid) - return(hashindex); /* Fortuitous find */ - } - - /* empty or wrong slot -- fill it with new value */ - hash_table[hashindex].uid = uid; - (void) strncpy(hash_table[hashindex].name, name, MAXLOGNAME - 1); - return(hashindex); -} - -/* - * Get a userid->name mapping from the system. - * If the passwd database is hashed (#define RANDOM_PW), we - * just handle this uid. Otherwise we scan the passwd file - * and cache any entries we pass over while looking. - */ - -int get_user(uid) - -int uid; - -{ - struct passwd *pwd; - -#ifdef RANDOM_PW - /* no performance penalty for using getpwuid makes it easy */ - if ((pwd = getpwuid(uid)) != NULL) - { - return(enter_user(pwd->pw_uid, pwd->pw_name, 1)); - } -#else - - int from_start = 0; - - /* - * If we just called getpwuid each time, things would be very slow - * since that just iterates through the passwd file each time. So, - * we walk through the file instead (using getpwent) and cache each - * entry as we go. Once the right record is found, we cache it and - * return immediately. The next time we come in, getpwent will get - * the next record. In theory, we never have to read the passwd file - * a second time (because we cache everything we read). But in - * practice, the cache may not be large enough, so if we don't find - * it the first time we have to scan the file a second time. This - * is not very efficient, but it will do for now. - */ - - while (from_start++ < 2) - { - while ((pwd = getpwent()) != NULL) - { - if (pwd->pw_uid == uid) - { - return(enter_user(pwd->pw_uid, pwd->pw_name, 1)); - } - (void) enter_user(pwd->pw_uid, pwd->pw_name, 0); - } - /* try again */ - setpwent(); - } -#endif - /* if we can't find the name at all, then use the uid as the name */ - return(enter_user(uid, itoa7(uid), 1)); -} Index: head/contrib/top/utils.h =================================================================== --- head/contrib/top/utils.h +++ head/contrib/top/utils.h @@ -1,26 +0,0 @@ -/* - * Top users/processes display for Unix - * Version 3 - * - * This program may be freely redistributed, - * but this entire comment MUST remain intact. - * - * Copyright (c) 1984, 1989, William LeFebvre, Rice University - * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University - */ - -/* prototypes for functions found in utils.c */ - -int atoiwi(); -char *itoa(); -char *itoa7(); -int digits(); -char *strecpy(); -char **argparse(); -long percentages(); -char *errmsg(); -char *format_time(); -char *format_k(); -char *format_k2(unsigned long long); -int string_index(char *string, char **array); - Index: head/contrib/top/utils.c =================================================================== --- head/contrib/top/utils.c +++ head/contrib/top/utils.c @@ -1,508 +0,0 @@ -/* - * Top users/processes display for Unix - * Version 3 - * - * This program may be freely redistributed, - * but this entire comment MUST remain intact. - * - * Copyright (c) 1984, 1989, William LeFebvre, Rice University - * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University - * - * $FreeBSD$ - */ - -/* - * This file contains various handy utilities used by top. - */ - -#include "top.h" -#include "os.h" - -int atoiwi(str) - -char *str; - -{ - register int len; - - len = strlen(str); - if (len != 0) - { - if (strncmp(str, "infinity", len) == 0 || - strncmp(str, "all", len) == 0 || - strncmp(str, "maximum", len) == 0) - { - return(Infinity); - } - else if (str[0] == '-') - { - return(Invalid); - } - else - { - return(atoi(str)); - } - } - return(0); -} - -/* - * itoa - convert integer (decimal) to ascii string for positive numbers - * only (we don't bother with negative numbers since we know we - * don't use them). - */ - - /* - * How do we know that 16 will suffice? - * Because the biggest number that we will - * ever convert will be 2^32-1, which is 10 - * digits. - */ -_Static_assert(sizeof(int) <= 4, "buffer too small for this sized int"); - -char *itoa(val) - -register int val; - -{ - register char *ptr; - static char buffer[16]; /* result is built here */ - /* 16 is sufficient since the largest number - we will ever convert will be 2^32-1, - which is 10 digits. */ - - ptr = buffer + sizeof(buffer); - *--ptr = '\0'; - if (val == 0) - { - *--ptr = '0'; - } - else while (val != 0) - { - *--ptr = (val % 10) + '0'; - val /= 10; - } - return(ptr); -} - -/* - * itoa7(val) - like itoa, except the number is right justified in a 7 - * character field. This code is a duplication of itoa instead of - * a front end to a more general routine for efficiency. - */ - -char *itoa7(val) - -register int val; - -{ - register char *ptr; - static char buffer[16]; /* result is built here */ - /* 16 is sufficient since the largest number - we will ever convert will be 2^32-1, - which is 10 digits. */ - - ptr = buffer + sizeof(buffer); - *--ptr = '\0'; - if (val == 0) - { - *--ptr = '0'; - } - else while (val != 0) - { - *--ptr = (val % 10) + '0'; - val /= 10; - } - while (ptr > buffer + sizeof(buffer) - 7) - { - *--ptr = ' '; - } - return(ptr); -} - -/* - * digits(val) - return number of decimal digits in val. Only works for - * positive numbers. If val <= 0 then digits(val) == 0. - */ - -int digits(val) - -int val; - -{ - register int cnt = 0; - - while (val > 0) - { - cnt++; - val /= 10; - } - return(cnt); -} - -/* - * strecpy(to, from) - copy string "from" into "to" and return a pointer - * to the END of the string "to". - */ - -char *strecpy(to, from) - -register char *to; -register char *from; - -{ - while ((*to++ = *from++) != '\0'); - return(--to); -} - -/* - * string_index(string, array) - find string in array and return index - */ - -int string_index(string, array) - -char *string; -char **array; - -{ - register int i = 0; - - while (*array != NULL) - { - if (strcmp(string, *array) == 0) - { - return(i); - } - array++; - i++; - } - return(-1); -} - -/* - * argparse(line, cntp) - parse arguments in string "line", separating them - * out into an argv-like array, and setting *cntp to the number of - * arguments encountered. This is a simple parser that doesn't understand - * squat about quotes. - */ - -char **argparse(line, cntp) - -char *line; -int *cntp; - -{ - register char *from; - register char *to; - register int cnt; - register int ch; - int length; - int lastch; - register char **argv; - char **argarray; - char *args; - - /* unfortunately, the only real way to do this is to go thru the - input string twice. */ - - /* step thru the string counting the white space sections */ - from = line; - lastch = cnt = length = 0; - while ((ch = *from++) != '\0') - { - length++; - if (ch == ' ' && lastch != ' ') - { - cnt++; - } - lastch = ch; - } - - /* add three to the count: one for the initial "dummy" argument, - one for the last argument and one for NULL */ - cnt += 3; - - /* allocate a char * array to hold the pointers */ - argarray = (char **)malloc(cnt * sizeof(char *)); - - /* allocate another array to hold the strings themselves */ - args = (char *)malloc(length+2); - - /* initialization for main loop */ - from = line; - to = args; - argv = argarray; - lastch = '\0'; - - /* create a dummy argument to keep getopt happy */ - *argv++ = to; - *to++ = '\0'; - cnt = 2; - - /* now build argv while copying characters */ - *argv++ = to; - while ((ch = *from++) != '\0') - { - if (ch != ' ') - { - if (lastch == ' ') - { - *to++ = '\0'; - *argv++ = to; - cnt++; - } - *to++ = ch; - } - lastch = ch; - } - *to++ = '\0'; - - /* set cntp and return the allocated array */ - *cntp = cnt; - return(argarray); -} - -/* - * percentages(cnt, out, new, old, diffs) - calculate percentage change - * between array "old" and "new", putting the percentages i "out". - * "cnt" is size of each array and "diffs" is used for scratch space. - * The array "old" is updated on each call. - * The routine assumes modulo arithmetic. This function is especially - * useful on BSD mchines for calculating cpu state percentages. - */ - -long percentages(cnt, out, new, old, diffs) - -int cnt; -int *out; -register long *new; -register long *old; -long *diffs; - -{ - register int i; - register long change; - register long total_change; - register long *dp; - long half_total; - - /* initialization */ - total_change = 0; - dp = diffs; - - /* calculate changes for each state and the overall change */ - for (i = 0; i < cnt; i++) - { - if ((change = *new - *old) < 0) - { - /* this only happens when the counter wraps */ - change = (int) - ((unsigned long)*new-(unsigned long)*old); - } - total_change += (*dp++ = change); - *old++ = *new++; - } - - /* avoid divide by zero potential */ - if (total_change == 0) - { - total_change = 1; - } - - /* calculate percentages based on overall change, rounding up */ - half_total = total_change / 2l; - - /* Do not divide by 0. Causes Floating point exception */ - if(total_change) { - for (i = 0; i < cnt; i++) - { - *out++ = (int)((*diffs++ * 1000 + half_total) / total_change); - } - } - - /* return the total in case the caller wants to use it */ - return(total_change); -} - -/* - * errmsg(errnum) - return an error message string appropriate to the - * error number "errnum". This is a substitute for the System V - * function "strerror". There appears to be no reliable way to - * determine if "strerror" exists at compile time, so I make do - * by providing something of similar functionality. For those - * systems that have strerror and NOT errlist, define - * -DHAVE_STRERROR in the module file and this function will - * use strerror. - */ - -/* externs referenced by errmsg */ - -#ifndef HAVE_STRERROR -#ifndef SYS_ERRLIST_DECLARED -#define SYS_ERRLIST_DECLARED -extern char *sys_errlist[]; -#endif - -extern int sys_nerr; -#endif - -char *errmsg(errnum) - -int errnum; - -{ -#ifdef HAVE_STRERROR - char *msg = strerror(errnum); - if (msg != NULL) - { - return msg; - } -#else - if (errnum > 0 && errnum < sys_nerr) - { - return((char *)sys_errlist[errnum]); - } -#endif - return("No error"); -} - -/* format_time(seconds) - format number of seconds into a suitable - * display that will fit within 6 characters. Note that this - * routine builds its string in a static area. If it needs - * to be called more than once without overwriting previous data, - * then we will need to adopt a technique similar to the - * one used for format_k. - */ - -/* Explanation: - We want to keep the output within 6 characters. For low values we use - the format mm:ss. For values that exceed 999:59, we switch to a format - that displays hours and fractions: hhh.tH. For values that exceed - 999.9, we use hhhh.t and drop the "H" designator. For values that - exceed 9999.9, we use "???". - */ - -char *format_time(seconds) - -long seconds; - -{ - register int value; - register int digit; - register char *ptr; - static char result[10]; - - /* sanity protection */ - if (seconds < 0 || seconds > (99999l * 360l)) - { - strcpy(result, " ???"); - } - else if (seconds >= (1000l * 60l)) - { - /* alternate (slow) method displaying hours and tenths */ - sprintf(result, "%5.1fH", (double)seconds / (double)(60l * 60l)); - - /* It is possible that the sprintf took more than 6 characters. - If so, then the "H" appears as result[6]. If not, then there - is a \0 in result[6]. Either way, it is safe to step on. - */ - result[6] = '\0'; - } - else - { - /* standard method produces MMM:SS */ - /* we avoid printf as must as possible to make this quick */ - sprintf(result, "%3ld:%02ld", - (long)(seconds / 60), (long)(seconds % 60)); - } - return(result); -} - -/* - * format_k(amt) - format a kilobyte memory value, returning a string - * suitable for display. Returns a pointer to a static - * area that changes each call. "amt" is converted to a - * string with a trailing "K". If "amt" is 10000 or greater, - * then it is formatted as megabytes (rounded) with a - * trailing "M". - */ - -/* - * Compromise time. We need to return a string, but we don't want the - * caller to have to worry about freeing a dynamically allocated string. - * Unfortunately, we can't just return a pointer to a static area as one - * of the common uses of this function is in a large call to sprintf where - * it might get invoked several times. Our compromise is to maintain an - * array of strings and cycle thru them with each invocation. We make the - * array large enough to handle the above mentioned case. The constant - * NUM_STRINGS defines the number of strings in this array: we can tolerate - * up to NUM_STRINGS calls before we start overwriting old information. - * Keeping NUM_STRINGS a power of two will allow an intelligent optimizer - * to convert the modulo operation into something quicker. What a hack! - */ - -#define NUM_STRINGS 8 - -char *format_k(amt) - -int amt; - -{ - static char retarray[NUM_STRINGS][16]; - static int index = 0; - register char *p; - register char *ret; - register char tag = 'K'; - - p = ret = retarray[index]; - index = (index + 1) % NUM_STRINGS; - - if (amt >= 10000) - { - amt = (amt + 512) / 1024; - tag = 'M'; - if (amt >= 10000) - { - amt = (amt + 512) / 1024; - tag = 'G'; - } - } - - p = strecpy(p, itoa(amt)); - *p++ = tag; - *p = '\0'; - - return(ret); -} - -char *format_k2(amt) - -unsigned long long amt; - -{ - static char retarray[NUM_STRINGS][16]; - static int index = 0; - register char *p; - register char *ret; - register char tag = 'K'; - - p = ret = retarray[index]; - index = (index + 1) % NUM_STRINGS; - - if (amt >= 100000) - { - amt = (amt + 512) / 1024; - tag = 'M'; - if (amt >= 100000) - { - amt = (amt + 512) / 1024; - tag = 'G'; - } - } - - p = strecpy(p, itoa((int)amt)); - *p++ = tag; - *p = '\0'; - - return(ret); -} Index: head/contrib/top/version.c =================================================================== --- head/contrib/top/version.c +++ head/contrib/top/version.c @@ -1,28 +0,0 @@ -/* - * Top users/processes display for Unix - * Version 3 - * - * This program may be freely redistributed, - * but this entire comment MUST remain intact. - * - * Copyright (c) 1984, 1989, William LeFebvre, Rice University - * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University - */ - -#include -#include - -#include "top.h" -#include "patchlevel.h" - -static char version[16]; - -char *version_string() - -{ - sprintf(version, "%d.%d", VERSION, PATCHLEVEL); -#ifdef BETA - strcat(version, BETA); -#endif - return(version); -} Index: head/usr.bin/top/Makefile =================================================================== --- head/usr.bin/top/Makefile +++ head/usr.bin/top/Makefile @@ -1,36 +1,21 @@ # $FreeBSD$ -TOPDIR= ${SRCTOP}/contrib/top -.PATH: ${TOPDIR} - PROG= top SRCS= commands.c display.c machine.c screen.c top.c \ - username.c utils.c version.c + username.c utils.c version.c SRCS+= sigdesc.h top.local.h -CFLAGS+= -DHAVE_GETOPT -DHAVE_STRERROR -DORDER -CFLAGS+= -I${.CURDIR} -I${TOPDIR} -I. +CFLAGS+= -DHAVE_GETOPT -DHAVE_STRERROR -DORDER -I ${.OBJDIR} +MAN= top.1 WARNS?= 0 -# -# The table size should be a prime number approximately twice as -# large as the number of lines in /etc/passwd. The default number -# is 20011; use /etc/make.conf to override this. -# -.if defined(TOP_TABLE_SIZE) -CFLAGS+= -D"Table_size=${TOP_TABLE_SIZE}" -.endif - LIBADD= ncursesw m kvm jail CLEANFILES= sigdesc.h -SIGCONV_AWK= ${SRCTOP}/contrib/top/sigconv.awk -STAGED_INCLUDE_DIR?= ${DESTDIR}/usr/include -SIGNAL_H= ${STAGED_INCLUDE_DIR}/sys/signal.h -sigdesc.h: ${SIGCONV_AWK} ${SIGNAL_H} - awk -f ${SIGCONV_AWK} < ${SIGNAL_H} > ${.TARGET} +SIGNAL_H= ${SRCTOP}/sys/sys/signal.h +sigdesc.h: sigconv.awk ${SIGNAL_H} + awk -f ${SRCTOP}/usr.bin/top/sigconv.awk < ${SIGNAL_H} > ${.TARGET} -CLEANFILES+= top.local.h top.x .SUFFIXES: .xs .x .hs .h .xs.x .hs.h: @${ECHO} Making ${.TARGET} from ${.IMPSRC} @@ -41,9 +26,5 @@ -e's,%delay%,2,g' \ -e's,%random%,1,g' \ ${.IMPSRC} > ${.TARGET} - -CLEANFILES+= top.1 -top.1: top.x top.local.1 - cat ${.ALLSRC} > ${.TARGET} .include Index: head/usr.bin/top/boolean.h =================================================================== --- head/usr.bin/top/boolean.h +++ head/usr.bin/top/boolean.h @@ -0,0 +1,5 @@ +/* My favorite names for boolean values */ +#define No 0 +#define Yes 1 +#define Maybe 2 /* tri-state boolean, actually */ + Index: head/usr.bin/top/commands.h =================================================================== --- head/usr.bin/top/commands.h +++ head/usr.bin/top/commands.h @@ -0,0 +1,21 @@ +/* + * Top users/processes display for Unix + * Version 3 + * + * This program may be freely redistributed, + * but this entire comment MUST remain intact. + * + * Copyright (c) 1984, 1989, William LeFebvre, Rice University + * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University + * Copyright (c) 2016, Randy Westlund + * + * $FreeBSD$ + */ +#ifndef COMMANDS_H +#define COMMANDS_H + +void show_errors(void); +int error_count(void); +void show_help(void); + +#endif /* COMMANDS_H */ Index: head/usr.bin/top/commands.c =================================================================== --- head/usr.bin/top/commands.c +++ head/usr.bin/top/commands.c @@ -0,0 +1,542 @@ +/* + * Top users/processes display for Unix + * Version 3 + * + * This program may be freely redistributed, + * but this entire comment MUST remain intact. + * + * Copyright (c) 1984, 1989, William LeFebvre, Rice University + * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University + * + * $FreeBSD$ + */ + +/* + * This file contains the routines that implement some of the interactive + * mode commands. Note that some of the commands are implemented in-line + * in "main". This is necessary because they change the global state of + * "top" (i.e.: changing the number of processes to display). + */ + +#include "os.h" + +#include +#include + +#include +#include +#include +#include + +#include "commands.h" +#include "sigdesc.h" /* generated automatically */ +#include "top.h" +#include "boolean.h" +#include "utils.h" +#include "machine.h" + +extern int errno; + +extern char *copyright; + +/* imported from screen.c */ +extern int overstrike; + +int err_compar(); +char *err_string(); +static int str_adderr(char *str, int len, int err); +static int str_addarg(char *str, int len, char *arg, int first); + +/* + * show_help() - display the help screen; invoked in response to + * either 'h' or '?'. + */ + +void +show_help() + +{ + printf("Top version %s, %s\n", version_string(), copyright); + fputs("\n\n\ +A top users display for Unix\n\ +\n\ +These single-character commands are available:\n\ +\n\ +^L - redraw screen\n\ +q - quit\n\ +h or ? - help; show this text\n", stdout); + + /* not all commands are availalbe with overstrike terminals */ + if (overstrike) + { + fputs("\n\ +Other commands are also available, but this terminal is not\n\ +sophisticated enough to handle those commands gracefully.\n\n", stdout); + } + else + { + fputs("\ +C - toggle the displaying of weighted CPU percentage\n\ +d - change number of displays to show\n\ +e - list errors generated by last \"kill\" or \"renice\" command\n\ +H - toggle the displaying of threads\n\ +i or I - toggle the displaying of idle processes\n\ +j - toggle the displaying of jail ID\n\ +J - display processes for only one jail (+ selects all jails)\n\ +k - kill processes; send a signal to a list of processes\n\ +m - toggle the display between 'cpu' and 'io' modes\n\ +n or # - change number of processes to display\n", stdout); +#ifdef ORDER + if (displaymode == DISP_CPU) + fputs("\ +o - specify sort order (pri, size, res, cpu, time, threads, jid, pid)\n", + stdout); + else + fputs("\ +o - specify sort order (vcsw, ivcsw, read, write, fault, total, jid, pid)\n", + stdout); +#endif + fputs("\ +P - toggle the displaying of per-CPU statistics\n\ +r - renice a process\n\ +s - change number of seconds to delay between updates\n\ +S - toggle the displaying of system processes\n\ +a - toggle the displaying of process titles\n\ +t - toggle the display of this process\n\ +u - display processes for only one user (+ selects all users)\n\ +w - toggle the display of swap use for each process\n\ +z - toggle the displaying of the system idle process\n\ +\n\ +\n", stdout); + } +} + +/* + * Utility routines that help with some of the commands. + */ + +char *next_field(str) + +register char *str; + +{ + if ((str = strchr(str, ' ')) == NULL) + { + return(NULL); + } + *str = '\0'; + while (*++str == ' ') /* loop */; + + /* if there is nothing left of the string, return NULL */ + /* This fix is dedicated to Greg Earle */ + return(*str == '\0' ? NULL : str); +} + +int +scanint(str, intp) + +char *str; +int *intp; + +{ + register int val = 0; + register char ch; + + /* if there is nothing left of the string, flag it as an error */ + /* This fix is dedicated to Greg Earle */ + if (*str == '\0') + { + return(-1); + } + + while ((ch = *str++) != '\0') + { + if (isdigit(ch)) + { + val = val * 10 + (ch - '0'); + } + else if (isspace(ch)) + { + break; + } + else + { + return(-1); + } + } + *intp = val; + return(0); +} + +/* + * Some of the commands make system calls that could generate errors. + * These errors are collected up in an array of structures for later + * contemplation and display. Such routines return a string containing an + * error message, or NULL if no errors occurred. The next few routines are + * for manipulating and displaying these errors. We need an upper limit on + * the number of errors, so we arbitrarily choose 20. + */ + +#define ERRMAX 20 + +struct errs /* structure for a system-call error */ +{ + int errnum; /* value of errno (that is, the actual error) */ + char *arg; /* argument that caused the error */ +}; + +static struct errs errs[ERRMAX]; +static int errcnt; +static char *err_toomany = " too many errors occurred"; +static char *err_listem = + " Many errors occurred. Press `e' to display the list of errors."; + +/* These macros get used to reset and log the errors */ +#define ERR_RESET errcnt = 0 +#define ERROR(p, e) if (errcnt >= ERRMAX) \ + { \ + return(err_toomany); \ + } \ + else \ + { \ + errs[errcnt].arg = (p); \ + errs[errcnt++].errnum = (e); \ + } + +/* + * err_string() - return an appropriate error string. This is what the + * command will return for displaying. If no errors were logged, then + * return NULL. The maximum length of the error string is defined by + * "STRMAX". + */ + +#define STRMAX 80 + +char *err_string() + +{ + register struct errs *errp; + register int cnt = 0; + register int first = Yes; + register int currerr = -1; + int stringlen; /* characters still available in "string" */ + static char string[STRMAX]; + + /* if there are no errors, return NULL */ + if (errcnt == 0) + { + return(NULL); + } + + /* sort the errors */ + qsort((char *)errs, errcnt, sizeof(struct errs), err_compar); + + /* need a space at the front of the error string */ + string[0] = ' '; + string[1] = '\0'; + stringlen = STRMAX - 2; + + /* loop thru the sorted list, building an error string */ + while (cnt < errcnt) + { + errp = &(errs[cnt++]); + if (errp->errnum != currerr) + { + if (currerr != -1) + { + if ((stringlen = str_adderr(string, stringlen, currerr)) < 2) + { + return(err_listem); + } + (void) strcat(string, "; "); /* we know there's more */ + } + currerr = errp->errnum; + first = Yes; + } + if ((stringlen = str_addarg(string, stringlen, errp->arg, first)) ==0) + { + return(err_listem); + } + first = No; + } + + /* add final message */ + stringlen = str_adderr(string, stringlen, currerr); + + /* return the error string */ + return(stringlen == 0 ? err_listem : string); +} + +/* + * str_adderr(str, len, err) - add an explanation of error "err" to + * the string "str". + */ + +static int +str_adderr(str, len, err) + +char *str; +int len; +int err; + +{ + register char *msg; + register int msglen; + + msg = err == 0 ? "Not a number" : errmsg(err); + msglen = strlen(msg) + 2; + if (len <= msglen) + { + return(0); + } + (void) strcat(str, ": "); + (void) strcat(str, msg); + return(len - msglen); +} + +/* + * str_addarg(str, len, arg, first) - add the string argument "arg" to + * the string "str". This is the first in the group when "first" + * is set (indicating that a comma should NOT be added to the front). + */ + +static int +str_addarg(str, len, arg, first) + +char *str; +int len; +char *arg; +int first; + +{ + register int arglen; + + arglen = strlen(arg); + if (!first) + { + arglen += 2; + } + if (len <= arglen) + { + return(0); + } + if (!first) + { + (void) strcat(str, ", "); + } + (void) strcat(str, arg); + return(len - arglen); +} + +/* + * err_compar(p1, p2) - comparison routine used by "qsort" + * for sorting errors. + */ + +int +err_compar(p1, p2) + +register struct errs *p1, *p2; + +{ + register int result; + + if ((result = p1->errnum - p2->errnum) == 0) + { + return(strcmp(p1->arg, p2->arg)); + } + return(result); +} + +/* + * error_count() - return the number of errors currently logged. + */ + +int +error_count() + +{ + return(errcnt); +} + +/* + * show_errors() - display on stdout the current log of errors. + */ + +void +show_errors() + +{ + register int cnt = 0; + register struct errs *errp = errs; + + printf("%d error%s:\n\n", errcnt, errcnt == 1 ? "" : "s"); + while (cnt++ < errcnt) + { + printf("%5s: %s\n", errp->arg, + errp->errnum == 0 ? "Not a number" : errmsg(errp->errnum)); + errp++; + } +} + +/* + * kill_procs(str) - send signals to processes, much like the "kill" + * command does; invoked in response to 'k'. + */ + +char *kill_procs(str) + +char *str; + +{ + register char *nptr; + int signum = SIGTERM; /* default */ + int procnum; + struct sigdesc *sigp; + int uid; + + /* reset error array */ + ERR_RESET; + + /* remember our uid */ + uid = getuid(); + + /* skip over leading white space */ + while (isspace(*str)) str++; + + if (str[0] == '-') + { + /* explicit signal specified */ + if ((nptr = next_field(str)) == NULL) + { + return(" kill: no processes specified"); + } + + if (isdigit(str[1])) + { + (void) scanint(str + 1, &signum); + if (signum <= 0 || signum >= NSIG) + { + return(" invalid signal number"); + } + } + else + { + /* translate the name into a number */ + for (sigp = sigdesc; sigp->name != NULL; sigp++) + { + if (strcmp(sigp->name, str + 1) == 0) + { + signum = sigp->number; + break; + } + } + + /* was it ever found */ + if (sigp->name == NULL) + { + return(" bad signal name"); + } + } + /* put the new pointer in place */ + str = nptr; + } + + /* loop thru the string, killing processes */ + do + { + if (scanint(str, &procnum) == -1) + { + ERROR(str, 0); + } + else + { + /* check process owner if we're not root */ + if (uid && (uid != proc_owner(procnum))) + { + ERROR(str, EACCES); + } + /* go in for the kill */ + else if (kill(procnum, signum) == -1) + { + /* chalk up an error */ + ERROR(str, errno); + } + } + } while ((str = next_field(str)) != NULL); + + /* return appropriate error string */ + return(err_string()); +} + +/* + * renice_procs(str) - change the "nice" of processes, much like the + * "renice" command does; invoked in response to 'r'. + */ + +char *renice_procs(str) + +char *str; + +{ + register char negate; + int prio; + int procnum; + int uid; + + ERR_RESET; + uid = getuid(); + + /* allow for negative priority values */ + if ((negate = (*str == '-')) != 0) + { + /* move past the minus sign */ + str++; + } + + /* use procnum as a temporary holding place and get the number */ + procnum = scanint(str, &prio); + + /* negate if necessary */ + if (negate) + { + prio = -prio; + } + +#if defined(PRIO_MIN) && defined(PRIO_MAX) + /* check for validity */ + if (procnum == -1 || prio < PRIO_MIN || prio > PRIO_MAX) + { + return(" bad priority value"); + } +#endif + + /* move to the first process number */ + if ((str = next_field(str)) == NULL) + { + return(" no processes specified"); + } + + /* loop thru the process numbers, renicing each one */ + do + { + if (scanint(str, &procnum) == -1) + { + ERROR(str, 0); + } + + /* check process owner if we're not root */ + else if (uid && (uid != proc_owner(procnum))) + { + ERROR(str, EACCES); + } + else if (setpriority(PRIO_PROCESS, procnum, prio) == -1) + { + ERROR(str, errno); + } + } while ((str = next_field(str)) != NULL); + + /* return appropriate error string */ + return(err_string()); +} + Index: head/usr.bin/top/display.h =================================================================== --- head/usr.bin/top/display.h +++ head/usr.bin/top/display.h @@ -0,0 +1,43 @@ +/* constants needed for display.c */ + +/* "type" argument for new_message function */ + +#define MT_standout 1 +#define MT_delayed 2 + +#include "machine.h" + +int display_updatecpus(struct statics *statics); +void clear_message(void); +int display_resize(void); +void i_header(char *text); +char *printable(char *string); +char *cpustates_tag(void); +void display_header(int t); +int display_init(struct statics *statics); +void i_arc(int *stats); +void i_carc(int *stats); +void i_cpustates(int *states); +void i_loadave(int mpid, double *avenrun); +void i_memory(int *stats); +void i_message(void); +void i_process(int line, char *thisline); +void i_procstates(int total, int *brkdn); +void i_swap(int *stats); +void i_timeofday(time_t *tod); +void i_uptime(struct timeval *bt, time_t *tod); +void new_message(); +int readline(char *buffer, int size, int numeric); +char *trim_header(char *text); +void u_arc(int *stats); +void u_carc(int *stats); +void u_cpustates(int *states); +void u_endscreen(int hi); +void u_header(char *text); +void u_loadave(int mpid, double *avenrun); +void u_memory(int *stats); +void u_message(void); +void u_process(int line, char *newline); +void u_procstates(int total, int *brkdn); +void u_swap(int *stats); +void z_cpustates(void); Index: head/usr.bin/top/display.c =================================================================== --- head/usr.bin/top/display.c +++ head/usr.bin/top/display.c @@ -0,0 +1,1455 @@ +/* + * Top users/processes display for Unix + * Version 3 + * + * This program may be freely redistributed, + * but this entire comment MUST remain intact. + * + * Copyright (c) 1984, 1989, William LeFebvre, Rice University + * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University + * + * $FreeBSD$ + */ + +/* + * This file contains the routines that display information on the screen. + * Each section of the screen has two routines: one for initially writing + * all constant and dynamic text, and one for only updating the text that + * changes. The prefix "i_" is used on all the "initial" routines and the + * prefix "u_" is used for all the "updating" routines. + * + * ASSUMPTIONS: + * None of the "i_" routines use any of the termcap capabilities. + * In this way, those routines can be safely used on terminals that + * have minimal (or nonexistant) terminal capabilities. + * + * The routines are called in this order: *_loadave, i_timeofday, + * *_procstates, *_cpustates, *_memory, *_message, *_header, + * *_process, u_endscreen. + */ + +#include "os.h" + +#include + +#include +#include +#include +#include +#include + +#include "screen.h" /* interface to screen package */ +#include "layout.h" /* defines for screen position layout */ +#include "display.h" +#include "top.h" +#include "top.local.h" +#include "boolean.h" +#include "machine.h" /* we should eliminate this!!! */ +#include "utils.h" + +#ifdef DEBUG +FILE *debug; +#endif + +/* imported from screen.c */ +extern int overstrike; + +static int lmpid = 0; +static int last_hi = 0; /* used in u_process and u_endscreen */ +static int lastline = 0; +static int display_width = MAX_COLS; + +#define lineindex(l) ((l)*display_width) + + +/* things initialized by display_init and used thruout */ + +/* buffer of proc information lines for display updating */ +char *screenbuf = NULL; + +static char **procstate_names; +static char **cpustate_names; +static char **memory_names; +static char **arc_names; +static char **carc_names; +static char **swap_names; + +static int num_procstates; +static int num_cpustates; +static int num_memory; +static int num_swap; + +static int *lprocstates; +static int *lcpustates; +static int *lmemory; +static int *lswap; + +static int num_cpus; +static int *cpustate_columns; +static int cpustate_total_length; +static int cpustates_column; + +static enum { OFF, ON, ERASE } header_status = ON; + +static int string_count(); +static void summary_format(); +static void line_update(); + +int x_lastpid = 10; +int y_lastpid = 0; +int x_loadave = 33; +int x_loadave_nompid = 15; +int y_loadave = 0; +int x_procstate = 0; +int y_procstate = 1; +int x_brkdn = 15; +int y_brkdn = 1; +int x_mem = 5; +int y_mem = 3; +int x_arc = 5; +int y_arc = 4; +int x_carc = 5; +int y_carc = 5; +int x_swap = 6; +int y_swap = 4; +int y_message = 5; +int x_header = 0; +int y_header = 6; +int x_idlecursor = 0; +int y_idlecursor = 5; +int y_procs = 7; + +int y_cpustates = 2; +int Header_lines = 7; + +int display_resize() + +{ + register int lines; + + /* first, deallocate any previous buffer that may have been there */ + if (screenbuf != NULL) + { + free(screenbuf); + } + + /* calculate the current dimensions */ + /* if operating in "dumb" mode, we only need one line */ + lines = smart_terminal ? screen_length - Header_lines : 1; + + if (lines < 0) + lines = 0; + /* we don't want more than MAX_COLS columns, since the machine-dependent + modules make static allocations based on MAX_COLS and we don't want + to run off the end of their buffers */ + display_width = screen_width; + if (display_width >= MAX_COLS) + { + display_width = MAX_COLS - 1; + } + + /* now, allocate space for the screen buffer */ + screenbuf = (char *)malloc(lines * display_width); + if (screenbuf == (char *)NULL) + { + /* oops! */ + return(-1); + } + + /* return number of lines available */ + /* for dumb terminals, pretend like we can show any amount */ + return(smart_terminal ? lines : Largest); +} + +int display_updatecpus(statics) + +struct statics *statics; + +{ + register int *lp; + register int lines; + register int i; + + /* call resize to do the dirty work */ + lines = display_resize(); + if (pcpu_stats) + num_cpus = statics->ncpus; + else + num_cpus = 1; + cpustates_column = 5; /* CPU: */ + if (num_cpus != 1) + cpustates_column += 2; /* CPU 0: */ + for (i = num_cpus; i > 9; i /= 10) + cpustates_column++; + + /* fill the "last" array with all -1s, to insure correct updating */ + lp = lcpustates; + i = num_cpustates * num_cpus; + while (--i >= 0) + { + *lp++ = -1; + } + + return(lines); +} + +int display_init(statics) + +struct statics *statics; + +{ + register int lines; + register char **pp; + register int *ip; + register int i; + + lines = display_updatecpus(statics); + + /* only do the rest if we need to */ + if (lines > -1) + { + /* save pointers and allocate space for names */ + procstate_names = statics->procstate_names; + num_procstates = string_count(procstate_names); + lprocstates = (int *)malloc(num_procstates * sizeof(int)); + + cpustate_names = statics->cpustate_names; + + swap_names = statics->swap_names; + num_swap = string_count(swap_names); + lswap = (int *)malloc(num_swap * sizeof(int)); + num_cpustates = string_count(cpustate_names); + lcpustates = (int *)malloc(num_cpustates * sizeof(int) * statics->ncpus); + cpustate_columns = (int *)malloc(num_cpustates * sizeof(int)); + + memory_names = statics->memory_names; + num_memory = string_count(memory_names); + lmemory = (int *)malloc(num_memory * sizeof(int)); + + arc_names = statics->arc_names; + carc_names = statics->carc_names; + + /* calculate starting columns where needed */ + cpustate_total_length = 0; + pp = cpustate_names; + ip = cpustate_columns; + while (*pp != NULL) + { + *ip++ = cpustate_total_length; + if ((i = strlen(*pp++)) > 0) + { + cpustate_total_length += i + 8; + } + } + } + + /* return number of lines available */ + return(lines); +} + +void +i_loadave(mpid, avenrun) + +int mpid; +double *avenrun; + +{ + register int i; + + /* i_loadave also clears the screen, since it is first */ + top_clear(); + + /* mpid == -1 implies this system doesn't have an _mpid */ + if (mpid != -1) + { + printf("last pid: %5d; ", mpid); + } + + printf("load averages"); + + for (i = 0; i < 3; i++) + { + printf("%c %5.2f", + i == 0 ? ':' : ',', + avenrun[i]); + } + lmpid = mpid; +} + +void +u_loadave(mpid, avenrun) + +int mpid; +double *avenrun; + +{ + register int i; + + if (mpid != -1) + { + /* change screen only when value has really changed */ + if (mpid != lmpid) + { + Move_to(x_lastpid, y_lastpid); + printf("%5d", mpid); + lmpid = mpid; + } + + /* i remembers x coordinate to move to */ + i = x_loadave; + } + else + { + i = x_loadave_nompid; + } + + /* move into position for load averages */ + Move_to(i, y_loadave); + + /* display new load averages */ + /* we should optimize this and only display changes */ + for (i = 0; i < 3; i++) + { + printf("%s%5.2f", + i == 0 ? "" : ", ", + avenrun[i]); + } +} + +void +i_timeofday(tod) + +time_t *tod; + +{ + /* + * Display the current time. + * "ctime" always returns a string that looks like this: + * + * Sun Sep 16 01:03:52 1973 + * 012345678901234567890123 + * 1 2 + * + * We want indices 11 thru 18 (length 8). + */ + + if (smart_terminal) + { + Move_to(screen_width - 8, 0); + } + else + { + fputs(" ", stdout); + } +#ifdef DEBUG + { + char *foo; + foo = ctime(tod); + fputs(foo, stdout); + } +#endif + printf("%-8.8s\n", &(ctime(tod)[11])); + lastline = 1; +} + +static int ltotal = 0; +static char procstates_buffer[MAX_COLS]; + +/* + * *_procstates(total, brkdn, names) - print the process summary line + * + * Assumptions: cursor is at the beginning of the line on entry + * lastline is valid + */ + +void +i_procstates(total, brkdn) + +int total; +int *brkdn; + +{ + register int i; + + /* write current number of processes and remember the value */ + printf("%d processes:", total); + ltotal = total; + + /* put out enough spaces to get to column 15 */ + i = digits(total); + while (i++ < 4) + { + putchar(' '); + } + + /* format and print the process state summary */ + summary_format(procstates_buffer, brkdn, procstate_names); + fputs(procstates_buffer, stdout); + + /* save the numbers for next time */ + memcpy(lprocstates, brkdn, num_procstates * sizeof(int)); +} + +void +u_procstates(total, brkdn) + +int total; +int *brkdn; + +{ + static char new[MAX_COLS]; + register int i; + + /* update number of processes only if it has changed */ + if (ltotal != total) + { + /* move and overwrite */ +#if (x_procstate == 0) + Move_to(x_procstate, y_procstate); +#else + /* cursor is already there...no motion needed */ + /* assert(lastline == 1); */ +#endif + printf("%d", total); + + /* if number of digits differs, rewrite the label */ + if (digits(total) != digits(ltotal)) + { + fputs(" processes:", stdout); + /* put out enough spaces to get to column 15 */ + i = digits(total); + while (i++ < 4) + { + putchar(' '); + } + /* cursor may end up right where we want it!!! */ + } + + /* save new total */ + ltotal = total; + } + + /* see if any of the state numbers has changed */ + if (memcmp(lprocstates, brkdn, num_procstates * sizeof(int)) != 0) + { + /* format and update the line */ + summary_format(new, brkdn, procstate_names); + line_update(procstates_buffer, new, x_brkdn, y_brkdn); + memcpy(lprocstates, brkdn, num_procstates * sizeof(int)); + } +} + +#ifdef no_more +/* + * *_cpustates(states, names) - print the cpu state percentages + * + * Assumptions: cursor is on the PREVIOUS line + */ + +/* cpustates_tag() calculates the correct tag to use to label the line */ + +char *cpustates_tag() + +{ + register char *use; + + static char *short_tag = "CPU: "; + static char *long_tag = "CPU states: "; + + /* if length + strlen(long_tag) >= screen_width, then we have to + use the shorter tag (we subtract 2 to account for ": ") */ + if (cpustate_total_length + (int)strlen(long_tag) - 2 >= screen_width) + { + use = short_tag; + } + else + { + use = long_tag; + } + + /* set cpustates_column accordingly then return result */ + cpustates_column = strlen(use); + return(use); +} +#endif + +void +i_cpustates(states) + +int *states; + +{ + register int i = 0; + register int value; + register char **names; + register char *thisname; + int cpu; + +for (cpu = 0; cpu < num_cpus; cpu++) { + names = cpustate_names; + + /* print tag and bump lastline */ + if (num_cpus == 1) + printf("\nCPU: "); + else { + value = printf("\nCPU %d: ", cpu); + while (value++ <= cpustates_column) + printf(" "); + } + lastline++; + + /* now walk thru the names and print the line */ + while ((thisname = *names++) != NULL) + { + if (*thisname != '\0') + { + /* retrieve the value and remember it */ + value = *states++; + + /* if percentage is >= 1000, print it as 100% */ + printf((value >= 1000 ? "%s%4.0f%% %s" : "%s%4.1f%% %s"), + (i++ % num_cpustates) == 0 ? "" : ", ", + ((float)value)/10., + thisname); + } + } +} + + /* copy over values into "last" array */ + memcpy(lcpustates, states, num_cpustates * sizeof(int) * num_cpus); +} + +void +u_cpustates(states) + +int *states; + +{ + register int value; + register char **names; + register char *thisname; + register int *lp; + register int *colp; + int cpu; + +for (cpu = 0; cpu < num_cpus; cpu++) { + names = cpustate_names; + + Move_to(cpustates_column, y_cpustates + cpu); + lastline = y_cpustates + cpu; + lp = lcpustates + (cpu * num_cpustates); + colp = cpustate_columns; + + /* we could be much more optimal about this */ + while ((thisname = *names++) != NULL) + { + if (*thisname != '\0') + { + /* did the value change since last time? */ + if (*lp != *states) + { + /* yes, move and change */ + Move_to(cpustates_column + *colp, y_cpustates + cpu); + lastline = y_cpustates + cpu; + + /* retrieve value and remember it */ + value = *states; + + /* if percentage is >= 1000, print it as 100% */ + printf((value >= 1000 ? "%4.0f" : "%4.1f"), + ((double)value)/10.); + + /* remember it for next time */ + *lp = value; + } + } + + /* increment and move on */ + lp++; + states++; + colp++; + } +} +} + +void +z_cpustates() + +{ + register int i = 0; + register char **names; + register char *thisname; + register int *lp; + int cpu, value; + +for (cpu = 0; cpu < num_cpus; cpu++) { + names = cpustate_names; + + /* show tag and bump lastline */ + if (num_cpus == 1) + printf("\nCPU: "); + else { + value = printf("\nCPU %d: ", cpu); + while (value++ <= cpustates_column) + printf(" "); + } + lastline++; + + while ((thisname = *names++) != NULL) + { + if (*thisname != '\0') + { + printf("%s %% %s", (i++ % num_cpustates) == 0 ? "" : ", ", thisname); + } + } +} + + /* fill the "last" array with all -1s, to insure correct updating */ + lp = lcpustates; + i = num_cpustates * num_cpus; + while (--i >= 0) + { + *lp++ = -1; + } +} + +/* + * *_memory(stats) - print "Memory: " followed by the memory summary string + * + * Assumptions: cursor is on "lastline" + * for i_memory ONLY: cursor is on the previous line + */ + +char memory_buffer[MAX_COLS]; + +void +i_memory(stats) + +int *stats; + +{ + fputs("\nMem: ", stdout); + lastline++; + + /* format and print the memory summary */ + summary_format(memory_buffer, stats, memory_names); + fputs(memory_buffer, stdout); +} + +void +u_memory(stats) + +int *stats; + +{ + static char new[MAX_COLS]; + + /* format the new line */ + summary_format(new, stats, memory_names); + line_update(memory_buffer, new, x_mem, y_mem); +} + +/* + * *_arc(stats) - print "ARC: " followed by the ARC summary string + * + * Assumptions: cursor is on "lastline" + * for i_arc ONLY: cursor is on the previous line + */ +char arc_buffer[MAX_COLS]; + +void +i_arc(stats) + +int *stats; + +{ + if (arc_names == NULL) + return; + + fputs("\nARC: ", stdout); + lastline++; + + /* format and print the memory summary */ + summary_format(arc_buffer, stats, arc_names); + fputs(arc_buffer, stdout); +} + +void +u_arc(stats) + +int *stats; + +{ + static char new[MAX_COLS]; + + if (arc_names == NULL) + return; + + /* format the new line */ + summary_format(new, stats, arc_names); + line_update(arc_buffer, new, x_arc, y_arc); +} + + +/* + * *_carc(stats) - print "Compressed ARC: " followed by the summary string + * + * Assumptions: cursor is on "lastline" + * for i_carc ONLY: cursor is on the previous line + */ +char carc_buffer[MAX_COLS]; + +void +i_carc(stats) + +int *stats; + +{ + if (carc_names == NULL) + return; + + fputs("\n ", stdout); + lastline++; + + /* format and print the memory summary */ + summary_format(carc_buffer, stats, carc_names); + fputs(carc_buffer, stdout); +} + +void +u_carc(stats) + +int *stats; + +{ + static char new[MAX_COLS]; + + if (carc_names == NULL) + return; + + /* format the new line */ + summary_format(new, stats, carc_names); + line_update(carc_buffer, new, x_carc, y_carc); +} + +/* + * *_swap(stats) - print "Swap: " followed by the swap summary string + * + * Assumptions: cursor is on "lastline" + * for i_swap ONLY: cursor is on the previous line + */ + +char swap_buffer[MAX_COLS]; + +void +i_swap(stats) + +int *stats; + +{ + fputs("\nSwap: ", stdout); + lastline++; + + /* format and print the swap summary */ + summary_format(swap_buffer, stats, swap_names); + fputs(swap_buffer, stdout); +} + +void +u_swap(stats) + +int *stats; + +{ + static char new[MAX_COLS]; + + /* format the new line */ + summary_format(new, stats, swap_names); + line_update(swap_buffer, new, x_swap, y_swap); +} + +/* + * *_message() - print the next pending message line, or erase the one + * that is there. + * + * Note that u_message is (currently) the same as i_message. + * + * Assumptions: lastline is consistent + */ + +/* + * i_message is funny because it gets its message asynchronously (with + * respect to screen updates). + */ + +static char next_msg[MAX_COLS + 5]; +static int msglen = 0; +/* Invariant: msglen is always the length of the message currently displayed + on the screen (even when next_msg doesn't contain that message). */ + +void +i_message() + +{ + while (lastline < y_message) + { + fputc('\n', stdout); + lastline++; + } + if (next_msg[0] != '\0') + { + top_standout(next_msg); + msglen = strlen(next_msg); + next_msg[0] = '\0'; + } + else if (msglen > 0) + { + (void) clear_eol(msglen); + msglen = 0; + } +} + +void +u_message() + +{ + i_message(); +} + +static int header_length; + +/* + * Trim a header string to the current display width and return a newly + * allocated area with the trimmed header. + */ + +char * +trim_header(text) + +char *text; + +{ + char *s; + int width; + + s = NULL; + width = display_width; + header_length = strlen(text); + if (header_length >= width) { + s = malloc((width + 1) * sizeof(char)); + if (s == NULL) + return (NULL); + strncpy(s, text, width); + s[width] = '\0'; + } + return (s); +} + +/* + * *_header(text) - print the header for the process area + * + * Assumptions: cursor is on the previous line and lastline is consistent + */ + +void +i_header(text) + +char *text; + +{ + char *s; + + s = trim_header(text); + if (s != NULL) + text = s; + + if (header_status == ON) + { + putchar('\n'); + fputs(text, stdout); + lastline++; + } + else if (header_status == ERASE) + { + header_status = OFF; + } + free(s); +} + +/*ARGSUSED*/ +void +u_header(text) + +char *text __unused; /* ignored */ + +{ + + if (header_status == ERASE) + { + putchar('\n'); + lastline++; + clear_eol(header_length); + header_status = OFF; + } +} + +/* + * *_process(line, thisline) - print one process line + * + * Assumptions: lastline is consistent + */ + +void +i_process(line, thisline) + +int line; +char *thisline; + +{ + register char *p; + register char *base; + + /* make sure we are on the correct line */ + while (lastline < y_procs + line) + { + putchar('\n'); + lastline++; + } + + /* truncate the line to conform to our current screen width */ + thisline[display_width] = '\0'; + + /* write the line out */ + fputs(thisline, stdout); + + /* copy it in to our buffer */ + base = smart_terminal ? screenbuf + lineindex(line) : screenbuf; + p = strecpy(base, thisline); + + /* zero fill the rest of it */ + memzero(p, display_width - (p - base)); +} + +void +u_process(line, newline) + +int line; +char *newline; + +{ + register char *optr; + register int screen_line = line + Header_lines; + register char *bufferline; + + /* remember a pointer to the current line in the screen buffer */ + bufferline = &screenbuf[lineindex(line)]; + + /* truncate the line to conform to our current screen width */ + newline[display_width] = '\0'; + + /* is line higher than we went on the last display? */ + if (line >= last_hi) + { + /* yes, just ignore screenbuf and write it out directly */ + /* get positioned on the correct line */ + if (screen_line - lastline == 1) + { + putchar('\n'); + lastline++; + } + else + { + Move_to(0, screen_line); + lastline = screen_line; + } + + /* now write the line */ + fputs(newline, stdout); + + /* copy it in to the buffer */ + optr = strecpy(bufferline, newline); + + /* zero fill the rest of it */ + memzero(optr, display_width - (optr - bufferline)); + } + else + { + line_update(bufferline, newline, 0, line + Header_lines); + } +} + +void +u_endscreen(hi) + +int hi; + +{ + register int screen_line = hi + Header_lines; + register int i; + + if (smart_terminal) + { + if (hi < last_hi) + { + /* need to blank the remainder of the screen */ + /* but only if there is any screen left below this line */ + if (lastline + 1 < screen_length) + { + /* efficiently move to the end of currently displayed info */ + if (screen_line - lastline < 5) + { + while (lastline < screen_line) + { + putchar('\n'); + lastline++; + } + } + else + { + Move_to(0, screen_line); + lastline = screen_line; + } + + if (clear_to_end) + { + /* we can do this the easy way */ + putcap(clear_to_end); + } + else + { + /* use clear_eol on each line */ + i = hi; + while ((void) clear_eol(strlen(&screenbuf[lineindex(i++)])), i < last_hi) + { + putchar('\n'); + } + } + } + } + last_hi = hi; + + /* move the cursor to a pleasant place */ + Move_to(x_idlecursor, y_idlecursor); + lastline = y_idlecursor; + } + else + { + /* separate this display from the next with some vertical room */ + fputs("\n\n", stdout); + } +} + +void +display_header(t) + +int t; + +{ + if (t) + { + header_status = ON; + } + else if (header_status == ON) + { + header_status = ERASE; + } +} + +/*VARARGS2*/ +void +new_message(type, msgfmt, a1, a2, a3) + +int type; +char *msgfmt; +caddr_t a1, a2, a3; + +{ + register int i; + + /* first, format the message */ + (void) snprintf(next_msg, sizeof(next_msg), msgfmt, a1, a2, a3); + + if (msglen > 0) + { + /* message there already -- can we clear it? */ + if (!overstrike) + { + /* yes -- write it and clear to end */ + i = strlen(next_msg); + if ((type & MT_delayed) == 0) + { + type & MT_standout ? top_standout(next_msg) : + fputs(next_msg, stdout); + (void) clear_eol(msglen - i); + msglen = i; + next_msg[0] = '\0'; + } + } + } + else + { + if ((type & MT_delayed) == 0) + { + type & MT_standout ? top_standout(next_msg) : fputs(next_msg, stdout); + msglen = strlen(next_msg); + next_msg[0] = '\0'; + } + } +} + +void +clear_message() + +{ + if (clear_eol(msglen) == 1) + { + putchar('\r'); + } +} + +int +readline(buffer, size, numeric) + +char *buffer; +int size; +int numeric; + +{ + register char *ptr = buffer; + register char ch; + register char cnt = 0; + register char maxcnt = 0; + + /* allow room for null terminator */ + size -= 1; + + /* read loop */ + while ((fflush(stdout), read(0, ptr, 1) > 0)) + { + /* newline means we are done */ + if ((ch = *ptr) == '\n' || ch == '\r') + { + break; + } + + /* handle special editing characters */ + if (ch == ch_kill) + { + /* kill line -- account for overstriking */ + if (overstrike) + { + msglen += maxcnt; + } + + /* return null string */ + *buffer = '\0'; + putchar('\r'); + return(-1); + } + else if (ch == ch_erase) + { + /* erase previous character */ + if (cnt <= 0) + { + /* none to erase! */ + putchar('\7'); + } + else + { + fputs("\b \b", stdout); + ptr--; + cnt--; + } + } + /* check for character validity and buffer overflow */ + else if (cnt == size || (numeric && !isdigit(ch)) || + !isprint(ch)) + { + /* not legal */ + putchar('\7'); + } + else + { + /* echo it and store it in the buffer */ + putchar(ch); + ptr++; + cnt++; + if (cnt > maxcnt) + { + maxcnt = cnt; + } + } + } + + /* all done -- null terminate the string */ + *ptr = '\0'; + + /* account for the extra characters in the message area */ + /* (if terminal overstrikes, remember the furthest they went) */ + msglen += overstrike ? maxcnt : cnt; + + /* return either inputted number or string length */ + putchar('\r'); + return(cnt == 0 ? -1 : numeric ? atoi(buffer) : cnt); +} + +/* internal support routines */ + +static int string_count(pp) + +register char **pp; + +{ + register int cnt; + + cnt = 0; + while (*pp++ != NULL) + { + cnt++; + } + return(cnt); +} + +static void summary_format(str, numbers, names) + +char *str; +int *numbers; +register char **names; + +{ + register char *p; + register int num; + register char *thisname; + register int useM = No; + char rbuf[6]; + + /* format each number followed by its string */ + p = str; + while ((thisname = *names++) != NULL) + { + /* get the number to format */ + num = *numbers++; + + /* display only non-zero numbers */ + if (num > 0) + { + /* is this number in kilobytes? */ + if (thisname[0] == 'K') + { + /* yes: format it as a memory value */ + p = strecpy(p, format_k(num)); + + /* skip over the K, since it was included by format_k */ + p = strecpy(p, thisname+1); + } + /* is this number a ratio? */ + else if (thisname[0] == ':') + { + (void) snprintf(rbuf, sizeof(rbuf), "%.2f", + (float)*(numbers - 2) / (float)num); + p = strecpy(p, rbuf); + p = strecpy(p, thisname); + } + else + { + p = strecpy(p, itoa(num)); + p = strecpy(p, thisname); + } + } + + /* ignore negative numbers, but display corresponding string */ + else if (num < 0) + { + p = strecpy(p, thisname); + } + } + + /* if the last two characters in the string are ", ", delete them */ + p -= 2; + if (p >= str && p[0] == ',' && p[1] == ' ') + { + *p = '\0'; + } +} + +static void line_update(old, new, start, line) + +register char *old; +register char *new; +int start; +int line; + +{ + register int ch; + register int diff; + register int newcol = start + 1; + register int lastcol = start; + char cursor_on_line = No; + char *current; + + /* compare the two strings and only rewrite what has changed */ + current = old; +#ifdef DEBUG + fprintf(debug, "line_update, starting at %d\n", start); + fputs(old, debug); + fputc('\n', debug); + fputs(new, debug); + fputs("\n-\n", debug); +#endif + + /* start things off on the right foot */ + /* this is to make sure the invariants get set up right */ + if ((ch = *new++) != *old) + { + if (line - lastline == 1 && start == 0) + { + putchar('\n'); + } + else + { + Move_to(start, line); + } + cursor_on_line = Yes; + putchar(ch); + *old = ch; + lastcol = 1; + } + old++; + + /* + * main loop -- check each character. If the old and new aren't the + * same, then update the display. When the distance from the + * current cursor position to the new change is small enough, + * the characters that belong there are written to move the + * cursor over. + * + * Invariants: + * lastcol is the column where the cursor currently is sitting + * (always one beyond the end of the last mismatch). + */ + do /* yes, a do...while */ + { + if ((ch = *new++) != *old) + { + /* new character is different from old */ + /* make sure the cursor is on top of this character */ + diff = newcol - lastcol; + if (diff > 0) + { + /* some motion is required--figure out which is shorter */ + if (diff < 6 && cursor_on_line) + { + /* overwrite old stuff--get it out of the old buffer */ + printf("%.*s", diff, ¤t[lastcol-start]); + } + else + { + /* use cursor addressing */ + Move_to(newcol, line); + cursor_on_line = Yes; + } + /* remember where the cursor is */ + lastcol = newcol + 1; + } + else + { + /* already there, update position */ + lastcol++; + } + + /* write what we need to */ + if (ch == '\0') + { + /* at the end--terminate with a clear-to-end-of-line */ + (void) clear_eol(strlen(old)); + } + else + { + /* write the new character */ + putchar(ch); + } + /* put the new character in the screen buffer */ + *old = ch; + } + + /* update working column and screen buffer pointer */ + newcol++; + old++; + + } while (ch != '\0'); + + /* zero out the rest of the line buffer -- MUST BE DONE! */ + diff = display_width - newcol; + if (diff > 0) + { + memzero(old, diff); + } + + /* remember where the current line is */ + if (cursor_on_line) + { + lastline = line; + } +} + +/* + * printable(str) - make the string pointed to by "str" into one that is + * printable (i.e.: all ascii), by converting all non-printable + * characters into '?'. Replacements are done in place and a pointer + * to the original buffer is returned. + */ + +char *printable(str) + +char *str; + +{ + register char *ptr; + register char ch; + + ptr = str; + while ((ch = *ptr) != '\0') + { + if (!isprint(ch)) + { + *ptr = '?'; + } + ptr++; + } + return(str); +} + +void +i_uptime(bt, tod) + +struct timeval* bt; +time_t *tod; + +{ + time_t uptime; + int days, hrs, mins, secs; + + if (bt->tv_sec != -1) { + uptime = *tod - bt->tv_sec; + days = uptime / 86400; + uptime %= 86400; + hrs = uptime / 3600; + uptime %= 3600; + mins = uptime / 60; + secs = uptime % 60; + + /* + * Display the uptime. + */ + + if (smart_terminal) + { + Move_to((screen_width - 24) - (days > 9 ? 1 : 0), 0); + } + else + { + fputs(" ", stdout); + } + printf(" up %d+%02d:%02d:%02d", days, hrs, mins, secs); + } +} Index: head/usr.bin/top/getopt.c =================================================================== --- head/usr.bin/top/getopt.c +++ head/usr.bin/top/getopt.c @@ -0,0 +1,90 @@ +/* + * "getopt" routine customized for top. + */ + +/* + * Many modern-day Unix implementations already have this function + * in libc. The standard "getopt" is perfectly sufficient for top's + * needs. If such a function exists in libc then you certainly don't + * need to compile this one in. To prevent this function from being + * compiled, define "HAVE_GETOPT". This is usually done in the "CFLAGS" + * line of the corresponding machine module. + */ + +/* + * This empty declaration exists solely to placate overexhuberant C + * compilers that like to warn you about content-free files. + */ +static void __empty(); + +#ifndef HAVE_GETOPT + +/*LINTLIBRARY*/ + +#include "os.h" +#ifndef NULL +#define NULL 0 +#endif +#ifndef EOF +#define EOF (-1) +#endif +#define ERR(s, c) if(opterr){\ + extern int write();\ + char errbuf[2];\ + errbuf[0] = c; errbuf[1] = '\n';\ + (void) write(2, argv[0], strlen(argv[0]));\ + (void) write(2, s, strlen(s));\ + (void) write(2, errbuf, 2);} + + +int opterr = 1; +int optind = 1; +int optopt; +char *optarg; + +int +getopt(argc, argv, opts) +int argc; +char **argv, *opts; +{ + static int sp = 1; + register int c; + register char *cp; + + if(sp == 1) + if(optind >= argc || + argv[optind][0] != '-' || argv[optind][1] == '\0') + return(EOF); + else if(strcmp(argv[optind], "--") == 0) { + optind++; + return(EOF); + } + optopt = c = argv[optind][sp]; + if(c == ':' || (cp=strchr(opts, c)) == NULL) { + ERR(": unknown option, -", c); + if(argv[optind][++sp] == '\0') { + optind++; + sp = 1; + } + return('?'); + } + if(*++cp == ':') { + if(argv[optind][sp+1] != '\0') + optarg = &argv[optind++][sp+1]; + else if(++optind >= argc) { + ERR(": argument missing for -", c); + sp = 1; + return('?'); + } else + optarg = argv[optind++]; + sp = 1; + } else { + if(argv[optind][++sp] == '\0') { + sp = 1; + optind++; + } + optarg = NULL; + } + return(c); +} +#endif /* HAVE_GETOPT */ Index: head/usr.bin/top/layout.h =================================================================== --- head/usr.bin/top/layout.h +++ head/usr.bin/top/layout.h @@ -0,0 +1,35 @@ +/* + * Top - a top users display for Berkeley Unix + * + * This file defines the locations on tne screen for various parts of the + * display. These definitions are used by the routines in "display.c" for + * cursor addressing. + * + * $FreeBSD$ + */ + +extern int x_lastpid; /* 10 */ +extern int y_lastpid; /* 0 */ +extern int x_loadave; /* 33 */ +extern int x_loadave_nompid; /* 15 */ +extern int y_loadave; /* 0 */ +extern int x_procstate; /* 0 */ +extern int y_procstate; /* 1 */ +extern int x_brkdn; /* 15 */ +extern int y_brkdn; /* 1 */ +extern int x_mem; /* 5 */ +extern int y_mem; /* 3 */ +extern int x_arc; /* 5 */ +extern int y_arc; /* 4 */ +extern int x_carc; /* 5 */ +extern int y_carc; /* 5 */ +extern int x_swap; /* 6 */ +extern int y_swap; /* 4 */ +extern int y_message; /* 5 */ +extern int x_header; /* 0 */ +extern int y_header; /* 6 */ +extern int x_idlecursor; /* 0 */ +extern int y_idlecursor; /* 5 */ +extern int y_procs; /* 7 */ + +extern int y_cpustates; /* 2 */ Index: head/usr.bin/top/loadavg.h =================================================================== --- head/usr.bin/top/loadavg.h +++ head/usr.bin/top/loadavg.h @@ -0,0 +1,57 @@ +/* + * Top - a top users display for Berkeley Unix + * + * Defines required to access load average figures. + * + * This include file sets up everything we need to access the load average + * values in the kernel in a machine independent way. First, it sets the + * typedef "load_avg" to be either double or long (depending on what is + * needed), then it defines these macros appropriately: + * + * loaddouble(la) - convert load_avg to double. + * intload(i) - convert integer to load_avg. + */ + +/* + * We assume that if FSCALE is defined, then avenrun and ccpu are type long. + * If your machine is an exception (mips, perhaps?) then make adjustments + * here. + * + * Defined types: load_avg for load averages, pctcpu for cpu percentages. + */ +#if defined(__mips__) && !(defined(__NetBSD__) || defined(__FreeBSD__)) +# include +# if defined(FBITS) && !defined(FSCALE) +# define FSCALE (1 << FBITS) /* RISC/os on mips */ +# endif +#endif + +#ifdef FSCALE +# define FIXED_LOADAVG FSCALE +# define FIXED_PCTCPU FSCALE +#endif + +#ifdef ibm032 +# undef FIXED_LOADAVG +# undef FIXED_PCTCPU +# define FIXED_PCTCPU PCT_SCALE +#endif + + +#ifdef FIXED_PCTCPU + typedef long pctcpu; +# define pctdouble(p) ((double)(p) / FIXED_PCTCPU) +#else +typedef double pctcpu; +# define pctdouble(p) (p) +#endif + +#ifdef FIXED_LOADAVG + typedef fixpt_t load_avg; +# define loaddouble(la) ((double)(la) / FIXED_LOADAVG) +# define intload(i) ((int)((i) * FIXED_LOADAVG)) +#else + typedef double load_avg; +# define loaddouble(la) (la) +# define intload(i) ((double)(i)) +#endif Index: head/usr.bin/top/machine.h =================================================================== --- head/usr.bin/top/machine.h +++ head/usr.bin/top/machine.h @@ -0,0 +1,96 @@ +/* + * $FreeBSD$ + */ + +/* + * This file defines the interface between top and the machine-dependent + * module. It is NOT machine dependent and should not need to be changed + * for any specific machine. + */ +#ifndef MACHINE_H +#define MACHINE_H + +#include "top.h" + +/* + * the statics struct is filled in by machine_init + */ +struct statics +{ + char **procstate_names; + char **cpustate_names; + char **memory_names; + char **arc_names; + char **carc_names; + char **swap_names; +#ifdef ORDER + char **order_names; +#endif + int ncpus; +}; + +/* + * the system_info struct is filled in by a machine dependent routine. + */ + +#ifdef p_active /* uw7 define macro p_active */ +#define P_ACTIVE p_pactive +#else +#define P_ACTIVE p_active +#endif + +struct system_info +{ + int last_pid; + double load_avg[NUM_AVERAGES]; + int p_total; + int P_ACTIVE; /* number of procs considered "active" */ + int *procstates; + int *cpustates; + int *memory; + int *arc; + int *carc; + int *swap; + struct timeval boottime; + int ncpus; +}; + +/* cpu_states is an array of percentages * 10. For example, + the (integer) value 105 is 10.5% (or .105). + */ + +/* + * the process_select struct tells get_process_info what processes we + * are interested in seeing + */ + +struct process_select +{ + int idle; /* show idle processes */ + int self; /* show self */ + int system; /* show system processes */ + int thread; /* show threads */ +#define TOP_MAX_UIDS 8 + int uid[TOP_MAX_UIDS]; /* only these uids (unless uid[0] == -1) */ + int wcpu; /* show weighted cpu */ + int jid; /* only this jid (unless jid == -1) */ + int jail; /* show jail ID */ + int swap; /* show swap usage */ + int kidle; /* show per-CPU idle threads */ + char *command; /* only this command (unless == NULL) */ +}; + +/* routines defined by the machine dependent module */ + +char *format_header(char *uname_field); +char *format_next_process(caddr_t handle, char *(*get_userid)(int), + int flags); +void toggle_pcpustats(void); +void get_system_info(struct system_info *si); +int machine_init(struct statics *statics, char do_unames); +int proc_owner(int pid); + +/* non-int routines typically used by the machine dependent module */ +char *printable(char *string); + +#endif /* MACHINE_H */ Index: head/usr.bin/top/os.h =================================================================== --- head/usr.bin/top/os.h +++ head/usr.bin/top/os.h @@ -0,0 +1,38 @@ +#include +#include /* This defines BSD */ +#if defined(BSD) && !defined(BSD4_4) && !defined(__osf__) +# include +# include +# define strchr(a, b) index((a), (b)) +# define strrchr(a, b) rindex((a), (b)) +# define memcpy(a, b, c) bcopy((b), (a), (c)) +# define memzero(a, b) bzero((a), (b)) +# define memcmp(a, b, c) bcmp((a), (b), (c)) +#if defined(NeXT) + typedef void sigret_t; +#else + typedef int sigret_t; +#endif + +/* system routines that don't return int */ +char *getenv(); +caddr_t malloc(); + +#else +# include +# define setbuffer(f, b, s) setvbuf((f), (b), (b) ? _IOFBF : _IONBF, (s)) +# include +# include +# include +# define memzero(a, b) memset((a), 0, (b)) + typedef void sigret_t; +#endif + +/* some systems declare sys_errlist in stdio.h! */ +#if defined(__NetBSD__) || defined(__FreeBSD__) +#if !defined(__m68k__) +# if !defined(__NetBSD132__) +#define SYS_ERRLIST_DECLARED +# endif /* __NetBSD132__ */ +#endif +#endif Index: head/usr.bin/top/patchlevel.h =================================================================== --- head/usr.bin/top/patchlevel.h +++ head/usr.bin/top/patchlevel.h @@ -0,0 +1,2 @@ +#define PATCHLEVEL 5 +#define BETA "beta12" Index: head/usr.bin/top/prime.c =================================================================== --- head/usr.bin/top/prime.c +++ head/usr.bin/top/prime.c @@ -0,0 +1,41 @@ +/* + * Prime number generator. It prints on stdout the next prime number + * higher than the number specified as argv[1]. + */ + +#include +#include + +main(argc, argv) + +int argc; +char *argv[]; + +{ + double i, j; + int f; + + if (argc < 2) + { + exit(1); + } + + i = atoi(argv[1]); + while (i++) + { + f=1; + for (j=2; j +#ifdef CBREAK +# include +# define SGTTY +#else +# ifdef TCGETA +# define TERMIO +# include +# else +# define TERMIOS +# include +# endif +#endif +#if defined(TERMIO) || defined(TERMIOS) +# ifndef TAB3 +# ifdef OXTABS +# define TAB3 OXTABS +# else +# define TAB3 0 +# endif +# endif +#endif +#include +#include +#include "screen.h" +#include "boolean.h" + +extern char *myname; + + +int overstrike; +int screen_length; +int screen_width; +char ch_erase; +char ch_kill; +char smart_terminal; +char PC; +char *tgetstr(); +char *tgoto(); +char termcap_buf[1024]; +char string_buffer[1024]; +char home[15]; +char lower_left[15]; +char *clear_line; +char *clear_screen; +char *clear_to_end; +char *cursor_motion; +char *start_standout; +char *end_standout; +char *terminal_init; +char *terminal_end; + +#ifdef SGTTY +static struct sgttyb old_settings; +static struct sgttyb new_settings; +#endif +#ifdef TERMIO +static struct termio old_settings; +static struct termio new_settings; +#endif +#ifdef TERMIOS +static struct termios old_settings; +static struct termios new_settings; +#endif +static char is_a_terminal = No; +#ifdef TOStop +static int old_lword; +static int new_lword; +#endif + +#define STDIN 0 +#define STDOUT 1 +#define STDERR 2 + +void +init_termcap(interactive) + +int interactive; + +{ + char *bufptr; + char *PCptr; + char *term_name; + char *getenv(); + int status; + + /* set defaults in case we aren't smart */ + screen_width = MAX_COLS; + screen_length = 0; + + if (!interactive) + { + /* pretend we have a dumb terminal */ + smart_terminal = No; + return; + } + + /* assume we have a smart terminal until proven otherwise */ + smart_terminal = Yes; + + /* get the terminal name */ + term_name = getenv("TERM"); + + /* if there is no TERM, assume it's a dumb terminal */ + /* patch courtesy of Sam Horrocks at telegraph.ics.uci.edu */ + if (term_name == NULL) + { + smart_terminal = No; + return; + } + + /* now get the termcap entry */ + if ((status = tgetent(termcap_buf, term_name)) != 1) + { + if (status == -1) + { + fprintf(stderr, "%s: can't open termcap file\n", myname); + } + else + { + fprintf(stderr, "%s: no termcap entry for a `%s' terminal\n", + myname, term_name); + } + + /* pretend it's dumb and proceed */ + smart_terminal = No; + return; + } + + /* "hardcopy" immediately indicates a very stupid terminal */ + if (tgetflag("hc")) + { + smart_terminal = No; + return; + } + + /* set up common terminal capabilities */ + if ((screen_length = tgetnum("li")) <= 0) + { + screen_length = smart_terminal = 0; + return; + } + + /* screen_width is a little different */ + if ((screen_width = tgetnum("co")) == -1) + { + screen_width = 79; + } + else + { + screen_width -= 1; + } + + /* terminals that overstrike need special attention */ + overstrike = tgetflag("os"); + + /* initialize the pointer into the termcap string buffer */ + bufptr = string_buffer; + + /* get "ce", clear to end */ + if (!overstrike) + { + clear_line = tgetstr("ce", &bufptr); + } + + /* get necessary capabilities */ + if ((clear_screen = tgetstr("cl", &bufptr)) == NULL || + (cursor_motion = tgetstr("cm", &bufptr)) == NULL) + { + smart_terminal = No; + return; + } + + /* get some more sophisticated stuff -- these are optional */ + clear_to_end = tgetstr("cd", &bufptr); + terminal_init = tgetstr("ti", &bufptr); + terminal_end = tgetstr("te", &bufptr); + start_standout = tgetstr("so", &bufptr); + end_standout = tgetstr("se", &bufptr); + + /* pad character */ + PC = (PCptr = tgetstr("pc", &bufptr)) ? *PCptr : 0; + + /* set convenience strings */ + (void) strncpy(home, tgoto(cursor_motion, 0, 0), sizeof(home) - 1); + home[sizeof(home) - 1] = '\0'; + /* (lower_left is set in get_screensize) */ + + /* get the actual screen size with an ioctl, if needed */ + /* This may change screen_width and screen_length, and it always + sets lower_left. */ + get_screensize(); + + /* if stdout is not a terminal, pretend we are a dumb terminal */ +#ifdef SGTTY + if (ioctl(STDOUT, TIOCGETP, &old_settings) == -1) + { + smart_terminal = No; + } +#endif +#ifdef TERMIO + if (ioctl(STDOUT, TCGETA, &old_settings) == -1) + { + smart_terminal = No; + } +#endif +#ifdef TERMIOS + if (tcgetattr(STDOUT, &old_settings) == -1) + { + smart_terminal = No; + } +#endif +} + +void +init_screen() + +{ + /* get the old settings for safe keeping */ +#ifdef SGTTY + if (ioctl(STDOUT, TIOCGETP, &old_settings) != -1) + { + /* copy the settings so we can modify them */ + new_settings = old_settings; + + /* turn on CBREAK and turn off character echo and tab expansion */ + new_settings.sg_flags |= CBREAK; + new_settings.sg_flags &= ~(ECHO|XTABS); + (void) ioctl(STDOUT, TIOCSETP, &new_settings); + + /* remember the erase and kill characters */ + ch_erase = old_settings.sg_erase; + ch_kill = old_settings.sg_kill; + +#ifdef TOStop + /* get the local mode word */ + (void) ioctl(STDOUT, TIOCLGET, &old_lword); + + /* modify it */ + new_lword = old_lword | LTOSTOP; + (void) ioctl(STDOUT, TIOCLSET, &new_lword); +#endif + /* remember that it really is a terminal */ + is_a_terminal = Yes; + + /* send the termcap initialization string */ + putcap(terminal_init); + } +#endif +#ifdef TERMIO + if (ioctl(STDOUT, TCGETA, &old_settings) != -1) + { + /* copy the settings so we can modify them */ + new_settings = old_settings; + + /* turn off ICANON, character echo and tab expansion */ + new_settings.c_lflag &= ~(ICANON|ECHO); + new_settings.c_oflag &= ~(TAB3); + new_settings.c_cc[VMIN] = 1; + new_settings.c_cc[VTIME] = 0; + (void) ioctl(STDOUT, TCSETA, &new_settings); + + /* remember the erase and kill characters */ + ch_erase = old_settings.c_cc[VERASE]; + ch_kill = old_settings.c_cc[VKILL]; + + /* remember that it really is a terminal */ + is_a_terminal = Yes; + + /* send the termcap initialization string */ + putcap(terminal_init); + } +#endif +#ifdef TERMIOS + if (tcgetattr(STDOUT, &old_settings) != -1) + { + /* copy the settings so we can modify them */ + new_settings = old_settings; + + /* turn off ICANON, character echo and tab expansion */ + new_settings.c_lflag &= ~(ICANON|ECHO); + new_settings.c_oflag &= ~(TAB3); + new_settings.c_cc[VMIN] = 1; + new_settings.c_cc[VTIME] = 0; + (void) tcsetattr(STDOUT, TCSADRAIN, &new_settings); + + /* remember the erase and kill characters */ + ch_erase = old_settings.c_cc[VERASE]; + ch_kill = old_settings.c_cc[VKILL]; + + /* remember that it really is a terminal */ + is_a_terminal = Yes; + + /* send the termcap initialization string */ + putcap(terminal_init); + } +#endif + + if (!is_a_terminal) + { + /* not a terminal at all---consider it dumb */ + smart_terminal = No; + } +} + +void +end_screen() + +{ + /* move to the lower left, clear the line and send "te" */ + if (smart_terminal) + { + putcap(lower_left); + putcap(clear_line); + fflush(stdout); + putcap(terminal_end); + } + + /* if we have settings to reset, then do so */ + if (is_a_terminal) + { +#ifdef SGTTY + (void) ioctl(STDOUT, TIOCSETP, &old_settings); +#ifdef TOStop + (void) ioctl(STDOUT, TIOCLSET, &old_lword); +#endif +#endif +#ifdef TERMIO + (void) ioctl(STDOUT, TCSETA, &old_settings); +#endif +#ifdef TERMIOS + (void) tcsetattr(STDOUT, TCSADRAIN, &old_settings); +#endif + } +} + +void +reinit_screen() + +{ + /* install our settings if it is a terminal */ + if (is_a_terminal) + { +#ifdef SGTTY + (void) ioctl(STDOUT, TIOCSETP, &new_settings); +#ifdef TOStop + (void) ioctl(STDOUT, TIOCLSET, &new_lword); +#endif +#endif +#ifdef TERMIO + (void) ioctl(STDOUT, TCSETA, &new_settings); +#endif +#ifdef TERMIOS + (void) tcsetattr(STDOUT, TCSADRAIN, &new_settings); +#endif + } + + /* send init string */ + if (smart_terminal) + { + putcap(terminal_init); + } +} + +void +get_screensize() + +{ + +#ifdef TIOCGWINSZ + + struct winsize ws; + + if (ioctl (1, TIOCGWINSZ, &ws) != -1) + { + if (ws.ws_row != 0) + { + screen_length = ws.ws_row; + } + if (ws.ws_col != 0) + { + screen_width = ws.ws_col - 1; + } + } + +#else +#ifdef TIOCGSIZE + + struct ttysize ts; + + if (ioctl (1, TIOCGSIZE, &ts) != -1) + { + if (ts.ts_lines != 0) + { + screen_length = ts.ts_lines; + } + if (ts.ts_cols != 0) + { + screen_width = ts.ts_cols - 1; + } + } + +#endif /* TIOCGSIZE */ +#endif /* TIOCGWINSZ */ + + (void) strncpy(lower_left, tgoto(cursor_motion, 0, screen_length - 1), + sizeof(lower_left) - 1); + lower_left[sizeof(lower_left) - 1] = '\0'; +} + +void +top_standout(char *msg) +{ + if (smart_terminal) + { + putcap(start_standout); + fputs(msg, stdout); + putcap(end_standout); + } + else + { + fputs(msg, stdout); + } +} + +void +top_clear() +{ + if (smart_terminal) + { + putcap(clear_screen); + } +} + +int +clear_eol(int len) +{ + if (smart_terminal && !overstrike && len > 0) + { + if (clear_line) + { + putcap(clear_line); + return(0); + } + else + { + while (len-- > 0) + { + putchar(' '); + } + return(1); + } + } + return(-1); +} + +void +go_home() + +{ + if (smart_terminal) + { + putcap(home); + } +} + +/* This has to be defined as a subroutine for tputs (instead of a macro) */ + +int +putstdout(int ch) +{ + return putchar(ch); +} Index: head/usr.bin/top/sigconv.awk =================================================================== --- head/usr.bin/top/sigconv.awk +++ head/usr.bin/top/sigconv.awk @@ -0,0 +1,55 @@ +# $FreeBSD$ + +BEGIN { + nsig = 0; + j = 0; + print "/* This file was automatically generated */" + print "/* by the awk script \"sigconv.awk\". */\n" + print "struct sigdesc {" + print " char *name;" + print " int number;" + print "};\n" + print "struct sigdesc sigdesc[] = {" + } + +/^#define[ \t][ \t]*SIG[A-Z]+[0-9]*[ \t]/ { + + j = sprintf("%d", $3); + str = $2; + + if (nsig < j) + nsig = j; + + siglist[j] = sprintf("{ \"%s\",\t%2d },", \ + substr(str, 4), j); + } +/^#[ \t]*define[ \t][ \t]*SIG[A-Z]+[0-9]*[ \t]/ { + + j = sprintf("%d", $4); + str = $3; + + if (nsig < j) + nsig = j; + + siglist[j] = sprintf("{ \"%s\",\t%2d },", \ + substr(str, 4), j); + } +/^#[ \t]*define[ \t][ \t]*_SIG[A-Z]+[0-9]*[ \t]/ { + + j = sprintf("%d", $4); + str = $3; + + if (nsig < j) + nsig = j; + + siglist[j] = sprintf("{ \"%s\",\t%2d },", \ + substr(str, 5), j); + } + +END { + for (n = 1; n <= nsig; n++) + if (siglist[n] != "") + printf(" %s\n", siglist[n]); + + printf(" { NULL,\t 0 }\n};\n"); + } Index: head/usr.bin/top/top.h =================================================================== --- head/usr.bin/top/top.h +++ head/usr.bin/top/top.h @@ -0,0 +1,54 @@ +/* + * $FreeBSD$ + */ +/* + * Top - a top users display for Berkeley Unix + * + * General (global) definitions + */ + +#ifndef TOP_H +#define TOP_H + +/* Current major version number */ +#define VERSION 3 + +/* Number of lines of header information on the standard screen */ +extern int Header_lines; /* 7 */ + +/* Maximum number of columns allowed for display */ +#define MAX_COLS 512 + +/* Log base 2 of 1024 is 10 (2^10 == 1024) */ +#define LOG1024 10 + +char *itoa(); +char *itoa7(); + +char *version_string(); + +/* Special atoi routine returns either a non-negative number or one of: */ +#define Infinity -1 +#define Invalid -2 + +/* maximum number we can have */ +#define Largest 0x7fffffff + +/* + * The entire display is based on these next numbers being defined as is. + */ + +#define NUM_AVERAGES 3 + +enum displaymodes { DISP_CPU = 0, DISP_IO, DISP_MAX }; + +/* + * Format modifiers + */ +#define FMT_SHOWARGS 0x00000001 + +extern enum displaymodes displaymode; + +extern int pcpu_stats; + +#endif /* TOP_H */ Index: head/usr.bin/top/top.1 =================================================================== --- head/usr.bin/top/top.1 +++ head/usr.bin/top/top.1 @@ -0,0 +1,543 @@ +.\" NOTE: changes to the manual page for "top" should be made in the +.\" file "top.X" and NOT in the file "top.1". +.\" $FreeBSD$ +.nr N -1 +.nr D 2 +.TH TOP 1 Local +.UC 4 +.SH NAME +top \- display and update information about the top cpu processes +.SH SYNOPSIS +.B top +[ +.B \-abCHIijnPqStuvwz +] [ +.BI \-d count +] [ +.BI \-m io | cpu +] [ +.BI \-o field +] [ +.BI \-s time +] [ +.BI \-J jail +] [ +.BI \-U username +] [ +.I number +] +.SH DESCRIPTION +.\" This defines appropriate quote strings for nroff and troff +.ds lq \&" +.ds rq \&" +.if t .ds lq `` +.if t .ds rq '' +.\" Just in case these number registers aren't set yet... +.if \nN==0 .nr N 10 +.if \nD==0 .nr D 2 +.I Top +displays the top +.if !\nN==-1 \nN +processes on the system and periodically updates this information. +.if \nN==-1 \ +\{\ +If standard output is an intelligent terminal (see below) then +as many processes as will fit on the terminal screen are displayed +by default. Otherwise, a good number of them are shown (around 20). +.\} +Raw cpu percentage is used to rank the processes. If +.I number +is given, then the top +.I number +processes will be displayed instead of the default. +.PP +.I Top +makes a distinction between terminals that support advanced capabilities +and those that do not. This +distinction affects the choice of defaults for certain options. In the +remainder of this document, an \*(lqintelligent\*(rq terminal is one that +supports cursor addressing, clear screen, and clear to end of line. +Conversely, a \*(lqdumb\*(rq terminal is one that does not support such +features. If the output of +.I top +is redirected to a file, it acts as if it were being run on a dumb +terminal. +.SH OPTIONS +.TP +.B \-C +Toggle CPU display mode. +By default top displays the weighted CPU percentage in the WCPU column +(this is the same value that +.IR ps (1) +displays as CPU). +Each time +.B \-C +flag is passed it toggles between \*(lqraw cpu\*(rq mode +and \*(lqweighted cpu\*(rq mode, showing the \*(lqCPU\*(rq or +the \*(lqWCPU\*(rq column respectively. +.TP +.B \-S +Show system processes in the display. Normally, system processes such as +the pager and the swapper are not shown. This option makes them visible. +.TP +.B \-a +Display command names derived from the argv[] vector, rather than real +executable name. It's useful when you want to watch applications, that +puts their status information there. If the real name differs from argv[0], +it will be displayed in parenthesis. +.TP +.B \-b +Use \*(lqbatch\*(rq mode. In this mode, all input from the terminal is +ignored. Interrupt characters (such as ^C and ^\e) still have an effect. +This is the default on a dumb terminal, or when the output is not a terminal. +.TP +.B \-H +Display each thread for a multithreaded process individually. +By default a single summary line is displayed for each process. +.TP +.B \-i +Use \*(lqinteractive\*(rq mode. In this mode, any input is immediately +read for processing. See the section on \*(lqInteractive Mode\*(rq +for an explanation of +which keys perform what functions. After the command is processed, the +screen will immediately be updated, even if the command was not +understood. This mode is the default when standard output is an +intelligent terminal. +.TP +.B \-I +Do not display idle processes. +By default, top displays both active and idle processes. +.TP +.B \-j +Display the +.IR jail (8) +ID. +.TP +.B \-t +Do not display the +.I top +process. +.TP +.BI \-m display +Display either 'cpu' or 'io' statistics. Default is 'cpu'. +.TP +.B \-n +Use \*(lqnon-interactive\*(rq mode. This is identical to \*(lqbatch\*(rq +mode. +.TP +.B \-P +Display per-cpu CPU usage statistics. +.TP +.B \-q +Renice +.I top +to -20 so that it will run faster. This can be used when the system is +being very sluggish to improve the possibility of discovering the problem. +This option can only be used by root. +.TP +.B \-u +Do not take the time to map uid numbers to usernames. Normally, +.I top +will read as much of the file \*(lq/etc/passwd\*(rq as is necessary to map +all the user id numbers it encounters into login names. This option +disables all that, while possibly decreasing execution time. The uid +numbers are displayed instead of the names. +.TP +.B \-v +Write version number information to stderr then exit immediately. +No other processing takes place when this option is used. To see current +revision information while top is running, use the help command \*(lq?\*(rq. +.TP +.B \-w +Display approximate swap usage for each process. +.TP +.B \-z +Do not display the system idle process. +.TP +.BI \-d count +Show only +.I count +displays, then exit. A display is considered to be one update of the +screen. This option allows the user to select the number of displays he +wants to see before +.I top +automatically exits. For intelligent terminals, no upper limit +is set. The default is 1 for dumb terminals. +.TP +.BI \-s time +Set the delay between screen updates to +.I time +seconds. The default delay between updates is \nD seconds. +.TP +.BI \-o field +Sort the process display area on the specified field. The field name +is the name of the column as seen in the output, but in lower case: +\*(lqcpu\*(lq, \*(rqsize\*(lq, \*(rqres\*(lq, \*(rqtime\*(lq, +\*(rqpri\*(lq, \*(rqthreads\*(lq, \*(lqtotal\*(lq, \*(rqread\*(lq, +\*(rqwrite\*(lq, \*(rqfault\*(lq, \*(rqvcsw\*(lq, \*(rqivcsw\*(lq, +\*(lqjid\*(lq, \*(rqswap\*(lq or \*(rqpid\*(lq. +.TP +.BI \-J jail +Show only those processes owned by +.IR jail . +This may be either the +.B jid +or +.B name +of the jail. +Use +.B 0 +to limit to host processes. +Using this option implies the +.B \-j +flag. +.PP +.BI \-U username +Show only those processes owned by +.IR username . +This option currently only accepts usernames and will not understand +uid numbers. +.PP +Both +.I count +and +.I number +fields can be specified as \*(lqinfinite\*(rq, indicating that they can +stretch as far as possible. This is accomplished by using any proper +prefix of the keywords +\*(lqinfinity\*(rq, +\*(lqmaximum\*(rq, +or +\*(lqall\*(rq. +The default for +.I count +on an intelligent terminal is, in fact, +.BI infinity . +.PP +The environment variable +.B TOP +is examined for options before the command line is scanned. This enables +a user to set his or her own defaults. The number of processes to display +can also be specified in the environment variable +.BR TOP . +The options +.BR \-a , +.BR \-C , +.BR \-H , +.BR \-I , +.BR \-j , +.BR \-P , +.BR \-S , +.BR \-t , +.BR \-u , +.BR \-w , +and +.B \-z +are actually toggles. A second specification of any of these options +will negate the first. Thus a user who has the environment variable +.B TOP +set to \*(lq\-I\*(rq may use the command \*(lqtop \-I\*(rq to see idle processes. +.SH "INTERACTIVE MODE" +When +.I top +is running in \*(lqinteractive mode\*(rq, it reads commands from the +terminal and acts upon them accordingly. In this mode, the terminal is +put in \*(lqCBREAK\*(rq, so that a character will be +processed as soon as it is typed. Almost always, a key will be +pressed when +.I top +is between displays; that is, while it is waiting for +.I time +seconds to elapse. If this is the case, the command will be +processed and the display will be updated immediately thereafter +(reflecting any changes that the command may have specified). This +happens even if the command was incorrect. If a key is pressed while +.I top +is in the middle of updating the display, it will finish the update and +then process the command. Some commands require additional information, +and the user will be prompted accordingly. While typing this information +in, the user's erase and kill keys (as set up by the command +.IR stty ) +are recognized, and a newline terminates the input. +.PP +These commands are currently recognized (^L refers to control-L): +.TP +.B ^L +Redraw the screen. +.IP "\fBh\fP\ or\ \fB?\fP" +Display a summary of the commands (help screen). Version information +is included in this display. +.TP +.B q +Quit +.IR top. +.TP +.B d +Change the number of displays to show (prompt for new number). +Remember that the next display counts as one, so typing +.B d1 +will make +.I top +show one final display and then immediately exit. +.TP +.B m +Toggle the display between 'cpu' and 'io' modes. +.TP +.B n or # +Change the number of processes to display (prompt for new number). +.TP +.B s +Change the number of seconds to delay between displays +(prompt for new number). +.TP +.B S +Toggle the display of system processes. +.TP +.B a +Toggle the display of process titles. +.TP +.B k +Send a signal (\*(lqkill\*(rq by default) to a list of processes. This +acts similarly to the command +.IR kill (1)). +.TP +.B r +Change the priority (the \*(lqnice\*(rq) of a list of processes. +This acts similarly to the command +.IR renice (8)). +.TP +.B u +Display only processes owned by a specific set of usernames (prompt for +username). If the username specified is simply \*(lq+\*(rq or \*(lq-\*(rq, +then processes belonging to all users will be displayed. Usernames can be added +to and removed from the set by prepending them with \*(lq+\*(rq and +\*(lq-\*(rq, respectively. +.TP +.B o +Change the order in which the display is sorted. This command is not +available on all systems. The sort key names vary from system to system +but usually include: \*(lqcpu\*(rq, \*(lqres\*(rq, \*(lqsize\*(rq, +\*(lqtime\*(rq. The default is cpu. +.TP +.B e +Display a list of system errors (if any) generated by the last +.BR k ill +or +.BR r enice +command. +.TP +.B H +Toggle the display of threads. +.TP +.B i +(or +.BR I ) +Toggle the display of idle processes. +.TP +.B j +Toggle the display of +.IR jail (8) +ID. +.TP +.B J +Display only processes owned by a specific jail (prompt for jail). +If the jail specified is simply \*(lq+\*(rq, then processes belonging +to all jails and the host will be displayed. +This will also enable the display of JID. +.TP +.B P +Toggle the display of per-CPU statistics. +.TP +.B t +Toggle the display of the +.I top +process. +.TP +.B w +Toggle the display of swap usage. +.TP +.B z +Toggle the display of the system idle process. +.SH "THE DISPLAY" +The actual display varies depending on the specific variant of Unix +that the machine is running. This description may not exactly match +what is seen by top running on this particular machine. Differences +are listed at the end of this manual entry. +.PP +The top few lines of the display show general information +about the state of the system, including +the last process id assigned to a process (on most systems), +the three load averages, +the current time, +the number of existing processes, +the number of processes in each state +(sleeping, running, starting, zombies, and stopped), +and a percentage of time spent in each of the processor states +(user, nice, system, and idle). +It also includes information about physical and virtual memory allocation. +.PP +The remainder of the screen displays information about individual +processes. This display is similar in spirit to +.IR ps (1) +but it is not exactly the same. PID is the process id, +JID, when displayed, is the +.IR jail (8) +ID corresponding to the process, +USERNAME is the name of the process's owner (if +.B \-u +is specified, a UID column will be substituted for USERNAME), +PRI is the current priority of the process, +NICE is the nice amount (in the range \-20 to 20), +SIZE is the total size of the process (text, data, and stack), +RES is the current amount of resident memory, +SWAP is the approximate amount of swap, if enabled +(SIZE, RES and SWAP are given in kilobytes), +STATE is the current state (one of \*(lqSTART\*(rq, \*(lqRUN\*(rq +(shown as \*(lqCPUn\*(rq on SMP systems), \*(lqSLEEP\*(rq, \*(lqSTOP\*(rq, +\*(lqZOMB\*(rq, \*(lqWAIT\*(rq, \*(lqLOCK\*(rq or the event on which the +process waits), +C is the processor number on which the process is executing +(visible only on SMP systems), +TIME is the number of system and user cpu seconds that the process has used, +WCPU, when displayed, is the weighted cpu percentage (this is the same +value that +.IR ps (1) +displays as CPU), +CPU is the raw percentage and is the field that is sorted to determine +the order of the processes, and +COMMAND is the name of the command that the process is currently running +(if the process is swapped out, this column is marked \*(lq\*(rq). +.SH NOTES +If a process is in the \*(lqSLEEP\*(rq or \*(lqLOCK\*(rq state, +the state column will report the name of the event or lock on which the +process is waiting. +Lock names are prefixed with an asterisk \*(lq*\*(rq while sleep events +are not. +.SH AUTHOR +William LeFebvre, EECS Department, Northwestern University +.SH ENVIRONMENT +.DT +TOP user-configurable defaults for options. +.SH FILES +.DT +/dev/kmem kernel memory +.br +/dev/mem physical memory +.br +/etc/passwd used to map uid numbers to user names +.br +/boot/kernel/kernel system image +.SH BUGS +Don't shoot me, but the default for +.B \-I +has changed once again. So many people were confused by the fact that +.I top +wasn't showing them all the processes that I have decided to make the +default behavior show idle processes, just like it did in version 2. +But to appease folks who can't stand that behavior, I have added the +ability to set \*(lqdefault\*(rq options in the environment variable +.B TOP +(see the OPTIONS section). Those who want the behavior that version +3.0 had need only set the environment variable +.B TOP +to \*(lq\-I\*(rq. +.PP +The command name for swapped processes should be tracked down, but this +would make the program run slower. +.PP +As with +.IR ps (1), +things can change while +.I top +is collecting information for an update. The picture it gives is only a +close approximation to reality. +.SH "SEE ALSO" +kill(1), +ps(1), +stty(1), +mem(4), +renice(8) +.\" $FreeBSD$ +.SH "FreeBSD NOTES" + +.SH DESCRIPTION OF MEMORY +Mem: 61M Active, 86M Inact, 368K Laundry, 22G Wired, 102G Free +ARC: 15G Total, 9303M MFU, 6155M MRU, 1464K Anon, 98M Header, 35M Other + 15G Compressed, 27G Uncompressed, 1.75:1 Ratio, 174M Overhead +Swap: 4096M Total, 532M Free, 13% Inuse, 80K In, 104K Out +.TP +.B K: +Kilobyte +.TP +.B M: +Megabyte +.TP +.B G: +Gigabyte +.TP +.B %: +1/100 +.SS Physical Memory Stats +.TP +.B Active: +number of bytes active +.TP +.B Inact: +number of clean bytes inactive +.TP +.B Laundry: +number of dirty bytes queued for laundering +.TP +.B Wired: +number of bytes wired down, including BIO-level cached file data pages +.TP +.B Buf: +number of bytes used for BIO-level disk caching +.TP +.B Free: +number of bytes free +.SS ZFS ARC Stats +These stats are only displayed when the ARC is in use. +.TP +.B Total: +number of wired bytes used for the ZFS ARC +.TP +.B MRU: +number of ARC bytes holding most recently used data +.TP +.B MFU: +number of ARC bytes holding most frequently used data +.TP +.B Anon: +number of ARC bytes holding in flight data +.TP +.B Header: +number of ARC bytes holding headers +.TP +.B Other: +miscellaneous ARC bytes +.TP +.B Compressed: +bytes of memory used by ARC caches +.TP +.B Uncompressed: +bytes of data stored in ARC caches before compression +.TP +.B Ratio: +compression ratio of data cached in the ARC +.SS Swap Stats +.TP +.B Total: +total available swap usage +.TP +.B Free: +total free swap usage +.TP +.B Inuse: +swap usage +.TP +.B In: +bytes paged in from swap devices (last interval) +.TP +.B Out: +bytes paged out to swap devices (last interval) Index: head/usr.bin/top/top.c =================================================================== --- head/usr.bin/top/top.c +++ head/usr.bin/top/top.c @@ -0,0 +1,1318 @@ +char *copyright = + "Copyright (c) 1984 through 1996, William LeFebvre"; + +/* + * Top users/processes display for Unix + * Version 3 + * + * This program may be freely redistributed, + * but this entire comment MUST remain intact. + * + * Copyright (c) 1984, 1989, William LeFebvre, Rice University + * Copyright (c) 1989 - 1994, William LeFebvre, Northwestern University + * Copyright (c) 1994, 1995, William LeFebvre, Argonne National Laboratory + * Copyright (c) 1996, William LeFebvre, Group sys Consulting + * + * $FreeBSD$ + */ + +/* + * See the file "Changes" for information on version-to-version changes. + */ + +/* + * This file contains "main" and other high-level routines. + */ + +/* + * The following preprocessor variables, when defined, are used to + * distinguish between different Unix implementations: + * + * SIGHOLD - use SVR4 sighold function when defined + * SIGRELSE - use SVR4 sigrelse function when defined + * FD_SET - macros FD_SET and FD_ZERO are used when defined + */ + +#include "os.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* includes specific to top */ +#include "commands.h" +#include "display.h" /* interface to display package */ +#include "screen.h" /* interface to screen package */ +#include "top.h" +#include "top.local.h" +#include "boolean.h" +#include "machine.h" +#include "utils.h" +#include "username.h" + +/* Size of the stdio buffer given to stdout */ +#define Buffersize 2048 + +/* The buffer that stdio will use */ +char stdoutbuf[Buffersize]; + +/* build Signal masks */ +#define Smask(s) (1 << ((s) - 1)) + +/* for getopt: */ +extern int optind; +extern char *optarg; + +/* imported from screen.c */ +extern int overstrike; + +static int fmt_flags = 0; +int pcpu_stats = No; + +/* signal handling routines */ +sigret_t leave(); +sigret_t tstop(); +#ifdef SIGWINCH +sigret_t top_winch(int); +#endif + +volatile sig_atomic_t leaveflag; +volatile sig_atomic_t tstopflag; +volatile sig_atomic_t winchflag; + +/* internal routines */ +void quit(); + +/* values which need to be accessed by signal handlers */ +static int max_topn; /* maximum displayable processes */ + +/* miscellaneous things */ +struct process_select ps; +char *myname = "top"; +jmp_buf jmp_int; + +/* routines that don't return int */ + +char *username(); +char *ctime(); +char *kill_procs(); +char *renice_procs(); + +#ifdef ORDER +extern int (*compares[])(); +#else +extern int proc_compare(); +extern int io_compare(); +#endif +time_t time(); + +caddr_t get_process_info(struct system_info *si, struct process_select *sel, + int (*compare)(const void *, const void *)); + +/* different routines for displaying the user's identification */ +/* (values assigned to get_userid) */ +char *username(); +char *itoa7(); + +/* pointers to display routines */ +void (*d_loadave)(int mpid, double *avenrun) = i_loadave; +void (*d_procstates)(int total, int *brkdn) = i_procstates; +void (*d_cpustates)(int *states) = i_cpustates; +void (*d_memory)(int *stats) = i_memory; +void (*d_arc)(int *stats) = i_arc; +void (*d_carc)(int *stats) = i_carc; +void (*d_swap)(int *stats) = i_swap; +void (*d_message)(void) = i_message; +void (*d_header)(char *text) = i_header; +void (*d_process)(int line, char *thisline) = i_process; + +void reset_display(void); + +static void +reset_uids() +{ + for (size_t i = 0; i < TOP_MAX_UIDS; ++i) + ps.uid[i] = -1; +} + +static int +add_uid(int uid) +{ + size_t i = 0; + + /* Add the uid if there's room */ + for (; i < TOP_MAX_UIDS; ++i) + { + if (ps.uid[i] == -1 || ps.uid[i] == uid) + { + ps.uid[i] = uid; + break; + } + } + + return (i == TOP_MAX_UIDS); +} + +static void +rem_uid(int uid) +{ + size_t i = 0; + size_t where = TOP_MAX_UIDS; + + /* Look for the user to remove - no problem if it's not there */ + for (; i < TOP_MAX_UIDS; ++i) + { + if (ps.uid[i] == -1) + break; + if (ps.uid[i] == uid) + where = i; + } + + /* Make sure we don't leave a hole in the middle */ + if (where != TOP_MAX_UIDS) + { + ps.uid[where] = ps.uid[i-1]; + ps.uid[i-1] = -1; + } +} + +static int +handle_user(char *buf, size_t buflen) +{ + int rc = 0; + int uid = -1; + char *buf2 = buf; + + new_message(MT_standout, "Username to show (+ for all): "); + if (readline(buf, buflen, No) <= 0) + { + clear_message(); + return rc; + } + + if (buf[0] == '+' || buf[0] == '-') + { + if (buf[1] == '\0') + { + reset_uids(); + goto end; + } + else + ++buf2; + } + + if ((uid = userid(buf2)) == -1) + { + new_message(MT_standout, " %s: unknown user", buf2); + rc = 1; + goto end; + } + + if (buf2 == buf) + { + reset_uids(); + ps.uid[0] = uid; + goto end; + } + + if (buf[0] == '+') + { + if (add_uid(uid)) + { + new_message(MT_standout, " too many users, reset with '+'"); + rc = 1; + goto end; + } + } + else + rem_uid(uid); + +end: + putchar('\r'); + return rc; +} + +int +main(argc, argv) + +int argc; +char *argv[]; + +{ + register int i; + register int active_procs; + register int change; + + struct system_info system_info; + struct statics statics; + caddr_t processes; + + static char tempbuf1[50]; + static char tempbuf2[50]; + int old_sigmask; /* only used for BSD-style signals */ + int topn = Default_TOPN; + int delay = Default_DELAY; + int displays = 0; /* indicates unspecified */ + int sel_ret = 0; + time_t curr_time; + char *(*get_userid)() = username; + char *uname_field = "USERNAME"; + char *header_text; + char *env_top; + char **preset_argv; + int preset_argc = 0; + char **av; + int ac; + char dostates = No; + char do_unames = Yes; + char interactive = Maybe; + char warnings = 0; +#if Default_TOPN == Infinity + char topn_specified = No; +#endif + char ch; + char *iptr; + char no_command = 1; + struct timeval timeout; +#ifdef ORDER + char *order_name = NULL; + int order_index = 0; +#endif +#ifndef FD_SET + /* FD_SET and friends are not present: fake it */ + typedef int fd_set; +#define FD_ZERO(x) (*(x) = 0) +#define FD_SET(f, x) (*(x) = 1< 0) + { + if ((myname = strrchr(argv[0], '/')) == 0) + { + myname = argv[0]; + } + else + { + myname++; + } + } + + /* initialize some selection options */ + ps.idle = Yes; + ps.self = -1; + ps.system = No; + reset_uids(); + ps.thread = No; + ps.wcpu = 1; + ps.jid = -1; + ps.jail = No; + ps.swap = No; + ps.kidle = Yes; + ps.command = NULL; + + /* get preset options from the environment */ + if ((env_top = getenv("TOP")) != NULL) + { + av = preset_argv = argparse(env_top, &preset_argc); + ac = preset_argc; + + /* set the dummy argument to an explanatory message, in case + getopt encounters a bad argument */ + preset_argv[0] = "while processing environment"; + } + + /* process options */ + do { + /* if we're done doing the presets, then process the real arguments */ + if (preset_argc == 0) + { + ac = argc; + av = argv; + + /* this should keep getopt happy... */ + optind = 1; + } + + while ((i = getopt(ac, av, "CSIHPabijJ:nquvzs:d:U:m:o:tw")) != EOF) + { + switch(i) + { + case 'v': /* show version number */ + fprintf(stderr, "%s: version %s\n", + myname, version_string()); + exit(1); + break; + + case 'u': /* toggle uid/username display */ + do_unames = !do_unames; + break; + + case 'U': /* display only username's processes */ + if ((ps.uid[0] = userid(optarg)) == -1) + { + fprintf(stderr, "%s: unknown user\n", optarg); + exit(1); + } + break; + + case 'S': /* show system processes */ + ps.system = !ps.system; + break; + + case 'I': /* show idle processes */ + ps.idle = !ps.idle; + break; + + case 'i': /* go interactive regardless */ + interactive = Yes; + break; + + case 'n': /* batch, or non-interactive */ + case 'b': + interactive = No; + break; + + case 'a': + fmt_flags ^= FMT_SHOWARGS; + break; + + case 'd': /* number of displays to show */ + if ((i = atoiwi(optarg)) == Invalid || i == 0) + { + fprintf(stderr, + "%s: warning: display count should be positive -- option ignored\n", + myname); + warnings++; + } + else + { + displays = i; + } + break; + + case 's': + if ((delay = atoi(optarg)) < 0 || (delay == 0 && getuid() != 0)) + { + fprintf(stderr, + "%s: warning: seconds delay should be positive -- using default\n", + myname); + delay = Default_DELAY; + warnings++; + } + break; + + case 'q': /* be quick about it */ + /* only allow this if user is really root */ + if (getuid() == 0) + { + /* be very un-nice! */ + (void) nice(-20); + } + else + { + fprintf(stderr, + "%s: warning: `-q' option can only be used by root\n", + myname); + warnings++; + } + break; + + case 'm': /* select display mode */ + if (strcmp(optarg, "io") == 0) { + displaymode = DISP_IO; + } else if (strcmp(optarg, "cpu") == 0) { + displaymode = DISP_CPU; + } else { + fprintf(stderr, + "%s: warning: `-m' option can only take args " + "'io' or 'cpu'\n", + myname); + exit(1); + } + break; + + case 'o': /* select sort order */ +#ifdef ORDER + order_name = optarg; +#else + fprintf(stderr, + "%s: this platform does not support arbitrary ordering. Sorry.\n", + myname); + warnings++; +#endif + break; + + case 't': + ps.self = (ps.self == -1) ? getpid() : -1; + break; + + case 'C': + ps.wcpu = !ps.wcpu; + break; + + case 'H': + ps.thread = !ps.thread; + break; + + case 'j': + ps.jail = !ps.jail; + break; + + case 'J': /* display only jail's processes */ + if ((ps.jid = jail_getid(optarg)) == -1) + { + fprintf(stderr, "%s: unknown jail\n", optarg); + exit(1); + } + ps.jail = 1; + break; + + case 'P': + pcpu_stats = !pcpu_stats; + break; + + case 'w': + ps.swap = 1; + break; + + case 'z': + ps.kidle = !ps.kidle; + break; + + default: + fprintf(stderr, +"Top version %s\n" +"Usage: %s [-abCHIijnPqStuvwz] [-d count] [-m io | cpu] [-o field] [-s time]\n" +" [-J jail] [-U username] [number]\n", + version_string(), myname); + exit(1); + } + } + + /* get count of top processes to display (if any) */ + if (optind < ac) + { + if ((topn = atoiwi(av[optind])) == Invalid) + { + fprintf(stderr, + "%s: warning: process display count should be non-negative -- using default\n", + myname); + warnings++; + } +#if Default_TOPN == Infinity + else + { + topn_specified = Yes; + } +#endif + } + + /* tricky: remember old value of preset_argc & set preset_argc = 0 */ + i = preset_argc; + preset_argc = 0; + + /* repeat only if we really did the preset arguments */ + } while (i != 0); + + /* set constants for username/uid display correctly */ + if (!do_unames) + { + uname_field = " UID "; + get_userid = itoa7; + } + + /* initialize the kernel memory interface */ + if (machine_init(&statics, do_unames) == -1) + { + exit(1); + } + +#ifdef ORDER + /* determine sorting order index, if necessary */ + if (order_name != NULL) + { + if ((order_index = string_index(order_name, statics.order_names)) == -1) + { + char **pp; + + fprintf(stderr, "%s: '%s' is not a recognized sorting order.\n", + myname, order_name); + fprintf(stderr, "\tTry one of these:"); + pp = statics.order_names; + while (*pp != NULL) + { + fprintf(stderr, " %s", *pp++); + } + fputc('\n', stderr); + exit(1); + } + } +#endif + +#ifdef no_initialization_needed + /* initialize the hashing stuff */ + if (do_unames) + { + init_hash(); + } +#endif + + /* initialize termcap */ + init_termcap(interactive); + + /* get the string to use for the process area header */ + header_text = format_header(uname_field); + + /* initialize display interface */ + if ((max_topn = display_init(&statics)) == -1) + { + fprintf(stderr, "%s: can't allocate sufficient memory\n", myname); + exit(4); + } + + /* print warning if user requested more processes than we can display */ + if (topn > max_topn) + { + fprintf(stderr, + "%s: warning: this terminal can only display %d processes.\n", + myname, max_topn); + warnings++; + } + + /* adjust for topn == Infinity */ + if (topn == Infinity) + { + /* + * For smart terminals, infinity really means everything that can + * be displayed, or Largest. + * On dumb terminals, infinity means every process in the system! + * We only really want to do that if it was explicitly specified. + * This is always the case when "Default_TOPN != Infinity". But if + * topn wasn't explicitly specified and we are on a dumb terminal + * and the default is Infinity, then (and only then) we use + * "Nominal_TOPN" instead. + */ +#if Default_TOPN == Infinity + topn = smart_terminal ? Largest : + (topn_specified ? Largest : Nominal_TOPN); +#else + topn = Largest; +#endif + } + + /* set header display accordingly */ + display_header(topn > 0); + + /* determine interactive state */ + if (interactive == Maybe) + { + interactive = smart_terminal; + } + + /* if # of displays not specified, fill it in */ + if (displays == 0) + { + displays = smart_terminal ? Infinity : 1; + } + + /* hold interrupt signals while setting up the screen and the handlers */ +#ifdef SIGHOLD + sighold(SIGINT); + sighold(SIGQUIT); + sighold(SIGTSTP); +#else + old_sigmask = sigblock(Smask(SIGINT) | Smask(SIGQUIT) | Smask(SIGTSTP)); +#endif + init_screen(); + (void) signal(SIGINT, leave); + (void) signal(SIGQUIT, leave); + (void) signal(SIGTSTP, tstop); +#ifdef SIGWINCH + (void) signal(SIGWINCH, top_winch); +#endif +#ifdef SIGRELSE + sigrelse(SIGINT); + sigrelse(SIGQUIT); + sigrelse(SIGTSTP); +#else + (void) sigsetmask(old_sigmask); +#endif + if (warnings) + { + fputs("....", stderr); + fflush(stderr); /* why must I do this? */ + sleep((unsigned)(3 * warnings)); + fputc('\n', stderr); + } + +restart: + + /* + * main loop -- repeat while display count is positive or while it + * indicates infinity (by being -1) + */ + + while ((displays == -1) || (displays-- > 0)) + { + int (*compare)(); + + + /* get the current stats */ + get_system_info(&system_info); + +#ifdef ORDER + compare = compares[order_index]; +#else + if (displaymode == DISP_CPU) + compare = proc_compare; + else + compare = io_compare; +#endif + + /* get the current set of processes */ + processes = + get_process_info(&system_info, &ps, compare); + + /* display the load averages */ + (*d_loadave)(system_info.last_pid, + system_info.load_avg); + + /* display the current time */ + /* this method of getting the time SHOULD be fairly portable */ + time(&curr_time); + i_uptime(&system_info.boottime, &curr_time); + i_timeofday(&curr_time); + + /* display process state breakdown */ + (*d_procstates)(system_info.p_total, + system_info.procstates); + + /* display the cpu state percentage breakdown */ + if (dostates) /* but not the first time */ + { + (*d_cpustates)(system_info.cpustates); + } + else + { + /* we'll do it next time */ + if (smart_terminal) + { + z_cpustates(); + } + else + { + putchar('\n'); + } + dostates = Yes; + } + + /* display memory stats */ + (*d_memory)(system_info.memory); + (*d_arc)(system_info.arc); + (*d_carc)(system_info.carc); + + /* display swap stats */ + (*d_swap)(system_info.swap); + + /* handle message area */ + (*d_message)(); + + /* update the header area */ + (*d_header)(header_text); + + if (topn > 0) + { + /* determine number of processes to actually display */ + /* this number will be the smallest of: active processes, + number user requested, number current screen accomodates */ + active_procs = system_info.P_ACTIVE; + if (active_procs > topn) + { + active_procs = topn; + } + if (active_procs > max_topn) + { + active_procs = max_topn; + } + + /* now show the top "n" processes. */ + for (i = 0; i < active_procs; i++) + { + (*d_process)(i, format_next_process(processes, get_userid, + fmt_flags)); + } + } + else + { + i = 0; + } + + /* do end-screen processing */ + u_endscreen(i); + + /* now, flush the output buffer */ + if (fflush(stdout) != 0) + { + new_message(MT_standout, " Write error on stdout"); + putchar('\r'); + quit(1); + /*NOTREACHED*/ + } + + /* only do the rest if we have more displays to show */ + if (displays) + { + /* switch out for new display on smart terminals */ + if (smart_terminal) + { + if (overstrike) + { + reset_display(); + } + else + { + d_loadave = u_loadave; + d_procstates = u_procstates; + d_cpustates = u_cpustates; + d_memory = u_memory; + d_arc = u_arc; + d_carc = u_carc; + d_swap = u_swap; + d_message = u_message; + d_header = u_header; + d_process = u_process; + } + } + + no_command = Yes; + if (!interactive) + { + sleep(delay); + if (leaveflag) { + end_screen(); + exit(0); + } + } + else while (no_command) + { + /* assume valid command unless told otherwise */ + no_command = No; + + /* set up arguments for select with timeout */ + FD_ZERO(&readfds); + FD_SET(0, &readfds); /* for standard input */ + timeout.tv_sec = delay; + timeout.tv_usec = 0; + + if (leaveflag) { + end_screen(); + exit(0); + } + + if (tstopflag) { + /* move to the lower left */ + end_screen(); + fflush(stdout); + + /* default the signal handler action */ + (void) signal(SIGTSTP, SIG_DFL); + + /* unblock the signal and send ourselves one */ +#ifdef SIGRELSE + sigrelse(SIGTSTP); +#else + (void) sigsetmask(sigblock(0) & ~(1 << (SIGTSTP - 1))); +#endif + (void) kill(0, SIGTSTP); + + /* reset the signal handler */ + (void) signal(SIGTSTP, tstop); + + /* reinit screen */ + reinit_screen(); + reset_display(); + tstopflag = 0; + goto restart; + } + + if (winchflag) { + /* reascertain the screen dimensions */ + get_screensize(); + + /* tell display to resize */ + max_topn = display_resize(); + + /* reset the signal handler */ + (void) signal(SIGWINCH, top_winch); + + reset_display(); + winchflag = 0; + goto restart; + } + + /* wait for either input or the end of the delay period */ + sel_ret = select(2, &readfds, NULL, NULL, &timeout); + if (sel_ret < 0 && errno != EINTR) + quit(0); + if (sel_ret > 0) + { + int newval; + char *errmsg; + + /* something to read -- clear the message area first */ + clear_message(); + + /* now read it and convert to command strchr */ + /* (use "change" as a temporary to hold strchr) */ + if (read(0, &ch, 1) != 1) + { + /* read error: either 0 or -1 */ + new_message(MT_standout, " Read error on stdin"); + putchar('\r'); + quit(1); + /*NOTREACHED*/ + } + if ((iptr = strchr(command_chars, ch)) == NULL) + { + if (ch != '\r' && ch != '\n') + { + /* illegal command */ + new_message(MT_standout, " Command not understood"); + } + putchar('\r'); + no_command = Yes; + } + else + { + change = iptr - command_chars; + if (overstrike && change > CMD_OSLIMIT) + { + /* error */ + new_message(MT_standout, + " Command cannot be handled by this terminal"); + putchar('\r'); + no_command = Yes; + } + else switch(change) + { + case CMD_redraw: /* redraw screen */ + reset_display(); + break; + + case CMD_update: /* merely update display */ + /* is the load average high? */ + if (system_info.load_avg[0] > LoadMax) + { + /* yes, go home for visual feedback */ + go_home(); + fflush(stdout); + } + break; + + case CMD_quit: /* quit */ + quit(0); + /*NOTREACHED*/ + break; + + case CMD_help1: /* help */ + case CMD_help2: + reset_display(); + top_clear(); + show_help(); + top_standout("Hit any key to continue: "); + fflush(stdout); + (void) read(0, &ch, 1); + break; + + case CMD_errors: /* show errors */ + if (error_count() == 0) + { + new_message(MT_standout, + " Currently no errors to report."); + putchar('\r'); + no_command = Yes; + } + else + { + reset_display(); + top_clear(); + show_errors(); + top_standout("Hit any key to continue: "); + fflush(stdout); + (void) read(0, &ch, 1); + } + break; + + case CMD_number1: /* new number */ + case CMD_number2: + new_message(MT_standout, + "Number of processes to show: "); + newval = readline(tempbuf1, 8, Yes); + if (newval > -1) + { + if (newval > max_topn) + { + new_message(MT_standout | MT_delayed, + " This terminal can only display %d processes.", + max_topn); + putchar('\r'); + } + + if (newval == 0) + { + /* inhibit the header */ + display_header(No); + } + else if (newval > topn && topn == 0) + { + /* redraw the header */ + display_header(Yes); + d_header = i_header; + } + topn = newval; + } + break; + + case CMD_delay: /* new seconds delay */ + new_message(MT_standout, "Seconds to delay: "); + if ((i = readline(tempbuf1, 8, Yes)) > -1) + { + if ((delay = i) == 0 && getuid() != 0) + { + delay = 1; + } + } + clear_message(); + break; + + case CMD_displays: /* change display count */ + new_message(MT_standout, + "Displays to show (currently %s): ", + displays == -1 ? "infinite" : + itoa(displays)); + if ((i = readline(tempbuf1, 10, Yes)) > 0) + { + displays = i; + } + else if (i == 0) + { + quit(0); + } + clear_message(); + break; + + case CMD_kill: /* kill program */ + new_message(0, "kill "); + if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) + { + if ((errmsg = kill_procs(tempbuf2)) != NULL) + { + new_message(MT_standout, "%s", errmsg); + putchar('\r'); + no_command = Yes; + } + } + else + { + clear_message(); + } + break; + + case CMD_renice: /* renice program */ + new_message(0, "renice "); + if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) + { + if ((errmsg = renice_procs(tempbuf2)) != NULL) + { + new_message(MT_standout, "%s", errmsg); + putchar('\r'); + no_command = Yes; + } + } + else + { + clear_message(); + } + break; + + case CMD_idletog: + case CMD_idletog2: + ps.idle = !ps.idle; + new_message(MT_standout | MT_delayed, + " %sisplaying idle processes.", + ps.idle ? "D" : "Not d"); + putchar('\r'); + break; + + case CMD_selftog: + ps.self = (ps.self == -1) ? getpid() : -1; + new_message(MT_standout | MT_delayed, + " %sisplaying self.", + (ps.self == -1) ? "D" : "Not d"); + putchar('\r'); + break; + + case CMD_user: + if (handle_user(tempbuf2, sizeof(tempbuf2))) + no_command = Yes; + break; + + case CMD_thrtog: + ps.thread = !ps.thread; + new_message(MT_standout | MT_delayed, + " Displaying threads %s", + ps.thread ? "separately" : "as a count"); + header_text = format_header(uname_field); + reset_display(); + putchar('\r'); + break; + case CMD_wcputog: + ps.wcpu = !ps.wcpu; + new_message(MT_standout | MT_delayed, + " Displaying %s CPU", + ps.wcpu ? "weighted" : "raw"); + header_text = format_header(uname_field); + reset_display(); + putchar('\r'); + break; + case CMD_viewtog: + if (++displaymode == DISP_MAX) + displaymode = 0; + header_text = format_header(uname_field); + display_header(Yes); + d_header = i_header; + reset_display(); + break; + case CMD_viewsys: + ps.system = !ps.system; + break; + case CMD_showargs: + fmt_flags ^= FMT_SHOWARGS; + break; +#ifdef ORDER + case CMD_order: + new_message(MT_standout, + "Order to sort: "); + if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) + { + if ((i = string_index(tempbuf2, statics.order_names)) == -1) + { + new_message(MT_standout, + " %s: unrecognized sorting order", tempbuf2); + no_command = Yes; + } + else + { + order_index = i; + } + putchar('\r'); + } + else + { + clear_message(); + } + break; +#endif + case CMD_jidtog: + ps.jail = !ps.jail; + new_message(MT_standout | MT_delayed, + " %sisplaying jail ID.", + ps.jail ? "D" : "Not d"); + header_text = format_header(uname_field); + reset_display(); + putchar('\r'); + break; + + case CMD_jail: + new_message(MT_standout, + "Jail to show (+ for all): "); + if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) + { + if (tempbuf2[0] == '+' && + tempbuf2[1] == '\0') + { + ps.jid = -1; + } + else if ((i = jail_getid(tempbuf2)) == -1) + { + new_message(MT_standout, + " %s: unknown jail", tempbuf2); + no_command = Yes; + } + else + { + ps.jid = i; + } + if (ps.jail == 0) { + ps.jail = 1; + new_message(MT_standout | + MT_delayed, " Displaying jail " + "ID."); + header_text = + format_header(uname_field); + reset_display(); + } + putchar('\r'); + } + else + { + clear_message(); + } + break; + + case CMD_kidletog: + ps.kidle = !ps.kidle; + new_message(MT_standout | MT_delayed, + " %sisplaying system idle process.", + ps.kidle ? "D" : "Not d"); + putchar('\r'); + break; + case CMD_pcputog: + pcpu_stats = !pcpu_stats; + new_message(MT_standout | MT_delayed, + " Displaying %sCPU statistics.", + pcpu_stats ? "per-" : "global "); + toggle_pcpustats(); + max_topn = display_updatecpus(&statics); + reset_display(); + putchar('\r'); + break; + case CMD_swaptog: + ps.swap = !ps.swap; + new_message(MT_standout | MT_delayed, + " %sisplaying per-process swap usage.", + ps.swap ? "D" : "Not d"); + header_text = format_header(uname_field); + reset_display(); + putchar('\r'); + break; + default: + new_message(MT_standout, " BAD CASE IN SWITCH!"); + putchar('\r'); + } + } + + /* flush out stuff that may have been written */ + fflush(stdout); + } + } + } + } + +#ifdef DEBUG + fclose(debug); +#endif + quit(0); + /*NOTREACHED*/ +} + +/* + * reset_display() - reset all the display routine pointers so that entire + * screen will get redrawn. + */ + +void +reset_display() + +{ + d_loadave = i_loadave; + d_procstates = i_procstates; + d_cpustates = i_cpustates; + d_memory = i_memory; + d_arc = i_arc; + d_carc = i_carc; + d_swap = i_swap; + d_message = i_message; + d_header = i_header; + d_process = i_process; +} + +/* + * signal handlers + */ + +sigret_t leave() /* exit under normal conditions -- INT handler */ + +{ + leaveflag = 1; +} + +sigret_t tstop(i) /* SIGTSTP handler */ + +int i; + +{ + tstopflag = 1; +} + +#ifdef SIGWINCH +sigret_t top_winch(int i) /* SIGWINCH handler */ +{ + winchflag = 1; +} +#endif + +void quit(status) /* exit under duress */ + +int status; + +{ + end_screen(); + exit(status); + /*NOTREACHED*/ +} Index: head/usr.bin/top/top.local.hs =================================================================== --- head/usr.bin/top/top.local.hs +++ head/usr.bin/top/top.local.hs @@ -0,0 +1,68 @@ +/* + * Top - a top users display for Berkeley Unix + * + * Definitions for things that might vary between installations. + */ + +/* + * The space command forces an immediate update. Sometimes, on loaded + * systems, this update will take a significant period of time (because all + * the output is buffered). So, if the short-term load average is above + * "LoadMax", then top will put the cursor home immediately after the space + * is pressed before the next update is attempted. This serves as a visual + * acknowledgement of the command. On Suns, "LoadMax" will get multiplied by + * "FSCALE" before being compared to avenrun[0]. Therefore, "LoadMax" + * should always be specified as a floating point number. + */ +#ifndef LoadMax +#define LoadMax %LoadMax% +#endif + +/* + * "Table_size" defines the size of the hash tables used to map uid to + * username. The number of users in /etc/passwd CANNOT be greater than + * this number. If the error message "table overflow: too many users" + * is printed by top, then "Table_size" needs to be increased. Things will + * work best if the number is a prime number that is about twice the number + * of lines in /etc/passwd. + */ +#ifndef Table_size +#define Table_size %TableSize% +#endif + +/* + * "Nominal_TOPN" is used as the default TOPN when Default_TOPN is Infinity + * and the output is a dumb terminal. If we didn't do this, then + * installations who use a default TOPN of Infinity will get every + * process in the system when running top on a dumb terminal (or redirected + * to a file). Note that Nominal_TOPN is a default: it can still be + * overridden on the command line, even with the value "infinity". + */ +#ifndef Nominal_TOPN +#define Nominal_TOPN %NominalTopn% +#endif + +#ifndef Default_TOPN +#define Default_TOPN %topn% +#endif + +#ifndef Default_DELAY +#define Default_DELAY %delay% +#endif + +/* + * If the local system's getpwnam interface uses random access to retrieve + * a record (i.e.: 4.3 systems, Sun "yellow pages"), then defining + * RANDOM_PW will take advantage of that fact. If RANDOM_PW is defined, + * then getpwnam is used and the result is cached. If not, then getpwent + * is used to read and cache the password entries sequentially until the + * desired one is found. + * + * We initially set RANDOM_PW to something which is controllable by the + * Configure script. Then if its value is 0, we undef it. + */ + +#define RANDOM_PW %random% +#if RANDOM_PW == 0 +#undef RANDOM_PW +#endif Index: head/usr.bin/top/top.local.1 =================================================================== --- head/usr.bin/top/top.local.1 +++ head/usr.bin/top/top.local.1 @@ -1,84 +0,0 @@ -.\" $FreeBSD$ -.SH "FreeBSD NOTES" - -.SH DESCRIPTION OF MEMORY -Mem: 61M Active, 86M Inact, 368K Laundry, 22G Wired, 102G Free -ARC: 15G Total, 9303M MFU, 6155M MRU, 1464K Anon, 98M Header, 35M Other - 15G Compressed, 27G Uncompressed, 1.75:1 Ratio, 174M Overhead -Swap: 4096M Total, 532M Free, 13% Inuse, 80K In, 104K Out -.TP -.B K: -Kilobyte -.TP -.B M: -Megabyte -.TP -.B G: -Gigabyte -.TP -.B %: -1/100 -.SS Physical Memory Stats -.TP -.B Active: -number of bytes active -.TP -.B Inact: -number of clean bytes inactive -.TP -.B Laundry: -number of dirty bytes queued for laundering -.TP -.B Wired: -number of bytes wired down, including BIO-level cached file data pages -.TP -.B Buf: -number of bytes used for BIO-level disk caching -.TP -.B Free: -number of bytes free -.SS ZFS ARC Stats -These stats are only displayed when the ARC is in use. -.TP -.B Total: -number of wired bytes used for the ZFS ARC -.TP -.B MRU: -number of ARC bytes holding most recently used data -.TP -.B MFU: -number of ARC bytes holding most frequently used data -.TP -.B Anon: -number of ARC bytes holding in flight data -.TP -.B Header: -number of ARC bytes holding headers -.TP -.B Other: -miscellaneous ARC bytes -.TP -.B Compressed: -bytes of memory used by ARC caches -.TP -.B Uncompressed: -bytes of data stored in ARC caches before compression -.TP -.B Ratio: -compression ratio of data cached in the ARC -.SS Swap Stats -.TP -.B Total: -total available swap usage -.TP -.B Free: -total free swap usage -.TP -.B Inuse: -swap usage -.TP -.B In: -bytes paged in from swap devices (last interval) -.TP -.B Out: -bytes paged out to swap devices (last interval) Index: head/usr.bin/top/top.xs =================================================================== --- head/usr.bin/top/top.xs +++ head/usr.bin/top/top.xs @@ -0,0 +1,459 @@ +.\" NOTE: changes to the manual page for "top" should be made in the +.\" file "top.X" and NOT in the file "top.1". +.\" $FreeBSD$ +.nr N %topn% +.nr D %delay% +.TH TOP 1 Local +.UC 4 +.SH NAME +top \- display and update information about the top cpu processes +.SH SYNOPSIS +.B top +[ +.B \-abCHIijnPqStuvwz +] [ +.BI \-d count +] [ +.BI \-m io | cpu +] [ +.BI \-o field +] [ +.BI \-s time +] [ +.BI \-J jail +] [ +.BI \-U username +] [ +.I number +] +.SH DESCRIPTION +.\" This defines appropriate quote strings for nroff and troff +.ds lq \&" +.ds rq \&" +.if t .ds lq `` +.if t .ds rq '' +.\" Just in case these number registers aren't set yet... +.if \nN==0 .nr N 10 +.if \nD==0 .nr D 2 +.I Top +displays the top +.if !\nN==-1 \nN +processes on the system and periodically updates this information. +.if \nN==-1 \ +\{\ +If standard output is an intelligent terminal (see below) then +as many processes as will fit on the terminal screen are displayed +by default. Otherwise, a good number of them are shown (around 20). +.\} +Raw cpu percentage is used to rank the processes. If +.I number +is given, then the top +.I number +processes will be displayed instead of the default. +.PP +.I Top +makes a distinction between terminals that support advanced capabilities +and those that do not. This +distinction affects the choice of defaults for certain options. In the +remainder of this document, an \*(lqintelligent\*(rq terminal is one that +supports cursor addressing, clear screen, and clear to end of line. +Conversely, a \*(lqdumb\*(rq terminal is one that does not support such +features. If the output of +.I top +is redirected to a file, it acts as if it were being run on a dumb +terminal. +.SH OPTIONS +.TP +.B \-C +Toggle CPU display mode. +By default top displays the weighted CPU percentage in the WCPU column +(this is the same value that +.IR ps (1) +displays as CPU). +Each time +.B \-C +flag is passed it toggles between \*(lqraw cpu\*(rq mode +and \*(lqweighted cpu\*(rq mode, showing the \*(lqCPU\*(rq or +the \*(lqWCPU\*(rq column respectively. +.TP +.B \-S +Show system processes in the display. Normally, system processes such as +the pager and the swapper are not shown. This option makes them visible. +.TP +.B \-a +Display command names derived from the argv[] vector, rather than real +executable name. It's useful when you want to watch applications, that +puts their status information there. If the real name differs from argv[0], +it will be displayed in parenthesis. +.TP +.B \-b +Use \*(lqbatch\*(rq mode. In this mode, all input from the terminal is +ignored. Interrupt characters (such as ^C and ^\e) still have an effect. +This is the default on a dumb terminal, or when the output is not a terminal. +.TP +.B \-H +Display each thread for a multithreaded process individually. +By default a single summary line is displayed for each process. +.TP +.B \-i +Use \*(lqinteractive\*(rq mode. In this mode, any input is immediately +read for processing. See the section on \*(lqInteractive Mode\*(rq +for an explanation of +which keys perform what functions. After the command is processed, the +screen will immediately be updated, even if the command was not +understood. This mode is the default when standard output is an +intelligent terminal. +.TP +.B \-I +Do not display idle processes. +By default, top displays both active and idle processes. +.TP +.B \-j +Display the +.IR jail (8) +ID. +.TP +.B \-t +Do not display the +.I top +process. +.TP +.BI \-m display +Display either 'cpu' or 'io' statistics. Default is 'cpu'. +.TP +.B \-n +Use \*(lqnon-interactive\*(rq mode. This is identical to \*(lqbatch\*(rq +mode. +.TP +.B \-P +Display per-cpu CPU usage statistics. +.TP +.B \-q +Renice +.I top +to -20 so that it will run faster. This can be used when the system is +being very sluggish to improve the possibility of discovering the problem. +This option can only be used by root. +.TP +.B \-u +Do not take the time to map uid numbers to usernames. Normally, +.I top +will read as much of the file \*(lq/etc/passwd\*(rq as is necessary to map +all the user id numbers it encounters into login names. This option +disables all that, while possibly decreasing execution time. The uid +numbers are displayed instead of the names. +.TP +.B \-v +Write version number information to stderr then exit immediately. +No other processing takes place when this option is used. To see current +revision information while top is running, use the help command \*(lq?\*(rq. +.TP +.B \-w +Display approximate swap usage for each process. +.TP +.B \-z +Do not display the system idle process. +.TP +.BI \-d count +Show only +.I count +displays, then exit. A display is considered to be one update of the +screen. This option allows the user to select the number of displays he +wants to see before +.I top +automatically exits. For intelligent terminals, no upper limit +is set. The default is 1 for dumb terminals. +.TP +.BI \-s time +Set the delay between screen updates to +.I time +seconds. The default delay between updates is \nD seconds. +.TP +.BI \-o field +Sort the process display area on the specified field. The field name +is the name of the column as seen in the output, but in lower case: +\*(lqcpu\*(lq, \*(rqsize\*(lq, \*(rqres\*(lq, \*(rqtime\*(lq, +\*(rqpri\*(lq, \*(rqthreads\*(lq, \*(lqtotal\*(lq, \*(rqread\*(lq, +\*(rqwrite\*(lq, \*(rqfault\*(lq, \*(rqvcsw\*(lq, \*(rqivcsw\*(lq, +\*(lqjid\*(lq, \*(rqswap\*(lq or \*(rqpid\*(lq. +.TP +.BI \-J jail +Show only those processes owned by +.IR jail . +This may be either the +.B jid +or +.B name +of the jail. +Use +.B 0 +to limit to host processes. +Using this option implies the +.B \-j +flag. +.PP +.BI \-U username +Show only those processes owned by +.IR username . +This option currently only accepts usernames and will not understand +uid numbers. +.PP +Both +.I count +and +.I number +fields can be specified as \*(lqinfinite\*(rq, indicating that they can +stretch as far as possible. This is accomplished by using any proper +prefix of the keywords +\*(lqinfinity\*(rq, +\*(lqmaximum\*(rq, +or +\*(lqall\*(rq. +The default for +.I count +on an intelligent terminal is, in fact, +.BI infinity . +.PP +The environment variable +.B TOP +is examined for options before the command line is scanned. This enables +a user to set his or her own defaults. The number of processes to display +can also be specified in the environment variable +.BR TOP . +The options +.BR \-a , +.BR \-C , +.BR \-H , +.BR \-I , +.BR \-j , +.BR \-P , +.BR \-S , +.BR \-t , +.BR \-u , +.BR \-w , +and +.B \-z +are actually toggles. A second specification of any of these options +will negate the first. Thus a user who has the environment variable +.B TOP +set to \*(lq\-I\*(rq may use the command \*(lqtop \-I\*(rq to see idle processes. +.SH "INTERACTIVE MODE" +When +.I top +is running in \*(lqinteractive mode\*(rq, it reads commands from the +terminal and acts upon them accordingly. In this mode, the terminal is +put in \*(lqCBREAK\*(rq, so that a character will be +processed as soon as it is typed. Almost always, a key will be +pressed when +.I top +is between displays; that is, while it is waiting for +.I time +seconds to elapse. If this is the case, the command will be +processed and the display will be updated immediately thereafter +(reflecting any changes that the command may have specified). This +happens even if the command was incorrect. If a key is pressed while +.I top +is in the middle of updating the display, it will finish the update and +then process the command. Some commands require additional information, +and the user will be prompted accordingly. While typing this information +in, the user's erase and kill keys (as set up by the command +.IR stty ) +are recognized, and a newline terminates the input. +.PP +These commands are currently recognized (^L refers to control-L): +.TP +.B ^L +Redraw the screen. +.IP "\fBh\fP\ or\ \fB?\fP" +Display a summary of the commands (help screen). Version information +is included in this display. +.TP +.B q +Quit +.IR top. +.TP +.B d +Change the number of displays to show (prompt for new number). +Remember that the next display counts as one, so typing +.B d1 +will make +.I top +show one final display and then immediately exit. +.TP +.B m +Toggle the display between 'cpu' and 'io' modes. +.TP +.B n or # +Change the number of processes to display (prompt for new number). +.TP +.B s +Change the number of seconds to delay between displays +(prompt for new number). +.TP +.B S +Toggle the display of system processes. +.TP +.B a +Toggle the display of process titles. +.TP +.B k +Send a signal (\*(lqkill\*(rq by default) to a list of processes. This +acts similarly to the command +.IR kill (1)). +.TP +.B r +Change the priority (the \*(lqnice\*(rq) of a list of processes. +This acts similarly to the command +.IR renice (8)). +.TP +.B u +Display only processes owned by a specific set of usernames (prompt for +username). If the username specified is simply \*(lq+\*(rq or \*(lq-\*(rq, +then processes belonging to all users will be displayed. Usernames can be added +to and removed from the set by prepending them with \*(lq+\*(rq and +\*(lq-\*(rq, respectively. +.TP +.B o +Change the order in which the display is sorted. This command is not +available on all systems. The sort key names vary from system to system +but usually include: \*(lqcpu\*(rq, \*(lqres\*(rq, \*(lqsize\*(rq, +\*(lqtime\*(rq. The default is cpu. +.TP +.B e +Display a list of system errors (if any) generated by the last +.BR k ill +or +.BR r enice +command. +.TP +.B H +Toggle the display of threads. +.TP +.B i +(or +.BR I ) +Toggle the display of idle processes. +.TP +.B j +Toggle the display of +.IR jail (8) +ID. +.TP +.B J +Display only processes owned by a specific jail (prompt for jail). +If the jail specified is simply \*(lq+\*(rq, then processes belonging +to all jails and the host will be displayed. +This will also enable the display of JID. +.TP +.B P +Toggle the display of per-CPU statistics. +.TP +.B t +Toggle the display of the +.I top +process. +.TP +.B w +Toggle the display of swap usage. +.TP +.B z +Toggle the display of the system idle process. +.SH "THE DISPLAY" +The actual display varies depending on the specific variant of Unix +that the machine is running. This description may not exactly match +what is seen by top running on this particular machine. Differences +are listed at the end of this manual entry. +.PP +The top few lines of the display show general information +about the state of the system, including +the last process id assigned to a process (on most systems), +the three load averages, +the current time, +the number of existing processes, +the number of processes in each state +(sleeping, running, starting, zombies, and stopped), +and a percentage of time spent in each of the processor states +(user, nice, system, and idle). +It also includes information about physical and virtual memory allocation. +.PP +The remainder of the screen displays information about individual +processes. This display is similar in spirit to +.IR ps (1) +but it is not exactly the same. PID is the process id, +JID, when displayed, is the +.IR jail (8) +ID corresponding to the process, +USERNAME is the name of the process's owner (if +.B \-u +is specified, a UID column will be substituted for USERNAME), +PRI is the current priority of the process, +NICE is the nice amount (in the range \-20 to 20), +SIZE is the total size of the process (text, data, and stack), +RES is the current amount of resident memory, +SWAP is the approximate amount of swap, if enabled +(SIZE, RES and SWAP are given in kilobytes), +STATE is the current state (one of \*(lqSTART\*(rq, \*(lqRUN\*(rq +(shown as \*(lqCPUn\*(rq on SMP systems), \*(lqSLEEP\*(rq, \*(lqSTOP\*(rq, +\*(lqZOMB\*(rq, \*(lqWAIT\*(rq, \*(lqLOCK\*(rq or the event on which the +process waits), +C is the processor number on which the process is executing +(visible only on SMP systems), +TIME is the number of system and user cpu seconds that the process has used, +WCPU, when displayed, is the weighted cpu percentage (this is the same +value that +.IR ps (1) +displays as CPU), +CPU is the raw percentage and is the field that is sorted to determine +the order of the processes, and +COMMAND is the name of the command that the process is currently running +(if the process is swapped out, this column is marked \*(lq\*(rq). +.SH NOTES +If a process is in the \*(lqSLEEP\*(rq or \*(lqLOCK\*(rq state, +the state column will report the name of the event or lock on which the +process is waiting. +Lock names are prefixed with an asterisk \*(lq*\*(rq while sleep events +are not. +.SH AUTHOR +William LeFebvre, EECS Department, Northwestern University +.SH ENVIRONMENT +.DT +TOP user-configurable defaults for options. +.SH FILES +.DT +/dev/kmem kernel memory +.br +/dev/mem physical memory +.br +/etc/passwd used to map uid numbers to user names +.br +/boot/kernel/kernel system image +.SH BUGS +Don't shoot me, but the default for +.B \-I +has changed once again. So many people were confused by the fact that +.I top +wasn't showing them all the processes that I have decided to make the +default behavior show idle processes, just like it did in version 2. +But to appease folks who can't stand that behavior, I have added the +ability to set \*(lqdefault\*(rq options in the environment variable +.B TOP +(see the OPTIONS section). Those who want the behavior that version +3.0 had need only set the environment variable +.B TOP +to \*(lq\-I\*(rq. +.PP +The command name for swapped processes should be tracked down, but this +would make the program run slower. +.PP +As with +.IR ps (1), +things can change while +.I top +is collecting information for an update. The picture it gives is only a +close approximation to reality. +.SH "SEE ALSO" +kill(1), +ps(1), +stty(1), +mem(4), +renice(8) Index: head/usr.bin/top/username.h =================================================================== --- head/usr.bin/top/username.h +++ head/usr.bin/top/username.h @@ -0,0 +1,23 @@ +/* + * Top users/processes display for Unix + * Version 3 + * + * This program may be freely redistributed, + * but this entire comment MUST remain intact. + * + * Copyright (c) 1984, 1989, William LeFebvre, Rice University + * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University + * Copyright (c) 2016, Randy Westlund + * + * $FreeBSD$ + */ +#ifndef USERNAME_H +#define USERNAME_H + +int enter_user(int uid, char *name, int wecare); +int get_user(int uid); +void init_hash(void); +char *username(int uid); +int userid(char *username); + +#endif /* USERNAME_H */ Index: head/usr.bin/top/username.c =================================================================== --- head/usr.bin/top/username.c +++ head/usr.bin/top/username.c @@ -0,0 +1,195 @@ +/* + * Top users/processes display for Unix + * Version 3 + * + * This program may be freely redistributed, + * but this entire comment MUST remain intact. + * + * Copyright (c) 1984, 1989, William LeFebvre, Rice University + * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University + * + * $FreeBSD$ + */ + +/* + * Username translation code for top. + * + * These routines handle uid to username mapping. + * They use a hashing table scheme to reduce reading overhead. + * For the time being, these are very straightforward hashing routines. + * Maybe someday I'll put in something better. But with the advent of + * "random access" password files, it might not be worth the effort. + * + * Changes to these have been provided by John Gilmore (gnu@toad.com). + * + * The hash has been simplified in this release, to avoid the + * table overflow problems of previous releases. If the value + * at the initial hash location is not right, it is replaced + * by the right value. Collisions will cause us to call getpw* + * but hey, this is a cache, not the Library of Congress. + * This makes the table size independent of the passwd file size. + */ + +#include +#include + +#include +#include +#include +#include + +#include "top.local.h" +#include "utils.h" +#include "username.h" + +struct hash_el { + int uid; + char name[MAXLOGNAME]; +}; + +#define is_empty_hash(x) (hash_table[x].name[0] == 0) + +/* simple minded hashing function */ +/* Uid "nobody" is -2 results in hashit(-2) = -2 which is out of bounds for + the hash_table. Applied abs() function to fix. 2/16/96 tpugh +*/ +#define hashit(i) (abs(i) % Table_size) + +/* K&R requires that statically declared tables be initialized to zero. */ +/* We depend on that for hash_table and YOUR compiler had BETTER do it! */ +struct hash_el hash_table[Table_size]; + + +void +init_hash() + +{ + /* + * There used to be some steps we had to take to initialize things. + * We don't need to do that anymore, but we will leave this stub in + * just in case future changes require initialization steps. + */ +} + +char *username(uid) + +int uid; + +{ + register int hashindex; + + hashindex = hashit(uid); + if (is_empty_hash(hashindex) || (hash_table[hashindex].uid != uid)) + { + /* not here or not right -- get it out of passwd */ + hashindex = get_user(uid); + } + return(hash_table[hashindex].name); +} + +int userid(username) + +char *username; + +{ + struct passwd *pwd; + + /* Eventually we want this to enter everything in the hash table, + but for now we just do it simply and remember just the result. + */ + + if ((pwd = getpwnam(username)) == NULL) + { + return(-1); + } + + /* enter the result in the hash table */ + enter_user(pwd->pw_uid, username, 1); + + /* return our result */ + return(pwd->pw_uid); +} + +int enter_user(uid, name, wecare) + +int uid; +char *name; +int wecare; /* 1 = enter it always, 0 = nice to have */ + +{ + register int hashindex; + +#ifdef DEBUG + fprintf(stderr, "enter_hash(%d, %s, %d)\n", uid, name, wecare); +#endif + + hashindex = hashit(uid); + + if (!is_empty_hash(hashindex)) + { + if (!wecare) + return 0; /* Don't clobber a slot for trash */ + if (hash_table[hashindex].uid == uid) + return(hashindex); /* Fortuitous find */ + } + + /* empty or wrong slot -- fill it with new value */ + hash_table[hashindex].uid = uid; + (void) strncpy(hash_table[hashindex].name, name, MAXLOGNAME - 1); + return(hashindex); +} + +/* + * Get a userid->name mapping from the system. + * If the passwd database is hashed (#define RANDOM_PW), we + * just handle this uid. Otherwise we scan the passwd file + * and cache any entries we pass over while looking. + */ + +int get_user(uid) + +int uid; + +{ + struct passwd *pwd; + +#ifdef RANDOM_PW + /* no performance penalty for using getpwuid makes it easy */ + if ((pwd = getpwuid(uid)) != NULL) + { + return(enter_user(pwd->pw_uid, pwd->pw_name, 1)); + } +#else + + int from_start = 0; + + /* + * If we just called getpwuid each time, things would be very slow + * since that just iterates through the passwd file each time. So, + * we walk through the file instead (using getpwent) and cache each + * entry as we go. Once the right record is found, we cache it and + * return immediately. The next time we come in, getpwent will get + * the next record. In theory, we never have to read the passwd file + * a second time (because we cache everything we read). But in + * practice, the cache may not be large enough, so if we don't find + * it the first time we have to scan the file a second time. This + * is not very efficient, but it will do for now. + */ + + while (from_start++ < 2) + { + while ((pwd = getpwent()) != NULL) + { + if (pwd->pw_uid == uid) + { + return(enter_user(pwd->pw_uid, pwd->pw_name, 1)); + } + (void) enter_user(pwd->pw_uid, pwd->pw_name, 0); + } + /* try again */ + setpwent(); + } +#endif + /* if we can't find the name at all, then use the uid as the name */ + return(enter_user(uid, itoa7(uid), 1)); +} Index: head/usr.bin/top/utils.h =================================================================== --- head/usr.bin/top/utils.h +++ head/usr.bin/top/utils.h @@ -0,0 +1,26 @@ +/* + * Top users/processes display for Unix + * Version 3 + * + * This program may be freely redistributed, + * but this entire comment MUST remain intact. + * + * Copyright (c) 1984, 1989, William LeFebvre, Rice University + * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University + */ + +/* prototypes for functions found in utils.c */ + +int atoiwi(); +char *itoa(); +char *itoa7(); +int digits(); +char *strecpy(); +char **argparse(); +long percentages(); +char *errmsg(); +char *format_time(); +char *format_k(); +char *format_k2(unsigned long long); +int string_index(char *string, char **array); + Index: head/usr.bin/top/utils.c =================================================================== --- head/usr.bin/top/utils.c +++ head/usr.bin/top/utils.c @@ -0,0 +1,508 @@ +/* + * Top users/processes display for Unix + * Version 3 + * + * This program may be freely redistributed, + * but this entire comment MUST remain intact. + * + * Copyright (c) 1984, 1989, William LeFebvre, Rice University + * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University + * + * $FreeBSD$ + */ + +/* + * This file contains various handy utilities used by top. + */ + +#include "top.h" +#include "os.h" + +int atoiwi(str) + +char *str; + +{ + register int len; + + len = strlen(str); + if (len != 0) + { + if (strncmp(str, "infinity", len) == 0 || + strncmp(str, "all", len) == 0 || + strncmp(str, "maximum", len) == 0) + { + return(Infinity); + } + else if (str[0] == '-') + { + return(Invalid); + } + else + { + return(atoi(str)); + } + } + return(0); +} + +/* + * itoa - convert integer (decimal) to ascii string for positive numbers + * only (we don't bother with negative numbers since we know we + * don't use them). + */ + + /* + * How do we know that 16 will suffice? + * Because the biggest number that we will + * ever convert will be 2^32-1, which is 10 + * digits. + */ +_Static_assert(sizeof(int) <= 4, "buffer too small for this sized int"); + +char *itoa(val) + +register int val; + +{ + register char *ptr; + static char buffer[16]; /* result is built here */ + /* 16 is sufficient since the largest number + we will ever convert will be 2^32-1, + which is 10 digits. */ + + ptr = buffer + sizeof(buffer); + *--ptr = '\0'; + if (val == 0) + { + *--ptr = '0'; + } + else while (val != 0) + { + *--ptr = (val % 10) + '0'; + val /= 10; + } + return(ptr); +} + +/* + * itoa7(val) - like itoa, except the number is right justified in a 7 + * character field. This code is a duplication of itoa instead of + * a front end to a more general routine for efficiency. + */ + +char *itoa7(val) + +register int val; + +{ + register char *ptr; + static char buffer[16]; /* result is built here */ + /* 16 is sufficient since the largest number + we will ever convert will be 2^32-1, + which is 10 digits. */ + + ptr = buffer + sizeof(buffer); + *--ptr = '\0'; + if (val == 0) + { + *--ptr = '0'; + } + else while (val != 0) + { + *--ptr = (val % 10) + '0'; + val /= 10; + } + while (ptr > buffer + sizeof(buffer) - 7) + { + *--ptr = ' '; + } + return(ptr); +} + +/* + * digits(val) - return number of decimal digits in val. Only works for + * positive numbers. If val <= 0 then digits(val) == 0. + */ + +int digits(val) + +int val; + +{ + register int cnt = 0; + + while (val > 0) + { + cnt++; + val /= 10; + } + return(cnt); +} + +/* + * strecpy(to, from) - copy string "from" into "to" and return a pointer + * to the END of the string "to". + */ + +char *strecpy(to, from) + +register char *to; +register char *from; + +{ + while ((*to++ = *from++) != '\0'); + return(--to); +} + +/* + * string_index(string, array) - find string in array and return index + */ + +int string_index(string, array) + +char *string; +char **array; + +{ + register int i = 0; + + while (*array != NULL) + { + if (strcmp(string, *array) == 0) + { + return(i); + } + array++; + i++; + } + return(-1); +} + +/* + * argparse(line, cntp) - parse arguments in string "line", separating them + * out into an argv-like array, and setting *cntp to the number of + * arguments encountered. This is a simple parser that doesn't understand + * squat about quotes. + */ + +char **argparse(line, cntp) + +char *line; +int *cntp; + +{ + register char *from; + register char *to; + register int cnt; + register int ch; + int length; + int lastch; + register char **argv; + char **argarray; + char *args; + + /* unfortunately, the only real way to do this is to go thru the + input string twice. */ + + /* step thru the string counting the white space sections */ + from = line; + lastch = cnt = length = 0; + while ((ch = *from++) != '\0') + { + length++; + if (ch == ' ' && lastch != ' ') + { + cnt++; + } + lastch = ch; + } + + /* add three to the count: one for the initial "dummy" argument, + one for the last argument and one for NULL */ + cnt += 3; + + /* allocate a char * array to hold the pointers */ + argarray = (char **)malloc(cnt * sizeof(char *)); + + /* allocate another array to hold the strings themselves */ + args = (char *)malloc(length+2); + + /* initialization for main loop */ + from = line; + to = args; + argv = argarray; + lastch = '\0'; + + /* create a dummy argument to keep getopt happy */ + *argv++ = to; + *to++ = '\0'; + cnt = 2; + + /* now build argv while copying characters */ + *argv++ = to; + while ((ch = *from++) != '\0') + { + if (ch != ' ') + { + if (lastch == ' ') + { + *to++ = '\0'; + *argv++ = to; + cnt++; + } + *to++ = ch; + } + lastch = ch; + } + *to++ = '\0'; + + /* set cntp and return the allocated array */ + *cntp = cnt; + return(argarray); +} + +/* + * percentages(cnt, out, new, old, diffs) - calculate percentage change + * between array "old" and "new", putting the percentages i "out". + * "cnt" is size of each array and "diffs" is used for scratch space. + * The array "old" is updated on each call. + * The routine assumes modulo arithmetic. This function is especially + * useful on BSD mchines for calculating cpu state percentages. + */ + +long percentages(cnt, out, new, old, diffs) + +int cnt; +int *out; +register long *new; +register long *old; +long *diffs; + +{ + register int i; + register long change; + register long total_change; + register long *dp; + long half_total; + + /* initialization */ + total_change = 0; + dp = diffs; + + /* calculate changes for each state and the overall change */ + for (i = 0; i < cnt; i++) + { + if ((change = *new - *old) < 0) + { + /* this only happens when the counter wraps */ + change = (int) + ((unsigned long)*new-(unsigned long)*old); + } + total_change += (*dp++ = change); + *old++ = *new++; + } + + /* avoid divide by zero potential */ + if (total_change == 0) + { + total_change = 1; + } + + /* calculate percentages based on overall change, rounding up */ + half_total = total_change / 2l; + + /* Do not divide by 0. Causes Floating point exception */ + if(total_change) { + for (i = 0; i < cnt; i++) + { + *out++ = (int)((*diffs++ * 1000 + half_total) / total_change); + } + } + + /* return the total in case the caller wants to use it */ + return(total_change); +} + +/* + * errmsg(errnum) - return an error message string appropriate to the + * error number "errnum". This is a substitute for the System V + * function "strerror". There appears to be no reliable way to + * determine if "strerror" exists at compile time, so I make do + * by providing something of similar functionality. For those + * systems that have strerror and NOT errlist, define + * -DHAVE_STRERROR in the module file and this function will + * use strerror. + */ + +/* externs referenced by errmsg */ + +#ifndef HAVE_STRERROR +#ifndef SYS_ERRLIST_DECLARED +#define SYS_ERRLIST_DECLARED +extern char *sys_errlist[]; +#endif + +extern int sys_nerr; +#endif + +char *errmsg(errnum) + +int errnum; + +{ +#ifdef HAVE_STRERROR + char *msg = strerror(errnum); + if (msg != NULL) + { + return msg; + } +#else + if (errnum > 0 && errnum < sys_nerr) + { + return((char *)sys_errlist[errnum]); + } +#endif + return("No error"); +} + +/* format_time(seconds) - format number of seconds into a suitable + * display that will fit within 6 characters. Note that this + * routine builds its string in a static area. If it needs + * to be called more than once without overwriting previous data, + * then we will need to adopt a technique similar to the + * one used for format_k. + */ + +/* Explanation: + We want to keep the output within 6 characters. For low values we use + the format mm:ss. For values that exceed 999:59, we switch to a format + that displays hours and fractions: hhh.tH. For values that exceed + 999.9, we use hhhh.t and drop the "H" designator. For values that + exceed 9999.9, we use "???". + */ + +char *format_time(seconds) + +long seconds; + +{ + register int value; + register int digit; + register char *ptr; + static char result[10]; + + /* sanity protection */ + if (seconds < 0 || seconds > (99999l * 360l)) + { + strcpy(result, " ???"); + } + else if (seconds >= (1000l * 60l)) + { + /* alternate (slow) method displaying hours and tenths */ + sprintf(result, "%5.1fH", (double)seconds / (double)(60l * 60l)); + + /* It is possible that the sprintf took more than 6 characters. + If so, then the "H" appears as result[6]. If not, then there + is a \0 in result[6]. Either way, it is safe to step on. + */ + result[6] = '\0'; + } + else + { + /* standard method produces MMM:SS */ + /* we avoid printf as must as possible to make this quick */ + sprintf(result, "%3ld:%02ld", + (long)(seconds / 60), (long)(seconds % 60)); + } + return(result); +} + +/* + * format_k(amt) - format a kilobyte memory value, returning a string + * suitable for display. Returns a pointer to a static + * area that changes each call. "amt" is converted to a + * string with a trailing "K". If "amt" is 10000 or greater, + * then it is formatted as megabytes (rounded) with a + * trailing "M". + */ + +/* + * Compromise time. We need to return a string, but we don't want the + * caller to have to worry about freeing a dynamically allocated string. + * Unfortunately, we can't just return a pointer to a static area as one + * of the common uses of this function is in a large call to sprintf where + * it might get invoked several times. Our compromise is to maintain an + * array of strings and cycle thru them with each invocation. We make the + * array large enough to handle the above mentioned case. The constant + * NUM_STRINGS defines the number of strings in this array: we can tolerate + * up to NUM_STRINGS calls before we start overwriting old information. + * Keeping NUM_STRINGS a power of two will allow an intelligent optimizer + * to convert the modulo operation into something quicker. What a hack! + */ + +#define NUM_STRINGS 8 + +char *format_k(amt) + +int amt; + +{ + static char retarray[NUM_STRINGS][16]; + static int index = 0; + register char *p; + register char *ret; + register char tag = 'K'; + + p = ret = retarray[index]; + index = (index + 1) % NUM_STRINGS; + + if (amt >= 10000) + { + amt = (amt + 512) / 1024; + tag = 'M'; + if (amt >= 10000) + { + amt = (amt + 512) / 1024; + tag = 'G'; + } + } + + p = strecpy(p, itoa(amt)); + *p++ = tag; + *p = '\0'; + + return(ret); +} + +char *format_k2(amt) + +unsigned long long amt; + +{ + static char retarray[NUM_STRINGS][16]; + static int index = 0; + register char *p; + register char *ret; + register char tag = 'K'; + + p = ret = retarray[index]; + index = (index + 1) % NUM_STRINGS; + + if (amt >= 100000) + { + amt = (amt + 512) / 1024; + tag = 'M'; + if (amt >= 100000) + { + amt = (amt + 512) / 1024; + tag = 'G'; + } + } + + p = strecpy(p, itoa((int)amt)); + *p++ = tag; + *p = '\0'; + + return(ret); +} Index: head/usr.bin/top/version.c =================================================================== --- head/usr.bin/top/version.c +++ head/usr.bin/top/version.c @@ -0,0 +1,28 @@ +/* + * Top users/processes display for Unix + * Version 3 + * + * This program may be freely redistributed, + * but this entire comment MUST remain intact. + * + * Copyright (c) 1984, 1989, William LeFebvre, Rice University + * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University + */ + +#include +#include + +#include "top.h" +#include "patchlevel.h" + +static char version[16]; + +char *version_string() + +{ + sprintf(version, "%d.%d", VERSION, PATCHLEVEL); +#ifdef BETA + strcat(version, BETA); +#endif + return(version); +}