1/*- 2 * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer, 10 * without modification. 11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13 * redistribution must be conditioned upon including a substantially 14 * similar Disclaimer requirement for further binary redistribution. 15 * 16 * NO WARRANTY 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 * THE POSSIBILITY OF SUCH DAMAGES. 28 */ 29 30#include <sys/param.h> 31#include <sys/hash.h> 32 33#ifdef _KERNEL 34 35#include <sys/systm.h> 36 37#else /* !_KERNEL */ 38 39#include <errno.h> 40#include <stdint.h> 41#include <stdlib.h> 42#include <string.h> 43 44#endif /* _KERNEL */ 45 46#include "bhnd_nvram_plistvar.h" 47#include "bhnd_nvram_private.h" 48 49static bhnd_nvram_plist_entry *bhnd_nvram_plist_get_entry( 50 bhnd_nvram_plist *plist, const char *name); 51 52/** 53 * Allocate and initialize a new, empty property list. 54 * 55 * The caller is responsible for releasing the returned property value 56 * via bhnd_nvram_plist_release(). 57 * 58 * @retval non-NULL success 59 * @retval NULL if allocation fails. 60 */ 61bhnd_nvram_plist * 62bhnd_nvram_plist_new(void) 63{ 64 bhnd_nvram_plist *plist; 65 66 plist = bhnd_nv_calloc(1, sizeof(*plist)); 67 if (plist == NULL) 68 return NULL; 69 70 /* Implicit caller-owned reference */ 71 plist->refs = 1; 72 73 /* Initialize entry list */ 74 plist->num_entries = 0; 75 TAILQ_INIT(&plist->entries); 76 77 /* Initialize entry hash table */ 78 for (size_t i = 0; i < nitems(plist->names); i++) 79 LIST_INIT(&plist->names[i]); 80 81 return (plist); 82} 83 84/** 85 * Retain a reference and return @p plist to the caller. 86 * 87 * The caller is responsible for releasing their reference ownership via 88 * bhnd_nvram_plist_release(). 89 * 90 * @param plist The property list to be retained. 91 */ 92bhnd_nvram_plist * 93bhnd_nvram_plist_retain(bhnd_nvram_plist *plist) 94{ 95 BHND_NV_ASSERT(plist->refs >= 1, ("plist over-released")); 96 97 refcount_acquire(&plist->refs); 98 return (plist); 99} 100 101/** 102 * Release a reference to @p plist. 103 * 104 * If this is the last reference, all associated resources will be freed. 105 * 106 * @param plist The property list to be released. 107 */ 108void 109bhnd_nvram_plist_release(bhnd_nvram_plist *plist) 110{ 111 bhnd_nvram_plist_entry *ple, *ple_next; 112 113 BHND_NV_ASSERT(plist->refs >= 1, ("plist over-released")); 114 115 /* Drop reference */ 116 if (!refcount_release(&plist->refs)) 117 return; 118 119 /* Free all property entries */ 120 TAILQ_FOREACH_SAFE(ple, &plist->entries, pl_link, ple_next) { 121 bhnd_nvram_prop_release(ple->prop); 122 bhnd_nv_free(ple); 123 } 124 125 /* Free plist instance */ 126 bhnd_nv_free(plist); 127} 128 129/** 130 * Return a shallow copy of @p plist. 131 * 132 * The caller is responsible for releasing the returned property value 133 * via bhnd_nvram_plist_release(). 134 * 135 * @retval non-NULL success 136 * @retval NULL if allocation fails. 137 */ 138bhnd_nvram_plist * 139bhnd_nvram_plist_copy(bhnd_nvram_plist *plist) 140{ 141 bhnd_nvram_plist *copy; 142 bhnd_nvram_prop *prop; 143 int error; 144 145 /* Allocate new, empty plist */ 146 if ((copy = bhnd_nvram_plist_new()) == NULL) 147 return (NULL); 148 149 /* Append all properties */ 150 prop = NULL; 151 while ((prop = bhnd_nvram_plist_next(plist, prop)) != NULL) { 152 error = bhnd_nvram_plist_append(copy, prop); 153 if (error) { 154 if (error != ENOMEM) { 155 BHND_NV_LOG("error copying property: %d\n", 156 error); 157 } 158 159 bhnd_nvram_plist_release(copy); 160 return (NULL); 161 } 162 } 163 164 /* Return ownership of the copy to our caller */ 165 return (copy); 166} 167 168/** 169 * Return the number of properties in @p plist. 170 */ 171size_t 172bhnd_nvram_plist_count(bhnd_nvram_plist *plist) 173{ 174 return (plist->num_entries); 175} 176 177/** 178 * Return true if @p plist contains a property name @p name, false otherwise. 179 * 180 * @param plist The property list to be queried. 181 * @param name The property name to be queried. 182 */ 183bool 184bhnd_nvram_plist_contains(bhnd_nvram_plist *plist, const char *name) 185{ 186 if (bhnd_nvram_plist_get_entry(plist, name) != NULL) 187 return (true); 188 189 return (false); 190} 191 192/** 193 * Replace the current property value for a property matching the name 194 * of @p prop, maintaining the property's current order in @p plist. 195 * 196 * If a matching property is not found in @p plist, @p prop will instead be 197 * appended. 198 * 199 * @param plist The property list to be modified. 200 * @param prop The replacement property. 201 * 202 * @retval 0 success 203 * @retval ENOMEM if allocation fails. 204 * @retval non-zero if modifying @p plist otherwise fails, a regular unix 205 * error code will be returned. 206 */ 207int 208bhnd_nvram_plist_replace(bhnd_nvram_plist *plist, bhnd_nvram_prop *prop) 209{ 210 bhnd_nvram_plist_entry *entry; 211 212 /* Fetch current entry */ 213 entry = bhnd_nvram_plist_get_entry(plist, prop->name); 214 if (entry == NULL) { 215 /* Not found -- append property instead */ 216 return (bhnd_nvram_plist_append(plist, prop)); 217 } 218 219 /* Replace the current entry's property reference */ 220 bhnd_nvram_prop_release(entry->prop); 221 entry->prop = bhnd_nvram_prop_retain(prop); 222 223 return (0); 224} 225 226/** 227 * Replace the current property value for a property matching @p name, 228 * maintaining the property's order in @p plist. 229 * 230 * If @p name is not found in @p plist, a new property will be appended. 231 * 232 * @param plist The property list to be modified. 233 * @param name The name of the property to be replaced. 234 * @param val The replacement value for @p name. 235 * 236 * @retval 0 success 237 * @retval ENOMEM if allocation fails. 238 * @retval non-zero if modifying @p plist otherwise fails, a regular unix 239 * error code will be returned. 240 */ 241int 242bhnd_nvram_plist_replace_val(bhnd_nvram_plist *plist, const char *name, 243 bhnd_nvram_val *val) 244{ 245 bhnd_nvram_prop *prop; 246 int error; 247 248 /* Construct a new property instance for the name and value */ 249 if ((prop = bhnd_nvram_prop_new(name, val)) == NULL) 250 return (ENOMEM); 251 252 /* Attempt replace */ 253 error = bhnd_nvram_plist_replace(plist, prop); 254 bhnd_nvram_prop_release(prop); 255 256 return (error); 257} 258 259/** 260 * Replace the current property value for a property matching @p name, copying 261 * the new property value from the given @p inp buffer of @p itype and @p ilen. 262 * 263 * The current property order of @p name in @p plist will be maintained. 264 * 265 * If @p name is not found in @p plist, a new property will be appended. 266 * 267 * @param plist The property list to be modified. 268 * @param name The name of the property to be replaced. 269 * @param inp Input buffer. 270 * @param ilen Input buffer length. 271 * @param itype Input buffer type. 272 * 273 * @retval 0 success 274 * @retval ENOMEM if allocation fails. 275 * @retval non-zero if modifying @p plist otherwise fails, a regular unix 276 * error code will be returned. 277 */ 278int 279bhnd_nvram_plist_replace_bytes(bhnd_nvram_plist *plist, const char *name, 280 const void *inp, size_t ilen, bhnd_nvram_type itype) 281{ 282 bhnd_nvram_prop *prop; 283 int error; 284 285 if ((prop = bhnd_nvram_prop_bytes_new(name, inp, ilen, itype)) == NULL) 286 return (ENOMEM); 287 288 error = bhnd_nvram_plist_replace(plist, prop); 289 bhnd_nvram_prop_release(prop); 290 291 return (error); 292} 293 294/** 295 * Replace the current property value for a property matching @p name, copying 296 * the new property value from @p val. 297 * 298 * The current property order of @p name in @p plist will be maintained. 299 * 300 * If @p name is not found in @p plist, a new property will be appended. 301 * 302 * @param plist The property list to be modified. 303 * @param name The name of the property to be replaced. 304 * @param val The property's replacement string value. 305 * 306 * @retval 0 success 307 * @retval ENOMEM if allocation fails. 308 * @retval non-zero if modifying @p plist otherwise fails, a regular unix 309 * error code will be returned. 310 */ 311int 312bhnd_nvram_plist_replace_string(bhnd_nvram_plist *plist, const char *name, 313 const char *val) 314{ 315 return (bhnd_nvram_plist_replace_bytes(plist, name, val, strlen(val)+1, 316 BHND_NVRAM_TYPE_STRING)); 317} 318 319/** 320 * Remove the property entry for the property @p name, if any. 321 * 322 * @param plist The property list to be modified. 323 * @param name The name of the property to be removed. 324 */ 325void 326bhnd_nvram_plist_remove(bhnd_nvram_plist *plist, const char *name) 327{ 328 bhnd_nvram_plist_entry *entry; 329 330 /* Fetch entry */ 331 entry = bhnd_nvram_plist_get_entry(plist, name); 332 if (entry == NULL) 333 return; 334 335 /* Remove from entry list and hash table */ 336 TAILQ_REMOVE(&plist->entries, entry, pl_link); 337 LIST_REMOVE(entry, pl_hash_link); 338 339 /* Free plist entry */ 340 bhnd_nvram_prop_release(entry->prop); 341 bhnd_nv_free(entry); 342 343 /* Decrement entry count */ 344 BHND_NV_ASSERT(plist->num_entries > 0, ("entry count over-release")); 345 plist->num_entries--; 346} 347 348/** 349 * Fetch the property list entry for @p name, if any. 350 * 351 * @param plist The property list to be queried. 352 * @param name The property name to be queried. 353 * 354 * @retval non-NULL if @p name is found. 355 * @retval NULL if @p name is not found. 356 */ 357static bhnd_nvram_plist_entry * 358bhnd_nvram_plist_get_entry(bhnd_nvram_plist *plist, const char *name) 359{ 360 bhnd_nvram_plist_entry_list *hash_list; 361 bhnd_nvram_plist_entry *entry; 362 uint32_t h; 363 364 h = hash32_str(name, HASHINIT); 365 hash_list = &plist->names[h % nitems(plist->names)]; 366 367 LIST_FOREACH(entry, hash_list, pl_hash_link) { 368 if (strcmp(entry->prop->name, name) == 0) 369 return (entry); 370 }; 371 372 /* Not found */ 373 return (NULL); 374} 375 376/** 377 * Append all properties from @p tail to @p plist. 378 * 379 * @param plist The property list to be modified. 380 * @param tail The property list to append. 381 * 382 * @retval 0 success 383 * @retval ENOMEM if allocation fails. 384 * @retval EEXIST an existing property from @p tail was found in @p plist. 385 */ 386int 387bhnd_nvram_plist_append_list(bhnd_nvram_plist *plist, bhnd_nvram_plist *tail) 388{ 389 bhnd_nvram_prop *p; 390 int error; 391 392 p = NULL; 393 while ((p = bhnd_nvram_plist_next(tail, p)) != NULL) { 394 if ((error = bhnd_nvram_plist_append(plist, p))) 395 return (error); 396 } 397 398 return (0); 399} 400 401/** 402 * Append @p prop to @p plist. 403 * 404 * @param plist The property list to be modified. 405 * @param prop The property to append. 406 * 407 * @retval 0 success 408 * @retval ENOMEM if allocation fails. 409 * @retval EEXIST an existing property with @p name was found in @p plist. 410 */ 411int 412bhnd_nvram_plist_append(bhnd_nvram_plist *plist, bhnd_nvram_prop *prop) 413{ 414 bhnd_nvram_plist_entry_list *hash_list; 415 bhnd_nvram_plist_entry *entry; 416 uint32_t h; 417 418 if (bhnd_nvram_plist_contains(plist, prop->name)) 419 return (EEXIST); 420 421 /* Have we hit the maximum representable entry count? */ 422 if (plist->num_entries == SIZE_MAX) 423 return (ENOMEM); 424 425 /* Allocate new entry */ 426 entry = bhnd_nv_malloc(sizeof(*entry)); 427 if (entry == NULL) 428 return (ENOMEM); 429 430 entry->prop = bhnd_nvram_prop_retain(prop); 431 432 /* Append to entry list */ 433 TAILQ_INSERT_TAIL(&plist->entries, entry, pl_link); 434 435 /* Add to name-based hash table */ 436 h = hash32_str(prop->name, HASHINIT); 437 hash_list = &plist->names[h % nitems(plist->names)]; 438 LIST_INSERT_HEAD(hash_list, entry, pl_hash_link); 439 440 /* Increment entry count */ 441 plist->num_entries++; 442 443 return (0); 444} 445 446/** 447 * Append a new property to @p plist with @p name and @p val. 448 * 449 * @param plist The property list to be modified. 450 * @param name The name of the property to be appended. 451 * @param val The value of the property to be appended. 452 * 453 * @retval 0 success 454 * @retval ENOMEM if allocation fails. 455 * @retval EEXIST an existing property with @p name was found in @p plist. 456 */ 457int 458bhnd_nvram_plist_append_val(bhnd_nvram_plist *plist, const char *name, 459 bhnd_nvram_val *val) 460{ 461 bhnd_nvram_prop *prop; 462 int error; 463 464 if ((prop = bhnd_nvram_prop_new(name, val)) == NULL) 465 return (ENOMEM); 466 467 error = bhnd_nvram_plist_append(plist, prop); 468 bhnd_nvram_prop_release(prop); 469 470 return (error); 471} 472 473/** 474 * Append a new property to @p plist, copying the property value from the 475 * given @p inp buffer of @p itype and @p ilen. 476 * 477 * @param plist The property list to be modified. 478 * @param name The name of the property to be appended. 479 * @param inp Input buffer. 480 * @param ilen Input buffer length. 481 * @param itype Input buffer type. 482 * 483 * @retval 0 success 484 * @retval ENOMEM if allocation fails. 485 * @retval EEXIST an existing property with @p name was found in @p plist. 486 */ 487int 488bhnd_nvram_plist_append_bytes(bhnd_nvram_plist *plist, const char *name, 489 const void *inp, size_t ilen, bhnd_nvram_type itype) 490{ 491 bhnd_nvram_prop *prop; 492 int error; 493 494 if ((prop = bhnd_nvram_prop_bytes_new(name, inp, ilen, itype)) == NULL) 495 return (ENOMEM); 496 497 error = bhnd_nvram_plist_append(plist, prop); 498 bhnd_nvram_prop_release(prop); 499 500 return (error); 501} 502 503/** 504 * Append a new string property to @p plist, copying the property value from 505 * @p val. 506 * 507 * @param plist The property list to be modified. 508 * @param name The name of the property to be appended. 509 * @param val The new property's string value. 510 * 511 * @retval 0 success 512 * @retval ENOMEM if allocation fails. 513 * @retval EEXIST an existing property with @p name was found in @p plist. 514 */ 515int 516bhnd_nvram_plist_append_string(bhnd_nvram_plist *plist, const char *name, 517 const char *val) 518{ 519 return (bhnd_nvram_plist_append_bytes(plist, name, val, strlen(val)+1, 520 BHND_NVRAM_TYPE_STRING)); 521} 522 523/** 524 * Iterate over all properties in @p plist. 525 * 526 * @param plist The property list to be iterated. 527 * @param prop A property in @p plist, or NULL to return the first 528 * property in @p plist. 529 * 530 * @retval non-NULL A borrowed reference to the next property in @p plist. 531 * @retval NULL If the end of the property list is reached or @p prop 532 * is not found in @p plist. 533 */ 534bhnd_nvram_prop * 535bhnd_nvram_plist_next(bhnd_nvram_plist *plist, bhnd_nvram_prop *prop) 536{ 537 bhnd_nvram_plist_entry *entry; 538 539 if (prop == NULL) { 540 if ((entry = TAILQ_FIRST(&plist->entries)) == NULL) 541 return (NULL); 542 543 return (entry->prop); 544 } 545 546 /* Look up previous property entry by name */ 547 if ((entry = bhnd_nvram_plist_get_entry(plist, prop->name)) == NULL) 548 return (NULL); 549 550 /* The property instance must be identical */ 551 if (entry->prop != prop) 552 return (NULL); 553 554 /* Fetch next entry */ 555 if ((entry = TAILQ_NEXT(entry, pl_link)) == NULL) 556 return (NULL); 557 558 return (entry->prop); 559} 560 561/** 562 * Return a borrowed reference to a named property, or NULL if @p name is 563 * not found in @p plist. 564 * 565 * @param plist The property list to be queried. 566 * @param name The name of the property to be returned. 567 * 568 * @retval non-NULL if @p name is found. 569 * @retval NULL if @p name is not found. 570 */ 571bhnd_nvram_prop * 572bhnd_nvram_plist_get_prop(bhnd_nvram_plist *plist, const char *name) 573{ 574 bhnd_nvram_plist_entry *entry; 575 576 if ((entry = bhnd_nvram_plist_get_entry(plist, name)) == NULL) 577 return (NULL); 578 579 return (entry->prop); 580} 581 582/** 583 * Return a borrowed reference to the named property's value, or NULL if 584 * @p name is not found in @p plist. 585 * 586 * @param plist The property list to be queried. 587 * @param name The name of the property to be returned. 588 * 589 * @retval non-NULL if @p name is found. 590 * @retval NULL if @p name is not found. 591 */ 592bhnd_nvram_val * 593bhnd_nvram_plist_get_val(bhnd_nvram_plist *plist, const char *name) 594{ 595 bhnd_nvram_prop *prop; 596 597 if ((prop = bhnd_nvram_plist_get_prop(plist, name)) == NULL) 598 return (NULL); 599 600 return (bhnd_nvram_prop_val(prop)); 601} 602 603/** 604 * Attempt to encode a named property's value as @p otype, writing the result 605 * to @p outp. 606 * 607 * @param plist The property list to be queried. 608 * @param name The name of the property value to be returned. 609 * @param[out] outp On success, the value will be written to this 610 * buffer. This argment may be NULL if the value is 611 * not desired. 612 * @param[in,out] olen The capacity of @p outp. On success, will be set 613 * to the actual size of the requested value. 614 * @param otype The data type to be written to @p outp. 615 * 616 * @retval 0 success 617 * @retval ENOENT If @p name is not found in @p plist. 618 * @retval ENOMEM If the @p outp is non-NULL, and the provided @p olen 619 * is too small to hold the encoded value. 620 * @retval EFTYPE If value coercion from @p prop to @p otype is 621 * impossible. 622 * @retval ERANGE If value coercion would overflow (or underflow) the 623 * a @p otype representation. 624 */ 625int 626bhnd_nvram_plist_get_encoded(bhnd_nvram_plist *plist, const char *name, 627 void *outp, size_t olen, bhnd_nvram_type otype) 628{ 629 bhnd_nvram_prop *prop; 630 631 if ((prop = bhnd_nvram_plist_get_prop(plist, name)) == NULL) 632 return (ENOENT); 633 634 return (bhnd_nvram_prop_encode(prop, outp, &olen, otype)); 635} 636 637/** 638 * Return the character representation of a named property's value. 639 * 640 * @param plist The property list to be queried. 641 * @param name The name of the property value to be returned. 642 * @param[out] val On success, the character value of @p name. 643 * 644 * @retval 0 success 645 * @retval ENOENT If @p name is not found in @p plist. 646 * @retval EFTYPE If coercion of the property's value to @p val. 647 * @retval ERANGE If coercion of the property's value would overflow 648 * (or underflow) @p val. 649 */ 650int 651bhnd_nvram_plist_get_char(bhnd_nvram_plist *plist, const char *name, 652 u_char *val) 653{ 654 return (bhnd_nvram_plist_get_encoded(plist, name, val, sizeof(*val), 655 BHND_NVRAM_TYPE_CHAR)); 656} 657 658/** 659 * Return the uint8 representation of a named property's value. 660 * 661 * @param plist The property list to be queried. 662 * @param name The name of the property value to be returned. 663 * @param[out] val On success, the uint8 value of @p name. 664 * 665 * @retval 0 success 666 * @retval ENOENT If @p name is not found in @p plist. 667 * @retval EFTYPE If coercion of the property's value to @p val. 668 * @retval ERANGE If coercion of the property's value would overflow 669 * (or underflow) @p val. 670 */ 671int 672bhnd_nvram_plist_get_uint8(bhnd_nvram_plist *plist, const char *name, 673 uint8_t *val) 674{ 675 return (bhnd_nvram_plist_get_encoded(plist, name, val, sizeof(*val), 676 BHND_NVRAM_TYPE_UINT8)); 677} 678 679/** 680 * Return the uint16 representation of a named property's value. 681 * 682 * @param plist The property list to be queried. 683 * @param name The name of the property value to be returned. 684 * @param[out] val On success, the uint16 value of @p name. 685 * 686 * @retval 0 success 687 * @retval ENOENT If @p name is not found in @p plist. 688 * @retval EFTYPE If coercion of the property's value to @p val. 689 * @retval ERANGE If coercion of the property's value would overflow 690 * (or underflow) @p val. 691 */ 692int 693bhnd_nvram_plist_get_uint16(bhnd_nvram_plist *plist, const char *name, 694 uint16_t *val) 695{ 696 return (bhnd_nvram_plist_get_encoded(plist, name, val, sizeof(*val), 697 BHND_NVRAM_TYPE_UINT16)); 698} 699 700/** 701 * Return the uint32 representation of a named property's value. 702 * 703 * @param plist The property list to be queried. 704 * @param name The name of the property value to be returned. 705 * @param[out] val On success, the uint32 value of @p name. 706 * 707 * @retval 0 success 708 * @retval ENOENT If @p name is not found in @p plist. 709 * @retval EFTYPE If coercion of the property's value to @p val. 710 * @retval ERANGE If coercion of the property's value would overflow 711 * (or underflow) @p val. 712 */ 713int 714bhnd_nvram_plist_get_uint32(bhnd_nvram_plist *plist, const char *name, 715 uint32_t *val) 716{ 717 return (bhnd_nvram_plist_get_encoded(plist, name, val, sizeof(*val), 718 BHND_NVRAM_TYPE_UINT32)); 719} 720 721/** 722 * Return the uint64 representation of a named property's value. 723 * 724 * @param plist The property list to be queried. 725 * @param name The name of the property value to be returned. 726 * @param[out] val On success, the uint64 value of @p name. 727 * 728 * @retval 0 success 729 * @retval ENOENT If @p name is not found in @p plist. 730 * @retval EFTYPE If coercion of the property's value to @p val. 731 * @retval ERANGE If coercion of the property's value would overflow 732 * (or underflow) @p val. 733 */ 734int 735bhnd_nvram_plist_get_uint64(bhnd_nvram_plist *plist, const char *name, 736 uint64_t *val) 737{ 738 return (bhnd_nvram_plist_get_encoded(plist, name, val, sizeof(*val), 739 BHND_NVRAM_TYPE_UINT64)); 740} 741 742/** 743 * Return the boolean representation of a named property's value. 744 * 745 * @param plist The property list to be queried. 746 * @param name The name of the property value to be returned. 747 * @param[out] val On success, the boolean value of @p name. 748 * 749 * @retval 0 success 750 * @retval ENOENT If @p name is not found in @p plist. 751 * @retval EFTYPE If coercion of the property's value to @p val. 752 * @retval ERANGE If coercion of the property's value would overflow 753 * (or underflow) @p val. 754 */ 755int 756bhnd_nvram_plist_get_bool(bhnd_nvram_plist *plist, const char *name, 757 bool *val) 758{ 759 return (bhnd_nvram_plist_get_encoded(plist, name, val, sizeof(*val), 760 BHND_NVRAM_TYPE_BOOL)); 761} 762 763/** 764 * Allocate and initialize a new property value. 765 * 766 * The caller is responsible for releasing the returned property value 767 * via bhnd_nvram_prop_release(). 768 * 769 * @param name Property name. 770 * @param val Property value. 771 * 772 * @retval non-NULL success 773 * @retval NULL if allocation fails. 774 */ 775struct bhnd_nvram_prop * 776bhnd_nvram_prop_new(const char *name, bhnd_nvram_val *val) 777{ 778 struct bhnd_nvram_prop *prop; 779 780 prop = bhnd_nv_calloc(1, sizeof(*prop)); 781 if (prop == NULL) 782 return NULL; 783 784 /* Implicit caller-owned reference */ 785 prop->refs = 1; 786 787 if ((prop->name = bhnd_nv_strdup(name)) == NULL) 788 goto failed; 789 790 if ((prop->val = bhnd_nvram_val_copy(val)) == NULL) 791 goto failed; 792 793 return (prop); 794 795failed: 796 if (prop->name != NULL) 797 bhnd_nv_free(prop->name); 798 799 if (prop->val != NULL) 800 bhnd_nvram_val_release(prop->val); 801 802 bhnd_nv_free(prop); 803 return (NULL); 804} 805 806/** 807 * Allocate a new property value and attempt to initialize its value from 808 * the given @p inp buffer of @p itype and @p ilen. 809 * 810 * The caller is responsible for releasing the returned property value 811 * via bhnd_nvram_prop_release(). 812 * 813 * @param name Property name. 814 * @param inp Input buffer. 815 * @param ilen Input buffer length. 816 * @param itype Input buffer type. 817 * 818 * @retval non-NULL success 819 * @retval NULL if allocation or initialization fails. 820 */ 821bhnd_nvram_prop * 822bhnd_nvram_prop_bytes_new(const char *name, const void *inp, size_t ilen, 823 bhnd_nvram_type itype) 824{ 825 bhnd_nvram_prop *prop; 826 bhnd_nvram_val *val; 827 int error; 828 829 /* Construct new value instance */ 830 error = bhnd_nvram_val_new(&val, NULL, inp, ilen, itype, 831 BHND_NVRAM_VAL_DYNAMIC); 832 if (error) { 833 if (error != ENOMEM) { 834 BHND_NV_LOG("invalid input data; initialization " 835 "failed: %d\n", error); 836 } 837 838 return (NULL); 839 } 840 841 /* Delegate to default implementation */ 842 prop = bhnd_nvram_prop_new(name, val); 843 844 /* Clean up */ 845 bhnd_nvram_val_release(val); 846 return (prop); 847} 848 849/** 850 * Retain a reference and return @p prop to the caller. 851 * 852 * The caller is responsible for releasing their reference ownership via 853 * bhnd_nvram_prop_release(). 854 * 855 * @param prop The property to be retained. 856 */ 857bhnd_nvram_prop * 858bhnd_nvram_prop_retain(bhnd_nvram_prop *prop) 859{ 860 BHND_NV_ASSERT(prop->refs >= 1, ("prop over-released")); 861 862 refcount_acquire(&prop->refs); 863 return (prop); 864} 865 866/** 867 * Release a reference to @p prop. 868 * 869 * If this is the last reference, all associated resources will be freed. 870 * 871 * @param prop The property to be released. 872 */ 873void 874bhnd_nvram_prop_release(bhnd_nvram_prop *prop) 875{ 876 BHND_NV_ASSERT(prop->refs >= 1, ("prop over-released")); 877 878 /* Drop reference */ 879 if (!refcount_release(&prop->refs)) 880 return; 881 882 /* Free property data */ 883 bhnd_nvram_val_release(prop->val); 884 bhnd_nv_free(prop->name); 885 bhnd_nv_free(prop); 886} 887 888/** 889 * Return a borrowed reference to the property's name. 890 * 891 * @param prop The property to query. 892 */ 893const char * 894bhnd_nvram_prop_name(bhnd_nvram_prop *prop) 895{ 896 return (prop->name); 897} 898 899/** 900 * Return a borrowed reference to the property's value. 901 * 902 * @param prop The property to query. 903 */ 904bhnd_nvram_val * 905bhnd_nvram_prop_val(bhnd_nvram_prop *prop) 906{ 907 return (prop->val); 908} 909 910/** 911 * Return the property's value type. 912 * 913 * @param prop The property to query. 914 */ 915bhnd_nvram_type 916bhnd_nvram_prop_type(bhnd_nvram_prop *prop) 917{ 918 return (bhnd_nvram_val_type(prop->val)); 919} 920 921/** 922 * Return true if @p prop has a NULL value type (BHND_NVRAM_TYPE_NULL), false 923 * otherwise. 924 * 925 * @param prop The property to query. 926 */ 927bool 928bhnd_nvram_prop_is_null(bhnd_nvram_prop *prop) 929{ 930 return (bhnd_nvram_prop_type(prop) == BHND_NVRAM_TYPE_NULL); 931} 932 933/** 934 * Return a borrowed reference to the property's internal value representation. 935 * 936 * @param prop The property to query. 937 * @param[out] olen The returned data's size, in bytes. 938 * @param[out] otype The returned data's type. 939 */ 940const void * 941bhnd_nvram_prop_bytes(bhnd_nvram_prop *prop, size_t *olen, 942 bhnd_nvram_type *otype) 943{ 944 const void *bytes; 945 946 bytes = bhnd_nvram_val_bytes(prop->val, olen, otype); 947 BHND_NV_ASSERT(*otype == bhnd_nvram_prop_type(prop), ("type mismatch")); 948 949 return (bytes); 950} 951 952/** 953 * Attempt to encode the property's value as @p otype, writing the result 954 * to @p outp. 955 * 956 * @param prop The property to be encoded. 957 * @param[out] outp On success, the value will be written to this 958 * buffer. This argment may be NULL if the value is 959 * not desired. 960 * @param[in,out] olen The capacity of @p outp. On success, will be set 961 * to the actual size of the requested value. 962 * @param otype The data type to be written to @p outp. 963 * 964 * @retval 0 success 965 * @retval ENOMEM If the @p outp is non-NULL, and the provided @p olen 966 * is too small to hold the encoded value. 967 * @retval EFTYPE If value coercion from @p prop to @p otype is 968 * impossible. 969 * @retval ERANGE If value coercion would overflow (or underflow) the 970 * a @p otype representation. 971 */ 972int 973bhnd_nvram_prop_encode(bhnd_nvram_prop *prop, void *outp, size_t *olen, 974 bhnd_nvram_type otype) 975{ 976 return (bhnd_nvram_val_encode(prop->val, outp, olen, otype)); 977} 978