xref: /openbsd/usr.bin/systat/main.c (revision 17df1aa7)
1 /* $Id: main.c,v 1.55 2009/07/21 17:07:38 sthen 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 double	dellave;
57 
58 kvm_t	*kd;
59 char	*nlistf = NULL;
60 char	*memf = NULL;
61 double	avenrun[3];
62 double	naptime = 5.0;
63 int	verbose = 1;		/* to report kvm read errs */
64 int	nflag = 1;
65 int	ut, hz, stathz;
66 char    hostname[MAXHOSTNAMELEN];
67 WINDOW  *wnd;
68 int	CMDLINE;
69 
70 #define TIMEPOS 55
71 
72 int  ucount(void);
73 void usage(void);
74 
75 /* command prompt */
76 
77 void cmd_delay(const char *);
78 void cmd_count(const char *);
79 void cmd_compat(const char *);
80 
81 struct command cm_compat = {"Command", cmd_compat};
82 struct command cm_delay = {"Seconds to delay", cmd_delay};
83 struct command cm_count = {"Number of lines to display", cmd_count};
84 
85 
86 /* display functions */
87 
88 int
89 print_header(void)
90 {
91 	time_t now;
92 	int start = dispstart + 1, end = dispstart + maxprint;
93 	char tbuf[26];
94 
95 	if (end > num_disp)
96 		end = num_disp;
97 
98 	tb_start();
99 
100 	getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0]));
101 
102 	time(&now);
103 	strlcpy(tbuf, ctime(&now), sizeof tbuf);
104 	tbprintf("   %d users", ucount());
105 	tbprintf("    Load %.2f %.2f %.2f", avenrun[0], avenrun[1], avenrun[2]);
106 	if (num_disp && (start > 1 || end != num_disp))
107 		tbprintf("  (%u-%u of %u)", start, end, num_disp);
108 
109 	if (paused)
110 		tbprintf(" PAUSED");
111 
112 	if (rawmode)
113 		printf("\n\n%s\n", tmp_buf);
114 	else
115 		mvprintw(0, 0, "%s", tmp_buf);
116 
117 	mvprintw(0, TIMEPOS, "%s", tbuf);
118 
119 
120 	return (1);
121 }
122 
123 /* compatibility functions, rearrange later */
124 void
125 error(const char *fmt, ...)
126 {
127 	va_list ap;
128 	char buf[MAX_LINE_BUF];
129 
130 	va_start(ap, fmt);
131 	vsnprintf(buf, sizeof buf, fmt, ap);
132 	va_end(ap);
133 
134 	message_set(buf);
135 }
136 
137 void
138 nlisterr(struct nlist namelist[])
139 {
140 	int i, n;
141 
142 	n = 0;
143 	clear();
144 	mvprintw(2, 10, "systat: nlist: can't find following symbols:");
145 	for (i = 0;
146 	    namelist[i].n_name != NULL && *namelist[i].n_name != '\0'; i++)
147 		if (namelist[i].n_value == 0)
148 			mvprintw(2 + ++n, 10, "%s", namelist[i].n_name);
149 	move(CMDLINE, 0);
150 	clrtoeol();
151 	refresh();
152 	endwin();
153 	exit(1);
154 }
155 
156 void
157 die(void)
158 {
159 	if (!rawmode)
160 		endwin();
161 	exit(0);
162 }
163 
164 
165 int
166 prefix(char *s1, char *s2)
167 {
168 
169 	while (*s1 == *s2) {
170 		if (*s1 == '\0')
171 			return (1);
172 		s1++, s2++;
173 	}
174 	return (*s1 == '\0');
175 }
176 
177 /* calculate number of users on the system */
178 int
179 ucount(void)
180 {
181 	int nusers = 0;
182 	struct	utmp utmp;
183 
184 	if (ut < 0)
185 		return (0);
186 	lseek(ut, (off_t)0, SEEK_SET);
187 	while (read(ut, &utmp, sizeof(utmp)))
188 		if (utmp.ut_name[0] != '\0')
189 			nusers++;
190 
191 	return (nusers);
192 }
193 
194 /* main program functions */
195 
196 void
197 usage(void)
198 {
199 	extern char *__progname;
200 	fprintf(stderr, "usage: %s [-abiNn] [-d count] "
201 	    "[-s delay] [-w width] [view] [delay]\n", __progname);
202 	exit(1);
203 }
204 
205 void
206 show_view(void)
207 {
208 	if (rawmode)
209 		return;
210 
211 	tb_start();
212 	tbprintf("%s %g", curr_view->name, naptime);
213 	tb_end();
214 	message_set(tmp_buf);
215 }
216 
217 void
218 add_view_tb(field_view *v)
219 {
220 	if (curr_view == v)
221 		tbprintf("[%s] ", v->name);
222 	else
223 		tbprintf("%s ", v->name);
224 }
225 
226 void
227 show_help(void)
228 {
229 	if (rawmode)
230 		return;
231 
232 	tb_start();
233 	foreach_view(add_view_tb);
234 	tb_end();
235 	message_set(tmp_buf);
236 }
237 
238 void
239 cmd_compat(const char *buf)
240 {
241 	const char *s;
242 
243 	if (strcasecmp(buf, "help") == 0) {
244 		show_help();
245 		need_update = 1;
246 		return;
247 	}
248 	if (strcasecmp(buf, "quit") == 0 || strcasecmp(buf, "q") == 0) {
249 		gotsig_close = 1;
250 		return;
251 	}
252 	if (strcasecmp(buf, "stop") == 0) {
253 		paused = 1;
254 		gotsig_alarm = 1;
255 		return;
256 	}
257 	if (strncasecmp(buf, "start", 5) == 0) {
258 		paused = 0;
259 		gotsig_alarm = 1;
260 		cmd_delay(buf + 5);
261 		return;
262 	}
263 
264 	for (s = buf; *s && strchr("0123456789+-.eE", *s) != NULL; s++)
265 		;
266 	if (*s) {
267 		if (set_view(buf))
268 			error("Invalid/ambiguous view: %s", buf);
269 	} else
270 		cmd_delay(buf);
271 }
272 
273 void
274 cmd_delay(const char *buf)
275 {
276 	double del;
277 	del = atof(buf);
278 
279 	if (del > 0) {
280 		udelay = (useconds_t)(del * 1000000);
281 		gotsig_alarm = 1;
282 		naptime = del;
283 	}
284 }
285 
286 void
287 cmd_count(const char *buf)
288 {
289 	int ms;
290 	ms = atoi(buf);
291 
292 	if (ms <= 0 || ms > lines - HEADER_LINES)
293 		maxprint = lines - HEADER_LINES;
294 	else
295 		maxprint = ms;
296 }
297 
298 
299 int
300 keyboard_callback(int ch)
301 {
302 	switch (ch) {
303 	case '?':
304 		/* FALLTHROUGH */
305 	case 'h':
306 		show_help();
307 		need_update = 1;
308 		break;
309 	case CTRL_G:
310 		show_view();
311 		need_update = 1;
312 		break;
313 	case 'l':
314 		command_set(&cm_count, NULL);
315 		break;
316 	case 's':
317 		command_set(&cm_delay, NULL);
318 		break;
319 	case ':':
320 		command_set(&cm_compat, NULL);
321 		break;
322 	default:
323 		return 0;
324 	};
325 
326 	return 1;
327 }
328 
329 void
330 initialize(void)
331 {
332 	engine_initialize();
333 
334 	initvmstat();
335 	initpigs();
336 	initifstat();
337 	initiostat();
338 	initsensors();
339 	initmembufs();
340 	initnetstat();
341 	initswap();
342 	initpftop();
343 	initpf();
344 	initpool();
345 	initmalloc();
346 	initnfs();
347 }
348 
349 void
350 gethz(void)
351 {
352 	struct clockinfo cinf;
353 	size_t  size = sizeof(cinf);
354 	int	mib[2];
355 
356 	mib[0] = CTL_KERN;
357 	mib[1] = KERN_CLOCKRATE;
358 	if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1)
359 		return;
360 	stathz = cinf.stathz;
361 	hz = cinf.hz;
362 }
363 
364 int
365 main(int argc, char *argv[])
366 {
367 	char errbuf[_POSIX2_LINE_MAX];
368 	extern char *optarg;
369 	extern int optind;
370 	double delay = 5;
371 
372 	char *viewstr = NULL;
373 
374 	gid_t gid;
375 	int countmax = 0;
376 	int maxlines = 0;
377 
378 	int ch;
379 
380 	ut = open(_PATH_UTMP, O_RDONLY);
381 	if (ut < 0) {
382 		warn("No utmp");
383 	}
384 
385 	kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
386 
387 	gid = getgid();
388 	if (setresgid(gid, gid, gid) == -1)
389 		err(1, "setresgid");
390 
391 	while ((ch = getopt(argc, argv, "Nabd:ins:w:")) != -1) {
392 		switch (ch) {
393 		case 'a':
394 			maxlines = -1;
395 			break;
396 		case 'b':
397 			rawmode = 1;
398 			interactive = 0;
399 			break;
400 		case 'd':
401 			countmax = atoi(optarg);
402 			if (countmax < 0)
403 				countmax = 0;
404 			break;
405 		case 'i':
406 			interactive = 1;
407 			break;
408 		case 'N':
409 			nflag = 0;
410 			break;
411 		case 'n':
412 			/* this is a noop, -n is the default */
413 			nflag = 1;
414 			break;
415 		case 's':
416 			delay = atof(optarg);
417 			if (delay <= 0)
418 				delay = 5;
419 			break;
420 		case 'w':
421 			rawwidth = atoi(optarg);
422 			if (rawwidth < 1)
423 				rawwidth = DEFAULT_WIDTH;
424 			if (rawwidth >= MAX_LINE_BUF)
425 				rawwidth = MAX_LINE_BUF - 1;
426 			break;
427 		default:
428 			usage();
429 			/* NOTREACHED */
430 		}
431 	}
432 
433 	if (kd == NULL)
434 		warnx("kvm_openfiles: %s", errbuf);
435 
436 	argc -= optind;
437 	argv += optind;
438 
439 	if (argc == 1) {
440 		double del = atof(argv[0]);
441 		if (del == 0)
442 			viewstr = argv[0];
443 		else
444 			delay = del;
445 	} else if (argc == 2) {
446 		viewstr = argv[0];
447 		delay = atof(argv[1]);
448 		if (delay <= 0)
449 			delay = 5;
450 	}
451 
452 	udelay = (useconds_t)(delay * 1000000.0);
453 	if (udelay < 1)
454 		udelay = 1;
455 
456 	naptime = (double)udelay / 1000000.0;
457 
458 	gethostname(hostname, sizeof (hostname));
459 	gethz();
460 
461 	initialize();
462 
463 	set_order(NULL);
464 	if (viewstr && set_view(viewstr)) {
465 		fprintf(stderr, "Unknown/ambiguous view name: %s\n", viewstr);
466 		return 1;
467 	}
468 
469 	if (!isatty(STDOUT_FILENO)) {
470 		rawmode = 1;
471 		interactive = 0;
472 	}
473 
474 	setup_term(maxlines);
475 
476 	if (rawmode && countmax == 0)
477 		countmax = 1;
478 
479 	gotsig_alarm = 1;
480 
481 	engine_loop(countmax);
482 
483 	return 0;
484 }
485