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