[BACK]Return to main.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / systat

Annotation of src/usr.bin/systat/main.c, Revision 1.75

1.75    ! millert     1: /* $OpenBSD: main.c,v 1.74 2021/06/02 08:32:22 martijn 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>
1.73      martijn    43: #include <math.h>
1.38      canacar    44: #include <netdb.h>
1.1       deraadt    45: #include <signal.h>
                     46: #include <stdio.h>
1.73      martijn    47: #include <stdint.h>
1.38      canacar    48: #include <stdlib.h>
1.1       deraadt    49: #include <string.h>
1.38      canacar    50: #include <stdarg.h>
1.3       deraadt    51: #include <unistd.h>
1.35      deraadt    52: #include <utmp.h>
1.1       deraadt    53:
1.38      canacar    54: #include "engine.h"
1.1       deraadt    55: #include "systat.h"
                     56:
1.66      otto       57: #define TIMEPOS (80 - 8 - 20 - 1)
1.58      lum        58:
1.21      deraadt    59: double dellave;
1.1       deraadt    60:
1.21      deraadt    61: kvm_t  *kd;
                     62: char   *nlistf = NULL;
1.20      pvalchev   63: char   *memf = NULL;
1.21      deraadt    64: double avenrun[3];
1.36      tedu       65: double naptime = 5.0;
1.21      deraadt    66: int    verbose = 1;            /* to report kvm read errs */
1.38      canacar    67: int    nflag = 1;
1.35      deraadt    68: int    ut, hz, stathz;
1.61      deraadt    69: char    hostname[HOST_NAME_MAX+1];
1.1       deraadt    70: WINDOW  *wnd;
1.32      deraadt    71: int    CMDLINE;
1.58      lum        72: char   timebuf[26];
                     73: char   uloadbuf[TIMEPOS];
1.1       deraadt    74:
1.38      canacar    75:
1.50      canacar    76: int  ucount(void);
                     77: void usage(void);
1.73      martijn    78: double strtodnum(const char *, double, double, const char **);
1.50      canacar    79:
1.38      canacar    80: /* command prompt */
                     81:
1.46      canacar    82: void cmd_delay(const char *);
                     83: void cmd_count(const char *);
                     84: void cmd_compat(const char *);
1.38      canacar    85:
                     86: struct command cm_compat = {"Command", cmd_compat};
                     87: struct command cm_delay = {"Seconds to delay", cmd_delay};
                     88: struct command cm_count = {"Number of lines to display", cmd_count};
1.1       deraadt    89:
1.38      canacar    90:
                     91: /* display functions */
1.3       deraadt    92:
1.2       deraadt    93: int
1.38      canacar    94: print_header(void)
1.1       deraadt    95: {
1.50      canacar    96:        time_t now;
1.40      deraadt    97:        int start = dispstart + 1, end = dispstart + maxprint;
1.58      lum        98:        char tmpbuf[TIMEPOS];
                     99:        char header[MAX_LINE_BUF];
1.38      canacar   100:
                    101:        if (end > num_disp)
                    102:                end = num_disp;
                    103:
                    104:        tb_start();
1.35      deraadt   105:
1.58      lum       106:        if (!paused) {
1.65      tedu      107:                char *ctim;
                    108:
1.58      lum       109:                getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0]));
1.38      canacar   110:
1.58      lum       111:                snprintf(uloadbuf, sizeof(uloadbuf),
1.66      otto      112:                    "%4d users Load %.2f %.2f %.2f",
1.58      lum       113:                    ucount(), avenrun[0], avenrun[1], avenrun[2]);
1.25      deraadt   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.66      otto      130:        snprintf(header, sizeof(header), "%-*s %19.19s %s", TIMEPOS - 1,
                    131:            tmpbuf, hostname, timebuf);
1.58      lum       132:
                    133:        if (rawmode)
                    134:                printf("\n\n%s\n", header);
                    135:        else
                    136:                mvprintw(0, 0, "%s", header);
