xref: /openbsd-src/usr.bin/top/top.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: top.c,v 1.9 2001/07/27 17:13:42 deraadt Exp $	*/
2 
3 const char copyright[] = "Copyright (c) 1984 through 1996, William LeFebvre";
4 
5 /*
6  *  Top users/processes display for Unix
7  *  Version 3
8  *
9  *  This program may be freely redistributed,
10  *  but this entire comment MUST remain intact.
11  *
12  *  Copyright (c) 1984, 1989, William LeFebvre, Rice University
13  *  Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University
14  */
15 
16 /*
17  *  See the file "Changes" for information on version-to-version changes.
18  */
19 
20 /*
21  *  This file contains "main" and other high-level routines.
22  */
23 
24 /*
25  * The following preprocessor variables, when defined, are used to
26  * distinguish between different Unix implementations:
27  *
28  *	SIGHOLD  - use SVR4 sighold function when defined
29  *	SIGRELSE - use SVR4 sigrelse function when defined
30  *	FD_SET   - macros FD_SET and FD_ZERO are used when defined
31  */
32 
33 #include <sys/types.h>
34 #include <stdio.h>
35 #include <ctype.h>
36 #include <signal.h>
37 #include <setjmp.h>
38 #include <string.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41 #include <errno.h>
42 #include <sys/time.h>
43 
44 /* includes specific to top */
45 #include "display.h"		/* interface to display package */
46 #include "screen.h"		/* interface to screen package */
47 #include "top.h"
48 #include "top.local.h"
49 #include "boolean.h"
50 #include "machine.h"
51 #include "utils.h"
52 
53 /* Size of the stdio buffer given to stdout */
54 #define Buffersize	2048
55 
56 /* The buffer that stdio will use */
57 char stdoutbuf[Buffersize];
58 
59 /* build Signal masks */
60 #define Smask(s)	(1 << ((s) - 1))
61 
62 /* imported from screen.c */
63 extern int overstrike;
64 
65 /* signal handling routines */
66 static void leave __P((int));
67 static void onalrm __P((int));
68 static void tstop __P((int));
69 #ifdef SIGWINCH
70 static void winch __P((int));
71 #endif
72 
73 sig_atomic_t leaveflag;
74 sig_atomic_t tstopflag;
75 sig_atomic_t winchflag;
76 
77 static void reset_display __P((void));
78 
79 /* values which need to be accessed by signal handlers */
80 static int max_topn;		/* maximum displayable processes */
81 
82 /* miscellaneous things */
83 char *myname = "top";
84 jmp_buf jmp_int;
85 
86 /* routines that don't return int */
87 
88 #ifdef ORDER
89 extern int (*proc_compares[])();
90 #else
91 extern int proc_compare();
92 #endif
93 time_t time();
94 
95 caddr_t get_process_info();
96 
97 /* pointers to display routines */
98 void (*d_loadave)() = i_loadave;
99 void (*d_procstates)() = i_procstates;
100 void (*d_cpustates)() = i_cpustates;
101 void (*d_memory)() = i_memory;
102 void (*d_message)() = i_message;
103 void (*d_header)() = i_header;
104 void (*d_process)() = i_process;
105 
106 
107 int main(argc, argv)
108 
109 int  argc;
110 char *argv[];
111 
112 {
113     register int i;
114     register int active_procs;
115     register int change;
116 
117     struct system_info system_info;
118     struct statics statics;
119     caddr_t processes;
120 
121     static char tempbuf1[50];
122     static char tempbuf2[50];
123     int old_sigmask;		/* only used for BSD-style signals */
124     int topn = Default_TOPN;
125     int delay = Default_DELAY;
126     int displays = 0;		/* indicates unspecified */
127     time_t curr_time;
128     char *(*get_userid)() = username;
129     char *uname_field = "USERNAME";
130     char *header_text;
131     char *env_top;
132     char **preset_argv;
133     int  preset_argc = 0;
134     char **av;
135     int  ac;
136     char dostates = No;
137     char do_unames = Yes;
138     char interactive = Maybe;
139     char warnings = 0;
140 #if Default_TOPN == Infinity
141     char topn_specified = No;
142 #endif
143     char ch;
144     char *iptr;
145     char no_command = 1;
146     struct timeval timeout;
147     struct process_select ps;
148 #ifdef ORDER
149     char *order_name = NULL;
150     int order_index = 0;
151 #endif
152 #ifndef FD_SET
153     /* FD_SET and friends are not present:  fake it */
154     typedef int fd_set;
155 #define FD_ZERO(x)     (*(x) = 0)
156 #define FD_SET(f, x)   (*(x) = f)
157 #endif
158     fd_set readfds;
159 
160 #ifdef ORDER
161     static char command_chars[] = "\f qh?en#sdkriIuo";
162 #else
163     static char command_chars[] = "\f qh?en#sdkriIu";
164 #endif
165 /* these defines enumerate the "strchr"s of the commands in command_chars */
166 #define CMD_redraw	0
167 #define CMD_update	1
168 #define CMD_quit	2
169 #define CMD_help1	3
170 #define CMD_help2	4
171 #define CMD_OSLIMIT	4    /* terminals with OS can only handle commands */
172 #define CMD_errors	5    /* less than or equal to CMD_OSLIMIT	   */
173 #define CMD_number1	6
174 #define CMD_number2	7
175 #define CMD_delay	8
176 #define CMD_displays	9
177 #define CMD_kill	10
178 #define CMD_renice	11
179 #define CMD_idletog     12
180 #define CMD_idletog2    13
181 #define CMD_user	14
182 #ifdef ORDER
183 #define CMD_order       15
184 #endif
185 
186     /* set the buffer for stdout */
187 #ifdef DEBUG
188     setbuffer(stdout, NULL, 0);
189 #else
190     setbuffer(stdout, stdoutbuf, Buffersize);
191 #endif
192 
193     /* get our name */
194     if (argc > 0)
195     {
196 	if ((myname = strrchr(argv[0], '/')) == 0)
197 	{
198 	    myname = argv[0];
199 	}
200 	else
201 	{
202 	    myname++;
203 	}
204     }
205 
206     /* initialize some selection options */
207     ps.idle    = Yes;
208     ps.system  = No;
209     ps.uid     = -1;
210     ps.command = NULL;
211 
212     /* get preset options from the environment */
213     if ((env_top = getenv("TOP")) != NULL)
214     {
215 	av = preset_argv = argparse(env_top, &preset_argc);
216 	ac = preset_argc;
217 
218 	/* set the dummy argument to an explanatory message, in case
219 	   getopt encounters a bad argument */
220 	preset_argv[0] = "while processing environment";
221     }
222 
223     /* process options */
224     do {
225 	/* if we're done doing the presets, then process the real arguments */
226 	if (preset_argc == 0)
227 	{
228 	    ac = argc;
229 	    av = argv;
230 
231 	    /* this should keep getopt happy... */
232 	    optind = 1;
233 	}
234 
235 	while ((i = getopt(ac, av, "SIbinqus:d:U:o:")) != -1)
236 	{
237 	    switch(i)
238 	    {
239 	      case 'u':			/* toggle uid/username display */
240 		do_unames = !do_unames;
241 		break;
242 
243 	      case 'U':			/* display only username's processes */
244 		if ((ps.uid = userid(optarg)) == -1)
245 		{
246 		    fprintf(stderr, "%s: unknown user\n", optarg);
247 		    exit(1);
248 		}
249 		break;
250 
251 	      case 'S':			/* show system processes */
252 		ps.system = !ps.system;
253 		break;
254 
255 	      case 'I':                   /* show idle processes */
256 		ps.idle = !ps.idle;
257 		break;
258 
259 	      case 'i':			/* go interactive regardless */
260 		interactive = Yes;
261 		break;
262 
263 	      case 'n':			/* batch, or non-interactive */
264 	      case 'b':
265 		interactive = No;
266 		break;
267 
268 	      case 'd':			/* number of displays to show */
269 		if ((i = atoiwi(optarg)) == Invalid || i == 0)
270 		{
271 		    fprintf(stderr,
272 			"%s: warning: display count should be positive -- option ignored\n",
273 			myname);
274 		    warnings++;
275 		}
276 		else
277 		{
278 		    displays = i;
279 		}
280 		break;
281 
282 	      case 's':
283 		{
284 		  char *endp;
285 
286 		  delay = strtoul(optarg, &endp, 10);
287 		  if (delay < 0 || *endp != '\0')
288 		  {
289 		    fprintf(stderr,
290 			"%s: warning: seconds delay should be non-negative -- using default\n",
291 			myname);
292 		    delay = Default_DELAY;
293 		    warnings++;
294 		  }
295 		}
296 		break;
297 
298 	      case 'q':		/* be quick about it */
299 		/* only allow this if user is really root */
300 		if (getuid() == 0)
301 		{
302 		    /* be very un-nice! */
303 		    (void) nice(-20);
304 		}
305 		else
306 		{
307 		    fprintf(stderr,
308 			"%s: warning: `-q' option can only be used by root\n",
309 			myname);
310 		    warnings++;
311 		}
312 		break;
313 
314 	      case 'o':		/* select sort order */
315 #ifdef ORDER
316 		order_name = optarg;
317 #else
318 		fprintf(stderr,
319 			"%s: this platform does not support arbitrary ordering.  Sorry.\n",
320 			myname);
321 		warnings++;
322 #endif
323 		break;
324 
325 	      default:
326 		fprintf(stderr, "\
327 Top version %s\n\
328 Usage: %s [-ISbinqu] [-d x] [-s x] [-o field] [-U username] [number]\n",
329 			version_string(), myname);
330 		exit(1);
331 	    }
332 	}
333 
334 	/* get count of top processes to display (if any) */
335 	if (optind < ac)
336 	{
337 	    if ((topn = atoiwi(av[optind])) == Invalid)
338 	    {
339 		fprintf(stderr,
340 			"%s: warning: process display count should be non-negative -- using default\n",
341 			myname);
342 		warnings++;
343 	    }
344 #if Default_TOPN == Infinity
345             else
346 	    {
347 		topn_specified = Yes;
348 	    }
349 #endif
350 	}
351 
352 	/* tricky:  remember old value of preset_argc & set preset_argc = 0 */
353 	i = preset_argc;
354 	preset_argc = 0;
355 
356     /* repeat only if we really did the preset arguments */
357     } while (i != 0);
358 
359     /* set constants for username/uid display correctly */
360     if (!do_unames)
361     {
362 	uname_field = "   UID  ";
363 	get_userid = itoa7;
364     }
365 
366     /* initialize the kernel memory interface */
367     if (machine_init(&statics) == -1)
368     {
369 	exit(1);
370     }
371 
372 #ifdef ORDER
373     /* determine sorting order index, if necessary */
374     if (order_name != NULL)
375     {
376 	if ((order_index = string_index(order_name, statics.order_names)) == -1)
377 	{
378 	    char **pp;
379 
380 	    fprintf(stderr, "%s: '%s' is not a recognized sorting order.\n",
381 		    myname, order_name);
382 	    fprintf(stderr, "\tTry one of these:");
383 	    pp = statics.order_names;
384 	    while (*pp != NULL)
385 	    {
386 		fprintf(stderr, " %s", *pp++);
387 	    }
388 	    fputc('\n', stderr);
389 	    exit(1);
390 	}
391     }
392 #endif
393 
394 #ifdef no_initialization_needed
395     /* initialize the hashing stuff */
396     if (do_unames)
397     {
398 	init_hash();
399     }
400 #endif
401 
402     /* initialize termcap */
403     init_termcap(interactive);
404 
405     /* get the string to use for the process area header */
406     header_text = format_header(uname_field);
407 
408     /* initialize display interface */
409     if ((max_topn = display_init(&statics)) == -1)
410     {
411 	fprintf(stderr, "%s: can't allocate sufficient memory\n", myname);
412 	exit(4);
413     }
414 
415     /* print warning if user requested more processes than we can display */
416     if (topn > max_topn)
417     {
418 	fprintf(stderr,
419 		"%s: warning: this terminal can only display %d processes.\n",
420 		myname, max_topn);
421 	warnings++;
422     }
423 
424     /* adjust for topn == Infinity */
425     if (topn == Infinity)
426     {
427 	/*
428 	 *  For smart terminals, infinity really means everything that can
429 	 *  be displayed, or Largest.
430 	 *  On dumb terminals, infinity means every process in the system!
431 	 *  We only really want to do that if it was explicitly specified.
432 	 *  This is always the case when "Default_TOPN != Infinity".  But if
433 	 *  topn wasn't explicitly specified and we are on a dumb terminal
434 	 *  and the default is Infinity, then (and only then) we use
435 	 *  "Nominal_TOPN" instead.
436 	 */
437 #if Default_TOPN == Infinity
438 	topn = smart_terminal ? Largest :
439 		    (topn_specified ? Largest : Nominal_TOPN);
440 #else
441 	topn = Largest;
442 #endif
443     }
444 
445     /* set header display accordingly */
446     display_header(topn > 0);
447 
448     /* determine interactive state */
449     if (interactive == Maybe)
450     {
451 	interactive = smart_terminal;
452     }
453 
454     /* if # of displays not specified, fill it in */
455     if (displays == 0)
456     {
457 	displays = smart_terminal ? Infinity : 1;
458     }
459 
460     /* hold interrupt signals while setting up the screen and the handlers */
461 #ifdef SIGHOLD
462     sighold(SIGINT);
463     sighold(SIGQUIT);
464     sighold(SIGTSTP);
465 #else
466     old_sigmask = sigblock(Smask(SIGINT) | Smask(SIGQUIT) | Smask(SIGTSTP));
467 #endif
468     init_screen();
469     (void) signal(SIGINT, leave);
470     (void) signal(SIGQUIT, leave);
471     (void) signal(SIGTSTP, tstop);
472 #ifdef SIGWINCH
473     (void) signal(SIGWINCH, winch);
474 #endif
475 #ifdef SIGRELSE
476     sigrelse(SIGINT);
477     sigrelse(SIGQUIT);
478     sigrelse(SIGTSTP);
479 #else
480     (void) sigsetmask(old_sigmask);
481 #endif
482     if (warnings)
483     {
484 	fputs("....", stderr);
485 	fflush(stderr);			/* why must I do this? */
486 	sleep((unsigned)(3 * warnings));
487 	fputc('\n', stderr);
488     }
489 
490 restart:
491 
492     /*
493      *  main loop -- repeat while display count is positive or while it
494      *		indicates infinity (by being -1)
495      */
496 
497     while ((displays == -1) || (displays-- > 0))
498     {
499 	/* get the current stats */
500 	get_system_info(&system_info);
501 
502 	/* get the current set of processes */
503 	processes =
504 		get_process_info(&system_info,
505 				 &ps,
506 #ifdef ORDER
507 				 proc_compares[order_index]);
508 #else
509 				 proc_compare);
510 #endif
511 
512 	/* display the load averages */
513 	(*d_loadave)(system_info.last_pid,
514 		     system_info.load_avg);
515 
516 	/* display the current time */
517 	/* this method of getting the time SHOULD be fairly portable */
518 	time(&curr_time);
519 	i_timeofday(&curr_time);
520 
521 	/* display process state breakdown */
522 	(*d_procstates)(system_info.p_total,
523 			system_info.procstates);
524 
525 	/* display the cpu state percentage breakdown */
526 	if (dostates)	/* but not the first time */
527 	{
528 	    (*d_cpustates)(system_info.cpustates);
529 	}
530 	else
531 	{
532 	    /* we'll do it next time */
533 	    if (smart_terminal)
534 	    {
535 		z_cpustates();
536 	    }
537 	    else
538 	    {
539 		if (putchar('\n') == EOF)
540 		    exit(1);
541 	    }
542 	    dostates = Yes;
543 	}
544 
545 	/* display memory stats */
546 	(*d_memory)(system_info.memory);
547 
548 	/* handle message area */
549 	(*d_message)();
550 
551 	/* update the header area */
552 	(*d_header)(header_text);
553 
554 	if (topn > 0)
555 	{
556 	    /* determine number of processes to actually display */
557 	    /* this number will be the smallest of:  active processes,
558 	       number user requested, number current screen accomodates */
559 	    active_procs = system_info.p_active;
560 	    if (active_procs > topn)
561 	    {
562 		active_procs = topn;
563 	    }
564 	    if (active_procs > max_topn)
565 	    {
566 		active_procs = max_topn;
567 	    }
568 
569 	    /* now show the top "n" processes. */
570 	    for (i = 0; i < active_procs; i++)
571 	    {
572 		(*d_process)(i, format_next_process(processes, get_userid));
573 	    }
574 	}
575 	else
576 	{
577 	    i = 0;
578 	}
579 
580 	/* do end-screen processing */
581 	u_endscreen(i);
582 
583 	/* now, flush the output buffer */
584 	fflush(stdout);
585 
586 	/* only do the rest if we have more displays to show */
587 	if (displays)
588 	{
589 	    /* switch out for new display on smart terminals */
590 	    if (smart_terminal)
591 	    {
592 		if (overstrike)
593 		{
594 		    reset_display();
595 		}
596 		else
597 		{
598 		    d_loadave = u_loadave;
599 		    d_procstates = u_procstates;
600 		    d_cpustates = u_cpustates;
601 		    d_memory = u_memory;
602 		    d_message = u_message;
603 		    d_header = u_header;
604 		    d_process = u_process;
605 		}
606 	    }
607 
608 	    no_command = Yes;
609 	    if (!interactive)
610 	    {
611 		/* set up alarm */
612 		(void) signal(SIGALRM, onalrm);
613 		(void) alarm((unsigned)delay);
614 
615 		/* wait for the rest of it .... */
616 		pause();
617 	    }
618 	    else while (no_command)
619 	    {
620 		/* assume valid command unless told otherwise */
621 		no_command = No;
622 
623 		/* set up arguments for select with timeout */
624 		FD_ZERO(&readfds);
625 		FD_SET(1, &readfds);		/* for standard input */
626 		timeout.tv_sec  = delay;
627 		timeout.tv_usec = 0;
628 
629 		if (leaveflag) {
630 		    end_screen();
631 		    exit(0);
632 		}
633 
634 		if (tstopflag) {
635 		    /* move to the lower left */
636 		    end_screen();
637 		    fflush(stdout);
638 
639 		    /* default the signal handler action */
640 		    (void) signal(SIGTSTP, SIG_DFL);
641 
642 		    /* unblock the signal and send ourselves one */
643 #ifdef SIGRELSE
644 		    sigrelse(SIGTSTP);
645 #else
646 		    (void) sigsetmask(sigblock(0) & ~(1 << (SIGTSTP - 1)));
647 #endif
648 		    (void) kill(0, SIGTSTP);
649 
650 		    /* reset the signal handler */
651 		    (void) signal(SIGTSTP, tstop);
652 
653 		    /* reinit screen */
654 		    reinit_screen();
655 		    reset_display();
656 		    tstopflag = 0;
657 		    goto restart;
658 		}
659 
660 		if (winchflag) {
661 		    /* reascertain the screen dimensions */
662 		    get_screensize();
663 
664 		    /* tell display to resize */
665 		    max_topn = display_resize();
666 
667 		    /* reset the signal handler */
668 		    (void) signal(SIGWINCH, winch);
669 
670 		    reset_display();
671 		    winchflag = 0;
672 		    goto restart;
673 		}
674 
675 		/* wait for either input or the end of the delay period */
676 		if (select(32, &readfds, (fd_set *)NULL, (fd_set *)NULL, &timeout) > 0)
677 		{
678 		    int newval;
679 		    char *errmsg;
680 
681 		    /* something to read -- clear the message area first */
682 		    clear_message();
683 
684 		    /* now read it and convert to command strchr */
685 		    /* (use "change" as a temporary to hold strchr) */
686 		    (void) read(0, &ch, 1);
687 		    if ((iptr = strchr(command_chars, ch)) == NULL)
688 		    {
689 			/* illegal command */
690 			new_message(MT_standout, " Command not understood");
691 			if (putchar('\r') == EOF)
692 			    exit(1);
693 			no_command = Yes;
694 		    }
695 		    else
696 		    {
697 			change = iptr - command_chars;
698 			if (overstrike && change > CMD_OSLIMIT)
699 			{
700 			    /* error */
701 			    new_message(MT_standout,
702 			    " Command cannot be handled by this terminal");
703 			    if (putchar('\r') == EOF)
704 			        exit(1);
705 			    no_command = Yes;
706 			}
707 			else switch(change)
708 			{
709 			    case CMD_redraw:	/* redraw screen */
710 				reset_display();
711 				break;
712 
713 			    case CMD_update:	/* merely update display */
714 				/* is the load average high? */
715 				if (system_info.load_avg[0] > LoadMax)
716 				{
717 				    /* yes, go home for visual feedback */
718 				    go_home();
719 				    fflush(stdout);
720 				}
721 				break;
722 
723 			    case CMD_quit:	/* quit */
724 				quit(0);
725 				/*NOTREACHED*/
726 				break;
727 
728 			    case CMD_help1:	/* help */
729 			    case CMD_help2:
730 				reset_display();
731 				clear();
732 				show_help();
733 				standout("Hit any key to continue: ");
734 				fflush(stdout);
735 				(void) read(0, &ch, 1);
736 				break;
737 
738 			    case CMD_errors:	/* show errors */
739 				if (error_count() == 0)
740 				{
741 				    new_message(MT_standout,
742 					" Currently no errors to report.");
743 				    if (putchar('\r') == EOF)
744 				        exit(1);
745 				    no_command = Yes;
746 				}
747 				else
748 				{
749 				    reset_display();
750 				    clear();
751 				    show_errors();
752 				    standout("Hit any key to continue: ");
753 				    fflush(stdout);
754 				    (void) read(0, &ch, 1);
755 				}
756 				break;
757 
758 			    case CMD_number1:	/* new number */
759 			    case CMD_number2:
760 				new_message(MT_standout,
761 				    "Number of processes to show: ");
762 				newval = readline(tempbuf1, 8, Yes);
763 				if (newval > -1)
764 				{
765 				    if (newval > max_topn)
766 				    {
767 					new_message(MT_standout | MT_delayed,
768 					  " This terminal can only display %d processes.",
769 					  max_topn);
770 					if (putchar('\r') == EOF)
771 					    exit(1);
772 				    }
773 
774 				    if (newval == 0)
775 				    {
776 					/* inhibit the header */
777 					display_header(No);
778 				    }
779 				    else if (newval > topn && topn == 0)
780 				    {
781 					/* redraw the header */
782 					display_header(Yes);
783 					d_header = i_header;
784 				    }
785 				    topn = newval;
786 				}
787 				break;
788 
789 			    case CMD_delay:	/* new seconds delay */
790 				new_message(MT_standout, "Seconds to delay: ");
791 				if ((i = readline(tempbuf1, 8, Yes)) > -1)
792 				{
793 				    delay = i;
794 				}
795 				clear_message();
796 				break;
797 
798 			    case CMD_displays:	/* change display count */
799 				new_message(MT_standout,
800 					"Displays to show (currently %s): ",
801 					displays == -1 ? "infinite" :
802 							 itoa(displays));
803 				if ((i = readline(tempbuf1, 10, Yes)) > 0)
804 				{
805 				    displays = i;
806 				}
807 				else if (i == 0)
808 				{
809 				    quit(0);
810 				}
811 				clear_message();
812 				break;
813 
814 			    case CMD_kill:	/* kill program */
815 				new_message(0, "kill ");
816 				if (readline(tempbuf2, sizeof(tempbuf2), No) > 0)
817 				{
818 				    if ((errmsg = kill_procs(tempbuf2)) != NULL)
819 				    {
820 					new_message(MT_standout, "%s", errmsg);
821 					if (putchar('\r') == EOF)
822 					    exit(1);
823 					no_command = Yes;
824 				    }
825 				}
826 				else
827 				{
828 				    clear_message();
829 				}
830 				break;
831 
832 			    case CMD_renice:	/* renice program */
833 				new_message(0, "renice ");
834 				if (readline(tempbuf2, sizeof(tempbuf2), No) > 0)
835 				{
836 				    if ((errmsg = renice_procs(tempbuf2)) != NULL)
837 				    {
838 					new_message(MT_standout, "%s", errmsg);
839 					if (putchar('\r') == EOF)
840 					    exit(1);
841 					no_command = Yes;
842 				    }
843 				}
844 				else
845 				{
846 				    clear_message();
847 				}
848 				break;
849 
850 			    case CMD_idletog:
851 			    case CMD_idletog2:
852 				ps.idle = !ps.idle;
853 				new_message(MT_standout | MT_delayed,
854 				    " %sisplaying idle processes.",
855 				    ps.idle ? "D" : "Not d");
856 				if (putchar('\r') == EOF)
857 				    exit(1);
858 				break;
859 
860 			    case CMD_user:
861 				new_message(MT_standout,
862 				    "Username to show: ");
863 				if (readline(tempbuf2, sizeof(tempbuf2), No) > 0)
864 				{
865 				    if (tempbuf2[0] == '+' &&
866 					tempbuf2[1] == '\0')
867 				    {
868 					ps.uid = -1;
869 				    }
870 				    else if ((i = userid(tempbuf2)) == -1)
871 				    {
872 					new_message(MT_standout,
873 					    " %s: unknown user", tempbuf2);
874 					no_command = Yes;
875 				    }
876 				    else
877 				    {
878 					ps.uid = i;
879 				    }
880 				    if (putchar('\r') == EOF)
881 				        exit(1);
882 				}
883 				else
884 				{
885 				    clear_message();
886 				}
887 				break;
888 
889 #ifdef ORDER
890 			    case CMD_order:
891 				new_message(MT_standout,
892 				    "Order to sort: ");
893 				if (readline(tempbuf2, sizeof(tempbuf2), No) > 0)
894 				{
895 				  if ((i = string_index(tempbuf2, statics.order_names)) == -1)
896 					{
897 					  new_message(MT_standout,
898 					      " %s: unrecognized sorting order", tempbuf2);
899 					  no_command = Yes;
900 				    }
901 				    else
902 				    {
903 					order_index = i;
904 				    }
905 				    if (putchar('\r') == EOF)
906 				        exit(1);
907 				}
908 				else
909 				{
910 				    clear_message();
911 				}
912 				break;
913 #endif
914 
915 			    default:
916 				new_message(MT_standout, " BAD CASE IN SWITCH!");
917 				if (putchar('\r') == EOF)
918 				    exit(1);
919 			}
920 		    }
921 
922 		    /* flush out stuff that may have been written */
923 		    fflush(stdout);
924 		}
925 	    }
926 	}
927     }
928 
929     quit(0);
930     /*NOTREACHED*/
931     return(0);
932 }
933 
934 /*
935  *  reset_display() - reset all the display routine pointers so that entire
936  *	screen will get redrawn.
937  */
938 
939 static void reset_display()
940 
941 {
942     d_loadave    = i_loadave;
943     d_procstates = i_procstates;
944     d_cpustates  = i_cpustates;
945     d_memory     = i_memory;
946     d_message	 = i_message;
947     d_header	 = i_header;
948     d_process	 = i_process;
949 }
950 
951 /*
952  *  signal handlers
953  */
954 
955 void leave(unused)	/* exit under normal conditions -- INT handler */
956 
957 int unused;
958 
959 {
960     leaveflag = 1;
961 }
962 
963 void tstop(i)	/* SIGTSTP handler */
964 
965 int i;
966 
967 {
968     tstopflag = 1;
969 }
970 
971 #ifdef SIGWINCH
972 void winch(i)		/* SIGWINCH handler */
973 
974 int i;
975 
976 {
977     winchflag = 1;
978 }
979 #endif
980 
981 void quit(status)		/* exit under duress */
982 
983 int status;
984 
985 {
986     end_screen();
987     exit(status);
988     /*NOTREACHED*/
989 }
990 
991 void onalrm(unused)	/* SIGALRM handler */
992 
993 int unused;
994 
995 {
996     /* this is only used in batch mode to break out of the pause() */
997     /* return; */
998 }
999 
1000