]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/bhnd/nvram/bhnd_nvram_plist.c
Upgrade to OpenPAM Tabebuia.
[FreeBSD/FreeBSD.git] / sys / dev / bhnd / nvram / bhnd_nvram_plist.c
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 }