fm/modules/eversholt: fix 64-bit compilation
[unleashed.git] / usr / src / cmd / fm / modules / common / eversholt / config.c
blob8b72e09a3915ac73360161846a3c9bf6d8320d86
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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.
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"
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));
69 retval->s = s;
70 retval->num = num;
71 retval->next = NULL;
72 retval->props = NULL;
73 retval->child = retval->parent = NULL;
75 return (retval);
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.
83 static void
84 config_node_cache(struct cfgdata *cdata, struct config *n)
86 if (n->s != stable("cpu"))
87 return;
88 cdata->cpucache = lut_add(cdata->cpucache,
89 (void *)n->num, (void *)n, NULL);
93 * config_lookup -- lookup/add components in configuration cache
95 struct config *
96 config_lookup(struct config *croot, char *path, int add)
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;
111 if (parent == NULL)
112 out(O_DIE, "uninitialized configuration");
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;
139 if (nextcom != NULL)
140 *nextcom++ = '/';
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;
151 if (!exists) {
152 /* creating new node */
153 if (!add) {
155 * indicate component not found by copying
156 * it to path (allows better error messages
157 * in the caller).
159 (void) strcpy(pathbegin, s);
160 return (NULL);
163 newnode = newcnode(s, num);
165 if (lastcp)
166 lastcp->next = newnode;
167 else
168 parent->child = newnode;
170 newnode->parent = parent;
171 parent = newnode;
174 if (nextcom == NULL)
175 return (parent); /* all done */
177 /* move on to next component */
178 path = nextcom;
180 return (parent);
184 * addconfigprop -- add a config prop to a config cache entry
186 static void
187 addconfigprop(const char *lhs, struct node *rhs, void *arg)
189 struct config *cp = (struct config *)arg;
191 ASSERT(cp != NULL);
192 ASSERT(lhs != NULL);
193 ASSERT(rhs != NULL);
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
202 /*ARGSUSED*/
203 static void
204 addconfig(struct node *lhs, struct node *rhs, void *arg)
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;
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);
222 s = rhs->u.name.s;
223 num = rhs->u.name.child->u.ull;
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;
234 if (!exists) {
235 /* creating new node */
237 newnode = newcnode(s, num);
239 if (lastcp)
240 lastcp->next = newnode;
241 else
242 parent->child = newnode;
244 newnode->parent = parent;
245 parent = newnode;
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
259 void
260 config_cook(struct cfgdata *cdata)
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;
270 cdata->cooked = newcnode(NULL, 0);
272 if ((cfgstr = cdata->begin) == cdata->nextfree) {
273 out(O_ALTFP|O_VERB, "Platform provided no config data.");
274 goto eftcfgs;
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) {
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++;
299 out(O_ALTFP|O_VERB3, NULL);
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);
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)
326 break;
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;
336 *equals = '\0';
337 pn = stable(cfgstr);
340 * only actually add the props if the rules use them (saves
341 * memory)
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);
353 * If this property is a device path, tp or devid, cache it
354 * for quick lookup.
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;
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 = ' ';
398 *equals = '=';
399 cfgstr += strlen(cfgstr) + 1;
402 eftcfgs:
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
410 struct cfgdata *
411 config_snapshot(void)
413 struct cfgdata *rawcfg;
415 rawcfg = platform_config_snapshot();
416 config_cook(rawcfg);
417 return (rawcfg);
421 * prop_destructor -- free a prop value
423 /*ARGSUSED*/
424 static void
425 prop_destructor(void *left, void *right, void *arg)
427 FREE(right);
431 * structconfig_free -- free a struct config pointer and all its relatives
433 void
434 structconfig_free(struct config *cp)
436 if (cp == NULL)
437 return;
439 structconfig_free(cp->child);
440 structconfig_free(cp->next);
441 lut_free(cp->props, prop_destructor, NULL);
442 FREE(cp);
446 * config_free -- free a configuration snapshot
448 void
449 config_free(struct cfgdata *cp)
451 if (cp == NULL)
452 return;
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);
474 * config_next -- get the "next" config node
476 struct config *
477 config_next(struct config *cp)
479 ASSERT(cp != NULL);
481 return ((struct config *)((struct config *)cp)->next);
486 * config_child -- get the "child" of a config node
488 struct config *
489 config_child(struct config *cp)
491 ASSERT(cp != NULL);
493 return ((struct config *)((struct config *)cp)->child);
497 * config_parent -- get the "parent" of a config node
499 struct config *
500 config_parent(struct config *cp)
502 ASSERT(cp != NULL);
504 return ((struct config *)((struct config *)cp)->parent);
508 * config_setprop -- add a property to a config node
510 void
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
521 const char *
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
530 void
531 config_getcompname(struct config *cp, char **name, int *inst)
533 ASSERT(cp != NULL);
535 if (name != NULL)
536 *name = (char *)cp->s;
537 if (inst != NULL)
538 *inst = cp->num;
542 * config_nodeize -- convert the config element represented by cp to struct
543 * node format
545 static struct node *
546 config_nodeize(struct config *cp)
548 struct node *tmpn, *ptmpn;
549 struct node *numn;
550 const char *sname;
552 if (cp == NULL || cp->s == NULL)
553 return (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)
561 return (tmpn);
562 return (tree_name_append(ptmpn, tmpn));
565 /*ARGSUSED*/
566 static void
567 prtdevcache(void *lhs, void *rhs, void *arg)
569 out(O_ALTFP|O_VERB3, "%s -> %p", (char *)lhs, rhs);
572 /*ARGSUSED*/
573 static void
574 prtdevidcache(void *lhs, void *rhs, void *arg)
576 out(O_ALTFP|O_VERB3, "%s -> %p", (char *)lhs, rhs);
579 /*ARGSUSED*/
580 static void
581 prttpcache(void *lhs, void *rhs, void *arg)
583 out(O_ALTFP|O_VERB3, "%s -> %p", (char *)lhs, rhs);
586 /*ARGSUSED*/
587 static void
588 prtcpucache(void *lhs, void *rhs, void *arg)
590 out(O_ALTFP|O_VERB, "%u -> %p", (uintptr_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.
597 struct node *
598 config_bydev_lookup(struct cfgdata *fromcfg, const char *path)
600 struct config *find;
601 struct node *np;
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)
608 return (NULL);
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);
616 return (np);
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.
623 struct node *
624 config_bydevid_lookup(struct cfgdata *fromcfg, const char *devid)
626 struct config *find;
627 struct node *np;
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)
634 return (NULL);
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);
642 return (np);
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.
649 struct node *
650 config_bytp_lookup(struct cfgdata *fromcfg, const char *tp)
652 struct config *find;
653 struct node *np;
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)
660 return (NULL);
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);
668 return (np);
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.
675 struct node *
676 config_bycpuid_lookup(struct cfgdata *fromcfg, uint32_t id)
678 struct config *find;
679 struct node *np;
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 *)(uintptr_t)id, NULL)) == NULL)
686 return (NULL);
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);
694 return (np);
698 * printprop -- print prop associated with config node
700 static void
701 printprop(const char *lhs, const char *rhs, void *arg)
703 intptr_t flags = (intptr_t)arg;
705 out(flags, "\t%s=%s", lhs, rhs);
709 * pconf -- internal printing function to recurse through the tree
711 static void
712 pconf(int flags, struct config *cp, char *buf, int offset, int limit)
714 char *sep = "/";
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 *)(intptr_t)flags);
725 } else
726 pconf(flags, cp->child, buf, strlen(buf), limit);
727 if (cp->next)
728 pconf(flags, cp->next, buf, offset, limit);
732 * config_print -- spew the current configuration cache
735 #define MAXCONFLINE 4096
737 void
738 config_print(int flags, struct config *croot)
740 char buf[MAXCONFLINE];
742 if (croot == NULL)
743 out(flags, "empty configuration");
744 else
745 pconf(flags, croot->child, buf, 0, MAXCONFLINE);