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