xref: /titanic_52/usr/src/cmd/fm/modules/common/eversholt/config.c (revision e58a33b62cd4c9a6815fd752ce58b5f389289da1)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5b6c60aa3Stimh  * Common Development and Distribution License (the "License").
6b6c60aa3Stimh  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21b6c60aa3Stimh 
227c478bd9Sstevel@tonic-gate /*
2344ed9dbbSStephen Hanson  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24b6c60aa3Stimh  */
25b6c60aa3Stimh 
26b6c60aa3Stimh /*
277c478bd9Sstevel@tonic-gate  * config.c -- system configuration cache module
287c478bd9Sstevel@tonic-gate  *
297c478bd9Sstevel@tonic-gate  * this module caches the system configuration in a format useful
307c478bd9Sstevel@tonic-gate  * to eft.  the information is loaded into this module by
317c478bd9Sstevel@tonic-gate  * config_snapshot() at the beginning of each FME.  config_snapshot()
327c478bd9Sstevel@tonic-gate  * calls the platform-specific platform_config_snapshot() to get
337c478bd9Sstevel@tonic-gate  * the configuration information loaded up.
347c478bd9Sstevel@tonic-gate  */
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate #include <stdio.h>
377c478bd9Sstevel@tonic-gate #include <stdlib.h>
387c478bd9Sstevel@tonic-gate #include <ctype.h>
397c478bd9Sstevel@tonic-gate #include <string.h>
407c478bd9Sstevel@tonic-gate #include <strings.h>
410eb822a1Scindi #include <fm/topo_hc.h>
427c478bd9Sstevel@tonic-gate #include "alloc.h"
437c478bd9Sstevel@tonic-gate #include "out.h"
447c478bd9Sstevel@tonic-gate #include "literals.h"
457c478bd9Sstevel@tonic-gate #include "stable.h"
467c478bd9Sstevel@tonic-gate #include "lut.h"
477c478bd9Sstevel@tonic-gate #include "tree.h"
487c478bd9Sstevel@tonic-gate #include "itree.h"
497c478bd9Sstevel@tonic-gate #include "ipath.h"
507c478bd9Sstevel@tonic-gate #include "ptree.h"
517c478bd9Sstevel@tonic-gate #include "eval.h"
527c478bd9Sstevel@tonic-gate #include "config.h"
536cb1ca52Saf #include "config_impl.h"
547c478bd9Sstevel@tonic-gate #include "fme.h"
557c478bd9Sstevel@tonic-gate #include "platform.h"
567c478bd9Sstevel@tonic-gate 
57b5016cbbSstephh static const char *config_lastcomp;
58b5016cbbSstephh 
597c478bd9Sstevel@tonic-gate /*
607c478bd9Sstevel@tonic-gate  * newcnode -- local function to allocate new config node
617c478bd9Sstevel@tonic-gate  */
627c478bd9Sstevel@tonic-gate static struct config *
637c478bd9Sstevel@tonic-gate newcnode(const char *s, int num)
647c478bd9Sstevel@tonic-gate {
657c478bd9Sstevel@tonic-gate 	struct config *retval;
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate 	retval = MALLOC(sizeof (struct config));
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate 	retval->s = s;
707c478bd9Sstevel@tonic-gate 	retval->num = num;
717c478bd9Sstevel@tonic-gate 	retval->next = NULL;
727c478bd9Sstevel@tonic-gate 	retval->props = NULL;
737c478bd9Sstevel@tonic-gate 	retval->child = retval->parent = NULL;
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate 	return (retval);
767c478bd9Sstevel@tonic-gate }
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate /*
797c478bd9Sstevel@tonic-gate  * If we need to cache certain types of nodes for reverse look-up or
807c478bd9Sstevel@tonic-gate  * somesuch, do it here.  Currently we need to cache nodes representing
817c478bd9Sstevel@tonic-gate  * cpus.
827c478bd9Sstevel@tonic-gate  */
837c478bd9Sstevel@tonic-gate static void
847c478bd9Sstevel@tonic-gate config_node_cache(struct cfgdata *cdata, struct config *n)
857c478bd9Sstevel@tonic-gate {
867c478bd9Sstevel@tonic-gate 	if (n->s != stable("cpu"))
877c478bd9Sstevel@tonic-gate 		return;
887c478bd9Sstevel@tonic-gate 	cdata->cpucache = lut_add(cdata->cpucache,
897c478bd9Sstevel@tonic-gate 	    (void *)n->num, (void *)n, NULL);
907c478bd9Sstevel@tonic-gate }
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate /*
937c478bd9Sstevel@tonic-gate  * config_lookup -- lookup/add components in configuration cache
947c478bd9Sstevel@tonic-gate  */
957c478bd9Sstevel@tonic-gate struct config *
967c478bd9Sstevel@tonic-gate config_lookup(struct config *croot, char *path, int add)
977c478bd9Sstevel@tonic-gate {
987c478bd9Sstevel@tonic-gate 	char *pathbegin = path;
997c478bd9Sstevel@tonic-gate 	struct config *parent = croot;
1007c478bd9Sstevel@tonic-gate 	struct config *cp;
1017c478bd9Sstevel@tonic-gate 	struct config *lastcp;
1027c478bd9Sstevel@tonic-gate 	struct config *newnode;
1037c478bd9Sstevel@tonic-gate 	char *thiscom;	/* this component */
1047c478bd9Sstevel@tonic-gate 	char *nextcom;	/* next component */
1057c478bd9Sstevel@tonic-gate 	char svdigit;
1067c478bd9Sstevel@tonic-gate 	int len;
1077c478bd9Sstevel@tonic-gate 	int num;
1087c478bd9Sstevel@tonic-gate 	const char *s;
1097c478bd9Sstevel@tonic-gate 	int exists;
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 	if (parent == NULL)
1127c478bd9Sstevel@tonic-gate 		out(O_DIE, "uninitialized configuration");
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate 	while (*path) {
1157c478bd9Sstevel@tonic-gate 		if ((nextcom = strchr(path, '/')) != NULL)
1167c478bd9Sstevel@tonic-gate 			*nextcom = '\0';
1177c478bd9Sstevel@tonic-gate 		if ((len = strlen(path)) == 0)
1187c478bd9Sstevel@tonic-gate 			out(O_DIE, "config_lookup: zero length component");
1197c478bd9Sstevel@tonic-gate 		/* start at end of string and work backwards */
1207c478bd9Sstevel@tonic-gate 		thiscom = &path[len - 1];
1217c478bd9Sstevel@tonic-gate 		if (!isdigit(*thiscom))
1227c478bd9Sstevel@tonic-gate 			out(O_DIE, "config_lookup: "
1237c478bd9Sstevel@tonic-gate 			    "component \"%s\" has no number following it",
1247c478bd9Sstevel@tonic-gate 			    path);
1257c478bd9Sstevel@tonic-gate 		while (thiscom > path && isdigit(*thiscom))
1267c478bd9Sstevel@tonic-gate 			thiscom--;
1277c478bd9Sstevel@tonic-gate 		if (thiscom == path && isdigit(*thiscom))
1287c478bd9Sstevel@tonic-gate 			out(O_DIE, "config_lookup: "
1297c478bd9Sstevel@tonic-gate 			    "component \"%s\" has no name part", path);
1307c478bd9Sstevel@tonic-gate 		thiscom++;	/* move to first numeric character */
1317c478bd9Sstevel@tonic-gate 		num = atoi(thiscom);
1327c478bd9Sstevel@tonic-gate 		svdigit = *thiscom;
1337c478bd9Sstevel@tonic-gate 		*thiscom = '\0';
1347c478bd9Sstevel@tonic-gate 		s = stable(path);
135b5016cbbSstephh 		if (add)
136b5016cbbSstephh 			config_lastcomp = s;
1377c478bd9Sstevel@tonic-gate 		*thiscom = svdigit;
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 		if (nextcom != NULL)
1407c478bd9Sstevel@tonic-gate 			*nextcom++ = '/';
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 		/* now we have s & num, figure out if it exists already */
1437c478bd9Sstevel@tonic-gate 		exists = 0;
1447c478bd9Sstevel@tonic-gate 		lastcp = NULL;
1457c478bd9Sstevel@tonic-gate 		for (cp = parent->child; cp; lastcp = cp, cp = cp->next)
1467c478bd9Sstevel@tonic-gate 			if (cp->s == s && cp->num == num) {
1477c478bd9Sstevel@tonic-gate 				exists = 1;
1487c478bd9Sstevel@tonic-gate 				parent = cp;
1497c478bd9Sstevel@tonic-gate 			}
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 		if (!exists) {
1527c478bd9Sstevel@tonic-gate 			/* creating new node */
1537c478bd9Sstevel@tonic-gate 			if (!add) {
1547c478bd9Sstevel@tonic-gate 				/*
1557c478bd9Sstevel@tonic-gate 				 * indicate component not found by copying
1567c478bd9Sstevel@tonic-gate 				 * it to path (allows better error messages
1577c478bd9Sstevel@tonic-gate 				 * in the caller).
1587c478bd9Sstevel@tonic-gate 				 */
1597c478bd9Sstevel@tonic-gate 				(void) strcpy(pathbegin, s);
1607c478bd9Sstevel@tonic-gate 				return (NULL);
1617c478bd9Sstevel@tonic-gate 			}
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 			newnode = newcnode(s, num);
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 			if (lastcp)
1667c478bd9Sstevel@tonic-gate 				lastcp->next = newnode;
1677c478bd9Sstevel@tonic-gate 			else
1687c478bd9Sstevel@tonic-gate 				parent->child = newnode;
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 			newnode->parent = parent;
1717c478bd9Sstevel@tonic-gate 			parent = newnode;
1727c478bd9Sstevel@tonic-gate 		}
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 		if (nextcom == NULL)
1757c478bd9Sstevel@tonic-gate 			return (parent);	/* all done */
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 		/* move on to next component */
1787c478bd9Sstevel@tonic-gate 		path = nextcom;
1797c478bd9Sstevel@tonic-gate 	}
1807c478bd9Sstevel@tonic-gate 	return (parent);
1817c478bd9Sstevel@tonic-gate }
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate /*
1847c478bd9Sstevel@tonic-gate  * addconfigprop -- add a config prop to a config cache entry
1857c478bd9Sstevel@tonic-gate  */
1867c478bd9Sstevel@tonic-gate static void
1877c478bd9Sstevel@tonic-gate addconfigprop(const char *lhs, struct node *rhs, void *arg)
1887c478bd9Sstevel@tonic-gate {
1897c478bd9Sstevel@tonic-gate 	struct config *cp = (struct config *)arg;
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	ASSERT(cp != NULL);
1927c478bd9Sstevel@tonic-gate 	ASSERT(lhs != NULL);
1937c478bd9Sstevel@tonic-gate 	ASSERT(rhs != NULL);
1947c478bd9Sstevel@tonic-gate 	ASSERT(rhs->t == T_QUOTE);
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 	config_setprop(cp, lhs, STRDUP(rhs->u.quote.s));
1977c478bd9Sstevel@tonic-gate }
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate /*
2007c478bd9Sstevel@tonic-gate  * addconfig -- add a config from parse tree to given configuration cache
2017c478bd9Sstevel@tonic-gate  */
2027c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2037c478bd9Sstevel@tonic-gate static void
2047c478bd9Sstevel@tonic-gate addconfig(struct node *lhs, struct node *rhs, void *arg)
2057c478bd9Sstevel@tonic-gate {
2067c478bd9Sstevel@tonic-gate 	struct config *parent = (struct config *)arg;
2077c478bd9Sstevel@tonic-gate 	struct config *cp;
2087c478bd9Sstevel@tonic-gate 	const char *s;
2097c478bd9Sstevel@tonic-gate 	int num;
2107c478bd9Sstevel@tonic-gate 	struct config *lastcp;
2117c478bd9Sstevel@tonic-gate 	struct config *newnode;
2127c478bd9Sstevel@tonic-gate 	int exists;
2137c478bd9Sstevel@tonic-gate 	struct lut *lutp;
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 	ASSERT(rhs->t == T_CONFIG);
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	lutp = rhs->u.stmt.lutp;
2187c478bd9Sstevel@tonic-gate 	rhs = rhs->u.stmt.np;
2197c478bd9Sstevel@tonic-gate 	while (rhs != NULL) {
2207c478bd9Sstevel@tonic-gate 		ASSERT(rhs->t == T_NAME);
2217c478bd9Sstevel@tonic-gate 		ASSERT(rhs->u.name.child->t == T_NUM);
2227c478bd9Sstevel@tonic-gate 		s = rhs->u.name.s;
2237c478bd9Sstevel@tonic-gate 		num = rhs->u.name.child->u.ull;
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 		/* now we have s & num, figure out if it exists already */
2267c478bd9Sstevel@tonic-gate 		exists = 0;
2277c478bd9Sstevel@tonic-gate 		lastcp = NULL;
2287c478bd9Sstevel@tonic-gate 		for (cp = parent->child; cp; lastcp = cp, cp = cp->next)
2297c478bd9Sstevel@tonic-gate 			if (cp->s == s && cp->num == num) {
2307c478bd9Sstevel@tonic-gate 				exists = 1;
2317c478bd9Sstevel@tonic-gate 				parent = cp;
2327c478bd9Sstevel@tonic-gate 			}
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 		if (!exists) {
2357c478bd9Sstevel@tonic-gate 			/* creating new node */
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 			newnode = newcnode(s, num);
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 			if (lastcp)
2407c478bd9Sstevel@tonic-gate 				lastcp->next = newnode;
2417c478bd9Sstevel@tonic-gate 			else
2427c478bd9Sstevel@tonic-gate 				parent->child = newnode;
2437c478bd9Sstevel@tonic-gate 
244b5016cbbSstephh 			newnode->parent = parent;
2457c478bd9Sstevel@tonic-gate 			parent = newnode;
2467c478bd9Sstevel@tonic-gate 		}
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 		/* move on to next component */
2497c478bd9Sstevel@tonic-gate 		rhs = rhs->u.name.next;
2507c478bd9Sstevel@tonic-gate 	}
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	/* add configuration properties */
2537c478bd9Sstevel@tonic-gate 	lut_walk(lutp, (lut_cb)addconfigprop, (void *)parent);
2547c478bd9Sstevel@tonic-gate }
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate /*
2577c478bd9Sstevel@tonic-gate  * config_cook -- convert raw config strings to eft internal representation
2587c478bd9Sstevel@tonic-gate  */
2597c478bd9Sstevel@tonic-gate void
2607c478bd9Sstevel@tonic-gate config_cook(struct cfgdata *cdata)
2617c478bd9Sstevel@tonic-gate {
2627c478bd9Sstevel@tonic-gate 	struct config *newnode;
2637c478bd9Sstevel@tonic-gate 	char *cfgstr, *equals;
2647c478bd9Sstevel@tonic-gate 	const char *pn, *sv;
2657c478bd9Sstevel@tonic-gate 	char *pv;
266b5016cbbSstephh 	const char *ptr;
267b5016cbbSstephh 	extern struct lut *Usedprops;
268b5016cbbSstephh 	extern struct lut *Usednames;
269b5016cbbSstephh 
2707c478bd9Sstevel@tonic-gate 	cdata->cooked = newcnode(NULL, 0);
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	if ((cfgstr = cdata->begin) == cdata->nextfree) {
2737c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, "Platform provided no config data.");
2747c478bd9Sstevel@tonic-gate 		goto eftcfgs;
2757c478bd9Sstevel@tonic-gate 	}
2767c478bd9Sstevel@tonic-gate 
277b5016cbbSstephh 	/*
278b5016cbbSstephh 	 * add the following properties to the "usedprops" table as they
279b5016cbbSstephh 	 * are used internally by eft
280b5016cbbSstephh 	 */
281b5016cbbSstephh 	ptr = stable("module");
282b5016cbbSstephh 	Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL);
283b5016cbbSstephh 	ptr = stable("resource");
284b5016cbbSstephh 	Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL);
285b0daa853SStephen Hanson 	ptr = stable("serial");
286b0daa853SStephen Hanson 	Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL);
287b5016cbbSstephh 
2887c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB3, "Raw config data follows:");
2897c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB3|O_NONL,
2907c478bd9Sstevel@tonic-gate 	    "nextfree is %p\n%p ", (void *)cdata->nextfree, (void *)cfgstr);
2917c478bd9Sstevel@tonic-gate 	while (cfgstr < cdata->nextfree) {
2927c478bd9Sstevel@tonic-gate 		if (!*cfgstr)
2937c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_VERB3|O_NONL, "\n%p ",
2947c478bd9Sstevel@tonic-gate 			    (void *)(cfgstr + 1));
2957c478bd9Sstevel@tonic-gate 		else
2967c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_VERB3|O_NONL, "%c", *cfgstr);
2977c478bd9Sstevel@tonic-gate 		cfgstr++;
2987c478bd9Sstevel@tonic-gate 	}
2997c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB3, NULL);
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	cfgstr = cdata->begin;
3027c478bd9Sstevel@tonic-gate 	while (cfgstr < cdata->nextfree) {
3037c478bd9Sstevel@tonic-gate 		while (*cfgstr == '/' && cfgstr < cdata->nextfree) {
3047c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_VERB3,
3057c478bd9Sstevel@tonic-gate 			    "next string (%p) is %s", (void *)cfgstr, cfgstr);
3067c478bd9Sstevel@tonic-gate 			/* skip the initial slash from libtopo */
3077c478bd9Sstevel@tonic-gate 			newnode = config_lookup(cdata->cooked, cfgstr + 1, 1);
3087c478bd9Sstevel@tonic-gate 			/*
3097c478bd9Sstevel@tonic-gate 			 * Note we'll only cache nodes that have
3107c478bd9Sstevel@tonic-gate 			 * properties on them.  Intermediate nodes
3117c478bd9Sstevel@tonic-gate 			 * will have been added to the config tree,
3127c478bd9Sstevel@tonic-gate 			 * but we don't have easy means of accessing
3137c478bd9Sstevel@tonic-gate 			 * them except if we climb the tree from this
3147c478bd9Sstevel@tonic-gate 			 * newnode to the root.
3157c478bd9Sstevel@tonic-gate 			 *
3167c478bd9Sstevel@tonic-gate 			 * Luckily, the nodes we care to cache
3177c478bd9Sstevel@tonic-gate 			 * (currently just cpus) always have some
3187c478bd9Sstevel@tonic-gate 			 * properties attached to them
3197c478bd9Sstevel@tonic-gate 			 * so we don't bother climbing the tree.
3207c478bd9Sstevel@tonic-gate 			 */
3217c478bd9Sstevel@tonic-gate 			config_node_cache(cdata, newnode);
3227c478bd9Sstevel@tonic-gate 			cfgstr += strlen(cfgstr) + 1;
3237c478bd9Sstevel@tonic-gate 		}
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 		if (cfgstr >= cdata->nextfree)
3267c478bd9Sstevel@tonic-gate 			break;
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB3, "next string (%p) is %s", (void *)cfgstr,
3297c478bd9Sstevel@tonic-gate 		    cfgstr);
3307c478bd9Sstevel@tonic-gate 		if ((equals = strchr(cfgstr, '=')) == NULL) {
3317c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_VERB3, "raw config data bad (%p); "
3327c478bd9Sstevel@tonic-gate 			    "property missing equals.\n", (void *)cfgstr);
3337c478bd9Sstevel@tonic-gate 			break;
3347c478bd9Sstevel@tonic-gate 		}
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 		*equals = '\0';
3377c478bd9Sstevel@tonic-gate 		pn = stable(cfgstr);
3387c478bd9Sstevel@tonic-gate 
339b5016cbbSstephh 		/*
340b5016cbbSstephh 		 * only actually add the props if the rules use them (saves
341b5016cbbSstephh 		 * memory)
342b5016cbbSstephh 		 */
343e5ba14ffSstephh 		if ((lut_lookup(Usedprops, (void *)pn, NULL) != NULL ||
344e5ba14ffSstephh 		    strncmp(pn, "serd_", 5) == 0) && lut_lookup(Usednames,
345e5ba14ffSstephh 		    (void *)config_lastcomp, NULL) != NULL) {
346b5016cbbSstephh 			pv = STRDUP(equals + 1);
347b5016cbbSstephh 			out(O_ALTFP|O_VERB3, "add prop (%s) val %p", pn,
348b5016cbbSstephh 			    (void *)pv);
3497c478bd9Sstevel@tonic-gate 			config_setprop(newnode, pn, pv);
350b5016cbbSstephh 		}
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 		/*
35344ed9dbbSStephen Hanson 		 * If this property is a device path, tp or devid, cache it
354602ca9eaScth 		 * for quick lookup.
3557c478bd9Sstevel@tonic-gate 		 */
356*e58a33b6SStephen Hanson 		if (config_lastcomp == stable(SCSI_DEVICE) ||
357*e58a33b6SStephen Hanson 		    config_lastcomp == stable(SMP_DEVICE)) {
358*e58a33b6SStephen Hanson 			/*
359*e58a33b6SStephen Hanson 			 * we can't get ereports on SCSI_DEVICE or SMP_DEVICE
360*e58a33b6SStephen Hanson 			 * nodes, so don't cache.
361*e58a33b6SStephen Hanson 			 */
362*e58a33b6SStephen Hanson 			out(O_ALTFP|O_VERB3, "not caching %s for %s",
363*e58a33b6SStephen Hanson 			    pn, config_lastcomp);
364*e58a33b6SStephen Hanson 		} else if (pn == stable(TOPO_IO_DEV)) {
365b5016cbbSstephh 			sv = stable(equals + 1);
36644ed9dbbSStephen Hanson 			out(O_ALTFP|O_VERB3, "caching dev %s", sv);
3677c478bd9Sstevel@tonic-gate 			cdata->devcache = lut_add(cdata->devcache,
3687c478bd9Sstevel@tonic-gate 			    (void *)sv, (void *)newnode, NULL);
369*e58a33b6SStephen Hanson 		} else if (pn == stable(TOPO_IO_DEVID) ||
370*e58a33b6SStephen Hanson 		    pn == stable(TOPO_PROP_SES_DEVID) ||
371*e58a33b6SStephen Hanson 		    pn == stable(TOPO_PROP_SMP_DEVID)) {
372602ca9eaScth 			sv = stable(equals + 1);
37344ed9dbbSStephen Hanson 			out(O_ALTFP|O_VERB3, "caching devid %s", sv);
374602ca9eaScth 			cdata->devidcache = lut_add(cdata->devidcache,
375602ca9eaScth 			    (void *)sv, (void *)newnode, NULL);
37644ed9dbbSStephen Hanson 		} else if (pn == stable(TOPO_STORAGE_TARGET_PORT_L0IDS)) {
37744ed9dbbSStephen Hanson 			/*
37844ed9dbbSStephen Hanson 			 * This was stored as a set of space-separated strings.
37944ed9dbbSStephen Hanson 			 * Find each string in turn and add to the lut. Then if
38044ed9dbbSStephen Hanson 			 * a ereport comes in with a target-path matching any
38144ed9dbbSStephen Hanson 			 * of the strings we will match it.
38244ed9dbbSStephen Hanson 			 */
38344ed9dbbSStephen Hanson 			char *x, *y = equals;
38444ed9dbbSStephen Hanson 			while (y != NULL) {
38544ed9dbbSStephen Hanson 				x = y + 1;
38644ed9dbbSStephen Hanson 				y = strchr(x, ' ');
38744ed9dbbSStephen Hanson 				if (y != NULL)
38844ed9dbbSStephen Hanson 					*y = '\0';
38944ed9dbbSStephen Hanson 				sv = stable(x);
39044ed9dbbSStephen Hanson 				out(O_ALTFP|O_VERB3, "caching tp %s", sv);
39144ed9dbbSStephen Hanson 				cdata->tpcache = lut_add(cdata->tpcache,
39244ed9dbbSStephen Hanson 				    (void *)sv, (void *)newnode, NULL);
39344ed9dbbSStephen Hanson 				if (y != NULL)
39444ed9dbbSStephen Hanson 					*y = ' ';
39544ed9dbbSStephen Hanson 			}
3967c478bd9Sstevel@tonic-gate 		}
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 		*equals = '=';
3997c478bd9Sstevel@tonic-gate 		cfgstr += strlen(cfgstr) + 1;
4007c478bd9Sstevel@tonic-gate 	}
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate eftcfgs:
4037c478bd9Sstevel@tonic-gate 	/* now run through Configs table, adding to config cache */
4047c478bd9Sstevel@tonic-gate 	lut_walk(Configs, (lut_cb)addconfig, (void *)cdata->cooked);
4057c478bd9Sstevel@tonic-gate }
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate /*
4087c478bd9Sstevel@tonic-gate  * config_snapshot -- gather a snapshot of the current configuration
4097c478bd9Sstevel@tonic-gate  */
4107c478bd9Sstevel@tonic-gate struct cfgdata *
4117c478bd9Sstevel@tonic-gate config_snapshot(void)
4127c478bd9Sstevel@tonic-gate {
4137c478bd9Sstevel@tonic-gate 	struct cfgdata *rawcfg;
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	rawcfg = platform_config_snapshot();
4167c478bd9Sstevel@tonic-gate 	config_cook(rawcfg);
4177c478bd9Sstevel@tonic-gate 	return (rawcfg);
4187c478bd9Sstevel@tonic-gate }
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate /*
4217c478bd9Sstevel@tonic-gate  * prop_destructor -- free a prop value
4227c478bd9Sstevel@tonic-gate  */
4237c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4247c478bd9Sstevel@tonic-gate static void
4257c478bd9Sstevel@tonic-gate prop_destructor(void *left, void *right, void *arg)
4267c478bd9Sstevel@tonic-gate {
4277c478bd9Sstevel@tonic-gate 	FREE(right);
4287c478bd9Sstevel@tonic-gate }
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate /*
4317c478bd9Sstevel@tonic-gate  * structconfig_free -- free a struct config pointer and all its relatives
4327c478bd9Sstevel@tonic-gate  */
433e5ba14ffSstephh void
4347c478bd9Sstevel@tonic-gate structconfig_free(struct config *cp)
4357c478bd9Sstevel@tonic-gate {
4367c478bd9Sstevel@tonic-gate 	if (cp == NULL)
4377c478bd9Sstevel@tonic-gate 		return;
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	structconfig_free(cp->child);
4407c478bd9Sstevel@tonic-gate 	structconfig_free(cp->next);
4417c478bd9Sstevel@tonic-gate 	lut_free(cp->props, prop_destructor, NULL);
4427c478bd9Sstevel@tonic-gate 	FREE(cp);
4437c478bd9Sstevel@tonic-gate }
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate /*
4467c478bd9Sstevel@tonic-gate  * config_free -- free a configuration snapshot
4477c478bd9Sstevel@tonic-gate  */
4487c478bd9Sstevel@tonic-gate void
4497c478bd9Sstevel@tonic-gate config_free(struct cfgdata *cp)
4507c478bd9Sstevel@tonic-gate {
4517c478bd9Sstevel@tonic-gate 	if (cp == NULL)
4527c478bd9Sstevel@tonic-gate 		return;
4537c478bd9Sstevel@tonic-gate 
454e5ba14ffSstephh 	if (--cp->raw_refcnt == 0) {
4557c478bd9Sstevel@tonic-gate 		if (cp->devcache != NULL)
4567c478bd9Sstevel@tonic-gate 			lut_free(cp->devcache, NULL, NULL);
457b5016cbbSstephh 		cp->devcache = NULL;
45844ed9dbbSStephen Hanson 		if (cp->tpcache != NULL)
45944ed9dbbSStephen Hanson 			lut_free(cp->tpcache, NULL, NULL);
46044ed9dbbSStephen Hanson 		cp->tpcache = NULL;
461602ca9eaScth 		if (cp->devidcache != NULL)
462602ca9eaScth 			lut_free(cp->devidcache, NULL, NULL);
463602ca9eaScth 		cp->devidcache = NULL;
4647c478bd9Sstevel@tonic-gate 		if (cp->cpucache != NULL)
4657c478bd9Sstevel@tonic-gate 			lut_free(cp->cpucache, NULL, NULL);
466b5016cbbSstephh 		cp->cpucache = NULL;
467b5016cbbSstephh 		if (cp->begin != NULL)
468b5016cbbSstephh 			FREE(cp->begin);
4697c478bd9Sstevel@tonic-gate 		FREE(cp);
4707c478bd9Sstevel@tonic-gate 	}
471b5016cbbSstephh }
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate /*
4747c478bd9Sstevel@tonic-gate  * config_next -- get the "next" config node
4757c478bd9Sstevel@tonic-gate  */
4767c478bd9Sstevel@tonic-gate struct config *
4777c478bd9Sstevel@tonic-gate config_next(struct config *cp)
4787c478bd9Sstevel@tonic-gate {
4797c478bd9Sstevel@tonic-gate 	ASSERT(cp != NULL);
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	return ((struct config *)((struct config *)cp)->next);
4827c478bd9Sstevel@tonic-gate }
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate /*
4867c478bd9Sstevel@tonic-gate  * config_child -- get the "child" of a config node
4877c478bd9Sstevel@tonic-gate  */
4887c478bd9Sstevel@tonic-gate struct config *
4897c478bd9Sstevel@tonic-gate config_child(struct config *cp)
4907c478bd9Sstevel@tonic-gate {
4917c478bd9Sstevel@tonic-gate 	ASSERT(cp != NULL);
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	return ((struct config *)((struct config *)cp)->child);
4947c478bd9Sstevel@tonic-gate }
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate /*
497b5016cbbSstephh  * config_parent -- get the "parent" of a config node
498b5016cbbSstephh  */
499b5016cbbSstephh struct config *
500b5016cbbSstephh config_parent(struct config *cp)
501b5016cbbSstephh {
502b5016cbbSstephh 	ASSERT(cp != NULL);
503b5016cbbSstephh 
504b5016cbbSstephh 	return ((struct config *)((struct config *)cp)->parent);
505b5016cbbSstephh }
506b5016cbbSstephh 
507b5016cbbSstephh /*
5087c478bd9Sstevel@tonic-gate  * config_setprop -- add a property to a config node
5097c478bd9Sstevel@tonic-gate  */
5107c478bd9Sstevel@tonic-gate void
5117c478bd9Sstevel@tonic-gate config_setprop(struct config *cp, const char *propname, const char *propvalue)
5127c478bd9Sstevel@tonic-gate {
5137c478bd9Sstevel@tonic-gate 	const char *pn = stable(propname);
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 	cp->props = lut_add(cp->props, (void *)pn, (void *)propvalue, NULL);
5167c478bd9Sstevel@tonic-gate }
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate /*
5197c478bd9Sstevel@tonic-gate  * config_getprop -- lookup a config property
5207c478bd9Sstevel@tonic-gate  */
5217c478bd9Sstevel@tonic-gate const char *
5227c478bd9Sstevel@tonic-gate config_getprop(struct config *cp, const char *propname)
5237c478bd9Sstevel@tonic-gate {
5247c478bd9Sstevel@tonic-gate 	return (lut_lookup(cp->props, (void *) stable(propname), NULL));
5257c478bd9Sstevel@tonic-gate }
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate /*
5287c478bd9Sstevel@tonic-gate  * config_getcompname -- get the component name of a config node
5297c478bd9Sstevel@tonic-gate  */
5307c478bd9Sstevel@tonic-gate void
5317c478bd9Sstevel@tonic-gate config_getcompname(struct config *cp, char **name, int *inst)
5327c478bd9Sstevel@tonic-gate {
5337c478bd9Sstevel@tonic-gate 	ASSERT(cp != NULL);
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 	if (name != NULL)
5367c478bd9Sstevel@tonic-gate 		*name = (char *)cp->s;
5377c478bd9Sstevel@tonic-gate 	if (inst != NULL)
5387c478bd9Sstevel@tonic-gate 		*inst = cp->num;
5397c478bd9Sstevel@tonic-gate }
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate /*
5427c478bd9Sstevel@tonic-gate  * config_nodeize -- convert the config element represented by cp to struct
5437c478bd9Sstevel@tonic-gate  *		     node format
5447c478bd9Sstevel@tonic-gate  */
5457c478bd9Sstevel@tonic-gate static struct node *
5467c478bd9Sstevel@tonic-gate config_nodeize(struct config *cp)
5477c478bd9Sstevel@tonic-gate {
5487c478bd9Sstevel@tonic-gate 	struct node *tmpn, *ptmpn;
5497c478bd9Sstevel@tonic-gate 	struct node *numn;
5507c478bd9Sstevel@tonic-gate 	const char *sname;
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 	if (cp == NULL || cp->s == NULL)
5537c478bd9Sstevel@tonic-gate 		return (NULL);
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 	sname = stable(cp->s);
5567c478bd9Sstevel@tonic-gate 	numn = newnode(T_NUM, NULL, 0);
5577c478bd9Sstevel@tonic-gate 	numn->u.ull = cp->num;
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 	tmpn = tree_name_iterator(tree_name(sname, IT_VERTICAL, NULL, 0), numn);
5607c478bd9Sstevel@tonic-gate 	if ((ptmpn = config_nodeize(cp->parent)) == NULL)
5617c478bd9Sstevel@tonic-gate 		return (tmpn);
5627c478bd9Sstevel@tonic-gate 	return (tree_name_append(ptmpn, tmpn));
5637c478bd9Sstevel@tonic-gate }
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5667c478bd9Sstevel@tonic-gate static void
5677c478bd9Sstevel@tonic-gate prtdevcache(void *lhs, void *rhs, void *arg)
5687c478bd9Sstevel@tonic-gate {
5697c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB3, "%s -> %p", (char *)lhs, rhs);
5707c478bd9Sstevel@tonic-gate }
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5737c478bd9Sstevel@tonic-gate static void
574602ca9eaScth prtdevidcache(void *lhs, void *rhs, void *arg)
575602ca9eaScth {
576602ca9eaScth 	out(O_ALTFP|O_VERB3, "%s -> %p", (char *)lhs, rhs);
577602ca9eaScth }
578602ca9eaScth 
579602ca9eaScth /*ARGSUSED*/
580602ca9eaScth static void
58144ed9dbbSStephen Hanson prttpcache(void *lhs, void *rhs, void *arg)
58244ed9dbbSStephen Hanson {
58344ed9dbbSStephen Hanson 	out(O_ALTFP|O_VERB3, "%s -> %p", (char *)lhs, rhs);
58444ed9dbbSStephen Hanson }
58544ed9dbbSStephen Hanson 
58644ed9dbbSStephen Hanson /*ARGSUSED*/
58744ed9dbbSStephen Hanson static void
5887c478bd9Sstevel@tonic-gate prtcpucache(void *lhs, void *rhs, void *arg)
5897c478bd9Sstevel@tonic-gate {
5907c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, "%u -> %p", (uint32_t)lhs, rhs);
5917c478bd9Sstevel@tonic-gate }
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate /*
594602ca9eaScth  * config_bydev_lookup -- look up the path in our devcache lut.  If we find
5957c478bd9Sstevel@tonic-gate  * it return the config path, but as a struct node.
5967c478bd9Sstevel@tonic-gate  */
5977c478bd9Sstevel@tonic-gate struct node *
5987c478bd9Sstevel@tonic-gate config_bydev_lookup(struct cfgdata *fromcfg, const char *path)
5997c478bd9Sstevel@tonic-gate {
6007c478bd9Sstevel@tonic-gate 	struct config *find;
6017c478bd9Sstevel@tonic-gate 	struct node *np;
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB3, "Device path cache:");
6047c478bd9Sstevel@tonic-gate 	lut_walk(fromcfg->devcache, (lut_cb)prtdevcache, NULL);
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 	if ((find = lut_lookup(fromcfg->devcache,
6077c478bd9Sstevel@tonic-gate 	    (void *) stable(path), NULL)) == NULL)
6087c478bd9Sstevel@tonic-gate 		return (NULL);
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 	np = config_nodeize(find);
6117c478bd9Sstevel@tonic-gate 	if (np != NULL) {
6127c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, "Matching config entry:");
6137c478bd9Sstevel@tonic-gate 		ptree_name_iter(O_ALTFP|O_VERB|O_NONL, np);
6147c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
6157c478bd9Sstevel@tonic-gate 	}
6167c478bd9Sstevel@tonic-gate 	return (np);
6177c478bd9Sstevel@tonic-gate }
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate /*
620602ca9eaScth  * config_bydevid_lookup -- look up the path in our DEVIDcache lut.
621602ca9eaScth  * If we find it return the config path, but as a struct node.
622602ca9eaScth  */
623602ca9eaScth struct node *
624602ca9eaScth config_bydevid_lookup(struct cfgdata *fromcfg, const char *devid)
625602ca9eaScth {
626602ca9eaScth 	struct config *find;
627602ca9eaScth 	struct node *np;
628602ca9eaScth 
629602ca9eaScth 	out(O_ALTFP|O_VERB3, "Device id cache:");
630602ca9eaScth 	lut_walk(fromcfg->devcache, (lut_cb)prtdevidcache, NULL);
631602ca9eaScth 
632602ca9eaScth 	if ((find = lut_lookup(fromcfg->devidcache,
633602ca9eaScth 	    (void *) stable(devid), NULL)) == NULL)
634602ca9eaScth 		return (NULL);
635602ca9eaScth 
636602ca9eaScth 	np = config_nodeize(find);
637602ca9eaScth 	if (np != NULL) {
638602ca9eaScth 		out(O_ALTFP|O_VERB, "Matching config entry:");
639602ca9eaScth 		ptree_name_iter(O_ALTFP|O_VERB|O_NONL, np);
640602ca9eaScth 		out(O_ALTFP|O_VERB, NULL);
641602ca9eaScth 	}
642602ca9eaScth 	return (np);
643602ca9eaScth }
644602ca9eaScth 
645602ca9eaScth /*
64644ed9dbbSStephen Hanson  * config_bytp_lookup -- look up the path in our TPcache lut.
64744ed9dbbSStephen Hanson  * If we find it return the config path, but as a struct node.
64844ed9dbbSStephen Hanson  */
64944ed9dbbSStephen Hanson struct node *
65044ed9dbbSStephen Hanson config_bytp_lookup(struct cfgdata *fromcfg, const char *tp)
65144ed9dbbSStephen Hanson {
65244ed9dbbSStephen Hanson 	struct config *find;
65344ed9dbbSStephen Hanson 	struct node *np;
65444ed9dbbSStephen Hanson 
65544ed9dbbSStephen Hanson 	out(O_ALTFP|O_VERB3, "Device id cache:");
65644ed9dbbSStephen Hanson 	lut_walk(fromcfg->devcache, (lut_cb)prttpcache, NULL);
65744ed9dbbSStephen Hanson 
65844ed9dbbSStephen Hanson 	if ((find = lut_lookup(fromcfg->tpcache,
65944ed9dbbSStephen Hanson 	    (void *) stable(tp), NULL)) == NULL)
66044ed9dbbSStephen Hanson 		return (NULL);
66144ed9dbbSStephen Hanson 
66244ed9dbbSStephen Hanson 	np = config_nodeize(find);
66344ed9dbbSStephen Hanson 	if (np != NULL) {
66444ed9dbbSStephen Hanson 		out(O_ALTFP|O_VERB, "Matching config entry:");
66544ed9dbbSStephen Hanson 		ptree_name_iter(O_ALTFP|O_VERB|O_NONL, np);
66644ed9dbbSStephen Hanson 		out(O_ALTFP|O_VERB, NULL);
66744ed9dbbSStephen Hanson 	}
66844ed9dbbSStephen Hanson 	return (np);
66944ed9dbbSStephen Hanson }
67044ed9dbbSStephen Hanson 
67144ed9dbbSStephen Hanson /*
6727c478bd9Sstevel@tonic-gate  * config_bycpuid_lookup -- look up the cpu id in our CPUcache lut.
6737c478bd9Sstevel@tonic-gate  * If we find it return the config path, but as a struct node.
6747c478bd9Sstevel@tonic-gate  */
6757c478bd9Sstevel@tonic-gate struct node *
6767c478bd9Sstevel@tonic-gate config_bycpuid_lookup(struct cfgdata *fromcfg, uint32_t id)
6777c478bd9Sstevel@tonic-gate {
6787c478bd9Sstevel@tonic-gate 	struct config *find;
6797c478bd9Sstevel@tonic-gate 	struct node *np;
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, "Cpu cache:");
6827c478bd9Sstevel@tonic-gate 	lut_walk(fromcfg->cpucache, (lut_cb)prtcpucache, NULL);
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 	if ((find = lut_lookup(fromcfg->cpucache,
6857c478bd9Sstevel@tonic-gate 	    (void *)id, NULL)) == NULL)
6867c478bd9Sstevel@tonic-gate 		return (NULL);
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 	np = config_nodeize(find);
6897c478bd9Sstevel@tonic-gate 	if (np != NULL) {
6907c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB3, "Matching config entry:");
6917c478bd9Sstevel@tonic-gate 		ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, np);
6927c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB3, NULL);
6937c478bd9Sstevel@tonic-gate 	}
6947c478bd9Sstevel@tonic-gate 	return (np);
6957c478bd9Sstevel@tonic-gate }
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate /*
6987c478bd9Sstevel@tonic-gate  * printprop -- print prop associated with config node
6997c478bd9Sstevel@tonic-gate  */
7007c478bd9Sstevel@tonic-gate static void
7017c478bd9Sstevel@tonic-gate printprop(const char *lhs, const char *rhs, void *arg)
7027c478bd9Sstevel@tonic-gate {
7037c478bd9Sstevel@tonic-gate 	int flags = (int)arg;
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 	out(flags, "\t%s=%s", lhs, rhs);
7067c478bd9Sstevel@tonic-gate }
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate /*
7097c478bd9Sstevel@tonic-gate  * pconf -- internal printing function to recurse through the tree
7107c478bd9Sstevel@tonic-gate  */
7117c478bd9Sstevel@tonic-gate static void
7127c478bd9Sstevel@tonic-gate pconf(int flags, struct config *cp, char *buf, int offset, int limit)
7137c478bd9Sstevel@tonic-gate {
7147c478bd9Sstevel@tonic-gate 	char *sep = "/";
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 	if (offset)
7177c478bd9Sstevel@tonic-gate 		sep = "/";
7187c478bd9Sstevel@tonic-gate 	else
7197c478bd9Sstevel@tonic-gate 		sep = "";
7207c478bd9Sstevel@tonic-gate 	(void) snprintf(&buf[offset], limit - offset, "%s%s%d",
7217c478bd9Sstevel@tonic-gate 	    sep, cp->s, cp->num);
7227c478bd9Sstevel@tonic-gate 	if (cp->child == NULL) {
7237c478bd9Sstevel@tonic-gate 		out(flags, "%s", buf);
7247c478bd9Sstevel@tonic-gate 		lut_walk(cp->props, (lut_cb)printprop, (void *)flags);
7257c478bd9Sstevel@tonic-gate 	} else
7267c478bd9Sstevel@tonic-gate 		pconf(flags, cp->child, buf, strlen(buf), limit);
7277c478bd9Sstevel@tonic-gate 	if (cp->next)
7287c478bd9Sstevel@tonic-gate 		pconf(flags, cp->next, buf, offset, limit);
7297c478bd9Sstevel@tonic-gate }
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate /*
7327c478bd9Sstevel@tonic-gate  * config_print -- spew the current configuration cache
7337c478bd9Sstevel@tonic-gate  */
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate #define	MAXCONFLINE 4096
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate void
7387c478bd9Sstevel@tonic-gate config_print(int flags, struct config *croot)
7397c478bd9Sstevel@tonic-gate {
7407c478bd9Sstevel@tonic-gate 	char buf[MAXCONFLINE];
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 	if (croot == NULL)
7437c478bd9Sstevel@tonic-gate 		out(flags, "empty configuration");
7447c478bd9Sstevel@tonic-gate 	else
7457c478bd9Sstevel@tonic-gate 		pconf(flags, croot->child, buf, 0, MAXCONFLINE);
7467c478bd9Sstevel@tonic-gate }
747