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