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