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