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

Annotation of src/usr.bin/kstat/kstat.c, Revision 1.12

1.12    ! dlg         1: /* $OpenBSD: kstat.c,v 1.11 2022/07/10 19:51:37 kn Exp $ */
1.1       dlg         2:
                      3: /*
                      4:  * Copyright (c) 2020 David Gwynne <dlg@openbsd.org>
                      5:  * Permission to use, copy, modify, and distribute this software for any
                      6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
                      8:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                      9:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     10:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     11:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     12:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     13:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     14:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     15:  */
                     16:
                     17: #include <ctype.h>
1.10      cheloha    18: #include <limits.h>
                     19: #include <signal.h>
1.1       dlg        20: #include <stdio.h>
                     21: #include <stdlib.h>
                     22: #include <stddef.h>
                     23: #include <string.h>
                     24: #include <inttypes.h>
1.2       dlg        25: #include <fnmatch.h>
1.1       dlg        26: #include <fcntl.h>
1.3       dlg        27: #include <unistd.h>
1.1       dlg        28: #include <errno.h>
                     29: #include <err.h>
                     30: #include <vis.h>
                     31:
                     32: #include <sys/tree.h>
                     33: #include <sys/ioctl.h>
                     34: #include <sys/time.h>
1.2       dlg        35: #include <sys/queue.h>
1.1       dlg        36:
                     37: #include <sys/kstat.h>
                     38:
                     39: #ifndef roundup
1.2       dlg        40: #define roundup(x, y)          ((((x)+((y)-1))/(y))*(y))
1.1       dlg        41: #endif
                     42:
1.2       dlg        43: #ifndef nitems
                     44: #define nitems(_a)             (sizeof((_a)) / sizeof((_a)[0]))
                     45: #endif
                     46:
                     47: #ifndef ISSET
                     48: #define ISSET(_i, _m)          ((_i) & (_m))
                     49: #endif
                     50:
                     51: #ifndef SET
                     52: #define SET(_i, _m)            ((_i) |= (_m))
                     53: #endif
                     54:
1.12    ! dlg        55: struct fmt_result {
        !            56:        uint64_t                val;
        !            57:        unsigned int            frac;
        !            58:        unsigned int            exp;
        !            59: };
        !            60:
        !            61: static void
        !            62: fmt_thing(struct fmt_result *fr, uint64_t val, uint64_t chunk)
        !            63: {
        !            64:        unsigned int exp = 0;
        !            65:        uint64_t rem = 0;
        !            66:
        !            67:        while (val > chunk) {
        !            68:                rem = val % chunk;
        !            69:                val /= chunk;
        !            70:                exp++;
        !            71:        }
        !            72:
        !            73:        fr->val = val;
        !            74:        fr->exp = exp;
        !            75:        fr->frac = (rem * 1000) / chunk;
        !            76: }
        !            77:
1.2       dlg        78: #define str_is_empty(_str)     (*(_str) == '\0')
                     79:
1.1       dlg        80: #define DEV_KSTAT "/dev/kstat"
                     81:
1.2       dlg        82: struct kstat_filter {
                     83:        TAILQ_ENTRY(kstat_filter)        kf_entry;
                     84:        const char                      *kf_provider;
                     85:        const char                      *kf_name;
                     86:        unsigned int                     kf_flags;
                     87: #define KSTAT_FILTER_F_INST                    (1 << 0)
                     88: #define KSTAT_FILTER_F_UNIT                    (1 << 1)
                     89:        unsigned int                     kf_instance;
                     90:        unsigned int                     kf_unit;
                     91: };
                     92:
                     93: TAILQ_HEAD(kstat_filters, kstat_filter);
                     94:
