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