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 }
Cache object: 9d837ce7f53c31f7f16048ac089dda95
|