xref: /titanic_53/usr/src/cmd/stat/kstat/kstat.c (revision 5918f984c877663f045498a174106df2e489ab55)
166448911SDavid Höppner /*
266448911SDavid Höppner  * CDDL HEADER START
366448911SDavid Höppner  *
466448911SDavid Höppner  * The contents of this file are subject to the terms of the
566448911SDavid Höppner  * Common Development and Distribution License (the "License").
666448911SDavid Höppner  * You may not use this file except in compliance with the License.
766448911SDavid Höppner  *
866448911SDavid Höppner  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
966448911SDavid Höppner  * or http://www.opensolaris.org/os/licensing.
1066448911SDavid Höppner  * See the License for the specific language governing permissions
1166448911SDavid Höppner  * and limitations under the License.
1266448911SDavid Höppner  *
1366448911SDavid Höppner  * When distributing Covered Code, include this CDDL HEADER in each
1466448911SDavid Höppner  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1566448911SDavid Höppner  * If applicable, add the following below this CDDL HEADER, with the
1666448911SDavid Höppner  * fields enclosed by brackets "[]" replaced with your own identifying
1766448911SDavid Höppner  * information: Portions Copyright [yyyy] [name of copyright owner]
1866448911SDavid Höppner  *
1966448911SDavid Höppner  * CDDL HEADER END
2066448911SDavid Höppner  */
2166448911SDavid Höppner 
2266448911SDavid Höppner /*
2366448911SDavid Höppner  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
2466448911SDavid Höppner  * Copyright (c) 2013 David Hoeppner. All rights reserved.
2566448911SDavid Höppner  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
2666448911SDavid Höppner  */
2766448911SDavid Höppner 
2866448911SDavid Höppner /*
2966448911SDavid Höppner  * Display kernel statistics
3066448911SDavid Höppner  *
3166448911SDavid Höppner  * This is a reimplementation of the perl kstat command originally found
3266448911SDavid Höppner  * under usr/src/cmd/kstat/kstat.pl
3366448911SDavid Höppner  *
3466448911SDavid Höppner  * Incompatibilities:
3566448911SDavid Höppner  *	- perl regular expressions replaced with extended REs bracketed by '/'
3666448911SDavid Höppner  *
3766448911SDavid Höppner  * Flags added:
3866448911SDavid Höppner  *	-C	similar to the -p option but value is separated by a colon
3966448911SDavid Höppner  *	-h	display help
4066448911SDavid Höppner  *	-j	json format
4166448911SDavid Höppner  */
4266448911SDavid Höppner 
4366448911SDavid Höppner #include <assert.h>
4466448911SDavid Höppner #include <ctype.h>
4566448911SDavid Höppner #include <errno.h>
4666448911SDavid Höppner #include <kstat.h>
4766448911SDavid Höppner #include <langinfo.h>
4866448911SDavid Höppner #include <libgen.h>
4966448911SDavid Höppner #include <limits.h>
5066448911SDavid Höppner #include <locale.h>
5166448911SDavid Höppner #include <signal.h>
5266448911SDavid Höppner #include <stddef.h>
5366448911SDavid Höppner #include <stdio.h>
5466448911SDavid Höppner #include <stdlib.h>
5566448911SDavid Höppner #include <string.h>
5666448911SDavid Höppner #include <strings.h>
5766448911SDavid Höppner #include <time.h>
5866448911SDavid Höppner #include <unistd.h>
5966448911SDavid Höppner #include <sys/list.h>
6066448911SDavid Höppner #include <sys/time.h>
6166448911SDavid Höppner #include <sys/types.h>
6266448911SDavid Höppner 
6366448911SDavid Höppner #include "kstat.h"
6466448911SDavid Höppner #include "statcommon.h"
6566448911SDavid Höppner 
6666448911SDavid Höppner char	*cmdname = "kstat";	/* Name of this command */
6766448911SDavid Höppner int	caught_cont = 0;	/* Have caught a SIGCONT */
6866448911SDavid Höppner 
6966448911SDavid Höppner static uint_t	g_timestamp_fmt = NODATE;
7066448911SDavid Höppner 
7166448911SDavid Höppner /* Helper flag - header was printed already? */
7266448911SDavid Höppner static boolean_t g_headerflg;
7366448911SDavid Höppner 
7466448911SDavid Höppner /* Saved command line options */
7566448911SDavid Höppner static boolean_t g_cflg = B_FALSE;
7666448911SDavid Höppner static boolean_t g_jflg = B_FALSE;
7766448911SDavid Höppner static boolean_t g_lflg = B_FALSE;
7866448911SDavid Höppner static boolean_t g_pflg = B_FALSE;
7966448911SDavid Höppner static boolean_t g_qflg = B_FALSE;
8066448911SDavid Höppner static ks_pattern_t	g_ks_class = {"*", 0};
8166448911SDavid Höppner 
8266448911SDavid Höppner /* Return zero if a selector did match */
8366448911SDavid Höppner static int	g_matched = 1;
8466448911SDavid Höppner 
8566448911SDavid Höppner /* Sorted list of kstat instances */
8666448911SDavid Höppner static list_t	instances_list;
8766448911SDavid Höppner static list_t	selector_list;
8866448911SDavid Höppner 
8966448911SDavid Höppner int
9066448911SDavid Höppner main(int argc, char **argv)
9166448911SDavid Höppner {
9266448911SDavid Höppner 	ks_selector_t	*nselector;
9366448911SDavid Höppner 	ks_selector_t	*uselector;
9466448911SDavid Höppner 	kstat_ctl_t	*kc;
9566448911SDavid Höppner 	hrtime_t	start_n;
9666448911SDavid Höppner 	hrtime_t	period_n;
9766448911SDavid Höppner 	boolean_t	errflg = B_FALSE;
9866448911SDavid Höppner 	boolean_t	nselflg = B_FALSE;
9966448911SDavid Höppner 	boolean_t	uselflg = B_FALSE;
10066448911SDavid Höppner 	char		*q;
10166448911SDavid Höppner 	int		count = 1;
10266448911SDavid Höppner 	int		infinite_cycles = 0;
10366448911SDavid Höppner 	int		interval = 0;
10466448911SDavid Höppner 	int		n = 0;
10566448911SDavid Höppner 	int		c, m, tmp;
10666448911SDavid Höppner 
10766448911SDavid Höppner 	(void) setlocale(LC_ALL, "");
10866448911SDavid Höppner #if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D */
10966448911SDavid Höppner #define	TEXT_DOMAIN "SYS_TEST"		/* Use this only if it wasn't */
11066448911SDavid Höppner #endif
11166448911SDavid Höppner 	(void) textdomain(TEXT_DOMAIN);
11266448911SDavid Höppner 
11366448911SDavid Höppner 	/*
11466448911SDavid Höppner 	 * Create the selector list and a dummy default selector to match
11566448911SDavid Höppner 	 * everything. While we process the cmdline options we will add
11666448911SDavid Höppner 	 * selectors to this list.
11766448911SDavid Höppner 	 */
11866448911SDavid Höppner 	list_create(&selector_list, sizeof (ks_selector_t),
11966448911SDavid Höppner 	    offsetof(ks_selector_t, ks_next));
12066448911SDavid Höppner 
12166448911SDavid Höppner 	nselector = new_selector();
12266448911SDavid Höppner 
12366448911SDavid Höppner 	/*
12466448911SDavid Höppner 	 * Parse named command line arguments.
12566448911SDavid Höppner 	 */
12666448911SDavid Höppner 	while ((c = getopt(argc, argv, "h?CqjlpT:m:i:n:s:c:")) != EOF)
12766448911SDavid Höppner 		switch (c) {
12866448911SDavid Höppner 		case 'h':
12966448911SDavid Höppner 		case '?':
13066448911SDavid Höppner 			usage();
13166448911SDavid Höppner 			exit(0);
13266448911SDavid Höppner 			break;
13366448911SDavid Höppner 		case 'C':
13466448911SDavid Höppner 			g_pflg = g_cflg = B_TRUE;
13566448911SDavid Höppner 			break;
13666448911SDavid Höppner 		case 'q':
13766448911SDavid Höppner 			g_qflg = B_TRUE;
13866448911SDavid Höppner 			break;
13966448911SDavid Höppner 		case 'j':
14066448911SDavid Höppner 			g_jflg = B_TRUE;
14166448911SDavid Höppner 			break;
14266448911SDavid Höppner 		case 'l':
14366448911SDavid Höppner 			g_pflg = g_lflg = B_TRUE;
14466448911SDavid Höppner 			break;
14566448911SDavid Höppner 		case 'p':
14666448911SDavid Höppner 			g_pflg = B_TRUE;
14766448911SDavid Höppner 			break;
14866448911SDavid Höppner 		case 'T':
14966448911SDavid Höppner 			switch (*optarg) {
15066448911SDavid Höppner 			case 'd':
15166448911SDavid Höppner 				g_timestamp_fmt = DDATE;
15266448911SDavid Höppner 				break;
15366448911SDavid Höppner 			case 'u':
15466448911SDavid Höppner 				g_timestamp_fmt = UDATE;
15566448911SDavid Höppner 				break;
15666448911SDavid Höppner 			default:
15766448911SDavid Höppner 				errflg = B_TRUE;
15866448911SDavid Höppner 			}
15966448911SDavid Höppner 			break;
16066448911SDavid Höppner 		case 'm':
16166448911SDavid Höppner 			nselflg = B_TRUE;
16266448911SDavid Höppner 			nselector->ks_module.pstr =
16366448911SDavid Höppner 			    (char *)ks_safe_strdup(optarg);
16466448911SDavid Höppner 			break;
16566448911SDavid Höppner 		case 'i':
16666448911SDavid Höppner 			nselflg = B_TRUE;
16766448911SDavid Höppner 			nselector->ks_instance.pstr =
16866448911SDavid Höppner 			    (char *)ks_safe_strdup(optarg);
16966448911SDavid Höppner 			break;
17066448911SDavid Höppner 		case 'n':
17166448911SDavid Höppner 			nselflg = B_TRUE;
17266448911SDavid Höppner 			nselector->ks_name.pstr =
17366448911SDavid Höppner 			    (char *)ks_safe_strdup(optarg);
17466448911SDavid Höppner 			break;
17566448911SDavid Höppner 		case 's':
17666448911SDavid Höppner 			nselflg = B_TRUE;
17766448911SDavid Höppner 			nselector->ks_statistic.pstr =
17866448911SDavid Höppner 			    (char *)ks_safe_strdup(optarg);
17966448911SDavid Höppner 			break;
18066448911SDavid Höppner 		case 'c':
18166448911SDavid Höppner 			g_ks_class.pstr =
18266448911SDavid Höppner 			    (char *)ks_safe_strdup(optarg);
18366448911SDavid Höppner 			break;
18466448911SDavid Höppner 		default:
18566448911SDavid Höppner 			errflg = B_TRUE;
18666448911SDavid Höppner 			break;
18766448911SDavid Höppner 		}
18866448911SDavid Höppner 
18966448911SDavid Höppner 	if (g_qflg && (g_jflg || g_pflg)) {
19066448911SDavid Höppner 		(void) fprintf(stderr, gettext(
19166448911SDavid Höppner 		    "-q and -lpj are mutually exclusive\n"));
19266448911SDavid Höppner 		errflg = B_TRUE;
19366448911SDavid Höppner 	}
19466448911SDavid Höppner 
19566448911SDavid Höppner 	if (errflg) {
19666448911SDavid Höppner 		usage();
19766448911SDavid Höppner 		exit(2);
19866448911SDavid Höppner 	}
19966448911SDavid Höppner 
20066448911SDavid Höppner 	argc -= optind;
20166448911SDavid Höppner 	argv += optind;
20266448911SDavid Höppner 
20366448911SDavid Höppner 	/*
20466448911SDavid Höppner 	 * Consume the rest of the command line. Parsing the
20566448911SDavid Höppner 	 * unnamed command line arguments.
20666448911SDavid Höppner 	 */
20766448911SDavid Höppner 	while (argc--) {
20866448911SDavid Höppner 		errno = 0;
20966448911SDavid Höppner 		tmp = strtoul(*argv, &q, 10);
21066448911SDavid Höppner 		if (tmp == ULONG_MAX && errno == ERANGE) {
21166448911SDavid Höppner 			if (n == 0) {
21266448911SDavid Höppner 				(void) fprintf(stderr, gettext(
21366448911SDavid Höppner 				    "Interval is too large\n"));
21466448911SDavid Höppner 			} else if (n == 1) {
21566448911SDavid Höppner 				(void) fprintf(stderr, gettext(
21666448911SDavid Höppner 				    "Count is too large\n"));
21766448911SDavid Höppner 			}
21866448911SDavid Höppner 			usage();
21966448911SDavid Höppner 			exit(2);
22066448911SDavid Höppner 		}
22166448911SDavid Höppner 
22266448911SDavid Höppner 		if (errno != 0 || *q != '\0') {
22366448911SDavid Höppner 			m = 0;
22466448911SDavid Höppner 			uselector = new_selector();
22566448911SDavid Höppner 			while ((q = (char *)strsep(argv, ":")) != NULL) {
22666448911SDavid Höppner 				m++;
22766448911SDavid Höppner 				if (m > 4) {
22866448911SDavid Höppner 					free(uselector);
22966448911SDavid Höppner 					usage();
23066448911SDavid Höppner 					exit(2);
23166448911SDavid Höppner 				}
23266448911SDavid Höppner 
23366448911SDavid Höppner 				if (*q != '\0') {
23466448911SDavid Höppner 					switch (m) {
23566448911SDavid Höppner 					case 1:
23666448911SDavid Höppner 						uselector->ks_module.pstr =
23766448911SDavid Höppner 						    (char *)ks_safe_strdup(q);
23866448911SDavid Höppner 						break;
23966448911SDavid Höppner 					case 2:
24066448911SDavid Höppner 						uselector->ks_instance.pstr =
24166448911SDavid Höppner 						    (char *)ks_safe_strdup(q);
24266448911SDavid Höppner 						break;
24366448911SDavid Höppner 					case 3:
24466448911SDavid Höppner 						uselector->ks_name.pstr =
24566448911SDavid Höppner 						    (char *)ks_safe_strdup(q);
24666448911SDavid Höppner 						break;
24766448911SDavid Höppner 					case 4:
24866448911SDavid Höppner 						uselector->ks_statistic.pstr =
24966448911SDavid Höppner 						    (char *)ks_safe_strdup(q);
25066448911SDavid Höppner 						break;
25166448911SDavid Höppner 					default:
25266448911SDavid Höppner 						assert(B_FALSE);
25366448911SDavid Höppner 					}
25466448911SDavid Höppner 				}
25566448911SDavid Höppner 			}
25666448911SDavid Höppner 
25766448911SDavid Höppner 			uselflg = B_TRUE;
25866448911SDavid Höppner 			list_insert_tail(&selector_list, uselector);
25966448911SDavid Höppner 		} else {
26066448911SDavid Höppner 			if (tmp < 1) {
26166448911SDavid Höppner 				if (n == 0) {
26266448911SDavid Höppner 					(void) fprintf(stderr, gettext(
26366448911SDavid Höppner 					    "Interval must be an "
26466448911SDavid Höppner 					    "integer >= 1"));
26566448911SDavid Höppner 				} else if (n == 1) {
26666448911SDavid Höppner 					(void) fprintf(stderr, gettext(
26766448911SDavid Höppner 					    "Count must be an integer >= 1"));
26866448911SDavid Höppner 				}
26966448911SDavid Höppner 				usage();
27066448911SDavid Höppner 				exit(2);
27166448911SDavid Höppner 			} else {
27266448911SDavid Höppner 				if (n == 0) {
27366448911SDavid Höppner 					interval = tmp;
27466448911SDavid Höppner 					count = -1;
27566448911SDavid Höppner 				} else if (n == 1) {
27666448911SDavid Höppner 					count = tmp;
27766448911SDavid Höppner 				} else {
27866448911SDavid Höppner 					usage();
27966448911SDavid Höppner 					exit(2);
28066448911SDavid Höppner 				}
28166448911SDavid Höppner 			}
28266448911SDavid Höppner 			n++;
28366448911SDavid Höppner 		}
28466448911SDavid Höppner 		argv++;
28566448911SDavid Höppner 	}
28666448911SDavid Höppner 
28766448911SDavid Höppner 	/*
28866448911SDavid Höppner 	 * Check if we founded a named selector on the cmdline.
28966448911SDavid Höppner 	 */
29066448911SDavid Höppner 	if (uselflg) {
29166448911SDavid Höppner 		if (nselflg) {
29266448911SDavid Höppner 			(void) fprintf(stderr, gettext(
293617413d1SRichard Lowe 			    "[module[:instance[:name[:statistic]]]] and "
29466448911SDavid Höppner 			    "-m -i -n -s are mutually exclusive"));
29566448911SDavid Höppner 			usage();
29666448911SDavid Höppner 			exit(2);
29766448911SDavid Höppner 		} else {
29866448911SDavid Höppner 			free(nselector);
29966448911SDavid Höppner 		}
30066448911SDavid Höppner 	} else {
30166448911SDavid Höppner 		list_insert_tail(&selector_list, nselector);
30266448911SDavid Höppner 	}
30366448911SDavid Höppner 
30466448911SDavid Höppner 	assert(!list_is_empty(&selector_list));
30566448911SDavid Höppner 
30666448911SDavid Höppner 	list_create(&instances_list, sizeof (ks_instance_t),
30766448911SDavid Höppner 	    offsetof(ks_instance_t, ks_next));
30866448911SDavid Höppner 
30966448911SDavid Höppner 	while ((kc = kstat_open()) == NULL) {
31066448911SDavid Höppner 		if (errno == EAGAIN) {
31166448911SDavid Höppner 			(void) poll(NULL, 0, 200);
31266448911SDavid Höppner 		} else {
31366448911SDavid Höppner 			perror("kstat_open");
31466448911SDavid Höppner 			exit(3);
31566448911SDavid Höppner 		}
31666448911SDavid Höppner 	}
31766448911SDavid Höppner 
31866448911SDavid Höppner 	if (count > 1) {
31966448911SDavid Höppner 		if (signal(SIGCONT, cont_handler) == SIG_ERR) {
32066448911SDavid Höppner 			(void) fprintf(stderr, gettext(
32166448911SDavid Höppner 			    "signal failed"));
32266448911SDavid Höppner 			exit(3);
32366448911SDavid Höppner 		}
32466448911SDavid Höppner 	}
32566448911SDavid Höppner 
32666448911SDavid Höppner 	period_n = (hrtime_t)interval * NANOSEC;
32766448911SDavid Höppner 	start_n = gethrtime();
32866448911SDavid Höppner 
32966448911SDavid Höppner 	while (count == -1 || count-- > 0) {
33066448911SDavid Höppner 		ks_instances_read(kc);
33166448911SDavid Höppner 		ks_instances_print();
33266448911SDavid Höppner 
33366448911SDavid Höppner 		if (interval && count) {
33466448911SDavid Höppner 			ks_sleep_until(&start_n, period_n, infinite_cycles,
33566448911SDavid Höppner 			    &caught_cont);
33666448911SDavid Höppner 			(void) kstat_chain_update(kc);
33766448911SDavid Höppner 			(void) putchar('\n');
33866448911SDavid Höppner 		}
33966448911SDavid Höppner 	}
34066448911SDavid Höppner 
34166448911SDavid Höppner 	(void) kstat_close(kc);
34266448911SDavid Höppner 
34366448911SDavid Höppner 	return (g_matched);
34466448911SDavid Höppner }
34566448911SDavid Höppner 
34666448911SDavid Höppner /*
34766448911SDavid Höppner  * Print usage.
34866448911SDavid Höppner  */
34966448911SDavid Höppner static void
35066448911SDavid Höppner usage(void)
35166448911SDavid Höppner {
35266448911SDavid Höppner 	(void) fprintf(stderr, gettext(
35366448911SDavid Höppner 	    "Usage:\n"
35466448911SDavid Höppner 	    "kstat [ -Cjlpq ] [ -T d|u ] [ -c class ]\n"
35566448911SDavid Höppner 	    "      [ -m module ] [ -i instance ] [ -n name ] [ -s statistic ]\n"
35666448911SDavid Höppner 	    "      [ interval [ count ] ]\n"
35766448911SDavid Höppner 	    "kstat [ -Cjlpq ] [ -T d|u ] [ -c class ]\n"
358617413d1SRichard Lowe 	    "      [ module[:instance[:name[:statistic]]] ... ]\n"
35966448911SDavid Höppner 	    "      [ interval [ count ] ]\n"));
36066448911SDavid Höppner }
36166448911SDavid Höppner 
36266448911SDavid Höppner /*
36366448911SDavid Höppner  * Sort compare function.
36466448911SDavid Höppner  */
36566448911SDavid Höppner static int
36666448911SDavid Höppner compare_instances(ks_instance_t *l_arg, ks_instance_t *r_arg)
36766448911SDavid Höppner {
36866448911SDavid Höppner 	int	rval;
36966448911SDavid Höppner 
37066448911SDavid Höppner 	rval = strcasecmp(l_arg->ks_module, r_arg->ks_module);
37166448911SDavid Höppner 	if (rval == 0) {
37266448911SDavid Höppner 		if (l_arg->ks_instance == r_arg->ks_instance) {
37366448911SDavid Höppner 			return (strcasecmp(l_arg->ks_name, r_arg->ks_name));
37466448911SDavid Höppner 		} else if (l_arg->ks_instance < r_arg->ks_instance) {
37566448911SDavid Höppner 			return (-1);
37666448911SDavid Höppner 		} else {
37766448911SDavid Höppner 			return (1);
37866448911SDavid Höppner 		}
37966448911SDavid Höppner 	} else {
38066448911SDavid Höppner 		return (rval);
38166448911SDavid Höppner 	}
38266448911SDavid Höppner }
38366448911SDavid Höppner 
38466448911SDavid Höppner static char *
38566448911SDavid Höppner ks_safe_strdup(char *str)
38666448911SDavid Höppner {
38766448911SDavid Höppner 	char	*ret;
38866448911SDavid Höppner 
38966448911SDavid Höppner 	if (str == NULL) {
39066448911SDavid Höppner 		return (NULL);
39166448911SDavid Höppner 	}
39266448911SDavid Höppner 
39366448911SDavid Höppner 	while ((ret = strdup(str)) == NULL) {
39466448911SDavid Höppner 		if (errno == EAGAIN) {
39566448911SDavid Höppner 			(void) poll(NULL, 0, 200);
39666448911SDavid Höppner 		} else {
39766448911SDavid Höppner 			perror("strdup");
39866448911SDavid Höppner 			exit(3);
39966448911SDavid Höppner 		}
40066448911SDavid Höppner 	}
40166448911SDavid Höppner 
40266448911SDavid Höppner 	return (ret);
40366448911SDavid Höppner }
40466448911SDavid Höppner 
40566448911SDavid Höppner static void
40666448911SDavid Höppner ks_sleep_until(hrtime_t *wakeup, hrtime_t interval, int forever,
40766448911SDavid Höppner     int *caught_cont)
40866448911SDavid Höppner {
40966448911SDavid Höppner 	hrtime_t	now, pause, pause_left;
41066448911SDavid Höppner 	struct timespec	pause_tv;
41166448911SDavid Höppner 	int		status;
41266448911SDavid Höppner 
41366448911SDavid Höppner 	now = gethrtime();
41466448911SDavid Höppner 	pause = *wakeup + interval - now;
41566448911SDavid Höppner 
41666448911SDavid Höppner 	if (pause <= 0 || pause < (interval / 4)) {
41766448911SDavid Höppner 		if (forever || *caught_cont) {
41866448911SDavid Höppner 			*wakeup = now + interval;
41966448911SDavid Höppner 			pause = interval;
42066448911SDavid Höppner 		} else {
42166448911SDavid Höppner 			pause = interval / 2;
42266448911SDavid Höppner 			*wakeup += interval;
42366448911SDavid Höppner 		}
42466448911SDavid Höppner 	} else {
42566448911SDavid Höppner 		*wakeup += interval;
42666448911SDavid Höppner 	}
42766448911SDavid Höppner 
42866448911SDavid Höppner 	if (pause < 1000) {
42966448911SDavid Höppner 		return;
43066448911SDavid Höppner 	}
43166448911SDavid Höppner 
43266448911SDavid Höppner 	pause_left = pause;
43366448911SDavid Höppner 	do {
43466448911SDavid Höppner 		pause_tv.tv_sec = pause_left / NANOSEC;
43566448911SDavid Höppner 		pause_tv.tv_nsec = pause_left % NANOSEC;
43666448911SDavid Höppner 		status = nanosleep(&pause_tv, (struct timespec *)NULL);
43766448911SDavid Höppner 		if (status < 0) {
43866448911SDavid Höppner 			if (errno == EINTR) {
43966448911SDavid Höppner 				now = gethrtime();
44066448911SDavid Höppner 				pause_left = *wakeup - now;
44166448911SDavid Höppner 				if (pause_left < 1000) {
44266448911SDavid Höppner 					return;
44366448911SDavid Höppner 				}
44466448911SDavid Höppner 			} else {
44566448911SDavid Höppner 				perror("nanosleep");
44666448911SDavid Höppner 				exit(3);
44766448911SDavid Höppner 			}
44866448911SDavid Höppner 		}
44966448911SDavid Höppner 	} while (status != 0);
45066448911SDavid Höppner }
45166448911SDavid Höppner 
45266448911SDavid Höppner /*
45366448911SDavid Höppner  * Inserts an instance in the per selector list.
45466448911SDavid Höppner  */
45566448911SDavid Höppner static void
45666448911SDavid Höppner nvpair_insert(ks_instance_t *ksi, char *name, ks_value_t *value,
45766448911SDavid Höppner     uchar_t data_type)
45866448911SDavid Höppner {
45966448911SDavid Höppner 	ks_nvpair_t	*instance;
46066448911SDavid Höppner 	ks_nvpair_t	*tmp;
46166448911SDavid Höppner 
46266448911SDavid Höppner 	instance = (ks_nvpair_t *)malloc(sizeof (ks_nvpair_t));
46366448911SDavid Höppner 	if (instance == NULL) {
46466448911SDavid Höppner 		perror("malloc");
46566448911SDavid Höppner 		exit(3);
46666448911SDavid Höppner 	}
46766448911SDavid Höppner 
46866448911SDavid Höppner 	(void) strlcpy(instance->name, name, KSTAT_STRLEN);
46966448911SDavid Höppner 	(void) memcpy(&instance->value, value, sizeof (ks_value_t));
47066448911SDavid Höppner 	instance->data_type = data_type;
47166448911SDavid Höppner 
47266448911SDavid Höppner 	tmp = list_head(&ksi->ks_nvlist);
47366448911SDavid Höppner 	while (tmp != NULL && strcasecmp(instance->name, tmp->name) > 0)
47466448911SDavid Höppner 		tmp = list_next(&ksi->ks_nvlist, tmp);
47566448911SDavid Höppner 
47666448911SDavid Höppner 	list_insert_before(&ksi->ks_nvlist, tmp, instance);
47766448911SDavid Höppner }
47866448911SDavid Höppner 
47966448911SDavid Höppner /*
48066448911SDavid Höppner  * Allocates a new all-matching selector.
48166448911SDavid Höppner  */
48266448911SDavid Höppner static ks_selector_t *
48366448911SDavid Höppner new_selector(void)
48466448911SDavid Höppner {
48566448911SDavid Höppner 	ks_selector_t	*selector;
48666448911SDavid Höppner 
48766448911SDavid Höppner 	selector = (ks_selector_t *)malloc(sizeof (ks_selector_t));
48866448911SDavid Höppner 	if (selector == NULL) {
48966448911SDavid Höppner 		perror("malloc");
49066448911SDavid Höppner 		exit(3);
49166448911SDavid Höppner 	}
49266448911SDavid Höppner 
49366448911SDavid Höppner 	list_link_init(&selector->ks_next);
49466448911SDavid Höppner 
49566448911SDavid Höppner 	selector->ks_module.pstr = "*";
49666448911SDavid Höppner 	selector->ks_instance.pstr = "*";
49766448911SDavid Höppner 	selector->ks_name.pstr = "*";
49866448911SDavid Höppner 	selector->ks_statistic.pstr = "*";
49966448911SDavid Höppner 
50066448911SDavid Höppner 	return (selector);
50166448911SDavid Höppner }
50266448911SDavid Höppner 
50366448911SDavid Höppner /*
50466448911SDavid Höppner  * This function was taken from the perl kstat module code - please
50566448911SDavid Höppner  * see for further comments there.
50666448911SDavid Höppner  */
50766448911SDavid Höppner static kstat_raw_reader_t
50866448911SDavid Höppner lookup_raw_kstat_fn(char *module, char *name)
50966448911SDavid Höppner {
51066448911SDavid Höppner 	char		key[KSTAT_STRLEN * 2];
51166448911SDavid Höppner 	register char 	*f, *t;
51266448911SDavid Höppner 	int		n = 0;
51366448911SDavid Höppner 
51466448911SDavid Höppner 	for (f = module, t = key; *f != '\0'; f++, t++) {
51566448911SDavid Höppner 		while (*f != '\0' && isdigit(*f))
51666448911SDavid Höppner 			f++;
51766448911SDavid Höppner 		*t = *f;
51866448911SDavid Höppner 	}
51966448911SDavid Höppner 	*t++ = ':';
52066448911SDavid Höppner 
52166448911SDavid Höppner 	for (f = name; *f != '\0'; f++, t++) {
52266448911SDavid Höppner 		while (*f != '\0' && isdigit(*f))
52366448911SDavid Höppner 			f++;
52466448911SDavid Höppner 		*t = *f;
52566448911SDavid Höppner 	}
52666448911SDavid Höppner 	*t = '\0';
52766448911SDavid Höppner 
52866448911SDavid Höppner 	while (ks_raw_lookup[n].fn != NULL) {
52966448911SDavid Höppner 		if (strncmp(ks_raw_lookup[n].name, key, strlen(key)) == 0)
53066448911SDavid Höppner 			return (ks_raw_lookup[n].fn);
53166448911SDavid Höppner 		n++;
53266448911SDavid Höppner 	}
53366448911SDavid Höppner 
53466448911SDavid Höppner 	return (0);
53566448911SDavid Höppner }
53666448911SDavid Höppner 
53766448911SDavid Höppner /*
53866448911SDavid Höppner  * Match a string against a shell glob or extended regular expression.
53966448911SDavid Höppner  */
54066448911SDavid Höppner static boolean_t
54166448911SDavid Höppner ks_match(const char *str, ks_pattern_t *pattern)
54266448911SDavid Höppner {
54366448911SDavid Höppner 	int	regcode;
54466448911SDavid Höppner 	char	*regstr;
54566448911SDavid Höppner 	char	*errbuf;
54666448911SDavid Höppner 	size_t	bufsz;
54766448911SDavid Höppner 
54866448911SDavid Höppner 	if (pattern->pstr != NULL && gmatch(pattern->pstr, "/*/") != 0) {
54966448911SDavid Höppner 		/* All regex patterns are strdup'd copies */
55066448911SDavid Höppner 		regstr = pattern->pstr + 1;
55166448911SDavid Höppner 		*(strrchr(regstr, '/')) = '\0';
55266448911SDavid Höppner 
55366448911SDavid Höppner 		regcode = regcomp(&pattern->preg, regstr,
55466448911SDavid Höppner 		    REG_EXTENDED | REG_NOSUB);
55566448911SDavid Höppner 		if (regcode != 0) {
55666448911SDavid Höppner 			bufsz = regerror(regcode, NULL, NULL, 0);
55766448911SDavid Höppner 			if (bufsz != 0) {
55866448911SDavid Höppner 				errbuf = malloc(bufsz);
55966448911SDavid Höppner 				if (errbuf == NULL) {
56066448911SDavid Höppner 					perror("malloc");
56166448911SDavid Höppner 					exit(3);
56266448911SDavid Höppner 				}
56366448911SDavid Höppner 				(void) regerror(regcode, NULL, errbuf, bufsz);
56466448911SDavid Höppner 				(void) fprintf(stderr, "kstat: %s\n", errbuf);
56566448911SDavid Höppner 			}
56666448911SDavid Höppner 			usage();
56766448911SDavid Höppner 			exit(2);
56866448911SDavid Höppner 		}
56966448911SDavid Höppner 
57066448911SDavid Höppner 		pattern->pstr = NULL;
57166448911SDavid Höppner 	}
57266448911SDavid Höppner 
57366448911SDavid Höppner 	if (pattern->pstr == NULL) {
57466448911SDavid Höppner 		return (regexec(&pattern->preg, str, 0, NULL, 0) == 0);
57566448911SDavid Höppner 	}
57666448911SDavid Höppner 
57766448911SDavid Höppner 	return ((gmatch(str, pattern->pstr) != 0));
57866448911SDavid Höppner }
57966448911SDavid Höppner 
58066448911SDavid Höppner /*
58166448911SDavid Höppner  * Iterate over all kernel statistics and save matches.
58266448911SDavid Höppner  */
58366448911SDavid Höppner static void
58466448911SDavid Höppner ks_instances_read(kstat_ctl_t *kc)
58566448911SDavid Höppner {
58666448911SDavid Höppner 	kstat_raw_reader_t save_raw = NULL;
58766448911SDavid Höppner 	kid_t		id;
58866448911SDavid Höppner 	ks_selector_t	*selector;
58966448911SDavid Höppner 	ks_instance_t	*ksi;
59066448911SDavid Höppner 	ks_instance_t	*tmp;
59166448911SDavid Höppner 	kstat_t		*kp;
59266448911SDavid Höppner 	boolean_t	skip;
59366448911SDavid Höppner 
59466448911SDavid Höppner 	for (kp = kc->kc_chain; kp != NULL; kp = kp->ks_next) {
59566448911SDavid Höppner 		/* Don't bother storing the kstat headers */
59666448911SDavid Höppner 		if (strncmp(kp->ks_name, "kstat_", 6) == 0) {
59766448911SDavid Höppner 			continue;
59866448911SDavid Höppner 		}
59966448911SDavid Höppner 
60066448911SDavid Höppner 		/* Don't bother storing raw stats we don't understand */
60166448911SDavid Höppner 		if (kp->ks_type == KSTAT_TYPE_RAW) {
60266448911SDavid Höppner 			save_raw = lookup_raw_kstat_fn(kp->ks_module,
60366448911SDavid Höppner 			    kp->ks_name);
60466448911SDavid Höppner 			if (save_raw == NULL) {
60566448911SDavid Höppner #ifdef REPORT_UNKNOWN
60666448911SDavid Höppner 				(void) fprintf(stderr,
60766448911SDavid Höppner 				    "Unknown kstat type %s:%d:%s - "
60866448911SDavid Höppner 				    "%d of size %d\n", kp->ks_module,
60966448911SDavid Höppner 				    kp->ks_instance, kp->ks_name,
61066448911SDavid Höppner 				    kp->ks_ndata, kp->ks_data_size);
61166448911SDavid Höppner #endif
61266448911SDavid Höppner 				continue;
61366448911SDavid Höppner 			}
61466448911SDavid Höppner 		}
61566448911SDavid Höppner 
61666448911SDavid Höppner 		/*
61766448911SDavid Höppner 		 * Iterate over the list of selectors and skip
61866448911SDavid Höppner 		 * instances we dont want. We filter for statistics
61966448911SDavid Höppner 		 * later, as we dont know them yet.
62066448911SDavid Höppner 		 */
62166448911SDavid Höppner 		skip = B_TRUE;
62266448911SDavid Höppner 		selector = list_head(&selector_list);
62366448911SDavid Höppner 		while (selector != NULL) {
62466448911SDavid Höppner 			if (ks_match(kp->ks_module, &selector->ks_module) ||
62566448911SDavid Höppner 			    ks_match(kp->ks_name, &selector->ks_name)) {
62666448911SDavid Höppner 				skip = B_FALSE;
62766448911SDavid Höppner 				break;
62866448911SDavid Höppner 			}
62966448911SDavid Höppner 			selector = list_next(&selector_list, selector);
63066448911SDavid Höppner 		}
63166448911SDavid Höppner 
63266448911SDavid Höppner 		if (skip) {
63366448911SDavid Höppner 			continue;
63466448911SDavid Höppner 		}
63566448911SDavid Höppner 
63666448911SDavid Höppner 		/*
63766448911SDavid Höppner 		 * Allocate a new instance and fill in the values
63866448911SDavid Höppner 		 * we know so far.
63966448911SDavid Höppner 		 */
64066448911SDavid Höppner 		ksi = (ks_instance_t *)malloc(sizeof (ks_instance_t));
64166448911SDavid Höppner 		if (ksi == NULL) {
64266448911SDavid Höppner 			perror("malloc");
64366448911SDavid Höppner 			exit(3);
64466448911SDavid Höppner 		}
64566448911SDavid Höppner 
64666448911SDavid Höppner 		list_link_init(&ksi->ks_next);
64766448911SDavid Höppner 
64866448911SDavid Höppner 		(void) strlcpy(ksi->ks_module, kp->ks_module, KSTAT_STRLEN);
64966448911SDavid Höppner 		(void) strlcpy(ksi->ks_name, kp->ks_name, KSTAT_STRLEN);
65066448911SDavid Höppner 		(void) strlcpy(ksi->ks_class, kp->ks_class, KSTAT_STRLEN);
65166448911SDavid Höppner 
65266448911SDavid Höppner 		ksi->ks_instance = kp->ks_instance;
65366448911SDavid Höppner 		ksi->ks_snaptime = kp->ks_snaptime;
65466448911SDavid Höppner 		ksi->ks_type = kp->ks_type;
65566448911SDavid Höppner 
65666448911SDavid Höppner 		list_create(&ksi->ks_nvlist, sizeof (ks_nvpair_t),
65766448911SDavid Höppner 		    offsetof(ks_nvpair_t, nv_next));
65866448911SDavid Höppner 
65966448911SDavid Höppner 		SAVE_HRTIME_X(ksi, "crtime", kp->ks_crtime);
66066448911SDavid Höppner 		SAVE_HRTIME_X(ksi, "snaptime", kp->ks_snaptime);
66166448911SDavid Höppner 		if (g_pflg) {
66266448911SDavid Höppner 			SAVE_STRING_X(ksi, "class", kp->ks_class);
66366448911SDavid Höppner 		}
66466448911SDavid Höppner 
66566448911SDavid Höppner 		/* Insert this instance into a sorted list */
66666448911SDavid Höppner 		tmp = list_head(&instances_list);
66766448911SDavid Höppner 		while (tmp != NULL && compare_instances(ksi, tmp) > 0)
66866448911SDavid Höppner 			tmp = list_next(&instances_list, tmp);
66966448911SDavid Höppner 
67066448911SDavid Höppner 		list_insert_before(&instances_list, tmp, ksi);
67166448911SDavid Höppner 
67266448911SDavid Höppner 		/* Read the actual statistics */
67366448911SDavid Höppner 		id = kstat_read(kc, kp, NULL);
67466448911SDavid Höppner 		if (id == -1) {
67566448911SDavid Höppner #ifdef REPORT_UNKNOWN
67666448911SDavid Höppner 			perror("kstat_read");
67766448911SDavid Höppner #endif
67866448911SDavid Höppner 			continue;
67966448911SDavid Höppner 		}
68066448911SDavid Höppner 
68166448911SDavid Höppner 		switch (kp->ks_type) {
68266448911SDavid Höppner 		case KSTAT_TYPE_RAW:
68366448911SDavid Höppner 			save_raw(kp, ksi);
68466448911SDavid Höppner 			break;
68566448911SDavid Höppner 		case KSTAT_TYPE_NAMED:
68666448911SDavid Höppner 			save_named(kp, ksi);
68766448911SDavid Höppner 			break;
68866448911SDavid Höppner 		case KSTAT_TYPE_INTR:
68966448911SDavid Höppner 			save_intr(kp, ksi);
69066448911SDavid Höppner 			break;
69166448911SDavid Höppner 		case KSTAT_TYPE_IO:
69266448911SDavid Höppner 			save_io(kp, ksi);
69366448911SDavid Höppner 			break;
69466448911SDavid Höppner 		case KSTAT_TYPE_TIMER:
69566448911SDavid Höppner 			save_timer(kp, ksi);
69666448911SDavid Höppner 			break;
69766448911SDavid Höppner 		default:
69866448911SDavid Höppner 			assert(B_FALSE); /* Invalid type */
69966448911SDavid Höppner 			break;
70066448911SDavid Höppner 		}
70166448911SDavid Höppner 	}
70266448911SDavid Höppner }
70366448911SDavid Höppner 
70466448911SDavid Höppner /*
70566448911SDavid Höppner  * Print the value of a name-value pair.
70666448911SDavid Höppner  */
70766448911SDavid Höppner static void
70866448911SDavid Höppner ks_value_print(ks_nvpair_t *nvpair)
70966448911SDavid Höppner {
71066448911SDavid Höppner 	switch (nvpair->data_type) {
71166448911SDavid Höppner 	case KSTAT_DATA_CHAR:
71266448911SDavid Höppner 		(void) fprintf(stdout, "%s", nvpair->value.c);
71366448911SDavid Höppner 		break;
71466448911SDavid Höppner 	case KSTAT_DATA_INT32:
71566448911SDavid Höppner 		(void) fprintf(stdout, "%d", nvpair->value.i32);
71666448911SDavid Höppner 		break;
71766448911SDavid Höppner 	case KSTAT_DATA_UINT32:
71866448911SDavid Höppner 		(void) fprintf(stdout, "%u", nvpair->value.ui32);
71966448911SDavid Höppner 		break;
72066448911SDavid Höppner 	case KSTAT_DATA_INT64:
72166448911SDavid Höppner 		(void) fprintf(stdout, "%lld", nvpair->value.i64);
72266448911SDavid Höppner 		break;
72366448911SDavid Höppner 	case KSTAT_DATA_UINT64:
72466448911SDavid Höppner 		(void) fprintf(stdout, "%llu", nvpair->value.ui64);
72566448911SDavid Höppner 		break;
72666448911SDavid Höppner 	case KSTAT_DATA_STRING:
72766448911SDavid Höppner 		(void) fprintf(stdout, "%s", KSTAT_NAMED_STR_PTR(nvpair));
72866448911SDavid Höppner 		break;
72966448911SDavid Höppner 	case KSTAT_DATA_HRTIME:
73066448911SDavid Höppner 		if (nvpair->value.ui64 == 0)
73166448911SDavid Höppner 			(void) fprintf(stdout, "0");
73266448911SDavid Höppner 		else
73366448911SDavid Höppner 			(void) fprintf(stdout, "%.9f",
73466448911SDavid Höppner 			    nvpair->value.ui64 / 1000000000.0);
73566448911SDavid Höppner 		break;
73666448911SDavid Höppner 	default:
73766448911SDavid Höppner 		assert(B_FALSE);
73866448911SDavid Höppner 	}
73966448911SDavid Höppner }
74066448911SDavid Höppner 
74166448911SDavid Höppner /*
74266448911SDavid Höppner  * Print a single instance.
74366448911SDavid Höppner  */
74466448911SDavid Höppner static void
74566448911SDavid Höppner ks_instance_print(ks_instance_t *ksi, ks_nvpair_t *nvpair)
74666448911SDavid Höppner {
74766448911SDavid Höppner 	if (g_headerflg) {
74866448911SDavid Höppner 		if (!g_pflg) {
74966448911SDavid Höppner 			(void) fprintf(stdout, DFLT_FMT,
75066448911SDavid Höppner 			    ksi->ks_module, ksi->ks_instance,
75166448911SDavid Höppner 			    ksi->ks_name, ksi->ks_class);
75266448911SDavid Höppner 		}
75366448911SDavid Höppner 		g_headerflg = B_FALSE;
75466448911SDavid Höppner 	}
75566448911SDavid Höppner 
75666448911SDavid Höppner 	if (g_pflg) {
75766448911SDavid Höppner 		(void) fprintf(stdout, KS_PFMT,
75866448911SDavid Höppner 		    ksi->ks_module, ksi->ks_instance,
75966448911SDavid Höppner 		    ksi->ks_name, nvpair->name);
76066448911SDavid Höppner 		if (!g_lflg) {
76166448911SDavid Höppner 			(void) putchar(g_cflg ? ':': '\t');
76266448911SDavid Höppner 			ks_value_print(nvpair);
76366448911SDavid Höppner 		}
76466448911SDavid Höppner 	} else {
76566448911SDavid Höppner 		(void) fprintf(stdout, KS_DFMT, nvpair->name);
76666448911SDavid Höppner 		ks_value_print(nvpair);
76766448911SDavid Höppner 	}
76866448911SDavid Höppner 
76966448911SDavid Höppner 	(void) putchar('\n');
77066448911SDavid Höppner }
77166448911SDavid Höppner 
77266448911SDavid Höppner /*
77366448911SDavid Höppner  * Print a single instance in JSON format.
77466448911SDavid Höppner  */
77566448911SDavid Höppner static void
77666448911SDavid Höppner ks_instance_print_json(ks_instance_t *ksi, ks_nvpair_t *nvpair)
77766448911SDavid Höppner {
77866448911SDavid Höppner 	if (g_headerflg) {
77966448911SDavid Höppner 		(void) fprintf(stdout, JSON_FMT,
78066448911SDavid Höppner 		    ksi->ks_module, ksi->ks_instance,
78166448911SDavid Höppner 		    ksi->ks_name, ksi->ks_class,
78266448911SDavid Höppner 		    ksi->ks_type);
78366448911SDavid Höppner 
78466448911SDavid Höppner 		if (ksi->ks_snaptime == 0)
78566448911SDavid Höppner 			(void) fprintf(stdout, "\t\"snaptime\": 0,\n");
78666448911SDavid Höppner 		else
78766448911SDavid Höppner 			(void) fprintf(stdout, "\t\"snaptime\": %.9f,\n",
78866448911SDavid Höppner 			    ksi->ks_snaptime / 1000000000.0);
78966448911SDavid Höppner 
79066448911SDavid Höppner 		(void) fprintf(stdout, "\t\"data\": {\n");
79166448911SDavid Höppner 
79266448911SDavid Höppner 		g_headerflg = B_FALSE;
79366448911SDavid Höppner 	}
79466448911SDavid Höppner 
79566448911SDavid Höppner 	(void) fprintf(stdout, KS_JFMT, nvpair->name);
79666448911SDavid Höppner 	if (nvpair->data_type == KSTAT_DATA_STRING) {
79766448911SDavid Höppner 		(void) putchar('\"');
79866448911SDavid Höppner 		ks_value_print(nvpair);
79966448911SDavid Höppner 		(void) putchar('\"');
80066448911SDavid Höppner 	} else {
80166448911SDavid Höppner 		ks_value_print(nvpair);
80266448911SDavid Höppner 	}
80366448911SDavid Höppner 	if (nvpair != list_tail(&ksi->ks_nvlist))
80466448911SDavid Höppner 		(void) putchar(',');
80566448911SDavid Höppner 
80666448911SDavid Höppner 	(void) putchar('\n');
80766448911SDavid Höppner }
80866448911SDavid Höppner 
80966448911SDavid Höppner /*
81066448911SDavid Höppner  * Print all instances.
81166448911SDavid Höppner  */
81266448911SDavid Höppner static void
81366448911SDavid Höppner ks_instances_print(void)
81466448911SDavid Höppner {
81566448911SDavid Höppner 	ks_selector_t	*selector;
81666448911SDavid Höppner 	ks_instance_t	*ksi, *ktmp;
81766448911SDavid Höppner 	ks_nvpair_t	*nvpair, *ntmp;
81866448911SDavid Höppner 	void		(*ks_print_fn)(ks_instance_t *, ks_nvpair_t *);
81966448911SDavid Höppner 	char		*ks_number;
82066448911SDavid Höppner 
82166448911SDavid Höppner 	if (g_timestamp_fmt != NODATE)
82266448911SDavid Höppner 		print_timestamp(g_timestamp_fmt);
82366448911SDavid Höppner 
82466448911SDavid Höppner 	if (g_jflg) {
82566448911SDavid Höppner 		ks_print_fn = &ks_instance_print_json;
82666448911SDavid Höppner 		(void) putchar('[');
82766448911SDavid Höppner 	} else {
82866448911SDavid Höppner 		ks_print_fn = &ks_instance_print;
82966448911SDavid Höppner 	}
83066448911SDavid Höppner 
83166448911SDavid Höppner 	/* Iterate over each selector */
83266448911SDavid Höppner 	selector = list_head(&selector_list);
83366448911SDavid Höppner 	while (selector != NULL) {
83466448911SDavid Höppner 
83566448911SDavid Höppner 		/* Iterate over each instance */
83666448911SDavid Höppner 		for (ksi = list_head(&instances_list); ksi != NULL;
83766448911SDavid Höppner 		    ksi = list_next(&instances_list, ksi)) {
83866448911SDavid Höppner 
83966448911SDavid Höppner 			(void) asprintf(&ks_number, "%d", ksi->ks_instance);
84066448911SDavid Höppner 			if (!(ks_match(ksi->ks_module, &selector->ks_module) &&
84166448911SDavid Höppner 			    ks_match(ksi->ks_name, &selector->ks_name) &&
84266448911SDavid Höppner 			    ks_match(ks_number, &selector->ks_instance) &&
84366448911SDavid Höppner 			    ks_match(ksi->ks_class, &g_ks_class))) {
84466448911SDavid Höppner 				free(ks_number);
84566448911SDavid Höppner 				continue;
84666448911SDavid Höppner 			}
84766448911SDavid Höppner 
84866448911SDavid Höppner 			free(ks_number);
84966448911SDavid Höppner 
85066448911SDavid Höppner 			/* Finally iterate over each statistic */
85166448911SDavid Höppner 			g_headerflg = B_TRUE;
85266448911SDavid Höppner 			for (nvpair = list_head(&ksi->ks_nvlist);
85366448911SDavid Höppner 			    nvpair != NULL;
85466448911SDavid Höppner 			    nvpair = list_next(&ksi->ks_nvlist, nvpair)) {
85566448911SDavid Höppner 				if (!ks_match(nvpair->name,
85666448911SDavid Höppner 				    &selector->ks_statistic))
85766448911SDavid Höppner 					continue;
85866448911SDavid Höppner 
85966448911SDavid Höppner 				g_matched = 0;
86066448911SDavid Höppner 				if (!g_qflg)
86166448911SDavid Höppner 					(*ks_print_fn)(ksi, nvpair);
86266448911SDavid Höppner 			}
86366448911SDavid Höppner 
86466448911SDavid Höppner 			if (!g_headerflg) {
86566448911SDavid Höppner 				if (g_jflg) {
86666448911SDavid Höppner 					(void) fprintf(stdout, "\t}\n}");
86766448911SDavid Höppner 					if (ksi != list_tail(&instances_list))
86866448911SDavid Höppner 						(void) putchar(',');
86966448911SDavid Höppner 				} else if (!g_pflg) {
87066448911SDavid Höppner 					(void) putchar('\n');
87166448911SDavid Höppner 				}
87266448911SDavid Höppner 			}
87366448911SDavid Höppner 		}
87466448911SDavid Höppner 
87566448911SDavid Höppner 		selector = list_next(&selector_list, selector);
87666448911SDavid Höppner 	}
87766448911SDavid Höppner 
87866448911SDavid Höppner 	if (g_jflg)
87966448911SDavid Höppner 		(void) fprintf(stdout, "]\n");
88066448911SDavid Höppner 
88166448911SDavid Höppner 	(void) fflush(stdout);
88266448911SDavid Höppner 
88366448911SDavid Höppner 	/* Free the instances list */
88466448911SDavid Höppner 	ksi = list_head(&instances_list);
88566448911SDavid Höppner 	while (ksi != NULL) {
88666448911SDavid Höppner 		nvpair = list_head(&ksi->ks_nvlist);
88766448911SDavid Höppner 		while (nvpair != NULL) {
88866448911SDavid Höppner 			ntmp = nvpair;
88966448911SDavid Höppner 			nvpair = list_next(&ksi->ks_nvlist, nvpair);
89066448911SDavid Höppner 			list_remove(&ksi->ks_nvlist, ntmp);
89166448911SDavid Höppner 			if (ntmp->data_type == KSTAT_DATA_STRING)
89266448911SDavid Höppner 				free(ntmp->value.str.addr.ptr);
89366448911SDavid Höppner 			free(ntmp);
89466448911SDavid Höppner 		}
89566448911SDavid Höppner 
89666448911SDavid Höppner 		ktmp = ksi;
89766448911SDavid Höppner 		ksi = list_next(&instances_list, ksi);
89866448911SDavid Höppner 		list_remove(&instances_list, ktmp);
89966448911SDavid Höppner 		list_destroy(&ktmp->ks_nvlist);
90066448911SDavid Höppner 		free(ktmp);
90166448911SDavid Höppner 	}
90266448911SDavid Höppner }
90366448911SDavid Höppner 
90466448911SDavid Höppner static void
90566448911SDavid Höppner save_cpu_stat(kstat_t *kp, ks_instance_t *ksi)
90666448911SDavid Höppner {
90766448911SDavid Höppner 	cpu_stat_t	*stat;
90866448911SDavid Höppner 	cpu_sysinfo_t	*sysinfo;
90966448911SDavid Höppner 	cpu_syswait_t	*syswait;
91066448911SDavid Höppner 	cpu_vminfo_t	*vminfo;
91166448911SDavid Höppner 
91266448911SDavid Höppner 	stat = (cpu_stat_t *)(kp->ks_data);
91366448911SDavid Höppner 	sysinfo = &stat->cpu_sysinfo;
91466448911SDavid Höppner 	syswait = &stat->cpu_syswait;
91566448911SDavid Höppner 	vminfo  = &stat->cpu_vminfo;
91666448911SDavid Höppner 
91766448911SDavid Höppner 	SAVE_UINT32_X(ksi, "idle", sysinfo->cpu[CPU_IDLE]);
91866448911SDavid Höppner 	SAVE_UINT32_X(ksi, "user", sysinfo->cpu[CPU_USER]);
91966448911SDavid Höppner 	SAVE_UINT32_X(ksi, "kernel", sysinfo->cpu[CPU_KERNEL]);
92066448911SDavid Höppner 	SAVE_UINT32_X(ksi, "wait", sysinfo->cpu[CPU_WAIT]);
921*5918f984SRichard Lowe 	SAVE_UINT32_X(ksi, "wait_io", sysinfo->wait[W_IO]);
922*5918f984SRichard Lowe 	SAVE_UINT32_X(ksi, "wait_swap", sysinfo->wait[W_SWAP]);
923*5918f984SRichard Lowe 	SAVE_UINT32_X(ksi, "wait_pio", sysinfo->wait[W_PIO]);
92466448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, bread);
92566448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, bwrite);
92666448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, lread);
92766448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, lwrite);
92866448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, phread);
92966448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, phwrite);
93066448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, pswitch);
93166448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, trap);
93266448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, intr);
93366448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, syscall);
93466448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, sysread);
93566448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, syswrite);
93666448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, sysfork);
93766448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, sysvfork);
93866448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, sysexec);
93966448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, readch);
94066448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, writech);
94166448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, rcvint);
94266448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, xmtint);
94366448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, mdmint);
94466448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, rawch);
94566448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, canch);
94666448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, outch);
94766448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, msg);
94866448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, sema);
94966448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, namei);
95066448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, ufsiget);
95166448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, ufsdirblk);
95266448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, ufsipage);
95366448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, ufsinopage);
95466448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, inodeovf);
95566448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, fileovf);
95666448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, procovf);
95766448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, intrthread);
95866448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, intrblk);
95966448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, idlethread);
96066448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, inv_swtch);
96166448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, nthreads);
96266448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, cpumigrate);
96366448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, xcalls);
96466448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, mutex_adenters);
96566448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, rw_rdfails);
96666448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, rw_wrfails);
96766448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, modload);
96866448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, modunload);
96966448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, bawrite);
97066448911SDavid Höppner #ifdef	STATISTICS	/* see header file */
97166448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, rw_enters);
97266448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, win_uo_cnt);
97366448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, win_uu_cnt);
97466448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, win_so_cnt);
97566448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, win_su_cnt);
97666448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, win_suo_cnt);
97766448911SDavid Höppner #endif
97866448911SDavid Höppner 
97966448911SDavid Höppner 	SAVE_INT32(ksi, syswait, iowait);
98066448911SDavid Höppner 	SAVE_INT32(ksi, syswait, swap);
98166448911SDavid Höppner 	SAVE_INT32(ksi, syswait, physio);
98266448911SDavid Höppner 
98366448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, pgrec);
98466448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, pgfrec);
98566448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, pgin);
98666448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, pgpgin);
98766448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, pgout);
98866448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, pgpgout);
98966448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, swapin);
99066448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, pgswapin);
99166448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, swapout);
99266448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, pgswapout);
99366448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, zfod);
99466448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, dfree);
99566448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, scan);
99666448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, rev);
99766448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, hat_fault);
99866448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, as_fault);
99966448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, maj_fault);
100066448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, cow_fault);
100166448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, prot_fault);
100266448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, softlock);
100366448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, kernel_asflt);
100466448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, pgrrun);
100566448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, execpgin);
100666448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, execpgout);
100766448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, execfree);
100866448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, anonpgin);
100966448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, anonpgout);
101066448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, anonfree);
101166448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, fspgin);
101266448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, fspgout);
101366448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, fsfree);
101466448911SDavid Höppner }
101566448911SDavid Höppner 
101666448911SDavid Höppner static void
101766448911SDavid Höppner save_var(kstat_t *kp, ks_instance_t *ksi)
101866448911SDavid Höppner {
101966448911SDavid Höppner 	struct var	*var = (struct var *)(kp->ks_data);
102066448911SDavid Höppner 
102166448911SDavid Höppner 	assert(kp->ks_data_size == sizeof (struct var));
102266448911SDavid Höppner 
102366448911SDavid Höppner 	SAVE_INT32(ksi, var, v_buf);
102466448911SDavid Höppner 	SAVE_INT32(ksi, var, v_call);
102566448911SDavid Höppner 	SAVE_INT32(ksi, var, v_proc);
102666448911SDavid Höppner 	SAVE_INT32(ksi, var, v_maxupttl);
102766448911SDavid Höppner 	SAVE_INT32(ksi, var, v_nglobpris);
102866448911SDavid Höppner 	SAVE_INT32(ksi, var, v_maxsyspri);
102966448911SDavid Höppner 	SAVE_INT32(ksi, var, v_clist);
103066448911SDavid Höppner 	SAVE_INT32(ksi, var, v_maxup);
103166448911SDavid Höppner 	SAVE_INT32(ksi, var, v_hbuf);
103266448911SDavid Höppner 	SAVE_INT32(ksi, var, v_hmask);
103366448911SDavid Höppner 	SAVE_INT32(ksi, var, v_pbuf);
103466448911SDavid Höppner 	SAVE_INT32(ksi, var, v_sptmap);
103566448911SDavid Höppner 	SAVE_INT32(ksi, var, v_maxpmem);
103666448911SDavid Höppner 	SAVE_INT32(ksi, var, v_autoup);
103766448911SDavid Höppner 	SAVE_INT32(ksi, var, v_bufhwm);
103866448911SDavid Höppner }
103966448911SDavid Höppner 
104066448911SDavid Höppner static void
104166448911SDavid Höppner save_ncstats(kstat_t *kp, ks_instance_t *ksi)
104266448911SDavid Höppner {
104366448911SDavid Höppner 	struct ncstats	*ncstats = (struct ncstats *)(kp->ks_data);
104466448911SDavid Höppner 
104566448911SDavid Höppner 	assert(kp->ks_data_size == sizeof (struct ncstats));
104666448911SDavid Höppner 
104766448911SDavid Höppner 	SAVE_INT32(ksi, ncstats, hits);
104866448911SDavid Höppner 	SAVE_INT32(ksi, ncstats, misses);
104966448911SDavid Höppner 	SAVE_INT32(ksi, ncstats, enters);
105066448911SDavid Höppner 	SAVE_INT32(ksi, ncstats, dbl_enters);
105166448911SDavid Höppner 	SAVE_INT32(ksi, ncstats, long_enter);
105266448911SDavid Höppner 	SAVE_INT32(ksi, ncstats, long_look);
105366448911SDavid Höppner 	SAVE_INT32(ksi, ncstats, move_to_front);
105466448911SDavid Höppner 	SAVE_INT32(ksi, ncstats, purges);
105566448911SDavid Höppner }
105666448911SDavid Höppner 
105766448911SDavid Höppner static void
105866448911SDavid Höppner save_sysinfo(kstat_t *kp, ks_instance_t *ksi)
105966448911SDavid Höppner {
106066448911SDavid Höppner 	sysinfo_t	*sysinfo = (sysinfo_t *)(kp->ks_data);
106166448911SDavid Höppner 
106266448911SDavid Höppner 	assert(kp->ks_data_size == sizeof (sysinfo_t));
106366448911SDavid Höppner 
106466448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, updates);
106566448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, runque);
106666448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, runocc);
106766448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, swpque);
106866448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, swpocc);
106966448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, waiting);
107066448911SDavid Höppner }
107166448911SDavid Höppner 
107266448911SDavid Höppner static void
107366448911SDavid Höppner save_vminfo(kstat_t *kp, ks_instance_t *ksi)
107466448911SDavid Höppner {
107566448911SDavid Höppner 	vminfo_t	*vminfo = (vminfo_t *)(kp->ks_data);
107666448911SDavid Höppner 
107766448911SDavid Höppner 	assert(kp->ks_data_size == sizeof (vminfo_t));
107866448911SDavid Höppner 
107966448911SDavid Höppner 	SAVE_UINT64(ksi, vminfo, freemem);
108066448911SDavid Höppner 	SAVE_UINT64(ksi, vminfo, swap_resv);
108166448911SDavid Höppner 	SAVE_UINT64(ksi, vminfo, swap_alloc);
108266448911SDavid Höppner 	SAVE_UINT64(ksi, vminfo, swap_avail);
108366448911SDavid Höppner 	SAVE_UINT64(ksi, vminfo, swap_free);
108466448911SDavid Höppner 	SAVE_UINT64(ksi, vminfo, updates);
108566448911SDavid Höppner }
108666448911SDavid Höppner 
108766448911SDavid Höppner static void
108866448911SDavid Höppner save_nfs(kstat_t *kp, ks_instance_t *ksi)
108966448911SDavid Höppner {
109066448911SDavid Höppner 	struct mntinfo_kstat *mntinfo = (struct mntinfo_kstat *)(kp->ks_data);
109166448911SDavid Höppner 
109266448911SDavid Höppner 	assert(kp->ks_data_size == sizeof (struct mntinfo_kstat));
109366448911SDavid Höppner 
109466448911SDavid Höppner 	SAVE_STRING(ksi, mntinfo, mik_proto);
109566448911SDavid Höppner 	SAVE_UINT32(ksi, mntinfo, mik_vers);
109666448911SDavid Höppner 	SAVE_UINT32(ksi, mntinfo, mik_flags);
109766448911SDavid Höppner 	SAVE_UINT32(ksi, mntinfo, mik_secmod);
109866448911SDavid Höppner 	SAVE_UINT32(ksi, mntinfo, mik_curread);
109966448911SDavid Höppner 	SAVE_UINT32(ksi, mntinfo, mik_curwrite);
110066448911SDavid Höppner 	SAVE_INT32(ksi, mntinfo, mik_timeo);
110166448911SDavid Höppner 	SAVE_INT32(ksi, mntinfo, mik_retrans);
110266448911SDavid Höppner 	SAVE_UINT32(ksi, mntinfo, mik_acregmin);
110366448911SDavid Höppner 	SAVE_UINT32(ksi, mntinfo, mik_acregmax);
110466448911SDavid Höppner 	SAVE_UINT32(ksi, mntinfo, mik_acdirmin);
110566448911SDavid Höppner 	SAVE_UINT32(ksi, mntinfo, mik_acdirmax);
110666448911SDavid Höppner 	SAVE_UINT32_X(ksi, "lookup_srtt", mntinfo->mik_timers[0].srtt);
110766448911SDavid Höppner 	SAVE_UINT32_X(ksi, "lookup_deviate", mntinfo->mik_timers[0].deviate);
110866448911SDavid Höppner 	SAVE_UINT32_X(ksi, "lookup_rtxcur", mntinfo->mik_timers[0].rtxcur);
110966448911SDavid Höppner 	SAVE_UINT32_X(ksi, "read_srtt", mntinfo->mik_timers[1].srtt);
111066448911SDavid Höppner 	SAVE_UINT32_X(ksi, "read_deviate", mntinfo->mik_timers[1].deviate);
111166448911SDavid Höppner 	SAVE_UINT32_X(ksi, "read_rtxcur", mntinfo->mik_timers[1].rtxcur);
111266448911SDavid Höppner 	SAVE_UINT32_X(ksi, "write_srtt", mntinfo->mik_timers[2].srtt);
111366448911SDavid Höppner 	SAVE_UINT32_X(ksi, "write_deviate", mntinfo->mik_timers[2].deviate);
111466448911SDavid Höppner 	SAVE_UINT32_X(ksi, "write_rtxcur", mntinfo->mik_timers[2].rtxcur);
111566448911SDavid Höppner 	SAVE_UINT32(ksi, mntinfo, mik_noresponse);
111666448911SDavid Höppner 	SAVE_UINT32(ksi, mntinfo, mik_failover);
111766448911SDavid Höppner 	SAVE_UINT32(ksi, mntinfo, mik_remap);
111866448911SDavid Höppner 	SAVE_STRING(ksi, mntinfo, mik_curserver);
111966448911SDavid Höppner }
112066448911SDavid Höppner 
112166448911SDavid Höppner #ifdef __sparc
112266448911SDavid Höppner static void
112366448911SDavid Höppner save_sfmmu_global_stat(kstat_t *kp, ks_instance_t *ksi)
112466448911SDavid Höppner {
112566448911SDavid Höppner 	struct sfmmu_global_stat *sfmmug =
112666448911SDavid Höppner 	    (struct sfmmu_global_stat *)(kp->ks_data);
112766448911SDavid Höppner 
112866448911SDavid Höppner 	assert(kp->ks_data_size == sizeof (struct sfmmu_global_stat));
112966448911SDavid Höppner 
113066448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tsb_exceptions);
113166448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tsb_raise_exception);
113266448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_pagefaults);
113366448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_uhash_searches);
113466448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_uhash_links);
113566448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_khash_searches);
113666448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_khash_links);
113766448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_swapout);
113866448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tsb_alloc);
113966448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tsb_allocfail);
114066448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tsb_sectsb_create);
114166448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_scd_1sttsb_alloc);
114266448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_scd_2ndtsb_alloc);
114366448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_scd_1sttsb_allocfail);
114466448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_scd_2ndtsb_allocfail);
114566448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tteload8k);
114666448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tteload64k);
114766448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tteload512k);
114866448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tteload4m);
114966448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tteload32m);
115066448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tteload256m);
115166448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tsb_load8k);
115266448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tsb_load4m);
115366448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_hblk_hit);
115466448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_hblk8_ncreate);
115566448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_hblk8_nalloc);
115666448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_hblk1_ncreate);
115766448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_hblk1_nalloc);
115866448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_hblk_slab_cnt);
115966448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_hblk_reserve_cnt);
116066448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_hblk_recurse_cnt);
116166448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_hblk_reserve_hit);
116266448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_get_free_success);
116366448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_get_free_throttle);
116466448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_get_free_fail);
116566448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_put_free_success);
116666448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_put_free_fail);
116766448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_pgcolor_conflict);
116866448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_uncache_conflict);
116966448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_unload_conflict);
117066448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_ism_uncache);
117166448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_ism_recache);
117266448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_recache);
117366448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_steal_count);
117466448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_pagesync);
117566448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_clrwrt);
117666448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_pagesync_invalid);
117766448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_kernel_xcalls);
117866448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_user_xcalls);
117966448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tsb_grow);
118066448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tsb_shrink);
118166448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tsb_resize_failures);
118266448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tsb_reloc);
118366448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_user_vtop);
118466448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_ctx_inv);
118566448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tlb_reprog_pgsz);
118666448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_region_remap_demap);
118766448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_create_scd);
118866448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_join_scd);
118966448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_leave_scd);
119066448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_destroy_scd);
119166448911SDavid Höppner }
119266448911SDavid Höppner #endif
119366448911SDavid Höppner 
119466448911SDavid Höppner #ifdef __sparc
119566448911SDavid Höppner static void
119666448911SDavid Höppner save_sfmmu_tsbsize_stat(kstat_t *kp, ks_instance_t *ksi)
119766448911SDavid Höppner {
119866448911SDavid Höppner 	struct sfmmu_tsbsize_stat *sfmmut;
119966448911SDavid Höppner 
120066448911SDavid Höppner 	assert(kp->ks_data_size == sizeof (struct sfmmu_tsbsize_stat));
120166448911SDavid Höppner 	sfmmut = (struct sfmmu_tsbsize_stat *)(kp->ks_data);
120266448911SDavid Höppner 
120366448911SDavid Höppner 	SAVE_INT32(ksi, sfmmut, sf_tsbsz_8k);
120466448911SDavid Höppner 	SAVE_INT32(ksi, sfmmut, sf_tsbsz_16k);
120566448911SDavid Höppner 	SAVE_INT32(ksi, sfmmut, sf_tsbsz_32k);
120666448911SDavid Höppner 	SAVE_INT32(ksi, sfmmut, sf_tsbsz_64k);
120766448911SDavid Höppner 	SAVE_INT32(ksi, sfmmut, sf_tsbsz_128k);
120866448911SDavid Höppner 	SAVE_INT32(ksi, sfmmut, sf_tsbsz_256k);
120966448911SDavid Höppner 	SAVE_INT32(ksi, sfmmut, sf_tsbsz_512k);
121066448911SDavid Höppner 	SAVE_INT32(ksi, sfmmut, sf_tsbsz_1m);
121166448911SDavid Höppner 	SAVE_INT32(ksi, sfmmut, sf_tsbsz_2m);
121266448911SDavid Höppner 	SAVE_INT32(ksi, sfmmut, sf_tsbsz_4m);
121366448911SDavid Höppner }
121466448911SDavid Höppner #endif
121566448911SDavid Höppner 
121666448911SDavid Höppner #ifdef __sparc
121766448911SDavid Höppner static void
121866448911SDavid Höppner save_simmstat(kstat_t *kp, ks_instance_t *ksi)
121966448911SDavid Höppner {
122066448911SDavid Höppner 	uchar_t	*simmstat;
122166448911SDavid Höppner 	char	*simm_buf;
122266448911SDavid Höppner 	char	*list = NULL;
122366448911SDavid Höppner 	int	i;
122466448911SDavid Höppner 
122566448911SDavid Höppner 	assert(kp->ks_data_size == sizeof (uchar_t) * SIMM_COUNT);
122666448911SDavid Höppner 
122766448911SDavid Höppner 	for (i = 0, simmstat = (uchar_t *)(kp->ks_data); i < SIMM_COUNT - 1;
122866448911SDavid Höppner 	    i++, simmstat++) {
122966448911SDavid Höppner 		if (list == NULL) {
123066448911SDavid Höppner 			(void) asprintf(&simm_buf, "%d,", *simmstat);
123166448911SDavid Höppner 		} else {
123266448911SDavid Höppner 			(void) asprintf(&simm_buf, "%s%d,", list, *simmstat);
123366448911SDavid Höppner 			free(list);
123466448911SDavid Höppner 		}
123566448911SDavid Höppner 		list = simm_buf;
123666448911SDavid Höppner 	}
123766448911SDavid Höppner 
123866448911SDavid Höppner 	(void) asprintf(&simm_buf, "%s%d", list, *simmstat);
123966448911SDavid Höppner 	SAVE_STRING_X(ksi, "status", simm_buf);
124066448911SDavid Höppner 	free(list);
124166448911SDavid Höppner 	free(simm_buf);
124266448911SDavid Höppner }
124366448911SDavid Höppner #endif
124466448911SDavid Höppner 
124566448911SDavid Höppner #ifdef __sparc
124666448911SDavid Höppner /*
124766448911SDavid Höppner  * Helper function for save_temperature().
124866448911SDavid Höppner  */
124966448911SDavid Höppner static char *
125066448911SDavid Höppner short_array_to_string(short *shortp, int len)
125166448911SDavid Höppner {
125266448911SDavid Höppner 	char	*list = NULL;
125366448911SDavid Höppner 	char	*list_buf;
125466448911SDavid Höppner 
125566448911SDavid Höppner 	for (; len > 1; len--, shortp++) {
125666448911SDavid Höppner 		if (list == NULL) {
1257e633f2d7SRichard Lowe 			(void) asprintf(&list_buf, "%hd,", *shortp);
125866448911SDavid Höppner 		} else {
1259e633f2d7SRichard Lowe 			(void) asprintf(&list_buf, "%s%hd,", list, *shortp);
126066448911SDavid Höppner 			free(list);
126166448911SDavid Höppner 		}
126266448911SDavid Höppner 		list = list_buf;
126366448911SDavid Höppner 	}
126466448911SDavid Höppner 
1265e633f2d7SRichard Lowe 	(void) asprintf(&list_buf, "%s%hd", list, *shortp);
126666448911SDavid Höppner 	free(list);
126766448911SDavid Höppner 	return (list_buf);
126866448911SDavid Höppner }
126966448911SDavid Höppner 
127066448911SDavid Höppner static void
127166448911SDavid Höppner save_temperature(kstat_t *kp, ks_instance_t *ksi)
127266448911SDavid Höppner {
127366448911SDavid Höppner 	struct temp_stats *temps = (struct temp_stats *)(kp->ks_data);
127466448911SDavid Höppner 	char	*buf;
127566448911SDavid Höppner 
127666448911SDavid Höppner 	assert(kp->ks_data_size == sizeof (struct temp_stats));
127766448911SDavid Höppner 
127866448911SDavid Höppner 	SAVE_UINT32(ksi, temps, index);
127966448911SDavid Höppner 
128066448911SDavid Höppner 	buf = short_array_to_string(temps->l1, L1_SZ);
128166448911SDavid Höppner 	SAVE_STRING_X(ksi, "l1", buf);
128266448911SDavid Höppner 	free(buf);
128366448911SDavid Höppner 
128466448911SDavid Höppner 	buf = short_array_to_string(temps->l2, L2_SZ);
128566448911SDavid Höppner 	SAVE_STRING_X(ksi, "l2", buf);
128666448911SDavid Höppner 	free(buf);
128766448911SDavid Höppner 
128866448911SDavid Höppner 	buf = short_array_to_string(temps->l3, L3_SZ);
128966448911SDavid Höppner 	SAVE_STRING_X(ksi, "l3", buf);
129066448911SDavid Höppner 	free(buf);
129166448911SDavid Höppner 
129266448911SDavid Höppner 	buf = short_array_to_string(temps->l4, L4_SZ);
129366448911SDavid Höppner 	SAVE_STRING_X(ksi, "l4", buf);
129466448911SDavid Höppner 	free(buf);
129566448911SDavid Höppner 
129666448911SDavid Höppner 	buf = short_array_to_string(temps->l5, L5_SZ);
129766448911SDavid Höppner 	SAVE_STRING_X(ksi, "l5", buf);
129866448911SDavid Höppner 	free(buf);
129966448911SDavid Höppner 
130066448911SDavid Höppner 	SAVE_INT32(ksi, temps, max);
130166448911SDavid Höppner 	SAVE_INT32(ksi, temps, min);
130266448911SDavid Höppner 	SAVE_INT32(ksi, temps, state);
130366448911SDavid Höppner 	SAVE_INT32(ksi, temps, temp_cnt);
130466448911SDavid Höppner 	SAVE_INT32(ksi, temps, shutdown_cnt);
130566448911SDavid Höppner 	SAVE_INT32(ksi, temps, version);
130666448911SDavid Höppner 	SAVE_INT32(ksi, temps, trend);
130766448911SDavid Höppner 	SAVE_INT32(ksi, temps, override);
130866448911SDavid Höppner }
130966448911SDavid Höppner #endif
131066448911SDavid Höppner 
131166448911SDavid Höppner #ifdef __sparc
131266448911SDavid Höppner static void
131366448911SDavid Höppner save_temp_over(kstat_t *kp, ks_instance_t *ksi)
131466448911SDavid Höppner {
131566448911SDavid Höppner 	short	*sh = (short *)(kp->ks_data);
131666448911SDavid Höppner 	char	*value;
131766448911SDavid Höppner 
131866448911SDavid Höppner 	assert(kp->ks_data_size == sizeof (short));
131966448911SDavid Höppner 
132066448911SDavid Höppner 	(void) asprintf(&value, "%hu", *sh);
132166448911SDavid Höppner 	SAVE_STRING_X(ksi, "override", value);
132266448911SDavid Höppner 	free(value);
132366448911SDavid Höppner }
132466448911SDavid Höppner #endif
132566448911SDavid Höppner 
132666448911SDavid Höppner #ifdef __sparc
132766448911SDavid Höppner static void
132866448911SDavid Höppner save_ps_shadow(kstat_t *kp, ks_instance_t *ksi)
132966448911SDavid Höppner {
133066448911SDavid Höppner 	uchar_t	*uchar = (uchar_t *)(kp->ks_data);
133166448911SDavid Höppner 
133266448911SDavid Höppner 	assert(kp->ks_data_size == SYS_PS_COUNT);
133366448911SDavid Höppner 
133466448911SDavid Höppner 	SAVE_CHAR_X(ksi, "core_0", *uchar++);
133566448911SDavid Höppner 	SAVE_CHAR_X(ksi, "core_1", *uchar++);
133666448911SDavid Höppner 	SAVE_CHAR_X(ksi, "core_2", *uchar++);
133766448911SDavid Höppner 	SAVE_CHAR_X(ksi, "core_3", *uchar++);
133866448911SDavid Höppner 	SAVE_CHAR_X(ksi, "core_4", *uchar++);
133966448911SDavid Höppner 	SAVE_CHAR_X(ksi, "core_5", *uchar++);
134066448911SDavid Höppner 	SAVE_CHAR_X(ksi, "core_6", *uchar++);
134166448911SDavid Höppner 	SAVE_CHAR_X(ksi, "core_7", *uchar++);
134266448911SDavid Höppner 	SAVE_CHAR_X(ksi, "pps_0", *uchar++);
134366448911SDavid Höppner 	SAVE_CHAR_X(ksi, "clk_33", *uchar++);
134466448911SDavid Höppner 	SAVE_CHAR_X(ksi, "clk_50", *uchar++);
134566448911SDavid Höppner 	SAVE_CHAR_X(ksi, "v5_p", *uchar++);
134666448911SDavid Höppner 	SAVE_CHAR_X(ksi, "v12_p", *uchar++);
134766448911SDavid Höppner 	SAVE_CHAR_X(ksi, "v5_aux", *uchar++);
134866448911SDavid Höppner 	SAVE_CHAR_X(ksi, "v5_p_pch", *uchar++);
134966448911SDavid Höppner 	SAVE_CHAR_X(ksi, "v12_p_pch", *uchar++);
135066448911SDavid Höppner 	SAVE_CHAR_X(ksi, "v3_pch", *uchar++);
135166448911SDavid Höppner 	SAVE_CHAR_X(ksi, "v5_pch", *uchar++);
135266448911SDavid Höppner 	SAVE_CHAR_X(ksi, "p_fan", *uchar++);
135366448911SDavid Höppner }
135466448911SDavid Höppner #endif
135566448911SDavid Höppner 
135666448911SDavid Höppner #ifdef __sparc
135766448911SDavid Höppner static void
135866448911SDavid Höppner save_fault_list(kstat_t *kp, ks_instance_t *ksi)
135966448911SDavid Höppner {
136066448911SDavid Höppner 	struct ft_list *fault;
136166448911SDavid Höppner 	char	name[KSTAT_STRLEN + 7];
136266448911SDavid Höppner 	int	i;
136366448911SDavid Höppner 
136466448911SDavid Höppner 	for (i = 1, fault = (struct ft_list *)(kp->ks_data);
136566448911SDavid Höppner 	    i <= 999999 && i <= kp->ks_data_size / sizeof (struct ft_list);
136666448911SDavid Höppner 	    i++, fault++) {
136766448911SDavid Höppner 		(void) snprintf(name, sizeof (name), "unit_%d", i);
136866448911SDavid Höppner 		SAVE_INT32_X(ksi, name, fault->unit);
136966448911SDavid Höppner 		(void) snprintf(name, sizeof (name), "type_%d", i);
137066448911SDavid Höppner 		SAVE_INT32_X(ksi, name, fault->type);
137166448911SDavid Höppner 		(void) snprintf(name, sizeof (name), "fclass_%d", i);
137266448911SDavid Höppner 		SAVE_INT32_X(ksi, name, fault->fclass);
137366448911SDavid Höppner 		(void) snprintf(name, sizeof (name), "create_time_%d", i);
137466448911SDavid Höppner 		SAVE_HRTIME_X(ksi, name, fault->create_time);
137566448911SDavid Höppner 		(void) snprintf(name, sizeof (name), "msg_%d", i);
1376e633f2d7SRichard Lowe 		SAVE_STRING_X(ksi, name, fault->msg);
137766448911SDavid Höppner 	}
137866448911SDavid Höppner }
137966448911SDavid Höppner #endif
138066448911SDavid Höppner 
138166448911SDavid Höppner static void
138266448911SDavid Höppner save_named(kstat_t *kp, ks_instance_t *ksi)
138366448911SDavid Höppner {
138466448911SDavid Höppner 	kstat_named_t *knp;
138566448911SDavid Höppner 	int	n;
138666448911SDavid Höppner 
138766448911SDavid Höppner 	for (n = kp->ks_ndata, knp = KSTAT_NAMED_PTR(kp); n > 0; n--, knp++) {
138866448911SDavid Höppner 		switch (knp->data_type) {
138966448911SDavid Höppner 		case KSTAT_DATA_CHAR:
139066448911SDavid Höppner 			nvpair_insert(ksi, knp->name,
139166448911SDavid Höppner 			    (ks_value_t *)&knp->value, KSTAT_DATA_CHAR);
139266448911SDavid Höppner 			break;
139366448911SDavid Höppner 		case KSTAT_DATA_INT32:
139466448911SDavid Höppner 			nvpair_insert(ksi, knp->name,
139566448911SDavid Höppner 			    (ks_value_t *)&knp->value, KSTAT_DATA_INT32);
139666448911SDavid Höppner 			break;
139766448911SDavid Höppner 		case KSTAT_DATA_UINT32:
139866448911SDavid Höppner 			nvpair_insert(ksi, knp->name,
139966448911SDavid Höppner 			    (ks_value_t *)&knp->value, KSTAT_DATA_UINT32);
140066448911SDavid Höppner 			break;
140166448911SDavid Höppner 		case KSTAT_DATA_INT64:
140266448911SDavid Höppner 			nvpair_insert(ksi, knp->name,
140366448911SDavid Höppner 			    (ks_value_t *)&knp->value, KSTAT_DATA_INT64);
140466448911SDavid Höppner 			break;
140566448911SDavid Höppner 		case KSTAT_DATA_UINT64:
140666448911SDavid Höppner 			nvpair_insert(ksi, knp->name,
140766448911SDavid Höppner 			    (ks_value_t *)&knp->value, KSTAT_DATA_UINT64);
140866448911SDavid Höppner 			break;
140966448911SDavid Höppner 		case KSTAT_DATA_STRING:
141066448911SDavid Höppner 			SAVE_STRING_X(ksi, knp->name, KSTAT_NAMED_STR_PTR(knp));
141166448911SDavid Höppner 			break;
141266448911SDavid Höppner 		default:
141366448911SDavid Höppner 			assert(B_FALSE); /* Invalid data type */
141466448911SDavid Höppner 			break;
141566448911SDavid Höppner 		}
141666448911SDavid Höppner 	}
141766448911SDavid Höppner }
141866448911SDavid Höppner 
141966448911SDavid Höppner static void
142066448911SDavid Höppner save_intr(kstat_t *kp, ks_instance_t *ksi)
142166448911SDavid Höppner {
142266448911SDavid Höppner 	kstat_intr_t *intr = KSTAT_INTR_PTR(kp);
142366448911SDavid Höppner 	char	*intr_names[] = {"hard", "soft", "watchdog", "spurious",
142466448911SDavid Höppner 	    "multiple_service"};
142566448911SDavid Höppner 	int	n;
142666448911SDavid Höppner 
142766448911SDavid Höppner 	for (n = 0; n < KSTAT_NUM_INTRS; n++)
142866448911SDavid Höppner 		SAVE_UINT32_X(ksi, intr_names[n], intr->intrs[n]);
142966448911SDavid Höppner }
143066448911SDavid Höppner 
143166448911SDavid Höppner static void
143266448911SDavid Höppner save_io(kstat_t *kp, ks_instance_t *ksi)
143366448911SDavid Höppner {
143466448911SDavid Höppner 	kstat_io_t	*ksio = KSTAT_IO_PTR(kp);
143566448911SDavid Höppner 
143666448911SDavid Höppner 	SAVE_UINT64(ksi, ksio, nread);
143766448911SDavid Höppner 	SAVE_UINT64(ksi, ksio, nwritten);
143866448911SDavid Höppner 	SAVE_UINT32(ksi, ksio, reads);
143966448911SDavid Höppner 	SAVE_UINT32(ksi, ksio, writes);
144066448911SDavid Höppner 	SAVE_HRTIME(ksi, ksio, wtime);
144166448911SDavid Höppner 	SAVE_HRTIME(ksi, ksio, wlentime);
144266448911SDavid Höppner 	SAVE_HRTIME(ksi, ksio, wlastupdate);
144366448911SDavid Höppner 	SAVE_HRTIME(ksi, ksio, rtime);
144466448911SDavid Höppner 	SAVE_HRTIME(ksi, ksio, rlentime);
144566448911SDavid Höppner 	SAVE_HRTIME(ksi, ksio, rlastupdate);
144666448911SDavid Höppner 	SAVE_UINT32(ksi, ksio, wcnt);
144766448911SDavid Höppner 	SAVE_UINT32(ksi, ksio, rcnt);
144866448911SDavid Höppner }
144966448911SDavid Höppner 
145066448911SDavid Höppner static void
145166448911SDavid Höppner save_timer(kstat_t *kp, ks_instance_t *ksi)
145266448911SDavid Höppner {
145366448911SDavid Höppner 	kstat_timer_t	*ktimer = KSTAT_TIMER_PTR(kp);
145466448911SDavid Höppner 
145566448911SDavid Höppner 	SAVE_STRING(ksi, ktimer, name);
145666448911SDavid Höppner 	SAVE_UINT64(ksi, ktimer, num_events);
145766448911SDavid Höppner 	SAVE_HRTIME(ksi, ktimer, elapsed_time);
145866448911SDavid Höppner 	SAVE_HRTIME(ksi, ktimer, min_time);
145966448911SDavid Höppner 	SAVE_HRTIME(ksi, ktimer, max_time);
146066448911SDavid Höppner 	SAVE_HRTIME(ksi, ktimer, start_time);
146166448911SDavid Höppner 	SAVE_HRTIME(ksi, ktimer, stop_time);
146266448911SDavid Höppner }
1463