xref: /openbsd-src/usr.bin/systat/main.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /* $Id: main.c,v 1.51 2008/11/08 06:38:27 canacar 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 [-abin] [-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 }
347 
348 void
349 gethz(void)
350 {
351 	struct clockinfo cinf;
352 	size_t  size = sizeof(cinf);
353 	int	mib[2];
354 
355 	mib[0] = CTL_KERN;
356 	mib[1] = KERN_CLOCKRATE;
357 	if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1)
358 		return;
359 	stathz = cinf.stathz;
360 	hz = cinf.hz;
361 }
362 
363 int
364 main(int argc, char *argv[])
365 {
366 	char errbuf[_POSIX2_LINE_MAX];
367 	extern char *optarg;
368 	extern int optind;
369 	double delay = 5;
370 
371 	char *viewstr = NULL;
372 
373 	gid_t gid;
374 	int countmax = 0;
375 	int maxlines = 0;
376 
377 	int ch;
378 
379 	ut = open(_PATH_UTMP, O_RDONLY);
380 	if (ut < 0) {
381 		warn("No utmp");
382 	}
383 
384 	kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
385 
386 	gid = getgid();
387 	if (setresgid(gid, gid, gid) == -1)
388 		err(1, "setresgid");
389 
390 	while ((ch = getopt(argc, argv, "abd:ins:w:")) != -1) {
391 		switch (ch) {
392 		case 'a':
393 			maxlines = -1;
394 			break;
395 		case 'b':
396 			rawmode = 1;
397 			interactive = 0;
398 			break;
399 		case 'd':
400 			countmax = atoi(optarg);
401 			if (countmax < 0)
402 				countmax = 0;
403 			break;
404 		case 'i':
405 			interactive = 1;
406 			break;
407 		case 'n':
408 			nflag = 1;
409 			break;
410 		case 's':
411 			delay = atof(optarg);
412 			if (delay <= 0)
413 				delay = 5;
414 			break;
415 		case 'w':
416 			rawwidth = atoi(optarg);
417 			if (rawwidth < 1)
418 				rawwidth = DEFAULT_WIDTH;
419 			if (rawwidth >= MAX_LINE_BUF)
420 				rawwidth = MAX_LINE_BUF - 1;
421 			break;
422 		default:
423 			usage();
424 			/* NOTREACHED */
425 		}
426 	}
427 
428 	if (kd == NULL)
429 		warnx("kvm_openfiles: %s", errbuf);
430 
431 	argc -= optind;
432 	argv += optind;
433 
434 	if (argc == 1) {
435 		double del = atof(argv[0]);
436 		if (del == 0)
437 			viewstr = argv[0];
438 		else
439 			delay = del;
440 	} else if (argc == 2) {
441 		viewstr = argv[0];
442 		delay = atof(argv[1]);
443 		if (delay <= 0)
444 			delay = 5;
445 	}
446 
447 	udelay = (useconds_t)(delay * 1000000.0);
448 	if (udelay < 1)
449 		udelay = 1;
450 
451 	naptime = (double)udelay / 1000000.0;
452 
453 	gethostname(hostname, sizeof (hostname));
454 	gethz();
455 
456 	initialize();
457 
458 	set_order(NULL);
459 	if (viewstr && set_view(viewstr)) {
460 		fprintf(stderr, "Unknown/ambiguous view name: %s\n", viewstr);
461 		return 1;
462 	}
463 
464 	if (!isatty(STDOUT_FILENO)) {
465 		rawmode = 1;
466 		interactive = 0;
467 	}
468 
469 	setup_term(maxlines);
470 
471 	if (rawmode && countmax == 0)
472 		countmax = 1;
473 
474 	gotsig_alarm = 1;
475 
476 	engine_loop(countmax);
477 
478 	return 0;
479 }
480