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