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