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