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
spcs_s_uinit(spcs_s_info_t ustatus)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
spcs_s_ucreate()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
last_code_idx(spcs_s_pinfo_t * p)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 *
spcs_s_string(spcs_s_info_t ustatus,char * msg)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
spcs_s_report(spcs_s_info_t ustatus,FILE * fd)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
spcs_s_exception(spcs_s_info_t ustatus,void * env)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
spcs_s_ufree(spcs_s_info_t * ustatus_a)242 spcs_s_ufree(spcs_s_info_t *ustatus_a)
243 {
244 free((void *)*ustatus_a);
245 *ustatus_a = NULL;
246 }
247