1 /* 2 * Copyright (c) 1984 through 2008, William LeFebvre 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * 16 * * Neither the name of William LeFebvre nor the names of other 17 * contributors may be used to endorse or promote products derived from 18 * this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 char *copyright = 34 "Copyright (c) 1984 through 2008, William LeFebvre"; 35 36 /* 37 * Changes to other files that we can do at the same time: 38 * screen.c:init_termcap: get rid of the "interactive" argument and have it 39 * pass back something meaningful (such as success/failure/error). 40 */ 41 42 #include "os.h" 43 #include <signal.h> 44 #include <setjmp.h> 45 #include <ctype.h> 46 #include <sys/types.h> 47 #include <sys/uio.h> 48 #include <unistd.h> 49 50 #ifdef HAVE_SYS_UTSNAME_H 51 #include <sys/utsname.h> 52 #endif 53 54 #ifdef HAVE_GETOPT_H 55 #include <getopt.h> 56 #endif 57 58 /* definitions */ 59 #ifndef STDIN_FILENO 60 #define STDIN_FILENO 0 61 #endif 62 63 /* determine which type of signal functions to use */ 64 /* cant have sigaction without sigprocmask */ 65 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGPROCMASK) 66 #undef HAVE_SIGACTION 67 #endif 68 /* always use sigaction when it is available */ 69 #ifdef HAVE_SIGACTION 70 #undef HAVE_SIGHOLD 71 #else 72 /* use sighold/sigrelse, otherwise use old fashioned BSD signals */ 73 #if !defined(HAVE_SIGHOLD) || !defined(HAVE_SIGRELSE) 74 #define BSD_SIGNALS 75 #endif 76 #endif 77 78 /* if FD_SET and friends aren't present, then fake something up */ 79 #ifndef FD_SET 80 typedef int fd_set; 81 #define FD_ZERO(x) (*(x) = 0) 82 #define FD_SET(f, x) (*(x) = 1<<f) 83 #endif 84 85 /* includes specific to top */ 86 87 #include "top.h" 88 #include "machine.h" 89 #include "globalstate.h" 90 #include "commands.h" 91 #include "display.h" 92 #include "screen.h" 93 #include "boolean.h" 94 #include "username.h" 95 #include "utils.h" 96 #include "version.h" 97 #ifdef ENABLE_COLOR 98 #include "color.h" 99 #endif 100 101 /* definitions */ 102 #define BUFFERSIZE 4096 103 #define JMP_RESUME 1 104 #define JMP_RESIZE 2 105 106 /* externs for getopt: */ 107 extern int optind; 108 extern char *optarg; 109 110 /* statics */ 111 static char stdoutbuf[BUFFERSIZE]; 112 static jmp_buf jmp_int; 113 114 /* globals */ 115 char *myname = "top"; 116 117 void 118 quit(int status) 119 120 { 121 screen_end(); 122 chdir("/tmp"); 123 exit(status); 124 /* NOTREACHED */ 125 } 126 127 /* 128 * signal handlers 129 */ 130 131 void 132 set_signal(int sig, RETSIGTYPE (*handler)(int)) 133 134 { 135 #ifdef HAVE_SIGACTION 136 struct sigaction action; 137 138 action.sa_handler = handler; 139 action.sa_flags = 0; 140 (void) sigaction(sig, &action, NULL); 141 #else 142 (void) signal(sig, handler); 143 #endif 144 } 145 146 void 147 release_signal(int sig) 148 149 { 150 #ifdef HAVE_SIGACTION 151 sigset_t set; 152 sigemptyset(&set); 153 sigaddset(&set, sig); 154 sigprocmask(SIG_UNBLOCK, &set, NULL); 155 #endif 156 157 #ifdef HAVE_SIGHOLD 158 sigrelse(sig); 159 #endif 160 161 #ifdef BSD_SIGNALS 162 (void) sigsetmask(sigblock(0) & ~(sigmask(sig))); 163 #endif 164 } 165 166 RETSIGTYPE 167 sig_leave(int i) /* exit under normal conditions -- INT handler */ 168 169 { 170 screen_end(); 171 exit(EX_OK); 172 } 173 174 RETSIGTYPE 175 sig_tstop(int i) /* SIGTSTP handler */ 176 177 { 178 /* move to the lower left */ 179 screen_end(); 180 fflush(stdout); 181 182 /* default the signal handler action */ 183 set_signal(SIGTSTP, SIG_DFL); 184 185 /* unblock the TSTP signal */ 186 release_signal(SIGTSTP); 187 188 /* send ourselves a TSTP to stop the process */ 189 (void) kill(0, SIGTSTP); 190 191 /* reset the signal handler */ 192 set_signal(SIGTSTP, sig_tstop); 193 194 /* reinit screen */ 195 screen_reinit(); 196 197 /* jump back to a known place in the main loop */ 198 longjmp(jmp_int, JMP_RESUME); 199 200 /* NOTREACHED */ 201 } 202 203 #ifdef SIGWINCH 204 RETSIGTYPE 205 sig_winch(int i) /* SIGWINCH handler */ 206 207 { 208 /* reascertain the screen dimensions */ 209 screen_getsize(); 210 211 /* jump back to a known place in the main loop */ 212 longjmp(jmp_int, JMP_RESIZE); 213 } 214 #endif 215 216 #ifdef HAVE_SIGACTION 217 static sigset_t signalset; 218 #endif 219 220 void * 221 hold_signals() 222 223 { 224 #ifdef HAVE_SIGACTION 225 sigemptyset(&signalset); 226 sigaddset(&signalset, SIGINT); 227 sigaddset(&signalset, SIGQUIT); 228 sigaddset(&signalset, SIGTSTP); 229 #ifdef SIGWINCH 230 sigaddset(&signalset, SIGWINCH); 231 #endif 232 sigprocmask(SIG_BLOCK, &signalset, NULL); 233 return (void *)(&signalset); 234 #endif 235 236 #ifdef HAVE_SIGHOLD 237 sighold(SIGINT); 238 sighold(SIGQUIT); 239 sighold(SIGTSTP); 240 #ifdef SIGWINCH 241 sighold(SIGWINCH); 242 return NULL; 243 #endif 244 #endif 245 246 #ifdef BSD_SIGNALS 247 int mask; 248 #ifdef SIGWINCH 249 mask = sigblock(sigmask(SIGINT) | sigmask(SIGQUIT) | 250 sigmask(SIGTSTP) | sigmask(SIGWINCH)); 251 #else 252 mask = sigblock(sigmask(SIGINT) | sigmask(SIGQUIT) | sigmask(SIGTSTP)); 253 return (void *)mask; 254 #endif 255 #endif 256 257 } 258 259 void 260 set_signals() 261 262 { 263 (void) set_signal(SIGINT, sig_leave); 264 (void) set_signal(SIGQUIT, sig_leave); 265 (void) set_signal(SIGTSTP, sig_tstop); 266 #ifdef SIGWINCH 267 (void) set_signal(SIGWINCH, sig_winch); 268 #endif 269 } 270 271 void 272 release_signals(void *parm) 273 274 { 275 #ifdef HAVE_SIGACTION 276 sigprocmask(SIG_UNBLOCK, (sigset_t *)parm, NULL); 277 #endif 278 279 #ifdef HAVE_SIGHOLD 280 sigrelse(SIGINT); 281 sigrelse(SIGQUIT); 282 sigrelse(SIGTSTP); 283 #ifdef SIGWINCH 284 sigrelse(SIGWINCH); 285 #endif 286 #endif 287 288 #ifdef BSD_SIGNALS 289 (void) sigsetmask((int)parm); 290 #endif 291 } 292 293 /* 294 * void do_arguments(globalstate *gstate, int ac, char **av) 295 * 296 * Arguments processing. gstate points to the global state, 297 * ac and av are the arguments to process. This can be called 298 * multiple times with different sets of arguments. 299 */ 300 301 #ifdef HAVE_GETOPT_LONG 302 static struct option longopts[] = { 303 { "color", no_argument, NULL, 'C' }, 304 { "debug", no_argument, NULL, 'D' }, 305 { "system-procs", no_argument, NULL, 'S' }, 306 { "idle-procs", no_argument, NULL, 'I' }, 307 { "tag-names", no_argument, NULL, 'T' }, 308 { "all", no_argument, NULL, 'a' }, 309 { "batch", no_argument, NULL, 'b' }, 310 { "full-commands", no_argument, NULL, 'c' }, 311 { "interactive", no_argument, NULL, 'i' }, 312 { "quick", no_argument, NULL, 'q' }, 313 { "threads", no_argument, NULL, 't' }, 314 { "uids", no_argument, NULL, 'u' }, 315 { "version", no_argument, NULL, 'v' }, 316 { "delay", required_argument, NULL, 's' }, 317 { "displays", required_argument, NULL, 'd' }, 318 { "user", required_argument, NULL, 'U' }, 319 { "sort-order", required_argument, NULL, 'o' }, 320 { "display-mode", required_argument, NULL, 'm' }, 321 { NULL, 0, NULL, 0 }, 322 }; 323 #endif 324 325 326 void 327 do_arguments(globalstate *gstate, int ac, char **av) 328 329 { 330 int i; 331 332 /* this appears to keep getopt happy */ 333 optind = 1; 334 335 #ifdef HAVE_GETOPT_LONG 336 while ((i = getopt_long(ac, av, "CDSIMTabcinqtuvs:d:U:o:m:", longopts, NULL)) != -1) 337 #else 338 while ((i = getopt(ac, av, "CDSIMTabcinqtuvs:d:U:o:m:")) != EOF) 339 #endif 340 { 341 switch(i) 342 { 343 #ifdef ENABLE_COLOR 344 case 'C': 345 gstate->use_color = !gstate->use_color; 346 break; 347 #endif 348 349 case 'D': 350 debug_set(1); 351 break; 352 353 case 'v': 354 fprintf(stderr, "%s: version %s\n", myname, version_string()); 355 exit(EX_OK); 356 break; 357 358 case 'b': 359 case 'n': 360 gstate->interactive = No; 361 break; 362 363 case 'a': 364 gstate->displays = Infinity; 365 gstate->topn = Infinity; 366 break; 367 368 case 'i': 369 gstate->interactive = Yes; 370 break; 371 372 case 'o': 373 gstate->order_name = optarg; 374 break; 375 376 case 'd': 377 i = atoiwi(optarg); 378 if (i == Invalid || i == 0) 379 { 380 message_error(" Bad display count"); 381 } 382 else 383 { 384 gstate->displays = i; 385 } 386 break; 387 388 case 's': 389 i = atoi(optarg); 390 if (i < 0 || (i == 0 && getuid() != 0)) 391 { 392 message_error(" Bad seconds delay"); 393 } 394 else 395 { 396 gstate->delay = i; 397 } 398 break; 399 400 case 'u': 401 gstate->show_usernames = !gstate->show_usernames; 402 break; 403 404 case 'U': 405 i = userid(optarg); 406 if (i == -1) 407 { 408 message_error(" Unknown user '%s'", optarg); 409 } 410 else 411 { 412 gstate->pselect.uid = i; 413 } 414 break; 415 416 case 'm': 417 i = atoi(optarg); 418 gstate->pselect.mode = i; 419 break; 420 421 case 'S': 422 gstate->pselect.system = !gstate->pselect.system; 423 break; 424 425 case 'I': 426 gstate->pselect.idle = !gstate->pselect.idle; 427 break; 428 429 case 'M': 430 enable_ncpus = 1; 431 break; 432 433 434 #ifdef ENABLE_COLOR 435 case 'T': 436 gstate->show_tags = 1; 437 break; 438 #endif 439 440 case 'c': 441 gstate->pselect.fullcmd = !gstate->pselect.fullcmd; 442 break; 443 444 case 't': 445 gstate->pselect.threads = !gstate->pselect.threads; 446 break; 447 448 case 'q': /* be quick about it */ 449 /* only allow this if user is really root */ 450 if (getuid() == 0) 451 { 452 /* be very un-nice! */ 453 (void) nice(-20); 454 } 455 else 456 { 457 message_error(" Option -q can only be used by root"); 458 } 459 break; 460 461 default: 462 fprintf(stderr, "\ 463 Top version %s\n\ 464 Usage: %s [-ISTabcinqu] [-d x] [-s x] [-o field] [-U username] [number]\n", 465 version_string(), myname); 466 exit(EX_USAGE); 467 } 468 } 469 470 /* get count of top processes to display */ 471 if (optind < ac && *av[optind]) 472 { 473 if ((i = atoiwi(av[optind])) == Invalid) 474 { 475 message_error(" Process count not a number"); 476 } 477 else 478 { 479 gstate->topn = i; 480 } 481 } 482 } 483 484 void 485 do_display(globalstate *gstate) 486 487 { 488 int active_procs; 489 int i; 490 time_t curr_time; 491 caddr_t processes; 492 struct system_info system_info; 493 char *hdr; 494 495 /* get the time */ 496 time_mark(&(gstate->now)); 497 curr_time = (time_t)(gstate->now.tv_sec); 498 499 /* get the current stats */ 500 get_system_info(&system_info); 501 502 /* get the current processes */ 503 processes = get_process_info(&system_info, &(gstate->pselect), gstate->order_index); 504 505 /* determine number of processes to actually display */ 506 if (gstate->topn > 0) 507 { 508 /* this number will be the smallest of: active processes, 509 number user requested, number current screen accomodates */ 510 active_procs = system_info.P_ACTIVE; 511 if (active_procs > gstate->topn) 512 { 513 active_procs = gstate->topn; 514 } 515 if (active_procs > gstate->max_topn) 516 { 517 active_procs = gstate->max_topn; 518 } 519 } 520 else 521 { 522 /* dont show any */ 523 active_procs = 0; 524 } 525 526 hdr = gstate->header_text; 527 528 /* full screen or update? */ 529 if (gstate->fulldraw) 530 { 531 struct timespec uts; 532 533 clock_gettime(CLOCK_UPTIME, &uts); 534 display_clear(); 535 i_loadave(system_info.last_pid, system_info.load_avg); 536 i_uptime(uts.tv_sec); 537 i_timeofday(&curr_time); 538 i_procstates(system_info.p_total, system_info.procstates, gstate->pselect.threads); 539 if (gstate->show_cpustates) 540 { 541 i_cpustates(system_info.cpustates); 542 } 543 else 544 { 545 if (smart_terminal) 546 { 547 z_cpustates(); 548 } 549 gstate->show_cpustates = Yes; 550 } 551 i_kernel(system_info.kernel); 552 i_memory(system_info.memory); 553 i_swap(system_info.swap); 554 i_message(&(gstate->now)); 555 i_header(hdr); 556 for (i = 0; i < active_procs; i++) 557 { 558 i_process(i, format_next_process(processes, gstate->get_userid)); 559 } 560 i_endscreen(); 561 if (gstate->smart_terminal) 562 { 563 gstate->fulldraw = No; 564 } 565 } 566 else 567 { 568 struct timespec uts; 569 570 clock_gettime(CLOCK_UPTIME, &uts); 571 u_loadave(system_info.last_pid, system_info.load_avg); 572 u_uptime(uts.tv_sec); 573 i_timeofday(&curr_time); 574 u_procstates(system_info.p_total, system_info.procstates, gstate->pselect.threads); 575 u_cpustates(system_info.cpustates); 576 u_kernel(system_info.kernel); 577 u_memory(system_info.memory); 578 u_swap(system_info.swap); 579 u_message(&(gstate->now)); 580 u_header(hdr); 581 for (i = 0; i < active_procs; i++) 582 { 583 u_process(i, format_next_process(processes, gstate->get_userid)); 584 } 585 u_endscreen(); 586 } 587 } 588 589 #ifdef DEBUG 590 void 591 timeval_xdprint(char *s, struct timeval tv) 592 593 { 594 xdprintf("%s %d.%06d\n", s, tv.tv_sec, tv.tv_usec); 595 } 596 #endif 597 598 void 599 do_wait(globalstate *gstate) 600 601 { 602 struct timeval wait; 603 604 wait.tv_sec = gstate->delay; 605 wait.tv_usec = 0; 606 select(0, NULL, NULL, NULL, &wait); 607 } 608 609 void 610 do_command(globalstate *gstate) 611 612 { 613 int status; 614 struct timeval wait = {0, 0}; 615 struct timeval now; 616 fd_set readfds; 617 unsigned char ch; 618 619 /* calculate new refresh time */ 620 gstate->refresh = gstate->now; 621 gstate->refresh.tv_sec += gstate->delay; 622 time_get(&now); 623 624 /* loop waiting for time to expire */ 625 do { 626 /* calculate time to wait */ 627 if (gstate->delay > 0) 628 { 629 wait = gstate->refresh; 630 wait.tv_usec -= now.tv_usec; 631 if (wait.tv_usec < 0) 632 { 633 wait.tv_usec += 1000000; 634 wait.tv_sec--; 635 } 636 wait.tv_sec -= now.tv_sec; 637 } 638 639 /* set up arguments for select on stdin (0) */ 640 FD_ZERO(&readfds); 641 FD_SET(STDIN_FILENO, &readfds); 642 643 /* wait for something to read or time out */ 644 if (select(32, &readfds, NULL, NULL, &wait) > 0) 645 { 646 /* read it */ 647 if (read(STDIN_FILENO, &ch, 1) != 1) 648 { 649 /* read error */ 650 message_error(" Read error on stdin"); 651 quit(EX_DATAERR); 652 /*NOTREACHED*/ 653 } 654 655 /* mark pending messages as old */ 656 message_mark(); 657 658 /* dispatch */ 659 status = command_process(gstate, (int)ch); 660 switch(status) 661 { 662 case CMD_ERROR: 663 quit(EX_SOFTWARE); 664 /*NOTREACHED*/ 665 666 case CMD_REFRESH: 667 return; 668 669 case CMD_UNKNOWN: 670 message_error(" Unknown command"); 671 break; 672 673 case CMD_NA: 674 message_error(" Command not available"); 675 } 676 } 677 678 /* get new time */ 679 time_get(&now); 680 } while (timercmp(&now, &(gstate->refresh), < )); 681 } 682 683 void 684 do_minidisplay(globalstate *gstate) 685 686 { 687 int real_delay; 688 struct system_info si; 689 690 /* save the real delay and substitute 1 second */ 691 real_delay = gstate->delay; 692 gstate->delay = 1; 693 694 /* wait 1 second for a command */ 695 time_mark(&(gstate->now)); 696 do_command(gstate); 697 698 /* do a mini update that only updates the cpustates */ 699 get_system_info(&si); 700 u_cpustates(si.cpustates); 701 702 /* restore the delay time */ 703 gstate->delay = real_delay; 704 705 /* done */ 706 i_endscreen(); 707 } 708 709 int 710 main(int argc, char *argv[]) 711 712 { 713 char *env_top; 714 char **preset_argv; 715 int preset_argc = 0; 716 void *mask; 717 int need_mini = 1; 718 719 struct statics statics; 720 globalstate *gstate; 721 722 /* get our name */ 723 if (argc > 0) 724 { 725 if ((myname = strrchr(argv[0], '/')) == NULL) 726 { 727 myname = argv[0]; 728 } 729 else 730 { 731 myname++; 732 } 733 } 734 735 /* binary compatibility check */ 736 #ifdef HAVE_UNAME 737 { 738 struct utsname uts; 739 740 if (uname(&uts) == 0) 741 { 742 if (strcmp(uts.machine, UNAME_HARDWARE) != 0) 743 { 744 fprintf(stderr, "%s: incompatible hardware platform\n", 745 myname); 746 exit(EX_UNAVAILABLE); 747 } 748 } 749 } 750 #endif 751 752 /* initialization */ 753 gstate = (globalstate *)calloc(1, sizeof(globalstate)); 754 gstate->statics = &statics; 755 time_mark(NULL); 756 757 /* preset defaults for various options */ 758 gstate->show_usernames = Yes; 759 gstate->topn = DEFAULT_TOPN; 760 gstate->delay = DEFAULT_DELAY; 761 gstate->fulldraw = Yes; 762 gstate->use_color = Yes; 763 gstate->interactive = Maybe; 764 765 /* preset defaults for process selection */ 766 gstate->pselect.idle = Yes; 767 gstate->pselect.system = No; 768 gstate->pselect.fullcmd = No; 769 gstate->pselect.command = NULL; 770 gstate->pselect.uid = -1; 771 gstate->pselect.mode = 0; 772 773 /* use a large buffer for stdout */ 774 #ifdef HAVE_SETVBUF 775 setvbuf(stdout, stdoutbuf, _IOFBF, BUFFERSIZE); 776 #else 777 #ifdef HAVE_SETBUFFER 778 setbuffer(stdout, stdoutbuf, BUFFERSIZE); 779 #endif 780 #endif 781 782 /* get preset options from the environment */ 783 if ((env_top = getenv("TOP")) != NULL) 784 { 785 preset_argv = argparse(env_top, &preset_argc); 786 preset_argv[0] = myname; 787 do_arguments(gstate, preset_argc, preset_argv); 788 } 789 790 /* process arguments */ 791 do_arguments(gstate, argc, argv); 792 793 #ifdef ENABLE_COLOR 794 /* If colour has been turned on read in the settings. */ 795 env_top = getenv("TOPCOLOURS"); 796 if (!env_top) 797 { 798 env_top = getenv("TOPCOLORS"); 799 } 800 /* must do something about error messages */ 801 color_env_parse(env_top); 802 color_activate(gstate->use_color); 803 #endif 804 805 /* in order to support forward compatability, we have to ensure that 806 the entire statics structure is set to a known value before we call 807 machine_init. This way fields that a module does not know about 808 will retain their default values */ 809 memzero((void *)&statics, sizeof(statics)); 810 811 /* call the platform-specific init */ 812 if (machine_init(&statics) == -1) 813 { 814 exit(EX_SOFTWARE); 815 } 816 817 /* create a helper list of sort order names */ 818 gstate->order_namelist = string_list(statics.order_names); 819 820 /* look up chosen sorting order */ 821 if (gstate->order_name != NULL) 822 { 823 int i; 824 825 if (statics.order_names == NULL) 826 { 827 message_error(" This platform does not support arbitrary ordering"); 828 } 829 else if ((i = string_index(gstate->order_name, 830 statics.order_names)) == -1) 831 { 832 message_error(" Sort order `%s' not recognized", gstate->order_name); 833 message_error(" Recognized sort orders: %s", gstate->order_namelist); 834 } 835 else 836 { 837 gstate->order_index = i; 838 } 839 } 840 841 /* initialize extensions */ 842 init_username(); 843 844 /* initialize termcap */ 845 gstate->smart_terminal = screen_readtermcap(gstate->interactive); 846 847 /* determine interactive state */ 848 if (gstate->interactive == Maybe) 849 { 850 gstate->interactive = smart_terminal; 851 } 852 853 /* if displays were not specified, choose an appropriate default */ 854 if (gstate->displays == 0) 855 { 856 gstate->displays = gstate->smart_terminal ? Infinity: 1; 857 } 858 859 /* we don't need a mini display when delay is less than 2 860 seconds or when we are not on a smart terminal */ 861 if (gstate->delay <= 1 || !smart_terminal) 862 { 863 need_mini = 0; 864 } 865 866 /* set constants for username/uid display */ 867 if (gstate->show_usernames) 868 { 869 gstate->header_text = format_header("USERNAME"); 870 gstate->get_userid = username; 871 } 872 else 873 { 874 gstate->header_text = format_header(" UID "); 875 gstate->get_userid = itoa7; 876 } 877 gstate->pselect.usernames = gstate->show_usernames; 878 879 /* initialize display */ 880 if ((gstate->max_topn = display_init(&statics)) == -1) 881 { 882 fprintf(stderr, "%s: can't allocate sufficient memory\n", myname); 883 exit(EX_OSERR); 884 } 885 886 /* check for infinity and for overflowed screen */ 887 if (gstate->topn == Infinity) 888 { 889 gstate->topn = INT_MAX; 890 } 891 else if (gstate->topn > gstate->max_topn) 892 { 893 #if 0 894 message_error(" This terminal can only display %d processes", 895 gstate->max_topn); 896 #endif 897 } 898 899 #ifdef ENABLE_COLOR 900 /* producing a list of color tags is easy */ 901 if (gstate->show_tags) 902 { 903 color_dump(stdout); 904 exit(EX_OK); 905 } 906 #endif 907 908 /* hold all signals while we initialize the screen */ 909 mask = hold_signals(); 910 screen_init(); 911 912 /* set the signal handlers */ 913 set_signals(); 914 915 /* longjmp re-entry point */ 916 /* set the jump buffer for long jumps out of signal handlers */ 917 if (setjmp(jmp_int) != 0) 918 { 919 /* this is where we end up after processing sigwinch or sigtstp */ 920 921 /* tell display to resize its buffers, and get the new length */ 922 if ((gstate->max_topn = display_resize()) == -1) 923 { 924 /* thats bad */ 925 quit(EX_OSERR); 926 /*NOTREACHED*/ 927 } 928 929 /* set up for a full redraw, and get the current line count */ 930 gstate->fulldraw = Yes; 931 932 /* safe to release the signals now */ 933 release_signals(mask); 934 } 935 else 936 { 937 /* release the signals */ 938 release_signals(mask); 939 940 /* some systems require a warmup */ 941 /* always do a warmup for batch mode */ 942 if (gstate->interactive == 0 || statics.flags.warmup) 943 { 944 struct system_info system_info; 945 struct timeval timeout; 946 947 time_mark(&(gstate->now)); 948 get_system_info(&system_info); 949 (void)get_process_info(&system_info, &gstate->pselect, 0); 950 timeout.tv_sec = 1; 951 timeout.tv_usec = 0; 952 select(0, NULL, NULL, NULL, &timeout); 953 954 /* if we've warmed up, then we can show good states too */ 955 gstate->show_cpustates = Yes; 956 need_mini = 0; 957 } 958 } 959 960 /* main loop */ 961 while ((gstate->displays == -1) || (--gstate->displays > 0)) 962 { 963 do_display(gstate); 964 if (gstate->interactive) 965 { 966 if (need_mini) 967 { 968 do_minidisplay(gstate); 969 need_mini = 0; 970 } 971 do_command(gstate); 972 } 973 else 974 { 975 do_wait(gstate); 976 } 977 } 978 979 /* do one last display */ 980 do_display(gstate); 981 982 quit(EX_OK); 983 /* NOTREACHED */ 984 return 1; /* Keep compiler quiet. */ 985 } 986