xref: /illumos-gate/usr/src/cmd/pcidr/pcidr_common.c (revision a07094369b21309434206d9b3601d162693466fc)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <strings.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <sys/param.h>
36 #include <sys/sysevent/eventdefs.h>
37 #include <sys/sysevent/dr.h>
38 #include <syslog.h>
39 #include <libnvpair.h>
40 #include <stdarg.h>
41 #include <assert.h>
42 #include <sys/stat.h>
43 #include <dlfcn.h>
44 #include <signal.h>
45 #include <pcidr.h>
46 
47 
48 /*
49  * How dpritab is used:
50  * dpritab[dlvl_t value] = corresponding syslog priority
51  *
52  * Be careful of some priorities (facility + severity) that get "lost" by
53  * default since they have no syslog.conf entries such as daemon.info and
54  * daemon.debug; see syslog(3C) and syslog.conf(4) for more info
55  */
56 int dpritab[] = {LOG_INFO, LOG_WARNING, LOG_NOTICE, LOG_NOTICE};
57 int dpritab_len = sizeof (dpritab) / sizeof (dpritab[0]);
58 
59 /*
60  * the following affects pcidr_set_logopt() which plugins should use to set
61  * these logging options received from the handler
62  */
63 dlvl_t dlvl = MIN_DLVL;	/* verbosity */
64 char *prg = "";		/* program name */
65 FILE *dfp = NULL;	/* file to output messages to */
66 int dsys = 1;		/* flag controlling output to syslog */
67 
68 
69 void *
70 pcidr_malloc(size_t size)
71 {
72 	int i = 0;
73 	void *buf;
74 
75 	errno = 0;
76 	buf = malloc(size);
77 	if (buf != NULL)
78 		return (buf);
79 
80 	for (i = 0; i < PCIDR_MALLOC_CNT; i++) {
81 		assert(errno == EAGAIN);
82 		if (errno != EAGAIN)
83 			exit(errno);
84 		(void) usleep(PCIDR_MALLOC_TIME);
85 
86 		errno = 0;
87 		buf = malloc(size);
88 		if (buf != NULL)
89 			return (buf);
90 	}
91 
92 	assert(buf != NULL);
93 	/* exit() in case assertions are disabled (NDEBUG defined) */
94 	exit(errno);
95 	return (NULL);
96 }
97 
98 
99 void
100 dprint(dlvl_t lvl, char *fmt, ...)
101 {
102 	int buflen, rv;
103 	char *buf;
104 	va_list ap;
105 
106 	if (dlvl < lvl || (dsys == 0 && dfp == NULL))
107 		return;
108 
109 	va_start(ap, fmt);
110 	/*LINTED*/
111 	buflen = vsnprintf(NULL, 0, fmt, ap);
112 	va_end(ap);
113 	if (buflen <= 0)
114 		return;
115 	buflen++;
116 	buf = (char *)pcidr_malloc(sizeof (char) * buflen);
117 
118 	va_start(ap, fmt);
119 	/*LINTED*/
120 	rv = vsnprintf(buf, buflen, fmt, ap);
121 	va_end(ap);
122 	if (rv <= 0) {
123 		free(buf);
124 		return;
125 	}
126 
127 #ifdef DEBUG
128 	if (dsys != 0)
129 		syslog(dpritab[lvl], "%s", buf);
130 #endif
131 	if (dfp != NULL)
132 		(void) fprintf(dfp, "%s", buf);
133 
134 	free(buf);
135 }
136 
137 
138 void
139 pcidr_set_logopt(pcidr_logopt_t *logopt)
140 {
141 	dlvl = logopt->dlvl;
142 	prg = logopt->prg;
143 	dfp = logopt->dfp;
144 	dsys = logopt->dsys;
145 }
146 
147 
148 /*
149  * if <name> is recognized, function will return its type through <typep> and
150  * return 0; else function will return non-zero
151  */
152 int
153 pcidr_name2type(char *name, data_type_t *typep)
154 {
155 	/* string type */
156 	if (strcmp(name, ATTRNM_CLASS) == 0 ||
157 	    strcmp(name, ATTRNM_SUBCLASS) == 0 ||
158 	    strcmp(name, ATTRNM_PUB_NAME) == 0 ||
159 	    strcmp(name, DR_REQ_TYPE) == 0 ||
160 	    strcmp(name, DR_AP_ID) == 0) {
161 		*typep = DATA_TYPE_STRING;
162 		return (0);
163 	}
164 
165 	return (1);
166 }
167 
168 
169 void
170 pcidr_print_attrlist(dlvl_t lvl, nvlist_t *attrlistp, char *prestr)
171 {
172 	char *fn = "pcidr_print_attrlist";
173 	nvpair_t *nvpairp;
174 	char *valstr, *name;
175 	data_type_t type;
176 	int rv;
177 
178 	if (prestr == NULL)
179 		prestr = "";
180 
181 	nvpairp = NULL;
182 	while ((nvpairp = nvlist_next_nvpair(attrlistp, nvpairp)) != NULL) {
183 		type = nvpair_type(nvpairp);
184 		name = nvpair_name(nvpairp);
185 
186 		switch (type) {
187 		case DATA_TYPE_STRING:
188 			rv = nvpair_value_string(nvpairp, &valstr);
189 			if (rv != 0) {
190 				dprint(lvl, "%s: nvpair_value_string() "
191 				    "failed: name = %s, rv = %d\n",
192 				    fn, name, rv);
193 				continue;
194 			}
195 			break;
196 		default:
197 			dprint(lvl, "%s: unsupported type: name = %s, "
198 			    "type = 0x%x\n", fn, name, (int)type);
199 			continue;
200 		}
201 		dprint(lvl, "%s%s = %s\n", prestr, name, valstr);
202 	}
203 }
204 
205 
206 /*
207  * if one of the args matches <valstr>, return 0; else return non-zero
208  * args list must be NULL terminated;
209  * if args list is empty, this will return 0 if <valstr> is NOT empty
210  */
211 int
212 pcidr_check_string(char *valstr, ...)
213 {
214 	va_list ap;
215 	int rv;
216 	char *argstr;
217 
218 	assert(valstr != NULL);
219 	rv = 1;
220 	va_start(ap, valstr);
221 	if (va_arg(ap, char *) == NULL) {
222 		if (valstr[0] != '\0')
223 			rv = 0;
224 		goto OUT;
225 	}
226 
227 	va_start(ap, valstr);
228 	while ((argstr = va_arg(ap, char *)) != NULL) {
229 		if (strcmp(argstr, valstr) == 0) {
230 			rv = 0;
231 			break;
232 		}
233 	}
234 OUT:
235 	va_end(ap);
236 	return (rv);
237 }
238 
239 
240 /*
241  * dr attribute values that the default plugin checks for;
242  * other plugins may also use this if they support a superset of these
243  * values.
244  * returns 0 if valid, else non-zero
245  */
246 int
247 pcidr_check_attrs(pcidr_attrs_t *drp)
248 {
249 	char *fn = "pcidr_check_attrs";
250 	int rv = 0;
251 	char *val, *name;
252 
253 	name = ATTRNM_CLASS;
254 	val = drp->class;
255 	if (pcidr_check_string(val, EC_DR, NULL) != 0) {
256 		dprint(DDEBUG, "%s: attribute \"%s\" has invalid value = %s\n",
257 		    fn, name, val);
258 		rv = 1;
259 	}
260 
261 	name = ATTRNM_SUBCLASS;
262 	val = drp->subclass;
263 	if (pcidr_check_string(val, ESC_DR_REQ, NULL) != 0) {
264 		dprint(DDEBUG, "%s: attribute \"%s\" has invalid value = %s\n",
265 		    fn, name, val);
266 		rv = 1;
267 	}
268 
269 	name = ATTRNM_PUB_NAME;
270 	val = drp->pub_name;
271 	if (pcidr_check_string(val, NULL) != 0) {
272 		dprint(DDEBUG, "%s: attribute \"%s\" is empty\n",
273 		    fn, name, val);
274 		rv = 1;
275 	}
276 
277 	name = DR_REQ_TYPE;
278 	val = drp->dr_req_type;
279 	if (pcidr_check_string(val, DR_REQ_INCOMING_RES, DR_REQ_OUTGOING_RES,
280 	    NULL) != 0) {
281 		dprint(DDEBUG, "%s: attribute \"%s\" has invalid value = %s\n",
282 		    fn, name, val);
283 		rv = 1;
284 	}
285 
286 	name = DR_AP_ID;
287 	val = drp->dr_ap_id;
288 	if (pcidr_check_string(drp->dr_ap_id, NULL) != 0) {
289 		dprint(DDEBUG, "%s: attribute \"%s\" is empty\n",
290 		    fn, name, val);
291 		rv = 1;
292 	}
293 
294 	return (rv);
295 }
296 
297 
298 /*
299  * get dr attributes from <listp> for the default plugin and returns
300  * them through <drp>;
301  * returns 0 on success
302  */
303 int
304 pcidr_get_attrs(nvlist_t *attrlistp, pcidr_attrs_t *drp)
305 {
306 	char *fn = "pcidr_get_attrs";
307 	char *name;
308 	int r, rv = 0;
309 
310 	name = ATTRNM_CLASS;
311 	r = nvlist_lookup_string(attrlistp, name, &drp->class);
312 	if (r != 0) {
313 		dprint(DDEBUG, "%s: nvlist_lookup_string() failed for "
314 		    "attribute \"%s\": rv = %d\n", fn, name, r);
315 		rv = r;
316 	}
317 
318 	name = ATTRNM_SUBCLASS;
319 	r = nvlist_lookup_string(attrlistp, name, &drp->subclass);
320 	if (r != 0) {
321 		dprint(DDEBUG, "%s: nvlist_lookup_string() failed for "
322 		    "attribute \"%s\": rv = %d\n", fn, name, r);
323 		rv = r;
324 	}
325 
326 	name = ATTRNM_PUB_NAME;
327 	r = nvlist_lookup_string(attrlistp, name, &drp->pub_name);
328 	if (r != 0) {
329 		dprint(DDEBUG, "%s: nvlist_lookup_string() failed for "
330 		    "attribute \"%s\": rv = %d\n", fn, name, r);
331 		rv = r;
332 	}
333 
334 	name = DR_REQ_TYPE;
335 	r = nvlist_lookup_string(attrlistp, name, &drp->dr_req_type);
336 	if (r != 0) {
337 		dprint(DDEBUG, "%s: nvlist_lookup_string() failed for "
338 		    "attribute \"%s\": rv = %d\n", fn, name, r);
339 		rv = r;
340 	}
341 
342 	name = DR_AP_ID;
343 	r = nvlist_lookup_string(attrlistp, name, &drp->dr_ap_id);
344 	if (r != 0) {
345 		dprint(DDEBUG, "%s: nvlist_lookup_string() failed for "
346 		    "attribute \"%s\": rv = %d\n", fn, name, r);
347 		rv = r;
348 	}
349 
350 	return (rv);
351 }
352