[BACK]Return to vmstat.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / usr.bin / systat

Annotation of src/usr.bin/systat/vmstat.c, Revision 1.82.6.1

1.82.6.1! christos    1: /*     $NetBSD: vmstat.c,v 1.86 2019/01/25 15:34:22 christos Exp $     */
1.2       jtc         2:
1.1       jtc         3: /*-
                      4:  * Copyright (c) 1983, 1989, 1992, 1993
                      5:  *     The Regents of the University of California.  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:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
1.53      agc        15:  * 3. Neither the name of the University nor the names of its contributors
1.1       jtc        16:  *    may be used to endorse or promote products derived from this software
                     17:  *    without specific prior written permission.
                     18:  *
                     19:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     20:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     21:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     22:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     23:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     24:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     25:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     26:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     27:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     28:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     29:  * SUCH DAMAGE.
                     30:  */
                     31:
1.8       mrg        32: #include <sys/cdefs.h>
1.1       jtc        33: #ifndef lint
1.2       jtc        34: #if 0
1.1       jtc        35: static char sccsid[] = "@(#)vmstat.c   8.2 (Berkeley) 1/12/94";
1.2       jtc        36: #endif
1.82.6.1! christos   37: __RCSID("$NetBSD: vmstat.c,v 1.86 2019/01/25 15:34:22 christos Exp $");
1.1       jtc        38: #endif /* not lint */
                     39:
                     40: /*
                     41:  * Cursed vmstat -- from Robert Elz.
                     42:  */
                     43:
                     44: #include <sys/param.h>
1.67      christos   45: #include <sys/uio.h>
1.1       jtc        46: #include <sys/namei.h>
                     47: #include <sys/sysctl.h>
1.70      dyoung     48: #include <sys/evcnt.h>
1.1       jtc        49:
1.11      mrg        50: #include <uvm/uvm_extern.h>
                     51:
1.66      yamt       52: #include <errno.h>
1.3       mycroft    53: #include <stdlib.h>
1.1       jtc        54: #include <string.h>
1.41      abs        55: #include <util.h>
1.3       mycroft    56:
1.1       jtc        57: #include "systat.h"
                     58: #include "extern.h"
1.65      blymn      59: #include "drvstats.h"
1.40      christos   60: #include "utmpentry.h"
1.63      dsl        61: #include "vmstat.h"
1.1       jtc        62:
                     63: static struct Info {
1.34      simonb     64:        struct  uvmexp_sysctl uvmexp;
1.1       jtc        65:        struct  vmtotal Total;
1.81      dennis     66:        struct  nchstats nchstats;
1.1       jtc        67:        long    nchcount;
                     68:        long    *intrcnt;
1.44      dsl        69:        u_int64_t       *evcnt;
1.1       jtc        70: } s, s1, s2, z;
                     71:
1.63      dsl        72: enum display_mode display_mode = TIME;
1.1       jtc        73:
1.33      ad         74: static void allocinfo(struct Info *);
                     75: static void copyinfo(struct Info *, struct Info *);
                     76: static float cputime(int);
1.49      dsl        77: static void dinfo(int, int, int);
1.63      dsl        78: static void getinfo(struct Info *);
1.33      ad         79: static int ucount(void);
1.1       jtc        80:
                     81: static char buf[26];
1.59      dsl        82: static u_int64_t temp;
1.1       jtc        83: static int nintr;
                     84: static long *intrloc;
                     85: static char **intrname;
                     86: static int nextintsrow;
1.49      dsl        87: static int disk_horiz = 1;
1.82.6.1! christos   88: static u_int nbuf;
1.1       jtc        89:
                     90: WINDOW *
1.33      ad         91: openvmstat(void)
1.1       jtc        92: {
                     93:        return (stdscr);
                     94: }
                     95:
                     96: void
1.33      ad         97: closevmstat(WINDOW *w)
1.1       jtc        98: {
                     99:
                    100:        if (w == NULL)
                    101:                return;
                    102:        wclear(w);
                    103:        wrefresh(w);
                    104: }
                    105:
                    106:
                    107: static struct nlist namelist[] = {
1.79      joerg     108: #define        X_INTRNAMES     0
1.69      christos  109:        { .n_name = "_intrnames" },
1.79      joerg     110: #define        X_EINTRNAMES    1
1.69      christos  111:        { .n_name = "_eintrnames" },
1.79      joerg     112: #define        X_INTRCNT       2
1.69      christos  113:        { .n_name = "_intrcnt" },
1.79      joerg     114: #define        X_EINTRCNT      3
1.69      christos  115:        { .n_name = "_eintrcnt" },
1.79      joerg     116: #define        X_ALLEVENTS     4
1.69      christos  117:        { .n_name = "_allevents" },
                    118:        { .n_name = NULL }
1.1       jtc       119: };
                    120:
                    121: /*
                    122:  * These constants define where the major pieces are laid out
                    123:  */
                    124: #define STATROW                 0      /* uses 1 row and 68 cols */
                    125: #define STATCOL                 2
1.82.6.1! christos  126: #define MEMROW          9      /* uses 5 rows and 31 cols */
1.1       jtc       127: #define MEMCOL          0
                    128: #define PAGEROW                 2      /* uses 4 rows and 26 cols */
1.48      dsl       129: #define PAGECOL                54
                    130: #define INTSROW                 9      /* uses all rows to bottom and 17 cols */
                    131: #define INTSCOL                40
                    132: #define INTSCOLEND     (VMSTATCOL - 0)
                    133: #define PROCSROW        2      /* uses 2 rows and 20 cols */
1.1       jtc       134: #define PROCSCOL        0
1.48      dsl       135: #define GENSTATROW      2      /* uses 2 rows and 30 cols */
1.58      christos  136: #define GENSTATCOL     17
1.48      dsl       137: #define VMSTATROW       7      /* uses 17 rows and 15 cols */
                    138: #define VMSTATCOL      64
                    139: #define GRAPHROW        5      /* uses 3 rows and 51 cols */
