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