1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2013 David Hoeppner. All rights reserved.
25 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
26 * Copyright 2016 Joyent, Inc.
27 * Copyright 2020 Peter Tribble.
28 */
29
30 /*
31 * Display kernel statistics
32 *
33 * This is a reimplementation of the perl kstat command originally found
34 * under usr/src/cmd/kstat/kstat.pl
35 *
36 * Incompatibilities:
37 * - perl regular expressions replaced with extended REs bracketed by '/'
38 *
39 * Flags added:
40 * -C similar to the -p option but value is separated by a colon
41 * -h display help
42 * -j json format
43 */
44
45 #include <assert.h>
46 #include <ctype.h>
47 #include <errno.h>
48 #include <kstat.h>
49 #include <langinfo.h>
50 #include <libgen.h>
51 #include <limits.h>
52 #include <locale.h>
53 #include <signal.h>
54 #include <stddef.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <strings.h>
59 #include <time.h>
60 #include <unistd.h>
61 #include <sys/list.h>
62 #include <sys/time.h>
63 #include <sys/types.h>
64
65 #include "kstat.h"
66 #include "statcommon.h"
67
68 char *cmdname = "kstat"; /* Name of this command */
69 int caught_cont = 0; /* Have caught a SIGCONT */
70
71 static uint_t g_timestamp_fmt = NODATE;
72
73 /* Helper flag - header was printed already? */
74 static boolean_t g_headerflg;
75
76 /* Saved command line options */
77 static boolean_t g_cflg = B_FALSE;
78 static boolean_t g_jflg = B_FALSE;
79 static boolean_t g_lflg = B_FALSE;
80 static boolean_t g_pflg = B_FALSE;
81 static boolean_t g_qflg = B_FALSE;
82 static ks_pattern_t g_ks_class = {"*", 0};
83
84 static boolean_t g_matched = B_FALSE;
85
86 /* Sorted list of kstat instances */
87 static list_t instances_list;
88 static list_t selector_list;
89
90 int
main(int argc,char ** argv)91 main(int argc, char **argv)
92 {
93 ks_selector_t *nselector;
94 ks_selector_t *uselector;
95 kstat_ctl_t *kc;
96 hrtime_t start_n;
97 hrtime_t period_n;
98 boolean_t errflg = B_FALSE;
99 boolean_t nselflg = B_FALSE;
100 boolean_t uselflg = B_FALSE;
101 char *q;
102 int count = 1;
103 int infinite_cycles = 0;
104 int interval = 0;
105 int n = 0;
106 int c, m, tmp;
107
108 (void) setlocale(LC_ALL, "");
109 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
110 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */
111 #endif
112 (void) textdomain(TEXT_DOMAIN);
113
114 /*
115 * Create the selector list and a dummy default selector to match
116 * everything. While we process the cmdline options we will add
117 * selectors to this list.
118 */
119 list_create(&selector_list, sizeof (ks_selector_t),
120 offsetof(ks_selector_t, ks_next));
121
122 nselector = new_selector();
123
124 /*
125 * Parse named command line arguments.
126 */
127 while ((c = getopt(argc, argv, "h?CqjlpT:m:i:n:s:c:")) != EOF)
128 switch (c) {
129 case 'h':
130 case '?':
131 usage();
132 exit(0);
133 break;
134 case 'C':
135 g_pflg = g_cflg = B_TRUE;
136 break;
137 case 'q':
138 g_qflg = B_TRUE;
139 break;
140 case 'j':
141 /*
142 * If we're printing JSON, we're going to force numeric
143 * representation to be in the C locale to assure that
144 * the decimal point is compliant with RFC 7159 (i.e.,
145 * ASCII 0x2e).
146 */
147 (void) setlocale(LC_NUMERIC, "C");
148 g_jflg = B_TRUE;
149 break;
150 case 'l':
151 g_pflg = g_lflg = B_TRUE;
152 break;
153 case 'p':
154 g_pflg = B_TRUE;
155 break;
156 case 'T':
157 switch (*optarg) {
158 case 'd':
159 g_timestamp_fmt = DDATE;
160 break;
161 case 'u':
162 g_timestamp_fmt = UDATE;
163 break;
164 default:
165 errflg = B_TRUE;
166 }
167 break;
168 case 'm':
169 nselflg = B_TRUE;
170 nselector->ks_module.pstr =
171 (char *)ks_safe_strdup(optarg);
172 break;
173 case 'i':
174 nselflg = B_TRUE;
175 nselector->ks_instance.pstr =
176 (char *)ks_safe_strdup(optarg);
177 break;
178 case 'n':
179 nselflg = B_TRUE;
180 nselector->ks_name.pstr =
181 (char *)ks_safe_strdup(optarg);
182 break;
183 case 's':
184 nselflg = B_TRUE;
185 nselector->ks_statistic.pstr =
186 (char *)ks_safe_strdup(optarg);
187 break;
188 case 'c':
189 g_ks_class.pstr =
190 (char *)ks_safe_strdup(optarg);
191 break;
192 default:
193 errflg = B_TRUE;
194 break;
195 }
196
197 if (g_qflg && (g_jflg || g_pflg)) {
198 (void) fprintf(stderr, gettext(
199 "-q and -lpj are mutually exclusive\n"));
200 errflg = B_TRUE;
201 }
202
203 if (errflg) {
204 usage();
205 exit(2);
206 }
207
208 argc -= optind;
209 argv += optind;
210
211 /*
212 * Consume the rest of the command line. Parsing the
213 * unnamed command line arguments.
214 */
215 while (argc--) {
216 errno = 0;
217 tmp = strtoul(*argv, &q, 10);
218 if (tmp == ULONG_MAX && errno == ERANGE) {
219 if (n == 0) {
220 (void) fprintf(stderr, gettext(
221 "Interval is too large\n"));
222 } else if (n == 1) {
223 (void) fprintf(stderr, gettext(
224 "Count is too large\n"));
225 }
226 usage();
227 exit(2);
228 }
229
230 if (errno != 0 || *q != '\0') {
231 m = 0;
232 uselector = new_selector();
233 while ((q = (char *)strsep(argv, ":")) != NULL) {
234 m++;
235 if (m > 4) {
236 free(uselector);
237 usage();
238 exit(2);
239 }
240
241 if (*q != '\0') {
242 switch (m) {
243 case 1:
244 uselector->ks_module.pstr =
245 (char *)ks_safe_strdup(q);
246 break;
247 case 2:
248 uselector->ks_instance.pstr =
249 (char *)ks_safe_strdup(q);
250 break;
251 case 3:
252 uselector->ks_name.pstr =
253 (char *)ks_safe_strdup(q);
254 break;
255 case 4:
256 uselector->ks_statistic.pstr =
257 (char *)ks_safe_strdup(q);
258 break;
259 default:
260 assert(B_FALSE);
261 }
262 }
263 }
264
265 uselflg = B_TRUE;
266 list_insert_tail(&selector_list, uselector);
267 } else {
268 if (tmp < 1) {
269 if (n == 0) {
270 (void) fprintf(stderr, gettext(
271 "Interval must be an "
272 "integer >= 1"));
273 } else if (n == 1) {
274 (void) fprintf(stderr, gettext(
275 "Count must be an integer >= 1"));
276 }
277 usage();
278 exit(2);
279 } else {
280 if (n == 0) {
281 interval = tmp;
282 count = -1;
283 } else if (n == 1) {
284 count = tmp;
285 } else {
286 usage();
287 exit(2);
288 }
289 }
290 n++;
291 }
292 argv++;
293 }
294
295 /*
296 * Check if we founded a named selector on the cmdline.
297 */
298 if (uselflg) {
299 if (nselflg) {
300 (void) fprintf(stderr, gettext(
301 "[module[:instance[:name[:statistic]]]] and "
302 "-m -i -n -s are mutually exclusive"));
303 usage();
304 exit(2);
305 } else {
306 free(nselector);
307 }
308 } else {
309 list_insert_tail(&selector_list, nselector);
310 }
311
312 assert(!list_is_empty(&selector_list));
313
314 list_create(&instances_list, sizeof (ks_instance_t),
315 offsetof(ks_instance_t, ks_next));
316
317 while ((kc = kstat_open()) == NULL) {
318 if (errno == EAGAIN) {
319 (void) poll(NULL, 0, 200);
320 } else {
321 perror("kstat_open");
322 exit(3);
323 }
324 }
325
326 if (count > 1) {
327 if (signal(SIGCONT, cont_handler) == SIG_ERR) {
328 (void) fprintf(stderr, gettext(
329 "signal failed"));
330 exit(3);
331 }
332 }
333
334 period_n = (hrtime_t)interval * NANOSEC;
335 start_n = gethrtime();
336
337 while (count == -1 || count-- > 0) {
338 ks_instances_read(kc);
339 ks_instances_print();
340
341 if (interval && count) {
342 ks_sleep_until(&start_n, period_n, infinite_cycles,
343 &caught_cont);
344 (void) kstat_chain_update(kc);
345 (void) putchar('\n');
346 }
347 }
348
349 (void) kstat_close(kc);
350
351 /*
352 * Return a non-zero exit code if we didn't match anything.
353 */
354 return (g_matched ? 0 : 1);
355 }
356
357 /*
358 * Print usage.
359 */
360 static void
usage(void)361 usage(void)
362 {
363 (void) fprintf(stderr, gettext(
364 "Usage:\n"
365 "kstat [ -Cjlpq ] [ -T d|u ] [ -c class ]\n"
366 " [ -m module ] [ -i instance ] [ -n name ] [ -s statistic ]\n"
367 " [ interval [ count ] ]\n"
368 "kstat [ -Cjlpq ] [ -T d|u ] [ -c class ]\n"
369 " [ module[:instance[:name[:statistic]]] ... ]\n"
370 " [ interval [ count ] ]\n"));
371 }
372
373 /*
374 * Sort compare function.
375 */
376 static int
compare_instances(ks_instance_t * l_arg,ks_instance_t * r_arg)377 compare_instances(ks_instance_t *l_arg, ks_instance_t *r_arg)
378 {
379 int rval;
380
381 rval = strcasecmp(l_arg->ks_module, r_arg->ks_module);
382 if (rval == 0) {
383 if (l_arg->ks_instance == r_arg->ks_instance) {
384 return (strcasecmp(l_arg->ks_name, r_arg->ks_name));
385 } else if (l_arg->ks_instance < r_arg->ks_instance) {
386 return (-1);
387 } else {
388 return (1);
389 }
390 } else {
391 return (rval);
392 }
393 }
394
395 static char *
ks_safe_strdup(char * str)396 ks_safe_strdup(char *str)
397 {
398 char *ret;
399
400 if (str == NULL) {
401 return (NULL);
402 }
403
404 while ((ret = strdup(str)) == NULL) {
405 if (errno == EAGAIN) {
406 (void) poll(NULL, 0, 200);
407 } else {
408 perror("strdup");
409 exit(3);
410 }
411 }
412
413 return (ret);
414 }
415
416 static void
ks_sleep_until(hrtime_t * wakeup,hrtime_t interval,int forever,int * caught_cont)417 ks_sleep_until(hrtime_t *wakeup, hrtime_t interval, int forever,
418 int *caught_cont)
419 {
420 hrtime_t now, pause, pause_left;
421 struct timespec pause_tv;
422 int status;
423
424 now = gethrtime();
425 pause = *wakeup + interval - now;
426
427 if (pause <= 0 || pause < (interval / 4)) {
428 if (forever || *caught_cont) {
429 *wakeup = now + interval;
430 pause = interval;
431 } else {
432 pause = interval / 2;
433 *wakeup += interval;
434 }
435 } else {
436 *wakeup += interval;
437 }
438
439 if (pause < 1000) {
440 return;
441 }
442
443 pause_left = pause;
444 do {
445 pause_tv.tv_sec = pause_left / NANOSEC;
446 pause_tv.tv_nsec = pause_left % NANOSEC;
447 status = nanosleep(&pause_tv, (struct timespec *)NULL);
448 if (status < 0) {
449 if (errno == EINTR) {
450 now = gethrtime();
451 pause_left = *wakeup - now;
452 if (pause_left < 1000) {
453 return;
454 }
455 } else {
456 perror("nanosleep");
457 exit(3);
458 }
459 }
460 } while (status != 0);
461 }
462
463 /*
464 * Inserts an instance in the per selector list.
465 */
466 static void
nvpair_insert(ks_instance_t * ksi,char * name,ks_value_t * value,uchar_t data_type)467 nvpair_insert(ks_instance_t *ksi, char *name, ks_value_t *value,
468 uchar_t data_type)
469 {
470 ks_nvpair_t *instance;
471 ks_nvpair_t *tmp;
472
473 instance = (ks_nvpair_t *)malloc(sizeof (ks_nvpair_t));
474 if (instance == NULL) {
475 perror("malloc");
476 exit(3);
477 }
478
479 (void) strlcpy(instance->name, name, KSTAT_STRLEN);
480 (void) memcpy(&instance->value, value, sizeof (ks_value_t));
481 instance->data_type = data_type;
482
483 tmp = list_head(&ksi->ks_nvlist);
484 while (tmp != NULL && strcasecmp(instance->name, tmp->name) > 0)
485 tmp = list_next(&ksi->ks_nvlist, tmp);
486
487 list_insert_before(&ksi->ks_nvlist, tmp, instance);
488 }
489
490 /*
491 * Allocates a new all-matching selector.
492 */
493 static ks_selector_t *
new_selector(void)494 new_selector(void)
495 {
496 ks_selector_t *selector;
497
498 selector = (ks_selector_t *)malloc(sizeof (ks_selector_t));
499 if (selector == NULL) {
500 perror("malloc");
501 exit(3);
502 }
503
504 list_link_init(&selector->ks_next);
505
506 selector->ks_module.pstr = "*";
507 selector->ks_instance.pstr = "*";
508 selector->ks_name.pstr = "*";
509 selector->ks_statistic.pstr = "*";
510
511 return (selector);
512 }
513
514 /*
515 * This function was taken from the perl kstat module code - please
516 * see for further comments there.
517 */
518 static kstat_raw_reader_t
lookup_raw_kstat_fn(char * module,char * name)519 lookup_raw_kstat_fn(char *module, char *name)
520 {
521 char key[KSTAT_STRLEN * 2];
522 register char *f, *t;
523 int n = 0;
524
525 for (f = module, t = key; *f != '\0'; f++, t++) {
526 while (*f != '\0' && isdigit(*f))
527 f++;
528 *t = *f;
529 }
530 *t++ = ':';
531
532 for (f = name; *f != '\0'; f++, t++) {
533 while (*f != '\0' && isdigit(*f))
534 f++;
535 *t = *f;
536 }
537 *t = '\0';
538
539 while (ks_raw_lookup[n].fn != NULL) {
540 if (strncmp(ks_raw_lookup[n].name, key, strlen(key)) == 0)
541 return (ks_raw_lookup[n].fn);
542 n++;
543 }
544
545 return (0);
546 }
547
548 /*
549 * Match a string against a shell glob or extended regular expression.
550 */
551 static boolean_t
ks_match(const char * str,ks_pattern_t * pattern)552 ks_match(const char *str, ks_pattern_t *pattern)
553 {
554 int regcode;
555 char *regstr;
556 char *errbuf;
557 size_t bufsz;
558
559 if (pattern->pstr != NULL && gmatch(pattern->pstr, "/*/") != 0) {
560 /* All regex patterns are strdup'd copies */
561 regstr = pattern->pstr + 1;
562 *(strrchr(regstr, '/')) = '\0';
563
564 regcode = regcomp(&pattern->preg, regstr,
565 REG_EXTENDED | REG_NOSUB);
566 if (regcode != 0) {
567 bufsz = regerror(regcode, NULL, NULL, 0);
568 if (bufsz != 0) {
569 errbuf = malloc(bufsz);
570 if (errbuf == NULL) {
571 perror("malloc");
572 exit(3);
573 }
574 (void) regerror(regcode, NULL, errbuf, bufsz);
575 (void) fprintf(stderr, "kstat: %s\n", errbuf);
576 }
577 usage();
578 exit(2);
579 }
580
581 pattern->pstr = NULL;
582 }
583
584 if (pattern->pstr == NULL) {
585 return (regexec(&pattern->preg, str, 0, NULL, 0) == 0);
586 }
587
588 return ((gmatch(str, pattern->pstr) != 0));
589 }
590
591 /*
592 * Iterate over all kernel statistics and save matches.
593 */
594 static void
ks_instances_read(kstat_ctl_t * kc)595 ks_instances_read(kstat_ctl_t *kc)
596 {
597 kstat_raw_reader_t save_raw = NULL;
598 kid_t id;
599 ks_selector_t *selector;
600 ks_instance_t *ksi;
601 ks_instance_t *tmp;
602 kstat_t *kp;
603 boolean_t skip;
604
605 for (kp = kc->kc_chain; kp != NULL; kp = kp->ks_next) {
606 /* Don't bother storing the kstat headers */
607 if (strncmp(kp->ks_name, "kstat_", 6) == 0) {
608 continue;
609 }
610
611 /* Don't bother storing raw stats we don't understand */
612 if (kp->ks_type == KSTAT_TYPE_RAW) {
613 save_raw = lookup_raw_kstat_fn(kp->ks_module,
614 kp->ks_name);
615 if (save_raw == NULL) {
616 #ifdef REPORT_UNKNOWN
617 (void) fprintf(stderr,
618 "Unknown kstat type %s:%d:%s - "
619 "%d of size %d\n", kp->ks_module,
620 kp->ks_instance, kp->ks_name,
621 kp->ks_ndata, kp->ks_data_size);
622 #endif
623 continue;
624 }
625 }
626
627 /*
628 * Iterate over the list of selectors and skip
629 * instances we dont want. We filter for statistics
630 * later, as we dont know them yet.
631 */
632 skip = B_TRUE;
633 selector = list_head(&selector_list);
634 while (selector != NULL) {
635 if (ks_match(kp->ks_module, &selector->ks_module) &&
636 ks_match(kp->ks_name, &selector->ks_name)) {
637 skip = B_FALSE;
638 break;
639 }
640 selector = list_next(&selector_list, selector);
641 }
642
643 if (skip) {
644 continue;
645 }
646
647 /*
648 * Allocate a new instance and fill in the values
649 * we know so far.
650 */
651 ksi = (ks_instance_t *)malloc(sizeof (ks_instance_t));
652 if (ksi == NULL) {
653 perror("malloc");
654 exit(3);
655 }
656
657 list_link_init(&ksi->ks_next);
658
659 (void) strlcpy(ksi->ks_module, kp->ks_module, KSTAT_STRLEN);
660 (void) strlcpy(ksi->ks_name, kp->ks_name, KSTAT_STRLEN);
661 (void) strlcpy(ksi->ks_class, kp->ks_class, KSTAT_STRLEN);
662
663 ksi->ks_instance = kp->ks_instance;
664 ksi->ks_snaptime = kp->ks_snaptime;
665 ksi->ks_type = kp->ks_type;
666
667 list_create(&ksi->ks_nvlist, sizeof (ks_nvpair_t),
668 offsetof(ks_nvpair_t, nv_next));
669
670 SAVE_HRTIME_X(ksi, "crtime", kp->ks_crtime);
671 if (g_pflg) {
672 SAVE_STRING_X(ksi, "class", kp->ks_class);
673 }
674
675 /* Insert this instance into a sorted list */
676 tmp = list_head(&instances_list);
677 while (tmp != NULL && compare_instances(ksi, tmp) > 0)
678 tmp = list_next(&instances_list, tmp);
679
680 list_insert_before(&instances_list, tmp, ksi);
681
682 /* Read the actual statistics */
683 id = kstat_read(kc, kp, NULL);
684 if (id == -1) {
685 #ifdef REPORT_UNKNOWN
686 perror("kstat_read");
687 #endif
688 continue;
689 }
690
691 SAVE_HRTIME_X(ksi, "snaptime", kp->ks_snaptime);
692
693 switch (kp->ks_type) {
694 case KSTAT_TYPE_RAW:
695 save_raw(kp, ksi);
696 break;
697 case KSTAT_TYPE_NAMED:
698 save_named(kp, ksi);
699 break;
700 case KSTAT_TYPE_INTR:
701 save_intr(kp, ksi);
702 break;
703 case KSTAT_TYPE_IO:
704 save_io(kp, ksi);
705 break;
706 case KSTAT_TYPE_TIMER:
707 save_timer(kp, ksi);
708 break;
709 default:
710 assert(B_FALSE); /* Invalid type */
711 break;
712 }
713 }
714 }
715
716 /*
717 * Print the value of a name-value pair.
718 */
719 static void
ks_value_print(ks_nvpair_t * nvpair)720 ks_value_print(ks_nvpair_t *nvpair)
721 {
722 switch (nvpair->data_type) {
723 case KSTAT_DATA_CHAR:
724 (void) fprintf(stdout, "%s", nvpair->value.c);
725 break;
726 case KSTAT_DATA_INT32:
727 (void) fprintf(stdout, "%d", nvpair->value.i32);
728 break;
729 case KSTAT_DATA_UINT32:
730 (void) fprintf(stdout, "%u", nvpair->value.ui32);
731 break;
732 case KSTAT_DATA_INT64:
733 (void) fprintf(stdout, "%lld", nvpair->value.i64);
734 break;
735 case KSTAT_DATA_UINT64:
736 (void) fprintf(stdout, "%llu", nvpair->value.ui64);
737 break;
738 case KSTAT_DATA_STRING:
739 (void) fprintf(stdout, "%s", KSTAT_NAMED_STR_PTR(nvpair));
740 break;
741 case KSTAT_DATA_HRTIME:
742 if (nvpair->value.ui64 == 0)
743 (void) fprintf(stdout, "0");
744 else
745 (void) fprintf(stdout, "%.9f",
746 nvpair->value.ui64 / 1000000000.0);
747 break;
748 default:
749 assert(B_FALSE);
750 }
751 }
752
753 /*
754 * Print a single instance.
755 */
756 /*ARGSUSED*/
757 static void
ks_instance_print(ks_instance_t * ksi,ks_nvpair_t * nvpair,boolean_t last)758 ks_instance_print(ks_instance_t *ksi, ks_nvpair_t *nvpair, boolean_t last)
759 {
760 if (g_headerflg) {
761 if (!g_pflg) {
762 (void) fprintf(stdout, DFLT_FMT,
763 ksi->ks_module, ksi->ks_instance,
764 ksi->ks_name, ksi->ks_class);
765 }
766 g_headerflg = B_FALSE;
767 }
768
769 if (g_pflg) {
770 (void) fprintf(stdout, KS_PFMT,
771 ksi->ks_module, ksi->ks_instance,
772 ksi->ks_name, nvpair->name);
773 if (!g_lflg) {
774 (void) putchar(g_cflg ? ':': '\t');
775 ks_value_print(nvpair);
776 }
777 } else {
778 (void) fprintf(stdout, KS_DFMT, nvpair->name);
779 ks_value_print(nvpair);
780 }
781
782 (void) putchar('\n');
783 }
784
785 /*
786 * Print a C string as a JSON string.
787 */
788 static void
ks_print_json_string(const char * str)789 ks_print_json_string(const char *str)
790 {
791 char c;
792
793 (void) putchar('"');
794
795 while ((c = *str++) != '\0') {
796 /*
797 * For readability, we use the allowed alternate escape
798 * sequence for quote, question mark, reverse solidus (look
799 * it up!), newline and tab -- and use the universal escape
800 * sequence for all other control characters.
801 */
802 switch (c) {
803 case '"':
804 case '?':
805 case '\\':
806 (void) fprintf(stdout, "\\%c", c);
807 break;
808
809 case '\n':
810 (void) fprintf(stdout, "\\n");
811 break;
812
813 case '\t':
814 (void) fprintf(stdout, "\\t");
815 break;
816
817 default:
818 /*
819 * By escaping those characters for which isprint(3C)
820 * is false, we escape both the RFC 7159 mandated
821 * escaped range of 0x01 through 0x1f as well as DEL
822 * (0x7f -- the control character that RFC 7159 forgot)
823 * and then everything else that's unprintable for
824 * good measure.
825 */
826 if (!isprint(c)) {
827 (void) fprintf(stdout, "\\u%04hhx", (uint8_t)c);
828 break;
829 }
830
831 (void) putchar(c);
832 break;
833 }
834 }
835
836 (void) putchar('"');
837 }
838
839 /*
840 * Print a single instance in JSON format.
841 */
842 static void
ks_instance_print_json(ks_instance_t * ksi,ks_nvpair_t * nvpair,boolean_t last)843 ks_instance_print_json(ks_instance_t *ksi, ks_nvpair_t *nvpair, boolean_t last)
844 {
845 static int headers;
846
847 if (g_headerflg) {
848 if (headers++ > 0)
849 (void) fprintf(stdout, ", ");
850
851 (void) fprintf(stdout, "{\n\t\"module\": ");
852 ks_print_json_string(ksi->ks_module);
853
854 (void) fprintf(stdout,
855 ",\n\t\"instance\": %d,\n\t\"name\": ", ksi->ks_instance);
856 ks_print_json_string(ksi->ks_name);
857
858 (void) fprintf(stdout, ",\n\t\"class\": ");
859 ks_print_json_string(ksi->ks_class);
860
861 (void) fprintf(stdout, ",\n\t\"type\": %d,\n", ksi->ks_type);
862
863 if (ksi->ks_snaptime == 0)
864 (void) fprintf(stdout, "\t\"snaptime\": 0,\n");
865 else
866 (void) fprintf(stdout, "\t\"snaptime\": %.9f,\n",
867 ksi->ks_snaptime / 1000000000.0);
868
869 (void) fprintf(stdout, "\t\"data\": {\n");
870
871 g_headerflg = B_FALSE;
872 }
873
874 (void) fprintf(stdout, "\t\t");
875 ks_print_json_string(nvpair->name);
876 (void) fprintf(stdout, ": ");
877
878 switch (nvpair->data_type) {
879 case KSTAT_DATA_CHAR:
880 ks_print_json_string(nvpair->value.c);
881 break;
882
883 case KSTAT_DATA_STRING:
884 ks_print_json_string(KSTAT_NAMED_STR_PTR(nvpair));
885 break;
886
887 default:
888 ks_value_print(nvpair);
889 break;
890 }
891
892 if (!last)
893 (void) putchar(',');
894
895 (void) putchar('\n');
896 }
897
898 /*
899 * Print all instances.
900 */
901 static void
ks_instances_print(void)902 ks_instances_print(void)
903 {
904 ks_selector_t *selector;
905 ks_instance_t *ksi, *ktmp;
906 ks_nvpair_t *nvpair, *ntmp, *next;
907 void (*ks_print_fn)(ks_instance_t *, ks_nvpair_t *, boolean_t);
908 char *ks_number;
909
910 if (g_timestamp_fmt != NODATE)
911 print_timestamp(g_timestamp_fmt);
912
913 if (g_jflg) {
914 ks_print_fn = &ks_instance_print_json;
915 (void) putchar('[');
916 } else {
917 ks_print_fn = &ks_instance_print;
918 }
919
920 /* Iterate over each selector */
921 selector = list_head(&selector_list);
922 while (selector != NULL) {
923
924 /* Iterate over each instance */
925 for (ksi = list_head(&instances_list); ksi != NULL;
926 ksi = list_next(&instances_list, ksi)) {
927
928 (void) asprintf(&ks_number, "%d", ksi->ks_instance);
929 if (!(ks_match(ksi->ks_module, &selector->ks_module) &&
930 ks_match(ksi->ks_name, &selector->ks_name) &&
931 ks_match(ks_number, &selector->ks_instance) &&
932 ks_match(ksi->ks_class, &g_ks_class))) {
933 free(ks_number);
934 continue;
935 }
936
937 free(ks_number);
938
939 g_headerflg = B_TRUE;
940
941 /*
942 * Find our first statistic to print.
943 */
944 for (nvpair = list_head(&ksi->ks_nvlist);
945 nvpair != NULL;
946 nvpair = list_next(&ksi->ks_nvlist, nvpair)) {
947 if (ks_match(nvpair->name,
948 &selector->ks_statistic))
949 break;
950 }
951
952 while (nvpair != NULL) {
953 boolean_t last;
954
955 /*
956 * Find the next statistic to print so we can
957 * indicate to the print function if this
958 * statistic is the last to be printed for
959 * this instance.
960 */
961 for (next = list_next(&ksi->ks_nvlist, nvpair);
962 next != NULL;
963 next = list_next(&ksi->ks_nvlist, next)) {
964 if (ks_match(next->name,
965 &selector->ks_statistic))
966 break;
967 }
968
969 g_matched = B_TRUE;
970 last = next == NULL ? B_TRUE : B_FALSE;
971
972 if (!g_qflg)
973 (*ks_print_fn)(ksi, nvpair, last);
974
975 nvpair = next;
976 }
977
978 if (!g_headerflg) {
979 if (g_jflg) {
980 (void) fprintf(stdout, "\t}\n}");
981 } else if (!g_pflg) {
982 (void) putchar('\n');
983 }
984 }
985 }
986
987 selector = list_next(&selector_list, selector);
988 }
989
990 if (g_jflg)
991 (void) fprintf(stdout, "]\n");
992
993 (void) fflush(stdout);
994
995 /* Free the instances list */
996 ksi = list_head(&instances_list);
997 while (ksi != NULL) {
998 nvpair = list_head(&ksi->ks_nvlist);
999 while (nvpair != NULL) {
1000 ntmp = nvpair;
1001 nvpair = list_next(&ksi->ks_nvlist, nvpair);
1002 list_remove(&ksi->ks_nvlist, ntmp);
1003 if (ntmp->data_type == KSTAT_DATA_STRING)
1004 free(ntmp->value.str.addr.ptr);
1005 free(ntmp);
1006 }
1007
1008 ktmp = ksi;
1009 ksi = list_next(&instances_list, ksi);
1010 list_remove(&instances_list, ktmp);
1011 list_destroy(&ktmp->ks_nvlist);
1012 free(ktmp);
1013 }
1014 }
1015
1016 static void
save_cpu_stat(kstat_t * kp,ks_instance_t * ksi)1017 save_cpu_stat(kstat_t *kp, ks_instance_t *ksi)
1018 {
1019 cpu_stat_t *stat;
1020 cpu_sysinfo_t *sysinfo;
1021 cpu_syswait_t *syswait;
1022 cpu_vminfo_t *vminfo;
1023
1024 stat = (cpu_stat_t *)(kp->ks_data);
1025 sysinfo = &stat->cpu_sysinfo;
1026 syswait = &stat->cpu_syswait;
1027 vminfo = &stat->cpu_vminfo;
1028
1029 SAVE_UINT32_X(ksi, "idle", sysinfo->cpu[CPU_IDLE]);
1030 SAVE_UINT32_X(ksi, "user", sysinfo->cpu[CPU_USER]);
1031 SAVE_UINT32_X(ksi, "kernel", sysinfo->cpu[CPU_KERNEL]);
1032 SAVE_UINT32_X(ksi, "wait", sysinfo->cpu[CPU_WAIT]);
1033 SAVE_UINT32_X(ksi, "wait_io", sysinfo->wait[W_IO]);
1034 SAVE_UINT32_X(ksi, "wait_swap", sysinfo->wait[W_SWAP]);
1035 SAVE_UINT32_X(ksi, "wait_pio", sysinfo->wait[W_PIO]);
1036 SAVE_UINT32(ksi, sysinfo, bread);
1037 SAVE_UINT32(ksi, sysinfo, bwrite);
1038 SAVE_UINT32(ksi, sysinfo, lread);
1039 SAVE_UINT32(ksi, sysinfo, lwrite);
1040 SAVE_UINT32(ksi, sysinfo, phread);
1041 SAVE_UINT32(ksi, sysinfo, phwrite);
1042 SAVE_UINT32(ksi, sysinfo, pswitch);
1043 SAVE_UINT32(ksi, sysinfo, trap);
1044 SAVE_UINT32(ksi, sysinfo, intr);
1045 SAVE_UINT32(ksi, sysinfo, syscall);
1046 SAVE_UINT32(ksi, sysinfo, sysread);
1047 SAVE_UINT32(ksi, sysinfo, syswrite);
1048 SAVE_UINT32(ksi, sysinfo, sysfork);
1049 SAVE_UINT32(ksi, sysinfo, sysvfork);
1050 SAVE_UINT32(ksi, sysinfo, sysexec);
1051 SAVE_UINT32(ksi, sysinfo, readch);
1052 SAVE_UINT32(ksi, sysinfo, writech);
1053 SAVE_UINT32(ksi, sysinfo, rcvint);
1054 SAVE_UINT32(ksi, sysinfo, xmtint);
1055 SAVE_UINT32(ksi, sysinfo, mdmint);
1056 SAVE_UINT32(ksi, sysinfo, rawch);
1057 SAVE_UINT32(ksi, sysinfo, canch);
1058 SAVE_UINT32(ksi, sysinfo, outch);
1059 SAVE_UINT32(ksi, sysinfo, msg);
1060 SAVE_UINT32(ksi, sysinfo, sema);
1061 SAVE_UINT32(ksi, sysinfo, namei);
1062 SAVE_UINT32(ksi, sysinfo, ufsiget);
1063 SAVE_UINT32(ksi, sysinfo, ufsdirblk);
1064 SAVE_UINT32(ksi, sysinfo, ufsipage);
1065 SAVE_UINT32(ksi, sysinfo, ufsinopage);
1066 SAVE_UINT32(ksi, sysinfo, inodeovf);
1067 SAVE_UINT32(ksi, sysinfo, fileovf);
1068 SAVE_UINT32(ksi, sysinfo, procovf);
1069 SAVE_UINT32(ksi, sysinfo, intrthread);
1070 SAVE_UINT32(ksi, sysinfo, intrblk);
1071 SAVE_UINT32(ksi, sysinfo, idlethread);
1072 SAVE_UINT32(ksi, sysinfo, inv_swtch);
1073 SAVE_UINT32(ksi, sysinfo, nthreads);
1074 SAVE_UINT32(ksi, sysinfo, cpumigrate);
1075 SAVE_UINT32(ksi, sysinfo, xcalls);
1076 SAVE_UINT32(ksi, sysinfo, mutex_adenters);
1077 SAVE_UINT32(ksi, sysinfo, rw_rdfails);
1078 SAVE_UINT32(ksi, sysinfo, rw_wrfails);
1079 SAVE_UINT32(ksi, sysinfo, modload);
1080 SAVE_UINT32(ksi, sysinfo, modunload);
1081 SAVE_UINT32(ksi, sysinfo, bawrite);
1082 #ifdef STATISTICS /* see header file */
1083 SAVE_UINT32(ksi, sysinfo, rw_enters);
1084 SAVE_UINT32(ksi, sysinfo, win_uo_cnt);
1085 SAVE_UINT32(ksi, sysinfo, win_uu_cnt);
1086 SAVE_UINT32(ksi, sysinfo, win_so_cnt);
1087 SAVE_UINT32(ksi, sysinfo, win_su_cnt);
1088 SAVE_UINT32(ksi, sysinfo, win_suo_cnt);
1089 #endif
1090
1091 SAVE_INT32(ksi, syswait, iowait);
1092 SAVE_INT32(ksi, syswait, swap);
1093 SAVE_INT32(ksi, syswait, physio);
1094
1095 SAVE_UINT32(ksi, vminfo, pgrec);
1096 SAVE_UINT32(ksi, vminfo, pgfrec);
1097 SAVE_UINT32(ksi, vminfo, pgin);
1098 SAVE_UINT32(ksi, vminfo, pgpgin);
1099 SAVE_UINT32(ksi, vminfo, pgout);
1100 SAVE_UINT32(ksi, vminfo, pgpgout);
1101 SAVE_UINT32(ksi, vminfo, swapin);
1102 SAVE_UINT32(ksi, vminfo, pgswapin);
1103 SAVE_UINT32(ksi, vminfo, swapout);
1104 SAVE_UINT32(ksi, vminfo, pgswapout);
1105 SAVE_UINT32(ksi, vminfo, zfod);
1106 SAVE_UINT32(ksi, vminfo, dfree);
1107 SAVE_UINT32(ksi, vminfo, scan);
1108 SAVE_UINT32(ksi, vminfo, rev);
1109 SAVE_UINT32(ksi, vminfo, hat_fault);
1110 SAVE_UINT32(ksi, vminfo, as_fault);
1111 SAVE_UINT32(ksi, vminfo, maj_fault);
1112 SAVE_UINT32(ksi, vminfo, cow_fault);
1113 SAVE_UINT32(ksi, vminfo, prot_fault);
1114 SAVE_UINT32(ksi, vminfo, softlock);
1115 SAVE_UINT32(ksi, vminfo, kernel_asflt);
1116 SAVE_UINT32(ksi, vminfo, pgrrun);
1117 SAVE_UINT32(ksi, vminfo, execpgin);
1118 SAVE_UINT32(ksi, vminfo, execpgout);
1119 SAVE_UINT32(ksi, vminfo, execfree);
1120 SAVE_UINT32(ksi, vminfo, anonpgin);
1121 SAVE_UINT32(ksi, vminfo, anonpgout);
1122 SAVE_UINT32(ksi, vminfo, anonfree);
1123 SAVE_UINT32(ksi, vminfo, fspgin);
1124 SAVE_UINT32(ksi, vminfo, fspgout);
1125 SAVE_UINT32(ksi, vminfo, fsfree);
1126 }
1127
1128 static void
save_var(kstat_t * kp,ks_instance_t * ksi)1129 save_var(kstat_t *kp, ks_instance_t *ksi)
1130 {
1131 struct var *var = (struct var *)(kp->ks_data);
1132
1133 assert(kp->ks_data_size == sizeof (struct var));
1134
1135 SAVE_INT32(ksi, var, v_buf);
1136 SAVE_INT32(ksi, var, v_call);
1137 SAVE_INT32(ksi, var, v_proc);
1138 SAVE_INT32(ksi, var, v_maxupttl);
1139 SAVE_INT32(ksi, var, v_nglobpris);
1140 SAVE_INT32(ksi, var, v_maxsyspri);
1141 SAVE_INT32(ksi, var, v_clist);
1142 SAVE_INT32(ksi, var, v_maxup);
1143 SAVE_INT32(ksi, var, v_hbuf);
1144 SAVE_INT32(ksi, var, v_hmask);
1145 SAVE_INT32(ksi, var, v_pbuf);
1146 SAVE_INT32(ksi, var, v_sptmap);
1147 SAVE_INT32(ksi, var, v_maxpmem);
1148 SAVE_INT32(ksi, var, v_autoup);
1149 SAVE_INT32(ksi, var, v_bufhwm);
1150 }
1151
1152 static void
save_ncstats(kstat_t * kp,ks_instance_t * ksi)1153 save_ncstats(kstat_t *kp, ks_instance_t *ksi)
1154 {
1155 struct ncstats *ncstats = (struct ncstats *)(kp->ks_data);
1156
1157 assert(kp->ks_data_size == sizeof (struct ncstats));
1158
1159 SAVE_INT32(ksi, ncstats, hits);
1160 SAVE_INT32(ksi, ncstats, misses);
1161 SAVE_INT32(ksi, ncstats, enters);
1162 SAVE_INT32(ksi, ncstats, dbl_enters);
1163 SAVE_INT32(ksi, ncstats, long_enter);
1164 SAVE_INT32(ksi, ncstats, long_look);
1165 SAVE_INT32(ksi, ncstats, move_to_front);
1166 SAVE_INT32(ksi, ncstats, purges);
1167 }
1168
1169 static void
save_sysinfo(kstat_t * kp,ks_instance_t * ksi)1170 save_sysinfo(kstat_t *kp, ks_instance_t *ksi)
1171 {
1172 sysinfo_t *sysinfo = (sysinfo_t *)(kp->ks_data);
1173
1174 assert(kp->ks_data_size == sizeof (sysinfo_t));
1175
1176 SAVE_UINT32(ksi, sysinfo, updates);
1177 SAVE_UINT32(ksi, sysinfo, runque);
1178 SAVE_UINT32(ksi, sysinfo, runocc);
1179 SAVE_UINT32(ksi, sysinfo, swpque);
1180 SAVE_UINT32(ksi, sysinfo, swpocc);
1181 SAVE_UINT32(ksi, sysinfo, waiting);
1182 }
1183
1184 static void
save_vminfo(kstat_t * kp,ks_instance_t * ksi)1185 save_vminfo(kstat_t *kp, ks_instance_t *ksi)
1186 {
1187 vminfo_t *vminfo = (vminfo_t *)(kp->ks_data);
1188
1189 assert(kp->ks_data_size == sizeof (vminfo_t));
1190
1191 SAVE_UINT64(ksi, vminfo, freemem);
1192 SAVE_UINT64(ksi, vminfo, swap_resv);
1193 SAVE_UINT64(ksi, vminfo, swap_alloc);
1194 SAVE_UINT64(ksi, vminfo, swap_avail);
1195 SAVE_UINT64(ksi, vminfo, swap_free);
1196 SAVE_UINT64(ksi, vminfo, updates);
1197 }
1198
1199 static void
save_nfs(kstat_t * kp,ks_instance_t * ksi)1200 save_nfs(kstat_t *kp, ks_instance_t *ksi)
1201 {
1202 struct mntinfo_kstat *mntinfo = (struct mntinfo_kstat *)(kp->ks_data);
1203
1204 assert(kp->ks_data_size == sizeof (struct mntinfo_kstat));
1205
1206 SAVE_STRING(ksi, mntinfo, mik_proto);
1207 SAVE_UINT32(ksi, mntinfo, mik_vers);
1208 SAVE_UINT32(ksi, mntinfo, mik_flags);
1209 SAVE_UINT32(ksi, mntinfo, mik_secmod);
1210 SAVE_UINT32(ksi, mntinfo, mik_curread);
1211 SAVE_UINT32(ksi, mntinfo, mik_curwrite);
1212 SAVE_INT32(ksi, mntinfo, mik_timeo);
1213 SAVE_INT32(ksi, mntinfo, mik_retrans);
1214 SAVE_UINT32(ksi, mntinfo, mik_acregmin);
1215 SAVE_UINT32(ksi, mntinfo, mik_acregmax);
1216 SAVE_UINT32(ksi, mntinfo, mik_acdirmin);
1217 SAVE_UINT32(ksi, mntinfo, mik_acdirmax);
1218 SAVE_UINT32_X(ksi, "lookup_srtt", mntinfo->mik_timers[0].srtt);
1219 SAVE_UINT32_X(ksi, "lookup_deviate", mntinfo->mik_timers[0].deviate);
1220 SAVE_UINT32_X(ksi, "lookup_rtxcur", mntinfo->mik_timers[0].rtxcur);
1221 SAVE_UINT32_X(ksi, "read_srtt", mntinfo->mik_timers[1].srtt);
1222 SAVE_UINT32_X(ksi, "read_deviate", mntinfo->mik_timers[1].deviate);
1223 SAVE_UINT32_X(ksi, "read_rtxcur", mntinfo->mik_timers[1].rtxcur);
1224 SAVE_UINT32_X(ksi, "write_srtt", mntinfo->mik_timers[2].srtt);
1225 SAVE_UINT32_X(ksi, "write_deviate", mntinfo->mik_timers[2].deviate);
1226 SAVE_UINT32_X(ksi, "write_rtxcur", mntinfo->mik_timers[2].rtxcur);
1227 SAVE_UINT32(ksi, mntinfo, mik_noresponse);
1228 SAVE_UINT32(ksi, mntinfo, mik_failover);
1229 SAVE_UINT32(ksi, mntinfo, mik_remap);
1230 SAVE_STRING(ksi, mntinfo, mik_curserver);
1231 }
1232
1233 #ifdef __sparc
1234 static void
save_sfmmu_global_stat(kstat_t * kp,ks_instance_t * ksi)1235 save_sfmmu_global_stat(kstat_t *kp, ks_instance_t *ksi)
1236 {
1237 struct sfmmu_global_stat *sfmmug =
1238 (struct sfmmu_global_stat *)(kp->ks_data);
1239
1240 assert(kp->ks_data_size == sizeof (struct sfmmu_global_stat));
1241
1242 SAVE_INT32(ksi, sfmmug, sf_tsb_exceptions);
1243 SAVE_INT32(ksi, sfmmug, sf_tsb_raise_exception);
1244 SAVE_INT32(ksi, sfmmug, sf_pagefaults);
1245 SAVE_INT32(ksi, sfmmug, sf_uhash_searches);
1246 SAVE_INT32(ksi, sfmmug, sf_uhash_links);
1247 SAVE_INT32(ksi, sfmmug, sf_khash_searches);
1248 SAVE_INT32(ksi, sfmmug, sf_khash_links);
1249 SAVE_INT32(ksi, sfmmug, sf_swapout);
1250 SAVE_INT32(ksi, sfmmug, sf_tsb_alloc);
1251 SAVE_INT32(ksi, sfmmug, sf_tsb_allocfail);
1252 SAVE_INT32(ksi, sfmmug, sf_tsb_sectsb_create);
1253 SAVE_INT32(ksi, sfmmug, sf_scd_1sttsb_alloc);
1254 SAVE_INT32(ksi, sfmmug, sf_scd_2ndtsb_alloc);
1255 SAVE_INT32(ksi, sfmmug, sf_scd_1sttsb_allocfail);
1256 SAVE_INT32(ksi, sfmmug, sf_scd_2ndtsb_allocfail);
1257 SAVE_INT32(ksi, sfmmug, sf_tteload8k);
1258 SAVE_INT32(ksi, sfmmug, sf_tteload64k);
1259 SAVE_INT32(ksi, sfmmug, sf_tteload512k);
1260 SAVE_INT32(ksi, sfmmug, sf_tteload4m);
1261 SAVE_INT32(ksi, sfmmug, sf_tteload32m);
1262 SAVE_INT32(ksi, sfmmug, sf_tteload256m);
1263 SAVE_INT32(ksi, sfmmug, sf_tsb_load8k);
1264 SAVE_INT32(ksi, sfmmug, sf_tsb_load4m);
1265 SAVE_INT32(ksi, sfmmug, sf_hblk_hit);
1266 SAVE_INT32(ksi, sfmmug, sf_hblk8_ncreate);
1267 SAVE_INT32(ksi, sfmmug, sf_hblk8_nalloc);
1268 SAVE_INT32(ksi, sfmmug, sf_hblk1_ncreate);
1269 SAVE_INT32(ksi, sfmmug, sf_hblk1_nalloc);
1270 SAVE_INT32(ksi, sfmmug, sf_hblk_slab_cnt);
1271 SAVE_INT32(ksi, sfmmug, sf_hblk_reserve_cnt);
1272 SAVE_INT32(ksi, sfmmug, sf_hblk_recurse_cnt);
1273 SAVE_INT32(ksi, sfmmug, sf_hblk_reserve_hit);
1274 SAVE_INT32(ksi, sfmmug, sf_get_free_success);
1275 SAVE_INT32(ksi, sfmmug, sf_get_free_throttle);
1276 SAVE_INT32(ksi, sfmmug, sf_get_free_fail);
1277 SAVE_INT32(ksi, sfmmug, sf_put_free_success);
1278 SAVE_INT32(ksi, sfmmug, sf_put_free_fail);
1279 SAVE_INT32(ksi, sfmmug, sf_pgcolor_conflict);
1280 SAVE_INT32(ksi, sfmmug, sf_uncache_conflict);
1281 SAVE_INT32(ksi, sfmmug, sf_unload_conflict);
1282 SAVE_INT32(ksi, sfmmug, sf_ism_uncache);
1283 SAVE_INT32(ksi, sfmmug, sf_ism_recache);
1284 SAVE_INT32(ksi, sfmmug, sf_recache);
1285 SAVE_INT32(ksi, sfmmug, sf_steal_count);
1286 SAVE_INT32(ksi, sfmmug, sf_pagesync);
1287 SAVE_INT32(ksi, sfmmug, sf_clrwrt);
1288 SAVE_INT32(ksi, sfmmug, sf_pagesync_invalid);
1289 SAVE_INT32(ksi, sfmmug, sf_kernel_xcalls);
1290 SAVE_INT32(ksi, sfmmug, sf_user_xcalls);
1291 SAVE_INT32(ksi, sfmmug, sf_tsb_grow);
1292 SAVE_INT32(ksi, sfmmug, sf_tsb_shrink);
1293 SAVE_INT32(ksi, sfmmug, sf_tsb_resize_failures);
1294 SAVE_INT32(ksi, sfmmug, sf_tsb_reloc);
1295 SAVE_INT32(ksi, sfmmug, sf_user_vtop);
1296 SAVE_INT32(ksi, sfmmug, sf_ctx_inv);
1297 SAVE_INT32(ksi, sfmmug, sf_tlb_reprog_pgsz);
1298 SAVE_INT32(ksi, sfmmug, sf_region_remap_demap);
1299 SAVE_INT32(ksi, sfmmug, sf_create_scd);
1300 SAVE_INT32(ksi, sfmmug, sf_join_scd);
1301 SAVE_INT32(ksi, sfmmug, sf_leave_scd);
1302 SAVE_INT32(ksi, sfmmug, sf_destroy_scd);
1303 }
1304 #endif
1305
1306 #ifdef __sparc
1307 static void
save_sfmmu_tsbsize_stat(kstat_t * kp,ks_instance_t * ksi)1308 save_sfmmu_tsbsize_stat(kstat_t *kp, ks_instance_t *ksi)
1309 {
1310 struct sfmmu_tsbsize_stat *sfmmut;
1311
1312 assert(kp->ks_data_size == sizeof (struct sfmmu_tsbsize_stat));
1313 sfmmut = (struct sfmmu_tsbsize_stat *)(kp->ks_data);
1314
1315 SAVE_INT32(ksi, sfmmut, sf_tsbsz_8k);
1316 SAVE_INT32(ksi, sfmmut, sf_tsbsz_16k);
1317 SAVE_INT32(ksi, sfmmut, sf_tsbsz_32k);
1318 SAVE_INT32(ksi, sfmmut, sf_tsbsz_64k);
1319 SAVE_INT32(ksi, sfmmut, sf_tsbsz_128k);
1320 SAVE_INT32(ksi, sfmmut, sf_tsbsz_256k);
1321 SAVE_INT32(ksi, sfmmut, sf_tsbsz_512k);
1322 SAVE_INT32(ksi, sfmmut, sf_tsbsz_1m);
1323 SAVE_INT32(ksi, sfmmut, sf_tsbsz_2m);
1324 SAVE_INT32(ksi, sfmmut, sf_tsbsz_4m);
1325 }
1326 #endif
1327
1328 static void
save_named(kstat_t * kp,ks_instance_t * ksi)1329 save_named(kstat_t *kp, ks_instance_t *ksi)
1330 {
1331 kstat_named_t *knp;
1332 int n;
1333
1334 for (n = kp->ks_ndata, knp = KSTAT_NAMED_PTR(kp); n > 0; n--, knp++) {
1335 /*
1336 * Annoyingly, some drivers have kstats with uninitialized
1337 * members (which kstat_install(9F) is sadly powerless to
1338 * prevent, and kstat_read(3KSTAT) unfortunately does nothing
1339 * to stop). To prevent these from confusing us to be
1340 * KSTAT_DATA_CHAR statistics, we skip over them.
1341 */
1342 if (knp->name[0] == '\0')
1343 continue;
1344
1345 switch (knp->data_type) {
1346 case KSTAT_DATA_CHAR:
1347 nvpair_insert(ksi, knp->name,
1348 (ks_value_t *)&knp->value, KSTAT_DATA_CHAR);
1349 break;
1350 case KSTAT_DATA_INT32:
1351 nvpair_insert(ksi, knp->name,
1352 (ks_value_t *)&knp->value, KSTAT_DATA_INT32);
1353 break;
1354 case KSTAT_DATA_UINT32:
1355 nvpair_insert(ksi, knp->name,
1356 (ks_value_t *)&knp->value, KSTAT_DATA_UINT32);
1357 break;
1358 case KSTAT_DATA_INT64:
1359 nvpair_insert(ksi, knp->name,
1360 (ks_value_t *)&knp->value, KSTAT_DATA_INT64);
1361 break;
1362 case KSTAT_DATA_UINT64:
1363 nvpair_insert(ksi, knp->name,
1364 (ks_value_t *)&knp->value, KSTAT_DATA_UINT64);
1365 break;
1366 case KSTAT_DATA_STRING:
1367 SAVE_STRING_X(ksi, knp->name, KSTAT_NAMED_STR_PTR(knp));
1368 break;
1369 default:
1370 assert(B_FALSE); /* Invalid data type */
1371 break;
1372 }
1373 }
1374 }
1375
1376 static void
save_intr(kstat_t * kp,ks_instance_t * ksi)1377 save_intr(kstat_t *kp, ks_instance_t *ksi)
1378 {
1379 kstat_intr_t *intr = KSTAT_INTR_PTR(kp);
1380 char *intr_names[] = {"hard", "soft", "watchdog", "spurious",
1381 "multiple_service"};
1382 int n;
1383
1384 for (n = 0; n < KSTAT_NUM_INTRS; n++)
1385 SAVE_UINT32_X(ksi, intr_names[n], intr->intrs[n]);
1386 }
1387
1388 static void
save_io(kstat_t * kp,ks_instance_t * ksi)1389 save_io(kstat_t *kp, ks_instance_t *ksi)
1390 {
1391 kstat_io_t *ksio = KSTAT_IO_PTR(kp);
1392
1393 SAVE_UINT64(ksi, ksio, nread);
1394 SAVE_UINT64(ksi, ksio, nwritten);
1395 SAVE_UINT32(ksi, ksio, reads);
1396 SAVE_UINT32(ksi, ksio, writes);
1397 SAVE_HRTIME(ksi, ksio, wtime);
1398 SAVE_HRTIME(ksi, ksio, wlentime);
1399 SAVE_HRTIME(ksi, ksio, wlastupdate);
1400 SAVE_HRTIME(ksi, ksio, rtime);
1401 SAVE_HRTIME(ksi, ksio, rlentime);
1402 SAVE_HRTIME(ksi, ksio, rlastupdate);
1403 SAVE_UINT32(ksi, ksio, wcnt);
1404 SAVE_UINT32(ksi, ksio, rcnt);
1405 }
1406
1407 static void
save_timer(kstat_t * kp,ks_instance_t * ksi)1408 save_timer(kstat_t *kp, ks_instance_t *ksi)
1409 {
1410 kstat_timer_t *ktimer = KSTAT_TIMER_PTR(kp);
1411
1412 SAVE_STRING(ksi, ktimer, name);
1413 SAVE_UINT64(ksi, ktimer, num_events);
1414 SAVE_HRTIME(ksi, ktimer, elapsed_time);
1415 SAVE_HRTIME(ksi, ktimer, min_time);
1416 SAVE_HRTIME(ksi, ktimer, max_time);
1417 SAVE_HRTIME(ksi, ktimer, start_time);
1418 SAVE_HRTIME(ksi, ktimer, stop_time);
1419 }
1420