1.1       jtc       140: #define GRAPHCOL        0
1.82.6.1! christos  141: #define NAMEIROW       15      /* uses 3 rows and 38 cols (must be MEMROW + 5 + 1) */
1.1       jtc       142: #define NAMEICOL        0
1.82.6.1! christos  143: #define DISKROW                19      /* uses 5 rows and 50 cols (for 9 drives) */
1.1       jtc       144: #define DISKCOL                 0
1.82.6.1! christos  145: #define DISKCOLWIDTH    8
1.49      dsl       146: #define DISKCOLEND     INTSCOL
1.1       jtc       147:
1.44      dsl       148: typedef struct intr_evcnt intr_evcnt_t;
                    149: struct intr_evcnt {
                    150:        char            *ie_group;
                    151:        char            *ie_name;
                    152:        u_int64_t       *ie_count;      /* kernel address... */
                    153:        int             ie_loc;         /* screen row */
                    154: } *ie_head;
                    155: int nevcnt;
                    156:
                    157: static void
                    158: get_interrupt_events(void)
                    159: {
                    160:        struct evcntlist allevents;
                    161:        struct evcnt evcnt, *evptr;
                    162:        intr_evcnt_t *ie;
1.55      itojun    163:        intr_evcnt_t *n;
1.44      dsl       164:
                    165:        if (!NREAD(X_ALLEVENTS, &allevents, sizeof allevents))
                    166:                return;
1.60      chs       167:        evptr = TAILQ_FIRST(&allevents);
                    168:        for (; evptr != NULL; evptr = TAILQ_NEXT(&evcnt, ev_list)) {
1.44      dsl       169:                if (!KREAD(evptr, &evcnt, sizeof evcnt))
                    170:                        return;
                    171:                if (evcnt.ev_type != EVCNT_TYPE_INTR)
                    172:                        continue;
1.55      itojun    173:                n = realloc(ie_head, sizeof *ie * (nevcnt + 1));
                    174:                if (n == NULL) {
1.44      dsl       175:                        error("realloc failed");
                    176:                        die(0);
                    177:                }
1.55      itojun    178:                ie_head = n;
1.44      dsl       179:                ie = ie_head + nevcnt;
                    180:                ie->ie_group = malloc(evcnt.ev_grouplen + 1);
                    181:                ie->ie_name = malloc(evcnt.ev_namelen + 1);
                    182:                if (ie->ie_group == NULL || ie->ie_name == NULL)
                    183:                        return;
1.46      dsl       184:                if (!KREAD(evcnt.ev_group, ie->ie_group, evcnt.ev_grouplen + 1))
1.44      dsl       185:                        return;
1.46      dsl       186:                if (!KREAD(evcnt.ev_name, ie->ie_name, evcnt.ev_namelen + 1))
1.44      dsl       187:                        return;
                    188:                ie->ie_count = &evptr->ev_count;
                    189:                ie->ie_loc = 0;
                    190:                nevcnt++;
                    191:        }
                    192: }
                    193:
1.1       jtc       194: int
1.33      ad        195: initvmstat(void)
1.1       jtc       196: {
1.64      dsl       197:        static char *intrnamebuf;
                    198:        char *cp;
1.1       jtc       199:        int i;
                    200:
1.64      dsl       201:        if (intrnamebuf)
                    202:                free(intrnamebuf);
                    203:        if (intrname)
                    204:                free(intrname);
                    205:        if (intrloc)
                    206:                free(intrloc);
                    207:
1.1       jtc       208:        if (namelist[0].n_type == 0) {
1.60      chs       209:                if (kvm_nlist(kd, namelist) &&
1.79      joerg     210:                    namelist[X_ALLEVENTS].n_type == 0) {
1.1       jtc       211:                        nlisterr(namelist);
                    212:                        return(0);
                    213:                }
                    214:        }
                    215:        hertz = stathz ? stathz : hz;
1.65      blymn     216:        if (!drvinit(1))
1.61      blymn     217:                return(0);
1.44      dsl       218:
                    219:        /* Old style interrupt counts - deprecated */
                    220:        nintr = (namelist[X_EINTRCNT].n_value -
                    221:                namelist[X_INTRCNT].n_value) / sizeof (long);
1.60      chs       222:        if (nintr) {
                    223:                intrloc = calloc(nintr, sizeof (long));
                    224:                intrname = calloc(nintr, sizeof (long));
                    225:                intrnamebuf = malloc(namelist[X_EINTRNAMES].n_value -
                    226:                                     namelist[X_INTRNAMES].n_value);
                    227:                if (intrnamebuf == NULL || intrname == 0 || intrloc == 0) {
                    228:                        error("Out of memory\n");
                    229:                        nintr = 0;
                    230:                        return(0);
                    231:                }
                    232:                NREAD(X_INTRNAMES, intrnamebuf, NVAL(X_EINTRNAMES) -
                    233:                      NVAL(X_INTRNAMES));
                    234:                for (cp = intrnamebuf, i = 0; i < nintr; i++) {
                    235:                        intrname[i] = cp;
                    236:                        cp += strlen(cp) + 1;
                    237:                }
1.44      dsl       238:        }
                    239:
                    240:        /* event counter interrupt counts */
                    241:        get_interrupt_events();
                    242:
1.48      dsl       243:        nextintsrow = INTSROW + 1;
1.44      dsl       244:        allocinfo(&s);
                    245:        allocinfo(&s1);
                    246:        allocinfo(&s2);
                    247:        allocinfo(&z);
                    248:
1.63      dsl       249:        getinfo(&s2);
1.1       jtc       250:        copyinfo(&s2, &s1);
                    251:        return(1);
                    252: }
                    253:
                    254: void
1.33      ad        255: fetchvmstat(void)
1.1       jtc       256: {
                    257:        time_t now;
                    258:
                    259:        time(&now);
1.50      itojun    260:        strlcpy(buf, ctime(&now), sizeof(buf));
1.18      marc      261:        buf[19] = '\0';
1.63      dsl       262:        getinfo(&s);
1.1       jtc       263: }
                    264:
