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