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) 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>
36 #include <fm/libtopo.h>
40 #include <topo_file.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
,
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
*,
59 strarr_free(topo_mod_t
*mod
, char **arr
, uint_t nelems
)
63 for (i
= 0; i
< nelems
; i
++)
64 topo_mod_strfree(mod
, arr
[i
]);
65 topo_mod_free(mod
, arr
, (nelems
* sizeof (char *)));
69 xmlattr_to_stab(topo_mod_t
*mp
, xmlNodePtr n
, const char *stabname
,
76 /* If there is no Stability defined, we default to private */
77 *rs
= TOPO_STABILITY_PRIVATE
;
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
;
104 return (topo_mod_seterrno(mp
, ETOPO_PRSR_BADSTAB
));
111 xmlattr_to_int(topo_mod_t
*mp
,
112 xmlNodePtr n
, const char *propname
, uint64_t *value
)
117 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "xmlattr_to_int(propname=%s)\n",
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);
123 /* no conversion was done */
125 return (topo_mod_seterrno(mp
, ETOPO_PRSR_BADNUM
));
132 xmlattr_to_fmri(topo_mod_t
*mp
,
133 xmlNodePtr xn
, const char *propname
, nvlist_t
**rnvl
)
137 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "xmlattr_to_fmri(propname=%s)\n",
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) {
150 xmlattr_to_type(topo_mod_t
*mp
, xmlNodePtr xn
, xmlChar
*attr
)
154 if ((str
= xmlGetProp(xn
, (xmlChar
*)attr
)) == NULL
) {
155 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
, "%s attribute missing",
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) {
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
;
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
);
189 return (TOPO_TYPE_INVALID
);
196 xlate_common(topo_mod_t
*mp
, xmlNodePtr xn
, topo_type_t ptype
, nvlist_t
*nvl
,
201 uint_t i
= 0, nelems
= 0;
206 nvlist_t
**nvlarrbuf
;
209 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "xlate_common(name=%s)\n", name
);
211 case TOPO_TYPE_INT32
:
212 if (xmlattr_to_int(mp
, xn
, Value
, &ui
) < 0)
214 rv
= nvlist_add_int32(nvl
, name
, (int32_t)ui
);
216 case TOPO_TYPE_UINT32
:
217 if (xmlattr_to_int(mp
, xn
, Value
, &ui
) < 0)
219 rv
= nvlist_add_uint32(nvl
, name
, (uint32_t)ui
);
221 case TOPO_TYPE_INT64
:
222 if (xmlattr_to_int(mp
, xn
, Value
, &ui
) < 0)
224 rv
= nvlist_add_int64(nvl
, name
, (int64_t)ui
);
226 case TOPO_TYPE_UINT64
:
227 if (xmlattr_to_int(mp
, xn
, Value
, &ui
) < 0)
229 rv
= nvlist_add_uint64(nvl
, name
, ui
);
232 if (xmlattr_to_fmri(mp
, xn
, Value
, &fmri
) < 0)
234 rv
= nvlist_add_nvlist(nvl
, name
, fmri
);
237 case TOPO_TYPE_STRING
:
238 if ((str
= xmlGetProp(xn
, (xmlChar
*)Value
)) == NULL
)
240 rv
= nvlist_add_string(nvl
, name
, (char *)str
);
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 for (cn
= xn
->xmlChildrenNode
; cn
!= NULL
; cn
= cn
->next
)
248 if ((xmlStrcmp(cn
->name
, (xmlChar
*)Propitem
) == 0) ||
249 (xmlStrcmp(cn
->name
, (xmlChar
*)Argitem
) == 0))
253 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
, "No <propitem> "
254 "or <argitem> elements found for array val");
257 if ((arrbuf
= topo_mod_alloc(mp
, (nelems
* sizeof (uint64_t))))
259 return (topo_mod_seterrno(mp
, ETOPO_NOMEM
));
261 case TOPO_TYPE_STRING_ARRAY
:
262 for (cn
= xn
->xmlChildrenNode
; cn
!= NULL
; cn
= cn
->next
)
263 if ((xmlStrcmp(cn
->name
, (xmlChar
*)Propitem
) == 0) ||
264 (xmlStrcmp(cn
->name
, (xmlChar
*)Argitem
) == 0))
268 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
, "No <propitem> "
269 "or <argitem> elements found for array val");
272 if ((strarrbuf
= topo_mod_alloc(mp
, (nelems
* sizeof (char *))))
274 return (topo_mod_seterrno(mp
, ETOPO_NOMEM
));
276 case TOPO_TYPE_FMRI_ARRAY
:
277 for (cn
= xn
->xmlChildrenNode
; cn
!= NULL
; cn
= cn
->next
)
278 if ((xmlStrcmp(cn
->name
, (xmlChar
*)Propitem
) == 0) ||
279 (xmlStrcmp(cn
->name
, (xmlChar
*)Argitem
) == 0))
283 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
, "No <propitem> "
284 "elements found for array prop");
287 if ((nvlarrbuf
= topo_mod_alloc(mp
, (nelems
*
288 sizeof (nvlist_t
*)))) == NULL
)
289 return (topo_mod_seterrno(mp
, ETOPO_NOMEM
));
292 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
293 "Unrecognized type attribute (ptype = %d)\n", ptype
);
294 return (topo_mod_seterrno(mp
, ETOPO_PRSR_BADTYPE
));
298 case TOPO_TYPE_INT32_ARRAY
:
299 for (cn
= xn
->xmlChildrenNode
; cn
!= NULL
; cn
= cn
->next
) {
300 if ((xmlStrcmp(cn
->name
, (xmlChar
*)Propitem
) == 0) ||
301 (xmlStrcmp(cn
->name
, (xmlChar
*)Argitem
) == 0)) {
303 if ((str
= xmlGetProp(xn
, (xmlChar
*)Value
))
307 ((int32_t *)arrbuf
)[i
++]
308 = atoi((const char *)str
);
313 rv
= nvlist_add_int32_array(nvl
, name
, (int32_t *)arrbuf
,
317 case TOPO_TYPE_UINT32_ARRAY
:
318 for (cn
= xn
->xmlChildrenNode
; cn
!= NULL
; cn
= cn
->next
) {
319 if ((xmlStrcmp(cn
->name
, (xmlChar
*)Propitem
) == 0) ||
320 (xmlStrcmp(cn
->name
, (xmlChar
*)Argitem
) == 0)) {
322 if ((str
= xmlGetProp(xn
, (xmlChar
*)Value
))
326 ((uint32_t *)arrbuf
)[i
++]
327 = atoi((const char *)str
);
332 rv
= nvlist_add_uint32_array(nvl
, name
, (uint32_t *)arrbuf
,
336 case TOPO_TYPE_INT64_ARRAY
:
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(xn
, (xmlChar
*)Value
))
345 ((int64_t *)arrbuf
)[i
++]
346 = atol((const char *)str
);
351 rv
= nvlist_add_int64_array(nvl
, name
, (int64_t *)arrbuf
,
355 case TOPO_TYPE_UINT64_ARRAY
:
356 for (cn
= xn
->xmlChildrenNode
; cn
!= NULL
; cn
= cn
->next
) {
357 if ((xmlStrcmp(cn
->name
, (xmlChar
*)Propitem
) == 0) ||
358 (xmlStrcmp(cn
->name
, (xmlChar
*)Argitem
) == 0)) {
360 if ((str
= xmlGetProp(xn
, (xmlChar
*)Value
))
364 ((uint64_t *)arrbuf
)[i
++]
365 = atol((const char *)str
);
370 rv
= nvlist_add_uint64_array(nvl
, name
, arrbuf
,
374 case TOPO_TYPE_STRING_ARRAY
:
375 for (cn
= xn
->xmlChildrenNode
; cn
!= NULL
; cn
= cn
->next
) {
376 if ((xmlStrcmp(cn
->name
, (xmlChar
*)Propitem
) == 0) ||
377 (xmlStrcmp(cn
->name
, (xmlChar
*)Argitem
) == 0)) {
379 if ((str
= xmlGetProp(cn
, (xmlChar
*)Value
))
384 topo_mod_strdup(mp
, (const char *)str
);
389 rv
= nvlist_add_string_array(nvl
, name
, strarrbuf
, nelems
);
390 strarr_free(mp
, strarrbuf
, nelems
);
392 case TOPO_TYPE_FMRI_ARRAY
:
393 for (cn
= xn
->xmlChildrenNode
; cn
!= NULL
; cn
= cn
->next
) {
394 if ((xmlStrcmp(cn
->name
, (xmlChar
*)Propitem
) == 0) ||
395 (xmlStrcmp(cn
->name
, (xmlChar
*)Argitem
) == 0)) {
397 if ((str
= xmlGetProp(xn
, (xmlChar
*)Value
))
401 if (topo_mod_str2nvl(mp
, (const char *)str
,
402 &(nvlarrbuf
[i
++])) < 0) {
410 rv
= nvlist_add_nvlist_array(nvl
, name
, nvlarrbuf
,
417 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
418 "Nvlist construction failed.\n");
419 return (topo_mod_seterrno(mp
, ETOPO_NOMEM
));
425 xmlprop_xlate(topo_mod_t
*mp
, xmlNodePtr xn
, nvlist_t
*nvl
)
430 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "xmlprop_xlate\n");
431 if ((str
= xmlGetProp(xn
, (xmlChar
*)Immutable
)) != NULL
) {
432 if (xmlStrcmp(str
, (xmlChar
*)False
) == 0)
433 (void) nvlist_add_boolean_value(nvl
, INV_IMMUTE
,
436 (void) nvlist_add_boolean_value(nvl
, INV_IMMUTE
,
440 (void) nvlist_add_boolean_value(nvl
, INV_IMMUTE
, B_TRUE
);
443 if ((ptype
= xmlattr_to_type(mp
, xn
, (xmlChar
*)Type
))
444 == TOPO_TYPE_INVALID
)
447 if (nvlist_add_int32(nvl
, INV_PVALTYPE
, ptype
) != 0)
450 return (xlate_common(mp
, xn
, ptype
, nvl
, INV_PVAL
));
454 dependent_create(topo_mod_t
*mp
,
455 tf_info_t
*xinfo
, tf_pad_t
*pad
, xmlNodePtr dxn
, tnode_t
*ptn
)
457 tf_rdata_t
*rp
, *pp
, *np
;
461 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "dependent_create\n");
462 if ((grptype
= xmlGetProp(dxn
, (xmlChar
*)Grouping
)) == NULL
) {
463 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
464 "Dependents missing grouping attribute");
465 return (topo_mod_seterrno(mp
, ETOPO_PRSR_NOATTR
));
469 if (xmlStrcmp(grptype
, (xmlChar
*)Siblings
) == 0) {
472 } else if (xmlStrcmp(grptype
, (xmlChar
*)Children
) == 0) {
473 rp
= pad
->tpad_child
;
475 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
476 "Dependents have bogus grouping attribute");
478 return (topo_mod_seterrno(mp
, ETOPO_PRSR_BADGRP
));
481 /* Add processed dependents to the tail of the list */
486 if ((np
= topo_xml_walk(mp
, xinfo
, dxn
, ptn
)) == NULL
) {
487 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
488 "error within dependent .xml topology: "
489 "%s\n", topo_strerror(topo_mod_errno(mp
)));
497 pad
->tpad_child
= np
;
502 dependents_create(topo_mod_t
*mp
,
503 tf_info_t
*xinfo
, tf_pad_t
*pad
, xmlNodePtr pxn
, tnode_t
*ptn
)
507 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "dependents_create\n");
508 for (cn
= pxn
->xmlChildrenNode
; cn
!= NULL
; cn
= cn
->next
) {
509 if (xmlStrcmp(cn
->name
, (xmlChar
*)Dependents
) == 0) {
510 if (dependent_create(mp
, xinfo
, pad
, cn
, ptn
) < 0)
518 prop_create(topo_mod_t
*mp
,
519 nvlist_t
*pfmri
, tnode_t
*ptn
, const char *gnm
, const char *pnm
,
520 topo_type_t ptype
, int flag
)
522 nvlist_t
*fmri
, **fmriarr
;
523 uint32_t ui32
, *ui32arr
;
524 uint64_t ui64
, *ui64arr
;
525 int32_t i32
, *i32arr
;
526 int64_t i64
, *i64arr
;
531 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "prop_create(pgrp = %s, "
532 "prop = %s)\n", gnm
, pnm
);
534 case TOPO_TYPE_INT32
:
535 e
= nvlist_lookup_int32(pfmri
, INV_PVAL
, &i32
);
537 case TOPO_TYPE_UINT32
:
538 e
= nvlist_lookup_uint32(pfmri
, INV_PVAL
, &ui32
);
540 case TOPO_TYPE_INT64
:
541 e
= nvlist_lookup_int64(pfmri
, INV_PVAL
, &i64
);
543 case TOPO_TYPE_UINT64
:
544 e
= nvlist_lookup_uint64(pfmri
, INV_PVAL
, &ui64
);
547 e
= nvlist_lookup_nvlist(pfmri
, INV_PVAL
, &fmri
);
549 case TOPO_TYPE_STRING
:
550 e
= nvlist_lookup_string(pfmri
, INV_PVAL
, &str
);
552 case TOPO_TYPE_INT32_ARRAY
:
553 e
= nvlist_lookup_int32_array(pfmri
, INV_PVAL
, &i32arr
, &nelem
);
555 case TOPO_TYPE_UINT32_ARRAY
:
556 e
= nvlist_lookup_uint32_array(pfmri
, INV_PVAL
, &ui32arr
,
559 case TOPO_TYPE_INT64_ARRAY
:
560 e
= nvlist_lookup_int64_array(pfmri
, INV_PVAL
, &i64arr
,
563 case TOPO_TYPE_UINT64_ARRAY
:
564 e
= nvlist_lookup_uint64_array(pfmri
, INV_PVAL
, &ui64arr
,
567 case TOPO_TYPE_STRING_ARRAY
:
568 e
= nvlist_lookup_string_array(pfmri
, INV_PVAL
, &strarr
,
571 case TOPO_TYPE_FMRI_ARRAY
:
572 e
= nvlist_lookup_nvlist_array(pfmri
, INV_PVAL
, &fmriarr
,
576 e
= ETOPO_PRSR_BADTYPE
;
579 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
580 "prop_create: prop value lookup failed.\n");
581 return (topo_mod_seterrno(mp
, e
));
584 case TOPO_TYPE_INT32
:
585 e
= topo_prop_set_int32(ptn
, gnm
, pnm
, flag
, i32
, &err
);
587 case TOPO_TYPE_UINT32
:
588 e
= topo_prop_set_uint32(ptn
, gnm
, pnm
, flag
, ui32
, &err
);
590 case TOPO_TYPE_INT64
:
591 e
= topo_prop_set_int64(ptn
, gnm
, pnm
, flag
, i64
, &err
);
593 case TOPO_TYPE_UINT64
:
594 e
= topo_prop_set_uint64(ptn
, gnm
, pnm
, flag
, ui64
, &err
);
597 e
= topo_prop_set_fmri(ptn
, gnm
, pnm
, flag
, fmri
, &err
);
599 case TOPO_TYPE_STRING
:
600 e
= topo_prop_set_string(ptn
, gnm
, pnm
, flag
, str
, &err
);
602 case TOPO_TYPE_INT32_ARRAY
:
603 e
= topo_prop_set_int32_array(ptn
, gnm
, pnm
, flag
, i32arr
,
606 case TOPO_TYPE_UINT32_ARRAY
:
607 e
= topo_prop_set_uint32_array(ptn
, gnm
, pnm
, flag
, ui32arr
,
610 case TOPO_TYPE_INT64_ARRAY
:
611 e
= topo_prop_set_int64_array(ptn
, gnm
, pnm
, flag
, i64arr
,
614 case TOPO_TYPE_UINT64_ARRAY
:
615 e
= topo_prop_set_uint64_array(ptn
, gnm
, pnm
, flag
, ui64arr
,
618 case TOPO_TYPE_STRING_ARRAY
:
619 e
= topo_prop_set_string_array(ptn
, gnm
, pnm
, flag
,
620 (const char **)strarr
, nelem
, &err
);
622 case TOPO_TYPE_FMRI_ARRAY
:
623 e
= topo_prop_set_fmri_array(ptn
, gnm
, pnm
, flag
,
624 (const nvlist_t
**)fmriarr
, nelem
, &err
);
627 if (e
!= 0 && err
!= ETOPO_PROP_DEFD
) {
630 * Some properties may have already been set
631 * in topo_node_bind() or topo_prop_inherit if we are
632 * enumerating from a static .xml file
634 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
, "prop set "
635 "failed %s/%s:%s\n", gnm
, pnm
, topo_strerror(err
));
636 return (topo_mod_seterrno(mp
, err
));
642 props_create(topo_mod_t
*mp
,
643 tnode_t
*ptn
, const char *gnm
, nvlist_t
**props
, int nprops
)
653 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "props_create(pgrp = %s)\n",
655 for (pn
= 0; pn
< nprops
; pn
++) {
656 e
= nvlist_lookup_string(props
[pn
], INV_PNAME
, &pnm
);
658 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
659 "props create lookup (%s) failure: %s",
660 INV_PNAME
, strerror(e
));
661 return (topo_mod_seterrno(mp
, ETOPO_PRSR_NVPROP
));
663 e
= nvlist_lookup_boolean_value(props
[pn
], INV_IMMUTE
, &pim
);
665 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
666 "props create lookup (%s) failure: %s",
667 INV_IMMUTE
, strerror(e
));
668 return (topo_mod_seterrno(mp
, ETOPO_PRSR_NVPROP
));
670 flag
= (pim
== B_TRUE
) ?
671 TOPO_PROP_IMMUTABLE
: TOPO_PROP_MUTABLE
;
673 e
= nvlist_lookup_int32(props
[pn
], INV_PVALTYPE
, &i32
);
675 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
676 "props create lookup (%s) failure: %s",
677 INV_PVALTYPE
, strerror(e
));
678 return (topo_mod_seterrno(mp
, ETOPO_PRSR_NVPROP
));
680 ptype
= (topo_type_t
)i32
;
681 if (prop_create(mp
, props
[pn
], ptn
, gnm
, pnm
, ptype
, flag
) < 0)
688 pgroups_create(topo_mod_t
*mp
, tf_pad_t
*pad
, tnode_t
*ptn
)
690 topo_pgroup_info_t pgi
;
693 char *nmstab
, *dstab
;
694 uint32_t rnprops
, nprops
;
699 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "pgroups_create: %s=%d\n",
700 topo_node_name(ptn
), topo_node_instance(ptn
));
701 for (pg
= 0; pg
< pad
->tpad_pgcnt
; pg
++) {
702 e
= nvlist_lookup_string(pad
->tpad_pgs
[pg
],
703 INV_PGRP_NAME
, &gnm
);
705 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
706 "pad lookup (%s) failed (%s).\n",
707 INV_PGRP_NAME
, strerror(errno
));
708 return (topo_mod_seterrno(mp
, ETOPO_PRSR_NVPROP
));
710 e
= nvlist_lookup_string(pad
->tpad_pgs
[pg
],
711 INV_PGRP_NMSTAB
, &nmstab
);
714 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
716 "failed.\n", INV_PGRP_NMSTAB
);
717 return (topo_mod_seterrno(mp
,
720 nmstab
= TOPO_STABSTR_PRIVATE
;
723 e
= nvlist_lookup_string(pad
->tpad_pgs
[pg
],
724 INV_PGRP_DSTAB
, &dstab
);
727 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
728 "pad lookup (%s) failed.\n",
730 return (topo_mod_seterrno(mp
,
733 dstab
= TOPO_STABSTR_PRIVATE
;
736 e
= nvlist_lookup_uint32(pad
->tpad_pgs
[pg
],
739 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
740 "pad lookup (%s) failed.\n",
742 return (topo_mod_seterrno(mp
, ETOPO_PRSR_NVPROP
));
745 pgi
.tpi_namestab
= topo_name2stability(nmstab
);
746 pgi
.tpi_datastab
= topo_name2stability(dstab
);
747 pgi
.tpi_version
= gv
;
748 if (topo_pgroup_create(ptn
, &pgi
, &e
) != 0) {
749 if (e
!= ETOPO_PROP_DEFD
) {
750 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
751 "pgroups create failure: %s\n",
756 e
= nvlist_lookup_uint32(pad
->tpad_pgs
[pg
],
757 INV_PGRP_NPROP
, &rnprops
);
759 * The number of properties could be zero if the property
760 * group only contains propmethod declarations
763 e
|= nvlist_lookup_nvlist_array(pad
->tpad_pgs
[pg
],
764 INV_PGRP_ALLPROPS
, &props
, &nprops
);
765 if (rnprops
!= nprops
) {
766 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
767 "recorded number of props %d does not "
768 "match number of props recorded %d.\n",
771 if (props_create(mp
, ptn
, gnm
, props
, nprops
) < 0)
779 pval_record(topo_mod_t
*mp
, xmlNodePtr xn
)
781 nvlist_t
*pnvl
= NULL
;
784 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "pval_record\n");
785 if ((pname
= xmlGetProp(xn
, (xmlChar
*)Name
)) == NULL
) {
786 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
,
787 "propval lacks a name\n");
788 (void) topo_mod_seterrno(mp
, ETOPO_PRSR_NOATTR
);
791 if (topo_mod_nvalloc(mp
, &pnvl
, NV_UNIQUE_NAME
) < 0) {
795 if (nvlist_add_string(pnvl
, INV_PNAME
, (char *)pname
) < 0) {
801 /* FMXXX stability of the property name */
803 if (xmlprop_xlate(mp
, xn
, pnvl
) < 0) {
811 struct propmeth_data
{
813 const char *prop_name
;
814 topo_type_t prop_type
;
815 const char *meth_name
;
816 topo_version_t meth_ver
;
821 register_method(topo_mod_t
*mp
, tnode_t
*ptn
, struct propmeth_data
*meth
)
825 if (topo_prop_method_version_register(ptn
, meth
->pg_name
,
826 meth
->prop_name
, meth
->prop_type
, meth
->meth_name
, meth
->meth_ver
,
827 meth
->arg_nvl
, &err
) != 0) {
829 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
, "failed to register "
830 "propmethod %s for property \"%s\" in propgrp %s on node "
832 meth
->meth_name
, meth
->prop_name
, meth
->pg_name
,
833 topo_node_name(ptn
), topo_node_instance(ptn
),
837 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
,
838 "registered method %s on %s=%d\n",
839 meth
->meth_name
, topo_node_name(ptn
), topo_node_instance(ptn
));
845 pmeth_record(topo_mod_t
*mp
, const char *pg_name
, xmlNodePtr xn
, tnode_t
*tn
,
846 const char *rname
, const char *ppgrp_name
)
848 nvlist_t
*arg_nvl
= NULL
;
850 xmlChar
*meth_name
= NULL
, *prop_name
= NULL
;
851 xmlChar
*arg_name
= NULL
;
852 uint64_t meth_ver
, is_mutable
= 0, is_nonvolatile
= 0;
853 topo_type_t prop_type
;
854 struct propmeth_data meth
;
859 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "pmeth_record: %s=%d "
860 "(pgrp=%s)\n", topo_node_name(tn
), topo_node_instance(tn
), pg_name
);
863 * Get propmethod attribute values
865 if ((meth_name
= xmlGetProp(xn
, (xmlChar
*)Name
)) == NULL
) {
866 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
867 "propmethod element lacks a name attribute\n");
868 return (topo_mod_seterrno(mp
, ETOPO_PRSR_NOATTR
));
870 if (xmlattr_to_int(mp
, xn
, Version
, &meth_ver
) < 0) {
871 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
872 "propmethod element lacks version attribute\n");
873 ret
= topo_mod_seterrno(mp
, ETOPO_PRSR_NOATTR
);
877 * The "mutable" and "nonvoltile" attributes are optional. If not
878 * specified we default to false (0)
880 (void) xmlattr_to_int(mp
, xn
, Mutable
, &is_mutable
);
881 (void) xmlattr_to_int(mp
, xn
, Nonvolatile
, &is_nonvolatile
);
883 if ((prop_name
= xmlGetProp(xn
, (xmlChar
*)Propname
)) == NULL
) {
884 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
885 "propmethod element lacks propname attribute\n");
886 ret
= topo_mod_seterrno(mp
, ETOPO_PRSR_NOATTR
);
889 if ((prop_type
= xmlattr_to_type(mp
, xn
, (xmlChar
*)Proptype
))
890 == TOPO_TYPE_INVALID
) {
891 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
892 "error decoding proptype attribute\n");
893 ret
= topo_mod_seterrno(mp
, ETOPO_PRSR_NOATTR
);
898 * Allocate method argument nvlist
900 if (topo_mod_nvalloc(mp
, &arg_nvl
, NV_UNIQUE_NAME
) < 0) {
901 ret
= topo_mod_seterrno(mp
, ETOPO_NOMEM
);
906 * Iterate through the argval nodes and build the argval nvlist
908 for (cn
= xn
->xmlChildrenNode
; cn
!= NULL
; cn
= cn
->next
) {
909 if (xmlStrcmp(cn
->name
, (xmlChar
*)Argval
) == 0) {
910 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
,
911 "found argval element\n");
912 if ((arg_name
= xmlGetProp(cn
, (xmlChar
*)Name
))
914 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
,
915 "argval element lacks a name attribute\n");
916 ret
= topo_mod_seterrno(mp
, ETOPO_PRSR_NOATTR
);
919 if ((ptype
= xmlattr_to_type(mp
, cn
, (xmlChar
*)Type
))
920 == TOPO_TYPE_INVALID
) {
921 ret
= topo_mod_seterrno(mp
, ETOPO_PRSR_BADTYPE
);
925 if (xlate_common(mp
, cn
, ptype
, arg_nvl
,
926 (const char *)arg_name
) != 0) {
927 ret
= topo_mod_seterrno(mp
, ETOPO_PRSR_BADTYPE
);
942 * Register the prop method for all of the nodes in our range
944 meth
.pg_name
= (const char *)pg_name
;
945 meth
.prop_name
= (const char *)prop_name
;
946 meth
.prop_type
= prop_type
;
947 meth
.meth_name
= (const char *)meth_name
;
948 meth
.meth_ver
= meth_ver
;
949 meth
.arg_nvl
= arg_nvl
;
952 * If the propgroup element is under a range element, we'll apply
953 * the method to all of the topo nodes at this level with the same
956 * Otherwise, if the propgroup element is under a node element
957 * then we'll simply register the method for this node.
959 if (strcmp(ppgrp_name
, Range
) == 0) {
960 for (tmp
= tn
; tmp
!= NULL
; tmp
= topo_child_next(NULL
, tmp
)) {
961 if (strcmp(rname
, topo_node_name(tmp
)) == 0) {
962 if (register_method(mp
, tmp
, &meth
) != 0) {
963 ret
= topo_mod_seterrno(mp
,
968 if (topo_prop_setmutable(tmp
,
969 meth
.pg_name
, meth
.prop_name
, &err
)
971 ret
= topo_mod_seterrno(mp
,
976 if (is_nonvolatile
) {
977 if (topo_prop_setnonvolatile(tmp
,
978 meth
.pg_name
, meth
.prop_name
, &err
)
980 ret
= topo_mod_seterrno(mp
,
988 if (register_method(mp
, tn
, &meth
) != 0) {
989 ret
= topo_mod_seterrno(mp
, ETOPO_PRSR_REGMETH
);
993 if (topo_prop_setmutable(tn
, meth
.pg_name
,
994 meth
.prop_name
, &err
) != 0) {
995 ret
= topo_mod_seterrno(mp
,
1000 if (is_nonvolatile
) {
1001 if (topo_prop_setnonvolatile(tn
, meth
.pg_name
,
1002 meth
.prop_name
, &err
) != 0) {
1003 ret
= topo_mod_seterrno(mp
,
1004 ETOPO_PRSR_REGMETH
);
1016 nvlist_free(arg_nvl
);
1022 pgroup_record(topo_mod_t
*mp
, xmlNodePtr pxn
, tnode_t
*tn
, const char *rname
,
1023 tf_pad_t
*rpad
, int pi
, const char *ppgrp_name
)
1025 topo_stability_t nmstab
, dstab
;
1029 nvlist_t
**apl
= NULL
;
1030 nvlist_t
*pgnvl
= NULL
;
1035 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "pgroup_record\n");
1036 if ((name
= xmlGetProp(pxn
, (xmlChar
*)Name
)) == NULL
) {
1037 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1038 "propgroup lacks a name\n");
1039 return (topo_mod_seterrno(mp
, ETOPO_PRSR_NOATTR
));
1041 if (xmlattr_to_int(mp
, pxn
, Version
, &ver
) < 0) {
1042 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1043 "propgroup lacks a version\n");
1044 return (topo_mod_seterrno(mp
, ETOPO_PRSR_NOATTR
));
1046 if (xmlattr_to_stab(mp
, pxn
, Namestab
, &nmstab
) < 0) {
1047 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1048 "propgroup lacks name-stability\n");
1049 return (topo_mod_seterrno(mp
, ETOPO_PRSR_NOATTR
));
1051 if (xmlattr_to_stab(mp
, pxn
, Datastab
, &dstab
) < 0) {
1052 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1053 "propgroup lacks data-stability\n");
1054 return (topo_mod_seterrno(mp
, ETOPO_PRSR_NOATTR
));
1057 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "pgroup %s\n", (char *)name
);
1058 for (cn
= pxn
->xmlChildrenNode
; cn
!= NULL
; cn
= cn
->next
) {
1059 if (xmlStrcmp(cn
->name
, (xmlChar
*)Propval
) == 0)
1063 if (topo_mod_nvalloc(mp
, &pgnvl
, NV_UNIQUE_NAME
) < 0) {
1065 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1066 "failed to allocate propgroup nvlist\n");
1067 return (topo_mod_seterrno(mp
, ETOPO_NOMEM
));
1070 e
= nvlist_add_string(pgnvl
, INV_PGRP_NAME
, (char *)name
);
1071 e
|= nvlist_add_uint32(pgnvl
, INV_PGRP_NMSTAB
, nmstab
);
1072 e
|= nvlist_add_uint32(pgnvl
, INV_PGRP_DSTAB
, dstab
);
1073 e
|= nvlist_add_uint32(pgnvl
, INV_PGRP_VER
, ver
);
1074 e
|= nvlist_add_uint32(pgnvl
, INV_PGRP_NPROP
, pcnt
);
1077 (apl
= topo_mod_zalloc(mp
, pcnt
* sizeof (nvlist_t
*)))
1081 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1082 "failed to allocate nvlist array for properties"
1084 return (topo_mod_seterrno(mp
, ETOPO_NOMEM
));
1086 for (cn
= pxn
->xmlChildrenNode
; cn
!= NULL
; cn
= cn
->next
) {
1087 if (xmlStrcmp(cn
->name
, (xmlChar
*)Propval
) == 0) {
1089 if ((apl
[ai
] = pval_record(mp
, cn
)) == NULL
)
1093 } else if (xmlStrcmp(cn
->name
, (xmlChar
*)Prop_meth
) == 0) {
1094 if (pmeth_record(mp
, (const char *)name
, cn
, tn
, rname
,
1102 e
|= nvlist_add_nvlist_array(pgnvl
, INV_PGRP_ALLPROPS
, apl
,
1104 for (ai
= 0; ai
< pcnt
; ai
++)
1105 if (apl
[ai
] != NULL
)
1106 nvlist_free(apl
[ai
]);
1107 topo_mod_free(mp
, apl
, pcnt
* sizeof (nvlist_t
*));
1113 rpad
->tpad_pgs
[pi
] = pgnvl
;
1118 pgroups_record(topo_mod_t
*mp
, xmlNodePtr pxn
, tnode_t
*tn
, const char *rname
,
1119 tf_pad_t
*rpad
, const char *ppgrp
)
1124 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "pgroups_record: pxn->name=%s\n",
1126 for (cn
= pxn
->xmlChildrenNode
; cn
!= NULL
; cn
= cn
->next
) {
1127 if (xmlStrcmp(cn
->name
, (xmlChar
*)Propgrp
) == 0) {
1128 if (pgroup_record(mp
, cn
, tn
, rname
, rpad
, pi
++, ppgrp
)
1137 * psn: pointer to a "set" XML node
1138 * key: string to search the set for
1140 * returns: 1, if the set contains key
1144 set_contains(topo_mod_t
*mp
, char *key
, char *set
)
1149 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "set_contains(key = %s, "
1150 "setlist = %s)\n", key
, set
);
1152 prod
= strtok((char *)set
, "|");
1153 if (prod
&& (strcmp(key
, prod
) == 0))
1156 while ((prod
= strtok(NULL
, "|")))
1157 if (strcmp(key
, prod
) == 0)
1165 * Process the property group and dependents xmlNode children of
1166 * parent xmlNode pxn.
1169 pad_process(topo_mod_t
*mp
, tf_rdata_t
*rd
, xmlNodePtr pxn
, tnode_t
*ptn
,
1172 xmlNodePtr cn
, gcn
, psn
, ecn
, target
;
1173 xmlNodePtr def_set
= NULL
;
1175 tf_pad_t
*new = *rpad
;
1180 int joined_set
= 0, inst
;
1184 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
,
1185 "pad_process beneath %s=%d\n", topo_node_name(ptn
),
1186 topo_node_instance(ptn
));
1188 for (cn
= pxn
->xmlChildrenNode
; cn
!= NULL
; cn
= cn
->next
) {
1189 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
,
1190 "cn->name is %s \n", (char *)cn
->name
);
1192 * We're iterating through the XML children looking for
1193 * four types of elements:
1194 * 1) dependents elements
1195 * 2) unconstrained pgroup elements
1196 * 3) pgroup elements constrained by set elements
1197 * 4) enum-method elements for the case that we want
1198 * to post-process a statically defined node
1200 if (xmlStrcmp(cn
->name
, (xmlChar
*)Dependents
) == 0)
1202 else if (xmlStrcmp(cn
->name
, (xmlChar
*)Propgrp
) == 0)
1204 else if (xmlStrcmp(cn
->name
, (xmlChar
*)Enum_meth
)
1208 } else if (xmlStrcmp(cn
->name
, (xmlChar
*)Set
) == 0) {
1211 set
= xmlGetProp(cn
, (xmlChar
*)Setlist
);
1213 if (mp
->tm_hdl
->th_product
)
1214 key
= mp
->tm_hdl
->th_product
;
1216 key
= mp
->tm_hdl
->th_platform
;
1219 * If it's the default set then we'll store
1220 * a pointer to it so that if none of the other
1221 * sets apply to our product we can fall
1224 if (strcmp((char *)set
, "default") == 0)
1226 else if (set_contains(mp
, key
, (char *)set
)) {
1229 for (gcn
= cn
->xmlChildrenNode
;
1230 gcn
!= NULL
; gcn
= gcn
->next
) {
1231 if (xmlStrcmp(gcn
->name
,
1232 (xmlChar
*)Propgrp
) == 0)
1240 * If we haven't found a set that contains our product AND
1241 * a default set exists, then we'll process it.
1243 if (!joined_set
&& def_set
) {
1244 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
,
1245 "Falling back to default set\n");
1248 for (gcn
= psn
->xmlChildrenNode
; gcn
!= NULL
;
1250 if (xmlStrcmp(gcn
->name
, (xmlChar
*)Propgrp
)
1255 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
,
1256 "pad_process: dcnt=%d, pgcnt=%d, ecnt=%d, joined_set=%d\n",
1257 dcnt
, pgcnt
, ecnt
, joined_set
);
1259 * If an enum-method element was found, AND we're a child of a
1260 * node element, then we invoke the enumerator so that it can do
1261 * post-processing of the node.
1263 if (ecnt
&& (strcmp((const char *)pxn
->name
, Node
) == 0)) {
1264 if ((tmp_rd
.rd_einfo
= enum_attributes_process(mp
, ecn
))
1268 tmp_rd
.rd_name
= rd
->rd_name
;
1269 tmp_rd
.rd_min
= rd
->rd_min
;
1270 tmp_rd
.rd_max
= rd
->rd_max
;
1272 if (enum_run(mp
, &tmp_rd
) < 0) {
1274 * Note the failure but continue on
1276 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1277 "pad_process: enumeration failed.\n");
1279 tf_edata_free(mp
, tmp_rd
.rd_einfo
);
1282 * Here we allocate an element in an intermediate data structure
1283 * which keeps track property groups and dependents of the range
1284 * currently being processed.
1286 * This structure is referenced in pgroups_record() to create
1287 * the actual property groups in the topo tree
1289 if ((new = tf_pad_new(mp
, pgcnt
, dcnt
)) == NULL
)
1294 topo_mod_zalloc(mp
, pgcnt
* sizeof (nvlist_t
*));
1295 if (new->tpad_pgs
== NULL
) {
1296 tf_pad_free(mp
, new);
1301 * If the property groups are contained within a set
1302 * then they will be one level lower in the XML tree.
1310 * If there is no "node" element under the "range"
1311 * element, then we need to attach the facility node to
1312 * each node in this range.
1314 * Otherwise we only attach it to the current node
1316 if (xmlStrcmp(target
->name
, (xmlChar
*)Range
) == 0 ||
1317 xmlStrcmp(target
->name
, (xmlChar
*)Set
) == 0) {
1318 for (ct
= topo_child_first(rd
->rd_pn
);
1320 ct
= topo_child_next(rd
->rd_pn
, ct
)) {
1322 if (strcmp(topo_node_name(ct
),
1326 inst
= topo_node_instance(ct
);
1327 if (inst
< rd
->rd_min
|| inst
> rd
->rd_max
)
1330 if (fac_enum_process(mp
, target
, ct
) < 0)
1333 if (fac_process(mp
, target
, rd
, ct
) < 0)
1337 if (fac_enum_process(mp
, target
, ptn
) < 0)
1339 if (fac_process(mp
, target
, rd
, ptn
) < 0)
1342 if (pgcnt
> 0 && pgroups_record(mp
, target
, ptn
, rd
->rd_name
,
1343 new, (const char *)pxn
->name
) < 0) {
1344 tf_pad_free(mp
, new);
1350 if (new->tpad_dcnt
> 0)
1351 if (dependents_create(mp
, rd
->rd_finfo
, new, pxn
, ptn
) < 0)
1354 if (new->tpad_pgcnt
> 0)
1355 if (pgroups_create(mp
, new, ptn
) < 0)
1363 fac_enum_process(topo_mod_t
*mp
, xmlNodePtr pn
, tnode_t
*ptn
)
1366 xmlChar
*fprov
= NULL
;
1369 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
,
1370 "fac_enum_process() called for %s=%d\n", topo_node_name(ptn
),
1371 topo_node_instance(ptn
));
1373 for (cn
= pn
->xmlChildrenNode
; cn
!= NULL
; cn
= cn
->next
) {
1375 if (xmlStrcmp(cn
->name
, (xmlChar
*)"fac-enum") != 0)
1378 if ((fprov
= xmlGetProp(cn
, (xmlChar
*)Provider
)) == NULL
)
1381 * Invoke enum entry point in facility provider which will
1382 * cause the facility enumeration node method to be
1385 if (fac_enum_run(mp
, ptn
, (const char *)fprov
) != 0) {
1386 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1387 "fac_enum_process: enum entry point failed!\n");
1394 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "fac-enum processing failed\n");
1404 fac_process(topo_mod_t
*mp
, xmlNodePtr pn
, tf_rdata_t
*rd
, tnode_t
*ptn
)
1407 xmlChar
*fname
= NULL
, *ftype
= NULL
, *provider
= NULL
;
1408 tnode_t
*ntn
= NULL
;
1411 topo_pgroup_info_t pgi
;
1413 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
,
1414 "fac_process() called for %s=%d\n", topo_node_name(ptn
),
1415 topo_node_instance(ptn
));
1417 for (cn
= pn
->xmlChildrenNode
; cn
!= NULL
; cn
= cn
->next
) {
1419 if (xmlStrcmp(cn
->name
, (xmlChar
*)Facility
) != 0)
1422 if ((fname
= xmlGetProp(cn
, (xmlChar
*)Name
)) == NULL
)
1425 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
,
1426 "processing facility node '%s'\n", fname
);
1428 if ((ftype
= xmlGetProp(cn
, (xmlChar
*)Type
)) == NULL
)
1431 if ((provider
= xmlGetProp(cn
, (xmlChar
*)Provider
)) == NULL
)
1434 if (xmlStrcmp(ftype
, (xmlChar
*)Sensor
) != 0 &&
1435 xmlStrcmp(ftype
, (xmlChar
*)Indicator
) != 0)
1438 if ((ntn
= topo_node_facbind(mp
, ptn
, (char *)fname
,
1439 (char *)ftype
)) == NULL
)
1442 pgi
.tpi_name
= TOPO_PGROUP_FACILITY
;
1443 pgi
.tpi_namestab
= TOPO_STABILITY_PRIVATE
;
1444 pgi
.tpi_datastab
= TOPO_STABILITY_PRIVATE
;
1445 pgi
.tpi_version
= 1;
1446 if (topo_pgroup_create(ntn
, &pgi
, &err
) != 0) {
1447 if (err
!= ETOPO_PROP_DEFD
) {
1448 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1449 "pgroups create failure: %s\n",
1450 topo_strerror(err
));
1455 * Invoke enum entry point in the facility provider module,
1456 * which will cause the provider methods to be registered on
1459 if (fac_enum_run(mp
, ntn
, (const char *)provider
) != 0) {
1460 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
, "fac_process: "
1461 "enum entry point failed for provider %s!\n",
1466 if ((newi
= tf_idata_new(mp
, 0, ntn
)) == NULL
)
1469 if (tf_idata_insert(&rd
->rd_instances
, newi
) < 0)
1472 if (pad_process(mp
, rd
, cn
, ntn
, &newi
->ti_pad
) < 0)
1475 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "done with "
1476 "facility %s=%s.\n", ftype
, fname
);
1486 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
, "facility processing failed\n");
1492 if (provider
!= NULL
)
1495 topo_node_unbind(ntn
);
1501 node_process(topo_mod_t
*mp
, xmlNodePtr nn
, tf_rdata_t
*rd
)
1504 topo_instance_t inst
;
1511 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
,
1512 "node_process %s\n", rd
->rd_name
);
1514 if (xmlattr_to_int(mp
, nn
, Instance
, &ui
) < 0)
1516 inst
= (topo_instance_t
)ui
;
1518 if ((str
= xmlGetProp(nn
, (xmlChar
*)Static
)) != NULL
) {
1519 if (xmlStrcmp(str
, (xmlChar
*)True
) == 0)
1525 if (topo_mod_enumerate(rd
->rd_mod
, rd
->rd_pn
,
1526 rd
->rd_finfo
->tf_scheme
, rd
->rd_name
, inst
, inst
,
1527 s
== 1 ? &s
: NULL
) < 0)
1530 ntn
= topo_node_lookup(rd
->rd_pn
, rd
->rd_name
, inst
);
1535 * If this is a static node declaration, we can
1536 * ignore the lookup failure and continue
1537 * processing. Otherwise, something
1538 * went wrong during enumeration
1544 if ((newi
= tf_idata_new(mp
, inst
, ntn
)) == NULL
) {
1545 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1546 "node_process: tf_idata_new failed.\n");
1549 if (tf_idata_insert(&rd
->rd_instances
, newi
) < 0) {
1550 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1551 "node_process: tf_idata_insert failed.\n");
1554 if (pad_process(mp
, rd
, nn
, ntn
, &newi
->ti_pad
) < 0)
1556 if (fac_process(mp
, nn
, rd
, ntn
) < 0)
1560 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "done with node %s.\n",
1566 enum_attributes_process(topo_mod_t
*mp
, xmlNodePtr en
)
1571 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "enum_attributes_process\n");
1572 if ((einfo
= topo_mod_zalloc(mp
, sizeof (tf_edata_t
))) == NULL
) {
1573 (void) topo_mod_seterrno(mp
, ETOPO_NOMEM
);
1576 einfo
->te_name
= (char *)xmlGetProp(en
, (xmlChar
*)Name
);
1577 if (einfo
->te_name
== NULL
) {
1578 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1579 "Enumerator name attribute missing.\n");
1580 (void) topo_mod_seterrno(mp
, ETOPO_PRSR_NOATTR
);
1585 * Check for recursive enumeration
1587 if (strcmp(einfo
->te_name
, mp
->tm_name
) == 0) {
1588 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1589 "Recursive enumeration detected for %s\n",
1591 (void) topo_mod_seterrno(mp
, ETOPO_ENUM_RECURS
);
1594 if (xmlattr_to_int(mp
, en
, Version
, &ui
) < 0)
1596 einfo
->te_vers
= (int)ui
;
1601 if (einfo
->te_name
!= NULL
)
1602 xmlFree(einfo
->te_name
);
1603 topo_mod_free(mp
, einfo
, sizeof (tf_edata_t
));
1608 enum_run(topo_mod_t
*mp
, tf_rdata_t
*rd
)
1610 topo_hdl_t
*thp
= mp
->tm_hdl
;
1613 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "enum_run\n");
1615 * Check if the enumerator module is already loaded.
1616 * Module loading is single-threaded at this point so there's
1617 * no need to worry about the module going away or bumping the
1620 if ((rd
->rd_mod
= topo_mod_lookup(thp
, rd
->rd_einfo
->te_name
,
1622 if ((rd
->rd_mod
= topo_mod_load(mp
, rd
->rd_einfo
->te_name
,
1623 rd
->rd_einfo
->te_vers
)) == NULL
) {
1624 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1625 "enum_run: mod_load of %s failed: %s.\n",
1626 rd
->rd_einfo
->te_name
,
1627 topo_strerror(topo_mod_errno(mp
)));
1628 (void) topo_hdl_seterrno(thp
, topo_mod_errno(mp
));
1633 * We're live, so let's enumerate.
1635 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "enumerate request. (%s)\n",
1636 rd
->rd_einfo
->te_name
);
1637 e
= topo_mod_enumerate(rd
->rd_mod
, rd
->rd_pn
, rd
->rd_einfo
->te_name
,
1638 rd
->rd_name
, rd
->rd_min
, rd
->rd_max
, NULL
);
1639 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "back from enumeration. %d\n",
1642 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1643 "Enumeration failed (%s)\n",
1644 topo_strerror(topo_mod_errno(mp
)));
1645 (void) topo_hdl_seterrno(thp
, EMOD_PARTIAL_ENUM
);
1646 return (topo_mod_seterrno(mp
, EMOD_PARTIAL_ENUM
));
1652 fac_enum_run(topo_mod_t
*mp
, tnode_t
*node
, const char *name
)
1654 topo_hdl_t
*thp
= mp
->tm_hdl
;
1658 topo_dprintf(thp
, TOPO_DBG_XML
, "fac_enum_run\n");
1660 * Check if the enumerator module is already loaded.
1661 * Module loading is single-threaded at this point so there's
1662 * no need to worry about the module going away or bumping the
1665 if ((fmod
= topo_mod_lookup(thp
, name
, 0)) == NULL
) {
1666 if ((fmod
= topo_mod_load(mp
, name
, TOPO_VERSION
)) == NULL
) {
1667 topo_dprintf(thp
, TOPO_DBG_ERR
,
1668 "fac_enum_run: mod_load of %s failed: %s.\n",
1669 name
, topo_strerror(topo_mod_errno(mp
)));
1670 (void) topo_hdl_seterrno(thp
, topo_mod_errno(mp
));
1675 * We're live, so let's enumerate.
1677 topo_dprintf(thp
, TOPO_DBG_XML
, "fac enumerate request. (%s)\n", name
);
1678 e
= topo_mod_enumerate(fmod
, node
, name
, name
, 0, 0, NULL
);
1679 topo_dprintf(thp
, TOPO_DBG_XML
, "back from enumeration. %d\n", e
);
1681 topo_dprintf(thp
, TOPO_DBG_ERR
,
1682 "Facility provider enumeration failed (%s)\n",
1683 topo_strerror(topo_mod_errno(mp
)));
1684 (void) topo_hdl_seterrno(thp
, EMOD_PARTIAL_ENUM
);
1685 return (topo_mod_seterrno(mp
, EMOD_PARTIAL_ENUM
));
1691 decorate_nodes(topo_mod_t
*mp
, tf_rdata_t
*rd
, xmlNodePtr pxn
, tnode_t
*ptn
,
1696 ctn
= topo_child_first(ptn
);
1697 while (ctn
!= NULL
) {
1698 /* Only care about instances within the range */
1699 if (strcmp(topo_node_name(ctn
), rd
->rd_name
) != 0) {
1700 ctn
= topo_child_next(ptn
, ctn
);
1703 if (pad_process(mp
, rd
, pxn
, ctn
, rpad
) < 0)
1705 if (decorate_nodes(mp
, rd
, pxn
, ctn
, rpad
) < 0)
1707 ctn
= topo_child_next(ptn
, ctn
);
1713 topo_xml_range_process(topo_mod_t
*mp
, xmlNodePtr rn
, tf_rdata_t
*rd
)
1716 * The range may have several children xmlNodes, that may
1717 * represent the enumeration method, property groups,
1718 * dependents, nodes or services.
1720 xmlNodePtr cn
, enum_node
= NULL
, pmap_node
= NULL
;
1725 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "topo_xml_range_process\n"
1726 "process %s range beneath %s\n", rd
->rd_name
,
1727 topo_node_name(rd
->rd_pn
));
1729 e
= topo_node_range_create(mp
,
1730 rd
->rd_pn
, rd
->rd_name
, rd
->rd_min
, rd
->rd_max
);
1731 if (e
!= 0 && topo_mod_errno(mp
) != EMOD_NODE_DUP
) {
1732 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1733 "Range create failed due to %s.\n",
1734 topo_strerror(topo_mod_errno(mp
)));
1739 * Before we process any of the other child xmlNodes, we iterate through
1740 * the children and looking for either enum-method or propmap elements.
1742 for (cn
= rn
->xmlChildrenNode
; cn
!= NULL
; cn
= cn
->next
)
1743 if (xmlStrcmp(cn
->name
, (xmlChar
*)Enum_meth
) == 0)
1745 else if (xmlStrcmp(cn
->name
, (xmlChar
*)Propmap
) == 0)
1749 * If we found an enum-method element, process it first
1751 if (enum_node
!= NULL
) {
1752 if ((rd
->rd_einfo
= enum_attributes_process(mp
, enum_node
))
1755 if (enum_run(mp
, rd
) < 0) {
1757 * Note the failure but continue on
1759 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1760 "Enumeration failed.\n");
1765 * Next, check if a propmap element was found and if so, load it in
1768 if (pmap_node
!= NULL
) {
1769 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "found a propmap "
1771 if ((pmap_name
= xmlGetProp(pmap_node
, (xmlChar
*)Name
))
1773 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1774 "propmap element missing name attribute.\n");
1776 if (topo_file_load(mp
, rd
->rd_pn
,
1777 (const char *)pmap_name
,
1778 rd
->rd_finfo
->tf_scheme
, 1) < 0) {
1780 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1781 "topo_xml_range_process: topo_file_load"
1783 topo_strerror(topo_mod_errno(mp
)));
1789 /* Now look for nodes, i.e., hard instances */
1790 for (cn
= rn
->xmlChildrenNode
; cn
!= NULL
; cn
= cn
->next
) {
1791 if (xmlStrcmp(cn
->name
, (xmlChar
*)Node
) == 0) {
1792 if (node_process(mp
, cn
, rd
) < 0) {
1793 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1794 "node processing failed: %s.\n",
1795 topo_strerror(topo_mod_errno(mp
)));
1796 return (topo_mod_seterrno(mp
,
1797 EMOD_PARTIAL_ENUM
));
1804 * Finally, process the property groups and dependents
1806 * If the TF_PROPMAP flag is set for the XML file we're currently
1807 * processing, then this XML file was loaded via propmap. In that case
1808 * we call a special routine to recursively apply the propgroup settings
1809 * to all of nodes in this range
1811 if (rd
->rd_finfo
->tf_flags
& TF_PROPMAP
)
1812 (void) decorate_nodes(mp
, rd
, rn
, rd
->rd_pn
, &rd
->rd_pad
);
1814 ct
= topo_child_first(rd
->rd_pn
);
1815 while (ct
!= NULL
) {
1816 /* Only care about instances within the range */
1817 if (strcmp(topo_node_name(ct
), rd
->rd_name
) != 0) {
1818 ct
= topo_child_next(rd
->rd_pn
, ct
);
1821 if (pad_process(mp
, rd
, rn
, ct
, &rd
->rd_pad
)
1825 if (fac_process(mp
, rn
, rd
, ct
) < 0)
1828 ct
= topo_child_next(rd
->rd_pn
, ct
);
1833 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "topo_xml_range_process: end "
1834 "range process %s\n", rd
->rd_name
);
1840 topo_xml_walk(topo_mod_t
*mp
,
1841 tf_info_t
*xinfo
, xmlNodePtr croot
, tnode_t
*troot
)
1843 xmlNodePtr curr
, def_set
= NULL
;
1844 tf_rdata_t
*rr
, *pr
, *rdp
;
1849 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "topo_xml_walk\n");
1852 * First iterate through all the XML nodes at this level to look for
1855 for (curr
= croot
->xmlChildrenNode
; curr
!= NULL
; curr
= curr
->next
) {
1856 if (curr
->name
== NULL
) {
1857 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
,
1858 "topo_xml_walk: Ignoring nameless xmlnode\n");
1861 if (xmlStrcmp(curr
->name
, (xmlChar
*)Set
) == 0) {
1865 set
= xmlGetProp(curr
, (xmlChar
*)Setlist
);
1867 if (mp
->tm_hdl
->th_product
)
1868 key
= mp
->tm_hdl
->th_product
;
1870 key
= mp
->tm_hdl
->th_platform
;
1873 * If it's the default set then we'll store
1874 * a pointer to it so that if none of the other
1875 * sets apply to our product we can fall
1878 if (strcmp((char *)set
, "default") == 0)
1880 else if (set_contains(mp
, key
, (char *)set
)) {
1882 if ((rdp
= topo_xml_walk(mp
, xinfo
, curr
,
1884 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
,
1885 "topo_xml_walk: failed1\n");
1900 * If we haven't found a set that contains our product AND a default set
1901 * exists, then we'll process it.
1903 if (!joined_set
&& def_set
) {
1904 if ((rdp
= topo_xml_walk(mp
, xinfo
, def_set
, troot
)) == NULL
) {
1905 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
,
1906 "topo_xml_walk: failed2\n");
1917 * Now we're interested in children xmlNodes of croot tagged
1918 * as 'ranges'. These define what topology nodes may exist, and need
1921 for (curr
= croot
->xmlChildrenNode
; curr
!= NULL
; curr
= curr
->next
) {
1922 if (curr
->name
== NULL
) {
1923 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
,
1924 "topo_xml_walk: Ignoring nameless xmlnode\n");
1927 if (xmlStrcmp(curr
->name
, (xmlChar
*)Range
) != 0)
1929 if ((rdp
= tf_rdata_new(mp
, xinfo
, curr
, troot
)) == NULL
) {
1931 * Range processing error, continue walk
1948 * Convert parsed xml topology description into topology nodes
1951 topo_xml_enum(topo_mod_t
*tmp
, tf_info_t
*xinfo
, tnode_t
*troot
)
1955 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_XML
, "topo_xml_enum\n");
1957 if ((xroot
= xmlDocGetRootElement(xinfo
->tf_xdoc
)) == NULL
) {
1958 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_ERR
,
1959 "Couldn't get root xmlNode.\n");
1962 if ((xinfo
->tf_rd
= topo_xml_walk(tmp
, xinfo
, xroot
, troot
)) == NULL
) {
1963 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_ERR
,
1964 "error within .xml topology: %s\n",
1965 topo_strerror(topo_mod_errno(tmp
)));
1972 * Load an XML tree from filename and read it into a DOM parse tree.
1975 txml_file_parse(topo_mod_t
*tmp
,
1976 int fd
, const char *filenm
, const char *escheme
)
1978 xmlValidCtxtPtr vcp
;
1981 xmlDtdPtr dtd
= NULL
;
1982 xmlChar
*scheme
= NULL
;
1983 char *dtdpath
= NULL
;
1986 int e
, validate
= 0;
1988 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_XML
,
1989 "txml_file_parse(filenm=%s, escheme=%s)\n", filenm
, escheme
);
1992 * Since topologies can XInclude other topologies, and libxml2
1993 * doesn't do DTD-based validation with XInclude, by default
1994 * we don't validate topology files. One can force
1995 * validation, though, by creating a TOPOXML_VALIDATE
1996 * environment variable and creating a TOPO_DTD environment
1997 * variable with the path to the DTD against which to validate.
1999 if (getenv("TOPOXML_VALIDATE") != NULL
) {
2000 dtdpath
= getenv("TOPO_DTD");
2001 if (dtdpath
!= NULL
)
2002 xmlLoadExtDtdDefaultValue
= 0;
2007 * Splat warnings and errors related to parsing the topology
2008 * file if the TOPOXML_PERROR environment variable exists.
2010 if (getenv("TOPOXML_PERROR") == NULL
)
2011 readflags
= XML_PARSE_NOERROR
| XML_PARSE_NOWARNING
;
2013 if ((document
= xmlReadFd(fd
, filenm
, NULL
, readflags
)) == NULL
) {
2014 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_ERR
,
2015 "txml_file_parse: couldn't parse document.\n");
2020 * Verify that this is a document type we understand.
2022 if ((dtd
= xmlGetIntSubset(document
)) == NULL
) {
2023 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_ERR
,
2024 "document has no DTD.\n");
2025 xmlFreeDoc(document
);
2029 if (strcmp((const char *)dtd
->SystemID
, TOPO_DTD_PATH
) != 0) {
2030 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_ERR
,
2031 "document DTD unknown; bad topology file\n");
2032 xmlFreeDoc(document
);
2036 if ((cursor
= xmlDocGetRootElement(document
)) == NULL
) {
2037 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_ERR
, "document is empty.\n");
2038 xmlFreeDoc(document
);
2043 * Make sure we're looking at a topology description in the
2046 if (xmlStrcmp(cursor
->name
, (xmlChar
*)Topology
) != 0) {
2047 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_ERR
,
2048 "document is not a topology description.\n");
2049 xmlFreeDoc(document
);
2052 if ((scheme
= xmlGetProp(cursor
, (xmlChar
*)Scheme
)) == NULL
) {
2053 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_ERR
,
2054 "topology lacks a scheme.\n");
2055 (void) topo_mod_seterrno(tmp
, ETOPO_PRSR_NOATTR
);
2056 xmlFreeDoc(document
);
2059 if (xmlStrcmp(scheme
, (xmlChar
*)escheme
) != 0) {
2060 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_ERR
,
2061 "topology in unrecognized scheme, %s, expecting %s\n",
2063 (void) topo_mod_seterrno(tmp
, ETOPO_PRSR_BADSCH
);
2065 xmlFreeDoc(document
);
2069 if (dtdpath
!= NULL
) {
2070 dtd
= xmlParseDTD(NULL
, (xmlChar
*)dtdpath
);
2072 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_ERR
,
2073 "Could not parse DTD \"%s\".\n",
2076 xmlFreeDoc(document
);
2080 if (document
->extSubset
!= NULL
)
2081 xmlFreeDtd(document
->extSubset
);
2083 document
->extSubset
= dtd
;
2086 if (xmlXIncludeProcessFlags(document
, XML_PARSE_XINCLUDE
) == -1) {
2088 xmlFreeDoc(document
);
2089 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_ERR
,
2090 "couldn't handle XInclude statements in document\n");
2095 if ((vcp
= xmlNewValidCtxt()) == NULL
) {
2097 xmlFreeDoc(document
);
2100 vcp
->warning
= xmlParserValidityWarning
;
2101 vcp
->error
= xmlParserValidityError
;
2103 e
= xmlValidateDocument(vcp
, document
);
2105 xmlFreeValidCtxt(vcp
);
2108 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_ERR
,
2109 "Document is not valid.\n");
2112 if ((r
= tf_info_new(tmp
, document
, scheme
)) == NULL
) {
2114 xmlFreeDoc(document
);
2124 topo_xml_read(topo_mod_t
*tmp
, const char *path
, const char *escheme
)
2129 if ((fd
= open(path
, O_RDONLY
)) < 0) {
2130 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_ERR
,
2131 "failed to open %s for reading\n", path
);
2134 tip
= txml_file_parse(tmp
, fd
, path
, escheme
);