Home | History | Annotate | Download | only in eversholt
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 /*
     30  * config.c -- system configuration cache module
     31  *
     32  * this module caches the system configuration in a format useful
     33  * to eft.  the information is loaded into this module by
     34  * config_snapshot() at the beginning of each FME.  config_snapshot()
     35  * calls the platform-specific platform_config_snapshot() to get
     36  * the configuration information loaded up.
     37  */
     38 
     39 #include <stdio.h>
     40 #include <stdlib.h>
     41 #include <ctype.h>
     42 #include <string.h>
     43 #include <strings.h>
     44 #include <fm/topo_hc.h>
     45 #include "alloc.h"
     46 #include "out.h"
     47 #include "literals.h"
     48 #include "stable.h"
     49 #include "lut.h"
     50 #include "tree.h"
     51 #include "itree.h"
     52 #include "ipath.h"
     53 #include "ptree.h"
     54 #include "eval.h"
     55 #include "config.h"
     56 #include "config_impl.h"
     57 #include "fme.h"
     58 #include "platform.h"
     59 
     60 static const char *config_lastcomp;
     61 
     62 /*
     63  * newcnode -- local function to allocate new config node
     64  */
     65 static struct config *
     66 newcnode(const char *s, int num)
     67 {
     68 	struct config *retval;
     69 
     70 	retval = MALLOC(sizeof (struct config));
     71 
     72 	retval->s = s;
     73 	retval->num = num;
     74 	retval->next = NULL;
     75 	retval->props = NULL;
     76 	retval->child = retval->parent = NULL;
     77 
     78 	return (retval);
     79 }
     80 
     81 /*
     82  * If we need to cache certain types of nodes for reverse look-up or
     83  * somesuch, do it here.  Currently we need to cache nodes representing
     84  * cpus.
     85  */
     86 static void
     87 config_node_cache(struct cfgdata *cdata, struct config *n)
     88 {
     89 	if (n->s != stable("cpu"))
     90 		return;
     91 	cdata->cpucache = lut_add(cdata->cpucache,
     92 	    (void *)n->num, (void *)n, NULL);
     93 }
     94 
     95 /*
     96  * config_lookup -- lookup/add components in configuration cache
     97  */
     98 struct config *
     99 config_lookup(struct config *croot, char *path, int add)
    100 {
    101 	char *pathbegin = path;
    102 	struct config *parent = croot;
    103 	struct config *cp;
    104 	struct config *lastcp;
    105 	struct config *newnode;
    106 	char *thiscom;	/* this component */
    107 	char *nextcom;	/* next component */
    108 	char svdigit;
    109 	int len;
    110 	int num;
    111 	const char *s;
    112 	int exists;
    113 
    114 	if (parent == NULL)
    115 		out(O_DIE, "uninitialized configuration");
    116 
    117 	while (*path) {
    118 		if ((nextcom = strchr(path, '/')) != NULL)
    119 			*nextcom = '\0';
    120 		if ((len = strlen(path)) == 0)
    121 			out(O_DIE, "config_lookup: zero length component");
    122 		/* start at end of string and work backwards */
    123 		thiscom = &path[len - 1];
    124 		if (!isdigit(*thiscom))
    125 			out(O_DIE, "config_lookup: "
    126 			    "component \"%s\" has no number following it",
    127 			    path);
    128 		while (thiscom > path && isdigit(*thiscom))
    129 			thiscom--;
    130 		if (thiscom == path && isdigit(*thiscom))
    131 			out(O_DIE, "config_lookup: "
    132 			    "component \"%s\" has no name part", path);
    133 		thiscom++;	/* move to first numeric character */
    134 		num = atoi(thiscom);
    135 		svdigit = *thiscom;
    136 		*thiscom = '\0';
    137 		s = stable(path);
    138 		if (add)
    139 			config_lastcomp = s;
    140 		*thiscom = svdigit;
    141 
    142 		if (nextcom != NULL)
    143 			*nextcom++ = '/';
    144 
    145 		/* now we have s & num, figure out if it exists already */
    146 		exists = 0;
    147 		lastcp = NULL;
    148 		for (cp = parent->child; cp; lastcp = cp, cp = cp->next)
    149 			if (cp->s == s && cp->num == num) {
    150 				exists = 1;
    151 				parent = cp;
    152 			}
    153 
    154 		if (!exists) {
    155 			/* creating new node */
    156 			if (!add) {
    157 				/*
    158 				 * indicate component not found by copying
    159 				 * it to path (allows better error messages
    160 				 * in the caller).
    161 				 */
    162 				(void) strcpy(pathbegin, s);
    163 				return (NULL);
    164 			}
    165 
    166 			newnode = newcnode(s, num);
    167 
    168 			if (lastcp)
    169 				lastcp->next = newnode;
    170 			else
    171 				parent->child = newnode;
    172 
    173 			newnode->parent = parent;
    174 			parent = newnode;
    175 		}
    176 
    177 		if (nextcom == NULL)
    178 			return (parent);	/* all done */
    179 
    180 		/* move on to next component */
    181 		path = nextcom;
    182 	}
    183 	return (parent);
    184 }
    185 
    186 /*
    187  * addconfigprop -- add a config prop to a config cache entry
    188  */
    189 static void
    190 addconfigprop(const char *lhs, struct node *rhs, void *arg)
    191 {
    192 	struct config *cp = (struct config *)arg;
    193 
    194 	ASSERT(cp != NULL);
    195 	ASSERT(lhs != NULL);
    196 	ASSERT(rhs != NULL);
    197 	ASSERT(rhs->t == T_QUOTE);
    198 
    199 	config_setprop(cp, lhs, STRDUP(rhs->u.quote.s));
    200 }
    201 
    202 /*
    203  * addconfig -- add a config from parse tree to given configuration cache
    204  */
    205 /*ARGSUSED*/
    206 static void
    207 addconfig(struct node *lhs, struct node *rhs, void *arg)
    208 {
    209 	struct config *parent = (struct config *)arg;
    210 	struct config *cp;
    211 	const char *s;
    212 	int num;
    213 	struct config *lastcp;
    214 	struct config *newnode;
    215 	int exists;
    216 	struct lut *lutp;
    217 
    218 	ASSERT(rhs->t == T_CONFIG);
    219 
    220 	lutp = rhs->u.stmt.lutp;
    221 	rhs = rhs->u.stmt.np;
    222 	while (rhs != NULL) {
    223 		ASSERT(rhs->t == T_NAME);
    224 		ASSERT(rhs->u.name.child->t == T_NUM);
    225 		s = rhs->u.name.s;
    226 		num = rhs->u.name.child->u.ull;
    227 
    228 		/* now we have s & num, figure out if it exists already */
    229 		exists = 0;
    230 		lastcp = NULL;
    231 		for (cp = parent->child; cp; lastcp = cp, cp = cp->next)
    232 			if (cp->s == s && cp->num == num) {
    233 				exists = 1;
    234 				parent = cp;
    235 			}
    236 
    237 		if (!exists) {
    238 			/* creating new node */
    239 
    240 			newnode = newcnode(s, num);
    241 
    242 			if (lastcp)
    243 				lastcp->next = newnode;
    244 			else
    245 				parent->child = newnode;
    246 
    247 			newnode->parent = parent;
    248 			parent = newnode;
    249 		}
    250 
    251 		/* move on to next component */
    252 		rhs = rhs->u.name.next;
    253 	}
    254 
    255 	/* add configuration properties */
    256 	lut_walk(lutp, (lut_cb)addconfigprop, (void *)parent);
    257 }
    258 
    259 /*
    260  * config_cook -- convert raw config strings to eft internal representation
    261  */
    262 void
    263 config_cook(struct cfgdata *cdata)
    264 {
    265 	struct config *newnode;
    266 	char *cfgstr, *equals;
    267 	const char *pn, *sv;
    268 	char *pv;
    269 	const char *ptr;
    270 	extern struct lut *Usedprops;
    271 	extern struct lut *Usednames;
    272 
    273 	cdata->cooked = newcnode(NULL, 0);
    274 
    275 	if ((cfgstr = cdata->begin) == cdata->nextfree) {
    276 		out(O_ALTFP|O_VERB, "Platform provided no config data.");
    277 		goto eftcfgs;
    278 	}
    279 
    280 	/*
    281 	 * add the following properties to the "usedprops" table as they
    282 	 * are used internally by eft
    283 	 */
    284 	ptr = stable("module");
    285 	Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL);
    286 	ptr = stable("resource");
    287 	Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL);
    288 
    289 	out(O_ALTFP|O_VERB3, "Raw config data follows:");
    290 	out(O_ALTFP|O_VERB3|O_NONL,
    291 	    "nextfree is %p\n%p ", (void *)cdata->nextfree, (void *)cfgstr);
    292 	while (cfgstr < cdata->nextfree) {
    293 		if (!*cfgstr)
    294 			out(O_ALTFP|O_VERB3|O_NONL, "\n%p ",
    295 			    (void *)(cfgstr + 1));
    296 		else
    297 			out(O_ALTFP|O_VERB3|O_NONL, "%c", *cfgstr);
    298 		cfgstr++;
    299 	}
    300 	out(O_ALTFP|O_VERB3, NULL);
    301 
    302 	cfgstr = cdata->begin;
    303 	while (cfgstr < cdata->nextfree) {
    304 		while (*cfgstr == '/' && cfgstr < cdata->nextfree) {
    305 			out(O_ALTFP|O_VERB3,
    306 			    "next string (%p) is %s", (void *)cfgstr, cfgstr);
    307 			/* skip the initial slash from libtopo */
    308 			newnode = config_lookup(cdata->cooked, cfgstr + 1, 1);
    309 			/*
    310 			 * Note we'll only cache nodes that have
    311 			 * properties on them.  Intermediate nodes
    312 			 * will have been added to the config tree,
    313 			 * but we don't have easy means of accessing
    314 			 * them except if we climb the tree from this
    315 			 * newnode to the root.
    316 			 *
    317 			 * Luckily, the nodes we care to cache
    318 			 * (currently just cpus) always have some
    319 			 * properties attached to them
    320 			 * so we don't bother climbing the tree.
    321 			 */
    322 			config_node_cache(cdata, newnode);
    323 			cfgstr += strlen(cfgstr) + 1;
    324 		}
    325 
    326 		if (cfgstr >= cdata->nextfree)
    327 			break;
    328 
    329 		out(O_ALTFP|O_VERB3, "next string (%p) is %s", (void *)cfgstr,
    330 		    cfgstr);
    331 		if ((equals = strchr(cfgstr, '=')) == NULL) {
    332 			out(O_ALTFP|O_VERB3, "raw config data bad (%p); "
    333 			    "property missing equals.\n", (void *)cfgstr);
    334 			break;
    335 		}
    336 
    337 		*equals = '\0';
    338 		pn = stable(cfgstr);
    339 
    340 		/*
    341 		 * only actually add the props if the rules use them (saves
    342 		 * memory)
    343 		 */
    344 		if ((lut_lookup(Usedprops, (void *)pn, NULL) != NULL ||
    345 		    strncmp(pn, "serd_", 5) == 0) && lut_lookup(Usednames,
    346 		    (void *)config_lastcomp, NULL) != NULL) {
    347 			pv = STRDUP(equals + 1);
    348 			out(O_ALTFP|O_VERB3, "add prop (%s) val %p", pn,
    349 			    (void *)pv);
    350 			config_setprop(newnode, pn, pv);
    351 		}
    352 
    353 		/*
    354 		 * If this property is a device path or devid, cache it
    355 		 * for quick lookup.
    356 		 */
    357 		if (pn == stable(TOPO_IO_DEV)) {
    358 			sv = stable(equals + 1);
    359 			out(O_ALTFP|O_VERB3, "caching dev %s\n", sv);
    360 			cdata->devcache = lut_add(cdata->devcache,
    361 			    (void *)sv, (void *)newnode, NULL);
    362 		} else if (pn == stable(TOPO_IO_DEVID)) {
    363 			sv = stable(equals + 1);
    364 			out(O_ALTFP|O_VERB3, "caching devid %s\n", sv);
    365 			cdata->devidcache = lut_add(cdata->devidcache,
    366 			    (void *)sv, (void *)newnode, NULL);
    367 		}
    368 
    369 		*equals = '=';
    370 		cfgstr += strlen(cfgstr) + 1;
    371 	}
    372 
    373 eftcfgs:
    374 	/* now run through Configs table, adding to config cache */
    375 	lut_walk(Configs, (lut_cb)addconfig, (void *)cdata->cooked);
    376 }
    377 
    378 /*
    379  * config_snapshot -- gather a snapshot of the current configuration
    380  */
    381 struct cfgdata *
    382 config_snapshot(void)
    383 {
    384 	struct cfgdata *rawcfg;
    385 
    386 	rawcfg = platform_config_snapshot();
    387 	config_cook(rawcfg);
    388 	return (rawcfg);
    389 }
    390 
    391 /*
    392  * prop_destructor -- free a prop value
    393  */
    394 /*ARGSUSED*/
    395 static void
    396 prop_destructor(void *left, void *right, void *arg)
    397 {
    398 	FREE(right);
    399 }
    400 
    401 /*
    402  * structconfig_free -- free a struct config pointer and all its relatives
    403  */
    404 void
    405 structconfig_free(struct config *cp)
    406 {
    407 	if (cp == NULL)
    408 		return;
    409 
    410 	structconfig_free(cp->child);
    411 	structconfig_free(cp->next);
    412 	lut_free(cp->props, prop_destructor, NULL);
    413 	FREE(cp);
    414 }
    415 
    416 /*
    417  * config_free -- free a configuration snapshot
    418  */
    419 void
    420 config_free(struct cfgdata *cp)
    421 {
    422 	if (cp == NULL)
    423 		return;
    424 
    425 	if (--cp->raw_refcnt == 0) {
    426 		if (cp->devcache != NULL)
    427 			lut_free(cp->devcache, NULL, NULL);
    428 		cp->devcache = NULL;
    429 		if (cp->devidcache != NULL)
    430 			lut_free(cp->devidcache, NULL, NULL);
    431 		cp->devidcache = NULL;
    432 		if (cp->cpucache != NULL)
    433 			lut_free(cp->cpucache, NULL, NULL);
    434 		cp->cpucache = NULL;
    435 		if (cp->begin != NULL)
    436 			FREE(cp->begin);
    437 		FREE(cp);
    438 	}
    439 }
    440 
    441 /*
    442  * config_next -- get the "next" config node
    443  */
    444 struct config *
    445 config_next(struct config *cp)
    446 {
    447 	ASSERT(cp != NULL);
    448 
    449 	return ((struct config *)((struct config *)cp)->next);
    450 }
    451 
    452 
    453 /*
    454  * config_child -- get the "child" of a config node
    455  */
    456 struct config *
    457 config_child(struct config *cp)
    458 {
    459 	ASSERT(cp != NULL);
    460 
    461 	return ((struct config *)((struct config *)cp)->child);
    462 }
    463 
    464 /*
    465  * config_parent -- get the "parent" of a config node
    466  */
    467 struct config *
    468 config_parent(struct config *cp)
    469 {
    470 	ASSERT(cp != NULL);
    471 
    472 	return ((struct config *)((struct config *)cp)->parent);
    473 }
    474 
    475 /*
    476  * config_setprop -- add a property to a config node
    477  */
    478 void
    479 config_setprop(struct config *cp, const char *propname, const char *propvalue)
    480 {
    481 	const char *pn = stable(propname);
    482 
    483 	cp->props = lut_add(cp->props, (void *)pn, (void *)propvalue, NULL);
    484 }
    485 
    486 /*
    487  * config_getprop -- lookup a config property
    488  */
    489 const char *
    490 config_getprop(struct config *cp, const char *propname)
    491 {
    492 	return (lut_lookup(cp->props, (void *) stable(propname), NULL));
    493 }
    494 
    495 /*
    496  * config_getcompname -- get the component name of a config node
    497  */
    498 void
    499 config_getcompname(struct config *cp, char **name, int *inst)
    500 {
    501 	ASSERT(cp != NULL);
    502 
    503 	if (name != NULL)
    504 		*name = (char *)cp->s;
    505 	if (inst != NULL)
    506 		*inst = cp->num;
    507 }
    508 
    509 /*
    510  * config_nodeize -- convert the config element represented by cp to struct
    511  *		     node format
    512  */
    513 static struct node *
    514 config_nodeize(struct config *cp)
    515 {
    516 	struct node *tmpn, *ptmpn;
    517 	struct node *numn;
    518 	const char *sname;
    519 
    520 	if (cp == NULL || cp->s == NULL)
    521 		return (NULL);
    522 
    523 	sname = stable(cp->s);
    524 	numn = newnode(T_NUM, NULL, 0);
    525 	numn->u.ull = cp->num;
    526 
    527 	tmpn = tree_name_iterator(tree_name(sname, IT_VERTICAL, NULL, 0), numn);
    528 	if ((ptmpn = config_nodeize(cp->parent)) == NULL)
    529 		return (tmpn);
    530 	return (tree_name_append(ptmpn, tmpn));
    531 }
    532 
    533 /*ARGSUSED*/
    534 static void
    535 prtdevcache(void *lhs, void *rhs, void *arg)
    536 {
    537 	out(O_ALTFP|O_VERB3, "%s -> %p", (char *)lhs, rhs);
    538 }
    539 
    540 /*ARGSUSED*/
    541 static void
    542 prtdevidcache(void *lhs, void *rhs, void *arg)
    543 {
    544 	out(O_ALTFP|O_VERB3, "%s -> %p", (char *)lhs, rhs);
    545 }
    546 
    547 /*ARGSUSED*/
    548 static void
    549 prtcpucache(void *lhs, void *rhs, void *arg)
    550 {
    551 	out(O_ALTFP|O_VERB, "%u -> %p", (uint32_t)lhs, rhs);
    552 }
    553 
    554 /*
    555  * config_bydev_lookup -- look up the path in our devcache lut.  If we find
    556  * it return the config path, but as a struct node.
    557  */
    558 struct node *
    559 config_bydev_lookup(struct cfgdata *fromcfg, const char *path)
    560 {
    561 	struct config *find;
    562 	struct node *np;
    563 
    564 	out(O_ALTFP|O_VERB3, "Device path cache:");
    565 	lut_walk(fromcfg->devcache, (lut_cb)prtdevcache, NULL);
    566 
    567 	if ((find = lut_lookup(fromcfg->devcache,
    568 	    (void *) stable(path), NULL)) == NULL)
    569 		return (NULL);
    570 
    571 	np = config_nodeize(find);
    572 	if (np != NULL) {
    573 		out(O_ALTFP|O_VERB, "Matching config entry:");
    574 		ptree_name_iter(O_ALTFP|O_VERB|O_NONL, np);
    575 		out(O_ALTFP|O_VERB, NULL);
    576 	}
    577 	return (np);
    578 }
    579 
    580 /*
    581  * config_bydevid_lookup -- look up the path in our DEVIDcache lut.
    582  * If we find it return the config path, but as a struct node.
    583  */
    584 struct node *
    585 config_bydevid_lookup(struct cfgdata *fromcfg, const char *devid)
    586 {
    587 	struct config *find;
    588 	struct node *np;
    589 
    590 	out(O_ALTFP|O_VERB3, "Device id cache:");
    591 	lut_walk(fromcfg->devcache, (lut_cb)prtdevidcache, NULL);
    592 
    593 	if ((find = lut_lookup(fromcfg->devidcache,
    594 	    (void *) stable(devid), NULL)) == NULL)
    595 		return (NULL);
    596 
    597 	np = config_nodeize(find);
    598 	if (np != NULL) {
    599 		out(O_ALTFP|O_VERB, "Matching config entry:");
    600 		ptree_name_iter(O_ALTFP|O_VERB|O_NONL, np);
    601 		out(O_ALTFP|O_VERB, NULL);
    602 	}
    603 	return (np);
    604 }
    605 
    606 /*
    607  * config_bycpuid_lookup -- look up the cpu id in our CPUcache lut.
    608  * If we find it return the config path, but as a struct node.
    609  */
    610 struct node *
    611 config_bycpuid_lookup(struct cfgdata *fromcfg, uint32_t id)
    612 {
    613 	struct config *find;
    614 	struct node *np;
    615 
    616 	out(O_ALTFP|O_VERB, "Cpu cache:");
    617 	lut_walk(fromcfg->cpucache, (lut_cb)prtcpucache, NULL);
    618 
    619 	if ((find = lut_lookup(fromcfg->cpucache,
    620 	    (void *)id, NULL)) == NULL)
    621 		return (NULL);
    622 
    623 	np = config_nodeize(find);
    624 	if (np != NULL) {
    625 		out(O_ALTFP|O_VERB3, "Matching config entry:");
    626 		ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, np);
    627 		out(O_ALTFP|O_VERB3, NULL);
    628 	}
    629 	return (np);
    630 }
    631 
    632 /*
    633  * printprop -- print prop associated with config node
    634  */
    635 static void
    636 printprop(const char *lhs, const char *rhs, void *arg)
    637 {
    638 	int flags = (int)arg;
    639 
    640 	out(flags, "\t%s=%s", lhs, rhs);
    641 }
    642 
    643 /*
    644  * pconf -- internal printing function to recurse through the tree
    645  */
    646 static void
    647 pconf(int flags, struct config *cp, char *buf, int offset, int limit)
    648 {
    649 	char *sep = "/";
    650 
    651 	if (offset)
    652 		sep = "/";
    653 	else
    654 		sep = "";
    655 	(void) snprintf(&buf[offset], limit - offset, "%s%s%d",
    656 	    sep, cp->s, cp->num);
    657 	if (cp->child == NULL) {
    658 		out(flags, "%s", buf);
    659 		lut_walk(cp->props, (lut_cb)printprop, (void *)flags);
    660 	} else
    661 		pconf(flags, cp->child, buf, strlen(buf), limit);
    662 	if (cp->next)
    663 		pconf(flags, cp->next, buf, offset, limit);
    664 }
    665 
    666 /*
    667  * config_print -- spew the current configuration cache
    668  */
    669 
    670 #define	MAXCONFLINE 4096
    671 
    672 void
    673 config_print(int flags, struct config *croot)
    674 {
    675 	char buf[MAXCONFLINE];
    676 
    677 	if (croot == NULL)
    678 		out(flags, "empty configuration");
    679 	else
    680 		pconf(flags, croot->child, buf, 0, MAXCONFLINE);
    681 }
    682