1.4       dlg        95: struct kstat_entry {
                     96:        struct kstat_req        kstat;
                     97:        RBT_ENTRY(kstat_entry)  entry;
                     98:        int                     serrno;
                     99: };
                    100:
                    101: RBT_HEAD(kstat_tree, kstat_entry);
                    102:
                    103: static inline int
                    104: kstat_cmp(const struct kstat_entry *ea, const struct kstat_entry *eb)
                    105: {
                    106:        const struct kstat_req *a = &ea->kstat;
                    107:        const struct kstat_req *b = &eb->kstat;
                    108:        int rv;
                    109:
                    110:        rv = strncmp(a->ks_provider, b->ks_provider, sizeof(a->ks_provider));
                    111:        if (rv != 0)
                    112:                return (rv);
                    113:        if (a->ks_instance > b->ks_instance)
                    114:                return (1);
                    115:        if (a->ks_instance < b->ks_instance)
                    116:                return (-1);
                    117:
                    118:        rv = strncmp(a->ks_name, b->ks_name, sizeof(a->ks_name));
                    119:        if (rv != 0)
                    120:                return (rv);
                    121:        if (a->ks_unit > b->ks_unit)
                    122:                return (1);
                    123:        if (a->ks_unit < b->ks_unit)
                    124:                return (-1);
                    125:
                    126:        return (0);
                    127: }
                    128:
                    129: RBT_PROTOTYPE(kstat_tree, kstat_entry, entry, kstat_cmp);
                    130: RBT_GENERATE(kstat_tree, kstat_entry, entry, kstat_cmp);
                    131:
1.10      cheloha   132: static void handle_alrm(int);
1.2       dlg       133: static struct kstat_filter *
                    134:                kstat_filter_parse(char *);
                    135: static int     kstat_filter_entry(struct kstat_filters *,
                    136:                    const struct kstat_req *);
                    137:
1.3       dlg       138: static void    kstat_list(struct kstat_tree *, int, unsigned int,
                    139:                    struct kstat_filters *);
                    140: static void    kstat_print(struct kstat_tree *);
