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