1.44      dsl       265: static void
                    266: print_ie_title(int i)
                    267: {
                    268:        int width, name_width, group_width;
                    269:
1.48      dsl       270:        width = INTSCOLEND - (INTSCOL + 9);
1.44      dsl       271:        if (width <= 0)
                    272:                return;
                    273:
                    274:        move(ie_head[i].ie_loc, INTSCOL + 9);
                    275:        group_width = strlen(ie_head[i].ie_group);
                    276:        name_width = strlen(ie_head[i].ie_name);
                    277:        width -= group_width + 1 + name_width;
                    278:        if (width < 0) {
1.47      dsl       279:                /*
                    280:                 * Screen to narrow for full strings
                    281:                 * This is all rather horrid, in some cases there are a lot
                    282:                 * of events in the same group, and in others the event
                    283:                 * name is "intr".  There are also names which need 7 or 8
                    284:                 * columns before they become meaningful.
                    285:                 * This is a bad compromise.
                    286:                 */
1.44      dsl       287:                width = -width;
                    288:                group_width -= (width + 1) / 2;
                    289:                name_width -= width / 2;
1.47      dsl       290:                /* some have the 'useful' name "intr", display their group */
                    291:                if (strcasecmp(ie_head[i].ie_name, "intr") == 0) {
                    292:                         group_width += name_width + 1;
                    293:                         name_width = 0;
                    294:                } else {
                    295:                        if (group_width <= 3 || name_width < 0) {
                    296:                                /* don't display group */
                    297:                                name_width += group_width + 1;
                    298:                                group_width = 0;
                    299:                        }
1.44      dsl       300:                }
                    301:        }
                    302:
1.47      dsl       303:        if (group_width != 0) {
                    304:                printw("%-.*s", group_width, ie_head[i].ie_group);
                    305:                if (name_width != 0)
                    306:                        printw(" ");
                    307:        }
                    308:        if (name_width != 0)
                    309:                printw("%-.*s", name_width, ie_head[i].ie_name);
1.44      dsl       310: }
                    311:
1.1       jtc       312: void
1.63      dsl       313: labelvmstat_top(void)
1.1       jtc       314: {
                    315:
                    316:        clear();
1.63      dsl       317:
1.1       jtc       318:        mvprintw(STATROW, STATCOL + 4, "users    Load");
1.13      mrg       319:
1.82.6.1! christos  320:        mvprintw(GENSTATROW, GENSTATCOL, "   Csw  Traps SysCal  Intr   Soft  Fault");
1.63      dsl       321:
                    322:        mvprintw(GRAPHROW, GRAPHCOL,
                    323:                "    . %% Sy    . %% Us    . %% Ni    . %% In    . %% Id");
1.75      rmind     324:        mvprintw(PROCSROW, PROCSCOL, "Proc:r  d  s");
1.63      dsl       325:        mvprintw(GRAPHROW + 1, GRAPHCOL,
                    326:                "|    |    |    |    |    |    |    |    |    |    |");
                    327:
                    328:        mvprintw(PAGEROW, PAGECOL + 8, "PAGING   SWAPPING ");
1.13      mrg       329:        mvprintw(PAGEROW + 1, PAGECOL, "        in  out   in  out ");
1.82.6.1! christos  330:        mvprintw(PAGEROW + 2, PAGECOL, "  ops                     ");
        !           331:        mvprintw(PAGEROW + 3, PAGECOL, "pages                     ");
1.63      dsl       332: }
                    333:
                    334: void
                    335: labelvmstat(void)
                    336: {
                    337:        int i;
1.1       jtc       338:
1.63      dsl       339:        /* Top few lines first */
1.1       jtc       340:
1.63      dsl       341:        labelvmstat_top();
1.1       jtc       342:
1.63      dsl       343:        /* Left hand column */
1.1       jtc       344:
1.82.6.1! christos  345:        mvprintw(MEMROW + 0, MEMCOL, "Anon                 %%   zero         ");
        !           346:        mvprintw(MEMROW + 1, MEMCOL, "Exec                 %%   wired        ");
        !           347:        mvprintw(MEMROW + 2, MEMCOL, "File                 %%   inact        ");
        !           348:        mvprintw(MEMROW + 3, MEMCOL, "Meta                 %%   bufs         ");
        !           349:        mvprintw(MEMROW + 4, MEMCOL, " (kB)        real   swaponly      free");
        !           350:        mvprintw(MEMROW + 5, MEMCOL, "Active                                ");
1.1       jtc       351:
                    352:        mvprintw(NAMEIROW, NAMEICOL, "Namei         Sys-cache     Proc-cache");
                    353:        mvprintw(NAMEIROW + 1, NAMEICOL,
                    354:                "    Calls     hits    %%     hits     %%");
1.63      dsl       355:
1.82.6.1! christos  356:        mvprintw(DISKROW, DISKCOL, "%*s", DISKCOLWIDTH, "Disks:");
1.49      dsl       357:        if (disk_horiz) {
                    358:                mvprintw(DISKROW + 1, DISKCOL + 1, "seeks");
                    359:                mvprintw(DISKROW + 2, DISKCOL + 1, "xfers");
                    360:                mvprintw(DISKROW + 3, DISKCOL + 1, "bytes");
                    361:                mvprintw(DISKROW + 4, DISKCOL + 1, "%%busy");
                    362:        } else {
1.82.6.1! christos  363:                mvprintw(DISKROW, DISKCOL + 1 * DISKCOLWIDTH, "%*s", DISKCOLWIDTH, "seeks");
        !           364:                mvprintw(DISKROW, DISKCOL + 2 * DISKCOLWIDTH, "%*s", DISKCOLWIDTH, "xfers");
        !           365:                mvprintw(DISKROW, DISKCOL + 3 * DISKCOLWIDTH, "%*s", DISKCOLWIDTH, "bytes");
        !           366:                mvprintw(DISKROW, DISKCOL + 4 * DISKCOLWIDTH, "%*s", DISKCOLWIDTH, "%busy");
1.49      dsl       367:        }
1.63      dsl       368:
                    369:        /* Middle column */
                    370:
                    371:        mvprintw(INTSROW, INTSCOL + 9, "Interrupts");
1.1       jtc       372:        for (i = 0; i < nintr; i++) {
                    373:                if (intrloc[i] == 0)
                    374:                        continue;
1.47      dsl       375:                mvprintw(intrloc[i], INTSCOL + 9, "%-.*s",
1.48      dsl       376:                        INTSCOLEND - (INTSCOL + 9), intrname[i]);
1.1       jtc       377:        }
1.44      dsl       378:        for (i = 0; i < nevcnt; i++) {
                    379:                if (ie_head[i].ie_loc == 0)
                    380:                        continue;
                    381:                print_ie_title(i);
                    382:        }
1.63      dsl       383:
                    384:        /* Right hand column */
                    385:
                    386:        mvprintw(VMSTATROW + 0, VMSTATCOL + 10, "forks");
                    387:        mvprintw(VMSTATROW + 1, VMSTATCOL + 10, "fkppw");
                    388:        mvprintw(VMSTATROW + 2, VMSTATCOL + 10, "fksvm");
                    389:        mvprintw(VMSTATROW + 3, VMSTATCOL + 10, "pwait");
                    390:        mvprintw(VMSTATROW + 4, VMSTATCOL + 10, "relck");
                    391:        mvprintw(VMSTATROW + 5, VMSTATCOL + 10, "rlkok");
                    392:        mvprintw(VMSTATROW + 6, VMSTATCOL + 10, "noram");
                    393:        mvprintw(VMSTATROW + 7, VMSTATCOL + 10, "ndcpy");
                    394:        mvprintw(VMSTATROW + 8, VMSTATCOL + 10, "fltcp");
                    395:        mvprintw(VMSTATROW + 9, VMSTATCOL + 10, "zfod");
                    396:        mvprintw(VMSTATROW + 10, VMSTATCOL + 10, "cow");
                    397:        mvprintw(VMSTATROW + 11, VMSTATCOL + 10, "fmin");
                    398:        mvprintw(VMSTATROW + 12, VMSTATCOL + 10, "ftarg");
                    399:        mvprintw(VMSTATROW + 13, VMSTATCOL + 10, "itarg");
1.82.6.1! christos  400:        mvprintw(VMSTATROW + 14, VMSTATCOL + 10, "flnan");
1.63      dsl       401:        mvprintw(VMSTATROW + 15, VMSTATCOL + 10, "pdfre");
                    402:
                    403:        if (LINES - 1 > VMSTATROW + 16)
                    404:                mvprintw(VMSTATROW + 16, VMSTATCOL + 10, "pdscn");
1.1       jtc       405: }
                    406:
