xref: /onnv-gate/usr/src/cmd/fm/modules/common/eversholt/config.c (revision 1490:f0438aa54aa4)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*1490Stimh  * Common Development and Distribution License (the "License").
6*1490Stimh  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21*1490Stimh 
220Sstevel@tonic-gate /*
23*1490Stimh  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
25*1490Stimh  */
26*1490Stimh 
27*1490Stimh #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*1490Stimh 
29*1490Stimh /*
300Sstevel@tonic-gate  * config.c -- system configuration cache module
310Sstevel@tonic-gate  *
320Sstevel@tonic-gate  * this module caches the system configuration in a format useful
330Sstevel@tonic-gate  * to eft.  the information is loaded into this module by
340Sstevel@tonic-gate  * config_snapshot() at the beginning of each FME.  config_snapshot()
350Sstevel@tonic-gate  * calls the platform-specific platform_config_snapshot() to get
360Sstevel@tonic-gate  * the configuration information loaded up.
370Sstevel@tonic-gate  */
380Sstevel@tonic-gate 
390Sstevel@tonic-gate #include <stdio.h>
400Sstevel@tonic-gate #include <stdlib.h>
410Sstevel@tonic-gate #include <ctype.h>
420Sstevel@tonic-gate #include <string.h>
430Sstevel@tonic-gate #include <strings.h>
440Sstevel@tonic-gate #include "alloc.h"
450Sstevel@tonic-gate #include "out.h"
460Sstevel@tonic-gate #include "literals.h"
470Sstevel@tonic-gate #include "stable.h"
480Sstevel@tonic-gate #include "lut.h"
490Sstevel@tonic-gate #include "tree.h"
500Sstevel@tonic-gate #include "itree.h"
510Sstevel@tonic-gate #include "ipath.h"
520Sstevel@tonic-gate #include "ptree.h"
530Sstevel@tonic-gate #include "eval.h"
540Sstevel@tonic-gate #include "config.h"
550Sstevel@tonic-gate #include "fme.h"
560Sstevel@tonic-gate #include "platform.h"
570Sstevel@tonic-gate 
580Sstevel@tonic-gate /*
590Sstevel@tonic-gate  * private data structure for storing config.  all access to
600Sstevel@tonic-gate  * to this information happens using the config.h interfaces.
610Sstevel@tonic-gate  */
620Sstevel@tonic-gate struct config {
630Sstevel@tonic-gate 	struct config *next;
640Sstevel@tonic-gate 	struct config *child;
650Sstevel@tonic-gate 	struct config *parent;
660Sstevel@tonic-gate 	const char *s;
670Sstevel@tonic-gate 	int num;
680Sstevel@tonic-gate 	struct lut *props;
690Sstevel@tonic-gate };
700Sstevel@tonic-gate 
710Sstevel@tonic-gate /*
720Sstevel@tonic-gate  * newcnode -- local function to allocate new config node
730Sstevel@tonic-gate  */
740Sstevel@tonic-gate static struct config *
750Sstevel@tonic-gate newcnode(const char *s, int num)
760Sstevel@tonic-gate {
770Sstevel@tonic-gate 	struct config *retval;
780Sstevel@tonic-gate 
790Sstevel@tonic-gate 	retval = MALLOC(sizeof (struct config));
800Sstevel@tonic-gate 
810Sstevel@tonic-gate 	retval->s = s;
820Sstevel@tonic-gate 	retval->num = num;
830Sstevel@tonic-gate 	retval->next = NULL;
840Sstevel@tonic-gate 	retval->props = NULL;
850Sstevel@tonic-gate 	retval->child = retval->parent = NULL;
860Sstevel@tonic-gate 
870Sstevel@tonic-gate 	return (retval);
880Sstevel@tonic-gate }
890Sstevel@tonic-gate 
900Sstevel@tonic-gate /*
910Sstevel@tonic-gate  * If we need to cache certain types of nodes for reverse look-up or
920Sstevel@tonic-gate  * somesuch, do it here.  Currently we need to cache nodes representing
930Sstevel@tonic-gate  * cpus.
940Sstevel@tonic-gate  */
950Sstevel@tonic-gate static void
960Sstevel@tonic-gate config_node_cache(struct cfgdata *cdata, struct config *n)
970Sstevel@tonic-gate {
980Sstevel@tonic-gate 	if (n->s != stable("cpu"))
990Sstevel@tonic-gate 		return;
1000Sstevel@tonic-gate 	cdata->cpucache = lut_add(cdata->cpucache,
1010Sstevel@tonic-gate 	    (void *)n->num, (void *)n, NULL);
1020Sstevel@tonic-gate }
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate /*
1050Sstevel@tonic-gate  * config_lookup -- lookup/add components in configuration cache
1060Sstevel@tonic-gate  */
1070Sstevel@tonic-gate struct config *
1080Sstevel@tonic-gate config_lookup(struct config *croot, char *path, int add)
1090Sstevel@tonic-gate {
1100Sstevel@tonic-gate 	char *pathbegin = path;
1110Sstevel@tonic-gate 	struct config *parent = croot;
1120Sstevel@tonic-gate 	struct config *cp;
1130Sstevel@tonic-gate 	struct config *lastcp;
1140Sstevel@tonic-gate 	struct config *newnode;
1150Sstevel@tonic-gate 	char *thiscom;	/* this component */
1160Sstevel@tonic-gate 	char *nextcom;	/* next component */
1170Sstevel@tonic-gate 	char svdigit;
1180Sstevel@tonic-gate 	int len;
1190Sstevel@tonic-gate 	int num;
1200Sstevel@tonic-gate 	const char *s;
1210Sstevel@tonic-gate 	int exists;
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 	if (parent == NULL)
1240Sstevel@tonic-gate 		out(O_DIE, "uninitialized configuration");
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	while (*path) {
1270Sstevel@tonic-gate 		if ((nextcom = strchr(path, '/')) != NULL)
1280Sstevel@tonic-gate 			*nextcom = '\0';
1290Sstevel@tonic-gate 		if ((len = strlen(path)) == 0)
1300Sstevel@tonic-gate 			out(O_DIE, "config_lookup: zero length component");
1310Sstevel@tonic-gate 		/* start at end of string and work backwards */
1320Sstevel@tonic-gate 		thiscom = &path[len - 1];
1330Sstevel@tonic-gate 		if (!isdigit(*thiscom))
1340Sstevel@tonic-gate 			out(O_DIE, "config_lookup: "
1350Sstevel@tonic-gate 			    "component \"%s\" has no number following it",
1360Sstevel@tonic-gate 			    path);
1370Sstevel@tonic-gate 		while (thiscom > path && isdigit(*thiscom))
1380Sstevel@tonic-gate 			thiscom--;
1390Sstevel@tonic-gate 		if (thiscom == path && isdigit(*thiscom))
1400Sstevel@tonic-gate 			out(O_DIE, "config_lookup: "
1410Sstevel@tonic-gate 			    "component \"%s\" has no name part", path);
1420Sstevel@tonic-gate 		thiscom++;	/* move to first numeric character */
1430Sstevel@tonic-gate 		num = atoi(thiscom);
1440Sstevel@tonic-gate 		svdigit = *thiscom;
1450Sstevel@tonic-gate 		*thiscom = '\0';
1460Sstevel@tonic-gate 		s = stable(path);
1470Sstevel@tonic-gate 		*thiscom = svdigit;
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 		if (nextcom != NULL)
1500Sstevel@tonic-gate 			*nextcom++ = '/';
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate 		/* now we have s & num, figure out if it exists already */
1530Sstevel@tonic-gate 		exists = 0;
1540Sstevel@tonic-gate 		lastcp = NULL;
1550Sstevel@tonic-gate 		for (cp = parent->child; cp; lastcp = cp, cp = cp->next)
1560Sstevel@tonic-gate 			if (cp->s == s && cp->num == num) {
1570Sstevel@tonic-gate 				exists = 1;
1580Sstevel@tonic-gate 				parent = cp;
1590Sstevel@tonic-gate 			}
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 		if (!exists) {
1620Sstevel@tonic-gate 			/* creating new node */
1630Sstevel@tonic-gate 			if (!add) {
1640Sstevel@tonic-gate 				/*
1650Sstevel@tonic-gate 				 * indicate component not found by copying
1660Sstevel@tonic-gate 				 * it to path (allows better error messages
1670Sstevel@tonic-gate 				 * in the caller).
1680Sstevel@tonic-gate 				 */
1690Sstevel@tonic-gate 				(void) strcpy(pathbegin, s);
1700Sstevel@tonic-gate 				return (NULL);
1710Sstevel@tonic-gate 			}
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 			newnode = newcnode(s, num);
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 			if (lastcp)
1760Sstevel@tonic-gate 				lastcp->next = newnode;
1770Sstevel@tonic-gate 			else
1780Sstevel@tonic-gate 				parent->child = newnode;
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 			newnode->parent = parent;
1810Sstevel@tonic-gate 			parent = newnode;
1820Sstevel@tonic-gate 		}
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 		if (nextcom == NULL)
1850Sstevel@tonic-gate 			return (parent);	/* all done */
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate 		/* move on to next component */
1880Sstevel@tonic-gate 		path = nextcom;
1890Sstevel@tonic-gate 	}
1900Sstevel@tonic-gate 	return (parent);
1910Sstevel@tonic-gate }
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate /*
1940Sstevel@tonic-gate  * addconfigprop -- add a config prop to a config cache entry
1950Sstevel@tonic-gate  */
1960Sstevel@tonic-gate static void
1970Sstevel@tonic-gate addconfigprop(const char *lhs, struct node *rhs, void *arg)
1980Sstevel@tonic-gate {
1990Sstevel@tonic-gate 	struct config *cp = (struct config *)arg;
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	ASSERT(cp != NULL);
2020Sstevel@tonic-gate 	ASSERT(lhs != NULL);
2030Sstevel@tonic-gate 	ASSERT(rhs != NULL);
2040Sstevel@tonic-gate 	ASSERT(rhs->t == T_QUOTE);
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	config_setprop(cp, lhs, STRDUP(rhs->u.quote.s));
2070Sstevel@tonic-gate }
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate /*
2100Sstevel@tonic-gate  * addconfig -- add a config from parse tree to given configuration cache
2110Sstevel@tonic-gate  */
2120Sstevel@tonic-gate /*ARGSUSED*/
2130Sstevel@tonic-gate static void
2140Sstevel@tonic-gate addconfig(struct node *lhs, struct node *rhs, void *arg)
2150Sstevel@tonic-gate {
2160Sstevel@tonic-gate 	struct config *parent = (struct config *)arg;
2170Sstevel@tonic-gate 	struct config *cp;
2180Sstevel@tonic-gate 	const char *s;
2190Sstevel@tonic-gate 	int num;
2200Sstevel@tonic-gate 	struct config *lastcp;
2210Sstevel@tonic-gate 	struct config *newnode;
2220Sstevel@tonic-gate 	int exists;
2230Sstevel@tonic-gate 	struct lut *lutp;
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 	ASSERT(rhs->t == T_CONFIG);
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 	lutp = rhs->u.stmt.lutp;
2280Sstevel@tonic-gate 	rhs = rhs->u.stmt.np;
2290Sstevel@tonic-gate 	while (rhs != NULL) {
2300Sstevel@tonic-gate 		ASSERT(rhs->t == T_NAME);
2310Sstevel@tonic-gate 		ASSERT(rhs->u.name.child->t == T_NUM);
2320Sstevel@tonic-gate 		s = rhs->u.name.s;
2330Sstevel@tonic-gate 		num = rhs->u.name.child->u.ull;
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 		/* now we have s & num, figure out if it exists already */
2360Sstevel@tonic-gate 		exists = 0;
2370Sstevel@tonic-gate 		lastcp = NULL;
2380Sstevel@tonic-gate 		for (cp = parent->child; cp; lastcp = cp, cp = cp->next)
2390Sstevel@tonic-gate 			if (cp->s == s && cp->num == num) {
2400Sstevel@tonic-gate 				exists = 1;
2410Sstevel@tonic-gate 				parent = cp;
2420Sstevel@tonic-gate 			}
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 		if (!exists) {
2450Sstevel@tonic-gate 			/* creating new node */
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 			newnode = newcnode(s, num);
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 			if (lastcp)
2500Sstevel@tonic-gate 				lastcp->next = newnode;
2510Sstevel@tonic-gate 			else
2520Sstevel@tonic-gate 				parent->child = newnode;
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 			parent = newnode;
2550Sstevel@tonic-gate 		}
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 		/* move on to next component */
2580Sstevel@tonic-gate 		rhs = rhs->u.name.next;
2590Sstevel@tonic-gate 	}
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	/* add configuration properties */
2620Sstevel@tonic-gate 	lut_walk(lutp, (lut_cb)addconfigprop, (void *)parent);
2630Sstevel@tonic-gate }
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate /*
2660Sstevel@tonic-gate  * config_cook -- convert raw config strings to eft internal representation
2670Sstevel@tonic-gate  */
2680Sstevel@tonic-gate void
2690Sstevel@tonic-gate config_cook(struct cfgdata *cdata)
2700Sstevel@tonic-gate {
2710Sstevel@tonic-gate 	struct config *newnode;
2720Sstevel@tonic-gate 	char *cfgstr, *equals;
2730Sstevel@tonic-gate 	const char *pn, *sv;
2740Sstevel@tonic-gate 	char *pv;
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 	if (cdata->cooked != NULL)
2770Sstevel@tonic-gate 		return;
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 	cdata->cooked = newcnode(NULL, 0);
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 	if ((cfgstr = cdata->begin) == cdata->nextfree) {
2820Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, "Platform provided no config data.");
2830Sstevel@tonic-gate 		goto eftcfgs;
2840Sstevel@tonic-gate 	}
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 	out(O_ALTFP|O_VERB3, "Raw config data follows:");
2870Sstevel@tonic-gate 	out(O_ALTFP|O_VERB3|O_NONL,
2880Sstevel@tonic-gate 	    "nextfree is %p\n%p ", (void *)cdata->nextfree, (void *)cfgstr);
2890Sstevel@tonic-gate 	while (cfgstr < cdata->nextfree) {
2900Sstevel@tonic-gate 		if (!*cfgstr)
2910Sstevel@tonic-gate 			out(O_ALTFP|O_VERB3|O_NONL, "\n%p ",
2920Sstevel@tonic-gate 			    (void *)(cfgstr + 1));
2930Sstevel@tonic-gate 		else
2940Sstevel@tonic-gate 			out(O_ALTFP|O_VERB3|O_NONL, "%c", *cfgstr);
2950Sstevel@tonic-gate 		cfgstr++;
2960Sstevel@tonic-gate 	}
2970Sstevel@tonic-gate 	out(O_ALTFP|O_VERB3, NULL);
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 	cfgstr = cdata->begin;
3000Sstevel@tonic-gate 	while (cfgstr < cdata->nextfree) {
3010Sstevel@tonic-gate 		while (*cfgstr == '/' && cfgstr < cdata->nextfree) {
3020Sstevel@tonic-gate 			out(O_ALTFP|O_VERB3,
3030Sstevel@tonic-gate 			    "next string (%p) is %s", (void *)cfgstr, cfgstr);
3040Sstevel@tonic-gate 			/* skip the initial slash from libtopo */
3050Sstevel@tonic-gate 			newnode = config_lookup(cdata->cooked, cfgstr + 1, 1);
3060Sstevel@tonic-gate 			/*
3070Sstevel@tonic-gate 			 * Note we'll only cache nodes that have
3080Sstevel@tonic-gate 			 * properties on them.  Intermediate nodes
3090Sstevel@tonic-gate 			 * will have been added to the config tree,
3100Sstevel@tonic-gate 			 * but we don't have easy means of accessing
3110Sstevel@tonic-gate 			 * them except if we climb the tree from this
3120Sstevel@tonic-gate 			 * newnode to the root.
3130Sstevel@tonic-gate 			 *
3140Sstevel@tonic-gate 			 * Luckily, the nodes we care to cache
3150Sstevel@tonic-gate 			 * (currently just cpus) always have some
3160Sstevel@tonic-gate 			 * properties attached to them
3170Sstevel@tonic-gate 			 * so we don't bother climbing the tree.
3180Sstevel@tonic-gate 			 */
3190Sstevel@tonic-gate 			config_node_cache(cdata, newnode);
3200Sstevel@tonic-gate 			cfgstr += strlen(cfgstr) + 1;
3210Sstevel@tonic-gate 		}
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 		if (cfgstr >= cdata->nextfree)
3240Sstevel@tonic-gate 			break;
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 		out(O_ALTFP|O_VERB3, "next string (%p) is %s", (void *)cfgstr,
3270Sstevel@tonic-gate 		    cfgstr);
3280Sstevel@tonic-gate 		if ((equals = strchr(cfgstr, '=')) == NULL) {
3290Sstevel@tonic-gate 			out(O_ALTFP|O_VERB3, "raw config data bad (%p); "
3300Sstevel@tonic-gate 			    "property missing equals.\n", (void *)cfgstr);
3310Sstevel@tonic-gate 			break;
3320Sstevel@tonic-gate 		}
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 		*equals = '\0';
3350Sstevel@tonic-gate 		pn = stable(cfgstr);
3360Sstevel@tonic-gate 		pv = STRDUP(equals + 1);
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 		out(O_ALTFP|O_VERB3, "add prop (%s) val %p", pn, (void *)pv);
3390Sstevel@tonic-gate 		config_setprop(newnode, pn, pv);
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 		/*
3420Sstevel@tonic-gate 		 * If this property is a device path, cache it for quick lookup
3430Sstevel@tonic-gate 		 */
344*1490Stimh 		if (pn == stable("DEV")) {
3450Sstevel@tonic-gate 			sv = stable(pv);
3460Sstevel@tonic-gate 			out(O_ALTFP|O_VERB3, "caching %s\n", sv);
3470Sstevel@tonic-gate 			cdata->devcache = lut_add(cdata->devcache,
3480Sstevel@tonic-gate 			    (void *)sv, (void *)newnode, NULL);
3490Sstevel@tonic-gate 		}
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 		*equals = '=';
3520Sstevel@tonic-gate 		cfgstr += strlen(cfgstr) + 1;
3530Sstevel@tonic-gate 	}
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate eftcfgs:
3560Sstevel@tonic-gate 	/* now run through Configs table, adding to config cache */
3570Sstevel@tonic-gate 	lut_walk(Configs, (lut_cb)addconfig, (void *)cdata->cooked);
3580Sstevel@tonic-gate }
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate /*
3610Sstevel@tonic-gate  * config_snapshot -- gather a snapshot of the current configuration
3620Sstevel@tonic-gate  */
3630Sstevel@tonic-gate struct cfgdata *
3640Sstevel@tonic-gate config_snapshot(void)
3650Sstevel@tonic-gate {
3660Sstevel@tonic-gate 	struct cfgdata *rawcfg;
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 	rawcfg = platform_config_snapshot();
3690Sstevel@tonic-gate 	config_cook(rawcfg);
3700Sstevel@tonic-gate 	return (rawcfg);
3710Sstevel@tonic-gate }
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate /*
3740Sstevel@tonic-gate  * prop_destructor -- free a prop value
3750Sstevel@tonic-gate  */
3760Sstevel@tonic-gate /*ARGSUSED*/
3770Sstevel@tonic-gate static void
3780Sstevel@tonic-gate prop_destructor(void *left, void *right, void *arg)
3790Sstevel@tonic-gate {
3800Sstevel@tonic-gate 	FREE(right);
3810Sstevel@tonic-gate }
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate /*
3840Sstevel@tonic-gate  * structconfig_free -- free a struct config pointer and all its relatives
3850Sstevel@tonic-gate  */
3860Sstevel@tonic-gate static void
3870Sstevel@tonic-gate structconfig_free(struct config *cp)
3880Sstevel@tonic-gate {
3890Sstevel@tonic-gate 	if (cp == NULL)
3900Sstevel@tonic-gate 		return;
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 	structconfig_free(cp->child);
3930Sstevel@tonic-gate 	structconfig_free(cp->next);
3940Sstevel@tonic-gate 	lut_free(cp->props, prop_destructor, NULL);
3950Sstevel@tonic-gate 	FREE(cp);
3960Sstevel@tonic-gate }
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate /*
3990Sstevel@tonic-gate  * config_free -- free a configuration snapshot
4000Sstevel@tonic-gate  */
4010Sstevel@tonic-gate void
4020Sstevel@tonic-gate config_free(struct cfgdata *cp)
4030Sstevel@tonic-gate {
4040Sstevel@tonic-gate 	if (cp == NULL)
4050Sstevel@tonic-gate 		return;
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 	if (--cp->refcnt > 0)
4080Sstevel@tonic-gate 		return;
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 	if (cp->cooked != NULL)
4110Sstevel@tonic-gate 		structconfig_free(cp->cooked);
4120Sstevel@tonic-gate 	if (cp->begin != NULL)
4130Sstevel@tonic-gate 		FREE(cp->begin);
4140Sstevel@tonic-gate 	if (cp->devcache != NULL)
4150Sstevel@tonic-gate 		lut_free(cp->devcache, NULL, NULL);
4160Sstevel@tonic-gate 	if (cp->cpucache != NULL)
4170Sstevel@tonic-gate 		lut_free(cp->cpucache, NULL, NULL);
4180Sstevel@tonic-gate 	FREE(cp);
4190Sstevel@tonic-gate }
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate /*
4220Sstevel@tonic-gate  * config_next -- get the "next" config node
4230Sstevel@tonic-gate  */
4240Sstevel@tonic-gate struct config *
4250Sstevel@tonic-gate config_next(struct config *cp)
4260Sstevel@tonic-gate {
4270Sstevel@tonic-gate 	ASSERT(cp != NULL);
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 	return ((struct config *)((struct config *)cp)->next);
4300Sstevel@tonic-gate }
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate /*
4340Sstevel@tonic-gate  * config_child -- get the "child" of a config node
4350Sstevel@tonic-gate  */
4360Sstevel@tonic-gate struct config *
4370Sstevel@tonic-gate config_child(struct config *cp)
4380Sstevel@tonic-gate {
4390Sstevel@tonic-gate 	ASSERT(cp != NULL);
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	return ((struct config *)((struct config *)cp)->child);
4420Sstevel@tonic-gate }
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate /*
4450Sstevel@tonic-gate  * config_setprop -- add a property to a config node
4460Sstevel@tonic-gate  */
4470Sstevel@tonic-gate void
4480Sstevel@tonic-gate config_setprop(struct config *cp, const char *propname, const char *propvalue)
4490Sstevel@tonic-gate {
4500Sstevel@tonic-gate 	const char *pn = stable(propname);
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 	cp->props = lut_add(cp->props, (void *)pn, (void *)propvalue, NULL);
4530Sstevel@tonic-gate }
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate /*
4560Sstevel@tonic-gate  * config_getprop -- lookup a config property
4570Sstevel@tonic-gate  */
4580Sstevel@tonic-gate const char *
4590Sstevel@tonic-gate config_getprop(struct config *cp, const char *propname)
4600Sstevel@tonic-gate {
4610Sstevel@tonic-gate 	return (lut_lookup(cp->props, (void *) stable(propname), NULL));
4620Sstevel@tonic-gate }
4630Sstevel@tonic-gate 
4640Sstevel@tonic-gate /*
4650Sstevel@tonic-gate  * config_getcompname -- get the component name of a config node
4660Sstevel@tonic-gate  */
4670Sstevel@tonic-gate void
4680Sstevel@tonic-gate config_getcompname(struct config *cp, char **name, int *inst)
4690Sstevel@tonic-gate {
4700Sstevel@tonic-gate 	ASSERT(cp != NULL);
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 	if (name != NULL)
4730Sstevel@tonic-gate 		*name = (char *)cp->s;
4740Sstevel@tonic-gate 	if (inst != NULL)
4750Sstevel@tonic-gate 		*inst = cp->num;
4760Sstevel@tonic-gate }
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate /*
4790Sstevel@tonic-gate  * config_nodeize -- convert the config element represented by cp to struct
4800Sstevel@tonic-gate  *		     node format
4810Sstevel@tonic-gate  */
4820Sstevel@tonic-gate static struct node *
4830Sstevel@tonic-gate config_nodeize(struct config *cp)
4840Sstevel@tonic-gate {
4850Sstevel@tonic-gate 	struct node *tmpn, *ptmpn;
4860Sstevel@tonic-gate 	struct node *numn;
4870Sstevel@tonic-gate 	const char *sname;
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate 	if (cp == NULL || cp->s == NULL)
4900Sstevel@tonic-gate 		return (NULL);
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 	sname = stable(cp->s);
4930Sstevel@tonic-gate 	numn = newnode(T_NUM, NULL, 0);
4940Sstevel@tonic-gate 	numn->u.ull = cp->num;
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 	tmpn = tree_name_iterator(tree_name(sname, IT_VERTICAL, NULL, 0), numn);
4970Sstevel@tonic-gate 	if ((ptmpn = config_nodeize(cp->parent)) == NULL)
4980Sstevel@tonic-gate 		return (tmpn);
4990Sstevel@tonic-gate 	return (tree_name_append(ptmpn, tmpn));
5000Sstevel@tonic-gate }
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate /*ARGSUSED*/
5030Sstevel@tonic-gate static void
5040Sstevel@tonic-gate prtdevcache(void *lhs, void *rhs, void *arg)
5050Sstevel@tonic-gate {
5060Sstevel@tonic-gate 	out(O_ALTFP|O_VERB3, "%s -> %p", (char *)lhs, rhs);
5070Sstevel@tonic-gate }
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate /*ARGSUSED*/
5100Sstevel@tonic-gate static void
5110Sstevel@tonic-gate prtcpucache(void *lhs, void *rhs, void *arg)
5120Sstevel@tonic-gate {
5130Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, "%u -> %p", (uint32_t)lhs, rhs);
5140Sstevel@tonic-gate }
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate /*
5170Sstevel@tonic-gate  * config_bydev_lookup -- look up the path in our DEVcache lut.  If we find
5180Sstevel@tonic-gate  * it return the config path, but as a struct node.
5190Sstevel@tonic-gate  */
5200Sstevel@tonic-gate struct node *
5210Sstevel@tonic-gate config_bydev_lookup(struct cfgdata *fromcfg, const char *path)
5220Sstevel@tonic-gate {
5230Sstevel@tonic-gate 	struct config *find;
5240Sstevel@tonic-gate 	struct node *np;
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 	out(O_ALTFP|O_VERB3, "Device path cache:");
5270Sstevel@tonic-gate 	lut_walk(fromcfg->devcache, (lut_cb)prtdevcache, NULL);
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 	if ((find = lut_lookup(fromcfg->devcache,
5300Sstevel@tonic-gate 	    (void *) stable(path), NULL)) == NULL)
5310Sstevel@tonic-gate 		return (NULL);
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 	np = config_nodeize(find);
5340Sstevel@tonic-gate 	if (np != NULL) {
5350Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, "Matching config entry:");
5360Sstevel@tonic-gate 		ptree_name_iter(O_ALTFP|O_VERB|O_NONL, np);
5370Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
5380Sstevel@tonic-gate 	}
5390Sstevel@tonic-gate 	return (np);
5400Sstevel@tonic-gate }
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate /*
5430Sstevel@tonic-gate  * config_bycpuid_lookup -- look up the cpu id in our CPUcache lut.
5440Sstevel@tonic-gate  * If we find it return the config path, but as a struct node.
5450Sstevel@tonic-gate  */
5460Sstevel@tonic-gate struct node *
5470Sstevel@tonic-gate config_bycpuid_lookup(struct cfgdata *fromcfg, uint32_t id)
5480Sstevel@tonic-gate {
5490Sstevel@tonic-gate 	struct config *find;
5500Sstevel@tonic-gate 	struct node *np;
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, "Cpu cache:");
5530Sstevel@tonic-gate 	lut_walk(fromcfg->cpucache, (lut_cb)prtcpucache, NULL);
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 	if ((find = lut_lookup(fromcfg->cpucache,
5560Sstevel@tonic-gate 	    (void *)id, NULL)) == NULL)
5570Sstevel@tonic-gate 		return (NULL);
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate 	np = config_nodeize(find);
5600Sstevel@tonic-gate 	if (np != NULL) {
5610Sstevel@tonic-gate 		out(O_ALTFP|O_VERB3, "Matching config entry:");
5620Sstevel@tonic-gate 		ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, np);
5630Sstevel@tonic-gate 		out(O_ALTFP|O_VERB3, NULL);
5640Sstevel@tonic-gate 	}
5650Sstevel@tonic-gate 	return (np);
5660Sstevel@tonic-gate }
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate /*
5690Sstevel@tonic-gate  * given the following:
5700Sstevel@tonic-gate  *   - np of type T_NAME which denotes a pathname
5710Sstevel@tonic-gate  *   - croot, the root node of a configuration
5720Sstevel@tonic-gate  *
5730Sstevel@tonic-gate  * return the cp for the last component in np's path
5740Sstevel@tonic-gate  */
5750Sstevel@tonic-gate static struct config *
5760Sstevel@tonic-gate name2cp(struct node *np, struct config *croot)
5770Sstevel@tonic-gate {
5780Sstevel@tonic-gate 	char *path;
5790Sstevel@tonic-gate 	struct config *cp;
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 	if (np->u.name.last->u.name.cp != NULL)
5820Sstevel@tonic-gate 		return (np->u.name.last->u.name.cp);
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 	path = ipath2str(NULL, ipath(np));
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 	cp = config_lookup(croot, path, 0);
5870Sstevel@tonic-gate 	FREE((void *)path);
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 	return (cp);
5900Sstevel@tonic-gate }
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate int
5930Sstevel@tonic-gate config_confprop(struct node *np, struct config *croot, struct evalue *valuep)
5940Sstevel@tonic-gate {
5950Sstevel@tonic-gate 	struct node *nodep;
5960Sstevel@tonic-gate 	struct config *cp;
5970Sstevel@tonic-gate 	const char *s;
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 	if (np->u.expr.left->u.func.s == L_fru)
6000Sstevel@tonic-gate 		nodep = eval_fru(np->u.expr.left->u.func.arglist);
6010Sstevel@tonic-gate 	else if (np->u.expr.left->u.func.s == L_asru)
6020Sstevel@tonic-gate 		nodep = eval_asru(np->u.expr.left->u.func.arglist);
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 	cp = name2cp(nodep, croot);
6050Sstevel@tonic-gate 	if (cp == NULL)
6060Sstevel@tonic-gate 		return (1);
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	/* for now s will point to a quote [see addconfigprop()] */
6090Sstevel@tonic-gate 	ASSERT(np->u.expr.right->t == T_QUOTE);
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 	s = config_getprop(cp, np->u.expr.right->u.quote.s);
6120Sstevel@tonic-gate 	if (s == NULL)
6130Sstevel@tonic-gate 		return (1);
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 	valuep->t = STRING;
6160Sstevel@tonic-gate 	valuep->v = (unsigned long long)stable(s);
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 	return (0);
6190Sstevel@tonic-gate }
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate #define	CONNECTED_SEPCHARS " ,"
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate int
6240Sstevel@tonic-gate config_is_connected(struct node *np, struct config *croot,
6250Sstevel@tonic-gate 		    struct evalue *valuep)
6260Sstevel@tonic-gate {
6270Sstevel@tonic-gate 	const char *connstrings[] = { "connected", "CONNECTED", NULL };
6280Sstevel@tonic-gate 	struct config *cp[2], *compcp;
6290Sstevel@tonic-gate 	struct node *nptr[2];
6300Sstevel@tonic-gate 	const char *searchforname, *matchthis[2], *s;
6310Sstevel@tonic-gate 	char *nameslist, *w;
6320Sstevel@tonic-gate 	int i, j;
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 	valuep->t = UINT64;
6350Sstevel@tonic-gate 	valuep->v = 0;
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 	if (np->u.expr.left->t == T_NAME)
6380Sstevel@tonic-gate 		nptr[0] = np->u.expr.left;
6390Sstevel@tonic-gate 	else if (np->u.expr.left->u.func.s == L_fru)
6400Sstevel@tonic-gate 		nptr[0] = eval_fru(np->u.expr.left->u.func.arglist);
6410Sstevel@tonic-gate 	else if (np->u.expr.left->u.func.s == L_asru)
6420Sstevel@tonic-gate 		nptr[0] = eval_asru(np->u.expr.left->u.func.arglist);
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate 	if (np->u.expr.right->t == T_NAME)
6450Sstevel@tonic-gate 		nptr[1] = np->u.expr.right;
6460Sstevel@tonic-gate 	else if (np->u.expr.right->u.func.s == L_fru)
6470Sstevel@tonic-gate 		nptr[1] = eval_fru(np->u.expr.right->u.func.arglist);
6480Sstevel@tonic-gate 	else if (np->u.expr.right->u.func.s == L_asru)
6490Sstevel@tonic-gate 		nptr[1] = eval_asru(np->u.expr.right->u.func.arglist);
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 	for (i = 0; i < 2; i++) {
6520Sstevel@tonic-gate 		cp[i] = name2cp(nptr[i], croot);
6530Sstevel@tonic-gate 		if (cp[i] == NULL)
6540Sstevel@tonic-gate 			return (1);
6550Sstevel@tonic-gate 	}
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 	/* to thine self always be connected */
6580Sstevel@tonic-gate 	if (cp[0] == cp[1]) {
6590Sstevel@tonic-gate 		valuep->v = 1;
6600Sstevel@tonic-gate 		return (0);
6610Sstevel@tonic-gate 	}
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 	/*
6640Sstevel@tonic-gate 	 * set one of the cp[]s to compcp and extract its "connected"
6650Sstevel@tonic-gate 	 * property.  search this property for the name associated with the
6660Sstevel@tonic-gate 	 * other cp[].
6670Sstevel@tonic-gate 	 */
6680Sstevel@tonic-gate 	for (i = 0; i < 2 && valuep->v == 0; i++) {
6690Sstevel@tonic-gate 		compcp = cp[i];
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 		searchforname = ipath2str(NULL, ipath(nptr[(i == 0 ? 1 : 0)]));
6720Sstevel@tonic-gate 		matchthis[i] = stable(searchforname);
6730Sstevel@tonic-gate 		FREE((void *)searchforname);
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 		for (j = 0; connstrings[j] != NULL && valuep->v == 0; j++) {
6760Sstevel@tonic-gate 			s = config_getprop(compcp, stable(connstrings[j]));
6770Sstevel@tonic-gate 			if (s != NULL) {
6780Sstevel@tonic-gate 				nameslist = STRDUP(s);
6790Sstevel@tonic-gate 				w = strtok(nameslist, CONNECTED_SEPCHARS);
6800Sstevel@tonic-gate 				while (w != NULL) {
6810Sstevel@tonic-gate 					if (stable(w) == matchthis[i]) {
6820Sstevel@tonic-gate 						valuep->v = 1;
6830Sstevel@tonic-gate 						break;
6840Sstevel@tonic-gate 					}
6850Sstevel@tonic-gate 					w = strtok(NULL, CONNECTED_SEPCHARS);
6860Sstevel@tonic-gate 				}
6870Sstevel@tonic-gate 				FREE(nameslist);
6880Sstevel@tonic-gate 			}
6890Sstevel@tonic-gate 		}
6900Sstevel@tonic-gate 	}
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 	/* a path shouldn't have more than one cp node */
6930Sstevel@tonic-gate 	if (valuep->v == 0)
6940Sstevel@tonic-gate 		ASSERT(matchthis[0] != matchthis[1]);
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate 	return (0);
6970Sstevel@tonic-gate }
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate int
7000Sstevel@tonic-gate config_is_type(struct node *np, struct config *croot, struct evalue *valuep)
7010Sstevel@tonic-gate {
7020Sstevel@tonic-gate 	const char *typestrings[] = { "type", "TYPE", NULL };
7030Sstevel@tonic-gate 	struct config *cp;
7040Sstevel@tonic-gate 	struct node *nodep;
7050Sstevel@tonic-gate 	const char *s;
7060Sstevel@tonic-gate 	int i;
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	valuep->t = STRING;
7090Sstevel@tonic-gate 	valuep->v = 0;
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 	if (np->u.func.s == L_fru)
7120Sstevel@tonic-gate 		nodep = eval_fru(np->u.func.arglist);
7130Sstevel@tonic-gate 	else if (np->u.func.s == L_asru)
7140Sstevel@tonic-gate 		nodep = eval_asru(np->u.func.arglist);
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 	cp = name2cp(nodep, croot);
7170Sstevel@tonic-gate 	if (cp == NULL)
7180Sstevel@tonic-gate 		return (1);
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate 	for (i = 0; typestrings[i] != NULL; i++) {
7210Sstevel@tonic-gate 		s = config_getprop(cp, stable(typestrings[i]));
7220Sstevel@tonic-gate 		if (s != NULL) {
7230Sstevel@tonic-gate 			valuep->v = (unsigned long long)stable(s);
7240Sstevel@tonic-gate 			break;
7250Sstevel@tonic-gate 		}
7260Sstevel@tonic-gate 	}
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 	/* no entry for "type" */
7290Sstevel@tonic-gate 	if (valuep->v == 0)
7300Sstevel@tonic-gate 		return (1);
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 	return (0);
7330Sstevel@tonic-gate }
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate int
7360Sstevel@tonic-gate config_is_on(struct node *np, struct config *croot, struct evalue *valuep)
7370Sstevel@tonic-gate {
7380Sstevel@tonic-gate 	const char *onstrings[] = { "on", "ON", NULL };
7390Sstevel@tonic-gate 	const char *truestrings[] = { "yes", "YES", "y", "Y",
7400Sstevel@tonic-gate 				    "true", "TRUE", "t", "T",
7410Sstevel@tonic-gate 				    "1", NULL };
7420Sstevel@tonic-gate 	struct config *cp;
7430Sstevel@tonic-gate 	struct node *nodep;
7440Sstevel@tonic-gate 	const char *s;
7450Sstevel@tonic-gate 	int i, j;
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	valuep->t = UINT64;
7480Sstevel@tonic-gate 	valuep->v = 0;
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 	if (np->u.func.s == L_fru)
7510Sstevel@tonic-gate 		nodep = eval_fru(np->u.func.arglist);
7520Sstevel@tonic-gate 	else if (np->u.func.s == L_asru)
7530Sstevel@tonic-gate 		nodep = eval_asru(np->u.func.arglist);
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate 	cp = name2cp(nodep, croot);
7560Sstevel@tonic-gate 	if (cp == NULL)
7570Sstevel@tonic-gate 		return (1);
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate 	for (i = 0; onstrings[i] != NULL; i++) {
7600Sstevel@tonic-gate 		s = config_getprop(cp, stable(onstrings[i]));
7610Sstevel@tonic-gate 		if (s != NULL) {
7620Sstevel@tonic-gate 			s = stable(s);
7630Sstevel@tonic-gate 			for (j = 0; truestrings[j] != NULL; j++) {
7640Sstevel@tonic-gate 				if (s == stable(truestrings[j])) {
7650Sstevel@tonic-gate 					valuep->v = 1;
7660Sstevel@tonic-gate 					return (0);
7670Sstevel@tonic-gate 				}
7680Sstevel@tonic-gate 			}
7690Sstevel@tonic-gate 		}
7700Sstevel@tonic-gate 	}
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate 	return (0);
7730Sstevel@tonic-gate }
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate int
7760Sstevel@tonic-gate config_is_present(struct node *np, struct config *croot, struct evalue *valuep)
7770Sstevel@tonic-gate {
7780Sstevel@tonic-gate 	struct config *cp;
7790Sstevel@tonic-gate 	struct node *nodep;
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 	valuep->t = UINT64;
7820Sstevel@tonic-gate 	valuep->v = 0;
7830Sstevel@tonic-gate 
7840Sstevel@tonic-gate 	if (np->u.func.s == L_fru)
7850Sstevel@tonic-gate 		nodep = eval_fru(np->u.func.arglist);
7860Sstevel@tonic-gate 	else if (np->u.func.s == L_asru)
7870Sstevel@tonic-gate 		nodep = eval_asru(np->u.func.arglist);
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 	cp = name2cp(nodep, croot);
7900Sstevel@tonic-gate 	if (cp != NULL)
7910Sstevel@tonic-gate 		valuep->v = 1;
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 	return (0);
7940Sstevel@tonic-gate }
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate /*
7970Sstevel@tonic-gate  * printprop -- print prop associated with config node
7980Sstevel@tonic-gate  */
7990Sstevel@tonic-gate static void
8000Sstevel@tonic-gate printprop(const char *lhs, const char *rhs, void *arg)
8010Sstevel@tonic-gate {
8020Sstevel@tonic-gate 	int flags = (int)arg;
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate 	out(flags, "\t%s=%s", lhs, rhs);
8050Sstevel@tonic-gate }
8060Sstevel@tonic-gate 
8070Sstevel@tonic-gate /*
8080Sstevel@tonic-gate  * pconf -- internal printing function to recurse through the tree
8090Sstevel@tonic-gate  */
8100Sstevel@tonic-gate static void
8110Sstevel@tonic-gate pconf(int flags, struct config *cp, char *buf, int offset, int limit)
8120Sstevel@tonic-gate {
8130Sstevel@tonic-gate 	char *sep = "/";
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 	if (offset)
8160Sstevel@tonic-gate 		sep = "/";
8170Sstevel@tonic-gate 	else
8180Sstevel@tonic-gate 		sep = "";
8190Sstevel@tonic-gate 	(void) snprintf(&buf[offset], limit - offset, "%s%s%d",
8200Sstevel@tonic-gate 	    sep, cp->s, cp->num);
8210Sstevel@tonic-gate 	if (cp->child == NULL) {
8220Sstevel@tonic-gate 		out(flags, "%s", buf);
8230Sstevel@tonic-gate 		lut_walk(cp->props, (lut_cb)printprop, (void *)flags);
8240Sstevel@tonic-gate 	} else
8250Sstevel@tonic-gate 		pconf(flags, cp->child, buf, strlen(buf), limit);
8260Sstevel@tonic-gate 	if (cp->next)
8270Sstevel@tonic-gate 		pconf(flags, cp->next, buf, offset, limit);
8280Sstevel@tonic-gate }
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate /*
8310Sstevel@tonic-gate  * config_print -- spew the current configuration cache
8320Sstevel@tonic-gate  */
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate #define	MAXCONFLINE 4096
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate void
8370Sstevel@tonic-gate config_print(int flags, struct config *croot)
8380Sstevel@tonic-gate {
8390Sstevel@tonic-gate 	char buf[MAXCONFLINE];
8400Sstevel@tonic-gate 
8410Sstevel@tonic-gate 	if (croot == NULL)
8420Sstevel@tonic-gate 		out(flags, "empty configuration");
8430Sstevel@tonic-gate 	else
8440Sstevel@tonic-gate 		pconf(flags, croot->child, buf, 0, MAXCONFLINE);
8450Sstevel@tonic-gate }
846