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