main.c revision 1.40
1/* $Id: main.c,v 1.40 2008/06/13 10:06:14 deraadt 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
56double	dellave;
57
58kvm_t	*kd;
59char	*nlistf = NULL;
60char	*memf = NULL;
61double	avenrun[3];
62double	naptime = 5.0;
63int	verbose = 1;		/* to report kvm read errs */
64int	nflag = 1;
65int	ut, hz, stathz;
66char    hostname[MAXHOSTNAMELEN];
67WINDOW  *wnd;
68int	CMDLINE;
69
70#define TIMEPOS 55
71
72/* command prompt */
73
74void cmd_delay(void);
75void cmd_count(void);
76void cmd_compat(void);
77
78struct command cm_compat = {"Command", cmd_compat};
79struct command cm_delay = {"Seconds to delay", cmd_delay};
80struct command cm_count = {"Number of lines to display", cmd_count};
81
82
83/* display functions */
84
85int
86print_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 */
135void
136error(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
148void
149nlisterr(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
167void
168die(void)
169{
170	if (!rawmode)
171		endwin();
172	exit(0);
173}
174
175
176int
177prefix(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 */
189int
190ucount(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
207void
208usage()
209{
210	extern char *__progname;
211	fprintf(stderr, "usage: %s [-abhir] [-c cache] [-d cnt]", __progname);
212	fprintf(stderr, " [-o field] [-s time] [-w width] [view] [num]\n");
213	exit(1);
214}
215
216
217void
218add_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
226void
227show_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
282void
283cmd_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) {
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
306void
307cmd_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
319void
320cmd_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
332int
333keyboard_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
358void
359initialize(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
375void
376gethz(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
390int
391main(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	if (kd == NULL)
413		warnx("kvm_openfiles: %s", errbuf);
414
415	gid = getgid();
416	if (setresgid(gid, gid, gid) == -1)
417		err(1, "setresgid");
418
419	while ((ch = getopt(argc, argv, "abd:hins:S:w:")) != -1) {
420		switch (ch) {
421		case 'a':
422			maxlines = -1;
423			break;
424		case 'b':
425			rawmode = 1;
426			interactive = 0;
427			break;
428		case 'd':
429			countmax = atoi(optarg);
430			if (countmax < 0)
431				countmax = 0;
432			break;
433		case 'i':
434			interactive = 1;
435			break;
436		case 'n':
437			nflag = 1;
438			break;
439		case 's':
440			delay = atof(optarg);
441			if (delay <= 0)
442				delay = 5;
443			break;
444		case 'S':
445			dispstart = atoi(optarg);
446			if (dispstart < 0)
447				dispstart = 0;
448			break;
449		case 'w':
450			rawwidth = atoi(optarg);
451			if (rawwidth < 1)
452				rawwidth = DEFAULT_WIDTH;
453			if (rawwidth >= MAX_LINE_BUF)
454				rawwidth = MAX_LINE_BUF - 1;
455			break;
456		case 'h':
457			/* FALLTHROUGH */
458		default:
459			usage();
460			/* NOTREACHED */
461		}
462	}
463
464	argc -= optind;
465	argv += optind;
466
467	if (argc == 1) {
468		double del = atof(argv[0]);
469		if (del == 0)
470			viewstr = argv[0];
471		else
472			delay = del;
473	} else if (argc == 2) {
474		viewstr = argv[0];
475		delay = atof(argv[1]);
476	}
477
478	udelay = (useconds_t)(delay * 1000000.0);
479	if (udelay < 1)
480		udelay = 1;
481
482	naptime = (double)udelay / 1000000.0;
483
484	gethostname(hostname, sizeof (hostname));
485	gethz();
486
487	initialize();
488
489	set_order(NULL);
490	if (viewstr && set_view(viewstr)) {
491		fprintf(stderr, "Unknown/ambigious view name: %s\n", viewstr);
492		return 1;
493	}
494
495	if (!isatty(STDOUT_FILENO)) {
496		rawmode = 1;
497		interactive = 0;
498	}
499
500	setup_term(maxlines);
501
502	if (rawmode && countmax == 0)
503		countmax = 1;
504
505	gotsig_alarm = 1;
506
507	engine_loop(countmax);
508
509	return 0;
510}
511