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