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