main.c revision 1.39
1/* $Id: main.c,v 1.39 2008/06/13 01:24:55 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
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;
90	order_type *ordering;
91
92	int start = dispstart + 1;
93	int end = dispstart + maxprint;
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	extern int ucount();
113	char tbuf[26];
114	time_t now;
115
116	time(&now);
117	strlcpy(tbuf, ctime(&now), sizeof tbuf);
118	tbprintf("   %d users", ucount());
119	tbprintf("    Load %.2f %.2f %.2f", avenrun[0], avenrun[1], avenrun[2]);
120	if (num_disp && (start > 1 || end != num_disp))
121		tbprintf("  (%u-%u of %u)", start, end, num_disp);
122
123	if (paused)
124		tbprintf(" PAUSED");
125
126	if (rawmode)
127		printf("\n\n%s\n", tmp_buf);
128	else
129		mvprintw(0, 0, "%s", tmp_buf);
130
131	mvprintw(0, TIMEPOS, "%s", tbuf);
132
133
134	return (1);
135}
136
137/* compatibility functions, rearrange later */
138void
139error(const char *fmt, ...)
140{
141	va_list ap;
142	char buf[MAX_LINE_BUF];
143
144	va_start(ap, fmt);
145	vsnprintf(buf, sizeof buf, fmt, ap);
146	va_end(ap);
147
148	message_set(buf);
149}
150
151void
152nlisterr(struct nlist namelist[])
153{
154	int i, n;
155
156	n = 0;
157	clear();
158	mvprintw(2, 10, "systat: nlist: can't find following symbols:");
159	for (i = 0;
160	    namelist[i].n_name != NULL && *namelist[i].n_name != '\0'; i++)
161		if (namelist[i].n_value == 0)
162			mvprintw(2 + ++n, 10, "%s", namelist[i].n_name);
163	move(CMDLINE, 0);
164	clrtoeol();
165	refresh();
166	endwin();
167	exit(1);
168}
169
170void
171die(void)
172{
173	if (!rawmode)
174		endwin();
175	exit(0);
176}
177
178
179int
180prefix(char *s1, char *s2)
181{
182
183	while (*s1 == *s2) {
184		if (*s1 == '\0')
185			return (1);
186		s1++, s2++;
187	}
188	return (*s1 == '\0');
189}
190
191/* calculate number of users on the system */
192int
193ucount(void)
194{
195	int nusers = 0;
196	struct	utmp utmp;
197
198	if (ut < 0)
199		return (0);
200	lseek(ut, (off_t)0, SEEK_SET);
201	while (read(ut, &utmp, sizeof(utmp)))
202		if (utmp.ut_name[0] != '\0')
203			nusers++;
204
205	return (nusers);
206}
207
208/* main program functions */
209
210void
211usage()
212{
213	extern char *__progname;
214	fprintf(stderr, "usage: %s [-abhir] [-c cache] [-d cnt]", __progname);
215	fprintf(stderr, " [-o field] [-s time] [-w width] [view] [num]\n");
216	exit(1);
217}
218
219
220void
221add_view_tb(field_view *v)
222{
223	if (curr_view == v)
224		tbprintf("[%s] ", v->name);
225	else
226		tbprintf("%s ", v->name);
227}
228
229void
230show_help(void)
231{
232	int line = 0;
233
234	if (rawmode)
235		return;
236
237	tb_start();
238	foreach_view(add_view_tb);
239	tb_end();
240	message_set(tmp_buf);
241
242#if 0
243	erase();
244	mvprintw(line, 2, "Systat Help");
245	line += 2;
246	mvprintw(line,    5, " h  - Help (this page)");
247	mvprintw(line++, 40, " l  - set number of Lines");
248	mvprintw(line,    5, " p  - Pause display");
249	mvprintw(line++, 40, " s  - Set update interval");
250	mvprintw(line,    5, " v  - next View");
251	mvprintw(line++, 40, " q  - Quit");
252	line++;
253	mvprintw(line++, 5, "0-7 - select view directly");
254	mvprintw(line++, 5, "SPC - update immediately");
255	mvprintw(line++, 5, "^L  - refresh display");
256	line++;
257	mvprintw(line++, 5, "cursor keys - scroll display");
258	line++;
259	mvprintw(line++,  3, "Netstat specific keys::");
260	mvprintw(line,    5, " t  - toggle TCP display");
261	mvprintw(line++, 40, " u  - toggle UDP display");
262	mvprintw(line++,  5, " n  - toggle Name resolution");
263	line++;
264	mvprintw(line++,  3, "Ifstat specific keys::");
265	mvprintw(line,    5, " r  - initialize RUN mode");
266	mvprintw(line++, 40, " b  - set BOOT mode");
267	mvprintw(line,    5, " t  - set TIME mode (default)");
268	line++;
269	line++;
270	mvprintw(line++,  3, "VMstat specific keys::");
271	mvprintw(line,    5, " r  - initialize RUN mode");
272	mvprintw(line++, 40, " b  - set BOOT mode");
273	mvprintw(line,    5, " t  - set TIME mode (default)");
274	mvprintw(line++, 40, " z  - zero in RUN mode");
275	line++;
276	mvprintw(line++, 6, "press any key to continue ...");
277
278	while (getch() == ERR) {
279		if (gotsig_close)
280			break;
281	}
282#endif
283}
284
285void
286cmd_compat(void)
287{
288	char *s;
289
290	if (strcasecmp(cmdbuf, "help") == 0) {
291		show_help();
292		need_update = 1;
293		return;
294	}
295	if (strcasecmp(cmdbuf, "quit") == 0) {
296		gotsig_close = 1;
297		return;
298	}
299
300	for (s = cmdbuf; *s && strchr("0123456789+-.eE", *s) != NULL; s++)
301		;
302	if (*s) {
303		if (set_view(cmdbuf))
304			error("Invalid/ambigious view: %s", cmdbuf);
305	} else
306		cmd_delay();
307}
308
309void
310cmd_delay(void)
311{
312	double del;
313	del = atof(cmdbuf);
314
315	if (del > 0) {
316		udelay = (useconds_t)(del * 1000000);
317		gotsig_alarm = 1;
318		naptime = del;
319	}
320}
321
322void
323cmd_count(void)
324{
325	int ms;
326	ms = atoi(cmdbuf);
327
328	if (ms <= 0 || ms > lines - HEADER_LINES)
329		maxprint = lines - HEADER_LINES;
330	else
331		maxprint = ms;
332}
333
334
335int
336keyboard_callback(int ch)
337{
338	switch (ch) {
339	case '?':
340		/* FALLTHROUGH */
341	case 'h':
342		show_help();
343		need_update = 1;
344		break;
345	case 'l':
346		command_set(&cm_count, NULL);
347		break;
348	case 's':
349		command_set(&cm_delay, NULL);
350		break;
351	case ':':
352		command_set(&cm_compat, NULL);
353		break;
354	default:
355		return 0;
356	};
357
358	return 1;
359}
360
361void
362initialize(void)
363{
364	engine_initialize();
365
366	initvmstat();
367	initpigs();
368	initifstat();
369	initiostat();
370	initsensors();
371	initmembufs();
372	initnetstat();
373	initswap();
374	initpftop();
375	initpf();
376}
377
378void
379gethz(void)
380{
381	struct clockinfo cinf;
382	size_t  size = sizeof(cinf);
383	int	mib[2];
384
385	mib[0] = CTL_KERN;
386	mib[1] = KERN_CLOCKRATE;
387	if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1)
388		return;
389	stathz = cinf.stathz;
390	hz = cinf.hz;
391}
392
393int
394main(int argc, char *argv[])
395{
396	char errbuf[_POSIX2_LINE_MAX];
397	extern char *optarg;
398	extern int optind;
399	double delay = 5;
400
401	char *viewstr = NULL;
402
403	gid_t gid;
404	int countmax = 0;
405	int maxlines = 0;
406
407	int ch;
408
409	ut = open(_PATH_UTMP, O_RDONLY);
410	if (ut < 0) {
411		warn("No utmp");
412	}
413
414	kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
415	if (kd == NULL)
416		warnx("kvm_openfiles: %s", errbuf);
417
418	gid = getgid();
419	if (setresgid(gid, gid, gid) == -1)
420		err(1, "setresgid");
421
422	while ((ch = getopt(argc, argv, "abd:hins:S:w:")) != -1) {
423		switch (ch) {
424		case 'a':
425			maxlines = -1;
426			break;
427		case 'b':
428			rawmode = 1;
429			interactive = 0;
430			break;
431		case 'd':
432			countmax = atoi(optarg);
433			if (countmax < 0)
434				countmax = 0;
435			break;
436		case 'i':
437			interactive = 1;
438			break;
439		case 'n':
440			nflag = 1;
441			break;
442		case 's':
443			delay = atof(optarg);
444			if (delay <= 0)
445				delay = 5;
446			break;
447		case 'S':
448			dispstart = atoi(optarg);
449			if (dispstart < 0)
450				dispstart = 0;
451			break;
452		case 'w':
453			rawwidth = atoi(optarg);
454			if (rawwidth < 1)
455				rawwidth = DEFAULT_WIDTH;
456			if (rawwidth >= MAX_LINE_BUF)
457				rawwidth = MAX_LINE_BUF - 1;
458			break;
459		case 'h':
460			/* FALLTHROUGH */
461		default:
462			usage();
463			/* NOTREACHED */
464		}
465	}
466
467	argc -= optind;
468	argv += optind;
469
470	if (argc == 1) {
471		double del = atof(argv[0]);
472		if (del == 0)
473			viewstr = argv[0];
474		else
475			delay = del;
476	} else if (argc == 2) {
477		viewstr = argv[0];
478		delay = atof(argv[1]);
479	}
480
481	udelay = (useconds_t)(delay * 1000000.0);
482	if (udelay < 1)
483		udelay = 1;
484
485	naptime = (double)udelay / 1000000.0;
486
487	gethostname(hostname, sizeof (hostname));
488	gethz();
489
490	initialize();
491
492	set_order(NULL);
493	if (viewstr && set_view(viewstr)) {
494		fprintf(stderr, "Unknown/ambigious view name: %s\n", viewstr);
495		return 1;
496	}
497
498	if (!isatty(STDOUT_FILENO)) {
499		rawmode = 1;
500		interactive = 0;
501	}
502
503	setup_term(maxlines);
504
505	if (rawmode && countmax == 0)
506		countmax = 1;
507
508	gotsig_alarm = 1;
509
510	engine_loop(countmax);
511
512	return 0;
513}
514