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