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 2006 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 /* 73 * newcnode -- local function to allocate new config node 74 */ 75 static struct config * 76 newcnode(const char *s, int num) 77 { 78 struct config *retval; 79 80 retval = MALLOC(sizeof (struct config)); 81 82 retval->s = s; 83 retval->num = num; 84 retval->next = NULL; 85 retval->props = NULL; 86 retval->child = retval->parent = NULL; 87 88 return (retval); 89 } 90 91 /* 92 * If we need to cache certain types of nodes for reverse look-up or 93 * somesuch, do it here. Currently we need to cache nodes representing 94 * cpus. 95 */ 96 static void 97 config_node_cache(struct cfgdata *cdata, struct config *n) 98 { 99 if (n->s != stable("cpu")) 100 return; 101 cdata->cpucache = lut_add(cdata->cpucache, 102 (void *)n->num, (void *)n, NULL); 103 } 104 105 /* 106 * config_lookup -- lookup/add components in configuration cache 107 */ 108 struct config * 109 config_lookup(struct config *croot, char *path, int add) 110 { 111 char *pathbegin = path; 112 struct config *parent = croot; 113 struct config *cp; 114 struct config *lastcp; 115 struct config *newnode; 116 char *thiscom; /* this component */ 117 char *nextcom; /* next component */ 118 char svdigit; 119 int len; 120 int num; 121 const char *s; 122 int exists; 123 124 if (parent == NULL) 125 out(O_DIE, "uninitialized configuration"); 126 127 while (*path) { 128 if ((nextcom = strchr(path, '/')) != NULL) 129 *nextcom = '\0'; 130 if ((len = strlen(path)) == 0) 131 out(O_DIE, "config_lookup: zero length component"); 132 /* start at end of string and work backwards */ 133 thiscom = &path[len - 1]; 134 if (!isdigit(*thiscom)) 135 out(O_DIE, "config_lookup: " 136 "component \"%s\" has no number following it", 137 path); 138 while (thiscom > path && isdigit(*thiscom)) 139 thiscom--; 140 if (thiscom == path && isdigit(*thiscom)) 141 out(O_DIE, "config_lookup: " 142 "component \"%s\" has no name part", path); 143 thiscom++; /* move to first numeric character */ 144 num = atoi(thiscom); 145 svdigit = *thiscom; 146 *thiscom = '\0'; 147 s = stable(path); 148 *thiscom = svdigit; 149 150 if (nextcom != NULL) 151 *nextcom++ = '/'; 152 153 /* now we have s & num, figure out if it exists already */ 154 exists = 0; 155 lastcp = NULL; 156 for (cp = parent->child; cp; lastcp = cp, cp = cp->next) 157 if (cp->s == s && cp->num == num) { 158 exists = 1; 159 parent = cp; 160 } 161 162 if (!exists) { 163 /* creating new node */ 164 if (!add) { 165 /* 166 * indicate component not found by copying 167 * it to path (allows better error messages 168 * in the caller). 169 */ 170 (void) strcpy(pathbegin, s); 171 return (NULL); 172 } 173 174 newnode = newcnode(s, num); 175 176 if (lastcp) 177 lastcp->next = newnode; 178 else 179 parent->child = newnode; 180 181 newnode->parent = parent; 182 parent = newnode; 183 } 184 185 if (nextcom == NULL) 186 return (parent); /* all done */ 187 188 /* move on to next component */ 189 path = nextcom; 190 } 191 return (parent); 192 } 193 194 /* 195 * addconfigprop -- add a config prop to a config cache entry 196 */ 197 static void 198 addconfigprop(const char *lhs, struct node *rhs, void *arg) 199 { 200 struct config *cp = (struct config *)arg; 201 202 ASSERT(cp != NULL); 203 ASSERT(lhs != NULL); 204 ASSERT(rhs != NULL); 205 ASSERT(rhs->t == T_QUOTE); 206 207 config_setprop(cp, lhs, STRDUP(rhs->u.quote.s)); 208 } 209 210 /* 211 * addconfig -- add a config from parse tree to given configuration cache 212 */ 213 /*ARGSUSED*/ 214 static void 215 addconfig(struct node *lhs, struct node *rhs, void *arg) 216 { 217 struct config *parent = (struct config *)arg; 218 struct config *cp; 219 const char *s; 220 int num; 221 struct config *lastcp; 222 struct config *newnode; 223 int exists; 224 struct lut *lutp; 225 226 ASSERT(rhs->t == T_CONFIG); 227 228 lutp = rhs->u.stmt.lutp; 229 rhs = rhs->u.stmt.np; 230 while (rhs != NULL) { 231 ASSERT(rhs->t == T_NAME); 232 ASSERT(rhs->u.name.child->t == T_NUM); 233 s = rhs->u.name.s; 234 num = rhs->u.name.child->u.ull; 235 236 /* now we have s & num, figure out if it exists already */ 237 exists = 0; 238 lastcp = NULL; 239 for (cp = parent->child; cp; lastcp = cp, cp = cp->next) 240 if (cp->s == s && cp->num == num) { 241 exists = 1; 242 parent = cp; 243 } 244 245 if (!exists) { 246 /* creating new node */ 247 248 newnode = newcnode(s, num); 249 250 if (lastcp) 251 lastcp->next = newnode; 252 else 253 parent->child = newnode; 254 255 parent = newnode; 256 } 257 258 /* move on to next component */ 259 rhs = rhs->u.name.next; 260 } 261 262 /* add configuration properties */ 263 lut_walk(lutp, (lut_cb)addconfigprop, (void *)parent); 264 } 265 266 /* 267 * config_cook -- convert raw config strings to eft internal representation 268 */ 269 void 270 config_cook(struct cfgdata *cdata) 271 { 272 struct config *newnode; 273 char *cfgstr, *equals; 274 const char *pn, *sv; 275 char *pv; 276 277 if (cdata->cooked != NULL) 278 return; 279 280 cdata->cooked = newcnode(NULL, 0); 281 282 if ((cfgstr = cdata->begin) == cdata->nextfree) { 283 out(O_ALTFP|O_VERB, "Platform provided no config data."); 284 goto eftcfgs; 285 } 286 287 out(O_ALTFP|O_VERB3, "Raw config data follows:"); 288 out(O_ALTFP|O_VERB3|O_NONL, 289 "nextfree is %p\n%p ", (void *)cdata->nextfree, (void *)cfgstr); 290 while (cfgstr < cdata->nextfree) { 291 if (!*cfgstr) 292 out(O_ALTFP|O_VERB3|O_NONL, "\n%p ", 293 (void *)(cfgstr + 1)); 294 else 295 out(O_ALTFP|O_VERB3|O_NONL, "%c", *cfgstr); 296 cfgstr++; 297 } 298 out(O_ALTFP|O_VERB3, NULL); 299 300 cfgstr = cdata->begin; 301 while (cfgstr < cdata->nextfree) { 302 while (*cfgstr == '/' && cfgstr < cdata->nextfree) { 303 out(O_ALTFP|O_VERB3, 304 "next string (%p) is %s", (void *)cfgstr, cfgstr); 305 /* skip the initial slash from libtopo */ 306 newnode = config_lookup(cdata->cooked, cfgstr + 1, 1); 307 /* 308 * Note we'll only cache nodes that have 309 * properties on them. Intermediate nodes 310 * will have been added to the config tree, 311 * but we don't have easy means of accessing 312 * them except if we climb the tree from this 313 * newnode to the root. 314 * 315 * Luckily, the nodes we care to cache 316 * (currently just cpus) always have some 317 * properties attached to them 318 * so we don't bother climbing the tree. 319 */ 320 config_node_cache(cdata, newnode); 321 cfgstr += strlen(cfgstr) + 1; 322 } 323 324 if (cfgstr >= cdata->nextfree) 325 break; 326 327 out(O_ALTFP|O_VERB3, "next string (%p) is %s", (void *)cfgstr, 328 cfgstr); 329 if ((equals = strchr(cfgstr, '=')) == NULL) { 330 out(O_ALTFP|O_VERB3, "raw config data bad (%p); " 331 "property missing equals.\n", (void *)cfgstr); 332 break; 333 } 334 335 *equals = '\0'; 336 pn = stable(cfgstr); 337 pv = STRDUP(equals + 1); 338 339 out(O_ALTFP|O_VERB3, "add prop (%s) val %p", pn, (void *)pv); 340 config_setprop(newnode, pn, pv); 341 342 /* 343 * If this property is a device path, cache it for quick lookup 344 */ 345 if (pn == stable(TOPO_IO_DEV)) { 346 sv = stable(pv); 347 out(O_ALTFP|O_VERB3, "caching %s\n", sv); 348 cdata->devcache = lut_add(cdata->devcache, 349 (void *)sv, (void *)newnode, NULL); 350 } 351 352 *equals = '='; 353 cfgstr += strlen(cfgstr) + 1; 354 } 355 356 eftcfgs: 357 /* now run through Configs table, adding to config cache */ 358 lut_walk(Configs, (lut_cb)addconfig, (void *)cdata->cooked); 359 } 360 361 /* 362 * config_snapshot -- gather a snapshot of the current configuration 363 */ 364 struct cfgdata * 365 config_snapshot(void) 366 { 367 struct cfgdata *rawcfg; 368 369 rawcfg = platform_config_snapshot(); 370 config_cook(rawcfg); 371 return (rawcfg); 372 } 373 374 /* 375 * prop_destructor -- free a prop value 376 */ 377 /*ARGSUSED*/ 378 static void 379 prop_destructor(void *left, void *right, void *arg) 380 { 381 FREE(right); 382 } 383 384 /* 385 * structconfig_free -- free a struct config pointer and all its relatives 386 */ 387 static void 388 structconfig_free(struct config *cp) 389 { 390 if (cp == NULL) 391 return; 392 393 structconfig_free(cp->child); 394 structconfig_free(cp->next); 395 lut_free(cp->props, prop_destructor, NULL); 396 FREE(cp); 397 } 398 399 /* 400 * config_free -- free a configuration snapshot 401 */ 402 void 403 config_free(struct cfgdata *cp) 404 { 405 if (cp == NULL) 406 return; 407 408 if (--cp->refcnt > 0) 409 return; 410 411 if (cp->cooked != NULL) 412 structconfig_free(cp->cooked); 413 if (cp->begin != NULL) 414 FREE(cp->begin); 415 if (cp->devcache != NULL) 416 lut_free(cp->devcache, NULL, NULL); 417 if (cp->cpucache != NULL) 418 lut_free(cp->cpucache, NULL, NULL); 419 FREE(cp); 420 } 421 422 /* 423 * config_next -- get the "next" config node 424 */ 425 struct config * 426 config_next(struct config *cp) 427 { 428 ASSERT(cp != NULL); 429 430 return ((struct config *)((struct config *)cp)->next); 431 } 432 433 434 /* 435 * config_child -- get the "child" of a config node 436 */ 437 struct config * 438 config_child(struct config *cp) 439 { 440 ASSERT(cp != NULL); 441 442 return ((struct config *)((struct config *)cp)->child); 443 } 444 445 /* 446 * config_setprop -- add a property to a config node 447 */ 448 void 449 config_setprop(struct config *cp, const char *propname, const char *propvalue) 450 { 451 const char *pn = stable(propname); 452 453 cp->props = lut_add(cp->props, (void *)pn, (void *)propvalue, NULL); 454 } 455 456 /* 457 * config_getprop -- lookup a config property 458 */ 459 const char * 460 config_getprop(struct config *cp, const char *propname) 461 { 462 return (lut_lookup(cp->props, (void *) stable(propname), NULL)); 463 } 464 465 /* 466 * config_getcompname -- get the component name of a config node 467 */ 468 void 469 config_getcompname(struct config *cp, char **name, int *inst) 470 { 471 ASSERT(cp != NULL); 472 473 if (name != NULL) 474 *name = (char *)cp->s; 475 if (inst != NULL) 476 *inst = cp->num; 477 } 478 479 /* 480 * config_nodeize -- convert the config element represented by cp to struct 481 * node format 482 */ 483 static struct node * 484 config_nodeize(struct config *cp) 485 { 486 struct node *tmpn, *ptmpn; 487 struct node *numn; 488 const char *sname; 489 490 if (cp == NULL || cp->s == NULL) 491 return (NULL); 492 493 sname = stable(cp->s); 494 numn = newnode(T_NUM, NULL, 0); 495 numn->u.ull = cp->num; 496 497 tmpn = tree_name_iterator(tree_name(sname, IT_VERTICAL, NULL, 0), numn); 498 if ((ptmpn = config_nodeize(cp->parent)) == NULL) 499 return (tmpn); 500 return (tree_name_append(ptmpn, tmpn)); 501 } 502 503 /*ARGSUSED*/ 504 static void 505 prtdevcache(void *lhs, void *rhs, void *arg) 506 { 507 out(O_ALTFP|O_VERB3, "%s -> %p", (char *)lhs, rhs); 508 } 509 510 /*ARGSUSED*/ 511 static void 512 prtcpucache(void *lhs, void *rhs, void *arg) 513 { 514 out(O_ALTFP|O_VERB, "%u -> %p", (uint32_t)lhs, rhs); 515 } 516 517 /* 518 * config_bydev_lookup -- look up the path in our DEVcache lut. If we find 519 * it return the config path, but as a struct node. 520 */ 521 struct node * 522 config_bydev_lookup(struct cfgdata *fromcfg, const char *path) 523 { 524 struct config *find; 525 struct node *np; 526 527 out(O_ALTFP|O_VERB3, "Device path cache:"); 528 lut_walk(fromcfg->devcache, (lut_cb)prtdevcache, NULL); 529 530 if ((find = lut_lookup(fromcfg->devcache, 531 (void *) stable(path), NULL)) == NULL) 532 return (NULL); 533 534 np = config_nodeize(find); 535 if (np != NULL) { 536 out(O_ALTFP|O_VERB, "Matching config entry:"); 537 ptree_name_iter(O_ALTFP|O_VERB|O_NONL, np); 538 out(O_ALTFP|O_VERB, NULL); 539 } 540 return (np); 541 } 542 543 /* 544 * config_bycpuid_lookup -- look up the cpu id in our CPUcache lut. 545 * If we find it return the config path, but as a struct node. 546 */ 547 struct node * 548 config_bycpuid_lookup(struct cfgdata *fromcfg, uint32_t id) 549 { 550 struct config *find; 551 struct node *np; 552 553 out(O_ALTFP|O_VERB, "Cpu cache:"); 554 lut_walk(fromcfg->cpucache, (lut_cb)prtcpucache, NULL); 555 556 if ((find = lut_lookup(fromcfg->cpucache, 557 (void *)id, NULL)) == NULL) 558 return (NULL); 559 560 np = config_nodeize(find); 561 if (np != NULL) { 562 out(O_ALTFP|O_VERB3, "Matching config entry:"); 563 ptree_name_iter(O_ALTFP|O_VERB3|O_NONL, np); 564 out(O_ALTFP|O_VERB3, NULL); 565 } 566 return (np); 567 } 568 569 /* 570 * given the following: 571 * - np of type T_NAME which denotes a pathname 572 * - croot, the root node of a configuration 573 * 574 * return the cp for the last component in np's path 575 */ 576 static struct config * 577 name2cp(struct node *np, struct config *croot) 578 { 579 char *path; 580 struct config *cp; 581 582 if (np->u.name.last->u.name.cp != NULL) 583 return (np->u.name.last->u.name.cp); 584 585 path = ipath2str(NULL, ipath(np)); 586 587 cp = config_lookup(croot, path, 0); 588 FREE((void *)path); 589 590 return (cp); 591 } 592 593 #define CONNECTED_SEPCHARS " ," 594 595 int 596 config_is_connected(struct node *np, struct config *croot, 597 struct evalue *valuep) 598 { 599 const char *connstrings[] = { "connected", "CONNECTED", NULL }; 600 struct config *cp[2], *compcp; 601 struct node *nptr[2]; 602 const char *searchforname, *matchthis[2], *s; 603 char *nameslist, *w; 604 int i, j; 605 606 valuep->t = UINT64; 607 valuep->v = 0; 608 609 if (np->u.expr.left->t == T_NAME) 610 nptr[0] = np->u.expr.left; 611 else if (np->u.expr.left->u.func.s == L_fru) 612 nptr[0] = eval_fru(np->u.expr.left->u.func.arglist); 613 else if (np->u.expr.left->u.func.s == L_asru) 614 nptr[0] = eval_asru(np->u.expr.left->u.func.arglist); 615 616 if (np->u.expr.right->t == T_NAME) 617 nptr[1] = np->u.expr.right; 618 else if (np->u.expr.right->u.func.s == L_fru) 619 nptr[1] = eval_fru(np->u.expr.right->u.func.arglist); 620 else if (np->u.expr.right->u.func.s == L_asru) 621 nptr[1] = eval_asru(np->u.expr.right->u.func.arglist); 622 623 for (i = 0; i < 2; i++) { 624 cp[i] = name2cp(nptr[i], croot); 625 if (cp[i] == NULL) 626 return (1); 627 } 628 629 /* to thine self always be connected */ 630 if (cp[0] == cp[1]) { 631 valuep->v = 1; 632 return (0); 633 } 634 635 /* 636 * set one of the cp[]s to compcp and extract its "connected" 637 * property. search this property for the name associated with the 638 * other cp[]. 639 */ 640 for (i = 0; i < 2 && valuep->v == 0; i++) { 641 compcp = cp[i]; 642 643 searchforname = ipath2str(NULL, ipath(nptr[(i == 0 ? 1 : 0)])); 644 matchthis[i] = stable(searchforname); 645 FREE((void *)searchforname); 646 647 for (j = 0; connstrings[j] != NULL && valuep->v == 0; j++) { 648 s = config_getprop(compcp, stable(connstrings[j])); 649 if (s != NULL) { 650 nameslist = STRDUP(s); 651 w = strtok(nameslist, CONNECTED_SEPCHARS); 652 while (w != NULL) { 653 if (stable(w) == matchthis[i]) { 654 valuep->v = 1; 655 break; 656 } 657 w = strtok(NULL, CONNECTED_SEPCHARS); 658 } 659 FREE(nameslist); 660 } 661 } 662 } 663 664 /* a path shouldn't have more than one cp node */ 665 if (valuep->v == 0) 666 ASSERT(matchthis[0] != matchthis[1]); 667 668 return (0); 669 } 670 671 int 672 config_is_type(struct node *np, struct config *croot, struct evalue *valuep) 673 { 674 const char *typestrings[] = { "type", "TYPE", NULL }; 675 struct config *cp; 676 struct node *nodep; 677 const char *s; 678 int i; 679 680 valuep->t = STRING; 681 valuep->v = 0; 682 683 if (np->u.func.s == L_fru) 684 nodep = eval_fru(np->u.func.arglist); 685 else if (np->u.func.s == L_asru) 686 nodep = eval_asru(np->u.func.arglist); 687 688 cp = name2cp(nodep, croot); 689 if (cp == NULL) 690 return (1); 691 692 for (i = 0; typestrings[i] != NULL; i++) { 693 s = config_getprop(cp, stable(typestrings[i])); 694 if (s != NULL) { 695 valuep->v = (uintptr_t)stable(s); 696 break; 697 } 698 } 699 700 /* no entry for "type" */ 701 if (valuep->v == 0) 702 return (1); 703 704 return (0); 705 } 706 707 int 708 config_is_on(struct node *np, struct config *croot, struct evalue *valuep) 709 { 710 const char *onstrings[] = { "on", "ON", NULL }; 711 const char *truestrings[] = { "yes", "YES", "y", "Y", 712 "true", "TRUE", "t", "T", 713 "1", NULL }; 714 struct config *cp; 715 struct node *nodep; 716 const char *s; 717 int i, j; 718 719 valuep->t = UINT64; 720 valuep->v = 0; 721 722 if (np->u.func.s == L_fru) 723 nodep = eval_fru(np->u.func.arglist); 724 else if (np->u.func.s == L_asru) 725 nodep = eval_asru(np->u.func.arglist); 726 727 cp = name2cp(nodep, croot); 728 if (cp == NULL) 729 return (1); 730 731 for (i = 0; onstrings[i] != NULL; i++) { 732 s = config_getprop(cp, stable(onstrings[i])); 733 if (s != NULL) { 734 s = stable(s); 735 for (j = 0; truestrings[j] != NULL; j++) { 736 if (s == stable(truestrings[j])) { 737 valuep->v = 1; 738 return (0); 739 } 740 } 741 } 742 } 743 744 return (0); 745 } 746 747 int 748 config_is_present(struct node *np, struct config *croot, struct evalue *valuep) 749 { 750 struct config *cp; 751 struct node *nodep; 752 753 valuep->t = UINT64; 754 valuep->v = 0; 755 756 if (np->u.func.s == L_fru) 757 nodep = eval_fru(np->u.func.arglist); 758 else if (np->u.func.s == L_asru) 759 nodep = eval_asru(np->u.func.arglist); 760 761 cp = name2cp(nodep, croot); 762 if (cp != NULL) 763 valuep->v = 1; 764 765 return (0); 766 } 767 768 /* 769 * printprop -- print prop associated with config node 770 */ 771 static void 772 printprop(const char *lhs, const char *rhs, void *arg) 773 { 774 int flags = (int)arg; 775 776 out(flags, "\t%s=%s", lhs, rhs); 777 } 778 779 /* 780 * pconf -- internal printing function to recurse through the tree 781 */ 782 static void 783 pconf(int flags, struct config *cp, char *buf, int offset, int limit) 784 { 785 char *sep = "/"; 786 787 if (offset) 788 sep = "/"; 789 else 790 sep = ""; 791 (void) snprintf(&buf[offset], limit - offset, "%s%s%d", 792 sep, cp->s, cp->num); 793 if (cp->child == NULL) { 794 out(flags, "%s", buf); 795 lut_walk(cp->props, (lut_cb)printprop, (void *)flags); 796 } else 797 pconf(flags, cp->child, buf, strlen(buf), limit); 798 if (cp->next) 799 pconf(flags, cp->next, buf, offset, limit); 800 } 801 802 /* 803 * config_print -- spew the current configuration cache 804 */ 805 806 #define MAXCONFLINE 4096 807 808 void 809 config_print(int flags, struct config *croot) 810 { 811 char buf[MAXCONFLINE]; 812 813 if (croot == NULL) 814 out(flags, "empty configuration"); 815 else 816 pconf(flags, croot->child, buf, 0, MAXCONFLINE); 817 } 818