1.24      deraadt   137:
1.38      canacar   138:        return (1);
1.1       deraadt   139: }
1.3       deraadt   140:
1.38      canacar   141: /* compatibility functions, rearrange later */
1.21      deraadt   142: void
1.38      canacar   143: error(const char *fmt, ...)
1.21      deraadt   144: {
1.38      canacar   145:        va_list ap;
                    146:        char buf[MAX_LINE_BUF];
                    147:
                    148:        va_start(ap, fmt);
                    149:        vsnprintf(buf, sizeof buf, fmt, ap);
                    150:        va_end(ap);
1.21      deraadt   151:
1.38      canacar   152:        message_set(buf);
1.21      deraadt   153: }
                    154:
1.38      canacar   155: void
                    156: nlisterr(struct nlist namelist[])
1.3       deraadt   157: {
1.38      canacar   158:        int i, n;
                    159:
                    160:        n = 0;
                    161:        clear();
                    162:        mvprintw(2, 10, "systat: nlist: can't find following symbols:");
                    163:        for (i = 0;
                    164:            namelist[i].n_name != NULL && *namelist[i].n_name != '\0'; i++)
                    165:                if (namelist[i].n_value == 0)
                    166:                        mvprintw(2 + ++n, 10, "%s", namelist[i].n_name);
                    167:        move(CMDLINE, 0);
                    168:        clrtoeol();
                    169:        refresh();
                    170:        endwin();
1.3       deraadt   171:        exit(1);
                    172: }
                    173:
1.1       deraadt   174: void
1.38      canacar   175: die(void)
1.1       deraadt   176: {
1.38      canacar   177:        if (!rawmode)
                    178:                endwin();
                    179:        exit(0);
1.1       deraadt   180: }
                    181:
1.38      canacar   182:
                    183: int
                    184: prefix(char *s1, char *s2)
1.1       deraadt   185: {
1.38      canacar   186:
                    187:        while (*s1 == *s2) {
                    188:                if (*s1 == '\0')
                    189:                        return (1);
                    190:                s1++, s2++;
                    191:        }
                    192:        return (*s1 == '\0');
1.21      deraadt   193: }
                    194:
1.38      canacar   195: /* calculate number of users on the system */
                    196: int
                    197: ucount(void)
1.21      deraadt   198: {
1.38      canacar   199:        int nusers = 0;
                    200:        struct  utmp utmp;
1.35      deraadt   201:
1.38      canacar   202:        if (ut < 0)
                    203:                return (0);
                    204:        lseek(ut, (off_t)0, SEEK_SET);
                    205:        while (read(ut, &utmp, sizeof(utmp)))
                    206:                if (utmp.ut_name[0] != '\0')
                    207:                        nusers++;
1.35      deraadt   208:
1.38      canacar   209:        return (nusers);
1.1       deraadt   210: }
                    211:
1.38      canacar   212: /* main program functions */
                    213:
1.1       deraadt   214: void
1.50      canacar   215: usage(void)
1.1       deraadt   216: {
1.38      canacar   217:        extern char *__progname;
1.72      martijn   218:        fprintf(stderr, "usage: %s [-aBbhiNn] [-d count] "
1.43      matthieu  219:            "[-s delay] [-w width] [view] [delay]\n", __progname);
1.38      canacar   220:        exit(1);
1.1       deraadt   221: }
                    222:
1.45      canacar   223: void
                    224: show_view(void)
                    225: {
                    226:        if (rawmode)
                    227:                return;
                    228:
                    229:        tb_start();
                    230:        tbprintf("%s %g", curr_view->name, naptime);
                    231:        tb_end();
                    232:        message_set(tmp_buf);
                    233: }
1.21      deraadt   234:
1.1       deraadt   235: void
1.38      canacar   236: add_view_tb(field_view *v)
1.1       deraadt   237: {
1.38      canacar   238:        if (curr_view == v)
                    239:                tbprintf("[%s] ", v->name);
                    240:        else
                    241:                tbprintf("%s ", v->name);
1.29      deraadt   242: }
                    243:
                    244: void
1.38      canacar   245: show_help(void)
1.29      deraadt   246: {
1.38      canacar   247:        if (rawmode)
                    248:                return;
                    249:
                    250:        tb_start();
                    251:        foreach_view(add_view_tb);
                    252:        tb_end();
                    253:        message_set(tmp_buf);
1.21      deraadt   254: }
                    255:
                    256: void