1.5       dlg       141: static void    kstat_read(struct kstat_tree *, int);
1.1       dlg       142:
                    143: __dead static void
                    144: usage(void)
                    145: {
                    146:        extern char *__progname;
1.2       dlg       147:
1.5       dlg       148:        fprintf(stderr, "usage: %s [-w wait] "
1.11      kn        149:            "[name | provider:instance:name:unit] ...\n", __progname);
1.2       dlg       150:
1.1       dlg       151:        exit(1);
                    152: }
                    153:
                    154: int
                    155: main(int argc, char *argv[])
                    156: {
1.2       dlg       157:        struct kstat_filters kfs = TAILQ_HEAD_INITIALIZER(kfs);
1.3       dlg       158:        struct kstat_tree kt = RBT_INITIALIZER();
1.1       dlg       159:        unsigned int version;
                    160:        int fd;
1.5       dlg       161:        const char *errstr;
                    162:        int ch;
1.10      cheloha   163:        struct itimerval itv;
                    164:        sigset_t empty, mask;
1.2       dlg       165:        int i;
1.10      cheloha   166:        unsigned int wait = 0;
1.2       dlg       167:
1.5       dlg       168:        while ((ch = getopt(argc, argv, "w:")) != -1) {
                    169:                switch (ch) {
                    170:                case 'w':
1.10      cheloha   171:                        wait = strtonum(optarg, 1, UINT_MAX, &errstr);
1.5       dlg       172:                        if (errstr != NULL)
1.10      cheloha   173:                                errx(1, "wait is %s: %s", errstr, optarg);
1.5       dlg       174:                        break;
                    175:                default:
                    176:                        usage();
                    177:                }
                    178:        }
                    179:
                    180:        argc -= optind;
                    181:        argv += optind;
                    182:
                    183:        for (i = 0; i < argc; i++) {
1.2       dlg       184:                struct kstat_filter *kf = kstat_filter_parse(argv[i]);
                    185:                TAILQ_INSERT_TAIL(&kfs, kf, kf_entry);
                    186:        }
1.1       dlg       187:
                    188:        fd = open(DEV_KSTAT, O_RDONLY);
                    189:        if (fd == -1)
                    190:                err(1, "%s", DEV_KSTAT);
                    191:
                    192:        if (ioctl(fd, KSTATIOC_VERSION, &version) == -1)
                    193:                err(1, "kstat version");
                    194:
1.3       dlg       195:        kstat_list(&kt, fd, version, &kfs);
                    196:        kstat_print(&kt);
1.2       dlg       197:
1.10      cheloha   198:        if (wait == 0)
1.5       dlg       199:                return (0);
                    200:
1.10      cheloha   201:        if (signal(SIGALRM, handle_alrm) == SIG_ERR)
                    202:                err(1, "signal");
                    203:        sigemptyset(&empty);
                    204:        sigemptyset(&mask);
                    205:        sigaddset(&mask, SIGALRM);
                    206:        if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
                    207:                err(1, "sigprocmask");
                    208:
                    209:        itv.it_value.tv_sec = wait;
                    210:        itv.it_value.tv_usec = 0;
                    211:        itv.it_interval = itv.it_value;
                    212:        if (setitimer(ITIMER_REAL, &itv, NULL) == -1)
                    213:                err(1, "setitimer");
                    214:
1.5       dlg       215:        for (;;) {
1.10      cheloha   216:                sigsuspend(&empty);
1.5       dlg       217:                kstat_read(&kt, fd);
                    218:                kstat_print(&kt);
                    219:        }
                    220:
1.2       dlg       221:        return (0);
                    222: }
                    223:
                    224: static struct kstat_filter *
                    225: kstat_filter_parse(char *arg)
                    226: {
                    227:        struct kstat_filter *kf;
                    228:        const char *errstr;
                    229:        char *argv[4];
                    230:        size_t argc;
                    231:
                    232:        for (argc = 0; argc < nitems(argv); argc++) {
                    233:                char *s = strsep(&arg, ":");
                    234:                if (s == NULL)
                    235:                        break;
                    236:
                    237:                argv[argc] = s;
                    238:        }
                    239:        if (arg != NULL)
                    240:                usage();
                    241:
                    242:        kf = malloc(sizeof(*kf));
                    243:        if (kf == NULL)
                    244:                err(1, NULL);
                    245:
                    246:        memset(kf, 0, sizeof(*kf));
                    247:
                    248:        switch (argc) {
                    249:        case 1:
                    250:                if (str_is_empty(argv[0]))
                    251:                        errx(1, "empty name");
                    252:
                    253:                kf->kf_name = argv[0];
                    254:                break;
                    255:        case 4:
                    256:                if (!str_is_empty(argv[0]))
                    257:                        kf->kf_provider = argv[0];
                    258:                if (!str_is_empty(argv[1])) {
                    259:                        kf->kf_instance =
                    260:                            strtonum(argv[1], 0, 0xffffffffU, &errstr);
                    261:                        if (errstr != NULL) {
                    262:                                errx(1, "%s:%s:%s:%s: instance %s: %s",
                    263:                                    argv[0], argv[1], argv[2], argv[3],
                    264:                                    argv[1], errstr);
                    265:                        }
                    266:                        SET(kf->kf_flags, KSTAT_FILTER_F_INST);
                    267:                }
                    268:                if (!str_is_empty(argv[2]))
                    269:                        kf->kf_name = argv[2];
                    270:                if (!str_is_empty(argv[3])) {
                    271:                        kf->kf_unit =
                    272:                            strtonum(argv[3], 0, 0xffffffffU, &errstr);
                    273:                        if (errstr != NULL) {
1.8       dlg       274:                                errx(1, "%s:%s:%s:%s: unit %s: %s",
1.2       dlg       275:                                    argv[0], argv[1], argv[2], argv[3],
1.8       dlg       276:                                    argv[3], errstr);
1.2       dlg       277:                        }
1.8       dlg       278:                        SET(kf->kf_flags, KSTAT_FILTER_F_UNIT);
1.2       dlg       279:                }
                    280:                break;
                    281:        default:
                    282:                usage();
                    283:        }
                    284:
                    285:        return (kf);
                    286: }
                    287:
                    288: static int
                    289: kstat_filter_entry(struct kstat_filters *kfs, const struct kstat_req *ksreq)
                    290: {
                    291:        struct kstat_filter *kf;
                    292:
                    293:        if (TAILQ_EMPTY(kfs))
                    294:                return (1);
                    295:
                    296:        TAILQ_FOREACH(kf, kfs, kf_entry) {
                    297:                if (kf->kf_provider != NULL) {
                    298:                        if (fnmatch(kf->kf_provider, ksreq->ks_provider,
                    299:                            FNM_NOESCAPE | FNM_LEADING_DIR) == FNM_NOMATCH)
                    300:                                continue;
                    301:                }
                    302:                if (ISSET(kf->kf_flags, KSTAT_FILTER_F_INST)) {
                    303:                        if (kf->kf_instance != ksreq->ks_instance)
                    304:                                continue;
                    305:                }
                    306:                if (kf->kf_name != NULL) {
                    307:                        if (fnmatch(kf->kf_name, ksreq->ks_name,
                    308:                            FNM_NOESCAPE | FNM_LEADING_DIR) == FNM_NOMATCH)
                    309:                                continue;
                    310:                }
                    311:                if (ISSET(kf->kf_flags, KSTAT_FILTER_F_UNIT)) {
                    312:                        if (kf->kf_unit != ksreq->ks_unit)
                    313:                                continue;
                    314:                }
                    315:
                    316:                return (1);
                    317:        }
1.1       dlg       318:
                    319:        return (0);
                    320: }
                    321:
                    322: static int
                    323: printable(int ch)
                    324: {
                    325:        if (ch == '\0')
                    326:                return ('_');
                    327:        if (!isprint(ch))
                    328:                return ('~');
                    329:        return (ch);
                    330: }
                    331:
                    332: static void
                    333: hexdump(const void *d, size_t datalen)
                    334: {
                    335:        const uint8_t *data = d;
                    336:        size_t i, j = 0;
                    337:
                    338:        for (i = 0; i < datalen; i += j) {
                    339:                printf("%4zu: ", i);
                    340:
                    341:                for (j = 0; j < 16 && i+j < datalen; j++)
                    342:                        printf("%02x ", data[i + j]);
                    343:                while (j++ < 16)
                    344:                        printf("   ");
                    345:                printf("|");
                    346:
                    347:                for (j = 0; j < 16 && i+j < datalen; j++)
                    348:                        putchar(printable(data[i + j]));
                    349:                printf("|\n");
                    350:        }
                    351: }
                    352:
                    353: static void
                    354: strdump(const void *s, size_t len)
                    355: {
                    356:        const char *str = s;
                    357:        char dst[8];
                    358:        size_t i;
                    359:
                    360:        for (i = 0; i < len; i++) {
                    361:                char ch = str[i];
                    362:                if (ch == '\0')
                    363:                        break;
                    364:
                    365:                vis(dst, ch, VIS_TAB | VIS_NL, 0);
                    366:                printf("%s", dst);
                    367:        }
                    368: }
                    369:
                    370: static void
                    371: strdumpnl(const void *s, size_t len)
                    372: {
                    373:        strdump(s, len);
                    374:        printf("\n");
                    375: }
                    376:
1.12    ! dlg       377: static const char *si_prefixes[] = { "", "k", "M", "G", "T", "P", "E" };
        !           378: #ifdef notyet
        !           379: static const char *iec_prefixes[] = { "", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei" };
        !           380: #endif
        !           381:
1.1       dlg       382: static void
                    383: kstat_kv(const void *d, ssize_t len)
                    384: {
                    385:        const uint8_t *buf;
                    386:        const struct kstat_kv *kv;
                    387:        ssize_t blen;
                    388:        void (*trailer)(const void *, size_t);
                    389:        double f;
1.12    ! dlg       390:        struct fmt_result fr;
1.1       dlg       391:
                    392:        if (len < (ssize_t)sizeof(*kv)) {
                    393:                warn("short kv (len %zu < size %zu)", len, sizeof(*kv));
                    394:                return;
                    395:        }
                    396:
                    397:        buf = d;
                    398:        do {
                    399:                kv = (const struct kstat_kv *)buf;
                    400:
                    401:                buf += sizeof(*kv);
                    402:                len -= sizeof(*kv);
                    403:
                    404:                blen = 0;
                    405:                trailer = hexdump;
                    406:
                    407:                printf("%16.16s: ", kv->kv_key);
                    408:
                    409:                switch (kv->kv_type) {
                    410:                case KSTAT_KV_T_NULL:
                    411:                        printf("null");
                    412:                        break;
                    413:                case KSTAT_KV_T_BOOL:
                    414:                        printf("%s", kstat_kv_bool(kv) ? "true" : "false");
                    415:                        break;
                    416:                case KSTAT_KV_T_COUNTER64:
                    417:                case KSTAT_KV_T_UINT64:
                    418:                        printf("%" PRIu64, kstat_kv_u64(kv));
                    419:                        break;
                    420:                case KSTAT_KV_T_INT64:
                    421:                        printf("%" PRId64, kstat_kv_s64(kv));
                    422:                        break;
                    423:                case KSTAT_KV_T_COUNTER32:
                    424:                case KSTAT_KV_T_UINT32:
                    425:                        printf("%" PRIu32, kstat_kv_u32(kv));
                    426:                        break;
                    427:                case KSTAT_KV_T_INT32:
                    428:                        printf("%" PRId32, kstat_kv_s32(kv));
1.9       dlg       429:                        break;
                    430:                case KSTAT_KV_T_COUNTER16:
                    431:                case KSTAT_KV_T_UINT16:
                    432:                        printf("%" PRIu16, kstat_kv_u16(kv));
                    433:                        break;
                    434:                case KSTAT_KV_T_INT16:
                    435:                        printf("%" PRId16, kstat_kv_s16(kv));
1.1       dlg       436:                        break;
                    437:                case KSTAT_KV_T_STR:
                    438:                        blen = kstat_kv_len(kv);
                    439:                        trailer = strdumpnl;
                    440:                        break;
                    441:                case KSTAT_KV_T_BYTES:
                    442:                        blen = kstat_kv_len(kv);
                    443:                        trailer = hexdump;
                    444:
                    445:                        printf("\n");
                    446:                        break;
                    447:
                    448:                case KSTAT_KV_T_ISTR:
                    449:                        strdump(kstat_kv_istr(kv), sizeof(kstat_kv_istr(kv)));
                    450:                        break;
                    451:
                    452:                case KSTAT_KV_T_TEMP:
                    453:                        f = kstat_kv_temp(kv);
                    454:                        printf("%.2f degC", (f - 273150000.0) / 1000000.0);
1.12    ! dlg       455:                        break;
        !           456:
        !           457:                case KSTAT_KV_T_FREQ:
        !           458:                        fmt_thing(&fr, kstat_kv_freq(kv), 1000);
        !           459:                        printf("%llu", fr.val);
        !           460:                        if (fr.frac > 10)
        !           461:                                printf(".%02u", fr.frac / 10);
        !           462:                        printf(" %sHz", si_prefixes[fr.exp]);
        !           463:                        break;
        !           464:
        !           465:                case KSTAT_KV_T_VOLTS_DC: /* uV */
        !           466:                        f = kstat_kv_volts(kv);
        !           467:                        printf("%.2f VDC", f / 1000000.0);
        !           468:                        break;
        !           469:
        !           470:                case KSTAT_KV_T_VOLTS_AC: /* uV */
        !           471:                        f = kstat_kv_volts(kv);
        !           472:                        printf("%.2f VAC", f / 1000000.0);
1.1       dlg       473:                        break;
                    474:
                    475:                default:
                    476:                        printf("unknown type %u, stopping\n", kv->kv_type);
                    477:                        return;
                    478:                }
                    479:
                    480:                switch (kv->kv_unit) {
                    481:                case KSTAT_KV_U_NONE:
                    482:                        break;
                    483:                case KSTAT_KV_U_PACKETS:
                    484:                        printf(" packets");
                    485:                        break;
                    486:                case KSTAT_KV_U_BYTES:
                    487:                        printf(" bytes");
                    488:                        break;
                    489:                case KSTAT_KV_U_CYCLES:
                    490:                        printf(" cycles");
                    491:                        break;
                    492:
                    493:                default:
                    494:                        printf(" unit-type-%u", kv->kv_unit);
                    495:                        break;
                    496:                }
                    497:
                    498:                if (blen > 0) {
                    499:                        if (blen > len) {
                    500:                                blen = len;
                    501:                        }
                    502:
                    503:                        (*trailer)(buf, blen);
                    504:                } else
                    505:                        printf("\n");
                    506:
                    507:                blen = roundup(blen, KSTAT_KV_ALIGN);
                    508:                buf += blen;
                    509:                len -= blen;
                    510:        } while (len >= (ssize_t)sizeof(*kv));
                    511: }
                    512:
                    513: static void
1.3       dlg       514: kstat_list(struct kstat_tree *kt, int fd, unsigned int version,
                    515:     struct kstat_filters *kfs)
1.1       dlg       516: {
                    517:        struct kstat_entry *kse;
                    518:        struct kstat_req *ksreq;
                    519:        size_t len;
                    520:        uint64_t id = 0;
                    521:
                    522:        for (;;) {
                    523:                kse = malloc(sizeof(*kse));
                    524:                if (kse == NULL)
                    525:                        err(1, NULL);
                    526:
                    527:                memset(kse, 0, sizeof(*kse));
                    528:                ksreq = &kse->kstat;
                    529:                ksreq->ks_version = version;
                    530:                ksreq->ks_id = ++id;
                    531:
                    532:                ksreq->ks_datalen = len = 64; /* magic */
                    533:                ksreq->ks_data = malloc(len);
                    534:                if (ksreq->ks_data == NULL)
                    535:                        err(1, "data alloc");
                    536:
                    537:                if (ioctl(fd, KSTATIOC_NFIND_ID, ksreq) == -1) {
                    538:                        if (errno == ENOENT) {
                    539:                                free(ksreq->ks_data);
                    540:                                free(kse);
                    541:                                break;
                    542:                        }
                    543:
                    544:                        kse->serrno = errno;
1.2       dlg       545:                } else
                    546:                        id = ksreq->ks_id;
                    547:
                    548:                if (!kstat_filter_entry(kfs, ksreq)) {
                    549:                        free(ksreq->ks_data);
                    550:                        free(kse);
                    551:                        continue;
1.1       dlg       552:                }
                    553:
1.3       dlg       554:                if (RBT_INSERT(kstat_tree, kt, kse) != NULL)
1.2       dlg       555:                        errx(1, "duplicate kstat entry");
                    556:
                    557:                if (kse->serrno != 0)
                    558:                        continue;
                    559:
1.1       dlg       560:                while (ksreq->ks_datalen > len) {
                    561:                        len = ksreq->ks_datalen;
                    562:                        ksreq->ks_data = realloc(ksreq->ks_data, len);
                    563:                        if (ksreq->ks_data == NULL)
                    564:                                err(1, "data resize (%zu)", len);
                    565:
                    566:                        if (ioctl(fd, KSTATIOC_FIND_ID, ksreq) == -1)
1.2       dlg       567:                                err(1, "find id %llu", ksreq->ks_id);
1.1       dlg       568:                }
                    569:        }
1.3       dlg       570: }
                    571:
                    572: static void
                    573: kstat_print(struct kstat_tree *kt)
                    574: {
                    575:        struct kstat_entry *kse;
                    576:        struct kstat_req *ksreq;
1.1       dlg       577:
1.3       dlg       578:        RBT_FOREACH(kse, kstat_tree, kt) {
1.1       dlg       579:                ksreq = &kse->kstat;
                    580:                printf("%s:%u:%s:%u\n",
                    581:                    ksreq->ks_provider, ksreq->ks_instance,
                    582:                    ksreq->ks_name, ksreq->ks_unit);
                    583:                if (kse->serrno != 0) {
                    584:                        printf("\t%s\n", strerror(kse->serrno));
                    585:                        continue;
                    586:                }
                    587:                switch (ksreq->ks_type) {
                    588:                case KSTAT_T_RAW:
                    589:                        hexdump(ksreq->ks_data, ksreq->ks_datalen);
                    590:                        break;
                    591:                case KSTAT_T_KV:
                    592:                        kstat_kv(ksreq->ks_data, ksreq->ks_datalen);
                    593:                        break;
                    594:                default:
                    595:                        hexdump(ksreq->ks_data, ksreq->ks_datalen);
                    596:                        break;
                    597:                }
1.5       dlg       598:        }
1.7       dlg       599:
                    600:        fflush(stdout);
1.5       dlg       601: }
                    602:
                    603: static void
                    604: kstat_read(struct kstat_tree *kt, int fd)
                    605: {
                    606:        struct kstat_entry *kse;
                    607:        struct kstat_req *ksreq;
                    608:
                    609:        RBT_FOREACH(kse, kstat_tree, kt) {
                    610:                ksreq = &kse->kstat;
                    611:                if (ioctl(fd, KSTATIOC_FIND_ID, ksreq) == -1)
                    612:                        err(1, "update id %llu", ksreq->ks_id);
1.1       dlg       613:        }
1.10      cheloha   614: }
                    615:
                    616: static void
                    617: handle_alrm(int signo)
                    618: {
1.1       dlg       619: }