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

Annotation of src/usr.bin/vmstat/dkstats.c, Revision 1.39

1.39    ! tb          1: /*     $OpenBSD: dkstats.c,v 1.38 2015/12/24 03:25:08 mmcc Exp $       */
1.2       deraadt     2: /*     $NetBSD: dkstats.c,v 1.1 1996/05/10 23:19:27 thorpej Exp $      */
1.1       tholo       3:
                      4: /*
1.2       deraadt     5:  * Copyright (c) 1996 John M. Vinopal
1.1       tholo       6:  * All rights reserved.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
                     16:  * 3. All advertising materials mentioning features or use of this software
                     17:  *    must display the following acknowledgement:
                     18:  *      This product includes software developed for the NetBSD Project
                     19:  *      by John M. Vinopal.
                     20:  * 4. The name of the author may not be used to endorse or promote products
                     21:  *    derived from this software without specific prior written permission.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     24:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     25:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     26:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     27:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
                     28:  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
                     29:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
                     30:  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
                     31:  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     32:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     33:  * SUCH DAMAGE.
                     34:  */
                     35:
                     36: #include <sys/time.h>
                     37: #include <sys/disk.h>
1.36      miod       38: #include <sys/sched.h>
1.10      angelos    39: #include <sys/sysctl.h>
                     40: #include <sys/tty.h>
1.1       tholo      41:
                     42: #include <err.h>
                     43: #include <fcntl.h>
                     44: #include <kvm.h>
                     45: #include <limits.h>
                     46: #include <nlist.h>
                     47: #include <stdio.h>
                     48: #include <stdlib.h>
                     49: #include <string.h>
                     50: #include <unistd.h>
                     51: #include "dkstats.h"
                     52:
1.16      deraadt    53: #if !defined(NOKVM)
1.1       tholo      54: static struct nlist namelist[] = {
1.18      deraadt    55: #define        X_TK_NIN        0               /* sysctl */
                     56:        { "_tk_nin" },
                     57: #define        X_TK_NOUT       1               /* sysctl */
                     58:        { "_tk_nout" },
                     59: #define        X_CP_TIME       2               /* sysctl */
                     60:        { "_cp_time" },
                     61: #define        X_HZ            3               /* sysctl */
                     62:        { "_hz" },
                     63: #define        X_STATHZ        4               /* sysctl */
1.1       tholo      64:        { "_stathz" },
1.18      deraadt    65: #define X_DISK_COUNT   5               /* sysctl */
                     66:        { "_disk_count" },
                     67: #define X_DISKLIST     6               /* sysctl */
                     68:        { "_disklist" },
1.1       tholo      69:        { NULL },
                     70: };
1.16      deraadt    71: #define        KVM_ERROR(_string) {                                            \
                     72:        warnx("%s", (_string));                                         \
                     73:        errx(1, "%s", kvm_geterr(kd));                                  \
                     74: }
                     75:
                     76: /*
1.30      deraadt    77:  * Dereference the namelist pointer `v' and fill in the local copy
1.16      deraadt    78:  * 'p' which is of size 's'.
                     79:  */
                     80: #define deref_nl(v, p, s) deref_kptr((void *)namelist[(v)].n_value, (p), (s));
                     81: static void deref_kptr(void *, void *, size_t);
                     82: #endif /* !defined(NOKVM) */
1.1       tholo      83:
                     84: /* Structures to hold the statistics. */
                     85: struct _disk   cur, last;
                     86:
                     87: /* Kernel pointers: nlistf and memf defined in calling program. */
1.19      deraadt    88: #if !defined(NOKVM)
1.20      deraadt    89: extern kvm_t   *kd;
1.19      deraadt    90: #endif
1.1       tholo      91: extern char    *nlistf;
                     92: extern char    *memf;
                     93:
1.19      deraadt    94: #if !defined(NOKVM)
1.1       tholo      95: /* Pointer to list of disks. */
                     96: static struct disk     *dk_drivehead = NULL;
1.19      deraadt    97: #endif
1.1       tholo      98:
                     99: /* Backward compatibility references. */
