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 }