1 /* $OpenBSD: top.c,v 1.79 2012/06/08 13:41:16 lum Exp $ */ 2 3 /* 4 * Top users/processes display for Unix 5 * Version 3 6 * 7 * Copyright (c) 1984, 1989, William LeFebvre, Rice University 8 * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR OR HIS EMPLOYER BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <sys/types.h> 32 #include <curses.h> 33 #include <err.h> 34 #include <errno.h> 35 #include <stdio.h> 36 #include <signal.h> 37 #include <string.h> 38 #include <poll.h> 39 #include <stdlib.h> 40 #include <limits.h> 41 #include <unistd.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 */ 56 char stdoutbuf[BUFFERSIZE]; 57 58 /* signal handling routines */ 59 static void leave(int); 60 static void onalrm(int); 61 static void tstop(int); 62 static void sigwinch(int); 63 64 volatile sig_atomic_t leaveflag, tstopflag, winchflag; 65 66 static void reset_display(void); 67 int rundisplay(void); 68 69 static int max_topn; /* maximum displayable processes */ 70 71 extern int (*proc_compares[])(const void *, const void *); 72 int order_index; 73 74 int displays = 0; /* indicates unspecified */ 75 char do_unames = Yes; 76 struct process_select ps; 77 char interactive = Maybe; 78 double delay = Default_DELAY; 79 char *order_name = NULL; 80 int topn = Default_TOPN; 81 int no_command = Yes; 82 int old_system = No; 83 int old_threads = No; 84 int show_args = No; 85 pid_t hlpid = -1; 86 int combine_cpus = 0; 87 88 #if Default_TOPN == Infinity 89 char topn_specified = No; 90 #endif 91 92 /* 93 * these defines enumerate the "strchr"s of the commands in 94 * command_chars 95 */ 96 #define CMD_redraw 0 97 #define CMD_update 1 98 #define CMD_quit 2 99 #define CMD_help1 3 100 #define CMD_help2 4 101 #define CMD_OSLIMIT 4 /* terminals with OS can only handle commands */ 102 #define CMD_errors 5 /* less than or equal to CMD_OSLIMIT */ 103 #define CMD_number1 6 104 #define CMD_number2 7 105 #define CMD_delay 8 106 #define CMD_displays 9 107 #define CMD_kill 10 108 #define CMD_renice 11 109 #define CMD_idletog 12 110 #define CMD_idletog2 13 111 #define CMD_user 14 112 #define CMD_system 15 113 #define CMD_order 16 114 #define CMD_pid 17 115 #define CMD_command 18 116 #define CMD_threads 19 117 #define CMD_grep 20 118 #define CMD_add 21 119 #define CMD_hl 22 120 #define CMD_cpus 23 121 122 static void 123 usage(void) 124 { 125 extern char *__progname; 126 127 fprintf(stderr, 128 "usage: %s [-1bCHIinqSu] [-d count] [-g string] [-o field] " 129 "[-p pid] [-s time]\n\t[-U [-]user] [number]\n", 130 __progname); 131 } 132 133 static void 134 parseargs(int ac, char **av) 135 { 136 char *endp; 137 int i; 138 139 while ((i = getopt(ac, av, "1SHICbinqus:d:p:U:o:g:")) != -1) { 140 switch (i) { 141 case '1': 142 combine_cpus = 1; 143 break; 144 case 'C': 145 show_args = Yes; 146 break; 147 case 'u': /* toggle uid/username display */ 148 do_unames = !do_unames; 149 break; 150 151 case 'U': /* display only username's processes */ 152 if (optarg[0] == '-') { 153 if ((ps.huid = userid(optarg+1)) == (uid_t)-1) 154 new_message(MT_delayed, "%s: unknown user", 155 optarg); 156 else 157 ps.uid = (uid_t)-1; 158 } else if ((ps.uid = userid(optarg)) == (uid_t)-1) 159 new_message(MT_delayed, "%s: unknown user", 160 optarg); 161 else 162 ps.huid = (uid_t)-1; 163 break; 164 165 case 'p': { /* display only process id */ 166 const char *errstr; 167 168 i = strtonum(optarg, 0, INT_MAX, &errstr); 169 if (errstr != NULL || !find_pid(i)) 170 new_message(MT_delayed, "%s: unknown pid", 171 optarg); 172 else { 173 ps.pid = (pid_t)i; 174 ps.system = Yes; 175 } 176 break; 177 } 178 179 case 'S': /* show system processes */ 180 ps.system = !ps.system; 181 old_system = !old_system; 182 break; 183 184 case 'H': /* show threads */ 185 ps.threads = Yes; 186 old_threads = Yes; 187 break; 188 189 case 'I': /* show idle processes */ 190 ps.idle = !ps.idle; 191 break; 192 193 case 'i': /* go interactive regardless */ 194 interactive = Yes; 195 break; 196 197 case 'n': /* batch, or non-interactive */ 198 case 'b': 199 interactive = No; 200 break; 201 202 case 'd': /* number of displays to show */ 203 if ((i = atoiwi(optarg)) != Invalid && i != 0) { 204 displays = i; 205 if (displays == 1) 206 interactive = No; 207 break; 208 } 209 new_message(MT_delayed, 210 "warning: display count should be positive " 211 "-- option ignored"); 212 break; 213 214 case 's': 215 delay = strtod(optarg, &endp); 216 217 if (delay >= 0 && delay <= 1000000 && *endp == '\0') 218 break; 219 220 new_message(MT_delayed, 221 "warning: delay should be a non-negative number" 222 " -- using default"); 223 delay = Default_DELAY; 224 break; 225 226 case 'q': /* be quick about it */ 227 /* only allow this if user is really root */ 228 if (getuid() == 0) { 229 /* be very un-nice! */ 230 (void) nice(-20); 231 break; 232 } 233 new_message(MT_delayed, 234 "warning: `-q' option can only be used by root"); 235 break; 236 237 case 'o': /* select sort order */ 238 order_name = optarg; 239 break; 240 241 case 'g': /* grep command name */ 242 free(ps.command); 243 if ((ps.command = strdup(optarg)) == NULL) 244 err(1, NULL); 245 break; 246 247 default: 248 usage(); 249 exit(1); 250 } 251 } 252 253 /* get count of top processes to display (if any) */ 254 if (optind < ac) { 255 if ((topn = atoiwi(av[optind])) == Invalid) { 256 new_message(MT_delayed, 257 "warning: process count should " 258 "be a non-negative number -- using default"); 259 topn = Infinity; 260 } 261 #if Default_TOPN == Infinity 262 else 263 topn_specified = Yes; 264 #endif 265 } 266 } 267 268 struct system_info system_info; 269 struct statics statics; 270 271 int 272 main(int argc, char *argv[]) 273 { 274 char *uname_field = "USERNAME", *header_text, *env_top; 275 char *(*get_userid)(uid_t) = username; 276 char **preset_argv = NULL, **av = argv; 277 int preset_argc = 0, ac = argc, active_procs, i; 278 sigset_t mask, oldmask; 279 time_t curr_time; 280 caddr_t processes; 281 282 /* set the buffer for stdout */ 283 #ifdef DEBUG 284 setbuffer(stdout, NULL, 0); 285 #else 286 setbuffer(stdout, stdoutbuf, sizeof stdoutbuf); 287 #endif 288 289 /* initialize some selection options */ 290 ps.idle = Yes; 291 ps.system = No; 292 ps.uid = (uid_t)-1; 293 ps.huid = (uid_t)-1; 294 ps.pid = (pid_t)-1; 295 ps.command = NULL; 296 297 /* get preset options from the environment */ 298 if ((env_top = getenv("TOP")) != NULL) { 299 av = preset_argv = argparse(env_top, &preset_argc); 300 ac = preset_argc; 301 302 /* 303 * set the dummy argument to an explanatory message, in case 304 * getopt encounters a bad argument 305 */ 306 preset_argv[0] = "while processing environment"; 307 } 308 /* process options */ 309 do { 310 /* 311 * if we're done doing the presets, then process the real 312 * arguments 313 */ 314 if (preset_argc == 0) { 315 ac = argc; 316 av = argv; 317 optind = 1; 318 } 319 parseargs(ac, av); 320 i = preset_argc; 321 preset_argc = 0; 322 } while (i != 0); 323 324 /* set constants for username/uid display correctly */ 325 if (!do_unames) { 326 uname_field = " UID "; 327 get_userid = format_uid; 328 } 329 /* initialize the kernel memory interface */ 330 if (machine_init(&statics) == -1) 331 exit(1); 332 333 /* determine sorting order index, if necessary */ 334 if (order_name != NULL) { 335 if ((order_index = string_index(order_name, 336 statics.order_names)) == -1) { 337 char **pp, msg[512]; 338 339 snprintf(msg, sizeof(msg), 340 "'%s' is not a recognized sorting order", 341 order_name); 342 strlcat(msg, ". Valid are:", sizeof(msg)); 343 pp = statics.order_names; 344 while (*pp != NULL) { 345 strlcat(msg, " ", sizeof(msg)); 346 strlcat(msg, *pp++, sizeof(msg)); 347 } 348 new_message(MT_delayed, msg); 349 order_index = 0; 350 } 351 } 352 353 /* initialize termcap */ 354 init_termcap(interactive); 355 356 /* get the string to use for the process area header */ 357 header_text = format_header(uname_field); 358 359 /* initialize display interface */ 360 max_topn = display_init(&statics); 361 362 /* print warning if user requested more processes than we can display */ 363 if (topn > max_topn) 364 new_message(MT_delayed, 365 "warning: this terminal can only display %d processes", 366 max_topn); 367 /* adjust for topn == Infinity */ 368 if (topn == Infinity) { 369 /* 370 * For smart terminals, infinity really means everything that can 371 * be displayed, or Largest. 372 * On dumb terminals, infinity means every process in the system! 373 * We only really want to do that if it was explicitly specified. 374 * This is always the case when "Default_TOPN != Infinity". But if 375 * topn wasn't explicitly specified and we are on a dumb terminal 376 * and the default is Infinity, then (and only then) we use 377 * "Nominal_TOPN" instead. 378 */ 379 #if Default_TOPN == Infinity 380 topn = smart_terminal ? Largest : 381 (topn_specified ? Largest : Nominal_TOPN); 382 #else 383 topn = Largest; 384 #endif 385 } 386 /* set header display accordingly */ 387 display_header(topn > 0); 388 389 /* determine interactive state */ 390 if (interactive == Maybe) 391 interactive = smart_terminal; 392 393 /* if # of displays not specified, fill it in */ 394 if (displays == 0) 395 displays = smart_terminal ? Infinity : 1; 396 397 /* 398 * block interrupt signals while setting up the screen and the 399 * handlers 400 */ 401 sigemptyset(&mask); 402 sigaddset(&mask, SIGINT); 403 sigaddset(&mask, SIGQUIT); 404 sigaddset(&mask, SIGTSTP); 405 sigprocmask(SIG_BLOCK, &mask, &oldmask); 406 if (interactive) 407 init_screen(); 408 (void) signal(SIGINT, leave); 409 siginterrupt(SIGINT, 1); 410 (void) signal(SIGQUIT, leave); 411 (void) signal(SIGTSTP, tstop); 412 if (smart_terminal) 413 (void) signal(SIGWINCH, sigwinch); 414 sigprocmask(SIG_SETMASK, &oldmask, NULL); 415 restart: 416 417 /* 418 * main loop -- repeat while display count is positive or while it 419 * indicates infinity (by being -1) 420 */ 421 while ((displays == -1) || (displays-- > 0)) { 422 if (winchflag) { 423 /* 424 * reascertain the screen 425 * dimensions 426 */ 427 get_screensize(); 428 resizeterm(screen_length, screen_width + 1); 429 430 /* tell display to resize */ 431 max_topn = display_resize(); 432 433 /* reset the signal handler */ 434 (void) signal(SIGWINCH, sigwinch); 435 436 reset_display(); 437 winchflag = 0; 438 } 439 440 /* get the current stats */ 441 get_system_info(&system_info); 442 443 /* get the current set of processes */ 444 processes = get_process_info(&system_info, &ps, 445 proc_compares[order_index]); 446 447 /* display the load averages */ 448 i_loadave(system_info.last_pid, system_info.load_avg); 449 450 /* display the current time */ 451 /* this method of getting the time SHOULD be fairly portable */ 452 time(&curr_time); 453 i_timeofday(&curr_time); 454 455 /* display process state breakdown */ 456 i_procstates(system_info.p_total, system_info.procstates); 457 458 /* display the cpu state percentage breakdown */ 459 i_cpustates(system_info.cpustates); 460 461 /* display memory stats */ 462 i_memory(system_info.memory); 463 464 /* handle message area */ 465 i_message(); 466 467 /* update the header area */ 468 i_header(header_text); 469 470 if (topn == Infinity) { 471 #if Default_TOPN == Infinity 472 topn = smart_terminal ? Largest : 473 (topn_specified ? Largest : Nominal_TOPN); 474 #else 475 topn = Largest; 476 #endif 477 } 478 479 if (topn > 0) { 480 /* determine number of processes to actually display */ 481 /* 482 * this number will be the smallest of: active 483 * processes, number user requested, number current 484 * screen accommodates 485 */ 486 active_procs = system_info.p_active; 487 if (active_procs > topn) 488 active_procs = topn; 489 if (active_procs > max_topn) 490 active_procs = max_topn; 491 /* now show the top "n" processes. */ 492 for (i = 0; i < active_procs; i++) { 493 pid_t pid; 494 char * s; 495 496 s = format_next_process(processes, get_userid, 497 &pid); 498 i_process(i, s, pid == hlpid); 499 } 500 } 501 502 /* do end-screen processing */ 503 u_endscreen(); 504 505 /* now, flush the output buffer */ 506 fflush(stdout); 507 508 if (smart_terminal) 509 refresh(); 510 511 /* only do the rest if we have more displays to show */ 512 if (displays) { 513 /* switch out for new display on smart terminals */ 514 no_command = Yes; 515 if (!interactive) { 516 /* set up alarm */ 517 (void) signal(SIGALRM, onalrm); 518 (void) alarm((unsigned) delay); 519 520 /* wait for the rest of it .... */ 521 pause(); 522 if (leaveflag) 523 exit(0); 524 if (tstopflag) { 525 (void) signal(SIGTSTP, SIG_DFL); 526 (void) kill(0, SIGTSTP); 527 /* reset the signal handler */ 528 (void) signal(SIGTSTP, tstop); 529 tstopflag = 0; 530 } 531 } else { 532 while (no_command) 533 if (rundisplay()) 534 goto restart; 535 } 536 } 537 } 538 539 quit(0); 540 /* NOTREACHED */ 541 return (0); 542 } 543 544 int 545 rundisplay(void) 546 { 547 static char tempbuf[TEMPBUFSIZE]; 548 sigset_t mask; 549 char ch, *iptr; 550 int change, i; 551 struct pollfd pfd[1]; 552 uid_t uid, huid; 553 static char command_chars[] = "\f qh?en#sdkriIuSopCHg+P1"; 554 555 /* 556 * assume valid command unless told 557 * otherwise 558 */ 559 no_command = No; 560 561 /* 562 * set up arguments for select with 563 * timeout 564 */ 565 pfd[0].fd = STDIN_FILENO; 566 pfd[0].events = POLLIN; 567 568 if (leaveflag) 569 quit(0); 570 if (tstopflag) { 571 /* move to the lower left */ 572 end_screen(); 573 fflush(stdout); 574 575 /* 576 * default the signal handler 577 * action 578 */ 579 (void) signal(SIGTSTP, SIG_DFL); 580 581 /* 582 * unblock the signal and 583 * send ourselves one 584 */ 585 sigemptyset(&mask); 586 sigaddset(&mask, SIGTSTP); 587 sigprocmask(SIG_UNBLOCK, &mask, NULL); 588 (void) kill(0, SIGTSTP); 589 590 /* reset the signal handler */ 591 (void) signal(SIGTSTP, tstop); 592 593 /* reinit screen */ 594 reinit_screen(); 595 reset_display(); 596 tstopflag = 0; 597 return 1; 598 } 599 /* 600 * wait for either input or the end 601 * of the delay period 602 */ 603 if (poll(pfd, 1, (int)(delay * 1000)) > 0 && 604 !(pfd[0].revents & (POLLERR|POLLHUP|POLLNVAL))) { 605 char *errmsg; 606 ssize_t len; 607 608 clear_message(); 609 610 /* 611 * now read it and convert to 612 * command strchr 613 */ 614 while (1) { 615 len = read(STDIN_FILENO, &ch, 1); 616 if (len == -1 && errno == EINTR) 617 continue; 618 if (len == 0) 619 exit(1); 620 break; 621 } 622 if ((iptr = strchr(command_chars, ch)) == NULL) { 623 /* illegal command */ 624 new_message(MT_standout, " Command not understood"); 625 putr(); 626 no_command = Yes; 627 fflush(stdout); 628 return (0); 629 } 630 631 change = iptr - command_chars; 632 633 switch (change) { 634 case CMD_redraw: /* redraw screen */ 635 reset_display(); 636 break; 637 638 case CMD_update: /* merely update display */ 639 /* 640 * is the load average high? 641 */ 642 if (system_info.load_avg[0] > LoadMax) { 643 /* yes, go home for visual feedback */ 644 go_home(); 645 fflush(stdout); 646 } 647 break; 648 649 case CMD_quit: /* quit */ 650 quit(0); 651 break; 652 653 case CMD_help1: /* help */ 654 case CMD_help2: 655 clear(); 656 show_help(); 657 anykey(); 658 clear(); 659 break; 660 661 case CMD_errors: /* show errors */ 662 if (error_count() == 0) { 663 new_message(MT_standout, 664 " Currently no errors to report."); 665 putr(); 666 no_command = Yes; 667 } else { 668 clear(); 669 show_errors(); 670 anykey(); 671 clear(); 672 } 673 break; 674 675 case CMD_number1: /* new number */ 676 case CMD_number2: 677 new_message(MT_standout, 678 "Number of processes to show: "); 679 680 if (readline(tempbuf, 8) > 0) { 681 if ((i = atoiwi(tempbuf)) != Invalid) { 682 if (i > max_topn) { 683 new_message(MT_standout | 684 MT_delayed, 685 " This terminal can only " 686 "display %d processes.", 687 max_topn); 688 putr(); 689 } 690 if ((i > topn || i == Infinity) 691 && topn == 0) { 692 /* redraw the header */ 693 display_header(Yes); 694 } else if (i == 0) 695 display_header(No); 696 topn = i; 697 } else { 698 new_message(MT_standout, 699 "Processes should be a " 700 "non-negative number"); 701 putr(); 702 no_command = Yes; 703 } 704 } else 705 clear_message(); 706 break; 707 708 case CMD_delay: /* new seconds delay */ 709 new_message(MT_standout, "Seconds to delay: "); 710 if (readline(tempbuf, sizeof(tempbuf)) > 0) { 711 char *endp; 712 double newdelay = strtod(tempbuf, &endp); 713 714 if (newdelay >= 0 && newdelay <= 1000000 && 715 *endp == '\0') { 716 delay = newdelay; 717 } else { 718 new_message(MT_standout, 719 "Delay should be a non-negative number"); 720 putr(); 721 no_command = Yes; 722 } 723 724 } else 725 clear_message(); 726 break; 727 728 case CMD_displays: /* change display count */ 729 new_message(MT_standout, 730 "Displays to show (currently %s): ", 731 displays == -1 ? "infinite" : 732 itoa(displays)); 733 734 if (readline(tempbuf, 10) > 0) { 735 if ((i = atoiwi(tempbuf)) != Invalid) { 736 if (i == 0) 737 quit(0); 738 displays = i; 739 } else { 740 new_message(MT_standout, 741 "Displays should be a non-negative number"); 742 putr(); 743 no_command = Yes; 744 } 745 } else 746 clear_message(); 747 break; 748 749 case CMD_kill: /* kill program */ 750 new_message(0, "kill "); 751 if (readline(tempbuf, sizeof(tempbuf)) > 0) { 752 if ((errmsg = kill_procs(tempbuf)) != NULL) { 753 new_message(MT_standout, "%s", errmsg); 754 putr(); 755 no_command = Yes; 756 } 757 } else 758 clear_message(); 759 break; 760 761 case CMD_renice: /* renice program */ 762 new_message(0, "renice "); 763 if (readline(tempbuf, sizeof(tempbuf)) > 0) { 764 if ((errmsg = renice_procs(tempbuf)) != NULL) { 765 new_message(MT_standout, "%s", errmsg); 766 putr(); 767 no_command = Yes; 768 } 769 } else 770 clear_message(); 771 break; 772 773 case CMD_idletog: 774 case CMD_idletog2: 775 ps.idle = !ps.idle; 776 new_message(MT_standout | MT_delayed, 777 " %sisplaying idle processes.", 778 ps.idle ? "D" : "Not d"); 779 putr(); 780 break; 781 782 case CMD_user: 783 new_message(MT_standout, 784 "Username to show: "); 785 if (readline(tempbuf, sizeof(tempbuf)) > 0) { 786 if ((tempbuf[0] == '+' || tempbuf[0] == '-') && 787 tempbuf[1] == '\0') { 788 ps.uid = (uid_t)-1; 789 ps.huid = (uid_t)-1; 790 } else if (tempbuf[0] == '-') { 791 if ((huid = userid(tempbuf+1)) == (uid_t)-1) { 792 new_message(MT_standout, 793 " %s: unknown user", tempbuf+1); 794 no_command = Yes; 795 } else { 796 ps.huid = huid; 797 ps.uid = (uid_t)-1; 798 } 799 } else if ((uid = userid(tempbuf)) == (uid_t)-1) { 800 new_message(MT_standout, 801 " %s: unknown user", tempbuf); 802 no_command = Yes; 803 } else { 804 ps.uid = uid; 805 ps.huid = (uid_t)-1; 806 } 807 putr(); 808 } else 809 clear_message(); 810 break; 811 812 case CMD_system: 813 ps.system = !ps.system; 814 old_system = ps.system; 815 new_message(MT_standout | MT_delayed, 816 " %sisplaying system processes.", 817 ps.system ? "D" : "Not d"); 818 break; 819 820 case CMD_order: 821 new_message(MT_standout, 822 "Order to sort: "); 823 if (readline(tempbuf, sizeof(tempbuf)) > 0) { 824 if ((i = string_index(tempbuf, 825 statics.order_names)) == -1) { 826 new_message(MT_standout, 827 " %s: unrecognized sorting order", 828 tempbuf); 829 no_command = Yes; 830 } else 831 order_index = i; 832 putr(); 833 } else 834 clear_message(); 835 break; 836 837 case CMD_pid: 838 new_message(MT_standout, "Process ID to show: "); 839 if (readline(tempbuf, sizeof(tempbuf)) > 0) { 840 if (tempbuf[0] == '+' && 841 tempbuf[1] == '\0') { 842 ps.pid = (pid_t)-1; 843 ps.system = old_system; 844 } else { 845 unsigned long long num; 846 const char *errstr; 847 848 num = strtonum(tempbuf, 0, INT_MAX, 849 &errstr); 850 if (errstr != NULL || !find_pid(num)) { 851 new_message(MT_standout, 852 " %s: unknown pid", 853 tempbuf); 854 no_command = Yes; 855 } else { 856 if (ps.system == No) 857 old_system = No; 858 ps.pid = (pid_t)num; 859 ps.system = Yes; 860 } 861 } 862 putr(); 863 } else 864 clear_message(); 865 break; 866 867 case CMD_command: 868 show_args = (show_args == No) ? Yes : No; 869 break; 870 871 case CMD_threads: 872 ps.threads = !ps.threads; 873 old_threads = ps.threads; 874 new_message(MT_standout | MT_delayed, 875 " %sisplaying threads.", 876 ps.threads ? "D" : "Not d"); 877 break; 878 879 case CMD_grep: 880 new_message(MT_standout, 881 "Grep command name: "); 882 if (readline(tempbuf, sizeof(tempbuf)) > 0) { 883 free(ps.command); 884 if (tempbuf[0] == '+' && 885 tempbuf[1] == '\0') 886 ps.command = NULL; 887 else 888 if ((ps.command = strdup(tempbuf)) == 889 NULL) 890 err(1, NULL); 891 putr(); 892 } else 893 clear_message(); 894 break; 895 896 case CMD_hl: 897 new_message(MT_standout, "Process ID to highlight: "); 898 if (readline(tempbuf, sizeof(tempbuf)) > 0) { 899 if (tempbuf[0] == '+' && 900 tempbuf[1] == '\0') { 901 hlpid = -1; 902 } else { 903 unsigned long long num; 904 const char *errstr; 905 906 num = strtonum(tempbuf, 0, INT_MAX, 907 &errstr); 908 if (errstr != NULL || !find_pid(num)) { 909 new_message(MT_standout, 910 " %s: unknown pid", 911 tempbuf); 912 no_command = Yes; 913 } else 914 hlpid = (pid_t)num; 915 } 916 putr(); 917 } else 918 clear_message(); 919 break; 920 921 case CMD_add: 922 ps.uid = (uid_t)-1; /* uid */ 923 ps.huid = (uid_t)-1; 924 ps.pid = (pid_t)-1; /* pid */ 925 ps.system = old_system; 926 ps.command = NULL; /* grep */ 927 hlpid = -1; 928 break; 929 case CMD_cpus: 930 combine_cpus = !combine_cpus; 931 max_topn = display_resize(); 932 reset_display(); 933 break; 934 default: 935 new_message(MT_standout, " BAD CASE IN SWITCH!"); 936 putr(); 937 } 938 } 939 940 /* flush out stuff that may have been written */ 941 fflush(stdout); 942 return 0; 943 } 944 945 946 /* 947 * reset_display() - reset all the display routine pointers so that entire 948 * screen will get redrawn. 949 */ 950 static void 951 reset_display(void) 952 { 953 if (smart_terminal) { 954 clear(); 955 refresh(); 956 } 957 } 958 959 /* ARGSUSED */ 960 void 961 leave(int signo) 962 { 963 leaveflag = 1; 964 } 965 966 /* ARGSUSED */ 967 void 968 tstop(int signo) 969 { 970 tstopflag = 1; 971 } 972 973 /* ARGSUSED */ 974 void 975 sigwinch(int signo) 976 { 977 winchflag = 1; 978 } 979 980 /* ARGSUSED */ 981 void 982 onalrm(int signo) 983 { 984 } 985 986 void 987 quit(int ret) 988 { 989 end_screen(); 990 exit(ret); 991 } 992