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