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