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