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 display_clear(); 532 i_loadave(system_info.last_pid, system_info.load_avg); 533 i_uptime(&(gstate->statics->boottime), &curr_time); 534 i_timeofday(&curr_time); 535 i_procstates(system_info.p_total, system_info.procstates, gstate->pselect.threads); 536 if (gstate->show_cpustates) 537 { 538 i_cpustates(system_info.cpustates); 539 } 540 else 541 { 542 if (smart_terminal) 543 { 544 z_cpustates(); 545 } 546 gstate->show_cpustates = Yes; 547 } 548 i_kernel(system_info.kernel); 549 i_memory(system_info.memory); 550 i_swap(system_info.swap); 551 i_message(&(gstate->now)); 552 i_header(hdr); 553 for (i = 0; i < active_procs; i++) 554 { 555 i_process(i, format_next_process(processes, gstate->get_userid)); 556 } 557 i_endscreen(); 558 if (gstate->smart_terminal) 559 { 560 gstate->fulldraw = No; 561 } 562 } 563 else 564 { 565 u_loadave(system_info.last_pid, system_info.load_avg); 566 u_uptime(&(gstate->statics->boottime), &curr_time); 567 i_timeofday(&curr_time); 568 u_procstates(system_info.p_total, system_info.procstates, gstate->pselect.threads); 569 u_cpustates(system_info.cpustates); 570 u_kernel(system_info.kernel); 571 u_memory(system_info.memory); 572 u_swap(system_info.swap); 573 u_message(&(gstate->now)); 574 u_header(hdr); 575 for (i = 0; i < active_procs; i++) 576 { 577 u_process(i, format_next_process(processes, gstate->get_userid)); 578 } 579 u_endscreen(); 580 } 581 } 582 583 #ifdef DEBUG 584 void 585 timeval_xdprint(char *s, struct timeval tv) 586 587 { 588 xdprintf("%s %d.%06d\n", s, tv.tv_sec, tv.tv_usec); 589 } 590 #endif 591 592 void 593 do_wait(globalstate *gstate) 594 595 { 596 struct timeval wait; 597 598 wait.tv_sec = gstate->delay; 599 wait.tv_usec = 0; 600 select(0, NULL, NULL, NULL, &wait); 601 } 602 603 void 604 do_command(globalstate *gstate) 605 606 { 607 int status; 608 struct timeval wait = {0, 0}; 609 struct timeval now; 610 fd_set readfds; 611 unsigned char ch; 612 613 /* calculate new refresh time */ 614 gstate->refresh = gstate->now; 615 gstate->refresh.tv_sec += gstate->delay; 616 time_get(&now); 617 618 /* loop waiting for time to expire */ 619 do { 620 /* calculate time to wait */ 621 if (gstate->delay > 0) 622 { 623 wait = gstate->refresh; 624 wait.tv_usec -= now.tv_usec; 625 if (wait.tv_usec < 0) 626 { 627 wait.tv_usec += 1000000; 628 wait.tv_sec--; 629 } 630 wait.tv_sec -= now.tv_sec; 631 } 632 633 /* set up arguments for select on stdin (0) */ 634 FD_ZERO(&readfds); 635 FD_SET(STDIN_FILENO, &readfds); 636 637 /* wait for something to read or time out */ 638 if (select(32, &readfds, NULL, NULL, &wait) > 0) 639 { 640 /* read it */ 641 if (read(STDIN_FILENO, &ch, 1) != 1) 642 { 643 /* read error */ 644 message_error(" Read error on stdin"); 645 quit(EX_DATAERR); 646 /*NOTREACHED*/ 647 } 648 649 /* mark pending messages as old */ 650 message_mark(); 651 652 /* dispatch */ 653 status = command_process(gstate, (int)ch); 654 switch(status) 655 { 656 case CMD_ERROR: 657 quit(EX_SOFTWARE); 658 /*NOTREACHED*/ 659 660 case CMD_REFRESH: 661 return; 662 663 case CMD_UNKNOWN: 664 message_error(" Unknown command"); 665 break; 666 667 case CMD_NA: 668 message_error(" Command not available"); 669 } 670 } 671 672 /* get new time */ 673 time_get(&now); 674 } while (timercmp(&now, &(gstate->refresh), < )); 675 } 676 677 void 678 do_minidisplay(globalstate *gstate) 679 680 { 681 int real_delay; 682 struct system_info si; 683 684 /* save the real delay and substitute 1 second */ 685 real_delay = gstate->delay; 686 gstate->delay = 1; 687 688 /* wait 1 second for a command */ 689 time_mark(&(gstate->now)); 690 do_command(gstate); 691 692 /* do a mini update that only updates the cpustates */ 693 get_system_info(&si); 694 u_cpustates(si.cpustates); 695 696 /* restore the delay time */ 697 gstate->delay = real_delay; 698 699 /* done */ 700 i_endscreen(); 701 } 702 703 int 704 main(int argc, char *argv[]) 705 706 { 707 char *env_top; 708 char **preset_argv; 709 int preset_argc = 0; 710 void *mask; 711 int need_mini = 1; 712 713 struct statics statics; 714 globalstate *gstate; 715 716 /* get our name */ 717 if (argc > 0) 718 { 719 if ((myname = strrchr(argv[0], '/')) == 0) 720 { 721 myname = argv[0]; 722 } 723 else 724 { 725 myname++; 726 } 727 } 728 729 /* binary compatibility check */ 730 #ifdef HAVE_UNAME 731 { 732 struct utsname uts; 733 734 if (uname(&uts) == 0) 735 { 736 if (strcmp(uts.machine, UNAME_HARDWARE) != 0) 737 { 738 fprintf(stderr, "%s: incompatible hardware platform\n", 739 myname); 740 exit(EX_UNAVAILABLE); 741 } 742 } 743 } 744 #endif 745 746 /* initialization */ 747 gstate = (globalstate *)calloc(1, sizeof(globalstate)); 748 gstate->statics = &statics; 749 time_mark(NULL); 750 751 /* preset defaults for various options */ 752 gstate->show_usernames = Yes; 753 gstate->topn = DEFAULT_TOPN; 754 gstate->delay = DEFAULT_DELAY; 755 gstate->fulldraw = Yes; 756 gstate->use_color = Yes; 757 gstate->interactive = Maybe; 758 759 /* preset defaults for process selection */ 760 gstate->pselect.idle = Yes; 761 gstate->pselect.system = No; 762 gstate->pselect.fullcmd = No; 763 gstate->pselect.command = NULL; 764 gstate->pselect.uid = -1; 765 gstate->pselect.mode = 0; 766 767 /* use a large buffer for stdout */ 768 #ifdef HAVE_SETVBUF 769 setvbuf(stdout, stdoutbuf, _IOFBF, BUFFERSIZE); 770 #else 771 #ifdef HAVE_SETBUFFER 772 setbuffer(stdout, stdoutbuf, BUFFERSIZE); 773 #endif 774 #endif 775 776 /* get preset options from the environment */ 777 if ((env_top = getenv("TOP")) != NULL) 778 { 779 preset_argv = argparse(env_top, &preset_argc); 780 preset_argv[0] = myname; 781 do_arguments(gstate, preset_argc, preset_argv); 782 } 783 784 /* process arguments */ 785 do_arguments(gstate, argc, argv); 786 787 #ifdef ENABLE_COLOR 788 /* If colour has been turned on read in the settings. */ 789 env_top = getenv("TOPCOLOURS"); 790 if (!env_top) 791 { 792 env_top = getenv("TOPCOLORS"); 793 } 794 /* must do something about error messages */ 795 color_env_parse(env_top); 796 color_activate(gstate->use_color); 797 #endif 798 799 /* in order to support forward compatability, we have to ensure that 800 the entire statics structure is set to a known value before we call 801 machine_init. This way fields that a module does not know about 802 will retain their default values */ 803 memzero((void *)&statics, sizeof(statics)); 804 statics.boottime = -1; 805 806 /* call the platform-specific init */ 807 if (machine_init(&statics) == -1) 808 { 809 exit(EX_SOFTWARE); 810 } 811 812 /* create a helper list of sort order names */ 813 gstate->order_namelist = string_list(statics.order_names); 814 815 /* look up chosen sorting order */ 816 if (gstate->order_name != NULL) 817 { 818 int i; 819 820 if (statics.order_names == NULL) 821 { 822 message_error(" This platform does not support arbitrary ordering"); 823 } 824 else if ((i = string_index(gstate->order_name, 825 statics.order_names)) == -1) 826 { 827 message_error(" Sort order `%s' not recognized", gstate->order_name); 828 message_error(" Recognized sort orders: %s", gstate->order_namelist); 829 } 830 else 831 { 832 gstate->order_index = i; 833 } 834 } 835 836 /* initialize extensions */ 837 init_username(); 838 839 /* initialize termcap */ 840 gstate->smart_terminal = screen_readtermcap(gstate->interactive); 841 842 /* determine interactive state */ 843 if (gstate->interactive == Maybe) 844 { 845 gstate->interactive = smart_terminal; 846 } 847 848 /* if displays were not specified, choose an appropriate default */ 849 if (gstate->displays == 0) 850 { 851 gstate->displays = gstate->smart_terminal ? Infinity: 1; 852 } 853 854 /* we don't need a mini display when delay is less than 2 855 seconds or when we are not on a smart terminal */ 856 if (gstate->delay <= 1 || !smart_terminal) 857 { 858 need_mini = 0; 859 } 860 861 /* set constants for username/uid display */ 862 if (gstate->show_usernames) 863 { 864 gstate->header_text = format_header("USERNAME"); 865 gstate->get_userid = username; 866 } 867 else 868 { 869 gstate->header_text = format_header(" UID "); 870 gstate->get_userid = itoa7; 871 } 872 gstate->pselect.usernames = gstate->show_usernames; 873 874 /* initialize display */ 875 if ((gstate->max_topn = display_init(&statics)) == -1) 876 { 877 fprintf(stderr, "%s: can't allocate sufficient memory\n", myname); 878 exit(EX_OSERR); 879 } 880 881 /* check for infinity and for overflowed screen */ 882 if (gstate->topn == Infinity) 883 { 884 gstate->topn = INT_MAX; 885 } 886 else if (gstate->topn > gstate->max_topn) 887 { 888 #if 0 889 message_error(" This terminal can only display %d processes", 890 gstate->max_topn); 891 #endif 892 } 893 894 #ifdef ENABLE_COLOR 895 /* producing a list of color tags is easy */ 896 if (gstate->show_tags) 897 { 898 color_dump(stdout); 899 exit(EX_OK); 900 } 901 #endif 902 903 /* hold all signals while we initialize the screen */ 904 mask = hold_signals(); 905 screen_init(); 906 907 /* set the signal handlers */ 908 set_signals(); 909 910 /* longjmp re-entry point */ 911 /* set the jump buffer for long jumps out of signal handlers */ 912 if (setjmp(jmp_int) != 0) 913 { 914 /* this is where we end up after processing sigwinch or sigtstp */ 915 916 /* tell display to resize its buffers, and get the new length */ 917 if ((gstate->max_topn = display_resize()) == -1) 918 { 919 /* thats bad */ 920 quit(EX_OSERR); 921 /*NOTREACHED*/ 922 } 923 924 /* set up for a full redraw, and get the current line count */ 925 gstate->fulldraw = Yes; 926 927 /* safe to release the signals now */ 928 release_signals(mask); 929 } 930 else 931 { 932 /* release the signals */ 933 release_signals(mask); 934 935 /* some systems require a warmup */ 936 /* always do a warmup for batch mode */ 937 if (gstate->interactive == 0 || statics.flags.warmup) 938 { 939 struct system_info system_info; 940 struct timeval timeout; 941 942 time_mark(&(gstate->now)); 943 get_system_info(&system_info); 944 (void)get_process_info(&system_info, &gstate->pselect, 0); 945 timeout.tv_sec = 1; 946 timeout.tv_usec = 0; 947 select(0, NULL, NULL, NULL, &timeout); 948 949 /* if we've warmed up, then we can show good states too */ 950 gstate->show_cpustates = Yes; 951 need_mini = 0; 952 } 953 } 954 955 /* main loop */ 956 while ((gstate->displays == -1) || (--gstate->displays > 0)) 957 { 958 do_display(gstate); 959 if (gstate->interactive) 960 { 961 if (need_mini) 962 { 963 do_minidisplay(gstate); 964 need_mini = 0; 965 } 966 do_command(gstate); 967 } 968 else 969 { 970 do_wait(gstate); 971 } 972 } 973 974 /* do one last display */ 975 do_display(gstate); 976 977 quit(EX_OK); 978 /* NOTREACHED */ 979 return 1; /* Keep compiler quiet. */ 980 } 981