1.30      deraadt   100: int            dk_ndrive = 0;
1.1       tholo     101: int            *dk_select;
                    102: char           **dr_name;
                    103:
                    104: /* Missing from <sys/time.h> */
1.16      deraadt   105: #define timerset(tvp, uvp) \
                    106:        ((uvp)->tv_sec = (tvp)->tv_sec);                \
                    107:        ((uvp)->tv_usec = (tvp)->tv_usec)
                    108:
                    109: #define SWAP(fld)      tmp = cur.fld;                          \
                    110:                        cur.fld -= last.fld;                    \
                    111:                        last.fld = tmp
1.1       tholo     112:
                    113: /*
                    114:  * Take the delta between the present values and the last recorded
                    115:  * values, storing the present values in the 'last' structure, and
                    116:  * the delta values in the 'cur' structure.
                    117:  */
                    118: void
1.21      deraadt   119: dkswap(void)
1.1       tholo     120: {
                    121:        u_int64_t tmp;
                    122:        int     i;
                    123:
1.22      tdeval    124:        for (i = 0; i < cur.dk_ndrive; i++) {
1.1       tholo     125:                struct timeval  tmp_timer;
                    126:
                    127:                if (!cur.dk_select[i])
                    128:                        continue;
                    129:
                    130:                /* Delta Values. */
1.24      tedu      131:                SWAP(dk_rxfer[i]);
                    132:                SWAP(dk_wxfer[i]);
1.1       tholo     133:                SWAP(dk_seek[i]);
1.24      tedu      134:                SWAP(dk_rbytes[i]);
                    135:                SWAP(dk_wbytes[i]);
1.1       tholo     136:
                    137:                /* Delta Time. */
                    138:                timerclear(&tmp_timer);
                    139:                timerset(&(cur.dk_time[i]), &tmp_timer);
                    140:                timersub(&tmp_timer, &(last.dk_time[i]), &(cur.dk_time[i]));
                    141:                timerclear(&(last.dk_time[i]));
                    142:                timerset(&tmp_timer, &(last.dk_time[i]));
                    143:        }
                    144:        for (i = 0; i < CPUSTATES; i++) {
1.29      deraadt   145:                long ltmp;
                    146:
                    147:                ltmp = cur.cp_time[i];
                    148:                cur.cp_time[i] -= last.cp_time[i];
                    149:                last.cp_time[i] = ltmp;
1.1       tholo     150:        }
                    151:        SWAP(tk_nin);
                    152:        SWAP(tk_nout);
                    153:
                    154: #undef SWAP
                    155: }
                    156:
                    157: /*
1.30      deraadt   158:  * Read the disk statistics for each disk in the disk list.
1.1       tholo     159:  * Also collect statistics for tty i/o and cpu ticks.
                    160:  */
                    161: void
