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_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 if ((pv = prop_create(node, pgname, pname, ptype, TOPO_PROP_MUTABLE, 876 err)) == NULL) { 877 /* node unlocked */ 878 return (register_methoderror(node, pm, err, 0, *err)); 879 } 880 881 if (pv->tp_method != NULL) 882 return (register_methoderror(node, pm, err, 1, 883 ETOPO_METHOD_DEFD)); 884 885 pv->tp_val = NULL; 886 pv->tp_method = pm; 887 888 topo_node_unlock(node); 889 890 return (0); 891 } 892 893 int 894 topo_prop_method_register(tnode_t *node, const char *pgname, const char *pname, 895 topo_type_t ptype, const char *mname, const nvlist_t *args, int *err) 896 { 897 topo_imethod_t *mp; 898 899 topo_node_lock(node); 900 901 if ((mp = topo_method_lookup(node, mname)) == NULL) 902 return (register_methoderror(node, NULL, err, 1, 903 ETOPO_METHOD_NOTSUP)); /* node unlocked */ 904 905 topo_node_lock(node); 906 907 return (prop_method_register(node, pgname, pname, ptype, mname, 908 mp->tim_version, args, err)); /* err set and node unlocked */ 909 } 910 911 int 912 topo_prop_method_version_register(tnode_t *node, const char *pgname, 913 const char *pname, topo_type_t ptype, const char *mname, 914 topo_version_t version, const nvlist_t *args, int *err) 915 { 916 topo_imethod_t *mp; 917 918 topo_node_lock(node); 919 920 if ((mp = topo_method_lookup(node, mname)) == NULL) 921 return (register_methoderror(node, NULL, err, 1, 922 ETOPO_METHOD_NOTSUP)); /* node unlocked */ 923 924 topo_node_lock(node); 925 926 if (version < mp->tim_version) 927 return (register_methoderror(node, NULL, err, 1, 928 ETOPO_METHOD_VEROLD)); 929 if (version > mp->tim_version) 930 return (register_methoderror(node, NULL, err, 1, 931 ETOPO_METHOD_VERNEW)); 932 933 return (prop_method_register(node, pgname, pname, ptype, mname, 934 version, args, err)); /* err set and node unlocked */ 935 } 936 937 void 938 topo_prop_method_unregister(tnode_t *node, const char *pgname, 939 const char *pname) 940 { 941 topo_propval_t *pv; 942 topo_pgroup_t *pg; 943 topo_proplist_t *pvl; 944 topo_hdl_t *thp = node->tn_hdl; 945 946 topo_node_lock(node); 947 948 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; 949 pg = topo_list_next(pg)) { 950 if (strcmp(pg->tpg_info->tpi_name, pgname) == 0) { 951 break; 952 } 953 } 954 955 if (pg == NULL) { 956 topo_node_unlock(node); 957 return; 958 } 959 960 for (pvl = topo_list_next(&pg->tpg_list); pvl != NULL; 961 pvl = topo_list_next(pvl)) { 962 pv = pvl->tp_pval; 963 if (strcmp(pv->tp_name, pname) == 0) { 964 topo_list_delete(&pg->tpg_pvals, pvl); 965 assert(pv->tp_refs == 1); 966 topo_prop_rele(pv); 967 topo_hdl_free(thp, pvl, sizeof (topo_proplist_t)); 968 break; 969 } 970 } 971 972 topo_node_unlock(node); 973 } 974 975 static int 976 inherit_seterror(tnode_t *node, int *errp, int err) 977 { 978 topo_node_unlock(node); 979 topo_node_unlock(node->tn_parent); 980 981 *errp = err; 982 983 return (-1); 984 } 985 986 int 987 topo_prop_inherit(tnode_t *node, const char *pgname, const char *name, int *err) 988 { 989 topo_hdl_t *thp = node->tn_hdl; 990 tnode_t *pnode = node->tn_parent; 991 topo_pgroup_t *pg; 992 topo_propval_t *pv; 993 topo_proplist_t *pvl; 994 995 topo_node_lock(pnode); 996 topo_node_lock(node); 997 /* 998 * Check for an existing property group and prop val 999 */ 1000 if ((pv = propval_get(pgroup_get(pnode, pgname), name)) == NULL) 1001 return (inherit_seterror(node, err, ETOPO_PROP_NOENT)); 1002 1003 /* 1004 * Can this propval be inherited? 1005 */ 1006 if (pv->tp_flag != TOPO_PROP_IMMUTABLE) 1007 return (inherit_seterror(node, err, ETOPO_PROP_NOINHERIT)); 1008 1009 /* 1010 * Property group should already exist: bump the ref count for this 1011 * propval and add it to the node's property group 1012 */ 1013 if ((pg = pgroup_get(node, pgname)) == NULL) 1014 return (inherit_seterror(node, err, ETOPO_PROP_NOENT)); 1015 1016 if ((pvl = topo_hdl_zalloc(thp, sizeof (topo_proplist_t))) 1017 == NULL) 1018 return (inherit_seterror(node, err, ETOPO_NOMEM)); 1019 1020 topo_prop_hold(pv); 1021 pvl->tp_pval = pv; 1022 topo_list_append(&pg->tpg_pvals, pvl); 1023 1024 topo_node_unlock(node); 1025 topo_node_unlock(pnode); 1026 1027 return (0); 1028 } 1029 1030 topo_pgroup_info_t * 1031 topo_pgroup_info(tnode_t *node, const char *pgname, int *err) 1032 { 1033 topo_hdl_t *thp = node->tn_hdl; 1034 topo_pgroup_t *pg; 1035 topo_ipgroup_info_t *pip; 1036 topo_pgroup_info_t *info; 1037 1038 topo_node_lock(node); 1039 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; 1040 pg = topo_list_next(pg)) { 1041 if (strcmp(pgname, pg->tpg_info->tpi_name) == 0) { 1042 if ((info = topo_hdl_alloc(thp, 1043 sizeof (topo_pgroup_info_t))) == NULL) 1044 return (NULL); 1045 1046 pip = pg->tpg_info; 1047 if ((info->tpi_name = 1048 topo_hdl_strdup(thp, pip->tpi_name)) == NULL) { 1049 *err = ETOPO_PROP_NOMEM; 1050 topo_hdl_free(thp, info, 1051 sizeof (topo_pgroup_info_t)); 1052 topo_node_unlock(node); 1053 return (NULL); 1054 } 1055 info->tpi_namestab = pip->tpi_namestab; 1056 info->tpi_datastab = pip->tpi_datastab; 1057 info->tpi_version = pip->tpi_version; 1058 topo_node_unlock(node); 1059 return (info); 1060 } 1061 } 1062 1063 *err = ETOPO_PROP_NOENT; 1064 topo_node_unlock(node); 1065 return (NULL); 1066 } 1067 1068 static int 1069 pgroup_seterr(tnode_t *node, topo_pgroup_t *pg, topo_ipgroup_info_t *pip, 1070 int *err) 1071 { 1072 topo_hdl_t *thp = node->tn_hdl; 1073 1074 if (pip != NULL) { 1075 if (pip->tpi_name != NULL) 1076 topo_hdl_strfree(thp, (char *)pip->tpi_name); 1077 topo_hdl_free(thp, pip, sizeof (topo_ipgroup_info_t)); 1078 } 1079 1080 topo_hdl_free(thp, pg, sizeof (topo_pgroup_t)); 1081 *err = ETOPO_NOMEM; 1082 1083 topo_node_unlock(node); 1084 1085 return (-1); 1086 } 1087 1088 int 1089 topo_pgroup_create(tnode_t *node, const topo_pgroup_info_t *pinfo, int *err) 1090 { 1091 topo_pgroup_t *pg; 1092 topo_ipgroup_info_t *pip; 1093 topo_hdl_t *thp = node->tn_hdl; 1094 1095 *err = 0; 1096 1097 topo_node_lock(node); 1098 /* 1099 * Check for an existing pgroup 1100 */ 1101 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; 1102 pg = topo_list_next(pg)) { 1103 if (strcmp(pg->tpg_info->tpi_name, pinfo->tpi_name) == 0) { 1104 *err = ETOPO_PROP_DEFD; 1105 topo_node_unlock(node); 1106 return (-1); 1107 } 1108 } 1109 1110 if ((pg = topo_hdl_zalloc(thp, sizeof (topo_pgroup_t))) == NULL) { 1111 *err = ETOPO_NOMEM; 1112 topo_node_unlock(node); 1113 return (-1); 1114 } 1115 1116 if ((pip = topo_hdl_zalloc(thp, sizeof (topo_ipgroup_info_t))) 1117 == NULL) 1118 return (pgroup_seterr(node, pg, pip, err)); 1119 1120 if ((pip->tpi_name = topo_hdl_strdup(thp, pinfo->tpi_name)) 1121 == NULL) 1122 return (pgroup_seterr(node, pg, pip, err)); 1123 1124 pip->tpi_namestab = pinfo->tpi_namestab; 1125 pip->tpi_datastab = pinfo->tpi_datastab; 1126 pip->tpi_version = pinfo->tpi_version; 1127 1128 pg->tpg_info = pip; 1129 1130 topo_list_append(&node->tn_pgroups, pg); 1131 topo_node_unlock(node); 1132 1133 return (0); 1134 } 1135 1136 void 1137 topo_pgroup_destroy(tnode_t *node, const char *pname) 1138 { 1139 topo_hdl_t *thp = node->tn_hdl; 1140 topo_pgroup_t *pg; 1141 topo_proplist_t *pvl; 1142 topo_ipgroup_info_t *pip; 1143 1144 topo_node_lock(node); 1145 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; 1146 pg = topo_list_next(pg)) { 1147 if (strcmp(pg->tpg_info->tpi_name, pname) == 0) { 1148 break; 1149 } 1150 } 1151 1152 if (pg == NULL) { 1153 topo_node_unlock(node); 1154 return; 1155 } 1156 1157 while ((pvl = topo_list_next(&pg->tpg_list)) != NULL) { 1158 topo_list_delete(&pg->tpg_pvals, pvl); 1159 topo_prop_rele(pvl->tp_pval); 1160 topo_hdl_free(thp, pvl, sizeof (topo_proplist_t)); 1161 } 1162 1163 topo_list_delete(&node->tn_pgroups, pg); 1164 topo_node_unlock(node); 1165 1166 pip = pg->tpg_info; 1167 if (pip != NULL) { 1168 if (pip->tpi_name != NULL) 1169 topo_hdl_strfree(thp, (char *)pip->tpi_name); 1170 topo_hdl_free(thp, pip, sizeof (topo_ipgroup_info_t)); 1171 } 1172 1173 topo_hdl_free(thp, pg, sizeof (topo_pgroup_t)); 1174 } 1175 1176 void 1177 topo_pgroup_destroy_all(tnode_t *node) 1178 { 1179 topo_hdl_t *thp = node->tn_hdl; 1180 topo_pgroup_t *pg; 1181 topo_proplist_t *pvl; 1182 topo_ipgroup_info_t *pip; 1183 1184 topo_node_lock(node); 1185 while ((pg = topo_list_next(&node->tn_pgroups)) != NULL) { 1186 while ((pvl = topo_list_next(&pg->tpg_pvals)) != NULL) { 1187 topo_list_delete(&pg->tpg_pvals, pvl); 1188 topo_prop_rele(pvl->tp_pval); 1189 topo_hdl_free(thp, pvl, sizeof (topo_proplist_t)); 1190 } 1191 1192 topo_list_delete(&node->tn_pgroups, pg); 1193 1194 pip = pg->tpg_info; 1195 if (pip != NULL) { 1196 if (pip->tpi_name != NULL) 1197 topo_hdl_strfree(thp, (char *)pip->tpi_name); 1198 topo_hdl_free(thp, pip, sizeof (topo_pgroup_info_t)); 1199 } 1200 1201 topo_hdl_free(thp, pg, sizeof (topo_pgroup_t)); 1202 } 1203 topo_node_unlock(node); 1204 } 1205 1206 static void 1207 propmethod_destroy(topo_hdl_t *thp, topo_propval_t *pv) 1208 { 1209 topo_propmethod_t *pm; 1210 1211 pm = pv->tp_method; 1212 if (pm != NULL) { 1213 if (pm->tpm_name != NULL) 1214 topo_hdl_strfree(thp, pm->tpm_name); 1215 if (pm->tpm_args != NULL) 1216 nvlist_free(pm->tpm_args); 1217 topo_hdl_free(thp, pm, sizeof (topo_propmethod_t)); 1218 pv->tp_method = NULL; 1219 } 1220 } 1221 1222 static void 1223 topo_propval_destroy(topo_propval_t *pv) 1224 { 1225 topo_hdl_t *thp; 1226 1227 if (pv == NULL) 1228 return; 1229 1230 thp = pv->tp_hdl; 1231 1232 if (pv->tp_name != NULL) 1233 topo_hdl_strfree(thp, pv->tp_name); 1234 1235 if (pv->tp_val != NULL) 1236 nvlist_free(pv->tp_val); 1237 1238 propmethod_destroy(thp, pv); 1239 1240 topo_hdl_free(thp, pv, sizeof (topo_propval_t)); 1241 } 1242 1243 void 1244 topo_prop_hold(topo_propval_t *pv) 1245 { 1246 pv->tp_refs++; 1247 } 1248 1249 void 1250 topo_prop_rele(topo_propval_t *pv) 1251 { 1252 pv->tp_refs--; 1253 1254 assert(pv->tp_refs >= 0); 1255 1256 if (pv->tp_refs == 0) 1257 topo_propval_destroy(pv); 1258 } 1259 1260 /* 1261 * topo_prop_getprop() and topo_prop_getprops() are private project functions 1262 * for fmtopo 1263 */ 1264 int 1265 topo_prop_getprop(tnode_t *node, const char *pgname, const char *pname, 1266 nvlist_t *args, nvlist_t **prop, int *err) 1267 { 1268 topo_hdl_t *thp = node->tn_hdl; 1269 topo_propval_t *pv; 1270 1271 topo_node_lock(node); 1272 if ((pv = prop_get(node, pgname, pname, args, err)) == NULL) { 1273 (void) get_properror(node, err, *err); 1274 return (-1); 1275 } 1276 1277 if (topo_hdl_nvdup(thp, pv->tp_val, prop) != 0) { 1278 (void) get_properror(node, err, ETOPO_NOMEM); 1279 return (-1); 1280 } 1281 topo_node_unlock(node); 1282 1283 return (0); 1284 } 1285 1286 static int 1287 prop_val_add(tnode_t *node, nvlist_t **nvl, topo_propval_t *pv, int *err) 1288 { 1289 if (pv->tp_method != NULL) 1290 if (prop_method_get(node, pv, pv->tp_method, NULL, err) < 0) 1291 return (-1); 1292 1293 if (pv->tp_val == NULL) { 1294 *err = ETOPO_PROP_NOENT; 1295 return (-1); 1296 } 1297 1298 if (topo_hdl_nvdup(pv->tp_hdl, pv->tp_val, nvl) != 0) { 1299 *err = ETOPO_PROP_NOMEM; 1300 return (-1); 1301 } 1302 1303 return (0); 1304 } 1305 1306 static int 1307 get_pgrp_seterror(tnode_t *node, nvlist_t *nvl, int *errp, int err) 1308 { 1309 topo_node_unlock(node); 1310 1311 if (nvl != NULL) 1312 nvlist_free(nvl); 1313 1314 *errp = err; 1315 1316 return (-1); 1317 } 1318 1319 int 1320 topo_prop_getpgrp(tnode_t *node, const char *pgname, nvlist_t **pgrp, 1321 int *err) 1322 { 1323 int ret; 1324 topo_hdl_t *thp = node->tn_hdl; 1325 nvlist_t *nvl, *pvnvl; 1326 topo_pgroup_t *pg; 1327 topo_propval_t *pv; 1328 topo_proplist_t *pvl; 1329 1330 if (topo_hdl_nvalloc(thp, &nvl, 0) != 0) { 1331 *err = ETOPO_NOMEM; 1332 return (-1); 1333 } 1334 1335 topo_node_lock(node); 1336 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; 1337 pg = topo_list_next(pg)) { 1338 1339 if (strcmp(pgname, pg->tpg_info->tpi_name) != 0) 1340 continue; 1341 1342 if (nvlist_add_string(nvl, TOPO_PROP_GROUP_NAME, 1343 pg->tpg_info->tpi_name) != 0 || 1344 nvlist_add_string(nvl, TOPO_PROP_GROUP_NSTAB, 1345 topo_stability2name(pg->tpg_info->tpi_namestab)) != 0 || 1346 nvlist_add_string(nvl, TOPO_PROP_GROUP_DSTAB, 1347 topo_stability2name(pg->tpg_info->tpi_datastab)) != 0 || 1348 nvlist_add_int32(nvl, TOPO_PROP_GROUP_VERSION, 1349 pg->tpg_info->tpi_version) != 0) 1350 return (get_pgrp_seterror(node, nvl, err, 1351 ETOPO_PROP_NVL)); 1352 1353 for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL; 1354 pvl = topo_list_next(pvl)) { 1355 1356 pv = pvl->tp_pval; 1357 if (prop_val_add(node, &pvnvl, pv, err) < 0) { 1358 return (get_pgrp_seterror(node, nvl, err, 1359 *err)); 1360 } 1361 if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_VAL, 1362 pvnvl)) != 0) { 1363 nvlist_free(pvnvl); 1364 return (get_pgrp_seterror(node, nvl, err, ret)); 1365 } 1366 1367 nvlist_free(pvnvl); 1368 } 1369 topo_node_unlock(node); 1370 *pgrp = nvl; 1371 return (0); 1372 } 1373 1374 topo_node_unlock(node); 1375 *err = ETOPO_PROP_NOENT; 1376 return (-1); 1377 } 1378 1379 static nvlist_t * 1380 get_all_seterror(tnode_t *node, nvlist_t *nvl, int *errp, int err) 1381 { 1382 topo_node_unlock(node); 1383 1384 if (nvl != NULL) 1385 nvlist_free(nvl); 1386 1387 *errp = err; 1388 1389 return (NULL); 1390 } 1391 1392 nvlist_t * 1393 topo_prop_getprops(tnode_t *node, int *err) 1394 { 1395 int ret; 1396 topo_hdl_t *thp = node->tn_hdl; 1397 nvlist_t *nvl, *pgnvl, *pvnvl; 1398 topo_pgroup_t *pg; 1399 topo_propval_t *pv; 1400 topo_proplist_t *pvl; 1401 1402 topo_node_lock(node); 1403 if (topo_hdl_nvalloc(thp, &nvl, 0) != 0) { 1404 return (get_all_seterror(node, NULL, err, ETOPO_NOMEM)); 1405 } 1406 1407 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; 1408 pg = topo_list_next(pg)) { 1409 if (topo_hdl_nvalloc(thp, &pgnvl, 0) != 0) 1410 return (get_all_seterror(node, nvl, err, ETOPO_NOMEM)); 1411 1412 if (nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NAME, 1413 pg->tpg_info->tpi_name) != 0 || 1414 nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NSTAB, 1415 topo_stability2name(pg->tpg_info->tpi_namestab)) != 0 || 1416 nvlist_add_string(pgnvl, TOPO_PROP_GROUP_DSTAB, 1417 topo_stability2name(pg->tpg_info->tpi_datastab)) != 0 || 1418 nvlist_add_int32(pgnvl, TOPO_PROP_GROUP_VERSION, 1419 pg->tpg_info->tpi_version) != 0) 1420 return (get_all_seterror(node, nvl, err, 1421 ETOPO_PROP_NVL)); 1422 1423 for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL; 1424 pvl = topo_list_next(pvl)) { 1425 1426 pv = pvl->tp_pval; 1427 if (prop_val_add(node, &pvnvl, pv, err) < 0) { 1428 nvlist_free(pgnvl); 1429 return (get_all_seterror(node, nvl, err, *err)); 1430 } 1431 if ((ret = nvlist_add_nvlist(pgnvl, TOPO_PROP_VAL, 1432 pvnvl)) != 0) { 1433 nvlist_free(pgnvl); 1434 nvlist_free(pvnvl); 1435 return (get_all_seterror(node, nvl, err, ret)); 1436 } 1437 1438 nvlist_free(pvnvl); 1439 } 1440 if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_GROUP, pgnvl)) 1441 != 0) { 1442 nvlist_free(pgnvl); 1443 return (get_all_seterror(node, nvl, err, ret)); 1444 } 1445 1446 nvlist_free(pgnvl); 1447 } 1448 1449 topo_node_unlock(node); 1450 1451 return (nvl); 1452 } 1453