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 xmlFree(str); 164 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 165 "Unrecognized type attribute value.\n"); 166 (void) topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE); 167 return (TOPO_TYPE_INVALID); 168 } 169 xmlFree(str); 170 return (rv); 171 } 172 173 static int 174 xlate_common(topo_mod_t *mp, xmlNodePtr xn, topo_type_t ptype, nvlist_t *nvl, 175 const char *name) 176 { 177 int rv; 178 uint64_t ui; 179 nvlist_t *fmri; 180 xmlChar *str; 181 182 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "xlate_common (name=%s)\n", 183 name); 184 switch (ptype) { 185 case TOPO_TYPE_INT32: 186 if (xmlattr_to_int(mp, xn, Value, &ui) < 0) 187 return (-1); 188 rv = nvlist_add_int32(nvl, name, (int32_t)ui); 189 break; 190 case TOPO_TYPE_UINT32: 191 if (xmlattr_to_int(mp, xn, Value, &ui) < 0) 192 return (-1); 193 rv = nvlist_add_uint32(nvl, name, (uint32_t)ui); 194 break; 195 case TOPO_TYPE_INT64: 196 if (xmlattr_to_int(mp, xn, Value, &ui) < 0) 197 return (-1); 198 rv = nvlist_add_int64(nvl, name, (int64_t)ui); 199 break; 200 case TOPO_TYPE_UINT64: 201 if (xmlattr_to_int(mp, xn, Value, &ui) < 0) 202 return (-1); 203 rv = nvlist_add_uint64(nvl, name, ui); 204 break; 205 case TOPO_TYPE_FMRI: 206 if (xmlattr_to_fmri(mp, xn, Value, &fmri) < 0) 207 return (-1); 208 rv = nvlist_add_nvlist(nvl, name, fmri); 209 nvlist_free(fmri); 210 break; 211 case TOPO_TYPE_STRING: 212 if ((str = xmlGetProp(xn, (xmlChar *)Value)) == NULL) 213 return (-1); 214 rv = nvlist_add_string(nvl, name, (char *)str); 215 xmlFree(str); 216 break; 217 default: 218 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 219 "Unrecognized type attribute.\n"); 220 return (topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE)); 221 } 222 if (rv != 0) { 223 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 224 "Nvlist construction failed.\n"); 225 return (topo_mod_seterrno(mp, ETOPO_NOMEM)); 226 } else 227 return (0); 228 } 229 230 static int 231 xmlprop_xlate(topo_mod_t *mp, xmlNodePtr xn, nvlist_t *nvl) 232 { 233 topo_type_t ptype; 234 xmlChar *str; 235 236 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "xmlprop_xlate\n"); 237 if ((str = xmlGetProp(xn, (xmlChar *)Immutable)) != NULL) { 238 if (xmlStrcmp(str, (xmlChar *)False) == 0) 239 (void) nvlist_add_boolean_value(nvl, INV_IMMUTE, 240 B_FALSE); 241 else 242 (void) nvlist_add_boolean_value(nvl, INV_IMMUTE, 243 B_TRUE); 244 xmlFree(str); 245 } else { 246 (void) nvlist_add_boolean_value(nvl, INV_IMMUTE, B_TRUE); 247 } 248 249 if ((ptype = xmlattr_to_type(mp, xn, (xmlChar *)Type)) 250 == TOPO_TYPE_INVALID) 251 return (-1); 252 253 if (nvlist_add_int32(nvl, INV_PVALTYPE, ptype) != 0) 254 return (-1); 255 256 return (xlate_common(mp, xn, ptype, nvl, INV_PVAL)); 257 } 258 259 static int 260 dependent_create(topo_mod_t *mp, 261 tf_info_t *xinfo, tf_pad_t *pad, xmlNodePtr dxn, tnode_t *ptn) 262 { 263 tf_rdata_t *rp, *pp, *np; 264 xmlChar *grptype; 265 int sibs = 0; 266 267 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "dependent_create\n"); 268 if ((grptype = xmlGetProp(dxn, (xmlChar *)Grouping)) == NULL) { 269 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 270 "Dependents missing grouping attribute"); 271 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR)); 272 } 273 274 pp = NULL; 275 if (xmlStrcmp(grptype, (xmlChar *)Siblings) == 0) { 276 rp = pad->tpad_sibs; 277 sibs++; 278 } else if (xmlStrcmp(grptype, (xmlChar *)Children) == 0) { 279 rp = pad->tpad_child; 280 } else { 281 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 282 "Dependents have bogus grouping attribute"); 283 xmlFree(grptype); 284 return (topo_mod_seterrno(mp, ETOPO_PRSR_BADGRP)); 285 } 286 xmlFree(grptype); 287 /* Add processed dependents to the tail of the list */ 288 while (rp != NULL) { 289 pp = rp; 290 rp = rp->rd_next; 291 } 292 if ((np = topo_xml_walk(mp, xinfo, dxn, ptn)) == NULL) { 293 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 294 "error within dependent .xml topology: " 295 "%s\n", topo_strerror(topo_mod_errno(mp))); 296 return (-1); 297 } 298 if (pp != NULL) 299 pp->rd_next = np; 300 else if (sibs == 1) 301 pad->tpad_sibs = np; 302 else 303 pad->tpad_child = np; 304 return (0); 305 } 306 307 static int 308 dependents_create(topo_mod_t *mp, 309 tf_info_t *xinfo, tf_pad_t *pad, xmlNodePtr pxn, tnode_t *ptn) 310 { 311 xmlNodePtr cn; 312 313 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "dependents_create\n"); 314 for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) { 315 if (xmlStrcmp(cn->name, (xmlChar *)Dependents) == 0) { 316 if (dependent_create(mp, xinfo, pad, cn, ptn) < 0) 317 return (-1); 318 } 319 } 320 return (0); 321 } 322 323 static int 324 prop_create(topo_mod_t *mp, 325 nvlist_t *pfmri, tnode_t *ptn, const char *gnm, const char *pnm, 326 topo_type_t ptype, int flag) 327 { 328 nvlist_t *fmri; 329 uint32_t ui32; 330 uint64_t ui64; 331 int32_t i32; 332 int64_t i64; 333 char *str; 334 int err, e; 335 336 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "prop_create(pgrp = %s, " 337 "prop = %s)\n", gnm, pnm); 338 switch (ptype) { 339 case TOPO_TYPE_INT32: 340 e = nvlist_lookup_int32(pfmri, INV_PVAL, &i32); 341 break; 342 case TOPO_TYPE_UINT32: 343 e = nvlist_lookup_uint32(pfmri, INV_PVAL, &ui32); 344 break; 345 case TOPO_TYPE_INT64: 346 e = nvlist_lookup_int64(pfmri, INV_PVAL, &i64); 347 break; 348 case TOPO_TYPE_UINT64: 349 e = nvlist_lookup_uint64(pfmri, INV_PVAL, &ui64); 350 break; 351 case TOPO_TYPE_FMRI: 352 e = nvlist_lookup_nvlist(pfmri, INV_PVAL, &fmri); 353 break; 354 case TOPO_TYPE_STRING: 355 e = nvlist_lookup_string(pfmri, INV_PVAL, &str); 356 break; 357 default: 358 e = ETOPO_PRSR_BADTYPE; 359 } 360 if (e != 0) { 361 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 362 "prop_create: prop value lookup failed.\n"); 363 return (topo_mod_seterrno(mp, e)); 364 } 365 switch (ptype) { 366 case TOPO_TYPE_INT32: 367 e = topo_prop_set_int32(ptn, gnm, pnm, flag, i32, &err); 368 break; 369 case TOPO_TYPE_UINT32: 370 e = topo_prop_set_uint32(ptn, gnm, pnm, flag, ui32, &err); 371 break; 372 case TOPO_TYPE_INT64: 373 e = topo_prop_set_int64(ptn, gnm, pnm, flag, i64, &err); 374 break; 375 case TOPO_TYPE_UINT64: 376 e = topo_prop_set_uint64(ptn, gnm, pnm, flag, ui64, &err); 377 break; 378 case TOPO_TYPE_FMRI: 379 e = topo_prop_set_fmri(ptn, gnm, pnm, flag, fmri, &err); 380 break; 381 case TOPO_TYPE_STRING: 382 e = topo_prop_set_string(ptn, gnm, pnm, flag, str, &err); 383 break; 384 } 385 if (e != 0 && err != ETOPO_PROP_DEFD) { 386 387 /* 388 * Some properties may have already been set 389 * in topo_node_bind() or topo_prop_inherit if we are 390 * enumerating from a static .xml file 391 */ 392 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "prop set " 393 "failed %s/%s:%s\n", gnm, pnm, topo_strerror(err)); 394 return (topo_mod_seterrno(mp, err)); 395 } 396 return (0); 397 } 398 399 static int 400 props_create(topo_mod_t *mp, 401 tnode_t *ptn, const char *gnm, nvlist_t **props, int nprops) 402 { 403 topo_type_t ptype; 404 boolean_t pim; 405 char *pnm; 406 int32_t i32; 407 int flag; 408 int pn; 409 int e; 410 411 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "props_create(pgrp = %s)\n", 412 gnm); 413 for (pn = 0; pn < nprops; pn++) { 414 e = nvlist_lookup_string(props[pn], INV_PNAME, &pnm); 415 if (e != 0) { 416 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 417 "props create lookup (%s) failure: %s", 418 INV_PNAME, strerror(e)); 419 return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP)); 420 } 421 e = nvlist_lookup_boolean_value(props[pn], INV_IMMUTE, &pim); 422 if (e != 0) { 423 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 424 "props create lookup (%s) failure: %s", 425 INV_IMMUTE, strerror(e)); 426 return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP)); 427 } 428 flag = (pim == B_TRUE) ? 429 TOPO_PROP_IMMUTABLE : TOPO_PROP_MUTABLE; 430 431 e = nvlist_lookup_int32(props[pn], INV_PVALTYPE, &i32); 432 if (e != 0) { 433 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 434 "props create lookup (%s) failure: %s", 435 INV_PVALTYPE, strerror(e)); 436 return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP)); 437 } 438 ptype = (topo_type_t)i32; 439 if (prop_create(mp, props[pn], ptn, gnm, pnm, ptype, flag) < 0) 440 return (-1); 441 } 442 return (0); 443 } 444 445 static int 446 pgroups_create(topo_mod_t *mp, tf_pad_t *pad, tnode_t *ptn) 447 { 448 topo_pgroup_info_t pgi; 449 nvlist_t **props; 450 char *gnm; 451 char *nmstab, *dstab; 452 uint32_t rnprops, nprops; 453 uint32_t gv; 454 int pg; 455 int e; 456 457 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroups_create: %s=%d\n", 458 topo_node_name(ptn), topo_node_instance(ptn)); 459 for (pg = 0; pg < pad->tpad_pgcnt; pg++) { 460 e = nvlist_lookup_string(pad->tpad_pgs[pg], 461 INV_PGRP_NAME, &gnm); 462 if (e != 0) { 463 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 464 "pad lookup (%s) failed (%s).\n", 465 INV_PGRP_NAME, strerror(errno)); 466 return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP)); 467 } 468 e = nvlist_lookup_string(pad->tpad_pgs[pg], 469 INV_PGRP_NMSTAB, &nmstab); 470 if (e != 0) { 471 if (e != ENOENT) { 472 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 473 "pad lookup (%s) " 474 "failed.\n", INV_PGRP_NMSTAB); 475 return (topo_mod_seterrno(mp, 476 ETOPO_PRSR_NVPROP)); 477 } else { 478 nmstab = TOPO_STABSTR_PRIVATE; 479 } 480 } 481 e = nvlist_lookup_string(pad->tpad_pgs[pg], 482 INV_PGRP_DSTAB, &dstab); 483 if (e != 0) { 484 if (e != ENOENT) { 485 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 486 "pad lookup (%s) failed.\n", 487 INV_PGRP_DSTAB); 488 return (topo_mod_seterrno(mp, 489 ETOPO_PRSR_NVPROP)); 490 } else { 491 dstab = TOPO_STABSTR_PRIVATE; 492 } 493 } 494 e = nvlist_lookup_uint32(pad->tpad_pgs[pg], 495 INV_PGRP_VER, &gv); 496 if (e != 0) { 497 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 498 "pad lookup (%s) failed.\n", 499 INV_PGRP_VER); 500 return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP)); 501 } 502 pgi.tpi_name = gnm; 503 pgi.tpi_namestab = topo_name2stability(nmstab); 504 pgi.tpi_datastab = topo_name2stability(dstab); 505 pgi.tpi_version = gv; 506 if (topo_pgroup_create(ptn, &pgi, &e) != 0) { 507 if (e != ETOPO_PROP_DEFD) { 508 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 509 "pgroups create failure: %s\n", 510 topo_strerror(e)); 511 return (-1); 512 } 513 } 514 e = nvlist_lookup_uint32(pad->tpad_pgs[pg], 515 INV_PGRP_NPROP, &rnprops); 516 /* 517 * The number of properties could be zero if the property 518 * group only contains propmethod declarations 519 */ 520 if (rnprops > 0) { 521 e |= nvlist_lookup_nvlist_array(pad->tpad_pgs[pg], 522 INV_PGRP_ALLPROPS, &props, &nprops); 523 if (rnprops != nprops) { 524 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 525 "recorded number of props %d does not " 526 "match number of props recorded %d.\n", 527 rnprops, nprops); 528 } 529 if (props_create(mp, ptn, gnm, props, nprops) < 0) 530 return (-1); 531 } 532 } 533 return (0); 534 } 535 536 static nvlist_t * 537 pval_record(topo_mod_t *mp, xmlNodePtr xn) 538 { 539 nvlist_t *pnvl = NULL; 540 xmlChar *pname; 541 542 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pval_record\n"); 543 if ((pname = xmlGetProp(xn, (xmlChar *)Name)) == NULL) { 544 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 545 "propval lacks a name\n"); 546 (void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR); 547 return (NULL); 548 } 549 if (topo_mod_nvalloc(mp, &pnvl, NV_UNIQUE_NAME) < 0) { 550 xmlFree(pname); 551 return (NULL); 552 } 553 if (nvlist_add_string(pnvl, INV_PNAME, (char *)pname) < 0) { 554 xmlFree(pname); 555 nvlist_free(pnvl); 556 return (NULL); 557 } 558 xmlFree(pname); 559 /* FMXXX stability of the property name */ 560 561 if (xmlprop_xlate(mp, xn, pnvl) < 0) { 562 nvlist_free(pnvl); 563 return (NULL); 564 } 565 return (pnvl); 566 } 567 568 569 struct propmeth_data { 570 const char *pg_name; 571 const char *prop_name; 572 topo_type_t prop_type; 573 const char *meth_name; 574 topo_version_t meth_ver; 575 nvlist_t *arg_nvl; 576 }; 577 578 static int 579 register_method(topo_mod_t *mp, tnode_t *ptn, struct propmeth_data *meth) 580 { 581 int err; 582 583 if (topo_prop_method_version_register(ptn, meth->pg_name, 584 meth->prop_name, meth->prop_type, meth->meth_name, meth->meth_ver, 585 meth->arg_nvl, &err) != 0) { 586 587 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "failed to register " 588 "propmethod %s for property \"%s\" in propgrp %s on node " 589 "%s=%d (%s)\n", 590 meth->meth_name, meth->prop_name, meth->pg_name, 591 topo_node_name(ptn), topo_node_instance(ptn), 592 topo_strerror(err)); 593 return (-1); 594 } 595 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 596 "registered method %s on %s=%d\n", 597 meth->meth_name, topo_node_name(ptn), topo_node_instance(ptn)); 598 599 return (0); 600 } 601 602 static int 603 pmeth_record(topo_mod_t *mp, const char *pg_name, xmlNodePtr xn, tnode_t *tn, 604 const char *rname, const char *ppgrp_name) 605 { 606 nvlist_t *arg_nvl = NULL; 607 xmlNodePtr cn; 608 xmlChar *meth_name = NULL, *prop_name = NULL; 609 xmlChar *arg_name = NULL; 610 uint64_t meth_ver, is_mutable = 0, 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\n", topo_node_name(ptn)); 944 if (new == NULL) { 945 for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) { 946 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 947 "cn->name is %s \n", (char *)cn->name); 948 /* 949 * We're iterating through the XML children looking for 950 * four types of elements: 951 * 1) dependents elements 952 * 2) unconstrained pgroup elements 953 * 3) pgroup elements constrained by set elements 954 * 4) enum-method elements for the case that we want 955 * to post-process a statically defined node 956 */ 957 if (xmlStrcmp(cn->name, (xmlChar *)Dependents) == 0) 958 dcnt++; 959 else if (xmlStrcmp(cn->name, (xmlChar *)Propgrp) == 0) 960 pgcnt++; 961 else if (xmlStrcmp(cn->name, (xmlChar *)Enum_meth) 962 == 0) { 963 ecn = cn; 964 ecnt++; 965 } else if (xmlStrcmp(cn->name, (xmlChar *)Set) == 0) { 966 if (joined_set) 967 continue; 968 set = xmlGetProp(cn, (xmlChar *)Setlist); 969 970 if (mp->tm_hdl->th_product) 971 key = mp->tm_hdl->th_product; 972 else 973 key = mp->tm_hdl->th_platform; 974 975 /* 976 * If it's the default set then we'll store 977 * a pointer to it so that if none of the other 978 * sets apply to our product we can fall 979 * back to this one. 980 */ 981 if (strcmp((char *)set, "default") == 0) 982 def_set = cn; 983 else if (set_contains(mp, key, (char *)set)) { 984 psn = cn; 985 joined_set = 1; 986 for (gcn = cn->xmlChildrenNode; 987 gcn != NULL; gcn = gcn->next) { 988 if (xmlStrcmp(gcn->name, 989 (xmlChar *)Propgrp) == 0) 990 pgcnt++; 991 } 992 } 993 xmlFree(set); 994 } 995 } 996 /* 997 * If we haven't found a set that contains our product AND 998 * a default set exists, then we'll process it. 999 */ 1000 if (!joined_set && def_set) { 1001 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1002 "Falling back to default set\n"); 1003 joined_set = 1; 1004 psn = def_set; 1005 for (gcn = psn->xmlChildrenNode; gcn != NULL; 1006 gcn = gcn->next) { 1007 if (xmlStrcmp(gcn->name, (xmlChar *)Propgrp) 1008 == 0) 1009 pgcnt++; 1010 } 1011 } 1012 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1013 "pad_process: dcnt=%d, pgcnt=%d, ecnt=%d, joined_set=%d\n", 1014 dcnt, pgcnt, ecnt, joined_set); 1015 /* 1016 * If an enum-method element was found, AND we're a child of a 1017 * node element, then we invoke the enumerator so that it can do 1018 * post-processing of the node. 1019 */ 1020 if (ecnt && (strcmp((const char *)pxn->name, Node) == 0)) { 1021 if ((tmp_rd.rd_einfo = enum_attributes_process(mp, ecn)) 1022 == NULL) 1023 return (-1); 1024 tmp_rd.rd_mod = mp; 1025 tmp_rd.rd_name = rd->rd_name; 1026 tmp_rd.rd_min = rd->rd_min; 1027 tmp_rd.rd_max = rd->rd_max; 1028 tmp_rd.rd_pn = ptn; 1029 if (enum_run(mp, &tmp_rd) < 0) { 1030 /* 1031 * Note the failure but continue on 1032 */ 1033 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1034 "pad_process: enumeration failed.\n"); 1035 } 1036 tf_edata_free(mp, tmp_rd.rd_einfo); 1037 } 1038 /* 1039 * Here we allocate an element in an intermediate data structure 1040 * which keeps track property groups and dependents of the range 1041 * currently being processed. 1042 * 1043 * This structure is referenced in pgroups_record() to create 1044 * the actual property groups in the topo tree 1045 */ 1046 if ((new = tf_pad_new(mp, pgcnt, dcnt)) == NULL) 1047 return (-1); 1048 1049 if (pgcnt > 0) { 1050 new->tpad_pgs = 1051 topo_mod_zalloc(mp, pgcnt * sizeof (nvlist_t *)); 1052 if (new->tpad_pgs == NULL) { 1053 tf_pad_free(mp, new); 1054 return (-1); 1055 } 1056 } 1057 /* 1058 * If the property groups are contained within a set 1059 * then they will be one level lower in the XML tree. 1060 */ 1061 if (joined_set) 1062 target = psn; 1063 else 1064 target = pxn; 1065 1066 /* 1067 * If there is no "node" element under the "range" 1068 * element, then we need to attach the facility node to 1069 * each node in this range. 1070 * 1071 * Otherwise we only attach it to the current node 1072 */ 1073 if (xmlStrcmp(target->name, (xmlChar *)Range) == 0 || 1074 xmlStrcmp(target->name, (xmlChar *)Set) == 0) { 1075 for (ct = topo_child_first(rd->rd_pn); 1076 ct != NULL; 1077 ct = topo_child_next(rd->rd_pn, ct)) { 1078 1079 if (strcmp(topo_node_name(ct), 1080 rd->rd_name) != 0) 1081 continue; 1082 1083 if (fac_enum_process(mp, target, ct) < 0) 1084 return (-1); 1085 1086 if (fac_process(mp, target, rd, ct) < 0) 1087 return (-1); 1088 } 1089 } else { 1090 if (fac_enum_process(mp, target, ptn) < 0) 1091 return (-1); 1092 if (fac_process(mp, target, rd, ptn) < 0) 1093 return (-1); 1094 } 1095 if (pgcnt > 0 && pgroups_record(mp, target, ptn, rd->rd_name, 1096 new, (const char *)pxn->name) < 0) { 1097 tf_pad_free(mp, new); 1098 return (-1); 1099 } 1100 *rpad = new; 1101 } 1102 1103 if (new->tpad_dcnt > 0) 1104 if (dependents_create(mp, rd->rd_finfo, new, pxn, ptn) < 0) 1105 return (-1); 1106 1107 if (new->tpad_pgcnt > 0) 1108 if (pgroups_create(mp, new, ptn) < 0) 1109 return (-1); 1110 1111 return (0); 1112 } 1113 1114 1115 static int 1116 fac_enum_process(topo_mod_t *mp, xmlNodePtr pn, tnode_t *ptn) 1117 { 1118 xmlNodePtr cn; 1119 xmlChar *fprov = NULL; 1120 int rv = 0; 1121 1122 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1123 "fac_enum_process() called for %s=%d\n", topo_node_name(ptn), 1124 topo_node_instance(ptn)); 1125 1126 for (cn = pn->xmlChildrenNode; cn != NULL; cn = cn->next) { 1127 1128 if (xmlStrcmp(cn->name, (xmlChar *)"fac-enum") != 0) 1129 continue; 1130 1131 if ((fprov = xmlGetProp(cn, (xmlChar *)Provider)) == NULL) 1132 goto fenumdone; 1133 1134 if (xmlStrcmp(fprov, (xmlChar *)"fac_prov_ipmi") != 0) { 1135 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1136 "Invalid provider specified: %s\n", fprov); 1137 goto fenumdone; 1138 } 1139 1140 /* 1141 * Invoke enum entry point in fac provider which will cause the 1142 * facility enumeration node method to be registered. 1143 */ 1144 if (fac_enum_run(mp, ptn, (const char *)fprov) != 0) { 1145 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1146 "fac_enum_process: enum entry point failed!\n"); 1147 goto fenumdone; 1148 } 1149 xmlFree(fprov); 1150 } 1151 return (0); 1152 fenumdone: 1153 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "fac-enum processing failed\n"); 1154 1155 if (fprov != NULL) 1156 xmlFree(fprov); 1157 1158 return (rv); 1159 } 1160 1161 1162 static int 1163 fac_process(topo_mod_t *mp, xmlNodePtr pn, tf_rdata_t *rd, tnode_t *ptn) 1164 { 1165 xmlNodePtr cn; 1166 xmlChar *fname = NULL, *ftype = NULL, *provider = NULL; 1167 tnode_t *ntn = NULL; 1168 tf_idata_t *newi; 1169 int err; 1170 topo_pgroup_info_t pgi; 1171 1172 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1173 "fac_process() called\n"); 1174 1175 for (cn = pn->xmlChildrenNode; cn != NULL; cn = cn->next) { 1176 1177 if (xmlStrcmp(cn->name, (xmlChar *)Facility) != 0) 1178 continue; 1179 1180 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1181 "facility processing\n"); 1182 1183 if ((fname = xmlGetProp(cn, (xmlChar *)Name)) == NULL) 1184 goto facdone; 1185 1186 if ((ftype = xmlGetProp(cn, (xmlChar *)Type)) == NULL) 1187 goto facdone; 1188 1189 if ((provider = xmlGetProp(cn, (xmlChar *)Provider)) == NULL) 1190 goto facdone; 1191 1192 if (xmlStrcmp(ftype, (xmlChar *)Sensor) != 0 && 1193 xmlStrcmp(ftype, (xmlChar *)Indicator) != 0) 1194 goto facdone; 1195 1196 if (xmlStrcmp(provider, (xmlChar *)"fac_prov_ipmi") != 0) { 1197 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "fac_process: " 1198 "Invalid provider attr value: %s\n", provider); 1199 goto facdone; 1200 } 1201 1202 if ((ntn = topo_node_facbind(mp, ptn, (char *)fname, 1203 (char *)ftype)) == NULL) 1204 goto facdone; 1205 1206 pgi.tpi_name = TOPO_PGROUP_FACILITY; 1207 pgi.tpi_namestab = TOPO_STABILITY_PRIVATE; 1208 pgi.tpi_datastab = TOPO_STABILITY_PRIVATE; 1209 pgi.tpi_version = 1; 1210 if (topo_pgroup_create(ntn, &pgi, &err) != 0) { 1211 if (err != ETOPO_PROP_DEFD) { 1212 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1213 "pgroups create failure: %s\n", 1214 topo_strerror(err)); 1215 return (-1); 1216 } 1217 } 1218 /* 1219 * Invoke enum entry point in fac_prov_ipmi module, which will 1220 * cause the provider methods to be registered on this node 1221 */ 1222 if (fac_enum_run(mp, ntn, (const char *)provider) != 0) { 1223 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "fac_process: " 1224 "enum entry point failed for provider %s!\n", 1225 provider); 1226 goto facdone; 1227 } 1228 1229 if ((newi = tf_idata_new(mp, 0, ntn)) == NULL) 1230 goto facdone; 1231 1232 if (tf_idata_insert(&rd->rd_instances, newi) < 0) 1233 goto facdone; 1234 1235 if (pad_process(mp, rd, cn, ntn, &newi->ti_pad) < 0) 1236 goto facdone; 1237 1238 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "done with " 1239 "facility %s=%s.\n", ftype, fname); 1240 1241 xmlFree(ftype); 1242 xmlFree(fname); 1243 xmlFree(provider); 1244 } 1245 1246 return (0); 1247 1248 facdone: 1249 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "facility processing failed\n"); 1250 1251 if (ftype != NULL) 1252 xmlFree(ftype); 1253 if (fname != NULL) 1254 xmlFree(fname); 1255 if (provider != NULL) 1256 xmlFree(provider); 1257 if (ntn != NULL) 1258 topo_node_unbind(ntn); 1259 1260 return (0); 1261 } 1262 1263 static int 1264 node_process(topo_mod_t *mp, xmlNodePtr nn, tf_rdata_t *rd) 1265 { 1266 xmlChar *str; 1267 topo_instance_t inst; 1268 tf_idata_t *newi; 1269 tnode_t *ntn; 1270 uint64_t ui; 1271 int rv = -1; 1272 int s = 0; 1273 1274 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1275 "node_process %s\n", rd->rd_name); 1276 1277 if (xmlattr_to_int(mp, nn, Instance, &ui) < 0) 1278 goto nodedone; 1279 inst = (topo_instance_t)ui; 1280 1281 if ((str = xmlGetProp(nn, (xmlChar *)Static)) != NULL) { 1282 if (xmlStrcmp(str, (xmlChar *)True) == 0) 1283 s = 1; 1284 xmlFree(str); 1285 } 1286 1287 if (s == 0) { 1288 if (topo_mod_enumerate(rd->rd_mod, rd->rd_pn, 1289 rd->rd_finfo->tf_scheme, rd->rd_name, inst, inst, 1290 s == 1 ? &s : NULL) < 0) 1291 goto nodedone; 1292 } 1293 ntn = topo_node_lookup(rd->rd_pn, rd->rd_name, inst); 1294 1295 if (ntn == NULL) { 1296 1297 /* 1298 * If this is a static node declaration, we can 1299 * ignore the lookup failure and continue 1300 * processing. Otherwise, something 1301 * went wrong during enumeration 1302 */ 1303 if (s == 1) 1304 rv = 0; 1305 goto nodedone; 1306 } 1307 if ((newi = tf_idata_new(mp, inst, ntn)) == NULL) { 1308 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1309 "node_process: tf_idata_new failed.\n"); 1310 goto nodedone; 1311 } 1312 if (tf_idata_insert(&rd->rd_instances, newi) < 0) { 1313 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1314 "node_process: tf_idata_insert failed.\n"); 1315 goto nodedone; 1316 } 1317 if (pad_process(mp, rd, nn, ntn, &newi->ti_pad) < 0) 1318 goto nodedone; 1319 if (fac_process(mp, nn, rd, ntn) < 0) 1320 goto nodedone; 1321 rv = 0; 1322 nodedone: 1323 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "done with node %s.\n", 1324 rd->rd_name); 1325 return (rv); 1326 } 1327 1328 static tf_edata_t * 1329 enum_attributes_process(topo_mod_t *mp, xmlNodePtr en) 1330 { 1331 tf_edata_t *einfo; 1332 uint64_t ui; 1333 1334 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "enum_attributes_process\n"); 1335 if ((einfo = topo_mod_zalloc(mp, sizeof (tf_edata_t))) == NULL) { 1336 (void) topo_mod_seterrno(mp, ETOPO_NOMEM); 1337 return (NULL); 1338 } 1339 einfo->te_name = (char *)xmlGetProp(en, (xmlChar *)Name); 1340 if (einfo->te_name == NULL) { 1341 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1342 "Enumerator name attribute missing.\n"); 1343 (void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR); 1344 goto enodedone; 1345 } 1346 1347 /* 1348 * Check for recursive enumeration 1349 */ 1350 if (strcmp(einfo->te_name, mp->tm_name) == 0) { 1351 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1352 "Recursive enumeration detected for %s\n", 1353 einfo->te_name); 1354 (void) topo_mod_seterrno(mp, ETOPO_ENUM_RECURS); 1355 goto enodedone; 1356 } 1357 if (xmlattr_to_int(mp, en, Version, &ui) < 0) 1358 goto enodedone; 1359 einfo->te_vers = (int)ui; 1360 1361 return (einfo); 1362 1363 enodedone: 1364 if (einfo->te_name != NULL) 1365 xmlFree(einfo->te_name); 1366 topo_mod_free(mp, einfo, sizeof (tf_edata_t)); 1367 return (NULL); 1368 } 1369 1370 static int 1371 enum_run(topo_mod_t *mp, tf_rdata_t *rd) 1372 { 1373 topo_hdl_t *thp = mp->tm_hdl; 1374 int e = -1; 1375 1376 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "enum_run\n"); 1377 /* 1378 * Check if the enumerator module is already loaded. 1379 * Module loading is single-threaded at this point so there's 1380 * no need to worry about the module going away or bumping the 1381 * ref count. 1382 */ 1383 if ((rd->rd_mod = topo_mod_lookup(thp, rd->rd_einfo->te_name, 1384 0)) == NULL) { 1385 if ((rd->rd_mod = topo_mod_load(mp, rd->rd_einfo->te_name, 1386 rd->rd_einfo->te_vers)) == NULL) { 1387 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1388 "enum_run: mod_load of %s failed: %s.\n", 1389 rd->rd_einfo->te_name, 1390 topo_strerror(topo_mod_errno(mp))); 1391 (void) topo_hdl_seterrno(thp, topo_mod_errno(mp)); 1392 return (e); 1393 } 1394 } 1395 /* 1396 * We're live, so let's enumerate. 1397 */ 1398 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "enumerate request. (%s)\n", 1399 rd->rd_einfo->te_name); 1400 e = topo_mod_enumerate(rd->rd_mod, rd->rd_pn, rd->rd_einfo->te_name, 1401 rd->rd_name, rd->rd_min, rd->rd_max, NULL); 1402 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "back from enumeration. %d\n", 1403 e); 1404 if (e != 0) { 1405 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1406 "Enumeration failed (%s)\n", 1407 topo_strerror(topo_mod_errno(mp))); 1408 (void) topo_hdl_seterrno(thp, EMOD_PARTIAL_ENUM); 1409 return (topo_mod_seterrno(mp, EMOD_PARTIAL_ENUM)); 1410 } 1411 return (e); 1412 } 1413 1414 static int 1415 fac_enum_run(topo_mod_t *mp, tnode_t *node, const char *name) 1416 { 1417 topo_hdl_t *thp = mp->tm_hdl; 1418 topo_mod_t *fmod; 1419 int e = -1; 1420 1421 topo_dprintf(thp, TOPO_DBG_XML, "fac_enum_run\n"); 1422 /* 1423 * Check if the enumerator module is already loaded. 1424 * Module loading is single-threaded at this point so there's 1425 * no need to worry about the module going away or bumping the 1426 * ref count. 1427 */ 1428 if ((fmod = topo_mod_lookup(thp, name, 0)) == NULL) { 1429 if ((fmod = topo_mod_load(mp, name, TOPO_VERSION)) == NULL) { 1430 topo_dprintf(thp, TOPO_DBG_ERR, 1431 "fac_enum_run: mod_load of %s failed: %s.\n", 1432 name, topo_strerror(topo_mod_errno(mp))); 1433 (void) topo_hdl_seterrno(thp, topo_mod_errno(mp)); 1434 return (e); 1435 } 1436 } 1437 /* 1438 * We're live, so let's enumerate. 1439 */ 1440 topo_dprintf(thp, TOPO_DBG_XML, "fac enumerate request. (%s)\n", name); 1441 e = topo_mod_enumerate(fmod, node, name, name, 0, 0, NULL); 1442 topo_dprintf(thp, TOPO_DBG_XML, "back from enumeration. %d\n", e); 1443 if (e != 0) { 1444 topo_dprintf(thp, TOPO_DBG_ERR, 1445 "Facility provider enumeration failed (%s)\n", 1446 topo_strerror(topo_mod_errno(mp))); 1447 (void) topo_hdl_seterrno(thp, EMOD_PARTIAL_ENUM); 1448 return (topo_mod_seterrno(mp, EMOD_PARTIAL_ENUM)); 1449 } 1450 return (e); 1451 } 1452 1453 int 1454 decorate_nodes(topo_mod_t *mp, tf_rdata_t *rd, xmlNodePtr pxn, tnode_t *ptn, 1455 tf_pad_t **rpad) 1456 { 1457 tnode_t *ctn; 1458 1459 ctn = topo_child_first(ptn); 1460 while (ctn != NULL) { 1461 /* Only care about instances within the range */ 1462 if (strcmp(topo_node_name(ctn), rd->rd_name) != 0) { 1463 ctn = topo_child_next(ptn, ctn); 1464 continue; 1465 } 1466 if (pad_process(mp, rd, pxn, ctn, rpad) < 0) 1467 return (-1); 1468 if (decorate_nodes(mp, rd, pxn, ctn, rpad) < 0) 1469 return (-1); 1470 ctn = topo_child_next(ptn, ctn); 1471 } 1472 return (0); 1473 } 1474 1475 int 1476 topo_xml_range_process(topo_mod_t *mp, xmlNodePtr rn, tf_rdata_t *rd) 1477 { 1478 /* 1479 * The range may have several children xmlNodes, that may 1480 * represent the enumeration method, property groups, 1481 * dependents, nodes or services. 1482 */ 1483 xmlNodePtr cn, enum_node = NULL, pmap_node = NULL; 1484 xmlChar *pmap_name; 1485 tnode_t *ct; 1486 int e, ccnt = 0; 1487 1488 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "topo_xml_range_process\n" 1489 "process %s range beneath %s\n", rd->rd_name, 1490 topo_node_name(rd->rd_pn)); 1491 1492 e = topo_node_range_create(mp, 1493 rd->rd_pn, rd->rd_name, rd->rd_min, rd->rd_max); 1494 if (e != 0 && topo_mod_errno(mp) != EMOD_NODE_DUP) { 1495 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1496 "Range create failed due to %s.\n", 1497 topo_strerror(topo_mod_errno(mp))); 1498 return (-1); 1499 } 1500 1501 /* 1502 * Before we process any of the other child xmlNodes, we iterate through 1503 * the children and looking for either enum-method or propmap elements. 1504 */ 1505 for (cn = rn->xmlChildrenNode; cn != NULL; cn = cn->next) 1506 if (xmlStrcmp(cn->name, (xmlChar *)Enum_meth) == 0) 1507 enum_node = cn; 1508 else if (xmlStrcmp(cn->name, (xmlChar *)Propmap) == 0) 1509 pmap_node = cn; 1510 1511 /* 1512 * If we found an enum-method element, process it first 1513 */ 1514 if (enum_node != NULL) { 1515 if ((rd->rd_einfo = enum_attributes_process(mp, enum_node)) 1516 == NULL) 1517 return (-1); 1518 if (enum_run(mp, rd) < 0) { 1519 /* 1520 * Note the failure but continue on 1521 */ 1522 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1523 "Enumeration failed.\n"); 1524 } 1525 } 1526 1527 /* 1528 * Next, check if a propmap element was found and if so, load it in 1529 * and parse it. 1530 */ 1531 if (pmap_node != NULL) { 1532 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "found a propmap " 1533 "element\n"); 1534 if ((pmap_name = xmlGetProp(pmap_node, (xmlChar *)Name)) 1535 == NULL) { 1536 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1537 "propmap element missing name attribute.\n"); 1538 } else { 1539 if (topo_file_load(mp, rd->rd_pn, 1540 (const char *)pmap_name, 1541 rd->rd_finfo->tf_scheme, 1) < 0) { 1542 1543 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1544 "topo_xml_range_process: topo_file_load" 1545 "failed: %s.\n", 1546 topo_strerror(topo_mod_errno(mp))); 1547 } 1548 xmlFree(pmap_name); 1549 } 1550 } 1551 1552 /* Now look for nodes, i.e., hard instances */ 1553 for (cn = rn->xmlChildrenNode; cn != NULL; cn = cn->next) { 1554 if (xmlStrcmp(cn->name, (xmlChar *)Node) == 0) { 1555 if (node_process(mp, cn, rd) < 0) { 1556 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 1557 "node processing failed: %s.\n", 1558 topo_strerror(topo_mod_errno(mp))); 1559 return (topo_mod_seterrno(mp, 1560 EMOD_PARTIAL_ENUM)); 1561 } 1562 ccnt++; 1563 } 1564 } 1565 1566 /* 1567 * Finally, process the property groups and dependents 1568 * 1569 * If the TF_PROPMAP flag is set for the XML file we're currently 1570 * processing, then this XML file was loaded via propmap. In that case 1571 * we call a special routine to recursively apply the propgroup settings 1572 * to all of nodes in this range 1573 */ 1574 if (rd->rd_finfo->tf_flags & TF_PROPMAP) 1575 (void) decorate_nodes(mp, rd, rn, rd->rd_pn, &rd->rd_pad); 1576 else { 1577 ct = topo_child_first(rd->rd_pn); 1578 while (ct != NULL) { 1579 /* Only care about instances within the range */ 1580 if (strcmp(topo_node_name(ct), rd->rd_name) != 0) { 1581 ct = topo_child_next(rd->rd_pn, ct); 1582 continue; 1583 } 1584 if (pad_process(mp, rd, rn, ct, &rd->rd_pad) 1585 < 0) 1586 return (-1); 1587 1588 if (fac_process(mp, rn, rd, ct) < 0) 1589 return (-1); 1590 1591 ct = topo_child_next(rd->rd_pn, ct); 1592 ccnt++; 1593 } 1594 } 1595 1596 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "topo_xml_range_process: end " 1597 "range process %s\n", rd->rd_name); 1598 1599 return (0); 1600 } 1601 1602 static tf_rdata_t * 1603 topo_xml_walk(topo_mod_t *mp, 1604 tf_info_t *xinfo, xmlNodePtr croot, tnode_t *troot) 1605 { 1606 xmlNodePtr curr, def_set = NULL; 1607 tf_rdata_t *rr, *pr, *rdp; 1608 xmlChar *set; 1609 char *key; 1610 int joined_set = 0; 1611 1612 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "topo_xml_walk\n"); 1613 rr = pr = NULL; 1614 /* 1615 * First iterate through all the XML nodes at this level to look for 1616 * set nodes. 1617 */ 1618 for (curr = croot->xmlChildrenNode; curr != NULL; curr = curr->next) { 1619 if (curr->name == NULL) { 1620 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1621 "topo_xml_walk: Ignoring nameless xmlnode\n"); 1622 continue; 1623 } 1624 if (xmlStrcmp(curr->name, (xmlChar *)Set) == 0) { 1625 if (joined_set) 1626 continue; 1627 1628 set = xmlGetProp(curr, (xmlChar *)Setlist); 1629 1630 if (mp->tm_hdl->th_product) 1631 key = mp->tm_hdl->th_product; 1632 else 1633 key = mp->tm_hdl->th_platform; 1634 1635 /* 1636 * If it's the default set then we'll store 1637 * a pointer to it so that if none of the other 1638 * sets apply to our product we can fall 1639 * back to this one. 1640 */ 1641 if (strcmp((char *)set, "default") == 0) 1642 def_set = curr; 1643 else if (set_contains(mp, key, (char *)set)) { 1644 joined_set = 1; 1645 if ((rdp = topo_xml_walk(mp, xinfo, curr, 1646 troot)) == NULL) { 1647 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1648 "topo_xml_walk: failed1\n"); 1649 } 1650 if (pr == NULL) { 1651 rr = pr = rdp; 1652 } else { 1653 pr->rd_next = rdp; 1654 pr = rdp; 1655 } 1656 rr->rd_cnt++; 1657 } 1658 xmlFree(set); 1659 } 1660 } 1661 /* 1662 * If we haven't found a set that contains our product AND a default set 1663 * exists, then we'll process it. 1664 */ 1665 if (!joined_set && def_set) 1666 if (topo_xml_walk(mp, xinfo, def_set, troot) == NULL) { 1667 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1668 "topo_xml_walk: failed2\n"); 1669 } 1670 1671 /* 1672 * Now we're interested in children xmlNodes of croot tagged 1673 * as 'ranges'. These define what topology nodes may exist, and need 1674 * to be verified. 1675 */ 1676 for (curr = croot->xmlChildrenNode; curr != NULL; curr = curr->next) { 1677 if (curr->name == NULL) { 1678 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1679 "topo_xml_walk: Ignoring nameless xmlnode\n"); 1680 continue; 1681 } 1682 if (xmlStrcmp(curr->name, (xmlChar *)Range) != 0) { 1683 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 1684 "topo_xml_walk: Ignoring non-range %s.\n", 1685 curr->name); 1686 continue; 1687 } 1688 if ((rdp = tf_rdata_new(mp, xinfo, curr, troot)) == NULL) { 1689 /* 1690 * Range processing error, continue walk 1691 */ 1692 continue; 1693 } 1694 if (pr == NULL) { 1695 rr = pr = rdp; 1696 } else { 1697 pr->rd_next = rdp; 1698 pr = rdp; 1699 } 1700 rr->rd_cnt++; 1701 } 1702 1703 return (rr); 1704 } 1705 1706 /* 1707 * Convert parsed xml topology description into topology nodes 1708 */ 1709 int 1710 topo_xml_enum(topo_mod_t *tmp, tf_info_t *xinfo, tnode_t *troot) 1711 { 1712 xmlNodePtr xroot; 1713 1714 topo_dprintf(tmp->tm_hdl, TOPO_DBG_XML, "topo_xml_enum\n"); 1715 1716 if ((xroot = xmlDocGetRootElement(xinfo->tf_xdoc)) == NULL) { 1717 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1718 "Couldn't get root xmlNode.\n"); 1719 return (-1); 1720 } 1721 if ((xinfo->tf_rd = topo_xml_walk(tmp, xinfo, xroot, troot)) == NULL) { 1722 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1723 "error within .xml topology: %s\n", 1724 topo_strerror(topo_mod_errno(tmp))); 1725 return (-1); 1726 } 1727 return (0); 1728 } 1729 1730 /* 1731 * Load an XML tree from filename and read it into a DOM parse tree. 1732 */ 1733 static tf_info_t * 1734 txml_file_parse(topo_mod_t *tmp, 1735 int fd, const char *filenm, const char *escheme) 1736 { 1737 xmlValidCtxtPtr vcp; 1738 xmlNodePtr cursor; 1739 xmlDocPtr document; 1740 xmlDtdPtr dtd = NULL; 1741 xmlChar *scheme = NULL; 1742 char *dtdpath = NULL; 1743 int readflags = 0; 1744 tf_info_t *r; 1745 int e, validate = 0; 1746 1747 topo_dprintf(tmp->tm_hdl, TOPO_DBG_XML, 1748 "txml_file_parse(filenm=%s, escheme=%s)\n", filenm, escheme); 1749 1750 /* 1751 * Since topologies can XInclude other topologies, and libxml2 1752 * doesn't do DTD-based validation with XInclude, by default 1753 * we don't validate topology files. One can force 1754 * validation, though, by creating a TOPOXML_VALIDATE 1755 * environment variable and creating a TOPO_DTD environment 1756 * variable with the path to the DTD against which to validate. 1757 */ 1758 if (getenv("TOPOXML_VALIDATE") != NULL) { 1759 dtdpath = getenv("TOPO_DTD"); 1760 if (dtdpath != NULL) 1761 xmlLoadExtDtdDefaultValue = 0; 1762 validate = 1; 1763 } 1764 1765 /* 1766 * Splat warnings and errors related to parsing the topology 1767 * file if the TOPOXML_PERROR environment variable exists. 1768 */ 1769 if (getenv("TOPOXML_PERROR") == NULL) 1770 readflags = XML_PARSE_NOERROR | XML_PARSE_NOWARNING; 1771 1772 if ((document = xmlReadFd(fd, filenm, NULL, readflags)) == NULL) { 1773 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1774 "txml_file_parse: couldn't parse document.\n"); 1775 return (NULL); 1776 } 1777 1778 /* 1779 * Verify that this is a document type we understand. 1780 */ 1781 if ((dtd = xmlGetIntSubset(document)) == NULL) { 1782 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1783 "document has no DTD.\n"); 1784 xmlFreeDoc(document); 1785 return (NULL); 1786 } 1787 1788 if (strcmp((const char *)dtd->SystemID, TOPO_DTD_PATH) != 0) { 1789 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1790 "document DTD unknown; bad topology file\n"); 1791 xmlFreeDoc(document); 1792 return (NULL); 1793 } 1794 1795 if ((cursor = xmlDocGetRootElement(document)) == NULL) { 1796 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, "document is empty.\n"); 1797 xmlFreeDoc(document); 1798 return (NULL); 1799 } 1800 1801 /* 1802 * Make sure we're looking at a topology description in the 1803 * expected scheme. 1804 */ 1805 if (xmlStrcmp(cursor->name, (xmlChar *)Topology) != 0) { 1806 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1807 "document is not a topology description.\n"); 1808 xmlFreeDoc(document); 1809 return (NULL); 1810 } 1811 if ((scheme = xmlGetProp(cursor, (xmlChar *)Scheme)) == NULL) { 1812 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1813 "topology lacks a scheme.\n"); 1814 (void) topo_mod_seterrno(tmp, ETOPO_PRSR_NOATTR); 1815 xmlFreeDoc(document); 1816 return (NULL); 1817 } 1818 if (xmlStrcmp(scheme, (xmlChar *)escheme) != 0) { 1819 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1820 "topology in unrecognized scheme, %s, expecting %s\n", 1821 scheme, escheme); 1822 (void) topo_mod_seterrno(tmp, ETOPO_PRSR_BADSCH); 1823 xmlFree(scheme); 1824 xmlFreeDoc(document); 1825 return (NULL); 1826 } 1827 1828 if (dtdpath != NULL) { 1829 dtd = xmlParseDTD(NULL, (xmlChar *)dtdpath); 1830 if (dtd == NULL) { 1831 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1832 "Could not parse DTD \"%s\".\n", 1833 dtdpath); 1834 xmlFree(scheme); 1835 xmlFreeDoc(document); 1836 return (NULL); 1837 } 1838 1839 if (document->extSubset != NULL) 1840 xmlFreeDtd(document->extSubset); 1841 1842 document->extSubset = dtd; 1843 } 1844 1845 if (xmlXIncludeProcessFlags(document, XML_PARSE_XINCLUDE) == -1) { 1846 xmlFree(scheme); 1847 xmlFreeDoc(document); 1848 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1849 "couldn't handle XInclude statements in document\n"); 1850 return (NULL); 1851 } 1852 1853 if (validate) { 1854 if ((vcp = xmlNewValidCtxt()) == NULL) { 1855 xmlFree(scheme); 1856 xmlFreeDoc(document); 1857 return (NULL); 1858 } 1859 vcp->warning = xmlParserValidityWarning; 1860 vcp->error = xmlParserValidityError; 1861 1862 e = xmlValidateDocument(vcp, document); 1863 1864 xmlFreeValidCtxt(vcp); 1865 1866 if (e == 0) 1867 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1868 "Document is not valid.\n"); 1869 } 1870 1871 if ((r = tf_info_new(tmp, document, scheme)) == NULL) { 1872 xmlFree(scheme); 1873 xmlFreeDoc(document); 1874 return (NULL); 1875 } 1876 1877 xmlFree(scheme); 1878 scheme = NULL; 1879 return (r); 1880 } 1881 1882 tf_info_t * 1883 topo_xml_read(topo_mod_t *tmp, const char *path, const char *escheme) 1884 { 1885 int fd; 1886 tf_info_t *tip; 1887 1888 if ((fd = open(path, O_RDONLY)) < 0) { 1889 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1890 "failed to open %s for reading\n", path); 1891 return (NULL); 1892 } 1893 tip = txml_file_parse(tmp, fd, path, escheme); 1894 (void) close(fd); 1895 return (tip); 1896 } 1897