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