1.21      deraadt   162: dkreadstats(void)
1.1       tholo     163: {
1.19      deraadt   164: #if !defined(NOKVM)
1.1       tholo     165:        struct disk     cur_disk, *p;
1.19      deraadt   166: #endif
1.22      tdeval    167:        int             i, j, mib[3];
1.10      angelos   168:        size_t          size;
1.22      tdeval    169:        char            *disknames, *name, *bufpp, **dk_name;
1.13      angelos   170:        struct diskstats *q;
1.1       tholo     171:
1.22      tdeval    172:        last.dk_ndrive = cur.dk_ndrive;
                    173:
1.10      angelos   174:        if (nlistf == NULL && memf == NULL) {
1.22      tdeval    175:                /* Get the number of attached drives. */
                    176:                mib[0] = CTL_HW;
                    177:                mib[1] = HW_DISKCOUNT;
                    178:                size = sizeof(dk_ndrive);
                    179:                if (sysctl(mib, 2, &dk_ndrive, &size, NULL, 0) < 0 ) {
                    180:                        warn("could not read hw.diskcount");
                    181:                        dk_ndrive = 0;
                    182:                }
                    183:
                    184:                if (cur.dk_ndrive != dk_ndrive) {
                    185:                        /* Re-read the disk names. */
1.29      deraadt   186:                        dk_name = calloc((size_t)dk_ndrive, sizeof(char *));
1.22      tdeval    187:                        if (dk_name == NULL)
                    188:                                err(1, NULL);
                    189:                        mib[0] = CTL_HW;
                    190:                        mib[1] = HW_DISKNAMES;
                    191:                        size = 0;
                    192:                        if (sysctl(mib, 2, NULL, &size, NULL, 0) < 0)
                    193:                                err(1, "can't get hw.disknames");
                    194:                        disknames = malloc(size);
                    195:                        if (disknames == NULL)
                    196:                                err(1, NULL);
                    197:                        if (sysctl(mib, 2, disknames, &size, NULL, 0) < 0)
                    198:                                err(1, "can't get hw.disknames");
                    199:                        bufpp = disknames;
1.35      deraadt   200:                        for (i = 0; i < dk_ndrive &&
                    201:                            (name = strsep(&bufpp, ",")) != NULL; i++)
1.23      millert   202:                                dk_name[i] = name;
1.35      deraadt   203:                        for (i = 0; i < dk_ndrive; i++) {
                    204:                                char *p = strchr(dk_name[i], ':');
                    205:                                if (p)
                    206:                                        *p = '\0';
                    207:                        }
1.22      tdeval    208:                        disknames = cur.dk_name[0];     /* To free old names. */
                    209:
                    210:                        if (dk_ndrive < cur.dk_ndrive) {
                    211:                                for (i = 0, j = 0; i < dk_ndrive; i++, j++) {
                    212:                                        while (j < cur.dk_ndrive &&
                    213:                                            strcmp(cur.dk_name[j], dk_name[i]))
                    214:                                                j++;
                    215:                                        if (i == j) continue;
                    216:
                    217:                                        if (j >= cur.dk_ndrive) {
                    218:                                                cur.dk_select[i] = 1;
1.24      tedu      219:                                                last.dk_rxfer[i] = 0;
                    220:                                                last.dk_wxfer[i] = 0;
1.22      tdeval    221:                                                last.dk_seek[i] = 0;
1.24      tedu      222:                                                last.dk_rbytes[i] = 0;
                    223:                                                last.dk_wbytes[i] = 0;
1.38      mmcc      224:                                                memset(&last.dk_time[i], 0,
1.22      tdeval    225:                                                    sizeof(struct timeval));
                    226:                                                continue;
                    227:                                        }
                    228:
                    229:                                        cur.dk_select[i] = cur.dk_select[j];
1.24      tedu      230:                                        last.dk_rxfer[i] = last.dk_rxfer[j];
                    231:                                        last.dk_wxfer[i] = last.dk_wxfer[j];
1.22      tdeval    232:                                        last.dk_seek[i] = last.dk_seek[j];
1.24      tedu      233:                                        last.dk_rbytes[i] = last.dk_rbytes[j];
                    234:                                        last.dk_wbytes[i] = last.dk_wbytes[j];
1.22      tdeval    235:                                        last.dk_time[i] = last.dk_time[j];
                    236:                                }
                    237:
1.39    ! tb        238:                                cur.dk_select = reallocarray(cur.dk_select,
        !           239:                                    dk_ndrive, sizeof(*cur.dk_select));
        !           240:                                cur.dk_rxfer = reallocarray(cur.dk_rxfer,
        !           241:                                    dk_ndrive, sizeof(*cur.dk_rxfer));
        !           242:                                cur.dk_wxfer = reallocarray(cur.dk_wxfer,
        !           243:                                    dk_ndrive, sizeof(*cur.dk_wxfer));
        !           244:                                cur.dk_seek = reallocarray(cur.dk_seek,
        !           245:                                    dk_ndrive, sizeof(*cur.dk_seek));
        !           246:                                cur.dk_rbytes = reallocarray(cur.dk_rbytes,
        !           247:                                    dk_ndrive, sizeof(*cur.dk_rbytes));
        !           248:                                cur.dk_wbytes = reallocarray(cur.dk_wbytes,
        !           249:                                    dk_ndrive, sizeof(*cur.dk_wbytes));
        !           250:                                cur.dk_time = reallocarray(cur.dk_time,
        !           251:                                    dk_ndrive, sizeof(*cur.dk_time));
        !           252:                                last.dk_rxfer = reallocarray(last.dk_rxfer,
        !           253:                                    dk_ndrive, sizeof(*last.dk_rxfer));
        !           254:                                last.dk_wxfer = reallocarray(last.dk_wxfer,
        !           255:                                    dk_ndrive, sizeof(*last.dk_wxfer));
        !           256:                                last.dk_seek = reallocarray(last.dk_seek,
        !           257:                                    dk_ndrive, sizeof(*last.dk_seek));
        !           258:                                last.dk_rbytes = reallocarray(last.dk_rbytes,
        !           259:                                    dk_ndrive, sizeof(*last.dk_rbytes));
        !           260:                                last.dk_wbytes = reallocarray(last.dk_wbytes,
        !           261:                                    dk_ndrive, sizeof(*last.dk_wbytes));
        !           262:                                last.dk_time = reallocarray(last.dk_time,
        !           263:                                    dk_ndrive, sizeof(*last.dk_time));
1.32      chl       264:
                    265:                                if (!cur.dk_select || !cur.dk_rxfer ||
                    266:                                    !cur.dk_wxfer || !cur.dk_seek ||
                    267:                                    !cur.dk_rbytes || !cur.dk_wbytes ||
                    268:                                    !cur.dk_time || !last.dk_rxfer ||
                    269:                                    !last.dk_wxfer || !last.dk_seek ||
                    270:                                    !last.dk_rbytes || !last.dk_wbytes ||
                    271:                                    !last.dk_time)
                    272:                                        errx(1, "Memory allocation failure.");
1.22      tdeval    273:                        } else {
1.39    ! tb        274:                                cur.dk_select = reallocarray(cur.dk_select,
        !           275:                                    dk_ndrive, sizeof(*cur.dk_select));
        !           276:                                cur.dk_rxfer = reallocarray(cur.dk_rxfer,
        !           277:                                    dk_ndrive, sizeof(*cur.dk_rxfer));
        !           278:                                cur.dk_wxfer = reallocarray(cur.dk_wxfer,
        !           279:                                    dk_ndrive, sizeof(*cur.dk_wxfer));
        !           280:                                cur.dk_seek = reallocarray(cur.dk_seek,
        !           281:                                    dk_ndrive, sizeof(*cur.dk_seek));
        !           282:                                cur.dk_rbytes = reallocarray(cur.dk_rbytes,
        !           283:                                    dk_ndrive, sizeof(*cur.dk_rbytes));
        !           284:                                cur.dk_wbytes = reallocarray(cur.dk_wbytes,
        !           285:                                    dk_ndrive, sizeof(*cur.dk_wbytes));
        !           286:                                cur.dk_time = reallocarray(cur.dk_time,
        !           287:                                    dk_ndrive, sizeof(*cur.dk_time));
        !           288:                                last.dk_rxfer = reallocarray(last.dk_rxfer,
        !           289:                                    dk_ndrive, sizeof(*last.dk_rxfer));
        !           290:                                last.dk_wxfer = reallocarray(last.dk_wxfer,
        !           291:                                    dk_ndrive, sizeof(*last.dk_wxfer));
        !           292:                                last.dk_seek = reallocarray(last.dk_seek,
        !           293:                                    dk_ndrive, sizeof(*last.dk_seek));
        !           294:                                last.dk_rbytes = reallocarray(last.dk_rbytes,
        !           295:                                    dk_ndrive, sizeof(*last.dk_rbytes));
        !           296:                                last.dk_wbytes = reallocarray(last.dk_wbytes,
        !           297:                                    dk_ndrive, sizeof(*last.dk_wbytes));
        !           298:                                last.dk_time = reallocarray(last.dk_time,
        !           299:                                    dk_ndrive, sizeof(*last.dk_time));
1.32      chl       300:
                    301:                                if (!cur.dk_select || !cur.dk_rxfer ||
                    302:                                    !cur.dk_wxfer || !cur.dk_seek ||
                    303:                                    !cur.dk_rbytes || !cur.dk_wbytes ||
                    304:                                    !cur.dk_time || !last.dk_rxfer ||
                    305:                                    !last.dk_wxfer || !last.dk_seek ||
                    306:                                    !last.dk_rbytes || !last.dk_wbytes ||
                    307:                                    !last.dk_time)
                    308:                                        errx(1, "Memory allocation failure.");
1.22      tdeval    309:
                    310:                                for (i = dk_ndrive - 1, j = cur.dk_ndrive - 1;
                    311:                                     i >= 0; i--) {
                    312:
                    313:                                        if (j < 0 ||
                    314:                                            strcmp(cur.dk_name[j], dk_name[i]))
                    315:                                        {
                    316:                                                cur.dk_select[i] = 1;
1.24      tedu      317:                                                last.dk_rxfer[i] = 0;
                    318:                                                last.dk_wxfer[i] = 0;
1.22      tdeval    319:                                                last.dk_seek[i] = 0;
1.24      tedu      320:                                                last.dk_rbytes[i] = 0;
                    321:                                                last.dk_wbytes[i] = 0;
1.38      mmcc      322:                                                memset(&last.dk_time[i], 0,
1.22      tdeval    323:                                                    sizeof(struct timeval));
                    324:                                                continue;
                    325:                                        }
                    326:
                    327:                                        if (i > j) {
                    328:                                                cur.dk_select[i] =
                    329:                                                    cur.dk_select[j];
1.24      tedu      330:                                                last.dk_rxfer[i] =
                    331:                                                    last.dk_rxfer[j];
                    332:                                                last.dk_wxfer[i] =
                    333:                                                    last.dk_wxfer[j];
1.22      tdeval    334:                                                last.dk_seek[i] =
                    335:                                                    last.dk_seek[j];
1.24      tedu      336:                                                last.dk_rbytes[i] =
                    337:                                                    last.dk_rbytes[j];
                    338:                                                last.dk_wbytes[i] =
                    339:                                                    last.dk_wbytes[j];
1.22      tdeval    340:                                                last.dk_time[i] =
                    341:                                                    last.dk_time[j];
                    342:                                        }
                    343:                                        j--;
                    344:                                }
                    345:                        }
                    346:
                    347:                        cur.dk_ndrive = dk_ndrive;
                    348:                        free(disknames);
                    349:                        cur.dk_name = dk_name;
                    350:                        dr_name = cur.dk_name;
                    351:                        dk_select = cur.dk_select;
                    352:                }
                    353:
                    354:                size = cur.dk_ndrive * sizeof(struct diskstats);
1.10      angelos   355:                mib[0] = CTL_HW;
                    356:                mib[1] = HW_DISKSTATS;
1.13      angelos   357:                q = malloc(size);
                    358:                if (q == NULL)
1.10      angelos   359:                        err(1, NULL);
1.13      angelos   360:                if (sysctl(mib, 2, q, &size, NULL, 0) < 0) {
1.22      tdeval    361: #ifdef DEBUG
1.10      angelos   362:                        warn("could not read hw.diskstats");
1.22      tdeval    363: #endif /* DEBUG */
1.38      mmcc      364:                        memset(q, 0, cur.dk_ndrive * sizeof(struct diskstats));
1.10      angelos   365:                }
                    366:
1.22      tdeval    367:                for (i = 0; i < cur.dk_ndrive; i++)     {
1.24      tedu      368:                        cur.dk_rxfer[i] = q[i].ds_rxfer;
                    369:                        cur.dk_wxfer[i] = q[i].ds_wxfer;
1.13      angelos   370:                        cur.dk_seek[i] = q[i].ds_seek;
1.24      tedu      371:                        cur.dk_rbytes[i] = q[i].ds_rbytes;
                    372:                        cur.dk_wbytes[i] = q[i].ds_wbytes;
1.13      angelos   373:                        timerset(&(q[i].ds_time), &(cur.dk_time[i]));
1.10      angelos   374:                }
1.14      deraadt   375:                free(q);
1.10      angelos   376:
1.30      deraadt   377:                size = sizeof(cur.cp_time);
1.10      angelos   378:                mib[0] = CTL_KERN;
                    379:                mib[1] = KERN_CPTIME;
                    380:                if (sysctl(mib, 2, cur.cp_time, &size, NULL, 0) < 0) {
1.11      angelos   381:                        warn("could not read kern.cp_time");
1.38      mmcc      382:                        memset(cur.cp_time, 0, sizeof(cur.cp_time));
1.10      angelos   383:                }
                    384:                size = sizeof(cur.tk_nin);
                    385:                mib[0] = CTL_KERN;
                    386:                mib[1] = KERN_TTY;
                    387:                mib[2] = KERN_TTY_TKNIN;
                    388:                if (sysctl(mib, 3, &cur.tk_nin, &size, NULL, 0) < 0) {
1.11      angelos   389:                        warn("could not read kern.tty.tk_nin");
1.10      angelos   390:                        cur.tk_nin = 0;
                    391:                }
                    392:                size = sizeof(cur.tk_nin);
                    393:                mib[0] = CTL_KERN;
                    394:                mib[1] = KERN_TTY;
                    395:                mib[2] = KERN_TTY_TKNOUT;
                    396:                if (sysctl(mib, 3, &cur.tk_nout, &size, NULL, 0) < 0) {
1.11      angelos   397:                        warn("could not read kern.tty.tk_nout");
1.10      angelos   398:                        cur.tk_nout = 0;
                    399:                }
                    400:        } else {
1.16      deraadt   401: #if !defined(NOKVM)
1.10      angelos   402:                p = dk_drivehead;
                    403:
1.22      tdeval    404:                for (i = 0; i < cur.dk_ndrive; i++) {
1.10      angelos   405:                        deref_kptr(p, &cur_disk, sizeof(cur_disk));
1.24      tedu      406:                        cur.dk_rxfer[i] = cur_disk.dk_rxfer;
                    407:                        cur.dk_wxfer[i] = cur_disk.dk_wxfer;
1.10      angelos   408:                        cur.dk_seek[i] = cur_disk.dk_seek;
1.24      tedu      409:                        cur.dk_rbytes[i] = cur_disk.dk_rbytes;
                    410:                        cur.dk_wbytes[i] = cur_disk.dk_wbytes;
1.10      angelos   411:                        timerset(&(cur_disk.dk_time), &(cur.dk_time[i]));
1.27      otto      412:                        p = TAILQ_NEXT(&cur_disk, dk_link);
1.10      angelos   413:                }
                    414:                deref_nl(X_CP_TIME, cur.cp_time, sizeof(cur.cp_time));
                    415:                deref_nl(X_TK_NIN, &cur.tk_nin, sizeof(cur.tk_nin));
                    416:                deref_nl(X_TK_NOUT, &cur.tk_nout, sizeof(cur.tk_nout));
1.16      deraadt   417: #endif /* !defined(NOKVM) */
1.1       tholo     418:        }
                    419: }
                    420:
                    421: /*
                    422:  * Perform all of the initialization and memory allocation needed to
                    423:  * track disk statistics.
                    424:  */
                    425: int
