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