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