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