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