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