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