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 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 /*
  26  *      The SPCS status support user utilities
  27  *      See spcs_s_u.h and the docs subdirectory for functional spec
  28  */
  29 
  30 #include <stdio.h>
  31 #include <stdlib.h>
  32 #include <stdarg.h>
  33 #include <string.h>
  34 #include <errno.h>
  35 #include <sys/types.h>
  36 #include <locale.h>
  37 #include <libintl.h>
  38 #include <sys/unistat/spcs_s.h>
  39 #include <sys/unistat/spcs_s_u.h>
  40 #include <sys/unistat/spcs_s_impl.h>
  41 #include <sys/unistat/spcs_errors.h>
  42 #include <sys/unistat/spcs_etext.h>
  43 #include <sys/unistat/spcs_etrinkets.h>
  44 #include <sys/unistat/spcs_dtrinkets.h>
  45 
  46 /*
  47  *      Initialize ioctl status storage to "remove" any old status present
  48  */
  49 
  50 void
  51 spcs_s_uinit(spcs_s_info_t ustatus)
  52 {
  53         spcs_s_pinfo_t *p = (spcs_s_pinfo_t *)ustatus;
  54         p->major = SPCS_S_MAJOR_REV;
  55         p->minor = SPCS_S_MINOR_REV;
  56         p->icount = 0;
  57         p->scount = 0;
  58         p->tcount = 0;
  59 }
  60 
  61 /*
  62  *      Create and initialize local status. Call this prior to invoking
  63  *      an ioctl.
  64  */
  65 
  66 spcs_s_info_t
  67 spcs_s_ucreate()
  68 {
  69         static int need_to_bind = 1;
  70         spcs_s_pinfo_t *ustatus;
  71 
  72         if (need_to_bind) {
  73             (void) setlocale(LC_ALL, "");
  74             (void) bindtextdomain("unistat", LIBUNISTAT_LOCALE);
  75             need_to_bind = 0;
  76         };
  77 
  78         ustatus = (spcs_s_pinfo_t *)malloc(sizeof (spcs_s_pinfo_t));
  79         spcs_s_uinit((spcs_s_info_t)ustatus);
  80 
  81         return ((spcs_s_info_t)ustatus);
  82 }
  83 
  84 /*
  85  *      Return the idata index of the last status code in the array (i.e.
  86  *      the "youngest" code present). The assumption is that the caller has
  87  *      checked to see that pcount is nonzero.
  88  */
  89 
  90 ISSTATIC int
  91 last_code_idx(spcs_s_pinfo_t *p)
  92 {
  93         int last = 0;
  94         int idx = 0;
  95 
  96         while (idx < p->icount) {
  97                 last = idx;
  98                 idx += p->idata[idx].f.sup_count + 1;
  99         }
 100         return (last);
 101 }
 102 
 103 /*
 104  *      Return a string with the module label and error message text or NULL
 105  *      if none left
 106  */
 107 
 108 char *
 109 spcs_s_string(spcs_s_info_t ustatus, char *msg)
 110 {
 111         spcs_s_pinfo_t *p = (spcs_s_pinfo_t *)ustatus;
 112         int idx;
 113         int sup;
 114         int s;
 115         char *format;
 116         char *sp[SPCS_S_MAXSUPP];
 117         char mtemp[SPCS_S_MAXLINE];
 118 
 119         if (p->icount > 0) {
 120                 idx = last_code_idx(p);
 121                 strcpy(msg, module_names[p->idata[idx].f.module]);
 122                 strcat(msg, ": ");
 123                 sup = p->idata[idx].f.sup_count;
 124 
 125                 if (p->idata[idx].f.module)
 126                         /*
 127                          * The gettext formal parameter is a const char*
 128                          * I guess the gettext creator couldn't imagine
 129                          * needing a variable string. If there is an underlying
 130                          * routine that can be called it should be used.
 131                          * otherwise there will be a compiler warning about this
 132                          * line FOREVER (TS).
 133                          */
 134                         format = (char *)dgettext("unistat",
 135                                 SPCS_S_MSG[p->idata[idx].f.module]
 136                                 [p->idata[idx].f.code]);
 137 
 138                 else
 139                         format = strerror(p->idata[idx].f.code);
 140 
 141                 /*
 142                  * step across the status code to the first supplemental data
 143                  * descriptor.
 144                  */
 145 
 146                 idx += 1;
 147 
 148                 /*
 149                  * Initialize the array with empty string pointers so we don't
 150                  * seg fault if there are actually fewer values than "%s"
 151                  * format descriptors.
 152                  */
 153                 for (s = 0; s < SPCS_S_MAXSUPP; s++)
 154                         sp[s] = "";
 155 
 156                 /*
 157                  * Walk through the supplemental value descriptors and build
 158                  * an array of string pointers.
 159                  */
 160 
 161                 for (s = 0; s < sup; s++) {
 162                         sp[s] = (char *)(p->sdata + p->idata[idx+s].su.offset);
 163                 }
 164 
 165                 /*
 166                  * Now format the message. The unused string pointers will be
 167                  * ignored.
 168                  * NOTE: Any change to SPCS_S_MAXSUPP requires a change to
 169                  * this sprintf.
 170                  */
 171 
 172                 sprintf(mtemp, format, sp[0], sp[1], sp[2], sp[3], sp[4], sp[5],
 173                                     sp[6], sp[7]);
 174 
 175                 /* remove the code and its supplemental info */
 176 
 177                 p->icount -= (sup + 1);
 178 
 179                 return (strcat(msg, mtemp));
 180         } else
 181                 return (NULL);
 182 }
 183 
 184 /*
 185  *      Write status info
 186  */
 187 
 188 void
 189 spcs_s_report(spcs_s_info_t ustatus, FILE *fd)
 190 {
 191         spcs_s_pinfo_t *p = (spcs_s_pinfo_t *)ustatus;
 192         short saved_count = p->icount;
 193         char msg[SPCS_S_MAXTEXT];
 194         char *sp;
 195         char *se;
 196         int first_time = 1;
 197 
 198         do {
 199                 if (sp = spcs_s_string(ustatus, msg))
 200                         fprintf(fd, "%s\n", sp);
 201                 else if (first_time && (errno > 0)) {
 202                         /*
 203                          * This covers the case where Solaris aborted the
 204                          * operation or the ioctl service code got an EFAULT
 205                          * or something from copyin or couldn't allocate the
 206                          * kernel status structure. If errno > 0 but not a
 207                          * valid Solaris error code the extended error is
 208                          * decoded and printed.
 209                          */
 210                         se = strerror(errno);
 211                         if (se)
 212                                 fprintf(fd, "%s\n", se);
 213                         else {
 214                                 spcs_s_udata_t spcs_errno;
 215 
 216                                 spcs_errno.i = errno;
 217                                 fprintf(fd, "%s: %s\n",
 218                                         module_names[spcs_errno.f.module],
 219                                         dgettext("unistat",
 220                                                 SPCS_S_MSG[spcs_errno.f.module]
 221                                                 [spcs_errno.f.code]));
 222 
 223                         }
 224                 }
 225                 first_time = 0;
 226         } while (sp);
 227 
 228         p->icount = saved_count;
 229 }
 230 
 231 /*ARGSUSED*/
 232 void
 233 spcs_s_exception(spcs_s_info_t ustatus, void *env)
 234 {
 235 }
 236 
 237 /*
 238  *      Release (free) ioctl status storage.
 239  */
 240 
 241 void
 242 spcs_s_ufree(spcs_s_info_t *ustatus_a)
 243 {
 244         free((void *)*ustatus_a);
 245         *ustatus_a = NULL;
 246 }