xref: /openbsd-src/usr.bin/systat/main.c (revision 850e275390052b330d93020bf619a739a3c277ac)
1 /* $Id: main.c,v 1.44 2008/08/13 06:20:48 jmc 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 /* command prompt */
73 
74 void cmd_delay(void);
75 void cmd_count(void);
76 void cmd_compat(void);
77 
78 struct command cm_compat = {"Command", cmd_compat};
79 struct command cm_delay = {"Seconds to delay", cmd_delay};
80 struct command cm_count = {"Number of lines to display", cmd_count};
81 
82 
83 /* display functions */
84 
85 int
86 print_header(void)
87 {
88 	struct tm *tp;
89 	time_t t, now;
90 	order_type *ordering;
91 	int start = dispstart + 1, end = dispstart + maxprint;
92 	extern int ucount();
93 	char tbuf[26];
94 
95 	if (end > num_disp)
96 		end = num_disp;
97 
98 	tb_start();
99 
100 #if 0
101 	if (curr_mgr && curr_mgr->sort_fn != NULL) {
102 		ordering = curr_mgr->order_curr;
103 		if (ordering != NULL) {
104 			tbprintf(", Order: %s", ordering->name);
105 			if (sortdir < 0 && ordering->func != NULL)
106 				tbprintf(" (rev)");
107 		}
108 	}
109 #endif
110 
111 	getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0]));
112 
113 	time(&now);
114 	strlcpy(tbuf, ctime(&now), sizeof tbuf);
115 	tbprintf("   %d users", ucount());
116 	tbprintf("    Load %.2f %.2f %.2f", avenrun[0], avenrun[1], avenrun[2]);
117 	if (num_disp && (start > 1 || end != num_disp))
118 		tbprintf("  (%u-%u of %u)", start, end, num_disp);
119 
120 	if (paused)
121 		tbprintf(" PAUSED");
122 
123 	if (rawmode)
124 		printf("\n\n%s\n", tmp_buf);
125 	else
126 		mvprintw(0, 0, "%s", tmp_buf);
127 
128 	mvprintw(0, TIMEPOS, "%s", tbuf);
129 
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()
209 {
210 	extern char *__progname;
211 	fprintf(stderr, "usage: %s [-abin] [-d count] "
212 	    "[-s delay] [-w width] [view] [delay]\n", __progname);
213 	exit(1);
214 }
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 	int line = 0;
230 
231 	if (rawmode)
232 		return;
233 
234 	tb_start();
235 	foreach_view(add_view_tb);
236 	tb_end();
237 	message_set(tmp_buf);
238 
239 #if 0
240 	erase();
241 	mvprintw(line, 2, "Systat Help");
242 	line += 2;
243 	mvprintw(line,    5, " h  - Help (this page)");
244 	mvprintw(line++, 40, " l  - set number of Lines");
245 	mvprintw(line,    5, " p  - Pause display");
246 	mvprintw(line++, 40, " s  - Set update interval");
247 	mvprintw(line,    5, " v  - next View");
248 	mvprintw(line++, 40, " q  - Quit");
249 	line++;
250 	mvprintw(line++, 5, "0-7 - select view directly");
251 	mvprintw(line++, 5, "SPC - update immediately");
252 	mvprintw(line++, 5, "^L  - refresh display");
253 	line++;
254 	mvprintw(line++, 5, "cursor keys - scroll display");
255 	line++;
256 	mvprintw(line++,  3, "Netstat specific keys::");
257 	mvprintw(line,    5, " t  - toggle TCP display");
258 	mvprintw(line++, 40, " u  - toggle UDP display");
259 	mvprintw(line++,  5, " n  - toggle Name resolution");
260 	line++;
261 	mvprintw(line++,  3, "Ifstat specific keys::");
262 	mvprintw(line,    5, " r  - initialize RUN mode");
263 	mvprintw(line++, 40, " b  - set BOOT mode");
264 	mvprintw(line,    5, " t  - set TIME mode (default)");
265 	line++;
266 	line++;
267 	mvprintw(line++,  3, "VMstat specific keys::");
268 	mvprintw(line,    5, " r  - initialize RUN mode");
269 	mvprintw(line++, 40, " b  - set BOOT mode");
270 	mvprintw(line,    5, " t  - set TIME mode (default)");
271 	mvprintw(line++, 40, " z  - zero in RUN mode");
272 	line++;
273 	mvprintw(line++, 6, "press any key to continue ...");
274 
275 	while (getch() == ERR) {
276 		if (gotsig_close)
277 			break;
278 	}
279 #endif
280 }
281 
282 void
283 cmd_compat(void)
284 {
285 	char *s;
286 
287 	if (strcasecmp(cmdbuf, "help") == 0) {
288 		show_help();
289 		need_update = 1;
290 		return;
291 	}
292 	if (strcasecmp(cmdbuf, "quit") == 0 || strcasecmp(cmdbuf, "q") == 0) {
293 		gotsig_close = 1;
294 		return;
295 	}
296 
297 	for (s = cmdbuf; *s && strchr("0123456789+-.eE", *s) != NULL; s++)
298 		;
299 	if (*s) {
300 		if (set_view(cmdbuf))
301 			error("Invalid/ambigious view: %s", cmdbuf);
302 	} else
303 		cmd_delay();
304 }
305 
306 void
307 cmd_delay(void)
308 {
309 	double del;
310 	del = atof(cmdbuf);
311 
312 	if (del > 0) {
313 		udelay = (useconds_t)(del * 1000000);
314 		gotsig_alarm = 1;
315 		naptime = del;
316 	}
317 }
318 
319 void
320 cmd_count(void)
321 {
322 	int ms;
323 	ms = atoi(cmdbuf);
324 
325 	if (ms <= 0 || ms > lines - HEADER_LINES)
326 		maxprint = lines - HEADER_LINES;
327 	else
328 		maxprint = ms;
329 }
330 
331 
332 int
333 keyboard_callback(int ch)
334 {
335 	switch (ch) {
336 	case '?':
337 		/* FALLTHROUGH */
338 	case 'h':
339 		show_help();
340 		need_update = 1;
341 		break;
342 	case 'l':
343 		command_set(&cm_count, NULL);
344 		break;
345 	case 's':
346 		command_set(&cm_delay, NULL);
347 		break;
348 	case ':':
349 		command_set(&cm_compat, NULL);
350 		break;
351 	default:
352 		return 0;
353 	};
354 
355 	return 1;
356 }
357 
358 void
359 initialize(void)
360 {
361 	engine_initialize();
362 
363 	initvmstat();
364 	initpigs();
365 	initifstat();
366 	initiostat();
367 	initsensors();
368 	initmembufs();
369 	initnetstat();
370 	initswap();
371 	initpftop();
372 	initpf();
373 }
374 
375 void
376 gethz(void)
377 {
378 	struct clockinfo cinf;
379 	size_t  size = sizeof(cinf);
380 	int	mib[2];
381 
382 	mib[0] = CTL_KERN;
383 	mib[1] = KERN_CLOCKRATE;
384 	if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1)
385 		return;
386 	stathz = cinf.stathz;
387 	hz = cinf.hz;
388 }
389 
390 int
391 main(int argc, char *argv[])
392 {
393 	char errbuf[_POSIX2_LINE_MAX];
394 	extern char *optarg;
395 	extern int optind;
396 	double delay = 5;
397 
398 	char *viewstr = NULL;
399 
400 	gid_t gid;
401 	int countmax = 0;
402 	int maxlines = 0;
403 
404 	int ch;
405 
406 	ut = open(_PATH_UTMP, O_RDONLY);
407 	if (ut < 0) {
408 		warn("No utmp");
409 	}
410 
411 	kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
412 
413 	gid = getgid();
414 	if (setresgid(gid, gid, gid) == -1)
415 		err(1, "setresgid");
416 
417 	while ((ch = getopt(argc, argv, "abd:ins:S:w:")) != -1) {
418 		switch (ch) {
419 		case 'a':
420 			maxlines = -1;
421 			break;
422 		case 'b':
423 			rawmode = 1;
424 			interactive = 0;
425 			break;
426 		case 'd':
427 			countmax = atoi(optarg);
428 			if (countmax < 0)
429 				countmax = 0;
430 			break;
431 		case 'i':
432 			interactive = 1;
433 			break;
434 		case 'n':
435 			nflag = 1;
436 			break;
437 		case 's':
438 			delay = atof(optarg);
439 			if (delay <= 0)
440 				delay = 5;
441 			break;
442 		case 'S':
443 			dispstart = atoi(optarg);
444 			if (dispstart < 0)
445 				dispstart = 0;
446 			break;
447 		case 'w':
448 			rawwidth = atoi(optarg);
449 			if (rawwidth < 1)
450 				rawwidth = DEFAULT_WIDTH;
451 			if (rawwidth >= MAX_LINE_BUF)
452 				rawwidth = MAX_LINE_BUF - 1;
453 			break;
454 		default:
455 			usage();
456 			/* NOTREACHED */
457 		}
458 	}
459 
460 	if (kd == NULL)
461 		warnx("kvm_openfiles: %s", errbuf);
462 
463 	argc -= optind;
464 	argv += optind;
465 
466 	if (argc == 1) {
467 		double del = atof(argv[0]);
468 		if (del == 0)
469 			viewstr = argv[0];
470 		else
471 			delay = del;
472 	} else if (argc == 2) {
473 		viewstr = argv[0];
474 		delay = atof(argv[1]);
475 		if (delay <= 0)
476 			delay = 5;
477 	}
478 
479 	udelay = (useconds_t)(delay * 1000000.0);
480 	if (udelay < 1)
481 		udelay = 1;
482 
483 	naptime = (double)udelay / 1000000.0;
484 
485 	gethostname(hostname, sizeof (hostname));
486 	gethz();
487 
488 	initialize();
489 
490 	set_order(NULL);
491 	if (viewstr && set_view(viewstr)) {
492 		fprintf(stderr, "Unknown/ambigious view name: %s\n", viewstr);
493 		return 1;
494 	}
495 
496 	if (!isatty(STDOUT_FILENO)) {
497 		rawmode = 1;
498 		interactive = 0;
499 	}
500 
501 	setup_term(maxlines);
502 
503 	if (rawmode && countmax == 0)
504 		countmax = 1;
505 
506 	gotsig_alarm = 1;
507 
508 	engine_loop(countmax);
509 
510 	return 0;
511 }
512