1.67      martijn   257: add_order_tb(order_type *o)
                    258: {
                    259:        if (curr_view->mgr->order_curr == o)
                    260:                tbprintf("[%s%s(%c)] ", o->name,
                    261:                    o->func != NULL && sortdir == -1 ? "^" : "",
                    262:                    (char) o->hotkey);
                    263:        else
                    264:                tbprintf("%s(%c) ", o->name, (char) o->hotkey);
                    265: }
                    266:
                    267: void
                    268: show_order(void)
                    269: {
                    270:        if (rawmode)
                    271:                return;
                    272:
                    273:        tb_start();
                    274:        if (foreach_order(add_order_tb) == -1) {
                    275:                tbprintf("No orders available");
                    276:        }
                    277:        tb_end();
                    278:        message_set(tmp_buf);
                    279: }
                    280:
                    281: void
1.46      canacar   282: cmd_compat(const char *buf)
1.21      deraadt   283: {
1.46      canacar   284:        const char *s;
1.38      canacar   285:
1.46      canacar   286:        if (strcasecmp(buf, "help") == 0) {
1.74      martijn   287:                message_toggle(MESSAGE_HELP);
1.38      canacar   288:                return;
                    289:        }
1.46      canacar   290:        if (strcasecmp(buf, "quit") == 0 || strcasecmp(buf, "q") == 0) {
1.38      canacar   291:                gotsig_close = 1;
                    292:                return;
                    293:        }
1.46      canacar   294:        if (strcasecmp(buf, "stop") == 0) {
                    295:                paused = 1;
                    296:                gotsig_alarm = 1;
                    297:                return;
                    298:        }
                    299:        if (strncasecmp(buf, "start", 5) == 0) {
                    300:                paused = 0;
                    301:                gotsig_alarm = 1;
1.47      canacar   302:                cmd_delay(buf + 5);
1.67      martijn   303:                return;
                    304:        }
                    305:        if (strncasecmp(buf, "order", 5) == 0) {
1.74      martijn   306:                message_toggle(MESSAGE_ORDER);
1.46      canacar   307:                return;
                    308:        }
1.72      martijn   309:        if (strncasecmp(buf, "human", 5) == 0) {
                    310:                humanreadable = !humanreadable;
                    311:                return;
                    312:        }
1.38      canacar   313:
1.46      canacar   314:        for (s = buf; *s && strchr("0123456789+-.eE", *s) != NULL; s++)
1.38      canacar   315:                ;
                    316:        if (*s) {
1.46      canacar   317:                if (set_view(buf))
1.49      espie     318:                        error("Invalid/ambiguous view: %s", buf);
1.38      canacar   319:        } else
1.46      canacar   320:                cmd_delay(buf);
1.38      canacar   321: }
                    322:
                    323: void
