main.c revision 1.64
1/* $Id: main.c,v 1.64 2016/01/02 15:02:05 benno 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/sysctl.h>
35
36
37#include <ctype.h>
38#include <curses.h>
39#include <err.h>
40#include <errno.h>
41#include <fcntl.h>
42#include <limits.h>
43#include <netdb.h>
44#include <signal.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <stdarg.h>
49#include <unistd.h>
50#include <utmp.h>
51
52#include "engine.h"
53#include "systat.h"
54
55#define TIMEPOS 55
56
57double	dellave;
58
59kvm_t	*kd;
60char	*nlistf = NULL;
61char	*memf = NULL;
62double	avenrun[3];
63double	naptime = 5.0;
64int	verbose = 1;		/* to report kvm read errs */
65int	nflag = 1;
66int	ut, hz, stathz;
67char    hostname[HOST_NAME_MAX+1];
68WINDOW  *wnd;
69int	CMDLINE;
70char	timebuf[26];
71char	uloadbuf[TIMEPOS];
72
73
74int  ucount(void);
75void usage(void);
76
77/* command prompt */
78
79void cmd_delay(const char *);
80void cmd_count(const char *);
81void cmd_compat(const char *);
82
83struct command cm_compat = {"Command", cmd_compat};
84struct command cm_delay = {"Seconds to delay", cmd_delay};
85struct command cm_count = {"Number of lines to display", cmd_count};
86
87
88/* display functions */
89
90int
91print_header(void)
92{
93	time_t now;
94	int start = dispstart + 1, end = dispstart + maxprint;
95	char tmpbuf[TIMEPOS];
96	char header[MAX_LINE_BUF];
97
98	if (end > num_disp)
99		end = num_disp;
100
101	tb_start();
102
103	if (!paused) {
104		getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0]));
105
106		snprintf(uloadbuf, sizeof(uloadbuf),
107		    "%5d users    Load %.2f %.2f %.2f",
108		    ucount(), avenrun[0], avenrun[1], avenrun[2]);
109
110		time(&now);
111		strlcpy(timebuf, ctime(&now), sizeof(timebuf));
112	}
113
114	if (num_disp && (start > 1 || end != num_disp))
115		snprintf(tmpbuf, sizeof(tmpbuf),
116		    "%s (%u-%u of %u) %s", uloadbuf, start, end, num_disp,
117		    paused ? "PAUSED" : "");
118	else
119		snprintf(tmpbuf, sizeof(tmpbuf),
120		    "%s %s", uloadbuf,
121		    paused ? "PAUSED" : "");
122
123	snprintf(header, sizeof(header), "%-55s%s", tmpbuf, timebuf);
124
125	if (rawmode)
126		printf("\n\n%s\n", header);
127	else
128		mvprintw(0, 0, "%s", header);
129
130	return (1);
131}
132
133/* compatibility functions, rearrange later */
134void
135error(const char *fmt, ...)
136{
137	va_list ap;
138	char buf[MAX_LINE_BUF];
139
140	va_start(ap, fmt);
141	vsnprintf(buf, sizeof buf, fmt, ap);
142	va_end(ap);
143
144	message_set(buf);
145}
146
147void
148nlisterr(struct nlist namelist[])
149{
150	int i, n;
151
152	n = 0;
153	clear();
154	mvprintw(2, 10, "systat: nlist: can't find following symbols:");
155	for (i = 0;
156	    namelist[i].n_name != NULL && *namelist[i].n_name != '\0'; i++)
157		if (namelist[i].n_value == 0)
158			mvprintw(2 + ++n, 10, "%s", namelist[i].n_name);
159	move(CMDLINE, 0);
160	clrtoeol();
161	refresh();
162	endwin();
163	exit(1);
164}
165
166void
167die(void)
168{
169	if (!rawmode)
170		endwin();
171	exit(0);
172}
173
174
175int
176prefix(char *s1, char *s2)
177{
178
179	while (*s1 == *s2) {
180		if (*s1 == '\0')
181			return (1);
182		s1++, s2++;
183	}
184	return (*s1 == '\0');
185}
186
187/* calculate number of users on the system */
188int
189ucount(void)
190{
191	int nusers = 0;
192	struct	utmp utmp;
193
194	if (ut < 0)
195		return (0);
196	lseek(ut, (off_t)0, SEEK_SET);
197	while (read(ut, &utmp, sizeof(utmp)))
198		if (utmp.ut_name[0] != '\0')
199			nusers++;
200
201	return (nusers);
202}
203
204/* main program functions */
205
206void
207usage(void)
208{
209	extern char *__progname;
210	fprintf(stderr, "usage: %s [-aBbiNn] [-d count] "
211	    "[-s delay] [-w width] [view] [delay]\n", __progname);
212	exit(1);
213}
214
215void
216show_view(void)
217{
218	if (rawmode)
219		return;
220
221	tb_start();
222	tbprintf("%s %g", curr_view->name, naptime);
223	tb_end();
224	message_set(tmp_buf);
225}
226
227void
228add_view_tb(field_view *v)
229{
230	if (curr_view == v)
231		tbprintf("[%s] ", v->name);
232	else
233		tbprintf("%s ", v->name);
234}
235
236void
237show_help(void)
238{
239	if (rawmode)
240		return;
241
242	tb_start();
243	foreach_view(add_view_tb);
244	tb_end();
245	message_set(tmp_buf);
246}
247
248void
249cmd_compat(const char *buf)
250{
251	const char *s;
252
253	if (strcasecmp(buf, "help") == 0) {
254		show_help();
255		need_update = 1;
256		return;
257	}
258	if (strcasecmp(buf, "quit") == 0 || strcasecmp(buf, "q") == 0) {
259		gotsig_close = 1;
260		return;
261	}
262	if (strcasecmp(buf, "stop") == 0) {
263		paused = 1;
264		gotsig_alarm = 1;
265		return;
266	}
267	if (strncasecmp(buf, "start", 5) == 0) {
268		paused = 0;
269		gotsig_alarm = 1;
270		cmd_delay(buf + 5);
271		return;
272	}
273
274	for (s = buf; *s && strchr("0123456789+-.eE", *s) != NULL; s++)
275		;
276	if (*s) {
277		if (set_view(buf))
278			error("Invalid/ambiguous view: %s", buf);
279	} else
280		cmd_delay(buf);
281}
282
283void
284cmd_delay(const char *buf)
285{
286	double del;
287	del = atof(buf);
288
289	if (del > 0) {
290		udelay = (useconds_t)(del * 1000000);
291		gotsig_alarm = 1;
292		naptime = del;
293	}
294}
295
296void
297cmd_count(const char *buf)
298{
299	const char *errstr;
300
301	maxprint = strtonum(buf, 1, lines - HEADER_LINES, &errstr);
302	if (errstr)
303		maxprint = lines - HEADER_LINES;
304}
305
306
307int
308keyboard_callback(int ch)
309{
310	switch (ch) {
311	case '?':
312		/* FALLTHROUGH */
313	case 'h':
314		show_help();
315		need_update = 1;
316		break;
317	case CTRL_G:
318		show_view();
319		need_update = 1;
320		break;
321	case 'l':
322		command_set(&cm_count, NULL);
323		break;
324	case 's':
325		command_set(&cm_delay, NULL);
326		break;
327	case ',':
328		separate_thousands = !separate_thousands;
329		gotsig_alarm = 1;
330		break;
331	case ':':
332		command_set(&cm_compat, NULL);
333		break;
334	default:
335		return 0;
336	};
337
338	return 1;
339}
340
341void
342initialize(void)
343{
344	engine_initialize();
345
346	initvmstat();
347	initpigs();
348	initifstat();
349	initiostat();
350	initsensors();
351	initmembufs();
352	initnetstat();
353	initswap();
354	initpftop();
355	initpf();
356	initpool();
357	initmalloc();
358	initnfs();
359	initcpu();
360}
361
362void
363gethz(void)
364{
365	struct clockinfo cinf;
366	size_t  size = sizeof(cinf);
367	int	mib[2];
368
369	mib[0] = CTL_KERN;
370	mib[1] = KERN_CLOCKRATE;
371	if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1)
372		return;
373	stathz = cinf.stathz;
374	hz = cinf.hz;
375}
376
377int
378main(int argc, char *argv[])
379{
380	char errbuf[_POSIX2_LINE_MAX];
381	const char *errstr;
382	extern char *optarg;
383	extern int optind;
384	double delay = 5;
385
386	char *viewstr = NULL;
387
388	gid_t gid;
389	int countmax = 0;
390	int maxlines = 0;
391
392	int ch;
393
394	ut = open(_PATH_UTMP, O_RDONLY);
395	if (ut < 0) {
396		warn("No utmp");
397	}
398
399	kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
400
401	gid = getgid();
402	if (setresgid(gid, gid, gid) == -1)
403		err(1, "setresgid");
404
405	while ((ch = getopt(argc, argv, "BNabd:ins:w:")) != -1) {
406		switch (ch) {
407		case 'a':
408			maxlines = -1;
409			break;
410		case 'B':
411			averageonly = 1;
412			if (countmax < 2)
413				countmax = 2;
414			/* FALLTHROUGH */
415		case 'b':
416			rawmode = 1;
417			interactive = 0;
418			break;
419		case 'd':
420			countmax = strtonum(optarg, 1, INT_MAX, &errstr);
421			if (errstr)
422				errx(1, "-d %s: %s", optarg, errstr);
423			break;
424		case 'i':
425			interactive = 1;
426			break;
427		case 'N':
428			nflag = 0;
429			break;
430		case 'n':
431			/* this is a noop, -n is the default */
432			nflag = 1;
433			break;
434		case 's':
435			delay = atof(optarg);
436			if (delay <= 0)
437				delay = 5;
438			break;
439		case 'w':
440			rawwidth = strtonum(optarg, 1, MAX_LINE_BUF-1, &errstr);
441			if (errstr)
442				errx(1, "-w %s: %s", optarg, errstr);
443			break;
444		default:
445			usage();
446			/* NOTREACHED */
447		}
448	}
449
450	if (kd == NULL)
451		warnx("kvm_openfiles: %s", errbuf);
452
453	argc -= optind;
454	argv += optind;
455
456	if (argc == 1) {
457		double del = atof(argv[0]);
458		if (del == 0)
459			viewstr = argv[0];
460		else
461			delay = del;
462	} else if (argc == 2) {
463		viewstr = argv[0];
464		delay = atof(argv[1]);
465		if (delay <= 0)
466			delay = 5;
467	}
468
469	udelay = (useconds_t)(delay * 1000000.0);
470	if (udelay < 1)
471		udelay = 1;
472
473	naptime = (double)udelay / 1000000.0;
474
475	gethostname(hostname, sizeof (hostname));
476	gethz();
477
478	initialize();
479
480	set_order(NULL);
481	if (viewstr && set_view(viewstr)) {
482		fprintf(stderr, "Unknown/ambiguous view name: %s\n", viewstr);
483		return 1;
484	}
485
486	if (check_termcap()) {
487		rawmode = 1;
488		interactive = 0;
489	}
490
491	setup_term(maxlines);
492
493	if (rawmode && countmax == 0)
494		countmax = 1;
495
496	gotsig_alarm = 1;
497
498	engine_loop(countmax);
499
500	return 0;
501}
502