8954 libtopo cannot handle any array type other than string_array.
[unleashed.git] / usr / src / lib / fm / topo / libtopo / common / topo_xml.c
blob228755c953d54e49b036d94b21012006e544ec13
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) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2013, Joyent, Inc. All rights reserved.
27 #include <libxml/parser.h>
28 #include <libxml/xinclude.h>
29 #include <sys/fm/protocol.h>
30 #include <assert.h>
31 #include <string.h>
32 #include <strings.h>
33 #include <ctype.h>
34 #include <errno.h>
35 #include <limits.h>
36 #include <fm/libtopo.h>
37 #include <unistd.h>
38 #include <sys/stat.h>
39 #include <fcntl.h>
40 #include <topo_file.h>
41 #include <topo_mod.h>
42 #include <topo_subr.h>
43 #include <topo_alloc.h>
44 #include <topo_parse.h>
45 #include <topo_error.h>
47 static tf_rdata_t *topo_xml_walk(topo_mod_t *, tf_info_t *, xmlNodePtr,
48 tnode_t *);
49 static tf_edata_t *enum_attributes_process(topo_mod_t *, xmlNodePtr);
50 static int enum_run(topo_mod_t *, tf_rdata_t *);
51 static int fac_enum_run(topo_mod_t *, tnode_t *, const char *);
52 static int fac_process(topo_mod_t *, xmlNodePtr, tf_rdata_t *, tnode_t *);
53 static int fac_enum_process(topo_mod_t *, xmlNodePtr, tnode_t *);
54 static int decorate_nodes(topo_mod_t *, tf_rdata_t *, xmlNodePtr, tnode_t *,
55 tf_pad_t **);
58 static void
59 strarr_free(topo_mod_t *mod, char **arr, uint_t nelems)
61 int i;
63 for (i = 0; i < nelems; i++)
64 topo_mod_strfree(mod, arr[i]);
65 topo_mod_free(mod, arr, (nelems * sizeof (char *)));
68 int
69 xmlattr_to_stab(topo_mod_t *mp, xmlNodePtr n, const char *stabname,
70 topo_stability_t *rs)
72 xmlChar *str;
73 int rv = 0;
75 if (n == NULL) {
76 /* If there is no Stability defined, we default to private */
77 *rs = TOPO_STABILITY_PRIVATE;
78 return (0);
80 if ((str = xmlGetProp(n, (xmlChar *)stabname)) == NULL) {
81 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
82 "attribute to stability:\n");
83 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
86 if (xmlStrcmp(str, (xmlChar *)Internal) == 0) {
87 *rs = TOPO_STABILITY_INTERNAL;
88 } else if (xmlStrcmp(str, (xmlChar *)Private) == 0) {
89 *rs = TOPO_STABILITY_PRIVATE;
90 } else if (xmlStrcmp(str, (xmlChar *)Obsolete) == 0) {
91 *rs = TOPO_STABILITY_OBSOLETE;
92 } else if (xmlStrcmp(str, (xmlChar *)External) == 0) {
93 *rs = TOPO_STABILITY_EXTERNAL;
94 } else if (xmlStrcmp(str, (xmlChar *)Unstable) == 0) {
95 *rs = TOPO_STABILITY_UNSTABLE;
96 } else if (xmlStrcmp(str, (xmlChar *)Evolving) == 0) {
97 *rs = TOPO_STABILITY_EVOLVING;
98 } else if (xmlStrcmp(str, (xmlChar *)Stable) == 0) {
99 *rs = TOPO_STABILITY_STABLE;
100 } else if (xmlStrcmp(str, (xmlChar *)Standard) == 0) {
101 *rs = TOPO_STABILITY_STANDARD;
102 } else {
103 xmlFree(str);
104 return (topo_mod_seterrno(mp, ETOPO_PRSR_BADSTAB));
106 xmlFree(str);
107 return (rv);
111 xmlattr_to_int(topo_mod_t *mp,
112 xmlNodePtr n, const char *propname, uint64_t *value)
114 xmlChar *str;
115 xmlChar *estr;
117 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "xmlattr_to_int(propname=%s)\n",
118 propname);
119 if ((str = xmlGetProp(n, (xmlChar *)propname)) == NULL)
120 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
121 *value = strtoull((char *)str, (char **)&estr, 10);
122 if (estr == str) {
123 /* no conversion was done */
124 xmlFree(str);
125 return (topo_mod_seterrno(mp, ETOPO_PRSR_BADNUM));
127 xmlFree(str);
128 return (0);
131 static int
132 xmlattr_to_fmri(topo_mod_t *mp,
133 xmlNodePtr xn, const char *propname, nvlist_t **rnvl)
135 xmlChar *str;
137 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "xmlattr_to_fmri(propname=%s)\n",
138 propname);
139 if ((str = xmlGetProp(xn, (xmlChar *)propname)) == NULL)
140 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
141 if (topo_mod_str2nvl(mp, (const char *)str, rnvl) < 0) {
142 xmlFree(str);
143 return (-1);
145 xmlFree(str);
146 return (0);
149 static topo_type_t
150 xmlattr_to_type(topo_mod_t *mp, xmlNodePtr xn, xmlChar *attr)
152 topo_type_t rv;
153 xmlChar *str;
154 if ((str = xmlGetProp(xn, (xmlChar *)attr)) == NULL) {
155 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "%s attribute missing",
156 attr);
157 (void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
158 return (TOPO_TYPE_INVALID);
160 if (xmlStrcmp(str, (xmlChar *)Int32) == 0) {
161 rv = TOPO_TYPE_INT32;
162 } else if (xmlStrcmp(str, (xmlChar *)UInt32) == 0) {
163 rv = TOPO_TYPE_UINT32;
164 } else if (xmlStrcmp(str, (xmlChar *)Int64) == 0) {
165 rv = TOPO_TYPE_INT64;
166 } else if (xmlStrcmp(str, (xmlChar *)UInt64) == 0) {
167 rv = TOPO_TYPE_UINT64;
168 } else if (xmlStrcmp(str, (xmlChar *)FMRI) == 0) {
169 rv = TOPO_TYPE_FMRI;
170 } else if (xmlStrcmp(str, (xmlChar *)String) == 0) {
171 rv = TOPO_TYPE_STRING;
172 } else if (xmlStrcmp(str, (xmlChar *)Int32_Arr) == 0) {
173 rv = TOPO_TYPE_INT32_ARRAY;
174 } else if (xmlStrcmp(str, (xmlChar *)UInt32_Arr) == 0) {
175 rv = TOPO_TYPE_UINT32_ARRAY;
176 } else if (xmlStrcmp(str, (xmlChar *)Int64_Arr) == 0) {
177 rv = TOPO_TYPE_INT64_ARRAY;
178 } else if (xmlStrcmp(str, (xmlChar *)UInt64_Arr) == 0) {
179 rv = TOPO_TYPE_UINT64_ARRAY;
180 } else if (xmlStrcmp(str, (xmlChar *)String_Arr) == 0) {
181 rv = TOPO_TYPE_STRING_ARRAY;
182 } else if (xmlStrcmp(str, (xmlChar *)FMRI_Arr) == 0) {
183 rv = TOPO_TYPE_FMRI_ARRAY;
184 } else {
185 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
186 "Unrecognized type attribute value '%s'.\n", str);
187 (void) topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE);
188 xmlFree(str);
189 return (TOPO_TYPE_INVALID);
191 xmlFree(str);
192 return (rv);
195 static int
196 xlate_common(topo_mod_t *mp, xmlNodePtr xn, topo_type_t ptype, nvlist_t *nvl,
197 const char *name)
199 int rv;
200 uint64_t ui;
201 uint_t i = 0, nelems = 0;
202 nvlist_t *fmri;
203 xmlChar *str;
204 char **strarrbuf;
205 void *arrbuf;
206 nvlist_t **nvlarrbuf;
207 xmlNodePtr cn;
209 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "xlate_common(name=%s)\n", name);
210 switch (ptype) {
211 case TOPO_TYPE_INT32:
212 if (xmlattr_to_int(mp, xn, Value, &ui) < 0)
213 return (-1);
214 rv = nvlist_add_int32(nvl, name, (int32_t)ui);
215 break;
216 case TOPO_TYPE_UINT32:
217 if (xmlattr_to_int(mp, xn, Value, &ui) < 0)
218 return (-1);
219 rv = nvlist_add_uint32(nvl, name, (uint32_t)ui);
220 break;
221 case TOPO_TYPE_INT64:
222 if (xmlattr_to_int(mp, xn, Value, &ui) < 0)
223 return (-1);
224 rv = nvlist_add_int64(nvl, name, (int64_t)ui);
225 break;
226 case TOPO_TYPE_UINT64:
227 if (xmlattr_to_int(mp, xn, Value, &ui) < 0)
228 return (-1);
229 rv = nvlist_add_uint64(nvl, name, ui);
230 break;
231 case TOPO_TYPE_FMRI:
232 if (xmlattr_to_fmri(mp, xn, Value, &fmri) < 0)
233 return (-1);
234 rv = nvlist_add_nvlist(nvl, name, fmri);
235 nvlist_free(fmri);
236 break;
237 case TOPO_TYPE_STRING:
238 if ((str = xmlGetProp(xn, (xmlChar *)Value)) == NULL)
239 return (-1);
240 rv = nvlist_add_string(nvl, name, (char *)str);
241 xmlFree(str);
242 break;
243 case TOPO_TYPE_INT32_ARRAY:
244 case TOPO_TYPE_UINT32_ARRAY:
245 case TOPO_TYPE_INT64_ARRAY:
246 case TOPO_TYPE_UINT64_ARRAY:
247 case TOPO_TYPE_STRING_ARRAY:
248 case TOPO_TYPE_FMRI_ARRAY:
249 for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next)
250 if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
251 (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0))
252 nelems++;
254 if (nelems < 1) {
255 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "No <propitem> "
256 "or <argitem> elements found for array val");
257 return (-1);
259 break;
260 default:
261 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
262 "Unrecognized type attribute (ptype = %d)\n", ptype);
263 return (topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE));
266 switch (ptype) {
267 case TOPO_TYPE_INT32_ARRAY:
268 if ((arrbuf = topo_mod_alloc(mp, (nelems * sizeof (int32_t))))
269 == NULL)
270 return (topo_mod_seterrno(mp, ETOPO_NOMEM));
271 for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
272 if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
273 (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
275 if ((str = xmlGetProp(cn, (xmlChar *)Value))
276 == NULL)
277 return (-1);
279 ((int32_t *)arrbuf)[i++]
280 = atoi((const char *)str);
281 xmlFree(str);
285 rv = nvlist_add_int32_array(nvl, name, (int32_t *)arrbuf,
286 nelems);
287 topo_mod_free(mp, arrbuf, (nelems * sizeof (int32_t)));
288 break;
289 case TOPO_TYPE_UINT32_ARRAY:
290 if ((arrbuf = topo_mod_alloc(mp, (nelems * sizeof (uint32_t))))
291 == NULL)
292 return (topo_mod_seterrno(mp, ETOPO_NOMEM));
293 for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
294 if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
295 (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
297 if ((str = xmlGetProp(cn, (xmlChar *)Value))
298 == NULL)
299 return (-1);
301 ((uint32_t *)arrbuf)[i++]
302 = atoi((const char *)str);
303 xmlFree(str);
307 rv = nvlist_add_uint32_array(nvl, name, (uint32_t *)arrbuf,
308 nelems);
309 topo_mod_free(mp, arrbuf, (nelems * sizeof (uint32_t)));
310 break;
311 case TOPO_TYPE_INT64_ARRAY:
312 if ((arrbuf = topo_mod_alloc(mp, (nelems * sizeof (int64_t))))
313 == NULL)
314 return (topo_mod_seterrno(mp, ETOPO_NOMEM));
315 for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
316 if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
317 (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
319 if ((str = xmlGetProp(cn, (xmlChar *)Value))
320 == NULL)
321 return (-1);
323 ((int64_t *)arrbuf)[i++]
324 = atol((const char *)str);
325 xmlFree(str);
329 rv = nvlist_add_int64_array(nvl, name, (int64_t *)arrbuf,
330 nelems);
331 topo_mod_free(mp, arrbuf, (nelems * sizeof (int64_t)));
332 break;
333 case TOPO_TYPE_UINT64_ARRAY:
334 if ((arrbuf = topo_mod_alloc(mp, (nelems * sizeof (uint64_t))))
335 == NULL)
336 return (topo_mod_seterrno(mp, ETOPO_NOMEM));
337 for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
338 if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
339 (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
341 if ((str = xmlGetProp(cn, (xmlChar *)Value))
342 == NULL)
343 return (-1);
345 ((uint64_t *)arrbuf)[i++]
346 = atol((const char *)str);
347 xmlFree(str);
351 rv = nvlist_add_uint64_array(nvl, name, arrbuf,
352 nelems);
353 topo_mod_free(mp, arrbuf, (nelems * sizeof (uint64_t)));
354 break;
355 case TOPO_TYPE_STRING_ARRAY:
356 if ((strarrbuf = topo_mod_alloc(mp, (nelems * sizeof (char *))))
357 == NULL)
358 return (topo_mod_seterrno(mp, ETOPO_NOMEM));
359 for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
360 if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
361 (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
363 if ((str = xmlGetProp(cn, (xmlChar *)Value))
364 == NULL)
365 return (-1);
367 strarrbuf[i++] =
368 topo_mod_strdup(mp, (const char *)str);
369 xmlFree(str);
373 rv = nvlist_add_string_array(nvl, name, strarrbuf, nelems);
374 strarr_free(mp, strarrbuf, nelems);
375 break;
376 case TOPO_TYPE_FMRI_ARRAY:
377 if ((nvlarrbuf = topo_mod_alloc(mp, (nelems *
378 sizeof (nvlist_t *)))) == NULL)
379 return (topo_mod_seterrno(mp, ETOPO_NOMEM));
380 for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
381 if ((xmlStrcmp(cn->name, (xmlChar *)Propitem) == 0) ||
382 (xmlStrcmp(cn->name, (xmlChar *)Argitem) == 0)) {
384 if ((str = xmlGetProp(cn, (xmlChar *)Value))
385 == NULL)
386 return (-1);
388 if (topo_mod_str2nvl(mp, (const char *)str,
389 &(nvlarrbuf[i++])) < 0) {
390 xmlFree(str);
391 return (-1);
393 xmlFree(str);
397 rv = nvlist_add_nvlist_array(nvl, name, nvlarrbuf,
398 nelems);
399 topo_mod_free(mp, nvlarrbuf, (nelems * sizeof (nvlist_t *)));
400 break;
403 if (rv != 0) {
404 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
405 "Nvlist construction failed.\n");
406 return (topo_mod_seterrno(mp, ETOPO_NOMEM));
407 } else
408 return (0);
411 static int
412 xmlprop_xlate(topo_mod_t *mp, xmlNodePtr xn, nvlist_t *nvl)
414 topo_type_t ptype;
415 xmlChar *str;
417 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "xmlprop_xlate\n");
418 if ((str = xmlGetProp(xn, (xmlChar *)Immutable)) != NULL) {
419 if (xmlStrcmp(str, (xmlChar *)False) == 0)
420 (void) nvlist_add_boolean_value(nvl, INV_IMMUTE,
421 B_FALSE);
422 else
423 (void) nvlist_add_boolean_value(nvl, INV_IMMUTE,
424 B_TRUE);
425 xmlFree(str);
426 } else {
427 (void) nvlist_add_boolean_value(nvl, INV_IMMUTE, B_TRUE);
430 if ((ptype = xmlattr_to_type(mp, xn, (xmlChar *)Type))
431 == TOPO_TYPE_INVALID)
432 return (-1);
434 if (nvlist_add_int32(nvl, INV_PVALTYPE, ptype) != 0)
435 return (-1);
437 return (xlate_common(mp, xn, ptype, nvl, INV_PVAL));
440 static int
441 dependent_create(topo_mod_t *mp,
442 tf_info_t *xinfo, tf_pad_t *pad, xmlNodePtr dxn, tnode_t *ptn)
444 tf_rdata_t *rp, *pp, *np;
445 xmlChar *grptype;
446 int sibs = 0;
448 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "dependent_create\n");
449 if ((grptype = xmlGetProp(dxn, (xmlChar *)Grouping)) == NULL) {
450 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
451 "Dependents missing grouping attribute");
452 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
455 pp = NULL;
456 if (xmlStrcmp(grptype, (xmlChar *)Siblings) == 0) {
457 rp = pad->tpad_sibs;
458 sibs++;
459 } else if (xmlStrcmp(grptype, (xmlChar *)Children) == 0) {
460 rp = pad->tpad_child;
461 } else {
462 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
463 "Dependents have bogus grouping attribute");
464 xmlFree(grptype);
465 return (topo_mod_seterrno(mp, ETOPO_PRSR_BADGRP));
467 xmlFree(grptype);
468 /* Add processed dependents to the tail of the list */
469 while (rp != NULL) {
470 pp = rp;
471 rp = rp->rd_next;
473 if ((np = topo_xml_walk(mp, xinfo, dxn, ptn)) == NULL) {
474 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
475 "error within dependent .xml topology: "
476 "%s\n", topo_strerror(topo_mod_errno(mp)));
477 return (-1);
479 if (pp != NULL)
480 pp->rd_next = np;
481 else if (sibs == 1)
482 pad->tpad_sibs = np;
483 else
484 pad->tpad_child = np;
485 return (0);
488 static int
489 dependents_create(topo_mod_t *mp,
490 tf_info_t *xinfo, tf_pad_t *pad, xmlNodePtr pxn, tnode_t *ptn)
492 xmlNodePtr cn;
494 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "dependents_create\n");
495 for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) {
496 if (xmlStrcmp(cn->name, (xmlChar *)Dependents) == 0) {
497 if (dependent_create(mp, xinfo, pad, cn, ptn) < 0)
498 return (-1);
501 return (0);
504 static int
505 prop_create(topo_mod_t *mp,
506 nvlist_t *pfmri, tnode_t *ptn, const char *gnm, const char *pnm,
507 topo_type_t ptype, int flag)
509 nvlist_t *fmri, **fmriarr;
510 uint32_t ui32, *ui32arr;
511 uint64_t ui64, *ui64arr;
512 int32_t i32, *i32arr;
513 int64_t i64, *i64arr;
514 uint_t nelem;
515 char *str, **strarr;
516 int err, e;
518 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "prop_create(pgrp = %s, "
519 "prop = %s)\n", gnm, pnm);
520 switch (ptype) {
521 case TOPO_TYPE_INT32:
522 e = nvlist_lookup_int32(pfmri, INV_PVAL, &i32);
523 break;
524 case TOPO_TYPE_UINT32:
525 e = nvlist_lookup_uint32(pfmri, INV_PVAL, &ui32);
526 break;
527 case TOPO_TYPE_INT64:
528 e = nvlist_lookup_int64(pfmri, INV_PVAL, &i64);
529 break;
530 case TOPO_TYPE_UINT64:
531 e = nvlist_lookup_uint64(pfmri, INV_PVAL, &ui64);
532 break;
533 case TOPO_TYPE_FMRI:
534 e = nvlist_lookup_nvlist(pfmri, INV_PVAL, &fmri);
535 break;
536 case TOPO_TYPE_STRING:
537 e = nvlist_lookup_string(pfmri, INV_PVAL, &str);
538 break;
539 case TOPO_TYPE_INT32_ARRAY:
540 e = nvlist_lookup_int32_array(pfmri, INV_PVAL, &i32arr, &nelem);
541 break;
542 case TOPO_TYPE_UINT32_ARRAY:
543 e = nvlist_lookup_uint32_array(pfmri, INV_PVAL, &ui32arr,
544 &nelem);
545 break;
546 case TOPO_TYPE_INT64_ARRAY:
547 e = nvlist_lookup_int64_array(pfmri, INV_PVAL, &i64arr,
548 &nelem);
549 break;
550 case TOPO_TYPE_UINT64_ARRAY:
551 e = nvlist_lookup_uint64_array(pfmri, INV_PVAL, &ui64arr,
552 &nelem);
553 break;
554 case TOPO_TYPE_STRING_ARRAY:
555 e = nvlist_lookup_string_array(pfmri, INV_PVAL, &strarr,
556 &nelem);
557 break;
558 case TOPO_TYPE_FMRI_ARRAY:
559 e = nvlist_lookup_nvlist_array(pfmri, INV_PVAL, &fmriarr,
560 &nelem);
561 break;
562 default:
563 e = ETOPO_PRSR_BADTYPE;
565 if (e != 0) {
566 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
567 "prop_create: prop value lookup failed.\n");
568 return (topo_mod_seterrno(mp, e));
570 switch (ptype) {
571 case TOPO_TYPE_INT32:
572 e = topo_prop_set_int32(ptn, gnm, pnm, flag, i32, &err);
573 break;
574 case TOPO_TYPE_UINT32:
575 e = topo_prop_set_uint32(ptn, gnm, pnm, flag, ui32, &err);
576 break;
577 case TOPO_TYPE_INT64:
578 e = topo_prop_set_int64(ptn, gnm, pnm, flag, i64, &err);
579 break;
580 case TOPO_TYPE_UINT64:
581 e = topo_prop_set_uint64(ptn, gnm, pnm, flag, ui64, &err);
582 break;
583 case TOPO_TYPE_FMRI:
584 e = topo_prop_set_fmri(ptn, gnm, pnm, flag, fmri, &err);
585 break;
586 case TOPO_TYPE_STRING:
587 e = topo_prop_set_string(ptn, gnm, pnm, flag, str, &err);
588 break;
589 case TOPO_TYPE_INT32_ARRAY:
590 e = topo_prop_set_int32_array(ptn, gnm, pnm, flag, i32arr,
591 nelem, &err);
592 break;
593 case TOPO_TYPE_UINT32_ARRAY:
594 e = topo_prop_set_uint32_array(ptn, gnm, pnm, flag, ui32arr,
595 nelem, &err);
596 break;
597 case TOPO_TYPE_INT64_ARRAY:
598 e = topo_prop_set_int64_array(ptn, gnm, pnm, flag, i64arr,
599 nelem, &err);
600 break;
601 case TOPO_TYPE_UINT64_ARRAY:
602 e = topo_prop_set_uint64_array(ptn, gnm, pnm, flag, ui64arr,
603 nelem, &err);
604 break;
605 case TOPO_TYPE_STRING_ARRAY:
606 e = topo_prop_set_string_array(ptn, gnm, pnm, flag,
607 (const char **)strarr, nelem, &err);
608 break;
609 case TOPO_TYPE_FMRI_ARRAY:
610 e = topo_prop_set_fmri_array(ptn, gnm, pnm, flag,
611 (const nvlist_t **)fmriarr, nelem, &err);
612 break;
614 if (e != 0 && err != ETOPO_PROP_DEFD) {
617 * Some properties may have already been set
618 * in topo_node_bind() or topo_prop_inherit if we are
619 * enumerating from a static .xml file
621 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "prop set "
622 "failed %s/%s:%s\n", gnm, pnm, topo_strerror(err));
623 return (topo_mod_seterrno(mp, err));
625 return (0);
628 static int
629 props_create(topo_mod_t *mp,
630 tnode_t *ptn, const char *gnm, nvlist_t **props, int nprops)
632 topo_type_t ptype;
633 boolean_t pim;
634 char *pnm;
635 int32_t i32;
636 int flag;
637 int pn;
638 int e;
640 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "props_create(pgrp = %s)\n",
641 gnm);
642 for (pn = 0; pn < nprops; pn++) {
643 e = nvlist_lookup_string(props[pn], INV_PNAME, &pnm);
644 if (e != 0) {
645 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
646 "props create lookup (%s) failure: %s",
647 INV_PNAME, strerror(e));
648 return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP));
650 e = nvlist_lookup_boolean_value(props[pn], INV_IMMUTE, &pim);
651 if (e != 0) {
652 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
653 "props create lookup (%s) failure: %s",
654 INV_IMMUTE, strerror(e));
655 return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP));
657 flag = (pim == B_TRUE) ?
658 TOPO_PROP_IMMUTABLE : TOPO_PROP_MUTABLE;
660 e = nvlist_lookup_int32(props[pn], INV_PVALTYPE, &i32);
661 if (e != 0) {
662 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
663 "props create lookup (%s) failure: %s",
664 INV_PVALTYPE, strerror(e));
665 return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP));
667 ptype = (topo_type_t)i32;
668 if (prop_create(mp, props[pn], ptn, gnm, pnm, ptype, flag) < 0)
669 return (-1);
671 return (0);
674 static int
675 pgroups_create(topo_mod_t *mp, tf_pad_t *pad, tnode_t *ptn)
677 topo_pgroup_info_t pgi;
678 nvlist_t **props;
679 char *gnm;
680 char *nmstab, *dstab;
681 uint32_t rnprops, nprops;
682 uint32_t gv;
683 int pg;
684 int e;
686 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroups_create: %s=%d\n",
687 topo_node_name(ptn), topo_node_instance(ptn));
688 for (pg = 0; pg < pad->tpad_pgcnt; pg++) {
689 e = nvlist_lookup_string(pad->tpad_pgs[pg],
690 INV_PGRP_NAME, &gnm);
691 if (e != 0) {
692 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
693 "pad lookup (%s) failed (%s).\n",
694 INV_PGRP_NAME, strerror(errno));
695 return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP));
697 e = nvlist_lookup_string(pad->tpad_pgs[pg],
698 INV_PGRP_NMSTAB, &nmstab);
699 if (e != 0) {
700 if (e != ENOENT) {
701 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
702 "pad lookup (%s) "
703 "failed.\n", INV_PGRP_NMSTAB);
704 return (topo_mod_seterrno(mp,
705 ETOPO_PRSR_NVPROP));
706 } else {
707 nmstab = TOPO_STABSTR_PRIVATE;
710 e = nvlist_lookup_string(pad->tpad_pgs[pg],
711 INV_PGRP_DSTAB, &dstab);
712 if (e != 0) {
713 if (e != ENOENT) {
714 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
715 "pad lookup (%s) failed.\n",
716 INV_PGRP_DSTAB);
717 return (topo_mod_seterrno(mp,
718 ETOPO_PRSR_NVPROP));
719 } else {
720 dstab = TOPO_STABSTR_PRIVATE;
723 e = nvlist_lookup_uint32(pad->tpad_pgs[pg],
724 INV_PGRP_VER, &gv);
725 if (e != 0) {
726 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
727 "pad lookup (%s) failed.\n",
728 INV_PGRP_VER);
729 return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP));
731 pgi.tpi_name = gnm;
732 pgi.tpi_namestab = topo_name2stability(nmstab);
733 pgi.tpi_datastab = topo_name2stability(dstab);
734 pgi.tpi_version = gv;
735 if (topo_pgroup_create(ptn, &pgi, &e) != 0) {
736 if (e != ETOPO_PROP_DEFD) {
737 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
738 "pgroups create failure: %s\n",
739 topo_strerror(e));
740 return (-1);
743 e = nvlist_lookup_uint32(pad->tpad_pgs[pg],
744 INV_PGRP_NPROP, &rnprops);
746 * The number of properties could be zero if the property
747 * group only contains propmethod declarations
749 if (rnprops > 0) {
750 e |= nvlist_lookup_nvlist_array(pad->tpad_pgs[pg],
751 INV_PGRP_ALLPROPS, &props, &nprops);
752 if (rnprops != nprops) {
753 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
754 "recorded number of props %d does not "
755 "match number of props recorded %d.\n",
756 rnprops, nprops);
758 if (props_create(mp, ptn, gnm, props, nprops) < 0)
759 return (-1);
762 return (0);
765 static nvlist_t *
766 pval_record(topo_mod_t *mp, xmlNodePtr xn)
768 nvlist_t *pnvl = NULL;
769 xmlChar *pname;
771 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pval_record\n");
772 if ((pname = xmlGetProp(xn, (xmlChar *)Name)) == NULL) {
773 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
774 "propval lacks a name\n");
775 (void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
776 return (NULL);
778 if (topo_mod_nvalloc(mp, &pnvl, NV_UNIQUE_NAME) < 0) {
779 xmlFree(pname);
780 return (NULL);
782 if (nvlist_add_string(pnvl, INV_PNAME, (char *)pname) < 0) {
783 xmlFree(pname);
784 nvlist_free(pnvl);
785 return (NULL);
787 xmlFree(pname);
788 /* FMXXX stability of the property name */
790 if (xmlprop_xlate(mp, xn, pnvl) < 0) {
791 nvlist_free(pnvl);
792 return (NULL);
794 return (pnvl);
798 struct propmeth_data {
799 const char *pg_name;
800 const char *prop_name;
801 topo_type_t prop_type;
802 const char *meth_name;
803 topo_version_t meth_ver;
804 nvlist_t *arg_nvl;
807 static int
808 register_method(topo_mod_t *mp, tnode_t *ptn, struct propmeth_data *meth)
810 int err;
812 if (topo_prop_method_version_register(ptn, meth->pg_name,
813 meth->prop_name, meth->prop_type, meth->meth_name, meth->meth_ver,
814 meth->arg_nvl, &err) != 0) {
816 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "failed to register "
817 "propmethod %s for property \"%s\" in propgrp %s on node "
818 "%s=%d (%s)\n",
819 meth->meth_name, meth->prop_name, meth->pg_name,
820 topo_node_name(ptn), topo_node_instance(ptn),
821 topo_strerror(err));
822 return (-1);
824 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
825 "registered method %s on %s=%d\n",
826 meth->meth_name, topo_node_name(ptn), topo_node_instance(ptn));
828 return (0);
831 static int
832 pmeth_record(topo_mod_t *mp, const char *pg_name, xmlNodePtr xn, tnode_t *tn,
833 const char *rname, const char *ppgrp_name)
835 nvlist_t *arg_nvl = NULL;
836 xmlNodePtr cn;
837 xmlChar *meth_name = NULL, *prop_name = NULL;
838 xmlChar *arg_name = NULL;
839 uint64_t meth_ver, is_mutable = 0, is_nonvolatile = 0;
840 topo_type_t prop_type;
841 struct propmeth_data meth;
842 int ret = 0, err;
843 topo_type_t ptype;
844 tnode_t *tmp;
846 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pmeth_record: %s=%d "
847 "(pgrp=%s)\n", topo_node_name(tn), topo_node_instance(tn), pg_name);
850 * Get propmethod attribute values
852 if ((meth_name = xmlGetProp(xn, (xmlChar *)Name)) == NULL) {
853 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
854 "propmethod element lacks a name attribute\n");
855 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
857 if (xmlattr_to_int(mp, xn, Version, &meth_ver) < 0) {
858 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
859 "propmethod element lacks version attribute\n");
860 ret = topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
861 goto pmr_done;
864 * The "mutable" and "nonvoltile" attributes are optional. If not
865 * specified we default to false (0)
867 (void) xmlattr_to_int(mp, xn, Mutable, &is_mutable);
868 (void) xmlattr_to_int(mp, xn, Nonvolatile, &is_nonvolatile);
870 if ((prop_name = xmlGetProp(xn, (xmlChar *)Propname)) == NULL) {
871 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
872 "propmethod element lacks propname attribute\n");
873 ret = topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
874 goto pmr_done;
876 if ((prop_type = xmlattr_to_type(mp, xn, (xmlChar *)Proptype))
877 == TOPO_TYPE_INVALID) {
878 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
879 "error decoding proptype attribute\n");
880 ret = topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
881 goto pmr_done;
885 * Allocate method argument nvlist
887 if (topo_mod_nvalloc(mp, &arg_nvl, NV_UNIQUE_NAME) < 0) {
888 ret = topo_mod_seterrno(mp, ETOPO_NOMEM);
889 goto pmr_done;
893 * Iterate through the argval nodes and build the argval nvlist
895 for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) {
896 if (xmlStrcmp(cn->name, (xmlChar *)Argval) == 0) {
897 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
898 "found argval element\n");
899 if ((arg_name = xmlGetProp(cn, (xmlChar *)Name))
900 == NULL) {
901 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
902 "argval element lacks a name attribute\n");
903 ret = topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
904 goto pmr_done;
906 if ((ptype = xmlattr_to_type(mp, cn, (xmlChar *)Type))
907 == TOPO_TYPE_INVALID) {
908 ret = topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE);
909 xmlFree(arg_name);
910 break;
912 if (xlate_common(mp, cn, ptype, arg_nvl,
913 (const char *)arg_name) != 0) {
914 ret = topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE);
915 xmlFree(arg_name);
916 break;
919 if (arg_name) {
920 xmlFree(arg_name);
921 arg_name = NULL;
925 if (ret != 0)
926 goto pmr_done;
929 * Register the prop method for all of the nodes in our range
931 meth.pg_name = (const char *)pg_name;
932 meth.prop_name = (const char *)prop_name;
933 meth.prop_type = prop_type;
934 meth.meth_name = (const char *)meth_name;
935 meth.meth_ver = meth_ver;
936 meth.arg_nvl = arg_nvl;
939 * If the propgroup element is under a range element, we'll apply
940 * the method to all of the topo nodes at this level with the same
941 * range name.
943 * Otherwise, if the propgroup element is under a node element
944 * then we'll simply register the method for this node.
946 if (strcmp(ppgrp_name, Range) == 0) {
947 for (tmp = tn; tmp != NULL; tmp = topo_child_next(NULL, tmp)) {
948 if (strcmp(rname, topo_node_name(tmp)) == 0) {
949 if (register_method(mp, tmp, &meth) != 0) {
950 ret = topo_mod_seterrno(mp,
951 ETOPO_PRSR_REGMETH);
952 goto pmr_done;
954 if (is_mutable) {
955 if (topo_prop_setmutable(tmp,
956 meth.pg_name, meth.prop_name, &err)
957 != 0) {
958 ret = topo_mod_seterrno(mp,
959 ETOPO_PRSR_REGMETH);
960 goto pmr_done;
963 if (is_nonvolatile) {
964 if (topo_prop_setnonvolatile(tmp,
965 meth.pg_name, meth.prop_name, &err)
966 != 0) {
967 ret = topo_mod_seterrno(mp,
968 ETOPO_PRSR_REGMETH);
969 goto pmr_done;
974 } else {
975 if (register_method(mp, tn, &meth) != 0) {
976 ret = topo_mod_seterrno(mp, ETOPO_PRSR_REGMETH);
977 goto pmr_done;
979 if (is_mutable) {
980 if (topo_prop_setmutable(tn, meth.pg_name,
981 meth.prop_name, &err) != 0) {
982 ret = topo_mod_seterrno(mp,
983 ETOPO_PRSR_REGMETH);
984 goto pmr_done;
987 if (is_nonvolatile) {
988 if (topo_prop_setnonvolatile(tn, meth.pg_name,
989 meth.prop_name, &err) != 0) {
990 ret = topo_mod_seterrno(mp,
991 ETOPO_PRSR_REGMETH);
992 goto pmr_done;
997 pmr_done:
998 if (meth_name)
999 xmlFree(meth_name);
1000 if (prop_name)
1001 xmlFree(prop_name);
1002 nvlist_free(arg_nvl);
1003 return (ret);
1007 static int
1008 pgroup_record(topo_mod_t *mp, xmlNodePtr pxn, tnode_t *tn, const char *rname,
1009 tf_pad_t *rpad, int pi, const char *ppgrp_name)
1011 topo_stability_t nmstab, dstab;
1012 uint64_t ver;
1013 xmlNodePtr cn;
1014 xmlChar *name;
1015 nvlist_t **apl = NULL;
1016 nvlist_t *pgnvl = NULL;
1017 int pcnt = 0;
1018 int ai = 0;
1019 int e;
1021 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroup_record\n");
1022 if ((name = xmlGetProp(pxn, (xmlChar *)Name)) == NULL) {
1023 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1024 "propgroup lacks a name\n");
1025 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
1027 if (xmlattr_to_int(mp, pxn, Version, &ver) < 0) {
1028 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1029 "propgroup lacks a version\n");
1030 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
1032 if (xmlattr_to_stab(mp, pxn, Namestab, &nmstab) < 0) {
1033 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1034 "propgroup lacks name-stability\n");
1035 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
1037 if (xmlattr_to_stab(mp, pxn, Datastab, &dstab) < 0) {
1038 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1039 "propgroup lacks data-stability\n");
1040 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR));
1043 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroup %s\n", (char *)name);
1044 for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) {
1045 if (xmlStrcmp(cn->name, (xmlChar *)Propval) == 0)
1046 pcnt++;
1049 if (topo_mod_nvalloc(mp, &pgnvl, NV_UNIQUE_NAME) < 0) {
1050 xmlFree(name);
1051 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1052 "failed to allocate propgroup nvlist\n");
1053 return (topo_mod_seterrno(mp, ETOPO_NOMEM));
1056 e = nvlist_add_string(pgnvl, INV_PGRP_NAME, (char *)name);
1057 e |= nvlist_add_uint32(pgnvl, INV_PGRP_NMSTAB, nmstab);
1058 e |= nvlist_add_uint32(pgnvl, INV_PGRP_DSTAB, dstab);
1059 e |= nvlist_add_uint32(pgnvl, INV_PGRP_VER, ver);
1060 e |= nvlist_add_uint32(pgnvl, INV_PGRP_NPROP, pcnt);
1061 if (pcnt > 0)
1062 if (e != 0 ||
1063 (apl = topo_mod_zalloc(mp, pcnt * sizeof (nvlist_t *)))
1064 == NULL) {
1065 xmlFree(name);
1066 nvlist_free(pgnvl);
1067 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1068 "failed to allocate nvlist array for properties"
1069 "(e=%d)\n", e);
1070 return (topo_mod_seterrno(mp, ETOPO_NOMEM));
1072 for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) {
1073 if (xmlStrcmp(cn->name, (xmlChar *)Propval) == 0) {
1074 if (ai < pcnt) {
1075 if ((apl[ai] = pval_record(mp, cn)) == NULL)
1076 break;
1078 ai++;
1079 } else if (xmlStrcmp(cn->name, (xmlChar *)Prop_meth) == 0) {
1080 if (pmeth_record(mp, (const char *)name, cn, tn, rname,
1081 ppgrp_name) < 0)
1082 break;
1085 xmlFree(name);
1086 if (pcnt > 0) {
1087 e |= (ai != pcnt);
1088 e |= nvlist_add_nvlist_array(pgnvl, INV_PGRP_ALLPROPS, apl,
1089 pcnt);
1090 for (ai = 0; ai < pcnt; ai++)
1091 nvlist_free(apl[ai]);
1092 topo_mod_free(mp, apl, pcnt * sizeof (nvlist_t *));
1093 if (e != 0) {
1094 nvlist_free(pgnvl);
1095 return (-1);
1098 rpad->tpad_pgs[pi] = pgnvl;
1099 return (0);
1102 static int
1103 pgroups_record(topo_mod_t *mp, xmlNodePtr pxn, tnode_t *tn, const char *rname,
1104 tf_pad_t *rpad, const char *ppgrp)
1106 xmlNodePtr cn;
1107 int pi = 0;
1109 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroups_record: pxn->name=%s\n",
1110 pxn->name);
1111 for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) {
1112 if (xmlStrcmp(cn->name, (xmlChar *)Propgrp) == 0) {
1113 if (pgroup_record(mp, cn, tn, rname, rpad, pi++, ppgrp)
1114 < 0)
1115 return (-1);
1118 return (0);
1122 * psn: pointer to a "set" XML node
1123 * key: string to search the set for
1125 * returns: 1, if the set contains key
1126 * 0, otherwise
1128 static int
1129 set_contains(topo_mod_t *mp, char *key, char *set)
1131 char *prod;
1132 int rv = 0;
1134 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "set_contains(key = %s, "
1135 "setlist = %s)\n", key, set);
1137 prod = strtok((char *)set, "|");
1138 if (prod && (strcmp(key, prod) == 0))
1139 return (1);
1141 while ((prod = strtok(NULL, "|")))
1142 if (strcmp(key, prod) == 0)
1143 return (1);
1145 return (rv);
1150 * Process the property group and dependents xmlNode children of
1151 * parent xmlNode pxn.
1153 static int
1154 pad_process(topo_mod_t *mp, tf_rdata_t *rd, xmlNodePtr pxn, tnode_t *ptn,
1155 tf_pad_t **rpad)
1157 xmlNodePtr cn, gcn, psn, ecn, target;
1158 xmlNodePtr def_set = NULL;
1159 tnode_t *ct;
1160 tf_pad_t *new = *rpad;
1161 tf_rdata_t tmp_rd;
1162 int pgcnt = 0;
1163 int dcnt = 0;
1164 int ecnt = 0;
1165 int joined_set = 0, inst;
1166 xmlChar *set;
1167 char *key;
1169 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
1170 "pad_process beneath %s=%d\n", topo_node_name(ptn),
1171 topo_node_instance(ptn));
1172 if (new == NULL) {
1173 for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) {
1174 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
1175 "cn->name is %s \n", (char *)cn->name);
1177 * We're iterating through the XML children looking for
1178 * four types of elements:
1179 * 1) dependents elements
1180 * 2) unconstrained pgroup elements
1181 * 3) pgroup elements constrained by set elements
1182 * 4) enum-method elements for the case that we want
1183 * to post-process a statically defined node
1185 if (xmlStrcmp(cn->name, (xmlChar *)Dependents) == 0)
1186 dcnt++;
1187 else if (xmlStrcmp(cn->name, (xmlChar *)Propgrp) == 0)
1188 pgcnt++;
1189 else if (xmlStrcmp(cn->name, (xmlChar *)Enum_meth)
1190 == 0) {
1191 ecn = cn;
1192 ecnt++;
1193 } else if (xmlStrcmp(cn->name, (xmlChar *)Set) == 0) {
1194 if (joined_set)
1195 continue;
1196 set = xmlGetProp(cn, (xmlChar *)Setlist);
1198 if (mp->tm_hdl->th_product)
1199 key = mp->tm_hdl->th_product;
1200 else
1201 key = mp->tm_hdl->th_platform;
1204 * If it's the default set then we'll store
1205 * a pointer to it so that if none of the other
1206 * sets apply to our product we can fall
1207 * back to this one.
1209 if (strcmp((char *)set, "default") == 0)
1210 def_set = cn;
1211 else if (set_contains(mp, key, (char *)set)) {
1212 psn = cn;
1213 joined_set = 1;
1214 for (gcn = cn->xmlChildrenNode;
1215 gcn != NULL; gcn = gcn->next) {
1216 if (xmlStrcmp(gcn->name,
1217 (xmlChar *)Propgrp) == 0)
1218 pgcnt++;
1221 xmlFree(set);
1225 * If we haven't found a set that contains our product AND
1226 * a default set exists, then we'll process it.
1228 if (!joined_set && def_set) {
1229 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
1230 "Falling back to default set\n");
1231 joined_set = 1;
1232 psn = def_set;
1233 for (gcn = psn->xmlChildrenNode; gcn != NULL;
1234 gcn = gcn->next) {
1235 if (xmlStrcmp(gcn->name, (xmlChar *)Propgrp)
1236 == 0)
1237 pgcnt++;
1240 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
1241 "pad_process: dcnt=%d, pgcnt=%d, ecnt=%d, joined_set=%d\n",
1242 dcnt, pgcnt, ecnt, joined_set);
1244 * If an enum-method element was found, AND we're a child of a
1245 * node element, then we invoke the enumerator so that it can do
1246 * post-processing of the node.
1248 if (ecnt && (strcmp((const char *)pxn->name, Node) == 0)) {
1249 if ((tmp_rd.rd_einfo = enum_attributes_process(mp, ecn))
1250 == NULL)
1251 return (-1);
1252 tmp_rd.rd_mod = mp;
1253 tmp_rd.rd_name = rd->rd_name;
1254 tmp_rd.rd_min = rd->rd_min;
1255 tmp_rd.rd_max = rd->rd_max;
1256 tmp_rd.rd_pn = ptn;
1257 if (enum_run(mp, &tmp_rd) < 0) {
1259 * Note the failure but continue on
1261 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1262 "pad_process: enumeration failed.\n");
1264 tf_edata_free(mp, tmp_rd.rd_einfo);
1267 * Here we allocate an element in an intermediate data structure
1268 * which keeps track property groups and dependents of the range
1269 * currently being processed.
1271 * This structure is referenced in pgroups_record() to create
1272 * the actual property groups in the topo tree
1274 if ((new = tf_pad_new(mp, pgcnt, dcnt)) == NULL)
1275 return (-1);
1277 if (pgcnt > 0) {
1278 new->tpad_pgs =
1279 topo_mod_zalloc(mp, pgcnt * sizeof (nvlist_t *));
1280 if (new->tpad_pgs == NULL) {
1281 tf_pad_free(mp, new);
1282 return (-1);
1286 * If the property groups are contained within a set
1287 * then they will be one level lower in the XML tree.
1289 if (joined_set)
1290 target = psn;
1291 else
1292 target = pxn;
1295 * If there is no "node" element under the "range"
1296 * element, then we need to attach the facility node to
1297 * each node in this range.
1299 * Otherwise we only attach it to the current node
1301 if (xmlStrcmp(target->name, (xmlChar *)Range) == 0 ||
1302 xmlStrcmp(target->name, (xmlChar *)Set) == 0) {
1303 for (ct = topo_child_first(rd->rd_pn);
1304 ct != NULL;
1305 ct = topo_child_next(rd->rd_pn, ct)) {
1307 if (strcmp(topo_node_name(ct),
1308 rd->rd_name) != 0)
1309 continue;
1311 inst = topo_node_instance(ct);
1312 if (inst < rd->rd_min || inst > rd->rd_max)
1313 continue;
1315 if (fac_enum_process(mp, target, ct) < 0)
1316 return (-1);
1318 if (fac_process(mp, target, rd, ct) < 0)
1319 return (-1);
1321 } else {
1322 if (fac_enum_process(mp, target, ptn) < 0)
1323 return (-1);
1324 if (fac_process(mp, target, rd, ptn) < 0)
1325 return (-1);
1327 if (pgcnt > 0 && pgroups_record(mp, target, ptn, rd->rd_name,
1328 new, (const char *)pxn->name) < 0) {
1329 tf_pad_free(mp, new);
1330 return (-1);
1332 *rpad = new;
1335 if (new->tpad_dcnt > 0)
1336 if (dependents_create(mp, rd->rd_finfo, new, pxn, ptn) < 0)
1337 return (-1);
1339 if (new->tpad_pgcnt > 0)
1340 if (pgroups_create(mp, new, ptn) < 0)
1341 return (-1);
1343 return (0);
1347 static int
1348 fac_enum_process(topo_mod_t *mp, xmlNodePtr pn, tnode_t *ptn)
1350 xmlNodePtr cn;
1351 xmlChar *fprov = NULL;
1352 int rv = 0;
1354 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
1355 "fac_enum_process() called for %s=%d\n", topo_node_name(ptn),
1356 topo_node_instance(ptn));
1358 for (cn = pn->xmlChildrenNode; cn != NULL; cn = cn->next) {
1360 if (xmlStrcmp(cn->name, (xmlChar *)"fac-enum") != 0)
1361 continue;
1363 if ((fprov = xmlGetProp(cn, (xmlChar *)Provider)) == NULL)
1364 goto fenumdone;
1366 * Invoke enum entry point in facility provider which will
1367 * cause the facility enumeration node method to be
1368 * registered.
1370 if (fac_enum_run(mp, ptn, (const char *)fprov) != 0) {
1371 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1372 "fac_enum_process: enum entry point failed!\n");
1373 goto fenumdone;
1375 xmlFree(fprov);
1377 return (0);
1378 fenumdone:
1379 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "fac-enum processing failed\n");
1381 if (fprov != NULL)
1382 xmlFree(fprov);
1384 return (rv);
1388 static int
1389 fac_process(topo_mod_t *mp, xmlNodePtr pn, tf_rdata_t *rd, tnode_t *ptn)
1391 xmlNodePtr cn;
1392 xmlChar *fname = NULL, *ftype = NULL, *provider = NULL;
1393 tnode_t *ntn = NULL;
1394 tf_idata_t *newi;
1395 int err;
1396 topo_pgroup_info_t pgi;
1398 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
1399 "fac_process() called for %s=%d\n", topo_node_name(ptn),
1400 topo_node_instance(ptn));
1402 for (cn = pn->xmlChildrenNode; cn != NULL; cn = cn->next) {
1404 if (xmlStrcmp(cn->name, (xmlChar *)Facility) != 0)
1405 continue;
1407 if ((fname = xmlGetProp(cn, (xmlChar *)Name)) == NULL)
1408 goto facdone;
1410 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
1411 "processing facility node '%s'\n", fname);
1413 if ((ftype = xmlGetProp(cn, (xmlChar *)Type)) == NULL)
1414 goto facdone;
1416 if ((provider = xmlGetProp(cn, (xmlChar *)Provider)) == NULL)
1417 goto facdone;
1419 if (xmlStrcmp(ftype, (xmlChar *)Sensor) != 0 &&
1420 xmlStrcmp(ftype, (xmlChar *)Indicator) != 0)
1421 goto facdone;
1423 if ((ntn = topo_node_facbind(mp, ptn, (char *)fname,
1424 (char *)ftype)) == NULL)
1425 goto facdone;
1427 pgi.tpi_name = TOPO_PGROUP_FACILITY;
1428 pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
1429 pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
1430 pgi.tpi_version = 1;
1431 if (topo_pgroup_create(ntn, &pgi, &err) != 0) {
1432 if (err != ETOPO_PROP_DEFD) {
1433 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1434 "pgroups create failure: %s\n",
1435 topo_strerror(err));
1436 return (-1);
1440 * Invoke enum entry point in the facility provider module,
1441 * which will cause the provider methods to be registered on
1442 * this node
1444 if (fac_enum_run(mp, ntn, (const char *)provider) != 0) {
1445 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "fac_process: "
1446 "enum entry point failed for provider %s!\n",
1447 provider);
1448 goto facdone;
1451 if ((newi = tf_idata_new(mp, 0, ntn)) == NULL)
1452 goto facdone;
1454 if (tf_idata_insert(&rd->rd_instances, newi) < 0)
1455 goto facdone;
1457 if (pad_process(mp, rd, cn, ntn, &newi->ti_pad) < 0)
1458 goto facdone;
1460 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "done with "
1461 "facility %s=%s.\n", ftype, fname);
1463 xmlFree(ftype);
1464 xmlFree(fname);
1465 xmlFree(provider);
1468 return (0);
1470 facdone:
1471 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "facility processing failed\n");
1473 if (ftype != NULL)
1474 xmlFree(ftype);
1475 if (fname != NULL)
1476 xmlFree(fname);
1477 if (provider != NULL)
1478 xmlFree(provider);
1479 if (ntn != NULL)
1480 topo_node_unbind(ntn);
1482 return (0);
1485 static int
1486 node_process(topo_mod_t *mp, xmlNodePtr nn, tf_rdata_t *rd)
1488 xmlChar *str;
1489 topo_instance_t inst;
1490 tf_idata_t *newi;
1491 tnode_t *ntn;
1492 uint64_t ui;
1493 int rv = -1;
1494 int s = 0;
1496 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
1497 "node_process %s\n", rd->rd_name);
1499 if (xmlattr_to_int(mp, nn, Instance, &ui) < 0)
1500 goto nodedone;
1501 inst = (topo_instance_t)ui;
1503 if ((str = xmlGetProp(nn, (xmlChar *)Static)) != NULL) {
1504 if (xmlStrcmp(str, (xmlChar *)True) == 0)
1505 s = 1;
1506 xmlFree(str);
1509 if (s == 0) {
1510 if (topo_mod_enumerate(rd->rd_mod, rd->rd_pn,
1511 rd->rd_finfo->tf_scheme, rd->rd_name, inst, inst,
1512 s == 1 ? &s : NULL) < 0)
1513 goto nodedone;
1515 ntn = topo_node_lookup(rd->rd_pn, rd->rd_name, inst);
1517 if (ntn == NULL) {
1520 * If this is a static node declaration, we can
1521 * ignore the lookup failure and continue
1522 * processing. Otherwise, something
1523 * went wrong during enumeration
1525 if (s == 1)
1526 rv = 0;
1527 goto nodedone;
1529 if ((newi = tf_idata_new(mp, inst, ntn)) == NULL) {
1530 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1531 "node_process: tf_idata_new failed.\n");
1532 goto nodedone;
1534 if (tf_idata_insert(&rd->rd_instances, newi) < 0) {
1535 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1536 "node_process: tf_idata_insert failed.\n");
1537 goto nodedone;
1539 if (pad_process(mp, rd, nn, ntn, &newi->ti_pad) < 0)
1540 goto nodedone;
1541 if (fac_process(mp, nn, rd, ntn) < 0)
1542 goto nodedone;
1543 rv = 0;
1544 nodedone:
1545 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "done with node %s.\n",
1546 rd->rd_name);
1547 return (rv);
1550 static tf_edata_t *
1551 enum_attributes_process(topo_mod_t *mp, xmlNodePtr en)
1553 tf_edata_t *einfo;
1554 uint64_t ui;
1556 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "enum_attributes_process\n");
1557 if ((einfo = topo_mod_zalloc(mp, sizeof (tf_edata_t))) == NULL) {
1558 (void) topo_mod_seterrno(mp, ETOPO_NOMEM);
1559 return (NULL);
1561 einfo->te_name = (char *)xmlGetProp(en, (xmlChar *)Name);
1562 if (einfo->te_name == NULL) {
1563 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1564 "Enumerator name attribute missing.\n");
1565 (void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR);
1566 goto enodedone;
1570 * Check for recursive enumeration
1572 if (strcmp(einfo->te_name, mp->tm_name) == 0) {
1573 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1574 "Recursive enumeration detected for %s\n",
1575 einfo->te_name);
1576 (void) topo_mod_seterrno(mp, ETOPO_ENUM_RECURS);
1577 goto enodedone;
1579 if (xmlattr_to_int(mp, en, Version, &ui) < 0)
1580 goto enodedone;
1581 einfo->te_vers = (int)ui;
1583 return (einfo);
1585 enodedone:
1586 if (einfo->te_name != NULL)
1587 xmlFree(einfo->te_name);
1588 topo_mod_free(mp, einfo, sizeof (tf_edata_t));
1589 return (NULL);
1592 static int
1593 enum_run(topo_mod_t *mp, tf_rdata_t *rd)
1595 topo_hdl_t *thp = mp->tm_hdl;
1596 int e = -1;
1598 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "enum_run\n");
1600 * Check if the enumerator module is already loaded.
1601 * Module loading is single-threaded at this point so there's
1602 * no need to worry about the module going away or bumping the
1603 * ref count.
1605 if ((rd->rd_mod = topo_mod_lookup(thp, rd->rd_einfo->te_name,
1606 0)) == NULL) {
1607 if ((rd->rd_mod = topo_mod_load(mp, rd->rd_einfo->te_name,
1608 rd->rd_einfo->te_vers)) == NULL) {
1609 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1610 "enum_run: mod_load of %s failed: %s.\n",
1611 rd->rd_einfo->te_name,
1612 topo_strerror(topo_mod_errno(mp)));
1613 (void) topo_hdl_seterrno(thp, topo_mod_errno(mp));
1614 return (e);
1618 * We're live, so let's enumerate.
1620 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "enumerate request. (%s)\n",
1621 rd->rd_einfo->te_name);
1622 e = topo_mod_enumerate(rd->rd_mod, rd->rd_pn, rd->rd_einfo->te_name,
1623 rd->rd_name, rd->rd_min, rd->rd_max, NULL);
1624 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "back from enumeration. %d\n",
1626 if (e != 0) {
1627 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1628 "Enumeration failed (%s)\n",
1629 topo_strerror(topo_mod_errno(mp)));
1630 (void) topo_hdl_seterrno(thp, EMOD_PARTIAL_ENUM);
1631 return (topo_mod_seterrno(mp, EMOD_PARTIAL_ENUM));
1633 return (e);
1636 static int
1637 fac_enum_run(topo_mod_t *mp, tnode_t *node, const char *name)
1639 topo_hdl_t *thp = mp->tm_hdl;
1640 topo_mod_t *fmod;
1641 int e = -1;
1643 topo_dprintf(thp, TOPO_DBG_XML, "fac_enum_run\n");
1645 * Check if the enumerator module is already loaded.
1646 * Module loading is single-threaded at this point so there's
1647 * no need to worry about the module going away or bumping the
1648 * ref count.
1650 if ((fmod = topo_mod_lookup(thp, name, 0)) == NULL) {
1651 if ((fmod = topo_mod_load(mp, name, TOPO_VERSION)) == NULL) {
1652 topo_dprintf(thp, TOPO_DBG_ERR,
1653 "fac_enum_run: mod_load of %s failed: %s.\n",
1654 name, topo_strerror(topo_mod_errno(mp)));
1655 (void) topo_hdl_seterrno(thp, topo_mod_errno(mp));
1656 return (e);
1660 * We're live, so let's enumerate.
1662 topo_dprintf(thp, TOPO_DBG_XML, "fac enumerate request. (%s)\n", name);
1663 e = topo_mod_enumerate(fmod, node, name, name, 0, 0, NULL);
1664 topo_dprintf(thp, TOPO_DBG_XML, "back from enumeration. %d\n", e);
1665 if (e != 0) {
1666 topo_dprintf(thp, TOPO_DBG_ERR,
1667 "Facility provider enumeration failed (%s)\n",
1668 topo_strerror(topo_mod_errno(mp)));
1669 (void) topo_hdl_seterrno(thp, EMOD_PARTIAL_ENUM);
1670 return (topo_mod_seterrno(mp, EMOD_PARTIAL_ENUM));
1672 return (e);
1676 decorate_nodes(topo_mod_t *mp, tf_rdata_t *rd, xmlNodePtr pxn, tnode_t *ptn,
1677 tf_pad_t **rpad)
1679 tnode_t *ctn;
1681 ctn = topo_child_first(ptn);
1682 while (ctn != NULL) {
1683 /* Only care about instances within the range */
1684 if (strcmp(topo_node_name(ctn), rd->rd_name) != 0) {
1685 ctn = topo_child_next(ptn, ctn);
1686 continue;
1688 if (pad_process(mp, rd, pxn, ctn, rpad) < 0)
1689 return (-1);
1690 if (decorate_nodes(mp, rd, pxn, ctn, rpad) < 0)
1691 return (-1);
1692 ctn = topo_child_next(ptn, ctn);
1694 return (0);
1698 topo_xml_range_process(topo_mod_t *mp, xmlNodePtr rn, tf_rdata_t *rd)
1701 * The range may have several children xmlNodes, that may
1702 * represent the enumeration method, property groups,
1703 * dependents, nodes or services.
1705 xmlNodePtr cn, enum_node = NULL, pmap_node = NULL;
1706 xmlChar *pmap_name;
1707 tnode_t *ct;
1708 int e, ccnt = 0;
1710 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "topo_xml_range_process\n"
1711 "process %s range beneath %s\n", rd->rd_name,
1712 topo_node_name(rd->rd_pn));
1714 e = topo_node_range_create(mp,
1715 rd->rd_pn, rd->rd_name, rd->rd_min, rd->rd_max);
1716 if (e != 0 && topo_mod_errno(mp) != EMOD_NODE_DUP) {
1717 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1718 "Range create failed due to %s.\n",
1719 topo_strerror(topo_mod_errno(mp)));
1720 return (-1);
1724 * Before we process any of the other child xmlNodes, we iterate through
1725 * the children and looking for either enum-method or propmap elements.
1727 for (cn = rn->xmlChildrenNode; cn != NULL; cn = cn->next)
1728 if (xmlStrcmp(cn->name, (xmlChar *)Enum_meth) == 0)
1729 enum_node = cn;
1730 else if (xmlStrcmp(cn->name, (xmlChar *)Propmap) == 0)
1731 pmap_node = cn;
1734 * If we found an enum-method element, process it first
1736 if (enum_node != NULL) {
1737 if ((rd->rd_einfo = enum_attributes_process(mp, enum_node))
1738 == NULL)
1739 return (-1);
1740 if (enum_run(mp, rd) < 0) {
1742 * Note the failure but continue on
1744 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1745 "Enumeration failed.\n");
1750 * Next, check if a propmap element was found and if so, load it in
1751 * and parse it.
1753 if (pmap_node != NULL) {
1754 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "found a propmap "
1755 "element\n");
1756 if ((pmap_name = xmlGetProp(pmap_node, (xmlChar *)Name))
1757 == NULL) {
1758 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1759 "propmap element missing name attribute.\n");
1760 } else {
1761 if (topo_file_load(mp, rd->rd_pn,
1762 (const char *)pmap_name,
1763 rd->rd_finfo->tf_scheme, 1) < 0) {
1765 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1766 "topo_xml_range_process: topo_file_load"
1767 "failed: %s.\n",
1768 topo_strerror(topo_mod_errno(mp)));
1770 xmlFree(pmap_name);
1774 /* Now look for nodes, i.e., hard instances */
1775 for (cn = rn->xmlChildrenNode; cn != NULL; cn = cn->next) {
1776 if (xmlStrcmp(cn->name, (xmlChar *)Node) == 0) {
1777 if (node_process(mp, cn, rd) < 0) {
1778 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR,
1779 "node processing failed: %s.\n",
1780 topo_strerror(topo_mod_errno(mp)));
1781 return (topo_mod_seterrno(mp,
1782 EMOD_PARTIAL_ENUM));
1784 ccnt++;
1789 * Finally, process the property groups and dependents
1791 * If the TF_PROPMAP flag is set for the XML file we're currently
1792 * processing, then this XML file was loaded via propmap. In that case
1793 * we call a special routine to recursively apply the propgroup settings
1794 * to all of nodes in this range
1796 if (rd->rd_finfo->tf_flags & TF_PROPMAP)
1797 (void) decorate_nodes(mp, rd, rn, rd->rd_pn, &rd->rd_pad);
1798 else {
1799 ct = topo_child_first(rd->rd_pn);
1800 while (ct != NULL) {
1801 /* Only care about instances within the range */
1802 if (strcmp(topo_node_name(ct), rd->rd_name) != 0) {
1803 ct = topo_child_next(rd->rd_pn, ct);
1804 continue;
1806 if (pad_process(mp, rd, rn, ct, &rd->rd_pad)
1807 < 0)
1808 return (-1);
1810 if (fac_process(mp, rn, rd, ct) < 0)
1811 return (-1);
1813 ct = topo_child_next(rd->rd_pn, ct);
1814 ccnt++;
1818 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "topo_xml_range_process: end "
1819 "range process %s\n", rd->rd_name);
1821 return (0);
1824 static tf_rdata_t *
1825 topo_xml_walk(topo_mod_t *mp,
1826 tf_info_t *xinfo, xmlNodePtr croot, tnode_t *troot)
1828 xmlNodePtr curr, def_set = NULL;
1829 tf_rdata_t *rr, *pr, *rdp;
1830 xmlChar *set;
1831 char *key;
1832 int joined_set = 0;
1834 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "topo_xml_walk\n");
1835 rr = pr = NULL;
1837 * First iterate through all the XML nodes at this level to look for
1838 * set nodes.
1840 for (curr = croot->xmlChildrenNode; curr != NULL; curr = curr->next) {
1841 if (curr->name == NULL) {
1842 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
1843 "topo_xml_walk: Ignoring nameless xmlnode\n");
1844 continue;
1846 if (xmlStrcmp(curr->name, (xmlChar *)Set) == 0) {
1847 if (joined_set)
1848 continue;
1850 set = xmlGetProp(curr, (xmlChar *)Setlist);
1852 if (mp->tm_hdl->th_product)
1853 key = mp->tm_hdl->th_product;
1854 else
1855 key = mp->tm_hdl->th_platform;
1858 * If it's the default set then we'll store
1859 * a pointer to it so that if none of the other
1860 * sets apply to our product we can fall
1861 * back to this one.
1863 if (strcmp((char *)set, "default") == 0)
1864 def_set = curr;
1865 else if (set_contains(mp, key, (char *)set)) {
1866 joined_set = 1;
1867 if ((rdp = topo_xml_walk(mp, xinfo, curr,
1868 troot)) == NULL) {
1869 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
1870 "topo_xml_walk: failed1\n");
1871 } else {
1872 if (pr == NULL) {
1873 rr = pr = rdp;
1874 } else {
1875 pr->rd_next = rdp;
1876 pr = rdp;
1878 rr->rd_cnt++;
1881 xmlFree(set);
1885 * If we haven't found a set that contains our product AND a default set
1886 * exists, then we'll process it.
1888 if (!joined_set && def_set) {
1889 if ((rdp = topo_xml_walk(mp, xinfo, def_set, troot)) == NULL) {
1890 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
1891 "topo_xml_walk: failed2\n");
1893 if (pr == NULL) {
1894 rr = pr = rdp;
1895 } else {
1896 pr->rd_next = rdp;
1897 pr = rdp;
1899 rr->rd_cnt++;
1902 * Now we're interested in children xmlNodes of croot tagged
1903 * as 'ranges'. These define what topology nodes may exist, and need
1904 * to be verified.
1906 for (curr = croot->xmlChildrenNode; curr != NULL; curr = curr->next) {
1907 if (curr->name == NULL) {
1908 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML,
1909 "topo_xml_walk: Ignoring nameless xmlnode\n");
1910 continue;
1912 if (xmlStrcmp(curr->name, (xmlChar *)Range) != 0)
1913 continue;
1914 if ((rdp = tf_rdata_new(mp, xinfo, curr, troot)) == NULL) {
1916 * Range processing error, continue walk
1918 continue;
1920 if (pr == NULL) {
1921 rr = pr = rdp;
1922 } else {
1923 pr->rd_next = rdp;
1924 pr = rdp;
1926 rr->rd_cnt++;
1929 return (rr);
1933 * Convert parsed xml topology description into topology nodes
1936 topo_xml_enum(topo_mod_t *tmp, tf_info_t *xinfo, tnode_t *troot)
1938 xmlNodePtr xroot;
1940 topo_dprintf(tmp->tm_hdl, TOPO_DBG_XML, "topo_xml_enum\n");
1942 if ((xroot = xmlDocGetRootElement(xinfo->tf_xdoc)) == NULL) {
1943 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
1944 "Couldn't get root xmlNode.\n");
1945 return (-1);
1947 if ((xinfo->tf_rd = topo_xml_walk(tmp, xinfo, xroot, troot)) == NULL) {
1948 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
1949 "error within .xml topology: %s\n",
1950 topo_strerror(topo_mod_errno(tmp)));
1951 return (-1);
1953 return (0);
1957 * Load an XML tree from filename and read it into a DOM parse tree.
1959 static tf_info_t *
1960 txml_file_parse(topo_mod_t *tmp,
1961 int fd, const char *filenm, const char *escheme)
1963 xmlValidCtxtPtr vcp;
1964 xmlNodePtr cursor;
1965 xmlDocPtr document;
1966 xmlDtdPtr dtd = NULL;
1967 xmlChar *scheme = NULL;
1968 char *dtdpath = NULL;
1969 int readflags = 0;
1970 tf_info_t *r;
1971 int e, validate = 0;
1973 topo_dprintf(tmp->tm_hdl, TOPO_DBG_XML,
1974 "txml_file_parse(filenm=%s, escheme=%s)\n", filenm, escheme);
1977 * Since topologies can XInclude other topologies, and libxml2
1978 * doesn't do DTD-based validation with XInclude, by default
1979 * we don't validate topology files. One can force
1980 * validation, though, by creating a TOPOXML_VALIDATE
1981 * environment variable and creating a TOPO_DTD environment
1982 * variable with the path to the DTD against which to validate.
1984 if (getenv("TOPOXML_VALIDATE") != NULL) {
1985 dtdpath = getenv("TOPO_DTD");
1986 if (dtdpath != NULL)
1987 xmlLoadExtDtdDefaultValue = 0;
1988 validate = 1;
1992 * Splat warnings and errors related to parsing the topology
1993 * file if the TOPOXML_PERROR environment variable exists.
1995 if (getenv("TOPOXML_PERROR") == NULL)
1996 readflags = XML_PARSE_NOERROR | XML_PARSE_NOWARNING;
1998 if ((document = xmlReadFd(fd, filenm, NULL, readflags)) == NULL) {
1999 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2000 "txml_file_parse: couldn't parse document.\n");
2001 return (NULL);
2005 * Verify that this is a document type we understand.
2007 if ((dtd = xmlGetIntSubset(document)) == NULL) {
2008 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2009 "document has no DTD.\n");
2010 xmlFreeDoc(document);
2011 return (NULL);
2014 if (strcmp((const char *)dtd->SystemID, TOPO_DTD_PATH) != 0) {
2015 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2016 "document DTD unknown; bad topology file\n");
2017 xmlFreeDoc(document);
2018 return (NULL);
2021 if ((cursor = xmlDocGetRootElement(document)) == NULL) {
2022 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, "document is empty.\n");
2023 xmlFreeDoc(document);
2024 return (NULL);
2028 * Make sure we're looking at a topology description in the
2029 * expected scheme.
2031 if (xmlStrcmp(cursor->name, (xmlChar *)Topology) != 0) {
2032 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2033 "document is not a topology description.\n");
2034 xmlFreeDoc(document);
2035 return (NULL);
2037 if ((scheme = xmlGetProp(cursor, (xmlChar *)Scheme)) == NULL) {
2038 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2039 "topology lacks a scheme.\n");
2040 (void) topo_mod_seterrno(tmp, ETOPO_PRSR_NOATTR);
2041 xmlFreeDoc(document);
2042 return (NULL);
2044 if (xmlStrcmp(scheme, (xmlChar *)escheme) != 0) {
2045 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2046 "topology in unrecognized scheme, %s, expecting %s\n",
2047 scheme, escheme);
2048 (void) topo_mod_seterrno(tmp, ETOPO_PRSR_BADSCH);
2049 xmlFree(scheme);
2050 xmlFreeDoc(document);
2051 return (NULL);
2054 if (dtdpath != NULL) {
2055 dtd = xmlParseDTD(NULL, (xmlChar *)dtdpath);
2056 if (dtd == NULL) {
2057 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2058 "Could not parse DTD \"%s\".\n",
2059 dtdpath);
2060 xmlFree(scheme);
2061 xmlFreeDoc(document);
2062 return (NULL);
2065 if (document->extSubset != NULL)
2066 xmlFreeDtd(document->extSubset);
2068 document->extSubset = dtd;
2071 if (xmlXIncludeProcessFlags(document, XML_PARSE_XINCLUDE) == -1) {
2072 xmlFree(scheme);
2073 xmlFreeDoc(document);
2074 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2075 "couldn't handle XInclude statements in document\n");
2076 return (NULL);
2079 if (validate) {
2080 if ((vcp = xmlNewValidCtxt()) == NULL) {
2081 xmlFree(scheme);
2082 xmlFreeDoc(document);
2083 return (NULL);
2085 vcp->warning = xmlParserValidityWarning;
2086 vcp->error = xmlParserValidityError;
2088 e = xmlValidateDocument(vcp, document);
2090 xmlFreeValidCtxt(vcp);
2092 if (e == 0)
2093 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2094 "Document is not valid.\n");
2097 if ((r = tf_info_new(tmp, document, scheme)) == NULL) {
2098 xmlFree(scheme);
2099 xmlFreeDoc(document);
2100 return (NULL);
2103 xmlFree(scheme);
2104 scheme = NULL;
2105 return (r);
2108 tf_info_t *
2109 topo_xml_read(topo_mod_t *tmp, const char *path, const char *escheme)
2111 int fd;
2112 tf_info_t *tip;
2114 if ((fd = open(path, O_RDONLY)) < 0) {
2115 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR,
2116 "failed to open %s for reading\n", path);
2117 return (NULL);
2119 tip = txml_file_parse(tmp, fd, path, escheme);
2120 (void) close(fd);
2121 return (tip);