xref: /illumos-gate/usr/src/cmd/stat/kstat/kstat.c (revision 66448911ac89c254e89afc52e114402115a497e3)
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 }
1471