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