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_refcnt++; 286 287 if (cdata->cooked != NULL) 288 return; 289 290 cdata->cooked = newcnode(NULL, 0); 291 292 if ((cfgstr = cdata->begin) == cdata->nextfree) { 293 out(O_ALTFP|O_VERB, "Platform provided no config data."); 294 goto eftcfgs; 295 } 296 297 /* 298 * add the following properties to the "usedprops" table as they 299 * are used internally by eft 300 */ 301 ptr = stable("module"); 302 Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL); 303 ptr = stable("resource"); 304 Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL); 305 ptr = stable("ASRU"); 306 Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL); 307 ptr = stable("FRU"); 308 Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL); 309 310 out(O_ALTFP|O_VERB3, "Raw config data follows:"); 311 out(O_ALTFP|O_VERB3|O_NONL, 312 "nextfree is %p\n%p ", (void *)cdata->nextfree, (void *)cfgstr); 313 while (cfgstr < cdata->nextfree) { 314 if (!*cfgstr) 315 out(O_ALTFP|O_VERB3|O_NONL, "\n%p ", 316 (void *)(cfgstr + 1)); 317 else 318 out(O_ALTFP|O_VERB3|O_NONL, "%c", *cfgstr); 319 cfgstr++; 320 } 321 out(O_ALTFP|O_VERB3, NULL); 322 323 cfgstr = cdata->begin; 324 while (cfgstr < cdata->nextfree) { 325 while (*cfgstr == '/' && cfgstr < cdata->nextfree) { 326 out(O_ALTFP|O_VERB3, 327 "next string (%p) is %s", (void *)cfgstr, cfgstr); 328 /* skip the initial slash from libtopo */ 329 newnode = config_lookup(cdata->cooked, cfgstr + 1, 1); 330 /* 331 * Note we'll only cache nodes that have 332 * properties on them. Intermediate nodes 333 * will have been added to the config tree, 334 * but we don't have easy means of accessing 335 * them except if we climb the tree from this 336 * newnode to the root. 337 * 338 * Luckily, the nodes we care to cache 339 * (currently just cpus) always have some 340 * properties attached to them 341 * so we don't bother climbing the tree. 342 */ 343 config_node_cache(cdata, newnode); 344 cfgstr += strlen(cfgstr) + 1; 345 } 346 347 if (cfgstr >= cdata->nextfree) 348 break; 349 350 out(O_ALTFP|O_VERB3, "next string (%p) is %s", (void *)cfgstr, 351 cfgstr); 352 if ((equals = strchr(cfgstr, '=')) == NULL) { 353 out(O_ALTFP|O_VERB3, "raw config data bad (%p); " 354 "property missing equals.\n", (void *)cfgstr); 355 break; 356 } 357 358 *equals = '\0'; 359 pn = stable(cfgstr); 360 361 /* 362 * only actually add the props if the rules use them (saves 363 * memory) 364 */ 365 if (lut_lookup(Usedprops, (void *)pn, NULL) != NULL && 366 lut_lookup(Usednames, (void *)config_lastcomp, NULL) != 367 NULL) { 368 pv = STRDUP(equals + 1); 369 out(O_ALTFP|O_VERB3, "add prop (%s) val %p", pn, 370 (void *)pv); 371 config_setprop(newnode, pn, pv); 372 } 373 374 /* 375 * If this property is a device path, cache it for quick lookup 376 */ 377 if (pn == stable(TOPO_IO_DEV)) { 378 sv = stable(equals + 1); 379 out(O_ALTFP|O_VERB3, "caching %s\n", sv); 380 cdata->devcache = lut_add(cdata->devcache, 381 (void *)sv, (void *)newnode, NULL); 382 } 383 384 *equals = '='; 385 cfgstr += strlen(cfgstr) + 1; 386 } 387 388 eftcfgs: 389 /* now run through Configs table, adding to config cache */ 390 lut_walk(Configs, (lut_cb)addconfig, (void *)cdata->cooked); 391 } 392 393 /* 394 * config_snapshot -- gather a snapshot of the current configuration 395 */ 396 struct cfgdata * 397 config_snapshot(void) 398 { 399 struct cfgdata *rawcfg; 400 401 rawcfg = platform_config_snapshot(); 402 config_cook(rawcfg); 403 return (rawcfg); 404 } 405 406 /* 407 * prop_destructor -- free a prop value 408 */ 409 /*ARGSUSED*/ 410 static void 411 prop_destructor(void *left, void *right, void *arg) 412 { 413 FREE(right); 414 } 415 416 /* 417 * structconfig_free -- free a struct config pointer and all its relatives 418 */ 419 static void 420 structconfig_free(struct config *cp) 421 { 422 if (cp == NULL) 423 return; 424 425 structconfig_free(cp->child); 426 structconfig_free(cp->next); 427 lut_free(cp->props, prop_destructor, NULL); 428 FREE(cp); 429 } 430 431 /* 432 * config_free -- free a configuration snapshot 433 */ 434 void 435 config_free(struct cfgdata *cp) 436 { 437 if (cp == NULL) 438 return; 439 440 if (--cp->cooked_refcnt == 0) { 441 if (cp->cooked != NULL) 442 structconfig_free(cp->cooked); 443 cp->cooked = NULL; 444 if (cp->devcache != NULL) 445 lut_free(cp->devcache, NULL, NULL); 446 cp->devcache = NULL; 447 if (cp->cpucache != NULL) 448 lut_free(cp->cpucache, NULL, NULL); 449 cp->cpucache = NULL; 450 } 451 452 if (--cp->raw_refcnt == 0) { 453 if (cp->begin != NULL) 454 FREE(cp->begin); 455 FREE(cp); 456 } 457 } 458 459 /* 460 * config_next -- get the "next" config node 461 */ 462 struct config * 463 config_next(struct config *cp) 464 { 465 ASSERT(cp != NULL); 466 467 return ((struct config *)((struct config *)cp)->next); 468 } 469 470 471 /* 472 * config_child -- get the "child" of a config node 473 */ 474 struct config * 475 config_child(struct config *cp) 476 { 477 ASSERT(cp != NULL); 478 479 return ((struct config *)((struct config *)cp)->child); 480 } 481 482 /* 483 * config_parent -- get the "parent" of a config node 484 */ 485 struct config * 486 config_parent(struct config *cp) 487 { 488 ASSERT(cp != NULL); 489 490 return ((struct config *)((struct config *)cp)->parent); 491 } 492 493 /* 494 * config_setprop -- add a property to a config node 495 */ 496 void 497 config_setprop(struct config *cp, const char *propname, const char *propvalue) 498 { 499 const char *pn = stable(propname); 500 501 cp->props = lut_add(cp->props, (void *)pn, (void *)propvalue, NULL); 502 } 503 504 /* 505 * config_getprop -- lookup a config property 506 */ 507 const char * 508 config_getprop(struct config *cp, const char *propname) 509 { 510 return (lut_lookup(cp->props, (void *) stable(propname), NULL)); 511 } 512 513 /* 514 * config_getcompname -- get the component name of a config node 515 */ 516 void 517 config_getcompname(struct config *cp, char **name, int *inst) 518 { 519 ASSERT(cp != NULL); 520 521 if (name != NULL) 522 *name = (char *)cp->s; 523 if (inst != NULL) 524 *inst = cp->num; 525 } 526 527 /* 528 * config_nodeize -- convert the config element represented by cp to struct 529 * node format 530 */ 531 static struct node * 532 config_nodeize(struct config *cp) 533 { 534 struct node *tmpn, *ptmpn; 535 struct node *numn; 536 const char *sname; 537 538 if (cp == NULL || cp->s == NULL) 539 return (NULL); 540 541 sname = stable(cp->s); 542 numn = newnode(T_NUM, NULL, 0); 543 numn->u.ull = cp->num; 544 545 tmpn = tree_name_iterator(tree_name(sname, IT_VERTICAL, NULL, 0), numn); 546 if ((ptmpn = config_nodeize(cp->parent)) == NULL) 547 return (tmpn); 548 return (tree_name_append(ptmpn, tmpn)); 549 } 550 551 /*ARGSUSED*/ 552 static void 553 prtdevcache(void *lhs, void *rhs, void *arg) 554 { 555 out(O_ALTFP|O_VERB3, "%s -> %p", (char *)lhs, rhs); 556 } 557 558 /*ARGSUSED*/ 559 static void 560 prtcpucache(void *lhs, void *rhs, void *arg) 561 { 562 out(O_ALTFP|O_VERB, "%u -> %p", (uint32_t)lhs, rhs); 563 } 564 565 /* 566 * config_bydev_lookup -- look up the path in our DEVcache lut. If we find 567 * it return the config path, but as a struct node. 568 */ 569 struct node * 570 config_bydev_lookup(struct cfgdata *fromcfg, const char *path) 571 { 572 struct config *find; 573 struct node *np; 574 575 out(O_ALTFP|O_VERB3, "Device path cache:"); 576 lut_walk(fromcfg->devcache, (lut_cb)prtdevcache, NULL); 577 578 if ((find = lut_lookup(fromcfg->devcache, 579 (void *) stable(path), NULL)) == NULL) 580 return (NULL); 581 582 np = config_nodeize(find); 583 if (np != NULL) { 584 out(O_ALTFP|O_VERB, "Matching config entry:"); 585 ptree_name_iter(O_ALTFP|O_VERB|O_NONL, np); 586 out(O_ALTFP|O_VERB, NULL); 587 } 588 return (np); 589 } 590 591 /* 592 * config_bycpuid_lookup -- look up the cpu id in our CPUcache lut. 593 * If we find it return the config path, but as a struct node. 594 */ 595 struct node * 596 config_bycpuid_lookup(struct cfgdata *fromcfg, uint32_t id) 597 { 598 struct config *find; 599 struct node *np; 600 601 out(O_ALTFP|O_VERB, "Cpu cache:"); 602 lut_walk(fromcfg->cpucache, (lut_cb)prtcpucache, NULL); 603 604 if ((find = lut_lookup(fromcfg->cpucache, 605 (void *)id, NULL)) == NULL) 606 return (NULL); 607 608 np = config_nodeize(find); 609 if (np != NULL) { 610 out(O_ALTFP|O_VERB3, "Matching config entry:"); 611 ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, np); 612 out(O_ALTFP|O_VERB3, NULL); 613 } 614 return (np); 615 } 616 617 /* 618 * printprop -- print prop associated with config node 619 */ 620 static void 621 printprop(const char *lhs, const char *rhs, void *arg) 622 { 623 int flags = (int)arg; 624 625 out(flags, "\t%s=%s", lhs, rhs); 626 } 627 628 /* 629 * pconf -- internal printing function to recurse through the tree 630 */ 631 static void 632 pconf(int flags, struct config *cp, char *buf, int offset, int limit) 633 { 634 char *sep = "/"; 635 636 if (offset) 637 sep = "/"; 638 else 639 sep = ""; 640 (void) snprintf(&buf[offset], limit - offset, "%s%s%d", 641 sep, cp->s, cp->num); 642 if (cp->child == NULL) { 643 out(flags, "%s", buf); 644 lut_walk(cp->props, (lut_cb)printprop, (void *)flags); 645 } else 646 pconf(flags, cp->child, buf, strlen(buf), limit); 647 if (cp->next) 648 pconf(flags, cp->next, buf, offset, limit); 649 } 650 651 /* 652 * config_print -- spew the current configuration cache 653 */ 654 655 #define MAXCONFLINE 4096 656 657 void 658 config_print(int flags, struct config *croot) 659 { 660 char buf[MAXCONFLINE]; 661 662 if (croot == NULL) 663 out(flags, "empty configuration"); 664 else 665 pconf(flags, croot->child, buf, 0, MAXCONFLINE); 666 } 667