1 /* 2 * CDDL HEADER START 3 * 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. 7 * 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. 12 * 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] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <libxml/parser.h> 28 #include <libxml/xinclude.h> 29 #include <sys/fm/protocol.h> 30 #include <assert.h> 31 #include <string.h> 32 #include <strings.h> 33 #include <ctype.h> 34 #include <errno.h> 35 #include <limits.h> 36 #include <fm/libtopo.h> 37 #include <unistd.h> 38 #include <sys/stat.h> 39 #include <fcntl.h> 40 #include <topo_file.h> 41 #include <topo_mod.h> 42 #include <topo_subr.h> 43 #include <topo_alloc.h> 44 #include <topo_parse.h> 45 #include <topo_error.h> 46 47 static tf_rdata_t *topo_xml_walk(topo_mod_t *, tf_info_t *, xmlNodePtr, 48 tnode_t *); 49 static tf_edata_t *enum_attributes_process(topo_mod_t *, xmlNodePtr); 50 static int enum_run(topo_mod_t *, tf_rdata_t *); 51 static int fac_enum_run(topo_mod_t *, tnode_t *, const char *); 52 static int fac_process(topo_mod_t *, xmlNodePtr, tf_rdata_t *, tnode_t *); 53 static int fac_enum_process(topo_mod_t *, xmlNodePtr, tnode_t *); 54 static int decorate_nodes(topo_mod_t *, tf_rdata_t *, xmlNodePtr, tnode_t *, 55 tf_pad_t **); 56 57 58 int 59 xmlattr_to_stab(topo_mod_t *mp, xmlNodePtr n, const char *stabname, 60 topo_stability_t *rs) 61 { 62 xmlChar *str; 63 int rv = 0; 64 65 if (n == NULL) { 66 /* If there is no Stability defined, we default to private */ 67 *rs = TOPO_STABILITY_PRIVATE; 68 return (0); 69 } 70 if ((str = xmlGetProp(n, (xmlChar *)stabname)) == NULL) { 71 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 72 "attribute to stability:\n"); 73 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR)); 74 } 75 76 if (xmlStrcmp(str, (xmlChar *)Internal) == 0) { 77 *rs = TOPO_STABILITY_INTERNAL; 78 } else if (xmlStrcmp(str, (xmlChar *)Private) == 0) { 79 *rs = TOPO_STABILITY_PRIVATE; 80 } else if (xmlStrcmp(str, (xmlChar *)Obsolete) == 0) { 81 *rs = TOPO_STABILITY_OBSOLETE; 82 } else if (xmlStrcmp(str, (xmlChar *)External) == 0) { 83 *rs = TOPO_STABILITY_EXTERNAL; 84 } else if (xmlStrcmp(str, (xmlChar *)Unstable) == 0) { 85 *rs = TOPO_STABILITY_UNSTABLE; 86 } else if (xmlStrcmp(str, (xmlChar *)Evolving) == 0) { 87 *rs = TOPO_STABILITY_EVOLVING; 88 } else if (xmlStrcmp(str, (xmlChar *)Stable) == 0) { 89 *rs = TOPO_STABILITY_STABLE; 90 } else if (xmlStrcmp(str, (xmlChar *)Standard) == 0) { 91 *rs = TOPO_STABILITY_STANDARD; 92 } else { 93 xmlFree(str); 94 return (topo_mod_seterrno(mp, ETOPO_PRSR_BADSTAB)); 95 } 96 xmlFree(str); 97 return (rv); 98 } 99 100 int 101 xmlattr_to_int(topo_mod_t *mp, 102 xmlNodePtr n, const char *propname, uint64_t *value) 103 { 104 xmlChar *str; 105 xmlChar *estr; 106 107 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "xmlattr_to_int(propname=%s)\n", 108 propname); 109 if ((str = xmlGetProp(n, (xmlChar *)propname)) == NULL) 110 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR)); 111 *value = strtoull((char *)str, (char **)&estr, 10); 112 if (estr == str) { 113 /* no conversion was done */ 114 xmlFree(str); 115 return (topo_mod_seterrno(mp, ETOPO_PRSR_BADNUM)); 116 } 117 xmlFree(str); 118 return (0); 119 } 120 121 static int 122 xmlattr_to_fmri(topo_mod_t *mp, 123 xmlNodePtr xn, const char *propname, nvlist_t **rnvl) 124 { 125 xmlChar *str; 126 127 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "xmlattr_to_fmri(propname=%s)\n", 128 propname); 129 if ((str = xmlGetProp(xn, (xmlChar *)propname)) == NULL) 130 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR)); 131 if (topo_mod_str2nvl(mp, (const char *)str, rnvl) < 0) { 132 xmlFree(str); 133 return (-1); 134 } 135 xmlFree(str); 136 return (0); 137 } 138 139 static topo_type_t 140 xmlattr_to_type(topo_mod_t *mp, xmlNodePtr xn, xmlChar *attr) 141 { 142 topo_type_t rv; 143 xmlChar *str; 144 if ((str = xmlGetProp(xn, (xmlChar *)attr)) == NULL) { 145 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "%s attribute missing", 146 attr); 147 (void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR); 148 return (TOPO_TYPE_INVALID); 149 } 150 if (xmlStrcmp(str, (xmlChar *)Int32) == 0) { 151 rv = TOPO_TYPE_INT32; 152 } else if (xmlStrcmp(str, (xmlChar *)UInt32) == 0) { 153 rv = TOPO_TYPE_UINT32; 154 } else if (xmlStrcmp(str, (xmlChar *)Int64) == 0) { 155 rv = TOPO_TYPE_INT64; 156 } else if (xmlStrcmp(str, (xmlChar *)UInt64) == 0) { 157 rv = TOPO_TYPE_UINT64; 158 } else if (xmlStrcmp(str, (xmlChar *)FMRI) == 0) { 159 rv = TOPO_TYPE_FMRI; 160 } else if (xmlStrcmp(str, (xmlChar *)String) == 0) { 161 rv = TOPO_TYPE_STRING; 162 } else { 163 xmlFree(str); 164 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 165 "Unrecognized type attribute value.\n"); 166 (void) topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE); 167 return (TOPO_TYPE_INVALID); 168 } 169 xmlFree(str); 170 return (rv); 171 } 172 173 static int 174 xlate_common(topo_mod_t *mp, xmlNodePtr xn, topo_type_t ptype, nvlist_t *nvl, 175 const char *name) 176 { 177 int rv; 178 uint64_t ui; 179 nvlist_t *fmri; 180 xmlChar *str; 181 182 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "xlate_common (name=%s)\n", 183 name); 184 switch (ptype) { 185 case TOPO_TYPE_INT32: 186 if (xmlattr_to_int(mp, xn, Value, &ui) < 0) 187 return (-1); 188 rv = nvlist_add_int32(nvl, name, (int32_t)ui); 189 break; 190 case TOPO_TYPE_UINT32: 191 if (xmlattr_to_int(mp, xn, Value, &ui) < 0) 192 return (-1); 193 rv = nvlist_add_uint32(nvl, name, (uint32_t)ui); 194 break; 195 case TOPO_TYPE_INT64: 196 if (xmlattr_to_int(mp, xn, Value, &ui) < 0) 197 return (-1); 198 rv = nvlist_add_int64(nvl, name, (int64_t)ui); 199 break; 200 case TOPO_TYPE_UINT64: 201 if (xmlattr_to_int(mp, xn, Value, &ui) < 0) 202 return (-1); 203 rv = nvlist_add_uint64(nvl, name, ui); 204 break; 205 case TOPO_TYPE_FMRI: 206 if (xmlattr_to_fmri(mp, xn, Value, &fmri) < 0) 207 return (-1); 208 rv = nvlist_add_nvlist(nvl, name, fmri); 209 nvlist_free(fmri); 210 break; 211 case TOPO_TYPE_STRING: 212 if ((str = xmlGetProp(xn, (xmlChar *)Value)) == NULL) 213 return (-1); 214 rv = nvlist_add_string(nvl, name, (char *)str); 215 xmlFree(str); 216 break; 217 default: 218 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 219 "Unrecognized type attribute.\n"); 220 return (topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE)); 221 } 222 if (rv != 0) { 223 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 224 "Nvlist construction failed.\n"); 225 return (topo_mod_seterrno(mp, ETOPO_NOMEM)); 226 } else 227 return (0); 228 } 229 230 static int 231 xmlprop_xlate(topo_mod_t *mp, xmlNodePtr xn, nvlist_t *nvl) 232 { 233 topo_type_t ptype; 234 xmlChar *str; 235 236 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "xmlprop_xlate\n"); 237 if ((str = xmlGetProp(xn, (xmlChar *)Immutable)) != NULL) { 238 if (xmlStrcmp(str, (xmlChar *)False) == 0) 239 (void) nvlist_add_boolean_value(nvl, INV_IMMUTE, 240 B_FALSE); 241 else 242 (void) nvlist_add_boolean_value(nvl, INV_IMMUTE, 243 B_TRUE); 244 xmlFree(str); 245 } else { 246 (void) nvlist_add_boolean_value(nvl, INV_IMMUTE, B_TRUE); 247 } 248 249 if ((ptype = xmlattr_to_type(mp, xn, (xmlChar *)Type)) 250 == TOPO_TYPE_INVALID) 251 return (-1); 252 253 if (nvlist_add_int32(nvl, INV_PVALTYPE, ptype) != 0) 254 return (-1); 255 256 return (xlate_common(mp, xn, ptype, nvl, INV_PVAL)); 257 } 258 259 static int 260 dependent_create(topo_mod_t *mp, 261 tf_info_t *xinfo, tf_pad_t *pad, xmlNodePtr dxn, tnode_t *ptn) 262 { 263 tf_rdata_t *rp, *pp, *np; 264 xmlChar *grptype; 265 int sibs = 0; 266 267 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "dependent_create\n"); 268 if ((grptype = xmlGetProp(dxn, (xmlChar *)Grouping)) == NULL) { 269 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 270 "Dependents missing grouping attribute"); 271 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR)); 272 } 273 274 pp = NULL; 275 if (xmlStrcmp(grptype, (xmlChar *)Siblings) == 0) { 276 rp = pad->tpad_sibs; 277 sibs++; 278 } else if (xmlStrcmp(grptype, (xmlChar *)Children) == 0) { 279 rp = pad->tpad_child; 280 } else { 281 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 282 "Dependents have bogus grouping attribute"); 283 xmlFree(grptype); 284 return (topo_mod_seterrno(mp, ETOPO_PRSR_BADGRP)); 285 } 286 xmlFree(grptype); 287 /* Add processed dependents to the tail of the list */ 288 while (rp != NULL) { 289 pp = rp; 290 rp = rp->rd_next; 291 } 292 if ((np = topo_xml_walk(mp, xinfo, dxn, ptn)) == NULL) { 293 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 294 "error within dependent .xml topology: " 295 "%s\n", topo_strerror(topo_mod_errno(mp))); 296 return (-1); 297 } 298 if (pp != NULL) 299 pp->rd_next = np; 300 else if (sibs == 1) 301 pad->tpad_sibs = np; 302 else 303 pad->tpad_child = np; 304 return (0); 305 } 306 307 static int 308 dependents_create(topo_mod_t *mp, 309 tf_info_t *xinfo, tf_pad_t *pad, xmlNodePtr pxn, tnode_t *ptn) 310 { 311 xmlNodePtr cn; 312 313 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "dependents_create\n"); 314 for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) { 315 if (xmlStrcmp(cn->name, (xmlChar *)Dependents) == 0) { 316 if (dependent_create(mp, xinfo, pad, cn, ptn) < 0) 317 return (-1); 318 } 319 } 320 return (0); 321 } 322 323 static int 324 prop_create(topo_mod_t *mp, 325 nvlist_t *pfmri, tnode_t *ptn, const char *gnm, const char *pnm, 326 topo_type_t ptype, int flag) 327 { 328 nvlist_t *fmri; 329 uint32_t ui32; 330 uint64_t ui64; 331 int32_t i32; 332 int64_t i64; 333 char *str; 334 int err, e; 335 336 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "prop_create(pgrp = %s, " 337 "prop = %s)\n", gnm, pnm); 338 switch (ptype) { 339 case TOPO_TYPE_INT32: 340 e = nvlist_lookup_int32(pfmri, INV_PVAL, &i32); 341 break; 342 case TOPO_TYPE_UINT32: 343 e = nvlist_lookup_uint32(pfmri, INV_PVAL, &ui32); 344 break; 345 case TOPO_TYPE_INT64: 346 e = nvlist_lookup_int64(pfmri, INV_PVAL, &i64); 347 break; 348 case TOPO_TYPE_UINT64: 349 e = nvlist_lookup_uint64(pfmri, INV_PVAL, &ui64); 350 break; 351 case TOPO_TYPE_FMRI: 352 e = nvlist_lookup_nvlist(pfmri, INV_PVAL, &fmri); 353 break; 354 case TOPO_TYPE_STRING: 355 e = nvlist_lookup_string(pfmri, INV_PVAL, &str); 356 break; 357 default: 358 e = ETOPO_PRSR_BADTYPE; 359 } 360 if (e != 0) { 361 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 362 "prop_create: prop value lookup failed.\n"); 363 return (topo_mod_seterrno(mp, e)); 364 } 365 switch (ptype) { 366 case TOPO_TYPE_INT32: 367 e = topo_prop_set_int32(ptn, gnm, pnm, flag, i32, &err); 368 break; 369 case TOPO_TYPE_UINT32: 370 e = topo_prop_set_uint32(ptn, gnm, pnm, flag, ui32, &err); 371 break; 372 case TOPO_TYPE_INT64: 373 e = topo_prop_set_int64(ptn, gnm, pnm, flag, i64, &err); 374 break; 375 case TOPO_TYPE_UINT64: 376 e = topo_prop_set_uint64(ptn, gnm, pnm, flag, ui64, &err); 377 break; 378 case TOPO_TYPE_FMRI: 379 e = topo_prop_set_fmri(ptn, gnm, pnm, flag, fmri, &err); 380 break; 381 case TOPO_TYPE_STRING: 382 e = topo_prop_set_string(ptn, gnm, pnm, flag, str, &err); 383 break; 384 } 385 if (e != 0 && err != ETOPO_PROP_DEFD) { 386 387 /* 388 * Some properties may have already been set 389 * in topo_node_bind() or topo_prop_inherit if we are 390 * enumerating from a static .xml file 391 */ 392 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "prop set " 393 "failed %s/%s:%s\n", gnm, pnm, topo_strerror(err)); 394 return (topo_mod_seterrno(mp, err)); 395 } 396 return (0); 397 } 398 399 static int 400 props_create(topo_mod_t *mp, 401 tnode_t *ptn, const char *gnm, nvlist_t **props, int nprops) 402 { 403 topo_type_t ptype; 404 boolean_t pim; 405 char *pnm; 406 int32_t i32; 407 int flag; 408 int pn; 409 int e; 410 411 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "props_create(pgrp = %s)\n", 412 gnm); 413 for (pn = 0; pn < nprops; pn++) { 414 e = nvlist_lookup_string(props[pn], INV_PNAME, &pnm); 415 if (e != 0) { 416 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 417 "props create lookup (%s) failure: %s", 418 INV_PNAME, strerror(e)); 419 return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP)); 420 } 421 e = nvlist_lookup_boolean_value(props[pn], INV_IMMUTE, &pim); 422 if (e != 0) { 423 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 424 "props create lookup (%s) failure: %s", 425 INV_IMMUTE, strerror(e)); 426 return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP)); 427 } 428 flag = (pim == B_TRUE) ? 429 TOPO_PROP_IMMUTABLE : TOPO_PROP_MUTABLE; 430 431 e = nvlist_lookup_int32(props[pn], INV_PVALTYPE, &i32); 432 if (e != 0) { 433 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 434 "props create lookup (%s) failure: %s", 435 INV_PVALTYPE, strerror(e)); 436 return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP)); 437 } 438 ptype = (topo_type_t)i32; 439 if (prop_create(mp, props[pn], ptn, gnm, pnm, ptype, flag) < 0) 440 return (-1); 441 } 442 return (0); 443 } 444 445 static int 446 pgroups_create(topo_mod_t *mp, tf_pad_t *pad, tnode_t *ptn) 447 { 448 topo_pgroup_info_t pgi; 449 nvlist_t **props; 450 char *gnm; 451 char *nmstab, *dstab; 452 uint32_t rnprops, nprops; 453 uint32_t gv; 454 int pg; 455 int e; 456 457 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroups_create: %s=%d\n", 458 topo_node_name(ptn), topo_node_instance(ptn)); 459 for (pg = 0; pg < pad->tpad_pgcnt; pg++) { 460 e = nvlist_lookup_string(pad->tpad_pgs[pg], 461 INV_PGRP_NAME, &gnm); 462 if (e != 0) { 463 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 464 "pad lookup (%s) failed (%s).\n", 465 INV_PGRP_NAME, strerror(errno)); 466 return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP)); 467 } 468 e = nvlist_lookup_string(pad->tpad_pgs[pg], 469 INV_PGRP_NMSTAB, &nmstab); 470 if (e != 0) { 471 if (e != ENOENT) { 472 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 473 "pad lookup (%s) " 474 "failed.\n", INV_PGRP_NMSTAB); 475 return (topo_mod_seterrno(mp, 476 ETOPO_PRSR_NVPROP)); 477 } else { 478 nmstab = TOPO_STABSTR_PRIVATE; 479 } 480 } 481 e = nvlist_lookup_string(pad->tpad_pgs[pg], 482 INV_PGRP_DSTAB, &dstab); 483 if (e != 0) { 484 if (e != ENOENT) { 485 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 486 "pad lookup (%s) failed.\n", 487 INV_PGRP_DSTAB); 488 return (topo_mod_seterrno(mp, 489 ETOPO_PRSR_NVPROP)); 490 } else { 491 dstab = TOPO_STABSTR_PRIVATE; 492 } 493 } 494 e = nvlist_lookup_uint32(pad->tpad_pgs[pg], 495 INV_PGRP_VER, &gv); 496 if (e != 0) { 497 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 498 "pad lookup (%s) failed.\n", 499 INV_PGRP_VER); 500 return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP)); 501 } 502 pgi.tpi_name = gnm; 503 pgi.tpi_namestab = topo_name2stability(nmstab); 504 pgi.tpi_datastab = topo_name2stability(dstab); 505 pgi.tpi_version = gv; 506 if (topo_pgroup_create(ptn, &pgi, &e) != 0) { 507 if (e != ETOPO_PROP_DEFD) { 508 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 509 "pgroups create failure: %s\n", 510 topo_strerror(e)); 511 return (-1); 512 } 513 } 514 e = nvlist_lookup_uint32(pad->tpad_pgs[pg], 515 INV_PGRP_NPROP, &rnprops); 516 /* 517 * The number of properties could be zero if the property 518 * group only contains propmethod declarations 519 */ 520 if (rnprops > 0) { 521 e |= nvlist_lookup_nvlist_array(pad->tpad_pgs[pg], 522 INV_PGRP_ALLPROPS, &props, &nprops); 523 if (rnprops != nprops) { 524 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 525 "recorded number of props %d does not " 526 "match number of props recorded %d.\n", 527 rnprops, nprops); 528 } 529 if (props_create(mp, ptn, gnm, props, nprops) < 0) 530 return (-1); 531 } 532 } 533 return (0); 534 } 535 536 static nvlist_t * 537 pval_record(topo_mod_t *mp, xmlNodePtr xn) 538 { 539 nvlist_t *pnvl = NULL; 540 xmlChar *pname; 541 542 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pval_record\n"); 543 if ((pname = xmlGetProp(xn, (xmlChar *)Name)) == NULL) { 544 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 545 "propval lacks a name\n"); 546 (void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR); 547 return (NULL); 548 } 549 if (topo_mod_nvalloc(mp, &pnvl, NV_UNIQUE_NAME) < 0) { 550 xmlFree(pname); 551 return (NULL); 552 } 553 if (nvlist_add_string(pnvl, INV_PNAME, (char *)pname) < 0) { 554 xmlFree(pname); 555 nvlist_free(pnvl); 556 return (NULL); 557 } 558 xmlFree(pname); 559 /* FMXXX stability of the property name */ 560 561 if (xmlprop_xlate(mp, xn, pnvl) < 0) { 562 nvlist_free(pnvl); 563 return (NULL); 564 } 565 return (pnvl); 566 } 567 568 569 struct propmeth_data { 570 const char *pg_name; 571 const char *prop_name; 572 topo_type_t prop_type; 573 const char *meth_name; 574 topo_version_t meth_ver; 575 nvlist_t *arg_nvl; 576 }; 577 578 static int 579 register_method(topo_mod_t *mp, tnode_t *ptn, struct propmeth_data *meth) 580 { 581 int err; 582 583 if (topo_prop_method_version_register(ptn, meth->pg_name, 584 meth->prop_name, meth->prop_type, meth->meth_name, meth->meth_ver, 585 meth->arg_nvl, &err) != 0) { 586 587 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "failed to register " 588 "propmethod %s for property \"%s\" in propgrp %s on node " 589 "%s=%d (%s)\n", 590 meth->meth_name, meth->prop_name, meth->pg_name, 591 topo_node_name(ptn), topo_node_instance(ptn), 592 topo_strerror(err)); 593 return (-1); 594 } 595 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 596 "registered method %s on %s=%d\n", 597 meth->meth_name, topo_node_name(ptn), topo_node_instance(ptn)); 598 599 return (0); 600 } 601 602 static int 603 pmeth_record(topo_mod_t *mp, const char *pg_name, xmlNodePtr xn, tnode_t *tn, 604 const char *rname, const char *ppgrp_name) 605 { 606 nvlist_t *arg_nvl = NULL; 607 xmlNodePtr cn; 608 xmlChar *meth_name = NULL, *prop_name = NULL; 609 xmlChar *arg_name = NULL; 610 uint64_t meth_ver, is_mutable = 0; 611 topo_type_t prop_type; 612 struct propmeth_data meth; 613 int ret = 0, err; 614 topo_type_t ptype; 615 tnode_t *tmp; 616 617 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pmeth_record: %s=%d " 618 "(pgrp=%s)\n", topo_node_name(tn), topo_node_instance(tn), pg_name); 619 620 /* 621 * Get propmethod attribute values 622 */ 623 if ((meth_name = xmlGetProp(xn, (xmlChar *)Name)) == NULL) { 624 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 625 "propmethod element lacks a name attribute\n"); 626 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR)); 627 } 628 if (xmlattr_to_int(mp, xn, Version, &meth_ver) < 0) { 629 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 630 "propmethod element lacks version attribute\n"); 631 ret = topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR); 632 goto pmr_done; 633 } 634 /* 635 * The "mutable" attribute is optional. If not specified we default to 636 * false (0) 637 */ 638 (void) xmlattr_to_int(mp, xn, Mutable, &is_mutable); 639 640 if ((prop_name = xmlGetProp(xn, (xmlChar *)Propname)) == NULL) { 641 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 642 "propmethod element lacks propname attribute\n"); 643 ret = topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR); 644 goto pmr_done; 645 } 646 if ((prop_type = xmlattr_to_type(mp, xn, (xmlChar *)Proptype)) 647 == TOPO_TYPE_INVALID) { 648 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 649 "error decoding proptype attribute\n"); 650 ret = topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR); 651 goto pmr_done; 652 } 653 654 /* 655 * Allocate method argument nvlist 656 */ 657 if (topo_mod_nvalloc(mp, &arg_nvl, NV_UNIQUE_NAME) < 0) { 658 ret = topo_mod_seterrno(mp, ETOPO_NOMEM); 659 goto pmr_done; 660 } 661 662 /* 663 * Iterate through the argval nodes and build the argval nvlist 664 */ 665 for (cn = xn->xmlChildrenNode; cn != NULL; cn = cn->next) { 666 if (xmlStrcmp(cn->name, (xmlChar *)Argval) == 0) { 667 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 668 "found argval element\n"); 669 if ((arg_name = xmlGetProp(cn, (xmlChar *)Name)) 670 == NULL) { 671 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 672 "argval element lacks a name attribute\n"); 673 ret = topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR); 674 goto pmr_done; 675 } 676 if ((ptype = xmlattr_to_type(mp, cn, (xmlChar *)Type)) 677 == TOPO_TYPE_INVALID) { 678 ret = topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE); 679 xmlFree(arg_name); 680 break; 681 } 682 if (xlate_common(mp, cn, ptype, arg_nvl, 683 (const char *)arg_name) != 0) { 684 ret = topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE); 685 xmlFree(arg_name); 686 break; 687 } 688 } 689 if (arg_name) { 690 xmlFree(arg_name); 691 arg_name = NULL; 692 } 693 } 694 695 if (ret != 0) 696 goto pmr_done; 697 698 /* 699 * Register the prop method for all of the nodes in our range 700 */ 701 meth.pg_name = (const char *)pg_name; 702 meth.prop_name = (const char *)prop_name; 703 meth.prop_type = prop_type; 704 meth.meth_name = (const char *)meth_name; 705 meth.meth_ver = meth_ver; 706 meth.arg_nvl = arg_nvl; 707 708 /* 709 * If the propgroup element is under a range element, we'll apply 710 * the method to all of the topo nodes at this level with the same 711 * range name. 712 * 713 * Otherwise, if the propgroup element is under a node element 714 * then we'll simply register the method for this node. 715 */ 716 if (strcmp(ppgrp_name, Range) == 0) { 717 for (tmp = tn; tmp != NULL; tmp = topo_child_next(NULL, tmp)) { 718 if (strcmp(rname, topo_node_name(tmp)) == 0) { 719 if (register_method(mp, tmp, &meth) != 0) { 720 ret = topo_mod_seterrno(mp, 721 ETOPO_PRSR_REGMETH); 722 goto pmr_done; 723 } 724 if (is_mutable) { 725 if (topo_prop_setmutable(tmp, 726 meth.pg_name, meth.prop_name, &err) 727 != 0) { 728 ret = topo_mod_seterrno(mp, 729 ETOPO_PRSR_REGMETH); 730 goto pmr_done; 731 } 732 } 733 } 734 } 735 } else { 736 if (register_method(mp, tn, &meth) != 0) { 737 ret = topo_mod_seterrno(mp, ETOPO_PRSR_REGMETH); 738 goto pmr_done; 739 } 740 if (is_mutable) { 741 if (topo_prop_setmutable(tn, meth.pg_name, 742 meth.prop_name, &err) != 0) { 743 ret = topo_mod_seterrno(mp, 744 ETOPO_PRSR_REGMETH); 745 goto pmr_done; 746 } 747 } 748 } 749 750 pmr_done: 751 if (meth_name) 752 xmlFree(meth_name); 753 if (prop_name) 754 xmlFree(prop_name); 755 if (arg_nvl) 756 nvlist_free(arg_nvl); 757 return (ret); 758 } 759 760 761 static int 762 pgroup_record(topo_mod_t *mp, xmlNodePtr pxn, tnode_t *tn, const char *rname, 763 tf_pad_t *rpad, int pi, const char *ppgrp_name) 764 { 765 topo_stability_t nmstab, dstab; 766 uint64_t ver; 767 xmlNodePtr cn; 768 xmlChar *name; 769 nvlist_t **apl = NULL; 770 nvlist_t *pgnvl = NULL; 771 int pcnt = 0; 772 int ai = 0; 773 int e; 774 775 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroup_record\n"); 776 if ((name = xmlGetProp(pxn, (xmlChar *)Name)) == NULL) { 777 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 778 "propgroup lacks a name\n"); 779 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR)); 780 } 781 if (xmlattr_to_int(mp, pxn, Version, &ver) < 0) { 782 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 783 "propgroup lacks a version\n"); 784 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR)); 785 } 786 if (xmlattr_to_stab(mp, pxn, Namestab, &nmstab) < 0) { 787 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 788 "propgroup lacks name-stability\n"); 789 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR)); 790 } 791 if (xmlattr_to_stab(mp, pxn, Datastab, &dstab) < 0) { 792 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 793 "propgroup lacks data-stability\n"); 794 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR)); 795 } 796 797 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroup %s\n", (char *)name); 798 for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) { 799 if (xmlStrcmp(cn->name, (xmlChar *)Propval) == 0) 800 pcnt++; 801 } 802 803 if (topo_mod_nvalloc(mp, &pgnvl, NV_UNIQUE_NAME) < 0) { 804 xmlFree(name); 805 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 806 "failed to allocate propgroup nvlist\n"); 807 return (topo_mod_seterrno(mp, ETOPO_NOMEM)); 808 } 809 810 e = nvlist_add_string(pgnvl, INV_PGRP_NAME, (char *)name); 811 e |= nvlist_add_uint32(pgnvl, INV_PGRP_NMSTAB, nmstab); 812 e |= nvlist_add_uint32(pgnvl, INV_PGRP_DSTAB, dstab); 813 e |= nvlist_add_uint32(pgnvl, INV_PGRP_VER, ver); 814 e |= nvlist_add_uint32(pgnvl, INV_PGRP_NPROP, pcnt); 815 if (pcnt > 0) 816 if (e != 0 || 817 (apl = topo_mod_zalloc(mp, pcnt * sizeof (nvlist_t *))) 818 == NULL) { 819 xmlFree(name); 820 nvlist_free(pgnvl); 821 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 822 "failed to allocate nvlist array for properties" 823 "(e=%d)\n", e); 824 return (topo_mod_seterrno(mp, ETOPO_NOMEM)); 825 } 826 for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) { 827 if (xmlStrcmp(cn->name, (xmlChar *)Propval) == 0) { 828 if (ai < pcnt) { 829 if ((apl[ai] = pval_record(mp, cn)) == NULL) 830 break; 831 } 832 ai++; 833 } else if (xmlStrcmp(cn->name, (xmlChar *)Prop_meth) == 0) { 834 if (pmeth_record(mp, (const char *)name, cn, tn, rname, 835 ppgrp_name) < 0) 836 break; 837 } 838 } 839 xmlFree(name); 840 if (pcnt > 0) { 841 e |= (ai != pcnt); 842 e |= nvlist_add_nvlist_array(pgnvl, INV_PGRP_ALLPROPS, apl, 843 pcnt); 844 for (ai = 0; ai < pcnt; ai++) 845 if (apl[ai] != NULL) 846 nvlist_free(apl[ai]); 847 topo_mod_free(mp, apl, pcnt * sizeof (nvlist_t *)); 848 if (e != 0) { 849 nvlist_free(pgnvl); 850 return (-1); 851 } 852 } 853 rpad->tpad_pgs[pi] = pgnvl; 854 return (0); 855 } 856 857 static int 858 pgroups_record(topo_mod_t *mp, xmlNodePtr pxn, tnode_t *tn, const char *rname, 859 tf_pad_t *rpad, const char *ppgrp) 860 { 861 xmlNodePtr cn; 862 int pi = 0; 863 864 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroups_record: pxn->name=%s\n", 865 pxn->name); 866 for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) { 867 if (xmlStrcmp(cn->name, (xmlChar *)Propgrp) == 0) { 868 if (pgroup_record(mp, cn, tn, rname, rpad, pi++, ppgrp) 869 < 0) 870 return (-1); 871 } 872 } 873 return (0); 874 } 875 876 /* 877 * psn: pointer to a "set" XML node 878 * key: string to search the set for 879 * 880 * returns: 1, if the set contains key 881 * 0, otherwise 882 */ 883 static int 884 set_contains(topo_mod_t *mp, char *key, char *set) 885 { 886 char *prod; 887 int rv = 0; 888 889 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "set_contains(key = %s, " 890 "setlist = %s)\n", key, set); 891 892 prod = strtok((char *)set, "|"); 893 if (prod && (strcmp(key, prod) == 0)) 894 return (1); 895 896 while ((prod = strtok(NULL, "|"))) 897 if (strcmp(key, prod) == 0) 898 return (1); 899 900 return (rv); 901 } 902 903 904 /* 905 * Process the property group and dependents xmlNode children of 906 * parent xmlNode pxn. 907 */ 908 static int 909 pad_process(topo_mod_t *mp, tf_rdata_t *rd, xmlNodePtr pxn, tnode_t *ptn, 910 tf_pad_t **rpad) 911 { 912 xmlNodePtr cn, gcn, psn, ecn, target; 913 xmlNodePtr def_set = NULL; 914 tnode_t *ct; 915 tf_pad_t *new = *rpad; 916 tf_rdata_t tmp_rd; 917 int pgcnt = 0; 918 int dcnt = 0; 919 int ecnt = 0; 920 int joined_set = 0; 921 xmlChar *set; 922 char *key; 923 924 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 925 "pad_process beneath %s\n", topo_node_name(ptn)); 926 if (new == NULL) { 927 for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) { 928 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 929 "cn->name is %s \n", (char *)cn->name); 930 /* 931 * We're iterating through the XML children looking for 932 * four types of elements: 933 * 1) dependents elements 934 * 2) unconstrained pgroup elements 935 * 3) pgroup elements constrained by set elements 936 * 4) enum-method elements for the case that we want 937 * to post-process a statically defined node 938 */ 939 if (xmlStrcmp(cn->name, (xmlChar *)Dependents) == 0) 940 dcnt++; 941 else if (xmlStrcmp(cn->name, (xmlChar *)Propgrp) == 0) 942 pgcnt++; 943 else if (xmlStrcmp(cn->name, (xmlChar *)Enum_meth) 944 == 0) { 945 ecn = cn; 946 ecnt++; 947 } else if (xmlStrcmp(cn->name, (xmlChar *)Set) == 0) { 948 if (joined_set) 949 continue; 950 set = xmlGetProp(cn, (xmlChar *)Setlist); 951 952 if (mp->tm_hdl->th_product) 953 key = mp->tm_hdl->th_product; 954 else 955 key = mp->tm_hdl->th_platform; 956 957 /* 958 * If it's the default set then we'll store 959 * a pointer to it so that if none of the other 960 * sets apply to our product we can fall 961 * back to this one. 962 */ 963 if (strcmp((char *)set, "default") == 0) 964 def_set = cn; 965 else if (set_contains(mp, key, (char *)set)) { 966 psn = cn; 967 joined_set = 1; 968 for (gcn = cn->xmlChildrenNode; 969 gcn != NULL; gcn = gcn->next) { 970 if (xmlStrcmp(gcn->name, 971 (xmlChar *)Propgrp) == 0) 972 pgcnt++; 973 } 974 } 975 xmlFree(set); 976 } 977 } 978 /* 979 * If we haven't found a set that contains our product AND 980 * a default set exists, then we'll process it. 981 */ 982 if (!joined_set && def_set) { 983 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 984 "Falling back to default set\n"); 985 joined_set = 1; 986 psn = def_set; 987 for (gcn = psn->xmlChildrenNode; gcn != NULL; 988 gcn = gcn->next) { 989 if (xmlStrcmp(gcn->name, (xmlChar *)Propgrp) 990 == 0) 991 pgcnt++; 992 } 993 } 994 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 995 "pad_process: dcnt=%d, pgcnt=%d, ecnt=%d, joined_set=%d\n", 996 dcnt, pgcnt, ecnt, joined_set); 997 /* 998 * If an enum-method element was found, AND we're a child of a 999 * node element, then we invoke the enumerator so that it can do 1000 * post-processing of the node. 1001 */ 1002 if (ecnt && (strcmp((const char *)pxn->name, Node) == 0)) { 1003 if ((tmp_rd.rd_einfo = enum_attributes_process(mp, ecn)) 1004 == NULL) 1005 return (-1); 1006 tmp_rd.rd_mod = mp; 1007 tmp_rd.rd_name = rd->rd_name; 1008 tmp_rd.rd_min = rd->rd_min; 1009 tmp_rd.rd_max = rd->rd_max; 1010 tmp_rd.rd_pn = ptn; 1011 if (enum_run(mp, &tmp_rd) < 0) { 1012 /* 1013 * Note the failure but continue on 1014 */ 1015 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1016 "pad_process: enumeration failed.\n"); 1017 } 1018 tf_edata_free(mp, tmp_rd.rd_einfo); 1019 } 1020 /* 1021 * Here we allocate an element in an intermediate data structure 1022 * which keeps track property groups and dependents of the range 1023 * currently being processed. 1024 * 1025 * This structure is referenced in pgroups_record() to create 1026 * the actual property groups in the topo tree 1027 */ 1028 if ((new = tf_pad_new(mp, pgcnt, dcnt)) == NULL) 1029 return (-1); 1030 1031 if (pgcnt > 0) { 1032 new->tpad_pgs = 1033 topo_mod_zalloc(mp, pgcnt * sizeof (nvlist_t *)); 1034 if (new->tpad_pgs == NULL) { 1035 tf_pad_free(mp, new); 1036 return (-1); 1037 } 1038 } 1039 /* 1040 * If the property groups are contained within a set 1041 * then they will be one level lower in the XML tree. 1042 */ 1043 if (joined_set) 1044 target = psn; 1045 else 1046 target = pxn; 1047 1048 /* 1049 * If there is no "node" element under the "range" 1050 * element, then we need to attach the facility node to 1051 * each node in this range. 1052 * 1053 * Otherwise we only attach it to the current node 1054 */ 1055 if (xmlStrcmp(target->name, (xmlChar *)Range) == 0 || 1056 xmlStrcmp(target->name, (xmlChar *)Set) == 0) { 1057 for (ct = topo_child_first(rd->rd_pn); 1058 ct != NULL; 1059 ct = topo_child_next(rd->rd_pn, ct)) { 1060 1061 if (strcmp(topo_node_name(ct), 1062 rd->rd_name) != 0) 1063 continue; 1064 1065 if (fac_enum_process(mp, target, ct) < 0) 1066 return (-1); 1067 1068 if (fac_process(mp, target, rd, ct) < 0) 1069 return (-1); 1070 } 1071 } else { 1072 if (fac_enum_process(mp, target, ptn) < 0) 1073 return (-1); 1074 if (fac_process(mp, target, rd, ptn) < 0) 1075 return (-1); 1076 } 1077 if (pgcnt > 0 && pgroups_record(mp, target, ptn, rd->rd_name, 1078 new, (const char *)pxn->name) < 0) { 1079 tf_pad_free(mp, new); 1080 return (-1); 1081 } 1082 *rpad = new; 1083 } 1084 1085 if (new->tpad_dcnt > 0) 1086 if (dependents_create(mp, rd->rd_finfo, new, pxn, ptn) < 0) 1087 return (-1); 1088 1089 if (new->tpad_pgcnt > 0) 1090 if (pgroups_create(mp, new, ptn) < 0) 1091 return (-1); 1092 1093 return (0); 1094 } 1095 1096 1097 static int 1098 fac_enum_process(topo_mod_t *mp, xmlNodePtr pn, tnode_t *ptn) 1099 { 1100 xmlNodePtr cn; 1101 xmlChar *fprov = NULL; 1102 int rv = 0; 1103 1104 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1105 "fac_enum_process() called for %s=%d\n", topo_node_name(ptn), 1106 topo_node_instance(ptn)); 1107 1108 for (cn = pn->xmlChildrenNode; cn != NULL; cn = cn->next) { 1109 1110 if (xmlStrcmp(cn->name, (xmlChar *)"fac-enum") != 0) 1111 continue; 1112 1113 if ((fprov = xmlGetProp(cn, (xmlChar *)Provider)) == NULL) 1114 goto fenumdone; 1115 1116 if (xmlStrcmp(fprov, (xmlChar *)"fac_prov_ipmi") != 0) { 1117 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1118 "Invalid provider specified: %s\n", fprov); 1119 goto fenumdone; 1120 } 1121 1122 /* 1123 * Invoke enum entry point in fac provider which will cause the 1124 * facility enumeration node method to be registered. 1125 */ 1126 if (fac_enum_run(mp, ptn, (const char *)fprov) != 0) { 1127 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1128 "fac_enum_process: enum entry point failed!\n"); 1129 goto fenumdone; 1130 } 1131 xmlFree(fprov); 1132 } 1133 return (0); 1134 fenumdone: 1135 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "fac-enum processing failed\n"); 1136 1137 if (fprov != NULL) 1138 xmlFree(fprov); 1139 1140 return (rv); 1141 } 1142 1143 1144 static int 1145 fac_process(topo_mod_t *mp, xmlNodePtr pn, tf_rdata_t *rd, tnode_t *ptn) 1146 { 1147 xmlNodePtr cn; 1148 xmlChar *fname = NULL, *ftype = NULL, *provider = NULL; 1149 tnode_t *ntn = NULL; 1150 tf_idata_t *newi; 1151 int err; 1152 topo_pgroup_info_t pgi; 1153 1154 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1155 "fac_process() called\n"); 1156 1157 for (cn = pn->xmlChildrenNode; cn != NULL; cn = cn->next) { 1158 1159 if (xmlStrcmp(cn->name, (xmlChar *)Facility) != 0) 1160 continue; 1161 1162 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1163 "facility processing\n"); 1164 1165 if ((fname = xmlGetProp(cn, (xmlChar *)Name)) == NULL) 1166 goto facdone; 1167 1168 if ((ftype = xmlGetProp(cn, (xmlChar *)Type)) == NULL) 1169 goto facdone; 1170 1171 if ((provider = xmlGetProp(cn, (xmlChar *)Provider)) == NULL) 1172 goto facdone; 1173 1174 if (xmlStrcmp(ftype, (xmlChar *)Sensor) != 0 && 1175 xmlStrcmp(ftype, (xmlChar *)Indicator) != 0) 1176 goto facdone; 1177 1178 if (xmlStrcmp(provider, (xmlChar *)"fac_prov_ipmi") != 0) { 1179 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "fac_process: " 1180 "Invalid provider attr value: %s\n", provider); 1181 goto facdone; 1182 } 1183 1184 if ((ntn = topo_node_facbind(mp, ptn, (char *)fname, 1185 (char *)ftype)) == NULL) 1186 goto facdone; 1187 1188 pgi.tpi_name = TOPO_PGROUP_FACILITY; 1189 pgi.tpi_namestab = TOPO_STABILITY_PRIVATE; 1190 pgi.tpi_datastab = TOPO_STABILITY_PRIVATE; 1191 pgi.tpi_version = 1; 1192 if (topo_pgroup_create(ntn, &pgi, &err) != 0) { 1193 if (err != ETOPO_PROP_DEFD) { 1194 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1195 "pgroups create failure: %s\n", 1196 topo_strerror(err)); 1197 return (-1); 1198 } 1199 } 1200 /* 1201 * Invoke enum entry point in fac_prov_ipmi module, which will 1202 * cause the provider methods to be registered on this node 1203 */ 1204 if (fac_enum_run(mp, ntn, (const char *)provider) != 0) { 1205 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "fac_process: " 1206 "enum entry point failed for provider %s!\n", 1207 provider); 1208 goto facdone; 1209 } 1210 1211 if ((newi = tf_idata_new(mp, 0, ntn)) == NULL) 1212 goto facdone; 1213 1214 if (tf_idata_insert(&rd->rd_instances, newi) < 0) 1215 goto facdone; 1216 1217 if (pad_process(mp, rd, cn, ntn, &newi->ti_pad) < 0) 1218 goto facdone; 1219 1220 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "done with " 1221 "facility %s=%s.\n", ftype, fname); 1222 1223 xmlFree(ftype); 1224 xmlFree(fname); 1225 xmlFree(provider); 1226 } 1227 1228 return (0); 1229 1230 facdone: 1231 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "facility processing failed\n"); 1232 1233 if (ftype != NULL) 1234 xmlFree(ftype); 1235 if (fname != NULL) 1236 xmlFree(fname); 1237 if (provider != NULL) 1238 xmlFree(provider); 1239 if (ntn != NULL) 1240 topo_node_unbind(ntn); 1241 1242 return (0); 1243 } 1244 1245 static int 1246 node_process(topo_mod_t *mp, xmlNodePtr nn, tf_rdata_t *rd) 1247 { 1248 xmlChar *str; 1249 topo_instance_t inst; 1250 tf_idata_t *newi; 1251 tnode_t *ntn; 1252 uint64_t ui; 1253 int rv = -1; 1254 int s = 0; 1255 1256 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1257 "node_process %s\n", rd->rd_name); 1258 1259 if (xmlattr_to_int(mp, nn, Instance, &ui) < 0) 1260 goto nodedone; 1261 inst = (topo_instance_t)ui; 1262 1263 if ((str = xmlGetProp(nn, (xmlChar *)Static)) != NULL) { 1264 if (xmlStrcmp(str, (xmlChar *)True) == 0) 1265 s = 1; 1266 xmlFree(str); 1267 } 1268 1269 if (s == 0) { 1270 if (topo_mod_enumerate(rd->rd_mod, rd->rd_pn, 1271 rd->rd_finfo->tf_scheme, rd->rd_name, inst, inst, 1272 s == 1 ? &s : NULL) < 0) 1273 goto nodedone; 1274 } 1275 ntn = topo_node_lookup(rd->rd_pn, rd->rd_name, inst); 1276 1277 if (ntn == NULL) { 1278 1279 /* 1280 * If this is a static node declaration, we can 1281 * ignore the lookup failure and continue 1282 * processing. Otherwise, something 1283 * went wrong during enumeration 1284 */ 1285 if (s == 1) 1286 rv = 0; 1287 goto nodedone; 1288 } 1289 if ((newi = tf_idata_new(mp, inst, ntn)) == NULL) { 1290 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1291 "node_process: tf_idata_new failed.\n"); 1292 goto nodedone; 1293 } 1294 if (tf_idata_insert(&rd->rd_instances, newi) < 0) { 1295 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1296 "node_process: tf_idata_insert failed.\n"); 1297 goto nodedone; 1298 } 1299 if (pad_process(mp, rd, nn, ntn, &newi->ti_pad) < 0) 1300 goto nodedone; 1301 if (fac_process(mp, nn, rd, ntn) < 0) 1302 goto nodedone; 1303 rv = 0; 1304 nodedone: 1305 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "done with node %s.\n", 1306 rd->rd_name); 1307 return (rv); 1308 } 1309 1310 static tf_edata_t * 1311 enum_attributes_process(topo_mod_t *mp, xmlNodePtr en) 1312 { 1313 tf_edata_t *einfo; 1314 uint64_t ui; 1315 1316 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "enum_attributes_process\n"); 1317 if ((einfo = topo_mod_zalloc(mp, sizeof (tf_edata_t))) == NULL) { 1318 (void) topo_mod_seterrno(mp, ETOPO_NOMEM); 1319 return (NULL); 1320 } 1321 einfo->te_name = (char *)xmlGetProp(en, (xmlChar *)Name); 1322 if (einfo->te_name == NULL) { 1323 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1324 "Enumerator name attribute missing.\n"); 1325 (void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR); 1326 goto enodedone; 1327 } 1328 1329 /* 1330 * Check for recursive enumeration 1331 */ 1332 if (strcmp(einfo->te_name, mp->tm_name) == 0) { 1333 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1334 "Recursive enumeration detected for %s\n", 1335 einfo->te_name); 1336 (void) topo_mod_seterrno(mp, ETOPO_ENUM_RECURS); 1337 goto enodedone; 1338 } 1339 if (xmlattr_to_int(mp, en, Version, &ui) < 0) 1340 goto enodedone; 1341 einfo->te_vers = (int)ui; 1342 1343 return (einfo); 1344 1345 enodedone: 1346 if (einfo->te_name != NULL) 1347 xmlFree(einfo->te_name); 1348 topo_mod_free(mp, einfo, sizeof (tf_edata_t)); 1349 return (NULL); 1350 } 1351 1352 static int 1353 enum_run(topo_mod_t *mp, tf_rdata_t *rd) 1354 { 1355 topo_hdl_t *thp = mp->tm_hdl; 1356 int e = -1; 1357 1358 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "enum_run\n"); 1359 /* 1360 * Check if the enumerator module is already loaded. 1361 * Module loading is single-threaded at this point so there's 1362 * no need to worry about the module going away or bumping the 1363 * ref count. 1364 */ 1365 if ((rd->rd_mod = topo_mod_lookup(thp, rd->rd_einfo->te_name, 1366 0)) == NULL) { 1367 if ((rd->rd_mod = topo_mod_load(mp, rd->rd_einfo->te_name, 1368 rd->rd_einfo->te_vers)) == NULL) { 1369 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1370 "enum_run: mod_load of %s failed: %s.\n", 1371 rd->rd_einfo->te_name, 1372 topo_strerror(topo_mod_errno(mp))); 1373 (void) topo_hdl_seterrno(thp, topo_mod_errno(mp)); 1374 return (e); 1375 } 1376 } 1377 /* 1378 * We're live, so let's enumerate. 1379 */ 1380 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "enumerate request. (%s)\n", 1381 rd->rd_einfo->te_name); 1382 e = topo_mod_enumerate(rd->rd_mod, rd->rd_pn, rd->rd_einfo->te_name, 1383 rd->rd_name, rd->rd_min, rd->rd_max, NULL); 1384 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "back from enumeration. %d\n", 1385 e); 1386 if (e != 0) { 1387 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1388 "Enumeration failed (%s)\n", 1389 topo_strerror(topo_mod_errno(mp))); 1390 (void) topo_hdl_seterrno(thp, EMOD_PARTIAL_ENUM); 1391 return (topo_mod_seterrno(mp, EMOD_PARTIAL_ENUM)); 1392 } 1393 return (e); 1394 } 1395 1396 static int 1397 fac_enum_run(topo_mod_t *mp, tnode_t *node, const char *name) 1398 { 1399 topo_hdl_t *thp = mp->tm_hdl; 1400 topo_mod_t *fmod; 1401 int e = -1; 1402 1403 topo_dprintf(thp, TOPO_DBG_XML, "fac_enum_run\n"); 1404 /* 1405 * Check if the enumerator module is already loaded. 1406 * Module loading is single-threaded at this point so there's 1407 * no need to worry about the module going away or bumping the 1408 * ref count. 1409 */ 1410 if ((fmod = topo_mod_lookup(thp, name, 0)) == NULL) { 1411 if ((fmod = topo_mod_load(mp, name, TOPO_VERSION)) == NULL) { 1412 topo_dprintf(thp, TOPO_DBG_ERR, 1413 "fac_enum_run: mod_load of %s failed: %s.\n", 1414 name, topo_strerror(topo_mod_errno(mp))); 1415 (void) topo_hdl_seterrno(thp, topo_mod_errno(mp)); 1416 return (e); 1417 } 1418 } 1419 /* 1420 * We're live, so let's enumerate. 1421 */ 1422 topo_dprintf(thp, TOPO_DBG_XML, "fac enumerate request. (%s)\n", name); 1423 e = topo_mod_enumerate(fmod, node, name, name, 0, 0, NULL); 1424 topo_dprintf(thp, TOPO_DBG_XML, "back from enumeration. %d\n", e); 1425 if (e != 0) { 1426 topo_dprintf(thp, TOPO_DBG_ERR, 1427 "Facility provider enumeration failed (%s)\n", 1428 topo_strerror(topo_mod_errno(mp))); 1429 (void) topo_hdl_seterrno(thp, EMOD_PARTIAL_ENUM); 1430 return (topo_mod_seterrno(mp, EMOD_PARTIAL_ENUM)); 1431 } 1432 return (e); 1433 } 1434 1435 int 1436 decorate_nodes(topo_mod_t *mp, tf_rdata_t *rd, xmlNodePtr pxn, tnode_t *ptn, 1437 tf_pad_t **rpad) 1438 { 1439 tnode_t *ctn; 1440 1441 ctn = topo_child_first(ptn); 1442 while (ctn != NULL) { 1443 /* Only care about instances within the range */ 1444 if (strcmp(topo_node_name(ctn), rd->rd_name) != 0) { 1445 ctn = topo_child_next(ptn, ctn); 1446 continue; 1447 } 1448 if (pad_process(mp, rd, pxn, ctn, rpad) < 0) 1449 return (-1); 1450 if (decorate_nodes(mp, rd, pxn, ctn, rpad) < 0) 1451 return (-1); 1452 ctn = topo_child_next(ptn, ctn); 1453 } 1454 return (0); 1455 } 1456 1457 int 1458 topo_xml_range_process(topo_mod_t *mp, xmlNodePtr rn, tf_rdata_t *rd) 1459 { 1460 /* 1461 * The range may have several children xmlNodes, that may 1462 * represent the enumeration method, property groups, 1463 * dependents, nodes or services. 1464 */ 1465 xmlNodePtr cn, enum_node = NULL, pmap_node = NULL; 1466 xmlChar *pmap_name; 1467 tnode_t *ct; 1468 int e, ccnt = 0; 1469 1470 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "topo_xml_range_process\n" 1471 "process %s range beneath %s\n", rd->rd_name, 1472 topo_node_name(rd->rd_pn)); 1473 1474 e = topo_node_range_create(mp, 1475 rd->rd_pn, rd->rd_name, rd->rd_min, rd->rd_max); 1476 if (e != 0 && topo_mod_errno(mp) != EMOD_NODE_DUP) { 1477 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1478 "Range create failed due to %s.\n", 1479 topo_strerror(topo_mod_errno(mp))); 1480 return (-1); 1481 } 1482 1483 /* 1484 * Before we process any of the other child xmlNodes, we iterate through 1485 * the children and looking for either enum-method or propmap elements. 1486 */ 1487 for (cn = rn->xmlChildrenNode; cn != NULL; cn = cn->next) 1488 if (xmlStrcmp(cn->name, (xmlChar *)Enum_meth) == 0) 1489 enum_node = cn; 1490 else if (xmlStrcmp(cn->name, (xmlChar *)Propmap) == 0) 1491 pmap_node = cn; 1492 1493 /* 1494 * If we found an enum-method element, process it first 1495 */ 1496 if (enum_node != NULL) { 1497 if ((rd->rd_einfo = enum_attributes_process(mp, enum_node)) 1498 == NULL) 1499 return (-1); 1500 if (enum_run(mp, rd) < 0) { 1501 /* 1502 * Note the failure but continue on 1503 */ 1504 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1505 "Enumeration failed.\n"); 1506 } 1507 } 1508 1509 /* 1510 * Next, check if a propmap element was found and if so, load it in 1511 * and parse it. 1512 */ 1513 if (pmap_node != NULL) { 1514 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "found a propmap " 1515 "element\n"); 1516 if ((pmap_name = xmlGetProp(pmap_node, (xmlChar *)Name)) 1517 == NULL) { 1518 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1519 "propmap element missing name attribute.\n"); 1520 } else { 1521 if (topo_file_load(mp, rd->rd_pn, 1522 (const char *)pmap_name, 1523 rd->rd_finfo->tf_scheme, 1) < 0) { 1524 1525 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1526 "topo_xml_range_process: topo_file_load" 1527 "failed: %s.\n", 1528 topo_strerror(topo_mod_errno(mp))); 1529 } 1530 xmlFree(pmap_name); 1531 } 1532 } 1533 1534 /* Now look for nodes, i.e., hard instances */ 1535 for (cn = rn->xmlChildrenNode; cn != NULL; cn = cn->next) { 1536 if (xmlStrcmp(cn->name, (xmlChar *)Node) == 0) { 1537 if (node_process(mp, cn, rd) < 0) { 1538 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1539 "node processing failed: %s.\n", 1540 topo_strerror(topo_mod_errno(mp))); 1541 return (topo_mod_seterrno(mp, 1542 EMOD_PARTIAL_ENUM)); 1543 } 1544 ccnt++; 1545 } 1546 } 1547 1548 /* 1549 * Finally, process the property groups and dependents 1550 * 1551 * If the TF_PROPMAP flag is set for the XML file we're currently 1552 * processing, then this XML file was loaded via propmap. In that case 1553 * we call a special routine to recursively apply the propgroup settings 1554 * to all of nodes in this range 1555 */ 1556 if (rd->rd_finfo->tf_flags & TF_PROPMAP) 1557 (void) decorate_nodes(mp, rd, rn, rd->rd_pn, &rd->rd_pad); 1558 else { 1559 ct = topo_child_first(rd->rd_pn); 1560 while (ct != NULL) { 1561 /* Only care about instances within the range */ 1562 if (strcmp(topo_node_name(ct), rd->rd_name) != 0) { 1563 ct = topo_child_next(rd->rd_pn, ct); 1564 continue; 1565 } 1566 if (pad_process(mp, rd, rn, ct, &rd->rd_pad) 1567 < 0) 1568 return (-1); 1569 1570 if (fac_process(mp, rn, rd, ct) < 0) 1571 return (-1); 1572 1573 ct = topo_child_next(rd->rd_pn, ct); 1574 ccnt++; 1575 } 1576 } 1577 1578 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "topo_xml_range_process: end " 1579 "range process %s\n", rd->rd_name); 1580 1581 return (0); 1582 } 1583 1584 static tf_rdata_t * 1585 topo_xml_walk(topo_mod_t *mp, 1586 tf_info_t *xinfo, xmlNodePtr croot, tnode_t *troot) 1587 { 1588 xmlNodePtr curr, def_set = NULL; 1589 tf_rdata_t *rr, *pr, *rdp; 1590 xmlChar *set; 1591 char *key; 1592 int joined_set = 0; 1593 1594 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "topo_xml_walk\n"); 1595 rr = pr = NULL; 1596 /* 1597 * First iterate through all the XML nodes at this level to look for 1598 * set nodes. 1599 */ 1600 for (curr = croot->xmlChildrenNode; curr != NULL; curr = curr->next) { 1601 if (curr->name == NULL) { 1602 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1603 "topo_xml_walk: Ignoring nameless xmlnode\n"); 1604 continue; 1605 } 1606 if (xmlStrcmp(curr->name, (xmlChar *)Set) == 0) { 1607 if (joined_set) 1608 continue; 1609 1610 set = xmlGetProp(curr, (xmlChar *)Setlist); 1611 1612 if (mp->tm_hdl->th_product) 1613 key = mp->tm_hdl->th_product; 1614 else 1615 key = mp->tm_hdl->th_platform; 1616 1617 /* 1618 * If it's the default set then we'll store 1619 * a pointer to it so that if none of the other 1620 * sets apply to our product we can fall 1621 * back to this one. 1622 */ 1623 if (strcmp((char *)set, "default") == 0) 1624 def_set = curr; 1625 else if (set_contains(mp, key, (char *)set)) { 1626 joined_set = 1; 1627 if ((rdp = topo_xml_walk(mp, xinfo, curr, 1628 troot)) == NULL) { 1629 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1630 "topo_xml_walk: failed1\n"); 1631 } 1632 if (pr == NULL) { 1633 rr = pr = rdp; 1634 } else { 1635 pr->rd_next = rdp; 1636 pr = rdp; 1637 } 1638 rr->rd_cnt++; 1639 } 1640 xmlFree(set); 1641 } 1642 } 1643 /* 1644 * If we haven't found a set that contains our product AND a default set 1645 * exists, then we'll process it. 1646 */ 1647 if (!joined_set && def_set) 1648 if (topo_xml_walk(mp, xinfo, def_set, troot) == NULL) { 1649 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1650 "topo_xml_walk: failed2\n"); 1651 } 1652 1653 /* 1654 * Now we're interested in children xmlNodes of croot tagged 1655 * as 'ranges'. These define what topology nodes may exist, and need 1656 * to be verified. 1657 */ 1658 for (curr = croot->xmlChildrenNode; curr != NULL; curr = curr->next) { 1659 if (curr->name == NULL) { 1660 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1661 "topo_xml_walk: Ignoring nameless xmlnode\n"); 1662 continue; 1663 } 1664 if (xmlStrcmp(curr->name, (xmlChar *)Range) != 0) { 1665 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1666 "topo_xml_walk: Ignoring non-range %s.\n", 1667 curr->name); 1668 continue; 1669 } 1670 if ((rdp = tf_rdata_new(mp, xinfo, curr, troot)) == NULL) { 1671 /* 1672 * Range processing error, continue walk 1673 */ 1674 continue; 1675 } 1676 if (pr == NULL) { 1677 rr = pr = rdp; 1678 } else { 1679 pr->rd_next = rdp; 1680 pr = rdp; 1681 } 1682 rr->rd_cnt++; 1683 } 1684 1685 return (rr); 1686 } 1687 1688 /* 1689 * Convert parsed xml topology description into topology nodes 1690 */ 1691 int 1692 topo_xml_enum(topo_mod_t *tmp, tf_info_t *xinfo, tnode_t *troot) 1693 { 1694 xmlNodePtr xroot; 1695 1696 topo_dprintf(tmp->tm_hdl, TOPO_DBG_XML, "topo_xml_enum\n"); 1697 1698 if ((xroot = xmlDocGetRootElement(xinfo->tf_xdoc)) == NULL) { 1699 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1700 "Couldn't get root xmlNode.\n"); 1701 return (-1); 1702 } 1703 if ((xinfo->tf_rd = topo_xml_walk(tmp, xinfo, xroot, troot)) == NULL) { 1704 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1705 "error within .xml topology: %s\n", 1706 topo_strerror(topo_mod_errno(tmp))); 1707 return (-1); 1708 } 1709 return (0); 1710 } 1711 1712 /* 1713 * Load an XML tree from filename and read it into a DOM parse tree. 1714 */ 1715 static tf_info_t * 1716 txml_file_parse(topo_mod_t *tmp, 1717 int fd, const char *filenm, const char *escheme) 1718 { 1719 xmlValidCtxtPtr vcp; 1720 xmlNodePtr cursor; 1721 xmlDocPtr document; 1722 xmlDtdPtr dtd = NULL; 1723 xmlChar *scheme = NULL; 1724 char *dtdpath = NULL; 1725 int readflags = 0; 1726 tf_info_t *r; 1727 int e, validate = 0; 1728 1729 topo_dprintf(tmp->tm_hdl, TOPO_DBG_XML, 1730 "txml_file_parse(filenm=%s, escheme=%s)\n", filenm, escheme); 1731 1732 /* 1733 * Since topologies can XInclude other topologies, and libxml2 1734 * doesn't do DTD-based validation with XInclude, by default 1735 * we don't validate topology files. One can force 1736 * validation, though, by creating a TOPOXML_VALIDATE 1737 * environment variable and creating a TOPO_DTD environment 1738 * variable with the path to the DTD against which to validate. 1739 */ 1740 if (getenv("TOPOXML_VALIDATE") != NULL) { 1741 dtdpath = getenv("TOPO_DTD"); 1742 if (dtdpath != NULL) 1743 xmlLoadExtDtdDefaultValue = 0; 1744 validate = 1; 1745 } 1746 1747 /* 1748 * Splat warnings and errors related to parsing the topology 1749 * file if the TOPOXML_PERROR environment variable exists. 1750 */ 1751 if (getenv("TOPOXML_PERROR") == NULL) 1752 readflags = XML_PARSE_NOERROR | XML_PARSE_NOWARNING; 1753 1754 if ((document = xmlReadFd(fd, filenm, NULL, readflags)) == NULL) { 1755 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1756 "txml_file_parse: couldn't parse document.\n"); 1757 return (NULL); 1758 } 1759 1760 /* 1761 * Verify that this is a document type we understand. 1762 */ 1763 if ((dtd = xmlGetIntSubset(document)) == NULL) { 1764 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1765 "document has no DTD.\n"); 1766 xmlFreeDoc(document); 1767 return (NULL); 1768 } 1769 1770 if (strcmp((const char *)dtd->SystemID, TOPO_DTD_PATH) != 0) { 1771 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1772 "document DTD unknown; bad topology file\n"); 1773 xmlFreeDoc(document); 1774 return (NULL); 1775 } 1776 1777 if ((cursor = xmlDocGetRootElement(document)) == NULL) { 1778 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, "document is empty.\n"); 1779 xmlFreeDoc(document); 1780 return (NULL); 1781 } 1782 1783 /* 1784 * Make sure we're looking at a topology description in the 1785 * expected scheme. 1786 */ 1787 if (xmlStrcmp(cursor->name, (xmlChar *)Topology) != 0) { 1788 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1789 "document is not a topology description.\n"); 1790 xmlFreeDoc(document); 1791 return (NULL); 1792 } 1793 if ((scheme = xmlGetProp(cursor, (xmlChar *)Scheme)) == NULL) { 1794 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1795 "topology lacks a scheme.\n"); 1796 (void) topo_mod_seterrno(tmp, ETOPO_PRSR_NOATTR); 1797 xmlFreeDoc(document); 1798 return (NULL); 1799 } 1800 if (xmlStrcmp(scheme, (xmlChar *)escheme) != 0) { 1801 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1802 "topology in unrecognized scheme, %s, expecting %s\n", 1803 scheme, escheme); 1804 (void) topo_mod_seterrno(tmp, ETOPO_PRSR_BADSCH); 1805 xmlFree(scheme); 1806 xmlFreeDoc(document); 1807 return (NULL); 1808 } 1809 1810 if (dtdpath != NULL) { 1811 dtd = xmlParseDTD(NULL, (xmlChar *)dtdpath); 1812 if (dtd == NULL) { 1813 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1814 "Could not parse DTD \"%s\".\n", 1815 dtdpath); 1816 xmlFree(scheme); 1817 xmlFreeDoc(document); 1818 return (NULL); 1819 } 1820 1821 if (document->extSubset != NULL) 1822 xmlFreeDtd(document->extSubset); 1823 1824 document->extSubset = dtd; 1825 } 1826 1827 if (xmlXIncludeProcessFlags(document, XML_PARSE_XINCLUDE) == -1) { 1828 xmlFree(scheme); 1829 xmlFreeDoc(document); 1830 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1831 "couldn't handle XInclude statements in document\n"); 1832 return (NULL); 1833 } 1834 1835 if (validate) { 1836 if ((vcp = xmlNewValidCtxt()) == NULL) { 1837 xmlFree(scheme); 1838 xmlFreeDoc(document); 1839 return (NULL); 1840 } 1841 vcp->warning = xmlParserValidityWarning; 1842 vcp->error = xmlParserValidityError; 1843 1844 e = xmlValidateDocument(vcp, document); 1845 1846 xmlFreeValidCtxt(vcp); 1847 1848 if (e == 0) 1849 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1850 "Document is not valid.\n"); 1851 } 1852 1853 if ((r = tf_info_new(tmp, document, scheme)) == NULL) { 1854 xmlFree(scheme); 1855 xmlFreeDoc(document); 1856 return (NULL); 1857 } 1858 1859 xmlFree(scheme); 1860 scheme = NULL; 1861 return (r); 1862 } 1863 1864 tf_info_t * 1865 topo_xml_read(topo_mod_t *tmp, const char *path, const char *escheme) 1866 { 1867 int fd; 1868 tf_info_t *tip; 1869 1870 if ((fd = open(path, O_RDONLY)) < 0) { 1871 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1872 "failed to open %s for reading\n", path); 1873 return (NULL); 1874 } 1875 tip = txml_file_parse(tmp, fd, path, escheme); 1876 (void) close(fd); 1877 return (tip); 1878 } 1879