1.28      otto      426: dkinit(int sel)
1.1       tholo     427: {
1.19      deraadt   428: #if !defined(NOKVM)
1.1       tholo     429:        struct disklist_head disk_head;
                    430:        struct disk     cur_disk, *p;
                    431:         char           errbuf[_POSIX2_LINE_MAX];
1.19      deraadt   432: #endif
1.1       tholo     433:        static int      once = 0;
                    434:        extern int      hz;
1.10      angelos   435:        int             i, mib[2];
                    436:        size_t          size;
                    437:        struct clockinfo clkinfo;
                    438:        char            *disknames, *name, *bufpp;
1.1       tholo     439:
                    440:        if (once)
                    441:                return(1);
                    442:
1.10      angelos   443:        if (nlistf != NULL || memf != NULL) {
1.16      deraadt   444: #if !defined(NOKVM)
1.10      angelos   445:                /* Open the kernel. */
1.20      deraadt   446:                if (kd == NULL &&
                    447:                    (kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY,
1.10      angelos   448:                    errbuf)) == NULL)
                    449:                        errx(1, "kvm_openfiles: %s", errbuf);
                    450:
                    451:                /* Obtain the namelist symbols from the kernel. */
                    452:                if (kvm_nlist(kd, namelist))
                    453:                        KVM_ERROR("kvm_nlist failed to read symbols.");
                    454:
                    455:                /* Get the number of attached drives. */
1.22      tdeval    456:                deref_nl(X_DISK_COUNT, &cur.dk_ndrive, sizeof(cur.dk_ndrive));
1.10      angelos   457:
1.22      tdeval    458:                if (cur.dk_ndrive < 0)
                    459:                        errx(1, "invalid _disk_count %d.", cur.dk_ndrive);
1.10      angelos   460:
1.1       tholo     461:                /* Get a pointer to the first disk. */
                    462:                deref_nl(X_DISKLIST, &disk_head, sizeof(disk_head));
1.27      otto      463:                dk_drivehead = TAILQ_FIRST(&disk_head);
1.10      angelos   464:
                    465:                /* Get ticks per second. */
                    466:                deref_nl(X_STATHZ, &hz, sizeof(hz));
                    467:                if (!hz)
                    468:                  deref_nl(X_HZ, &hz, sizeof(hz));
1.16      deraadt   469: #endif /* !defined(NOKVM) */
1.10      angelos   470:        } else {
                    471:                /* Get the number of attached drives. */
                    472:                mib[0] = CTL_HW;
                    473:                mib[1] = HW_DISKCOUNT;
1.22      tdeval    474:                size = sizeof(cur.dk_ndrive);
                    475:                if (sysctl(mib, 2, &cur.dk_ndrive, &size, NULL, 0) < 0 ) {
1.11      angelos   476:                        warn("could not read hw.diskcount");
1.22      tdeval    477:                        cur.dk_ndrive = 0;
1.10      angelos   478:                }
                    479:
                    480:                /* Get ticks per second. */
                    481:                mib[0] = CTL_KERN;
                    482:                mib[1] = KERN_CLOCKRATE;
                    483:                size = sizeof(clkinfo);
                    484:                if (sysctl(mib, 2, &clkinfo, &size, NULL, 0) < 0) {
1.11      angelos   485:                        warn("could not read kern.clockrate");
1.10      angelos   486:                        hz = 0;
                    487:                } else
                    488:                        hz = clkinfo.stathz;
1.1       tholo     489:        }
                    490:
                    491:        /* allocate space for the statistics */
