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