xref: /openbsd/usr.bin/systat/main.c (revision 8932bfb7)
1 /* $Id: main.c,v 1.59 2011/04/05 07:35:32 mpf Exp $	 */
2 /*
3  * Copyright (c) 2001, 2007 Can Erkin Acar
4  * Copyright (c) 2001 Daniel Hartmeier
5  * 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  *
11  *    - Redistributions of source code must retain the above copyright
12  *      notice, this list of conditions and the following disclaimer.
13  *    - Redistributions in binary form must reproduce the above
14  *      copyright notice, this list of conditions and the following
15  *      disclaimer in the documentation and/or other materials provided
16  *      with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  */
32 
33 #include <sys/types.h>
34 #include <sys/param.h>
35 #include <sys/sysctl.h>
36 
37 
38 #include <ctype.h>
39 #include <curses.h>
40 #include <err.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <limits.h>
44 #include <netdb.h>
45 #include <signal.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <stdarg.h>
50 #include <unistd.h>
51 #include <utmp.h>
52 
53 #include "engine.h"
54 #include "systat.h"
55 
56 #define TIMEPOS 55
57 
58 double	dellave;
59 
60 kvm_t	*kd;
61 char	*nlistf = NULL;
62 char	*memf = NULL;
63 double	avenrun[3];
64 double	naptime = 5.0;
65 int	verbose = 1;		/* to report kvm read errs */
66 int	nflag = 1;
67 int	ut, hz, stathz;
68 char    hostname[MAXHOSTNAMELEN];
69 WINDOW  *wnd;
70 int	CMDLINE;
71 char	timebuf[26];
72 char	uloadbuf[TIMEPOS];
73 
74 
75 int  ucount(void);
76 void usage(void);
77 
78 /* command prompt */
79 
80 void cmd_delay(const char *);
81 void cmd_count(const char *);
82 void cmd_compat(const char *);
83 
84 struct command cm_compat = {"Command", cmd_compat};
85 struct command cm_delay = {"Seconds to delay", cmd_delay};
86 struct command cm_count = {"Number of lines to display", cmd_count};
87 
88 
89 /* display functions */
90 
91 int
92 print_header(void)
93 {
94 	time_t now;
95 	int start = dispstart + 1, end = dispstart + maxprint;
96 	char tmpbuf[TIMEPOS];
97 	char header[MAX_LINE_BUF];
98 
99 	if (end > num_disp)
100 		end = num_disp;
101 
102 	tb_start();
103 
104 	if (!paused) {
105 		getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0]));
106 
107 		snprintf(uloadbuf, sizeof(uloadbuf),
108 		    "%5d users    Load %.2f %.2f %.2f",
109 		    ucount(), avenrun[0], avenrun[1], avenrun[2]);
110 
111 		time(&now);
112 		strlcpy(timebuf, ctime(&now), sizeof(timebuf));
113 	}
114 
115 	if (num_disp && (start > 1 || end != num_disp))
116 		snprintf(tmpbuf, sizeof(tmpbuf),
117 		    "%s (%u-%u of %u) %s", uloadbuf, start, end, num_disp,
118 		    paused ? "PAUSED" : "");
119 	else
120 		snprintf(tmpbuf, sizeof(tmpbuf),
121 		    "%s %s", uloadbuf,
122 		    paused ? "PAUSED" : "");
123 
124 	snprintf(header, sizeof(header), "%-55s%s", tmpbuf, timebuf);
125 
126 	if (rawmode)
127 		printf("\n\n%s\n", header);
128 	else
129 		mvprintw(0, 0, "%s", header);
130 
131 	return (1);
132 }
133 
134 /* compatibility functions, rearrange later */
135 void
136 error(const char *fmt, ...)
137 {
138 	va_list ap;
139 	char buf[MAX_LINE_BUF];
140 
141 	va_start(ap, fmt);
142 	vsnprintf(buf, sizeof buf, fmt, ap);
143 	va_end(ap);
144 
145 	message_set(buf);
146 }
147 
148 void
149 nlisterr(struct nlist namelist[])
150 {
151 	int i, n;
152 
153 	n = 0;
154 	clear();
155 	mvprintw(2, 10, "systat: nlist: can't find following symbols:");
156 	for (i = 0;
157 	    namelist[i].n_name != NULL && *namelist[i].n_name != '\0'; i++)
158 		if (namelist[i].n_value == 0)
159 			mvprintw(2 + ++n, 10, "%s", namelist[i].n_name);
160 	move(CMDLINE, 0);
161 	clrtoeol();
162 	refresh();
163 	endwin();
164 	exit(1);
165 }
166 
167 void
168 die(void)
169 {
170 	if (!rawmode)
171 		endwin();
172 	exit(0);
173 }
174 
175 
176 int
177 prefix(char *s1, char *s2)
178 {
179 
180 	while (*s1 == *s2) {
181 		if (*s1 == '\0')
182 			return (1);
183 		s1++, s2++;
184 	}
185 	return (*s1 == '\0');
186 }
187 
188 /* calculate number of users on the system */
189 int
190 ucount(void)
191 {
192 	int nusers = 0;
193 	struct	utmp utmp;
194 
195 	if (ut < 0)
196 		return (0);
197 	lseek(ut, (off_t)0, SEEK_SET);
198 	while (read(ut, &utmp, sizeof(utmp)))
199 		if (utmp.ut_name[0] != '\0')
200 			nusers++;
201 
202 	return (nusers);
203 }
204 
205 /* main program functions */
206 
207 void
208 usage(void)
209 {
210 	extern char *__progname;
211 	fprintf(stderr, "usage: %s [-abiNn] [-d count] "
212 	    "[-s delay] [-w width] [view] [delay]\n", __progname);
213 	exit(1);
214 }
215 
216 void
217 show_view(void)
218 {
219 	if (rawmode)
220 		return;
221 
222 	tb_start();
223 	tbprintf("%s %g", curr_view->name, naptime);
224 	tb_end();
225 	message_set(tmp_buf);
226 }
227 
228 void
229 add_view_tb(field_view *v)
230 {
231 	if (curr_view == v)
232 		tbprintf("[%s] ", v->name);
233 	else
234 		tbprintf("%s ", v->name);
235 }
236 
237 void
238 show_help(void)
239 {
240 	if (rawmode)
241 		return;
242 
243 	tb_start();
244 	foreach_view(add_view_tb);
245 	tb_end();
246 	message_set(tmp_buf);
247 }
248 
249 void
250 cmd_compat(const char *buf)
251 {
252 	const char *s;
253 
254 	if (strcasecmp(buf, "help") == 0) {
255 		show_help();
256 		need_update = 1;
257 		return;
258 	}
259 	if (strcasecmp(buf, "quit") == 0 || strcasecmp(buf, "q") == 0) {
260 		gotsig_close = 1;
261 		return;
262 	}
263 	if (strcasecmp(buf, "stop") == 0) {
264 		paused = 1;
265 		gotsig_alarm = 1;
266 		return;
267 	}
268 	if (strncasecmp(buf, "start", 5) == 0) {
269 		paused = 0;
270 		gotsig_alarm = 1;
271 		cmd_delay(buf + 5);
272 		return;
273 	}
274 
275 	for (s = buf; *s && strchr("0123456789+-.eE", *s) != NULL; s++)
276 		;
277 	if (*s) {
278 		if (set_view(buf))
279 			error("Invalid/ambiguous view: %s", buf);
280 	} else
281 		cmd_delay(buf);
282 }
283 
284 void
285 cmd_delay(const char *buf)
286 {
287 	double del;
288 	del = atof(buf);
289 
290 	if (del > 0) {
291 		udelay = (useconds_t)(del * 1000000);
292 		gotsig_alarm = 1;
293 		naptime = del;
294 	}
295 }
296 
297 void
298 cmd_count(const char *buf)
299 {
300 	int ms;
301 	ms = atoi(buf);
302 
303 	if (ms <= 0 || ms > lines - HEADER_LINES)
304 		maxprint = lines - HEADER_LINES;
305 	else
306 		maxprint = ms;
307 }
308 
309 
310 int
311 keyboard_callback(int ch)
312 {
313 	switch (ch) {
314 	case '?':
315 		/* FALLTHROUGH */
316 	case 'h':
317 		show_help();
318 		need_update = 1;
319 		break;
320 	case CTRL_G:
321 		show_view();
322 		need_update = 1;
323 		break;
324 	case 'l':
325 		command_set(&cm_count, NULL);
326 		break;
327 	case 's':
328 		command_set(&cm_delay, NULL);
329 		break;
330 	case ',':
331 		separate_thousands = !separate_thousands;
332 		gotsig_alarm = 1;
333 		break;
334 	case ':':
335 		command_set(&cm_compat, NULL);
336 		break;
337 	default:
338 		return 0;
339 	};
340 
341 	return 1;
342 }
343 
344 void
345 initialize(void)
346 {
347 	engine_initialize();
348 
349 	initvmstat();
350 	initpigs();
351 	initifstat();
352 	initiostat();
353 	initsensors();
354 	initmembufs();
355 	initnetstat();
356 	initswap();
357 	initpftop();
358 	initpf();
359 	initpool();
360 	initmalloc();
361 	initnfs();
362 }
363 
364 void
365 gethz(void)
366 {
367 	struct clockinfo cinf;
368 	size_t  size = sizeof(cinf);
369 	int	mib[2];
370 
371 	mib[0] = CTL_KERN;
372 	mib[1] = KERN_CLOCKRATE;
373 	if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1)
374 		return;
375 	stathz = cinf.stathz;
376 	hz = cinf.hz;
377 }
378 
379 int
380 main(int argc, char *argv[])
381 {
382 	char errbuf[_POSIX2_LINE_MAX];
383 	extern char *optarg;
384 	extern int optind;
385 	double delay = 5;
386 
387 	char *viewstr = NULL;
388 
389 	gid_t gid;
390 	int countmax = 0;
391 	int maxlines = 0;
392 
393 	int ch;
394 
395 	ut = open(_PATH_UTMP, O_RDONLY);
396 	if (ut < 0) {
397 		warn("No utmp");
398 	}
399 
400 	kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
401 
402 	gid = getgid();
403 	if (setresgid(gid, gid, gid) == -1)
404 		err(1, "setresgid");
405 
406 	while ((ch = getopt(argc, argv, "Nabd:ins:w:")) != -1) {
407 		switch (ch) {
408 		case 'a':
409 			maxlines = -1;
410 			break;
411 		case 'b':
412 			rawmode = 1;
413 			interactive = 0;
414 			break;
415 		case 'd':
416 			countmax = atoi(optarg);
417 			if (countmax < 0)
418 				countmax = 0;
419 			break;
420 		case 'i':
421 			interactive = 1;
422 			break;
423 		case 'N':
424 			nflag = 0;
425 			break;
426 		case 'n':
427 			/* this is a noop, -n is the default */
428 			nflag = 1;
429 			break;
430 		case 's':
431 			delay = atof(optarg);
432 			if (delay <= 0)
433 				delay = 5;
434 			break;
435 		case 'w':
436 			rawwidth = atoi(optarg);
437 			if (rawwidth < 1)
438 				rawwidth = DEFAULT_WIDTH;
439 			if (rawwidth >= MAX_LINE_BUF)
440 				rawwidth = MAX_LINE_BUF - 1;
441 			break;
442 		default:
443 			usage();
444 			/* NOTREACHED */
445 		}
446 	}
447 
448 	if (kd == NULL)
449 		warnx("kvm_openfiles: %s", errbuf);
450 
451 	argc -= optind;
452 	argv += optind;
453 
454 	if (argc == 1) {
455 		double del = atof(argv[0]);
456 		if (del == 0)
457 			viewstr = argv[0];
458 		else
459 			delay = del;
460 	} else if (argc == 2) {
461 		viewstr = argv[0];
462 		delay = atof(argv[1]);
463 		if (delay <= 0)
464 			delay = 5;
465 	}
466 
467 	udelay = (useconds_t)(delay * 1000000.0);
468 	if (udelay < 1)
469 		udelay = 1;
470 
471 	naptime = (double)udelay / 1000000.0;
472 
473 	gethostname(hostname, sizeof (hostname));
474 	gethz();
475 
476 	initialize();
477 
478 	set_order(NULL);
479 	if (viewstr && set_view(viewstr)) {
480 		fprintf(stderr, "Unknown/ambiguous view name: %s\n", viewstr);
481 		return 1;
482 	}
483 
484 	if (check_termcap()) {
485 		rawmode = 1;
486 		interactive = 0;
487 	}
488 
489 	setup_term(maxlines);
490 
491 	if (rawmode && countmax == 0)
492 		countmax = 1;
493 
494 	gotsig_alarm = 1;
495 
496 	engine_loop(countmax);
497 
498 	return 0;
499 }
500