1.29      deraadt   492:        cur.dk_time = calloc((size_t)cur.dk_ndrive, sizeof(struct timeval));
                    493:        cur.dk_rxfer = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t));
                    494:        cur.dk_wxfer = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t));
                    495:        cur.dk_seek = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t));
                    496:        cur.dk_rbytes = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t));
                    497:        cur.dk_wbytes = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t));
1.31      chl       498:        cur.dk_select = calloc((size_t)cur.dk_ndrive, sizeof(int));
                    499:        cur.dk_name = calloc((size_t)cur.dk_ndrive, sizeof(char *));
1.29      deraadt   500:        last.dk_time = calloc((size_t)cur.dk_ndrive, sizeof(struct timeval));
                    501:        last.dk_rxfer = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t));
                    502:        last.dk_wxfer = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t));
                    503:        last.dk_seek = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t));
                    504:        last.dk_rbytes = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t));
                    505:        last.dk_wbytes = calloc((size_t)cur.dk_ndrive, sizeof(u_int64_t));
1.30      deraadt   506:
1.24      tedu      507:        if (!cur.dk_time || !cur.dk_rxfer || !cur.dk_wxfer || !cur.dk_seek ||
1.31      chl       508:            !cur.dk_rbytes || !cur.dk_wbytes || !cur.dk_select ||
                    509:            !cur.dk_name || !last.dk_time || !last.dk_rxfer ||
                    510:            !last.dk_wxfer || !last.dk_seek || !last.dk_rbytes ||
                    511:            !last.dk_wbytes)
