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