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