main.c revision 1.27 1 /* $NetBSD: main.c,v 1.27 2000/08/25 04:48:56 hubertf 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.27 2000/08/25 04:48:56 hubertf Exp $");
44 #endif /* not lint */
45
46 #include <sys/param.h>
47
48 #include <err.h>
49 #include <limits.h>
50 #include <nlist.h>
51 #include <signal.h>
52 #include <stdio.h>
53 #include <string.h>
54 #include <unistd.h>
55 #include <stdlib.h>
56 #include <ctype.h>
57 #include <stdarg.h>
58
59 #include "systat.h"
60 #include "extern.h"
61
62 static struct nlist namelist[] = {
63 #define X_FIRST 0
64 #define X_HZ 0
65 { "_hz" },
66 #define X_STATHZ 1
67 { "_stathz" },
68 { "" }
69 };
70 static int dellave;
71
72 kvm_t *kd;
73 char *memf = NULL;
74 char *nlistf = NULL;
75 sig_t sigtstpdfl;
76 double avenrun[3];
77 int col;
78 int naptime = 5;
79 int verbose = 1; /* to report kvm read errs */
80 int hz, stathz;
81 char c;
82 char *namp;
83 char hostname[MAXHOSTNAMELEN + 1];
84 WINDOW *wnd;
85 int CMDLINE;
86 int turns = 2; /* stay how many refresh-turns in 'all' mode? */
87 int allflag;
88 int allcounter;
89
90 static WINDOW *wload; /* one line window for load average */
91
92 static void usage(void);
93 int main(int, char **);
94
95 gid_t egid; /* XXX needed by initiostat() and initkre() */
96
97 int
98 main(int argc, char **argv)
99 {
100 int ch;
101 char errbuf[_POSIX2_LINE_MAX];
102
103 egid = getegid();
104 (void)setegid(getgid());
105
106 while ((ch = getopt(argc, argv, "M:N:nw:t:")) != -1)
107 switch(ch) {
108 case 'M':
109 memf = optarg;
110 break;
111 case 'N':
112 nlistf = optarg;
113 break;
114 case 'n':
115 nflag = !nflag;
116 break;
117 case 'w':
118 if ((naptime = atoi(optarg)) <= 0)
119 errx(1, "interval <= 0.");
120 break;
121 case 't':
122 if ((turns = atoi(optarg)) <= 0)
123 errx(1, "turns <= 0.");
124 break;
125 case '?':
126 default:
127 usage();
128 }
129 argc -= optind;
130 argv += optind;
131
132
133 for ( ; argc > 0; argc--, argv++) {
134 struct mode *p;
135 int modefound = 0;
136
137 if (isdigit(argv[0][0])) {
138 naptime = atoi(argv[0]);
139 if (naptime <= 0)
140 naptime = 5;
141 continue;
142 }
143
144 for (p = modes; p->c_name ; p++) {
145 if (strstr(p->c_name, argv[0]) == p->c_name) {
146 curmode = p;
147 modefound++;
148 break;
149 }
150
151 if(strstr("all",argv[0]) == "all"){
152 allcounter=0;
153 allflag=1;
154 }
155 }
156
157
158 if (!modefound && !allflag)
159 error("%s: Unknown command.", argv[0]);
160 }
161
162 /*
163 * Discard setgid privileges. If not the running kernel, we toss
164 * them away totally so that bad guys can't print interesting stuff
165 * from kernel memory, otherwise switch back to kmem for the
166 * duration of the kvm_openfiles() call.
167 */
168 if (nlistf != NULL || memf != NULL)
169 (void)setgid(getgid());
170 else
171 (void)setegid(egid);
172
173 kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
174 if (kd == NULL) {
175 error("%s", errbuf);
176 exit(1);
177 }
178
179 /* Get rid of privs for now. */
180 if (nlistf == NULL && memf == NULL)
181 (void)setegid(getgid());
182
183 if (kvm_nlist(kd, namelist)) {
184 nlisterr(namelist);
185 exit(1);
186 }
187 if (namelist[X_FIRST].n_type == 0)
188 errx(1, "couldn't read namelist");
189 signal(SIGINT, die);
190 signal(SIGQUIT, die);
191 signal(SIGTERM, die);
192 signal(SIGWINCH, redraw);
193
194 /*
195 * Initialize display. Load average appears in a one line
196 * window of its own. Current command's display appears in
197 * an overlapping sub-window of stdscr configured by the display
198 * routines to minimize update work by curses.
199 */
200 if (initscr() == NULL)
201 {
202 warnx("couldn't initialize screen");
203 exit(0);
204 }
205
206 CMDLINE = LINES - 1;
207 wnd = (*curmode->c_open)();
208 if (wnd == NULL) {
209 warnx("couldn't initialize display");
210 die(0);
211 }
212 wload = newwin(1, 0, 3, 20);
213 if (wload == NULL) {
214 warnx("couldn't set up load average window");
215 die(0);
216 }
217 gethostname(hostname, sizeof (hostname));
218 hostname[sizeof(hostname) - 1] = '\0';
219 NREAD(X_HZ, &hz, sizeof hz);
220 NREAD(X_STATHZ, &stathz, sizeof stathz);
221 (*curmode->c_init)();
222 curmode->c_flags |= CF_INIT;
223 labels();
224
225 dellave = 0.0;
226
227 signal(SIGALRM, display);
228 display(0);
229 noecho();
230 crmode();
231 keyboard();
232 /*NOTREACHED*/
233 }
234
235 static void
236 usage(void)
237 {
238 fprintf(stderr, "usage: systat [-n] [-M core] [-N system] [-w wait] "
239 "[-t turns]\n\t\t[display] [refresh-interval]\n");
240 exit(1);
241 }
242
243
244 void
245 labels(void)
246 {
247 if (curmode->c_flags & CF_LOADAV) {
248 mvaddstr(2, 20,
249 "/0 /1 /2 /3 /4 /5 /6 /7 /8 /9 /10");
250 mvaddstr(3, 5, "Load Average");
251 }
252 (*curmode->c_label)();
253 #ifdef notdef
254 mvprintw(21, 25, "CPU usage on %s", hostname);
255 #endif
256 refresh();
257 }
258
259 void
260 display(int signo)
261 {
262 int j;
263 sigset_t set;
264 struct mode *p;
265
266 sigemptyset(&set);
267 sigaddset(&set, SIGALRM);
268 sigprocmask(SIG_BLOCK, &set, NULL);
269
270 /* Get the load average over the last minute. */
271 (void)getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0]));
272 (*curmode->c_fetch)();
273 if (curmode->c_flags & CF_LOADAV) {
274 j = 5.0*avenrun[0] + 0.5;
275 dellave -= avenrun[0];
276 if (dellave >= 0.0)
277 c = '<';
278 else {
279 c = '>';
280 dellave = -dellave;
281 }
282 if (dellave < 0.1)
283 c = '|';
284 dellave = avenrun[0];
285 wmove(wload, 0, 0);
286 wclrtoeol(wload);
287 whline(wload, c, (j > 50) ? 50 : j);
288 if (j > 50)
289 wprintw(wload, " %4.1f", avenrun[0]);
290 }
291 (*curmode->c_refresh)();
292 if (curmode->c_flags & CF_LOADAV)
293 wrefresh(wload);
294 wrefresh(wnd);
295 move(CMDLINE, col);
296 refresh();
297
298 if (allflag && signo==SIGALRM) {
299 if (allcounter >= turns){
300 p = curmode;
301 p++;
302 if (p->c_name == NULL)
303 p = modes;
304 switch_mode(p);
305 allcounter=0;
306 } else
307 allcounter++;
308 }
309
310 sigprocmask(SIG_UNBLOCK, &set, NULL);
311 alarm(naptime);
312 }
313
314 void
315 redraw(int signo)
316 {
317 sigset_t set;
318
319 sigemptyset(&set);
320 sigaddset(&set, SIGALRM);
321 sigprocmask(SIG_BLOCK, &set, NULL);
322 wrefresh(curscr);
323 refresh();
324 sigprocmask(SIG_UNBLOCK, &set, NULL);
325 }
326
327 void
328 die(int signo)
329 {
330 move(CMDLINE, 0);
331 clrtoeol();
332 refresh();
333 endwin();
334 exit(0);
335 }
336
337 void
338 error(const char *fmt, ...)
339 {
340 va_list ap;
341 char buf[255];
342 int oy, ox;
343
344 va_start(ap, fmt);
345
346 if (wnd) {
347 getyx(stdscr, oy, ox);
348 (void) vsnprintf(buf, sizeof(buf), fmt, ap);
349 clrtoeol();
350 standout();
351 mvaddstr(CMDLINE, 0, buf);
352 standend();
353 move(oy, ox);
354 refresh();
355 } else {
356 (void) vfprintf(stderr, fmt, ap);
357 fprintf(stderr, "\n");
358 }
359 va_end(ap);
360 }
361
362 void
363 nlisterr(struct nlist namelist[])
364 {
365 int i, n;
366
367 n = 0;
368 clear();
369 mvprintw(2, 10, "systat: nlist: can't find following symbols:");
370 for (i = 0;
371 namelist[i].n_name != NULL && *namelist[i].n_name != '\0'; i++)
372 if (namelist[i].n_value == 0)
373 mvprintw(2 + ++n, 10, "%s", namelist[i].n_name);
374 move(CMDLINE, 0);
375 clrtoeol();
376 refresh();
377 endwin();
378 exit(1);
379 }
380