Annotation of src/usr.bin/systat/main.c, Revision 1.46
1.46 ! canacar 1: /* $Id: main.c,v 1.45 2008/10/31 06:06:46 canacar 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.1 deraadt 34: #include <sys/param.h>
1.21 deraadt 35: #include <sys/sysctl.h>
1.1 deraadt 36:
1.38 canacar 37:
38: #include <ctype.h>
39: #include <curses.h>
1.1 deraadt 40: #include <err.h>
1.38 canacar 41: #include <errno.h>
42: #include <fcntl.h>
43: #include <limits.h>
44: #include <netdb.h>
1.1 deraadt 45: #include <signal.h>
46: #include <stdio.h>
1.38 canacar 47: #include <stdlib.h>
1.1 deraadt 48: #include <string.h>
1.38 canacar 49: #include <stdarg.h>
1.3 deraadt 50: #include <unistd.h>
1.35 deraadt 51: #include <utmp.h>
1.1 deraadt 52:
1.38 canacar 53: #include "engine.h"
1.1 deraadt 54: #include "systat.h"
55:
1.21 deraadt 56: double dellave;
1.1 deraadt 57:
1.21 deraadt 58: kvm_t *kd;
59: char *nlistf = NULL;
1.20 pvalchev 60: char *memf = NULL;
1.21 deraadt 61: double avenrun[3];
1.36 tedu 62: double naptime = 5.0;
1.21 deraadt 63: int verbose = 1; /* to report kvm read errs */
1.38 canacar 64: int nflag = 1;
1.35 deraadt 65: int ut, hz, stathz;
1.1 deraadt 66: char hostname[MAXHOSTNAMELEN];
67: WINDOW *wnd;
1.32 deraadt 68: int CMDLINE;
1.1 deraadt 69:
1.38 canacar 70: #define TIMEPOS 55
71:
72: /* command prompt */
73:
1.46 ! canacar 74: void cmd_delay(const char *);
! 75: void cmd_count(const char *);
! 76: void cmd_compat(const char *);
1.38 canacar 77:
78: struct command cm_compat = {"Command", cmd_compat};
79: struct command cm_delay = {"Seconds to delay", cmd_delay};
80: struct command cm_count = {"Number of lines to display", cmd_count};
1.1 deraadt 81:
1.38 canacar 82:
83: /* display functions */
1.3 deraadt 84:
1.2 deraadt 85: int
1.38 canacar 86: print_header(void)
1.1 deraadt 87: {
1.38 canacar 88: struct tm *tp;
1.40 deraadt 89: time_t t, now;
1.38 canacar 90: order_type *ordering;
1.40 deraadt 91: int start = dispstart + 1, end = dispstart + maxprint;
92: extern int ucount();
93: char tbuf[26];
1.38 canacar 94:
95: if (end > num_disp)
96: end = num_disp;
97:
98: tb_start();
1.35 deraadt 99:
1.38 canacar 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: }
1.35 deraadt 108: }
1.38 canacar 109: #endif
1.1 deraadt 110:
1.38 canacar 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);
1.25 deraadt 119:
1.38 canacar 120: if (paused)
121: tbprintf(" PAUSED");
1.25 deraadt 122:
1.38 canacar 123: if (rawmode)
124: printf("\n\n%s\n", tmp_buf);
125: else
126: mvprintw(0, 0, "%s", tmp_buf);
1.36 tedu 127:
1.38 canacar 128: mvprintw(0, TIMEPOS, "%s", tbuf);
1.3 deraadt 129:
1.24 deraadt 130:
1.38 canacar 131: return (1);
1.1 deraadt 132: }
1.3 deraadt 133:
1.38 canacar 134: /* compatibility functions, rearrange later */
1.21 deraadt 135: void
1.38 canacar 136: error(const char *fmt, ...)
1.21 deraadt 137: {
1.38 canacar 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);
1.21 deraadt 144:
1.38 canacar 145: message_set(buf);
1.21 deraadt 146: }
147:
1.38 canacar 148: void
149: nlisterr(struct nlist namelist[])
1.3 deraadt 150: {
1.38 canacar 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();
1.3 deraadt 164: exit(1);
165: }
166:
1.1 deraadt 167: void
1.38 canacar 168: die(void)
1.1 deraadt 169: {
1.38 canacar 170: if (!rawmode)
171: endwin();
172: exit(0);
1.1 deraadt 173: }
174:
1.38 canacar 175:
176: int
177: prefix(char *s1, char *s2)
1.1 deraadt 178: {
1.38 canacar 179:
180: while (*s1 == *s2) {
181: if (*s1 == '\0')
182: return (1);
183: s1++, s2++;
184: }
185: return (*s1 == '\0');
1.21 deraadt 186: }
187:
1.38 canacar 188: /* calculate number of users on the system */
189: int
190: ucount(void)
1.21 deraadt 191: {
1.38 canacar 192: int nusers = 0;
193: struct utmp utmp;
1.35 deraadt 194:
1.38 canacar 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++;
1.35 deraadt 201:
1.38 canacar 202: return (nusers);
1.1 deraadt 203: }
204:
1.38 canacar 205: /* main program functions */
206:
1.1 deraadt 207: void
1.38 canacar 208: usage()
1.1 deraadt 209: {
1.38 canacar 210: extern char *__progname;
1.44 jmc 211: fprintf(stderr, "usage: %s [-abin] [-d count] "
1.43 matthieu 212: "[-s delay] [-w width] [view] [delay]\n", __progname);
1.38 canacar 213: exit(1);
1.1 deraadt 214: }
215:
1.45 canacar 216: void
217: show_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: }
1.21 deraadt 227:
1.1 deraadt 228: void
1.38 canacar 229: add_view_tb(field_view *v)
1.1 deraadt 230: {
1.38 canacar 231: if (curr_view == v)
232: tbprintf("[%s] ", v->name);
233: else
234: tbprintf("%s ", v->name);
1.29 deraadt 235: }
236:
237: void
1.38 canacar 238: show_help(void)
1.29 deraadt 239: {
1.38 canacar 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: #if 0
251: erase();
252: mvprintw(line, 2, "Systat Help");
253: line += 2;
254: mvprintw(line, 5, " h - Help (this page)");
255: mvprintw(line++, 40, " l - set number of Lines");
256: mvprintw(line, 5, " p - Pause display");
257: mvprintw(line++, 40, " s - Set update interval");
258: mvprintw(line, 5, " v - next View");
259: mvprintw(line++, 40, " q - Quit");
260: line++;
261: mvprintw(line++, 5, "0-7 - select view directly");
262: mvprintw(line++, 5, "SPC - update immediately");
263: mvprintw(line++, 5, "^L - refresh display");
264: line++;
265: mvprintw(line++, 5, "cursor keys - scroll display");
266: line++;
267: mvprintw(line++, 3, "Netstat specific keys::");
268: mvprintw(line, 5, " t - toggle TCP display");
269: mvprintw(line++, 40, " u - toggle UDP display");
270: mvprintw(line++, 5, " n - toggle Name resolution");
271: line++;
272: mvprintw(line++, 3, "Ifstat specific keys::");
273: mvprintw(line, 5, " r - initialize RUN mode");
274: mvprintw(line++, 40, " b - set BOOT mode");
275: mvprintw(line, 5, " t - set TIME mode (default)");
276: line++;
277: line++;
278: mvprintw(line++, 3, "VMstat specific keys::");
279: mvprintw(line, 5, " r - initialize RUN mode");
280: mvprintw(line++, 40, " b - set BOOT mode");
281: mvprintw(line, 5, " t - set TIME mode (default)");
282: mvprintw(line++, 40, " z - zero in RUN mode");
283: line++;
284: mvprintw(line++, 6, "press any key to continue ...");
285:
286: while (getch() == ERR) {
287: if (gotsig_close)
288: break;
289: }
290: #endif
1.21 deraadt 291: }
292:
293: void
1.46 ! canacar 294: cmd_compat(const char *buf)
1.21 deraadt 295: {
1.46 ! canacar 296: const char *s;
1.38 canacar 297:
1.46 ! canacar 298: if (strcasecmp(buf, "help") == 0) {
1.38 canacar 299: show_help();
300: need_update = 1;
301: return;
302: }
1.46 ! canacar 303: if (strcasecmp(buf, "quit") == 0 || strcasecmp(buf, "q") == 0) {
1.38 canacar 304: gotsig_close = 1;
305: return;
306: }
1.46 ! canacar 307: if (strcasecmp(buf, "stop") == 0) {
! 308: paused = 1;
! 309: gotsig_alarm = 1;
! 310: return;
! 311: }
! 312: if (strncasecmp(buf, "start", 5) == 0) {
! 313: paused = 0;
! 314: gotsig_alarm = 1;
! 315: cmd_delay(buf + 6);
! 316: return;
! 317: }
1.38 canacar 318:
1.46 ! canacar 319: for (s = buf; *s && strchr("0123456789+-.eE", *s) != NULL; s++)
1.38 canacar 320: ;
321: if (*s) {
1.46 ! canacar 322: if (set_view(buf))
! 323: error("Invalid/ambigious view: %s", buf);
1.38 canacar 324: } else
1.46 ! canacar 325: cmd_delay(buf);
1.38 canacar 326: }
327:
328: void
1.46 ! canacar 329: cmd_delay(const char *buf)
1.38 canacar 330: {
331: double del;
1.46 ! canacar 332: del = atof(buf);
1.39 canacar 333:
1.38 canacar 334: if (del > 0) {
335: udelay = (useconds_t)(del * 1000000);
336: gotsig_alarm = 1;
1.39 canacar 337: naptime = del;
1.13 deraadt 338: }
1.1 deraadt 339: }
1.14 kstailey 340:
341: void
1.46 ! canacar 342: cmd_count(const char *buf)
1.14 kstailey 343: {
1.38 canacar 344: int ms;
1.46 ! canacar 345: ms = atoi(buf);
1.38 canacar 346:
347: if (ms <= 0 || ms > lines - HEADER_LINES)
348: maxprint = lines - HEADER_LINES;
349: else
350: maxprint = ms;
1.14 kstailey 351: }
352:
1.38 canacar 353:
354: int
355: keyboard_callback(int ch)
1.1 deraadt 356: {
1.38 canacar 357: switch (ch) {
358: case '?':
359: /* FALLTHROUGH */
360: case 'h':
361: show_help();
1.45 canacar 362: need_update = 1;
363: break;
364: case CTRL_G:
365: show_view();
1.38 canacar 366: need_update = 1;
367: break;
368: case 'l':
369: command_set(&cm_count, NULL);
370: break;
371: case 's':
372: command_set(&cm_delay, NULL);
373: break;
374: case ':':
375: command_set(&cm_compat, NULL);
376: break;
377: default:
378: return 0;
379: };
380:
381: return 1;
382: }
1.23 millert 383:
1.38 canacar 384: void
385: initialize(void)
386: {
387: engine_initialize();
388:
389: initvmstat();
390: initpigs();
391: initifstat();
392: initiostat();
393: initsensors();
394: initmembufs();
395: initnetstat();
396: initswap();
397: initpftop();
398: initpf();
1.1 deraadt 399: }
400:
401: void
1.38 canacar 402: gethz(void)
1.1 deraadt 403: {
1.38 canacar 404: struct clockinfo cinf;
405: size_t size = sizeof(cinf);
406: int mib[2];
1.1 deraadt 407:
1.38 canacar 408: mib[0] = CTL_KERN;
409: mib[1] = KERN_CLOCKRATE;
410: if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1)
411: return;
412: stathz = cinf.stathz;
413: hz = cinf.hz;
1.35 deraadt 414: }
415:
416: int
1.38 canacar 417: main(int argc, char *argv[])
1.35 deraadt 418: {
1.38 canacar 419: char errbuf[_POSIX2_LINE_MAX];
420: extern char *optarg;
421: extern int optind;
422: double delay = 5;
423:
424: char *viewstr = NULL;
425:
426: gid_t gid;
427: int countmax = 0;
428: int maxlines = 0;
429:
430: int ch;
431:
432: ut = open(_PATH_UTMP, O_RDONLY);
433: if (ut < 0) {
434: warn("No utmp");
435: }
436:
437: kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
438:
439: gid = getgid();
440: if (setresgid(gid, gid, gid) == -1)
441: err(1, "setresgid");
442:
1.43 matthieu 443: while ((ch = getopt(argc, argv, "abd:ins:S:w:")) != -1) {
1.38 canacar 444: switch (ch) {
445: case 'a':
446: maxlines = -1;
447: break;
448: case 'b':
449: rawmode = 1;
450: interactive = 0;
451: break;
452: case 'd':
453: countmax = atoi(optarg);
454: if (countmax < 0)
455: countmax = 0;
456: break;
457: case 'i':
458: interactive = 1;
459: break;
460: case 'n':
461: nflag = 1;
462: break;
463: case 's':
464: delay = atof(optarg);
1.39 canacar 465: if (delay <= 0)
1.38 canacar 466: delay = 5;
467: break;
468: case 'S':
469: dispstart = atoi(optarg);
470: if (dispstart < 0)
471: dispstart = 0;
472: break;
473: case 'w':
474: rawwidth = atoi(optarg);
475: if (rawwidth < 1)
476: rawwidth = DEFAULT_WIDTH;
477: if (rawwidth >= MAX_LINE_BUF)
478: rawwidth = MAX_LINE_BUF - 1;
479: break;
480: default:
481: usage();
482: /* NOTREACHED */
483: }
484: }
1.43 matthieu 485:
486: if (kd == NULL)
487: warnx("kvm_openfiles: %s", errbuf);
1.38 canacar 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]);
1.42 canacar 501: if (delay <= 0)
502: delay = 5;
1.38 canacar 503: }
504:
505: udelay = (useconds_t)(delay * 1000000.0);
506: if (udelay < 1)
507: udelay = 1;
1.39 canacar 508:
509: naptime = (double)udelay / 1000000.0;
1.38 canacar 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/ambigious view name: %s\n", viewstr);
519: return 1;
520: }
521:
522: if (!isatty(STDOUT_FILENO)) {
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;
1.35 deraadt 533:
1.38 canacar 534: engine_loop(countmax);
1.35 deraadt 535:
1.38 canacar 536: return 0;
1.1 deraadt 537: }