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