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