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