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