xref: /illumos-gate/usr/src/lib/fm/topo/libtopo/common/topo_subr.c (revision 8393544efeffe8042bf5273c148010b32fa827e2)
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 /*
23  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 #include <alloca.h>
27 #include <ctype.h>
28 #include <limits.h>
29 #include <syslog.h>
30 #include <strings.h>
31 #include <unistd.h>
32 
33 #include <topo_error.h>
34 #include <topo_subr.h>
35 
36 void
37 topo_hdl_lock(topo_hdl_t *thp)
38 {
39 	(void) pthread_mutex_lock(&thp->th_lock);
40 }
41 
42 void
43 topo_hdl_unlock(topo_hdl_t *thp)
44 {
45 	(void) pthread_mutex_unlock(&thp->th_lock);
46 }
47 
48 const char *
49 topo_stability2name(topo_stability_t s)
50 {
51 	switch (s) {
52 	case TOPO_STABILITY_INTERNAL:	return (TOPO_STABSTR_INTERNAL);
53 	case TOPO_STABILITY_PRIVATE:	return (TOPO_STABSTR_PRIVATE);
54 	case TOPO_STABILITY_OBSOLETE:	return (TOPO_STABSTR_OBSOLETE);
55 	case TOPO_STABILITY_EXTERNAL:	return (TOPO_STABSTR_EXTERNAL);
56 	case TOPO_STABILITY_UNSTABLE:	return (TOPO_STABSTR_UNSTABLE);
57 	case TOPO_STABILITY_EVOLVING:	return (TOPO_STABSTR_EVOLVING);
58 	case TOPO_STABILITY_STABLE:	return (TOPO_STABSTR_STABLE);
59 	case TOPO_STABILITY_STANDARD:	return (TOPO_STABSTR_STANDARD);
60 	default:			return (TOPO_STABSTR_UNKNOWN);
61 	}
62 }
63 
64 topo_stability_t
65 topo_name2stability(const char *name)
66 {
67 	if (strcmp(name, TOPO_STABSTR_INTERNAL) == 0)
68 		return (TOPO_STABILITY_INTERNAL);
69 	else if (strcmp(name, TOPO_STABSTR_PRIVATE) == 0)
70 		return (TOPO_STABILITY_PRIVATE);
71 	else if (strcmp(name, TOPO_STABSTR_OBSOLETE) == 0)
72 		return (TOPO_STABILITY_OBSOLETE);
73 	else if (strcmp(name, TOPO_STABSTR_EXTERNAL) == 0)
74 		return (TOPO_STABILITY_EXTERNAL);
75 	else if (strcmp(name, TOPO_STABSTR_UNSTABLE) == 0)
76 		return (TOPO_STABILITY_UNSTABLE);
77 	else if (strcmp(name, TOPO_STABSTR_EVOLVING) == 0)
78 		return (TOPO_STABILITY_EVOLVING);
79 	else if (strcmp(name, TOPO_STABSTR_STABLE) == 0)
80 		return (TOPO_STABILITY_STABLE);
81 	else if (strcmp(name, TOPO_STABSTR_STANDARD) == 0)
82 		return (TOPO_STABILITY_STANDARD);
83 
84 	return (TOPO_STABILITY_UNKNOWN);
85 }
86 
87 static const topo_debug_mode_t _topo_dbout_modes[] = {
88 	{ "stderr", "send debug messages to stderr", TOPO_DBOUT_STDERR },
89 	{ "syslog", "send debug messages to syslog", TOPO_DBOUT_SYSLOG },
90 	{ NULL, NULL, 0 }
91 };
92 
93 static const topo_debug_mode_t _topo_dbflag_modes[] = {
94 	{ "error", "error handling debug messages enabled", TOPO_DBG_ERR },
95 	{ "module", "module debug messages enabled", TOPO_DBG_MOD },
96 	{ "modulesvc", "module services debug messages enabled",
97 	    TOPO_DBG_MODSVC },
98 	{ "walk", "walker subsystem debug messages enabled", TOPO_DBG_WALK },
99 	{ "xml", "xml file parsing messages enabled", TOPO_DBG_XML },
100 	{ "devinfoforce", "devinfo DINFOFORCE snapshot used", TOPO_DBG_FORCE },
101 	{ "all", "all debug modes enabled", TOPO_DBG_ALL},
102 	{ NULL, NULL, 0 }
103 };
104 
105 void
106 env_process_value(topo_hdl_t *thp, const char *begin, const char *end)
107 {
108 	char buf[MAXNAMELEN];
109 	size_t count;
110 	topo_debug_mode_t *dbp;
111 
112 	while (begin < end && isspace(*begin))
113 		begin++;
114 
115 	while (begin < end && isspace(*(end - 1)))
116 		end--;
117 
118 	if (begin >= end)
119 		return;
120 
121 	count = end - begin;
122 	count += 1;
123 
124 	if (count > sizeof (buf))
125 		return;
126 
127 	(void) snprintf(buf, count, "%s", begin);
128 
129 	for (dbp = (topo_debug_mode_t *)_topo_dbflag_modes;
130 	    dbp->tdm_name != NULL; ++dbp) {
131 		if (strcmp(buf, dbp->tdm_name) == 0)
132 			thp->th_debug |= dbp->tdm_mode;
133 	}
134 }
135 
136 void
137 topo_debug_set(topo_hdl_t *thp, const char *dbmode, const char *dout)
138 {
139 	char *end, *value, *next;
140 	topo_debug_mode_t *dbp;
141 
142 	topo_hdl_lock(thp);
143 	value = (char *)dbmode;
144 
145 	for (end = (char *)dbmode; *end != '\0'; value = next) {
146 		end = strchr(value, ',');
147 		if (end != NULL)
148 			next = end + 1;	/* skip the comma */
149 		else
150 			next = end = value + strlen(value);
151 
152 		env_process_value(thp, value, end);
153 	}
154 
155 	if (dout == NULL) {
156 		topo_hdl_unlock(thp);
157 		return;
158 	}
159 
160 	for (dbp = (topo_debug_mode_t *)_topo_dbout_modes;
161 	    dbp->tdm_name != NULL; ++dbp) {
162 		if (strcmp(dout, dbp->tdm_name) == 0)
163 		thp->th_dbout = dbp->tdm_mode;
164 	}
165 	topo_hdl_unlock(thp);
166 }
167 
168 void
169 topo_vdprintf(topo_hdl_t *thp, int mask, const char *mod, const char *format,
170     va_list ap)
171 {
172 	char *msg;
173 	size_t len;
174 	char c;
175 
176 	if (!(thp->th_debug & mask))
177 		return;
178 
179 	len = vsnprintf(&c, 1, format, ap);
180 	msg = alloca(len + 2);
181 	(void) vsnprintf(msg, len + 1, format, ap);
182 
183 	if (msg[len - 1] != '\n')
184 		(void) strcpy(&msg[len], "\n");
185 
186 	if (thp->th_dbout == TOPO_DBOUT_SYSLOG) {
187 		if (mod == NULL) {
188 			syslog(LOG_DEBUG | LOG_USER, "libtopo DEBUG: %s", msg);
189 		} else {
190 			syslog(LOG_DEBUG | LOG_USER, "libtopo DEBUG: %s: %s",
191 			    mod, msg);
192 		}
193 	} else {
194 		if (mod == NULL) {
195 			(void) fprintf(stderr, "libtopo DEBUG: %s", msg);
196 		} else {
197 			(void) fprintf(stderr, "libtopo DEBUG: %s: %s", mod,
198 			    msg);
199 		}
200 	}
201 }
202 
203 /*PRINTFLIKE3*/
204 void
205 topo_dprintf(topo_hdl_t *thp, int mask, const char *format, ...)
206 {
207 	va_list ap;
208 
209 	va_start(ap, format);
210 	topo_vdprintf(thp, mask, NULL, format, ap);
211 	va_end(ap);
212 }
213 
214 tnode_t *
215 topo_hdl_root(topo_hdl_t *thp, const char *scheme)
216 {
217 	ttree_t *tp;
218 
219 	for (tp = topo_list_next(&thp->th_trees); tp != NULL;
220 	    tp = topo_list_next(tp)) {
221 		if (strcmp(scheme, tp->tt_scheme) == 0)
222 			return (tp->tt_root);
223 	}
224 
225 	return (NULL);
226 }
227 
228 /*
229  * buf_append -- Append str to buf (if it's non-NULL).  Place prepend
230  * in buf in front of str and append behind it (if they're non-NULL).
231  * Continue to update size even if we run out of space to actually
232  * stuff characters in the buffer.
233  */
234 void
235 topo_fmristr_build(ssize_t *sz, char *buf, size_t buflen, char *str,
236     char *prepend, char *append)
237 {
238 	ssize_t left;
239 
240 	if (str == NULL)
241 		return;
242 
243 	if (buflen == 0 || (left = buflen - *sz) < 0)
244 		left = 0;
245 
246 	if (buf != NULL && left != 0)
247 		buf += *sz;
248 
249 	if (prepend == NULL && append == NULL)
250 		*sz += snprintf(buf, left, "%s", str);
251 	else if (append == NULL)
252 		*sz += snprintf(buf, left, "%s%s", prepend, str);
253 	else if (prepend == NULL)
254 		*sz += snprintf(buf, left, "%s%s", str, append);
255 	else
256 		*sz += snprintf(buf, left, "%s%s%s", prepend, str, append);
257 }
258 
259 #define	TOPO_PLATFORM_PATH	"%s/usr/platform/%s/lib/fm/topo/%s"
260 #define	TOPO_COMMON_PATH	"%s/usr/lib/fm/topo/%s"
261 
262 char *
263 topo_search_path(topo_mod_t *mod, const char *rootdir, const char *file)
264 {
265 	char *pp, sp[PATH_MAX];
266 	topo_hdl_t *thp = mod->tm_hdl;
267 
268 	/*
269 	 * Search for file name in order of platform, machine and common
270 	 * topo directories
271 	 */
272 	(void) snprintf(sp, PATH_MAX, TOPO_PLATFORM_PATH, rootdir,
273 	    thp->th_platform, file);
274 	if (access(sp, F_OK) != 0) {
275 		(void) snprintf(sp, PATH_MAX, TOPO_PLATFORM_PATH,
276 		    thp->th_rootdir, thp->th_machine, file);
277 		if (access(sp, F_OK) != 0) {
278 			(void) snprintf(sp, PATH_MAX, TOPO_COMMON_PATH,
279 			    thp->th_rootdir, file);
280 			if (access(sp, F_OK) != 0) {
281 				return (NULL);
282 			}
283 		}
284 	}
285 
286 	pp = topo_mod_strdup(mod, sp);
287 
288 	return (pp);
289 }
290 
291 /*
292  * SMBIOS serial numbers can contain characters (particularly ':' and ' ')
293  * that are invalid for the authority and can break FMRI parsing.  We translate
294  * any invalid characters to a safe '-', as well as trimming any leading or
295  * trailing whitespace.  Similarly, '/' can be found in some product names
296  * so we translate that to '-'.
297  */
298 char *
299 topo_cleanup_auth_str(topo_hdl_t *thp, const char *begin)
300 {
301 	char buf[MAXNAMELEN];
302 	const char *end, *cp;
303 	char *pp;
304 	char c;
305 	int i;
306 
307 	end = begin + strlen(begin);
308 
309 	while (begin < end && isspace(*begin))
310 		begin++;
311 	while (begin < end && isspace(*(end - 1)))
312 		end--;
313 
314 	if (begin >= end)
315 		return (NULL);
316 
317 	cp = begin;
318 	for (i = 0; i < MAXNAMELEN - 1; i++) {
319 		if (cp >= end)
320 			break;
321 		c = *cp;
322 		if (c == ':' || c == '=' || c == '/' || isspace(c) ||
323 		    !isprint(c))
324 			buf[i] = '-';
325 		else
326 			buf[i] = c;
327 		cp++;
328 	}
329 	buf[i] = 0;
330 
331 	pp = topo_hdl_strdup(thp, buf);
332 	return (pp);
333 }
334 
335 void
336 topo_sensor_type_name(uint32_t type, char *buf, size_t len)
337 {
338 	topo_name_trans_t *ntp;
339 
340 	for (ntp = &topo_sensor_type_table[0]; ntp->int_name != NULL; ntp++) {
341 		if (ntp->int_value == type) {
342 			(void) strlcpy(buf, ntp->int_name, len);
343 			return;
344 		}
345 	}
346 
347 	(void) snprintf(buf, len, "0x%02x", type);
348 }
349 
350 void
351 topo_sensor_units_name(uint8_t type, char *buf, size_t len)
352 {
353 	topo_name_trans_t *ntp;
354 
355 	for (ntp = &topo_units_type_table[0]; ntp->int_name != NULL; ntp++) {
356 		if (ntp->int_value == type) {
357 			(void) strlcpy(buf, ntp->int_name, len);
358 			return;
359 		}
360 	}
361 
362 	(void) snprintf(buf, len, "0x%02x", type);
363 }
364 
365 void
366 topo_led_type_name(uint8_t type, char *buf, size_t len)
367 {
368 	topo_name_trans_t *ntp;
369 
370 	for (ntp = &topo_led_type_table[0]; ntp->int_name != NULL; ntp++) {
371 		if (ntp->int_value == type) {
372 			(void) strlcpy(buf, ntp->int_name, len);
373 			return;
374 		}
375 	}
376 
377 	(void) snprintf(buf, len, "0x%02x", type);
378 }
379 
380 void
381 topo_led_state_name(uint8_t type, char *buf, size_t len)
382 {
383 	topo_name_trans_t *ntp;
384 
385 	for (ntp = &topo_led_states_table[0]; ntp->int_name != NULL; ntp++) {
386 		if (ntp->int_value == type) {
387 			(void) strlcpy(buf, ntp->int_name, len);
388 			return;
389 		}
390 	}
391 
392 	(void) snprintf(buf, len, "0x%02x", type);
393 }
394 
395 void
396 topo_sensor_state_name(uint32_t sensor_type, uint8_t state, char *buf,
397 size_t len)
398 {
399 	topo_name_trans_t *ntp;
400 
401 	switch (sensor_type) {
402 		case TOPO_SENSOR_TYPE_PHYSICAL:
403 			ntp = &topo_sensor_states_physical_table[0];
404 			break;
405 		case TOPO_SENSOR_TYPE_PLATFORM:
406 			ntp = &topo_sensor_states_platform_table[0];
407 			break;
408 		case TOPO_SENSOR_TYPE_PROCESSOR:
409 			ntp = &topo_sensor_states_processor_table[0];
410 			break;
411 		case TOPO_SENSOR_TYPE_POWER_SUPPLY:
412 			ntp = &topo_sensor_states_power_supply_table[0];
413 			break;
414 		case TOPO_SENSOR_TYPE_POWER_UNIT:
415 			ntp = &topo_sensor_states_power_unit_table[0];
416 			break;
417 		case TOPO_SENSOR_TYPE_MEMORY:
418 			ntp = &topo_sensor_states_memory_table[0];
419 			break;
420 		case TOPO_SENSOR_TYPE_BAY:
421 			ntp = &topo_sensor_states_bay_table[0];
422 			break;
423 		case TOPO_SENSOR_TYPE_FIRMWARE:
424 			ntp = &topo_sensor_states_firmware_table[0];
425 			break;
426 		case TOPO_SENSOR_TYPE_EVENT_LOG:
427 			ntp = &topo_sensor_states_event_log_table[0];
428 			break;
429 		case TOPO_SENSOR_TYPE_WATCHDOG1:
430 			ntp = &topo_sensor_states_watchdog1_table[0];
431 			break;
432 		case TOPO_SENSOR_TYPE_SYSTEM:
433 			ntp = &topo_sensor_states_system_table[0];
434 			break;
435 		case TOPO_SENSOR_TYPE_CRITICAL:
436 			ntp = &topo_sensor_states_critical_table[0];
437 			break;
438 		case TOPO_SENSOR_TYPE_BUTTON:
439 			ntp = &topo_sensor_states_button_table[0];
440 			break;
441 		case TOPO_SENSOR_TYPE_CABLE:
442 			ntp = &topo_sensor_states_cable_table[0];
443 			break;
444 		case TOPO_SENSOR_TYPE_BOOT_STATE:
445 			ntp = &topo_sensor_states_boot_state_table[0];
446 			break;
447 		case TOPO_SENSOR_TYPE_BOOT_ERROR:
448 			ntp = &topo_sensor_states_boot_error_table[0];
449 			break;
450 		case TOPO_SENSOR_TYPE_BOOT_OS:
451 			ntp = &topo_sensor_states_boot_os_table[0];
452 			break;
453 		case TOPO_SENSOR_TYPE_OS_SHUTDOWN:
454 			ntp = &topo_sensor_states_os_table[0];
455 			break;
456 		case TOPO_SENSOR_TYPE_SLOT:
457 			ntp = &topo_sensor_states_slot_table[0];
458 			break;
459 		case TOPO_SENSOR_TYPE_ACPI:
460 			ntp = &topo_sensor_states_acpi_table[0];
461 			break;
462 		case TOPO_SENSOR_TYPE_WATCHDOG2:
463 			ntp = &topo_sensor_states_watchdog2_table[0];
464 			break;
465 		case TOPO_SENSOR_TYPE_ALERT:
466 			ntp = &topo_sensor_states_alert_table[0];
467 			break;
468 		case TOPO_SENSOR_TYPE_PRESENCE:
469 			ntp = &topo_sensor_states_presence_table[0];
470 			break;
471 		case TOPO_SENSOR_TYPE_LAN:
472 			ntp = &topo_sensor_states_lan_table[0];
473 			break;
474 		case TOPO_SENSOR_TYPE_HEALTH:
475 			ntp = &topo_sensor_states_health_table[0];
476 			break;
477 		case TOPO_SENSOR_TYPE_BATTERY:
478 			ntp = &topo_sensor_states_battery_table[0];
479 			break;
480 		case TOPO_SENSOR_TYPE_AUDIT:
481 			ntp = &topo_sensor_states_audit_table[0];
482 			break;
483 		case TOPO_SENSOR_TYPE_VERSION:
484 			ntp = &topo_sensor_states_version_table[0];
485 			break;
486 		case TOPO_SENSOR_TYPE_FRU_STATE:
487 			ntp = &topo_sensor_states_fru_state_table[0];
488 			break;
489 		case TOPO_SENSOR_TYPE_THRESHOLD_STATE:
490 			ntp = &topo_sensor_states_thresh_table[0];
491 			break;
492 		case TOPO_SENSOR_TYPE_GENERIC_USAGE:
493 			ntp = &topo_sensor_states_generic_usage_table[0];
494 			break;
495 		case TOPO_SENSOR_TYPE_GENERIC_STATE:
496 			ntp = &topo_sensor_states_generic_state_table[0];
497 			break;
498 		case TOPO_SENSOR_TYPE_GENERIC_PREDFAIL:
499 			ntp = &topo_sensor_states_generic_predfail_table[0];
500 			break;
501 		case TOPO_SENSOR_TYPE_GENERIC_LIMIT:
502 			ntp = &topo_sensor_states_generic_limit_table[0];
503 			break;
504 		case TOPO_SENSOR_TYPE_GENERIC_PERFORMANCE:
505 			ntp = &topo_sensor_states_generic_perf_table[0];
506 			break;
507 		case TOPO_SENSOR_TYPE_SEVERITY:
508 			ntp = &topo_sensor_states_severity_table[0];
509 			break;
510 		case TOPO_SENSOR_TYPE_GENERIC_PRESENCE:
511 			ntp = &topo_sensor_states_generic_presence_table[0];
512 			break;
513 		case TOPO_SENSOR_TYPE_GENERIC_AVAILABILITY:
514 			ntp = &topo_sensor_states_generic_avail_table[0];
515 			break;
516 		case TOPO_SENSOR_TYPE_GENERIC_STATUS:
517 			ntp = &topo_sensor_states_generic_status_table[0];
518 			break;
519 		case TOPO_SENSOR_TYPE_GENERIC_ACPI:
520 			ntp = &topo_sensor_states_generic_acpi_pwr_table[0];
521 			break;
522 		case TOPO_SENSOR_TYPE_GENERIC_FAILURE:
523 			ntp = &topo_sensor_states_generic_failure_table[0];
524 			break;
525 		case TOPO_SENSOR_TYPE_GENERIC_OK:
526 			ntp = &topo_sensor_states_generic_ok_table[0];
527 			break;
528 		default:
529 			(void) snprintf(buf, len, "0x%02x", state);
530 			return;
531 	}
532 	for (; ntp->int_name != NULL; ntp++) {
533 		if (ntp->int_value == state) {
534 			(void) strlcpy(buf, ntp->int_name, len);
535 			return;
536 		}
537 	}
538 
539 	(void) snprintf(buf, len, "0x%02x", state);
540 }
541