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 (config_lastcomp == stable(SCSI_DEVICE) || 357 config_lastcomp == stable(SMP_DEVICE)) { 358 /* 359 * we can't get ereports on SCSI_DEVICE or SMP_DEVICE 360 * nodes, so don't cache. 361 */ 362 out(O_ALTFP|O_VERB3, "not caching %s for %s", 363 pn, config_lastcomp); 364 } else if (pn == stable(TOPO_IO_DEV)) { 365 sv = stable(equals + 1); 366 out(O_ALTFP|O_VERB3, "caching dev %s", sv); 367 cdata->devcache = lut_add(cdata->devcache, 368 (void *)sv, (void *)newnode, NULL); 369 } else if (pn == stable(TOPO_IO_DEVID) || 370 pn == stable(TOPO_PROP_SES_DEVID) || 371 pn == stable(TOPO_PROP_SMP_DEVID)) { 372 sv = stable(equals + 1); 373 out(O_ALTFP|O_VERB3, "caching devid %s", sv); 374 cdata->devidcache = lut_add(cdata->devidcache, 375 (void *)sv, (void *)newnode, NULL); 376 } else if (pn == stable(TOPO_STORAGE_TARGET_PORT_L0IDS)) { 377 /* 378 * This was stored as a set of space-separated strings. 379 * Find each string in turn and add to the lut. Then if 380 * a ereport comes in with a target-path matching any 381 * of the strings we will match it. 382 */ 383 char *x, *y = equals; 384 while (y != NULL) { 385 x = y + 1; 386 y = strchr(x, ' '); 387 if (y != NULL) 388 *y = '\0'; 389 sv = stable(x); 390 out(O_ALTFP|O_VERB3, "caching tp %s", sv); 391 cdata->tpcache = lut_add(cdata->tpcache, 392 (void *)sv, (void *)newnode, NULL); 393 if (y != NULL) 394 *y = ' '; 395 } 396 } 397 398 *equals = '='; 399 cfgstr += strlen(cfgstr) + 1; 400 } 401 402 eftcfgs: 403 /* now run through Configs table, adding to config cache */ 404 lut_walk(Configs, (lut_cb)addconfig, (void *)cdata->cooked); 405 } 406 407 /* 408 * config_snapshot -- gather a snapshot of the current configuration 409 */ 410 struct cfgdata * 411 config_snapshot(void) 412 { 413 struct cfgdata *rawcfg; 414 415 rawcfg = platform_config_snapshot(); 416 config_cook(rawcfg); 417 return (rawcfg); 418 } 419 420 /* 421 * prop_destructor -- free a prop value 422 */ 423 /*ARGSUSED*/ 424 static void 425 prop_destructor(void *left, void *right, void *arg) 426 { 427 FREE(right); 428 } 429 430 /* 431 * structconfig_free -- free a struct config pointer and all its relatives 432 */ 433 void 434 structconfig_free(struct config *cp) 435 { 436 if (cp == NULL) 437 return; 438 439 structconfig_free(cp->child); 440 structconfig_free(cp->next); 441 lut_free(cp->props, prop_destructor, NULL); 442 FREE(cp); 443 } 444 445 /* 446 * config_free -- free a configuration snapshot 447 */ 448 void 449 config_free(struct cfgdata *cp) 450 { 451 if (cp == NULL) 452 return; 453 454 if (--cp->raw_refcnt == 0) { 455 if (cp->devcache != NULL) 456 lut_free(cp->devcache, NULL, NULL); 457 cp->devcache = NULL; 458 if (cp->tpcache != NULL) 459 lut_free(cp->tpcache, NULL, NULL); 460 cp->tpcache = NULL; 461 if (cp->devidcache != NULL) 462 lut_free(cp->devidcache, NULL, NULL); 463 cp->devidcache = NULL; 464 if (cp->cpucache != NULL) 465 lut_free(cp->cpucache, NULL, NULL); 466 cp->cpucache = NULL; 467 if (cp->begin != NULL) 468 FREE(cp->begin); 469 FREE(cp); 470 } 471 } 472 473 /* 474 * config_next -- get the "next" config node 475 */ 476 struct config * 477 config_next(struct config *cp) 478 { 479 ASSERT(cp != NULL); 480 481 return ((struct config *)((struct config *)cp)->next); 482 } 483 484 485 /* 486 * config_child -- get the "child" of a config node 487 */ 488 struct config * 489 config_child(struct config *cp) 490 { 491 ASSERT(cp != NULL); 492 493 return ((struct config *)((struct config *)cp)->child); 494 } 495 496 /* 497 * config_parent -- get the "parent" of a config node 498 */ 499 struct config * 500 config_parent(struct config *cp) 501 { 502 ASSERT(cp != NULL); 503 504 return ((struct config *)((struct config *)cp)->parent); 505 } 506 507 /* 508 * config_setprop -- add a property to a config node 509 */ 510 void 511 config_setprop(struct config *cp, const char *propname, const char *propvalue) 512 { 513 const char *pn = stable(propname); 514 515 cp->props = lut_add(cp->props, (void *)pn, (void *)propvalue, NULL); 516 } 517 518 /* 519 * config_getprop -- lookup a config property 520 */ 521 const char * 522 config_getprop(struct config *cp, const char *propname) 523 { 524 return (lut_lookup(cp->props, (void *) stable(propname), NULL)); 525 } 526 527 /* 528 * config_getcompname -- get the component name of a config node 529 */ 530 void 531 config_getcompname(struct config *cp, char **name, int *inst) 532 { 533 ASSERT(cp != NULL); 534 535 if (name != NULL) 536 *name = (char *)cp->s; 537 if (inst != NULL) 538 *inst = cp->num; 539 } 540 541 /* 542 * config_nodeize -- convert the config element represented by cp to struct 543 * node format 544 */ 545 static struct node * 546 config_nodeize(struct config *cp) 547 { 548 struct node *tmpn, *ptmpn; 549 struct node *numn; 550 const char *sname; 551 552 if (cp == NULL || cp->s == NULL) 553 return (NULL); 554 555 sname = stable(cp->s); 556 numn = newnode(T_NUM, NULL, 0); 557 numn->u.ull = cp->num; 558 559 tmpn = tree_name_iterator(tree_name(sname, IT_VERTICAL, NULL, 0), numn); 560 if ((ptmpn = config_nodeize(cp->parent)) == NULL) 561 return (tmpn); 562 return (tree_name_append(ptmpn, tmpn)); 563 } 564 565 /*ARGSUSED*/ 566 static void 567 prtdevcache(void *lhs, void *rhs, void *arg) 568 { 569 out(O_ALTFP|O_VERB3, "%s -> %p", (char *)lhs, rhs); 570 } 571 572 /*ARGSUSED*/ 573 static void 574 prtdevidcache(void *lhs, void *rhs, void *arg) 575 { 576 out(O_ALTFP|O_VERB3, "%s -> %p", (char *)lhs, rhs); 577 } 578 579 /*ARGSUSED*/ 580 static void 581 prttpcache(void *lhs, void *rhs, void *arg) 582 { 583 out(O_ALTFP|O_VERB3, "%s -> %p", (char *)lhs, rhs); 584 } 585 586 /*ARGSUSED*/ 587 static void 588 prtcpucache(void *lhs, void *rhs, void *arg) 589 { 590 out(O_ALTFP|O_VERB, "%u -> %p", (uint32_t)lhs, rhs); 591 } 592 593 /* 594 * config_bydev_lookup -- look up the path in our devcache lut. If we find 595 * it return the config path, but as a struct node. 596 */ 597 struct node * 598 config_bydev_lookup(struct cfgdata *fromcfg, const char *path) 599 { 600 struct config *find; 601 struct node *np; 602 603 out(O_ALTFP|O_VERB3, "Device path cache:"); 604 lut_walk(fromcfg->devcache, (lut_cb)prtdevcache, NULL); 605 606 if ((find = lut_lookup(fromcfg->devcache, 607 (void *) stable(path), NULL)) == NULL) 608 return (NULL); 609 610 np = config_nodeize(find); 611 if (np != NULL) { 612 out(O_ALTFP|O_VERB, "Matching config entry:"); 613 ptree_name_iter(O_ALTFP|O_VERB|O_NONL, np); 614 out(O_ALTFP|O_VERB, NULL); 615 } 616 return (np); 617 } 618 619 /* 620 * config_bydevid_lookup -- look up the path in our DEVIDcache lut. 621 * If we find it return the config path, but as a struct node. 622 */ 623 struct node * 624 config_bydevid_lookup(struct cfgdata *fromcfg, const char *devid) 625 { 626 struct config *find; 627 struct node *np; 628 629 out(O_ALTFP|O_VERB3, "Device id cache:"); 630 lut_walk(fromcfg->devcache, (lut_cb)prtdevidcache, NULL); 631 632 if ((find = lut_lookup(fromcfg->devidcache, 633 (void *) stable(devid), NULL)) == NULL) 634 return (NULL); 635 636 np = config_nodeize(find); 637 if (np != NULL) { 638 out(O_ALTFP|O_VERB, "Matching config entry:"); 639 ptree_name_iter(O_ALTFP|O_VERB|O_NONL, np); 640 out(O_ALTFP|O_VERB, NULL); 641 } 642 return (np); 643 } 644 645 /* 646 * config_bytp_lookup -- look up the path in our TPcache lut. 647 * If we find it return the config path, but as a struct node. 648 */ 649 struct node * 650 config_bytp_lookup(struct cfgdata *fromcfg, const char *tp) 651 { 652 struct config *find; 653 struct node *np; 654 655 out(O_ALTFP|O_VERB3, "Device id cache:"); 656 lut_walk(fromcfg->devcache, (lut_cb)prttpcache, NULL); 657 658 if ((find = lut_lookup(fromcfg->tpcache, 659 (void *) stable(tp), NULL)) == NULL) 660 return (NULL); 661 662 np = config_nodeize(find); 663 if (np != NULL) { 664 out(O_ALTFP|O_VERB, "Matching config entry:"); 665 ptree_name_iter(O_ALTFP|O_VERB|O_NONL, np); 666 out(O_ALTFP|O_VERB, NULL); 667 } 668 return (np); 669 } 670 671 /* 672 * config_bycpuid_lookup -- look up the cpu id in our CPUcache lut. 673 * If we find it return the config path, but as a struct node. 674 */ 675 struct node * 676 config_bycpuid_lookup(struct cfgdata *fromcfg, uint32_t id) 677 { 678 struct config *find; 679 struct node *np; 680 681 out(O_ALTFP|O_VERB, "Cpu cache:"); 682 lut_walk(fromcfg->cpucache, (lut_cb)prtcpucache, NULL); 683 684 if ((find = lut_lookup(fromcfg->cpucache, 685 (void *)id, NULL)) == NULL) 686 return (NULL); 687 688 np = config_nodeize(find); 689 if (np != NULL) { 690 out(O_ALTFP|O_VERB3, "Matching config entry:"); 691 ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, np); 692 out(O_ALTFP|O_VERB3, NULL); 693 } 694 return (np); 695 } 696 697 /* 698 * printprop -- print prop associated with config node 699 */ 700 static void 701 printprop(const char *lhs, const char *rhs, void *arg) 702 { 703 int flags = (int)arg; 704 705 out(flags, "\t%s=%s", lhs, rhs); 706 } 707 708 /* 709 * pconf -- internal printing function to recurse through the tree 710 */ 711 static void 712 pconf(int flags, struct config *cp, char *buf, int offset, int limit) 713 { 714 char *sep = "/"; 715 716 if (offset) 717 sep = "/"; 718 else 719 sep = ""; 720 (void) snprintf(&buf[offset], limit - offset, "%s%s%d", 721 sep, cp->s, cp->num); 722 if (cp->child == NULL) { 723 out(flags, "%s", buf); 724 lut_walk(cp->props, (lut_cb)printprop, (void *)flags); 725 } else 726 pconf(flags, cp->child, buf, strlen(buf), limit); 727 if (cp->next) 728 pconf(flags, cp->next, buf, offset, limit); 729 } 730 731 /* 732 * config_print -- spew the current configuration cache 733 */ 734 735 #define MAXCONFLINE 4096 736 737 void 738 config_print(int flags, struct config *croot) 739 { 740 char buf[MAXCONFLINE]; 741 742 if (croot == NULL) 743 out(flags, "empty configuration"); 744 else 745 pconf(flags, croot->child, buf, 0, MAXCONFLINE); 746 } 747