xref: /illumos-gate/usr/src/lib/fm/topo/libtopo/common/topo_subr.c (revision 0eb822a1c0c2bea495647510b75f77f0e57633eb)
17aec1d6eScindi /*
27aec1d6eScindi  * CDDL HEADER START
37aec1d6eScindi  *
47aec1d6eScindi  * The contents of this file are subject to the terms of the
574a31ce6Stimh  * Common Development and Distribution License (the "License").
674a31ce6Stimh  * You may not use this file except in compliance with the License.
77aec1d6eScindi  *
87aec1d6eScindi  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97aec1d6eScindi  * or http://www.opensolaris.org/os/licensing.
107aec1d6eScindi  * See the License for the specific language governing permissions
117aec1d6eScindi  * and limitations under the License.
127aec1d6eScindi  *
137aec1d6eScindi  * When distributing Covered Code, include this CDDL HEADER in each
147aec1d6eScindi  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157aec1d6eScindi  * If applicable, add the following below this CDDL HEADER, with the
167aec1d6eScindi  * fields enclosed by brackets "[]" replaced with your own identifying
177aec1d6eScindi  * information: Portions Copyright [yyyy] [name of copyright owner]
187aec1d6eScindi  *
197aec1d6eScindi  * CDDL HEADER END
207aec1d6eScindi  */
217aec1d6eScindi 
227aec1d6eScindi /*
237aec1d6eScindi  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
247aec1d6eScindi  * Use is subject to license terms.
257aec1d6eScindi  */
267aec1d6eScindi 
277aec1d6eScindi #pragma ident	"%Z%%M%	%I%	%E% SMI"
287aec1d6eScindi 
297aec1d6eScindi #include <alloca.h>
30*0eb822a1Scindi #include <ctype.h>
31*0eb822a1Scindi #include <limits.h>
327aec1d6eScindi #include <syslog.h>
337aec1d6eScindi #include <strings.h>
34*0eb822a1Scindi #include <unistd.h>
357aec1d6eScindi 
367aec1d6eScindi #include <topo_error.h>
377aec1d6eScindi #include <topo_subr.h>
387aec1d6eScindi 
397aec1d6eScindi struct _rwlock;
407aec1d6eScindi struct _lwp_mutex;
417aec1d6eScindi 
427aec1d6eScindi int
437aec1d6eScindi topo_rw_read_held(pthread_rwlock_t *lock)
447aec1d6eScindi {
457aec1d6eScindi 	extern int _rw_read_held(struct _rwlock *);
467aec1d6eScindi 	return (_rw_read_held((struct _rwlock *)lock));
477aec1d6eScindi }
487aec1d6eScindi 
497aec1d6eScindi int
507aec1d6eScindi topo_rw_write_held(pthread_rwlock_t *lock)
517aec1d6eScindi {
527aec1d6eScindi 	extern int _rw_write_held(struct _rwlock *);
537aec1d6eScindi 	return (_rw_write_held((struct _rwlock *)lock));
547aec1d6eScindi }
557aec1d6eScindi 
567aec1d6eScindi int
577aec1d6eScindi topo_mutex_held(pthread_mutex_t *lock)
587aec1d6eScindi {
597aec1d6eScindi 	extern int _mutex_held(struct _lwp_mutex *);
607aec1d6eScindi 	return (_mutex_held((struct _lwp_mutex *)lock));
617aec1d6eScindi }
627aec1d6eScindi 
637aec1d6eScindi void
647aec1d6eScindi topo_hdl_lock(topo_hdl_t *thp)
657aec1d6eScindi {
667aec1d6eScindi 	(void) pthread_mutex_lock(&thp->th_lock);
677aec1d6eScindi }
687aec1d6eScindi 
697aec1d6eScindi void
707aec1d6eScindi topo_hdl_unlock(topo_hdl_t *thp)
717aec1d6eScindi {
727aec1d6eScindi 	(void) pthread_mutex_unlock(&thp->th_lock);
737aec1d6eScindi }
747aec1d6eScindi 
757aec1d6eScindi const char *
76*0eb822a1Scindi topo_stability2name(topo_stability_t s)
777aec1d6eScindi {
787aec1d6eScindi 	switch (s) {
79*0eb822a1Scindi 	case TOPO_STABILITY_INTERNAL:	return (TOPO_STABSTR_INTERNAL);
80*0eb822a1Scindi 	case TOPO_STABILITY_PRIVATE:	return (TOPO_STABSTR_PRIVATE);
81*0eb822a1Scindi 	case TOPO_STABILITY_OBSOLETE:	return (TOPO_STABSTR_OBSOLETE);
82*0eb822a1Scindi 	case TOPO_STABILITY_EXTERNAL:	return (TOPO_STABSTR_EXTERNAL);
83*0eb822a1Scindi 	case TOPO_STABILITY_UNSTABLE:	return (TOPO_STABSTR_UNSTABLE);
84*0eb822a1Scindi 	case TOPO_STABILITY_EVOLVING:	return (TOPO_STABSTR_EVOLVING);
85*0eb822a1Scindi 	case TOPO_STABILITY_STABLE:	return (TOPO_STABSTR_STABLE);
86*0eb822a1Scindi 	case TOPO_STABILITY_STANDARD:	return (TOPO_STABSTR_STANDARD);
87*0eb822a1Scindi 	default:			return (TOPO_STABSTR_UNKNOWN);
887aec1d6eScindi 	}
897aec1d6eScindi }
907aec1d6eScindi 
91*0eb822a1Scindi topo_stability_t
92*0eb822a1Scindi topo_name2stability(const char *name)
93*0eb822a1Scindi {
94*0eb822a1Scindi 	if (strcmp(name, TOPO_STABSTR_INTERNAL) == 0)
95*0eb822a1Scindi 		return (TOPO_STABILITY_INTERNAL);
96*0eb822a1Scindi 	else if (strcmp(name, TOPO_STABSTR_PRIVATE) == 0)
97*0eb822a1Scindi 		return (TOPO_STABILITY_PRIVATE);
98*0eb822a1Scindi 	else if (strcmp(name, TOPO_STABSTR_OBSOLETE) == 0)
99*0eb822a1Scindi 		return (TOPO_STABILITY_OBSOLETE);
100*0eb822a1Scindi 	else if (strcmp(name, TOPO_STABSTR_EXTERNAL) == 0)
101*0eb822a1Scindi 		return (TOPO_STABILITY_EXTERNAL);
102*0eb822a1Scindi 	else if (strcmp(name, TOPO_STABSTR_UNSTABLE) == 0)
103*0eb822a1Scindi 		return (TOPO_STABILITY_UNSTABLE);
104*0eb822a1Scindi 	else if (strcmp(name, TOPO_STABSTR_EVOLVING) == 0)
105*0eb822a1Scindi 		return (TOPO_STABILITY_EVOLVING);
106*0eb822a1Scindi 	else if (strcmp(name, TOPO_STABSTR_STABLE) == 0)
107*0eb822a1Scindi 		return (TOPO_STABILITY_STABLE);
108*0eb822a1Scindi 	else if (strcmp(name, TOPO_STABSTR_STANDARD) == 0)
109*0eb822a1Scindi 		return (TOPO_STABILITY_STANDARD);
110*0eb822a1Scindi 
111*0eb822a1Scindi 	return (TOPO_STABILITY_UNKNOWN);
112*0eb822a1Scindi }
113*0eb822a1Scindi 
1147aec1d6eScindi static const topo_debug_mode_t _topo_dbout_modes[] = {
1157aec1d6eScindi 	{ "stderr", "send debug messages to stderr", TOPO_DBOUT_STDERR },
1167aec1d6eScindi 	{ "syslog", "send debug messages to syslog", TOPO_DBOUT_SYSLOG },
1177aec1d6eScindi 	{ NULL, NULL, 0 }
1187aec1d6eScindi };
1197aec1d6eScindi 
120*0eb822a1Scindi static const topo_debug_mode_t _topo_dbflag_modes[] = {
121*0eb822a1Scindi 	{ "error", "error handling debug messages enabled", TOPO_DBG_ERR },
122*0eb822a1Scindi 	{ "module", "module debug messages enabled", TOPO_DBG_MOD },
123*0eb822a1Scindi 	{ "modulesvc", "module services debug messages enabled",
124*0eb822a1Scindi 	    TOPO_DBG_MODSVC },
125*0eb822a1Scindi 	{ "walk", "walker subsystem debug messages enabled", TOPO_DBG_WALK },
126*0eb822a1Scindi 	{ "xml", "xml file parsing messages enabled", TOPO_DBG_XML },
127*0eb822a1Scindi 	{ "all", "all debug modes enabled", TOPO_DBG_ALL},
128*0eb822a1Scindi 	{ NULL, NULL, 0 }
129*0eb822a1Scindi };
130*0eb822a1Scindi 
1317aec1d6eScindi void
132*0eb822a1Scindi env_process_value(topo_hdl_t *thp, const char *begin, const char *end)
1337aec1d6eScindi {
134*0eb822a1Scindi 	char buf[MAXNAMELEN];
135*0eb822a1Scindi 	size_t count;
136*0eb822a1Scindi 	topo_debug_mode_t *dbp;
137*0eb822a1Scindi 
138*0eb822a1Scindi 	while (begin < end && isspace(*begin))
139*0eb822a1Scindi 		begin++;
140*0eb822a1Scindi 
141*0eb822a1Scindi 	while (begin < end && isspace(*(end - 1)))
142*0eb822a1Scindi 		end--;
143*0eb822a1Scindi 
144*0eb822a1Scindi 	if (begin >= end)
145*0eb822a1Scindi 		return;
146*0eb822a1Scindi 
147*0eb822a1Scindi 	count = end - begin;
148*0eb822a1Scindi 	count += 1;
149*0eb822a1Scindi 
150*0eb822a1Scindi 	if (count > sizeof (buf))
151*0eb822a1Scindi 		return;
152*0eb822a1Scindi 
153*0eb822a1Scindi 	(void) snprintf(buf, count, "%s", begin);
154*0eb822a1Scindi 
155*0eb822a1Scindi 	for (dbp = (topo_debug_mode_t *)_topo_dbflag_modes;
156*0eb822a1Scindi 	    dbp->tdm_name != NULL; ++dbp) {
157*0eb822a1Scindi 		if (strcmp(buf, dbp->tdm_name) == 0)
158*0eb822a1Scindi 			thp->th_debug |= dbp->tdm_mode;
159*0eb822a1Scindi 	}
160*0eb822a1Scindi }
161*0eb822a1Scindi 
162*0eb822a1Scindi void
163*0eb822a1Scindi topo_debug_set(topo_hdl_t *thp, const char *dbmode, const char *dout)
164*0eb822a1Scindi {
165*0eb822a1Scindi 	char *end, *value, *next;
166*0eb822a1Scindi 	topo_debug_mode_t *dbp;
167*0eb822a1Scindi 
168*0eb822a1Scindi 	topo_hdl_lock(thp);
169*0eb822a1Scindi 	value = (char *)dbmode;
170*0eb822a1Scindi 
171*0eb822a1Scindi 	for (end = (char *)dbmode; *end != '\0'; value = next) {
172*0eb822a1Scindi 		end = strchr(value, ',');
173*0eb822a1Scindi 		if (end != NULL)
174*0eb822a1Scindi 			next = end + 1;	/* skip the comma */
175*0eb822a1Scindi 		else
176*0eb822a1Scindi 			next = end = value + strlen(value);
177*0eb822a1Scindi 
178*0eb822a1Scindi 		env_process_value(thp, value, end);
179*0eb822a1Scindi 	}
180*0eb822a1Scindi 
181*0eb822a1Scindi 	if (dout == NULL) {
182*0eb822a1Scindi 		topo_hdl_unlock(thp);
183*0eb822a1Scindi 		return;
1847aec1d6eScindi 	}
185*0eb822a1Scindi 
186*0eb822a1Scindi 	for (dbp = (topo_debug_mode_t *)_topo_dbout_modes;
187*0eb822a1Scindi 	    dbp->tdm_name != NULL; ++dbp) {
188*0eb822a1Scindi 		if (strcmp(dout, dbp->tdm_name) == 0)
189*0eb822a1Scindi 		thp->th_dbout = dbp->tdm_mode;
190*0eb822a1Scindi 	}
191*0eb822a1Scindi 	topo_hdl_unlock(thp);
1927aec1d6eScindi }
1937aec1d6eScindi 
1947aec1d6eScindi void
195*0eb822a1Scindi topo_vdprintf(topo_hdl_t *thp, int mask, const char *mod, const char *format,
196*0eb822a1Scindi     va_list ap)
1977aec1d6eScindi {
1987aec1d6eScindi 	char *msg;
1997aec1d6eScindi 	size_t len;
2007aec1d6eScindi 	char c;
2017aec1d6eScindi 
202*0eb822a1Scindi 	if (!(thp->th_debug & mask))
2037aec1d6eScindi 		return;
2047aec1d6eScindi 
2057aec1d6eScindi 	len = vsnprintf(&c, 1, format, ap);
2067aec1d6eScindi 	msg = alloca(len + 2);
2077aec1d6eScindi 	(void) vsnprintf(msg, len + 1, format, ap);
2087aec1d6eScindi 
2097aec1d6eScindi 	if (msg[len - 1] != '\n')
2107aec1d6eScindi 		(void) strcpy(&msg[len], "\n");
2117aec1d6eScindi 
212*0eb822a1Scindi 	if (thp->th_dbout == TOPO_DBOUT_SYSLOG) {
213*0eb822a1Scindi 		if (mod == NULL) {
214*0eb822a1Scindi 			syslog(LOG_DEBUG | LOG_USER, "libtopo DEBUG: %s", msg);
215*0eb822a1Scindi 		} else {
216*0eb822a1Scindi 			syslog(LOG_DEBUG | LOG_USER, "libtopo DEBUG: %s: %s",
217*0eb822a1Scindi 			    mod, msg);
218*0eb822a1Scindi 		}
219*0eb822a1Scindi 	} else {
220*0eb822a1Scindi 		if (mod == NULL) {
221*0eb822a1Scindi 			(void) fprintf(stderr, "libtopo DEBUG: %s", msg);
222*0eb822a1Scindi 		} else {
223*0eb822a1Scindi 			(void) fprintf(stderr, "libtopo DEBUG: %s: %s", mod,
224*0eb822a1Scindi 			    msg);
225*0eb822a1Scindi 		}
226*0eb822a1Scindi 	}
2277aec1d6eScindi }
2287aec1d6eScindi 
229*0eb822a1Scindi /*PRINTFLIKE3*/
2307aec1d6eScindi void
231*0eb822a1Scindi topo_dprintf(topo_hdl_t *thp, int mask, const char *format, ...)
2327aec1d6eScindi {
2337aec1d6eScindi 	va_list ap;
2347aec1d6eScindi 
2357aec1d6eScindi 	va_start(ap, format);
236*0eb822a1Scindi 	topo_vdprintf(thp, mask, NULL, format, ap);
2377aec1d6eScindi 	va_end(ap);
2387aec1d6eScindi }
2397aec1d6eScindi 
2407aec1d6eScindi tnode_t *
2417aec1d6eScindi topo_hdl_root(topo_hdl_t *thp, const char *scheme)
2427aec1d6eScindi {
2437aec1d6eScindi 	ttree_t *tp;
2447aec1d6eScindi 
2457aec1d6eScindi 	for (tp = topo_list_next(&thp->th_trees); tp != NULL;
2467aec1d6eScindi 	    tp = topo_list_next(tp)) {
2477aec1d6eScindi 		if (strcmp(scheme, tp->tt_scheme) == 0)
2487aec1d6eScindi 			return (tp->tt_root);
2497aec1d6eScindi 	}
2507aec1d6eScindi 
2517aec1d6eScindi 	return (NULL);
2527aec1d6eScindi }
25374a31ce6Stimh 
25474a31ce6Stimh /*
25574a31ce6Stimh  * buf_append -- Append str to buf (if it's non-NULL).  Place prepend
25674a31ce6Stimh  * in buf in front of str and append behind it (if they're non-NULL).
25774a31ce6Stimh  * Continue to update size even if we run out of space to actually
25874a31ce6Stimh  * stuff characters in the buffer.
25974a31ce6Stimh  */
26074a31ce6Stimh void
26174a31ce6Stimh topo_fmristr_build(ssize_t *sz, char *buf, size_t buflen, char *str,
26274a31ce6Stimh     char *prepend, char *append)
26374a31ce6Stimh {
26474a31ce6Stimh 	ssize_t left;
26574a31ce6Stimh 
26674a31ce6Stimh 	if (str == NULL)
26774a31ce6Stimh 		return;
26874a31ce6Stimh 
26974a31ce6Stimh 	if (buflen == 0 || (left = buflen - *sz) < 0)
27074a31ce6Stimh 		left = 0;
27174a31ce6Stimh 
27274a31ce6Stimh 	if (buf != NULL && left != 0)
27374a31ce6Stimh 		buf += *sz;
27474a31ce6Stimh 
27574a31ce6Stimh 	if (prepend == NULL && append == NULL)
27674a31ce6Stimh 		*sz += snprintf(buf, left, "%s", str);
27774a31ce6Stimh 	else if (append == NULL)
27874a31ce6Stimh 		*sz += snprintf(buf, left, "%s%s", prepend, str);
27974a31ce6Stimh 	else if (prepend == NULL)
28074a31ce6Stimh 		*sz += snprintf(buf, left, "%s%s", str, append);
28174a31ce6Stimh 	else
28274a31ce6Stimh 		*sz += snprintf(buf, left, "%s%s%s", prepend, str, append);
28374a31ce6Stimh }
284*0eb822a1Scindi 
285*0eb822a1Scindi #define	TOPO_PLATFORM_PATH	"%s/usr/platform/%s/lib/fm/topo/%s"
286*0eb822a1Scindi #define	TOPO_COMMON_PATH	"%s/usr/lib/fm/topo/%s"
287*0eb822a1Scindi 
288*0eb822a1Scindi char *
289*0eb822a1Scindi topo_search_path(topo_mod_t *mod, const char *rootdir, const char *file)
290*0eb822a1Scindi {
291*0eb822a1Scindi 	char *pp, sp[PATH_MAX];
292*0eb822a1Scindi 	topo_hdl_t *thp = mod->tm_hdl;
293*0eb822a1Scindi 
294*0eb822a1Scindi 	/*
295*0eb822a1Scindi 	 * Search for file name in order of platform, machine and common
296*0eb822a1Scindi 	 * topo directories
297*0eb822a1Scindi 	 */
298*0eb822a1Scindi 	(void) snprintf(sp, PATH_MAX, TOPO_PLATFORM_PATH, rootdir,
299*0eb822a1Scindi 	    thp->th_platform, file);
300*0eb822a1Scindi 	if (access(sp, F_OK) != 0) {
301*0eb822a1Scindi 		(void) snprintf(sp, PATH_MAX, TOPO_PLATFORM_PATH,
302*0eb822a1Scindi 		    thp->th_rootdir, thp->th_machine, file);
303*0eb822a1Scindi 		if (access(sp, F_OK) != 0) {
304*0eb822a1Scindi 			(void) snprintf(sp, PATH_MAX, TOPO_COMMON_PATH,
305*0eb822a1Scindi 			    thp->th_rootdir, file);
306*0eb822a1Scindi 			if (access(sp, F_OK) != 0) {
307*0eb822a1Scindi 				return (NULL);
308*0eb822a1Scindi 			}
309*0eb822a1Scindi 		}
310*0eb822a1Scindi 	}
311*0eb822a1Scindi 
312*0eb822a1Scindi 	pp = topo_mod_strdup(mod, sp);
313*0eb822a1Scindi 
314*0eb822a1Scindi 	return (pp);
315*0eb822a1Scindi }
316