1.63      dsl       407: #define X(s, s1, fld)  {temp = (s).fld[i]; (s).fld[i] -= (s1).fld[i]; \
                    408:                        if (display_mode == TIME) (s1).fld[i] = temp;}
                    409: #define Z(s, s1, fld)  {temp = (s).nchstats.fld; \
                    410:                        (s).nchstats.fld -= (s1).nchstats.fld; \
                    411:                        if (display_mode == TIME) (s1).nchstats.fld = temp;}
                    412: #define PUTRATE(s, s1, fld, l, c, w) \
                    413:                        {temp = (s).fld; (s).fld -= (s1).fld; \
                    414:                        if (display_mode == TIME) (s1).fld = temp; \
                    415:                        putint((int)((float)(s).fld/etime + 0.5), l, c, w);}
1.1       jtc       416:
1.25      simonb    417: static char cpuchar[CPUSTATES] = { '=' , '>', '-', '%', ' ' };
                    418: static char cpuorder[CPUSTATES] = { CP_SYS, CP_USER, CP_NICE, CP_INTR, CP_IDLE };
1.1       jtc       419:
                    420: void
1.63      dsl       421: show_vmstat_top(vmtotal_t *Total, uvmexp_sysctl_t *uvm, uvmexp_sysctl_t *uvm1)
                    422: {
                    423:        float f1, f2;
                    424:        int psiz;
                    425:        int i, l, c;
                    426:        struct {
                    427:                struct uvmexp_sysctl *uvmexp;
                    428:        } us, us1;
                    429:
                    430:        us.uvmexp = uvm;
                    431:        us1.uvmexp = uvm1;
                    432:
                    433:        putint(ucount(), STATROW, STATCOL, 3);
                    434:        putfloat(avenrun[0], STATROW, STATCOL + 17, 6, 2, 0);
                    435:        putfloat(avenrun[1], STATROW, STATCOL + 23, 6, 2, 0);
                    436:        putfloat(avenrun[2], STATROW, STATCOL + 29, 6, 2, 0);
                    437:        mvaddstr(STATROW, STATCOL + 53, buf);
                    438:
                    439:        putint(Total->t_rq - 1, PROCSROW + 1, PROCSCOL + 3, 3);
                    440:        putint(Total->t_dw, PROCSROW + 1, PROCSCOL + 6, 3);
                    441:        putint(Total->t_sl, PROCSROW + 1, PROCSCOL + 9, 3);
                    442:
                    443:        PUTRATE(us, us1, uvmexp->swtch, GENSTATROW + 1, GENSTATCOL - 1, 7);
1.68      dsl       444:        PUTRATE(us, us1, uvmexp->traps, GENSTATROW + 1, GENSTATCOL + 7, 6);
                    445:        PUTRATE(us, us1, uvmexp->syscalls, GENSTATROW + 1, GENSTATCOL + 14, 6);
                    446:        PUTRATE(us, us1, uvmexp->intrs, GENSTATROW + 1, GENSTATCOL + 21, 5);
1.72      njoly     447:        PUTRATE(us, us1, uvmexp->softs, GENSTATROW + 1, GENSTATCOL + 27, 6);
                    448:        PUTRATE(us, us1, uvmexp->faults, GENSTATROW + 1, GENSTATCOL + 34, 6);
1.63      dsl       449:
1.82.6.1! christos  450:        /*
        !           451:         * XXX it sure would be nice if this did what top(1) does and showed
        !           452:         * the utilization of each CPU on a separate line, though perhaps IFF
        !           453:         * the screen is tall enough
        !           454:         */
1.63      dsl       455:        /* Last CPU state not calculated yet. */
                    456:        for (f2 = 0.0, psiz = 0, c = 0; c < CPUSTATES; c++) {
                    457:                i = cpuorder[c];
                    458:                f1 = cputime(i);
                    459:                f2 += f1;
                    460:                l = (int) ((f2 + 1.0) / 2.0) - psiz;
                    461:                if (c == 0)
                    462:                        putfloat(f1, GRAPHROW, GRAPHCOL + 1, 5, 1, 0);
                    463:                else
                    464:                        putfloat(f1, GRAPHROW, GRAPHCOL + 10 * c + 1, 5, 1, 0);
                    465:                mvhline(GRAPHROW + 2, psiz, cpuchar[c], l);
                    466:                psiz += l;
                    467:        }
                    468:
                    469:        PUTRATE(us, us1, uvmexp->pageins, PAGEROW + 2, PAGECOL + 5, 5);
                    470:        PUTRATE(us, us1, uvmexp->pdpageouts, PAGEROW + 2, PAGECOL + 10, 5);
                    471:        PUTRATE(us, us1, uvmexp->pgswapin, PAGEROW + 3, PAGECOL + 5, 5);
                    472:        PUTRATE(us, us1, uvmexp->pgswapout, PAGEROW + 3, PAGECOL + 10, 5);
                    473: }
                    474:
                    475: void
