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