xref: /dflybsd-src/usr.bin/top/top.c (revision da0d35cf5f1c213e98d1d2ab31bf1d7794d56691)
1dc4f0af1Szrj /*
2dc4f0af1Szrj  * Copyright (c) 1984 through 2008, William LeFebvre
3dc4f0af1Szrj  * All rights reserved.
4dc4f0af1Szrj  *
5dc4f0af1Szrj  * Redistribution and use in source and binary forms, with or without
6dc4f0af1Szrj  * modification, are permitted provided that the following conditions are met:
7dc4f0af1Szrj  *
8dc4f0af1Szrj  *     * Redistributions of source code must retain the above copyright
9dc4f0af1Szrj  * notice, this list of conditions and the following disclaimer.
10dc4f0af1Szrj  *
11dc4f0af1Szrj  *     * Redistributions in binary form must reproduce the above
12dc4f0af1Szrj  * copyright notice, this list of conditions and the following disclaimer
13dc4f0af1Szrj  * in the documentation and/or other materials provided with the
14dc4f0af1Szrj  * distribution.
15dc4f0af1Szrj  *
16dc4f0af1Szrj  *     * Neither the name of William LeFebvre nor the names of other
17dc4f0af1Szrj  * contributors may be used to endorse or promote products derived from
18dc4f0af1Szrj  * this software without specific prior written permission.
19dc4f0af1Szrj  *
20dc4f0af1Szrj  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21dc4f0af1Szrj  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22dc4f0af1Szrj  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23dc4f0af1Szrj  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24dc4f0af1Szrj  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25dc4f0af1Szrj  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26dc4f0af1Szrj  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27dc4f0af1Szrj  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28dc4f0af1Szrj  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29dc4f0af1Szrj  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30dc4f0af1Szrj  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31dc4f0af1Szrj  */
32dc4f0af1Szrj 
33dc4f0af1Szrj char *copyright =
34dc4f0af1Szrj     "Copyright (c) 1984 through 2008, William LeFebvre";
35dc4f0af1Szrj 
36dc4f0af1Szrj /*
37dc4f0af1Szrj  * Changes to other files that we can do at the same time:
38dc4f0af1Szrj  * screen.c:init_termcap: get rid of the "interactive" argument and have it
39dc4f0af1Szrj  *      pass back something meaningful (such as success/failure/error).
40dc4f0af1Szrj  */
41dc4f0af1Szrj 
42dc4f0af1Szrj #include "os.h"
43dc4f0af1Szrj #include <signal.h>
44dc4f0af1Szrj #include <setjmp.h>
45dc4f0af1Szrj #include <ctype.h>
46dc4f0af1Szrj #include <sys/types.h>
47dc4f0af1Szrj #include <sys/uio.h>
48dc4f0af1Szrj #include <unistd.h>
49dc4f0af1Szrj 
50dc4f0af1Szrj #ifdef HAVE_SYS_UTSNAME_H
51dc4f0af1Szrj #include <sys/utsname.h>
52dc4f0af1Szrj #endif
53dc4f0af1Szrj 
54dc4f0af1Szrj #ifdef HAVE_GETOPT_H
55dc4f0af1Szrj #include <getopt.h>
56dc4f0af1Szrj #endif
57dc4f0af1Szrj 
58dc4f0af1Szrj /* definitions */
59dc4f0af1Szrj #ifndef STDIN_FILENO
60dc4f0af1Szrj #define STDIN_FILENO 0
61dc4f0af1Szrj #endif
62dc4f0af1Szrj 
63dc4f0af1Szrj /* determine which type of signal functions to use */
64dc4f0af1Szrj /* cant have sigaction without sigprocmask */
65dc4f0af1Szrj #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGPROCMASK)
66dc4f0af1Szrj #undef HAVE_SIGACTION
67dc4f0af1Szrj #endif
68dc4f0af1Szrj /* always use sigaction when it is available */
69dc4f0af1Szrj #ifdef HAVE_SIGACTION
70dc4f0af1Szrj #undef HAVE_SIGHOLD
71dc4f0af1Szrj #else
72dc4f0af1Szrj /* use sighold/sigrelse, otherwise use old fashioned BSD signals */
73dc4f0af1Szrj #if !defined(HAVE_SIGHOLD) || !defined(HAVE_SIGRELSE)
74dc4f0af1Szrj #define BSD_SIGNALS
75dc4f0af1Szrj #endif
76dc4f0af1Szrj #endif
77dc4f0af1Szrj 
78dc4f0af1Szrj /* if FD_SET and friends aren't present, then fake something up */
79dc4f0af1Szrj #ifndef FD_SET
80dc4f0af1Szrj typedef int fd_set;
81dc4f0af1Szrj #define FD_ZERO(x)     (*(x) = 0)
82dc4f0af1Szrj #define FD_SET(f, x)   (*(x) = 1<<f)
83dc4f0af1Szrj #endif
84dc4f0af1Szrj 
85dc4f0af1Szrj /* includes specific to top */
86dc4f0af1Szrj 
87dc4f0af1Szrj #include "top.h"
88dc4f0af1Szrj #include "machine.h"
89dc4f0af1Szrj #include "globalstate.h"
90dc4f0af1Szrj #include "commands.h"
91dc4f0af1Szrj #include "display.h"
92dc4f0af1Szrj #include "screen.h"
93dc4f0af1Szrj #include "boolean.h"
94dc4f0af1Szrj #include "username.h"
95dc4f0af1Szrj #include "utils.h"
96dc4f0af1Szrj #include "version.h"
97dc4f0af1Szrj #ifdef ENABLE_COLOR
98dc4f0af1Szrj #include "color.h"
99dc4f0af1Szrj #endif
100dc4f0af1Szrj 
101dc4f0af1Szrj /* definitions */
102dc4f0af1Szrj #define BUFFERSIZE 4096
103dc4f0af1Szrj #define JMP_RESUME 1
104dc4f0af1Szrj #define JMP_RESIZE 2
105dc4f0af1Szrj 
106dc4f0af1Szrj /* externs for getopt: */
107dc4f0af1Szrj extern int  optind;
108dc4f0af1Szrj extern char *optarg;
109dc4f0af1Szrj 
110dc4f0af1Szrj /* statics */
111dc4f0af1Szrj static char stdoutbuf[BUFFERSIZE];
112dc4f0af1Szrj static jmp_buf jmp_int;
113dc4f0af1Szrj 
114dc4f0af1Szrj /* globals */
115dc4f0af1Szrj char *myname = "top";
116dc4f0af1Szrj 
117dc4f0af1Szrj void
quit(int status)118dc4f0af1Szrj quit(int status)
119dc4f0af1Szrj 
120dc4f0af1Szrj {
121dc4f0af1Szrj     screen_end();
122dc4f0af1Szrj     chdir("/tmp");
123dc4f0af1Szrj     exit(status);
124dc4f0af1Szrj     /* NOTREACHED */
125dc4f0af1Szrj }
126dc4f0af1Szrj 
127dc4f0af1Szrj /*
128dc4f0af1Szrj  *  signal handlers
129dc4f0af1Szrj  */
130dc4f0af1Szrj 
131dc4f0af1Szrj void
set_signal(int sig,RETSIGTYPE (* handler)(int))132dc4f0af1Szrj set_signal(int sig, RETSIGTYPE (*handler)(int))
133dc4f0af1Szrj 
134dc4f0af1Szrj {
135dc4f0af1Szrj #ifdef HAVE_SIGACTION
136dc4f0af1Szrj     struct sigaction action;
137dc4f0af1Szrj 
138dc4f0af1Szrj     action.sa_handler = handler;
139dc4f0af1Szrj     action.sa_flags = 0;
140dc4f0af1Szrj     (void) sigaction(sig, &action, NULL);
141dc4f0af1Szrj #else
142dc4f0af1Szrj     (void) signal(sig, handler);
143dc4f0af1Szrj #endif
144dc4f0af1Szrj }
145dc4f0af1Szrj 
146dc4f0af1Szrj void
release_signal(int sig)147dc4f0af1Szrj release_signal(int sig)
148dc4f0af1Szrj 
149dc4f0af1Szrj {
150dc4f0af1Szrj #ifdef HAVE_SIGACTION
151dc4f0af1Szrj     sigset_t set;
152dc4f0af1Szrj     sigemptyset(&set);
153dc4f0af1Szrj     sigaddset(&set, sig);
154dc4f0af1Szrj     sigprocmask(SIG_UNBLOCK, &set, NULL);
155dc4f0af1Szrj #endif
156dc4f0af1Szrj 
157dc4f0af1Szrj #ifdef HAVE_SIGHOLD
158dc4f0af1Szrj     sigrelse(sig);
159dc4f0af1Szrj #endif
160dc4f0af1Szrj 
161dc4f0af1Szrj #ifdef BSD_SIGNALS
162dc4f0af1Szrj     (void) sigsetmask(sigblock(0) & ~(sigmask(sig)));
163dc4f0af1Szrj #endif
164dc4f0af1Szrj }
165dc4f0af1Szrj 
166dc4f0af1Szrj RETSIGTYPE
sig_leave(int i)167dc4f0af1Szrj sig_leave(int i)	/* exit under normal conditions -- INT handler */
168dc4f0af1Szrj 
169dc4f0af1Szrj {
170dc4f0af1Szrj     screen_end();
171dc4f0af1Szrj     exit(EX_OK);
172dc4f0af1Szrj }
173dc4f0af1Szrj 
174dc4f0af1Szrj RETSIGTYPE
sig_tstop(int i)175dc4f0af1Szrj sig_tstop(int i)	/* SIGTSTP handler */
176dc4f0af1Szrj 
177dc4f0af1Szrj {
178dc4f0af1Szrj     /* move to the lower left */
179dc4f0af1Szrj     screen_end();
180dc4f0af1Szrj     fflush(stdout);
181dc4f0af1Szrj 
182dc4f0af1Szrj     /* default the signal handler action */
183dc4f0af1Szrj     set_signal(SIGTSTP, SIG_DFL);
184dc4f0af1Szrj 
185dc4f0af1Szrj     /* unblock the TSTP signal */
186dc4f0af1Szrj     release_signal(SIGTSTP);
187dc4f0af1Szrj 
188dc4f0af1Szrj     /* send ourselves a TSTP to stop the process */
189dc4f0af1Szrj     (void) kill(0, SIGTSTP);
190dc4f0af1Szrj 
191dc4f0af1Szrj     /* reset the signal handler */
192dc4f0af1Szrj     set_signal(SIGTSTP, sig_tstop);
193dc4f0af1Szrj 
194dc4f0af1Szrj     /* reinit screen */
195dc4f0af1Szrj     screen_reinit();
196dc4f0af1Szrj 
197dc4f0af1Szrj     /* jump back to a known place in the main loop */
198dc4f0af1Szrj     longjmp(jmp_int, JMP_RESUME);
199dc4f0af1Szrj 
200dc4f0af1Szrj     /* NOTREACHED */
201dc4f0af1Szrj }
202dc4f0af1Szrj 
203dc4f0af1Szrj #ifdef SIGWINCH
204dc4f0af1Szrj RETSIGTYPE
sig_winch(int i)205dc4f0af1Szrj sig_winch(int i)		/* SIGWINCH handler */
206dc4f0af1Szrj 
207dc4f0af1Szrj {
208dc4f0af1Szrj     /* reascertain the screen dimensions */
209dc4f0af1Szrj     screen_getsize();
210dc4f0af1Szrj 
211dc4f0af1Szrj     /* jump back to a known place in the main loop */
212dc4f0af1Szrj     longjmp(jmp_int, JMP_RESIZE);
213dc4f0af1Szrj }
214dc4f0af1Szrj #endif
215dc4f0af1Szrj 
216dc4f0af1Szrj #ifdef HAVE_SIGACTION
217dc4f0af1Szrj static sigset_t signalset;
218dc4f0af1Szrj #endif
219dc4f0af1Szrj 
220dc4f0af1Szrj void *
hold_signals()221dc4f0af1Szrj hold_signals()
222dc4f0af1Szrj 
223dc4f0af1Szrj {
224dc4f0af1Szrj #ifdef HAVE_SIGACTION
225dc4f0af1Szrj     sigemptyset(&signalset);
226dc4f0af1Szrj     sigaddset(&signalset, SIGINT);
227dc4f0af1Szrj     sigaddset(&signalset, SIGQUIT);
228dc4f0af1Szrj     sigaddset(&signalset, SIGTSTP);
229dc4f0af1Szrj #ifdef SIGWINCH
230dc4f0af1Szrj     sigaddset(&signalset, SIGWINCH);
231dc4f0af1Szrj #endif
232dc4f0af1Szrj     sigprocmask(SIG_BLOCK, &signalset, NULL);
233dc4f0af1Szrj     return (void *)(&signalset);
234dc4f0af1Szrj #endif
235dc4f0af1Szrj 
236dc4f0af1Szrj #ifdef HAVE_SIGHOLD
237dc4f0af1Szrj     sighold(SIGINT);
238dc4f0af1Szrj     sighold(SIGQUIT);
239dc4f0af1Szrj     sighold(SIGTSTP);
240dc4f0af1Szrj #ifdef SIGWINCH
241dc4f0af1Szrj     sighold(SIGWINCH);
242dc4f0af1Szrj     return NULL;
243dc4f0af1Szrj #endif
244dc4f0af1Szrj #endif
245dc4f0af1Szrj 
246dc4f0af1Szrj #ifdef BSD_SIGNALS
247dc4f0af1Szrj     int mask;
248dc4f0af1Szrj #ifdef SIGWINCH
249dc4f0af1Szrj     mask = sigblock(sigmask(SIGINT) | sigmask(SIGQUIT) |
250dc4f0af1Szrj 		    sigmask(SIGTSTP) | sigmask(SIGWINCH));
251dc4f0af1Szrj #else
252dc4f0af1Szrj     mask = sigblock(sigmask(SIGINT) | sigmask(SIGQUIT) | sigmask(SIGTSTP));
253dc4f0af1Szrj     return (void *)mask;
254dc4f0af1Szrj #endif
255dc4f0af1Szrj #endif
256dc4f0af1Szrj 
257dc4f0af1Szrj }
258dc4f0af1Szrj 
259dc4f0af1Szrj void
set_signals()260dc4f0af1Szrj set_signals()
261dc4f0af1Szrj 
262dc4f0af1Szrj {
263dc4f0af1Szrj     (void) set_signal(SIGINT, sig_leave);
264dc4f0af1Szrj     (void) set_signal(SIGQUIT, sig_leave);
265dc4f0af1Szrj     (void) set_signal(SIGTSTP, sig_tstop);
266dc4f0af1Szrj #ifdef SIGWINCH
267dc4f0af1Szrj     (void) set_signal(SIGWINCH, sig_winch);
268dc4f0af1Szrj #endif
269dc4f0af1Szrj }
270dc4f0af1Szrj 
271dc4f0af1Szrj void
release_signals(void * parm)272dc4f0af1Szrj release_signals(void *parm)
273dc4f0af1Szrj 
274dc4f0af1Szrj {
275dc4f0af1Szrj #ifdef HAVE_SIGACTION
276dc4f0af1Szrj     sigprocmask(SIG_UNBLOCK, (sigset_t *)parm, NULL);
277dc4f0af1Szrj #endif
278dc4f0af1Szrj 
279dc4f0af1Szrj #ifdef HAVE_SIGHOLD
280dc4f0af1Szrj     sigrelse(SIGINT);
281dc4f0af1Szrj     sigrelse(SIGQUIT);
282dc4f0af1Szrj     sigrelse(SIGTSTP);
283dc4f0af1Szrj #ifdef SIGWINCH
284dc4f0af1Szrj     sigrelse(SIGWINCH);
285dc4f0af1Szrj #endif
286dc4f0af1Szrj #endif
287dc4f0af1Szrj 
288dc4f0af1Szrj #ifdef BSD_SIGNALS
289dc4f0af1Szrj     (void) sigsetmask((int)parm);
290dc4f0af1Szrj #endif
291dc4f0af1Szrj }
292dc4f0af1Szrj 
293dc4f0af1Szrj /*
294dc4f0af1Szrj  * void do_arguments(globalstate *gstate, int ac, char **av)
295dc4f0af1Szrj  *
296dc4f0af1Szrj  * Arguments processing.  gstate points to the global state,
297dc4f0af1Szrj  * ac and av are the arguments to process.  This can be called
298dc4f0af1Szrj  * multiple times with different sets of arguments.
299dc4f0af1Szrj  */
300dc4f0af1Szrj 
301dc4f0af1Szrj #ifdef HAVE_GETOPT_LONG
302dc4f0af1Szrj static struct option longopts[] = {
303dc4f0af1Szrj     { "color", no_argument, NULL, 'C' },
304dc4f0af1Szrj     { "debug", no_argument, NULL, 'D' },
305dc4f0af1Szrj     { "system-procs", no_argument, NULL, 'S' },
306dc4f0af1Szrj     { "idle-procs", no_argument, NULL, 'I' },
307dc4f0af1Szrj     { "tag-names", no_argument, NULL, 'T' },
308dc4f0af1Szrj     { "all", no_argument, NULL, 'a' },
309dc4f0af1Szrj     { "batch", no_argument, NULL, 'b' },
310dc4f0af1Szrj     { "full-commands", no_argument, NULL, 'c' },
311dc4f0af1Szrj     { "interactive", no_argument, NULL, 'i' },
312dc4f0af1Szrj     { "quick", no_argument, NULL, 'q' },
313dc4f0af1Szrj     { "threads", no_argument, NULL, 't' },
314dc4f0af1Szrj     { "uids", no_argument, NULL, 'u' },
315dc4f0af1Szrj     { "version", no_argument, NULL, 'v' },
316dc4f0af1Szrj     { "delay", required_argument, NULL, 's' },
317dc4f0af1Szrj     { "displays", required_argument, NULL, 'd' },
318dc4f0af1Szrj     { "user", required_argument, NULL, 'U' },
319dc4f0af1Szrj     { "sort-order", required_argument, NULL, 'o' },
320dc4f0af1Szrj     { "display-mode", required_argument, NULL, 'm' },
321dc4f0af1Szrj     { NULL, 0, NULL, 0 },
322dc4f0af1Szrj };
323dc4f0af1Szrj #endif
324dc4f0af1Szrj 
325dc4f0af1Szrj 
326dc4f0af1Szrj void
do_arguments(globalstate * gstate,int ac,char ** av)327dc4f0af1Szrj do_arguments(globalstate *gstate, int ac, char **av)
328dc4f0af1Szrj 
329dc4f0af1Szrj {
330dc4f0af1Szrj     int i;
331dc4f0af1Szrj 
332dc4f0af1Szrj     /* this appears to keep getopt happy */
333dc4f0af1Szrj     optind = 1;
334dc4f0af1Szrj 
335dc4f0af1Szrj #ifdef HAVE_GETOPT_LONG
336dc4f0af1Szrj     while ((i = getopt_long(ac, av, "CDSIMTabcinqtuvs:d:U:o:m:", longopts, NULL)) != -1)
337dc4f0af1Szrj #else
338dc4f0af1Szrj     while ((i = getopt(ac, av, "CDSIMTabcinqtuvs:d:U:o:m:")) != EOF)
339dc4f0af1Szrj #endif
340dc4f0af1Szrj     {
341dc4f0af1Szrj 	switch(i)
342dc4f0af1Szrj 	{
343dc4f0af1Szrj #ifdef ENABLE_COLOR
344dc4f0af1Szrj 	case 'C':
345dc4f0af1Szrj 	    gstate->use_color = !gstate->use_color;
346dc4f0af1Szrj 	    break;
347dc4f0af1Szrj #endif
348dc4f0af1Szrj 
349dc4f0af1Szrj 	case 'D':
350dc4f0af1Szrj 	    debug_set(1);
351dc4f0af1Szrj 	    break;
352dc4f0af1Szrj 
353dc4f0af1Szrj 	case 'v':
354dc4f0af1Szrj 	    fprintf(stderr, "%s: version %s\n", myname, version_string());
355dc4f0af1Szrj 	    exit(EX_OK);
356dc4f0af1Szrj 	    break;
357dc4f0af1Szrj 
358dc4f0af1Szrj 	case 'b':
359dc4f0af1Szrj 	case 'n':
360dc4f0af1Szrj 	    gstate->interactive = No;
361dc4f0af1Szrj 	    break;
362dc4f0af1Szrj 
363dc4f0af1Szrj 	case 'a':
364dc4f0af1Szrj 	    gstate->displays = Infinity;
365dc4f0af1Szrj 	    gstate->topn = Infinity;
366dc4f0af1Szrj 	    break;
367dc4f0af1Szrj 
368dc4f0af1Szrj 	case 'i':
369dc4f0af1Szrj 	    gstate->interactive = Yes;
370dc4f0af1Szrj 	    break;
371dc4f0af1Szrj 
372dc4f0af1Szrj 	case 'o':
373dc4f0af1Szrj 	    gstate->order_name = optarg;
374dc4f0af1Szrj 	    break;
375dc4f0af1Szrj 
376dc4f0af1Szrj 	case 'd':
377dc4f0af1Szrj 	    i = atoiwi(optarg);
378dc4f0af1Szrj 	    if (i == Invalid || i == 0)
379dc4f0af1Szrj 	    {
380dc4f0af1Szrj 		message_error(" Bad display count");
381dc4f0af1Szrj 	    }
382dc4f0af1Szrj 	    else
383dc4f0af1Szrj 	    {
384dc4f0af1Szrj 		gstate->displays = i;
385dc4f0af1Szrj 	    }
386dc4f0af1Szrj 	    break;
387dc4f0af1Szrj 
388dc4f0af1Szrj 	case 's':
389dc4f0af1Szrj 	    i = atoi(optarg);
390dc4f0af1Szrj 	    if (i < 0 || (i == 0 && getuid() != 0))
391dc4f0af1Szrj 	    {
392dc4f0af1Szrj 		message_error(" Bad seconds delay");
393dc4f0af1Szrj 	    }
394dc4f0af1Szrj 	    else
395dc4f0af1Szrj 	    {
396dc4f0af1Szrj 		gstate->delay = i;
397dc4f0af1Szrj 	    }
398dc4f0af1Szrj 	    break;
399dc4f0af1Szrj 
400dc4f0af1Szrj 	case 'u':
401dc4f0af1Szrj 	    gstate->show_usernames = !gstate->show_usernames;
402dc4f0af1Szrj 	    break;
403dc4f0af1Szrj 
404dc4f0af1Szrj 	case 'U':
405dc4f0af1Szrj 	    i = userid(optarg);
406dc4f0af1Szrj 	    if (i == -1)
407dc4f0af1Szrj 	    {
408dc4f0af1Szrj 		message_error(" Unknown user '%s'", optarg);
409dc4f0af1Szrj 	    }
410dc4f0af1Szrj 	    else
411dc4f0af1Szrj 	    {
412dc4f0af1Szrj 		gstate->pselect.uid = i;
413dc4f0af1Szrj 	    }
414dc4f0af1Szrj 	    break;
415dc4f0af1Szrj 
416dc4f0af1Szrj 	case 'm':
417dc4f0af1Szrj 	    i = atoi(optarg);
418dc4f0af1Szrj 	    gstate->pselect.mode = i;
419dc4f0af1Szrj 	    break;
420dc4f0af1Szrj 
421dc4f0af1Szrj 	case 'S':
422dc4f0af1Szrj 	    gstate->pselect.system = !gstate->pselect.system;
423dc4f0af1Szrj 	    break;
424dc4f0af1Szrj 
425dc4f0af1Szrj 	case 'I':
426dc4f0af1Szrj 	    gstate->pselect.idle = !gstate->pselect.idle;
427dc4f0af1Szrj 	    break;
428dc4f0af1Szrj 
429dc4f0af1Szrj         case 'M':
430dc4f0af1Szrj 	    enable_ncpus = 1;
431dc4f0af1Szrj             break;
432dc4f0af1Szrj 
433dc4f0af1Szrj 
434dc4f0af1Szrj #ifdef ENABLE_COLOR
435dc4f0af1Szrj 	case 'T':
436dc4f0af1Szrj 	    gstate->show_tags = 1;
437dc4f0af1Szrj 	    break;
438dc4f0af1Szrj #endif
439dc4f0af1Szrj 
440dc4f0af1Szrj 	case 'c':
441dc4f0af1Szrj 	    gstate->pselect.fullcmd = !gstate->pselect.fullcmd;
442dc4f0af1Szrj 	    break;
443dc4f0af1Szrj 
444dc4f0af1Szrj 	case 't':
445dc4f0af1Szrj 	    gstate->pselect.threads = !gstate->pselect.threads;
446dc4f0af1Szrj 	    break;
447dc4f0af1Szrj 
448dc4f0af1Szrj 	case 'q':		/* be quick about it */
449dc4f0af1Szrj 	    /* only allow this if user is really root */
450dc4f0af1Szrj 	    if (getuid() == 0)
451dc4f0af1Szrj 	    {
452dc4f0af1Szrj 		/* be very un-nice! */
453dc4f0af1Szrj 		(void) nice(-20);
454dc4f0af1Szrj 	    }
455dc4f0af1Szrj 	    else
456dc4f0af1Szrj 	    {
457dc4f0af1Szrj 		message_error(" Option -q can only be used by root");
458dc4f0af1Szrj 	    }
459dc4f0af1Szrj 	    break;
460dc4f0af1Szrj 
461dc4f0af1Szrj 	default:
462dc4f0af1Szrj 	    fprintf(stderr, "\
463dc4f0af1Szrj Top version %s\n\
464dc4f0af1Szrj Usage: %s [-ISTabcinqu] [-d x] [-s x] [-o field] [-U username] [number]\n",
465dc4f0af1Szrj 		    version_string(), myname);
466dc4f0af1Szrj 	    exit(EX_USAGE);
467dc4f0af1Szrj 	}
468dc4f0af1Szrj     }
469dc4f0af1Szrj 
470dc4f0af1Szrj     /* get count of top processes to display */
471dc4f0af1Szrj     if (optind < ac && *av[optind])
472dc4f0af1Szrj     {
473dc4f0af1Szrj 	if ((i = atoiwi(av[optind])) == Invalid)
474dc4f0af1Szrj 	{
475dc4f0af1Szrj 	    message_error(" Process count not a number");
476dc4f0af1Szrj 	}
477dc4f0af1Szrj 	else
478dc4f0af1Szrj 	{
479dc4f0af1Szrj 	    gstate->topn = i;
480dc4f0af1Szrj 	}
481dc4f0af1Szrj     }
482dc4f0af1Szrj }
483dc4f0af1Szrj 
484dc4f0af1Szrj void
do_display(globalstate * gstate)485dc4f0af1Szrj do_display(globalstate *gstate)
486dc4f0af1Szrj 
487dc4f0af1Szrj {
488dc4f0af1Szrj     int active_procs;
489dc4f0af1Szrj     int i;
490dc4f0af1Szrj     time_t curr_time;
491dc4f0af1Szrj     caddr_t processes;
492dc4f0af1Szrj     struct system_info system_info;
493dc4f0af1Szrj     char *hdr;
494dc4f0af1Szrj 
495dc4f0af1Szrj     /* get the time */
496dc4f0af1Szrj     time_mark(&(gstate->now));
497dc4f0af1Szrj     curr_time = (time_t)(gstate->now.tv_sec);
498dc4f0af1Szrj 
499dc4f0af1Szrj     /* get the current stats */
500dc4f0af1Szrj     get_system_info(&system_info);
501dc4f0af1Szrj 
502dc4f0af1Szrj     /* get the current processes */
503dc4f0af1Szrj     processes = get_process_info(&system_info, &(gstate->pselect), gstate->order_index);
504dc4f0af1Szrj 
505dc4f0af1Szrj     /* determine number of processes to actually display */
506dc4f0af1Szrj     if (gstate->topn > 0)
507dc4f0af1Szrj     {
508dc4f0af1Szrj 	/* this number will be the smallest of:  active processes,
509dc4f0af1Szrj 	   number user requested, number current screen accomodates */
510dc4f0af1Szrj 	active_procs = system_info.P_ACTIVE;
511dc4f0af1Szrj 	if (active_procs > gstate->topn)
512dc4f0af1Szrj 	{
513dc4f0af1Szrj 	    active_procs = gstate->topn;
514dc4f0af1Szrj 	}
515dc4f0af1Szrj 	if (active_procs > gstate->max_topn)
516dc4f0af1Szrj 	{
517dc4f0af1Szrj 	    active_procs = gstate->max_topn;
518dc4f0af1Szrj 	}
519dc4f0af1Szrj     }
520dc4f0af1Szrj     else
521dc4f0af1Szrj     {
522dc4f0af1Szrj 	/* dont show any */
523dc4f0af1Szrj 	active_procs = 0;
524dc4f0af1Szrj     }
525dc4f0af1Szrj 
526dc4f0af1Szrj     hdr = gstate->header_text;
527dc4f0af1Szrj 
528dc4f0af1Szrj     /* full screen or update? */
529dc4f0af1Szrj     if (gstate->fulldraw)
530dc4f0af1Szrj     {
531*da0d35cfSMatthew Dillon 	struct timespec uts;
532*da0d35cfSMatthew Dillon 
533*da0d35cfSMatthew Dillon 	clock_gettime(CLOCK_UPTIME, &uts);
534dc4f0af1Szrj 	display_clear();
535dc4f0af1Szrj 	i_loadave(system_info.last_pid, system_info.load_avg);
536*da0d35cfSMatthew Dillon 	i_uptime(uts.tv_sec);
537dc4f0af1Szrj 	i_timeofday(&curr_time);
538dc4f0af1Szrj 	i_procstates(system_info.p_total, system_info.procstates, gstate->pselect.threads);
539dc4f0af1Szrj 	if (gstate->show_cpustates)
540dc4f0af1Szrj 	{
541dc4f0af1Szrj 	    i_cpustates(system_info.cpustates);
542dc4f0af1Szrj 	}
543dc4f0af1Szrj 	else
544dc4f0af1Szrj 	{
545dc4f0af1Szrj 	    if (smart_terminal)
546dc4f0af1Szrj 	    {
547dc4f0af1Szrj 		z_cpustates();
548dc4f0af1Szrj 	    }
549dc4f0af1Szrj 	    gstate->show_cpustates = Yes;
550dc4f0af1Szrj 	}
551dc4f0af1Szrj 	i_kernel(system_info.kernel);
552dc4f0af1Szrj 	i_memory(system_info.memory);
553dc4f0af1Szrj 	i_swap(system_info.swap);
554dc4f0af1Szrj 	i_message(&(gstate->now));
555dc4f0af1Szrj 	i_header(hdr);
556dc4f0af1Szrj 	for (i = 0; i < active_procs; i++)
557dc4f0af1Szrj 	{
558dc4f0af1Szrj 	    i_process(i, format_next_process(processes, gstate->get_userid));
559dc4f0af1Szrj 	}
560dc4f0af1Szrj 	i_endscreen();
561dc4f0af1Szrj 	if (gstate->smart_terminal)
562dc4f0af1Szrj 	{
563dc4f0af1Szrj 	    gstate->fulldraw = No;
564dc4f0af1Szrj 	}
565dc4f0af1Szrj     }
566dc4f0af1Szrj     else
567dc4f0af1Szrj     {
568*da0d35cfSMatthew Dillon 	struct timespec uts;
569*da0d35cfSMatthew Dillon 
570*da0d35cfSMatthew Dillon 	clock_gettime(CLOCK_UPTIME, &uts);
571dc4f0af1Szrj 	u_loadave(system_info.last_pid, system_info.load_avg);
572*da0d35cfSMatthew Dillon 	u_uptime(uts.tv_sec);
573dc4f0af1Szrj 	i_timeofday(&curr_time);
574dc4f0af1Szrj 	u_procstates(system_info.p_total, system_info.procstates, gstate->pselect.threads);
575dc4f0af1Szrj 	u_cpustates(system_info.cpustates);
576dc4f0af1Szrj 	u_kernel(system_info.kernel);
577dc4f0af1Szrj 	u_memory(system_info.memory);
578dc4f0af1Szrj 	u_swap(system_info.swap);
579dc4f0af1Szrj 	u_message(&(gstate->now));
580dc4f0af1Szrj 	u_header(hdr);
581dc4f0af1Szrj 	for (i = 0; i < active_procs; i++)
582dc4f0af1Szrj 	{
583dc4f0af1Szrj 	    u_process(i, format_next_process(processes, gstate->get_userid));
584dc4f0af1Szrj 	}
585dc4f0af1Szrj 	u_endscreen();
586dc4f0af1Szrj     }
587dc4f0af1Szrj }
588dc4f0af1Szrj 
589dc4f0af1Szrj #ifdef DEBUG
590dc4f0af1Szrj void
timeval_xdprint(char * s,struct timeval tv)591dc4f0af1Szrj timeval_xdprint(char *s, struct timeval tv)
592dc4f0af1Szrj 
593dc4f0af1Szrj {
594dc4f0af1Szrj     xdprintf("%s %d.%06d\n", s, tv.tv_sec, tv.tv_usec);
595dc4f0af1Szrj }
596dc4f0af1Szrj #endif
597dc4f0af1Szrj 
598dc4f0af1Szrj void
do_wait(globalstate * gstate)599dc4f0af1Szrj do_wait(globalstate *gstate)
600dc4f0af1Szrj 
601dc4f0af1Szrj {
602dc4f0af1Szrj     struct timeval wait;
603dc4f0af1Szrj 
604dc4f0af1Szrj     wait.tv_sec = gstate->delay;
605dc4f0af1Szrj     wait.tv_usec = 0;
606dc4f0af1Szrj     select(0, NULL, NULL, NULL, &wait);
607dc4f0af1Szrj }
608dc4f0af1Szrj 
609dc4f0af1Szrj void
do_command(globalstate * gstate)610dc4f0af1Szrj do_command(globalstate *gstate)
611dc4f0af1Szrj 
612dc4f0af1Szrj {
613dc4f0af1Szrj     int status;
614dc4f0af1Szrj     struct timeval wait = {0, 0};
615dc4f0af1Szrj     struct timeval now;
616dc4f0af1Szrj     fd_set readfds;
617dc4f0af1Szrj     unsigned char ch;
618dc4f0af1Szrj 
619dc4f0af1Szrj     /* calculate new refresh time */
620dc4f0af1Szrj     gstate->refresh = gstate->now;
621dc4f0af1Szrj     gstate->refresh.tv_sec += gstate->delay;
622dc4f0af1Szrj     time_get(&now);
623dc4f0af1Szrj 
624dc4f0af1Szrj     /* loop waiting for time to expire */
625dc4f0af1Szrj     do {
626dc4f0af1Szrj 	/* calculate time to wait */
627dc4f0af1Szrj 	if (gstate->delay > 0)
628dc4f0af1Szrj 	{
629dc4f0af1Szrj 	    wait = gstate->refresh;
630dc4f0af1Szrj 	    wait.tv_usec -= now.tv_usec;
631dc4f0af1Szrj 	    if (wait.tv_usec < 0)
632dc4f0af1Szrj 	    {
633dc4f0af1Szrj 		wait.tv_usec += 1000000;
634dc4f0af1Szrj 		wait.tv_sec--;
635dc4f0af1Szrj 	    }
636dc4f0af1Szrj 	    wait.tv_sec -= now.tv_sec;
637dc4f0af1Szrj 	}
638dc4f0af1Szrj 
639dc4f0af1Szrj 	/* set up arguments for select on stdin (0) */
640dc4f0af1Szrj 	FD_ZERO(&readfds);
641dc4f0af1Szrj 	FD_SET(STDIN_FILENO, &readfds);
642dc4f0af1Szrj 
643dc4f0af1Szrj 	/* wait for something to read or time out */
644dc4f0af1Szrj 	if (select(32, &readfds, NULL, NULL, &wait) > 0)
645dc4f0af1Szrj 	{
646dc4f0af1Szrj 	    /* read it */
647dc4f0af1Szrj 	    if (read(STDIN_FILENO, &ch, 1) != 1)
648dc4f0af1Szrj 	    {
649dc4f0af1Szrj 		/* read error */
650dc4f0af1Szrj 		message_error(" Read error on stdin");
651dc4f0af1Szrj 		quit(EX_DATAERR);
652dc4f0af1Szrj 		/*NOTREACHED*/
653dc4f0af1Szrj 	    }
654dc4f0af1Szrj 
655dc4f0af1Szrj 	    /* mark pending messages as old */
656dc4f0af1Szrj 	    message_mark();
657dc4f0af1Szrj 
658dc4f0af1Szrj 	    /* dispatch */
659dc4f0af1Szrj 	    status = command_process(gstate, (int)ch);
660dc4f0af1Szrj 	    switch(status)
661dc4f0af1Szrj 	    {
662dc4f0af1Szrj 	    case CMD_ERROR:
663dc4f0af1Szrj 		quit(EX_SOFTWARE);
664dc4f0af1Szrj 		/*NOTREACHED*/
665dc4f0af1Szrj 
666dc4f0af1Szrj 	    case CMD_REFRESH:
667dc4f0af1Szrj 		return;
668dc4f0af1Szrj 
669dc4f0af1Szrj 	    case CMD_UNKNOWN:
670dc4f0af1Szrj 		message_error(" Unknown command");
671dc4f0af1Szrj 		break;
672dc4f0af1Szrj 
673dc4f0af1Szrj 	    case CMD_NA:
674dc4f0af1Szrj 		message_error(" Command not available");
675dc4f0af1Szrj 	    }
676dc4f0af1Szrj 	}
677dc4f0af1Szrj 
678dc4f0af1Szrj 	/* get new time */
679dc4f0af1Szrj 	time_get(&now);
680dc4f0af1Szrj     } while (timercmp(&now, &(gstate->refresh), < ));
681dc4f0af1Szrj }
682dc4f0af1Szrj 
683dc4f0af1Szrj void
do_minidisplay(globalstate * gstate)684dc4f0af1Szrj do_minidisplay(globalstate *gstate)
685dc4f0af1Szrj 
686dc4f0af1Szrj {
687dc4f0af1Szrj     int real_delay;
688dc4f0af1Szrj     struct system_info si;
689dc4f0af1Szrj 
690dc4f0af1Szrj     /* save the real delay and substitute 1 second */
691dc4f0af1Szrj     real_delay = gstate->delay;
692dc4f0af1Szrj     gstate->delay = 1;
693dc4f0af1Szrj 
694dc4f0af1Szrj     /* wait 1 second for a command */
695dc4f0af1Szrj     time_mark(&(gstate->now));
696dc4f0af1Szrj     do_command(gstate);
697dc4f0af1Szrj 
698dc4f0af1Szrj     /* do a mini update that only updates the cpustates */
699dc4f0af1Szrj     get_system_info(&si);
700dc4f0af1Szrj     u_cpustates(si.cpustates);
701dc4f0af1Szrj 
702dc4f0af1Szrj     /* restore the delay time */
703dc4f0af1Szrj     gstate->delay = real_delay;
704dc4f0af1Szrj 
705dc4f0af1Szrj     /* done */
706dc4f0af1Szrj     i_endscreen();
707dc4f0af1Szrj }
708dc4f0af1Szrj 
709dc4f0af1Szrj int
main(int argc,char * argv[])710dc4f0af1Szrj main(int argc, char *argv[])
711dc4f0af1Szrj 
712dc4f0af1Szrj {
713dc4f0af1Szrj     char *env_top;
714dc4f0af1Szrj     char **preset_argv;
715dc4f0af1Szrj     int preset_argc = 0;
716dc4f0af1Szrj     void *mask;
717dc4f0af1Szrj     int need_mini = 1;
718dc4f0af1Szrj 
719dc4f0af1Szrj     struct statics statics;
720dc4f0af1Szrj     globalstate *gstate;
721dc4f0af1Szrj 
722dc4f0af1Szrj     /* get our name */
723dc4f0af1Szrj     if (argc > 0)
724dc4f0af1Szrj     {
7255e83d98bSSascha Wildner 	if ((myname = strrchr(argv[0], '/')) == NULL)
726dc4f0af1Szrj 	{
727dc4f0af1Szrj 	    myname = argv[0];
728dc4f0af1Szrj 	}
729dc4f0af1Szrj 	else
730dc4f0af1Szrj 	{
731dc4f0af1Szrj 	    myname++;
732dc4f0af1Szrj 	}
733dc4f0af1Szrj     }
734dc4f0af1Szrj 
735dc4f0af1Szrj     /* binary compatibility check */
736dc4f0af1Szrj #ifdef HAVE_UNAME
737dc4f0af1Szrj     {
738dc4f0af1Szrj 	struct utsname uts;
739dc4f0af1Szrj 
740dc4f0af1Szrj 	if (uname(&uts) == 0)
741dc4f0af1Szrj 	{
742dc4f0af1Szrj 	    if (strcmp(uts.machine, UNAME_HARDWARE) != 0)
743dc4f0af1Szrj 	    {
744dc4f0af1Szrj 		fprintf(stderr, "%s: incompatible hardware platform\n",
745dc4f0af1Szrj 			myname);
746dc4f0af1Szrj 		exit(EX_UNAVAILABLE);
747dc4f0af1Szrj 	    }
748dc4f0af1Szrj 	}
749dc4f0af1Szrj     }
750dc4f0af1Szrj #endif
751dc4f0af1Szrj 
752dc4f0af1Szrj     /* initialization */
753dc4f0af1Szrj     gstate = (globalstate *)calloc(1, sizeof(globalstate));
754dc4f0af1Szrj     gstate->statics = &statics;
755dc4f0af1Szrj     time_mark(NULL);
756dc4f0af1Szrj 
757dc4f0af1Szrj     /* preset defaults for various options */
758dc4f0af1Szrj     gstate->show_usernames = Yes;
759dc4f0af1Szrj     gstate->topn = DEFAULT_TOPN;
760dc4f0af1Szrj     gstate->delay = DEFAULT_DELAY;
761dc4f0af1Szrj     gstate->fulldraw = Yes;
762dc4f0af1Szrj     gstate->use_color = Yes;
763dc4f0af1Szrj     gstate->interactive = Maybe;
764dc4f0af1Szrj 
765dc4f0af1Szrj     /* preset defaults for process selection */
766dc4f0af1Szrj     gstate->pselect.idle = Yes;
767dc4f0af1Szrj     gstate->pselect.system = No;
768dc4f0af1Szrj     gstate->pselect.fullcmd = No;
769dc4f0af1Szrj     gstate->pselect.command = NULL;
770dc4f0af1Szrj     gstate->pselect.uid = -1;
771dc4f0af1Szrj     gstate->pselect.mode = 0;
772dc4f0af1Szrj 
773dc4f0af1Szrj     /* use a large buffer for stdout */
774dc4f0af1Szrj #ifdef HAVE_SETVBUF
775dc4f0af1Szrj     setvbuf(stdout, stdoutbuf, _IOFBF, BUFFERSIZE);
776dc4f0af1Szrj #else
777dc4f0af1Szrj #ifdef HAVE_SETBUFFER
778dc4f0af1Szrj     setbuffer(stdout, stdoutbuf, BUFFERSIZE);
779dc4f0af1Szrj #endif
780dc4f0af1Szrj #endif
781dc4f0af1Szrj 
782dc4f0af1Szrj     /* get preset options from the environment */
783dc4f0af1Szrj     if ((env_top = getenv("TOP")) != NULL)
784dc4f0af1Szrj     {
785dc4f0af1Szrj 	preset_argv = argparse(env_top, &preset_argc);
786dc4f0af1Szrj 	preset_argv[0] = myname;
787dc4f0af1Szrj 	do_arguments(gstate, preset_argc, preset_argv);
788dc4f0af1Szrj     }
789dc4f0af1Szrj 
790dc4f0af1Szrj     /* process arguments */
791dc4f0af1Szrj     do_arguments(gstate, argc, argv);
792dc4f0af1Szrj 
793dc4f0af1Szrj #ifdef ENABLE_COLOR
794dc4f0af1Szrj     /* If colour has been turned on read in the settings. */
795dc4f0af1Szrj     env_top = getenv("TOPCOLOURS");
796dc4f0af1Szrj     if (!env_top)
797dc4f0af1Szrj     {
798dc4f0af1Szrj 	env_top = getenv("TOPCOLORS");
799dc4f0af1Szrj     }
800dc4f0af1Szrj     /* must do something about error messages */
801dc4f0af1Szrj     color_env_parse(env_top);
802dc4f0af1Szrj     color_activate(gstate->use_color);
803dc4f0af1Szrj #endif
804dc4f0af1Szrj 
805dc4f0af1Szrj     /* in order to support forward compatability, we have to ensure that
806dc4f0af1Szrj        the entire statics structure is set to a known value before we call
807dc4f0af1Szrj        machine_init.  This way fields that a module does not know about
808dc4f0af1Szrj        will retain their default values */
809dc4f0af1Szrj     memzero((void *)&statics, sizeof(statics));
810dc4f0af1Szrj 
811dc4f0af1Szrj     /* call the platform-specific init */
812dc4f0af1Szrj     if (machine_init(&statics) == -1)
813dc4f0af1Szrj     {
814dc4f0af1Szrj 	exit(EX_SOFTWARE);
815dc4f0af1Szrj     }
816dc4f0af1Szrj 
817dc4f0af1Szrj     /* create a helper list of sort order names */
818dc4f0af1Szrj     gstate->order_namelist = string_list(statics.order_names);
819dc4f0af1Szrj 
820dc4f0af1Szrj     /* look up chosen sorting order */
821dc4f0af1Szrj     if (gstate->order_name != NULL)
822dc4f0af1Szrj     {
823dc4f0af1Szrj 	int i;
824dc4f0af1Szrj 
825dc4f0af1Szrj 	if (statics.order_names == NULL)
826dc4f0af1Szrj 	{
827dc4f0af1Szrj 	    message_error(" This platform does not support arbitrary ordering");
828dc4f0af1Szrj 	}
829dc4f0af1Szrj 	else if ((i = string_index(gstate->order_name,
830dc4f0af1Szrj 				   statics.order_names)) == -1)
831dc4f0af1Szrj 	{
832dc4f0af1Szrj 	    message_error(" Sort order `%s' not recognized", gstate->order_name);
833dc4f0af1Szrj 	    message_error(" Recognized sort orders: %s", gstate->order_namelist);
834dc4f0af1Szrj 	}
835dc4f0af1Szrj 	else
836dc4f0af1Szrj 	{
837dc4f0af1Szrj 	    gstate->order_index = i;
838dc4f0af1Szrj 	}
839dc4f0af1Szrj     }
840dc4f0af1Szrj 
841dc4f0af1Szrj     /* initialize extensions */
842dc4f0af1Szrj     init_username();
843dc4f0af1Szrj 
844dc4f0af1Szrj     /* initialize termcap */
845dc4f0af1Szrj     gstate->smart_terminal = screen_readtermcap(gstate->interactive);
846dc4f0af1Szrj 
847dc4f0af1Szrj     /* determine interactive state */
848dc4f0af1Szrj     if (gstate->interactive == Maybe)
849dc4f0af1Szrj     {
850dc4f0af1Szrj 	gstate->interactive = smart_terminal;
851dc4f0af1Szrj     }
852dc4f0af1Szrj 
853dc4f0af1Szrj     /* if displays were not specified, choose an appropriate default */
854dc4f0af1Szrj     if (gstate->displays == 0)
855dc4f0af1Szrj     {
856dc4f0af1Szrj 	gstate->displays = gstate->smart_terminal ? Infinity: 1;
857dc4f0af1Szrj     }
858dc4f0af1Szrj 
859dc4f0af1Szrj     /* we don't need a mini display when delay is less than 2
860dc4f0af1Szrj        seconds or when we are not on a smart terminal */
861dc4f0af1Szrj     if (gstate->delay <= 1 || !smart_terminal)
862dc4f0af1Szrj     {
863dc4f0af1Szrj 	need_mini = 0;
864dc4f0af1Szrj     }
865dc4f0af1Szrj 
866dc4f0af1Szrj     /* set constants for username/uid display */
867dc4f0af1Szrj     if (gstate->show_usernames)
868dc4f0af1Szrj     {
869dc4f0af1Szrj 	gstate->header_text = format_header("USERNAME");
870dc4f0af1Szrj 	gstate->get_userid = username;
871dc4f0af1Szrj     }
872dc4f0af1Szrj     else
873dc4f0af1Szrj     {
874dc4f0af1Szrj 	gstate->header_text = format_header("   UID  ");
875dc4f0af1Szrj 	gstate->get_userid = itoa7;
876dc4f0af1Szrj     }
877dc4f0af1Szrj     gstate->pselect.usernames = gstate->show_usernames;
878dc4f0af1Szrj 
879dc4f0af1Szrj     /* initialize display */
880dc4f0af1Szrj     if ((gstate->max_topn = display_init(&statics)) == -1)
881dc4f0af1Szrj     {
882dc4f0af1Szrj 	fprintf(stderr, "%s: can't allocate sufficient memory\n", myname);
883dc4f0af1Szrj 	exit(EX_OSERR);
884dc4f0af1Szrj     }
885dc4f0af1Szrj 
886dc4f0af1Szrj     /* check for infinity and for overflowed screen */
887dc4f0af1Szrj     if (gstate->topn == Infinity)
888dc4f0af1Szrj     {
889dc4f0af1Szrj 	gstate->topn = INT_MAX;
890dc4f0af1Szrj     }
891dc4f0af1Szrj     else if (gstate->topn > gstate->max_topn)
892dc4f0af1Szrj     {
893dc4f0af1Szrj #if 0
894dc4f0af1Szrj 	message_error(" This terminal can only display %d processes",
895dc4f0af1Szrj 		      gstate->max_topn);
896dc4f0af1Szrj #endif
897dc4f0af1Szrj     }
898dc4f0af1Szrj 
899dc4f0af1Szrj #ifdef ENABLE_COLOR
900dc4f0af1Szrj     /* producing a list of color tags is easy */
901dc4f0af1Szrj     if (gstate->show_tags)
902dc4f0af1Szrj     {
903dc4f0af1Szrj 	color_dump(stdout);
904dc4f0af1Szrj 	exit(EX_OK);
905dc4f0af1Szrj     }
906dc4f0af1Szrj #endif
907dc4f0af1Szrj 
908dc4f0af1Szrj     /* hold all signals while we initialize the screen */
909dc4f0af1Szrj     mask = hold_signals();
910dc4f0af1Szrj     screen_init();
911dc4f0af1Szrj 
912dc4f0af1Szrj     /* set the signal handlers */
913dc4f0af1Szrj     set_signals();
914dc4f0af1Szrj 
915dc4f0af1Szrj     /* longjmp re-entry point */
916dc4f0af1Szrj     /* set the jump buffer for long jumps out of signal handlers */
917dc4f0af1Szrj     if (setjmp(jmp_int) != 0)
918dc4f0af1Szrj     {
919dc4f0af1Szrj 	/* this is where we end up after processing sigwinch or sigtstp */
920dc4f0af1Szrj 
921dc4f0af1Szrj 	/* tell display to resize its buffers, and get the new length */
922dc4f0af1Szrj 	if ((gstate->max_topn = display_resize()) == -1)
923dc4f0af1Szrj 	{
924dc4f0af1Szrj 	    /* thats bad */
925dc4f0af1Szrj 	    quit(EX_OSERR);
926dc4f0af1Szrj 	    /*NOTREACHED*/
927dc4f0af1Szrj 	}
928dc4f0af1Szrj 
929dc4f0af1Szrj 	/* set up for a full redraw, and get the current line count */
930dc4f0af1Szrj 	gstate->fulldraw = Yes;
931dc4f0af1Szrj 
932dc4f0af1Szrj 	/* safe to release the signals now */
933dc4f0af1Szrj 	release_signals(mask);
934dc4f0af1Szrj     }
935dc4f0af1Szrj     else
936dc4f0af1Szrj     {
937dc4f0af1Szrj 	/* release the signals */
938dc4f0af1Szrj 	release_signals(mask);
939dc4f0af1Szrj 
940dc4f0af1Szrj 	/* some systems require a warmup */
941dc4f0af1Szrj 	/* always do a warmup for batch mode */
942dc4f0af1Szrj 	if (gstate->interactive == 0 || statics.flags.warmup)
943dc4f0af1Szrj 	{
944dc4f0af1Szrj 	    struct system_info system_info;
945dc4f0af1Szrj 	    struct timeval timeout;
946dc4f0af1Szrj 
947dc4f0af1Szrj 	    time_mark(&(gstate->now));
948dc4f0af1Szrj 	    get_system_info(&system_info);
949dc4f0af1Szrj 	    (void)get_process_info(&system_info, &gstate->pselect, 0);
950dc4f0af1Szrj 	    timeout.tv_sec = 1;
951dc4f0af1Szrj 	    timeout.tv_usec = 0;
952dc4f0af1Szrj 	    select(0, NULL, NULL, NULL, &timeout);
953dc4f0af1Szrj 
954dc4f0af1Szrj 	    /* if we've warmed up, then we can show good states too */
955dc4f0af1Szrj 	    gstate->show_cpustates = Yes;
956dc4f0af1Szrj 	    need_mini = 0;
957dc4f0af1Szrj 	}
958dc4f0af1Szrj     }
959dc4f0af1Szrj 
960dc4f0af1Szrj     /* main loop */
961dc4f0af1Szrj     while ((gstate->displays == -1) || (--gstate->displays > 0))
962dc4f0af1Szrj     {
963dc4f0af1Szrj 	do_display(gstate);
964dc4f0af1Szrj 	if (gstate->interactive)
965dc4f0af1Szrj 	{
966dc4f0af1Szrj 	    if (need_mini)
967dc4f0af1Szrj 	    {
968dc4f0af1Szrj 		do_minidisplay(gstate);
969dc4f0af1Szrj 		need_mini = 0;
970dc4f0af1Szrj 	    }
971dc4f0af1Szrj 	    do_command(gstate);
972dc4f0af1Szrj 	}
973dc4f0af1Szrj 	else
974dc4f0af1Szrj 	{
975dc4f0af1Szrj 	    do_wait(gstate);
976dc4f0af1Szrj 	}
977dc4f0af1Szrj     }
978dc4f0af1Szrj 
979dc4f0af1Szrj     /* do one last display */
980dc4f0af1Szrj     do_display(gstate);
981dc4f0af1Szrj 
982dc4f0af1Szrj     quit(EX_OK);
983dc4f0af1Szrj     /* NOTREACHED */
984dc4f0af1Szrj     return 1; /* Keep compiler quiet. */
985dc4f0af1Szrj }
986