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.
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.
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]
23 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
27 * config.c -- system configuration cache module
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.
41 #include <fm/topo_hc.h>
53 #include "config_impl.h"
57 static const char *config_lastcomp
;
60 * newcnode -- local function to allocate new config node
62 static struct config
*
63 newcnode(const char *s
, int num
)
65 struct config
*retval
;
67 retval
= MALLOC(sizeof (struct config
));
73 retval
->child
= retval
->parent
= NULL
;
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
84 config_node_cache(struct cfgdata
*cdata
, struct config
*n
)
86 if (n
->s
!= stable("cpu"))
88 cdata
->cpucache
= lut_add(cdata
->cpucache
,
89 (void *)n
->num
, (void *)n
, NULL
);
93 * config_lookup -- lookup/add components in configuration cache
96 config_lookup(struct config
*croot
, char *path
, int add
)
98 char *pathbegin
= path
;
99 struct config
*parent
= croot
;
101 struct config
*lastcp
;
102 struct config
*newnode
;
103 char *thiscom
; /* this component */
104 char *nextcom
; /* next component */
112 out(O_DIE
, "uninitialized configuration");
115 if ((nextcom
= strchr(path
, '/')) != NULL
)
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",
125 while (thiscom
> path
&& isdigit(*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 */
142 /* now we have s & num, figure out if it exists already */
145 for (cp
= parent
->child
; cp
; lastcp
= cp
, cp
= cp
->next
)
146 if (cp
->s
== s
&& cp
->num
== num
) {
152 /* creating new node */
155 * indicate component not found by copying
156 * it to path (allows better error messages
159 (void) strcpy(pathbegin
, s
);
163 newnode
= newcnode(s
, num
);
166 lastcp
->next
= newnode
;
168 parent
->child
= newnode
;
170 newnode
->parent
= parent
;
175 return (parent
); /* all done */
177 /* move on to next component */
184 * addconfigprop -- add a config prop to a config cache entry
187 addconfigprop(const char *lhs
, struct node
*rhs
, void *arg
)
189 struct config
*cp
= (struct config
*)arg
;
194 ASSERT(rhs
->t
== T_QUOTE
);
196 config_setprop(cp
, lhs
, STRDUP(rhs
->u
.quote
.s
));
200 * addconfig -- add a config from parse tree to given configuration cache
204 addconfig(struct node
*lhs
, struct node
*rhs
, void *arg
)
206 struct config
*parent
= (struct config
*)arg
;
210 struct config
*lastcp
;
211 struct config
*newnode
;
215 ASSERT(rhs
->t
== T_CONFIG
);
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
);
223 num
= rhs
->u
.name
.child
->u
.ull
;
225 /* now we have s & num, figure out if it exists already */
228 for (cp
= parent
->child
; cp
; lastcp
= cp
, cp
= cp
->next
)
229 if (cp
->s
== s
&& cp
->num
== num
) {
235 /* creating new node */
237 newnode
= newcnode(s
, num
);
240 lastcp
->next
= newnode
;
242 parent
->child
= newnode
;
244 newnode
->parent
= parent
;
248 /* move on to next component */
249 rhs
= rhs
->u
.name
.next
;
252 /* add configuration properties */
253 lut_walk(lutp
, (lut_cb
)addconfigprop
, (void *)parent
);
257 * config_cook -- convert raw config strings to eft internal representation
260 config_cook(struct cfgdata
*cdata
)
262 struct config
*newnode
;
263 char *cfgstr
, *equals
;
267 extern struct lut
*Usedprops
;
268 extern struct lut
*Usednames
;
270 cdata
->cooked
= newcnode(NULL
, 0);
272 if ((cfgstr
= cdata
->begin
) == cdata
->nextfree
) {
273 out(O_ALTFP
|O_VERB
, "Platform provided no config data.");
278 * add the following properties to the "usedprops" table as they
279 * are used internally by eft
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
);
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
) {
293 out(O_ALTFP
|O_VERB3
|O_NONL
, "\n%p ",
294 (void *)(cfgstr
+ 1));
296 out(O_ALTFP
|O_VERB3
|O_NONL
, "%c", *cfgstr
);
299 out(O_ALTFP
|O_VERB3
, NULL
);
301 cfgstr
= cdata
->begin
;
302 while (cfgstr
< cdata
->nextfree
) {
303 while (*cfgstr
== '/' && cfgstr
< cdata
->nextfree
) {
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);
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.
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.
321 config_node_cache(cdata
, newnode
);
322 cfgstr
+= strlen(cfgstr
) + 1;
325 if (cfgstr
>= cdata
->nextfree
)
328 out(O_ALTFP
|O_VERB3
, "next string (%p) is %s", (void *)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
);
340 * only actually add the props if the rules use them (saves
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
,
349 config_setprop(newnode
, pn
, pv
);
353 * If this property is a device path, tp or devid, cache it
356 if (config_lastcomp
== stable(SCSI_DEVICE
) ||
357 config_lastcomp
== stable(SMP_DEVICE
)) {
359 * we can't get ereports on SCSI_DEVICE or SMP_DEVICE
360 * nodes, so don't cache.
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
)) {
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.
383 char *x
, *y
= equals
;
390 out(O_ALTFP
|O_VERB3
, "caching tp %s", sv
);
391 cdata
->tpcache
= lut_add(cdata
->tpcache
,
392 (void *)sv
, (void *)newnode
, NULL
);
399 cfgstr
+= strlen(cfgstr
) + 1;
403 /* now run through Configs table, adding to config cache */
404 lut_walk(Configs
, (lut_cb
)addconfig
, (void *)cdata
->cooked
);
408 * config_snapshot -- gather a snapshot of the current configuration
411 config_snapshot(void)
413 struct cfgdata
*rawcfg
;
415 rawcfg
= platform_config_snapshot();
421 * prop_destructor -- free a prop value
425 prop_destructor(void *left
, void *right
, void *arg
)
431 * structconfig_free -- free a struct config pointer and all its relatives
434 structconfig_free(struct config
*cp
)
439 structconfig_free(cp
->child
);
440 structconfig_free(cp
->next
);
441 lut_free(cp
->props
, prop_destructor
, NULL
);
446 * config_free -- free a configuration snapshot
449 config_free(struct cfgdata
*cp
)
454 if (--cp
->raw_refcnt
== 0) {
455 if (cp
->devcache
!= NULL
)
456 lut_free(cp
->devcache
, NULL
, NULL
);
458 if (cp
->tpcache
!= NULL
)
459 lut_free(cp
->tpcache
, NULL
, 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
);
467 if (cp
->begin
!= NULL
)
474 * config_next -- get the "next" config node
477 config_next(struct config
*cp
)
481 return ((struct config
*)((struct config
*)cp
)->next
);
486 * config_child -- get the "child" of a config node
489 config_child(struct config
*cp
)
493 return ((struct config
*)((struct config
*)cp
)->child
);
497 * config_parent -- get the "parent" of a config node
500 config_parent(struct config
*cp
)
504 return ((struct config
*)((struct config
*)cp
)->parent
);
508 * config_setprop -- add a property to a config node
511 config_setprop(struct config
*cp
, const char *propname
, const char *propvalue
)
513 const char *pn
= stable(propname
);
515 cp
->props
= lut_add(cp
->props
, (void *)pn
, (void *)propvalue
, NULL
);
519 * config_getprop -- lookup a config property
522 config_getprop(struct config
*cp
, const char *propname
)
524 return (lut_lookup(cp
->props
, (void *) stable(propname
), NULL
));
528 * config_getcompname -- get the component name of a config node
531 config_getcompname(struct config
*cp
, char **name
, int *inst
)
536 *name
= (char *)cp
->s
;
542 * config_nodeize -- convert the config element represented by cp to struct
546 config_nodeize(struct config
*cp
)
548 struct node
*tmpn
, *ptmpn
;
552 if (cp
== NULL
|| cp
->s
== NULL
)
555 sname
= stable(cp
->s
);
556 numn
= newnode(T_NUM
, NULL
, 0);
557 numn
->u
.ull
= cp
->num
;
559 tmpn
= tree_name_iterator(tree_name(sname
, IT_VERTICAL
, NULL
, 0), numn
);
560 if ((ptmpn
= config_nodeize(cp
->parent
)) == NULL
)
562 return (tree_name_append(ptmpn
, tmpn
));
567 prtdevcache(void *lhs
, void *rhs
, void *arg
)
569 out(O_ALTFP
|O_VERB3
, "%s -> %p", (char *)lhs
, rhs
);
574 prtdevidcache(void *lhs
, void *rhs
, void *arg
)
576 out(O_ALTFP
|O_VERB3
, "%s -> %p", (char *)lhs
, rhs
);
581 prttpcache(void *lhs
, void *rhs
, void *arg
)
583 out(O_ALTFP
|O_VERB3
, "%s -> %p", (char *)lhs
, rhs
);
588 prtcpucache(void *lhs
, void *rhs
, void *arg
)
590 out(O_ALTFP
|O_VERB
, "%u -> %p", (uint32_t)lhs
, rhs
);
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.
598 config_bydev_lookup(struct cfgdata
*fromcfg
, const char *path
)
603 out(O_ALTFP
|O_VERB3
, "Device path cache:");
604 lut_walk(fromcfg
->devcache
, (lut_cb
)prtdevcache
, NULL
);
606 if ((find
= lut_lookup(fromcfg
->devcache
,
607 (void *) stable(path
), NULL
)) == NULL
)
610 np
= config_nodeize(find
);
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
);
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.
624 config_bydevid_lookup(struct cfgdata
*fromcfg
, const char *devid
)
629 out(O_ALTFP
|O_VERB3
, "Device id cache:");
630 lut_walk(fromcfg
->devcache
, (lut_cb
)prtdevidcache
, NULL
);
632 if ((find
= lut_lookup(fromcfg
->devidcache
,
633 (void *) stable(devid
), NULL
)) == NULL
)
636 np
= config_nodeize(find
);
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
);
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.
650 config_bytp_lookup(struct cfgdata
*fromcfg
, const char *tp
)
655 out(O_ALTFP
|O_VERB3
, "Device id cache:");
656 lut_walk(fromcfg
->devcache
, (lut_cb
)prttpcache
, NULL
);
658 if ((find
= lut_lookup(fromcfg
->tpcache
,
659 (void *) stable(tp
), NULL
)) == NULL
)
662 np
= config_nodeize(find
);
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
);
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.
676 config_bycpuid_lookup(struct cfgdata
*fromcfg
, uint32_t id
)
681 out(O_ALTFP
|O_VERB
, "Cpu cache:");
682 lut_walk(fromcfg
->cpucache
, (lut_cb
)prtcpucache
, NULL
);
684 if ((find
= lut_lookup(fromcfg
->cpucache
,
685 (void *)id
, NULL
)) == NULL
)
688 np
= config_nodeize(find
);
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
);
698 * printprop -- print prop associated with config node
701 printprop(const char *lhs
, const char *rhs
, void *arg
)
703 int flags
= (int)arg
;
705 out(flags
, "\t%s=%s", lhs
, rhs
);
709 * pconf -- internal printing function to recurse through the tree
712 pconf(int flags
, struct config
*cp
, char *buf
, int offset
, int limit
)
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
);
726 pconf(flags
, cp
->child
, buf
, strlen(buf
), limit
);
728 pconf(flags
, cp
->next
, buf
, offset
, limit
);
732 * config_print -- spew the current configuration cache
735 #define MAXCONFLINE 4096
738 config_print(int flags
, struct config
*croot
)
740 char buf
[MAXCONFLINE
];
743 out(flags
, "empty configuration");
745 pconf(flags
, croot
->child
, buf
, 0, MAXCONFLINE
);