xref: /illumos-gate/usr/src/cmd/stat/kstat/kstat.c (revision 8af765f5)
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.
266a19b866SRobert Mustacchi  * Copyright 2016 Joyent, Inc.
27*8af765f5SPeter Tribble  * Copyright 2020 Peter Tribble.
2866448911SDavid Höppner  */
2966448911SDavid Höppner 
3066448911SDavid Höppner /*
3166448911SDavid Höppner  * Display kernel statistics
3266448911SDavid Höppner  *
3366448911SDavid Höppner  * This is a reimplementation of the perl kstat command originally found
3466448911SDavid Höppner  * under usr/src/cmd/kstat/kstat.pl
3566448911SDavid Höppner  *
3666448911SDavid Höppner  * Incompatibilities:
3766448911SDavid Höppner  *	- perl regular expressions replaced with extended REs bracketed by '/'
3866448911SDavid Höppner  *
3966448911SDavid Höppner  * Flags added:
4066448911SDavid Höppner  *	-C	similar to the -p option but value is separated by a colon
4166448911SDavid Höppner  *	-h	display help
4266448911SDavid Höppner  *	-j	json format
4366448911SDavid Höppner  */
4466448911SDavid Höppner 
4566448911SDavid Höppner #include <assert.h>
4666448911SDavid Höppner #include <ctype.h>
4766448911SDavid Höppner #include <errno.h>
4866448911SDavid Höppner #include <kstat.h>
4966448911SDavid Höppner #include <langinfo.h>
5066448911SDavid Höppner #include <libgen.h>
5166448911SDavid Höppner #include <limits.h>
5266448911SDavid Höppner #include <locale.h>
5366448911SDavid Höppner #include <signal.h>
5466448911SDavid Höppner #include <stddef.h>
5566448911SDavid Höppner #include <stdio.h>
5666448911SDavid Höppner #include <stdlib.h>
5766448911SDavid Höppner #include <string.h>
5866448911SDavid Höppner #include <strings.h>
5966448911SDavid Höppner #include <time.h>
6066448911SDavid Höppner #include <unistd.h>
6166448911SDavid Höppner #include <sys/list.h>
6266448911SDavid Höppner #include <sys/time.h>
6366448911SDavid Höppner #include <sys/types.h>
6466448911SDavid Höppner 
6566448911SDavid Höppner #include "kstat.h"
6666448911SDavid Höppner #include "statcommon.h"
6766448911SDavid Höppner 
6866448911SDavid Höppner char	*cmdname = "kstat";	/* Name of this command */
6966448911SDavid Höppner int	caught_cont = 0;	/* Have caught a SIGCONT */
7066448911SDavid Höppner 
7166448911SDavid Höppner static uint_t	g_timestamp_fmt = NODATE;
7266448911SDavid Höppner 
7366448911SDavid Höppner /* Helper flag - header was printed already? */
7466448911SDavid Höppner static boolean_t g_headerflg;
7566448911SDavid Höppner 
7666448911SDavid Höppner /* Saved command line options */
7766448911SDavid Höppner static boolean_t g_cflg = B_FALSE;
7866448911SDavid Höppner static boolean_t g_jflg = B_FALSE;
7966448911SDavid Höppner static boolean_t g_lflg = B_FALSE;
8066448911SDavid Höppner static boolean_t g_pflg = B_FALSE;
8166448911SDavid Höppner static boolean_t g_qflg = B_FALSE;
8266448911SDavid Höppner static ks_pattern_t	g_ks_class = {"*", 0};
8366448911SDavid Höppner 
8477481491SBryan Cantrill static boolean_t g_matched = B_FALSE;
8566448911SDavid Höppner 
8666448911SDavid Höppner /* Sorted list of kstat instances */
8766448911SDavid Höppner static list_t	instances_list;
8866448911SDavid Höppner static list_t	selector_list;
8966448911SDavid Höppner 
9066448911SDavid Höppner int
main(int argc,char ** argv)9166448911SDavid Höppner main(int argc, char **argv)
9266448911SDavid Höppner {
9366448911SDavid Höppner 	ks_selector_t	*nselector;
9466448911SDavid Höppner 	ks_selector_t	*uselector;
9566448911SDavid Höppner 	kstat_ctl_t	*kc;
9666448911SDavid Höppner 	hrtime_t	start_n;
9766448911SDavid Höppner 	hrtime_t	period_n;
9866448911SDavid Höppner 	boolean_t	errflg = B_FALSE;
9966448911SDavid Höppner 	boolean_t	nselflg = B_FALSE;
10066448911SDavid Höppner 	boolean_t	uselflg = B_FALSE;
10166448911SDavid Höppner 	char		*q;
10266448911SDavid Höppner 	int		count = 1;
10366448911SDavid Höppner 	int		infinite_cycles = 0;
10466448911SDavid Höppner 	int		interval = 0;
10566448911SDavid Höppner 	int		n = 0;
10666448911SDavid Höppner 	int		c, m, tmp;
10766448911SDavid Höppner 
10866448911SDavid Höppner 	(void) setlocale(LC_ALL, "");
10966448911SDavid Höppner #if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D */
11066448911SDavid Höppner #define	TEXT_DOMAIN "SYS_TEST"		/* Use this only if it wasn't */
11166448911SDavid Höppner #endif
11266448911SDavid Höppner 	(void) textdomain(TEXT_DOMAIN);
11366448911SDavid Höppner 
11466448911SDavid Höppner 	/*
11566448911SDavid Höppner 	 * Create the selector list and a dummy default selector to match
11666448911SDavid Höppner 	 * everything. While we process the cmdline options we will add
11766448911SDavid Höppner 	 * selectors to this list.
11866448911SDavid Höppner 	 */
11966448911SDavid Höppner 	list_create(&selector_list, sizeof (ks_selector_t),
12066448911SDavid Höppner 	    offsetof(ks_selector_t, ks_next));
12166448911SDavid Höppner 
12266448911SDavid Höppner 	nselector = new_selector();
12366448911SDavid Höppner 
12466448911SDavid Höppner 	/*
12566448911SDavid Höppner 	 * Parse named command line arguments.
12666448911SDavid Höppner 	 */
12766448911SDavid Höppner 	while ((c = getopt(argc, argv, "h?CqjlpT:m:i:n:s:c:")) != EOF)
12866448911SDavid Höppner 		switch (c) {
12966448911SDavid Höppner 		case 'h':
13066448911SDavid Höppner 		case '?':
13166448911SDavid Höppner 			usage();
13266448911SDavid Höppner 			exit(0);
13366448911SDavid Höppner 			break;
13466448911SDavid Höppner 		case 'C':
13566448911SDavid Höppner 			g_pflg = g_cflg = B_TRUE;
13666448911SDavid Höppner 			break;
13766448911SDavid Höppner 		case 'q':
13866448911SDavid Höppner 			g_qflg = B_TRUE;
13966448911SDavid Höppner 			break;
14066448911SDavid Höppner 		case 'j':
14177481491SBryan Cantrill 			/*
14277481491SBryan Cantrill 			 * If we're printing JSON, we're going to force numeric
14377481491SBryan Cantrill 			 * representation to be in the C locale to assure that
14477481491SBryan Cantrill 			 * the decimal point is compliant with RFC 7159 (i.e.,
14577481491SBryan Cantrill 			 * ASCII 0x2e).
14677481491SBryan Cantrill 			 */
14777481491SBryan Cantrill 			(void) setlocale(LC_NUMERIC, "C");
14866448911SDavid Höppner 			g_jflg = B_TRUE;
14966448911SDavid Höppner 			break;
15066448911SDavid Höppner 		case 'l':
15166448911SDavid Höppner 			g_pflg = g_lflg = B_TRUE;
15266448911SDavid Höppner 			break;
15366448911SDavid Höppner 		case 'p':
15466448911SDavid Höppner 			g_pflg = B_TRUE;
15566448911SDavid Höppner 			break;
15666448911SDavid Höppner 		case 'T':
15766448911SDavid Höppner 			switch (*optarg) {
15866448911SDavid Höppner 			case 'd':
15966448911SDavid Höppner 				g_timestamp_fmt = DDATE;
16066448911SDavid Höppner 				break;
16166448911SDavid Höppner 			case 'u':
16266448911SDavid Höppner 				g_timestamp_fmt = UDATE;
16366448911SDavid Höppner 				break;
16466448911SDavid Höppner 			default:
16566448911SDavid Höppner 				errflg = B_TRUE;
16666448911SDavid Höppner 			}
16766448911SDavid Höppner 			break;
16866448911SDavid Höppner 		case 'm':
16966448911SDavid Höppner 			nselflg = B_TRUE;
17066448911SDavid Höppner 			nselector->ks_module.pstr =
17166448911SDavid Höppner 			    (char *)ks_safe_strdup(optarg);
17266448911SDavid Höppner 			break;
17366448911SDavid Höppner 		case 'i':
17466448911SDavid Höppner 			nselflg = B_TRUE;
17566448911SDavid Höppner 			nselector->ks_instance.pstr =
17666448911SDavid Höppner 			    (char *)ks_safe_strdup(optarg);
17766448911SDavid Höppner 			break;
17866448911SDavid Höppner 		case 'n':
17966448911SDavid Höppner 			nselflg = B_TRUE;
18066448911SDavid Höppner 			nselector->ks_name.pstr =
18166448911SDavid Höppner 			    (char *)ks_safe_strdup(optarg);
18266448911SDavid Höppner 			break;
18366448911SDavid Höppner 		case 's':
18466448911SDavid Höppner 			nselflg = B_TRUE;
18566448911SDavid Höppner 			nselector->ks_statistic.pstr =
18666448911SDavid Höppner 			    (char *)ks_safe_strdup(optarg);
18766448911SDavid Höppner 			break;
18866448911SDavid Höppner 		case 'c':
18966448911SDavid Höppner 			g_ks_class.pstr =
19066448911SDavid Höppner 			    (char *)ks_safe_strdup(optarg);
19166448911SDavid Höppner 			break;
19266448911SDavid Höppner 		default:
19366448911SDavid Höppner 			errflg = B_TRUE;
19466448911SDavid Höppner 			break;
19566448911SDavid Höppner 		}
19666448911SDavid Höppner 
19766448911SDavid Höppner 	if (g_qflg && (g_jflg || g_pflg)) {
19866448911SDavid Höppner 		(void) fprintf(stderr, gettext(
19966448911SDavid Höppner 		    "-q and -lpj are mutually exclusive\n"));
20066448911SDavid Höppner 		errflg = B_TRUE;
20166448911SDavid Höppner 	}
20266448911SDavid Höppner 
20366448911SDavid Höppner 	if (errflg) {
20466448911SDavid Höppner 		usage();
20566448911SDavid Höppner 		exit(2);
20666448911SDavid Höppner 	}
20766448911SDavid Höppner 
20866448911SDavid Höppner 	argc -= optind;
20966448911SDavid Höppner 	argv += optind;
21066448911SDavid Höppner 
21166448911SDavid Höppner 	/*
21266448911SDavid Höppner 	 * Consume the rest of the command line. Parsing the
21366448911SDavid Höppner 	 * unnamed command line arguments.
21466448911SDavid Höppner 	 */
21566448911SDavid Höppner 	while (argc--) {
21666448911SDavid Höppner 		errno = 0;
21766448911SDavid Höppner 		tmp = strtoul(*argv, &q, 10);
21866448911SDavid Höppner 		if (tmp == ULONG_MAX && errno == ERANGE) {
21966448911SDavid Höppner 			if (n == 0) {
22066448911SDavid Höppner 				(void) fprintf(stderr, gettext(
22166448911SDavid Höppner 				    "Interval is too large\n"));
22266448911SDavid Höppner 			} else if (n == 1) {
22366448911SDavid Höppner 				(void) fprintf(stderr, gettext(
22466448911SDavid Höppner 				    "Count is too large\n"));
22566448911SDavid Höppner 			}
22666448911SDavid Höppner 			usage();
22766448911SDavid Höppner 			exit(2);
22866448911SDavid Höppner 		}
22966448911SDavid Höppner 
23066448911SDavid Höppner 		if (errno != 0 || *q != '\0') {
23166448911SDavid Höppner 			m = 0;
23266448911SDavid Höppner 			uselector = new_selector();
23366448911SDavid Höppner 			while ((q = (char *)strsep(argv, ":")) != NULL) {
23466448911SDavid Höppner 				m++;
23566448911SDavid Höppner 				if (m > 4) {
23666448911SDavid Höppner 					free(uselector);
23766448911SDavid Höppner 					usage();
23866448911SDavid Höppner 					exit(2);
23966448911SDavid Höppner 				}
24066448911SDavid Höppner 
24166448911SDavid Höppner 				if (*q != '\0') {
24266448911SDavid Höppner 					switch (m) {
24366448911SDavid Höppner 					case 1:
24466448911SDavid Höppner 						uselector->ks_module.pstr =
24566448911SDavid Höppner 						    (char *)ks_safe_strdup(q);
24666448911SDavid Höppner 						break;
24766448911SDavid Höppner 					case 2:
24866448911SDavid Höppner 						uselector->ks_instance.pstr =
24966448911SDavid Höppner 						    (char *)ks_safe_strdup(q);
25066448911SDavid Höppner 						break;
25166448911SDavid Höppner 					case 3:
25266448911SDavid Höppner 						uselector->ks_name.pstr =
25366448911SDavid Höppner 						    (char *)ks_safe_strdup(q);
25466448911SDavid Höppner 						break;
25566448911SDavid Höppner 					case 4:
25666448911SDavid Höppner 						uselector->ks_statistic.pstr =
25766448911SDavid Höppner 						    (char *)ks_safe_strdup(q);
25866448911SDavid Höppner 						break;
25966448911SDavid Höppner 					default:
26066448911SDavid Höppner 						assert(B_FALSE);
26166448911SDavid Höppner 					}
26266448911SDavid Höppner 				}
26366448911SDavid Höppner 			}
26466448911SDavid Höppner 
26566448911SDavid Höppner 			uselflg = B_TRUE;
26666448911SDavid Höppner 			list_insert_tail(&selector_list, uselector);
26766448911SDavid Höppner 		} else {
26866448911SDavid Höppner 			if (tmp < 1) {
26966448911SDavid Höppner 				if (n == 0) {
27066448911SDavid Höppner 					(void) fprintf(stderr, gettext(
27166448911SDavid Höppner 					    "Interval must be an "
27266448911SDavid Höppner 					    "integer >= 1"));
27366448911SDavid Höppner 				} else if (n == 1) {
27466448911SDavid Höppner 					(void) fprintf(stderr, gettext(
27566448911SDavid Höppner 					    "Count must be an integer >= 1"));
27666448911SDavid Höppner 				}
27766448911SDavid Höppner 				usage();
27866448911SDavid Höppner 				exit(2);
27966448911SDavid Höppner 			} else {
28066448911SDavid Höppner 				if (n == 0) {
28166448911SDavid Höppner 					interval = tmp;
28266448911SDavid Höppner 					count = -1;
28366448911SDavid Höppner 				} else if (n == 1) {
28466448911SDavid Höppner 					count = tmp;
28566448911SDavid Höppner 				} else {
28666448911SDavid Höppner 					usage();
28766448911SDavid Höppner 					exit(2);
28866448911SDavid Höppner 				}
28966448911SDavid Höppner 			}
29066448911SDavid Höppner 			n++;
29166448911SDavid Höppner 		}
29266448911SDavid Höppner 		argv++;
29366448911SDavid Höppner 	}
29466448911SDavid Höppner 
29566448911SDavid Höppner 	/*
29666448911SDavid Höppner 	 * Check if we founded a named selector on the cmdline.
29766448911SDavid Höppner 	 */
29866448911SDavid Höppner 	if (uselflg) {
29966448911SDavid Höppner 		if (nselflg) {
30066448911SDavid Höppner 			(void) fprintf(stderr, gettext(
301617413d1SRichard Lowe 			    "[module[:instance[:name[:statistic]]]] and "
30266448911SDavid Höppner 			    "-m -i -n -s are mutually exclusive"));
30366448911SDavid Höppner 			usage();
30466448911SDavid Höppner 			exit(2);
30566448911SDavid Höppner 		} else {
30666448911SDavid Höppner 			free(nselector);
30766448911SDavid Höppner 		}
30866448911SDavid Höppner 	} else {
30966448911SDavid Höppner 		list_insert_tail(&selector_list, nselector);
31066448911SDavid Höppner 	}
31166448911SDavid Höppner 
31266448911SDavid Höppner 	assert(!list_is_empty(&selector_list));
31366448911SDavid Höppner 
31466448911SDavid Höppner 	list_create(&instances_list, sizeof (ks_instance_t),
31566448911SDavid Höppner 	    offsetof(ks_instance_t, ks_next));
31666448911SDavid Höppner 
31766448911SDavid Höppner 	while ((kc = kstat_open()) == NULL) {
31866448911SDavid Höppner 		if (errno == EAGAIN) {
31966448911SDavid Höppner 			(void) poll(NULL, 0, 200);
32066448911SDavid Höppner 		} else {
32166448911SDavid Höppner 			perror("kstat_open");
32266448911SDavid Höppner 			exit(3);
32366448911SDavid Höppner 		}
32466448911SDavid Höppner 	}
32566448911SDavid Höppner 
32666448911SDavid Höppner 	if (count > 1) {
32766448911SDavid Höppner 		if (signal(SIGCONT, cont_handler) == SIG_ERR) {
32866448911SDavid Höppner 			(void) fprintf(stderr, gettext(
32966448911SDavid Höppner 			    "signal failed"));
33066448911SDavid Höppner 			exit(3);
33166448911SDavid Höppner 		}
33266448911SDavid Höppner 	}
33366448911SDavid Höppner 
33466448911SDavid Höppner 	period_n = (hrtime_t)interval * NANOSEC;
33566448911SDavid Höppner 	start_n = gethrtime();
33666448911SDavid Höppner 
33766448911SDavid Höppner 	while (count == -1 || count-- > 0) {
33866448911SDavid Höppner 		ks_instances_read(kc);
33966448911SDavid Höppner 		ks_instances_print();
34066448911SDavid Höppner 
34166448911SDavid Höppner 		if (interval && count) {
34266448911SDavid Höppner 			ks_sleep_until(&start_n, period_n, infinite_cycles,
34366448911SDavid Höppner 			    &caught_cont);
34466448911SDavid Höppner 			(void) kstat_chain_update(kc);
34566448911SDavid Höppner 			(void) putchar('\n');
34666448911SDavid Höppner 		}
34766448911SDavid Höppner 	}
34866448911SDavid Höppner 
34966448911SDavid Höppner 	(void) kstat_close(kc);
35066448911SDavid Höppner 
35177481491SBryan Cantrill 	/*
35277481491SBryan Cantrill 	 * Return a non-zero exit code if we didn't match anything.
35377481491SBryan Cantrill 	 */
35477481491SBryan Cantrill 	return (g_matched ? 0 : 1);
35566448911SDavid Höppner }
35666448911SDavid Höppner 
35766448911SDavid Höppner /*
35866448911SDavid Höppner  * Print usage.
35966448911SDavid Höppner  */
36066448911SDavid Höppner static void
usage(void)36166448911SDavid Höppner usage(void)
36266448911SDavid Höppner {
36366448911SDavid Höppner 	(void) fprintf(stderr, gettext(
36466448911SDavid Höppner 	    "Usage:\n"
36566448911SDavid Höppner 	    "kstat [ -Cjlpq ] [ -T d|u ] [ -c class ]\n"
36666448911SDavid Höppner 	    "      [ -m module ] [ -i instance ] [ -n name ] [ -s statistic ]\n"
36766448911SDavid Höppner 	    "      [ interval [ count ] ]\n"
36866448911SDavid Höppner 	    "kstat [ -Cjlpq ] [ -T d|u ] [ -c class ]\n"
369617413d1SRichard Lowe 	    "      [ module[:instance[:name[:statistic]]] ... ]\n"
37066448911SDavid Höppner 	    "      [ interval [ count ] ]\n"));
37166448911SDavid Höppner }
37266448911SDavid Höppner 
37366448911SDavid Höppner /*
37466448911SDavid Höppner  * Sort compare function.
37566448911SDavid Höppner  */
37666448911SDavid Höppner static int
compare_instances(ks_instance_t * l_arg,ks_instance_t * r_arg)37766448911SDavid Höppner compare_instances(ks_instance_t *l_arg, ks_instance_t *r_arg)
37866448911SDavid Höppner {
37966448911SDavid Höppner 	int	rval;
38066448911SDavid Höppner 
38166448911SDavid Höppner 	rval = strcasecmp(l_arg->ks_module, r_arg->ks_module);
38266448911SDavid Höppner 	if (rval == 0) {
38366448911SDavid Höppner 		if (l_arg->ks_instance == r_arg->ks_instance) {
38466448911SDavid Höppner 			return (strcasecmp(l_arg->ks_name, r_arg->ks_name));
38566448911SDavid Höppner 		} else if (l_arg->ks_instance < r_arg->ks_instance) {
38666448911SDavid Höppner 			return (-1);
38766448911SDavid Höppner 		} else {
38866448911SDavid Höppner 			return (1);
38966448911SDavid Höppner 		}
39066448911SDavid Höppner 	} else {
39166448911SDavid Höppner 		return (rval);
39266448911SDavid Höppner 	}
39366448911SDavid Höppner }
39466448911SDavid Höppner 
39566448911SDavid Höppner static char *
ks_safe_strdup(char * str)39666448911SDavid Höppner ks_safe_strdup(char *str)
39766448911SDavid Höppner {
39866448911SDavid Höppner 	char	*ret;
39966448911SDavid Höppner 
40066448911SDavid Höppner 	if (str == NULL) {
40166448911SDavid Höppner 		return (NULL);
40266448911SDavid Höppner 	}
40366448911SDavid Höppner 
40466448911SDavid Höppner 	while ((ret = strdup(str)) == NULL) {
40566448911SDavid Höppner 		if (errno == EAGAIN) {
40666448911SDavid Höppner 			(void) poll(NULL, 0, 200);
40766448911SDavid Höppner 		} else {
40866448911SDavid Höppner 			perror("strdup");
40966448911SDavid Höppner 			exit(3);
41066448911SDavid Höppner 		}
41166448911SDavid Höppner 	}
41266448911SDavid Höppner 
41366448911SDavid Höppner 	return (ret);
41466448911SDavid Höppner }
41566448911SDavid Höppner 
41666448911SDavid Höppner static void
ks_sleep_until(hrtime_t * wakeup,hrtime_t interval,int forever,int * caught_cont)41766448911SDavid Höppner ks_sleep_until(hrtime_t *wakeup, hrtime_t interval, int forever,
41866448911SDavid Höppner     int *caught_cont)
41966448911SDavid Höppner {
42066448911SDavid Höppner 	hrtime_t	now, pause, pause_left;
42166448911SDavid Höppner 	struct timespec	pause_tv;
42266448911SDavid Höppner 	int		status;
42366448911SDavid Höppner 
42466448911SDavid Höppner 	now = gethrtime();
42566448911SDavid Höppner 	pause = *wakeup + interval - now;
42666448911SDavid Höppner 
42766448911SDavid Höppner 	if (pause <= 0 || pause < (interval / 4)) {
42866448911SDavid Höppner 		if (forever || *caught_cont) {
42966448911SDavid Höppner 			*wakeup = now + interval;
43066448911SDavid Höppner 			pause = interval;
43166448911SDavid Höppner 		} else {
43266448911SDavid Höppner 			pause = interval / 2;
43366448911SDavid Höppner 			*wakeup += interval;
43466448911SDavid Höppner 		}
43566448911SDavid Höppner 	} else {
43666448911SDavid Höppner 		*wakeup += interval;
43766448911SDavid Höppner 	}
43866448911SDavid Höppner 
43966448911SDavid Höppner 	if (pause < 1000) {
44066448911SDavid Höppner 		return;
44166448911SDavid Höppner 	}
44266448911SDavid Höppner 
44366448911SDavid Höppner 	pause_left = pause;
44466448911SDavid Höppner 	do {
44566448911SDavid Höppner 		pause_tv.tv_sec = pause_left / NANOSEC;
44666448911SDavid Höppner 		pause_tv.tv_nsec = pause_left % NANOSEC;
44766448911SDavid Höppner 		status = nanosleep(&pause_tv, (struct timespec *)NULL);
44866448911SDavid Höppner 		if (status < 0) {
44966448911SDavid Höppner 			if (errno == EINTR) {
45066448911SDavid Höppner 				now = gethrtime();
45166448911SDavid Höppner 				pause_left = *wakeup - now;
45266448911SDavid Höppner 				if (pause_left < 1000) {
45366448911SDavid Höppner 					return;
45466448911SDavid Höppner 				}
45566448911SDavid Höppner 			} else {
45666448911SDavid Höppner 				perror("nanosleep");
45766448911SDavid Höppner 				exit(3);
45866448911SDavid Höppner 			}
45966448911SDavid Höppner 		}
46066448911SDavid Höppner 	} while (status != 0);
46166448911SDavid Höppner }
46266448911SDavid Höppner 
46366448911SDavid Höppner /*
46466448911SDavid Höppner  * Inserts an instance in the per selector list.
46566448911SDavid Höppner  */
46666448911SDavid Höppner static void
nvpair_insert(ks_instance_t * ksi,char * name,ks_value_t * value,uchar_t data_type)46766448911SDavid Höppner nvpair_insert(ks_instance_t *ksi, char *name, ks_value_t *value,
46866448911SDavid Höppner     uchar_t data_type)
46966448911SDavid Höppner {
47066448911SDavid Höppner 	ks_nvpair_t	*instance;
47166448911SDavid Höppner 	ks_nvpair_t	*tmp;
47266448911SDavid Höppner 
47366448911SDavid Höppner 	instance = (ks_nvpair_t *)malloc(sizeof (ks_nvpair_t));
47466448911SDavid Höppner 	if (instance == NULL) {
47566448911SDavid Höppner 		perror("malloc");
47666448911SDavid Höppner 		exit(3);
47766448911SDavid Höppner 	}
47866448911SDavid Höppner 
47966448911SDavid Höppner 	(void) strlcpy(instance->name, name, KSTAT_STRLEN);
48066448911SDavid Höppner 	(void) memcpy(&instance->value, value, sizeof (ks_value_t));
48166448911SDavid Höppner 	instance->data_type = data_type;
48266448911SDavid Höppner 
48366448911SDavid Höppner 	tmp = list_head(&ksi->ks_nvlist);
48466448911SDavid Höppner 	while (tmp != NULL && strcasecmp(instance->name, tmp->name) > 0)
48566448911SDavid Höppner 		tmp = list_next(&ksi->ks_nvlist, tmp);
48666448911SDavid Höppner 
48766448911SDavid Höppner 	list_insert_before(&ksi->ks_nvlist, tmp, instance);
48866448911SDavid Höppner }
48966448911SDavid Höppner 
49066448911SDavid Höppner /*
49166448911SDavid Höppner  * Allocates a new all-matching selector.
49266448911SDavid Höppner  */
49366448911SDavid Höppner static ks_selector_t *
new_selector(void)49466448911SDavid Höppner new_selector(void)
49566448911SDavid Höppner {
49666448911SDavid Höppner 	ks_selector_t	*selector;
49766448911SDavid Höppner 
49866448911SDavid Höppner 	selector = (ks_selector_t *)malloc(sizeof (ks_selector_t));
49966448911SDavid Höppner 	if (selector == NULL) {
50066448911SDavid Höppner 		perror("malloc");
50166448911SDavid Höppner 		exit(3);
50266448911SDavid Höppner 	}
50366448911SDavid Höppner 
50466448911SDavid Höppner 	list_link_init(&selector->ks_next);
50566448911SDavid Höppner 
50666448911SDavid Höppner 	selector->ks_module.pstr = "*";
50766448911SDavid Höppner 	selector->ks_instance.pstr = "*";
50866448911SDavid Höppner 	selector->ks_name.pstr = "*";
50966448911SDavid Höppner 	selector->ks_statistic.pstr = "*";
51066448911SDavid Höppner 
51166448911SDavid Höppner 	return (selector);
51266448911SDavid Höppner }
51366448911SDavid Höppner 
51466448911SDavid Höppner /*
51566448911SDavid Höppner  * This function was taken from the perl kstat module code - please
51666448911SDavid Höppner  * see for further comments there.
51766448911SDavid Höppner  */
51866448911SDavid Höppner static kstat_raw_reader_t
lookup_raw_kstat_fn(char * module,char * name)51966448911SDavid Höppner lookup_raw_kstat_fn(char *module, char *name)
52066448911SDavid Höppner {
52166448911SDavid Höppner 	char		key[KSTAT_STRLEN * 2];
522*8af765f5SPeter Tribble 	register char	*f, *t;
52366448911SDavid Höppner 	int		n = 0;
52466448911SDavid Höppner 
52566448911SDavid Höppner 	for (f = module, t = key; *f != '\0'; f++, t++) {
52666448911SDavid Höppner 		while (*f != '\0' && isdigit(*f))
52766448911SDavid Höppner 			f++;
52866448911SDavid Höppner 		*t = *f;
52966448911SDavid Höppner 	}
53066448911SDavid Höppner 	*t++ = ':';
53166448911SDavid Höppner 
53266448911SDavid Höppner 	for (f = name; *f != '\0'; f++, t++) {
53366448911SDavid Höppner 		while (*f != '\0' && isdigit(*f))
53466448911SDavid Höppner 			f++;
53566448911SDavid Höppner 		*t = *f;
53666448911SDavid Höppner 	}
53766448911SDavid Höppner 	*t = '\0';
53866448911SDavid Höppner 
53966448911SDavid Höppner 	while (ks_raw_lookup[n].fn != NULL) {
54066448911SDavid Höppner 		if (strncmp(ks_raw_lookup[n].name, key, strlen(key)) == 0)
54166448911SDavid Höppner 			return (ks_raw_lookup[n].fn);
54266448911SDavid Höppner 		n++;
54366448911SDavid Höppner 	}
54466448911SDavid Höppner 
54566448911SDavid Höppner 	return (0);
54666448911SDavid Höppner }
54766448911SDavid Höppner 
54866448911SDavid Höppner /*
54966448911SDavid Höppner  * Match a string against a shell glob or extended regular expression.
55066448911SDavid Höppner  */
55166448911SDavid Höppner static boolean_t
ks_match(const char * str,ks_pattern_t * pattern)55266448911SDavid Höppner ks_match(const char *str, ks_pattern_t *pattern)
55366448911SDavid Höppner {
55466448911SDavid Höppner 	int	regcode;
55566448911SDavid Höppner 	char	*regstr;
55666448911SDavid Höppner 	char	*errbuf;
55766448911SDavid Höppner 	size_t	bufsz;
55866448911SDavid Höppner 
55966448911SDavid Höppner 	if (pattern->pstr != NULL && gmatch(pattern->pstr, "/*/") != 0) {
56066448911SDavid Höppner 		/* All regex patterns are strdup'd copies */
56166448911SDavid Höppner 		regstr = pattern->pstr + 1;
56266448911SDavid Höppner 		*(strrchr(regstr, '/')) = '\0';
56366448911SDavid Höppner 
56466448911SDavid Höppner 		regcode = regcomp(&pattern->preg, regstr,
56566448911SDavid Höppner 		    REG_EXTENDED | REG_NOSUB);
56666448911SDavid Höppner 		if (regcode != 0) {
56766448911SDavid Höppner 			bufsz = regerror(regcode, NULL, NULL, 0);
56866448911SDavid Höppner 			if (bufsz != 0) {
56966448911SDavid Höppner 				errbuf = malloc(bufsz);
57066448911SDavid Höppner 				if (errbuf == NULL) {
57166448911SDavid Höppner 					perror("malloc");
57266448911SDavid Höppner 					exit(3);
57366448911SDavid Höppner 				}
57466448911SDavid Höppner 				(void) regerror(regcode, NULL, errbuf, bufsz);
57566448911SDavid Höppner 				(void) fprintf(stderr, "kstat: %s\n", errbuf);
57666448911SDavid Höppner 			}
57766448911SDavid Höppner 			usage();
57866448911SDavid Höppner 			exit(2);
57966448911SDavid Höppner 		}
58066448911SDavid Höppner 
58166448911SDavid Höppner 		pattern->pstr = NULL;
58266448911SDavid Höppner 	}
58366448911SDavid Höppner 
58466448911SDavid Höppner 	if (pattern->pstr == NULL) {
58566448911SDavid Höppner 		return (regexec(&pattern->preg, str, 0, NULL, 0) == 0);
58666448911SDavid Höppner 	}
58766448911SDavid Höppner 
58866448911SDavid Höppner 	return ((gmatch(str, pattern->pstr) != 0));
58966448911SDavid Höppner }
59066448911SDavid Höppner 
59166448911SDavid Höppner /*
59266448911SDavid Höppner  * Iterate over all kernel statistics and save matches.
59366448911SDavid Höppner  */
59466448911SDavid Höppner static void
ks_instances_read(kstat_ctl_t * kc)59566448911SDavid Höppner ks_instances_read(kstat_ctl_t *kc)
59666448911SDavid Höppner {
59766448911SDavid Höppner 	kstat_raw_reader_t save_raw = NULL;
59866448911SDavid Höppner 	kid_t		id;
59966448911SDavid Höppner 	ks_selector_t	*selector;
60066448911SDavid Höppner 	ks_instance_t	*ksi;
60166448911SDavid Höppner 	ks_instance_t	*tmp;
60266448911SDavid Höppner 	kstat_t		*kp;
60366448911SDavid Höppner 	boolean_t	skip;
60466448911SDavid Höppner 
60566448911SDavid Höppner 	for (kp = kc->kc_chain; kp != NULL; kp = kp->ks_next) {
60666448911SDavid Höppner 		/* Don't bother storing the kstat headers */
60766448911SDavid Höppner 		if (strncmp(kp->ks_name, "kstat_", 6) == 0) {
60866448911SDavid Höppner 			continue;
60966448911SDavid Höppner 		}
61066448911SDavid Höppner 
61166448911SDavid Höppner 		/* Don't bother storing raw stats we don't understand */
61266448911SDavid Höppner 		if (kp->ks_type == KSTAT_TYPE_RAW) {
61366448911SDavid Höppner 			save_raw = lookup_raw_kstat_fn(kp->ks_module,
61466448911SDavid Höppner 			    kp->ks_name);
61566448911SDavid Höppner 			if (save_raw == NULL) {
61666448911SDavid Höppner #ifdef REPORT_UNKNOWN
61766448911SDavid Höppner 				(void) fprintf(stderr,
61866448911SDavid Höppner 				    "Unknown kstat type %s:%d:%s - "
61966448911SDavid Höppner 				    "%d of size %d\n", kp->ks_module,
62066448911SDavid Höppner 				    kp->ks_instance, kp->ks_name,
62166448911SDavid Höppner 				    kp->ks_ndata, kp->ks_data_size);
62266448911SDavid Höppner #endif
62366448911SDavid Höppner 				continue;
62466448911SDavid Höppner 			}
62566448911SDavid Höppner 		}
62666448911SDavid Höppner 
62766448911SDavid Höppner 		/*
62866448911SDavid Höppner 		 * Iterate over the list of selectors and skip
62966448911SDavid Höppner 		 * instances we dont want. We filter for statistics
63066448911SDavid Höppner 		 * later, as we dont know them yet.
63166448911SDavid Höppner 		 */
63266448911SDavid Höppner 		skip = B_TRUE;
63366448911SDavid Höppner 		selector = list_head(&selector_list);
63466448911SDavid Höppner 		while (selector != NULL) {
6359736aecdSBryan Cantrill 			if (ks_match(kp->ks_module, &selector->ks_module) &&
63666448911SDavid Höppner 			    ks_match(kp->ks_name, &selector->ks_name)) {
63766448911SDavid Höppner 				skip = B_FALSE;
63866448911SDavid Höppner 				break;
63966448911SDavid Höppner 			}
64066448911SDavid Höppner 			selector = list_next(&selector_list, selector);
64166448911SDavid Höppner 		}
64266448911SDavid Höppner 
64366448911SDavid Höppner 		if (skip) {
64466448911SDavid Höppner 			continue;
64566448911SDavid Höppner 		}
64666448911SDavid Höppner 
64766448911SDavid Höppner 		/*
64866448911SDavid Höppner 		 * Allocate a new instance and fill in the values
64966448911SDavid Höppner 		 * we know so far.
65066448911SDavid Höppner 		 */
65166448911SDavid Höppner 		ksi = (ks_instance_t *)malloc(sizeof (ks_instance_t));
65266448911SDavid Höppner 		if (ksi == NULL) {
65366448911SDavid Höppner 			perror("malloc");
65466448911SDavid Höppner 			exit(3);
65566448911SDavid Höppner 		}
65666448911SDavid Höppner 
65766448911SDavid Höppner 		list_link_init(&ksi->ks_next);
65866448911SDavid Höppner 
65966448911SDavid Höppner 		(void) strlcpy(ksi->ks_module, kp->ks_module, KSTAT_STRLEN);
66066448911SDavid Höppner 		(void) strlcpy(ksi->ks_name, kp->ks_name, KSTAT_STRLEN);
66166448911SDavid Höppner 		(void) strlcpy(ksi->ks_class, kp->ks_class, KSTAT_STRLEN);
66266448911SDavid Höppner 
66366448911SDavid Höppner 		ksi->ks_instance = kp->ks_instance;
66466448911SDavid Höppner 		ksi->ks_snaptime = kp->ks_snaptime;
66566448911SDavid Höppner 		ksi->ks_type = kp->ks_type;
66666448911SDavid Höppner 
66766448911SDavid Höppner 		list_create(&ksi->ks_nvlist, sizeof (ks_nvpair_t),
66866448911SDavid Höppner 		    offsetof(ks_nvpair_t, nv_next));
66966448911SDavid Höppner 
67066448911SDavid Höppner 		SAVE_HRTIME_X(ksi, "crtime", kp->ks_crtime);
67166448911SDavid Höppner 		if (g_pflg) {
67266448911SDavid Höppner 			SAVE_STRING_X(ksi, "class", kp->ks_class);
67366448911SDavid Höppner 		}
67466448911SDavid Höppner 
67566448911SDavid Höppner 		/* Insert this instance into a sorted list */
67666448911SDavid Höppner 		tmp = list_head(&instances_list);
67766448911SDavid Höppner 		while (tmp != NULL && compare_instances(ksi, tmp) > 0)
67866448911SDavid Höppner 			tmp = list_next(&instances_list, tmp);
67966448911SDavid Höppner 
68066448911SDavid Höppner 		list_insert_before(&instances_list, tmp, ksi);
68166448911SDavid Höppner 
68266448911SDavid Höppner 		/* Read the actual statistics */
68366448911SDavid Höppner 		id = kstat_read(kc, kp, NULL);
68466448911SDavid Höppner 		if (id == -1) {
68566448911SDavid Höppner #ifdef REPORT_UNKNOWN
68666448911SDavid Höppner 			perror("kstat_read");
68766448911SDavid Höppner #endif
68866448911SDavid Höppner 			continue;
68966448911SDavid Höppner 		}
69066448911SDavid Höppner 
6916a19b866SRobert Mustacchi 		SAVE_HRTIME_X(ksi, "snaptime", kp->ks_snaptime);
6926a19b866SRobert Mustacchi 
69366448911SDavid Höppner 		switch (kp->ks_type) {
69466448911SDavid Höppner 		case KSTAT_TYPE_RAW:
69566448911SDavid Höppner 			save_raw(kp, ksi);
69666448911SDavid Höppner 			break;
69766448911SDavid Höppner 		case KSTAT_TYPE_NAMED:
69866448911SDavid Höppner 			save_named(kp, ksi);
69966448911SDavid Höppner 			break;
70066448911SDavid Höppner 		case KSTAT_TYPE_INTR:
70166448911SDavid Höppner 			save_intr(kp, ksi);
70266448911SDavid Höppner 			break;
70366448911SDavid Höppner 		case KSTAT_TYPE_IO:
70466448911SDavid Höppner 			save_io(kp, ksi);
70566448911SDavid Höppner 			break;
70666448911SDavid Höppner 		case KSTAT_TYPE_TIMER:
70766448911SDavid Höppner 			save_timer(kp, ksi);
70866448911SDavid Höppner 			break;
70966448911SDavid Höppner 		default:
71066448911SDavid Höppner 			assert(B_FALSE); /* Invalid type */
71166448911SDavid Höppner 			break;
71266448911SDavid Höppner 		}
71366448911SDavid Höppner 	}
71466448911SDavid Höppner }
71566448911SDavid Höppner 
71666448911SDavid Höppner /*
71766448911SDavid Höppner  * Print the value of a name-value pair.
71866448911SDavid Höppner  */
71966448911SDavid Höppner static void
ks_value_print(ks_nvpair_t * nvpair)72066448911SDavid Höppner ks_value_print(ks_nvpair_t *nvpair)
72166448911SDavid Höppner {
72266448911SDavid Höppner 	switch (nvpair->data_type) {
72366448911SDavid Höppner 	case KSTAT_DATA_CHAR:
72466448911SDavid Höppner 		(void) fprintf(stdout, "%s", nvpair->value.c);
72566448911SDavid Höppner 		break;
72666448911SDavid Höppner 	case KSTAT_DATA_INT32:
72766448911SDavid Höppner 		(void) fprintf(stdout, "%d", nvpair->value.i32);
72866448911SDavid Höppner 		break;
72966448911SDavid Höppner 	case KSTAT_DATA_UINT32:
73066448911SDavid Höppner 		(void) fprintf(stdout, "%u", nvpair->value.ui32);
73166448911SDavid Höppner 		break;
73266448911SDavid Höppner 	case KSTAT_DATA_INT64:
73366448911SDavid Höppner 		(void) fprintf(stdout, "%lld", nvpair->value.i64);
73466448911SDavid Höppner 		break;
73566448911SDavid Höppner 	case KSTAT_DATA_UINT64:
73666448911SDavid Höppner 		(void) fprintf(stdout, "%llu", nvpair->value.ui64);
73766448911SDavid Höppner 		break;
73866448911SDavid Höppner 	case KSTAT_DATA_STRING:
73966448911SDavid Höppner 		(void) fprintf(stdout, "%s", KSTAT_NAMED_STR_PTR(nvpair));
74066448911SDavid Höppner 		break;
74166448911SDavid Höppner 	case KSTAT_DATA_HRTIME:
74266448911SDavid Höppner 		if (nvpair->value.ui64 == 0)
74366448911SDavid Höppner 			(void) fprintf(stdout, "0");
74466448911SDavid Höppner 		else
74566448911SDavid Höppner 			(void) fprintf(stdout, "%.9f",
74666448911SDavid Höppner 			    nvpair->value.ui64 / 1000000000.0);
74766448911SDavid Höppner 		break;
74866448911SDavid Höppner 	default:
74966448911SDavid Höppner 		assert(B_FALSE);
75066448911SDavid Höppner 	}
75166448911SDavid Höppner }
75266448911SDavid Höppner 
75366448911SDavid Höppner /*
75466448911SDavid Höppner  * Print a single instance.
75566448911SDavid Höppner  */
75677481491SBryan Cantrill /*ARGSUSED*/
75766448911SDavid Höppner static void
ks_instance_print(ks_instance_t * ksi,ks_nvpair_t * nvpair,boolean_t last)75877481491SBryan Cantrill ks_instance_print(ks_instance_t *ksi, ks_nvpair_t *nvpair, boolean_t last)
75966448911SDavid Höppner {
76066448911SDavid Höppner 	if (g_headerflg) {
76166448911SDavid Höppner 		if (!g_pflg) {
76266448911SDavid Höppner 			(void) fprintf(stdout, DFLT_FMT,
76366448911SDavid Höppner 			    ksi->ks_module, ksi->ks_instance,
76466448911SDavid Höppner 			    ksi->ks_name, ksi->ks_class);
76566448911SDavid Höppner 		}
76666448911SDavid Höppner 		g_headerflg = B_FALSE;
76766448911SDavid Höppner 	}
76866448911SDavid Höppner 
76966448911SDavid Höppner 	if (g_pflg) {
77066448911SDavid Höppner 		(void) fprintf(stdout, KS_PFMT,
77166448911SDavid Höppner 		    ksi->ks_module, ksi->ks_instance,
77266448911SDavid Höppner 		    ksi->ks_name, nvpair->name);
77366448911SDavid Höppner 		if (!g_lflg) {
77466448911SDavid Höppner 			(void) putchar(g_cflg ? ':': '\t');
77566448911SDavid Höppner 			ks_value_print(nvpair);
77666448911SDavid Höppner 		}
77766448911SDavid Höppner 	} else {
77866448911SDavid Höppner 		(void) fprintf(stdout, KS_DFMT, nvpair->name);
77966448911SDavid Höppner 		ks_value_print(nvpair);
78066448911SDavid Höppner 	}
78166448911SDavid Höppner 
78266448911SDavid Höppner 	(void) putchar('\n');
78366448911SDavid Höppner }
78466448911SDavid Höppner 
78577481491SBryan Cantrill /*
78677481491SBryan Cantrill  * Print a C string as a JSON string.
78777481491SBryan Cantrill  */
78877481491SBryan Cantrill static void
ks_print_json_string(const char * str)78977481491SBryan Cantrill ks_print_json_string(const char *str)
79077481491SBryan Cantrill {
79177481491SBryan Cantrill 	char c;
79277481491SBryan Cantrill 
79377481491SBryan Cantrill 	(void) putchar('"');
79477481491SBryan Cantrill 
79577481491SBryan Cantrill 	while ((c = *str++) != '\0') {
79677481491SBryan Cantrill 		/*
79777481491SBryan Cantrill 		 * For readability, we use the allowed alternate escape
79877481491SBryan Cantrill 		 * sequence for quote, question mark, reverse solidus (look
79977481491SBryan Cantrill 		 * it up!), newline and tab -- and use the universal escape
80077481491SBryan Cantrill 		 * sequence for all other control characters.
80177481491SBryan Cantrill 		 */
80277481491SBryan Cantrill 		switch (c) {
80377481491SBryan Cantrill 		case '"':
80477481491SBryan Cantrill 		case '?':
80577481491SBryan Cantrill 		case '\\':
80677481491SBryan Cantrill 			(void) fprintf(stdout, "\\%c", c);
80777481491SBryan Cantrill 			break;
80877481491SBryan Cantrill 
80977481491SBryan Cantrill 		case '\n':
81077481491SBryan Cantrill 			(void) fprintf(stdout, "\\n");
81177481491SBryan Cantrill 			break;
81277481491SBryan Cantrill 
81377481491SBryan Cantrill 		case '\t':
81477481491SBryan Cantrill 			(void) fprintf(stdout, "\\t");
81577481491SBryan Cantrill 			break;
81677481491SBryan Cantrill 
81777481491SBryan Cantrill 		default:
81877481491SBryan Cantrill 			/*
81977481491SBryan Cantrill 			 * By escaping those characters for which isprint(3C)
82077481491SBryan Cantrill 			 * is false, we escape both the RFC 7159 mandated
82177481491SBryan Cantrill 			 * escaped range of 0x01 through 0x1f as well as DEL
82277481491SBryan Cantrill 			 * (0x7f -- the control character that RFC 7159 forgot)
82377481491SBryan Cantrill 			 * and then everything else that's unprintable for
82477481491SBryan Cantrill 			 * good measure.
82577481491SBryan Cantrill 			 */
82677481491SBryan Cantrill 			if (!isprint(c)) {
82777481491SBryan Cantrill 				(void) fprintf(stdout, "\\u%04hhx", (uint8_t)c);
82877481491SBryan Cantrill 				break;
82977481491SBryan Cantrill 			}
83077481491SBryan Cantrill 
83177481491SBryan Cantrill 			(void) putchar(c);
83277481491SBryan Cantrill 			break;
83377481491SBryan Cantrill 		}
83477481491SBryan Cantrill 	}
83577481491SBryan Cantrill 
83677481491SBryan Cantrill 	(void) putchar('"');
83777481491SBryan Cantrill }
83877481491SBryan Cantrill 
83966448911SDavid Höppner /*
84066448911SDavid Höppner  * Print a single instance in JSON format.
84166448911SDavid Höppner  */
84266448911SDavid Höppner static void
ks_instance_print_json(ks_instance_t * ksi,ks_nvpair_t * nvpair,boolean_t last)84377481491SBryan Cantrill ks_instance_print_json(ks_instance_t *ksi, ks_nvpair_t *nvpair, boolean_t last)
84466448911SDavid Höppner {
84577481491SBryan Cantrill 	static int headers;
84677481491SBryan Cantrill 
84766448911SDavid Höppner 	if (g_headerflg) {
84877481491SBryan Cantrill 		if (headers++ > 0)
84977481491SBryan Cantrill 			(void) fprintf(stdout, ", ");
85077481491SBryan Cantrill 
85177481491SBryan Cantrill 		(void) fprintf(stdout, "{\n\t\"module\": ");
85277481491SBryan Cantrill 		ks_print_json_string(ksi->ks_module);
85377481491SBryan Cantrill 
85477481491SBryan Cantrill 		(void) fprintf(stdout,
85577481491SBryan Cantrill 		    ",\n\t\"instance\": %d,\n\t\"name\": ", ksi->ks_instance);
85677481491SBryan Cantrill 		ks_print_json_string(ksi->ks_name);
85777481491SBryan Cantrill 
85877481491SBryan Cantrill 		(void) fprintf(stdout, ",\n\t\"class\": ");
85977481491SBryan Cantrill 		ks_print_json_string(ksi->ks_class);
86077481491SBryan Cantrill 
86177481491SBryan Cantrill 		(void) fprintf(stdout, ",\n\t\"type\": %d,\n", ksi->ks_type);
86266448911SDavid Höppner 
86366448911SDavid Höppner 		if (ksi->ks_snaptime == 0)
86466448911SDavid Höppner 			(void) fprintf(stdout, "\t\"snaptime\": 0,\n");
86566448911SDavid Höppner 		else
86666448911SDavid Höppner 			(void) fprintf(stdout, "\t\"snaptime\": %.9f,\n",
86766448911SDavid Höppner 			    ksi->ks_snaptime / 1000000000.0);
86866448911SDavid Höppner 
86966448911SDavid Höppner 		(void) fprintf(stdout, "\t\"data\": {\n");
87066448911SDavid Höppner 
87166448911SDavid Höppner 		g_headerflg = B_FALSE;
87266448911SDavid Höppner 	}
87366448911SDavid Höppner 
87477481491SBryan Cantrill 	(void) fprintf(stdout, "\t\t");
87577481491SBryan Cantrill 	ks_print_json_string(nvpair->name);
87677481491SBryan Cantrill 	(void) fprintf(stdout, ": ");
87777481491SBryan Cantrill 
87877481491SBryan Cantrill 	switch (nvpair->data_type) {
87977481491SBryan Cantrill 	case KSTAT_DATA_CHAR:
88077481491SBryan Cantrill 		ks_print_json_string(nvpair->value.c);
88177481491SBryan Cantrill 		break;
88277481491SBryan Cantrill 
88377481491SBryan Cantrill 	case KSTAT_DATA_STRING:
88477481491SBryan Cantrill 		ks_print_json_string(KSTAT_NAMED_STR_PTR(nvpair));
88577481491SBryan Cantrill 		break;
88677481491SBryan Cantrill 
88777481491SBryan Cantrill 	default:
88866448911SDavid Höppner 		ks_value_print(nvpair);
88977481491SBryan Cantrill 		break;
89066448911SDavid Höppner 	}
89177481491SBryan Cantrill 
89277481491SBryan Cantrill 	if (!last)
89366448911SDavid Höppner 		(void) putchar(',');
89466448911SDavid Höppner 
89566448911SDavid Höppner 	(void) putchar('\n');
89666448911SDavid Höppner }
89766448911SDavid Höppner 
89866448911SDavid Höppner /*
89966448911SDavid Höppner  * Print all instances.
90066448911SDavid Höppner  */
90166448911SDavid Höppner static void
ks_instances_print(void)90266448911SDavid Höppner ks_instances_print(void)
90366448911SDavid Höppner {
90477481491SBryan Cantrill 	ks_selector_t *selector;
90577481491SBryan Cantrill 	ks_instance_t *ksi, *ktmp;
90677481491SBryan Cantrill 	ks_nvpair_t *nvpair, *ntmp, *next;
90777481491SBryan Cantrill 	void (*ks_print_fn)(ks_instance_t *, ks_nvpair_t *, boolean_t);
90877481491SBryan Cantrill 	char *ks_number;
90966448911SDavid Höppner 
91066448911SDavid Höppner 	if (g_timestamp_fmt != NODATE)
91166448911SDavid Höppner 		print_timestamp(g_timestamp_fmt);
91266448911SDavid Höppner 
91366448911SDavid Höppner 	if (g_jflg) {
91466448911SDavid Höppner 		ks_print_fn = &ks_instance_print_json;
91566448911SDavid Höppner 		(void) putchar('[');
91666448911SDavid Höppner 	} else {
91766448911SDavid Höppner 		ks_print_fn = &ks_instance_print;
91866448911SDavid Höppner 	}
91966448911SDavid Höppner 
92066448911SDavid Höppner 	/* Iterate over each selector */
92166448911SDavid Höppner 	selector = list_head(&selector_list);
92266448911SDavid Höppner 	while (selector != NULL) {
92366448911SDavid Höppner 
92466448911SDavid Höppner 		/* Iterate over each instance */
92566448911SDavid Höppner 		for (ksi = list_head(&instances_list); ksi != NULL;
92666448911SDavid Höppner 		    ksi = list_next(&instances_list, ksi)) {
92766448911SDavid Höppner 
92866448911SDavid Höppner 			(void) asprintf(&ks_number, "%d", ksi->ks_instance);
92966448911SDavid Höppner 			if (!(ks_match(ksi->ks_module, &selector->ks_module) &&
93066448911SDavid Höppner 			    ks_match(ksi->ks_name, &selector->ks_name) &&
93166448911SDavid Höppner 			    ks_match(ks_number, &selector->ks_instance) &&
93266448911SDavid Höppner 			    ks_match(ksi->ks_class, &g_ks_class))) {
93366448911SDavid Höppner 				free(ks_number);
93466448911SDavid Höppner 				continue;
93566448911SDavid Höppner 			}
93666448911SDavid Höppner 
93766448911SDavid Höppner 			free(ks_number);
93866448911SDavid Höppner 
93966448911SDavid Höppner 			g_headerflg = B_TRUE;
94077481491SBryan Cantrill 
94177481491SBryan Cantrill 			/*
94277481491SBryan Cantrill 			 * Find our first statistic to print.
94377481491SBryan Cantrill 			 */
94466448911SDavid Höppner 			for (nvpair = list_head(&ksi->ks_nvlist);
94566448911SDavid Höppner 			    nvpair != NULL;
94666448911SDavid Höppner 			    nvpair = list_next(&ksi->ks_nvlist, nvpair)) {
94777481491SBryan Cantrill 				if (ks_match(nvpair->name,
94866448911SDavid Höppner 				    &selector->ks_statistic))
94977481491SBryan Cantrill 					break;
95077481491SBryan Cantrill 			}
95177481491SBryan Cantrill 
95277481491SBryan Cantrill 			while (nvpair != NULL) {
95377481491SBryan Cantrill 				boolean_t last;
95477481491SBryan Cantrill 
95577481491SBryan Cantrill 				/*
95677481491SBryan Cantrill 				 * Find the next statistic to print so we can
95777481491SBryan Cantrill 				 * indicate to the print function if this
95877481491SBryan Cantrill 				 * statistic is the last to be printed for
95977481491SBryan Cantrill 				 * this instance.
96077481491SBryan Cantrill 				 */
96177481491SBryan Cantrill 				for (next = list_next(&ksi->ks_nvlist, nvpair);
96277481491SBryan Cantrill 				    next != NULL;
96377481491SBryan Cantrill 				    next = list_next(&ksi->ks_nvlist, next)) {
96477481491SBryan Cantrill 					if (ks_match(next->name,
96577481491SBryan Cantrill 					    &selector->ks_statistic))
96677481491SBryan Cantrill 						break;
96777481491SBryan Cantrill 				}
96877481491SBryan Cantrill 
96977481491SBryan Cantrill 				g_matched = B_TRUE;
97077481491SBryan Cantrill 				last = next == NULL ? B_TRUE : B_FALSE;
97166448911SDavid Höppner 
97266448911SDavid Höppner 				if (!g_qflg)
97377481491SBryan Cantrill 					(*ks_print_fn)(ksi, nvpair, last);
97477481491SBryan Cantrill 
97577481491SBryan Cantrill 				nvpair = next;
97666448911SDavid Höppner 			}
97766448911SDavid Höppner 
97866448911SDavid Höppner 			if (!g_headerflg) {
97966448911SDavid Höppner 				if (g_jflg) {
98066448911SDavid Höppner 					(void) fprintf(stdout, "\t}\n}");
98166448911SDavid Höppner 				} else if (!g_pflg) {
98266448911SDavid Höppner 					(void) putchar('\n');
98366448911SDavid Höppner 				}
98466448911SDavid Höppner 			}
98566448911SDavid Höppner 		}
98666448911SDavid Höppner 
98766448911SDavid Höppner 		selector = list_next(&selector_list, selector);
98866448911SDavid Höppner 	}
98966448911SDavid Höppner 
99066448911SDavid Höppner 	if (g_jflg)
99166448911SDavid Höppner 		(void) fprintf(stdout, "]\n");
99266448911SDavid Höppner 
99366448911SDavid Höppner 	(void) fflush(stdout);
99466448911SDavid Höppner 
99566448911SDavid Höppner 	/* Free the instances list */
99666448911SDavid Höppner 	ksi = list_head(&instances_list);
99766448911SDavid Höppner 	while (ksi != NULL) {
99866448911SDavid Höppner 		nvpair = list_head(&ksi->ks_nvlist);
99966448911SDavid Höppner 		while (nvpair != NULL) {
100066448911SDavid Höppner 			ntmp = nvpair;
100166448911SDavid Höppner 			nvpair = list_next(&ksi->ks_nvlist, nvpair);
100266448911SDavid Höppner 			list_remove(&ksi->ks_nvlist, ntmp);
100366448911SDavid Höppner 			if (ntmp->data_type == KSTAT_DATA_STRING)
100466448911SDavid Höppner 				free(ntmp->value.str.addr.ptr);
100566448911SDavid Höppner 			free(ntmp);
100666448911SDavid Höppner 		}
100766448911SDavid Höppner 
100866448911SDavid Höppner 		ktmp = ksi;
100966448911SDavid Höppner 		ksi = list_next(&instances_list, ksi);
101066448911SDavid Höppner 		list_remove(&instances_list, ktmp);
101166448911SDavid Höppner 		list_destroy(&ktmp->ks_nvlist);
101266448911SDavid Höppner 		free(ktmp);
101366448911SDavid Höppner 	}
101466448911SDavid Höppner }
101566448911SDavid Höppner 
101666448911SDavid Höppner static void
save_cpu_stat(kstat_t * kp,ks_instance_t * ksi)101766448911SDavid Höppner save_cpu_stat(kstat_t *kp, ks_instance_t *ksi)
101866448911SDavid Höppner {
101966448911SDavid Höppner 	cpu_stat_t	*stat;
102066448911SDavid Höppner 	cpu_sysinfo_t	*sysinfo;
102166448911SDavid Höppner 	cpu_syswait_t	*syswait;
102266448911SDavid Höppner 	cpu_vminfo_t	*vminfo;
102366448911SDavid Höppner 
102466448911SDavid Höppner 	stat = (cpu_stat_t *)(kp->ks_data);
102566448911SDavid Höppner 	sysinfo = &stat->cpu_sysinfo;
102666448911SDavid Höppner 	syswait = &stat->cpu_syswait;
102766448911SDavid Höppner 	vminfo  = &stat->cpu_vminfo;
102866448911SDavid Höppner 
102966448911SDavid Höppner 	SAVE_UINT32_X(ksi, "idle", sysinfo->cpu[CPU_IDLE]);
103066448911SDavid Höppner 	SAVE_UINT32_X(ksi, "user", sysinfo->cpu[CPU_USER]);
103166448911SDavid Höppner 	SAVE_UINT32_X(ksi, "kernel", sysinfo->cpu[CPU_KERNEL]);
103266448911SDavid Höppner 	SAVE_UINT32_X(ksi, "wait", sysinfo->cpu[CPU_WAIT]);
10335918f984SRichard Lowe 	SAVE_UINT32_X(ksi, "wait_io", sysinfo->wait[W_IO]);
10345918f984SRichard Lowe 	SAVE_UINT32_X(ksi, "wait_swap", sysinfo->wait[W_SWAP]);
10355918f984SRichard Lowe 	SAVE_UINT32_X(ksi, "wait_pio", sysinfo->wait[W_PIO]);
103666448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, bread);
103766448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, bwrite);
103866448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, lread);
103966448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, lwrite);
104066448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, phread);
104166448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, phwrite);
104266448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, pswitch);
104366448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, trap);
104466448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, intr);
104566448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, syscall);
104666448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, sysread);
104766448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, syswrite);
104866448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, sysfork);
104966448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, sysvfork);
105066448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, sysexec);
105166448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, readch);
105266448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, writech);
105366448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, rcvint);
105466448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, xmtint);
105566448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, mdmint);
105666448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, rawch);
105766448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, canch);
105866448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, outch);
105966448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, msg);
106066448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, sema);
106166448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, namei);
106266448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, ufsiget);
106366448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, ufsdirblk);
106466448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, ufsipage);
106566448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, ufsinopage);
106666448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, inodeovf);
106766448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, fileovf);
106866448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, procovf);
106966448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, intrthread);
107066448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, intrblk);
107166448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, idlethread);
107266448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, inv_swtch);
107366448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, nthreads);
107466448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, cpumigrate);
107566448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, xcalls);
107666448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, mutex_adenters);
107766448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, rw_rdfails);
107866448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, rw_wrfails);
107966448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, modload);
108066448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, modunload);
108166448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, bawrite);
108266448911SDavid Höppner #ifdef	STATISTICS	/* see header file */
108366448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, rw_enters);
108466448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, win_uo_cnt);
108566448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, win_uu_cnt);
108666448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, win_so_cnt);
108766448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, win_su_cnt);
108866448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, win_suo_cnt);
108966448911SDavid Höppner #endif
109066448911SDavid Höppner 
109166448911SDavid Höppner 	SAVE_INT32(ksi, syswait, iowait);
109266448911SDavid Höppner 	SAVE_INT32(ksi, syswait, swap);
109366448911SDavid Höppner 	SAVE_INT32(ksi, syswait, physio);
109466448911SDavid Höppner 
109566448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, pgrec);
109666448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, pgfrec);
109766448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, pgin);
109866448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, pgpgin);
109966448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, pgout);
110066448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, pgpgout);
110166448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, swapin);
110266448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, pgswapin);
110366448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, swapout);
110466448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, pgswapout);
110566448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, zfod);
110666448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, dfree);
110766448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, scan);
110866448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, rev);
110966448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, hat_fault);
111066448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, as_fault);
111166448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, maj_fault);
111266448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, cow_fault);
111366448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, prot_fault);
111466448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, softlock);
111566448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, kernel_asflt);
111666448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, pgrrun);
111766448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, execpgin);
111866448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, execpgout);
111966448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, execfree);
112066448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, anonpgin);
112166448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, anonpgout);
112266448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, anonfree);
112366448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, fspgin);
112466448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, fspgout);
112566448911SDavid Höppner 	SAVE_UINT32(ksi, vminfo, fsfree);
112666448911SDavid Höppner }
112766448911SDavid Höppner 
112866448911SDavid Höppner static void
save_var(kstat_t * kp,ks_instance_t * ksi)112966448911SDavid Höppner save_var(kstat_t *kp, ks_instance_t *ksi)
113066448911SDavid Höppner {
113166448911SDavid Höppner 	struct var	*var = (struct var *)(kp->ks_data);
113266448911SDavid Höppner 
113366448911SDavid Höppner 	assert(kp->ks_data_size == sizeof (struct var));
113466448911SDavid Höppner 
113566448911SDavid Höppner 	SAVE_INT32(ksi, var, v_buf);
113666448911SDavid Höppner 	SAVE_INT32(ksi, var, v_call);
113766448911SDavid Höppner 	SAVE_INT32(ksi, var, v_proc);
113866448911SDavid Höppner 	SAVE_INT32(ksi, var, v_maxupttl);
113966448911SDavid Höppner 	SAVE_INT32(ksi, var, v_nglobpris);
114066448911SDavid Höppner 	SAVE_INT32(ksi, var, v_maxsyspri);
114166448911SDavid Höppner 	SAVE_INT32(ksi, var, v_clist);
114266448911SDavid Höppner 	SAVE_INT32(ksi, var, v_maxup);
114366448911SDavid Höppner 	SAVE_INT32(ksi, var, v_hbuf);
114466448911SDavid Höppner 	SAVE_INT32(ksi, var, v_hmask);
114566448911SDavid Höppner 	SAVE_INT32(ksi, var, v_pbuf);
114666448911SDavid Höppner 	SAVE_INT32(ksi, var, v_sptmap);
114766448911SDavid Höppner 	SAVE_INT32(ksi, var, v_maxpmem);
114866448911SDavid Höppner 	SAVE_INT32(ksi, var, v_autoup);
114966448911SDavid Höppner 	SAVE_INT32(ksi, var, v_bufhwm);
115066448911SDavid Höppner }
115166448911SDavid Höppner 
115266448911SDavid Höppner static void
save_ncstats(kstat_t * kp,ks_instance_t * ksi)115366448911SDavid Höppner save_ncstats(kstat_t *kp, ks_instance_t *ksi)
115466448911SDavid Höppner {
115566448911SDavid Höppner 	struct ncstats	*ncstats = (struct ncstats *)(kp->ks_data);
115666448911SDavid Höppner 
115766448911SDavid Höppner 	assert(kp->ks_data_size == sizeof (struct ncstats));
115866448911SDavid Höppner 
115966448911SDavid Höppner 	SAVE_INT32(ksi, ncstats, hits);
116066448911SDavid Höppner 	SAVE_INT32(ksi, ncstats, misses);
116166448911SDavid Höppner 	SAVE_INT32(ksi, ncstats, enters);
116266448911SDavid Höppner 	SAVE_INT32(ksi, ncstats, dbl_enters);
116366448911SDavid Höppner 	SAVE_INT32(ksi, ncstats, long_enter);
116466448911SDavid Höppner 	SAVE_INT32(ksi, ncstats, long_look);
116566448911SDavid Höppner 	SAVE_INT32(ksi, ncstats, move_to_front);
116666448911SDavid Höppner 	SAVE_INT32(ksi, ncstats, purges);
116766448911SDavid Höppner }
116866448911SDavid Höppner 
116966448911SDavid Höppner static void
save_sysinfo(kstat_t * kp,ks_instance_t * ksi)117066448911SDavid Höppner save_sysinfo(kstat_t *kp, ks_instance_t *ksi)
117166448911SDavid Höppner {
117266448911SDavid Höppner 	sysinfo_t	*sysinfo = (sysinfo_t *)(kp->ks_data);
117366448911SDavid Höppner 
117466448911SDavid Höppner 	assert(kp->ks_data_size == sizeof (sysinfo_t));
117566448911SDavid Höppner 
117666448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, updates);
117766448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, runque);
117866448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, runocc);
117966448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, swpque);
118066448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, swpocc);
118166448911SDavid Höppner 	SAVE_UINT32(ksi, sysinfo, waiting);
118266448911SDavid Höppner }
118366448911SDavid Höppner 
118466448911SDavid Höppner static void
save_vminfo(kstat_t * kp,ks_instance_t * ksi)118566448911SDavid Höppner save_vminfo(kstat_t *kp, ks_instance_t *ksi)
118666448911SDavid Höppner {
118766448911SDavid Höppner 	vminfo_t	*vminfo = (vminfo_t *)(kp->ks_data);
118866448911SDavid Höppner 
118966448911SDavid Höppner 	assert(kp->ks_data_size == sizeof (vminfo_t));
119066448911SDavid Höppner 
119166448911SDavid Höppner 	SAVE_UINT64(ksi, vminfo, freemem);
119266448911SDavid Höppner 	SAVE_UINT64(ksi, vminfo, swap_resv);
119366448911SDavid Höppner 	SAVE_UINT64(ksi, vminfo, swap_alloc);
119466448911SDavid Höppner 	SAVE_UINT64(ksi, vminfo, swap_avail);
119566448911SDavid Höppner 	SAVE_UINT64(ksi, vminfo, swap_free);
119666448911SDavid Höppner 	SAVE_UINT64(ksi, vminfo, updates);
119766448911SDavid Höppner }
119866448911SDavid Höppner 
119966448911SDavid Höppner static void
save_nfs(kstat_t * kp,ks_instance_t * ksi)120066448911SDavid Höppner save_nfs(kstat_t *kp, ks_instance_t *ksi)
120166448911SDavid Höppner {
120266448911SDavid Höppner 	struct mntinfo_kstat *mntinfo = (struct mntinfo_kstat *)(kp->ks_data);
120366448911SDavid Höppner 
120466448911SDavid Höppner 	assert(kp->ks_data_size == sizeof (struct mntinfo_kstat));
120566448911SDavid Höppner 
120666448911SDavid Höppner 	SAVE_STRING(ksi, mntinfo, mik_proto);
120766448911SDavid Höppner 	SAVE_UINT32(ksi, mntinfo, mik_vers);
120866448911SDavid Höppner 	SAVE_UINT32(ksi, mntinfo, mik_flags);
120966448911SDavid Höppner 	SAVE_UINT32(ksi, mntinfo, mik_secmod);
121066448911SDavid Höppner 	SAVE_UINT32(ksi, mntinfo, mik_curread);
121166448911SDavid Höppner 	SAVE_UINT32(ksi, mntinfo, mik_curwrite);
121266448911SDavid Höppner 	SAVE_INT32(ksi, mntinfo, mik_timeo);
121366448911SDavid Höppner 	SAVE_INT32(ksi, mntinfo, mik_retrans);
121466448911SDavid Höppner 	SAVE_UINT32(ksi, mntinfo, mik_acregmin);
121566448911SDavid Höppner 	SAVE_UINT32(ksi, mntinfo, mik_acregmax);
121666448911SDavid Höppner 	SAVE_UINT32(ksi, mntinfo, mik_acdirmin);
121766448911SDavid Höppner 	SAVE_UINT32(ksi, mntinfo, mik_acdirmax);
121866448911SDavid Höppner 	SAVE_UINT32_X(ksi, "lookup_srtt", mntinfo->mik_timers[0].srtt);
121966448911SDavid Höppner 	SAVE_UINT32_X(ksi, "lookup_deviate", mntinfo->mik_timers[0].deviate);
122066448911SDavid Höppner 	SAVE_UINT32_X(ksi, "lookup_rtxcur", mntinfo->mik_timers[0].rtxcur);
122166448911SDavid Höppner 	SAVE_UINT32_X(ksi, "read_srtt", mntinfo->mik_timers[1].srtt);
122266448911SDavid Höppner 	SAVE_UINT32_X(ksi, "read_deviate", mntinfo->mik_timers[1].deviate);
122366448911SDavid Höppner 	SAVE_UINT32_X(ksi, "read_rtxcur", mntinfo->mik_timers[1].rtxcur);
122466448911SDavid Höppner 	SAVE_UINT32_X(ksi, "write_srtt", mntinfo->mik_timers[2].srtt);
122566448911SDavid Höppner 	SAVE_UINT32_X(ksi, "write_deviate", mntinfo->mik_timers[2].deviate);
122666448911SDavid Höppner 	SAVE_UINT32_X(ksi, "write_rtxcur", mntinfo->mik_timers[2].rtxcur);
122766448911SDavid Höppner 	SAVE_UINT32(ksi, mntinfo, mik_noresponse);
122866448911SDavid Höppner 	SAVE_UINT32(ksi, mntinfo, mik_failover);
122966448911SDavid Höppner 	SAVE_UINT32(ksi, mntinfo, mik_remap);
123066448911SDavid Höppner 	SAVE_STRING(ksi, mntinfo, mik_curserver);
123166448911SDavid Höppner }
123266448911SDavid Höppner 
123366448911SDavid Höppner #ifdef __sparc
123466448911SDavid Höppner static void
save_sfmmu_global_stat(kstat_t * kp,ks_instance_t * ksi)123566448911SDavid Höppner save_sfmmu_global_stat(kstat_t *kp, ks_instance_t *ksi)
123666448911SDavid Höppner {
123766448911SDavid Höppner 	struct sfmmu_global_stat *sfmmug =
123866448911SDavid Höppner 	    (struct sfmmu_global_stat *)(kp->ks_data);
123966448911SDavid Höppner 
124066448911SDavid Höppner 	assert(kp->ks_data_size == sizeof (struct sfmmu_global_stat));
124166448911SDavid Höppner 
124266448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tsb_exceptions);
124366448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tsb_raise_exception);
124466448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_pagefaults);
124566448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_uhash_searches);
124666448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_uhash_links);
124766448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_khash_searches);
124866448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_khash_links);
124966448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_swapout);
125066448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tsb_alloc);
125166448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tsb_allocfail);
125266448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tsb_sectsb_create);
125366448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_scd_1sttsb_alloc);
125466448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_scd_2ndtsb_alloc);
125566448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_scd_1sttsb_allocfail);
125666448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_scd_2ndtsb_allocfail);
125766448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tteload8k);
125866448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tteload64k);
125966448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tteload512k);
126066448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tteload4m);
126166448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tteload32m);
126266448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tteload256m);
126366448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tsb_load8k);
126466448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tsb_load4m);
126566448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_hblk_hit);
126666448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_hblk8_ncreate);
126766448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_hblk8_nalloc);
126866448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_hblk1_ncreate);
126966448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_hblk1_nalloc);
127066448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_hblk_slab_cnt);
127166448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_hblk_reserve_cnt);
127266448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_hblk_recurse_cnt);
127366448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_hblk_reserve_hit);
127466448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_get_free_success);
127566448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_get_free_throttle);
127666448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_get_free_fail);
127766448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_put_free_success);
127866448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_put_free_fail);
127966448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_pgcolor_conflict);
128066448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_uncache_conflict);
128166448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_unload_conflict);
128266448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_ism_uncache);
128366448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_ism_recache);
128466448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_recache);
128566448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_steal_count);
128666448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_pagesync);
128766448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_clrwrt);
128866448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_pagesync_invalid);
128966448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_kernel_xcalls);
129066448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_user_xcalls);
129166448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tsb_grow);
129266448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tsb_shrink);
129366448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tsb_resize_failures);
129466448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tsb_reloc);
129566448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_user_vtop);
129666448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_ctx_inv);
129766448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_tlb_reprog_pgsz);
129866448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_region_remap_demap);
129966448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_create_scd);
130066448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_join_scd);
130166448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_leave_scd);
130266448911SDavid Höppner 	SAVE_INT32(ksi, sfmmug, sf_destroy_scd);
130366448911SDavid Höppner }
130466448911SDavid Höppner #endif
130566448911SDavid Höppner 
130666448911SDavid Höppner #ifdef __sparc
130766448911SDavid Höppner static void
save_sfmmu_tsbsize_stat(kstat_t * kp,ks_instance_t * ksi)130866448911SDavid Höppner save_sfmmu_tsbsize_stat(kstat_t *kp, ks_instance_t *ksi)
130966448911SDavid Höppner {
131066448911SDavid Höppner 	struct sfmmu_tsbsize_stat *sfmmut;
131166448911SDavid Höppner 
131266448911SDavid Höppner 	assert(kp->ks_data_size == sizeof (struct sfmmu_tsbsize_stat));
131366448911SDavid Höppner 	sfmmut = (struct sfmmu_tsbsize_stat *)(kp->ks_data);
131466448911SDavid Höppner 
131566448911SDavid Höppner 	SAVE_INT32(ksi, sfmmut, sf_tsbsz_8k);
131666448911SDavid Höppner 	SAVE_INT32(ksi, sfmmut, sf_tsbsz_16k);
131766448911SDavid Höppner 	SAVE_INT32(ksi, sfmmut, sf_tsbsz_32k);
131866448911SDavid Höppner 	SAVE_INT32(ksi, sfmmut, sf_tsbsz_64k);
131966448911SDavid Höppner 	SAVE_INT32(ksi, sfmmut, sf_tsbsz_128k);
132066448911SDavid Höppner 	SAVE_INT32(ksi, sfmmut, sf_tsbsz_256k);
132166448911SDavid Höppner 	SAVE_INT32(ksi, sfmmut, sf_tsbsz_512k);
132266448911SDavid Höppner 	SAVE_INT32(ksi, sfmmut, sf_tsbsz_1m);
132366448911SDavid Höppner 	SAVE_INT32(ksi, sfmmut, sf_tsbsz_2m);
132466448911SDavid Höppner 	SAVE_INT32(ksi, sfmmut, sf_tsbsz_4m);
132566448911SDavid Höppner }
132666448911SDavid Höppner #endif
132766448911SDavid Höppner 
132866448911SDavid Höppner static void
save_named(kstat_t * kp,ks_instance_t * ksi)132966448911SDavid Höppner save_named(kstat_t *kp, ks_instance_t *ksi)
133066448911SDavid Höppner {
133166448911SDavid Höppner 	kstat_named_t *knp;
133266448911SDavid Höppner 	int	n;
133366448911SDavid Höppner 
133466448911SDavid Höppner 	for (n = kp->ks_ndata, knp = KSTAT_NAMED_PTR(kp); n > 0; n--, knp++) {
133577481491SBryan Cantrill 		/*
133677481491SBryan Cantrill 		 * Annoyingly, some drivers have kstats with uninitialized
133777481491SBryan Cantrill 		 * members (which kstat_install(9F) is sadly powerless to
133877481491SBryan Cantrill 		 * prevent, and kstat_read(3KSTAT) unfortunately does nothing
133977481491SBryan Cantrill 		 * to stop).  To prevent these from confusing us to be
134077481491SBryan Cantrill 		 * KSTAT_DATA_CHAR statistics, we skip over them.
134177481491SBryan Cantrill 		 */
134277481491SBryan Cantrill 		if (knp->name[0] == '\0')
134377481491SBryan Cantrill 			continue;
134477481491SBryan Cantrill 
134566448911SDavid Höppner 		switch (knp->data_type) {
134666448911SDavid Höppner 		case KSTAT_DATA_CHAR:
134766448911SDavid Höppner 			nvpair_insert(ksi, knp->name,
134866448911SDavid Höppner 			    (ks_value_t *)&knp->value, KSTAT_DATA_CHAR);
134966448911SDavid Höppner 			break;
135066448911SDavid Höppner 		case KSTAT_DATA_INT32:
135166448911SDavid Höppner 			nvpair_insert(ksi, knp->name,
135266448911SDavid Höppner 			    (ks_value_t *)&knp->value, KSTAT_DATA_INT32);
135366448911SDavid Höppner 			break;
135466448911SDavid Höppner 		case KSTAT_DATA_UINT32:
135566448911SDavid Höppner 			nvpair_insert(ksi, knp->name,
135666448911SDavid Höppner 			    (ks_value_t *)&knp->value, KSTAT_DATA_UINT32);
135766448911SDavid Höppner 			break;
135866448911SDavid Höppner 		case KSTAT_DATA_INT64:
135966448911SDavid Höppner 			nvpair_insert(ksi, knp->name,
136066448911SDavid Höppner 			    (ks_value_t *)&knp->value, KSTAT_DATA_INT64);
136166448911SDavid Höppner 			break;
136266448911SDavid Höppner 		case KSTAT_DATA_UINT64:
136366448911SDavid Höppner 			nvpair_insert(ksi, knp->name,
136466448911SDavid Höppner 			    (ks_value_t *)&knp->value, KSTAT_DATA_UINT64);
136566448911SDavid Höppner 			break;
136666448911SDavid Höppner 		case KSTAT_DATA_STRING:
136766448911SDavid Höppner 			SAVE_STRING_X(ksi, knp->name, KSTAT_NAMED_STR_PTR(knp));
136866448911SDavid Höppner 			break;
136966448911SDavid Höppner 		default:
137066448911SDavid Höppner 			assert(B_FALSE); /* Invalid data type */
137166448911SDavid Höppner 			break;
137266448911SDavid Höppner 		}
137366448911SDavid Höppner 	}
137466448911SDavid Höppner }
137566448911SDavid Höppner 
137666448911SDavid Höppner static void
save_intr(kstat_t * kp,ks_instance_t * ksi)137766448911SDavid Höppner save_intr(kstat_t *kp, ks_instance_t *ksi)
137866448911SDavid Höppner {
137966448911SDavid Höppner 	kstat_intr_t *intr = KSTAT_INTR_PTR(kp);
138066448911SDavid Höppner 	char	*intr_names[] = {"hard", "soft", "watchdog", "spurious",
138166448911SDavid Höppner 	    "multiple_service"};
138266448911SDavid Höppner 	int	n;
138366448911SDavid Höppner 
138466448911SDavid Höppner 	for (n = 0; n < KSTAT_NUM_INTRS; n++)
138566448911SDavid Höppner 		SAVE_UINT32_X(ksi, intr_names[n], intr->intrs[n]);
138666448911SDavid Höppner }
138766448911SDavid Höppner 
138866448911SDavid Höppner static void
save_io(kstat_t * kp,ks_instance_t * ksi)138966448911SDavid Höppner save_io(kstat_t *kp, ks_instance_t *ksi)
139066448911SDavid Höppner {
139166448911SDavid Höppner 	kstat_io_t	*ksio = KSTAT_IO_PTR(kp);
139266448911SDavid Höppner 
139366448911SDavid Höppner 	SAVE_UINT64(ksi, ksio, nread);
139466448911SDavid Höppner 	SAVE_UINT64(ksi, ksio, nwritten);
139566448911SDavid Höppner 	SAVE_UINT32(ksi, ksio, reads);
139666448911SDavid Höppner 	SAVE_UINT32(ksi, ksio, writes);
139766448911SDavid Höppner 	SAVE_HRTIME(ksi, ksio, wtime);
139866448911SDavid Höppner 	SAVE_HRTIME(ksi, ksio, wlentime);
139966448911SDavid Höppner 	SAVE_HRTIME(ksi, ksio, wlastupdate);
140066448911SDavid Höppner 	SAVE_HRTIME(ksi, ksio, rtime);
140166448911SDavid Höppner 	SAVE_HRTIME(ksi, ksio, rlentime);
140266448911SDavid Höppner 	SAVE_HRTIME(ksi, ksio, rlastupdate);
140366448911SDavid Höppner 	SAVE_UINT32(ksi, ksio, wcnt);
140466448911SDavid Höppner 	SAVE_UINT32(ksi, ksio, rcnt);
140566448911SDavid Höppner }
140666448911SDavid Höppner 
140766448911SDavid Höppner static void
save_timer(kstat_t * kp,ks_instance_t * ksi)140866448911SDavid Höppner save_timer(kstat_t *kp, ks_instance_t *ksi)
140966448911SDavid Höppner {
141066448911SDavid Höppner 	kstat_timer_t	*ktimer = KSTAT_TIMER_PTR(kp);
141166448911SDavid Höppner 
141266448911SDavid Höppner 	SAVE_STRING(ksi, ktimer, name);
141366448911SDavid Höppner 	SAVE_UINT64(ksi, ktimer, num_events);
141466448911SDavid Höppner 	SAVE_HRTIME(ksi, ktimer, elapsed_time);
141566448911SDavid Höppner 	SAVE_HRTIME(ksi, ktimer, min_time);
141666448911SDavid Höppner 	SAVE_HRTIME(ksi, ktimer, max_time);
141766448911SDavid Höppner 	SAVE_HRTIME(ksi, ktimer, start_time);
141866448911SDavid Höppner 	SAVE_HRTIME(ksi, ktimer, stop_time);
141966448911SDavid Höppner }
1420