1.33      ad        476: showvmstat(void)
1.1       jtc       477: {
1.63      dsl       478:        int inttotal;
1.49      dsl       479:        int i, l, r, c;
1.1       jtc       480:        static int failcnt = 0;
1.49      dsl       481:        static int relabel = 0;
                    482:        static int last_disks = 0;
1.82.6.1! christos  483:        static u_long bufmem;
        !           484:        struct buf_sysctl *buffers;
        !           485:        int mib[6];
        !           486:        size_t size;
        !           487:        int extraslop = 0;
1.49      dsl       488:
                    489:        if (relabel) {
                    490:                labelvmstat();
                    491:                relabel = 0;
                    492:        }
1.39      sommerfe  493:
1.62      dsl       494:        cpuswap();
1.63      dsl       495:        if (display_mode == TIME) {
1.65      blymn     496:                drvswap();
1.82.6.1! christos  497:                if (toofast(&failcnt))
1.44      dsl       498:                        return;
                    499:        } else
                    500:                etime = 1.0;
                    501:
1.63      dsl       502:        show_vmstat_top(&s.Total, &s.uvmexp, &s1.uvmexp);
1.1       jtc       503:
1.63      dsl       504:        /* Memory totals */
1.17      drochner  505: #define pgtokb(pg)     ((pg) * (s.uvmexp.pagesize / 1024))
1.82.6.1! christos  506:
        !           507:        putint(pgtokb(s.uvmexp.anonpages),                              MEMROW + 0, MEMCOL + 7, 10);
        !           508:        putint((s.uvmexp.anonpages * 100 + 0.5) / s.uvmexp.npages,      MEMROW + 0, MEMCOL + 17, 4);
        !           509:
        !           510:        putint(pgtokb(s.uvmexp.zeropages),                              MEMROW + 0, MEMCOL + 30, 8);
        !           511:
        !           512:        putint(pgtokb(s.uvmexp.execpages),                              MEMROW + 1, MEMCOL + 7, 10);
        !           513:        putint((s.uvmexp.execpages * 100 + 0.5) / s.uvmexp.npages,      MEMROW + 1, MEMCOL + 17, 4);
        !           514:
        !           515:        putint(pgtokb(s.uvmexp.wired),                                  MEMROW + 1, MEMCOL + 30, 8);
        !           516:
        !           517:        putint(pgtokb(s.uvmexp.filepages),                              MEMROW + 2, MEMCOL + 7, 10);
        !           518:        putint((s.uvmexp.filepages * 100 + 0.5) / s.uvmexp.npages,      MEMROW + 2, MEMCOL + 17, 4);
        !           519:
        !           520:        putint(pgtokb(s.uvmexp.inactive),                               MEMROW + 2, MEMCOL + 30, 8);
        !           521:
        !           522:        /* Get total size of metadata buffers */
        !           523:        size = sizeof(bufmem);
        !           524:        if (sysctlbyname("vm.bufmem", &bufmem, &size, NULL, 0) < 0) {
        !           525:                error("can't get buffers size: %s\n", strerror(errno));
        !           526:                return;
        !           527:        }
        !           528:
        !           529:        /* Get number of metadata buffers */
        !           530:        size = 0;
        !           531:        buffers = NULL;
        !           532:        mib[0] = CTL_KERN;
        !           533:        mib[1] = KERN_BUF;
        !           534:        mib[2] = KERN_BUF_ALL;
        !           535:        mib[3] = KERN_BUF_ALL;
        !           536:        mib[4] = (int)sizeof(struct buf_sysctl);
        !           537:        mib[5] = INT_MAX; /* we want them all */
        !           538: again:
        !           539:        if (sysctl(mib, 6, NULL, &size, NULL, 0) < 0) {
        !           540:                error("can't get buffers size: %s\n", strerror(errno));
        !           541:                return;
        !           542:        }
        !           543:        if (size == 0) {
        !           544:                error("buffers size is zero: %s\n", strerror(errno));
        !           545:                return;
        !           546:        }
        !           547:        size += extraslop * sizeof(struct buf_sysctl);
        !           548:        buffers = malloc(size);
        !           549:        if (buffers == NULL) {
        !           550:                error("can't allocate buffers: %s\n", strerror(errno));
        !           551:                return;
        !           552:        }
        !           553:        if (sysctl(mib, 6, buffers, &size, NULL, 0) < 0) {
        !           554:                free(buffers);
        !           555:                if (extraslop == 0) {
        !           556:                        extraslop = 100;
        !           557:                        goto again;
        !           558:                }
        !           559:                error("can't get buffers: %s\n", strerror(errno));
        !           560:                return;
        !           561:        }
        !           562:        free(buffers);                  /* XXX there must be a better way! */
        !           563:        nbuf = size / sizeof(struct buf_sysctl);
        !           564:
        !           565:        putint((int) (bufmem / 1024),           MEMROW + 3, MEMCOL + 5, 12);
        !           566:        putint((int) ((bufmem * 100) + 0.5) / s.uvmexp.pagesize / s.uvmexp.npages,
        !           567:                                                MEMROW + 3, MEMCOL + 17, 4);
        !           568:        putint(nbuf,                            MEMROW + 3, MEMCOL + 30, 8);
        !           569:
        !           570:        putint(pgtokb(s.uvmexp.active),         MEMROW + 5, MEMCOL + 7, 10);
        !           571:        putint(pgtokb(s.uvmexp.swpgonly),       MEMROW + 5, MEMCOL + 18, 10);
        !           572:        putint(pgtokb(s.uvmexp.free),           MEMROW + 5, MEMCOL + 28, 10);
        !           573:
1.63      dsl       574: #undef pgtokb
                    575:
                    576:        /* Namei cache */
                    577:        Z(s, s1, ncs_goodhits); Z(s, s1, ncs_badhits); Z(s, s1, ncs_miss);
                    578:        Z(s, s1, ncs_long); Z(s, s1, ncs_pass2); Z(s, s1, ncs_2passes);
                    579:        s.nchcount = s.nchstats.ncs_goodhits + s.nchstats.ncs_badhits +
1.77      njoly     580:            s.nchstats.ncs_miss + s.nchstats.ncs_long +
                    581:            s.nchstats.ncs_pass2 + s.nchstats.ncs_2passes;
1.63      dsl       582:        if (display_mode == TIME)
                    583:                s1.nchcount = s.nchcount;
                    584:
                    585:        putint(s.nchcount, NAMEIROW + 2, NAMEICOL, 9);
                    586:        putint(s.nchstats.ncs_goodhits, NAMEIROW + 2, NAMEICOL + 9, 9);
                    587: #define nz(x)  ((x) ? (x) : 1)
                    588:        putfloat(s.nchstats.ncs_goodhits * 100.0 / nz(s.nchcount),
                    589:           NAMEIROW + 2, NAMEICOL + 19, 4, 0, 1);
                    590:        putint(s.nchstats.ncs_pass2, NAMEIROW + 2, NAMEICOL + 23, 9);
                    591:        putfloat(s.nchstats.ncs_pass2 * 100.0 / nz(s.nchcount),
                    592:           NAMEIROW + 2, NAMEICOL + 34, 4, 0, 1);
                    593: #undef nz
1.12      mrg       594:
1.63      dsl       595:        /* Disks */
1.61      blymn     596:        for (l = 0, i = 0, r = DISKROW, c = DISKCOL;
1.73      lukem     597:             i < (int)ndrive; i++) {
1.65      blymn     598:                if (!drv_select[i])
                    599:                        continue;
1.61      blymn     600:
1.49      dsl       601:                if (disk_horiz)
                    602:                        c += DISKCOLWIDTH;
                    603:                else
                    604:                        r++;
                    605:                if (c + DISKCOLWIDTH > DISKCOLEND) {
                    606:                        if (disk_horiz && LINES - 1 - DISKROW >
1.61      blymn     607:                            (DISKCOLEND - DISKCOL) / DISKCOLWIDTH) {
1.49      dsl       608:                                disk_horiz = 0;
                    609:                                relabel = 1;
                    610:                        }
                    611:                        break;
1.1       jtc       612:                }
1.49      dsl       613:                if (r >= LINES - 1) {
                    614:                        if (!disk_horiz && LINES - 1 - DISKROW <
1.61      blymn     615:                            (DISKCOLEND - DISKCOL) / DISKCOLWIDTH) {
1.49      dsl       616:                                disk_horiz = 1;
                    617:                                relabel = 1;
                    618:                        }
                    619:                        break;
                    620:                }
                    621:                l++;
                    622:
1.65      blymn     623:                dinfo(i, r, c);
1.49      dsl       624:        }
                    625:        /* blank out if we lost any disks */
                    626:        for (i = l; i < last_disks; i++) {
                    627:                int j;
                    628:                if (disk_horiz)
                    629:                        c += DISKCOLWIDTH;
                    630:                else
                    631:                        r++;
                    632:                for (j = 0; j < 5; j++) {
                    633:                        if (disk_horiz)
1.56      mycroft   634:                                mvprintw(r+j, c, "%*s", DISKCOLWIDTH, "");
1.49      dsl       635:                        else
1.56      mycroft   636:                                mvprintw(r, c+j*DISKCOLWIDTH, "%*s", DISKCOLWIDTH, "");
1.49      dsl       637:                }
                    638:        }
                    639:        last_disks = l;
1.63      dsl       640:
                    641:        /* Interrupts */
                    642:        failcnt = 0;
                    643:        inttotal = 0;
                    644:        for (i = 0; i < nintr; i++) {
                    645:                if (s.intrcnt[i] == 0)
                    646:                        continue;
                    647:                if (intrloc[i] == 0) {
                    648:                        if (nextintsrow == LINES)
                    649:                                continue;
                    650:                        intrloc[i] = nextintsrow++;
                    651:                        mvprintw(intrloc[i], INTSCOL + 9, "%-.*s",
                    652:                                INTSCOLEND - (INTSCOL + 9), intrname[i]);
                    653:                }
                    654:                X(s, s1, intrcnt);
                    655:                l = (int)((float)s.intrcnt[i]/etime + 0.5);
                    656:                inttotal += l;
                    657:                putint(l, intrloc[i], INTSCOL, 8);
                    658:        }
                    659:
                    660:        for (i = 0; i < nevcnt; i++) {
                    661:                if (s.evcnt[i] == 0)
                    662:                        continue;
                    663:                if (ie_head[i].ie_loc == 0) {
                    664:                        if (nextintsrow == LINES)
                    665:                                continue;
                    666:                        ie_head[i].ie_loc = nextintsrow++;
                    667:                        print_ie_title(i);
                    668:                }
                    669:                X(s, s1, evcnt);
                    670:                l = (int)((float)s.evcnt[i]/etime + 0.5);
                    671:                inttotal += l;
                    672:                putint(l, ie_head[i].ie_loc, INTSCOL, 8);
                    673:        }
                    674:        putint(inttotal, INTSROW, INTSCOL, 8);
                    675:
                    676:        PUTRATE(s, s1, uvmexp.forks, VMSTATROW + 0, VMSTATCOL + 3, 6);
                    677:        PUTRATE(s, s1, uvmexp.forks_ppwait, VMSTATROW + 1, VMSTATCOL + 3, 6);
                    678:        PUTRATE(s, s1, uvmexp.forks_sharevm, VMSTATROW + 2, VMSTATCOL + 3, 6);
                    679:        PUTRATE(s, s1, uvmexp.fltpgwait, VMSTATROW + 3, VMSTATCOL + 4, 5);
                    680:        PUTRATE(s, s1, uvmexp.fltrelck, VMSTATROW + 4, VMSTATCOL + 3, 6);
                    681:        PUTRATE(s, s1, uvmexp.fltrelckok, VMSTATROW + 5, VMSTATCOL + 3, 6);
                    682:        PUTRATE(s, s1, uvmexp.fltnoram, VMSTATROW + 6, VMSTATCOL + 3, 6);
                    683:        PUTRATE(s, s1, uvmexp.fltamcopy, VMSTATROW + 7, VMSTATCOL + 3, 6);
                    684:        PUTRATE(s, s1, uvmexp.flt_prcopy, VMSTATROW + 8, VMSTATCOL + 3, 6);
                    685:        PUTRATE(s, s1, uvmexp.flt_przero, VMSTATROW + 9, VMSTATCOL + 3, 6);
                    686:        PUTRATE(s, s1, uvmexp.flt_acow, VMSTATROW + 10, VMSTATCOL, 9);
                    687:        putint(s.uvmexp.freemin, VMSTATROW + 11, VMSTATCOL, 9);
                    688:        putint(s.uvmexp.freetarg, VMSTATROW + 12, VMSTATCOL, 9);
                    689:        putint(s.uvmexp.inactarg, VMSTATROW + 13, VMSTATCOL, 9);
1.82.6.1! christos  690:        putint(s.uvmexp.fltnoanon, VMSTATROW + 14, VMSTATCOL, 9);
1.63      dsl       691:        PUTRATE(s, s1, uvmexp.pdfreed, VMSTATROW + 15, VMSTATCOL, 9);
                    692:        if (LINES - 1 > VMSTATROW + 16)
                    693:                PUTRATE(s, s1, uvmexp.pdscans, VMSTATROW + 16, VMSTATCOL, 9);
                    694:
1.1       jtc       695: }
                    696:
