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 2007 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 "fme.h" 57 #include "platform.h" 58 59 /* 60 * private data structure for storing config. all access to 61 * to this information happens using the config.h interfaces. 62 */ 63 struct config { 64 struct config *next; 65 struct config *child; 66 struct config *parent; 67 const char *s; 68 int num; 69 struct lut *props; 70 }; 71 72 static const char *config_lastcomp; 73 74 /* 75 * newcnode -- local function to allocate new config node 76 */ 77 static struct config * 78 newcnode(const char *s, int num) 79 { 80 struct config *retval; 81 82 retval = MALLOC(sizeof (struct config)); 83 84 retval->s = s; 85 retval->num = num; 86 retval->next = NULL; 87 retval->props = NULL; 88 retval->child = retval->parent = NULL; 89 90 return (retval); 91 } 92 93 /* 94 * If we need to cache certain types of nodes for reverse look-up or 95 * somesuch, do it here. Currently we need to cache nodes representing 96 * cpus. 97 */ 98 static void 99 config_node_cache(struct cfgdata *cdata, struct config *n) 100 { 101 if (n->s != stable("cpu")) 102 return; 103 cdata->cpucache = lut_add(cdata->cpucache, 104 (void *)n->num, (void *)n, NULL); 105 } 106 107 /* 108 * config_lookup -- lookup/add components in configuration cache 109 */ 110 struct config * 111 config_lookup(struct config *croot, char *path, int add) 112 { 113 char *pathbegin = path; 114 struct config *parent = croot; 115 struct config *cp; 116 struct config *lastcp; 117 struct config *newnode; 118 char *thiscom; /* this component */ 119 char *nextcom; /* next component */ 120 char svdigit; 121 int len; 122 int num; 123 const char *s; 124 int exists; 125 126 if (parent == NULL) 127 out(O_DIE, "uninitialized configuration"); 128 129 while (*path) { 130 if ((nextcom = strchr(path, '/')) != NULL) 131 *nextcom = '\0'; 132 if ((len = strlen(path)) == 0) 133 out(O_DIE, "config_lookup: zero length component"); 134 /* start at end of string and work backwards */ 135 thiscom = &path[len - 1]; 136 if (!isdigit(*thiscom)) 137 out(O_DIE, "config_lookup: " 138 "component \"%s\" has no number following it", 139 path); 140 while (thiscom > path && isdigit(*thiscom)) 141 thiscom--; 142 if (thiscom == path && isdigit(*thiscom)) 143 out(O_DIE, "config_lookup: " 144 "component \"%s\" has no name part", path); 145 thiscom++; /* move to first numeric character */ 146 num = atoi(thiscom); 147 svdigit = *thiscom; 148 *thiscom = '\0'; 149 s = stable(path); 150 if (add) 151 config_lastcomp = s; 152 *thiscom = svdigit; 153 154 if (nextcom != NULL) 155 *nextcom++ = '/'; 156 157 /* now we have s & num, figure out if it exists already */ 158 exists = 0; 159 lastcp = NULL; 160 for (cp = parent->child; cp; lastcp = cp, cp = cp->next) 161 if (cp->s == s && cp->num == num) { 162 exists = 1; 163 parent = cp; 164 } 165 166 if (!exists) { 167 /* creating new node */ 168 if (!add) { 169 /* 170 * indicate component not found by copying 171 * it to path (allows better error messages 172 * in the caller). 173 */ 174 (void) strcpy(pathbegin, s); 175 return (NULL); 176 } 177 178 newnode = newcnode(s, num); 179 180 if (lastcp) 181 lastcp->next = newnode; 182 else 183 parent->child = newnode; 184 185 newnode->parent = parent; 186 parent = newnode; 187 } 188 189 if (nextcom == NULL) 190 return (parent); /* all done */ 191 192 /* move on to next component */ 193 path = nextcom; 194 } 195 return (parent); 196 } 197 198 /* 199 * addconfigprop -- add a config prop to a config cache entry 200 */ 201 static void 202 addconfigprop(const char *lhs, struct node *rhs, void *arg) 203 { 204 struct config *cp = (struct config *)arg; 205 206 ASSERT(cp != NULL); 207 ASSERT(lhs != NULL); 208 ASSERT(rhs != NULL); 209 ASSERT(rhs->t == T_QUOTE); 210 211 config_setprop(cp, lhs, STRDUP(rhs->u.quote.s)); 212 } 213 214 /* 215 * addconfig -- add a config from parse tree to given configuration cache 216 */ 217 /*ARGSUSED*/ 218 static void 219 addconfig(struct node *lhs, struct node *rhs, void *arg) 220 { 221 struct config *parent = (struct config *)arg; 222 struct config *cp; 223 const char *s; 224 int num; 225 struct config *lastcp; 226 struct config *newnode; 227 int exists; 228 struct lut *lutp; 229 230 ASSERT(rhs->t == T_CONFIG); 231 232 lutp = rhs->u.stmt.lutp; 233 rhs = rhs->u.stmt.np; 234 while (rhs != NULL) { 235 ASSERT(rhs->t == T_NAME); 236 ASSERT(rhs->u.name.child->t == T_NUM); 237 s = rhs->u.name.s; 238 num = rhs->u.name.child->u.ull; 239 240 /* now we have s & num, figure out if it exists already */ 241 exists = 0; 242 lastcp = NULL; 243 for (cp = parent->child; cp; lastcp = cp, cp = cp->next) 244 if (cp->s == s && cp->num == num) { 245 exists = 1; 246 parent = cp; 247 } 248 249 if (!exists) { 250 /* creating new node */ 251 252 newnode = newcnode(s, num); 253 254 if (lastcp) 255 lastcp->next = newnode; 256 else 257 parent->child = newnode; 258 259 newnode->parent = parent; 260 parent = newnode; 261 } 262 263 /* move on to next component */ 264 rhs = rhs->u.name.next; 265 } 266 267 /* add configuration properties */ 268 lut_walk(lutp, (lut_cb)addconfigprop, (void *)parent); 269 } 270 271 /* 272 * config_cook -- convert raw config strings to eft internal representation 273 */ 274 void 275 config_cook(struct cfgdata *cdata) 276 { 277 struct config *newnode; 278 char *cfgstr, *equals; 279 const char *pn, *sv; 280 char *pv; 281 const char *ptr; 282 extern struct lut *Usedprops; 283 extern struct lut *Usednames; 284 285 cdata->cooked = newcnode(NULL, 0); 286 287 if ((cfgstr = cdata->begin) == cdata->nextfree) { 288 out(O_ALTFP|O_VERB, "Platform provided no config data."); 289 goto eftcfgs; 290 } 291 292 /* 293 * add the following properties to the "usedprops" table as they 294 * are used internally by eft 295 */ 296 ptr = stable("module"); 297 Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL); 298 ptr = stable("resource"); 299 Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL); 300 ptr = stable("ASRU"); 301 Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL); 302 ptr = stable("FRU"); 303 Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL); 304 305 out(O_ALTFP|O_VERB3, "Raw config data follows:"); 306 out(O_ALTFP|O_VERB3|O_NONL, 307 "nextfree is %p\n%p ", (void *)cdata->nextfree, (void *)cfgstr); 308 while (cfgstr < cdata->nextfree) { 309 if (!*cfgstr) 310 out(O_ALTFP|O_VERB3|O_NONL, "\n%p ", 311 (void *)(cfgstr + 1)); 312 else 313 out(O_ALTFP|O_VERB3|O_NONL, "%c", *cfgstr); 314 cfgstr++; 315 } 316 out(O_ALTFP|O_VERB3, NULL); 317 318 cfgstr = cdata->begin; 319 while (cfgstr < cdata->nextfree) { 320 while (*cfgstr == '/' && cfgstr < cdata->nextfree) { 321 out(O_ALTFP|O_VERB3, 322 "next string (%p) is %s", (void *)cfgstr, cfgstr); 323 /* skip the initial slash from libtopo */ 324 newnode = config_lookup(cdata->cooked, cfgstr + 1, 1); 325 /* 326 * Note we'll only cache nodes that have 327 * properties on them. Intermediate nodes 328 * will have been added to the config tree, 329 * but we don't have easy means of accessing 330 * them except if we climb the tree from this 331 * newnode to the root. 332 * 333 * Luckily, the nodes we care to cache 334 * (currently just cpus) always have some 335 * properties attached to them 336 * so we don't bother climbing the tree. 337 */ 338 config_node_cache(cdata, newnode); 339 cfgstr += strlen(cfgstr) + 1; 340 } 341 342 if (cfgstr >= cdata->nextfree) 343 break; 344 345 out(O_ALTFP|O_VERB3, "next string (%p) is %s", (void *)cfgstr, 346 cfgstr); 347 if ((equals = strchr(cfgstr, '=')) == NULL) { 348 out(O_ALTFP|O_VERB3, "raw config data bad (%p); " 349 "property missing equals.\n", (void *)cfgstr); 350 break; 351 } 352 353 *equals = '\0'; 354 pn = stable(cfgstr); 355 356 /* 357 * only actually add the props if the rules use them (saves 358 * memory) 359 */ 360 if ((lut_lookup(Usedprops, (void *)pn, NULL) != NULL || 361 strncmp(pn, "serd_", 5) == 0) && lut_lookup(Usednames, 362 (void *)config_lastcomp, NULL) != NULL) { 363 pv = STRDUP(equals + 1); 364 out(O_ALTFP|O_VERB3, "add prop (%s) val %p", pn, 365 (void *)pv); 366 config_setprop(newnode, pn, pv); 367 } 368 369 /* 370 * If this property is a device path, cache it for quick lookup 371 */ 372 if (pn == stable(TOPO_IO_DEV)) { 373 sv = stable(equals + 1); 374 out(O_ALTFP|O_VERB3, "caching %s\n", sv); 375 cdata->devcache = lut_add(cdata->devcache, 376 (void *)sv, (void *)newnode, NULL); 377 } 378 379 *equals = '='; 380 cfgstr += strlen(cfgstr) + 1; 381 } 382 383 eftcfgs: 384 /* now run through Configs table, adding to config cache */ 385 lut_walk(Configs, (lut_cb)addconfig, (void *)cdata->cooked); 386 } 387 388 /* 389 * config_snapshot -- gather a snapshot of the current configuration 390 */ 391 struct cfgdata * 392 config_snapshot(void) 393 { 394 struct cfgdata *rawcfg; 395 396 rawcfg = platform_config_snapshot(); 397 config_cook(rawcfg); 398 return (rawcfg); 399 } 400 401 /* 402 * prop_destructor -- free a prop value 403 */ 404 /*ARGSUSED*/ 405 static void 406 prop_destructor(void *left, void *right, void *arg) 407 { 408 FREE(right); 409 } 410 411 /* 412 * structconfig_free -- free a struct config pointer and all its relatives 413 */ 414 void 415 structconfig_free(struct config *cp) 416 { 417 if (cp == NULL) 418 return; 419 420 structconfig_free(cp->child); 421 structconfig_free(cp->next); 422 lut_free(cp->props, prop_destructor, NULL); 423 FREE(cp); 424 } 425 426 /* 427 * config_free -- free a configuration snapshot 428 */ 429 void 430 config_free(struct cfgdata *cp) 431 { 432 if (cp == NULL) 433 return; 434 435 if (--cp->raw_refcnt == 0) { 436 if (cp->devcache != NULL) 437 lut_free(cp->devcache, NULL, NULL); 438 cp->devcache = NULL; 439 if (cp->cpucache != NULL) 440 lut_free(cp->cpucache, NULL, NULL); 441 cp->cpucache = NULL; 442 if (cp->begin != NULL) 443 FREE(cp->begin); 444 FREE(cp); 445 } 446 } 447 448 /* 449 * config_next -- get the "next" config node 450 */ 451 struct config * 452 config_next(struct config *cp) 453 { 454 ASSERT(cp != NULL); 455 456 return ((struct config *)((struct config *)cp)->next); 457 } 458 459 460 /* 461 * config_child -- get the "child" of a config node 462 */ 463 struct config * 464 config_child(struct config *cp) 465 { 466 ASSERT(cp != NULL); 467 468 return ((struct config *)((struct config *)cp)->child); 469 } 470 471 /* 472 * config_parent -- get the "parent" of a config node 473 */ 474 struct config * 475 config_parent(struct config *cp) 476 { 477 ASSERT(cp != NULL); 478 479 return ((struct config *)((struct config *)cp)->parent); 480 } 481 482 /* 483 * config_setprop -- add a property to a config node 484 */ 485 void 486 config_setprop(struct config *cp, const char *propname, const char *propvalue) 487 { 488 const char *pn = stable(propname); 489 490 cp->props = lut_add(cp->props, (void *)pn, (void *)propvalue, NULL); 491 } 492 493 /* 494 * config_getprop -- lookup a config property 495 */ 496 const char * 497 config_getprop(struct config *cp, const char *propname) 498 { 499 return (lut_lookup(cp->props, (void *) stable(propname), NULL)); 500 } 501 502 /* 503 * config_getcompname -- get the component name of a config node 504 */ 505 void 506 config_getcompname(struct config *cp, char **name, int *inst) 507 { 508 ASSERT(cp != NULL); 509 510 if (name != NULL) 511 *name = (char *)cp->s; 512 if (inst != NULL) 513 *inst = cp->num; 514 } 515 516 /* 517 * config_nodeize -- convert the config element represented by cp to struct 518 * node format 519 */ 520 static struct node * 521 config_nodeize(struct config *cp) 522 { 523 struct node *tmpn, *ptmpn; 524 struct node *numn; 525 const char *sname; 526 527 if (cp == NULL || cp->s == NULL) 528 return (NULL); 529 530 sname = stable(cp->s); 531 numn = newnode(T_NUM, NULL, 0); 532 numn->u.ull = cp->num; 533 534 tmpn = tree_name_iterator(tree_name(sname, IT_VERTICAL, NULL, 0), numn); 535 if ((ptmpn = config_nodeize(cp->parent)) == NULL) 536 return (tmpn); 537 return (tree_name_append(ptmpn, tmpn)); 538 } 539 540 /*ARGSUSED*/ 541 static void 542 prtdevcache(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_bycpuid_lookup -- look up the cpu id in our CPUcache lut. 582 * If we find it return the config path, but as a struct node. 583 */ 584 struct node * 585 config_bycpuid_lookup(struct cfgdata *fromcfg, uint32_t id) 586 { 587 struct config *find; 588 struct node *np; 589 590 out(O_ALTFP|O_VERB, "Cpu cache:"); 591 lut_walk(fromcfg->cpucache, (lut_cb)prtcpucache, NULL); 592 593 if ((find = lut_lookup(fromcfg->cpucache, 594 (void *)id, NULL)) == NULL) 595 return (NULL); 596 597 np = config_nodeize(find); 598 if (np != NULL) { 599 out(O_ALTFP|O_VERB3, "Matching config entry:"); 600 ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, np); 601 out(O_ALTFP|O_VERB3, NULL); 602 } 603 return (np); 604 } 605 606 /* 607 * printprop -- print prop associated with config node 608 */ 609 static void 610 printprop(const char *lhs, const char *rhs, void *arg) 611 { 612 int flags = (int)arg; 613 614 out(flags, "\t%s=%s", lhs, rhs); 615 } 616 617 /* 618 * pconf -- internal printing function to recurse through the tree 619 */ 620 static void 621 pconf(int flags, struct config *cp, char *buf, int offset, int limit) 622 { 623 char *sep = "/"; 624 625 if (offset) 626 sep = "/"; 627 else 628 sep = ""; 629 (void) snprintf(&buf[offset], limit - offset, "%s%s%d", 630 sep, cp->s, cp->num); 631 if (cp->child == NULL) { 632 out(flags, "%s", buf); 633 lut_walk(cp->props, (lut_cb)printprop, (void *)flags); 634 } else 635 pconf(flags, cp->child, buf, strlen(buf), limit); 636 if (cp->next) 637 pconf(flags, cp->next, buf, offset, limit); 638 } 639 640 /* 641 * config_print -- spew the current configuration cache 642 */ 643 644 #define MAXCONFLINE 4096 645 646 void 647 config_print(int flags, struct config *croot) 648 { 649 char buf[MAXCONFLINE]; 650 651 if (croot == NULL) 652 out(flags, "empty configuration"); 653 else 654 pconf(flags, croot->child, buf, 0, MAXCONFLINE); 655 } 656