1.1       tholo     512:                errx(1, "Memory allocation failure.");
                    513:
                    514:        /* Set up the compatibility interfaces. */
1.22      tdeval    515:        dk_ndrive = cur.dk_ndrive;
1.1       tholo     516:        dk_select = cur.dk_select;
                    517:        dr_name = cur.dk_name;
                    518:
1.22      tdeval    519:        /* Read the disk names and set initial selection. */
1.10      angelos   520:        if (nlistf == NULL && memf == NULL) {
                    521:                mib[0] = CTL_HW;
                    522:                mib[1] = HW_DISKNAMES;
                    523:                size = 0;
                    524:                if (sysctl(mib, 2, NULL, &size, NULL, 0) < 0)
                    525:                        err(1, "can't get hw.disknames");
1.12      angelos   526:                disknames = malloc(size);
1.10      angelos   527:                if (disknames == NULL)
                    528:                        err(1, NULL);
                    529:                if (sysctl(mib, 2, disknames, &size, NULL, 0) < 0)
                    530:                        err(1, "can't get hw.disknames");
                    531:                bufpp = disknames;
1.23      millert   532:                for (i = 0; i < dk_ndrive && (name = strsep(&bufpp, ",")) != NULL; i++) {
                    533:                        cur.dk_name[i] = name;
1.28      otto      534:                        cur.dk_select[i] = sel;
1.35      deraadt   535:                }
                    536:                for (i = 0; i < dk_ndrive; i++) {
                    537:                        char *p = strchr(cur.dk_name[i], ':');
                    538:                        if (p)
                    539:                                *p = '\0';
1.10      angelos   540:                }
                    541:        } else {
1.16      deraadt   542: #if !defined(NOKVM)
1.10      angelos   543:                p = dk_drivehead;
1.22      tdeval    544:                for (i = 0; i < cur.dk_ndrive; i++) {
1.10      angelos   545:                        char    buf[10];
1.16      deraadt   546:
1.10      angelos   547:                        deref_kptr(p, &cur_disk, sizeof(cur_disk));
                    548:                        deref_kptr(cur_disk.dk_name, buf, sizeof(buf));
                    549:                        cur.dk_name[i] = strdup(buf);
                    550:                        if (!cur.dk_name[i])
                    551:                                errx(1, "Memory allocation failure.");
1.28      otto      552:                        cur.dk_select[i] = sel;
1.1       tholo     553:
1.27      otto      554:                        p = TAILQ_NEXT(&cur_disk, dk_link);
1.10      angelos   555:                }
1.16      deraadt   556: #endif /* !defined(NOKVM) */
1.1       tholo     557:        }
                    558:
1.33      martynas  559:        /* Never do this initialization again. */
1.1       tholo     560:        once = 1;
                    561:        return(1);
                    562: }
                    563:
1.16      deraadt   564: #if !defined(NOKVM)
1.1       tholo     565: /*
1.30      deraadt   566:  * Dereference the kernel pointer `kptr' and fill in the local copy
1.1       tholo     567:  * pointed to by `ptr'.  The storage space must be pre-allocated,
                    568:  * and the size of the copy passed in `len'.
                    569:  */
                    570: static void
1.21      deraadt   571: deref_kptr(void *kptr, void *ptr, size_t len)
1.1       tholo     572: {
                    573:        char buf[128];
                    574:
1.6       art       575:        if (kvm_read(kd, (u_long)kptr, ptr, len) != len) {
1.38      mmcc      576:                memset(buf, 0, sizeof(buf));
1.1       tholo     577:                snprintf(buf, (sizeof(buf) - 1),
1.2       deraadt   578:                     "can't dereference kptr 0x%lx", (u_long)kptr);
1.1       tholo     579:                KVM_ERROR(buf);
                    580:        }
                    581: }
1.17      drahn     582: #endif /* !defined(NOKVM) */