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
);
1015 nvlist_free(arg_nvl
);
1021 pgroup_record(topo_mod_t
*mp
, xmlNodePtr pxn
, tnode_t
*tn
, const char *rname
,
1022 tf_pad_t
*rpad
, int pi
, const char *ppgrp_name
)
1024 topo_stability_t nmstab
, dstab
;
1028 nvlist_t
**apl
= NULL
;
1029 nvlist_t
*pgnvl
= NULL
;
1034 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "pgroup_record\n");
1035 if ((name
= xmlGetProp(pxn
, (xmlChar
*)Name
)) == NULL
) {
1036 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1037 "propgroup lacks a name\n");
1038 return (topo_mod_seterrno(mp
, ETOPO_PRSR_NOATTR
));
1040 if (xmlattr_to_int(mp
, pxn
, Version
, &ver
) < 0) {
1041 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1042 "propgroup lacks a version\n");
1043 return (topo_mod_seterrno(mp
, ETOPO_PRSR_NOATTR
));
1045 if (xmlattr_to_stab(mp
, pxn
, Namestab
, &nmstab
) < 0) {
1046 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1047 "propgroup lacks name-stability\n");
1048 return (topo_mod_seterrno(mp
, ETOPO_PRSR_NOATTR
));
1050 if (xmlattr_to_stab(mp
, pxn
, Datastab
, &dstab
) < 0) {
1051 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1052 "propgroup lacks data-stability\n");
1053 return (topo_mod_seterrno(mp
, ETOPO_PRSR_NOATTR
));
1056 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "pgroup %s\n", (char *)name
);
1057 for (cn
= pxn
->xmlChildrenNode
; cn
!= NULL
; cn
= cn
->next
) {
1058 if (xmlStrcmp(cn
->name
, (xmlChar
*)Propval
) == 0)
1062 if (topo_mod_nvalloc(mp
, &pgnvl
, NV_UNIQUE_NAME
) < 0) {
1064 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1065 "failed to allocate propgroup nvlist\n");
1066 return (topo_mod_seterrno(mp
, ETOPO_NOMEM
));
1069 e
= nvlist_add_string(pgnvl
, INV_PGRP_NAME
, (char *)name
);
1070 e
|= nvlist_add_uint32(pgnvl
, INV_PGRP_NMSTAB
, nmstab
);
1071 e
|= nvlist_add_uint32(pgnvl
, INV_PGRP_DSTAB
, dstab
);
1072 e
|= nvlist_add_uint32(pgnvl
, INV_PGRP_VER
, ver
);
1073 e
|= nvlist_add_uint32(pgnvl
, INV_PGRP_NPROP
, pcnt
);
1076 (apl
= topo_mod_zalloc(mp
, pcnt
* sizeof (nvlist_t
*)))
1080 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1081 "failed to allocate nvlist array for properties"
1083 return (topo_mod_seterrno(mp
, ETOPO_NOMEM
));
1085 for (cn
= pxn
->xmlChildrenNode
; cn
!= NULL
; cn
= cn
->next
) {
1086 if (xmlStrcmp(cn
->name
, (xmlChar
*)Propval
) == 0) {
1088 if ((apl
[ai
] = pval_record(mp
, cn
)) == NULL
)
1092 } else if (xmlStrcmp(cn
->name
, (xmlChar
*)Prop_meth
) == 0) {
1093 if (pmeth_record(mp
, (const char *)name
, cn
, tn
, rname
,
1101 e
|= nvlist_add_nvlist_array(pgnvl
, INV_PGRP_ALLPROPS
, apl
,
1103 for (ai
= 0; ai
< pcnt
; ai
++)
1104 nvlist_free(apl
[ai
]);
1105 topo_mod_free(mp
, apl
, pcnt
* sizeof (nvlist_t
*));
1111 rpad
->tpad_pgs
[pi
] = pgnvl
;
1116 pgroups_record(topo_mod_t
*mp
, xmlNodePtr pxn
, tnode_t
*tn
, const char *rname
,
1117 tf_pad_t
*rpad
, const char *ppgrp
)
1122 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "pgroups_record: pxn->name=%s\n",
1124 for (cn
= pxn
->xmlChildrenNode
; cn
!= NULL
; cn
= cn
->next
) {
1125 if (xmlStrcmp(cn
->name
, (xmlChar
*)Propgrp
) == 0) {
1126 if (pgroup_record(mp
, cn
, tn
, rname
, rpad
, pi
++, ppgrp
)
1135 * psn: pointer to a "set" XML node
1136 * key: string to search the set for
1138 * returns: 1, if the set contains key
1142 set_contains(topo_mod_t
*mp
, char *key
, char *set
)
1147 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "set_contains(key = %s, "
1148 "setlist = %s)\n", key
, set
);
1150 prod
= strtok((char *)set
, "|");
1151 if (prod
&& (strcmp(key
, prod
) == 0))
1154 while ((prod
= strtok(NULL
, "|")))
1155 if (strcmp(key
, prod
) == 0)
1163 * Process the property group and dependents xmlNode children of
1164 * parent xmlNode pxn.
1167 pad_process(topo_mod_t
*mp
, tf_rdata_t
*rd
, xmlNodePtr pxn
, tnode_t
*ptn
,
1170 xmlNodePtr cn
, gcn
, psn
, ecn
, target
;
1171 xmlNodePtr def_set
= NULL
;
1173 tf_pad_t
*new = *rpad
;
1178 int joined_set
= 0, inst
;
1182 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
,
1183 "pad_process beneath %s=%d\n", topo_node_name(ptn
),
1184 topo_node_instance(ptn
));
1186 for (cn
= pxn
->xmlChildrenNode
; cn
!= NULL
; cn
= cn
->next
) {
1187 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
,
1188 "cn->name is %s \n", (char *)cn
->name
);
1190 * We're iterating through the XML children looking for
1191 * four types of elements:
1192 * 1) dependents elements
1193 * 2) unconstrained pgroup elements
1194 * 3) pgroup elements constrained by set elements
1195 * 4) enum-method elements for the case that we want
1196 * to post-process a statically defined node
1198 if (xmlStrcmp(cn
->name
, (xmlChar
*)Dependents
) == 0)
1200 else if (xmlStrcmp(cn
->name
, (xmlChar
*)Propgrp
) == 0)
1202 else if (xmlStrcmp(cn
->name
, (xmlChar
*)Enum_meth
)
1206 } else if (xmlStrcmp(cn
->name
, (xmlChar
*)Set
) == 0) {
1209 set
= xmlGetProp(cn
, (xmlChar
*)Setlist
);
1211 if (mp
->tm_hdl
->th_product
)
1212 key
= mp
->tm_hdl
->th_product
;
1214 key
= mp
->tm_hdl
->th_platform
;
1217 * If it's the default set then we'll store
1218 * a pointer to it so that if none of the other
1219 * sets apply to our product we can fall
1222 if (strcmp((char *)set
, "default") == 0)
1224 else if (set_contains(mp
, key
, (char *)set
)) {
1227 for (gcn
= cn
->xmlChildrenNode
;
1228 gcn
!= NULL
; gcn
= gcn
->next
) {
1229 if (xmlStrcmp(gcn
->name
,
1230 (xmlChar
*)Propgrp
) == 0)
1238 * If we haven't found a set that contains our product AND
1239 * a default set exists, then we'll process it.
1241 if (!joined_set
&& def_set
) {
1242 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
,
1243 "Falling back to default set\n");
1246 for (gcn
= psn
->xmlChildrenNode
; gcn
!= NULL
;
1248 if (xmlStrcmp(gcn
->name
, (xmlChar
*)Propgrp
)
1253 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
,
1254 "pad_process: dcnt=%d, pgcnt=%d, ecnt=%d, joined_set=%d\n",
1255 dcnt
, pgcnt
, ecnt
, joined_set
);
1257 * If an enum-method element was found, AND we're a child of a
1258 * node element, then we invoke the enumerator so that it can do
1259 * post-processing of the node.
1261 if (ecnt
&& (strcmp((const char *)pxn
->name
, Node
) == 0)) {
1262 if ((tmp_rd
.rd_einfo
= enum_attributes_process(mp
, ecn
))
1266 tmp_rd
.rd_name
= rd
->rd_name
;
1267 tmp_rd
.rd_min
= rd
->rd_min
;
1268 tmp_rd
.rd_max
= rd
->rd_max
;
1270 if (enum_run(mp
, &tmp_rd
) < 0) {
1272 * Note the failure but continue on
1274 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1275 "pad_process: enumeration failed.\n");
1277 tf_edata_free(mp
, tmp_rd
.rd_einfo
);
1280 * Here we allocate an element in an intermediate data structure
1281 * which keeps track property groups and dependents of the range
1282 * currently being processed.
1284 * This structure is referenced in pgroups_record() to create
1285 * the actual property groups in the topo tree
1287 if ((new = tf_pad_new(mp
, pgcnt
, dcnt
)) == NULL
)
1292 topo_mod_zalloc(mp
, pgcnt
* sizeof (nvlist_t
*));
1293 if (new->tpad_pgs
== NULL
) {
1294 tf_pad_free(mp
, new);
1299 * If the property groups are contained within a set
1300 * then they will be one level lower in the XML tree.
1308 * If there is no "node" element under the "range"
1309 * element, then we need to attach the facility node to
1310 * each node in this range.
1312 * Otherwise we only attach it to the current node
1314 if (xmlStrcmp(target
->name
, (xmlChar
*)Range
) == 0 ||
1315 xmlStrcmp(target
->name
, (xmlChar
*)Set
) == 0) {
1316 for (ct
= topo_child_first(rd
->rd_pn
);
1318 ct
= topo_child_next(rd
->rd_pn
, ct
)) {
1320 if (strcmp(topo_node_name(ct
),
1324 inst
= topo_node_instance(ct
);
1325 if (inst
< rd
->rd_min
|| inst
> rd
->rd_max
)
1328 if (fac_enum_process(mp
, target
, ct
) < 0)
1331 if (fac_process(mp
, target
, rd
, ct
) < 0)
1335 if (fac_enum_process(mp
, target
, ptn
) < 0)
1337 if (fac_process(mp
, target
, rd
, ptn
) < 0)
1340 if (pgcnt
> 0 && pgroups_record(mp
, target
, ptn
, rd
->rd_name
,
1341 new, (const char *)pxn
->name
) < 0) {
1342 tf_pad_free(mp
, new);
1348 if (new->tpad_dcnt
> 0)
1349 if (dependents_create(mp
, rd
->rd_finfo
, new, pxn
, ptn
) < 0)
1352 if (new->tpad_pgcnt
> 0)
1353 if (pgroups_create(mp
, new, ptn
) < 0)
1361 fac_enum_process(topo_mod_t
*mp
, xmlNodePtr pn
, tnode_t
*ptn
)
1364 xmlChar
*fprov
= NULL
;
1367 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
,
1368 "fac_enum_process() called for %s=%d\n", topo_node_name(ptn
),
1369 topo_node_instance(ptn
));
1371 for (cn
= pn
->xmlChildrenNode
; cn
!= NULL
; cn
= cn
->next
) {
1373 if (xmlStrcmp(cn
->name
, (xmlChar
*)"fac-enum") != 0)
1376 if ((fprov
= xmlGetProp(cn
, (xmlChar
*)Provider
)) == NULL
)
1379 * Invoke enum entry point in facility provider which will
1380 * cause the facility enumeration node method to be
1383 if (fac_enum_run(mp
, ptn
, (const char *)fprov
) != 0) {
1384 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1385 "fac_enum_process: enum entry point failed!\n");
1392 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "fac-enum processing failed\n");
1402 fac_process(topo_mod_t
*mp
, xmlNodePtr pn
, tf_rdata_t
*rd
, tnode_t
*ptn
)
1405 xmlChar
*fname
= NULL
, *ftype
= NULL
, *provider
= NULL
;
1406 tnode_t
*ntn
= NULL
;
1409 topo_pgroup_info_t pgi
;
1411 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
,
1412 "fac_process() called for %s=%d\n", topo_node_name(ptn
),
1413 topo_node_instance(ptn
));
1415 for (cn
= pn
->xmlChildrenNode
; cn
!= NULL
; cn
= cn
->next
) {
1417 if (xmlStrcmp(cn
->name
, (xmlChar
*)Facility
) != 0)
1420 if ((fname
= xmlGetProp(cn
, (xmlChar
*)Name
)) == NULL
)
1423 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
,
1424 "processing facility node '%s'\n", fname
);
1426 if ((ftype
= xmlGetProp(cn
, (xmlChar
*)Type
)) == NULL
)
1429 if ((provider
= xmlGetProp(cn
, (xmlChar
*)Provider
)) == NULL
)
1432 if (xmlStrcmp(ftype
, (xmlChar
*)Sensor
) != 0 &&
1433 xmlStrcmp(ftype
, (xmlChar
*)Indicator
) != 0)
1436 if ((ntn
= topo_node_facbind(mp
, ptn
, (char *)fname
,
1437 (char *)ftype
)) == NULL
)
1440 pgi
.tpi_name
= TOPO_PGROUP_FACILITY
;
1441 pgi
.tpi_namestab
= TOPO_STABILITY_PRIVATE
;
1442 pgi
.tpi_datastab
= TOPO_STABILITY_PRIVATE
;
1443 pgi
.tpi_version
= 1;
1444 if (topo_pgroup_create(ntn
, &pgi
, &err
) != 0) {
1445 if (err
!= ETOPO_PROP_DEFD
) {
1446 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1447 "pgroups create failure: %s\n",
1448 topo_strerror(err
));
1453 * Invoke enum entry point in the facility provider module,
1454 * which will cause the provider methods to be registered on
1457 if (fac_enum_run(mp
, ntn
, (const char *)provider
) != 0) {
1458 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
, "fac_process: "
1459 "enum entry point failed for provider %s!\n",
1464 if ((newi
= tf_idata_new(mp
, 0, ntn
)) == NULL
)
1467 if (tf_idata_insert(&rd
->rd_instances
, newi
) < 0)
1470 if (pad_process(mp
, rd
, cn
, ntn
, &newi
->ti_pad
) < 0)
1473 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "done with "
1474 "facility %s=%s.\n", ftype
, fname
);
1484 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
, "facility processing failed\n");
1490 if (provider
!= NULL
)
1493 topo_node_unbind(ntn
);
1499 node_process(topo_mod_t
*mp
, xmlNodePtr nn
, tf_rdata_t
*rd
)
1502 topo_instance_t inst
;
1509 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
,
1510 "node_process %s\n", rd
->rd_name
);
1512 if (xmlattr_to_int(mp
, nn
, Instance
, &ui
) < 0)
1514 inst
= (topo_instance_t
)ui
;
1516 if ((str
= xmlGetProp(nn
, (xmlChar
*)Static
)) != NULL
) {
1517 if (xmlStrcmp(str
, (xmlChar
*)True
) == 0)
1523 if (topo_mod_enumerate(rd
->rd_mod
, rd
->rd_pn
,
1524 rd
->rd_finfo
->tf_scheme
, rd
->rd_name
, inst
, inst
,
1525 s
== 1 ? &s
: NULL
) < 0)
1528 ntn
= topo_node_lookup(rd
->rd_pn
, rd
->rd_name
, inst
);
1533 * If this is a static node declaration, we can
1534 * ignore the lookup failure and continue
1535 * processing. Otherwise, something
1536 * went wrong during enumeration
1542 if ((newi
= tf_idata_new(mp
, inst
, ntn
)) == NULL
) {
1543 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1544 "node_process: tf_idata_new failed.\n");
1547 if (tf_idata_insert(&rd
->rd_instances
, newi
) < 0) {
1548 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1549 "node_process: tf_idata_insert failed.\n");
1552 if (pad_process(mp
, rd
, nn
, ntn
, &newi
->ti_pad
) < 0)
1554 if (fac_process(mp
, nn
, rd
, ntn
) < 0)
1558 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "done with node %s.\n",
1564 enum_attributes_process(topo_mod_t
*mp
, xmlNodePtr en
)
1569 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "enum_attributes_process\n");
1570 if ((einfo
= topo_mod_zalloc(mp
, sizeof (tf_edata_t
))) == NULL
) {
1571 (void) topo_mod_seterrno(mp
, ETOPO_NOMEM
);
1574 einfo
->te_name
= (char *)xmlGetProp(en
, (xmlChar
*)Name
);
1575 if (einfo
->te_name
== NULL
) {
1576 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1577 "Enumerator name attribute missing.\n");
1578 (void) topo_mod_seterrno(mp
, ETOPO_PRSR_NOATTR
);
1583 * Check for recursive enumeration
1585 if (strcmp(einfo
->te_name
, mp
->tm_name
) == 0) {
1586 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1587 "Recursive enumeration detected for %s\n",
1589 (void) topo_mod_seterrno(mp
, ETOPO_ENUM_RECURS
);
1592 if (xmlattr_to_int(mp
, en
, Version
, &ui
) < 0)
1594 einfo
->te_vers
= (int)ui
;
1599 if (einfo
->te_name
!= NULL
)
1600 xmlFree(einfo
->te_name
);
1601 topo_mod_free(mp
, einfo
, sizeof (tf_edata_t
));
1606 enum_run(topo_mod_t
*mp
, tf_rdata_t
*rd
)
1608 topo_hdl_t
*thp
= mp
->tm_hdl
;
1611 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "enum_run\n");
1613 * Check if the enumerator module is already loaded.
1614 * Module loading is single-threaded at this point so there's
1615 * no need to worry about the module going away or bumping the
1618 if ((rd
->rd_mod
= topo_mod_lookup(thp
, rd
->rd_einfo
->te_name
,
1620 if ((rd
->rd_mod
= topo_mod_load(mp
, rd
->rd_einfo
->te_name
,
1621 rd
->rd_einfo
->te_vers
)) == NULL
) {
1622 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1623 "enum_run: mod_load of %s failed: %s.\n",
1624 rd
->rd_einfo
->te_name
,
1625 topo_strerror(topo_mod_errno(mp
)));
1626 (void) topo_hdl_seterrno(thp
, topo_mod_errno(mp
));
1631 * We're live, so let's enumerate.
1633 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "enumerate request. (%s)\n",
1634 rd
->rd_einfo
->te_name
);
1635 e
= topo_mod_enumerate(rd
->rd_mod
, rd
->rd_pn
, rd
->rd_einfo
->te_name
,
1636 rd
->rd_name
, rd
->rd_min
, rd
->rd_max
, NULL
);
1637 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "back from enumeration. %d\n",
1640 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1641 "Enumeration failed (%s)\n",
1642 topo_strerror(topo_mod_errno(mp
)));
1643 (void) topo_hdl_seterrno(thp
, EMOD_PARTIAL_ENUM
);
1644 return (topo_mod_seterrno(mp
, EMOD_PARTIAL_ENUM
));
1650 fac_enum_run(topo_mod_t
*mp
, tnode_t
*node
, const char *name
)
1652 topo_hdl_t
*thp
= mp
->tm_hdl
;
1656 topo_dprintf(thp
, TOPO_DBG_XML
, "fac_enum_run\n");
1658 * Check if the enumerator module is already loaded.
1659 * Module loading is single-threaded at this point so there's
1660 * no need to worry about the module going away or bumping the
1663 if ((fmod
= topo_mod_lookup(thp
, name
, 0)) == NULL
) {
1664 if ((fmod
= topo_mod_load(mp
, name
, TOPO_VERSION
)) == NULL
) {
1665 topo_dprintf(thp
, TOPO_DBG_ERR
,
1666 "fac_enum_run: mod_load of %s failed: %s.\n",
1667 name
, topo_strerror(topo_mod_errno(mp
)));
1668 (void) topo_hdl_seterrno(thp
, topo_mod_errno(mp
));
1673 * We're live, so let's enumerate.
1675 topo_dprintf(thp
, TOPO_DBG_XML
, "fac enumerate request. (%s)\n", name
);
1676 e
= topo_mod_enumerate(fmod
, node
, name
, name
, 0, 0, NULL
);
1677 topo_dprintf(thp
, TOPO_DBG_XML
, "back from enumeration. %d\n", e
);
1679 topo_dprintf(thp
, TOPO_DBG_ERR
,
1680 "Facility provider enumeration failed (%s)\n",
1681 topo_strerror(topo_mod_errno(mp
)));
1682 (void) topo_hdl_seterrno(thp
, EMOD_PARTIAL_ENUM
);
1683 return (topo_mod_seterrno(mp
, EMOD_PARTIAL_ENUM
));
1689 decorate_nodes(topo_mod_t
*mp
, tf_rdata_t
*rd
, xmlNodePtr pxn
, tnode_t
*ptn
,
1694 ctn
= topo_child_first(ptn
);
1695 while (ctn
!= NULL
) {
1696 /* Only care about instances within the range */
1697 if (strcmp(topo_node_name(ctn
), rd
->rd_name
) != 0) {
1698 ctn
= topo_child_next(ptn
, ctn
);
1701 if (pad_process(mp
, rd
, pxn
, ctn
, rpad
) < 0)
1703 if (decorate_nodes(mp
, rd
, pxn
, ctn
, rpad
) < 0)
1705 ctn
= topo_child_next(ptn
, ctn
);
1711 topo_xml_range_process(topo_mod_t
*mp
, xmlNodePtr rn
, tf_rdata_t
*rd
)
1714 * The range may have several children xmlNodes, that may
1715 * represent the enumeration method, property groups,
1716 * dependents, nodes or services.
1718 xmlNodePtr cn
, enum_node
= NULL
, pmap_node
= NULL
;
1723 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "topo_xml_range_process\n"
1724 "process %s range beneath %s\n", rd
->rd_name
,
1725 topo_node_name(rd
->rd_pn
));
1727 e
= topo_node_range_create(mp
,
1728 rd
->rd_pn
, rd
->rd_name
, rd
->rd_min
, rd
->rd_max
);
1729 if (e
!= 0 && topo_mod_errno(mp
) != EMOD_NODE_DUP
) {
1730 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1731 "Range create failed due to %s.\n",
1732 topo_strerror(topo_mod_errno(mp
)));
1737 * Before we process any of the other child xmlNodes, we iterate through
1738 * the children and looking for either enum-method or propmap elements.
1740 for (cn
= rn
->xmlChildrenNode
; cn
!= NULL
; cn
= cn
->next
)
1741 if (xmlStrcmp(cn
->name
, (xmlChar
*)Enum_meth
) == 0)
1743 else if (xmlStrcmp(cn
->name
, (xmlChar
*)Propmap
) == 0)
1747 * If we found an enum-method element, process it first
1749 if (enum_node
!= NULL
) {
1750 if ((rd
->rd_einfo
= enum_attributes_process(mp
, enum_node
))
1753 if (enum_run(mp
, rd
) < 0) {
1755 * Note the failure but continue on
1757 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1758 "Enumeration failed.\n");
1763 * Next, check if a propmap element was found and if so, load it in
1766 if (pmap_node
!= NULL
) {
1767 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "found a propmap "
1769 if ((pmap_name
= xmlGetProp(pmap_node
, (xmlChar
*)Name
))
1771 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1772 "propmap element missing name attribute.\n");
1774 if (topo_file_load(mp
, rd
->rd_pn
,
1775 (const char *)pmap_name
,
1776 rd
->rd_finfo
->tf_scheme
, 1) < 0) {
1778 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1779 "topo_xml_range_process: topo_file_load"
1781 topo_strerror(topo_mod_errno(mp
)));
1787 /* Now look for nodes, i.e., hard instances */
1788 for (cn
= rn
->xmlChildrenNode
; cn
!= NULL
; cn
= cn
->next
) {
1789 if (xmlStrcmp(cn
->name
, (xmlChar
*)Node
) == 0) {
1790 if (node_process(mp
, cn
, rd
) < 0) {
1791 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_ERR
,
1792 "node processing failed: %s.\n",
1793 topo_strerror(topo_mod_errno(mp
)));
1794 return (topo_mod_seterrno(mp
,
1795 EMOD_PARTIAL_ENUM
));
1802 * Finally, process the property groups and dependents
1804 * If the TF_PROPMAP flag is set for the XML file we're currently
1805 * processing, then this XML file was loaded via propmap. In that case
1806 * we call a special routine to recursively apply the propgroup settings
1807 * to all of nodes in this range
1809 if (rd
->rd_finfo
->tf_flags
& TF_PROPMAP
)
1810 (void) decorate_nodes(mp
, rd
, rn
, rd
->rd_pn
, &rd
->rd_pad
);
1812 ct
= topo_child_first(rd
->rd_pn
);
1813 while (ct
!= NULL
) {
1814 /* Only care about instances within the range */
1815 if (strcmp(topo_node_name(ct
), rd
->rd_name
) != 0) {
1816 ct
= topo_child_next(rd
->rd_pn
, ct
);
1819 if (pad_process(mp
, rd
, rn
, ct
, &rd
->rd_pad
)
1823 if (fac_process(mp
, rn
, rd
, ct
) < 0)
1826 ct
= topo_child_next(rd
->rd_pn
, ct
);
1831 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "topo_xml_range_process: end "
1832 "range process %s\n", rd
->rd_name
);
1838 topo_xml_walk(topo_mod_t
*mp
,
1839 tf_info_t
*xinfo
, xmlNodePtr croot
, tnode_t
*troot
)
1841 xmlNodePtr curr
, def_set
= NULL
;
1842 tf_rdata_t
*rr
, *pr
, *rdp
;
1847 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
, "topo_xml_walk\n");
1850 * First iterate through all the XML nodes at this level to look for
1853 for (curr
= croot
->xmlChildrenNode
; curr
!= NULL
; curr
= curr
->next
) {
1854 if (curr
->name
== NULL
) {
1855 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
,
1856 "topo_xml_walk: Ignoring nameless xmlnode\n");
1859 if (xmlStrcmp(curr
->name
, (xmlChar
*)Set
) == 0) {
1863 set
= xmlGetProp(curr
, (xmlChar
*)Setlist
);
1865 if (mp
->tm_hdl
->th_product
)
1866 key
= mp
->tm_hdl
->th_product
;
1868 key
= mp
->tm_hdl
->th_platform
;
1871 * If it's the default set then we'll store
1872 * a pointer to it so that if none of the other
1873 * sets apply to our product we can fall
1876 if (strcmp((char *)set
, "default") == 0)
1878 else if (set_contains(mp
, key
, (char *)set
)) {
1880 if ((rdp
= topo_xml_walk(mp
, xinfo
, curr
,
1882 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
,
1883 "topo_xml_walk: failed1\n");
1898 * If we haven't found a set that contains our product AND a default set
1899 * exists, then we'll process it.
1901 if (!joined_set
&& def_set
) {
1902 if ((rdp
= topo_xml_walk(mp
, xinfo
, def_set
, troot
)) == NULL
) {
1903 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
,
1904 "topo_xml_walk: failed2\n");
1915 * Now we're interested in children xmlNodes of croot tagged
1916 * as 'ranges'. These define what topology nodes may exist, and need
1919 for (curr
= croot
->xmlChildrenNode
; curr
!= NULL
; curr
= curr
->next
) {
1920 if (curr
->name
== NULL
) {
1921 topo_dprintf(mp
->tm_hdl
, TOPO_DBG_XML
,
1922 "topo_xml_walk: Ignoring nameless xmlnode\n");
1925 if (xmlStrcmp(curr
->name
, (xmlChar
*)Range
) != 0)
1927 if ((rdp
= tf_rdata_new(mp
, xinfo
, curr
, troot
)) == NULL
) {
1929 * Range processing error, continue walk
1946 * Convert parsed xml topology description into topology nodes
1949 topo_xml_enum(topo_mod_t
*tmp
, tf_info_t
*xinfo
, tnode_t
*troot
)
1953 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_XML
, "topo_xml_enum\n");
1955 if ((xroot
= xmlDocGetRootElement(xinfo
->tf_xdoc
)) == NULL
) {
1956 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_ERR
,
1957 "Couldn't get root xmlNode.\n");
1960 if ((xinfo
->tf_rd
= topo_xml_walk(tmp
, xinfo
, xroot
, troot
)) == NULL
) {
1961 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_ERR
,
1962 "error within .xml topology: %s\n",
1963 topo_strerror(topo_mod_errno(tmp
)));
1970 * Load an XML tree from filename and read it into a DOM parse tree.
1973 txml_file_parse(topo_mod_t
*tmp
,
1974 int fd
, const char *filenm
, const char *escheme
)
1976 xmlValidCtxtPtr vcp
;
1979 xmlDtdPtr dtd
= NULL
;
1980 xmlChar
*scheme
= NULL
;
1981 char *dtdpath
= NULL
;
1984 int e
, validate
= 0;
1986 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_XML
,
1987 "txml_file_parse(filenm=%s, escheme=%s)\n", filenm
, escheme
);
1990 * Since topologies can XInclude other topologies, and libxml2
1991 * doesn't do DTD-based validation with XInclude, by default
1992 * we don't validate topology files. One can force
1993 * validation, though, by creating a TOPOXML_VALIDATE
1994 * environment variable and creating a TOPO_DTD environment
1995 * variable with the path to the DTD against which to validate.
1997 if (getenv("TOPOXML_VALIDATE") != NULL
) {
1998 dtdpath
= getenv("TOPO_DTD");
1999 if (dtdpath
!= NULL
)
2000 xmlLoadExtDtdDefaultValue
= 0;
2005 * Splat warnings and errors related to parsing the topology
2006 * file if the TOPOXML_PERROR environment variable exists.
2008 if (getenv("TOPOXML_PERROR") == NULL
)
2009 readflags
= XML_PARSE_NOERROR
| XML_PARSE_NOWARNING
;
2011 if ((document
= xmlReadFd(fd
, filenm
, NULL
, readflags
)) == NULL
) {
2012 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_ERR
,
2013 "txml_file_parse: couldn't parse document.\n");
2018 * Verify that this is a document type we understand.
2020 if ((dtd
= xmlGetIntSubset(document
)) == NULL
) {
2021 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_ERR
,
2022 "document has no DTD.\n");
2023 xmlFreeDoc(document
);
2027 if (strcmp((const char *)dtd
->SystemID
, TOPO_DTD_PATH
) != 0) {
2028 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_ERR
,
2029 "document DTD unknown; bad topology file\n");
2030 xmlFreeDoc(document
);
2034 if ((cursor
= xmlDocGetRootElement(document
)) == NULL
) {
2035 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_ERR
, "document is empty.\n");
2036 xmlFreeDoc(document
);
2041 * Make sure we're looking at a topology description in the
2044 if (xmlStrcmp(cursor
->name
, (xmlChar
*)Topology
) != 0) {
2045 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_ERR
,
2046 "document is not a topology description.\n");
2047 xmlFreeDoc(document
);
2050 if ((scheme
= xmlGetProp(cursor
, (xmlChar
*)Scheme
)) == NULL
) {
2051 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_ERR
,
2052 "topology lacks a scheme.\n");
2053 (void) topo_mod_seterrno(tmp
, ETOPO_PRSR_NOATTR
);
2054 xmlFreeDoc(document
);
2057 if (xmlStrcmp(scheme
, (xmlChar
*)escheme
) != 0) {
2058 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_ERR
,
2059 "topology in unrecognized scheme, %s, expecting %s\n",
2061 (void) topo_mod_seterrno(tmp
, ETOPO_PRSR_BADSCH
);
2063 xmlFreeDoc(document
);
2067 if (dtdpath
!= NULL
) {
2068 dtd
= xmlParseDTD(NULL
, (xmlChar
*)dtdpath
);
2070 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_ERR
,
2071 "Could not parse DTD \"%s\".\n",
2074 xmlFreeDoc(document
);
2078 if (document
->extSubset
!= NULL
)
2079 xmlFreeDtd(document
->extSubset
);
2081 document
->extSubset
= dtd
;
2084 if (xmlXIncludeProcessFlags(document
, XML_PARSE_XINCLUDE
) == -1) {
2086 xmlFreeDoc(document
);
2087 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_ERR
,
2088 "couldn't handle XInclude statements in document\n");
2093 if ((vcp
= xmlNewValidCtxt()) == NULL
) {
2095 xmlFreeDoc(document
);
2098 vcp
->warning
= xmlParserValidityWarning
;
2099 vcp
->error
= xmlParserValidityError
;
2101 e
= xmlValidateDocument(vcp
, document
);
2103 xmlFreeValidCtxt(vcp
);
2106 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_ERR
,
2107 "Document is not valid.\n");
2110 if ((r
= tf_info_new(tmp
, document
, scheme
)) == NULL
) {
2112 xmlFreeDoc(document
);
2122 topo_xml_read(topo_mod_t
*tmp
, const char *path
, const char *escheme
)
2127 if ((fd
= open(path
, O_RDONLY
)) < 0) {
2128 topo_dprintf(tmp
->tm_hdl
, TOPO_DBG_ERR
,
2129 "failed to open %s for reading\n", path
);
2132 tip
= txml_file_parse(tmp
, fd
, path
, escheme
);