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