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