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 2009 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 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 164 "Unrecognized type attribute value '%s'.\n", str); 165 (void) topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE); 166 xmlFree(str); 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, is_nonvolatile = 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" and "nonvoltile" attributes are optional. If not 636 * specified we default to false (0) 637 */ 638 (void) xmlattr_to_int(mp, xn, Mutable, &is_mutable); 639 (void) xmlattr_to_int(mp, xn, Nonvolatile, &is_nonvolatile); 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 if (is_nonvolatile) { 735 if (topo_prop_setnonvolatile(tmp, 736 meth.pg_name, meth.prop_name, &err) 737 != 0) { 738 ret = topo_mod_seterrno(mp, 739 ETOPO_PRSR_REGMETH); 740 goto pmr_done; 741 } 742 } 743 } 744 } 745 } else { 746 if (register_method(mp, tn, &meth) != 0) { 747 ret = topo_mod_seterrno(mp, ETOPO_PRSR_REGMETH); 748 goto pmr_done; 749 } 750 if (is_mutable) { 751 if (topo_prop_setmutable(tn, meth.pg_name, 752 meth.prop_name, &err) != 0) { 753 ret = topo_mod_seterrno(mp, 754 ETOPO_PRSR_REGMETH); 755 goto pmr_done; 756 } 757 } 758 if (is_nonvolatile) { 759 if (topo_prop_setnonvolatile(tn, meth.pg_name, 760 meth.prop_name, &err) != 0) { 761 ret = topo_mod_seterrno(mp, 762 ETOPO_PRSR_REGMETH); 763 goto pmr_done; 764 } 765 } 766 } 767 768 pmr_done: 769 if (meth_name) 770 xmlFree(meth_name); 771 if (prop_name) 772 xmlFree(prop_name); 773 if (arg_nvl) 774 nvlist_free(arg_nvl); 775 return (ret); 776 } 777 778 779 static int 780 pgroup_record(topo_mod_t *mp, xmlNodePtr pxn, tnode_t *tn, const char *rname, 781 tf_pad_t *rpad, int pi, const char *ppgrp_name) 782 { 783 topo_stability_t nmstab, dstab; 784 uint64_t ver; 785 xmlNodePtr cn; 786 xmlChar *name; 787 nvlist_t **apl = NULL; 788 nvlist_t *pgnvl = NULL; 789 int pcnt = 0; 790 int ai = 0; 791 int e; 792 793 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroup_record\n"); 794 if ((name = xmlGetProp(pxn, (xmlChar *)Name)) == NULL) { 795 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 796 "propgroup lacks a name\n"); 797 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR)); 798 } 799 if (xmlattr_to_int(mp, pxn, Version, &ver) < 0) { 800 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 801 "propgroup lacks a version\n"); 802 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR)); 803 } 804 if (xmlattr_to_stab(mp, pxn, Namestab, &nmstab) < 0) { 805 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 806 "propgroup lacks name-stability\n"); 807 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR)); 808 } 809 if (xmlattr_to_stab(mp, pxn, Datastab, &dstab) < 0) { 810 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 811 "propgroup lacks data-stability\n"); 812 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR)); 813 } 814 815 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroup %s\n", (char *)name); 816 for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) { 817 if (xmlStrcmp(cn->name, (xmlChar *)Propval) == 0) 818 pcnt++; 819 } 820 821 if (topo_mod_nvalloc(mp, &pgnvl, NV_UNIQUE_NAME) < 0) { 822 xmlFree(name); 823 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 824 "failed to allocate propgroup nvlist\n"); 825 return (topo_mod_seterrno(mp, ETOPO_NOMEM)); 826 } 827 828 e = nvlist_add_string(pgnvl, INV_PGRP_NAME, (char *)name); 829 e |= nvlist_add_uint32(pgnvl, INV_PGRP_NMSTAB, nmstab); 830 e |= nvlist_add_uint32(pgnvl, INV_PGRP_DSTAB, dstab); 831 e |= nvlist_add_uint32(pgnvl, INV_PGRP_VER, ver); 832 e |= nvlist_add_uint32(pgnvl, INV_PGRP_NPROP, pcnt); 833 if (pcnt > 0) 834 if (e != 0 || 835 (apl = topo_mod_zalloc(mp, pcnt * sizeof (nvlist_t *))) 836 == NULL) { 837 xmlFree(name); 838 nvlist_free(pgnvl); 839 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 840 "failed to allocate nvlist array for properties" 841 "(e=%d)\n", e); 842 return (topo_mod_seterrno(mp, ETOPO_NOMEM)); 843 } 844 for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) { 845 if (xmlStrcmp(cn->name, (xmlChar *)Propval) == 0) { 846 if (ai < pcnt) { 847 if ((apl[ai] = pval_record(mp, cn)) == NULL) 848 break; 849 } 850 ai++; 851 } else if (xmlStrcmp(cn->name, (xmlChar *)Prop_meth) == 0) { 852 if (pmeth_record(mp, (const char *)name, cn, tn, rname, 853 ppgrp_name) < 0) 854 break; 855 } 856 } 857 xmlFree(name); 858 if (pcnt > 0) { 859 e |= (ai != pcnt); 860 e |= nvlist_add_nvlist_array(pgnvl, INV_PGRP_ALLPROPS, apl, 861 pcnt); 862 for (ai = 0; ai < pcnt; ai++) 863 if (apl[ai] != NULL) 864 nvlist_free(apl[ai]); 865 topo_mod_free(mp, apl, pcnt * sizeof (nvlist_t *)); 866 if (e != 0) { 867 nvlist_free(pgnvl); 868 return (-1); 869 } 870 } 871 rpad->tpad_pgs[pi] = pgnvl; 872 return (0); 873 } 874 875 static int 876 pgroups_record(topo_mod_t *mp, xmlNodePtr pxn, tnode_t *tn, const char *rname, 877 tf_pad_t *rpad, const char *ppgrp) 878 { 879 xmlNodePtr cn; 880 int pi = 0; 881 882 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroups_record: pxn->name=%s\n", 883 pxn->name); 884 for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) { 885 if (xmlStrcmp(cn->name, (xmlChar *)Propgrp) == 0) { 886 if (pgroup_record(mp, cn, tn, rname, rpad, pi++, ppgrp) 887 < 0) 888 return (-1); 889 } 890 } 891 return (0); 892 } 893 894 /* 895 * psn: pointer to a "set" XML node 896 * key: string to search the set for 897 * 898 * returns: 1, if the set contains key 899 * 0, otherwise 900 */ 901 static int 902 set_contains(topo_mod_t *mp, char *key, char *set) 903 { 904 char *prod; 905 int rv = 0; 906 907 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "set_contains(key = %s, " 908 "setlist = %s)\n", key, set); 909 910 prod = strtok((char *)set, "|"); 911 if (prod && (strcmp(key, prod) == 0)) 912 return (1); 913 914 while ((prod = strtok(NULL, "|"))) 915 if (strcmp(key, prod) == 0) 916 return (1); 917 918 return (rv); 919 } 920 921 922 /* 923 * Process the property group and dependents xmlNode children of 924 * parent xmlNode pxn. 925 */ 926 static int 927 pad_process(topo_mod_t *mp, tf_rdata_t *rd, xmlNodePtr pxn, tnode_t *ptn, 928 tf_pad_t **rpad) 929 { 930 xmlNodePtr cn, gcn, psn, ecn, target; 931 xmlNodePtr def_set = NULL; 932 tnode_t *ct; 933 tf_pad_t *new = *rpad; 934 tf_rdata_t tmp_rd; 935 int pgcnt = 0; 936 int dcnt = 0; 937 int ecnt = 0; 938 int joined_set = 0; 939 xmlChar *set; 940 char *key; 941 942 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 943 "pad_process beneath %s=%d\n", topo_node_name(ptn), 944 topo_node_instance(ptn)); 945 if (new == NULL) { 946 for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) { 947 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 948 "cn->name is %s \n", (char *)cn->name); 949 /* 950 * We're iterating through the XML children looking for 951 * four types of elements: 952 * 1) dependents elements 953 * 2) unconstrained pgroup elements 954 * 3) pgroup elements constrained by set elements 955 * 4) enum-method elements for the case that we want 956 * to post-process a statically defined node 957 */ 958 if (xmlStrcmp(cn->name, (xmlChar *)Dependents) == 0) 959 dcnt++; 960 else if (xmlStrcmp(cn->name, (xmlChar *)Propgrp) == 0) 961 pgcnt++; 962 else if (xmlStrcmp(cn->name, (xmlChar *)Enum_meth) 963 == 0) { 964 ecn = cn; 965 ecnt++; 966 } else if (xmlStrcmp(cn->name, (xmlChar *)Set) == 0) { 967 if (joined_set) 968 continue; 969 set = xmlGetProp(cn, (xmlChar *)Setlist); 970 971 if (mp->tm_hdl->th_product) 972 key = mp->tm_hdl->th_product; 973 else 974 key = mp->tm_hdl->th_platform; 975 976 /* 977 * If it's the default set then we'll store 978 * a pointer to it so that if none of the other 979 * sets apply to our product we can fall 980 * back to this one. 981 */ 982 if (strcmp((char *)set, "default") == 0) 983 def_set = cn; 984 else if (set_contains(mp, key, (char *)set)) { 985 psn = cn; 986 joined_set = 1; 987 for (gcn = cn->xmlChildrenNode; 988 gcn != NULL; gcn = gcn->next) { 989 if (xmlStrcmp(gcn->name, 990 (xmlChar *)Propgrp) == 0) 991 pgcnt++; 992 } 993 } 994 xmlFree(set); 995 } 996 } 997 /* 998 * If we haven't found a set that contains our product AND 999 * a default set exists, then we'll process it. 1000 */ 1001 if (!joined_set && def_set) { 1002 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1003 "Falling back to default set\n"); 1004 joined_set = 1; 1005 psn = def_set; 1006 for (gcn = psn->xmlChildrenNode; gcn != NULL; 1007 gcn = gcn->next) { 1008 if (xmlStrcmp(gcn->name, (xmlChar *)Propgrp) 1009 == 0) 1010 pgcnt++; 1011 } 1012 } 1013 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1014 "pad_process: dcnt=%d, pgcnt=%d, ecnt=%d, joined_set=%d\n", 1015 dcnt, pgcnt, ecnt, joined_set); 1016 /* 1017 * If an enum-method element was found, AND we're a child of a 1018 * node element, then we invoke the enumerator so that it can do 1019 * post-processing of the node. 1020 */ 1021 if (ecnt && (strcmp((const char *)pxn->name, Node) == 0)) { 1022 if ((tmp_rd.rd_einfo = enum_attributes_process(mp, ecn)) 1023 == NULL) 1024 return (-1); 1025 tmp_rd.rd_mod = mp; 1026 tmp_rd.rd_name = rd->rd_name; 1027 tmp_rd.rd_min = rd->rd_min; 1028 tmp_rd.rd_max = rd->rd_max; 1029 tmp_rd.rd_pn = ptn; 1030 if (enum_run(mp, &tmp_rd) < 0) { 1031 /* 1032 * Note the failure but continue on 1033 */ 1034 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1035 "pad_process: enumeration failed.\n"); 1036 } 1037 tf_edata_free(mp, tmp_rd.rd_einfo); 1038 } 1039 /* 1040 * Here we allocate an element in an intermediate data structure 1041 * which keeps track property groups and dependents of the range 1042 * currently being processed. 1043 * 1044 * This structure is referenced in pgroups_record() to create 1045 * the actual property groups in the topo tree 1046 */ 1047 if ((new = tf_pad_new(mp, pgcnt, dcnt)) == NULL) 1048 return (-1); 1049 1050 if (pgcnt > 0) { 1051 new->tpad_pgs = 1052 topo_mod_zalloc(mp, pgcnt * sizeof (nvlist_t *)); 1053 if (new->tpad_pgs == NULL) { 1054 tf_pad_free(mp, new); 1055 return (-1); 1056 } 1057 } 1058 /* 1059 * If the property groups are contained within a set 1060 * then they will be one level lower in the XML tree. 1061 */ 1062 if (joined_set) 1063 target = psn; 1064 else 1065 target = pxn; 1066 1067 /* 1068 * If there is no "node" element under the "range" 1069 * element, then we need to attach the facility node to 1070 * each node in this range. 1071 * 1072 * Otherwise we only attach it to the current node 1073 */ 1074 if (xmlStrcmp(target->name, (xmlChar *)Range) == 0 || 1075 xmlStrcmp(target->name, (xmlChar *)Set) == 0) { 1076 for (ct = topo_child_first(rd->rd_pn); 1077 ct != NULL; 1078 ct = topo_child_next(rd->rd_pn, ct)) { 1079 1080 if (strcmp(topo_node_name(ct), 1081 rd->rd_name) != 0) 1082 continue; 1083 1084 if (fac_enum_process(mp, target, ct) < 0) 1085 return (-1); 1086 1087 if (fac_process(mp, target, rd, ct) < 0) 1088 return (-1); 1089 } 1090 } else { 1091 if (fac_enum_process(mp, target, ptn) < 0) 1092 return (-1); 1093 if (fac_process(mp, target, rd, ptn) < 0) 1094 return (-1); 1095 } 1096 if (pgcnt > 0 && pgroups_record(mp, target, ptn, rd->rd_name, 1097 new, (const char *)pxn->name) < 0) { 1098 tf_pad_free(mp, new); 1099 return (-1); 1100 } 1101 *rpad = new; 1102 } 1103 1104 if (new->tpad_dcnt > 0) 1105 if (dependents_create(mp, rd->rd_finfo, new, pxn, ptn) < 0) 1106 return (-1); 1107 1108 if (new->tpad_pgcnt > 0) 1109 if (pgroups_create(mp, new, ptn) < 0) 1110 return (-1); 1111 1112 return (0); 1113 } 1114 1115 1116 static int 1117 fac_enum_process(topo_mod_t *mp, xmlNodePtr pn, tnode_t *ptn) 1118 { 1119 xmlNodePtr cn; 1120 xmlChar *fprov = NULL; 1121 int rv = 0; 1122 1123 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1124 "fac_enum_process() called for %s=%d\n", topo_node_name(ptn), 1125 topo_node_instance(ptn)); 1126 1127 for (cn = pn->xmlChildrenNode; cn != NULL; cn = cn->next) { 1128 1129 if (xmlStrcmp(cn->name, (xmlChar *)"fac-enum") != 0) 1130 continue; 1131 1132 if ((fprov = xmlGetProp(cn, (xmlChar *)Provider)) == NULL) 1133 goto fenumdone; 1134 1135 if (xmlStrcmp(fprov, (xmlChar *)"fac_prov_ipmi") != 0) { 1136 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1137 "Invalid provider specified: %s\n", fprov); 1138 goto fenumdone; 1139 } 1140 1141 /* 1142 * Invoke enum entry point in fac provider which will cause the 1143 * facility enumeration node method to be registered. 1144 */ 1145 if (fac_enum_run(mp, ptn, (const char *)fprov) != 0) { 1146 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1147 "fac_enum_process: enum entry point failed!\n"); 1148 goto fenumdone; 1149 } 1150 xmlFree(fprov); 1151 } 1152 return (0); 1153 fenumdone: 1154 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "fac-enum processing failed\n"); 1155 1156 if (fprov != NULL) 1157 xmlFree(fprov); 1158 1159 return (rv); 1160 } 1161 1162 1163 static int 1164 fac_process(topo_mod_t *mp, xmlNodePtr pn, tf_rdata_t *rd, tnode_t *ptn) 1165 { 1166 xmlNodePtr cn; 1167 xmlChar *fname = NULL, *ftype = NULL, *provider = NULL; 1168 tnode_t *ntn = NULL; 1169 tf_idata_t *newi; 1170 int err; 1171 topo_pgroup_info_t pgi; 1172 1173 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1174 "fac_process() called for %s=%d\n", topo_node_name(ptn), 1175 topo_node_instance(ptn)); 1176 1177 for (cn = pn->xmlChildrenNode; cn != NULL; cn = cn->next) { 1178 1179 if (xmlStrcmp(cn->name, (xmlChar *)Facility) != 0) 1180 continue; 1181 1182 if ((fname = xmlGetProp(cn, (xmlChar *)Name)) == NULL) 1183 goto facdone; 1184 1185 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1186 "processing facility node '%s'\n", fname); 1187 1188 if ((ftype = xmlGetProp(cn, (xmlChar *)Type)) == NULL) 1189 goto facdone; 1190 1191 if ((provider = xmlGetProp(cn, (xmlChar *)Provider)) == NULL) 1192 goto facdone; 1193 1194 if (xmlStrcmp(ftype, (xmlChar *)Sensor) != 0 && 1195 xmlStrcmp(ftype, (xmlChar *)Indicator) != 0) 1196 goto facdone; 1197 1198 if (xmlStrcmp(provider, (xmlChar *)"fac_prov_ipmi") != 0) { 1199 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "fac_process: " 1200 "Invalid provider attr value: %s\n", provider); 1201 goto facdone; 1202 } 1203 1204 if ((ntn = topo_node_facbind(mp, ptn, (char *)fname, 1205 (char *)ftype)) == NULL) 1206 goto facdone; 1207 1208 pgi.tpi_name = TOPO_PGROUP_FACILITY; 1209 pgi.tpi_namestab = TOPO_STABILITY_PRIVATE; 1210 pgi.tpi_datastab = TOPO_STABILITY_PRIVATE; 1211 pgi.tpi_version = 1; 1212 if (topo_pgroup_create(ntn, &pgi, &err) != 0) { 1213 if (err != ETOPO_PROP_DEFD) { 1214 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1215 "pgroups create failure: %s\n", 1216 topo_strerror(err)); 1217 return (-1); 1218 } 1219 } 1220 /* 1221 * Invoke enum entry point in fac_prov_ipmi module, which will 1222 * cause the provider methods to be registered on this node 1223 */ 1224 if (fac_enum_run(mp, ntn, (const char *)provider) != 0) { 1225 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "fac_process: " 1226 "enum entry point failed for provider %s!\n", 1227 provider); 1228 goto facdone; 1229 } 1230 1231 if ((newi = tf_idata_new(mp, 0, ntn)) == NULL) 1232 goto facdone; 1233 1234 if (tf_idata_insert(&rd->rd_instances, newi) < 0) 1235 goto facdone; 1236 1237 if (pad_process(mp, rd, cn, ntn, &newi->ti_pad) < 0) 1238 goto facdone; 1239 1240 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "done with " 1241 "facility %s=%s.\n", ftype, fname); 1242 1243 xmlFree(ftype); 1244 xmlFree(fname); 1245 xmlFree(provider); 1246 } 1247 1248 return (0); 1249 1250 facdone: 1251 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "facility processing failed\n"); 1252 1253 if (ftype != NULL) 1254 xmlFree(ftype); 1255 if (fname != NULL) 1256 xmlFree(fname); 1257 if (provider != NULL) 1258 xmlFree(provider); 1259 if (ntn != NULL) 1260 topo_node_unbind(ntn); 1261 1262 return (0); 1263 } 1264 1265 static int 1266 node_process(topo_mod_t *mp, xmlNodePtr nn, tf_rdata_t *rd) 1267 { 1268 xmlChar *str; 1269 topo_instance_t inst; 1270 tf_idata_t *newi; 1271 tnode_t *ntn; 1272 uint64_t ui; 1273 int rv = -1; 1274 int s = 0; 1275 1276 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1277 "node_process %s\n", rd->rd_name); 1278 1279 if (xmlattr_to_int(mp, nn, Instance, &ui) < 0) 1280 goto nodedone; 1281 inst = (topo_instance_t)ui; 1282 1283 if ((str = xmlGetProp(nn, (xmlChar *)Static)) != NULL) { 1284 if (xmlStrcmp(str, (xmlChar *)True) == 0) 1285 s = 1; 1286 xmlFree(str); 1287 } 1288 1289 if (s == 0) { 1290 if (topo_mod_enumerate(rd->rd_mod, rd->rd_pn, 1291 rd->rd_finfo->tf_scheme, rd->rd_name, inst, inst, 1292 s == 1 ? &s : NULL) < 0) 1293 goto nodedone; 1294 } 1295 ntn = topo_node_lookup(rd->rd_pn, rd->rd_name, inst); 1296 1297 if (ntn == NULL) { 1298 1299 /* 1300 * If this is a static node declaration, we can 1301 * ignore the lookup failure and continue 1302 * processing. Otherwise, something 1303 * went wrong during enumeration 1304 */ 1305 if (s == 1) 1306 rv = 0; 1307 goto nodedone; 1308 } 1309 if ((newi = tf_idata_new(mp, inst, ntn)) == NULL) { 1310 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1311 "node_process: tf_idata_new failed.\n"); 1312 goto nodedone; 1313 } 1314 if (tf_idata_insert(&rd->rd_instances, newi) < 0) { 1315 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1316 "node_process: tf_idata_insert failed.\n"); 1317 goto nodedone; 1318 } 1319 if (pad_process(mp, rd, nn, ntn, &newi->ti_pad) < 0) 1320 goto nodedone; 1321 if (fac_process(mp, nn, rd, ntn) < 0) 1322 goto nodedone; 1323 rv = 0; 1324 nodedone: 1325 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "done with node %s.\n", 1326 rd->rd_name); 1327 return (rv); 1328 } 1329 1330 static tf_edata_t * 1331 enum_attributes_process(topo_mod_t *mp, xmlNodePtr en) 1332 { 1333 tf_edata_t *einfo; 1334 uint64_t ui; 1335 1336 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "enum_attributes_process\n"); 1337 if ((einfo = topo_mod_zalloc(mp, sizeof (tf_edata_t))) == NULL) { 1338 (void) topo_mod_seterrno(mp, ETOPO_NOMEM); 1339 return (NULL); 1340 } 1341 einfo->te_name = (char *)xmlGetProp(en, (xmlChar *)Name); 1342 if (einfo->te_name == NULL) { 1343 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1344 "Enumerator name attribute missing.\n"); 1345 (void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR); 1346 goto enodedone; 1347 } 1348 1349 /* 1350 * Check for recursive enumeration 1351 */ 1352 if (strcmp(einfo->te_name, mp->tm_name) == 0) { 1353 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1354 "Recursive enumeration detected for %s\n", 1355 einfo->te_name); 1356 (void) topo_mod_seterrno(mp, ETOPO_ENUM_RECURS); 1357 goto enodedone; 1358 } 1359 if (xmlattr_to_int(mp, en, Version, &ui) < 0) 1360 goto enodedone; 1361 einfo->te_vers = (int)ui; 1362 1363 return (einfo); 1364 1365 enodedone: 1366 if (einfo->te_name != NULL) 1367 xmlFree(einfo->te_name); 1368 topo_mod_free(mp, einfo, sizeof (tf_edata_t)); 1369 return (NULL); 1370 } 1371 1372 static int 1373 enum_run(topo_mod_t *mp, tf_rdata_t *rd) 1374 { 1375 topo_hdl_t *thp = mp->tm_hdl; 1376 int e = -1; 1377 1378 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "enum_run\n"); 1379 /* 1380 * Check if the enumerator module is already loaded. 1381 * Module loading is single-threaded at this point so there's 1382 * no need to worry about the module going away or bumping the 1383 * ref count. 1384 */ 1385 if ((rd->rd_mod = topo_mod_lookup(thp, rd->rd_einfo->te_name, 1386 0)) == NULL) { 1387 if ((rd->rd_mod = topo_mod_load(mp, rd->rd_einfo->te_name, 1388 rd->rd_einfo->te_vers)) == NULL) { 1389 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1390 "enum_run: mod_load of %s failed: %s.\n", 1391 rd->rd_einfo->te_name, 1392 topo_strerror(topo_mod_errno(mp))); 1393 (void) topo_hdl_seterrno(thp, topo_mod_errno(mp)); 1394 return (e); 1395 } 1396 } 1397 /* 1398 * We're live, so let's enumerate. 1399 */ 1400 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "enumerate request. (%s)\n", 1401 rd->rd_einfo->te_name); 1402 e = topo_mod_enumerate(rd->rd_mod, rd->rd_pn, rd->rd_einfo->te_name, 1403 rd->rd_name, rd->rd_min, rd->rd_max, NULL); 1404 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "back from enumeration. %d\n", 1405 e); 1406 if (e != 0) { 1407 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1408 "Enumeration failed (%s)\n", 1409 topo_strerror(topo_mod_errno(mp))); 1410 (void) topo_hdl_seterrno(thp, EMOD_PARTIAL_ENUM); 1411 return (topo_mod_seterrno(mp, EMOD_PARTIAL_ENUM)); 1412 } 1413 return (e); 1414 } 1415 1416 static int 1417 fac_enum_run(topo_mod_t *mp, tnode_t *node, const char *name) 1418 { 1419 topo_hdl_t *thp = mp->tm_hdl; 1420 topo_mod_t *fmod; 1421 int e = -1; 1422 1423 topo_dprintf(thp, TOPO_DBG_XML, "fac_enum_run\n"); 1424 /* 1425 * Check if the enumerator module is already loaded. 1426 * Module loading is single-threaded at this point so there's 1427 * no need to worry about the module going away or bumping the 1428 * ref count. 1429 */ 1430 if ((fmod = topo_mod_lookup(thp, name, 0)) == NULL) { 1431 if ((fmod = topo_mod_load(mp, name, TOPO_VERSION)) == NULL) { 1432 topo_dprintf(thp, TOPO_DBG_ERR, 1433 "fac_enum_run: mod_load of %s failed: %s.\n", 1434 name, topo_strerror(topo_mod_errno(mp))); 1435 (void) topo_hdl_seterrno(thp, topo_mod_errno(mp)); 1436 return (e); 1437 } 1438 } 1439 /* 1440 * We're live, so let's enumerate. 1441 */ 1442 topo_dprintf(thp, TOPO_DBG_XML, "fac enumerate request. (%s)\n", name); 1443 e = topo_mod_enumerate(fmod, node, name, name, 0, 0, NULL); 1444 topo_dprintf(thp, TOPO_DBG_XML, "back from enumeration. %d\n", e); 1445 if (e != 0) { 1446 topo_dprintf(thp, TOPO_DBG_ERR, 1447 "Facility provider enumeration failed (%s)\n", 1448 topo_strerror(topo_mod_errno(mp))); 1449 (void) topo_hdl_seterrno(thp, EMOD_PARTIAL_ENUM); 1450 return (topo_mod_seterrno(mp, EMOD_PARTIAL_ENUM)); 1451 } 1452 return (e); 1453 } 1454 1455 int 1456 decorate_nodes(topo_mod_t *mp, tf_rdata_t *rd, xmlNodePtr pxn, tnode_t *ptn, 1457 tf_pad_t **rpad) 1458 { 1459 tnode_t *ctn; 1460 1461 ctn = topo_child_first(ptn); 1462 while (ctn != NULL) { 1463 /* Only care about instances within the range */ 1464 if (strcmp(topo_node_name(ctn), rd->rd_name) != 0) { 1465 ctn = topo_child_next(ptn, ctn); 1466 continue; 1467 } 1468 if (pad_process(mp, rd, pxn, ctn, rpad) < 0) 1469 return (-1); 1470 if (decorate_nodes(mp, rd, pxn, ctn, rpad) < 0) 1471 return (-1); 1472 ctn = topo_child_next(ptn, ctn); 1473 } 1474 return (0); 1475 } 1476 1477 int 1478 topo_xml_range_process(topo_mod_t *mp, xmlNodePtr rn, tf_rdata_t *rd) 1479 { 1480 /* 1481 * The range may have several children xmlNodes, that may 1482 * represent the enumeration method, property groups, 1483 * dependents, nodes or services. 1484 */ 1485 xmlNodePtr cn, enum_node = NULL, pmap_node = NULL; 1486 xmlChar *pmap_name; 1487 tnode_t *ct; 1488 int e, ccnt = 0; 1489 1490 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "topo_xml_range_process\n" 1491 "process %s range beneath %s\n", rd->rd_name, 1492 topo_node_name(rd->rd_pn)); 1493 1494 e = topo_node_range_create(mp, 1495 rd->rd_pn, rd->rd_name, rd->rd_min, rd->rd_max); 1496 if (e != 0 && topo_mod_errno(mp) != EMOD_NODE_DUP) { 1497 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1498 "Range create failed due to %s.\n", 1499 topo_strerror(topo_mod_errno(mp))); 1500 return (-1); 1501 } 1502 1503 /* 1504 * Before we process any of the other child xmlNodes, we iterate through 1505 * the children and looking for either enum-method or propmap elements. 1506 */ 1507 for (cn = rn->xmlChildrenNode; cn != NULL; cn = cn->next) 1508 if (xmlStrcmp(cn->name, (xmlChar *)Enum_meth) == 0) 1509 enum_node = cn; 1510 else if (xmlStrcmp(cn->name, (xmlChar *)Propmap) == 0) 1511 pmap_node = cn; 1512 1513 /* 1514 * If we found an enum-method element, process it first 1515 */ 1516 if (enum_node != NULL) { 1517 if ((rd->rd_einfo = enum_attributes_process(mp, enum_node)) 1518 == NULL) 1519 return (-1); 1520 if (enum_run(mp, rd) < 0) { 1521 /* 1522 * Note the failure but continue on 1523 */ 1524 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1525 "Enumeration failed.\n"); 1526 } 1527 } 1528 1529 /* 1530 * Next, check if a propmap element was found and if so, load it in 1531 * and parse it. 1532 */ 1533 if (pmap_node != NULL) { 1534 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "found a propmap " 1535 "element\n"); 1536 if ((pmap_name = xmlGetProp(pmap_node, (xmlChar *)Name)) 1537 == NULL) { 1538 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1539 "propmap element missing name attribute.\n"); 1540 } else { 1541 if (topo_file_load(mp, rd->rd_pn, 1542 (const char *)pmap_name, 1543 rd->rd_finfo->tf_scheme, 1) < 0) { 1544 1545 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1546 "topo_xml_range_process: topo_file_load" 1547 "failed: %s.\n", 1548 topo_strerror(topo_mod_errno(mp))); 1549 } 1550 xmlFree(pmap_name); 1551 } 1552 } 1553 1554 /* Now look for nodes, i.e., hard instances */ 1555 for (cn = rn->xmlChildrenNode; cn != NULL; cn = cn->next) { 1556 if (xmlStrcmp(cn->name, (xmlChar *)Node) == 0) { 1557 if (node_process(mp, cn, rd) < 0) { 1558 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1559 "node processing failed: %s.\n", 1560 topo_strerror(topo_mod_errno(mp))); 1561 return (topo_mod_seterrno(mp, 1562 EMOD_PARTIAL_ENUM)); 1563 } 1564 ccnt++; 1565 } 1566 } 1567 1568 /* 1569 * Finally, process the property groups and dependents 1570 * 1571 * If the TF_PROPMAP flag is set for the XML file we're currently 1572 * processing, then this XML file was loaded via propmap. In that case 1573 * we call a special routine to recursively apply the propgroup settings 1574 * to all of nodes in this range 1575 */ 1576 if (rd->rd_finfo->tf_flags & TF_PROPMAP) 1577 (void) decorate_nodes(mp, rd, rn, rd->rd_pn, &rd->rd_pad); 1578 else { 1579 ct = topo_child_first(rd->rd_pn); 1580 while (ct != NULL) { 1581 /* Only care about instances within the range */ 1582 if (strcmp(topo_node_name(ct), rd->rd_name) != 0) { 1583 ct = topo_child_next(rd->rd_pn, ct); 1584 continue; 1585 } 1586 if (pad_process(mp, rd, rn, ct, &rd->rd_pad) 1587 < 0) 1588 return (-1); 1589 1590 if (fac_process(mp, rn, rd, ct) < 0) 1591 return (-1); 1592 1593 ct = topo_child_next(rd->rd_pn, ct); 1594 ccnt++; 1595 } 1596 } 1597 1598 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "topo_xml_range_process: end " 1599 "range process %s\n", rd->rd_name); 1600 1601 return (0); 1602 } 1603 1604 static tf_rdata_t * 1605 topo_xml_walk(topo_mod_t *mp, 1606 tf_info_t *xinfo, xmlNodePtr croot, tnode_t *troot) 1607 { 1608 xmlNodePtr curr, def_set = NULL; 1609 tf_rdata_t *rr, *pr, *rdp; 1610 xmlChar *set; 1611 char *key; 1612 int joined_set = 0; 1613 1614 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "topo_xml_walk\n"); 1615 rr = pr = NULL; 1616 /* 1617 * First iterate through all the XML nodes at this level to look for 1618 * set nodes. 1619 */ 1620 for (curr = croot->xmlChildrenNode; curr != NULL; curr = curr->next) { 1621 if (curr->name == NULL) { 1622 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1623 "topo_xml_walk: Ignoring nameless xmlnode\n"); 1624 continue; 1625 } 1626 if (xmlStrcmp(curr->name, (xmlChar *)Set) == 0) { 1627 if (joined_set) 1628 continue; 1629 1630 set = xmlGetProp(curr, (xmlChar *)Setlist); 1631 1632 if (mp->tm_hdl->th_product) 1633 key = mp->tm_hdl->th_product; 1634 else 1635 key = mp->tm_hdl->th_platform; 1636 1637 /* 1638 * If it's the default set then we'll store 1639 * a pointer to it so that if none of the other 1640 * sets apply to our product we can fall 1641 * back to this one. 1642 */ 1643 if (strcmp((char *)set, "default") == 0) 1644 def_set = curr; 1645 else if (set_contains(mp, key, (char *)set)) { 1646 joined_set = 1; 1647 if ((rdp = topo_xml_walk(mp, xinfo, curr, 1648 troot)) == NULL) { 1649 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1650 "topo_xml_walk: failed1\n"); 1651 } 1652 if (pr == NULL) { 1653 rr = pr = rdp; 1654 } else { 1655 pr->rd_next = rdp; 1656 pr = rdp; 1657 } 1658 rr->rd_cnt++; 1659 } 1660 xmlFree(set); 1661 } 1662 } 1663 /* 1664 * If we haven't found a set that contains our product AND a default set 1665 * exists, then we'll process it. 1666 */ 1667 if (!joined_set && def_set) 1668 if (topo_xml_walk(mp, xinfo, def_set, troot) == NULL) { 1669 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1670 "topo_xml_walk: failed2\n"); 1671 } 1672 1673 /* 1674 * Now we're interested in children xmlNodes of croot tagged 1675 * as 'ranges'. These define what topology nodes may exist, and need 1676 * to be verified. 1677 */ 1678 for (curr = croot->xmlChildrenNode; curr != NULL; curr = curr->next) { 1679 if (curr->name == NULL) { 1680 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1681 "topo_xml_walk: Ignoring nameless xmlnode\n"); 1682 continue; 1683 } 1684 if (xmlStrcmp(curr->name, (xmlChar *)Range) != 0) 1685 continue; 1686 if ((rdp = tf_rdata_new(mp, xinfo, curr, troot)) == NULL) { 1687 /* 1688 * Range processing error, continue walk 1689 */ 1690 continue; 1691 } 1692 if (pr == NULL) { 1693 rr = pr = rdp; 1694 } else { 1695 pr->rd_next = rdp; 1696 pr = rdp; 1697 } 1698 rr->rd_cnt++; 1699 } 1700 1701 return (rr); 1702 } 1703 1704 /* 1705 * Convert parsed xml topology description into topology nodes 1706 */ 1707 int 1708 topo_xml_enum(topo_mod_t *tmp, tf_info_t *xinfo, tnode_t *troot) 1709 { 1710 xmlNodePtr xroot; 1711 1712 topo_dprintf(tmp->tm_hdl, TOPO_DBG_XML, "topo_xml_enum\n"); 1713 1714 if ((xroot = xmlDocGetRootElement(xinfo->tf_xdoc)) == NULL) { 1715 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1716 "Couldn't get root xmlNode.\n"); 1717 return (-1); 1718 } 1719 if ((xinfo->tf_rd = topo_xml_walk(tmp, xinfo, xroot, troot)) == NULL) { 1720 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1721 "error within .xml topology: %s\n", 1722 topo_strerror(topo_mod_errno(tmp))); 1723 return (-1); 1724 } 1725 return (0); 1726 } 1727 1728 /* 1729 * Load an XML tree from filename and read it into a DOM parse tree. 1730 */ 1731 static tf_info_t * 1732 txml_file_parse(topo_mod_t *tmp, 1733 int fd, const char *filenm, const char *escheme) 1734 { 1735 xmlValidCtxtPtr vcp; 1736 xmlNodePtr cursor; 1737 xmlDocPtr document; 1738 xmlDtdPtr dtd = NULL; 1739 xmlChar *scheme = NULL; 1740 char *dtdpath = NULL; 1741 int readflags = 0; 1742 tf_info_t *r; 1743 int e, validate = 0; 1744 1745 topo_dprintf(tmp->tm_hdl, TOPO_DBG_XML, 1746 "txml_file_parse(filenm=%s, escheme=%s)\n", filenm, escheme); 1747 1748 /* 1749 * Since topologies can XInclude other topologies, and libxml2 1750 * doesn't do DTD-based validation with XInclude, by default 1751 * we don't validate topology files. One can force 1752 * validation, though, by creating a TOPOXML_VALIDATE 1753 * environment variable and creating a TOPO_DTD environment 1754 * variable with the path to the DTD against which to validate. 1755 */ 1756 if (getenv("TOPOXML_VALIDATE") != NULL) { 1757 dtdpath = getenv("TOPO_DTD"); 1758 if (dtdpath != NULL) 1759 xmlLoadExtDtdDefaultValue = 0; 1760 validate = 1; 1761 } 1762 1763 /* 1764 * Splat warnings and errors related to parsing the topology 1765 * file if the TOPOXML_PERROR environment variable exists. 1766 */ 1767 if (getenv("TOPOXML_PERROR") == NULL) 1768 readflags = XML_PARSE_NOERROR | XML_PARSE_NOWARNING; 1769 1770 if ((document = xmlReadFd(fd, filenm, NULL, readflags)) == NULL) { 1771 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1772 "txml_file_parse: couldn't parse document.\n"); 1773 return (NULL); 1774 } 1775 1776 /* 1777 * Verify that this is a document type we understand. 1778 */ 1779 if ((dtd = xmlGetIntSubset(document)) == NULL) { 1780 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1781 "document has no DTD.\n"); 1782 xmlFreeDoc(document); 1783 return (NULL); 1784 } 1785 1786 if (strcmp((const char *)dtd->SystemID, TOPO_DTD_PATH) != 0) { 1787 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1788 "document DTD unknown; bad topology file\n"); 1789 xmlFreeDoc(document); 1790 return (NULL); 1791 } 1792 1793 if ((cursor = xmlDocGetRootElement(document)) == NULL) { 1794 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, "document is empty.\n"); 1795 xmlFreeDoc(document); 1796 return (NULL); 1797 } 1798 1799 /* 1800 * Make sure we're looking at a topology description in the 1801 * expected scheme. 1802 */ 1803 if (xmlStrcmp(cursor->name, (xmlChar *)Topology) != 0) { 1804 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1805 "document is not a topology description.\n"); 1806 xmlFreeDoc(document); 1807 return (NULL); 1808 } 1809 if ((scheme = xmlGetProp(cursor, (xmlChar *)Scheme)) == NULL) { 1810 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1811 "topology lacks a scheme.\n"); 1812 (void) topo_mod_seterrno(tmp, ETOPO_PRSR_NOATTR); 1813 xmlFreeDoc(document); 1814 return (NULL); 1815 } 1816 if (xmlStrcmp(scheme, (xmlChar *)escheme) != 0) { 1817 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1818 "topology in unrecognized scheme, %s, expecting %s\n", 1819 scheme, escheme); 1820 (void) topo_mod_seterrno(tmp, ETOPO_PRSR_BADSCH); 1821 xmlFree(scheme); 1822 xmlFreeDoc(document); 1823 return (NULL); 1824 } 1825 1826 if (dtdpath != NULL) { 1827 dtd = xmlParseDTD(NULL, (xmlChar *)dtdpath); 1828 if (dtd == NULL) { 1829 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1830 "Could not parse DTD \"%s\".\n", 1831 dtdpath); 1832 xmlFree(scheme); 1833 xmlFreeDoc(document); 1834 return (NULL); 1835 } 1836 1837 if (document->extSubset != NULL) 1838 xmlFreeDtd(document->extSubset); 1839 1840 document->extSubset = dtd; 1841 } 1842 1843 if (xmlXIncludeProcessFlags(document, XML_PARSE_XINCLUDE) == -1) { 1844 xmlFree(scheme); 1845 xmlFreeDoc(document); 1846 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1847 "couldn't handle XInclude statements in document\n"); 1848 return (NULL); 1849 } 1850 1851 if (validate) { 1852 if ((vcp = xmlNewValidCtxt()) == NULL) { 1853 xmlFree(scheme); 1854 xmlFreeDoc(document); 1855 return (NULL); 1856 } 1857 vcp->warning = xmlParserValidityWarning; 1858 vcp->error = xmlParserValidityError; 1859 1860 e = xmlValidateDocument(vcp, document); 1861 1862 xmlFreeValidCtxt(vcp); 1863 1864 if (e == 0) 1865 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1866 "Document is not valid.\n"); 1867 } 1868 1869 if ((r = tf_info_new(tmp, document, scheme)) == NULL) { 1870 xmlFree(scheme); 1871 xmlFreeDoc(document); 1872 return (NULL); 1873 } 1874 1875 xmlFree(scheme); 1876 scheme = NULL; 1877 return (r); 1878 } 1879 1880 tf_info_t * 1881 topo_xml_read(topo_mod_t *tmp, const char *path, const char *escheme) 1882 { 1883 int fd; 1884 tf_info_t *tip; 1885 1886 if ((fd = open(path, O_RDONLY)) < 0) { 1887 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1888 "failed to open %s for reading\n", path); 1889 return (NULL); 1890 } 1891 tip = txml_file_parse(tmp, fd, path, escheme); 1892 (void) close(fd); 1893 return (tip); 1894 } 1895