main.c revision 1.49
1/* $Id: main.c,v 1.49 2008/11/04 19:00:08 espie 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(const char *);
75void cmd_count(const char *);
76void cmd_compat(const char *);
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 [-abin] [-d count] "
212	    "[-s delay] [-w width] [view] [delay]\n", __progname);
213	exit(1);
214}
215
216void
217show_view(void)
218{
219	if (rawmode)
220		return;
221
222	tb_start();
223	tbprintf("%s %g", curr_view->name, naptime);
224	tb_end();
225	message_set(tmp_buf);
226}
227
228void
229add_view_tb(field_view *v)
230{
231	if (curr_view == v)
232		tbprintf("[%s] ", v->name);
233	else
234		tbprintf("%s ", v->name);
235}
236
237void
238show_help(void)
239{
240	int line = 0;
241
242	if (rawmode)
243		return;
244
245	tb_start();
246	foreach_view(add_view_tb);
247	tb_end();
248	message_set(tmp_buf);
249}
250
251void
252cmd_compat(const char *buf)
253{
254	const char *s;
255
256	if (strcasecmp(buf, "help") == 0) {
257		show_help();
258		need_update = 1;
259		return;
260	}
261	if (strcasecmp(buf, "quit") == 0 || strcasecmp(buf, "q") == 0) {
262		gotsig_close = 1;
263		return;
264	}
265	if (strcasecmp(buf, "stop") == 0) {
266		paused = 1;
267		gotsig_alarm = 1;
268		return;
269	}
270	if (strncasecmp(buf, "start", 5) == 0) {
271		paused = 0;
272		gotsig_alarm = 1;
273		cmd_delay(buf + 5);
274		return;
275	}
276
277	for (s = buf; *s && strchr("0123456789+-.eE", *s) != NULL; s++)
278		;
279	if (*s) {
280		if (set_view(buf))
281			error("Invalid/ambiguous view: %s", buf);
282	} else
283		cmd_delay(buf);
284}
285
286void
287cmd_delay(const char *buf)
288{
289	double del;
290	del = atof(buf);
291
292	if (del > 0) {
293		udelay = (useconds_t)(del * 1000000);
294		gotsig_alarm = 1;
295		naptime = del;
296	}
297}
298
299void
300cmd_count(const char *buf)
301{
302	int ms;
303	ms = atoi(buf);
304
305	if (ms <= 0 || ms > lines - HEADER_LINES)
306		maxprint = lines - HEADER_LINES;
307	else
308		maxprint = ms;
309}
310
311
312int
313keyboard_callback(int ch)
314{
315	switch (ch) {
316	case '?':
317		/* FALLTHROUGH */
318	case 'h':
319		show_help();
320		need_update = 1;
321		break;
322	case CTRL_G:
323		show_view();
324		need_update = 1;
325		break;
326	case 'l':
327		command_set(&cm_count, NULL);
328		break;
329	case 's':
330		command_set(&cm_delay, NULL);
331		break;
332	case ':':
333		command_set(&cm_compat, NULL);
334		break;
335	default:
336		return 0;
337	};
338
339	return 1;
340}
341
342void
343initialize(void)
344{
345	engine_initialize();
346
347	initvmstat();
348	initpigs();
349	initifstat();
350	initiostat();
351	initsensors();
352	initmembufs();
353	initnetstat();
354	initswap();
355	initpftop();
356	initpf();
357	initpool();
358}
359
360void
361gethz(void)
362{
363	struct clockinfo cinf;
364	size_t  size = sizeof(cinf);
365	int	mib[2];
366
367	mib[0] = CTL_KERN;
368	mib[1] = KERN_CLOCKRATE;
369	if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1)
370		return;
371	stathz = cinf.stathz;
372	hz = cinf.hz;
373}
374
375int
376main(int argc, char *argv[])
377{
378	char errbuf[_POSIX2_LINE_MAX];
379	extern char *optarg;
380	extern int optind;
381	double delay = 5;
382
383	char *viewstr = NULL;
384
385	gid_t gid;
386	int countmax = 0;
387	int maxlines = 0;
388
389	int ch;
390
391	ut = open(_PATH_UTMP, O_RDONLY);
392	if (ut < 0) {
393		warn("No utmp");
394	}
395
396	kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
397
398	gid = getgid();
399	if (setresgid(gid, gid, gid) == -1)
400		err(1, "setresgid");
401
402	while ((ch = getopt(argc, argv, "abd:ins:w:")) != -1) {
403		switch (ch) {
404		case 'a':
405			maxlines = -1;
406			break;
407		case 'b':
408			rawmode = 1;
409			interactive = 0;
410			break;
411		case 'd':
412			countmax = atoi(optarg);
413			if (countmax < 0)
414				countmax = 0;
415			break;
416		case 'i':
417			interactive = 1;
418			break;
419		case 'n':
420			nflag = 1;
421			break;
422		case 's':
423			delay = atof(optarg);
424			if (delay <= 0)
425				delay = 5;
426			break;
427		case 'w':
428			rawwidth = atoi(optarg);
429			if (rawwidth < 1)
430				rawwidth = DEFAULT_WIDTH;
431			if (rawwidth >= MAX_LINE_BUF)
432				rawwidth = MAX_LINE_BUF - 1;
433			break;
434		default:
435			usage();
436			/* NOTREACHED */
437		}
438	}
439
440	if (kd == NULL)
441		warnx("kvm_openfiles: %s", errbuf);
442
443	argc -= optind;
444	argv += optind;
445
446	if (argc == 1) {
447		double del = atof(argv[0]);
448		if (del == 0)
449			viewstr = argv[0];
450		else
451			delay = del;
452	} else if (argc == 2) {
453		viewstr = argv[0];
454		delay = atof(argv[1]);
455		if (delay <= 0)
456			delay = 5;
457	}
458
459	udelay = (useconds_t)(delay * 1000000.0);
460	if (udelay < 1)
461		udelay = 1;
462
463	naptime = (double)udelay / 1000000.0;
464
465	gethostname(hostname, sizeof (hostname));
466	gethz();
467
468	initialize();
469
470	set_order(NULL);
471	if (viewstr && set_view(viewstr)) {
472		fprintf(stderr, "Unknown/ambiguous view name: %s\n", viewstr);
473		return 1;
474	}
475
476	if (!isatty(STDOUT_FILENO)) {
477		rawmode = 1;
478		interactive = 0;
479	}
480
481	setup_term(maxlines);
482
483	if (rawmode && countmax == 0)
484		countmax = 1;
485
486	gotsig_alarm = 1;
487
488	engine_loop(countmax);
489
490	return 0;
491}
492