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  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #include <stdio.h>
  27 #include <stdlib.h>
  28 #include <string.h>
  29 #include <strings.h>
  30 #include <errno.h>
  31 #include <kstat.h>
  32 #include <signal.h>
  33 #include <setjmp.h>
  34 
  35 #include "sdbc_stats.h"
  36 #include "report.h"
  37 #include "common.h"
  38 
  39 static sigjmp_buf env;
  40 static sig_atomic_t sig_raised = 0;
  41 static void sig_handler(int);
  42 
  43 void
  44 sig_handler(int sig)
  45 {
  46         switch (sig) {
  47                 case SIGSEGV:
  48                         sig_raised = 1;
  49                         siglongjmp(env, sig);
  50                 default:
  51                         exit(sig);
  52         }
  53 }
  54 
  55 /*
  56  * kstat_retrieve() - populate the ks_data field of the kstat_t structure
  57  *
  58  * This function is a user-land equivalent of a ks_snapshot
  59  *
  60  * parameters
  61  *      kstat_ctl_t *kc - kstat_ctl_t structure representing returned from
  62  *                        kstat_open()
  63  *      kstat_t *ksp - kstat_t strcture to popluate ks_data into
  64  *
  65  * returns
  66  *      NULL pointer on failure
  67  *      kstat_t * structure on success
  68  */
  69 kstat_t *
  70 kstat_retrieve(kstat_ctl_t *kc, kstat_t *ksp)
  71 {
  72 
  73         kstat_t *rval;
  74         kstat_named_t *knp;
  75         char *end;
  76         int i;
  77         struct sigaction segv_act;      /* default actions */
  78 
  79         if (ksp == NULL)
  80                 return (NULL);
  81 
  82         if (ksp->ks_data == NULL &&
  83             kstat_read(kc, ksp, NULL) == -1)
  84                 return (NULL);
  85 
  86         rval = (kstat_t *)calloc(1, sizeof (*ksp));
  87         (void) memcpy(rval, ksp, sizeof (*ksp));
  88 
  89         rval->ks_data = (void *) calloc(1, ksp->ks_data_size);
  90         (void) memcpy(rval->ks_data, ksp->ks_data,
  91             sizeof (kstat_named_t) * ksp->ks_ndata);
  92 
  93         /* special handling for variable length string KSTAT_DATA_STRING */
  94         knp = (kstat_named_t *)rval->ks_data;
  95         end = (char *)(knp + ksp->ks_ndata);
  96         for (i = 0; i < ksp->ks_ndata; i++, knp++) {
  97                 if (knp->data_type == KSTAT_DATA_STRING &&
  98                     KSTAT_NAMED_STR_PTR(knp) != NULL) {
  99                         /* catch SIGSEGV (bug 6384130) */
 100                         sig_raised = 0;
 101                         (void) sigaction(SIGSEGV, NULL, &segv_act);
 102                         (void) signal(SIGSEGV, sig_handler);
 103 
 104                         (void) strncpy(end, KSTAT_NAMED_STR_PTR(knp),
 105                             KSTAT_NAMED_STR_BUFLEN(knp));
 106                         KSTAT_NAMED_STR_PTR(knp) = end;
 107                         end += KSTAT_NAMED_STR_BUFLEN(knp);
 108 
 109                         /* bug 6384130 */
 110                         (void) sigsetjmp(env, 0);
 111                         if (sig_raised) {
 112                                 bzero(end, KSTAT_NAMED_STR_BUFLEN(knp));
 113                                 KSTAT_NAMED_STR_PTR(knp) = end;
 114                                 end += KSTAT_NAMED_STR_BUFLEN(knp);
 115                         }
 116                         (void) sigaction(SIGSEGV, &segv_act, NULL);
 117                 }
 118         }
 119 
 120         return (rval);
 121 }
 122 
 123 /*
 124  * kstat_value() - retrieve value of a field in a kstat_named_t kstat.
 125  *
 126  * parameters
 127  *      kstat_t *ksp - kstat containing the field
 128  *      char *name - text string representing the field name
 129  *
 130  * returns
 131  *      void * - pointer to data retrieved
 132  */
 133 void *
 134 kstat_value(kstat_t *ksp, char *name)
 135 {
 136         kstat_named_t *knm;
 137 
 138         if ((knm = kstat_data_lookup(ksp, name)) == NULL)
 139                 return (NULL);
 140 
 141         switch (knm->data_type) {
 142                 case KSTAT_DATA_CHAR :
 143                         return (knm->value.c);
 144                 case KSTAT_DATA_INT32 :
 145                         return (&knm->value.i32);
 146                 case KSTAT_DATA_UINT32 :
 147                         return (&knm->value.ui32);
 148                 case KSTAT_DATA_INT64 :
 149                         return (&knm->value.i64);
 150                 case KSTAT_DATA_UINT64 :
 151                         return (&knm->value.ui64);
 152                 case KSTAT_DATA_STRING :
 153                         return (KSTAT_NAMED_STR_PTR(knm));
 154         }
 155 
 156         return (NULL);
 157 }
 158 
 159 /*
 160  * kstat_free() - deallocated memory associated with a kstat
 161  *
 162  * paramters
 163  *      kstat_t ksp - kstat to be deallocated
 164  *
 165  * returns
 166  *      void
 167  */
 168 void
 169 kstat_free(kstat_t *ksp)
 170 {
 171         if (ksp != NULL) {
 172                 if (ksp->ks_data != NULL)
 173                         free(ksp->ks_data);
 174                 free(ksp);
 175         }
 176 }
 177 
 178 uint32_t
 179 kstat_delta(kstat_t *pksp, kstat_t *cksp, char *name)
 180 {
 181         uint32_t *pv, *cv;
 182 
 183         pv = kstat_value(pksp, name);
 184         cv = kstat_value(cksp, name);
 185 
 186         return (u32_delta(*pv, *cv));
 187 }