Annotation of src/usr.bin/systat/main.c, Revision 1.72
1.72 ! martijn 1: /* $OpenBSD: main.c,v 1.71 2019/10/14 19:22:17 deraadt 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.66 otto 55: #define TIMEPOS (80 - 8 - 20 - 1)
1.58 lum 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.58 lum 70: char timebuf[26];
71: char uloadbuf[TIMEPOS];
1.1 deraadt 72:
1.38 canacar 73:
1.50 canacar 74: int ucount(void);
75: void usage(void);
76:
1.38 canacar 77: /* command prompt */
78:
1.46 canacar 79: void cmd_delay(const char *);
80: void cmd_count(const char *);
81: void cmd_compat(const char *);
1.38 canacar 82:
83: struct command cm_compat = {"Command", cmd_compat};
84: struct command cm_delay = {"Seconds to delay", cmd_delay};
85: struct command cm_count = {"Number of lines to display", cmd_count};
1.1 deraadt 86:
1.38 canacar 87:
88: /* display functions */
1.3 deraadt 89:
1.2 deraadt 90: int
1.38 canacar 91: print_header(void)
1.1 deraadt 92: {
1.50 canacar 93: time_t now;
1.40 deraadt 94: int start = dispstart + 1, end = dispstart + maxprint;
1.58 lum 95: char tmpbuf[TIMEPOS];
96: char header[MAX_LINE_BUF];
1.38 canacar 97:
98: if (end > num_disp)
99: end = num_disp;
100:
101: tb_start();
1.35 deraadt 102:
1.58 lum 103: if (!paused) {
1.65 tedu 104: char *ctim;
105:
1.58 lum 106: getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0]));
1.38 canacar 107:
1.58 lum 108: snprintf(uloadbuf, sizeof(uloadbuf),
1.66 otto 109: "%4d users Load %.2f %.2f %.2f",
1.58 lum 110: ucount(), avenrun[0], avenrun[1], avenrun[2]);
1.25 deraadt 111:
1.58 lum 112: time(&now);
1.65 tedu 113: ctim = ctime(&now);
114: ctim[11+8] = '\0';
115: strlcpy(timebuf, ctim + 11, sizeof(timebuf));
1.58 lum 116: }
1.25 deraadt 117:
1.58 lum 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:
1.66 otto 127: snprintf(header, sizeof(header), "%-*s %19.19s %s", TIMEPOS - 1,
128: tmpbuf, hostname, timebuf);
1.58 lum 129:
130: if (rawmode)
131: printf("\n\n%s\n", header);
132: else
133: mvprintw(0, 0, "%s", header);
1.24 deraadt 134:
1.38 canacar 135: return (1);
1.1 deraadt 136: }
1.3 deraadt 137:
1.38 canacar 138: /* compatibility functions, rearrange later */
1.21 deraadt 139: void
1.38 canacar 140: error(const char *fmt, ...)
1.21 deraadt 141: {
1.38 canacar 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);
1.21 deraadt 148:
1.38 canacar 149: message_set(buf);
1.21 deraadt 150: }
151:
1.38 canacar 152: void
153: nlisterr(struct nlist namelist[])
1.3 deraadt 154: {
1.38 canacar 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();
1.3 deraadt 168: exit(1);
169: }
170:
1.1 deraadt 171: void
1.38 canacar 172: die(void)
1.1 deraadt 173: {
1.38 canacar 174: if (!rawmode)
175: endwin();
176: exit(0);
1.1 deraadt 177: }
178:
1.38 canacar 179:
180: int
181: prefix(char *s1, char *s2)
1.1 deraadt 182: {
1.38 canacar 183:
184: while (*s1 == *s2) {
185: if (*s1 == '\0')
186: return (1);
187: s1++, s2++;
188: }
189: return (*s1 == '\0');
1.21 deraadt 190: }
191:
1.38 canacar 192: /* calculate number of users on the system */
193: int
194: ucount(void)
1.21 deraadt 195: {
1.38 canacar 196: int nusers = 0;
197: struct utmp utmp;
1.35 deraadt 198:
1.38 canacar 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++;
1.35 deraadt 205:
1.38 canacar 206: return (nusers);
1.1 deraadt 207: }
208:
1.38 canacar 209: /* main program functions */
210:
1.1 deraadt 211: void
1.50 canacar 212: usage(void)
1.1 deraadt 213: {
1.38 canacar 214: extern char *__progname;
1.72 ! martijn 215: fprintf(stderr, "usage: %s [-aBbhiNn] [-d count] "
1.43 matthieu 216: "[-s delay] [-w width] [view] [delay]\n", __progname);
1.38 canacar 217: exit(1);
1.1 deraadt 218: }
219:
1.45 canacar 220: void
221: show_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: }
1.21 deraadt 231:
1.1 deraadt 232: void
1.38 canacar 233: add_view_tb(field_view *v)
1.1 deraadt 234: {
1.38 canacar 235: if (curr_view == v)
236: tbprintf("[%s] ", v->name);
237: else
238: tbprintf("%s ", v->name);
1.29 deraadt 239: }
240:
241: void
1.38 canacar 242: show_help(void)
1.29 deraadt 243: {
1.38 canacar 244: if (rawmode)
245: return;
246:
247: tb_start();
248: foreach_view(add_view_tb);
249: tb_end();
250: message_set(tmp_buf);
1.21 deraadt 251: }
252:
253: void
1.67 martijn 254: add_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:
264: void
265: show_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:
278: void
1.46 canacar 279: cmd_compat(const char *buf)
1.21 deraadt 280: {
1.46 canacar 281: const char *s;
1.38 canacar 282:
1.46 canacar 283: if (strcasecmp(buf, "help") == 0) {
1.38 canacar 284: show_help();
285: need_update = 1;
286: return;
287: }
1.46 canacar 288: if (strcasecmp(buf, "quit") == 0 || strcasecmp(buf, "q") == 0) {
1.38 canacar 289: gotsig_close = 1;
290: return;
291: }
1.46 canacar 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;
1.47 canacar 300: cmd_delay(buf + 5);
1.67 martijn 301: return;
302: }
303: if (strncasecmp(buf, "order", 5) == 0) {
304: show_order();
305: need_update = 1;
1.46 canacar 306: return;
307: }
1.72 ! martijn 308: if (strncasecmp(buf, "human", 5) == 0) {
! 309: humanreadable = !humanreadable;
! 310: return;
! 311: }
1.38 canacar 312:
1.46 canacar 313: for (s = buf; *s && strchr("0123456789+-.eE", *s) != NULL; s++)
1.38 canacar 314: ;
315: if (*s) {
1.46 canacar 316: if (set_view(buf))
1.49 espie 317: error("Invalid/ambiguous view: %s", buf);
1.38 canacar 318: } else
1.46 canacar 319: cmd_delay(buf);
1.38 canacar 320: }
321:
322: void
1.46 canacar 323: cmd_delay(const char *buf)
1.38 canacar 324: {
325: double del;
1.46 canacar 326: del = atof(buf);
1.39 canacar 327:
1.38 canacar 328: if (del > 0) {
329: udelay = (useconds_t)(del * 1000000);
330: gotsig_alarm = 1;
1.39 canacar 331: naptime = del;
1.13 deraadt 332: }
1.1 deraadt 333: }
1.14 kstailey 334:
335: void
1.46 canacar 336: cmd_count(const char *buf)
1.14 kstailey 337: {
1.63 deraadt 338: const char *errstr;
1.38 canacar 339:
1.63 deraadt 340: maxprint = strtonum(buf, 1, lines - HEADER_LINES, &errstr);
341: if (errstr)
1.38 canacar 342: maxprint = lines - HEADER_LINES;
1.14 kstailey 343: }
344:
1.38 canacar 345:
346: int
347: keyboard_callback(int ch)
1.1 deraadt 348: {
1.38 canacar 349: switch (ch) {
350: case '?':
351: /* FALLTHROUGH */
352: case 'h':
353: show_help();
1.45 canacar 354: need_update = 1;
355: break;
356: case CTRL_G:
357: show_view();
1.38 canacar 358: need_update = 1;
359: break;
360: case 'l':
361: command_set(&cm_count, NULL);
362: break;
363: case 's':
364: command_set(&cm_delay, NULL);
1.59 mpf 365: break;
366: case ',':
367: separate_thousands = !separate_thousands;
368: gotsig_alarm = 1;
1.38 canacar 369: break;
370: case ':':
371: command_set(&cm_compat, NULL);
372: break;
373: default:
374: return 0;
375: };
376:
377: return 1;
378: }
1.23 millert 379:
1.38 canacar 380: void
381: initialize(void)
382: {
383: engine_initialize();
384:
385: initvmstat();
386: initpigs();
387: initifstat();
388: initiostat();
389: initsensors();
390: initmembufs();
391: initnetstat();
392: initswap();
393: initpftop();
394: initpf();
1.48 canacar 395: initpool();
1.51 canacar 396: initmalloc();
1.52 jasper 397: initnfs();
1.60 reyk 398: initcpu();
1.68 krw 399: inituvm();
1.1 deraadt 400: }
401:
402: void
1.38 canacar 403: gethz(void)
1.1 deraadt 404: {
1.38 canacar 405: struct clockinfo cinf;
406: size_t size = sizeof(cinf);
407: int mib[2];
1.1 deraadt 408:
1.38 canacar 409: mib[0] = CTL_KERN;
410: mib[1] = KERN_CLOCKRATE;
411: if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1)
412: return;
413: stathz = cinf.stathz;
414: hz = cinf.hz;
1.35 deraadt 415: }
416:
417: int
1.38 canacar 418: main(int argc, char *argv[])
1.35 deraadt 419: {
1.38 canacar 420: char errbuf[_POSIX2_LINE_MAX];
1.63 deraadt 421: const char *errstr;
1.38 canacar 422: extern char *optarg;
423: extern int optind;
424: double delay = 5;
425:
426: char *viewstr = NULL;
427:
428: gid_t gid;
429: int countmax = 0;
430: int maxlines = 0;
431:
432: int ch;
433:
434: ut = open(_PATH_UTMP, O_RDONLY);
1.70 deraadt 435: if (ut == -1) {
1.38 canacar 436: warn("No utmp");
437: }
438:
1.62 claudio 439: kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
1.38 canacar 440:
441: gid = getgid();
442: if (setresgid(gid, gid, gid) == -1)
443: err(1, "setresgid");
444:
1.72 ! martijn 445: while ((ch = getopt(argc, argv, "BNabd:hins:w:")) != -1) {
1.38 canacar 446: switch (ch) {
447: case 'a':
448: maxlines = -1;
449: break;
1.60 reyk 450: case 'B':
451: averageonly = 1;
452: if (countmax < 2)
453: countmax = 2;
454: /* FALLTHROUGH */
1.38 canacar 455: case 'b':
456: rawmode = 1;
457: interactive = 0;
458: break;
459: case 'd':
1.63 deraadt 460: countmax = strtonum(optarg, 1, INT_MAX, &errstr);
461: if (errstr)
462: errx(1, "-d %s: %s", optarg, errstr);
1.72 ! martijn 463: break;
! 464: case 'h':
! 465: humanreadable = 1;
1.38 canacar 466: break;
467: case 'i':
468: interactive = 1;
469: break;
1.55 sthen 470: case 'N':
471: nflag = 0;
472: break;
1.38 canacar 473: case 'n':
1.55 sthen 474: /* this is a noop, -n is the default */
1.38 canacar 475: nflag = 1;
476: break;
477: case 's':
478: delay = atof(optarg);
1.39 canacar 479: if (delay <= 0)
1.38 canacar 480: delay = 5;
481: break;
482: case 'w':
1.63 deraadt 483: rawwidth = strtonum(optarg, 1, MAX_LINE_BUF-1, &errstr);
484: if (errstr)
485: errx(1, "-w %s: %s", optarg, errstr);
1.38 canacar 486: break;
487: default:
488: usage();
489: /* NOTREACHED */
490: }
491: }
1.43 matthieu 492:
493: if (kd == NULL)
494: warnx("kvm_openfiles: %s", errbuf);
1.38 canacar 495:
496: argc -= optind;
497: argv += optind;
498:
499: if (argc == 1) {
500: double del = atof(argv[0]);
501: if (del == 0)
502: viewstr = argv[0];
503: else
504: delay = del;
505: } else if (argc == 2) {
506: viewstr = argv[0];
507: delay = atof(argv[1]);
1.42 canacar 508: if (delay <= 0)
509: delay = 5;
1.38 canacar 510: }
511:
512: udelay = (useconds_t)(delay * 1000000.0);
513: if (udelay < 1)
514: udelay = 1;
1.39 canacar 515:
516: naptime = (double)udelay / 1000000.0;
1.38 canacar 517:
518: gethostname(hostname, sizeof (hostname));
519: gethz();
520:
521: initialize();
522:
523: set_order(NULL);
524: if (viewstr && set_view(viewstr)) {
1.49 espie 525: fprintf(stderr, "Unknown/ambiguous view name: %s\n", viewstr);
1.38 canacar 526: return 1;
527: }
528:
1.57 lum 529: if (check_termcap()) {
1.38 canacar 530: rawmode = 1;
531: interactive = 0;
532: }
533:
534: setup_term(maxlines);
1.71 deraadt 535:
536: if (unveil("/", "r") == -1)
537: err(1, "unveil");
538: if (unveil(NULL, NULL) == -1)
539: err(1, "unveil");
1.38 canacar 540:
541: if (rawmode && countmax == 0)
542: countmax = 1;
543:
544: gotsig_alarm = 1;
1.35 deraadt 545:
1.38 canacar 546: engine_loop(countmax);
1.35 deraadt 547:
1.38 canacar 548: return 0;
1.1 deraadt 549: }