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
usage(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
getorder(char * field)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
filteruser(char buf[])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
filterpid(char buf[],int hl)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
filterrtable(char buf[])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
parseargs(int ac,char ** av)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
main(int argc,char * argv[])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
rundisplay(void)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
reset_display(void)1090 reset_display(void)
1091 {
1092 if (smart_terminal) {
1093 clear();
1094 refresh();
1095 }
1096 }
1097
1098 void
leave(int signo)1099 leave(int signo)
1100 {
1101 leaveflag = 1;
1102 }
1103
1104 void
tstop(int signo)1105 tstop(int signo)
1106 {
1107 tstopflag = 1;
1108 }
1109
1110 void
sigwinch(int signo)1111 sigwinch(int signo)
1112 {
1113 winchflag = 1;
1114 }
1115
1116 void
onalrm(int signo)1117 onalrm(int signo)
1118 {
1119 }
1120
1121 void
quit(int ret)1122 quit(int ret)
1123 {
1124 end_screen();
1125 exit(ret);
1126 }
1127