main.c revision 1.28 1 /* $NetBSD: main.c,v 1.28 2000/12/01 02:19:44 simonb Exp $ */
2
3 /*-
4 * Copyright (c) 1980, 1992, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include <sys/cdefs.h>
37 #ifndef lint
38 __COPYRIGHT("@(#) Copyright (c) 1980, 1992, 1993\n\
39 The Regents of the University of California. All rights reserved.\n");
40 #if 0
41 static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93";
42 #endif
43 __RCSID("$NetBSD: main.c,v 1.28 2000/12/01 02:19:44 simonb Exp $");
44 #endif /* not lint */
45
46 #include <sys/param.h>
47
48 #include <ctype.h>
49 #include <err.h>
50 #include <limits.h>
51 #include <signal.h>
52 #include <stdarg.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <unistd.h>
57
58 #include "systat.h"
59 #include "extern.h"
60
61 static struct nlist namelist[] = {
62 #define X_FIRST 0
63 #define X_HZ 0
64 { "_hz" },
65 #define X_STATHZ 1
66 { "_stathz" },
67 { "" }
68 };
69 static int dellave;
70
71 kvm_t *kd;
72 char *memf = NULL;
73 char *nlistf = NULL;
74 sig_t sigtstpdfl;
75 double avenrun[3];
76 int col;
77 int naptime = 5;
78 int verbose = 1; /* to report kvm read errs */
79 int hz, stathz;
80 char c;
81 char *namp;
82 char hostname[MAXHOSTNAMELEN + 1];
83 WINDOW *wnd;
84 int CMDLINE;
85 int turns = 2; /* stay how many refresh-turns in 'all' mode? */
86 int allflag;
87 int allcounter;
88
89 static WINDOW *wload; /* one line window for load average */
90
91 static void usage(void);
92 int main(int, char **);
93
94 gid_t egid; /* XXX needed by initiostat() and initkre() */
95
96 int
97 main(int argc, char **argv)
98 {
99 int ch;
100 char errbuf[_POSIX2_LINE_MAX];
101
102 egid = getegid();
103 (void)setegid(getgid());
104
105 while ((ch = getopt(argc, argv, "M:N:nw:t:")) != -1)
106 switch(ch) {
107 case 'M':
108 memf = optarg;
109 break;
110 case 'N':
111 nlistf = optarg;
112 break;
113 case 'n':
114 nflag = !nflag;
115 break;
116 case 'w':
117 if ((naptime = atoi(optarg)) <= 0)
118 errx(1, "interval <= 0.");
119 break;
120 case 't':
121 if ((turns = atoi(optarg)) <= 0)
122 errx(1, "turns <= 0.");
123 break;
124 case '?':
125 default:
126 usage();
127 }
128 argc -= optind;
129 argv += optind;
130
131
132 for ( ; argc > 0; argc--, argv++) {
133 struct mode *p;
134 int modefound = 0;
135
136 if (isdigit(argv[0][0])) {
137 naptime = atoi(argv[0]);
138 if (naptime <= 0)
139 naptime = 5;
140 continue;
141 }
142
143 for (p = modes; p->c_name ; p++) {
144 if (strstr(p->c_name, argv[0]) == p->c_name) {
145 curmode = p;
146 modefound++;
147 break;
148 }
149
150 if(strstr("all",argv[0]) == "all"){
151 allcounter=0;
152 allflag=1;
153 }
154 }
155
156
157 if (!modefound && !allflag)
158 error("%s: Unknown command.", argv[0]);
159 }
160
161 /*
162 * Discard setgid privileges. If not the running kernel, we toss
163 * them away totally so that bad guys can't print interesting stuff
164 * from kernel memory, otherwise switch back to kmem for the
165 * duration of the kvm_openfiles() call.
166 */
167 if (nlistf != NULL || memf != NULL)
168 (void)setgid(getgid());
169 else
170 (void)setegid(egid);
171
172 kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
173 if (kd == NULL) {
174 error("%s", errbuf);
175 exit(1);
176 }
177
178 /* Get rid of privs for now. */
179 if (nlistf == NULL && memf == NULL)
180 (void)setegid(getgid());
181
182 if (kvm_nlist(kd, namelist)) {
183 nlisterr(namelist);
184 exit(1);
185 }
186 if (namelist[X_FIRST].n_type == 0)
187 errx(1, "couldn't read namelist");
188 signal(SIGINT, die);
189 signal(SIGQUIT, die);
190 signal(SIGTERM, die);
191 signal(SIGWINCH, redraw);
192
193 /*
194 * Initialize display. Load average appears in a one line
195 * window of its own. Current command's display appears in
196 * an overlapping sub-window of stdscr configured by the display
197 * routines to minimize update work by curses.
198 */
199 if (initscr() == NULL)
200 {
201 warnx("couldn't initialize screen");
202 exit(0);
203 }
204
205 CMDLINE = LINES - 1;
206 wnd = (*curmode->c_open)();
207 if (wnd == NULL) {
208 warnx("couldn't initialize display");
209 die(0);
210 }
211 wload = newwin(1, 0, 3, 20);
212 if (wload == NULL) {
213 warnx("couldn't set up load average window");
214 die(0);
215 }
216 gethostname(hostname, sizeof (hostname));
217 hostname[sizeof(hostname) - 1] = '\0';
218 NREAD(X_HZ, &hz, sizeof hz);
219 NREAD(X_STATHZ, &stathz, sizeof stathz);
220 (*curmode->c_init)();
221 curmode->c_flags |= CF_INIT;
222 labels();
223
224 dellave = 0.0;
225
226 signal(SIGALRM, display);
227 display(0);
228 noecho();
229 crmode();
230 keyboard();
231 /*NOTREACHED*/
232 }
233
234 static void
235 usage(void)
236 {
237 fprintf(stderr, "usage: systat [-n] [-M core] [-N system] [-w wait] "
238 "[-t turns]\n\t\t[display] [refresh-interval]\n");
239 exit(1);
240 }
241
242
243 void
244 labels(void)
245 {
246 if (curmode->c_flags & CF_LOADAV) {
247 mvaddstr(2, 20,
248 "/0 /1 /2 /3 /4 /5 /6 /7 /8 /9 /10");
249 mvaddstr(3, 5, "Load Average");
250 }
251 (*curmode->c_label)();
252 #ifdef notdef
253 mvprintw(21, 25, "CPU usage on %s", hostname);
254 #endif
255 refresh();
256 }
257
258 void
259 display(int signo)
260 {
261 int j;
262 sigset_t set;
263 struct mode *p;
264
265 sigemptyset(&set);
266 sigaddset(&set, SIGALRM);
267 sigprocmask(SIG_BLOCK, &set, NULL);
268
269 /* Get the load average over the last minute. */
270 (void)getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0]));
271 (*curmode->c_fetch)();
272 if (curmode->c_flags & CF_LOADAV) {
273 j = 5.0*avenrun[0] + 0.5;
274 dellave -= avenrun[0];
275 if (dellave >= 0.0)
276 c = '<';
277 else {
278 c = '>';
279 dellave = -dellave;
280 }
281 if (dellave < 0.1)
282 c = '|';
283 dellave = avenrun[0];
284 wmove(wload, 0, 0);
285 wclrtoeol(wload);
286 whline(wload, c, (j > 50) ? 50 : j);
287 if (j > 50)
288 wprintw(wload, " %4.1f", avenrun[0]);
289 }
290 (*curmode->c_refresh)();
291 if (curmode->c_flags & CF_LOADAV)
292 wrefresh(wload);
293 wrefresh(wnd);
294 move(CMDLINE, col);
295 refresh();
296
297 if (allflag && signo==SIGALRM) {
298 if (allcounter >= turns){
299 p = curmode;
300 p++;
301 if (p->c_name == NULL)
302 p = modes;
303 switch_mode(p);
304 allcounter=0;
305 } else
306 allcounter++;
307 }
308
309 sigprocmask(SIG_UNBLOCK, &set, NULL);
310 alarm(naptime);
311 }
312
313 void
314 redraw(int signo)
315 {
316 sigset_t set;
317
318 sigemptyset(&set);
319 sigaddset(&set, SIGALRM);
320 sigprocmask(SIG_BLOCK, &set, NULL);
321 wrefresh(curscr);
322 refresh();
323 sigprocmask(SIG_UNBLOCK, &set, NULL);
324 }
325
326 void
327 die(int signo)
328 {
329 move(CMDLINE, 0);
330 clrtoeol();
331 refresh();
332 endwin();
333 exit(0);
334 }
335
336 void
337 error(const char *fmt, ...)
338 {
339 va_list ap;
340 char buf[255];
341 int oy, ox;
342
343 va_start(ap, fmt);
344
345 if (wnd) {
346 getyx(stdscr, oy, ox);
347 (void) vsnprintf(buf, sizeof(buf), fmt, ap);
348 clrtoeol();
349 standout();
350 mvaddstr(CMDLINE, 0, buf);
351 standend();
352 move(oy, ox);
353 refresh();
354 } else {
355 (void) vfprintf(stderr, fmt, ap);
356 fprintf(stderr, "\n");
357 }
358 va_end(ap);
359 }
360
361 void
362 nlisterr(struct nlist namelist[])
363 {
364 int i, n;
365
366 n = 0;
367 clear();
368 mvprintw(2, 10, "systat: nlist: can't find following symbols:");
369 for (i = 0;
370 namelist[i].n_name != NULL && *namelist[i].n_name != '\0'; i++)
371 if (namelist[i].n_value == 0)
372 mvprintw(2 + ++n, 10, "%s", namelist[i].n_name);
373 move(CMDLINE, 0);
374 clrtoeol();
375 refresh();
376 endwin();
377 exit(1);
378 }
379