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 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <libxml/parser.h> 30 #include <libxml/xinclude.h> 31 #include <sys/fm/protocol.h> 32 #include <assert.h> 33 #include <string.h> 34 #include <strings.h> 35 #include <ctype.h> 36 #include <errno.h> 37 #include <limits.h> 38 #include <fm/libtopo.h> 39 #include <unistd.h> 40 #include <sys/stat.h> 41 #include <fcntl.h> 42 #include <topo_mod.h> 43 #include <topo_subr.h> 44 #include <topo_alloc.h> 45 #include <topo_parse.h> 46 #include <topo_error.h> 47 48 static tf_rdata_t *topo_xml_walk(topo_mod_t *, 49 tf_info_t *, xmlNodePtr, tnode_t *); 50 51 int 52 xmlattr_to_stab(topo_mod_t *mp, xmlNodePtr n, const char *stabname, 53 topo_stability_t *rs) 54 { 55 xmlChar *str; 56 int rv = 0; 57 58 if (n == NULL) { 59 /* If there is no Stability defined, we default to private */ 60 *rs = TOPO_STABILITY_PRIVATE; 61 return (0); 62 } 63 if ((str = xmlGetProp(n, (xmlChar *)stabname)) == NULL) { 64 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 65 "attribute to stability:\n"); 66 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR)); 67 } 68 69 if (xmlStrcmp(str, (xmlChar *)Internal) == 0) { 70 *rs = TOPO_STABILITY_INTERNAL; 71 } else if (xmlStrcmp(str, (xmlChar *)Private) == 0) { 72 *rs = TOPO_STABILITY_PRIVATE; 73 } else if (xmlStrcmp(str, (xmlChar *)Obsolete) == 0) { 74 *rs = TOPO_STABILITY_OBSOLETE; 75 } else if (xmlStrcmp(str, (xmlChar *)External) == 0) { 76 *rs = TOPO_STABILITY_EXTERNAL; 77 } else if (xmlStrcmp(str, (xmlChar *)Unstable) == 0) { 78 *rs = TOPO_STABILITY_UNSTABLE; 79 } else if (xmlStrcmp(str, (xmlChar *)Evolving) == 0) { 80 *rs = TOPO_STABILITY_EVOLVING; 81 } else if (xmlStrcmp(str, (xmlChar *)Stable) == 0) { 82 *rs = TOPO_STABILITY_STABLE; 83 } else if (xmlStrcmp(str, (xmlChar *)Standard) == 0) { 84 *rs = TOPO_STABILITY_STANDARD; 85 } else { 86 xmlFree(str); 87 return (topo_mod_seterrno(mp, ETOPO_PRSR_BADSTAB)); 88 } 89 xmlFree(str); 90 return (rv); 91 } 92 93 int 94 xmlattr_to_int(topo_mod_t *mp, 95 xmlNodePtr n, const char *propname, uint64_t *value) 96 { 97 xmlChar *str; 98 xmlChar *estr; 99 100 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "attribute to int\n"); 101 if ((str = xmlGetProp(n, (xmlChar *)propname)) == NULL) 102 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR)); 103 *value = strtoull((char *)str, (char **)&estr, 10); 104 if (estr == str) { 105 /* no conversion was done */ 106 xmlFree(str); 107 return (topo_mod_seterrno(mp, ETOPO_PRSR_BADNUM)); 108 } 109 xmlFree(str); 110 return (0); 111 } 112 113 static int 114 xmlattr_to_fmri(topo_mod_t *mp, 115 xmlNodePtr xn, const char *propname, nvlist_t **rnvl) 116 { 117 xmlChar *str; 118 119 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "attribute to int\n"); 120 if ((str = xmlGetProp(xn, (xmlChar *)propname)) == NULL) 121 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR)); 122 if (topo_mod_str2nvl(mp, (const char *)str, rnvl) < 0) 123 return (-1); 124 xmlFree(str); 125 return (0); 126 } 127 128 static topo_type_t 129 xmlattr_to_type(topo_mod_t *mp, xmlNodePtr xn) 130 { 131 topo_type_t rv; 132 xmlChar *str; 133 if ((str = xmlGetProp(xn, (xmlChar *)Type)) == NULL) { 134 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "Property missing type"); 135 (void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR); 136 return (TOPO_TYPE_INVALID); 137 } 138 if (xmlStrcmp(str, (xmlChar *)Int32) == 0) { 139 rv = TOPO_TYPE_INT32; 140 } else if (xmlStrcmp(str, (xmlChar *)UInt32) == 0) { 141 rv = TOPO_TYPE_UINT32; 142 } else if (xmlStrcmp(str, (xmlChar *)Int64) == 0) { 143 rv = TOPO_TYPE_INT64; 144 } else if (xmlStrcmp(str, (xmlChar *)UInt64) == 0) { 145 rv = TOPO_TYPE_UINT64; 146 } else if (xmlStrcmp(str, (xmlChar *)FMRI) == 0) { 147 rv = TOPO_TYPE_FMRI; 148 } else if (xmlStrcmp(str, (xmlChar *)String) == 0) { 149 rv = TOPO_TYPE_STRING; 150 } else { 151 xmlFree(str); 152 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 153 "Unrecognized type attribute.\n"); 154 (void) topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE); 155 return (TOPO_TYPE_INVALID); 156 } 157 xmlFree(str); 158 return (rv); 159 } 160 161 static int 162 xmlprop_xlate(topo_mod_t *mp, xmlNodePtr xn, nvlist_t *nvl) 163 { 164 topo_type_t ptype; 165 xmlChar *str; 166 nvlist_t *fmri; 167 uint64_t ui; 168 int e; 169 170 if ((str = xmlGetProp(xn, (xmlChar *)Immutable)) != NULL) { 171 if (xmlStrcmp(str, (xmlChar *)False) == 0) 172 (void) nvlist_add_boolean_value(nvl, INV_IMMUTE, 173 B_FALSE); 174 else 175 (void) nvlist_add_boolean_value(nvl, INV_IMMUTE, 176 B_TRUE); 177 xmlFree(str); 178 } else { 179 (void) nvlist_add_boolean_value(nvl, INV_IMMUTE, B_TRUE); 180 } 181 182 if ((ptype = xmlattr_to_type(mp, xn)) == TOPO_TYPE_INVALID) 183 return (-1); 184 e = nvlist_add_int32(nvl, INV_PVALTYPE, ptype); 185 if (e != 0) 186 return (-1); 187 switch (ptype) { 188 case TOPO_TYPE_INT32: 189 if (xmlattr_to_int(mp, xn, Value, &ui) < 0) 190 return (-1); 191 e = nvlist_add_int32(nvl, INV_PVAL, (int32_t)ui); 192 break; 193 case TOPO_TYPE_UINT32: 194 if (xmlattr_to_int(mp, xn, Value, &ui) < 0) 195 return (-1); 196 e = nvlist_add_uint32(nvl, INV_PVAL, (uint32_t)ui); 197 break; 198 case TOPO_TYPE_INT64: 199 if (xmlattr_to_int(mp, xn, Value, &ui) < 0) 200 return (-1); 201 e = nvlist_add_int64(nvl, INV_PVAL, (int64_t)ui); 202 break; 203 case TOPO_TYPE_UINT64: 204 if (xmlattr_to_int(mp, xn, Value, &ui) < 0) 205 return (-1); 206 e = nvlist_add_uint64(nvl, INV_PVAL, ui); 207 break; 208 case TOPO_TYPE_FMRI: 209 if (xmlattr_to_fmri(mp, xn, Value, &fmri) < 0) 210 return (-1); 211 e = nvlist_add_nvlist(nvl, INV_PVAL, fmri); 212 nvlist_free(fmri); 213 break; 214 case TOPO_TYPE_STRING: 215 if ((str = xmlGetProp(xn, (xmlChar *)Value)) == NULL) 216 return (-1); 217 e = nvlist_add_string(nvl, INV_PVAL, (char *)str); 218 xmlFree(str); 219 break; 220 default: 221 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 222 "Unrecognized type attribute.\n"); 223 return (topo_mod_seterrno(mp, ETOPO_PRSR_BADTYPE)); 224 } 225 if (e != 0) { 226 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 227 "Nvlist construction failed.\n"); 228 return (topo_mod_seterrno(mp, ETOPO_NOMEM)); 229 } 230 return (0); 231 } 232 233 static int 234 dependent_create(topo_mod_t *mp, 235 tf_info_t *xinfo, tf_pad_t *pad, xmlNodePtr dxn, tnode_t *ptn) 236 { 237 tf_rdata_t *rp, *pp, *np; 238 xmlChar *grptype; 239 int sibs = 0; 240 241 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "dependent create\n"); 242 if ((grptype = xmlGetProp(dxn, (xmlChar *)Grouping)) == NULL) { 243 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 244 "Dependents missing grouping attribute"); 245 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR)); 246 } 247 248 pp = NULL; 249 if (xmlStrcmp(grptype, (xmlChar *)Siblings) == 0) { 250 rp = pad->tpad_sibs; 251 sibs++; 252 } else if (xmlStrcmp(grptype, (xmlChar *)Children) == 0) { 253 rp = pad->tpad_child; 254 } else { 255 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 256 "Dependents have bogus grouping attribute"); 257 xmlFree(grptype); 258 return (topo_mod_seterrno(mp, ETOPO_PRSR_BADGRP)); 259 } 260 xmlFree(grptype); 261 /* Add processed dependents to the tail of the list */ 262 while (rp != NULL) { 263 pp = rp; 264 rp = rp->rd_next; 265 } 266 if ((np = topo_xml_walk(mp, xinfo, dxn, ptn)) == NULL) { 267 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 268 "error within dependent .xml topology: " 269 "%s\n", topo_strerror(topo_mod_errno(mp))); 270 return (-1); 271 } 272 if (pp != NULL) 273 pp->rd_next = np; 274 else if (sibs == 1) 275 pad->tpad_sibs = np; 276 else 277 pad->tpad_child = np; 278 return (0); 279 } 280 281 static int 282 dependents_create(topo_mod_t *mp, 283 tf_info_t *xinfo, tf_pad_t *pad, xmlNodePtr pxn, tnode_t *ptn) 284 { 285 xmlNodePtr cn; 286 287 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "dependents create\n"); 288 for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) { 289 if (xmlStrcmp(cn->name, (xmlChar *)Dependents) == 0) { 290 if (dependent_create(mp, xinfo, pad, cn, ptn) < 0) 291 return (-1); 292 } 293 } 294 return (0); 295 } 296 297 static int 298 prop_create(topo_mod_t *mp, 299 nvlist_t *pfmri, tnode_t *ptn, const char *gnm, const char *pnm, 300 topo_type_t ptype, int flag) 301 { 302 nvlist_t *fmri; 303 uint32_t ui32; 304 uint64_t ui64; 305 int32_t i32; 306 int64_t i64; 307 char *str; 308 int err, e; 309 310 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "prop create\n"); 311 switch (ptype) { 312 case TOPO_TYPE_INT32: 313 e = nvlist_lookup_int32(pfmri, INV_PVAL, &i32); 314 break; 315 case TOPO_TYPE_UINT32: 316 e = nvlist_lookup_uint32(pfmri, INV_PVAL, &ui32); 317 break; 318 case TOPO_TYPE_INT64: 319 e = nvlist_lookup_int64(pfmri, INV_PVAL, &i64); 320 break; 321 case TOPO_TYPE_UINT64: 322 e = nvlist_lookup_uint64(pfmri, INV_PVAL, &ui64); 323 break; 324 case TOPO_TYPE_FMRI: 325 e = nvlist_lookup_nvlist(pfmri, INV_PVAL, &fmri); 326 break; 327 case TOPO_TYPE_STRING: 328 e = nvlist_lookup_string(pfmri, INV_PVAL, &str); 329 break; 330 default: 331 e = ETOPO_PRSR_BADTYPE; 332 } 333 if (e != 0) { 334 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 335 "prop value lookup failed.\n"); 336 return (topo_mod_seterrno(mp, e)); 337 } 338 switch (ptype) { 339 case TOPO_TYPE_INT32: 340 e = topo_prop_set_int32(ptn, gnm, pnm, flag, i32, &err); 341 break; 342 case TOPO_TYPE_UINT32: 343 e = topo_prop_set_uint32(ptn, gnm, pnm, flag, ui32, &err); 344 break; 345 case TOPO_TYPE_INT64: 346 e = topo_prop_set_int64(ptn, gnm, pnm, flag, i64, &err); 347 break; 348 case TOPO_TYPE_UINT64: 349 e = topo_prop_set_uint64(ptn, gnm, pnm, flag, ui64, &err); 350 break; 351 case TOPO_TYPE_FMRI: 352 e = topo_prop_set_fmri(ptn, gnm, pnm, flag, fmri, &err); 353 break; 354 case TOPO_TYPE_STRING: 355 e = topo_prop_set_string(ptn, gnm, pnm, flag, str, &err); 356 break; 357 } 358 if (e != 0 && err != ETOPO_PROP_DEFD) { 359 360 /* 361 * Some properties may have already been set 362 * in topo_node_bind() or topo_prop_inherit if we are 363 * enumerating from a static .xml file 364 */ 365 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, "prop set " 366 "failed %s/%s:%s\n", gnm, pnm, topo_strerror(err)); 367 return (topo_mod_seterrno(mp, err)); 368 } 369 return (0); 370 } 371 372 static int 373 props_create(topo_mod_t *mp, 374 tnode_t *ptn, const char *gnm, nvlist_t **props, int nprops) 375 { 376 topo_type_t ptype; 377 boolean_t pim; 378 char *pnm; 379 int32_t i32; 380 int flag; 381 int pn; 382 int e; 383 384 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "props create\n"); 385 for (pn = 0; pn < nprops; pn++) { 386 e = nvlist_lookup_string(props[pn], INV_PNAME, &pnm); 387 if (e != 0) { 388 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 389 "props create lookup (%s) failure: %s", 390 INV_PNAME, topo_strerror(e)); 391 return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP)); 392 } 393 e = nvlist_lookup_boolean_value(props[pn], INV_IMMUTE, &pim); 394 if (e != 0) { 395 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 396 "props create lookup (%s) failure: %s", 397 INV_IMMUTE, topo_strerror(e)); 398 return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP)); 399 } 400 flag = (pim == B_TRUE) ? 401 TOPO_PROP_IMMUTABLE : TOPO_PROP_MUTABLE; 402 403 e = nvlist_lookup_int32(props[pn], INV_PVALTYPE, &i32); 404 if (e != 0) { 405 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 406 "props create lookup (%s) failure: %s", 407 INV_PVALTYPE, topo_strerror(e)); 408 return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP)); 409 } 410 ptype = (topo_type_t)i32; 411 if (prop_create(mp, props[pn], ptn, gnm, pnm, ptype, flag) < 0) 412 return (-1); 413 } 414 return (0); 415 } 416 417 static int 418 pgroups_create(topo_mod_t *mp, tf_pad_t *pad, tnode_t *ptn) 419 { 420 topo_pgroup_info_t pgi; 421 nvlist_t **props; 422 char *gnm; 423 char *nmstab, *dstab; 424 uint32_t rnprops, nprops; 425 uint32_t gv; 426 int pg; 427 int e; 428 429 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroups create\n"); 430 for (pg = 0; pg < pad->tpad_pgcnt; pg++) { 431 e = nvlist_lookup_string(pad->tpad_pgs[pg], 432 INV_PGRP_NAME, &gnm); 433 if (e != 0) { 434 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 435 "pad lookup (%s) failed.\n", 436 INV_PGRP_NAME); 437 return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP)); 438 } 439 e = nvlist_lookup_string(pad->tpad_pgs[pg], 440 INV_PGRP_NMSTAB, &nmstab); 441 if (e != 0) { 442 if (e != ENOENT) { 443 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 444 "pad lookup (%s) " 445 "failed.\n", INV_PGRP_NMSTAB); 446 return (topo_mod_seterrno(mp, 447 ETOPO_PRSR_NVPROP)); 448 } else { 449 nmstab = TOPO_STABSTR_PRIVATE; 450 } 451 } 452 e = nvlist_lookup_string(pad->tpad_pgs[pg], 453 INV_PGRP_DSTAB, &dstab); 454 if (e != 0) { 455 if (e != ENOENT) { 456 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 457 "pad lookup (%s) failed.\n", 458 INV_PGRP_DSTAB); 459 return (topo_mod_seterrno(mp, 460 ETOPO_PRSR_NVPROP)); 461 } else { 462 dstab = TOPO_STABSTR_PRIVATE; 463 } 464 } 465 e = nvlist_lookup_uint32(pad->tpad_pgs[pg], 466 INV_PGRP_VER, &gv); 467 if (e != 0) { 468 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 469 "pad lookup (%s) failed.\n", 470 INV_PGRP_VER); 471 return (topo_mod_seterrno(mp, ETOPO_PRSR_NVPROP)); 472 } 473 pgi.tpi_name = gnm; 474 pgi.tpi_namestab = topo_name2stability(nmstab); 475 pgi.tpi_datastab = topo_name2stability(dstab); 476 pgi.tpi_version = gv; 477 if (topo_pgroup_create(ptn, &pgi, &e) != 0) { 478 if (e != ETOPO_PROP_DEFD) { 479 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 480 "pgroups create failure: %s\n", 481 topo_strerror(e)); 482 return (-1); 483 } 484 } 485 e = nvlist_lookup_uint32(pad->tpad_pgs[pg], 486 INV_PGRP_NPROP, &rnprops); 487 e |= nvlist_lookup_nvlist_array(pad->tpad_pgs[pg], 488 INV_PGRP_ALLPROPS, &props, &nprops); 489 if (rnprops != nprops) { 490 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 491 "recorded number of props %d does not " 492 "match number of props recorded %d.\n", 493 rnprops, nprops); 494 } 495 if (props_create(mp, ptn, gnm, props, nprops) < 0) 496 return (-1); 497 } 498 return (0); 499 } 500 501 static nvlist_t * 502 pval_record(topo_mod_t *mp, xmlNodePtr xn) 503 { 504 nvlist_t *pnvl = NULL; 505 xmlChar *pname; 506 507 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pval record\n"); 508 if ((pname = xmlGetProp(xn, (xmlChar *)Name)) == NULL) { 509 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 510 "propval lacks a name\n"); 511 (void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR); 512 return (NULL); 513 } 514 if (topo_mod_nvalloc(mp, &pnvl, NV_UNIQUE_NAME) < 0) { 515 xmlFree(pname); 516 return (NULL); 517 } 518 if (nvlist_add_string(pnvl, INV_PNAME, (char *)pname) < 0) { 519 xmlFree(pname); 520 nvlist_free(pnvl); 521 return (NULL); 522 } 523 xmlFree(pname); 524 /* FMXXX stability of the property name */ 525 526 if (xmlprop_xlate(mp, xn, pnvl) < 0) { 527 nvlist_free(pnvl); 528 return (NULL); 529 } 530 return (pnvl); 531 } 532 533 static int 534 pgroup_record(topo_mod_t *mp, xmlNodePtr pxn, tf_pad_t *rpad, int pi) 535 { 536 topo_stability_t nmstab, dstab; 537 uint64_t ver; 538 xmlNodePtr cn; 539 xmlChar *name; 540 nvlist_t **apl = NULL; 541 nvlist_t *pgnvl = NULL; 542 int pcnt = 0; 543 int ai = 0; 544 int e; 545 546 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroup record\n"); 547 if ((name = xmlGetProp(pxn, (xmlChar *)Name)) == NULL) { 548 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 549 "propgroup lacks a name\n"); 550 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR)); 551 } 552 if (xmlattr_to_int(mp, pxn, Version, &ver) < 0) { 553 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 554 "propgroup lacks a version\n"); 555 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR)); 556 } 557 if (xmlattr_to_stab(mp, pxn, Namestab, &nmstab) < 0) { 558 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 559 "propgroup lacks name-stability\n"); 560 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR)); 561 } 562 if (xmlattr_to_stab(mp, pxn, Datastab, &dstab) < 0) { 563 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 564 "propgroup lacks data-stability\n"); 565 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR)); 566 } 567 568 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroup %s\n", (char *)name); 569 for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) { 570 if (xmlStrcmp(cn->name, (xmlChar *)Propval) == 0) 571 pcnt++; 572 } 573 574 if (topo_mod_nvalloc(mp, &pgnvl, NV_UNIQUE_NAME) < 0) { 575 xmlFree(name); 576 return (-1); 577 } 578 579 e = nvlist_add_string(pgnvl, INV_PGRP_NAME, (char *)name); 580 e |= nvlist_add_uint32(pgnvl, INV_PGRP_NMSTAB, nmstab); 581 e |= nvlist_add_uint32(pgnvl, INV_PGRP_DSTAB, dstab); 582 e |= nvlist_add_uint32(pgnvl, INV_PGRP_VER, ver); 583 e |= nvlist_add_uint32(pgnvl, INV_PGRP_NPROP, pcnt); 584 if (e != 0 || 585 (apl = topo_mod_zalloc(mp, pcnt * sizeof (nvlist_t *))) == NULL) { 586 xmlFree(name); 587 nvlist_free(pgnvl); 588 return (-1); 589 } 590 for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) { 591 if (xmlStrcmp(cn->name, (xmlChar *)Propval) == 0) { 592 if (ai < pcnt) { 593 if ((apl[ai] = pval_record(mp, cn)) == NULL) 594 break; 595 } 596 ai++; 597 } 598 } 599 xmlFree(name); 600 e |= (ai != pcnt); 601 e |= nvlist_add_nvlist_array(pgnvl, INV_PGRP_ALLPROPS, apl, pcnt); 602 for (ai = 0; ai < pcnt; ai++) 603 if (apl[ai] != NULL) 604 nvlist_free(apl[ai]); 605 topo_mod_free(mp, apl, pcnt * sizeof (nvlist_t *)); 606 if (e != 0) { 607 nvlist_free(pgnvl); 608 return (-1); 609 } 610 rpad->tpad_pgs[pi] = pgnvl; 611 return (0); 612 } 613 614 static int 615 pgroups_record(topo_mod_t *mp, xmlNodePtr pxn, tf_pad_t *rpad) 616 { 617 xmlNodePtr cn; 618 int pi = 0; 619 620 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "pgroups record\n"); 621 for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) { 622 if (xmlStrcmp(cn->name, (xmlChar *)Propgrp) == 0) { 623 if (pgroup_record(mp, cn, rpad, pi++) < 0) 624 return (-1); 625 } 626 } 627 return (0); 628 } 629 630 /* 631 * Process the property group and dependents xmlNode children of 632 * parent xmlNode pxn. 633 */ 634 static int 635 pad_process(topo_mod_t *mp, 636 tf_info_t *xinfo, xmlNodePtr pxn, tnode_t *ptn, tf_pad_t **rpad) 637 { 638 xmlNodePtr cn; 639 tf_pad_t *new = *rpad; 640 int pgcnt = 0; 641 int dcnt = 0; 642 643 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 644 "pad process beneath %s\n", topo_node_name(ptn)); 645 if (new == NULL) { 646 for (cn = pxn->xmlChildrenNode; cn != NULL; cn = cn->next) { 647 if (xmlStrcmp(cn->name, (xmlChar *)Dependents) == 0) 648 dcnt++; 649 else if (xmlStrcmp(cn->name, (xmlChar *)Propgrp) == 0) 650 pgcnt++; 651 } 652 if ((new = tf_pad_new(mp, pgcnt, dcnt)) == NULL) 653 return (-1); 654 if (dcnt == 0 && pgcnt == 0) { 655 *rpad = new; 656 return (0); 657 } 658 659 if (pgcnt > 0) { 660 new->tpad_pgs = 661 topo_mod_zalloc(mp, pgcnt * sizeof (nvlist_t *)); 662 if (new->tpad_pgs == NULL) { 663 tf_pad_free(mp, new); 664 return (NULL); 665 } 666 if (pgroups_record(mp, pxn, new) < 0) { 667 tf_pad_free(mp, new); 668 return (NULL); 669 } 670 } 671 *rpad = new; 672 } 673 674 if (new->tpad_dcnt > 0) 675 if (dependents_create(mp, xinfo, new, pxn, ptn) < 0) 676 return (-1); 677 678 if (new->tpad_pgcnt > 0) 679 if (pgroups_create(mp, new, ptn) < 0) 680 return (-1); 681 return (0); 682 } 683 684 static int 685 node_process(topo_mod_t *mp, xmlNodePtr nn, tf_rdata_t *rd) 686 { 687 xmlChar *str; 688 topo_instance_t inst; 689 tf_idata_t *newi; 690 tnode_t *ntn; 691 uint64_t ui; 692 int rv = -1; 693 int s = 0; 694 695 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 696 "node process %s\n", rd->rd_name); 697 698 if (xmlattr_to_int(mp, nn, Instance, &ui) < 0) 699 goto nodedone; 700 inst = (topo_instance_t)ui; 701 702 if ((str = xmlGetProp(nn, (xmlChar *)Static)) != NULL) { 703 if (xmlStrcmp(str, (xmlChar *)True) == 0) 704 s = 1; 705 xmlFree(str); 706 } 707 708 if (s == 0) { 709 if (topo_mod_enumerate(rd->rd_mod, rd->rd_pn, 710 rd->rd_finfo->tf_scheme, rd->rd_name, inst, inst, 711 s == 1 ? &s : NULL) < 0) 712 goto nodedone; 713 } 714 ntn = topo_node_lookup(rd->rd_pn, rd->rd_name, inst); 715 if (ntn == NULL) { 716 717 /* 718 * If this is a static node declaration, we can 719 * ignore the lookup failure and continue 720 * processing. Otherwise, something 721 * went wrong during enumeration 722 */ 723 if (s == 1) 724 rv = 0; 725 goto nodedone; 726 } 727 728 if ((newi = tf_idata_new(mp, inst, ntn)) == NULL) { 729 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 730 "tf_idata_new failed.\n"); 731 goto nodedone; 732 } 733 if (tf_idata_insert(&rd->rd_instances, newi) < 0) { 734 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 735 "tf_idata_insert failed.\n"); 736 goto nodedone; 737 } 738 if (pad_process(mp, rd->rd_finfo, nn, ntn, &newi->ti_pad) < 0) 739 goto nodedone; 740 rv = 0; 741 nodedone: 742 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "done with node %s.\n", 743 rd->rd_name); 744 return (rv); 745 } 746 747 static tf_edata_t * 748 enum_attributes_process(topo_mod_t *mp, xmlNodePtr en) 749 { 750 tf_edata_t *einfo; 751 uint64_t ui; 752 753 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "enum attributes process\n"); 754 if ((einfo = topo_mod_zalloc(mp, sizeof (tf_edata_t))) == NULL) { 755 (void) topo_mod_seterrno(mp, ETOPO_NOMEM); 756 return (NULL); 757 } 758 einfo->te_name = (char *)xmlGetProp(en, (xmlChar *)Name); 759 if (einfo->te_name == NULL) { 760 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 761 "Enumerator name attribute missing.\n"); 762 (void) topo_mod_seterrno(mp, ETOPO_PRSR_NOATTR); 763 goto enodedone; 764 } 765 766 /* 767 * Check for recursive enumeration 768 */ 769 if (strcmp(einfo->te_name, mp->tm_name) == 0) { 770 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 771 "Recursive enumeration detected for %s\n", 772 einfo->te_name); 773 (void) topo_mod_seterrno(mp, ETOPO_ENUM_RECURS); 774 goto enodedone; 775 } 776 if (xmlattr_to_int(mp, en, Version, &ui) < 0) 777 goto enodedone; 778 einfo->te_vers = (int)ui; 779 780 return (einfo); 781 782 enodedone: 783 if (einfo->te_name != NULL) 784 xmlFree(einfo->te_name); 785 return (NULL); 786 } 787 788 static int 789 enum_run(topo_mod_t *mp, tf_rdata_t *rd) 790 { 791 topo_hdl_t *thp = mp->tm_hdl; 792 int e = -1; 793 794 /* 795 * Check if the enumerator module is already loaded. 796 * Module loading is single-threaded at this point so there's 797 * no need to worry about the module going away or bumping the 798 * ref count. 799 */ 800 if ((rd->rd_mod = topo_mod_lookup(thp, rd->rd_einfo->te_name, 801 0)) == NULL) { 802 if ((rd->rd_mod = topo_mod_load(mp, rd->rd_einfo->te_name, 803 rd->rd_einfo->te_vers)) == NULL) { 804 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 805 "mod_load of %s failed: %s.\n", 806 rd->rd_einfo->te_name, 807 topo_strerror(topo_mod_errno(mp))); 808 (void) topo_hdl_seterrno(thp, topo_mod_errno(mp)); 809 return (e); 810 } 811 } 812 /* 813 * We're live, so let's enumerate. 814 */ 815 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "enumerate request. (%s)\n", 816 rd->rd_einfo->te_name); 817 e = topo_mod_enumerate(rd->rd_mod, rd->rd_pn, rd->rd_einfo->te_name, 818 rd->rd_name, rd->rd_min, rd->rd_max, NULL); 819 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "back from enumeration. %d\n", 820 e); 821 if (e != 0) { 822 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 823 "Enumeration failed (%s)\n", 824 topo_strerror(topo_mod_errno(mp))); 825 (void) topo_hdl_seterrno(thp, EMOD_PARTIAL_ENUM); 826 return (topo_mod_seterrno(mp, EMOD_PARTIAL_ENUM)); 827 } 828 return (e); 829 } 830 831 int 832 topo_xml_range_process(topo_mod_t *mp, xmlNodePtr rn, tf_rdata_t *rd) 833 { 834 /* 835 * The range may have several children xmlNodes, that may 836 * represent the enumeration method, property groups, 837 * dependents or nodes. 838 */ 839 xmlNodePtr cn; 840 tnode_t *ct; 841 int e; 842 843 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "process %s range beneath %s\n", 844 rd->rd_name, topo_node_name(rd->rd_pn)); 845 e = topo_node_range_create(mp, 846 rd->rd_pn, rd->rd_name, rd->rd_min, rd->rd_max); 847 if (e != 0 && topo_mod_errno(mp) != ETOPO_NODE_DUP) { 848 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 849 "Range create failed due to %s.\n", 850 topo_strerror(topo_mod_errno(mp))); 851 return (-1); 852 } 853 for (cn = rn->xmlChildrenNode; cn != NULL; cn = cn->next) 854 if (xmlStrcmp(cn->name, (xmlChar *)Enum_meth) == 0) 855 break; 856 857 if (cn != NULL) { 858 if ((rd->rd_einfo = enum_attributes_process(mp, cn)) == NULL) 859 return (-1); 860 if (enum_run(mp, rd) < 0) { 861 /* 862 * Note the failure but continue on 863 */ 864 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 865 "Enumeration failed.\n"); 866 } 867 } 868 869 /* Now look for nodes, i.e., hard instances */ 870 for (cn = rn->xmlChildrenNode; cn != NULL; cn = cn->next) { 871 if (xmlStrcmp(cn->name, (xmlChar *)Node) == 0) 872 if (node_process(mp, cn, rd) < 0) { 873 topo_dprintf(mp->tm_hdl, TOPO_DBG_ERR, 874 "node processing failed: %s.\n", 875 topo_strerror(topo_mod_errno(mp))); 876 return (topo_mod_seterrno(mp, 877 EMOD_PARTIAL_ENUM)); 878 } 879 } 880 881 /* Property groups and Dependencies */ 882 ct = topo_child_first(rd->rd_pn); 883 while (ct != NULL) { 884 /* Only care about instances within the range */ 885 if (strcmp(topo_node_name(ct), rd->rd_name) != 0) { 886 ct = topo_child_next(rd->rd_pn, ct); 887 continue; 888 } 889 if (pad_process(mp, rd->rd_finfo, rn, ct, &rd->rd_pad) < 0) 890 return (-1); 891 ct = topo_child_next(rd->rd_pn, ct); 892 } 893 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "end range process %s\n", 894 rd->rd_name); 895 return (0); 896 } 897 898 static tf_rdata_t * 899 topo_xml_walk(topo_mod_t *mp, 900 tf_info_t *xinfo, xmlNodePtr croot, tnode_t *troot) 901 { 902 xmlNodePtr curr; 903 tf_rdata_t *rr, *pr, *rdp; 904 905 /* 906 * What we're interested in are children xmlNodes of croot tagged 907 * as 'ranges', these define topology nodes may exist, and need 908 * to be verified. 909 */ 910 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, "topo_xml_walk\n"); 911 rr = pr = NULL; 912 for (curr = croot->xmlChildrenNode; curr != NULL; curr = curr->next) { 913 if (curr->name == NULL) { 914 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 915 "Ignoring nameless xmlnode\n"); 916 continue; 917 } 918 if (xmlStrcmp(curr->name, (xmlChar *)Range) != 0) { 919 topo_dprintf(mp->tm_hdl, TOPO_DBG_XML, 920 "Ignoring non-range %s.\n", curr->name); 921 continue; 922 } 923 if ((rdp = tf_rdata_new(mp, xinfo, curr, troot)) == NULL) { 924 tf_rdata_free(mp, rr); 925 return (NULL); 926 } 927 if (pr == NULL) { 928 rr = pr = rdp; 929 } else { 930 pr->rd_next = rdp; 931 pr = rdp; 932 } 933 rr->rd_cnt++; 934 } 935 return (rr); 936 } 937 938 /* 939 * Convert parsed xml topology description into topology nodes 940 */ 941 int 942 topo_xml_enum(topo_mod_t *tmp, tf_info_t *xinfo, tnode_t *troot) 943 { 944 xmlNodePtr xroot; 945 946 if ((xroot = xmlDocGetRootElement(xinfo->tf_xdoc)) == NULL) { 947 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 948 "Couldn't get root xmlNode.\n"); 949 return (-1); 950 } 951 if ((xinfo->tf_rd = topo_xml_walk(tmp, xinfo, xroot, troot)) == NULL) { 952 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 953 "error within .xml topology: %s\n", 954 topo_strerror(topo_mod_errno(tmp))); 955 return (-1); 956 } 957 return (0); 958 } 959 960 /* 961 * Load an XML tree from filename and read it into a DOM parse tree. 962 */ 963 static tf_info_t * 964 txml_file_parse(topo_mod_t *tmp, 965 int fd, const char *filenm, const char *escheme) 966 { 967 xmlValidCtxtPtr vcp; 968 xmlNodePtr cursor; 969 xmlDocPtr document; 970 xmlDtdPtr dtd = NULL; 971 xmlChar *scheme = NULL; 972 char *dtdpath = NULL; 973 int readflags = 0; 974 tf_info_t *r; 975 int e, validate = 0; 976 977 /* 978 * Since topologies can XInclude other topologies, and libxml2 979 * doesn't do DTD-based validation with XInclude, by default 980 * we don't validate topology files. One can force 981 * validation, though, by creating a TOPOXML_VALIDATE 982 * environment variable and creating a TOPO_DTD environment 983 * variable with the path to the DTD against which to validate. 984 */ 985 if (getenv("TOPOXML_VALIDATE") != NULL) { 986 dtdpath = getenv("TOPO_DTD"); 987 if (dtdpath != NULL) 988 xmlLoadExtDtdDefaultValue = 0; 989 validate = 1; 990 } 991 992 /* 993 * Splat warnings and errors related to parsing the topology 994 * file if the TOPOXML_PERROR environment variable exists. 995 */ 996 if (getenv("TOPOXML_PERROR") == NULL) 997 readflags = XML_PARSE_NOERROR | XML_PARSE_NOWARNING; 998 999 if ((document = xmlReadFd(fd, filenm, NULL, readflags)) == NULL) { 1000 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1001 "couldn't parse document.\n"); 1002 return (NULL); 1003 } 1004 1005 /* 1006 * Verify that this is a document type we understand. 1007 */ 1008 if ((dtd = xmlGetIntSubset(document)) == NULL) { 1009 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1010 "document has no DTD.\n"); 1011 return (NULL); 1012 } 1013 1014 if (strcmp((const char *)dtd->SystemID, TOPO_DTD_PATH) != 0) { 1015 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1016 "document DTD unknown; bad topology file\n"); 1017 return (NULL); 1018 } 1019 1020 if ((cursor = xmlDocGetRootElement(document)) == NULL) { 1021 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, "document is empty.\n"); 1022 xmlFreeDoc(document); 1023 return (NULL); 1024 } 1025 1026 /* 1027 * Make sure we're looking at a topology description in the 1028 * expected scheme. 1029 */ 1030 if (xmlStrcmp(cursor->name, (xmlChar *)Topology) != 0) { 1031 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1032 "document is not a topology description.\n"); 1033 xmlFreeDoc(document); 1034 return (NULL); 1035 } 1036 if ((scheme = xmlGetProp(cursor, (xmlChar *)Scheme)) == NULL) { 1037 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1038 "topology lacks a scheme.\n"); 1039 (void) topo_mod_seterrno(tmp, ETOPO_PRSR_NOATTR); 1040 xmlFreeDoc(document); 1041 return (NULL); 1042 } 1043 if (xmlStrcmp(scheme, (xmlChar *)escheme) != 0) { 1044 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1045 "topology in unrecognized scheme, %s, expecting %s\n", 1046 scheme, escheme); 1047 (void) topo_mod_seterrno(tmp, ETOPO_PRSR_BADSCH); 1048 xmlFree(scheme); 1049 xmlFreeDoc(document); 1050 return (NULL); 1051 } 1052 1053 if (dtdpath != NULL) { 1054 dtd = xmlParseDTD(NULL, (xmlChar *)dtdpath); 1055 if (dtd == NULL) { 1056 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1057 "Could not parse DTD \"%s\".\n", 1058 dtdpath); 1059 return (NULL); 1060 } 1061 1062 if (document->extSubset != NULL) 1063 xmlFreeDtd(document->extSubset); 1064 1065 document->extSubset = dtd; 1066 } 1067 1068 if (xmlXIncludeProcessFlags(document, XML_PARSE_XINCLUDE) == -1) {; 1069 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1070 "couldn't handle XInclude statements in document\n"); 1071 return (NULL); 1072 } 1073 1074 if (validate) { 1075 if ((vcp = xmlNewValidCtxt()) == NULL) { 1076 xmlFree(scheme); 1077 scheme = NULL; 1078 return (NULL); 1079 } 1080 vcp->warning = xmlParserValidityWarning; 1081 vcp->error = xmlParserValidityError; 1082 1083 e = xmlValidateDocument(vcp, document); 1084 1085 xmlFreeValidCtxt(vcp); 1086 1087 if (e == 0) 1088 topo_dprintf(tmp->tm_hdl, TOPO_DBG_ERR, 1089 "Document is not valid.\n"); 1090 } 1091 1092 if ((r = tf_info_new(tmp, document, scheme)) == NULL) 1093 return (NULL); 1094 1095 xmlFree(scheme); 1096 scheme = NULL; 1097 return (r); 1098 } 1099 1100 static int 1101 txml_file_open(topo_mod_t *mp, const char *filename) 1102 { 1103 int rfd; 1104 if ((rfd = open(filename, O_RDONLY)) < 0) 1105 return (topo_mod_seterrno(mp, ETOPO_PRSR_NOENT)); 1106 return (rfd); 1107 } 1108 1109 tf_info_t * 1110 topo_xml_read(topo_mod_t *tmp, const char *path, const char *escheme) 1111 { 1112 int fd; 1113 tf_info_t *tip; 1114 1115 if ((fd = txml_file_open(tmp, path)) < 0) { 1116 return (NULL); 1117 } 1118 tip = txml_file_parse(tmp, fd, path, escheme); 1119 (void) close(fd); 1120 return (tip); 1121 } 1122