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