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