1.46      canacar   324: cmd_delay(const char *buf)
1.38      canacar   325: {
                    326:        double del;
1.73      martijn   327:        const char *errstr;
1.39      canacar   328:
1.73      martijn   329:        if (buf[0] == '\0')
                    330:                return;
                    331:        del = strtodnum(buf, 0, UINT32_MAX / 1000000, &errstr);
                    332:        if (errstr != NULL)
                    333:                error("s: \"%s\": delay value is %s", buf, errstr);
                    334:        else {
1.75    ! millert   335:                refresh_delay(del);
1.38      canacar   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.63      deraadt   344:        const char *errstr;
1.38      canacar   345:
1.63      deraadt   346:        maxprint = strtonum(buf, 1, lines - HEADER_LINES, &errstr);
                    347:        if (errstr)
1.38      canacar   348:                maxprint = lines - HEADER_LINES;
1.14      kstailey  349: }
                    350:
1.38      canacar   351:
                    352: int
                    353: keyboard_callback(int ch)
1.1       deraadt   354: {
1.38      canacar   355:        switch (ch) {
                    356:        case '?':
                    357:                /* FALLTHROUGH */
                    358:        case 'h':
1.74      martijn   359:                message_toggle(MESSAGE_HELP);
1.45      canacar   360:                break;
                    361:        case CTRL_G:
1.74      martijn   362:                message_toggle(MESSAGE_VIEW);
1.38      canacar   363:                break;
                    364:        case 'l':
                    365:                command_set(&cm_count, NULL);
                    366:                break;
                    367:        case 's':
                    368:                command_set(&cm_delay, NULL);
1.59      mpf       369:                break;
                    370:        case ',':
                    371:                separate_thousands = !separate_thousands;
                    372:                gotsig_alarm = 1;
1.38      canacar   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.48      canacar   399:        initpool();
1.51      canacar   400:        initmalloc();
1.52      jasper    401:        initnfs();
1.60      reyk      402:        initcpu();
1.68      krw       403:        inituvm();
1.1       deraadt   404: }
                    405:
                    406: void
1.38      canacar   407: gethz(void)
1.1       deraadt   408: {
1.38      canacar   409:        struct clockinfo cinf;
                    410:        size_t  size = sizeof(cinf);
                    411:        int     mib[2];
1.1       deraadt   412:
1.38      canacar   413:        mib[0] = CTL_KERN;
                    414:        mib[1] = KERN_CLOCKRATE;
                    415:        if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1)
                    416:                return;
                    417:        stathz = cinf.stathz;
                    418:        hz = cinf.hz;
1.35      deraadt   419: }
                    420:
1.73      martijn   421: #define        INVALID         1
                    422: #define        TOOSMALL        2
                    423: #define        TOOLARGE        3
                    424:
                    425: double
                    426: strtodnum(const char *nptr, double minval, double maxval, const char **errstrp)
                    427: {
                    428:        double d = 0;
                    429:        int error = 0;
                    430:        char *ep;
                    431:        struct errval {
                    432:                const char *errstr;
                    433:                int err;
                    434:        } ev[4] = {
                    435:                { NULL,         0 },
                    436:                { "invalid",    EINVAL },
                    437:                { "too small",  ERANGE },
                    438:                { "too large",  ERANGE },
                    439:        };
                    440:
                    441:        ev[0].err = errno;
                    442:        errno = 0;
                    443:        if (minval > maxval) {
                    444:                error = INVALID;
                    445:        } else {
                    446:                d = strtod(nptr, &ep);
                    447:                if (nptr == ep || *ep != '\0')
                    448:                        error = INVALID;
                    449:                else if ((d == -HUGE_VAL && errno == ERANGE) || d < minval)
                    450:                        error = TOOSMALL;
                    451:                else if ((d == HUGE_VAL && errno == ERANGE) || d > maxval)
                    452:                        error = TOOLARGE;
                    453:        }
                    454:        if (errstrp != NULL)
                    455:                *errstrp = ev[error].errstr;
                    456:        errno = ev[error].err;
                    457:        if (error)
                    458:                d = 0;
                    459:
                    460:        return (d);
                    461: }
                    462:
1.35      deraadt   463: int
1.38      canacar   464: main(int argc, char *argv[])
1.35      deraadt   465: {
1.38      canacar   466:        char errbuf[_POSIX2_LINE_MAX];
1.63      deraadt   467:        const char *errstr;
1.38      canacar   468:        extern char *optarg;
                    469:        extern int optind;
1.73      martijn   470:        double delay = 5, del;
1.38      canacar   471:
                    472:        char *viewstr = NULL;
                    473:
                    474:        gid_t gid;
                    475:        int countmax = 0;
                    476:        int maxlines = 0;
                    477:
                    478:        int ch;
                    479:
                    480:        ut = open(_PATH_UTMP, O_RDONLY);
1.70      deraadt   481:        if (ut == -1) {
1.38      canacar   482:                warn("No utmp");
                    483:        }
                    484:
1.62      claudio   485:        kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
1.38      canacar   486:
                    487:        gid = getgid();
                    488:        if (setresgid(gid, gid, gid) == -1)
                    489:                err(1, "setresgid");
                    490:
1.72      martijn   491:        while ((ch = getopt(argc, argv, "BNabd:hins:w:")) != -1) {
1.38      canacar   492:                switch (ch) {
                    493:                case 'a':
                    494:                        maxlines = -1;
                    495:                        break;
1.60      reyk      496:                case 'B':
                    497:                        averageonly = 1;
                    498:                        if (countmax < 2)
                    499:                                countmax = 2;
                    500:                        /* FALLTHROUGH */
1.38      canacar   501:                case 'b':
                    502:                        rawmode = 1;
                    503:                        interactive = 0;
                    504:                        break;
                    505:                case 'd':
1.63      deraadt   506:                        countmax = strtonum(optarg, 1, INT_MAX, &errstr);
                    507:                        if (errstr)
                    508:                                errx(1, "-d %s: %s", optarg, errstr);
1.72      martijn   509:                        break;
                    510:                case 'h':
                    511:                        humanreadable = 1;
1.38      canacar   512:                        break;
                    513:                case 'i':
                    514:                        interactive = 1;
                    515:                        break;
1.55      sthen     516:                case 'N':
                    517:                        nflag = 0;
                    518:                        break;
1.38      canacar   519:                case 'n':
1.55      sthen     520:                        /* this is a noop, -n is the default */
1.38      canacar   521:                        nflag = 1;
                    522:                        break;
                    523:                case 's':
1.73      martijn   524:                        delay = strtodnum(optarg, 0, UINT32_MAX / 1000000,
                    525:                            &errstr);
                    526:                        if (errstr != NULL)
                    527:                                errx(1, "-s \"%s\": delay value is %s", optarg,
                    528:                                    errstr);
1.38      canacar   529:                        break;
                    530:                case 'w':
1.63      deraadt   531:                        rawwidth = strtonum(optarg, 1, MAX_LINE_BUF-1, &errstr);
                    532:                        if (errstr)
                    533:                                errx(1, "-w %s: %s", optarg, errstr);
1.38      canacar   534:                        break;
                    535:                default:
                    536:                        usage();
                    537:                        /* NOTREACHED */
                    538:                }
                    539:        }
1.43      matthieu  540:
                    541:        if (kd == NULL)
                    542:                warnx("kvm_openfiles: %s", errbuf);
1.38      canacar   543:
                    544:        argc -= optind;
                    545:        argv += optind;
                    546:
                    547:        if (argc == 1) {
1.73      martijn   548:                del = strtodnum(argv[0], 0, UINT32_MAX / 1000000, &errstr);
                    549:                if (errstr != NULL)
1.38      canacar   550:                        viewstr = argv[0];
                    551:                else
                    552:                        delay = del;
                    553:        } else if (argc == 2) {
                    554:                viewstr = argv[0];
1.73      martijn   555:                delay = strtodnum(argv[1], 0, UINT32_MAX / 1000000, &errstr);
                    556:                if (errstr != NULL)
                    557:                        errx(1, "\"%s\": delay value is %s", argv[1], errstr);
1.38      canacar   558:        }
                    559:
1.75    ! millert   560:        refresh_delay(delay);
        !           561:        naptime = delay;
1.38      canacar   562:
                    563:        gethostname(hostname, sizeof (hostname));
                    564:        gethz();
                    565:
                    566:        initialize();
                    567:
                    568:        set_order(NULL);
                    569:        if (viewstr && set_view(viewstr)) {
1.49      espie     570:                fprintf(stderr, "Unknown/ambiguous view name: %s\n", viewstr);
1.38      canacar   571:                return 1;
                    572:        }
                    573:
1.57      lum       574:        if (check_termcap()) {
1.38      canacar   575:                rawmode = 1;
                    576:                interactive = 0;
                    577:        }
                    578:
                    579:        setup_term(maxlines);
1.71      deraadt   580:
                    581:        if (unveil("/", "r") == -1)
                    582:                err(1, "unveil");
                    583:        if (unveil(NULL, NULL) == -1)
                    584:                err(1, "unveil");
1.38      canacar   585:
                    586:        if (rawmode && countmax == 0)
                    587:                countmax = 1;
                    588:
                    589:        gotsig_alarm = 1;
1.35      deraadt   590:
1.38      canacar   591:        engine_loop(countmax);
1.35      deraadt   592:
1.38      canacar   593:        return 0;
1.1       deraadt   594: }