GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/top/top.c Lines: 0 420 0.0 %
Date: 2017-11-07 Branches: 0 332 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: top.c,v 1.89 2017/03/15 04:24: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 [-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
	setvbuf(stdout, NULL, _IONBUF, 0);
292
#else
293
	setvbuf(stdout, stdoutbuf, _IOFBF, 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
	if (pledge("stdio rpath getpw tty proc ps vminfo flock cpath wpath", NULL) == -1)
332
		err(1, "pledge");
333
334
	/* set constants for username/uid display correctly */
335
	if (!do_unames) {
336
		uname_field = "   UID  ";
337
		get_userid = format_uid;
338
	}
339
	/* initialize the kernel memory interface */
340
	if (machine_init(&statics) == -1)
341
		exit(1);
342
343
	/* determine sorting order index, if necessary */
344
	if (order_name != NULL) {
345
		if ((order_index = string_index(order_name,
346
		    statics.order_names)) == -1) {
347
			char **pp, msg[512];
348
349
			snprintf(msg, sizeof(msg),
350
			    "'%s' is not a recognized sorting order",
351
			    order_name);
352
			strlcat(msg, ". Valid are:", sizeof(msg));
353
			pp = statics.order_names;
354
			while (*pp != NULL) {
355
				strlcat(msg, " ", sizeof(msg));
356
				strlcat(msg, *pp++, sizeof(msg));
357
			}
358
			new_message(MT_delayed, msg);
359
			order_index = 0;
360
		}
361
	}
362
363
	/* initialize termcap */
364
	init_termcap(interactive);
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
		/* get the string to use for the process area header */
476
		header_text = format_header(uname_field, ps.threads);
477
478
		/* update the header area */
479
		i_header(header_text);
480
481
		if (topn == Infinity) {
482
#if Default_TOPN == Infinity
483
			topn = smart_terminal ? Largest :
484
			    (topn_specified ? Largest : Nominal_TOPN);
485
#else
486
			topn = Largest;
487
#endif
488
		}
489
490
		if (topn > 0) {
491
			/* determine number of processes to actually display */
492
			/*
493
			 * this number will be the smallest of:  active
494
			 * processes, number user requested, number current
495
			 * screen accommodates
496
			 */
497
			active_procs = system_info.p_active;
498
			if (active_procs > topn)
499
				active_procs = topn;
500
			if (active_procs > max_topn)
501
				active_procs = max_topn;
502
			/* now show the top "n" processes. */
503
			for (i = 0; i < active_procs; i++) {
504
				pid_t pid;
505
				char * s;
506
507
				s = format_next_process(processes, get_userid,
508
				    &pid, ps.threads);
509
				i_process(i, s, pid == hlpid);
510
			}
511
		}
512
513
		/* do end-screen processing */
514
		u_endscreen();
515
516
		/* now, flush the output buffer */
517
		fflush(stdout);
518
519
		if (smart_terminal)
520
			refresh();
521
522
		/* only do the rest if we have more displays to show */
523
		if (displays) {
524
			/* switch out for new display on smart terminals */
525
			no_command = Yes;
526
			if (!interactive) {
527
				/* set up alarm */
528
				(void) signal(SIGALRM, onalrm);
529
				(void) alarm((unsigned) delay);
530
531
				/* wait for the rest of it .... */
532
				pause();
533
				if (leaveflag)
534
					exit(0);
535
				if (tstopflag) {
536
					(void) signal(SIGTSTP, SIG_DFL);
537
					(void) kill(0, SIGTSTP);
538
					/* reset the signal handler */
539
					(void) signal(SIGTSTP, tstop);
540
					tstopflag = 0;
541
				}
542
			} else {
543
				while (no_command)
544
					if (rundisplay())
545
						goto restart;
546
			}
547
		}
548
	}
549
550
	quit(0);
551
	/* NOTREACHED */
552
	return (0);
553
}
554
555
int
556
rundisplay(void)
557
{
558
	static char tempbuf[TEMPBUFSIZE];
559
	sigset_t mask;
560
	char ch, *iptr;
561
	int change, i;
562
	struct pollfd pfd[1];
563
	uid_t uid, huid;
564
	static char command_chars[] = "\f qh?en#sdkriIuSopCHg+P1";
565
566
	/*
567
	 * assume valid command unless told
568
	 * otherwise
569
	 */
570
	no_command = No;
571
572
	/*
573
	 * set up arguments for select with
574
	 * timeout
575
	 */
576
	pfd[0].fd = STDIN_FILENO;
577
	pfd[0].events = POLLIN;
578
579
	if (leaveflag)
580
		quit(0);
581
	if (tstopflag) {
582
		/* move to the lower left */
583
		end_screen();
584
		fflush(stdout);
585
586
		/*
587
		 * default the signal handler
588
		 * action
589
		 */
590
		(void) signal(SIGTSTP, SIG_DFL);
591
592
		/*
593
		 * unblock the signal and
594
		 * send ourselves one
595
		 */
596
		sigemptyset(&mask);
597
		sigaddset(&mask, SIGTSTP);
598
		sigprocmask(SIG_UNBLOCK, &mask, NULL);
599
		(void) kill(0, SIGTSTP);
600
601
		/* reset the signal handler */
602
		(void) signal(SIGTSTP, tstop);
603
604
		/* reinit screen */
605
		reinit_screen();
606
		reset_display();
607
		tstopflag = 0;
608
		return 1;
609
	}
610
	/*
611
	 * wait for either input or the end
612
	 * of the delay period
613
	 */
614
	if (poll(pfd, 1, (int)(delay * 1000)) > 0) {
615
		char *errmsg;
616
		ssize_t len;
617
618
		if ((pfd[0].revents & (POLLERR|POLLHUP|POLLNVAL)))
619
			exit(1);
620
621
		clear_message();
622
623
		/*
624
		 * now read it and convert to
625
		 * command strchr
626
		 */
627
		while (1) {
628
			len = read(STDIN_FILENO, &ch, 1);
629
			if (len == -1 && errno == EINTR)
630
				continue;
631
			if (len == 0)
632
				exit(1);
633
			break;
634
		}
635
		if ((iptr = strchr(command_chars, ch)) == NULL) {
636
			/* illegal command */
637
			new_message(MT_standout, " Command not understood");
638
			putr();
639
			no_command = Yes;
640
			fflush(stdout);
641
			return (0);
642
		}
643
644
		change = iptr - command_chars;
645
646
		switch (change) {
647
		case CMD_redraw:	/* redraw screen */
648
			reset_display();
649
			break;
650
651
		case CMD_update:	/* merely update display */
652
			/*
653
			 * is the load average high?
654
			 */
655
			if (system_info.load_avg[0] > LoadMax) {
656
				/* yes, go home for visual feedback */
657
				go_home();
658
				fflush(stdout);
659
			}
660
			break;
661
662
		case CMD_quit:	/* quit */
663
			quit(0);
664
			break;
665
666
		case CMD_help1:	/* help */
667
		case CMD_help2:
668
			clear();
669
			show_help();
670
			anykey();
671
			clear();
672
			break;
673
674
		case CMD_errors:	/* show errors */
675
			if (error_count() == 0) {
676
				new_message(MT_standout,
677
				    " Currently no errors to report.");
678
				putr();
679
				no_command = Yes;
680
			} else {
681
				clear();
682
				show_errors();
683
				anykey();
684
				clear();
685
			}
686
			break;
687
688
		case CMD_number1:	/* new number */
689
		case CMD_number2:
690
			new_message(MT_standout,
691
			    "Number of processes to show: ");
692
693
			if (readline(tempbuf, 8) > 0) {
694
				if ((i = atoiwi(tempbuf)) != Invalid) {
695
					if (i > max_topn) {
696
						new_message(MT_standout |
697
						    MT_delayed,
698
						    " This terminal can only "
699
						    "display %d processes.",
700
						    max_topn);
701
						putr();
702
					}
703
					if ((i > topn || i == Infinity)
704
					    && topn == 0) {
705
						/* redraw the header */
706
						display_header(Yes);
707
					} else if (i == 0)
708
						display_header(No);
709
					topn = i;
710
				} else {
711
					new_message(MT_standout,
712
					    "Processes should be a "
713
					    "non-negative number");
714
					putr();
715
					no_command = Yes;
716
				}
717
			} else
718
				clear_message();
719
			break;
720
721
		case CMD_delay:	/* new seconds delay */
722
			new_message(MT_standout, "Seconds to delay: ");
723
			if (readline(tempbuf, sizeof(tempbuf)) > 0) {
724
				char *endp;
725
				double newdelay = strtod(tempbuf, &endp);
726
727
				if (newdelay >= 0 && newdelay <= 1000000 &&
728
				    *endp == '\0') {
729
					delay = newdelay;
730
				} else {
731
					new_message(MT_standout,
732
					    "Delay should be a non-negative number");
733
					putr();
734
					no_command = Yes;
735
				}
736
737
			} else
738
				clear_message();
739
			break;
740
741
		case CMD_displays:	/* change display count */
742
			new_message(MT_standout,
743
			    "Displays to show (currently %s): ",
744
			    displays == -1 ? "infinite" :
745
			    itoa(displays));
746
747
			if (readline(tempbuf, 10) > 0) {
748
				if ((i = atoiwi(tempbuf)) != Invalid) {
749
					if (i == 0)
750
						quit(0);
751
					displays = i;
752
				} else {
753
					new_message(MT_standout,
754
					    "Displays should be a non-negative number");
755
					putr();
756
					no_command = Yes;
757
				}
758
			} else
759
				clear_message();
760
			break;
761
762
		case CMD_kill:	/* kill program */
763
			new_message(0, "kill ");
764
			if (readline(tempbuf, sizeof(tempbuf)) > 0) {
765
				if ((errmsg = kill_procs(tempbuf)) != NULL) {
766
					new_message(MT_standout, "%s", errmsg);
767
					putr();
768
					no_command = Yes;
769
				}
770
			} else
771
				clear_message();
772
			break;
773
774
		case CMD_renice:	/* renice program */
775
			new_message(0, "renice ");
776
			if (readline(tempbuf, sizeof(tempbuf)) > 0) {
777
				if ((errmsg = renice_procs(tempbuf)) != NULL) {
778
					new_message(MT_standout, "%s", errmsg);
779
					putr();
780
					no_command = Yes;
781
				}
782
			} else
783
				clear_message();
784
			break;
785
786
		case CMD_idletog:
787
		case CMD_idletog2:
788
			ps.idle = !ps.idle;
789
			new_message(MT_standout | MT_delayed,
790
			    " %sisplaying idle processes.",
791
			    ps.idle ? "D" : "Not d");
792
			putr();
793
			break;
794
795
		case CMD_user:
796
			new_message(MT_standout,
797
			    "Username to show: ");
798
			if (readline(tempbuf, sizeof(tempbuf)) > 0) {
799
				if ((tempbuf[0] == '+' || tempbuf[0] == '-') &&
800
				    tempbuf[1] == '\0') {
801
					ps.uid = (uid_t)-1;
802
					ps.huid = (uid_t)-1;
803
				} else if (tempbuf[0] == '-') {
804
					if ((huid = userid(tempbuf+1)) == (uid_t)-1) {
805
						new_message(MT_standout,
806
						    " %s: unknown user", tempbuf+1);
807
						no_command = Yes;
808
					} else {
809
						ps.huid = huid;
810
						ps.uid = (uid_t)-1;
811
					}
812
				} else if ((uid = userid(tempbuf)) == (uid_t)-1) {
813
						new_message(MT_standout,
814
						    " %s: unknown user", tempbuf);
815
						no_command = Yes;
816
				} else {
817
					ps.uid = uid;
818
					ps.huid = (uid_t)-1;
819
				}
820
				putr();
821
			} else
822
				clear_message();
823
			break;
824
825
		case CMD_system:
826
			ps.system = !ps.system;
827
			old_system = ps.system;
828
			new_message(MT_standout | MT_delayed,
829
			    " %sisplaying system processes.",
830
			    ps.system ? "D" : "Not d");
831
			break;
832
833
		case CMD_order:
834
			new_message(MT_standout,
835
			    "Order to sort: ");
836
			if (readline(tempbuf, sizeof(tempbuf)) > 0) {
837
				if ((i = string_index(tempbuf,
838
				    statics.order_names)) == -1) {
839
					new_message(MT_standout,
840
					    " %s: unrecognized sorting order",
841
					    tempbuf);
842
					no_command = Yes;
843
				} else
844
					order_index = i;
845
				putr();
846
			} else
847
				clear_message();
848
			break;
849
850
		case CMD_pid:
851
			new_message(MT_standout, "Process ID to show: ");
852
			if (readline(tempbuf, sizeof(tempbuf)) > 0) {
853
				if (tempbuf[0] == '+' &&
854
				    tempbuf[1] == '\0') {
855
					ps.pid = (pid_t)-1;
856
					ps.system = old_system;
857
				} else {
858
					unsigned long long num;
859
					const char *errstr;
860
861
					num = strtonum(tempbuf, 0, INT_MAX,
862
					    &errstr);
863
					if (errstr != NULL || !find_pid(num)) {
864
						new_message(MT_standout,
865
						    " %s: unknown pid",
866
						    tempbuf);
867
						no_command = Yes;
868
					} else {
869
						if (ps.system == No)
870
							old_system = No;
871
						ps.pid = (pid_t)num;
872
						ps.system = Yes;
873
					}
874
				}
875
				putr();
876
			} else
877
				clear_message();
878
			break;
879
880
		case CMD_command:
881
			show_args = (show_args == No) ? Yes : No;
882
			break;
883
884
		case CMD_threads:
885
			ps.threads = !ps.threads;
886
			old_threads = ps.threads;
887
			new_message(MT_standout | MT_delayed,
888
			    " %sisplaying threads.",
889
			    ps.threads ? "D" : "Not d");
890
			break;
891
892
		case CMD_grep:
893
			new_message(MT_standout,
894
			    "Grep command name: ");
895
			if (readline(tempbuf, sizeof(tempbuf)) > 0) {
896
				free(ps.command);
897
				if (tempbuf[0] == '+' &&
898
				    tempbuf[1] == '\0')
899
					ps.command = NULL;
900
				else
901
					if ((ps.command = strdup(tempbuf)) ==
902
					    NULL)
903
						err(1, NULL);
904
				putr();
905
			} else
906
				clear_message();
907
			break;
908
909
		case CMD_hl:
910
			new_message(MT_standout, "Process ID to highlight: ");
911
			if (readline(tempbuf, sizeof(tempbuf)) > 0) {
912
				if (tempbuf[0] == '+' &&
913
				    tempbuf[1] == '\0') {
914
					hlpid = -1;
915
				} else {
916
					unsigned long long num;
917
					const char *errstr;
918
919
					num = strtonum(tempbuf, 0, INT_MAX,
920
					    &errstr);
921
					if (errstr != NULL || !find_pid(num)) {
922
						new_message(MT_standout,
923
						    " %s: unknown pid",
924
						    tempbuf);
925
						no_command = Yes;
926
					} else
927
						hlpid = (pid_t)num;
928
				}
929
				putr();
930
			} else
931
				clear_message();
932
			break;
933
934
		case CMD_add:
935
			ps.uid = (uid_t)-1;	/* uid */
936
			ps.huid = (uid_t)-1;
937
			ps.pid = (pid_t)-1;	/* pid */
938
			ps.system = old_system;
939
			ps.command = NULL;	/* grep */
940
			hlpid = -1;
941
			break;
942
		case CMD_cpus:
943
			combine_cpus = !combine_cpus;
944
			max_topn = display_resize();
945
			reset_display();
946
			break;
947
		default:
948
			new_message(MT_standout, " BAD CASE IN SWITCH!");
949
			putr();
950
		}
951
	}
952
953
	/* flush out stuff that may have been written */
954
	fflush(stdout);
955
	return 0;
956
}
957
958
959
/*
960
 *  reset_display() - reset all the display routine pointers so that entire
961
 *	screen will get redrawn.
962
 */
963
static void
964
reset_display(void)
965
{
966
	if (smart_terminal) {
967
		clear();
968
		refresh();
969
	}
970
}
971
972
/* ARGSUSED */
973
void
974
leave(int signo)
975
{
976
	leaveflag = 1;
977
}
978
979
/* ARGSUSED */
980
void
981
tstop(int signo)
982
{
983
	tstopflag = 1;
984
}
985
986
/* ARGSUSED */
987
void
988
sigwinch(int signo)
989
{
990
	winchflag = 1;
991
}
992
993
/* ARGSUSED */
994
void
995
onalrm(int signo)
996
{
997
}
998
999
void
1000
quit(int ret)
1001
{
1002
	end_screen();
1003
	exit(ret);
1004
}