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 topo_node_unlock(node); 389 return (0); 390 } 391 392 int 393 topo_prop_get_int32(tnode_t *node, const char *pgname, const char *pname, 394 int32_t *val, int *err) 395 { 396 return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_INT32, 397 NULL, err)); 398 } 399 400 int 401 topo_prop_get_uint32(tnode_t *node, const char *pgname, const char *pname, 402 uint32_t *val, int *err) 403 { 404 return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_UINT32, 405 NULL, err)); 406 } 407 408 int 409 topo_prop_get_int64(tnode_t *node, const char *pgname, const char *pname, 410 int64_t *val, int *err) 411 { 412 return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_INT64, 413 NULL, err)); 414 } 415 416 int 417 topo_prop_get_uint64(tnode_t *node, const char *pgname, const char *pname, 418 uint64_t *val, int *err) 419 { 420 return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_UINT64, 421 NULL, err)); 422 } 423 424 int 425 topo_prop_get_double(tnode_t *node, const char *pgname, const char *pname, 426 double *val, int *err) 427 { 428 return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_DOUBLE, 429 NULL, err)); 430 } 431 432 int 433 topo_prop_get_string(tnode_t *node, const char *pgname, const char *pname, 434 char **val, int *err) 435 { 436 return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_STRING, 437 NULL, err)); 438 } 439 440 int 441 topo_prop_get_fmri(tnode_t *node, const char *pgname, const char *pname, 442 nvlist_t **val, int *err) 443 { 444 return (prop_getval(node, pgname, pname, (void *)val, TOPO_TYPE_FMRI, 445 NULL, err)); 446 } 447 448 int 449 topo_prop_get_int32_array(tnode_t *node, const char *pgname, const char *pname, 450 int32_t **val, uint_t *nelem, int *err) 451 { 452 return (prop_getval(node, pgname, pname, (void *)val, 453 TOPO_TYPE_INT32_ARRAY, nelem, err)); 454 } 455 456 int 457 topo_prop_get_uint32_array(tnode_t *node, const char *pgname, const char *pname, 458 uint32_t **val, uint_t *nelem, int *err) 459 { 460 return (prop_getval(node, pgname, pname, (void *)val, 461 TOPO_TYPE_UINT32_ARRAY, nelem, err)); 462 } 463 464 int 465 topo_prop_get_int64_array(tnode_t *node, const char *pgname, const char *pname, 466 int64_t **val, uint_t *nelem, int *err) 467 { 468 return (prop_getval(node, pgname, pname, (void *)val, 469 TOPO_TYPE_INT64_ARRAY, nelem, err)); 470 } 471 472 int 473 topo_prop_get_uint64_array(tnode_t *node, const char *pgname, const char *pname, 474 uint64_t **val, uint_t *nelem, int *err) 475 { 476 return (prop_getval(node, pgname, pname, (void *)val, 477 TOPO_TYPE_UINT64_ARRAY, nelem, err)); 478 } 479 480 int 481 topo_prop_get_string_array(tnode_t *node, const char *pgname, const char *pname, 482 char ***val, uint_t *nelem, int *err) 483 { 484 return (prop_getval(node, pgname, pname, (void *)val, 485 TOPO_TYPE_STRING_ARRAY, nelem, err)); 486 } 487 488 int 489 topo_prop_get_fmri_array(tnode_t *node, const char *pgname, const char *pname, 490 nvlist_t ***val, uint_t *nelem, int *err) 491 { 492 return (prop_getval(node, pgname, pname, (void *)val, 493 TOPO_TYPE_FMRI_ARRAY, nelem, err)); 494 } 495 496 static topo_propval_t * 497 set_seterror(tnode_t *node, topo_proplist_t *pvl, int *errp, int err) 498 { 499 topo_hdl_t *thp = node->tn_hdl; 500 topo_propval_t *pv; 501 502 if (pvl != NULL) { 503 pv = pvl->tp_pval; 504 topo_propval_destroy(pv); 505 topo_hdl_free(thp, pvl, sizeof (topo_proplist_t)); 506 } 507 508 topo_node_unlock(node); 509 *errp = err; 510 511 return (NULL); 512 } 513 514 static topo_propval_t * 515 prop_create(tnode_t *node, const char *pgname, const char *pname, 516 topo_type_t type, int flag, int *err) 517 { 518 topo_hdl_t *thp = node->tn_hdl; 519 topo_pgroup_t *pg; 520 topo_propval_t *pv; 521 topo_proplist_t *pvl; 522 523 /* 524 * Replace existing prop value with new one 525 */ 526 if ((pg = pgroup_get(node, pgname)) == NULL) { 527 topo_node_unlock(node); 528 *err = ETOPO_PROP_NOENT; 529 return (NULL); 530 } 531 532 if ((pv = propval_get(pg, pname)) != NULL) { 533 if (pv->tp_type != type) 534 return (set_seterror(node, NULL, err, ETOPO_PROP_TYPE)); 535 else if (! (pv->tp_flag & TOPO_PROP_MUTABLE)) 536 return (set_seterror(node, NULL, err, ETOPO_PROP_DEFD)); 537 538 nvlist_free(pv->tp_val); 539 pv->tp_val = NULL; 540 } else { 541 if ((pvl = topo_hdl_zalloc(thp, sizeof (topo_proplist_t))) 542 == NULL) 543 return (set_seterror(node, NULL, err, ETOPO_NOMEM)); 544 545 if ((pv = topo_hdl_zalloc(thp, sizeof (topo_propval_t))) 546 == NULL) 547 return (set_seterror(node, pvl, err, ETOPO_NOMEM)); 548 549 pv->tp_hdl = thp; 550 pvl->tp_pval = pv; 551 552 if ((pv->tp_name = topo_hdl_strdup(thp, pname)) 553 == NULL) 554 return (set_seterror(node, pvl, err, ETOPO_NOMEM)); 555 pv->tp_flag = flag; 556 pv->tp_type = type; 557 topo_prop_hold(pv); 558 topo_list_append(&pg->tpg_pvals, pvl); 559 } 560 561 return (pv); 562 } 563 564 static int 565 topo_prop_set(tnode_t *node, const char *pgname, const char *pname, 566 topo_type_t type, int flag, void *val, int nelems, int *err) 567 { 568 int ret; 569 topo_hdl_t *thp = node->tn_hdl; 570 nvlist_t *nvl; 571 572 if (topo_hdl_nvalloc(thp, &nvl, NV_UNIQUE_NAME) < 0) { 573 *err = ETOPO_PROP_NVL; 574 return (-1); 575 } 576 577 ret = nvlist_add_string(nvl, TOPO_PROP_VAL_NAME, pname); 578 ret |= nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, type); 579 switch (type) { 580 case TOPO_TYPE_INT32: 581 ret |= nvlist_add_int32(nvl, TOPO_PROP_VAL_VAL, 582 *(int32_t *)val); 583 break; 584 case TOPO_TYPE_UINT32: 585 ret |= nvlist_add_uint32(nvl, TOPO_PROP_VAL_VAL, 586 *(uint32_t *)val); 587 break; 588 case TOPO_TYPE_INT64: 589 ret |= nvlist_add_int64(nvl, TOPO_PROP_VAL_VAL, 590 *(int64_t *)val); 591 break; 592 case TOPO_TYPE_UINT64: 593 ret |= nvlist_add_uint64(nvl, TOPO_PROP_VAL_VAL, 594 *(uint64_t *)val); 595 break; 596 case TOPO_TYPE_DOUBLE: 597 ret |= nvlist_add_double(nvl, TOPO_PROP_VAL_VAL, 598 *(double *)val); 599 break; 600 case TOPO_TYPE_STRING: 601 ret |= nvlist_add_string(nvl, TOPO_PROP_VAL_VAL, 602 (char *)val); 603 break; 604 case TOPO_TYPE_FMRI: 605 ret |= nvlist_add_nvlist(nvl, TOPO_PROP_VAL_VAL, 606 (nvlist_t *)val); 607 break; 608 case TOPO_TYPE_INT32_ARRAY: 609 ret |= nvlist_add_int32_array(nvl, 610 TOPO_PROP_VAL_VAL, (int32_t *)val, nelems); 611 break; 612 case TOPO_TYPE_UINT32_ARRAY: 613 ret |= nvlist_add_uint32_array(nvl, 614 TOPO_PROP_VAL_VAL, (uint32_t *)val, nelems); 615 break; 616 case TOPO_TYPE_INT64_ARRAY: 617 ret |= nvlist_add_int64_array(nvl, 618 TOPO_PROP_VAL_VAL, (int64_t *)val, nelems); 619 break; 620 case TOPO_TYPE_UINT64_ARRAY: 621 ret |= nvlist_add_uint64_array(nvl, 622 TOPO_PROP_VAL_VAL, (uint64_t *)val, nelems); 623 break; 624 case TOPO_TYPE_STRING_ARRAY: 625 ret |= nvlist_add_string_array(nvl, 626 TOPO_PROP_VAL_VAL, (char **)val, nelems); 627 break; 628 case TOPO_TYPE_FMRI_ARRAY: 629 ret |= nvlist_add_nvlist_array(nvl, 630 TOPO_PROP_VAL_VAL, (nvlist_t **)val, nelems); 631 break; 632 default: 633 *err = ETOPO_PROP_TYPE; 634 return (-1); 635 } 636 637 if (ret != 0) { 638 nvlist_free(nvl); 639 if (ret == ENOMEM) { 640 *err = ETOPO_PROP_NOMEM; 641 return (-1); 642 } else { 643 *err = ETOPO_PROP_NVL; 644 return (-1); 645 } 646 } 647 648 if (topo_prop_setprop(node, pgname, nvl, flag, nvl, err) != 0) { 649 nvlist_free(nvl); 650 return (-1); /* err set */ 651 } 652 nvlist_free(nvl); 653 return (ret); 654 } 655 656 int 657 topo_prop_set_int32(tnode_t *node, const char *pgname, const char *pname, 658 int flag, int32_t val, int *err) 659 { 660 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT32, flag, 661 &val, 1, err)); 662 } 663 664 int 665 topo_prop_set_uint32(tnode_t *node, const char *pgname, const char *pname, 666 int flag, uint32_t val, int *err) 667 { 668 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT32, flag, 669 &val, 1, err)); 670 } 671 672 int 673 topo_prop_set_int64(tnode_t *node, const char *pgname, const char *pname, 674 int flag, int64_t val, int *err) 675 { 676 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT64, flag, 677 &val, 1, err)); 678 } 679 680 int 681 topo_prop_set_uint64(tnode_t *node, const char *pgname, const char *pname, 682 int flag, uint64_t val, int *err) 683 { 684 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT64, flag, 685 &val, 1, err)); 686 } 687 688 int 689 topo_prop_set_double(tnode_t *node, const char *pgname, const char *pname, 690 int flag, double val, int *err) 691 { 692 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_DOUBLE, flag, 693 &val, 1, err)); 694 } 695 696 int 697 topo_prop_set_string(tnode_t *node, const char *pgname, const char *pname, 698 int flag, const char *val, int *err) 699 { 700 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_STRING, flag, 701 (void *)val, 1, err)); 702 } 703 704 int 705 topo_prop_set_fmri(tnode_t *node, const char *pgname, const char *pname, 706 int flag, const nvlist_t *fmri, int *err) 707 { 708 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_FMRI, flag, 709 (void *)fmri, 1, err)); 710 } 711 712 int 713 topo_prop_set_int32_array(tnode_t *node, const char *pgname, const char *pname, 714 int flag, int32_t *val, uint_t nelems, int *err) 715 { 716 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT32_ARRAY, flag, 717 val, nelems, err)); 718 } 719 720 int 721 topo_prop_set_uint32_array(tnode_t *node, const char *pgname, const char *pname, 722 int flag, uint32_t *val, uint_t nelems, int *err) 723 { 724 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT32_ARRAY, flag, 725 val, nelems, err)); 726 } 727 728 int 729 topo_prop_set_int64_array(tnode_t *node, const char *pgname, const char *pname, 730 int flag, int64_t *val, uint_t nelems, int *err) 731 { 732 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_INT64_ARRAY, flag, 733 val, nelems, err)); 734 } 735 736 int 737 topo_prop_set_uint64_array(tnode_t *node, const char *pgname, const char *pname, 738 int flag, uint64_t *val, uint_t nelems, int *err) 739 { 740 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_UINT64_ARRAY, flag, 741 val, nelems, err)); 742 } 743 744 int 745 topo_prop_set_string_array(tnode_t *node, const char *pgname, const char *pname, 746 int flag, const char **val, uint_t nelems, int *err) 747 { 748 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_STRING_ARRAY, flag, 749 (void *)val, nelems, err)); 750 } 751 752 int 753 topo_prop_set_fmri_array(tnode_t *node, const char *pgname, const char *pname, 754 int flag, const nvlist_t **fmri, uint_t nelems, int *err) 755 { 756 return (topo_prop_set(node, pgname, pname, TOPO_TYPE_FMRI_ARRAY, flag, 757 (void *)fmri, nelems, err)); 758 } 759 760 /* 761 * topo_prop_setprop() is a private project function for fmtopo 762 */ 763 int 764 topo_prop_setprop(tnode_t *node, const char *pgname, nvlist_t *prop, 765 int flag, nvlist_t *pargs, int *err) 766 { 767 int ret; 768 topo_hdl_t *thp = node->tn_hdl; 769 topo_propval_t *pv; 770 nvlist_t *nvl, *args; 771 char *name; 772 topo_type_t type; 773 774 if (nvlist_lookup_string(prop, TOPO_PROP_VAL_NAME, &name) != 0) { 775 *err = ETOPO_PROP_NAME; 776 return (-1); 777 } 778 if (nvlist_lookup_uint32(prop, TOPO_PROP_VAL_TYPE, (uint32_t *)&type) 779 != 0) { 780 *err = ETOPO_PROP_TYPE; 781 return (-1); 782 } 783 784 topo_node_lock(node); 785 if ((pv = prop_create(node, pgname, name, type, flag, err)) == NULL) 786 return (-1); /* unlocked and err set */ 787 788 /* 789 * Set by method or set to new prop value. If we fail, leave 790 * property in list with old value. 791 */ 792 if (pv->tp_method != NULL) { 793 topo_propmethod_t *pm = pv->tp_method; 794 795 if (topo_hdl_nvalloc(pv->tp_hdl, &args, NV_UNIQUE_NAME) < 0) { 796 topo_node_unlock(node); 797 *err = ETOPO_PROP_NOMEM; 798 return (-1); 799 } 800 ret = nvlist_add_nvlist(args, TOPO_PROP_ARGS, pm->tpm_args); 801 if (pargs != NULL) 802 ret |= nvlist_add_nvlist(args, TOPO_PROP_PARGS, pargs); 803 804 if (ret != 0) { 805 topo_node_unlock(node); 806 nvlist_free(args); 807 *err = ETOPO_PROP_NVL; 808 return (-1); 809 } 810 811 /* 812 * 813 * Grab a reference to the property and then unlock the node. 814 * This will allow property methods to safely re-enter the 815 * prop_get codepath, making it possible for property methods 816 * to access other property values on the same node w\o causing 817 * a deadlock. 818 * 819 * We don't technically need this now, since this interface is 820 * currently only used by fmtopo (which is single-threaded), but 821 * we may make this interface available to other parts of 822 * libtopo in the future, so best to make it MT-safe now. 823 */ 824 topo_prop_hold(pv); 825 topo_node_unlock(node); 826 ret = topo_method_call(node, pm->tpm_name, pm->tpm_version, 827 args, &nvl, err); 828 topo_node_lock(node); 829 topo_prop_rele(pv); 830 831 nvlist_free(args); 832 } else { 833 if ((ret = topo_hdl_nvdup(thp, prop, &nvl)) != 0) 834 *err = ETOPO_PROP_NOMEM; 835 } 836 837 if (ret != 0) { 838 topo_node_unlock(node); 839 return (-1); 840 } 841 842 pv->tp_val = nvl; 843 topo_node_unlock(node); 844 return (0); 845 } 846 847 static int 848 register_methoderror(tnode_t *node, topo_propmethod_t *pm, int *errp, int l, 849 int err) 850 { 851 topo_hdl_t *thp = node->tn_hdl; 852 853 if (pm != NULL) { 854 if (pm->tpm_name != NULL) 855 topo_hdl_strfree(thp, pm->tpm_name); 856 nvlist_free(pm->tpm_args); 857 topo_hdl_free(thp, pm, sizeof (topo_propmethod_t)); 858 } 859 860 *errp = err; 861 862 if (l != 0) 863 topo_node_unlock(node); 864 865 return (-1); 866 } 867 868 int 869 prop_method_register(tnode_t *node, const char *pgname, const char *pname, 870 topo_type_t ptype, const char *mname, topo_version_t version, 871 const nvlist_t *args, int *err) 872 { 873 topo_hdl_t *thp = node->tn_hdl; 874 topo_propmethod_t *pm = NULL; 875 topo_propval_t *pv = NULL; 876 877 if ((pm = topo_hdl_zalloc(thp, sizeof (topo_propmethod_t))) == NULL) 878 return (register_methoderror(node, pm, err, 1, 879 ETOPO_PROP_NOMEM)); 880 881 if ((pm->tpm_name = topo_hdl_strdup(thp, mname)) == NULL) 882 return (register_methoderror(node, pm, err, 1, 883 ETOPO_PROP_NOMEM)); 884 885 pm->tpm_version = version; 886 887 if (topo_hdl_nvdup(thp, (nvlist_t *)args, &pm->tpm_args) != 0) 888 return (register_methoderror(node, pm, err, 1, 889 ETOPO_PROP_NOMEM)); 890 891 /* 892 * It's possible the property may already exist. However we still want 893 * to allow the method to be registered. This is to handle the case 894 * where we specify a prop method in an xml map to override the value 895 * that was set by the enumerator. 896 * 897 * By default, propmethod-backed properties are not MUTABLE. This is 898 * done to simplify the programming model for modules that implement 899 * property methods as most propmethods tend to only support get 900 * operations. Enumerator modules can override this by calling 901 * topo_prop_setmutable(). Propmethods that are registered via XML can 902 * be set as mutable via the optional "mutable" attribute, which will 903 * result in the xml parser calling topo_prop_setflags() after 904 * registering the propmethod. 905 */ 906 if ((pv = propval_get(pgroup_get(node, pgname), pname)) == NULL) 907 if ((pv = prop_create(node, pgname, pname, ptype, 908 TOPO_PROP_IMMUTABLE, err)) == NULL) { 909 /* node unlocked */ 910 return (register_methoderror(node, pm, err, 0, *err)); 911 } 912 913 if (pv->tp_method != NULL) 914 return (register_methoderror(node, pm, err, 1, 915 ETOPO_METHOD_DEFD)); 916 917 if (pv->tp_val != NULL) { 918 nvlist_free(pv->tp_val); 919 pv->tp_val = NULL; 920 } 921 pv->tp_method = pm; 922 923 topo_node_unlock(node); 924 925 return (0); 926 } 927 928 int 929 topo_prop_method_register(tnode_t *node, const char *pgname, const char *pname, 930 topo_type_t ptype, const char *mname, const nvlist_t *args, int *err) 931 { 932 topo_imethod_t *mp; 933 934 topo_node_lock(node); 935 936 if ((mp = topo_method_lookup(node, mname)) == NULL) 937 return (register_methoderror(node, NULL, err, 1, 938 ETOPO_METHOD_NOTSUP)); /* node unlocked */ 939 940 topo_node_lock(node); 941 942 return (prop_method_register(node, pgname, pname, ptype, mname, 943 mp->tim_version, args, err)); /* err set and node unlocked */ 944 } 945 946 int 947 topo_prop_method_version_register(tnode_t *node, const char *pgname, 948 const char *pname, topo_type_t ptype, const char *mname, 949 topo_version_t version, const nvlist_t *args, int *err) 950 { 951 topo_imethod_t *mp; 952 953 topo_node_lock(node); 954 955 if ((mp = topo_method_lookup(node, mname)) == NULL) 956 return (register_methoderror(node, NULL, err, 1, 957 ETOPO_METHOD_NOTSUP)); /* node unlocked */ 958 959 topo_node_lock(node); 960 961 if (version < mp->tim_version) 962 return (register_methoderror(node, NULL, err, 1, 963 ETOPO_METHOD_VEROLD)); 964 if (version > mp->tim_version) 965 return (register_methoderror(node, NULL, err, 1, 966 ETOPO_METHOD_VERNEW)); 967 968 return (prop_method_register(node, pgname, pname, ptype, mname, 969 version, args, err)); /* err set and node unlocked */ 970 } 971 972 void 973 topo_prop_method_unregister(tnode_t *node, const char *pgname, 974 const char *pname) 975 { 976 topo_propval_t *pv; 977 topo_pgroup_t *pg; 978 topo_proplist_t *pvl; 979 topo_hdl_t *thp = node->tn_hdl; 980 981 topo_node_lock(node); 982 983 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; 984 pg = topo_list_next(pg)) { 985 if (strcmp(pg->tpg_info->tpi_name, pgname) == 0) { 986 break; 987 } 988 } 989 990 if (pg == NULL) { 991 topo_node_unlock(node); 992 return; 993 } 994 995 for (pvl = topo_list_next(&pg->tpg_list); pvl != NULL; 996 pvl = topo_list_next(pvl)) { 997 pv = pvl->tp_pval; 998 if (strcmp(pv->tp_name, pname) == 0) { 999 topo_list_delete(&pg->tpg_pvals, pvl); 1000 assert(pv->tp_refs == 1); 1001 topo_prop_rele(pv); 1002 topo_hdl_free(thp, pvl, sizeof (topo_proplist_t)); 1003 break; 1004 } 1005 } 1006 1007 topo_node_unlock(node); 1008 } 1009 1010 int 1011 topo_prop_setmutable(tnode_t *node, const char *pgname, const char *pname, 1012 int *err) 1013 { 1014 topo_propval_t *pv = NULL; 1015 1016 topo_node_lock(node); 1017 if ((pv = propval_get(pgroup_get(node, pgname), pname)) == NULL) { 1018 topo_node_unlock(node); 1019 *err = ETOPO_PROP_NOENT; 1020 return (-1); 1021 } 1022 1023 /* 1024 * If the property is being inherited then we don't want to allow a 1025 * change from IMMUTABLE to MUTABLE. 1026 */ 1027 if (pv->tp_refs > 1) { 1028 topo_node_unlock(node); 1029 *err = ETOPO_PROP_DEFD; 1030 return (-1); 1031 } 1032 pv->tp_flag |= TOPO_PROP_MUTABLE; 1033 1034 topo_node_unlock(node); 1035 1036 return (0); 1037 } 1038 int 1039 topo_prop_setnonvolatile(tnode_t *node, const char *pgname, const char *pname, 1040 int *err) 1041 { 1042 topo_propval_t *pv = NULL; 1043 1044 topo_node_lock(node); 1045 if ((pv = propval_get(pgroup_get(node, pgname), pname)) == NULL) { 1046 topo_node_unlock(node); 1047 *err = ETOPO_PROP_NOENT; 1048 return (-1); 1049 } 1050 1051 pv->tp_flag |= TOPO_PROP_NONVOLATILE; 1052 1053 topo_node_unlock(node); 1054 1055 return (0); 1056 } 1057 1058 static int 1059 inherit_seterror(tnode_t *node, int *errp, int err) 1060 { 1061 topo_node_unlock(node); 1062 topo_node_unlock(node->tn_parent); 1063 1064 *errp = err; 1065 1066 return (-1); 1067 } 1068 1069 int 1070 topo_prop_inherit(tnode_t *node, const char *pgname, const char *name, int *err) 1071 { 1072 topo_hdl_t *thp = node->tn_hdl; 1073 tnode_t *pnode = node->tn_parent; 1074 topo_pgroup_t *pg; 1075 topo_propval_t *pv; 1076 topo_proplist_t *pvl; 1077 1078 topo_node_lock(pnode); 1079 topo_node_lock(node); 1080 1081 /* 1082 * Check if the requested property group and prop val are already set 1083 * on the node. 1084 */ 1085 if (propval_get(pgroup_get(node, pgname), name) != NULL) 1086 return (inherit_seterror(node, err, ETOPO_PROP_DEFD)); 1087 1088 /* 1089 * Check if the requested property group and prop val exists on the 1090 * parent node 1091 */ 1092 if ((pv = propval_get(pgroup_get(pnode, pgname), name)) == NULL) 1093 return (inherit_seterror(node, err, ETOPO_PROP_NOENT)); 1094 1095 /* 1096 * Can this propval be inherited? 1097 */ 1098 if (pv->tp_flag & TOPO_PROP_MUTABLE) 1099 return (inherit_seterror(node, err, ETOPO_PROP_NOINHERIT)); 1100 1101 /* 1102 * Property group should already exist: bump the ref count for this 1103 * propval and add it to the node's property group 1104 */ 1105 if ((pg = pgroup_get(node, pgname)) == NULL) 1106 return (inherit_seterror(node, err, ETOPO_PROP_NOENT)); 1107 1108 if ((pvl = topo_hdl_zalloc(thp, sizeof (topo_proplist_t))) 1109 == NULL) 1110 return (inherit_seterror(node, err, ETOPO_NOMEM)); 1111 1112 topo_prop_hold(pv); 1113 pvl->tp_pval = pv; 1114 topo_list_append(&pg->tpg_pvals, pvl); 1115 1116 topo_node_unlock(node); 1117 topo_node_unlock(pnode); 1118 1119 return (0); 1120 } 1121 1122 topo_pgroup_info_t * 1123 topo_pgroup_info(tnode_t *node, const char *pgname, int *err) 1124 { 1125 topo_hdl_t *thp = node->tn_hdl; 1126 topo_pgroup_t *pg; 1127 topo_ipgroup_info_t *pip; 1128 topo_pgroup_info_t *info; 1129 1130 topo_node_lock(node); 1131 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; 1132 pg = topo_list_next(pg)) { 1133 if (strcmp(pgname, pg->tpg_info->tpi_name) == 0) { 1134 if ((info = topo_hdl_alloc(thp, 1135 sizeof (topo_pgroup_info_t))) == NULL) 1136 return (NULL); 1137 1138 pip = pg->tpg_info; 1139 if ((info->tpi_name = 1140 topo_hdl_strdup(thp, pip->tpi_name)) == NULL) { 1141 *err = ETOPO_PROP_NOMEM; 1142 topo_hdl_free(thp, info, 1143 sizeof (topo_pgroup_info_t)); 1144 topo_node_unlock(node); 1145 return (NULL); 1146 } 1147 info->tpi_namestab = pip->tpi_namestab; 1148 info->tpi_datastab = pip->tpi_datastab; 1149 info->tpi_version = pip->tpi_version; 1150 topo_node_unlock(node); 1151 return (info); 1152 } 1153 } 1154 1155 *err = ETOPO_PROP_NOENT; 1156 topo_node_unlock(node); 1157 return (NULL); 1158 } 1159 1160 static int 1161 pgroup_seterr(tnode_t *node, topo_pgroup_t *pg, topo_ipgroup_info_t *pip, 1162 int *err) 1163 { 1164 topo_hdl_t *thp = node->tn_hdl; 1165 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 *err = ETOPO_NOMEM; 1174 1175 topo_node_unlock(node); 1176 1177 return (-1); 1178 } 1179 1180 int 1181 topo_pgroup_create(tnode_t *node, const topo_pgroup_info_t *pinfo, int *err) 1182 { 1183 topo_pgroup_t *pg; 1184 topo_ipgroup_info_t *pip; 1185 topo_hdl_t *thp = node->tn_hdl; 1186 1187 *err = 0; 1188 1189 topo_node_lock(node); 1190 /* 1191 * Check for an existing pgroup 1192 */ 1193 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; 1194 pg = topo_list_next(pg)) { 1195 if (strcmp(pg->tpg_info->tpi_name, pinfo->tpi_name) == 0) { 1196 *err = ETOPO_PROP_DEFD; 1197 topo_node_unlock(node); 1198 return (-1); 1199 } 1200 } 1201 1202 if ((pg = topo_hdl_zalloc(thp, sizeof (topo_pgroup_t))) == NULL) { 1203 *err = ETOPO_NOMEM; 1204 topo_node_unlock(node); 1205 return (-1); 1206 } 1207 1208 if ((pip = topo_hdl_zalloc(thp, sizeof (topo_ipgroup_info_t))) 1209 == NULL) 1210 return (pgroup_seterr(node, pg, pip, err)); 1211 1212 if ((pip->tpi_name = topo_hdl_strdup(thp, pinfo->tpi_name)) 1213 == NULL) 1214 return (pgroup_seterr(node, pg, pip, err)); 1215 1216 pip->tpi_namestab = pinfo->tpi_namestab; 1217 pip->tpi_datastab = pinfo->tpi_datastab; 1218 pip->tpi_version = pinfo->tpi_version; 1219 1220 pg->tpg_info = pip; 1221 1222 topo_list_append(&node->tn_pgroups, pg); 1223 topo_node_unlock(node); 1224 1225 return (0); 1226 } 1227 1228 void 1229 topo_pgroup_destroy(tnode_t *node, const char *pname) 1230 { 1231 topo_hdl_t *thp = node->tn_hdl; 1232 topo_pgroup_t *pg; 1233 topo_proplist_t *pvl; 1234 topo_ipgroup_info_t *pip; 1235 1236 topo_node_lock(node); 1237 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; 1238 pg = topo_list_next(pg)) { 1239 if (strcmp(pg->tpg_info->tpi_name, pname) == 0) { 1240 break; 1241 } 1242 } 1243 1244 if (pg == NULL) { 1245 topo_node_unlock(node); 1246 return; 1247 } 1248 1249 while ((pvl = topo_list_next(&pg->tpg_list)) != NULL) { 1250 topo_list_delete(&pg->tpg_pvals, pvl); 1251 topo_prop_rele(pvl->tp_pval); 1252 topo_hdl_free(thp, pvl, sizeof (topo_proplist_t)); 1253 } 1254 1255 topo_list_delete(&node->tn_pgroups, pg); 1256 topo_node_unlock(node); 1257 1258 pip = pg->tpg_info; 1259 if (pip != NULL) { 1260 if (pip->tpi_name != NULL) 1261 topo_hdl_strfree(thp, (char *)pip->tpi_name); 1262 topo_hdl_free(thp, pip, sizeof (topo_ipgroup_info_t)); 1263 } 1264 1265 topo_hdl_free(thp, pg, sizeof (topo_pgroup_t)); 1266 } 1267 1268 void 1269 topo_pgroup_destroy_all(tnode_t *node) 1270 { 1271 topo_hdl_t *thp = node->tn_hdl; 1272 topo_pgroup_t *pg; 1273 topo_proplist_t *pvl; 1274 topo_ipgroup_info_t *pip; 1275 1276 topo_node_lock(node); 1277 while ((pg = topo_list_next(&node->tn_pgroups)) != NULL) { 1278 while ((pvl = topo_list_next(&pg->tpg_pvals)) != NULL) { 1279 topo_list_delete(&pg->tpg_pvals, pvl); 1280 topo_prop_rele(pvl->tp_pval); 1281 topo_hdl_free(thp, pvl, sizeof (topo_proplist_t)); 1282 } 1283 1284 topo_list_delete(&node->tn_pgroups, pg); 1285 1286 pip = pg->tpg_info; 1287 if (pip != NULL) { 1288 if (pip->tpi_name != NULL) 1289 topo_hdl_strfree(thp, (char *)pip->tpi_name); 1290 topo_hdl_free(thp, pip, sizeof (topo_pgroup_info_t)); 1291 } 1292 1293 topo_hdl_free(thp, pg, sizeof (topo_pgroup_t)); 1294 } 1295 topo_node_unlock(node); 1296 } 1297 1298 static void 1299 propmethod_destroy(topo_hdl_t *thp, topo_propval_t *pv) 1300 { 1301 topo_propmethod_t *pm; 1302 1303 pm = pv->tp_method; 1304 if (pm != NULL) { 1305 if (pm->tpm_name != NULL) 1306 topo_hdl_strfree(thp, pm->tpm_name); 1307 nvlist_free(pm->tpm_args); 1308 topo_hdl_free(thp, pm, sizeof (topo_propmethod_t)); 1309 pv->tp_method = NULL; 1310 } 1311 } 1312 1313 static void 1314 topo_propval_destroy(topo_propval_t *pv) 1315 { 1316 topo_hdl_t *thp; 1317 1318 if (pv == NULL) 1319 return; 1320 1321 thp = pv->tp_hdl; 1322 1323 if (pv->tp_name != NULL) 1324 topo_hdl_strfree(thp, pv->tp_name); 1325 1326 nvlist_free(pv->tp_val); 1327 1328 propmethod_destroy(thp, pv); 1329 1330 topo_hdl_free(thp, pv, sizeof (topo_propval_t)); 1331 } 1332 1333 void 1334 topo_prop_hold(topo_propval_t *pv) 1335 { 1336 pv->tp_refs++; 1337 } 1338 1339 void 1340 topo_prop_rele(topo_propval_t *pv) 1341 { 1342 pv->tp_refs--; 1343 1344 assert(pv->tp_refs >= 0); 1345 1346 if (pv->tp_refs == 0) 1347 topo_propval_destroy(pv); 1348 } 1349 1350 /* 1351 * topo_prop_getprop() and topo_prop_getprops() are private project functions 1352 * for fmtopo 1353 */ 1354 int 1355 topo_prop_getprop(tnode_t *node, const char *pgname, const char *pname, 1356 nvlist_t *args, nvlist_t **prop, int *err) 1357 { 1358 topo_hdl_t *thp = node->tn_hdl; 1359 topo_propval_t *pv; 1360 1361 topo_node_lock(node); 1362 if ((pv = prop_get(node, pgname, pname, args, err)) == NULL) { 1363 (void) get_properror(node, err, *err); 1364 return (-1); 1365 } 1366 1367 if (topo_hdl_nvdup(thp, pv->tp_val, prop) != 0) { 1368 (void) get_properror(node, err, ETOPO_NOMEM); 1369 return (-1); 1370 } 1371 topo_node_unlock(node); 1372 1373 return (0); 1374 } 1375 1376 static int 1377 prop_val_add(tnode_t *node, nvlist_t **nvl, topo_propval_t *pv, int *err) 1378 { 1379 if (pv->tp_method != NULL) 1380 if (prop_method_get(node, pv, pv->tp_method, NULL, err) < 0) 1381 return (-1); 1382 1383 if (pv->tp_val == NULL) { 1384 *err = ETOPO_PROP_NOENT; 1385 return (-1); 1386 } 1387 1388 if (topo_hdl_nvdup(pv->tp_hdl, pv->tp_val, nvl) != 0) { 1389 *err = ETOPO_PROP_NOMEM; 1390 return (-1); 1391 } 1392 1393 return (0); 1394 } 1395 1396 static int 1397 get_pgrp_seterror(tnode_t *node, nvlist_t *nvl, int *errp, int err) 1398 { 1399 topo_node_unlock(node); 1400 1401 nvlist_free(nvl); 1402 1403 *errp = err; 1404 1405 return (-1); 1406 } 1407 1408 int 1409 topo_prop_getpgrp(tnode_t *node, const char *pgname, nvlist_t **pgrp, 1410 int *err) 1411 { 1412 int ret; 1413 topo_hdl_t *thp = node->tn_hdl; 1414 nvlist_t *nvl, *pvnvl; 1415 topo_pgroup_t *pg; 1416 topo_propval_t *pv; 1417 topo_proplist_t *pvl; 1418 1419 if (topo_hdl_nvalloc(thp, &nvl, 0) != 0) { 1420 *err = ETOPO_NOMEM; 1421 return (-1); 1422 } 1423 1424 topo_node_lock(node); 1425 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; 1426 pg = topo_list_next(pg)) { 1427 1428 if (strcmp(pgname, pg->tpg_info->tpi_name) != 0) 1429 continue; 1430 1431 if (nvlist_add_string(nvl, TOPO_PROP_GROUP_NAME, 1432 pg->tpg_info->tpi_name) != 0 || 1433 nvlist_add_string(nvl, TOPO_PROP_GROUP_NSTAB, 1434 topo_stability2name(pg->tpg_info->tpi_namestab)) != 0 || 1435 nvlist_add_string(nvl, TOPO_PROP_GROUP_DSTAB, 1436 topo_stability2name(pg->tpg_info->tpi_datastab)) != 0 || 1437 nvlist_add_int32(nvl, TOPO_PROP_GROUP_VERSION, 1438 pg->tpg_info->tpi_version) != 0) 1439 return (get_pgrp_seterror(node, nvl, err, 1440 ETOPO_PROP_NVL)); 1441 1442 for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL; 1443 pvl = topo_list_next(pvl)) { 1444 1445 pv = pvl->tp_pval; 1446 if (prop_val_add(node, &pvnvl, pv, err) < 0) { 1447 return (get_pgrp_seterror(node, nvl, err, 1448 *err)); 1449 } 1450 if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_VAL, 1451 pvnvl)) != 0) { 1452 nvlist_free(pvnvl); 1453 return (get_pgrp_seterror(node, nvl, err, ret)); 1454 } 1455 1456 nvlist_free(pvnvl); 1457 } 1458 topo_node_unlock(node); 1459 *pgrp = nvl; 1460 return (0); 1461 } 1462 1463 topo_node_unlock(node); 1464 *err = ETOPO_PROP_NOENT; 1465 return (-1); 1466 } 1467 1468 static nvlist_t * 1469 get_all_seterror(tnode_t *node, nvlist_t *nvl, int *errp, int err) 1470 { 1471 topo_node_unlock(node); 1472 1473 nvlist_free(nvl); 1474 1475 *errp = err; 1476 1477 return (NULL); 1478 } 1479 1480 nvlist_t * 1481 topo_prop_getprops(tnode_t *node, int *err) 1482 { 1483 int ret; 1484 topo_hdl_t *thp = node->tn_hdl; 1485 nvlist_t *nvl, *pgnvl, *pvnvl; 1486 topo_pgroup_t *pg; 1487 topo_propval_t *pv; 1488 topo_proplist_t *pvl; 1489 1490 topo_node_lock(node); 1491 if (topo_hdl_nvalloc(thp, &nvl, 0) != 0) { 1492 return (get_all_seterror(node, NULL, err, ETOPO_NOMEM)); 1493 } 1494 1495 for (pg = topo_list_next(&node->tn_pgroups); pg != NULL; 1496 pg = topo_list_next(pg)) { 1497 if (topo_hdl_nvalloc(thp, &pgnvl, 0) != 0) 1498 return (get_all_seterror(node, nvl, err, ETOPO_NOMEM)); 1499 1500 if (nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NAME, 1501 pg->tpg_info->tpi_name) != 0 || 1502 nvlist_add_string(pgnvl, TOPO_PROP_GROUP_NSTAB, 1503 topo_stability2name(pg->tpg_info->tpi_namestab)) != 0 || 1504 nvlist_add_string(pgnvl, TOPO_PROP_GROUP_DSTAB, 1505 topo_stability2name(pg->tpg_info->tpi_datastab)) != 0 || 1506 nvlist_add_int32(pgnvl, TOPO_PROP_GROUP_VERSION, 1507 pg->tpg_info->tpi_version) != 0) 1508 return (get_all_seterror(node, nvl, err, 1509 ETOPO_PROP_NVL)); 1510 1511 for (pvl = topo_list_next(&pg->tpg_pvals); pvl != NULL; 1512 pvl = topo_list_next(pvl)) { 1513 1514 pv = pvl->tp_pval; 1515 if (prop_val_add(node, &pvnvl, pv, err) < 0) { 1516 nvlist_free(pgnvl); 1517 return (get_all_seterror(node, nvl, err, *err)); 1518 } 1519 if ((ret = nvlist_add_nvlist(pgnvl, TOPO_PROP_VAL, 1520 pvnvl)) != 0) { 1521 nvlist_free(pgnvl); 1522 nvlist_free(pvnvl); 1523 return (get_all_seterror(node, nvl, err, ret)); 1524 } 1525 1526 nvlist_free(pvnvl); 1527 } 1528 if ((ret = nvlist_add_nvlist(nvl, TOPO_PROP_GROUP, pgnvl)) 1529 != 0) { 1530 nvlist_free(pgnvl); 1531 return (get_all_seterror(node, nvl, err, ret)); 1532 } 1533 1534 nvlist_free(pgnvl); 1535 } 1536 1537 topo_node_unlock(node); 1538 1539 return (nvl); 1540 } 1541