top.c revision 81187
124139Sjoergchar *copyright = 224139Sjoerg "Copyright (c) 1984 through 1996, William LeFebvre"; 324139Sjoerg 424139Sjoerg/* 524139Sjoerg * Top users/processes display for Unix 624139Sjoerg * Version 3 724139Sjoerg * 824139Sjoerg * This program may be freely redistributed, 924139Sjoerg * but this entire comment MUST remain intact. 1024139Sjoerg * 1124139Sjoerg * Copyright (c) 1984, 1989, William LeFebvre, Rice University 1224139Sjoerg * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University 1366641Simp * 1466641Simp * $FreeBSD: head/contrib/top/top.c 81187 2001-08-06 03:19:22Z kris $ 1524139Sjoerg */ 1624139Sjoerg 1724139Sjoerg/* 1824139Sjoerg * See the file "Changes" for information on version-to-version changes. 1924139Sjoerg */ 2024139Sjoerg 2124139Sjoerg/* 2224139Sjoerg * This file contains "main" and other high-level routines. 2324139Sjoerg */ 2424139Sjoerg 2524139Sjoerg/* 2624139Sjoerg * The following preprocessor variables, when defined, are used to 2724139Sjoerg * distinguish between different Unix implementations: 2824139Sjoerg * 2924139Sjoerg * SIGHOLD - use SVR4 sighold function when defined 3024139Sjoerg * SIGRELSE - use SVR4 sigrelse function when defined 3124139Sjoerg * FD_SET - macros FD_SET and FD_ZERO are used when defined 3224139Sjoerg */ 3324139Sjoerg 3424139Sjoerg#include "os.h" 3524139Sjoerg#include <signal.h> 3624139Sjoerg#include <setjmp.h> 3724139Sjoerg#include <ctype.h> 3824139Sjoerg#include <sys/time.h> 3924139Sjoerg 4024139Sjoerg/* includes specific to top */ 4124139Sjoerg#include "display.h" /* interface to display package */ 4224139Sjoerg#include "screen.h" /* interface to screen package */ 4324139Sjoerg#include "top.h" 4424139Sjoerg#include "top.local.h" 4524139Sjoerg#include "boolean.h" 4624139Sjoerg#include "machine.h" 4724139Sjoerg#include "utils.h" 4824139Sjoerg 4924139Sjoerg/* Size of the stdio buffer given to stdout */ 5024139Sjoerg#define Buffersize 2048 5124139Sjoerg 5224139Sjoerg/* The buffer that stdio will use */ 5324139Sjoergchar stdoutbuf[Buffersize]; 5424139Sjoerg 5524139Sjoerg/* build Signal masks */ 5624139Sjoerg#define Smask(s) (1 << ((s) - 1)) 5724139Sjoerg 5824139Sjoerg/* for system errors */ 5924139Sjoergextern int errno; 6024139Sjoerg 6124139Sjoerg/* for getopt: */ 6224139Sjoergextern int optind; 6324139Sjoergextern char *optarg; 6424139Sjoerg 6524139Sjoerg/* imported from screen.c */ 6624139Sjoergextern int overstrike; 6724139Sjoerg 6824139Sjoerg/* signal handling routines */ 6924139Sjoergsigret_t leave(); 7024139Sjoergsigret_t onalrm(); 7124139Sjoergsigret_t tstop(); 7224139Sjoerg#ifdef SIGWINCH 7324139Sjoergsigret_t winch(); 7424139Sjoerg#endif 7524139Sjoerg 7681187Skrisvolatile sig_atomic_t leaveflag; 7781187Skrisvolatile sig_atomic_t tstopflag; 7881187Skrisvolatile sig_atomic_t winchflag; 7981187Skris 8024139Sjoerg/* internal routines */ 8124139Sjoergvoid quit(); 8224139Sjoerg 8324139Sjoerg/* values which need to be accessed by signal handlers */ 8424139Sjoergstatic int max_topn; /* maximum displayable processes */ 8524139Sjoerg 8624139Sjoerg/* miscellaneous things */ 8724139Sjoergchar *myname = "top"; 8824139Sjoergjmp_buf jmp_int; 8924139Sjoerg 9024139Sjoerg/* routines that don't return int */ 9124139Sjoerg 9224139Sjoergchar *username(); 9324139Sjoergchar *ctime(); 9424139Sjoergchar *kill_procs(); 9524139Sjoergchar *renice_procs(); 9624139Sjoerg 9724139Sjoerg#ifdef ORDER 9824139Sjoergextern int (*proc_compares[])(); 9924139Sjoerg#else 10024139Sjoergextern int proc_compare(); 10124139Sjoerg#endif 10224139Sjoergtime_t time(); 10324139Sjoerg 10424139Sjoergcaddr_t get_process_info(); 10524139Sjoerg 10624139Sjoerg/* different routines for displaying the user's identification */ 10724139Sjoerg/* (values assigned to get_userid) */ 10824139Sjoergchar *username(); 10924139Sjoergchar *itoa7(); 11024139Sjoerg 11124139Sjoerg/* display routines that need to be predeclared */ 11224139Sjoergint i_loadave(); 11324139Sjoergint u_loadave(); 11424139Sjoergint i_procstates(); 11524139Sjoergint u_procstates(); 11624139Sjoergint i_cpustates(); 11724139Sjoergint u_cpustates(); 11824139Sjoergint i_memory(); 11924139Sjoergint u_memory(); 12024142Sjoergint i_swap(); 12124142Sjoergint u_swap(); 12224139Sjoergint i_message(); 12324139Sjoergint u_message(); 12424139Sjoergint i_header(); 12524139Sjoergint u_header(); 12624139Sjoergint i_process(); 12724139Sjoergint u_process(); 12824139Sjoerg 12924139Sjoerg/* pointers to display routines */ 13024139Sjoergint (*d_loadave)() = i_loadave; 13124139Sjoergint (*d_procstates)() = i_procstates; 13224139Sjoergint (*d_cpustates)() = i_cpustates; 13324139Sjoergint (*d_memory)() = i_memory; 13424142Sjoergint (*d_swap)() = i_swap; 13524139Sjoergint (*d_message)() = i_message; 13624139Sjoergint (*d_header)() = i_header; 13724139Sjoergint (*d_process)() = i_process; 13824139Sjoerg 13924139Sjoerg 14024139Sjoergmain(argc, argv) 14124139Sjoerg 14224139Sjoergint argc; 14324139Sjoergchar *argv[]; 14424139Sjoerg 14524139Sjoerg{ 14624139Sjoerg register int i; 14724139Sjoerg register int active_procs; 14824139Sjoerg register int change; 14924139Sjoerg 15024139Sjoerg struct system_info system_info; 15124139Sjoerg struct statics statics; 15224139Sjoerg caddr_t processes; 15324139Sjoerg 15424139Sjoerg static char tempbuf1[50]; 15524139Sjoerg static char tempbuf2[50]; 15624139Sjoerg int old_sigmask; /* only used for BSD-style signals */ 15724139Sjoerg int topn = Default_TOPN; 15824139Sjoerg int delay = Default_DELAY; 15924139Sjoerg int displays = 0; /* indicates unspecified */ 16024139Sjoerg time_t curr_time; 16124139Sjoerg char *(*get_userid)() = username; 16224139Sjoerg char *uname_field = "USERNAME"; 16324139Sjoerg char *header_text; 16424139Sjoerg char *env_top; 16524139Sjoerg char **preset_argv; 16624139Sjoerg int preset_argc = 0; 16724139Sjoerg char **av; 16824139Sjoerg int ac; 16924139Sjoerg char dostates = No; 17024139Sjoerg char do_unames = Yes; 17124139Sjoerg char interactive = Maybe; 17224139Sjoerg char warnings = 0; 17324139Sjoerg#if Default_TOPN == Infinity 17424139Sjoerg char topn_specified = No; 17524139Sjoerg#endif 17624139Sjoerg char ch; 17724139Sjoerg char *iptr; 17824139Sjoerg char no_command = 1; 17924139Sjoerg struct timeval timeout; 18024139Sjoerg struct process_select ps; 18124139Sjoerg#ifdef ORDER 18224139Sjoerg char *order_name = NULL; 18324139Sjoerg int order_index = 0; 18424139Sjoerg#endif 18524139Sjoerg#ifndef FD_SET 18624139Sjoerg /* FD_SET and friends are not present: fake it */ 18724139Sjoerg typedef int fd_set; 18824139Sjoerg#define FD_ZERO(x) (*(x) = 0) 18924139Sjoerg#define FD_SET(f, x) (*(x) = f) 19024139Sjoerg#endif 19124139Sjoerg fd_set readfds; 19224139Sjoerg 19324139Sjoerg#ifdef ORDER 19438090Sdes static char command_chars[] = "\f qh?en#sdkriIuto"; 19524139Sjoerg#else 19638090Sdes static char command_chars[] = "\f qh?en#sdkriIut"; 19724139Sjoerg#endif 19824139Sjoerg/* these defines enumerate the "strchr"s of the commands in command_chars */ 19924139Sjoerg#define CMD_redraw 0 20024139Sjoerg#define CMD_update 1 20124139Sjoerg#define CMD_quit 2 20224139Sjoerg#define CMD_help1 3 20324139Sjoerg#define CMD_help2 4 20424139Sjoerg#define CMD_OSLIMIT 4 /* terminals with OS can only handle commands */ 20524139Sjoerg#define CMD_errors 5 /* less than or equal to CMD_OSLIMIT */ 20624139Sjoerg#define CMD_number1 6 20724139Sjoerg#define CMD_number2 7 20824139Sjoerg#define CMD_delay 8 20924139Sjoerg#define CMD_displays 9 21024139Sjoerg#define CMD_kill 10 21124139Sjoerg#define CMD_renice 11 21224139Sjoerg#define CMD_idletog 12 21324139Sjoerg#define CMD_idletog2 13 21424139Sjoerg#define CMD_user 14 21538090Sdes#define CMD_selftog 15 21624139Sjoerg#ifdef ORDER 21738090Sdes#define CMD_order 16 21824139Sjoerg#endif 21924139Sjoerg 22024139Sjoerg /* set the buffer for stdout */ 22124139Sjoerg#ifdef DEBUG 22224139Sjoerg setbuffer(stdout, NULL, 0); 22324139Sjoerg#else 22424139Sjoerg setbuffer(stdout, stdoutbuf, Buffersize); 22524139Sjoerg#endif 22624139Sjoerg 22724139Sjoerg /* get our name */ 22824139Sjoerg if (argc > 0) 22924139Sjoerg { 23024139Sjoerg if ((myname = strrchr(argv[0], '/')) == 0) 23124139Sjoerg { 23224139Sjoerg myname = argv[0]; 23324139Sjoerg } 23424139Sjoerg else 23524139Sjoerg { 23624139Sjoerg myname++; 23724139Sjoerg } 23824139Sjoerg } 23924139Sjoerg 24024139Sjoerg /* initialize some selection options */ 24124139Sjoerg ps.idle = Yes; 24238090Sdes ps.self = -1; 24324139Sjoerg ps.system = No; 24424139Sjoerg ps.uid = -1; 24524139Sjoerg ps.command = NULL; 24624139Sjoerg 24724139Sjoerg /* get preset options from the environment */ 24824139Sjoerg if ((env_top = getenv("TOP")) != NULL) 24924139Sjoerg { 25024139Sjoerg av = preset_argv = argparse(env_top, &preset_argc); 25124139Sjoerg ac = preset_argc; 25224139Sjoerg 25324139Sjoerg /* set the dummy argument to an explanatory message, in case 25424139Sjoerg getopt encounters a bad argument */ 25524139Sjoerg preset_argv[0] = "while processing environment"; 25624139Sjoerg } 25724139Sjoerg 25824139Sjoerg /* process options */ 25924139Sjoerg do { 26024139Sjoerg /* if we're done doing the presets, then process the real arguments */ 26124139Sjoerg if (preset_argc == 0) 26224139Sjoerg { 26324139Sjoerg ac = argc; 26424139Sjoerg av = argv; 26524139Sjoerg 26624139Sjoerg /* this should keep getopt happy... */ 26724139Sjoerg optind = 1; 26824139Sjoerg } 26924139Sjoerg 27038090Sdes while ((i = getopt(ac, av, "SIbinqus:d:U:o:t")) != EOF) 27124139Sjoerg { 27224139Sjoerg switch(i) 27324139Sjoerg { 27424139Sjoerg case 'u': /* toggle uid/username display */ 27524139Sjoerg do_unames = !do_unames; 27624139Sjoerg break; 27724139Sjoerg 27824139Sjoerg case 'U': /* display only username's processes */ 27924139Sjoerg if ((ps.uid = userid(optarg)) == -1) 28024139Sjoerg { 28124139Sjoerg fprintf(stderr, "%s: unknown user\n", optarg); 28224139Sjoerg exit(1); 28324139Sjoerg } 28424139Sjoerg break; 28524139Sjoerg 28624139Sjoerg case 'S': /* show system processes */ 28724139Sjoerg ps.system = !ps.system; 28824139Sjoerg break; 28924139Sjoerg 29024139Sjoerg case 'I': /* show idle processes */ 29124139Sjoerg ps.idle = !ps.idle; 29224139Sjoerg break; 29324139Sjoerg 29424139Sjoerg case 'i': /* go interactive regardless */ 29524139Sjoerg interactive = Yes; 29624139Sjoerg break; 29724139Sjoerg 29824139Sjoerg case 'n': /* batch, or non-interactive */ 29924139Sjoerg case 'b': 30024139Sjoerg interactive = No; 30124139Sjoerg break; 30224139Sjoerg 30324139Sjoerg case 'd': /* number of displays to show */ 30424139Sjoerg if ((i = atoiwi(optarg)) == Invalid || i == 0) 30524139Sjoerg { 30624139Sjoerg fprintf(stderr, 30724139Sjoerg "%s: warning: display count should be positive -- option ignored\n", 30824139Sjoerg myname); 30924139Sjoerg warnings++; 31024139Sjoerg } 31124139Sjoerg else 31224139Sjoerg { 31324139Sjoerg displays = i; 31424139Sjoerg } 31524139Sjoerg break; 31624139Sjoerg 31724139Sjoerg case 's': 31824139Sjoerg if ((delay = atoi(optarg)) < 0) 31924139Sjoerg { 32024139Sjoerg fprintf(stderr, 32124139Sjoerg "%s: warning: seconds delay should be non-negative -- using default\n", 32224139Sjoerg myname); 32324139Sjoerg delay = Default_DELAY; 32424139Sjoerg warnings++; 32524139Sjoerg } 32624139Sjoerg break; 32724139Sjoerg 32824139Sjoerg case 'q': /* be quick about it */ 32924139Sjoerg /* only allow this if user is really root */ 33024139Sjoerg if (getuid() == 0) 33124139Sjoerg { 33224139Sjoerg /* be very un-nice! */ 33324139Sjoerg (void) nice(-20); 33424139Sjoerg } 33524139Sjoerg else 33624139Sjoerg { 33724139Sjoerg fprintf(stderr, 33824139Sjoerg "%s: warning: `-q' option can only be used by root\n", 33924139Sjoerg myname); 34024139Sjoerg warnings++; 34124139Sjoerg } 34224139Sjoerg break; 34324139Sjoerg 34424139Sjoerg case 'o': /* select sort order */ 34524139Sjoerg#ifdef ORDER 34624139Sjoerg order_name = optarg; 34724139Sjoerg#else 34824139Sjoerg fprintf(stderr, 34924139Sjoerg "%s: this platform does not support arbitrary ordering. Sorry.\n", 35024139Sjoerg myname); 35124139Sjoerg warnings++; 35224139Sjoerg#endif 35324139Sjoerg break; 35424139Sjoerg 35538090Sdes case 't': 35638090Sdes ps.self = (ps.self == -1) ? getpid() : -1; 35738090Sdes break; 35838090Sdes 35924139Sjoerg default: 36024139Sjoerg fprintf(stderr, "\ 36124139SjoergTop version %s\n\ 36238090SdesUsage: %s [-ISbinqut] [-d x] [-s x] [-o field] [-U username] [number]\n", 36324139Sjoerg version_string(), myname); 36424139Sjoerg exit(1); 36524139Sjoerg } 36624139Sjoerg } 36724139Sjoerg 36824139Sjoerg /* get count of top processes to display (if any) */ 36924139Sjoerg if (optind < ac) 37024139Sjoerg { 37124139Sjoerg if ((topn = atoiwi(av[optind])) == Invalid) 37224139Sjoerg { 37324139Sjoerg fprintf(stderr, 37424139Sjoerg "%s: warning: process display count should be non-negative -- using default\n", 37524139Sjoerg myname); 37624139Sjoerg warnings++; 37724139Sjoerg } 37824139Sjoerg#if Default_TOPN == Infinity 37924139Sjoerg else 38024139Sjoerg { 38124139Sjoerg topn_specified = Yes; 38224139Sjoerg } 38324139Sjoerg#endif 38424139Sjoerg } 38524139Sjoerg 38624139Sjoerg /* tricky: remember old value of preset_argc & set preset_argc = 0 */ 38724139Sjoerg i = preset_argc; 38824139Sjoerg preset_argc = 0; 38924139Sjoerg 39024139Sjoerg /* repeat only if we really did the preset arguments */ 39124139Sjoerg } while (i != 0); 39224139Sjoerg 39324139Sjoerg /* set constants for username/uid display correctly */ 39424139Sjoerg if (!do_unames) 39524139Sjoerg { 39624139Sjoerg uname_field = " UID "; 39724139Sjoerg get_userid = itoa7; 39824139Sjoerg } 39924139Sjoerg 40024139Sjoerg /* initialize the kernel memory interface */ 40124139Sjoerg if (machine_init(&statics) == -1) 40224139Sjoerg { 40324139Sjoerg exit(1); 40424139Sjoerg } 40524139Sjoerg 40624139Sjoerg#ifdef ORDER 40724139Sjoerg /* determine sorting order index, if necessary */ 40824139Sjoerg if (order_name != NULL) 40924139Sjoerg { 41024139Sjoerg if ((order_index = string_index(order_name, statics.order_names)) == -1) 41124139Sjoerg { 41224139Sjoerg char **pp; 41324139Sjoerg 41424139Sjoerg fprintf(stderr, "%s: '%s' is not a recognized sorting order.\n", 41524139Sjoerg myname, order_name); 41624139Sjoerg fprintf(stderr, "\tTry one of these:"); 41724139Sjoerg pp = statics.order_names; 41824139Sjoerg while (*pp != NULL) 41924139Sjoerg { 42024139Sjoerg fprintf(stderr, " %s", *pp++); 42124139Sjoerg } 42224139Sjoerg fputc('\n', stderr); 42324139Sjoerg exit(1); 42424139Sjoerg } 42524139Sjoerg } 42624139Sjoerg#endif 42724139Sjoerg 42824139Sjoerg#ifdef no_initialization_needed 42924139Sjoerg /* initialize the hashing stuff */ 43024139Sjoerg if (do_unames) 43124139Sjoerg { 43224139Sjoerg init_hash(); 43324139Sjoerg } 43424139Sjoerg#endif 43524139Sjoerg 43624139Sjoerg /* initialize termcap */ 43724139Sjoerg init_termcap(interactive); 43824139Sjoerg 43924139Sjoerg /* get the string to use for the process area header */ 44024139Sjoerg header_text = format_header(uname_field); 44124139Sjoerg 44224139Sjoerg /* initialize display interface */ 44324139Sjoerg if ((max_topn = display_init(&statics)) == -1) 44424139Sjoerg { 44524139Sjoerg fprintf(stderr, "%s: can't allocate sufficient memory\n", myname); 44624139Sjoerg exit(4); 44724139Sjoerg } 44824139Sjoerg 44924139Sjoerg /* print warning if user requested more processes than we can display */ 45024139Sjoerg if (topn > max_topn) 45124139Sjoerg { 45224139Sjoerg fprintf(stderr, 45324139Sjoerg "%s: warning: this terminal can only display %d processes.\n", 45424139Sjoerg myname, max_topn); 45524139Sjoerg warnings++; 45624139Sjoerg } 45724139Sjoerg 45824139Sjoerg /* adjust for topn == Infinity */ 45924139Sjoerg if (topn == Infinity) 46024139Sjoerg { 46124139Sjoerg /* 46224139Sjoerg * For smart terminals, infinity really means everything that can 46324139Sjoerg * be displayed, or Largest. 46424139Sjoerg * On dumb terminals, infinity means every process in the system! 46524139Sjoerg * We only really want to do that if it was explicitly specified. 46624139Sjoerg * This is always the case when "Default_TOPN != Infinity". But if 46724139Sjoerg * topn wasn't explicitly specified and we are on a dumb terminal 46824139Sjoerg * and the default is Infinity, then (and only then) we use 46924139Sjoerg * "Nominal_TOPN" instead. 47024139Sjoerg */ 47124139Sjoerg#if Default_TOPN == Infinity 47224139Sjoerg topn = smart_terminal ? Largest : 47324139Sjoerg (topn_specified ? Largest : Nominal_TOPN); 47424139Sjoerg#else 47524139Sjoerg topn = Largest; 47624139Sjoerg#endif 47724139Sjoerg } 47824139Sjoerg 47924139Sjoerg /* set header display accordingly */ 48024139Sjoerg display_header(topn > 0); 48124139Sjoerg 48224139Sjoerg /* determine interactive state */ 48324139Sjoerg if (interactive == Maybe) 48424139Sjoerg { 48524139Sjoerg interactive = smart_terminal; 48624139Sjoerg } 48724139Sjoerg 48824139Sjoerg /* if # of displays not specified, fill it in */ 48924139Sjoerg if (displays == 0) 49024139Sjoerg { 49124139Sjoerg displays = smart_terminal ? Infinity : 1; 49224139Sjoerg } 49324139Sjoerg 49424139Sjoerg /* hold interrupt signals while setting up the screen and the handlers */ 49524139Sjoerg#ifdef SIGHOLD 49624139Sjoerg sighold(SIGINT); 49724139Sjoerg sighold(SIGQUIT); 49824139Sjoerg sighold(SIGTSTP); 49924139Sjoerg#else 50024139Sjoerg old_sigmask = sigblock(Smask(SIGINT) | Smask(SIGQUIT) | Smask(SIGTSTP)); 50124139Sjoerg#endif 50224139Sjoerg init_screen(); 50324139Sjoerg (void) signal(SIGINT, leave); 50424139Sjoerg (void) signal(SIGQUIT, leave); 50524139Sjoerg (void) signal(SIGTSTP, tstop); 50624139Sjoerg#ifdef SIGWINCH 50724139Sjoerg (void) signal(SIGWINCH, winch); 50824139Sjoerg#endif 50924139Sjoerg#ifdef SIGRELSE 51024139Sjoerg sigrelse(SIGINT); 51124139Sjoerg sigrelse(SIGQUIT); 51224139Sjoerg sigrelse(SIGTSTP); 51324139Sjoerg#else 51424139Sjoerg (void) sigsetmask(old_sigmask); 51524139Sjoerg#endif 51624139Sjoerg if (warnings) 51724139Sjoerg { 51824139Sjoerg fputs("....", stderr); 51924139Sjoerg fflush(stderr); /* why must I do this? */ 52024139Sjoerg sleep((unsigned)(3 * warnings)); 52124139Sjoerg fputc('\n', stderr); 52224139Sjoerg } 52324139Sjoerg 52481187Skrisrestart: 52524139Sjoerg 52624139Sjoerg /* 52724139Sjoerg * main loop -- repeat while display count is positive or while it 52824139Sjoerg * indicates infinity (by being -1) 52924139Sjoerg */ 53024139Sjoerg 53124139Sjoerg while ((displays == -1) || (displays-- > 0)) 53224139Sjoerg { 53324139Sjoerg /* get the current stats */ 53424139Sjoerg get_system_info(&system_info); 53524139Sjoerg 53624139Sjoerg /* get the current set of processes */ 53724139Sjoerg processes = 53824139Sjoerg get_process_info(&system_info, 53924139Sjoerg &ps, 54024139Sjoerg#ifdef ORDER 54124139Sjoerg proc_compares[order_index]); 54224139Sjoerg#else 54324139Sjoerg proc_compare); 54424139Sjoerg#endif 54524139Sjoerg 54624139Sjoerg /* display the load averages */ 54724139Sjoerg (*d_loadave)(system_info.last_pid, 54824139Sjoerg system_info.load_avg); 54924139Sjoerg 55024139Sjoerg /* display the current time */ 55124139Sjoerg /* this method of getting the time SHOULD be fairly portable */ 55224139Sjoerg time(&curr_time); 55342447Sobrien i_uptime(&system_info.boottime, &curr_time); 55424139Sjoerg i_timeofday(&curr_time); 55524139Sjoerg 55624139Sjoerg /* display process state breakdown */ 55724139Sjoerg (*d_procstates)(system_info.p_total, 55824139Sjoerg system_info.procstates); 55924139Sjoerg 56024139Sjoerg /* display the cpu state percentage breakdown */ 56124139Sjoerg if (dostates) /* but not the first time */ 56224139Sjoerg { 56324139Sjoerg (*d_cpustates)(system_info.cpustates); 56424139Sjoerg } 56524139Sjoerg else 56624139Sjoerg { 56724139Sjoerg /* we'll do it next time */ 56824139Sjoerg if (smart_terminal) 56924139Sjoerg { 57024139Sjoerg z_cpustates(); 57124139Sjoerg } 57224139Sjoerg else 57324139Sjoerg { 57424139Sjoerg putchar('\n'); 57524139Sjoerg } 57624139Sjoerg dostates = Yes; 57724139Sjoerg } 57824139Sjoerg 57924139Sjoerg /* display memory stats */ 58024139Sjoerg (*d_memory)(system_info.memory); 58124139Sjoerg 58224142Sjoerg /* display swap stats */ 58324142Sjoerg (*d_swap)(system_info.swap); 58424142Sjoerg 58524139Sjoerg /* handle message area */ 58624139Sjoerg (*d_message)(); 58724139Sjoerg 58824139Sjoerg /* update the header area */ 58924139Sjoerg (*d_header)(header_text); 59024139Sjoerg 59124139Sjoerg if (topn > 0) 59224139Sjoerg { 59324139Sjoerg /* determine number of processes to actually display */ 59424139Sjoerg /* this number will be the smallest of: active processes, 59524139Sjoerg number user requested, number current screen accomodates */ 59624139Sjoerg active_procs = system_info.p_active; 59724139Sjoerg if (active_procs > topn) 59824139Sjoerg { 59924139Sjoerg active_procs = topn; 60024139Sjoerg } 60124139Sjoerg if (active_procs > max_topn) 60224139Sjoerg { 60324139Sjoerg active_procs = max_topn; 60424139Sjoerg } 60524139Sjoerg 60624139Sjoerg /* now show the top "n" processes. */ 60724139Sjoerg for (i = 0; i < active_procs; i++) 60824139Sjoerg { 60924139Sjoerg (*d_process)(i, format_next_process(processes, get_userid)); 61024139Sjoerg } 61124139Sjoerg } 61224139Sjoerg else 61324139Sjoerg { 61424139Sjoerg i = 0; 61524139Sjoerg } 61624139Sjoerg 61724139Sjoerg /* do end-screen processing */ 61824139Sjoerg u_endscreen(i); 61924139Sjoerg 62024139Sjoerg /* now, flush the output buffer */ 62124139Sjoerg fflush(stdout); 62224139Sjoerg 62324139Sjoerg /* only do the rest if we have more displays to show */ 62424139Sjoerg if (displays) 62524139Sjoerg { 62624139Sjoerg /* switch out for new display on smart terminals */ 62724139Sjoerg if (smart_terminal) 62824139Sjoerg { 62924139Sjoerg if (overstrike) 63024139Sjoerg { 63124139Sjoerg reset_display(); 63224139Sjoerg } 63324139Sjoerg else 63424139Sjoerg { 63524139Sjoerg d_loadave = u_loadave; 63624139Sjoerg d_procstates = u_procstates; 63724139Sjoerg d_cpustates = u_cpustates; 63824139Sjoerg d_memory = u_memory; 63924142Sjoerg d_swap = u_swap; 64024139Sjoerg d_message = u_message; 64124139Sjoerg d_header = u_header; 64224139Sjoerg d_process = u_process; 64324139Sjoerg } 64424139Sjoerg } 64524139Sjoerg 64624139Sjoerg no_command = Yes; 64724139Sjoerg if (!interactive) 64824139Sjoerg { 64924139Sjoerg /* set up alarm */ 65024139Sjoerg (void) signal(SIGALRM, onalrm); 65124139Sjoerg (void) alarm((unsigned)delay); 65224139Sjoerg 65324139Sjoerg /* wait for the rest of it .... */ 65424139Sjoerg pause(); 65524139Sjoerg } 65624139Sjoerg else while (no_command) 65724139Sjoerg { 65824139Sjoerg /* assume valid command unless told otherwise */ 65924139Sjoerg no_command = No; 66024139Sjoerg 66124139Sjoerg /* set up arguments for select with timeout */ 66224139Sjoerg FD_ZERO(&readfds); 66324139Sjoerg FD_SET(1, &readfds); /* for standard input */ 66424139Sjoerg timeout.tv_sec = delay; 66524139Sjoerg timeout.tv_usec = 0; 66624139Sjoerg 66781187Skris if (leaveflag) { 66881187Skris end_screen(); 66981187Skris exit(0); 67081187Skris } 67181187Skris 67281187Skris if (tstopflag) { 67381187Skris /* move to the lower left */ 67481187Skris end_screen(); 67581187Skris fflush(stdout); 67681187Skris 67781187Skris /* default the signal handler action */ 67881187Skris (void) signal(SIGTSTP, SIG_DFL); 67981187Skris 68081187Skris /* unblock the signal and send ourselves one */ 68181187Skris#ifdef SIGRELSE 68281187Skris sigrelse(SIGTSTP); 68381187Skris#else 68481187Skris (void) sigsetmask(sigblock(0) & ~(1 << (SIGTSTP - 1))); 68581187Skris#endif 68681187Skris (void) kill(0, SIGTSTP); 68781187Skris 68881187Skris /* reset the signal handler */ 68981187Skris (void) signal(SIGTSTP, tstop); 69081187Skris 69181187Skris /* reinit screen */ 69281187Skris reinit_screen(); 69381187Skris reset_display(); 69481187Skris tstopflag = 0; 69581187Skris goto restart; 69681187Skris } 69781187Skris 69881187Skris if (winchflag) { 69981187Skris /* reascertain the screen dimensions */ 70081187Skris get_screensize(); 70181187Skris 70281187Skris /* tell display to resize */ 70381187Skris max_topn = display_resize(); 70481187Skris 70581187Skris /* reset the signal handler */ 70681187Skris (void) signal(SIGWINCH, winch); 70781187Skris 70881187Skris reset_display(); 70981187Skris winchflag = 0; 71081187Skris goto restart; 71181187Skris } 71281187Skris 71324139Sjoerg /* wait for either input or the end of the delay period */ 71424139Sjoerg if (select(32, &readfds, (fd_set *)NULL, (fd_set *)NULL, &timeout) > 0) 71524139Sjoerg { 71624139Sjoerg int newval; 71724139Sjoerg char *errmsg; 71824139Sjoerg 71924139Sjoerg /* something to read -- clear the message area first */ 72024139Sjoerg clear_message(); 72124139Sjoerg 72224139Sjoerg /* now read it and convert to command strchr */ 72324139Sjoerg /* (use "change" as a temporary to hold strchr) */ 72424139Sjoerg (void) read(0, &ch, 1); 72524139Sjoerg if ((iptr = strchr(command_chars, ch)) == NULL) 72624139Sjoerg { 72724142Sjoerg if (ch != '\r' && ch != '\n') 72824142Sjoerg { 72924142Sjoerg /* illegal command */ 73024142Sjoerg new_message(MT_standout, " Command not understood"); 73124142Sjoerg } 73224139Sjoerg putchar('\r'); 73324139Sjoerg no_command = Yes; 73424139Sjoerg } 73524139Sjoerg else 73624139Sjoerg { 73724139Sjoerg change = iptr - command_chars; 73824139Sjoerg if (overstrike && change > CMD_OSLIMIT) 73924139Sjoerg { 74024139Sjoerg /* error */ 74124139Sjoerg new_message(MT_standout, 74224139Sjoerg " Command cannot be handled by this terminal"); 74324139Sjoerg putchar('\r'); 74424139Sjoerg no_command = Yes; 74524139Sjoerg } 74624139Sjoerg else switch(change) 74724139Sjoerg { 74824139Sjoerg case CMD_redraw: /* redraw screen */ 74924139Sjoerg reset_display(); 75024139Sjoerg break; 75124139Sjoerg 75224139Sjoerg case CMD_update: /* merely update display */ 75324139Sjoerg /* is the load average high? */ 75424139Sjoerg if (system_info.load_avg[0] > LoadMax) 75524139Sjoerg { 75624139Sjoerg /* yes, go home for visual feedback */ 75724139Sjoerg go_home(); 75824139Sjoerg fflush(stdout); 75924139Sjoerg } 76024139Sjoerg break; 76124139Sjoerg 76224139Sjoerg case CMD_quit: /* quit */ 76324139Sjoerg quit(0); 76424139Sjoerg /*NOTREACHED*/ 76524139Sjoerg break; 76624139Sjoerg 76724139Sjoerg case CMD_help1: /* help */ 76824139Sjoerg case CMD_help2: 76924139Sjoerg reset_display(); 77024139Sjoerg clear(); 77124139Sjoerg show_help(); 77224139Sjoerg standout("Hit any key to continue: "); 77324139Sjoerg fflush(stdout); 77424139Sjoerg (void) read(0, &ch, 1); 77524139Sjoerg break; 77624139Sjoerg 77724139Sjoerg case CMD_errors: /* show errors */ 77824139Sjoerg if (error_count() == 0) 77924139Sjoerg { 78024139Sjoerg new_message(MT_standout, 78124139Sjoerg " Currently no errors to report."); 78224139Sjoerg putchar('\r'); 78324139Sjoerg no_command = Yes; 78424139Sjoerg } 78524139Sjoerg else 78624139Sjoerg { 78724139Sjoerg reset_display(); 78824139Sjoerg clear(); 78924139Sjoerg show_errors(); 79024139Sjoerg standout("Hit any key to continue: "); 79124139Sjoerg fflush(stdout); 79224139Sjoerg (void) read(0, &ch, 1); 79324139Sjoerg } 79424139Sjoerg break; 79524139Sjoerg 79624139Sjoerg case CMD_number1: /* new number */ 79724139Sjoerg case CMD_number2: 79824139Sjoerg new_message(MT_standout, 79924139Sjoerg "Number of processes to show: "); 80024139Sjoerg newval = readline(tempbuf1, 8, Yes); 80124139Sjoerg if (newval > -1) 80224139Sjoerg { 80324139Sjoerg if (newval > max_topn) 80424139Sjoerg { 80524139Sjoerg new_message(MT_standout | MT_delayed, 80624139Sjoerg " This terminal can only display %d processes.", 80724139Sjoerg max_topn); 80824139Sjoerg putchar('\r'); 80924139Sjoerg } 81024139Sjoerg 81124139Sjoerg if (newval == 0) 81224139Sjoerg { 81324139Sjoerg /* inhibit the header */ 81424139Sjoerg display_header(No); 81524139Sjoerg } 81624139Sjoerg else if (newval > topn && topn == 0) 81724139Sjoerg { 81824139Sjoerg /* redraw the header */ 81924139Sjoerg display_header(Yes); 82024139Sjoerg d_header = i_header; 82124139Sjoerg } 82224139Sjoerg topn = newval; 82324139Sjoerg } 82424139Sjoerg break; 82524139Sjoerg 82624139Sjoerg case CMD_delay: /* new seconds delay */ 82724139Sjoerg new_message(MT_standout, "Seconds to delay: "); 82824139Sjoerg if ((i = readline(tempbuf1, 8, Yes)) > -1) 82924139Sjoerg { 83024139Sjoerg delay = i; 83124139Sjoerg } 83224139Sjoerg clear_message(); 83324139Sjoerg break; 83424139Sjoerg 83524139Sjoerg case CMD_displays: /* change display count */ 83624139Sjoerg new_message(MT_standout, 83724139Sjoerg "Displays to show (currently %s): ", 83824139Sjoerg displays == -1 ? "infinite" : 83924139Sjoerg itoa(displays)); 84024139Sjoerg if ((i = readline(tempbuf1, 10, Yes)) > 0) 84124139Sjoerg { 84224139Sjoerg displays = i; 84324139Sjoerg } 84424139Sjoerg else if (i == 0) 84524139Sjoerg { 84624139Sjoerg quit(0); 84724139Sjoerg } 84824139Sjoerg clear_message(); 84924139Sjoerg break; 85024139Sjoerg 85124139Sjoerg case CMD_kill: /* kill program */ 85224139Sjoerg new_message(0, "kill "); 85324139Sjoerg if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) 85424139Sjoerg { 85524139Sjoerg if ((errmsg = kill_procs(tempbuf2)) != NULL) 85624139Sjoerg { 85766641Simp new_message(MT_standout, "%s", errmsg); 85824139Sjoerg putchar('\r'); 85924139Sjoerg no_command = Yes; 86024139Sjoerg } 86124139Sjoerg } 86224139Sjoerg else 86324139Sjoerg { 86424139Sjoerg clear_message(); 86524139Sjoerg } 86624139Sjoerg break; 86724139Sjoerg 86824139Sjoerg case CMD_renice: /* renice program */ 86924139Sjoerg new_message(0, "renice "); 87024139Sjoerg if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) 87124139Sjoerg { 87224139Sjoerg if ((errmsg = renice_procs(tempbuf2)) != NULL) 87324139Sjoerg { 87468293Simp new_message(MT_standout, "%s", errmsg); 87524139Sjoerg putchar('\r'); 87624139Sjoerg no_command = Yes; 87724139Sjoerg } 87824139Sjoerg } 87924139Sjoerg else 88024139Sjoerg { 88124139Sjoerg clear_message(); 88224139Sjoerg } 88324139Sjoerg break; 88424139Sjoerg 88524139Sjoerg case CMD_idletog: 88624139Sjoerg case CMD_idletog2: 88724139Sjoerg ps.idle = !ps.idle; 88824139Sjoerg new_message(MT_standout | MT_delayed, 88924139Sjoerg " %sisplaying idle processes.", 89024139Sjoerg ps.idle ? "D" : "Not d"); 89124139Sjoerg putchar('\r'); 89224139Sjoerg break; 89324139Sjoerg 89438090Sdes case CMD_selftog: 89538090Sdes ps.self = (ps.self == -1) ? getpid() : -1; 89638090Sdes new_message(MT_standout | MT_delayed, 89738090Sdes " %sisplaying self.", 89838090Sdes (ps.self == -1) ? "D" : "Not d"); 89938090Sdes putchar('\r'); 90038090Sdes break; 90138090Sdes 90224139Sjoerg case CMD_user: 90324139Sjoerg new_message(MT_standout, 90424139Sjoerg "Username to show: "); 90524139Sjoerg if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) 90624139Sjoerg { 90724139Sjoerg if (tempbuf2[0] == '+' && 90824139Sjoerg tempbuf2[1] == '\0') 90924139Sjoerg { 91024139Sjoerg ps.uid = -1; 91124139Sjoerg } 91224139Sjoerg else if ((i = userid(tempbuf2)) == -1) 91324139Sjoerg { 91424139Sjoerg new_message(MT_standout, 91524139Sjoerg " %s: unknown user", tempbuf2); 91624139Sjoerg no_command = Yes; 91724139Sjoerg } 91824139Sjoerg else 91924139Sjoerg { 92024139Sjoerg ps.uid = i; 92124139Sjoerg } 92224139Sjoerg putchar('\r'); 92324139Sjoerg } 92424139Sjoerg else 92524139Sjoerg { 92624139Sjoerg clear_message(); 92724139Sjoerg } 92824139Sjoerg break; 92924139Sjoerg 93024139Sjoerg#ifdef ORDER 93124139Sjoerg case CMD_order: 93224139Sjoerg new_message(MT_standout, 93324139Sjoerg "Order to sort: "); 93424139Sjoerg if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) 93524139Sjoerg { 93624139Sjoerg if ((i = string_index(tempbuf2, statics.order_names)) == -1) 93724139Sjoerg { 93824139Sjoerg new_message(MT_standout, 93924139Sjoerg " %s: unrecognized sorting order", tempbuf2); 94024139Sjoerg no_command = Yes; 94124139Sjoerg } 94224139Sjoerg else 94324139Sjoerg { 94424139Sjoerg order_index = i; 94524139Sjoerg } 94624139Sjoerg putchar('\r'); 94724139Sjoerg } 94824139Sjoerg else 94924139Sjoerg { 95024139Sjoerg clear_message(); 95124139Sjoerg } 95224139Sjoerg break; 95324139Sjoerg#endif 95424139Sjoerg 95524139Sjoerg default: 95624139Sjoerg new_message(MT_standout, " BAD CASE IN SWITCH!"); 95724139Sjoerg putchar('\r'); 95824139Sjoerg } 95924139Sjoerg } 96024139Sjoerg 96124139Sjoerg /* flush out stuff that may have been written */ 96224139Sjoerg fflush(stdout); 96324139Sjoerg } 96424139Sjoerg } 96524139Sjoerg } 96624139Sjoerg } 96724139Sjoerg 96824139Sjoerg quit(0); 96924139Sjoerg /*NOTREACHED*/ 97024139Sjoerg} 97124139Sjoerg 97224139Sjoerg/* 97324139Sjoerg * reset_display() - reset all the display routine pointers so that entire 97424139Sjoerg * screen will get redrawn. 97524139Sjoerg */ 97624139Sjoerg 97724139Sjoergreset_display() 97824139Sjoerg 97924139Sjoerg{ 98024139Sjoerg d_loadave = i_loadave; 98124139Sjoerg d_procstates = i_procstates; 98224139Sjoerg d_cpustates = i_cpustates; 98324139Sjoerg d_memory = i_memory; 98424142Sjoerg d_swap = i_swap; 98524139Sjoerg d_message = i_message; 98624139Sjoerg d_header = i_header; 98724139Sjoerg d_process = i_process; 98824139Sjoerg} 98924139Sjoerg 99024139Sjoerg/* 99124139Sjoerg * signal handlers 99224139Sjoerg */ 99324139Sjoerg 99424139Sjoergsigret_t leave() /* exit under normal conditions -- INT handler */ 99524139Sjoerg 99624139Sjoerg{ 99781187Skris leaveflag = 1; 99824139Sjoerg} 99924139Sjoerg 100024139Sjoergsigret_t tstop(i) /* SIGTSTP handler */ 100124139Sjoerg 100224139Sjoergint i; 100324139Sjoerg 100424139Sjoerg{ 100581187Skris tstopflag = 1; 100624139Sjoerg} 100724139Sjoerg 100824139Sjoerg#ifdef SIGWINCH 100924139Sjoergsigret_t winch(i) /* SIGWINCH handler */ 101024139Sjoerg 101124139Sjoergint i; 101224139Sjoerg 101324139Sjoerg{ 101481187Skris winchflag = 1; 101524139Sjoerg} 101624139Sjoerg#endif 101724139Sjoerg 101824139Sjoergvoid quit(status) /* exit under duress */ 101924139Sjoerg 102024139Sjoergint status; 102124139Sjoerg 102224139Sjoerg{ 102324139Sjoerg end_screen(); 102424139Sjoerg exit(status); 102524139Sjoerg /*NOTREACHED*/ 102624139Sjoerg} 102724139Sjoerg 102824139Sjoergsigret_t onalrm() /* SIGALRM handler */ 102924139Sjoerg 103024139Sjoerg{ 103124139Sjoerg /* this is only used in batch mode to break out of the pause() */ 103224139Sjoerg /* return; */ 103324139Sjoerg} 103424139Sjoerg 1035