xref: /titanic_41/usr/src/lib/libunistat/common/spcs_s_u.c (revision 2f172c55ef76964744bc62b4500ece87f3089b4d)
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 }
247