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