[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.1

1.1     ! dlg         1: /* $OpenBSD$ */
        !             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>
        !            18: #include <stdio.h>
        !            19: #include <stdlib.h>
        !            20: #include <stddef.h>
        !            21: #include <string.h>
        !            22: #include <inttypes.h>
        !            23: #include <fcntl.h>
        !            24: #include <errno.h>
        !            25: #include <err.h>
        !            26: #include <vis.h>
        !            27:
        !            28: #include <sys/tree.h>
        !            29: #include <sys/ioctl.h>
        !            30: #include <sys/time.h>
        !            31:
        !            32: #include <sys/kstat.h>
        !            33:
        !            34: #ifndef roundup
        !            35: #define roundup(x, y)   ((((x)+((y)-1))/(y))*(y))
        !            36: #endif
        !            37:
        !            38: #define DEV_KSTAT "/dev/kstat"
        !            39:
        !            40: static void    kstat_list(int, unsigned int);
        !            41:
        !            42: #if 0
        !            43: __dead static void
        !            44: usage(void)
        !            45: {
        !            46:        extern char *__progname;
        !            47:        fprintf(stderr, "usage: %s\n", __progname);
        !            48:        exit(1);
        !            49: }
        !            50: #endif
        !            51:
        !            52: int
        !            53: main(int argc, char *argv[])
        !            54: {
        !            55:        unsigned int version;
        !            56:        int fd;
        !            57:
        !            58:        fd = open(DEV_KSTAT, O_RDONLY);
        !            59:        if (fd == -1)
        !            60:                err(1, "%s", DEV_KSTAT);
        !            61:
        !            62:        if (ioctl(fd, KSTATIOC_VERSION, &version) == -1)
        !            63:                err(1, "kstat version");
        !            64:
        !            65:        kstat_list(fd, version);
        !            66:
        !            67:        return (0);
        !            68: }
        !            69:
        !            70: struct kstat_entry {
        !            71:        struct kstat_req        kstat;
        !            72:        RBT_ENTRY(kstat_entry)  entry;
        !            73:        int                     serrno;
        !            74: };
        !            75:
        !            76: RBT_HEAD(kstat_tree, kstat_entry);
        !            77:
        !            78: static inline int
        !            79: kstat_cmp(const struct kstat_entry *ea, const struct kstat_entry *eb)
        !            80: {
        !            81:        const struct kstat_req *a = &ea->kstat;
        !            82:        const struct kstat_req *b = &eb->kstat;
        !            83:        int rv;
        !            84:
        !            85:        rv = strncmp(a->ks_provider, b->ks_provider, sizeof(a->ks_provider));
        !            86:        if (rv != 0)
        !            87:                return (rv);
        !            88:        if (a->ks_instance > b->ks_instance)
        !            89:                return (1);
        !            90:        if (a->ks_instance < b->ks_instance)
        !            91:                return (-1);
        !            92:
        !            93:        rv = strncmp(a->ks_name, b->ks_name, sizeof(a->ks_name));
        !            94:        if (rv != 0)
        !            95:                return (rv);
        !            96:        if (a->ks_unit > b->ks_unit)
        !            97:                return (1);
        !            98:        if (a->ks_unit < b->ks_unit)
        !            99:                return (-1);
        !           100:
        !           101:        return (0);
        !           102: }
        !           103:
        !           104: RBT_PROTOTYPE(kstat_tree, kstat_entry, entry, kstat_cmp);
        !           105: RBT_GENERATE(kstat_tree, kstat_entry, entry, kstat_cmp);
        !           106:
        !           107: static int
        !           108: printable(int ch)
        !           109: {
        !           110:        if (ch == '\0')
        !           111:                return ('_');
        !           112:        if (!isprint(ch))
        !           113:                return ('~');
        !           114:        return (ch);
        !           115: }
        !           116:
        !           117: static void
        !           118: hexdump(const void *d, size_t datalen)
        !           119: {
        !           120:        const uint8_t *data = d;
        !           121:        size_t i, j = 0;
        !           122:
        !           123:        for (i = 0; i < datalen; i += j) {
        !           124:                printf("%4zu: ", i);
        !           125:
        !           126:                for (j = 0; j < 16 && i+j < datalen; j++)
        !           127:                        printf("%02x ", data[i + j]);
        !           128:                while (j++ < 16)
        !           129:                        printf("   ");
        !           130:                printf("|");
        !           131:
        !           132:                for (j = 0; j < 16 && i+j < datalen; j++)
        !           133:                        putchar(printable(data[i + j]));
        !           134:                printf("|\n");
        !           135:        }
        !           136: }
        !           137:
        !           138: static void
        !           139: strdump(const void *s, size_t len)
        !           140: {
        !           141:        const char *str = s;
        !           142:        char dst[8];
        !           143:        size_t i;
        !           144:
        !           145:        for (i = 0; i < len; i++) {
        !           146:                char ch = str[i];
        !           147:                if (ch == '\0')
        !           148:                        break;
        !           149:
        !           150:                vis(dst, ch, VIS_TAB | VIS_NL, 0);
        !           151:                printf("%s", dst);
        !           152:        }
        !           153: }
        !           154:
        !           155: static void
        !           156: strdumpnl(const void *s, size_t len)
        !           157: {
        !           158:        strdump(s, len);
        !           159:        printf("\n");
        !           160: }
        !           161:
        !           162: static void
        !           163: kstat_kv(const void *d, ssize_t len)
        !           164: {
        !           165:        const uint8_t *buf;
        !           166:        const struct kstat_kv *kv;
        !           167:        ssize_t blen;
        !           168:        void (*trailer)(const void *, size_t);
        !           169:        double f;
        !           170:
        !           171:        if (len < (ssize_t)sizeof(*kv)) {
        !           172:                warn("short kv (len %zu < size %zu)", len, sizeof(*kv));
        !           173:                return;
        !           174:        }
        !           175:
        !           176:        buf = d;
        !           177:        do {
        !           178:                kv = (const struct kstat_kv *)buf;
        !           179:
        !           180:                buf += sizeof(*kv);
        !           181:                len -= sizeof(*kv);
        !           182:
        !           183:                blen = 0;
        !           184:                trailer = hexdump;
        !           185:
        !           186:                printf("%16.16s: ", kv->kv_key);
        !           187:
        !           188:                switch (kv->kv_type) {
        !           189:                case KSTAT_KV_T_NULL:
        !           190:                        printf("null");
        !           191:                        break;
        !           192:                case KSTAT_KV_T_BOOL:
        !           193:                        printf("%s", kstat_kv_bool(kv) ? "true" : "false");
        !           194:                        break;
        !           195:                case KSTAT_KV_T_COUNTER64:
        !           196:                case KSTAT_KV_T_UINT64:
        !           197:                        printf("%" PRIu64, kstat_kv_u64(kv));
        !           198:                        break;
        !           199:                case KSTAT_KV_T_INT64:
        !           200:                        printf("%" PRId64, kstat_kv_s64(kv));
        !           201:                        break;
        !           202:                case KSTAT_KV_T_COUNTER32:
        !           203:                case KSTAT_KV_T_UINT32:
        !           204:                        printf("%" PRIu32, kstat_kv_u32(kv));
        !           205:                        break;
        !           206:                case KSTAT_KV_T_INT32:
        !           207:                        printf("%" PRId32, kstat_kv_s32(kv));
        !           208:                        break;
        !           209:                case KSTAT_KV_T_STR:
        !           210:                        blen = kstat_kv_len(kv);
        !           211:                        trailer = strdumpnl;
        !           212:                        break;
        !           213:                case KSTAT_KV_T_BYTES:
        !           214:                        blen = kstat_kv_len(kv);
        !           215:                        trailer = hexdump;
        !           216:
        !           217:                        printf("\n");
        !           218:                        break;
        !           219:
        !           220:                case KSTAT_KV_T_ISTR:
        !           221:                        strdump(kstat_kv_istr(kv), sizeof(kstat_kv_istr(kv)));
        !           222:                        break;
        !           223:
        !           224:                case KSTAT_KV_T_TEMP:
        !           225:                        f = kstat_kv_temp(kv);
        !           226:                        printf("%.2f degC", (f - 273150000.0) / 1000000.0);
        !           227:                        break;
        !           228:
        !           229:                default:
        !           230:                        printf("unknown type %u, stopping\n", kv->kv_type);
        !           231:                        return;
        !           232:                }
        !           233:
        !           234:                switch (kv->kv_unit) {
        !           235:                case KSTAT_KV_U_NONE:
        !           236:                        break;
        !           237:                case KSTAT_KV_U_PACKETS:
        !           238:                        printf(" packets");
        !           239:                        break;
        !           240:                case KSTAT_KV_U_BYTES:
        !           241:                        printf(" bytes");
        !           242:                        break;
        !           243:                case KSTAT_KV_U_CYCLES:
        !           244:                        printf(" cycles");
        !           245:                        break;
        !           246:
        !           247:                default:
        !           248:                        printf(" unit-type-%u", kv->kv_unit);
        !           249:                        break;
        !           250:                }
        !           251:
        !           252:                if (blen > 0) {
        !           253:                        if (blen > len) {
        !           254:                                blen = len;
        !           255:                        }
        !           256:
        !           257:                        (*trailer)(buf, blen);
        !           258:                } else
        !           259:                        printf("\n");
        !           260:
        !           261:                blen = roundup(blen, KSTAT_KV_ALIGN);
        !           262:                buf += blen;
        !           263:                len -= blen;
        !           264:        } while (len >= (ssize_t)sizeof(*kv));
        !           265: }
        !           266:
        !           267: static void
        !           268: kstat_list(int fd, unsigned int version)
        !           269: {
        !           270:        struct kstat_entry *kse;
        !           271:        struct kstat_req *ksreq;
        !           272:        size_t len;
        !           273:        uint64_t id = 0;
        !           274:        struct kstat_tree kstat_tree = RBT_INITIALIZER();
        !           275:
        !           276:        for (;;) {
        !           277:                kse = malloc(sizeof(*kse));
        !           278:                if (kse == NULL)
        !           279:                        err(1, NULL);
        !           280:
        !           281:                memset(kse, 0, sizeof(*kse));
        !           282:                ksreq = &kse->kstat;
        !           283:                ksreq->ks_version = version;
        !           284:                ksreq->ks_id = ++id;
        !           285:
        !           286:                ksreq->ks_datalen = len = 64; /* magic */
        !           287:                ksreq->ks_data = malloc(len);
        !           288:                if (ksreq->ks_data == NULL)
        !           289:                        err(1, "data alloc");
        !           290:
        !           291:                if (ioctl(fd, KSTATIOC_NFIND_ID, ksreq) == -1) {
        !           292:                        if (errno == ENOENT) {
        !           293:                                free(ksreq->ks_data);
        !           294:                                free(kse);
        !           295:                                break;
        !           296:                        }
        !           297:
        !           298:                        kse->serrno = errno;
        !           299:                        goto next;
        !           300:                }
        !           301:
        !           302:                while (ksreq->ks_datalen > len) {
        !           303:                        len = ksreq->ks_datalen;
        !           304:                        ksreq->ks_data = realloc(ksreq->ks_data, len);
        !           305:                        if (ksreq->ks_data == NULL)
        !           306:                                err(1, "data resize (%zu)", len);
        !           307:
        !           308:                        if (ioctl(fd, KSTATIOC_FIND_ID, ksreq) == -1)
        !           309:                                err(1, "find id %llu", id);
        !           310:                }
        !           311:
        !           312: next:
        !           313:                if (RBT_INSERT(kstat_tree, &kstat_tree, kse) != NULL)
        !           314:                        errx(1, "duplicate kstat entry");
        !           315:
        !           316:                id = ksreq->ks_id;
        !           317:        }
        !           318:
        !           319:        RBT_FOREACH(kse, kstat_tree, &kstat_tree) {
        !           320:                ksreq = &kse->kstat;
        !           321:                printf("%s:%u:%s:%u\n",
        !           322:                    ksreq->ks_provider, ksreq->ks_instance,
        !           323:                    ksreq->ks_name, ksreq->ks_unit);
        !           324:                if (kse->serrno != 0) {
        !           325:                        printf("\t%s\n", strerror(kse->serrno));
        !           326:                        continue;
        !           327:                }
        !           328:                switch (ksreq->ks_type) {
        !           329:                case KSTAT_T_RAW:
        !           330:                        hexdump(ksreq->ks_data, ksreq->ks_datalen);
        !           331:                        break;
        !           332:                case KSTAT_T_KV:
        !           333:                        kstat_kv(ksreq->ks_data, ksreq->ks_datalen);
        !           334:                        break;
        !           335:                default:
        !           336:                        hexdump(ksreq->ks_data, ksreq->ks_datalen);
        !           337:                        break;
        !           338:                }
        !           339:        }
        !           340: }