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 *
newcnode(const char * s,int num)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
config_node_cache(struct cfgdata * cdata,struct config * n)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 *
config_lookup(struct config * croot,char * path,int add)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
addconfigprop(const char * lhs,struct node * rhs,void * arg)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
addconfig(struct node * lhs,struct node * rhs,void * arg)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
config_cook(struct cfgdata * cdata)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 *
config_snapshot(void)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
prop_destructor(void * left,void * right,void * arg)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
structconfig_free(struct config * cp)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
config_free(struct cfgdata * cp)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 *
config_next(struct config * cp)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 *
config_child(struct config * cp)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 *
config_parent(struct config * cp)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
config_setprop(struct config * cp,const char * propname,const char * propvalue)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 *
config_getprop(struct config * cp,const char * propname)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
config_getcompname(struct config * cp,char ** name,int * inst)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 *
config_nodeize(struct config * cp)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
prtdevcache(void * lhs,void * rhs,void * arg)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
prtdevidcache(void * lhs,void * rhs,void * arg)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
prttpcache(void * lhs,void * rhs,void * arg)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
prtcpucache(void * lhs,void * rhs,void * arg)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 *
config_bydev_lookup(struct cfgdata * fromcfg,const char * path)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 *
config_bydevid_lookup(struct cfgdata * fromcfg,const char * devid)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 *
config_bytp_lookup(struct cfgdata * fromcfg,const char * tp)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 *
config_bycpuid_lookup(struct cfgdata * fromcfg,uint32_t id)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
printprop(const char * lhs,const char * rhs,void * arg)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
pconf(int flags,struct config * cp,char * buf,int offset,int limit)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
config_print(int flags,struct config * croot)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