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