1.22      jwise     697: void
1.33      ad        698: vmstat_boot(char *args)
1.22      jwise     699: {
                    700:        copyinfo(&z, &s1);
1.63      dsl       701:        display_mode = BOOT;
1.22      jwise     702: }
                    703:
                    704: void
1.33      ad        705: vmstat_run(char *args)
1.22      jwise     706: {
                    707:        copyinfo(&s1, &s2);
1.63      dsl       708:        display_mode = RUN;
1.22      jwise     709: }
                    710:
                    711: void
1.44      dsl       712: vmstat_time(char *args)
1.1       jtc       713: {
1.63      dsl       714:        display_mode = TIME;
1.22      jwise     715: }
1.1       jtc       716:
1.22      jwise     717: void
1.33      ad        718: vmstat_zero(char *args)
1.22      jwise     719: {
1.63      dsl       720:        if (display_mode == RUN)
                    721:                getinfo(&s1);
1.1       jtc       722: }
                    723:
                    724: /* calculate number of users on the system */
                    725: static int
1.33      ad        726: ucount(void)
1.1       jtc       727: {
1.40      christos  728:        static int onusers = -1;
                    729:        int nusers = 0;
                    730:        struct utmpentry *ehead;
                    731:
                    732:        nusers = getutentries(NULL, &ehead);
1.1       jtc       733:
1.21      mrg       734:        if (nusers != onusers) {
                    735:                if (nusers == 1)
                    736:                        mvprintw(STATROW, STATCOL + 8, " ");
                    737:                else
                    738:                        mvprintw(STATROW, STATCOL + 8, "s");
                    739:        }
                    740:        onusers = nusers;
1.1       jtc       741:        return (nusers);
                    742: }
                    743:
                    744: static float
