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 51490Stimh * Common Development and Distribution License (the "License"). 61490Stimh * 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 */ 211490Stimh 220Sstevel@tonic-gate /* 23*6640Scth * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 251490Stimh */ 261490Stimh 271490Stimh #pragma ident "%Z%%M% %I% %E% SMI" 281490Stimh 291490Stimh /* 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> 443062Scindi #include <fm/topo_hc.h> 450Sstevel@tonic-gate #include "alloc.h" 460Sstevel@tonic-gate #include "out.h" 470Sstevel@tonic-gate #include "literals.h" 480Sstevel@tonic-gate #include "stable.h" 490Sstevel@tonic-gate #include "lut.h" 500Sstevel@tonic-gate #include "tree.h" 510Sstevel@tonic-gate #include "itree.h" 520Sstevel@tonic-gate #include "ipath.h" 530Sstevel@tonic-gate #include "ptree.h" 540Sstevel@tonic-gate #include "eval.h" 550Sstevel@tonic-gate #include "config.h" 565433Saf #include "config_impl.h" 570Sstevel@tonic-gate #include "fme.h" 580Sstevel@tonic-gate #include "platform.h" 590Sstevel@tonic-gate 604436Sstephh static const char *config_lastcomp; 614436Sstephh 620Sstevel@tonic-gate /* 630Sstevel@tonic-gate * newcnode -- local function to allocate new config node 640Sstevel@tonic-gate */ 650Sstevel@tonic-gate static struct config * 660Sstevel@tonic-gate newcnode(const char *s, int num) 670Sstevel@tonic-gate { 680Sstevel@tonic-gate struct config *retval; 690Sstevel@tonic-gate 700Sstevel@tonic-gate retval = MALLOC(sizeof (struct config)); 710Sstevel@tonic-gate 720Sstevel@tonic-gate retval->s = s; 730Sstevel@tonic-gate retval->num = num; 740Sstevel@tonic-gate retval->next = NULL; 750Sstevel@tonic-gate retval->props = NULL; 760Sstevel@tonic-gate retval->child = retval->parent = NULL; 770Sstevel@tonic-gate 780Sstevel@tonic-gate return (retval); 790Sstevel@tonic-gate } 800Sstevel@tonic-gate 810Sstevel@tonic-gate /* 820Sstevel@tonic-gate * If we need to cache certain types of nodes for reverse look-up or 830Sstevel@tonic-gate * somesuch, do it here. Currently we need to cache nodes representing 840Sstevel@tonic-gate * cpus. 850Sstevel@tonic-gate */ 860Sstevel@tonic-gate static void 870Sstevel@tonic-gate config_node_cache(struct cfgdata *cdata, struct config *n) 880Sstevel@tonic-gate { 890Sstevel@tonic-gate if (n->s != stable("cpu")) 900Sstevel@tonic-gate return; 910Sstevel@tonic-gate cdata->cpucache = lut_add(cdata->cpucache, 920Sstevel@tonic-gate (void *)n->num, (void *)n, NULL); 930Sstevel@tonic-gate } 940Sstevel@tonic-gate 950Sstevel@tonic-gate /* 960Sstevel@tonic-gate * config_lookup -- lookup/add components in configuration cache 970Sstevel@tonic-gate */ 980Sstevel@tonic-gate struct config * 990Sstevel@tonic-gate config_lookup(struct config *croot, char *path, int add) 1000Sstevel@tonic-gate { 1010Sstevel@tonic-gate char *pathbegin = path; 1020Sstevel@tonic-gate struct config *parent = croot; 1030Sstevel@tonic-gate struct config *cp; 1040Sstevel@tonic-gate struct config *lastcp; 1050Sstevel@tonic-gate struct config *newnode; 1060Sstevel@tonic-gate char *thiscom; /* this component */ 1070Sstevel@tonic-gate char *nextcom; /* next component */ 1080Sstevel@tonic-gate char svdigit; 1090Sstevel@tonic-gate int len; 1100Sstevel@tonic-gate int num; 1110Sstevel@tonic-gate const char *s; 1120Sstevel@tonic-gate int exists; 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate if (parent == NULL) 1150Sstevel@tonic-gate out(O_DIE, "uninitialized configuration"); 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate while (*path) { 1180Sstevel@tonic-gate if ((nextcom = strchr(path, '/')) != NULL) 1190Sstevel@tonic-gate *nextcom = '\0'; 1200Sstevel@tonic-gate if ((len = strlen(path)) == 0) 1210Sstevel@tonic-gate out(O_DIE, "config_lookup: zero length component"); 1220Sstevel@tonic-gate /* start at end of string and work backwards */ 1230Sstevel@tonic-gate thiscom = &path[len - 1]; 1240Sstevel@tonic-gate if (!isdigit(*thiscom)) 1250Sstevel@tonic-gate out(O_DIE, "config_lookup: " 1260Sstevel@tonic-gate "component \"%s\" has no number following it", 1270Sstevel@tonic-gate path); 1280Sstevel@tonic-gate while (thiscom > path && isdigit(*thiscom)) 1290Sstevel@tonic-gate thiscom--; 1300Sstevel@tonic-gate if (thiscom == path && isdigit(*thiscom)) 1310Sstevel@tonic-gate out(O_DIE, "config_lookup: " 1320Sstevel@tonic-gate "component \"%s\" has no name part", path); 1330Sstevel@tonic-gate thiscom++; /* move to first numeric character */ 1340Sstevel@tonic-gate num = atoi(thiscom); 1350Sstevel@tonic-gate svdigit = *thiscom; 1360Sstevel@tonic-gate *thiscom = '\0'; 1370Sstevel@tonic-gate s = stable(path); 1384436Sstephh if (add) 1394436Sstephh config_lastcomp = s; 1400Sstevel@tonic-gate *thiscom = svdigit; 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate if (nextcom != NULL) 1430Sstevel@tonic-gate *nextcom++ = '/'; 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate /* now we have s & num, figure out if it exists already */ 1460Sstevel@tonic-gate exists = 0; 1470Sstevel@tonic-gate lastcp = NULL; 1480Sstevel@tonic-gate for (cp = parent->child; cp; lastcp = cp, cp = cp->next) 1490Sstevel@tonic-gate if (cp->s == s && cp->num == num) { 1500Sstevel@tonic-gate exists = 1; 1510Sstevel@tonic-gate parent = cp; 1520Sstevel@tonic-gate } 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate if (!exists) { 1550Sstevel@tonic-gate /* creating new node */ 1560Sstevel@tonic-gate if (!add) { 1570Sstevel@tonic-gate /* 1580Sstevel@tonic-gate * indicate component not found by copying 1590Sstevel@tonic-gate * it to path (allows better error messages 1600Sstevel@tonic-gate * in the caller). 1610Sstevel@tonic-gate */ 1620Sstevel@tonic-gate (void) strcpy(pathbegin, s); 1630Sstevel@tonic-gate return (NULL); 1640Sstevel@tonic-gate } 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate newnode = newcnode(s, num); 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate if (lastcp) 1690Sstevel@tonic-gate lastcp->next = newnode; 1700Sstevel@tonic-gate else 1710Sstevel@tonic-gate parent->child = newnode; 1720Sstevel@tonic-gate 1730Sstevel@tonic-gate newnode->parent = parent; 1740Sstevel@tonic-gate parent = newnode; 1750Sstevel@tonic-gate } 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate if (nextcom == NULL) 1780Sstevel@tonic-gate return (parent); /* all done */ 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate /* move on to next component */ 1810Sstevel@tonic-gate path = nextcom; 1820Sstevel@tonic-gate } 1830Sstevel@tonic-gate return (parent); 1840Sstevel@tonic-gate } 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate /* 1870Sstevel@tonic-gate * addconfigprop -- add a config prop to a config cache entry 1880Sstevel@tonic-gate */ 1890Sstevel@tonic-gate static void 1900Sstevel@tonic-gate addconfigprop(const char *lhs, struct node *rhs, void *arg) 1910Sstevel@tonic-gate { 1920Sstevel@tonic-gate struct config *cp = (struct config *)arg; 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate ASSERT(cp != NULL); 1950Sstevel@tonic-gate ASSERT(lhs != NULL); 1960Sstevel@tonic-gate ASSERT(rhs != NULL); 1970Sstevel@tonic-gate ASSERT(rhs->t == T_QUOTE); 1980Sstevel@tonic-gate 1990Sstevel@tonic-gate config_setprop(cp, lhs, STRDUP(rhs->u.quote.s)); 2000Sstevel@tonic-gate } 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate /* 2030Sstevel@tonic-gate * addconfig -- add a config from parse tree to given configuration cache 2040Sstevel@tonic-gate */ 2050Sstevel@tonic-gate /*ARGSUSED*/ 2060Sstevel@tonic-gate static void 2070Sstevel@tonic-gate addconfig(struct node *lhs, struct node *rhs, void *arg) 2080Sstevel@tonic-gate { 2090Sstevel@tonic-gate struct config *parent = (struct config *)arg; 2100Sstevel@tonic-gate struct config *cp; 2110Sstevel@tonic-gate const char *s; 2120Sstevel@tonic-gate int num; 2130Sstevel@tonic-gate struct config *lastcp; 2140Sstevel@tonic-gate struct config *newnode; 2150Sstevel@tonic-gate int exists; 2160Sstevel@tonic-gate struct lut *lutp; 2170Sstevel@tonic-gate 2180Sstevel@tonic-gate ASSERT(rhs->t == T_CONFIG); 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate lutp = rhs->u.stmt.lutp; 2210Sstevel@tonic-gate rhs = rhs->u.stmt.np; 2220Sstevel@tonic-gate while (rhs != NULL) { 2230Sstevel@tonic-gate ASSERT(rhs->t == T_NAME); 2240Sstevel@tonic-gate ASSERT(rhs->u.name.child->t == T_NUM); 2250Sstevel@tonic-gate s = rhs->u.name.s; 2260Sstevel@tonic-gate num = rhs->u.name.child->u.ull; 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate /* now we have s & num, figure out if it exists already */ 2290Sstevel@tonic-gate exists = 0; 2300Sstevel@tonic-gate lastcp = NULL; 2310Sstevel@tonic-gate for (cp = parent->child; cp; lastcp = cp, cp = cp->next) 2320Sstevel@tonic-gate if (cp->s == s && cp->num == num) { 2330Sstevel@tonic-gate exists = 1; 2340Sstevel@tonic-gate parent = cp; 2350Sstevel@tonic-gate } 2360Sstevel@tonic-gate 2370Sstevel@tonic-gate if (!exists) { 2380Sstevel@tonic-gate /* creating new node */ 2390Sstevel@tonic-gate 2400Sstevel@tonic-gate newnode = newcnode(s, num); 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate if (lastcp) 2430Sstevel@tonic-gate lastcp->next = newnode; 2440Sstevel@tonic-gate else 2450Sstevel@tonic-gate parent->child = newnode; 2460Sstevel@tonic-gate 2474436Sstephh newnode->parent = parent; 2480Sstevel@tonic-gate parent = newnode; 2490Sstevel@tonic-gate } 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate /* move on to next component */ 2520Sstevel@tonic-gate rhs = rhs->u.name.next; 2530Sstevel@tonic-gate } 2540Sstevel@tonic-gate 2550Sstevel@tonic-gate /* add configuration properties */ 2560Sstevel@tonic-gate lut_walk(lutp, (lut_cb)addconfigprop, (void *)parent); 2570Sstevel@tonic-gate } 2580Sstevel@tonic-gate 2590Sstevel@tonic-gate /* 2600Sstevel@tonic-gate * config_cook -- convert raw config strings to eft internal representation 2610Sstevel@tonic-gate */ 2620Sstevel@tonic-gate void 2630Sstevel@tonic-gate config_cook(struct cfgdata *cdata) 2640Sstevel@tonic-gate { 2650Sstevel@tonic-gate struct config *newnode; 2660Sstevel@tonic-gate char *cfgstr, *equals; 2670Sstevel@tonic-gate const char *pn, *sv; 2680Sstevel@tonic-gate char *pv; 2694436Sstephh const char *ptr; 2704436Sstephh extern struct lut *Usedprops; 2714436Sstephh extern struct lut *Usednames; 2724436Sstephh 2730Sstevel@tonic-gate cdata->cooked = newcnode(NULL, 0); 2740Sstevel@tonic-gate 2750Sstevel@tonic-gate if ((cfgstr = cdata->begin) == cdata->nextfree) { 2760Sstevel@tonic-gate out(O_ALTFP|O_VERB, "Platform provided no config data."); 2770Sstevel@tonic-gate goto eftcfgs; 2780Sstevel@tonic-gate } 2790Sstevel@tonic-gate 2804436Sstephh /* 2814436Sstephh * add the following properties to the "usedprops" table as they 2824436Sstephh * are used internally by eft 2834436Sstephh */ 2844436Sstephh ptr = stable("module"); 2854436Sstephh Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL); 2864436Sstephh ptr = stable("resource"); 2874436Sstephh Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL); 2884436Sstephh ptr = stable("ASRU"); 2894436Sstephh Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL); 2904436Sstephh ptr = stable("FRU"); 2914436Sstephh Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL); 2924436Sstephh 2930Sstevel@tonic-gate out(O_ALTFP|O_VERB3, "Raw config data follows:"); 2940Sstevel@tonic-gate out(O_ALTFP|O_VERB3|O_NONL, 2950Sstevel@tonic-gate "nextfree is %p\n%p ", (void *)cdata->nextfree, (void *)cfgstr); 2960Sstevel@tonic-gate while (cfgstr < cdata->nextfree) { 2970Sstevel@tonic-gate if (!*cfgstr) 2980Sstevel@tonic-gate out(O_ALTFP|O_VERB3|O_NONL, "\n%p ", 2990Sstevel@tonic-gate (void *)(cfgstr + 1)); 3000Sstevel@tonic-gate else 3010Sstevel@tonic-gate out(O_ALTFP|O_VERB3|O_NONL, "%c", *cfgstr); 3020Sstevel@tonic-gate cfgstr++; 3030Sstevel@tonic-gate } 3040Sstevel@tonic-gate out(O_ALTFP|O_VERB3, NULL); 3050Sstevel@tonic-gate 3060Sstevel@tonic-gate cfgstr = cdata->begin; 3070Sstevel@tonic-gate while (cfgstr < cdata->nextfree) { 3080Sstevel@tonic-gate while (*cfgstr == '/' && cfgstr < cdata->nextfree) { 3090Sstevel@tonic-gate out(O_ALTFP|O_VERB3, 3100Sstevel@tonic-gate "next string (%p) is %s", (void *)cfgstr, cfgstr); 3110Sstevel@tonic-gate /* skip the initial slash from libtopo */ 3120Sstevel@tonic-gate newnode = config_lookup(cdata->cooked, cfgstr + 1, 1); 3130Sstevel@tonic-gate /* 3140Sstevel@tonic-gate * Note we'll only cache nodes that have 3150Sstevel@tonic-gate * properties on them. Intermediate nodes 3160Sstevel@tonic-gate * will have been added to the config tree, 3170Sstevel@tonic-gate * but we don't have easy means of accessing 3180Sstevel@tonic-gate * them except if we climb the tree from this 3190Sstevel@tonic-gate * newnode to the root. 3200Sstevel@tonic-gate * 3210Sstevel@tonic-gate * Luckily, the nodes we care to cache 3220Sstevel@tonic-gate * (currently just cpus) always have some 3230Sstevel@tonic-gate * properties attached to them 3240Sstevel@tonic-gate * so we don't bother climbing the tree. 3250Sstevel@tonic-gate */ 3260Sstevel@tonic-gate config_node_cache(cdata, newnode); 3270Sstevel@tonic-gate cfgstr += strlen(cfgstr) + 1; 3280Sstevel@tonic-gate } 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate if (cfgstr >= cdata->nextfree) 3310Sstevel@tonic-gate break; 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate out(O_ALTFP|O_VERB3, "next string (%p) is %s", (void *)cfgstr, 3340Sstevel@tonic-gate cfgstr); 3350Sstevel@tonic-gate if ((equals = strchr(cfgstr, '=')) == NULL) { 3360Sstevel@tonic-gate out(O_ALTFP|O_VERB3, "raw config data bad (%p); " 3370Sstevel@tonic-gate "property missing equals.\n", (void *)cfgstr); 3380Sstevel@tonic-gate break; 3390Sstevel@tonic-gate } 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate *equals = '\0'; 3420Sstevel@tonic-gate pn = stable(cfgstr); 3430Sstevel@tonic-gate 3444436Sstephh /* 3454436Sstephh * only actually add the props if the rules use them (saves 3464436Sstephh * memory) 3474436Sstephh */ 3485204Sstephh if ((lut_lookup(Usedprops, (void *)pn, NULL) != NULL || 3495204Sstephh strncmp(pn, "serd_", 5) == 0) && lut_lookup(Usednames, 3505204Sstephh (void *)config_lastcomp, NULL) != NULL) { 3514436Sstephh pv = STRDUP(equals + 1); 3524436Sstephh out(O_ALTFP|O_VERB3, "add prop (%s) val %p", pn, 3534436Sstephh (void *)pv); 3544436Sstephh config_setprop(newnode, pn, pv); 3554436Sstephh } 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate /* 358*6640Scth * If this property is a device path or devid, cache it 359*6640Scth * for quick lookup. 3600Sstevel@tonic-gate */ 3613062Scindi if (pn == stable(TOPO_IO_DEV)) { 3624436Sstephh sv = stable(equals + 1); 363*6640Scth out(O_ALTFP|O_VERB3, "caching dev %s\n", sv); 3640Sstevel@tonic-gate cdata->devcache = lut_add(cdata->devcache, 3650Sstevel@tonic-gate (void *)sv, (void *)newnode, NULL); 366*6640Scth } else if (pn == stable(TOPO_IO_DEVID)) { 367*6640Scth sv = stable(equals + 1); 368*6640Scth out(O_ALTFP|O_VERB3, "caching devid %s\n", sv); 369*6640Scth cdata->devidcache = lut_add(cdata->devidcache, 370*6640Scth (void *)sv, (void *)newnode, NULL); 3710Sstevel@tonic-gate } 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate *equals = '='; 3740Sstevel@tonic-gate cfgstr += strlen(cfgstr) + 1; 3750Sstevel@tonic-gate } 3760Sstevel@tonic-gate 3770Sstevel@tonic-gate eftcfgs: 3780Sstevel@tonic-gate /* now run through Configs table, adding to config cache */ 3790Sstevel@tonic-gate lut_walk(Configs, (lut_cb)addconfig, (void *)cdata->cooked); 3800Sstevel@tonic-gate } 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate /* 3830Sstevel@tonic-gate * config_snapshot -- gather a snapshot of the current configuration 3840Sstevel@tonic-gate */ 3850Sstevel@tonic-gate struct cfgdata * 3860Sstevel@tonic-gate config_snapshot(void) 3870Sstevel@tonic-gate { 3880Sstevel@tonic-gate struct cfgdata *rawcfg; 3890Sstevel@tonic-gate 3900Sstevel@tonic-gate rawcfg = platform_config_snapshot(); 3910Sstevel@tonic-gate config_cook(rawcfg); 3920Sstevel@tonic-gate return (rawcfg); 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate /* 3960Sstevel@tonic-gate * prop_destructor -- free a prop value 3970Sstevel@tonic-gate */ 3980Sstevel@tonic-gate /*ARGSUSED*/ 3990Sstevel@tonic-gate static void 4000Sstevel@tonic-gate prop_destructor(void *left, void *right, void *arg) 4010Sstevel@tonic-gate { 4020Sstevel@tonic-gate FREE(right); 4030Sstevel@tonic-gate } 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate /* 4060Sstevel@tonic-gate * structconfig_free -- free a struct config pointer and all its relatives 4070Sstevel@tonic-gate */ 4085204Sstephh void 4090Sstevel@tonic-gate structconfig_free(struct config *cp) 4100Sstevel@tonic-gate { 4110Sstevel@tonic-gate if (cp == NULL) 4120Sstevel@tonic-gate return; 4130Sstevel@tonic-gate 4140Sstevel@tonic-gate structconfig_free(cp->child); 4150Sstevel@tonic-gate structconfig_free(cp->next); 4160Sstevel@tonic-gate lut_free(cp->props, prop_destructor, NULL); 4170Sstevel@tonic-gate FREE(cp); 4180Sstevel@tonic-gate } 4190Sstevel@tonic-gate 4200Sstevel@tonic-gate /* 4210Sstevel@tonic-gate * config_free -- free a configuration snapshot 4220Sstevel@tonic-gate */ 4230Sstevel@tonic-gate void 4240Sstevel@tonic-gate config_free(struct cfgdata *cp) 4250Sstevel@tonic-gate { 4260Sstevel@tonic-gate if (cp == NULL) 4270Sstevel@tonic-gate return; 4280Sstevel@tonic-gate 4295204Sstephh if (--cp->raw_refcnt == 0) { 4304436Sstephh if (cp->devcache != NULL) 4314436Sstephh lut_free(cp->devcache, NULL, NULL); 4324436Sstephh cp->devcache = NULL; 433*6640Scth if (cp->devidcache != NULL) 434*6640Scth lut_free(cp->devidcache, NULL, NULL); 435*6640Scth cp->devidcache = NULL; 4364436Sstephh if (cp->cpucache != NULL) 4374436Sstephh lut_free(cp->cpucache, NULL, NULL); 4384436Sstephh cp->cpucache = NULL; 4394436Sstephh if (cp->begin != NULL) 4404436Sstephh FREE(cp->begin); 4414436Sstephh FREE(cp); 4424436Sstephh } 4430Sstevel@tonic-gate } 4440Sstevel@tonic-gate 4450Sstevel@tonic-gate /* 4460Sstevel@tonic-gate * config_next -- get the "next" config node 4470Sstevel@tonic-gate */ 4480Sstevel@tonic-gate struct config * 4490Sstevel@tonic-gate config_next(struct config *cp) 4500Sstevel@tonic-gate { 4510Sstevel@tonic-gate ASSERT(cp != NULL); 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate return ((struct config *)((struct config *)cp)->next); 4540Sstevel@tonic-gate } 4550Sstevel@tonic-gate 4560Sstevel@tonic-gate 4570Sstevel@tonic-gate /* 4580Sstevel@tonic-gate * config_child -- get the "child" of a config node 4590Sstevel@tonic-gate */ 4600Sstevel@tonic-gate struct config * 4610Sstevel@tonic-gate config_child(struct config *cp) 4620Sstevel@tonic-gate { 4630Sstevel@tonic-gate ASSERT(cp != NULL); 4640Sstevel@tonic-gate 4650Sstevel@tonic-gate return ((struct config *)((struct config *)cp)->child); 4660Sstevel@tonic-gate } 4670Sstevel@tonic-gate 4680Sstevel@tonic-gate /* 4694436Sstephh * config_parent -- get the "parent" of a config node 4704436Sstephh */ 4714436Sstephh struct config * 4724436Sstephh config_parent(struct config *cp) 4734436Sstephh { 4744436Sstephh ASSERT(cp != NULL); 4754436Sstephh 4764436Sstephh return ((struct config *)((struct config *)cp)->parent); 4774436Sstephh } 4784436Sstephh 4794436Sstephh /* 4800Sstevel@tonic-gate * config_setprop -- add a property to a config node 4810Sstevel@tonic-gate */ 4820Sstevel@tonic-gate void 4830Sstevel@tonic-gate config_setprop(struct config *cp, const char *propname, const char *propvalue) 4840Sstevel@tonic-gate { 4850Sstevel@tonic-gate const char *pn = stable(propname); 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate cp->props = lut_add(cp->props, (void *)pn, (void *)propvalue, NULL); 4880Sstevel@tonic-gate } 4890Sstevel@tonic-gate 4900Sstevel@tonic-gate /* 4910Sstevel@tonic-gate * config_getprop -- lookup a config property 4920Sstevel@tonic-gate */ 4930Sstevel@tonic-gate const char * 4940Sstevel@tonic-gate config_getprop(struct config *cp, const char *propname) 4950Sstevel@tonic-gate { 4960Sstevel@tonic-gate return (lut_lookup(cp->props, (void *) stable(propname), NULL)); 4970Sstevel@tonic-gate } 4980Sstevel@tonic-gate 4990Sstevel@tonic-gate /* 5000Sstevel@tonic-gate * config_getcompname -- get the component name of a config node 5010Sstevel@tonic-gate */ 5020Sstevel@tonic-gate void 5030Sstevel@tonic-gate config_getcompname(struct config *cp, char **name, int *inst) 5040Sstevel@tonic-gate { 5050Sstevel@tonic-gate ASSERT(cp != NULL); 5060Sstevel@tonic-gate 5070Sstevel@tonic-gate if (name != NULL) 5080Sstevel@tonic-gate *name = (char *)cp->s; 5090Sstevel@tonic-gate if (inst != NULL) 5100Sstevel@tonic-gate *inst = cp->num; 5110Sstevel@tonic-gate } 5120Sstevel@tonic-gate 5130Sstevel@tonic-gate /* 5140Sstevel@tonic-gate * config_nodeize -- convert the config element represented by cp to struct 5150Sstevel@tonic-gate * node format 5160Sstevel@tonic-gate */ 5170Sstevel@tonic-gate static struct node * 5180Sstevel@tonic-gate config_nodeize(struct config *cp) 5190Sstevel@tonic-gate { 5200Sstevel@tonic-gate struct node *tmpn, *ptmpn; 5210Sstevel@tonic-gate struct node *numn; 5220Sstevel@tonic-gate const char *sname; 5230Sstevel@tonic-gate 5240Sstevel@tonic-gate if (cp == NULL || cp->s == NULL) 5250Sstevel@tonic-gate return (NULL); 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate sname = stable(cp->s); 5280Sstevel@tonic-gate numn = newnode(T_NUM, NULL, 0); 5290Sstevel@tonic-gate numn->u.ull = cp->num; 5300Sstevel@tonic-gate 5310Sstevel@tonic-gate tmpn = tree_name_iterator(tree_name(sname, IT_VERTICAL, NULL, 0), numn); 5320Sstevel@tonic-gate if ((ptmpn = config_nodeize(cp->parent)) == NULL) 5330Sstevel@tonic-gate return (tmpn); 5340Sstevel@tonic-gate return (tree_name_append(ptmpn, tmpn)); 5350Sstevel@tonic-gate } 5360Sstevel@tonic-gate 5370Sstevel@tonic-gate /*ARGSUSED*/ 5380Sstevel@tonic-gate static void 5390Sstevel@tonic-gate prtdevcache(void *lhs, void *rhs, void *arg) 5400Sstevel@tonic-gate { 5410Sstevel@tonic-gate out(O_ALTFP|O_VERB3, "%s -> %p", (char *)lhs, rhs); 5420Sstevel@tonic-gate } 5430Sstevel@tonic-gate 5440Sstevel@tonic-gate /*ARGSUSED*/ 5450Sstevel@tonic-gate static void 546*6640Scth prtdevidcache(void *lhs, void *rhs, void *arg) 547*6640Scth { 548*6640Scth out(O_ALTFP|O_VERB3, "%s -> %p", (char *)lhs, rhs); 549*6640Scth } 550*6640Scth 551*6640Scth /*ARGSUSED*/ 552*6640Scth static void 5530Sstevel@tonic-gate prtcpucache(void *lhs, void *rhs, void *arg) 5540Sstevel@tonic-gate { 5550Sstevel@tonic-gate out(O_ALTFP|O_VERB, "%u -> %p", (uint32_t)lhs, rhs); 5560Sstevel@tonic-gate } 5570Sstevel@tonic-gate 5580Sstevel@tonic-gate /* 559*6640Scth * config_bydev_lookup -- look up the path in our devcache lut. If we find 5600Sstevel@tonic-gate * it return the config path, but as a struct node. 5610Sstevel@tonic-gate */ 5620Sstevel@tonic-gate struct node * 5630Sstevel@tonic-gate config_bydev_lookup(struct cfgdata *fromcfg, const char *path) 5640Sstevel@tonic-gate { 5650Sstevel@tonic-gate struct config *find; 5660Sstevel@tonic-gate struct node *np; 5670Sstevel@tonic-gate 5680Sstevel@tonic-gate out(O_ALTFP|O_VERB3, "Device path cache:"); 5690Sstevel@tonic-gate lut_walk(fromcfg->devcache, (lut_cb)prtdevcache, NULL); 5700Sstevel@tonic-gate 5710Sstevel@tonic-gate if ((find = lut_lookup(fromcfg->devcache, 5720Sstevel@tonic-gate (void *) stable(path), NULL)) == NULL) 5730Sstevel@tonic-gate return (NULL); 5740Sstevel@tonic-gate 5750Sstevel@tonic-gate np = config_nodeize(find); 5760Sstevel@tonic-gate if (np != NULL) { 5770Sstevel@tonic-gate out(O_ALTFP|O_VERB, "Matching config entry:"); 5780Sstevel@tonic-gate ptree_name_iter(O_ALTFP|O_VERB|O_NONL, np); 5790Sstevel@tonic-gate out(O_ALTFP|O_VERB, NULL); 5800Sstevel@tonic-gate } 5810Sstevel@tonic-gate return (np); 5820Sstevel@tonic-gate } 5830Sstevel@tonic-gate 5840Sstevel@tonic-gate /* 585*6640Scth * config_bydevid_lookup -- look up the path in our DEVIDcache lut. 586*6640Scth * If we find it return the config path, but as a struct node. 587*6640Scth */ 588*6640Scth struct node * 589*6640Scth config_bydevid_lookup(struct cfgdata *fromcfg, const char *devid) 590*6640Scth { 591*6640Scth struct config *find; 592*6640Scth struct node *np; 593*6640Scth 594*6640Scth out(O_ALTFP|O_VERB3, "Device id cache:"); 595*6640Scth lut_walk(fromcfg->devcache, (lut_cb)prtdevidcache, NULL); 596*6640Scth 597*6640Scth if ((find = lut_lookup(fromcfg->devidcache, 598*6640Scth (void *) stable(devid), NULL)) == NULL) 599*6640Scth return (NULL); 600*6640Scth 601*6640Scth np = config_nodeize(find); 602*6640Scth if (np != NULL) { 603*6640Scth out(O_ALTFP|O_VERB, "Matching config entry:"); 604*6640Scth ptree_name_iter(O_ALTFP|O_VERB|O_NONL, np); 605*6640Scth out(O_ALTFP|O_VERB, NULL); 606*6640Scth } 607*6640Scth return (np); 608*6640Scth } 609*6640Scth 610*6640Scth /* 6110Sstevel@tonic-gate * config_bycpuid_lookup -- look up the cpu id in our CPUcache lut. 6120Sstevel@tonic-gate * If we find it return the config path, but as a struct node. 6130Sstevel@tonic-gate */ 6140Sstevel@tonic-gate struct node * 6150Sstevel@tonic-gate config_bycpuid_lookup(struct cfgdata *fromcfg, uint32_t id) 6160Sstevel@tonic-gate { 6170Sstevel@tonic-gate struct config *find; 6180Sstevel@tonic-gate struct node *np; 6190Sstevel@tonic-gate 6200Sstevel@tonic-gate out(O_ALTFP|O_VERB, "Cpu cache:"); 6210Sstevel@tonic-gate lut_walk(fromcfg->cpucache, (lut_cb)prtcpucache, NULL); 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate if ((find = lut_lookup(fromcfg->cpucache, 6240Sstevel@tonic-gate (void *)id, NULL)) == NULL) 6250Sstevel@tonic-gate return (NULL); 6260Sstevel@tonic-gate 6270Sstevel@tonic-gate np = config_nodeize(find); 6280Sstevel@tonic-gate if (np != NULL) { 6290Sstevel@tonic-gate out(O_ALTFP|O_VERB3, "Matching config entry:"); 6300Sstevel@tonic-gate ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, np); 6310Sstevel@tonic-gate out(O_ALTFP|O_VERB3, NULL); 6320Sstevel@tonic-gate } 6330Sstevel@tonic-gate return (np); 6340Sstevel@tonic-gate } 6350Sstevel@tonic-gate 6360Sstevel@tonic-gate /* 6370Sstevel@tonic-gate * printprop -- print prop associated with config node 6380Sstevel@tonic-gate */ 6390Sstevel@tonic-gate static void 6400Sstevel@tonic-gate printprop(const char *lhs, const char *rhs, void *arg) 6410Sstevel@tonic-gate { 6420Sstevel@tonic-gate int flags = (int)arg; 6430Sstevel@tonic-gate 6440Sstevel@tonic-gate out(flags, "\t%s=%s", lhs, rhs); 6450Sstevel@tonic-gate } 6460Sstevel@tonic-gate 6470Sstevel@tonic-gate /* 6480Sstevel@tonic-gate * pconf -- internal printing function to recurse through the tree 6490Sstevel@tonic-gate */ 6500Sstevel@tonic-gate static void 6510Sstevel@tonic-gate pconf(int flags, struct config *cp, char *buf, int offset, int limit) 6520Sstevel@tonic-gate { 6530Sstevel@tonic-gate char *sep = "/"; 6540Sstevel@tonic-gate 6550Sstevel@tonic-gate if (offset) 6560Sstevel@tonic-gate sep = "/"; 6570Sstevel@tonic-gate else 6580Sstevel@tonic-gate sep = ""; 6590Sstevel@tonic-gate (void) snprintf(&buf[offset], limit - offset, "%s%s%d", 6600Sstevel@tonic-gate sep, cp->s, cp->num); 6610Sstevel@tonic-gate if (cp->child == NULL) { 6620Sstevel@tonic-gate out(flags, "%s", buf); 6630Sstevel@tonic-gate lut_walk(cp->props, (lut_cb)printprop, (void *)flags); 6640Sstevel@tonic-gate } else 6650Sstevel@tonic-gate pconf(flags, cp->child, buf, strlen(buf), limit); 6660Sstevel@tonic-gate if (cp->next) 6670Sstevel@tonic-gate pconf(flags, cp->next, buf, offset, limit); 6680Sstevel@tonic-gate } 6690Sstevel@tonic-gate 6700Sstevel@tonic-gate /* 6710Sstevel@tonic-gate * config_print -- spew the current configuration cache 6720Sstevel@tonic-gate */ 6730Sstevel@tonic-gate 6740Sstevel@tonic-gate #define MAXCONFLINE 4096 6750Sstevel@tonic-gate 6760Sstevel@tonic-gate void 6770Sstevel@tonic-gate config_print(int flags, struct config *croot) 6780Sstevel@tonic-gate { 6790Sstevel@tonic-gate char buf[MAXCONFLINE]; 6800Sstevel@tonic-gate 6810Sstevel@tonic-gate if (croot == NULL) 6820Sstevel@tonic-gate out(flags, "empty configuration"); 6830Sstevel@tonic-gate else 6840Sstevel@tonic-gate pconf(flags, croot->child, buf, 0, MAXCONFLINE); 6850Sstevel@tonic-gate } 686