top.c revision 223937
119304Speterchar *copyright = 219304Speter "Copyright (c) 1984 through 1996, William LeFebvre"; 319304Speter 419304Speter/* 519304Speter * Top users/processes display for Unix 619304Speter * Version 3 719304Speter * 819304Speter * This program may be freely redistributed, 919304Speter * but this entire comment MUST remain intact. 1019304Speter * 1119304Speter * Copyright (c) 1984, 1989, William LeFebvre, Rice University 1219304Speter * Copyright (c) 1989 - 1994, William LeFebvre, Northwestern University 13254225Speter * Copyright (c) 1994, 1995, William LeFebvre, Argonne National Laboratory 1419304Speter * Copyright (c) 1996, William LeFebvre, Group sys Consulting 1519304Speter * 1619304Speter * $FreeBSD: head/contrib/top/top.c 223937 2011-07-11 16:51:29Z jhb $ 1719304Speter */ 1819304Speter 1919304Speter/* 2019304Speter * See the file "Changes" for information on version-to-version changes. 2119304Speter */ 2219304Speter 2319304Speter/* 2419304Speter * This file contains "main" and other high-level routines. 2519304Speter */ 2619304Speter 2719304Speter/* 2819304Speter * The following preprocessor variables, when defined, are used to 2919304Speter * distinguish between different Unix implementations: 3019304Speter * 3119304Speter * SIGHOLD - use SVR4 sighold function when defined 3219304Speter * SIGRELSE - use SVR4 sigrelse function when defined 3319304Speter * FD_SET - macros FD_SET and FD_ZERO are used when defined 3419304Speter */ 3519304Speter 3619304Speter#include "os.h" 3719304Speter#include <errno.h> 3819304Speter#include <signal.h> 3919304Speter#include <setjmp.h> 4019304Speter#include <ctype.h> 4119304Speter#include <sys/time.h> 4219304Speter 43254225Speter/* includes specific to top */ 4419304Speter#include "display.h" /* interface to display package */ 4519304Speter#include "screen.h" /* interface to screen package */ 4619304Speter#include "top.h" 47254225Speter#include "top.local.h" 48254225Speter#include "boolean.h" 4919304Speter#include "machine.h" 5019304Speter#include "utils.h" 5119304Speter 5219304Speter/* Size of the stdio buffer given to stdout */ 5319304Speter#define Buffersize 2048 5419304Speter 5519304Speter/* The buffer that stdio will use */ 5619304Speterchar stdoutbuf[Buffersize]; 5719304Speter 5819304Speter/* build Signal masks */ 59254225Speter#define Smask(s) (1 << ((s) - 1)) 6019304Speter 6119304Speter/* for getopt: */ 6219304Speterextern int optind; 6319304Speterextern char *optarg; 6419304Speter 6519304Speter/* imported from screen.c */ 6619304Speterextern int overstrike; 6719304Speter 6819304Speterstatic int fmt_flags = 0; 6919304Speterint pcpu_stats = No; 7019304Speter 7119304Speter/* signal handling routines */ 7219304Spetersigret_t leave(); 7319304Spetersigret_t onalrm(); 7419304Spetersigret_t tstop(); 7519304Speter#ifdef SIGWINCH 7619304Spetersigret_t winch(); 7719304Speter#endif 7819304Speter 7919304Spetervolatile sig_atomic_t leaveflag; 8019304Spetervolatile sig_atomic_t tstopflag; 8119304Spetervolatile sig_atomic_t winchflag; 8219304Speter 8319304Speter/* internal routines */ 8419304Spetervoid quit(); 8519304Speter 8619304Speter/* values which need to be accessed by signal handlers */ 8719304Speterstatic int max_topn; /* maximum displayable processes */ 8819304Speter 8919304Speter/* miscellaneous things */ 9019304Speterstruct process_select ps; 9119304Speterchar *myname = "top"; 9219304Speterjmp_buf jmp_int; 9319304Speter 9419304Speter/* routines that don't return int */ 95254225Speter 9619304Speterchar *username(); 9719304Speterchar *ctime(); 9819304Speterchar *kill_procs(); 9919304Speterchar *renice_procs(); 10019304Speter 10119304Speter#ifdef ORDER 10219304Speterextern int (*compares[])(); 10319304Speter#else 10419304Speterextern int proc_compare(); 10519304Speterextern int io_compare(); 10619304Speter#endif 10719304Spetertime_t time(); 10819304Speter 10919304Spetercaddr_t get_process_info(); 11019304Speter 11119304Speter/* different routines for displaying the user's identification */ 11219304Speter/* (values assigned to get_userid) */ 113254225Speterchar *username(); 11419304Speterchar *itoa7(); 11519304Speter 11619304Speter/* display routines that need to be predeclared */ 11719304Speterint i_loadave(); 11819304Speterint u_loadave(); 11919304Speterint i_procstates(); 12019304Speterint u_procstates(); 12119304Speterint i_cpustates(); 12219304Speterint u_cpustates(); 12319304Speterint i_memory(); 124254225Speterint u_memory(); 12519304Speterint i_swap(); 12619304Speterint u_swap(); 12719304Speterint i_message(); 128254225Speterint u_message(); 129254225Speterint i_header(); 13019304Speterint u_header(); 13119304Speterint i_process(); 13219304Speterint u_process(); 13319304Speter 13419304Speter/* pointers to display routines */ 13519304Speterint (*d_loadave)() = i_loadave; 13619304Speterint (*d_procstates)() = i_procstates; 13719304Speterint (*d_cpustates)() = i_cpustates; 13819304Speterint (*d_memory)() = i_memory; 13919304Speterint (*d_swap)() = i_swap; 140254225Speterint (*d_message)() = i_message; 14119304Speterint (*d_header)() = i_header; 14219304Speterint (*d_process)() = i_process; 14319304Speter 144254225Speter 145254225Spetermain(argc, argv) 14619304Speter 14719304Speterint argc; 14819304Speterchar *argv[]; 14919304Speter 15019304Speter{ 15119304Speter register int i; 15219304Speter register int active_procs; 15319304Speter register int change; 15419304Speter 15519304Speter struct system_info system_info; 156254225Speter struct statics statics; 15719304Speter caddr_t processes; 15819304Speter 15919304Speter static char tempbuf1[50]; 160254225Speter static char tempbuf2[50]; 161254225Speter int old_sigmask; /* only used for BSD-style signals */ 16219304Speter int topn = Default_TOPN; 16319304Speter int delay = Default_DELAY; 16419304Speter int displays = 0; /* indicates unspecified */ 16519304Speter int sel_ret = 0; 16619304Speter time_t curr_time; 16719304Speter char *(*get_userid)() = username; 16819304Speter char *uname_field = "USERNAME"; 16919304Speter char *header_text; 17019304Speter char *env_top; 17119304Speter char **preset_argv; 172254225Speter int preset_argc = 0; 17319304Speter char **av; 17419304Speter int ac; 17519304Speter char dostates = No; 176254225Speter char do_unames = Yes; 177254225Speter char interactive = Maybe; 17819304Speter char warnings = 0; 17919304Speter#if Default_TOPN == Infinity 18019304Speter char topn_specified = No; 18119304Speter#endif 18219304Speter char ch; 18319304Speter char *iptr; 18419304Speter char no_command = 1; 18519304Speter struct timeval timeout; 18619304Speter#ifdef ORDER 18719304Speter char *order_name = NULL; 18819304Speter int order_index = 0; 18919304Speter#endif 19019304Speter#ifndef FD_SET 19119304Speter /* FD_SET and friends are not present: fake it */ 192254225Speter typedef int fd_set; 193254225Speter#define FD_ZERO(x) (*(x) = 0) 194254225Speter#define FD_SET(f, x) (*(x) = 1<<f) 19519304Speter#endif 19619304Speter fd_set readfds; 19719304Speter 19819304Speter#ifdef ORDER 19919304Speter static char command_chars[] = "\f qh?en#sdkriIutHmSCajzPo"; 20019304Speter#else 20119304Speter static char command_chars[] = "\f qh?en#sdkriIutHmSCajzP"; 20219304Speter#endif 20319304Speter/* these defines enumerate the "strchr"s of the commands in command_chars */ 20419304Speter#define CMD_redraw 0 205254225Speter#define CMD_update 1 20619304Speter#define CMD_quit 2 20719304Speter#define CMD_help1 3 20819304Speter#define CMD_help2 4 209254225Speter#define CMD_OSLIMIT 4 /* terminals with OS can only handle commands */ 210254225Speter#define CMD_errors 5 /* less than or equal to CMD_OSLIMIT */ 21119304Speter#define CMD_number1 6 21219304Speter#define CMD_number2 7 21319304Speter#define CMD_delay 8 21419304Speter#define CMD_displays 9 21519304Speter#define CMD_kill 10 21619304Speter#define CMD_renice 11 21719304Speter#define CMD_idletog 12 21819304Speter#define CMD_idletog2 13 21919304Speter#define CMD_user 14 22019304Speter#define CMD_selftog 15 221254225Speter#define CMD_thrtog 16 22219304Speter#define CMD_viewtog 17 22319304Speter#define CMD_viewsys 18 22419304Speter#define CMD_wcputog 19 225254225Speter#define CMD_showargs 20 22619304Speter#define CMD_jidtog 21 22719304Speter#define CMD_kidletog 22 22819304Speter#define CMD_pcputog 23 22919304Speter#ifdef ORDER 23019304Speter#define CMD_order 24 23119304Speter#endif 23219304Speter 23319304Speter /* set the buffer for stdout */ 23419304Speter#ifdef DEBUG 23519304Speter extern FILE *debug; 236254225Speter debug = fopen("debug.run", "w"); 23719304Speter setbuffer(stdout, NULL, 0); 23819304Speter#else 23919304Speter setbuffer(stdout, stdoutbuf, Buffersize); 24019304Speter#endif 24119304Speter 24219304Speter /* get our name */ 24319304Speter if (argc > 0) 24419304Speter { 24519304Speter if ((myname = strrchr(argv[0], '/')) == 0) 24619304Speter { 24719304Speter myname = argv[0]; 24819304Speter } 24919304Speter else 25019304Speter { 25119304Speter myname++; 25219304Speter } 25319304Speter } 25419304Speter 25519304Speter /* initialize some selection options */ 25619304Speter ps.idle = Yes; 25719304Speter ps.self = -1; 25819304Speter ps.system = No; 25919304Speter ps.uid = -1; 26019304Speter ps.thread = No; 26119304Speter ps.wcpu = 1; 262254225Speter ps.jail = No; 263254225Speter ps.kidle = Yes; 26419304Speter ps.command = NULL; 26519304Speter 266254225Speter /* get preset options from the environment */ 26719304Speter if ((env_top = getenv("TOP")) != NULL) 26819304Speter { 26919304Speter av = preset_argv = argparse(env_top, &preset_argc); 27019304Speter ac = preset_argc; 27119304Speter 27219304Speter /* set the dummy argument to an explanatory message, in case 27319304Speter getopt encounters a bad argument */ 27419304Speter preset_argv[0] = "while processing environment"; 27519304Speter } 27619304Speter 27719304Speter /* process options */ 27819304Speter do { 27919304Speter /* if we're done doing the presets, then process the real arguments */ 28019304Speter if (preset_argc == 0) 28119304Speter { 28219304Speter ac = argc; 28319304Speter av = argv; 28419304Speter 285254225Speter /* this should keep getopt happy... */ 28619304Speter optind = 1; 28719304Speter } 28819304Speter 28919304Speter while ((i = getopt(ac, av, "CSIHPabijnquvzs:d:U:m:o:t")) != EOF) 29019304Speter { 29119304Speter switch(i) 29219304Speter { 29319304Speter case 'v': /* show version number */ 29419304Speter fprintf(stderr, "%s: version %s\n", 295254225Speter myname, version_string()); 29619304Speter exit(1); 29719304Speter break; 29819304Speter 29919304Speter case 'u': /* toggle uid/username display */ 30019304Speter do_unames = !do_unames; 30119304Speter break; 30219304Speter 30319304Speter case 'U': /* display only username's processes */ 30419304Speter if ((ps.uid = userid(optarg)) == -1) 30519304Speter { 30619304Speter fprintf(stderr, "%s: unknown user\n", optarg); 30719304Speter exit(1); 30819304Speter } 30919304Speter break; 310254225Speter 31119304Speter case 'S': /* show system processes */ 31219304Speter ps.system = !ps.system; 31319304Speter break; 31419304Speter 31519304Speter case 'I': /* show idle processes */ 31619304Speter ps.idle = !ps.idle; 31719304Speter break; 31819304Speter 31919304Speter case 'i': /* go interactive regardless */ 32019304Speter interactive = Yes; 32119304Speter break; 32219304Speter 32319304Speter case 'n': /* batch, or non-interactive */ 32419304Speter case 'b': 325254225Speter interactive = No; 32619304Speter break; 32719304Speter 32819304Speter case 'a': 32919304Speter fmt_flags ^= FMT_SHOWARGS; 33019304Speter break; 33119304Speter 33219304Speter case 'd': /* number of displays to show */ 33319304Speter if ((i = atoiwi(optarg)) == Invalid || i == 0) 33419304Speter { 33519304Speter fprintf(stderr, 33619304Speter "%s: warning: display count should be positive -- option ignored\n", 33719304Speter myname); 33819304Speter warnings++; 33919304Speter } 34019304Speter else 34119304Speter { 34219304Speter displays = i; 34319304Speter } 34419304Speter break; 34519304Speter 34619304Speter case 's': 34719304Speter if ((delay = atoi(optarg)) < 0 || (delay == 0 && getuid() != 0)) 34819304Speter { 34919304Speter fprintf(stderr, 35019304Speter "%s: warning: seconds delay should be positive -- using default\n", 35119304Speter myname); 35219304Speter delay = Default_DELAY; 353254225Speter warnings++; 35419304Speter } 35519304Speter break; 35619304Speter 35719304Speter case 'q': /* be quick about it */ 35819304Speter /* only allow this if user is really root */ 35919304Speter if (getuid() == 0) 36019304Speter { 36119304Speter /* be very un-nice! */ 36219304Speter (void) nice(-20); 36319304Speter } 36419304Speter else 36519304Speter { 36619304Speter fprintf(stderr, 36719304Speter "%s: warning: `-q' option can only be used by root\n", 36819304Speter myname); 36919304Speter warnings++; 37019304Speter } 371208612Sjh break; 372208612Sjh 373208612Sjh case 'm': /* select display mode */ 374208612Sjh if (strcmp(optarg, "io") == 0) { 37519304Speter displaymode = DISP_IO; 37619304Speter } else if (strcmp(optarg, "cpu") == 0) { 37719304Speter displaymode = DISP_CPU; 37819304Speter } else { 37919304Speter fprintf(stderr, 38019304Speter "%s: warning: `-m' option can only take args " 38119304Speter "'io' or 'cpu'\n", 38219304Speter myname); 38319304Speter exit(1); 38419304Speter } 38519304Speter break; 38619304Speter 38719304Speter case 'o': /* select sort order */ 38819304Speter#ifdef ORDER 38919304Speter order_name = optarg; 39019304Speter#else 39119304Speter fprintf(stderr, 39219304Speter "%s: this platform does not support arbitrary ordering. Sorry.\n", 39319304Speter myname); 39419304Speter warnings++; 39519304Speter#endif 39619304Speter break; 39719304Speter 39819304Speter case 't': 39919304Speter ps.self = (ps.self == -1) ? getpid() : -1; 40019304Speter break; 40119304Speter 40219304Speter case 'C': 40319304Speter ps.wcpu = !ps.wcpu; 40419304Speter break; 40519304Speter 40619304Speter case 'H': 40719304Speter ps.thread = !ps.thread; 40819304Speter break; 40919304Speter 41019304Speter case 'j': 41119304Speter ps.jail = !ps.jail; 41219304Speter break; 41319304Speter 41419304Speter case 'P': 41519304Speter pcpu_stats = !pcpu_stats; 41619304Speter break; 41719304Speter 41819304Speter case 'z': 41919304Speter ps.kidle = !ps.kidle; 42019304Speter break; 42119304Speter 42219304Speter default: 42319304Speter fprintf(stderr, 42419304Speter"Top version %s\n" 42519304Speter"Usage: %s [-abCHIijnPqStuvz] [-d count] [-m io | cpu] [-o field] [-s time]\n" 42619304Speter" [-U username] [number]\n", 42719304Speter version_string(), myname); 42819304Speter exit(1); 42919304Speter } 43019304Speter } 43119304Speter 43219304Speter /* get count of top processes to display (if any) */ 43319304Speter if (optind < ac) 43419304Speter { 43519304Speter if ((topn = atoiwi(av[optind])) == Invalid) 43619304Speter { 43719304Speter fprintf(stderr, 43819304Speter "%s: warning: process display count should be non-negative -- using default\n", 43919304Speter myname); 44019304Speter warnings++; 44119304Speter } 44219304Speter#if Default_TOPN == Infinity 44319304Speter else 44419304Speter { 44519304Speter topn_specified = Yes; 44619304Speter } 44719304Speter#endif 44819304Speter } 44919304Speter 45019304Speter /* tricky: remember old value of preset_argc & set preset_argc = 0 */ 45119304Speter i = preset_argc; 45219304Speter preset_argc = 0; 453254225Speter 45419304Speter /* repeat only if we really did the preset arguments */ 45519304Speter } while (i != 0); 45619304Speter 45719304Speter /* set constants for username/uid display correctly */ 45819304Speter if (!do_unames) 45919304Speter { 46019304Speter uname_field = " UID "; 46119304Speter get_userid = itoa7; 46219304Speter } 46319304Speter 46419304Speter /* initialize the kernel memory interface */ 46519304Speter if (machine_init(&statics, do_unames) == -1) 46619304Speter { 46719304Speter exit(1); 46819304Speter } 46919304Speter 47019304Speter#ifdef ORDER 47119304Speter /* determine sorting order index, if necessary */ 47219304Speter if (order_name != NULL) 47319304Speter { 47419304Speter if ((order_index = string_index(order_name, statics.order_names)) == -1) 47519304Speter { 47619304Speter char **pp; 47719304Speter 47819304Speter fprintf(stderr, "%s: '%s' is not a recognized sorting order.\n", 47919304Speter myname, order_name); 48019304Speter fprintf(stderr, "\tTry one of these:"); 48119304Speter pp = statics.order_names; 48219304Speter while (*pp != NULL) 48319304Speter { 48419304Speter fprintf(stderr, " %s", *pp++); 48519304Speter } 48619304Speter fputc('\n', stderr); 48719304Speter exit(1); 48819304Speter } 48919304Speter } 49019304Speter#endif 49119304Speter 49219304Speter#ifdef no_initialization_needed 49319304Speter /* initialize the hashing stuff */ 49419304Speter if (do_unames) 495254225Speter { 49619304Speter init_hash(); 49719304Speter } 49819304Speter#endif 49919304Speter 50019304Speter /* initialize termcap */ 50119304Speter init_termcap(interactive); 50219304Speter 50319304Speter /* get the string to use for the process area header */ 50419304Speter header_text = format_header(uname_field); 50519304Speter 50619304Speter /* initialize display interface */ 50719304Speter if ((max_topn = display_init(&statics)) == -1) 50819304Speter { 50919304Speter fprintf(stderr, "%s: can't allocate sufficient memory\n", myname); 51019304Speter exit(4); 51119304Speter } 51219304Speter 51319304Speter /* print warning if user requested more processes than we can display */ 51419304Speter if (topn > max_topn) 51519304Speter { 51619304Speter fprintf(stderr, 51719304Speter "%s: warning: this terminal can only display %d processes.\n", 51819304Speter myname, max_topn); 51919304Speter warnings++; 52019304Speter } 52119304Speter 52219304Speter /* adjust for topn == Infinity */ 52319304Speter if (topn == Infinity) 52419304Speter { 52519304Speter /* 52619304Speter * For smart terminals, infinity really means everything that can 52719304Speter * be displayed, or Largest. 52819304Speter * On dumb terminals, infinity means every process in the system! 52919304Speter * We only really want to do that if it was explicitly specified. 53019304Speter * This is always the case when "Default_TOPN != Infinity". But if 531254225Speter * topn wasn't explicitly specified and we are on a dumb terminal 532254225Speter * and the default is Infinity, then (and only then) we use 533254225Speter * "Nominal_TOPN" instead. 534254225Speter */ 535254225Speter#if Default_TOPN == Infinity 53619304Speter topn = smart_terminal ? Largest : 53719304Speter (topn_specified ? Largest : Nominal_TOPN); 53819304Speter#else 53919304Speter topn = Largest; 54019304Speter#endif 54119304Speter } 54219304Speter 54319304Speter /* set header display accordingly */ 54419304Speter display_header(topn > 0); 54519304Speter 54619304Speter /* determine interactive state */ 54719304Speter if (interactive == Maybe) 54819304Speter { 549254225Speter interactive = smart_terminal; 55019304Speter } 55119304Speter 552254225Speter /* if # of displays not specified, fill it in */ 55319304Speter if (displays == 0) 55419304Speter { 55519304Speter displays = smart_terminal ? Infinity : 1; 55619304Speter } 55719304Speter 55819304Speter /* hold interrupt signals while setting up the screen and the handlers */ 55919304Speter#ifdef SIGHOLD 56019304Speter sighold(SIGINT); 56119304Speter sighold(SIGQUIT); 56219304Speter sighold(SIGTSTP); 56319304Speter#else 56419304Speter old_sigmask = sigblock(Smask(SIGINT) | Smask(SIGQUIT) | Smask(SIGTSTP)); 56519304Speter#endif 56619304Speter init_screen(); 56719304Speter (void) signal(SIGINT, leave); 56819304Speter (void) signal(SIGQUIT, leave); 56919304Speter (void) signal(SIGTSTP, tstop); 57019304Speter#ifdef SIGWINCH 57119304Speter (void) signal(SIGWINCH, winch); 57219304Speter#endif 57319304Speter#ifdef SIGRELSE 57419304Speter sigrelse(SIGINT); 57519304Speter sigrelse(SIGQUIT); 57619304Speter sigrelse(SIGTSTP); 57719304Speter#else 578254225Speter (void) sigsetmask(old_sigmask); 57919304Speter#endif 58019304Speter if (warnings) 58119304Speter { 582254225Speter fputs("....", stderr); 583254225Speter fflush(stderr); /* why must I do this? */ 584254225Speter sleep((unsigned)(3 * warnings)); 58519304Speter fputc('\n', stderr); 58619304Speter } 58719304Speter 58819304Speterrestart: 58919304Speter 590254225Speter /* 591254225Speter * main loop -- repeat while display count is positive or while it 59219304Speter * indicates infinity (by being -1) 59319304Speter */ 59419304Speter 59519304Speter while ((displays == -1) || (displays-- > 0)) 596254225Speter { 59719304Speter int (*compare)(); 59819304Speter 599254225Speter 60019304Speter /* get the current stats */ 60119304Speter get_system_info(&system_info); 602254225Speter 603254225Speter#ifdef ORDER 604254225Speter compare = compares[order_index]; 605254225Speter#else 606254225Speter if (displaymode == DISP_CPU) 607254225Speter compare = proc_compare; 608254225Speter else 609254225Speter compare = io_compare; 610254225Speter#endif 611254225Speter 612254225Speter /* get the current set of processes */ 613254225Speter processes = 614254225Speter get_process_info(&system_info, &ps, compare); 61519304Speter 61619304Speter /* display the load averages */ 61719304Speter (*d_loadave)(system_info.last_pid, 61819304Speter system_info.load_avg); 61919304Speter 62019304Speter /* display the current time */ 62119304Speter /* this method of getting the time SHOULD be fairly portable */ 62219304Speter time(&curr_time); 623254225Speter i_uptime(&system_info.boottime, &curr_time); 62419304Speter i_timeofday(&curr_time); 62519304Speter 62619304Speter /* display process state breakdown */ 62719304Speter (*d_procstates)(system_info.p_total, 62819304Speter system_info.procstates); 62919304Speter 63019304Speter /* display the cpu state percentage breakdown */ 63119304Speter if (dostates) /* but not the first time */ 63219304Speter { 63319304Speter (*d_cpustates)(system_info.cpustates); 63419304Speter } 63519304Speter else 63619304Speter { 63719304Speter /* we'll do it next time */ 63819304Speter if (smart_terminal) 63919304Speter { 64019304Speter z_cpustates(); 64119304Speter } 642254225Speter else 64319304Speter { 64419304Speter putchar('\n'); 64519304Speter } 64619304Speter dostates = Yes; 64719304Speter } 64819304Speter 64919304Speter /* display memory stats */ 65019304Speter (*d_memory)(system_info.memory); 651 652 /* display swap stats */ 653 (*d_swap)(system_info.swap); 654 655 /* handle message area */ 656 (*d_message)(); 657 658 /* update the header area */ 659 (*d_header)(header_text); 660 661 if (topn > 0) 662 { 663 /* determine number of processes to actually display */ 664 /* this number will be the smallest of: active processes, 665 number user requested, number current screen accomodates */ 666 active_procs = system_info.P_ACTIVE; 667 if (active_procs > topn) 668 { 669 active_procs = topn; 670 } 671 if (active_procs > max_topn) 672 { 673 active_procs = max_topn; 674 } 675 676 /* now show the top "n" processes. */ 677 for (i = 0; i < active_procs; i++) 678 { 679 (*d_process)(i, format_next_process(processes, get_userid, 680 fmt_flags)); 681 } 682 } 683 else 684 { 685 i = 0; 686 } 687 688 /* do end-screen processing */ 689 u_endscreen(i); 690 691 /* now, flush the output buffer */ 692 if (fflush(stdout) != 0) 693 { 694 new_message(MT_standout, " Write error on stdout"); 695 putchar('\r'); 696 quit(1); 697 /*NOTREACHED*/ 698 } 699 700 /* only do the rest if we have more displays to show */ 701 if (displays) 702 { 703 /* switch out for new display on smart terminals */ 704 if (smart_terminal) 705 { 706 if (overstrike) 707 { 708 reset_display(); 709 } 710 else 711 { 712 d_loadave = u_loadave; 713 d_procstates = u_procstates; 714 d_cpustates = u_cpustates; 715 d_memory = u_memory; 716 d_swap = u_swap; 717 d_message = u_message; 718 d_header = u_header; 719 d_process = u_process; 720 } 721 } 722 723 no_command = Yes; 724 if (!interactive) 725 { 726 /* set up alarm */ 727 (void) signal(SIGALRM, onalrm); 728 (void) alarm((unsigned)delay); 729 730 /* wait for the rest of it .... */ 731 pause(); 732 } 733 else while (no_command) 734 { 735 /* assume valid command unless told otherwise */ 736 no_command = No; 737 738 /* set up arguments for select with timeout */ 739 FD_ZERO(&readfds); 740 FD_SET(0, &readfds); /* for standard input */ 741 timeout.tv_sec = delay; 742 timeout.tv_usec = 0; 743 744 if (leaveflag) { 745 end_screen(); 746 exit(0); 747 } 748 749 if (tstopflag) { 750 /* move to the lower left */ 751 end_screen(); 752 fflush(stdout); 753 754 /* default the signal handler action */ 755 (void) signal(SIGTSTP, SIG_DFL); 756 757 /* unblock the signal and send ourselves one */ 758#ifdef SIGRELSE 759 sigrelse(SIGTSTP); 760#else 761 (void) sigsetmask(sigblock(0) & ~(1 << (SIGTSTP - 1))); 762#endif 763 (void) kill(0, SIGTSTP); 764 765 /* reset the signal handler */ 766 (void) signal(SIGTSTP, tstop); 767 768 /* reinit screen */ 769 reinit_screen(); 770 reset_display(); 771 tstopflag = 0; 772 goto restart; 773 } 774 775 if (winchflag) { 776 /* reascertain the screen dimensions */ 777 get_screensize(); 778 779 /* tell display to resize */ 780 max_topn = display_resize(); 781 782 /* reset the signal handler */ 783 (void) signal(SIGWINCH, winch); 784 785 reset_display(); 786 winchflag = 0; 787 goto restart; 788 } 789 790 /* wait for either input or the end of the delay period */ 791 sel_ret = select(2, &readfds, NULL, NULL, &timeout); 792 if (sel_ret < 0 && errno != EINTR) 793 quit(0); 794 if (sel_ret > 0) 795 { 796 int newval; 797 char *errmsg; 798 799 /* something to read -- clear the message area first */ 800 clear_message(); 801 802 /* now read it and convert to command strchr */ 803 /* (use "change" as a temporary to hold strchr) */ 804 if (read(0, &ch, 1) != 1) 805 { 806 /* read error: either 0 or -1 */ 807 new_message(MT_standout, " Read error on stdin"); 808 putchar('\r'); 809 quit(1); 810 /*NOTREACHED*/ 811 } 812 if ((iptr = strchr(command_chars, ch)) == NULL) 813 { 814 if (ch != '\r' && ch != '\n') 815 { 816 /* illegal command */ 817 new_message(MT_standout, " Command not understood"); 818 } 819 putchar('\r'); 820 no_command = Yes; 821 } 822 else 823 { 824 change = iptr - command_chars; 825 if (overstrike && change > CMD_OSLIMIT) 826 { 827 /* error */ 828 new_message(MT_standout, 829 " Command cannot be handled by this terminal"); 830 putchar('\r'); 831 no_command = Yes; 832 } 833 else switch(change) 834 { 835 case CMD_redraw: /* redraw screen */ 836 reset_display(); 837 break; 838 839 case CMD_update: /* merely update display */ 840 /* is the load average high? */ 841 if (system_info.load_avg[0] > LoadMax) 842 { 843 /* yes, go home for visual feedback */ 844 go_home(); 845 fflush(stdout); 846 } 847 break; 848 849 case CMD_quit: /* quit */ 850 quit(0); 851 /*NOTREACHED*/ 852 break; 853 854 case CMD_help1: /* help */ 855 case CMD_help2: 856 reset_display(); 857 clear(); 858 show_help(); 859 standout("Hit any key to continue: "); 860 fflush(stdout); 861 (void) read(0, &ch, 1); 862 break; 863 864 case CMD_errors: /* show errors */ 865 if (error_count() == 0) 866 { 867 new_message(MT_standout, 868 " Currently no errors to report."); 869 putchar('\r'); 870 no_command = Yes; 871 } 872 else 873 { 874 reset_display(); 875 clear(); 876 show_errors(); 877 standout("Hit any key to continue: "); 878 fflush(stdout); 879 (void) read(0, &ch, 1); 880 } 881 break; 882 883 case CMD_number1: /* new number */ 884 case CMD_number2: 885 new_message(MT_standout, 886 "Number of processes to show: "); 887 newval = readline(tempbuf1, 8, Yes); 888 if (newval > -1) 889 { 890 if (newval > max_topn) 891 { 892 new_message(MT_standout | MT_delayed, 893 " This terminal can only display %d processes.", 894 max_topn); 895 putchar('\r'); 896 } 897 898 if (newval == 0) 899 { 900 /* inhibit the header */ 901 display_header(No); 902 } 903 else if (newval > topn && topn == 0) 904 { 905 /* redraw the header */ 906 display_header(Yes); 907 d_header = i_header; 908 } 909 topn = newval; 910 } 911 break; 912 913 case CMD_delay: /* new seconds delay */ 914 new_message(MT_standout, "Seconds to delay: "); 915 if ((i = readline(tempbuf1, 8, Yes)) > -1) 916 { 917 if ((delay = i) == 0 && getuid() != 0) 918 { 919 delay = 1; 920 } 921 } 922 clear_message(); 923 break; 924 925 case CMD_displays: /* change display count */ 926 new_message(MT_standout, 927 "Displays to show (currently %s): ", 928 displays == -1 ? "infinite" : 929 itoa(displays)); 930 if ((i = readline(tempbuf1, 10, Yes)) > 0) 931 { 932 displays = i; 933 } 934 else if (i == 0) 935 { 936 quit(0); 937 } 938 clear_message(); 939 break; 940 941 case CMD_kill: /* kill program */ 942 new_message(0, "kill "); 943 if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) 944 { 945 if ((errmsg = kill_procs(tempbuf2)) != NULL) 946 { 947 new_message(MT_standout, "%s", errmsg); 948 putchar('\r'); 949 no_command = Yes; 950 } 951 } 952 else 953 { 954 clear_message(); 955 } 956 break; 957 958 case CMD_renice: /* renice program */ 959 new_message(0, "renice "); 960 if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) 961 { 962 if ((errmsg = renice_procs(tempbuf2)) != NULL) 963 { 964 new_message(MT_standout, "%s", errmsg); 965 putchar('\r'); 966 no_command = Yes; 967 } 968 } 969 else 970 { 971 clear_message(); 972 } 973 break; 974 975 case CMD_idletog: 976 case CMD_idletog2: 977 ps.idle = !ps.idle; 978 new_message(MT_standout | MT_delayed, 979 " %sisplaying idle processes.", 980 ps.idle ? "D" : "Not d"); 981 putchar('\r'); 982 break; 983 984 case CMD_selftog: 985 ps.self = (ps.self == -1) ? getpid() : -1; 986 new_message(MT_standout | MT_delayed, 987 " %sisplaying self.", 988 (ps.self == -1) ? "D" : "Not d"); 989 putchar('\r'); 990 break; 991 992 case CMD_user: 993 new_message(MT_standout, 994 "Username to show: "); 995 if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) 996 { 997 if (tempbuf2[0] == '+' && 998 tempbuf2[1] == '\0') 999 { 1000 ps.uid = -1; 1001 } 1002 else if ((i = userid(tempbuf2)) == -1) 1003 { 1004 new_message(MT_standout, 1005 " %s: unknown user", tempbuf2); 1006 no_command = Yes; 1007 } 1008 else 1009 { 1010 ps.uid = i; 1011 } 1012 putchar('\r'); 1013 } 1014 else 1015 { 1016 clear_message(); 1017 } 1018 break; 1019 1020 case CMD_thrtog: 1021 ps.thread = !ps.thread; 1022 new_message(MT_standout | MT_delayed, 1023 " Displaying threads %s", 1024 ps.thread ? "separately" : "as a count"); 1025 header_text = format_header(uname_field); 1026 reset_display(); 1027 putchar('\r'); 1028 break; 1029 case CMD_wcputog: 1030 ps.wcpu = !ps.wcpu; 1031 new_message(MT_standout | MT_delayed, 1032 " Displaying %sCPU", 1033 ps.wcpu ? "W" : ""); 1034 header_text = format_header(uname_field); 1035 reset_display(); 1036 putchar('\r'); 1037 break; 1038 case CMD_viewtog: 1039 if (++displaymode == DISP_MAX) 1040 displaymode = 0; 1041 header_text = format_header(uname_field); 1042 display_header(Yes); 1043 d_header = i_header; 1044 reset_display(); 1045 break; 1046 case CMD_viewsys: 1047 ps.system = !ps.system; 1048 break; 1049 case CMD_showargs: 1050 fmt_flags ^= FMT_SHOWARGS; 1051 break; 1052#ifdef ORDER 1053 case CMD_order: 1054 new_message(MT_standout, 1055 "Order to sort: "); 1056 if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) 1057 { 1058 if ((i = string_index(tempbuf2, statics.order_names)) == -1) 1059 { 1060 new_message(MT_standout, 1061 " %s: unrecognized sorting order", tempbuf2); 1062 no_command = Yes; 1063 } 1064 else 1065 { 1066 order_index = i; 1067 } 1068 putchar('\r'); 1069 } 1070 else 1071 { 1072 clear_message(); 1073 } 1074 break; 1075#endif 1076 case CMD_jidtog: 1077 ps.jail = !ps.jail; 1078 new_message(MT_standout | MT_delayed, 1079 " %sisplaying jail ID.", 1080 ps.jail ? "D" : "Not d"); 1081 header_text = format_header(uname_field); 1082 reset_display(); 1083 putchar('\r'); 1084 break; 1085 case CMD_kidletog: 1086 ps.kidle = !ps.kidle; 1087 new_message(MT_standout | MT_delayed, 1088 " %sisplaying system idle process.", 1089 ps.kidle ? "D" : "Not d"); 1090 putchar('\r'); 1091 break; 1092 case CMD_pcputog: 1093 pcpu_stats = !pcpu_stats; 1094 new_message(MT_standout | MT_delayed, 1095 " Displaying %sCPU statistics.", 1096 pcpu_stats ? "per-" : "global "); 1097 toggle_pcpustats(&statics); 1098 max_topn = display_updatecpus(&statics); 1099 reset_display(); 1100 putchar('\r'); 1101 break; 1102 default: 1103 new_message(MT_standout, " BAD CASE IN SWITCH!"); 1104 putchar('\r'); 1105 } 1106 } 1107 1108 /* flush out stuff that may have been written */ 1109 fflush(stdout); 1110 } 1111 } 1112 } 1113 } 1114 1115#ifdef DEBUG 1116 fclose(debug); 1117#endif 1118 quit(0); 1119 /*NOTREACHED*/ 1120} 1121 1122/* 1123 * reset_display() - reset all the display routine pointers so that entire 1124 * screen will get redrawn. 1125 */ 1126 1127reset_display() 1128 1129{ 1130 d_loadave = i_loadave; 1131 d_procstates = i_procstates; 1132 d_cpustates = i_cpustates; 1133 d_memory = i_memory; 1134 d_swap = i_swap; 1135 d_message = i_message; 1136 d_header = i_header; 1137 d_process = i_process; 1138} 1139 1140/* 1141 * signal handlers 1142 */ 1143 1144sigret_t leave() /* exit under normal conditions -- INT handler */ 1145 1146{ 1147 leaveflag = 1; 1148} 1149 1150sigret_t tstop(i) /* SIGTSTP handler */ 1151 1152int i; 1153 1154{ 1155 tstopflag = 1; 1156} 1157 1158#ifdef SIGWINCH 1159sigret_t winch(i) /* SIGWINCH handler */ 1160 1161int i; 1162 1163{ 1164 winchflag = 1; 1165} 1166#endif 1167 1168void quit(status) /* exit under duress */ 1169 1170int status; 1171 1172{ 1173 end_screen(); 1174 exit(status); 1175 /*NOTREACHED*/ 1176} 1177 1178sigret_t onalrm() /* SIGALRM handler */ 1179 1180{ 1181 /* this is only used in batch mode to break out of the pause() */ 1182 /* return; */ 1183} 1184 1185