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