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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <strings.h> 29 #include <assert.h> 30 #include <fm/libtopo.h> 31 #include <topo_prop.h> 32 #include <topo_string.h> 33 #include <topo_alloc.h> 34 #include <topo_error.h> 35 #include <topo_method.h> 36 37 /* 38 * Topology nodes are permitted to contain property information. 39 * Property information is organized according to property grouping. 40 * Each property group defines a name, a stability level for that name, 41 * a stability level for all underlying property data (name, type, values), 42 * a version for the property group definition and and a list of uniquely 43 * defined properties. Property group versions are incremented when one of 44 * the following changes occurs: 45 * - a property name changes 46 * - a property type changes 47 * - a property definition is removed from the group 48 * Compatible changes such as new property definitions in the group do 49 * not require version changes. 50 * 51 * Each property defines a unique (within the group) name, a type and 52 * a value. Properties may be statically defined as int32, uint32, int64, 53 * uint64, fmri, string or arrays of each type. Properties may also be 54 * dynamically exported via module registered methods. For example, a module 55 * may register a method to export an ASRU property that is dynamically 56 * contructed when a call to topo_node_fmri() is invoked for a particular 57 * topology node. 58 * 59 * Static properties are persistently attached to topology nodes during 60 * enumeration by an enumeration module or as part of XML statements in a 61 * toplogy map file using the topo_prop_set* family of routines. Similarly, 62 * property methods are registered during enumeration or as part of 63 * statements in topololgy map files. Set-up of property methods is performed 64 * by calling topo_prop_method_register(). 65 * 66 * All properties, whether statically persisted in a snapshot or dynamically 67 * obtained, may be read via the topo_prop_get* family of interfaces. 68 * Callers wishing to receive all property groups and properties for a given 69 * node may use topo_prop_getall(). This routine returns a nested nvlist 70 * of all groupings and property (name, type, value) sets. Groupings 71 * are defined by TOPO_PROP_GROUP (name, data stability, name stability and 72 * version) and a nested nvlist of properties (TOPO_PROP_VAL). Each property 73 * value is defined by its name, type and value. 74 */ 75 static void topo_propval_destroy(topo_propval_t *); 76 77 static topo_pgroup_t * 78 pgroup_get(tnode_t *node, const char *pgname) 79 { 80 topo_pgroup_t *pg; 81 /* 82 * Check for an existing pgroup 83 */ 84 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; 85 pg = topo_list_next(pg)) { 86 if (strcmp(pg->tpg_info->tpi_name, pgname) == 0) { 87 return (pg); 88 } 89 } 90 91 return (NULL); 92 } 93 94 static topo_propval_t * 95 propval_get(topo_pgroup_t *pg, const char *pname) 96 { 97 topo_proplist_t *pvl; 98 99 if (pg == NULL) 100 return (NULL); 101 102 for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL; 103 pvl = topo_list_next(pvl)) { 104 if (strcmp(pvl->tp_pval->tp_name, pname) == 0) 105 return (pvl->tp_pval); 106 } 107 108 return (NULL); 109 } 110 111 static int 112 method_geterror(nvlist_t *nvl, int err, int *errp) 113 { 114 if (nvl != NULL) 115 nvlist_free(nvl); 116 117 *errp = err; 118 119 return (-1); 120 } 121 122 static int 123 prop_method_get(tnode_t *node, topo_propval_t *pv, topo_propmethod_t *pm, 124 nvlist_t *pargs, int *err) 125 { 126 int ret; 127 nvlist_t *args, *nvl; 128 char *name; 129 topo_type_t type; 130 131 if (topo_hdl_nvalloc(pv->tp_hdl, &args, NV_UNIQUE_NAME) < 0 || 132 nvlist_add_nvlist(args, TOPO_PROP_ARGS, pm->tpm_args) != 0) 133 return (method_geterror(NULL, ETOPO_PROP_NVL, err)); 134 135 if (pargs != NULL) 136 if (nvlist_add_nvlist(args, TOPO_PROP_PARGS, pargs) != 0) 137 return (method_geterror(args, ETOPO_PROP_NVL, err)); 138 139 /* 140 * Now, get the latest value 141 * 142 * Grab a reference to the property and then unlock the node. This will 143 * allow property methods to safely re-enter the prop_get codepath, 144 * making it possible for property methods to access other property 145 * values on the same node w\o causing a deadlock. 146 */ 147 topo_prop_hold(pv); 148 topo_node_unlock(node); 149 if (topo_method_call(node, pm->tpm_name, pm->tpm_version, 150 args, &nvl, err) < 0) { 151 topo_node_lock(node); 152 topo_prop_rele(pv); 153 return (method_geterror(args, *err, err)); 154 } 155 topo_node_lock(node); 156 topo_prop_rele(pv); 157 158 nvlist_free(args); 159 160 /* Verify the property contents */ 161 ret = nvlist_lookup_string(nvl, TOPO_PROP_VAL_NAME, &name); 162 if (ret != 0 || strcmp(name, pv->tp_name) != 0) 163 return (method_geterror(nvl, ETOPO_PROP_NAME, err)); 164 165 ret = nvlist_lookup_uint32(nvl, TOPO_PROP_VAL_TYPE, (uint32_t *)&type); 166 if (ret != 0 || type != pv->tp_type) 167 return (method_geterror(nvl, ETOPO_PROP_TYPE, err)); 168 169 /* Release the last value and re-assign to the new value */ 170 if (pv->tp_val != NULL) 171 nvlist_free(pv->tp_val); 172 pv->tp_val = nvl; 173 174 return (0); 175 } 176 177 static topo_propval_t * 178 prop_get(tnode_t *node, const char *pgname, const char *pname, nvlist_t *pargs, 179 int *err) 180 { 181 topo_propval_t *pv = NULL; 182 183 if ((pv = propval_get(pgroup_get(node, pgname), pname)) == NULL) { 184 *err = ETOPO_PROP_NOENT; 185 return (NULL); 186 } 187 188 if (pv->tp_method != NULL) { 189 if (prop_method_get(node, pv, pv->tp_method, pargs, err) < 0) 190 return (NULL); 191 } 192 193 return (pv); 194 } 195 196 static int 197 get_properror(tnode_t *node, int *errp, int err) 198 { 199 topo_node_unlock(node); 200 *errp = err; 201 return (-1); 202 } 203 204 static int 205 prop_getval(tnode_t *node, const char *pgname, const char *pname, void *val, 206 topo_type_t type, uint_t *nelems, int *err) 207 { 208 int i, j, ret = 0; 209 topo_hdl_t *thp = node->tn_hdl; 210 topo_propval_t *pv; 211 212 topo_node_lock(node); 213 if ((pv = prop_get(node, pgname, pname, NULL, err)) 214 == NULL) 215 return (get_properror(node, err, *err)); 216 217 if (pv->tp_type != type) 218 return (get_properror(node, err, ETOPO_PROP_TYPE)); 219 220 switch (type) { 221 case TOPO_TYPE_INT32: 222 ret = nvlist_lookup_int32(pv->tp_val, TOPO_PROP_VAL_VAL, 223 (int32_t *)val); 224 break; 225 case TOPO_TYPE_UINT32: 226 ret = nvlist_lookup_uint32(pv->tp_val, 227 TOPO_PROP_VAL_VAL, (uint32_t *)val); 228 break; 229 case TOPO_TYPE_INT64: 230 ret = nvlist_lookup_int64(pv->tp_val, TOPO_PROP_VAL_VAL, 231 (int64_t *)val); 232 break; 233 case TOPO_TYPE_UINT64: 234 ret = nvlist_lookup_uint64(pv->tp_val, 235 TOPO_PROP_VAL_VAL, (uint64_t *)val); 236 break; 237 case TOPO_TYPE_STRING: { 238 char *str; 239 240 ret = nvlist_lookup_string(pv->tp_val, 241 TOPO_PROP_VAL_VAL, &str); 242 if (ret == 0) { 243 char *s2; 244 if ((s2 = topo_hdl_strdup(thp, str)) == NULL) 245 ret = -1; 246 else 247 *(char **)val = s2; 248 } 249 break; 250 } 251 case TOPO_TYPE_FMRI: { 252 nvlist_t *nvl; 253 254 ret = nvlist_lookup_nvlist(pv->tp_val, 255 TOPO_PROP_VAL_VAL, &nvl); 256 if (ret == 0) 257 ret = topo_hdl_nvdup(thp, nvl, 258 (nvlist_t **)val); 259 break; 260 } 261 case TOPO_TYPE_INT32_ARRAY: { 262 int32_t *a1, *a2; 263 264 if ((ret = nvlist_lookup_int32_array(pv->tp_val, 265 TOPO_PROP_VAL_VAL, &a2, nelems)) != 0) 266 break; 267 if ((a1 = topo_hdl_alloc(thp, sizeof (int32_t) * 268 *nelems)) == NULL) { 269 ret = ETOPO_NOMEM; 270 break; 271 } 272 for (i = 0; i < *nelems; ++i) 273 a1[i] = a2[i]; 274 *(int32_t **)val = a1; 275 break; 276 } 277 case TOPO_TYPE_UINT32_ARRAY: { 278 uint32_t *a1, *a2; 279 280 if ((ret = nvlist_lookup_uint32_array(pv->tp_val, 281 TOPO_PROP_VAL_VAL, &a2, nelems)) != 0) 282 break; 283 if ((a1 = topo_hdl_alloc(thp, sizeof (uint32_t) * 284 *nelems)) == NULL) { 285 ret = ETOPO_NOMEM; 286 break; 287 } 288 for (i = 0; i < *nelems; ++i) 289 a1[i] = a2[i]; 290 *(uint32_t **)val = a1; 291 break; 292 } 293 case TOPO_TYPE_INT64_ARRAY: { 294 int64_t *a1, *a2; 295 296 if ((ret = nvlist_lookup_int64_array(pv->tp_val, 297 TOPO_PROP_VAL_VAL, &a2, nelems)) != 0) 298 break; 299 if ((a1 = topo_hdl_alloc(thp, sizeof (int64_t) * 300 *nelems)) == NULL) { 301 ret = ETOPO_NOMEM; 302 break; 303 } 304 for (i = 0; i < *nelems; ++i) 305 a1[i] = a2[i]; 306 *(int64_t **)val = a1; 307 break; 308 } 309 case TOPO_TYPE_UINT64_ARRAY: { 310 uint64_t *a1, *a2; 311 312 if ((ret = nvlist_lookup_uint64_array(pv->tp_val, 313 TOPO_PROP_VAL_VAL, &a2, nelems)) != 0) 314 break; 315 if ((a1 = topo_hdl_alloc(thp, sizeof (uint64_t) * 316 *nelems)) == NULL) { 317 ret = ETOPO_NOMEM; 318 break; 319 } 320 for (i = 0; i < *nelems; ++i) 321 a1[i] = a2[i]; 322 *(uint64_t **)val = a1; 323 break; 324 } 325 case TOPO_TYPE_STRING_ARRAY: { 326 char **a1, **a2; 327 328 if ((ret = nvlist_lookup_string_array(pv->tp_val, 329 TOPO_PROP_VAL_VAL, &a2, nelems)) != 0) 330 break; 331 if ((a1 = topo_hdl_alloc(thp, sizeof (char *) * 332 *nelems)) == NULL) { 333 ret = ETOPO_NOMEM; 334 break; 335 } 336 for (i = 0; i < *nelems; ++i) { 337 if ((a1[i] = topo_hdl_strdup(thp, a2[i])) 338 == NULL) { 339 for (j = 0; j < i; ++j) 340 topo_hdl_free(thp, a1[j], 341 sizeof (char *)); 342 topo_hdl_free(thp, a1, 343 sizeof (char *) * *nelems); 344 break; 345 } 346 } 347 *(char ***)val = a1; 348 break; 349 } 350 case TOPO_TYPE_FMRI_ARRAY: { 351 nvlist_t **a1, **a2; 352 353 if ((ret = nvlist_lookup_nvlist_array(pv->tp_val, 354 TOPO_PROP_VAL_VAL, &a2, nelems)) != 0) 355 break; 356 if ((a1 = topo_hdl_alloc(thp, sizeof (nvlist_t *) * 357 *nelems)) == NULL) { 358 ret = ETOPO_NOMEM; 359 break; 360 } 361 for (i = 0; i < *nelems; ++i) { 362 if (topo_hdl_nvdup(thp, a2[i], &a1[i]) < 0) { 363 for (j = 0; j < i; ++j) 364 nvlist_free(a1[j]); 365 topo_hdl_free(thp, a1, 366 sizeof (nvlist_t *) * *nelems); 367 break; 368 } 369 } 370 *(nvlist_t ***)val = a1; 371 break; 372 } 373 default: 374 ret = ETOPO_PROP_NOENT; 375 } 376 377 if (ret != 0) 378 if (ret == ENOENT) 379 return (get_properror(node, err, ETOPO_PROP_NOENT)); 380 else if (ret < ETOPO_UNKNOWN) 381 return (get_properror(node, err, ETOPO_PROP_NVL)); 382 else 383 return (get_properror(node, err, ret)); 384 385 topo_node_unlock(node); 386 return (0); 387 } 388 389 int 390 topo_prop_get_int32(tnode_t *node, const char *pgname, const char *pname, 391 int32_t *val, int *err) 392 { 393 return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_INT32, 394 NULL, err)); 395 } 396 397 int 398 topo_prop_get_uint32(tnode_t *node, const char *pgname, const char *pname, 399 uint32_t *val, int *err) 400 { 401 return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_UINT32, 402 NULL, err)); 403 } 404 405 int 406 topo_prop_get_int64(tnode_t *node, const char *pgname, const char *pname, 407 int64_t *val, int *err) 408 { 409 return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_INT64, 410 NULL, err)); 411 } 412 413 int 414 topo_prop_get_uint64(tnode_t *node, const char *pgname, const char *pname, 415 uint64_t *val, int *err) 416 { 417 return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_UINT64, 418 NULL, err)); 419 } 420 421 int 422 topo_prop_get_string(tnode_t *node, const char *pgname, const char *pname, 423 char **val, int *err) 424 { 425 return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_STRING, 426 NULL, err)); 427 } 428 429 int 430 topo_prop_get_fmri(tnode_t *node, const char *pgname, const char *pname, 431 nvlist_t **val, int *err) 432 { 433 return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_FMRI, 434 NULL, err)); 435 } 436 437 int 438 topo_prop_get_int32_array(tnode_t *node, const char *pgname, const char *pname, 439 int32_t **val, uint_t *nelem, int *err) 440 { 441 return (prop_getval(node, pgname, pname, (void *)val, 442 TOPO_TYPE_INT32_ARRAY, nelem, err)); 443 } 444 445 int 446 topo_prop_get_uint32_array(tnode_t *node, const char *pgname, const char *pname, 447 uint32_t **val, uint_t *nelem, int *err) 448 { 449 return (prop_getval(node, pgname, pname, (void *)val, 450 TOPO_TYPE_UINT32_ARRAY, nelem, err)); 451 } 452 453 int 454 topo_prop_get_int64_array(tnode_t *node, const char *pgname, const char *pname, 455 int64_t **val, uint_t *nelem, int *err) 456 { 457 return (prop_getval(node, pgname, pname, (void *)val, 458 TOPO_TYPE_INT64_ARRAY, nelem, err)); 459 } 460 461 int 462 topo_prop_get_uint64_array(tnode_t *node, const char *pgname, const char *pname, 463 uint64_t **val, uint_t *nelem, int *err) 464 { 465 return (prop_getval(node, pgname, pname, (void *)val, 466 TOPO_TYPE_UINT64_ARRAY, nelem, err)); 467 } 468 469 int 470 topo_prop_get_string_array(tnode_t *node, const char *pgname, const char *pname, 471 char ***val, uint_t *nelem, int *err) 472 { 473 return (prop_getval(node, pgname, pname, (void *)val, 474 TOPO_TYPE_STRING_ARRAY, nelem, err)); 475 } 476 477 int 478 topo_prop_get_fmri_array(tnode_t *node, const char *pgname, const char *pname, 479 nvlist_t ***val, uint_t *nelem, int *err) 480 { 481 return (prop_getval(node, pgname, pname, (void *)val, 482 TOPO_TYPE_FMRI_ARRAY, nelem, err)); 483 } 484 485 static topo_propval_t * 486 set_seterror(tnode_t *node, topo_proplist_t *pvl, int *errp, int err) 487 { 488 topo_hdl_t *thp = node->tn_hdl; 489 topo_propval_t *pv; 490 491 if (pvl != NULL) { 492 pv = pvl->tp_pval; 493 topo_propval_destroy(pv); 494 topo_hdl_free(thp, pvl, sizeof (topo_proplist_t)); 495 } 496 497 topo_node_unlock(node); 498 *errp = err; 499 500 return (NULL); 501 } 502 503 static topo_propval_t * 504 prop_create(tnode_t *node, const char *pgname, const char *pname, 505 topo_type_t type, int flag, int *err) 506 { 507 topo_hdl_t *thp = node->tn_hdl; 508 topo_pgroup_t *pg; 509 topo_propval_t *pv; 510 topo_proplist_t *pvl; 511 512 /* 513 * Replace existing prop value with new one 514 */ 515 if ((pg = pgroup_get(node, pgname)) == NULL) { 516 topo_node_unlock(node); 517 *err = ETOPO_PROP_NOENT; 518 return (NULL); 519 } 520 521 if ((pv = propval_get(pg, pname)) != NULL) { 522 if (pv->tp_type != type) 523 return (set_seterror(node, NULL, err, ETOPO_PROP_TYPE)); 524 else if (pv->tp_flag == TOPO_PROP_IMMUTABLE) 525 return (set_seterror(node, NULL, err, ETOPO_PROP_DEFD)); 526 527 nvlist_free(pv->tp_val); 528 pv->tp_val = NULL; 529 } else { 530 if ((pvl = topo_hdl_zalloc(thp, sizeof (topo_proplist_t))) 531 == NULL) 532 return (set_seterror(node, NULL, err, ETOPO_NOMEM)); 533 534 if ((pv = topo_hdl_zalloc(thp, sizeof (topo_propval_t))) 535 == NULL) 536 return (set_seterror(node, pvl, err, ETOPO_NOMEM)); 537 538 pv->tp_hdl = thp; 539 pvl->tp_pval = pv; 540 541 if ((pv->tp_name = topo_hdl_strdup(thp, pname)) 542 == NULL) 543 return (set_seterror(node, pvl, err, ETOPO_NOMEM)); 544 pv->tp_flag = flag; 545 pv->tp_type = type; 546 topo_prop_hold(pv); 547 topo_list_append(&pg->tpg_pvals, pvl); 548 } 549 550 return (pv); 551 } 552 553 static int 554 topo_prop_set(tnode_t *node, const char *pgname, const char *pname, 555 topo_type_t type, int flag, void *val, int nelems, int *err) 556 { 557 int ret; 558 topo_hdl_t *thp = node->tn_hdl; 559 nvlist_t *nvl; 560 topo_propval_t *pv; 561 562 if (topo_hdl_nvalloc(thp, &nvl, NV_UNIQUE_NAME) < 0) { 563 *err = ETOPO_PROP_NVL; 564 return (-1); 565 } 566 567 ret = nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, pname); 568 ret |= nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, type); 569 switch (type) { 570 case TOPO_TYPE_INT32: 571 ret |= nvlist_add_int32(nvl, TOPO_PROP_VAL_VAL, 572 *(int32_t *)val); 573 break; 574 case TOPO_TYPE_UINT32: 575 ret |= nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, 576 *(uint32_t *)val); 577 break; 578 case TOPO_TYPE_INT64: 579 ret |= nvlist_add_int64(nvl, TOPO_PROP_VAL_VAL, 580 *(int64_t *)val); 581 break; 582 case TOPO_TYPE_UINT64: 583 ret |= nvlist_add_uint64(nvl, TOPO_PROP_VAL_VAL, 584 *(uint64_t *)val); 585 break; 586 case TOPO_TYPE_STRING: 587 ret |= nvlist_add_string(nvl, TOPO_PROP_VAL_VAL, 588 (char *)val); 589 break; 590 case TOPO_TYPE_FMRI: 591 ret |= nvlist_add_nvlist(nvl, TOPO_PROP_VAL_VAL, 592 (nvlist_t *)val); 593 break; 594 case TOPO_TYPE_INT32_ARRAY: 595 ret |= nvlist_add_int32_array(nvl, 596 TOPO_PROP_VAL_VAL, (int32_t *)val, nelems); 597 break; 598 case TOPO_TYPE_UINT32_ARRAY: 599 ret |= nvlist_add_uint32_array(nvl, 600 TOPO_PROP_VAL_VAL, (uint32_t *)val, nelems); 601 break; 602 case TOPO_TYPE_INT64_ARRAY: 603 ret |= nvlist_add_int64_array(nvl, 604 TOPO_PROP_VAL_VAL, (int64_t *)val, nelems); 605 break; 606 case TOPO_TYPE_UINT64_ARRAY: 607 ret |= nvlist_add_uint64_array(nvl, 608 TOPO_PROP_VAL_VAL, (uint64_t *)val, nelems); 609 break; 610 case TOPO_TYPE_STRING_ARRAY: 611 ret |= nvlist_add_string_array(nvl, 612 TOPO_PROP_VAL_VAL, (char **)val, nelems); 613 break; 614 case TOPO_TYPE_FMRI_ARRAY: 615 ret |= nvlist_add_nvlist_array(nvl, 616 TOPO_PROP_VAL_VAL, (nvlist_t **)val, nelems); 617 break; 618 default: 619 *err = ETOPO_PROP_TYPE; 620 return (-1); 621 } 622 623 if (ret != 0) { 624 nvlist_free(nvl); 625 if (ret == ENOMEM) { 626 *err = ETOPO_PROP_NOMEM; 627 return (-1); 628 } else { 629 *err = ETOPO_PROP_NVL; 630 return (-1); 631 } 632 } 633 634 topo_node_lock(node); 635 if ((pv = prop_create(node, pgname, pname, type, flag, err)) == NULL) { 636 nvlist_free(nvl); 637 return (-1); /* unlocked and err set */ 638 } 639 640 pv->tp_val = nvl; 641 642 topo_node_unlock(node); 643 644 return (ret); 645 } 646 647 int 648 topo_prop_set_int32(tnode_t *node, const char *pgname, const char *pname, 649 int flag, int32_t val, int *err) 650 { 651 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT32, flag, 652 &val, 1, err)); 653 } 654 655 int 656 topo_prop_set_uint32(tnode_t *node, const char *pgname, const char *pname, 657 int flag, uint32_t val, int *err) 658 { 659 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT32, flag, 660 &val, 1, err)); 661 } 662 663 int 664 topo_prop_set_int64(tnode_t *node, const char *pgname, const char *pname, 665 int flag, int64_t val, int *err) 666 { 667 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT64, flag, 668 &val, 1, err)); 669 } 670 671 int 672 topo_prop_set_uint64(tnode_t *node, const char *pgname, const char *pname, 673 int flag, uint64_t val, int *err) 674 { 675 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT64, flag, 676 &val, 1, err)); 677 } 678 679 int 680 topo_prop_set_string(tnode_t *node, const char *pgname, const char *pname, 681 int flag, const char *val, int *err) 682 { 683 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_STRING, flag, 684 (void *)val, 1, err)); 685 } 686 687 int 688 topo_prop_set_fmri(tnode_t *node, const char *pgname, const char *pname, 689 int flag, const nvlist_t *fmri, int *err) 690 { 691 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_FMRI, flag, 692 (void *)fmri, 1, err)); 693 } 694 695 int 696 topo_prop_set_int32_array(tnode_t *node, const char *pgname, const char *pname, 697 int flag, int32_t *val, uint_t nelems, int *err) 698 { 699 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT32_ARRAY, flag, 700 val, nelems, err)); 701 } 702 703 int 704 topo_prop_set_uint32_array(tnode_t *node, const char *pgname, const char *pname, 705 int flag, uint32_t *val, uint_t nelems, int *err) 706 { 707 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT32_ARRAY, flag, 708 val, nelems, err)); 709 } 710 711 int 712 topo_prop_set_int64_array(tnode_t *node, const char *pgname, const char *pname, 713 int flag, int64_t *val, uint_t nelems, int *err) 714 { 715 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT64_ARRAY, flag, 716 val, nelems, err)); 717 } 718 719 int 720 topo_prop_set_uint64_array(tnode_t *node, const char *pgname, const char *pname, 721 int flag, uint64_t *val, uint_t nelems, int *err) 722 { 723 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT64_ARRAY, flag, 724 val, nelems, err)); 725 } 726 727 int 728 topo_prop_set_string_array(tnode_t *node, const char *pgname, const char *pname, 729 int flag, const char **val, uint_t nelems, int *err) 730 { 731 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_STRING_ARRAY, flag, 732 (void *)val, nelems, err)); 733 } 734 735 int 736 topo_prop_set_fmri_array(tnode_t *node, const char *pgname, const char *pname, 737 int flag, const nvlist_t **fmri, uint_t nelems, int *err) 738 { 739 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_FMRI_ARRAY, flag, 740 (void *)fmri, nelems, err)); 741 } 742 743 /* 744 * topo_prop_setprop() is a private project function for fmtopo 745 */ 746 int 747 topo_prop_setprop(tnode_t *node, const char *pgname, nvlist_t *prop, 748 int flag, nvlist_t *pargs, int *err) 749 { 750 int ret; 751 topo_hdl_t *thp = node->tn_hdl; 752 topo_propval_t *pv; 753 nvlist_t *nvl, *args; 754 char *name; 755 topo_type_t type; 756 757 if (nvlist_lookup_string(prop, TOPO_PROP_VAL_NAME, &name) != 0) { 758 *err = ETOPO_PROP_NAME; 759 return (-1); 760 } 761 if (nvlist_lookup_uint32(prop, TOPO_PROP_VAL_TYPE, (uint32_t *)&type) 762 != 0) { 763 *err = ETOPO_PROP_TYPE; 764 return (-1); 765 } 766 767 topo_node_lock(node); 768 if ((pv = prop_create(node, pgname, name, type, flag, err)) == NULL) 769 return (-1); /* unlocked and err set */ 770 771 /* 772 * Set by method or set to new prop value. If we fail, leave 773 * property in list with old value. 774 */ 775 if (pv->tp_method != NULL) { 776 topo_propmethod_t *pm = pv->tp_method; 777 778 if (topo_hdl_nvalloc(pv->tp_hdl, &args, NV_UNIQUE_NAME) < 0) { 779 topo_node_unlock(node); 780 *err = ETOPO_PROP_NOMEM; 781 return (-1); 782 } 783 ret = nvlist_add_nvlist(args, TOPO_PROP_ARGS, pm->tpm_args); 784 if (pargs != NULL) 785 ret |= nvlist_add_nvlist(args, TOPO_PROP_PARGS, pargs); 786 787 if (ret != 0) { 788 topo_node_unlock(node); 789 nvlist_free(args); 790 *err = ETOPO_PROP_NVL; 791 return (-1); 792 } 793 794 /* 795 * 796 * Grab a reference to the property and then unlock the node. 797 * This will allow property methods to safely re-enter the 798 * prop_get codepath, making it possible for property methods 799 * to access other property values on the same node w\o causing 800 * a deadlock. 801 * 802 * We don't technically need this now, since this interface is 803 * currently only used by fmtopo (which is single-threaded), but 804 * we may make this interface available to other parts of 805 * libtopo in the future, so best to make it MT-safe now. 806 */ 807 topo_prop_hold(pv); 808 topo_node_unlock(node); 809 ret = topo_method_call(node, pm->tpm_name, pm->tpm_version, 810 args, &nvl, err); 811 topo_node_lock(node); 812 topo_prop_rele(pv); 813 814 nvlist_free(args); 815 } else { 816 if ((ret = topo_hdl_nvdup(thp, prop, &nvl)) != 0) 817 *err = ETOPO_PROP_NOMEM; 818 } 819 820 if (ret != 0) { 821 topo_node_unlock(node); 822 return (-1); 823 } 824 825 pv->tp_val = nvl; 826 topo_node_unlock(node); 827 return (0); 828 } 829 830 static int 831 register_methoderror(tnode_t *node, topo_propmethod_t *pm, int *errp, int l, 832 int err) 833 { 834 topo_hdl_t *thp = node->tn_hdl; 835 836 if (pm != NULL) { 837 if (pm->tpm_name != NULL) 838 topo_hdl_strfree(thp, pm->tpm_name); 839 if (pm->tpm_args != NULL) 840 nvlist_free(pm->tpm_args); 841 topo_hdl_free(thp, pm, sizeof (topo_propmethod_t)); 842 } 843 844 *errp = err; 845 846 if (l != 0) 847 topo_node_unlock(node); 848 849 return (-1); 850 } 851 852 int 853 prop_method_register(tnode_t *node, const char *pgname, const char *pname, 854 topo_type_t ptype, const char *mname, topo_version_t version, 855 const nvlist_t *args, int *err) 856 { 857 topo_hdl_t *thp = node->tn_hdl; 858 topo_propmethod_t *pm = NULL; 859 topo_propval_t *pv = NULL; 860 861 if ((pm = topo_hdl_zalloc(thp, sizeof (topo_propmethod_t))) == NULL) 862 return (register_methoderror(node, pm, err, 1, 863 ETOPO_PROP_NOMEM)); 864 865 if ((pm->tpm_name = topo_hdl_strdup(thp, mname)) == NULL) 866 return (register_methoderror(node, pm, err, 1, 867 ETOPO_PROP_NOMEM)); 868 869 pm->tpm_version = version; 870 871 if (topo_hdl_nvdup(thp, (nvlist_t *)args, &pm->tpm_args) != 0) 872 return (register_methoderror(node, pm, err, 1, 873 ETOPO_PROP_NOMEM)); 874 875 /* 876 * It's possible the property may already exist. However we still want 877 * to allow the method to be registered. This is to handle the case 878 * where we specify an prop method in an xml map to override the value 879 * that was set by the enumerator. 880 */ 881 if ((pv = propval_get(pgroup_get(node, pgname), pname)) == NULL) 882 if ((pv = prop_create(node, pgname, pname, ptype, 883 TOPO_PROP_MUTABLE, err)) == NULL) { 884 /* node unlocked */ 885 return (register_methoderror(node, pm, err, 0, *err)); 886 } 887 888 if (pv->tp_method != NULL) 889 return (register_methoderror(node, pm, err, 1, 890 ETOPO_METHOD_DEFD)); 891 892 if (pv->tp_val != NULL) { 893 nvlist_free(pv->tp_val); 894 pv->tp_val = NULL; 895 } 896 pv->tp_method = pm; 897 898 topo_node_unlock(node); 899 900 return (0); 901 } 902 903 int 904 topo_prop_method_register(tnode_t *node, const char *pgname, const char *pname, 905 topo_type_t ptype, const char *mname, const nvlist_t *args, int *err) 906 { 907 topo_imethod_t *mp; 908 909 topo_node_lock(node); 910 911 if ((mp = topo_method_lookup(node, mname)) == NULL) 912 return (register_methoderror(node, NULL, err, 1, 913 ETOPO_METHOD_NOTSUP)); /* node unlocked */ 914 915 topo_node_lock(node); 916 917 return (prop_method_register(node, pgname, pname, ptype, mname, 918 mp->tim_version, args, err)); /* err set and node unlocked */ 919 } 920 921 int 922 topo_prop_method_version_register(tnode_t *node, const char *pgname, 923 const char *pname, topo_type_t ptype, const char *mname, 924 topo_version_t version, const nvlist_t *args, int *err) 925 { 926 topo_imethod_t *mp; 927 928 topo_node_lock(node); 929 930 if ((mp = topo_method_lookup(node, mname)) == NULL) 931 return (register_methoderror(node, NULL, err, 1, 932 ETOPO_METHOD_NOTSUP)); /* node unlocked */ 933 934 topo_node_lock(node); 935 936 if (version < mp->tim_version) 937 return (register_methoderror(node, NULL, err, 1, 938 ETOPO_METHOD_VEROLD)); 939 if (version > mp->tim_version) 940 return (register_methoderror(node, NULL, err, 1, 941 ETOPO_METHOD_VERNEW)); 942 943 return (prop_method_register(node, pgname, pname, ptype, mname, 944 version, args, err)); /* err set and node unlocked */ 945 } 946 947 void 948 topo_prop_method_unregister(tnode_t *node, const char *pgname, 949 const char *pname) 950 { 951 topo_propval_t *pv; 952 topo_pgroup_t *pg; 953 topo_proplist_t *pvl; 954 topo_hdl_t *thp = node->tn_hdl; 955 956 topo_node_lock(node); 957 958 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; 959 pg = topo_list_next(pg)) { 960 if (strcmp(pg->tpg_info->tpi_name, pgname) == 0) { 961 break; 962 } 963 } 964 965 if (pg == NULL) { 966 topo_node_unlock(node); 967 return; 968 } 969 970 for (pvl = topo_list_next(&pg->tpg_list); pvl != NULL; 971 pvl = topo_list_next(pvl)) { 972 pv = pvl->tp_pval; 973 if (strcmp(pv->tp_name, pname) == 0) { 974 topo_list_delete(&pg->tpg_pvals, pvl); 975 assert(pv->tp_refs == 1); 976 topo_prop_rele(pv); 977 topo_hdl_free(thp, pvl, sizeof (topo_proplist_t)); 978 break; 979 } 980 } 981 982 topo_node_unlock(node); 983 } 984 985 static int 986 inherit_seterror(tnode_t *node, int *errp, int err) 987 { 988 topo_node_unlock(node); 989 topo_node_unlock(node->tn_parent); 990 991 *errp = err; 992 993 return (-1); 994 } 995 996 int 997 topo_prop_inherit(tnode_t *node, const char *pgname, const char *name, int *err) 998 { 999 topo_hdl_t *thp = node->tn_hdl; 1000 tnode_t *pnode = node->tn_parent; 1001 topo_pgroup_t *pg; 1002 topo_propval_t *pv; 1003 topo_proplist_t *pvl; 1004 1005 topo_node_lock(pnode); 1006 topo_node_lock(node); 1007 1008 /* 1009 * Check if the requested property group and prop val are already set 1010 * on the node. 1011 */ 1012 if (propval_get(pgroup_get(node, pgname), name) != NULL) 1013 return (inherit_seterror(node, err, ETOPO_PROP_DEFD)); 1014 1015 /* 1016 * Check if the requested property group and prop val exists on the 1017 * parent node 1018 */ 1019 if ((pv = propval_get(pgroup_get(pnode, pgname), name)) == NULL) 1020 return (inherit_seterror(node, err, ETOPO_PROP_NOENT)); 1021 1022 /* 1023 * Can this propval be inherited? 1024 */ 1025 if (pv->tp_flag != TOPO_PROP_IMMUTABLE) 1026 return (inherit_seterror(node, err, ETOPO_PROP_NOINHERIT)); 1027 1028 /* 1029 * Property group should already exist: bump the ref count for this 1030 * propval and add it to the node's property group 1031 */ 1032 if ((pg = pgroup_get(node, pgname)) == NULL) 1033 return (inherit_seterror(node, err, ETOPO_PROP_NOENT)); 1034 1035 if ((pvl = topo_hdl_zalloc(thp, sizeof (topo_proplist_t))) 1036 == NULL) 1037 return (inherit_seterror(node, err, ETOPO_NOMEM)); 1038 1039 topo_prop_hold(pv); 1040 pvl->tp_pval = pv; 1041 topo_list_append(&pg->tpg_pvals, pvl); 1042 1043 topo_node_unlock(node); 1044 topo_node_unlock(pnode); 1045 1046 return (0); 1047 } 1048 1049 topo_pgroup_info_t * 1050 topo_pgroup_info(tnode_t *node, const char *pgname, int *err) 1051 { 1052 topo_hdl_t *thp = node->tn_hdl; 1053 topo_pgroup_t *pg; 1054 topo_ipgroup_info_t *pip; 1055 topo_pgroup_info_t *info; 1056 1057 topo_node_lock(node); 1058 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; 1059 pg = topo_list_next(pg)) { 1060 if (strcmp(pgname, pg->tpg_info->tpi_name) == 0) { 1061 if ((info = topo_hdl_alloc(thp, 1062 sizeof (topo_pgroup_info_t))) == NULL) 1063 return (NULL); 1064 1065 pip = pg->tpg_info; 1066 if ((info->tpi_name = 1067 topo_hdl_strdup(thp, pip->tpi_name)) == NULL) { 1068 *err = ETOPO_PROP_NOMEM; 1069 topo_hdl_free(thp, info, 1070 sizeof (topo_pgroup_info_t)); 1071 topo_node_unlock(node); 1072 return (NULL); 1073 } 1074 info->tpi_namestab = pip->tpi_namestab; 1075 info->tpi_datastab = pip->tpi_datastab; 1076 info->tpi_version = pip->tpi_version; 1077 topo_node_unlock(node); 1078 return (info); 1079 } 1080 } 1081 1082 *err = ETOPO_PROP_NOENT; 1083 topo_node_unlock(node); 1084 return (NULL); 1085 } 1086 1087 static int 1088 pgroup_seterr(tnode_t *node, topo_pgroup_t *pg, topo_ipgroup_info_t *pip, 1089 int *err) 1090 { 1091 topo_hdl_t *thp = node->tn_hdl; 1092 1093 if (pip != NULL) { 1094 if (pip->tpi_name != NULL) 1095 topo_hdl_strfree(thp, (char *)pip->tpi_name); 1096 topo_hdl_free(thp, pip, sizeof (topo_ipgroup_info_t)); 1097 } 1098 1099 topo_hdl_free(thp, pg, sizeof (topo_pgroup_t)); 1100 *err = ETOPO_NOMEM; 1101 1102 topo_node_unlock(node); 1103 1104 return (-1); 1105 } 1106 1107 int 1108 topo_pgroup_create(tnode_t *node, const topo_pgroup_info_t *pinfo, int *err) 1109 { 1110 topo_pgroup_t *pg; 1111 topo_ipgroup_info_t *pip; 1112 topo_hdl_t *thp = node->tn_hdl; 1113 1114 *err = 0; 1115 1116 topo_node_lock(node); 1117 /* 1118 * Check for an existing pgroup 1119 */ 1120 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; 1121 pg = topo_list_next(pg)) { 1122 if (strcmp(pg->tpg_info->tpi_name, pinfo->tpi_name) == 0) { 1123 *err = ETOPO_PROP_DEFD; 1124 topo_node_unlock(node); 1125 return (-1); 1126 } 1127 } 1128 1129 if ((pg = topo_hdl_zalloc(thp, sizeof (topo_pgroup_t))) == NULL) { 1130 *err = ETOPO_NOMEM; 1131 topo_node_unlock(node); 1132 return (-1); 1133 } 1134 1135 if ((pip = topo_hdl_zalloc(thp, sizeof (topo_ipgroup_info_t))) 1136 == NULL) 1137 return (pgroup_seterr(node, pg, pip, err)); 1138 1139 if ((pip->tpi_name = topo_hdl_strdup(thp, pinfo->tpi_name)) 1140 == NULL) 1141 return (pgroup_seterr(node, pg, pip, err)); 1142 1143 pip->tpi_namestab = pinfo->tpi_namestab; 1144 pip->tpi_datastab = pinfo->tpi_datastab; 1145 pip->tpi_version = pinfo->tpi_version; 1146 1147 pg->tpg_info = pip; 1148 1149 topo_list_append(&node->tn_pgroups, pg); 1150 topo_node_unlock(node); 1151 1152 return (0); 1153 } 1154 1155 void 1156 topo_pgroup_destroy(tnode_t *node, const char *pname) 1157 { 1158 topo_hdl_t *thp = node->tn_hdl; 1159 topo_pgroup_t *pg; 1160 topo_proplist_t *pvl; 1161 topo_ipgroup_info_t *pip; 1162 1163 topo_node_lock(node); 1164 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; 1165 pg = topo_list_next(pg)) { 1166 if (strcmp(pg->tpg_info->tpi_name, pname) == 0) { 1167 break; 1168 } 1169 } 1170 1171 if (pg == NULL) { 1172 topo_node_unlock(node); 1173 return; 1174 } 1175 1176 while ((pvl = topo_list_next(&pg->tpg_list)) != NULL) { 1177 topo_list_delete(&pg->tpg_pvals, pvl); 1178 topo_prop_rele(pvl->tp_pval); 1179 topo_hdl_free(thp, pvl, sizeof (topo_proplist_t)); 1180 } 1181 1182 topo_list_delete(&node->tn_pgroups, pg); 1183 topo_node_unlock(node); 1184 1185 pip = pg->tpg_info; 1186 if (pip != NULL) { 1187 if (pip->tpi_name != NULL) 1188 topo_hdl_strfree(thp, (char *)pip->tpi_name); 1189 topo_hdl_free(thp, pip, sizeof (topo_ipgroup_info_t)); 1190 } 1191 1192 topo_hdl_free(thp, pg, sizeof (topo_pgroup_t)); 1193 } 1194 1195 void 1196 topo_pgroup_destroy_all(tnode_t *node) 1197 { 1198 topo_hdl_t *thp = node->tn_hdl; 1199 topo_pgroup_t *pg; 1200 topo_proplist_t *pvl; 1201 topo_ipgroup_info_t *pip; 1202 1203 topo_node_lock(node); 1204 while ((pg = topo_list_next(&node->tn_pgroups)) != NULL) { 1205 while ((pvl = topo_list_next(&pg->tpg_pvals)) != NULL) { 1206 topo_list_delete(&pg->tpg_pvals, pvl); 1207 topo_prop_rele(pvl->tp_pval); 1208 topo_hdl_free(thp, pvl, sizeof (topo_proplist_t)); 1209 } 1210 1211 topo_list_delete(&node->tn_pgroups, pg); 1212 1213 pip = pg->tpg_info; 1214 if (pip != NULL) { 1215 if (pip->tpi_name != NULL) 1216 topo_hdl_strfree(thp, (char *)pip->tpi_name); 1217 topo_hdl_free(thp, pip, sizeof (topo_pgroup_info_t)); 1218 } 1219 1220 topo_hdl_free(thp, pg, sizeof (topo_pgroup_t)); 1221 } 1222 topo_node_unlock(node); 1223 } 1224 1225 static void 1226 propmethod_destroy(topo_hdl_t *thp, topo_propval_t *pv) 1227 { 1228 topo_propmethod_t *pm; 1229 1230 pm = pv->tp_method; 1231 if (pm != NULL) { 1232 if (pm->tpm_name != NULL) 1233 topo_hdl_strfree(thp, pm->tpm_name); 1234 if (pm->tpm_args != NULL) 1235 nvlist_free(pm->tpm_args); 1236 topo_hdl_free(thp, pm, sizeof (topo_propmethod_t)); 1237 pv->tp_method = NULL; 1238 } 1239 } 1240 1241 static void 1242 topo_propval_destroy(topo_propval_t *pv) 1243 { 1244 topo_hdl_t *thp; 1245 1246 if (pv == NULL) 1247 return; 1248 1249 thp = pv->tp_hdl; 1250 1251 if (pv->tp_name != NULL) 1252 topo_hdl_strfree(thp, pv->tp_name); 1253 1254 if (pv->tp_val != NULL) 1255 nvlist_free(pv->tp_val); 1256 1257 propmethod_destroy(thp, pv); 1258 1259 topo_hdl_free(thp, pv, sizeof (topo_propval_t)); 1260 } 1261 1262 void 1263 topo_prop_hold(topo_propval_t *pv) 1264 { 1265 pv->tp_refs++; 1266 } 1267 1268 void 1269 topo_prop_rele(topo_propval_t *pv) 1270 { 1271 pv->tp_refs--; 1272 1273 assert(pv->tp_refs >= 0); 1274 1275 if (pv->tp_refs == 0) 1276 topo_propval_destroy(pv); 1277 } 1278 1279 /* 1280 * topo_prop_getprop() and topo_prop_getprops() are private project functions 1281 * for fmtopo 1282 */ 1283 int 1284 topo_prop_getprop(tnode_t *node, const char *pgname, const char *pname, 1285 nvlist_t *args, nvlist_t **prop, int *err) 1286 { 1287 topo_hdl_t *thp = node->tn_hdl; 1288 topo_propval_t *pv; 1289 1290 topo_node_lock(node); 1291 if ((pv = prop_get(node, pgname, pname, args, err)) == NULL) { 1292 (void) get_properror(node, err, *err); 1293 return (-1); 1294 } 1295 1296 if (topo_hdl_nvdup(thp, pv->tp_val, prop) != 0) { 1297 (void) get_properror(node, err, ETOPO_NOMEM); 1298 return (-1); 1299 } 1300 topo_node_unlock(node); 1301 1302 return (0); 1303 } 1304 1305 static int 1306 prop_val_add(tnode_t *node, nvlist_t **nvl, topo_propval_t *pv, int *err) 1307 { 1308 if (pv->tp_method != NULL) 1309 if (prop_method_get(node, pv, pv->tp_method, NULL, err) < 0) 1310 return (-1); 1311 1312 if (pv->tp_val == NULL) { 1313 *err = ETOPO_PROP_NOENT; 1314 return (-1); 1315 } 1316 1317 if (topo_hdl_nvdup(pv->tp_hdl, pv->tp_val, nvl) != 0) { 1318 *err = ETOPO_PROP_NOMEM; 1319 return (-1); 1320 } 1321 1322 return (0); 1323 } 1324 1325 static int 1326 get_pgrp_seterror(tnode_t *node, nvlist_t *nvl, int *errp, int err) 1327 { 1328 topo_node_unlock(node); 1329 1330 if (nvl != NULL) 1331 nvlist_free(nvl); 1332 1333 *errp = err; 1334 1335 return (-1); 1336 } 1337 1338 int 1339 topo_prop_getpgrp(tnode_t *node, const char *pgname, nvlist_t **pgrp, 1340 int *err) 1341 { 1342 int ret; 1343 topo_hdl_t *thp = node->tn_hdl; 1344 nvlist_t *nvl, *pvnvl; 1345 topo_pgroup_t *pg; 1346 topo_propval_t *pv; 1347 topo_proplist_t *pvl; 1348 1349 if (topo_hdl_nvalloc(thp, &nvl, 0) != 0) { 1350 *err = ETOPO_NOMEM; 1351 return (-1); 1352 } 1353 1354 topo_node_lock(node); 1355 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; 1356 pg = topo_list_next(pg)) { 1357 1358 if (strcmp(pgname, pg->tpg_info->tpi_name) != 0) 1359 continue; 1360 1361 if (nvlist_add_string(nvl, TOPO_PROP_GROUP_NAME, 1362 pg->tpg_info->tpi_name) != 0 || 1363 nvlist_add_string(nvl, TOPO_PROP_GROUP_NSTAB, 1364 topo_stability2name(pg->tpg_info->tpi_namestab)) != 0 || 1365 nvlist_add_string(nvl, TOPO_PROP_GROUP_DSTAB, 1366 topo_stability2name(pg->tpg_info->tpi_datastab)) != 0 || 1367 nvlist_add_int32(nvl, TOPO_PROP_GROUP_VERSION, 1368 pg->tpg_info->tpi_version) != 0) 1369 return (get_pgrp_seterror(node, nvl, err, 1370 ETOPO_PROP_NVL)); 1371 1372 for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL; 1373 pvl = topo_list_next(pvl)) { 1374 1375 pv = pvl->tp_pval; 1376 if (prop_val_add(node, &pvnvl, pv, err) < 0) { 1377 return (get_pgrp_seterror(node, nvl, err, 1378 *err)); 1379 } 1380 if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_VAL, 1381 pvnvl)) != 0) { 1382 nvlist_free(pvnvl); 1383 return (get_pgrp_seterror(node, nvl, err, ret)); 1384 } 1385 1386 nvlist_free(pvnvl); 1387 } 1388 topo_node_unlock(node); 1389 *pgrp = nvl; 1390 return (0); 1391 } 1392 1393 topo_node_unlock(node); 1394 *err = ETOPO_PROP_NOENT; 1395 return (-1); 1396 } 1397 1398 static nvlist_t * 1399 get_all_seterror(tnode_t *node, nvlist_t *nvl, int *errp, int err) 1400 { 1401 topo_node_unlock(node); 1402 1403 if (nvl != NULL) 1404 nvlist_free(nvl); 1405 1406 *errp = err; 1407 1408 return (NULL); 1409 } 1410 1411 nvlist_t * 1412 topo_prop_getprops(tnode_t *node, int *err) 1413 { 1414 int ret; 1415 topo_hdl_t *thp = node->tn_hdl; 1416 nvlist_t *nvl, *pgnvl, *pvnvl; 1417 topo_pgroup_t *pg; 1418 topo_propval_t *pv; 1419 topo_proplist_t *pvl; 1420 1421 topo_node_lock(node); 1422 if (topo_hdl_nvalloc(thp, &nvl, 0) != 0) { 1423 return (get_all_seterror(node, NULL, err, ETOPO_NOMEM)); 1424 } 1425 1426 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; 1427 pg = topo_list_next(pg)) { 1428 if (topo_hdl_nvalloc(thp, &pgnvl, 0) != 0) 1429 return (get_all_seterror(node, nvl, err, ETOPO_NOMEM)); 1430 1431 if (nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NAME, 1432 pg->tpg_info->tpi_name) != 0 || 1433 nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NSTAB, 1434 topo_stability2name(pg->tpg_info->tpi_namestab)) != 0 || 1435 nvlist_add_string(pgnvl, TOPO_PROP_GROUP_DSTAB, 1436 topo_stability2name(pg->tpg_info->tpi_datastab)) != 0 || 1437 nvlist_add_int32(pgnvl, TOPO_PROP_GROUP_VERSION, 1438 pg->tpg_info->tpi_version) != 0) 1439 return (get_all_seterror(node, nvl, err, 1440 ETOPO_PROP_NVL)); 1441 1442 for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL; 1443 pvl = topo_list_next(pvl)) { 1444 1445 pv = pvl->tp_pval; 1446 if (prop_val_add(node, &pvnvl, pv, err) < 0) { 1447 nvlist_free(pgnvl); 1448 return (get_all_seterror(node, nvl, err, *err)); 1449 } 1450 if ((ret = nvlist_add_nvlist(pgnvl, TOPO_PROP_VAL, 1451 pvnvl)) != 0) { 1452 nvlist_free(pgnvl); 1453 nvlist_free(pvnvl); 1454 return (get_all_seterror(node, nvl, err, ret)); 1455 } 1456 1457 nvlist_free(pvnvl); 1458 } 1459 if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_GROUP, pgnvl)) 1460 != 0) { 1461 nvlist_free(pgnvl); 1462 return (get_all_seterror(node, nvl, err, ret)); 1463 } 1464 1465 nvlist_free(pgnvl); 1466 } 1467 1468 topo_node_unlock(node); 1469 1470 return (nvl); 1471 } 1472