1.33      ad        745: cputime(int indx)
1.1       jtc       746: {
                    747:        double t;
1.10      lukem     748:        int i;
1.1       jtc       749:
                    750:        t = 0;
                    751:        for (i = 0; i < CPUSTATES; i++)
1.39      sommerfe  752:                t += cur.cp_time[i];
1.1       jtc       753:        if (t == 0.0)
                    754:                t = 1.0;
1.39      sommerfe  755:        return (cur.cp_time[indx] * 100.0 / t);
1.1       jtc       756: }
                    757:
1.63      dsl       758: void
1.44      dsl       759: puthumanint(u_int64_t n, int l, int c, int w)
1.41      abs       760: {
                    761:        char b[128];
                    762:
1.48      dsl       763:        if (move(l, c) != OK)
                    764:                return;
1.41      abs       765:        if (n == 0) {
                    766:                hline(' ', w);
                    767:                return;
                    768:        }
1.44      dsl       769:        if (humanize_number(b, w, n, "", HN_AUTOSCALE, HN_NOSPACE) == -1 ) {
1.41      abs       770:                hline('*', w);
                    771:                return;
                    772:        }
1.63      dsl       773:        printw("%*s", w, b);
1.41      abs       774: }
                    775:
1.63      dsl       776: void
1.33      ad        777: putint(int n, int l, int c, int w)
1.1       jtc       778: {
                    779:        char b[128];
                    780:
1.48      dsl       781:        if (move(l, c) != OK)
                    782:                return;
1.1       jtc       783:        if (n == 0) {
1.30      mycroft   784:                hline(' ', w);
1.1       jtc       785:                return;
                    786:        }
1.14      mrg       787:        (void)snprintf(b, sizeof b, "%*d", w, n);
1.73      lukem     788:        if ((int)strlen(b) > w) {
1.63      dsl       789:                if (display_mode == TIME)
                    790:                        hline('*', w);
                    791:                else
                    792:                        puthumanint(n, l, c, w);
1.1       jtc       793:                return;
                    794:        }
                    795:        addstr(b);
                    796: }
                    797:
