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