top.c revision 301836
1char *copyright = 2 "Copyright (c) 1984 through 1996, William LeFebvre"; 3 4/* 5 * Top users/processes display for Unix 6 * Version 3 7 * 8 * This program may be freely redistributed, 9 * but this entire comment MUST remain intact. 10 * 11 * Copyright (c) 1984, 1989, William LeFebvre, Rice University 12 * Copyright (c) 1989 - 1994, William LeFebvre, Northwestern University 13 * Copyright (c) 1994, 1995, William LeFebvre, Argonne National Laboratory 14 * Copyright (c) 1996, William LeFebvre, Group sys Consulting 15 * 16 * $FreeBSD: stable/10/contrib/top/top.c 301836 2016-06-12 05:57:42Z ngie $ 17 */ 18 19/* 20 * See the file "Changes" for information on version-to-version changes. 21 */ 22 23/* 24 * This file contains "main" and other high-level routines. 25 */ 26 27/* 28 * The following preprocessor variables, when defined, are used to 29 * distinguish between different Unix implementations: 30 * 31 * SIGHOLD - use SVR4 sighold function when defined 32 * SIGRELSE - use SVR4 sigrelse function when defined 33 * FD_SET - macros FD_SET and FD_ZERO are used when defined 34 */ 35 36#include "os.h" 37 38#include <sys/jail.h> 39#include <sys/time.h> 40 41#include <ctype.h> 42#include <errno.h> 43#include <jail.h> 44#include <setjmp.h> 45#include <signal.h> 46#include <unistd.h> 47 48/* includes specific to top */ 49#include "commands.h" 50#include "display.h" /* interface to display package */ 51#include "screen.h" /* interface to screen package */ 52#include "top.h" 53#include "top.local.h" 54#include "boolean.h" 55#include "machine.h" 56#include "utils.h" 57#include "username.h" 58 59/* Size of the stdio buffer given to stdout */ 60#define Buffersize 2048 61 62/* The buffer that stdio will use */ 63char stdoutbuf[Buffersize]; 64 65/* build Signal masks */ 66#define Smask(s) (1 << ((s) - 1)) 67 68/* for getopt: */ 69extern int optind; 70extern char *optarg; 71 72/* imported from screen.c */ 73extern int overstrike; 74 75static int fmt_flags = 0; 76int pcpu_stats = No; 77 78/* signal handling routines */ 79sigret_t leave(); 80sigret_t tstop(); 81#ifdef SIGWINCH 82sigret_t winch(); 83#endif 84 85volatile sig_atomic_t leaveflag; 86volatile sig_atomic_t tstopflag; 87volatile sig_atomic_t winchflag; 88 89/* internal routines */ 90void quit(); 91 92/* values which need to be accessed by signal handlers */ 93static int max_topn; /* maximum displayable processes */ 94 95/* miscellaneous things */ 96struct process_select ps; 97char *myname = "top"; 98jmp_buf jmp_int; 99 100/* routines that don't return int */ 101 102char *username(); 103char *ctime(); 104char *kill_procs(); 105char *renice_procs(); 106 107#ifdef ORDER 108extern int (*compares[])(); 109#else 110extern int proc_compare(); 111extern int io_compare(); 112#endif 113time_t time(); 114 115caddr_t get_process_info(); 116 117/* different routines for displaying the user's identification */ 118/* (values assigned to get_userid) */ 119char *username(); 120char *itoa7(); 121 122/* pointers to display routines */ 123void (*d_loadave)() = i_loadave; 124void (*d_procstates)() = i_procstates; 125void (*d_cpustates)() = i_cpustates; 126void (*d_memory)() = i_memory; 127void (*d_arc)() = i_arc; 128void (*d_swap)() = i_swap; 129void (*d_message)() = i_message; 130void (*d_header)() = i_header; 131void (*d_process)() = i_process; 132 133void reset_display(void); 134 135 136int 137main(argc, argv) 138 139int argc; 140char *argv[]; 141 142{ 143 register int i; 144 register int active_procs; 145 register int change; 146 147 struct system_info system_info; 148 struct statics statics; 149 caddr_t processes; 150 151 static char tempbuf1[50]; 152 static char tempbuf2[50]; 153 int old_sigmask; /* only used for BSD-style signals */ 154 int topn = Default_TOPN; 155 int delay = Default_DELAY; 156 int displays = 0; /* indicates unspecified */ 157 int sel_ret = 0; 158 time_t curr_time; 159 char *(*get_userid)() = username; 160 char *uname_field = "USERNAME"; 161 char *header_text; 162 char *env_top; 163 char **preset_argv; 164 int preset_argc = 0; 165 char **av; 166 int ac; 167 char dostates = No; 168 char do_unames = Yes; 169 char interactive = Maybe; 170 char warnings = 0; 171#if Default_TOPN == Infinity 172 char topn_specified = No; 173#endif 174 char ch; 175 char *iptr; 176 char no_command = 1; 177 struct timeval timeout; 178#ifdef ORDER 179 char *order_name = NULL; 180 int order_index = 0; 181#endif 182#ifndef FD_SET 183 /* FD_SET and friends are not present: fake it */ 184 typedef int fd_set; 185#define FD_ZERO(x) (*(x) = 0) 186#define FD_SET(f, x) (*(x) = 1<<f) 187#endif 188 fd_set readfds; 189 190#ifdef ORDER 191 static char command_chars[] = "\f qh?en#sdkriIutHmSCajzPJo"; 192#else 193 static char command_chars[] = "\f qh?en#sdkriIutHmSCajzPJ"; 194#endif 195/* these defines enumerate the "strchr"s of the commands in command_chars */ 196#define CMD_redraw 0 197#define CMD_update 1 198#define CMD_quit 2 199#define CMD_help1 3 200#define CMD_help2 4 201#define CMD_OSLIMIT 4 /* terminals with OS can only handle commands */ 202#define CMD_errors 5 /* less than or equal to CMD_OSLIMIT */ 203#define CMD_number1 6 204#define CMD_number2 7 205#define CMD_delay 8 206#define CMD_displays 9 207#define CMD_kill 10 208#define CMD_renice 11 209#define CMD_idletog 12 210#define CMD_idletog2 13 211#define CMD_user 14 212#define CMD_selftog 15 213#define CMD_thrtog 16 214#define CMD_viewtog 17 215#define CMD_viewsys 18 216#define CMD_wcputog 19 217#define CMD_showargs 20 218#define CMD_jidtog 21 219#define CMD_kidletog 22 220#define CMD_pcputog 23 221#define CMD_jail 24 222#ifdef ORDER 223#define CMD_order 25 224#endif 225 226 /* set the buffer for stdout */ 227#ifdef DEBUG 228 extern FILE *debug; 229 debug = fopen("debug.run", "w"); 230 setbuffer(stdout, NULL, 0); 231#else 232 setbuffer(stdout, stdoutbuf, Buffersize); 233#endif 234 235 /* get our name */ 236 if (argc > 0) 237 { 238 if ((myname = strrchr(argv[0], '/')) == 0) 239 { 240 myname = argv[0]; 241 } 242 else 243 { 244 myname++; 245 } 246 } 247 248 /* initialize some selection options */ 249 ps.idle = Yes; 250 ps.self = -1; 251 ps.system = No; 252 ps.uid = -1; 253 ps.thread = No; 254 ps.wcpu = 1; 255 ps.jid = -1; 256 ps.jail = No; 257 ps.kidle = Yes; 258 ps.command = NULL; 259 260 /* get preset options from the environment */ 261 if ((env_top = getenv("TOP")) != NULL) 262 { 263 av = preset_argv = argparse(env_top, &preset_argc); 264 ac = preset_argc; 265 266 /* set the dummy argument to an explanatory message, in case 267 getopt encounters a bad argument */ 268 preset_argv[0] = "while processing environment"; 269 } 270 271 /* process options */ 272 do { 273 /* if we're done doing the presets, then process the real arguments */ 274 if (preset_argc == 0) 275 { 276 ac = argc; 277 av = argv; 278 279 /* this should keep getopt happy... */ 280 optind = 1; 281 } 282 283 while ((i = getopt(ac, av, "CSIHPabijJ:nquvzs:d:U:m:o:t")) != EOF) 284 { 285 switch(i) 286 { 287 case 'v': /* show version number */ 288 fprintf(stderr, "%s: version %s\n", 289 myname, version_string()); 290 exit(1); 291 break; 292 293 case 'u': /* toggle uid/username display */ 294 do_unames = !do_unames; 295 break; 296 297 case 'U': /* display only username's processes */ 298 if ((ps.uid = userid(optarg)) == -1) 299 { 300 fprintf(stderr, "%s: unknown user\n", optarg); 301 exit(1); 302 } 303 break; 304 305 case 'S': /* show system processes */ 306 ps.system = !ps.system; 307 break; 308 309 case 'I': /* show idle processes */ 310 ps.idle = !ps.idle; 311 break; 312 313 case 'i': /* go interactive regardless */ 314 interactive = Yes; 315 break; 316 317 case 'n': /* batch, or non-interactive */ 318 case 'b': 319 interactive = No; 320 break; 321 322 case 'a': 323 fmt_flags ^= FMT_SHOWARGS; 324 break; 325 326 case 'd': /* number of displays to show */ 327 if ((i = atoiwi(optarg)) == Invalid || i == 0) 328 { 329 fprintf(stderr, 330 "%s: warning: display count should be positive -- option ignored\n", 331 myname); 332 warnings++; 333 } 334 else 335 { 336 displays = i; 337 } 338 break; 339 340 case 's': 341 if ((delay = atoi(optarg)) < 0 || (delay == 0 && getuid() != 0)) 342 { 343 fprintf(stderr, 344 "%s: warning: seconds delay should be positive -- using default\n", 345 myname); 346 delay = Default_DELAY; 347 warnings++; 348 } 349 break; 350 351 case 'q': /* be quick about it */ 352 /* only allow this if user is really root */ 353 if (getuid() == 0) 354 { 355 /* be very un-nice! */ 356 (void) nice(-20); 357 } 358 else 359 { 360 fprintf(stderr, 361 "%s: warning: `-q' option can only be used by root\n", 362 myname); 363 warnings++; 364 } 365 break; 366 367 case 'm': /* select display mode */ 368 if (strcmp(optarg, "io") == 0) { 369 displaymode = DISP_IO; 370 } else if (strcmp(optarg, "cpu") == 0) { 371 displaymode = DISP_CPU; 372 } else { 373 fprintf(stderr, 374 "%s: warning: `-m' option can only take args " 375 "'io' or 'cpu'\n", 376 myname); 377 exit(1); 378 } 379 break; 380 381 case 'o': /* select sort order */ 382#ifdef ORDER 383 order_name = optarg; 384#else 385 fprintf(stderr, 386 "%s: this platform does not support arbitrary ordering. Sorry.\n", 387 myname); 388 warnings++; 389#endif 390 break; 391 392 case 't': 393 ps.self = (ps.self == -1) ? getpid() : -1; 394 break; 395 396 case 'C': 397 ps.wcpu = !ps.wcpu; 398 break; 399 400 case 'H': 401 ps.thread = !ps.thread; 402 break; 403 404 case 'j': 405 ps.jail = !ps.jail; 406 break; 407 408 case 'J': /* display only jail's processes */ 409 if ((ps.jid = jail_getid(optarg)) == -1) 410 { 411 fprintf(stderr, "%s: unknown jail\n", optarg); 412 exit(1); 413 } 414 ps.jail = 1; 415 break; 416 417 case 'P': 418 pcpu_stats = !pcpu_stats; 419 break; 420 421 case 'z': 422 ps.kidle = !ps.kidle; 423 break; 424 425 default: 426 fprintf(stderr, 427"Top version %s\n" 428"Usage: %s [-abCHIijnPqStuvz] [-d count] [-m io | cpu] [-o field] [-s time]\n" 429" [-J jail] [-U username] [number]\n", 430 version_string(), myname); 431 exit(1); 432 } 433 } 434 435 /* get count of top processes to display (if any) */ 436 if (optind < ac) 437 { 438 if ((topn = atoiwi(av[optind])) == Invalid) 439 { 440 fprintf(stderr, 441 "%s: warning: process display count should be non-negative -- using default\n", 442 myname); 443 warnings++; 444 } 445#if Default_TOPN == Infinity 446 else 447 { 448 topn_specified = Yes; 449 } 450#endif 451 } 452 453 /* tricky: remember old value of preset_argc & set preset_argc = 0 */ 454 i = preset_argc; 455 preset_argc = 0; 456 457 /* repeat only if we really did the preset arguments */ 458 } while (i != 0); 459 460 /* set constants for username/uid display correctly */ 461 if (!do_unames) 462 { 463 uname_field = " UID "; 464 get_userid = itoa7; 465 } 466 467 /* initialize the kernel memory interface */ 468 if (machine_init(&statics, do_unames) == -1) 469 { 470 exit(1); 471 } 472 473#ifdef ORDER 474 /* determine sorting order index, if necessary */ 475 if (order_name != NULL) 476 { 477 if ((order_index = string_index(order_name, statics.order_names)) == -1) 478 { 479 char **pp; 480 481 fprintf(stderr, "%s: '%s' is not a recognized sorting order.\n", 482 myname, order_name); 483 fprintf(stderr, "\tTry one of these:"); 484 pp = statics.order_names; 485 while (*pp != NULL) 486 { 487 fprintf(stderr, " %s", *pp++); 488 } 489 fputc('\n', stderr); 490 exit(1); 491 } 492 } 493#endif 494 495#ifdef no_initialization_needed 496 /* initialize the hashing stuff */ 497 if (do_unames) 498 { 499 init_hash(); 500 } 501#endif 502 503 /* initialize termcap */ 504 init_termcap(interactive); 505 506 /* get the string to use for the process area header */ 507 header_text = format_header(uname_field); 508 509 /* initialize display interface */ 510 if ((max_topn = display_init(&statics)) == -1) 511 { 512 fprintf(stderr, "%s: can't allocate sufficient memory\n", myname); 513 exit(4); 514 } 515 516 /* print warning if user requested more processes than we can display */ 517 if (topn > max_topn) 518 { 519 fprintf(stderr, 520 "%s: warning: this terminal can only display %d processes.\n", 521 myname, max_topn); 522 warnings++; 523 } 524 525 /* adjust for topn == Infinity */ 526 if (topn == Infinity) 527 { 528 /* 529 * For smart terminals, infinity really means everything that can 530 * be displayed, or Largest. 531 * On dumb terminals, infinity means every process in the system! 532 * We only really want to do that if it was explicitly specified. 533 * This is always the case when "Default_TOPN != Infinity". But if 534 * topn wasn't explicitly specified and we are on a dumb terminal 535 * and the default is Infinity, then (and only then) we use 536 * "Nominal_TOPN" instead. 537 */ 538#if Default_TOPN == Infinity 539 topn = smart_terminal ? Largest : 540 (topn_specified ? Largest : Nominal_TOPN); 541#else 542 topn = Largest; 543#endif 544 } 545 546 /* set header display accordingly */ 547 display_header(topn > 0); 548 549 /* determine interactive state */ 550 if (interactive == Maybe) 551 { 552 interactive = smart_terminal; 553 } 554 555 /* if # of displays not specified, fill it in */ 556 if (displays == 0) 557 { 558 displays = smart_terminal ? Infinity : 1; 559 } 560 561 /* hold interrupt signals while setting up the screen and the handlers */ 562#ifdef SIGHOLD 563 sighold(SIGINT); 564 sighold(SIGQUIT); 565 sighold(SIGTSTP); 566#else 567 old_sigmask = sigblock(Smask(SIGINT) | Smask(SIGQUIT) | Smask(SIGTSTP)); 568#endif 569 init_screen(); 570 (void) signal(SIGINT, leave); 571 (void) signal(SIGQUIT, leave); 572 (void) signal(SIGTSTP, tstop); 573#ifdef SIGWINCH 574 (void) signal(SIGWINCH, winch); 575#endif 576#ifdef SIGRELSE 577 sigrelse(SIGINT); 578 sigrelse(SIGQUIT); 579 sigrelse(SIGTSTP); 580#else 581 (void) sigsetmask(old_sigmask); 582#endif 583 if (warnings) 584 { 585 fputs("....", stderr); 586 fflush(stderr); /* why must I do this? */ 587 sleep((unsigned)(3 * warnings)); 588 fputc('\n', stderr); 589 } 590 591restart: 592 593 /* 594 * main loop -- repeat while display count is positive or while it 595 * indicates infinity (by being -1) 596 */ 597 598 while ((displays == -1) || (displays-- > 0)) 599 { 600 int (*compare)(); 601 602 603 /* get the current stats */ 604 get_system_info(&system_info); 605 606#ifdef ORDER 607 compare = compares[order_index]; 608#else 609 if (displaymode == DISP_CPU) 610 compare = proc_compare; 611 else 612 compare = io_compare; 613#endif 614 615 /* get the current set of processes */ 616 processes = 617 get_process_info(&system_info, &ps, compare); 618 619 /* display the load averages */ 620 (*d_loadave)(system_info.last_pid, 621 system_info.load_avg); 622 623 /* display the current time */ 624 /* this method of getting the time SHOULD be fairly portable */ 625 time(&curr_time); 626 i_uptime(&system_info.boottime, &curr_time); 627 i_timeofday(&curr_time); 628 629 /* display process state breakdown */ 630 (*d_procstates)(system_info.p_total, 631 system_info.procstates); 632 633 /* display the cpu state percentage breakdown */ 634 if (dostates) /* but not the first time */ 635 { 636 (*d_cpustates)(system_info.cpustates); 637 } 638 else 639 { 640 /* we'll do it next time */ 641 if (smart_terminal) 642 { 643 z_cpustates(); 644 } 645 else 646 { 647 putchar('\n'); 648 } 649 dostates = Yes; 650 } 651 652 /* display memory stats */ 653 (*d_memory)(system_info.memory); 654 (*d_arc)(system_info.arc); 655 656 /* display swap stats */ 657 (*d_swap)(system_info.swap); 658 659 /* handle message area */ 660 (*d_message)(); 661 662 /* update the header area */ 663 (*d_header)(header_text); 664 665 if (topn > 0) 666 { 667 /* determine number of processes to actually display */ 668 /* this number will be the smallest of: active processes, 669 number user requested, number current screen accomodates */ 670 active_procs = system_info.P_ACTIVE; 671 if (active_procs > topn) 672 { 673 active_procs = topn; 674 } 675 if (active_procs > max_topn) 676 { 677 active_procs = max_topn; 678 } 679 680 /* now show the top "n" processes. */ 681 for (i = 0; i < active_procs; i++) 682 { 683 (*d_process)(i, format_next_process(processes, get_userid, 684 fmt_flags)); 685 } 686 } 687 else 688 { 689 i = 0; 690 } 691 692 /* do end-screen processing */ 693 u_endscreen(i); 694 695 /* now, flush the output buffer */ 696 if (fflush(stdout) != 0) 697 { 698 new_message(MT_standout, " Write error on stdout"); 699 putchar('\r'); 700 quit(1); 701 /*NOTREACHED*/ 702 } 703 704 /* only do the rest if we have more displays to show */ 705 if (displays) 706 { 707 /* switch out for new display on smart terminals */ 708 if (smart_terminal) 709 { 710 if (overstrike) 711 { 712 reset_display(); 713 } 714 else 715 { 716 d_loadave = u_loadave; 717 d_procstates = u_procstates; 718 d_cpustates = u_cpustates; 719 d_memory = u_memory; 720 d_arc = u_arc; 721 d_swap = u_swap; 722 d_message = u_message; 723 d_header = u_header; 724 d_process = u_process; 725 } 726 } 727 728 no_command = Yes; 729 if (!interactive) 730 { 731 sleep(delay); 732 if (leaveflag) { 733 end_screen(); 734 exit(0); 735 } 736 } 737 else while (no_command) 738 { 739 /* assume valid command unless told otherwise */ 740 no_command = No; 741 742 /* set up arguments for select with timeout */ 743 FD_ZERO(&readfds); 744 FD_SET(0, &readfds); /* for standard input */ 745 timeout.tv_sec = delay; 746 timeout.tv_usec = 0; 747 748 if (leaveflag) { 749 end_screen(); 750 exit(0); 751 } 752 753 if (tstopflag) { 754 /* move to the lower left */ 755 end_screen(); 756 fflush(stdout); 757 758 /* default the signal handler action */ 759 (void) signal(SIGTSTP, SIG_DFL); 760 761 /* unblock the signal and send ourselves one */ 762#ifdef SIGRELSE 763 sigrelse(SIGTSTP); 764#else 765 (void) sigsetmask(sigblock(0) & ~(1 << (SIGTSTP - 1))); 766#endif 767 (void) kill(0, SIGTSTP); 768 769 /* reset the signal handler */ 770 (void) signal(SIGTSTP, tstop); 771 772 /* reinit screen */ 773 reinit_screen(); 774 reset_display(); 775 tstopflag = 0; 776 goto restart; 777 } 778 779 if (winchflag) { 780 /* reascertain the screen dimensions */ 781 get_screensize(); 782 783 /* tell display to resize */ 784 max_topn = display_resize(); 785 786 /* reset the signal handler */ 787 (void) signal(SIGWINCH, winch); 788 789 reset_display(); 790 winchflag = 0; 791 goto restart; 792 } 793 794 /* wait for either input or the end of the delay period */ 795 sel_ret = select(2, &readfds, NULL, NULL, &timeout); 796 if (sel_ret < 0 && errno != EINTR) 797 quit(0); 798 if (sel_ret > 0) 799 { 800 int newval; 801 char *errmsg; 802 803 /* something to read -- clear the message area first */ 804 clear_message(); 805 806 /* now read it and convert to command strchr */ 807 /* (use "change" as a temporary to hold strchr) */ 808 if (read(0, &ch, 1) != 1) 809 { 810 /* read error: either 0 or -1 */ 811 new_message(MT_standout, " Read error on stdin"); 812 putchar('\r'); 813 quit(1); 814 /*NOTREACHED*/ 815 } 816 if ((iptr = strchr(command_chars, ch)) == NULL) 817 { 818 if (ch != '\r' && ch != '\n') 819 { 820 /* illegal command */ 821 new_message(MT_standout, " Command not understood"); 822 } 823 putchar('\r'); 824 no_command = Yes; 825 } 826 else 827 { 828 change = iptr - command_chars; 829 if (overstrike && change > CMD_OSLIMIT) 830 { 831 /* error */ 832 new_message(MT_standout, 833 " Command cannot be handled by this terminal"); 834 putchar('\r'); 835 no_command = Yes; 836 } 837 else switch(change) 838 { 839 case CMD_redraw: /* redraw screen */ 840 reset_display(); 841 break; 842 843 case CMD_update: /* merely update display */ 844 /* is the load average high? */ 845 if (system_info.load_avg[0] > LoadMax) 846 { 847 /* yes, go home for visual feedback */ 848 go_home(); 849 fflush(stdout); 850 } 851 break; 852 853 case CMD_quit: /* quit */ 854 quit(0); 855 /*NOTREACHED*/ 856 break; 857 858 case CMD_help1: /* help */ 859 case CMD_help2: 860 reset_display(); 861 clear(); 862 show_help(); 863 standout("Hit any key to continue: "); 864 fflush(stdout); 865 (void) read(0, &ch, 1); 866 break; 867 868 case CMD_errors: /* show errors */ 869 if (error_count() == 0) 870 { 871 new_message(MT_standout, 872 " Currently no errors to report."); 873 putchar('\r'); 874 no_command = Yes; 875 } 876 else 877 { 878 reset_display(); 879 clear(); 880 show_errors(); 881 standout("Hit any key to continue: "); 882 fflush(stdout); 883 (void) read(0, &ch, 1); 884 } 885 break; 886 887 case CMD_number1: /* new number */ 888 case CMD_number2: 889 new_message(MT_standout, 890 "Number of processes to show: "); 891 newval = readline(tempbuf1, 8, Yes); 892 if (newval > -1) 893 { 894 if (newval > max_topn) 895 { 896 new_message(MT_standout | MT_delayed, 897 " This terminal can only display %d processes.", 898 max_topn); 899 putchar('\r'); 900 } 901 902 if (newval == 0) 903 { 904 /* inhibit the header */ 905 display_header(No); 906 } 907 else if (newval > topn && topn == 0) 908 { 909 /* redraw the header */ 910 display_header(Yes); 911 d_header = i_header; 912 } 913 topn = newval; 914 } 915 break; 916 917 case CMD_delay: /* new seconds delay */ 918 new_message(MT_standout, "Seconds to delay: "); 919 if ((i = readline(tempbuf1, 8, Yes)) > -1) 920 { 921 if ((delay = i) == 0 && getuid() != 0) 922 { 923 delay = 1; 924 } 925 } 926 clear_message(); 927 break; 928 929 case CMD_displays: /* change display count */ 930 new_message(MT_standout, 931 "Displays to show (currently %s): ", 932 displays == -1 ? "infinite" : 933 itoa(displays)); 934 if ((i = readline(tempbuf1, 10, Yes)) > 0) 935 { 936 displays = i; 937 } 938 else if (i == 0) 939 { 940 quit(0); 941 } 942 clear_message(); 943 break; 944 945 case CMD_kill: /* kill program */ 946 new_message(0, "kill "); 947 if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) 948 { 949 if ((errmsg = kill_procs(tempbuf2)) != NULL) 950 { 951 new_message(MT_standout, "%s", errmsg); 952 putchar('\r'); 953 no_command = Yes; 954 } 955 } 956 else 957 { 958 clear_message(); 959 } 960 break; 961 962 case CMD_renice: /* renice program */ 963 new_message(0, "renice "); 964 if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) 965 { 966 if ((errmsg = renice_procs(tempbuf2)) != NULL) 967 { 968 new_message(MT_standout, "%s", errmsg); 969 putchar('\r'); 970 no_command = Yes; 971 } 972 } 973 else 974 { 975 clear_message(); 976 } 977 break; 978 979 case CMD_idletog: 980 case CMD_idletog2: 981 ps.idle = !ps.idle; 982 new_message(MT_standout | MT_delayed, 983 " %sisplaying idle processes.", 984 ps.idle ? "D" : "Not d"); 985 putchar('\r'); 986 break; 987 988 case CMD_selftog: 989 ps.self = (ps.self == -1) ? getpid() : -1; 990 new_message(MT_standout | MT_delayed, 991 " %sisplaying self.", 992 (ps.self == -1) ? "D" : "Not d"); 993 putchar('\r'); 994 break; 995 996 case CMD_user: 997 new_message(MT_standout, 998 "Username to show (+ for all): "); 999 if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) 1000 { 1001 if (tempbuf2[0] == '+' && 1002 tempbuf2[1] == '\0') 1003 { 1004 ps.uid = -1; 1005 } 1006 else if ((i = userid(tempbuf2)) == -1) 1007 { 1008 new_message(MT_standout, 1009 " %s: unknown user", tempbuf2); 1010 no_command = Yes; 1011 } 1012 else 1013 { 1014 ps.uid = i; 1015 } 1016 putchar('\r'); 1017 } 1018 else 1019 { 1020 clear_message(); 1021 } 1022 break; 1023 1024 case CMD_thrtog: 1025 ps.thread = !ps.thread; 1026 new_message(MT_standout | MT_delayed, 1027 " Displaying threads %s", 1028 ps.thread ? "separately" : "as a count"); 1029 header_text = format_header(uname_field); 1030 reset_display(); 1031 putchar('\r'); 1032 break; 1033 case CMD_wcputog: 1034 ps.wcpu = !ps.wcpu; 1035 new_message(MT_standout | MT_delayed, 1036 " Displaying %s CPU", 1037 ps.wcpu ? "weighted" : "raw"); 1038 header_text = format_header(uname_field); 1039 reset_display(); 1040 putchar('\r'); 1041 break; 1042 case CMD_viewtog: 1043 if (++displaymode == DISP_MAX) 1044 displaymode = 0; 1045 header_text = format_header(uname_field); 1046 display_header(Yes); 1047 d_header = i_header; 1048 reset_display(); 1049 break; 1050 case CMD_viewsys: 1051 ps.system = !ps.system; 1052 break; 1053 case CMD_showargs: 1054 fmt_flags ^= FMT_SHOWARGS; 1055 break; 1056#ifdef ORDER 1057 case CMD_order: 1058 new_message(MT_standout, 1059 "Order to sort: "); 1060 if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) 1061 { 1062 if ((i = string_index(tempbuf2, statics.order_names)) == -1) 1063 { 1064 new_message(MT_standout, 1065 " %s: unrecognized sorting order", tempbuf2); 1066 no_command = Yes; 1067 } 1068 else 1069 { 1070 order_index = i; 1071 } 1072 putchar('\r'); 1073 } 1074 else 1075 { 1076 clear_message(); 1077 } 1078 break; 1079#endif 1080 case CMD_jidtog: 1081 ps.jail = !ps.jail; 1082 new_message(MT_standout | MT_delayed, 1083 " %sisplaying jail ID.", 1084 ps.jail ? "D" : "Not d"); 1085 header_text = format_header(uname_field); 1086 reset_display(); 1087 putchar('\r'); 1088 break; 1089 1090 case CMD_jail: 1091 new_message(MT_standout, 1092 "Jail to show (+ for all): "); 1093 if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) 1094 { 1095 if (tempbuf2[0] == '+' && 1096 tempbuf2[1] == '\0') 1097 { 1098 ps.jid = -1; 1099 } 1100 else if ((i = jail_getid(tempbuf2)) == -1) 1101 { 1102 new_message(MT_standout, 1103 " %s: unknown jail", tempbuf2); 1104 no_command = Yes; 1105 } 1106 else 1107 { 1108 ps.jid = i; 1109 } 1110 if (ps.jail == 0) { 1111 ps.jail = 1; 1112 new_message(MT_standout | 1113 MT_delayed, " Displaying jail " 1114 "ID."); 1115 header_text = 1116 format_header(uname_field); 1117 reset_display(); 1118 } 1119 putchar('\r'); 1120 } 1121 else 1122 { 1123 clear_message(); 1124 } 1125 break; 1126 1127 case CMD_kidletog: 1128 ps.kidle = !ps.kidle; 1129 new_message(MT_standout | MT_delayed, 1130 " %sisplaying system idle process.", 1131 ps.kidle ? "D" : "Not d"); 1132 putchar('\r'); 1133 break; 1134 case CMD_pcputog: 1135 pcpu_stats = !pcpu_stats; 1136 new_message(MT_standout | MT_delayed, 1137 " Displaying %sCPU statistics.", 1138 pcpu_stats ? "per-" : "global "); 1139 toggle_pcpustats(); 1140 max_topn = display_updatecpus(&statics); 1141 reset_display(); 1142 putchar('\r'); 1143 break; 1144 default: 1145 new_message(MT_standout, " BAD CASE IN SWITCH!"); 1146 putchar('\r'); 1147 } 1148 } 1149 1150 /* flush out stuff that may have been written */ 1151 fflush(stdout); 1152 } 1153 } 1154 } 1155 } 1156 1157#ifdef DEBUG 1158 fclose(debug); 1159#endif 1160 quit(0); 1161 /*NOTREACHED*/ 1162} 1163 1164/* 1165 * reset_display() - reset all the display routine pointers so that entire 1166 * screen will get redrawn. 1167 */ 1168 1169void 1170reset_display() 1171 1172{ 1173 d_loadave = i_loadave; 1174 d_procstates = i_procstates; 1175 d_cpustates = i_cpustates; 1176 d_memory = i_memory; 1177 d_arc = i_arc; 1178 d_swap = i_swap; 1179 d_message = i_message; 1180 d_header = i_header; 1181 d_process = i_process; 1182} 1183 1184/* 1185 * signal handlers 1186 */ 1187 1188sigret_t leave() /* exit under normal conditions -- INT handler */ 1189 1190{ 1191 leaveflag = 1; 1192} 1193 1194sigret_t tstop(i) /* SIGTSTP handler */ 1195 1196int i; 1197 1198{ 1199 tstopflag = 1; 1200} 1201 1202#ifdef SIGWINCH 1203sigret_t winch(i) /* SIGWINCH handler */ 1204 1205int i; 1206 1207{ 1208 winchflag = 1; 1209} 1210#endif 1211 1212void quit(status) /* exit under duress */ 1213 1214int status; 1215 1216{ 1217 end_screen(); 1218 exit(status); 1219 /*NOTREACHED*/ 1220} 1221