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