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