main.c revision 1.68
1/* $Id: main.c,v 1.68 2018/05/30 13:43:51 krw 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 (80 - 8 - 20 - 1)
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		char *ctim;
105
106		getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0]));
107
108		snprintf(uloadbuf, sizeof(uloadbuf),
109		    "%4d users Load %.2f %.2f %.2f",
110		    ucount(), avenrun[0], avenrun[1], avenrun[2]);
111
112		time(&now);
113		ctim = ctime(&now);
114		ctim[11+8] = '\0';
115		strlcpy(timebuf, ctim + 11, sizeof(timebuf));
116	}
117
118	if (num_disp && (start > 1 || end != num_disp))
119		snprintf(tmpbuf, sizeof(tmpbuf),
120		    "%s (%u-%u of %u) %s", uloadbuf, start, end, num_disp,
121		    paused ? "PAUSED" : "");
122	else
123		snprintf(tmpbuf, sizeof(tmpbuf),
124		    "%s %s", uloadbuf,
125		    paused ? "PAUSED" : "");
126
127	snprintf(header, sizeof(header), "%-*s %19.19s %s", TIMEPOS - 1,
128	    tmpbuf, hostname, timebuf);
129
130	if (rawmode)
131		printf("\n\n%s\n", header);
132	else
133		mvprintw(0, 0, "%s", header);
134
135	return (1);
136}
137
138/* compatibility functions, rearrange later */
139void
140error(const char *fmt, ...)
141{
142	va_list ap;
143	char buf[MAX_LINE_BUF];
144
145	va_start(ap, fmt);
146	vsnprintf(buf, sizeof buf, fmt, ap);
147	va_end(ap);
148
149	message_set(buf);
150}
151
152void
153nlisterr(struct nlist namelist[])
154{
155	int i, n;
156
157	n = 0;
158	clear();
159	mvprintw(2, 10, "systat: nlist: can't find following symbols:");
160	for (i = 0;
161	    namelist[i].n_name != NULL && *namelist[i].n_name != '\0'; i++)
162		if (namelist[i].n_value == 0)
163			mvprintw(2 + ++n, 10, "%s", namelist[i].n_name);
164	move(CMDLINE, 0);
165	clrtoeol();
166	refresh();
167	endwin();
168	exit(1);
169}
170
171void
172die(void)
173{
174	if (!rawmode)
175		endwin();
176	exit(0);
177}
178
179
180int
181prefix(char *s1, char *s2)
182{
183
184	while (*s1 == *s2) {
185		if (*s1 == '\0')
186			return (1);
187		s1++, s2++;
188	}
189	return (*s1 == '\0');
190}
191
192/* calculate number of users on the system */
193int
194ucount(void)
195{
196	int nusers = 0;
197	struct	utmp utmp;
198
199	if (ut < 0)
200		return (0);
201	lseek(ut, (off_t)0, SEEK_SET);
202	while (read(ut, &utmp, sizeof(utmp)))
203		if (utmp.ut_name[0] != '\0')
204			nusers++;
205
206	return (nusers);
207}
208
209/* main program functions */
210
211void
212usage(void)
213{
214	extern char *__progname;
215	fprintf(stderr, "usage: %s [-aBbiNn] [-d count] "
216	    "[-s delay] [-w width] [view] [delay]\n", __progname);
217	exit(1);
218}
219
220void
221show_view(void)
222{
223	if (rawmode)
224		return;
225
226	tb_start();
227	tbprintf("%s %g", curr_view->name, naptime);
228	tb_end();
229	message_set(tmp_buf);
230}
231
232void
233add_view_tb(field_view *v)
234{
235	if (curr_view == v)
236		tbprintf("[%s] ", v->name);
237	else
238		tbprintf("%s ", v->name);
239}
240
241void
242show_help(void)
243{
244	if (rawmode)
245		return;
246
247	tb_start();
248	foreach_view(add_view_tb);
249	tb_end();
250	message_set(tmp_buf);
251}
252
253void
254add_order_tb(order_type *o)
255{
256	if (curr_view->mgr->order_curr == o)
257		tbprintf("[%s%s(%c)] ", o->name,
258		    o->func != NULL && sortdir == -1 ? "^" : "",
259		    (char) o->hotkey);
260	else
261		tbprintf("%s(%c) ", o->name, (char) o->hotkey);
262}
263
264void
265show_order(void)
266{
267	if (rawmode)
268		return;
269
270	tb_start();
271	if (foreach_order(add_order_tb) == -1) {
272		tbprintf("No orders available");
273	}
274	tb_end();
275	message_set(tmp_buf);
276}
277
278void
279cmd_compat(const char *buf)
280{
281	const char *s;
282
283	if (strcasecmp(buf, "help") == 0) {
284		show_help();
285		need_update = 1;
286		return;
287	}
288	if (strcasecmp(buf, "quit") == 0 || strcasecmp(buf, "q") == 0) {
289		gotsig_close = 1;
290		return;
291	}
292	if (strcasecmp(buf, "stop") == 0) {
293		paused = 1;
294		gotsig_alarm = 1;
295		return;
296	}
297	if (strncasecmp(buf, "start", 5) == 0) {
298		paused = 0;
299		gotsig_alarm = 1;
300		cmd_delay(buf + 5);
301		return;
302	}
303	if (strncasecmp(buf, "order", 5) == 0) {
304		show_order();
305		need_update = 1;
306		return;
307	}
308
309	for (s = buf; *s && strchr("0123456789+-.eE", *s) != NULL; s++)
310		;
311	if (*s) {
312		if (set_view(buf))
313			error("Invalid/ambiguous view: %s", buf);
314	} else
315		cmd_delay(buf);
316}
317
318void
319cmd_delay(const char *buf)
320{
321	double del;
322	del = atof(buf);
323
324	if (del > 0) {
325		udelay = (useconds_t)(del * 1000000);
326		gotsig_alarm = 1;
327		naptime = del;
328	}
329}
330
331void
332cmd_count(const char *buf)
333{
334	const char *errstr;
335
336	maxprint = strtonum(buf, 1, lines - HEADER_LINES, &errstr);
337	if (errstr)
338		maxprint = lines - HEADER_LINES;
339}
340
341
342int
343keyboard_callback(int ch)
344{
345	switch (ch) {
346	case '?':
347		/* FALLTHROUGH */
348	case 'h':
349		show_help();
350		need_update = 1;
351		break;
352	case CTRL_G:
353		show_view();
354		need_update = 1;
355		break;
356	case 'l':
357		command_set(&cm_count, NULL);
358		break;
359	case 's':
360		command_set(&cm_delay, NULL);
361		break;
362	case ',':
363		separate_thousands = !separate_thousands;
364		gotsig_alarm = 1;
365		break;
366	case ':':
367		command_set(&cm_compat, NULL);
368		break;
369	default:
370		return 0;
371	};
372
373	return 1;
374}
375
376void
377initialize(void)
378{
379	engine_initialize();
380
381	initvmstat();
382	initpigs();
383	initifstat();
384	initiostat();
385	initsensors();
386	initmembufs();
387	initnetstat();
388	initswap();
389	initpftop();
390	initpf();
391	initpool();
392	initmalloc();
393	initnfs();
394	initcpu();
395	inituvm();
396}
397
398void
399gethz(void)
400{
401	struct clockinfo cinf;
402	size_t  size = sizeof(cinf);
403	int	mib[2];
404
405	mib[0] = CTL_KERN;
406	mib[1] = KERN_CLOCKRATE;
407	if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1)
408		return;
409	stathz = cinf.stathz;
410	hz = cinf.hz;
411}
412
413int
414main(int argc, char *argv[])
415{
416	char errbuf[_POSIX2_LINE_MAX];
417	const char *errstr;
418	extern char *optarg;
419	extern int optind;
420	double delay = 5;
421
422	char *viewstr = NULL;
423
424	gid_t gid;
425	int countmax = 0;
426	int maxlines = 0;
427
428	int ch;
429
430	ut = open(_PATH_UTMP, O_RDONLY);
431	if (ut < 0) {
432		warn("No utmp");
433	}
434
435	kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
436
437	gid = getgid();
438	if (setresgid(gid, gid, gid) == -1)
439		err(1, "setresgid");
440
441	while ((ch = getopt(argc, argv, "BNabd:ins:w:")) != -1) {
442		switch (ch) {
443		case 'a':
444			maxlines = -1;
445			break;
446		case 'B':
447			averageonly = 1;
448			if (countmax < 2)
449				countmax = 2;
450			/* FALLTHROUGH */
451		case 'b':
452			rawmode = 1;
453			interactive = 0;
454			break;
455		case 'd':
456			countmax = strtonum(optarg, 1, INT_MAX, &errstr);
457			if (errstr)
458				errx(1, "-d %s: %s", optarg, errstr);
459			break;
460		case 'i':
461			interactive = 1;
462			break;
463		case 'N':
464			nflag = 0;
465			break;
466		case 'n':
467			/* this is a noop, -n is the default */
468			nflag = 1;
469			break;
470		case 's':
471			delay = atof(optarg);
472			if (delay <= 0)
473				delay = 5;
474			break;
475		case 'w':
476			rawwidth = strtonum(optarg, 1, MAX_LINE_BUF-1, &errstr);
477			if (errstr)
478				errx(1, "-w %s: %s", optarg, errstr);
479			break;
480		default:
481			usage();
482			/* NOTREACHED */
483		}
484	}
485
486	if (kd == NULL)
487		warnx("kvm_openfiles: %s", errbuf);
488
489	argc -= optind;
490	argv += optind;
491
492	if (argc == 1) {
493		double del = atof(argv[0]);
494		if (del == 0)
495			viewstr = argv[0];
496		else
497			delay = del;
498	} else if (argc == 2) {
499		viewstr = argv[0];
500		delay = atof(argv[1]);
501		if (delay <= 0)
502			delay = 5;
503	}
504
505	udelay = (useconds_t)(delay * 1000000.0);
506	if (udelay < 1)
507		udelay = 1;
508
509	naptime = (double)udelay / 1000000.0;
510
511	gethostname(hostname, sizeof (hostname));
512	gethz();
513
514	initialize();
515
516	set_order(NULL);
517	if (viewstr && set_view(viewstr)) {
518		fprintf(stderr, "Unknown/ambiguous view name: %s\n", viewstr);
519		return 1;
520	}
521
522	if (check_termcap()) {
523		rawmode = 1;
524		interactive = 0;
525	}
526
527	setup_term(maxlines);
528
529	if (rawmode && countmax == 0)
530		countmax = 1;
531
532	gotsig_alarm = 1;
533
534	engine_loop(countmax);
535
536	return 0;
537}
538