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