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