Bug Summary

File:src/usr.bin/kstat/kstat.c
Warning:line 196, column 2
Potential leak of memory pointed to by 'kfs.tqh_first'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name kstat.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/kstat/obj -resource-dir /usr/local/llvm16/lib/clang/16 -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/kstat/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fno-jump-tables -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/scan/2024-01-11-140451-98009-1 -x c /usr/src/usr.bin/kstat/kstat.c
1/* $OpenBSD: kstat.c,v 1.13 2023/11/16 03:17:34 dlg Exp $ */
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 <limits.h>
19#include <signal.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <stddef.h>
23#include <string.h>
24#include <inttypes.h>
25#include <fnmatch.h>
26#include <fcntl.h>
27#include <unistd.h>
28#include <errno(*__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>
35#include <sys/queue.h>
36
37#include <sys/kstat.h>
38
39#ifndef roundup
40#define roundup(x, y)((((x)+((y)-1))/(y))*(y)) ((((x)+((y)-1))/(y))*(y))
41#endif
42
43#ifndef nitems
44#define nitems(_a)(sizeof((_a)) / sizeof((_a)[0])) (sizeof((_a)) / sizeof((_a)[0]))
45#endif
46
47#ifndef ISSET
48#define ISSET(_i, _m)((_i) & (_m)) ((_i) & (_m))
49#endif
50
51#ifndef SET
52#define SET(_i, _m)((_i) |= (_m)) ((_i) |= (_m))
53#endif
54
55struct fmt_result {
56 uint64_t val;
57 unsigned int frac;
58 unsigned int exp;
59};
60
61static void
62fmt_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
78#define str_is_empty(_str)(*(_str) == '\0') (*(_str) == '\0')
79
80#define DEV_KSTAT"/dev/kstat" "/dev/kstat"
81
82struct kstat_filter {
83 TAILQ_ENTRY(kstat_filter)struct { struct kstat_filter *tqe_next; struct kstat_filter *
*tqe_prev; }
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) (1 << 0)
88#define KSTAT_FILTER_F_UNIT(1 << 1) (1 << 1)
89 unsigned int kf_instance;
90 unsigned int kf_unit;
91};
92
93TAILQ_HEAD(kstat_filters, kstat_filter)struct kstat_filters { struct kstat_filter *tqh_first; struct
kstat_filter **tqh_last; }
;
94
95struct kstat_entry {
96 struct kstat_req kstat;
97 RBT_ENTRY(kstat_entry)struct rb_entry entry;
98 int serrno;
99};
100
101RBT_HEAD(kstat_tree, kstat_entry)struct kstat_tree { struct rb_tree rbh_root; };
102
103static inline int
104kstat_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
129RBT_PROTOTYPE(kstat_tree, kstat_entry, entry, kstat_cmp)extern const struct rb_type *const kstat_tree_RBT_TYPE; __attribute__
((__unused__)) static inline void kstat_tree_RBT_INIT(struct kstat_tree
*head) { _rb_init(&head->rbh_root); } __attribute__((
__unused__)) static inline struct kstat_entry * kstat_tree_RBT_INSERT
(struct kstat_tree *head, struct kstat_entry *elm) { return _rb_insert
(kstat_tree_RBT_TYPE, &head->rbh_root, elm); } __attribute__
((__unused__)) static inline struct kstat_entry * kstat_tree_RBT_REMOVE
(struct kstat_tree *head, struct kstat_entry *elm) { return _rb_remove
(kstat_tree_RBT_TYPE, &head->rbh_root, elm); } __attribute__
((__unused__)) static inline struct kstat_entry * kstat_tree_RBT_FIND
(struct kstat_tree *head, const struct kstat_entry *key) { return
_rb_find(kstat_tree_RBT_TYPE, &head->rbh_root, key); }
__attribute__((__unused__)) static inline struct kstat_entry
* kstat_tree_RBT_NFIND(struct kstat_tree *head, const struct
kstat_entry *key) { return _rb_nfind(kstat_tree_RBT_TYPE, &
head->rbh_root, key); } __attribute__((__unused__)) static
inline struct kstat_entry * kstat_tree_RBT_ROOT(struct kstat_tree
*head) { return _rb_root(kstat_tree_RBT_TYPE, &head->
rbh_root); } __attribute__((__unused__)) static inline int kstat_tree_RBT_EMPTY
(struct kstat_tree *head) { return _rb_empty(&head->rbh_root
); } __attribute__((__unused__)) static inline struct kstat_entry
* kstat_tree_RBT_MIN(struct kstat_tree *head) { return _rb_min
(kstat_tree_RBT_TYPE, &head->rbh_root); } __attribute__
((__unused__)) static inline struct kstat_entry * kstat_tree_RBT_MAX
(struct kstat_tree *head) { return _rb_max(kstat_tree_RBT_TYPE
, &head->rbh_root); } __attribute__((__unused__)) static
inline struct kstat_entry * kstat_tree_RBT_NEXT(struct kstat_entry
*elm) { return _rb_next(kstat_tree_RBT_TYPE, elm); } __attribute__
((__unused__)) static inline struct kstat_entry * kstat_tree_RBT_PREV
(struct kstat_entry *elm) { return _rb_prev(kstat_tree_RBT_TYPE
, elm); } __attribute__((__unused__)) static inline struct kstat_entry
* kstat_tree_RBT_LEFT(struct kstat_entry *elm) { return _rb_left
(kstat_tree_RBT_TYPE, elm); } __attribute__((__unused__)) static
inline struct kstat_entry * kstat_tree_RBT_RIGHT(struct kstat_entry
*elm) { return _rb_right(kstat_tree_RBT_TYPE, elm); } __attribute__
((__unused__)) static inline struct kstat_entry * kstat_tree_RBT_PARENT
(struct kstat_entry *elm) { return _rb_parent(kstat_tree_RBT_TYPE
, elm); } __attribute__((__unused__)) static inline void kstat_tree_RBT_SET_LEFT
(struct kstat_entry *elm, struct kstat_entry *left) { _rb_set_left
(kstat_tree_RBT_TYPE, elm, left); } __attribute__((__unused__
)) static inline void kstat_tree_RBT_SET_RIGHT(struct kstat_entry
*elm, struct kstat_entry *right) { _rb_set_right(kstat_tree_RBT_TYPE
, elm, right); } __attribute__((__unused__)) static inline void
kstat_tree_RBT_SET_PARENT(struct kstat_entry *elm, struct kstat_entry
*parent) { _rb_set_parent(kstat_tree_RBT_TYPE, elm, parent);
} __attribute__((__unused__)) static inline void kstat_tree_RBT_POISON
(struct kstat_entry *elm, unsigned long poison) { _rb_poison(
kstat_tree_RBT_TYPE, elm, poison); } __attribute__((__unused__
)) static inline int kstat_tree_RBT_CHECK(struct kstat_entry *
elm, unsigned long poison) { return _rb_check(kstat_tree_RBT_TYPE
, elm, poison); }
;
130RBT_GENERATE(kstat_tree, kstat_entry, entry, kstat_cmp)static int kstat_tree_RBT_COMPARE(const void *lptr, const void
*rptr) { const struct kstat_entry *l = lptr, *r = rptr; return
kstat_cmp(l, r); } static const struct rb_type kstat_tree_RBT_INFO
= { kstat_tree_RBT_COMPARE, ((void *)0), __builtin_offsetof(
struct kstat_entry, entry), }; const struct rb_type *const kstat_tree_RBT_TYPE
= &kstat_tree_RBT_INFO
;
131
132static void handle_alrm(int);
133static struct kstat_filter *
134 kstat_filter_parse(char *);
135static int kstat_filter_entry(struct kstat_filters *,
136 const struct kstat_req *);
137
138static void kstat_list(struct kstat_tree *, int, unsigned int,
139 struct kstat_filters *);
140static void kstat_print(struct kstat_tree *);
141static void kstat_read(struct kstat_tree *, int);
142
143__dead__attribute__((__noreturn__)) static void
144usage(void)
145{
146 extern char *__progname;
147
148 fprintf(stderr(&__sF[2]), "usage: %s [-w wait] "
149 "[name | provider:instance:name:unit] ...\n", __progname);
150
151 exit(1);
152}
153
154int
155main(int argc, char *argv[])
156{
157 struct kstat_filters kfs = TAILQ_HEAD_INITIALIZER(kfs){ ((void *)0), &(kfs).tqh_first };
158 struct kstat_tree kt = RBT_INITIALIZER(){ { ((void *)0) } };
159 unsigned int version;
160 int fd;
161 const char *errstr;
162 int ch;
163 struct itimerval itv;
164 sigset_t empty, mask;
165 int i;
166 unsigned int wait = 0;
167
168 while ((ch = getopt(argc, argv, "w:")) != -1) {
1
Assuming the condition is false
2
Loop condition is false. Execution continues on line 180
169 switch (ch) {
170 case 'w':
171 wait = strtonum(optarg, 1, UINT_MAX0xffffffffU, &errstr);
172 if (errstr != NULL((void *)0))
173 errx(1, "wait is %s: %s", errstr, optarg);
174 break;
175 default:
176 usage();
177 }
178 }
179
180 argc -= optind;
181 argv += optind;
182
183 for (i = 0; i < argc; i++) {
3
Assuming 'i' is < 'argc'
4
Loop condition is true. Entering loop body
24
Assuming 'i' is >= 'argc'
25
Loop condition is false. Execution continues on line 188
184 struct kstat_filter *kf = kstat_filter_parse(argv[i]);
5
Calling 'kstat_filter_parse'
22
Returned allocated memory
185 TAILQ_INSERT_TAIL(&kfs, kf, kf_entry)do { (kf)->kf_entry.tqe_next = ((void *)0); (kf)->kf_entry
.tqe_prev = (&kfs)->tqh_last; *(&kfs)->tqh_last
= (kf); (&kfs)->tqh_last = &(kf)->kf_entry.tqe_next
; } while (0)
;
23
Loop condition is false. Exiting loop
186 }
187
188 fd = open(DEV_KSTAT"/dev/kstat", O_RDONLY0x0000);
189 if (fd == -1)
26
Assuming the condition is false
27
Taking false branch
190 err(1, "%s", DEV_KSTAT"/dev/kstat");
191
192 if (ioctl(fd, KSTATIOC_VERSION((unsigned long)0x40000000 | ((sizeof(unsigned int) & 0x1fff
) << 16) | ((('k')) << 8) | ((1)))
, &version) == -1
)
28
Assuming the condition is false
29
Taking false branch
193 err(1, "kstat version");
194
195 kstat_list(&kt, fd, version, &kfs);
196 kstat_read(&kt, fd);
30
Potential leak of memory pointed to by 'kfs.tqh_first'
197 kstat_print(&kt);
198
199 if (wait == 0)
200 return (0);
201
202 if (signal(SIGALRM14, handle_alrm) == SIG_ERR(void (*)(int))-1)
203 err(1, "signal");
204 sigemptyset(&empty);
205 sigemptyset(&mask);
206 sigaddset(&mask, SIGALRM14);
207 if (sigprocmask(SIG_BLOCK1, &mask, NULL((void *)0)) == -1)
208 err(1, "sigprocmask");
209
210 itv.it_value.tv_sec = wait;
211 itv.it_value.tv_usec = 0;
212 itv.it_interval = itv.it_value;
213 if (setitimer(ITIMER_REAL0, &itv, NULL((void *)0)) == -1)
214 err(1, "setitimer");
215
216 for (;;) {
217 sigsuspend(&empty);
218 kstat_read(&kt, fd);
219 kstat_print(&kt);
220 }
221
222 return (0);
223}
224
225static struct kstat_filter *
226kstat_filter_parse(char *arg)
227{
228 struct kstat_filter *kf;
229 const char *errstr;
230 char *argv[4];
231 size_t argc;
232
233 for (argc = 0; argc < nitems(argv)(sizeof((argv)) / sizeof((argv)[0])); argc++) {
6
Loop condition is true. Entering loop body
9
Loop condition is true. Entering loop body
234 char *s = strsep(&arg, ":");
235 if (s == NULL((void *)0))
7
Assuming 's' is not equal to NULL
8
Taking false branch
10
Assuming 's' is equal to NULL
11
Taking true branch
236 break;
237
238 argv[argc] = s;
239 }
240 if (arg != NULL((void *)0))
12
Execution continues on line 240
13
Assuming 'arg' is equal to NULL
14
Taking false branch
241 usage();
242
243 kf = malloc(sizeof(*kf));
15
Memory is allocated
244 if (kf == NULL((void *)0))
16
Assuming 'kf' is not equal to NULL
17
Taking false branch
245 err(1, NULL((void *)0));
246
247 memset(kf, 0, sizeof(*kf));
248
249 switch (argc) {
18
Control jumps to 'case 1:' at line 250
250 case 1:
251 if (str_is_empty(argv[0])(*(argv[0]) == '\0'))
19
Assuming the condition is false
20
Taking false branch
252 errx(1, "empty name");
253
254 kf->kf_name = argv[0];
255 break;
21
Execution continues on line 286
256 case 4:
257 if (!str_is_empty(argv[0])(*(argv[0]) == '\0'))
258 kf->kf_provider = argv[0];
259 if (!str_is_empty(argv[1])(*(argv[1]) == '\0')) {
260 kf->kf_instance =
261 strtonum(argv[1], 0, 0xffffffffU, &errstr);
262 if (errstr != NULL((void *)0)) {
263 errx(1, "%s:%s:%s:%s: instance %s: %s",
264 argv[0], argv[1], argv[2], argv[3],
265 argv[1], errstr);
266 }
267 SET(kf->kf_flags, KSTAT_FILTER_F_INST)((kf->kf_flags) |= ((1 << 0)));
268 }
269 if (!str_is_empty(argv[2])(*(argv[2]) == '\0'))
270 kf->kf_name = argv[2];
271 if (!str_is_empty(argv[3])(*(argv[3]) == '\0')) {
272 kf->kf_unit =
273 strtonum(argv[3], 0, 0xffffffffU, &errstr);
274 if (errstr != NULL((void *)0)) {
275 errx(1, "%s:%s:%s:%s: unit %s: %s",
276 argv[0], argv[1], argv[2], argv[3],
277 argv[3], errstr);
278 }
279 SET(kf->kf_flags, KSTAT_FILTER_F_UNIT)((kf->kf_flags) |= ((1 << 1)));
280 }
281 break;
282 default:
283 usage();
284 }
285
286 return (kf);
287}
288
289static int
290kstat_filter_entry(struct kstat_filters *kfs, const struct kstat_req *ksreq)
291{
292 struct kstat_filter *kf;
293
294 if (TAILQ_EMPTY(kfs)(((kfs)->tqh_first) == ((void *)0)))
295 return (1);
296
297 TAILQ_FOREACH(kf, kfs, kf_entry)for((kf) = ((kfs)->tqh_first); (kf) != ((void *)0); (kf) =
((kf)->kf_entry.tqe_next))
{
298 if (kf->kf_provider != NULL((void *)0)) {
299 if (fnmatch(kf->kf_provider, ksreq->ks_provider,
300 FNM_NOESCAPE0x01 | FNM_LEADING_DIR0x08) == FNM_NOMATCH1)
301 continue;
302 }
303 if (ISSET(kf->kf_flags, KSTAT_FILTER_F_INST)((kf->kf_flags) & ((1 << 0)))) {
304 if (kf->kf_instance != ksreq->ks_instance)
305 continue;
306 }
307 if (kf->kf_name != NULL((void *)0)) {
308 if (fnmatch(kf->kf_name, ksreq->ks_name,
309 FNM_NOESCAPE0x01 | FNM_LEADING_DIR0x08) == FNM_NOMATCH1)
310 continue;
311 }
312 if (ISSET(kf->kf_flags, KSTAT_FILTER_F_UNIT)((kf->kf_flags) & ((1 << 1)))) {
313 if (kf->kf_unit != ksreq->ks_unit)
314 continue;
315 }
316
317 return (1);
318 }
319
320 return (0);
321}
322
323static int
324printable(int ch)
325{
326 if (ch == '\0')
327 return ('_');
328 if (!isprint(ch))
329 return ('~');
330 return (ch);
331}
332
333static void
334hexdump(const void *d, size_t datalen)
335{
336 const uint8_t *data = d;
337 size_t i, j = 0;
338
339 for (i = 0; i < datalen; i += j) {
340 printf("%4zu: ", i);
341
342 for (j = 0; j < 16 && i+j < datalen; j++)
343 printf("%02x ", data[i + j]);
344 while (j++ < 16)
345 printf(" ");
346 printf("|");
347
348 for (j = 0; j < 16 && i+j < datalen; j++)
349 putchar(printable(data[i + j]))(!__isthreaded ? __sputc(printable(data[i + j]), (&__sF[1
])) : (putc)(printable(data[i + j]), (&__sF[1])))
;
350 printf("|\n");
351 }
352}
353
354static void
355strdump(const void *s, size_t len)
356{
357 const char *str = s;
358 char dst[8];
359 size_t i;
360
361 for (i = 0; i < len; i++) {
362 char ch = str[i];
363 if (ch == '\0')
364 break;
365
366 vis(dst, ch, VIS_TAB0x08 | VIS_NL0x10, 0);
367 printf("%s", dst);
368 }
369}
370
371static void
372strdumpnl(const void *s, size_t len)
373{
374 strdump(s, len);
375 printf("\n");
376}
377
378static const char *si_prefixes[] = { "", "k", "M", "G", "T", "P", "E" };
379#ifdef notyet
380static const char *iec_prefixes[] = { "", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei" };
381#endif
382
383static void
384kstat_kv(const void *d, ssize_t len)
385{
386 const uint8_t *buf;
387 const struct kstat_kv *kv;
388 ssize_t blen;
389 void (*trailer)(const void *, size_t);
390 double f;
391 struct fmt_result fr;
392
393 if (len < (ssize_t)sizeof(*kv)) {
394 warn("short kv (len %zu < size %zu)", len, sizeof(*kv));
395 return;
396 }
397
398 buf = d;
399 do {
400 kv = (const struct kstat_kv *)buf;
401
402 buf += sizeof(*kv);
403 len -= sizeof(*kv);
404
405 blen = 0;
406 trailer = hexdump;
407
408 printf("%16.16s: ", kv->kv_key);
409
410 switch (kv->kv_type) {
411 case KSTAT_KV_T_NULL:
412 printf("null");
413 break;
414 case KSTAT_KV_T_BOOL:
415 printf("%s", kstat_kv_bool(kv)(kv)->kv_v.v_bool ? "true" : "false");
416 break;
417 case KSTAT_KV_T_COUNTER64:
418 case KSTAT_KV_T_UINT64:
419 printf("%" PRIu64"llu", kstat_kv_u64(kv)(kv)->kv_v.v_u64);
420 break;
421 case KSTAT_KV_T_INT64:
422 printf("%" PRId64"lld", kstat_kv_s64(kv)(kv)->kv_v.v_s64);
423 break;
424 case KSTAT_KV_T_COUNTER32:
425 case KSTAT_KV_T_UINT32:
426 printf("%" PRIu32"u", kstat_kv_u32(kv)(kv)->kv_v.v_u32);
427 break;
428 case KSTAT_KV_T_INT32:
429 printf("%" PRId32"d", kstat_kv_s32(kv)(kv)->kv_v.v_s32);
430 break;
431 case KSTAT_KV_T_COUNTER16:
432 case KSTAT_KV_T_UINT16:
433 printf("%" PRIu16"u", kstat_kv_u16(kv)(kv)->kv_v.v_u16);
434 break;
435 case KSTAT_KV_T_INT16:
436 printf("%" PRId16"d", kstat_kv_s16(kv)(kv)->kv_v.v_s16);
437 break;
438 case KSTAT_KV_T_STR:
439 blen = kstat_kv_len(kv)(kv)->kv_v.v_len;
440 trailer = strdumpnl;
441 break;
442 case KSTAT_KV_T_BYTES:
443 blen = kstat_kv_len(kv)(kv)->kv_v.v_len;
444 trailer = hexdump;
445
446 printf("\n");
447 break;
448
449 case KSTAT_KV_T_ISTR:
450 strdump(kstat_kv_istr(kv)(kv)->kv_v.v_istr, sizeof(kstat_kv_istr(kv)(kv)->kv_v.v_istr));
451 break;
452
453 case KSTAT_KV_T_TEMP:
454 f = kstat_kv_temp(kv)(kv)->kv_v.v_u64;
455 printf("%.2f degC", (f - 273150000.0) / 1000000.0);
456 break;
457
458 case KSTAT_KV_T_FREQ:
459 fmt_thing(&fr, kstat_kv_freq(kv)(kv)->kv_v.v_u64, 1000);
460 printf("%llu", fr.val);
461 if (fr.frac > 10)
462 printf(".%02u", fr.frac / 10);
463 printf(" %sHz", si_prefixes[fr.exp]);
464 break;
465
466 case KSTAT_KV_T_VOLTS_DC: /* uV */
467 f = kstat_kv_volts(kv)(kv)->kv_v.v_u64;
468 printf("%.2f VDC", f / 1000000.0);
469 break;
470
471 case KSTAT_KV_T_VOLTS_AC: /* uV */
472 f = kstat_kv_volts(kv)(kv)->kv_v.v_u64;
473 printf("%.2f VAC", f / 1000000.0);
474 break;
475
476 default:
477 printf("unknown type %u, stopping\n", kv->kv_type);
478 return;
479 }
480
481 switch (kv->kv_unit) {
482 case KSTAT_KV_U_NONE:
483 break;
484 case KSTAT_KV_U_PACKETS:
485 printf(" packets");
486 break;
487 case KSTAT_KV_U_BYTES:
488 printf(" bytes");
489 break;
490 case KSTAT_KV_U_CYCLES:
491 printf(" cycles");
492 break;
493
494 default:
495 printf(" unit-type-%u", kv->kv_unit);
496 break;
497 }
498
499 if (blen > 0) {
500 if (blen > len) {
501 blen = len;
502 }
503
504 (*trailer)(buf, blen);
505 } else
506 printf("\n");
507
508 blen = roundup(blen, KSTAT_KV_ALIGN)((((blen)+((sizeof(uint64_t))-1))/(sizeof(uint64_t)))*(sizeof
(uint64_t)))
;
509 buf += blen;
510 len -= blen;
511 } while (len >= (ssize_t)sizeof(*kv));
512}
513
514static void
515kstat_list(struct kstat_tree *kt, int fd, unsigned int version,
516 struct kstat_filters *kfs)
517{
518 struct kstat_entry *kse;
519 struct kstat_req *ksreq;
520 uint64_t id = 0;
521
522 for (;;) {
523 kse = malloc(sizeof(*kse));
524 if (kse == NULL((void *)0))
525 err(1, NULL((void *)0));
526
527 memset(kse, 0, sizeof(*kse));
528 ksreq = &kse->kstat;
529 ksreq->ks_version = version;
530 ksreq->ks_id = ++id;
531
532 if (ioctl(fd, KSTATIOC_NFIND_ID(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct kstat_req) & 0x1fff) << 16) | ((('k')) <<
8) | ((3)))
, ksreq) == -1) {
533 if (errno(*__errno()) == ENOENT2) {
534 free(ksreq->ks_data);
535 free(kse);
536 break;
537 }
538 } else
539 id = ksreq->ks_id;
540
541 if (!kstat_filter_entry(kfs, ksreq)) {
542 free(ksreq->ks_data);
543 free(kse);
544 continue;
545 }
546
547 if (RBT_INSERT(kstat_tree, kt, kse)kstat_tree_RBT_INSERT(kt, kse) != NULL((void *)0))
548 errx(1, "duplicate kstat entry");
549
550 ksreq->ks_data = malloc(ksreq->ks_datalen);
551 if (ksreq->ks_data == NULL((void *)0))
552 err(1, "kstat data alloc");
553 }
554}
555
556static void
557kstat_print(struct kstat_tree *kt)
558{
559 struct kstat_entry *kse;
560 struct kstat_req *ksreq;
561
562 RBT_FOREACH(kse, kstat_tree, kt)for ((kse) = kstat_tree_RBT_MIN((kt)); (kse) != ((void *)0); (
kse) = kstat_tree_RBT_NEXT((kse)))
{
563 ksreq = &kse->kstat;
564 printf("%s:%u:%s:%u\n",
565 ksreq->ks_provider, ksreq->ks_instance,
566 ksreq->ks_name, ksreq->ks_unit);
567 if (kse->serrno != 0) {
568 printf("\tkstat read error: %s\n",
569 strerror(kse->serrno));
570 continue;
571 }
572 switch (ksreq->ks_type) {
573 case KSTAT_T_RAW0:
574 hexdump(ksreq->ks_data, ksreq->ks_datalen);
575 break;
576 case KSTAT_T_KV1:
577 kstat_kv(ksreq->ks_data, ksreq->ks_datalen);
578 break;
579 default:
580 hexdump(ksreq->ks_data, ksreq->ks_datalen);
581 break;
582 }
583 }
584
585 fflush(stdout(&__sF[1]));
586}
587
588static void
589kstat_read(struct kstat_tree *kt, int fd)
590{
591 struct kstat_entry *kse;
592 struct kstat_req *ksreq;
593
594 RBT_FOREACH(kse, kstat_tree, kt)for ((kse) = kstat_tree_RBT_MIN((kt)); (kse) != ((void *)0); (
kse) = kstat_tree_RBT_NEXT((kse)))
{
595 kse->serrno = 0;
596 ksreq = &kse->kstat;
597 if (ioctl(fd, KSTATIOC_FIND_ID(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct kstat_req) & 0x1fff) << 16) | ((('k')) <<
8) | ((2)))
, ksreq) == -1)
598 kse->serrno = errno(*__errno());
599 }
600}
601
602static void
603handle_alrm(int signo)
604{
605}