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 49 static 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 */ 61 bhnd_nvram_plist * 62 bhnd_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 */ 92 bhnd_nvram_plist * 93 bhnd_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 */ 108 void 109 bhnd_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 */ 138 bhnd_nvram_plist * 139 bhnd_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 */ 171 size_t 172 bhnd_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 */ 183 bool 184 bhnd_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 */ 207 int 208 bhnd_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 */ 241 int 242 bhnd_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 */ 278 int 279 bhnd_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 */ 311 int 312 bhnd_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 */ 325 void 326 bhnd_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 */ 357 static bhnd_nvram_plist_entry * 358 bhnd_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 */ 386 int 387 bhnd_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 */ 411 int 412 bhnd_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 */ 457 int 458 bhnd_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 */ 487 int 488 bhnd_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 */ 515 int 516 bhnd_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 */ 534 bhnd_nvram_prop * 535 bhnd_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 */ 571 bhnd_nvram_prop * 572 bhnd_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 */ 592 bhnd_nvram_val * 593 bhnd_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 */ 625 int 626 bhnd_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 */ 650 int 651 bhnd_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 */ 671 int 672 bhnd_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 */ 692 int 693 bhnd_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 */ 713 int 714 bhnd_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 */ 734 int 735 bhnd_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 */ 755 int 756 bhnd_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 */ 775 struct bhnd_nvram_prop * 776 bhnd_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 795 failed: 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 */ 821 bhnd_nvram_prop * 822 bhnd_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 */ 857 bhnd_nvram_prop * 858 bhnd_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 */ 873 void 874 bhnd_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 */ 893 const char * 894 bhnd_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 */ 904 bhnd_nvram_val * 905 bhnd_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 */ 915 bhnd_nvram_type 916 bhnd_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 */ 927 bool 928 bhnd_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 */ 940 const void * 941 bhnd_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 */ 972 int 973 bhnd_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