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