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