1.63      dsl       798: void
1.33      ad        799: putfloat(double f, int l, int c, int w, int d, int nz)
1.1       jtc       800: {
                    801:        char b[128];
                    802:
1.48      dsl       803:        if (move(l, c) != OK)
                    804:                return;
1.1       jtc       805:        if (nz && f == 0.0) {
1.30      mycroft   806:                hline(' ', w);
1.1       jtc       807:                return;
                    808:        }
1.14      mrg       809:        (void)snprintf(b, sizeof b, "%*.*f", w, d, f);
1.73      lukem     810:        if ((int)strlen(b) > w) {
1.30      mycroft   811:                hline('*', w);
1.1       jtc       812:                return;
                    813:        }
                    814:        addstr(b);
                    815: }
                    816:
                    817: static void
1.63      dsl       818: getinfo(struct Info *stats)
1.1       jtc       819: {
1.4       cgd       820:        int mib[2];
                    821:        size_t size;
1.44      dsl       822:        int i;
1.1       jtc       823:
1.62      dsl       824:        cpureadstats();
1.65      blymn     825:        drvreadstats();
1.78      joerg     826:        size = sizeof(stats->nchstats);
                    827:        if (sysctlbyname("vfs.namecache_stats", &stats->nchstats, &size,
                    828:            NULL, 0) < 0) {
                    829:                error("can't get namecache statistics: %s\n", strerror(errno));
                    830:                memset(&stats->nchstats, 0, sizeof(stats->nchstats));
                    831:        }
1.60      chs       832:        if (nintr)
1.82.6.1! christos  833:                NREAD(X_INTRCNT, stats->intrcnt, nintr * sizeof(long));
1.44      dsl       834:        for (i = 0; i < nevcnt; i++)
1.60      chs       835:                KREAD(ie_head[i].ie_count, &stats->evcnt[i],
                    836:                      sizeof stats->evcnt[i]);
1.59      dsl       837:        size = sizeof(stats->uvmexp);
1.11      mrg       838:        mib[0] = CTL_VM;
1.34      simonb    839:        mib[1] = VM_UVMEXP2;
1.59      dsl       840:        if (sysctl(mib, 2, &stats->uvmexp, &size, NULL, 0) < 0) {
1.11      mrg       841:                error("can't get uvmexp: %s\n", strerror(errno));
1.59      dsl       842:                memset(&stats->uvmexp, 0, sizeof(stats->uvmexp));
1.11      mrg       843:        }
1.59      dsl       844:        size = sizeof(stats->Total);
1.1       jtc       845:        mib[0] = CTL_VM;
                    846:        mib[1] = VM_METER;
1.59      dsl       847:        if (sysctl(mib, 2, &stats->Total, &size, NULL, 0) < 0) {
1.1       jtc       848:                error("Can't get kernel info: %s\n", strerror(errno));
1.59      dsl       849:                memset(&stats->Total, 0, sizeof(stats->Total));
1.1       jtc       850:        }
                    851: }
                    852:
                    853: static void
1.59      dsl       854: allocinfo(struct Info *stats)
1.1       jtc       855: {
                    856:
1.60      chs       857:        if (nintr &&
                    858:            (stats->intrcnt = calloc(nintr, sizeof(long))) == NULL) {
1.44      dsl       859:                error("calloc failed");
                    860:                die(0);
                    861:        }
1.59      dsl       862:        if ((stats->evcnt = calloc(nevcnt, sizeof(u_int64_t))) == NULL) {
1.44      dsl       863:                error("calloc failed");
1.23      jwise     864:                die(0);
                    865:        }
1.1       jtc       866: }
                    867:
                    868: static void
1.33      ad        869: copyinfo(struct Info *from, struct Info *to)
1.1       jtc       870: {
                    871:        long *intrcnt;
1.44      dsl       872:        u_int64_t *evcnt;
1.1       jtc       873:
1.5       thorpej   874:        intrcnt = to->intrcnt;
1.44      dsl       875:        evcnt = to->evcnt;
1.1       jtc       876:        *to = *from;
1.54      dsl       877:        memmove(to->intrcnt = intrcnt, from->intrcnt, nintr * sizeof *intrcnt);
1.44      dsl       878:        memmove(to->evcnt = evcnt, from->evcnt, nevcnt * sizeof *evcnt);
1.1       jtc       879: }
                    880:
                    881: static void
1.49      dsl       882: dinfo(int dn, int r, int c)
1.1       jtc       883: {
1.82      mlelstv   884:        double atime, dtime;
1.49      dsl       885: #define ADV if (disk_horiz) r++; else c += DISKCOLWIDTH
                    886:
1.82      mlelstv   887:        /* elapsed time for disk stats */
                    888:        dtime = etime;
                    889:        if (cur.timestamp[dn].tv_sec || cur.timestamp[dn].tv_usec) {
                    890:                dtime = (double)cur.timestamp[dn].tv_sec +
                    891:                        ((double)cur.timestamp[dn].tv_usec / (double)1000000);
                    892:        }
                    893:
1.49      dsl       894:        mvprintw(r, c, "%*.*s", DISKCOLWIDTH, DISKCOLWIDTH, dr_name[dn]);
                    895:        ADV;
1.1       jtc       896:
1.82      mlelstv   897:        putint((int)(cur.seek[dn]/dtime+0.5), r, c, DISKCOLWIDTH);
1.61      blymn     898:        ADV;
1.82      mlelstv   899:        putint((int)((cur.rxfer[dn]+cur.wxfer[dn])/dtime+0.5),
1.61      blymn     900:            r, c, DISKCOLWIDTH);
                    901:        ADV;
1.82      mlelstv   902:        puthumanint((cur.rbytes[dn] + cur.wbytes[dn]) / dtime + 0.5,
1.61      blymn     903:                    r, c, DISKCOLWIDTH);
                    904:        ADV;
                    905:
                    906:        /* time busy in disk activity */
1.65      blymn     907:        atime = cur.time[dn].tv_sec + cur.time[dn].tv_usec / 1000000.0;
1.82      mlelstv   908:        atime = atime * 100.0 / dtime;
1.61      blymn     909:        if (atime >= 100)
                    910:                putint(100, r, c, DISKCOLWIDTH);
                    911:        else
                    912:                putfloat(atime, r, c, DISKCOLWIDTH, 1, 1);
1.1       jtc       913: }

CVSweb <webmaster@jp.NetBSD.org>