=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/kstat/kstat.c,v retrieving revision 1.1 retrieving revision 1.2 diff -c -r1.1 -r1.2 *** src/usr.bin/kstat/kstat.c 2020/07/06 07:09:50 1.1 --- src/usr.bin/kstat/kstat.c 2020/08/10 01:13:28 1.2 *************** *** 1,4 **** ! /* $OpenBSD: kstat.c,v 1.1 2020/07/06 07:09:50 dlg Exp $ */ /* * Copyright (c) 2020 David Gwynne --- 1,4 ---- ! /* $OpenBSD: kstat.c,v 1.2 2020/08/10 01:13:28 dlg Exp $ */ /* * Copyright (c) 2020 David Gwynne *************** *** 20,25 **** --- 20,26 ---- #include #include #include + #include #include #include #include *************** *** 28,60 **** #include #include #include #include #ifndef roundup ! #define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) #endif #define DEV_KSTAT "/dev/kstat" ! static void kstat_list(int, unsigned int); ! #if 0 __dead static void usage(void) { extern char *__progname; ! fprintf(stderr, "usage: %s\n", __progname); exit(1); } - #endif int main(int argc, char *argv[]) { unsigned int version; int fd; fd = open(DEV_KSTAT, O_RDONLY); if (fd == -1) err(1, "%s", DEV_KSTAT); --- 29,102 ---- #include #include #include + #include #include #ifndef roundup ! #define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) #endif + #ifndef nitems + #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) + #endif + + #ifndef ISSET + #define ISSET(_i, _m) ((_i) & (_m)) + #endif + + #ifndef SET + #define SET(_i, _m) ((_i) |= (_m)) + #endif + + #define str_is_empty(_str) (*(_str) == '\0') + #define DEV_KSTAT "/dev/kstat" ! struct kstat_filter { ! TAILQ_ENTRY(kstat_filter) kf_entry; ! const char *kf_provider; ! const char *kf_name; ! unsigned int kf_flags; ! #define KSTAT_FILTER_F_INST (1 << 0) ! #define KSTAT_FILTER_F_UNIT (1 << 1) ! unsigned int kf_instance; ! unsigned int kf_unit; ! }; ! TAILQ_HEAD(kstat_filters, kstat_filter); ! ! static struct kstat_filter * ! kstat_filter_parse(char *); ! static int kstat_filter_entry(struct kstat_filters *, ! const struct kstat_req *); ! ! static void kstat_list(int, unsigned int, struct kstat_filters *); ! __dead static void usage(void) { extern char *__progname; ! ! fprintf(stderr, "usage: %s [name|provider:0:name:unit ...]\n", ! __progname); ! exit(1); } int main(int argc, char *argv[]) { + struct kstat_filters kfs = TAILQ_HEAD_INITIALIZER(kfs); unsigned int version; int fd; + int i; + for (i = 1; i < argc; i++) { + struct kstat_filter *kf = kstat_filter_parse(argv[i]); + TAILQ_INSERT_TAIL(&kfs, kf, kf_entry); + } + fd = open(DEV_KSTAT, O_RDONLY); if (fd == -1) err(1, "%s", DEV_KSTAT); *************** *** 62,72 **** if (ioctl(fd, KSTATIOC_VERSION, &version) == -1) err(1, "kstat version"); ! kstat_list(fd, version); return (0); } struct kstat_entry { struct kstat_req kstat; RBT_ENTRY(kstat_entry) entry; --- 104,212 ---- if (ioctl(fd, KSTATIOC_VERSION, &version) == -1) err(1, "kstat version"); ! kstat_list(fd, version, &kfs); return (0); } + static struct kstat_filter * + kstat_filter_parse(char *arg) + { + struct kstat_filter *kf; + const char *errstr; + char *argv[4]; + size_t argc; + + for (argc = 0; argc < nitems(argv); argc++) { + char *s = strsep(&arg, ":"); + if (s == NULL) + break; + + argv[argc] = s; + } + if (arg != NULL) + usage(); + + kf = malloc(sizeof(*kf)); + if (kf == NULL) + err(1, NULL); + + memset(kf, 0, sizeof(*kf)); + + switch (argc) { + case 1: + if (str_is_empty(argv[0])) + errx(1, "empty name"); + + kf->kf_name = argv[0]; + break; + case 4: + if (!str_is_empty(argv[0])) + kf->kf_provider = argv[0]; + if (!str_is_empty(argv[1])) { + kf->kf_instance = + strtonum(argv[1], 0, 0xffffffffU, &errstr); + if (errstr != NULL) { + errx(1, "%s:%s:%s:%s: instance %s: %s", + argv[0], argv[1], argv[2], argv[3], + argv[1], errstr); + } + SET(kf->kf_flags, KSTAT_FILTER_F_INST); + } + if (!str_is_empty(argv[2])) + kf->kf_name = argv[2]; + if (!str_is_empty(argv[3])) { + kf->kf_unit = + strtonum(argv[3], 0, 0xffffffffU, &errstr); + if (errstr != NULL) { + errx(1, "%s:%s:%s:%s: instance %s: %s", + argv[0], argv[1], argv[2], argv[3], + argv[1], errstr); + } + SET(kf->kf_flags, KSTAT_FILTER_F_INST); + } + break; + default: + usage(); + } + + return (kf); + } + + static int + kstat_filter_entry(struct kstat_filters *kfs, const struct kstat_req *ksreq) + { + struct kstat_filter *kf; + + if (TAILQ_EMPTY(kfs)) + return (1); + + TAILQ_FOREACH(kf, kfs, kf_entry) { + if (kf->kf_provider != NULL) { + if (fnmatch(kf->kf_provider, ksreq->ks_provider, + FNM_NOESCAPE | FNM_LEADING_DIR) == FNM_NOMATCH) + continue; + } + if (ISSET(kf->kf_flags, KSTAT_FILTER_F_INST)) { + if (kf->kf_instance != ksreq->ks_instance) + continue; + } + if (kf->kf_name != NULL) { + if (fnmatch(kf->kf_name, ksreq->ks_name, + FNM_NOESCAPE | FNM_LEADING_DIR) == FNM_NOMATCH) + continue; + } + if (ISSET(kf->kf_flags, KSTAT_FILTER_F_UNIT)) { + if (kf->kf_unit != ksreq->ks_unit) + continue; + } + + return (1); + } + + return (0); + } + struct kstat_entry { struct kstat_req kstat; RBT_ENTRY(kstat_entry) entry; *************** *** 265,271 **** } static void ! kstat_list(int fd, unsigned int version) { struct kstat_entry *kse; struct kstat_req *ksreq; --- 405,411 ---- } static void ! kstat_list(int fd, unsigned int version, struct kstat_filters *kfs) { struct kstat_entry *kse; struct kstat_req *ksreq; *************** *** 296,304 **** } kse->serrno = errno; ! goto next; } while (ksreq->ks_datalen > len) { len = ksreq->ks_datalen; ksreq->ks_data = realloc(ksreq->ks_data, len); --- 436,456 ---- } kse->serrno = errno; ! } else ! id = ksreq->ks_id; ! ! if (!kstat_filter_entry(kfs, ksreq)) { ! free(ksreq->ks_data); ! free(kse); ! continue; } + if (RBT_INSERT(kstat_tree, &kstat_tree, kse) != NULL) + errx(1, "duplicate kstat entry"); + + if (kse->serrno != 0) + continue; + while (ksreq->ks_datalen > len) { len = ksreq->ks_datalen; ksreq->ks_data = realloc(ksreq->ks_data, len); *************** *** 306,319 **** err(1, "data resize (%zu)", len); if (ioctl(fd, KSTATIOC_FIND_ID, ksreq) == -1) ! err(1, "find id %llu", id); } - - next: - if (RBT_INSERT(kstat_tree, &kstat_tree, kse) != NULL) - errx(1, "duplicate kstat entry"); - - id = ksreq->ks_id; } RBT_FOREACH(kse, kstat_tree, &kstat_tree) { --- 458,465 ---- err(1, "data resize (%zu)", len); if (ioctl(fd, KSTATIOC_FIND_ID, ksreq) == -1) ! err(1, "find id %llu", ksreq->ks_id); } } RBT_FOREACH(kse, kstat_tree, &kstat_tree) {