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