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/limits.h>
35 #include <sys/sbuf.h>
36
37 #ifdef _KERNEL
38
39 #include <sys/ctype.h>
40 #include <sys/kernel.h>
41 #include <sys/malloc.h>
42 #include <sys/systm.h>
43
44 #include <machine/_inttypes.h>
45
46 #else /* !_KERNEL */
47
48 #include <ctype.h>
49 #include <inttypes.h>
50 #include <errno.h>
51 #include <stdlib.h>
52 #include <string.h>
53
54 #endif /* _KERNEL */
55
56 #include "bhnd_nvram_private.h"
57 #include "bhnd_nvram_valuevar.h"
58
59 #ifdef _KERNEL
60 #define bhnd_nv_hex2ascii(hex) hex2ascii(hex)
61 #else /* !_KERNEL */
62 static char const bhnd_nv_hex2ascii[] = "0123456789abcdefghijklmnopqrstuvwxyz";
63 #define bhnd_nv_hex2ascii(hex) (bhnd_nv_hex2ascii[hex])
64 #endif /* _KERNEL */
65
66 /**
67 * Maximum size, in bytes, of a string-encoded NVRAM integer value, not
68 * including any prefix (0x, 0, etc).
69 *
70 * We assume the largest possible encoding is the base-2 representation
71 * of a 64-bit integer.
72 */
73 #define NV_NUMSTR_MAX ((sizeof(uint64_t) * CHAR_BIT) + 1)
74
75 /**
76 * Format a string representation of @p value using @p fmt, with, writing the
77 * result to @p outp.
78 *
79 * @param value The value to be formatted.
80 * @param fmt The format string.
81 * @param[out] outp On success, the string will be written to this
82 * buffer. This argment may be NULL if the value is
83 * not desired.
84 * @param[in,out] olen The capacity of @p outp. On success, will be set
85 * to the actual number of bytes required for the
86 * requested string encoding (including a trailing
87 * NUL).
88 *
89 * Refer to bhnd_nvram_val_vprintf() for full format string documentation.
90 *
91 * @retval 0 success
92 * @retval EINVAL If @p fmt contains unrecognized format string
93 * specifiers.
94 * @retval ENOMEM If the @p outp is non-NULL, and the provided @p olen
95 * is too small to hold the encoded value.
96 * @retval EFTYPE If value coercion from @p value to a single string
97 * value via @p fmt is unsupported.
98 * @retval ERANGE If value coercion of @p value would overflow (or
99 * underflow) the representation defined by @p fmt.
100 */
101 int
102 bhnd_nvram_val_printf(bhnd_nvram_val *value, const char *fmt, char *outp,
103 size_t *olen, ...)
104 {
105 va_list ap;
106 int error;
107
108 va_start(ap, olen);
109 error = bhnd_nvram_val_vprintf(value, fmt, outp, olen, ap);
110 va_end(ap);
111
112 return (error);
113 }
114
115 /**
116 * Format a string representation of the elements of @p value using @p fmt,
117 * writing the result to @p outp.
118 *
119 * @param value The value to be formatted.
120 * @param fmt The format string.
121 * @param[out] outp On success, the string will be written to this
122 * buffer. This argment may be NULL if the value is
123 * not desired.
124 * @param[in,out] olen The capacity of @p outp. On success, will be set
125 * to the actual number of bytes required for the
126 * requested string encoding (including a trailing
127 * NUL).
128 * @param ap Argument list.
129 *
130 * @par Format Strings
131 *
132 * Value format strings are similar, but not identical to, those used
133 * by printf(3).
134 *
135 * Format specifier format:
136 * %[repeat][flags][width][.precision][length modifier][specifier]
137 *
138 * The format specifier is interpreted as an encoding directive for an
139 * individual value element; each format specifier will fetch the next element
140 * from the value, encode the element as the appropriate type based on the
141 * length modifiers and specifier, and then format the result as a string.
142 *
143 * For example, given a string value of '0x000F', and a format specifier of
144 * '%#hhx', the value will be asked to encode its first element as
145 * BHND_NVRAM_TYPE_UINT8. String formatting will then be applied to the 8-bit
146 * unsigned integer representation, producing a string value of "0xF".
147 *
148 * Repeat:
149 * - [digits] Repeatedly apply the format specifier to the input
150 * value's elements up to `digits` times. The delimiter
151 * must be passed as a string in the next variadic
152 * argument.
153 * - [] Repeatedly apply the format specifier to the input
154 * value's elements until all elements have been. The
155 * processed. The delimiter must be passed as a string in
156 * the next variadic argument.
157 * - [*] Repeatedly apply the format specifier to the input
158 * value's elements. The repeat count is read from the
159 * next variadic argument as a size_t value
160 *
161 * Flags:
162 * - '#' use alternative form (e.g. 0x/0X prefixing of hex
163 * strings).
164 * - '' zero padding
165 * - '-' left adjust padding
166 * - '+' include a sign character
167 * - ' ' include a space in place of a sign character for
168 * positive numbers.
169 *
170 * Width/Precision:
171 * - digits minimum field width.
172 * - * read the minimum field width from the next variadic
173 * argument as a ssize_t value. A negative value enables
174 * left adjustment.
175 * - .digits field precision.
176 * - .* read the field precision from the next variadic argument
177 * as a ssize_t value. A negative value enables left
178 * adjustment.
179 *
180 * Length Modifiers:
181 * - 'hh', 'I8' Convert the value to an 8-bit signed or unsigned
182 * integer.
183 * - 'h', 'I16' Convert the value to an 16-bit signed or unsigned
184 * integer.
185 * - 'l', 'I32' Convert the value to an 32-bit signed or unsigned
186 * integer.
187 * - 'll', 'j', 'I64' Convert the value to an 64-bit signed or unsigned
188 * integer.
189 *
190 * Data Specifiers:
191 * - 'd', 'i' Convert and format as a signed decimal integer.
192 * - 'u' Convert and format as an unsigned decimal integer.
193 * - 'o' Convert and format as an unsigned octal integer.
194 * - 'x' Convert and format as an unsigned hexadecimal integer,
195 * using lowercase hex digits.
196 * - 'X' Convert and format as an unsigned hexadecimal integer,
197 * using uppercase hex digits.
198 * - 's' Convert and format as a string.
199 * - '%' Print a literal '%' character.
200 *
201 * @retval 0 success
202 * @retval EINVAL If @p fmt contains unrecognized format string
203 * specifiers.
204 * @retval ENOMEM If the @p outp is non-NULL, and the provided @p olen
205 * is too small to hold the encoded value.
206 * @retval EFTYPE If value coercion from @p value to a single string
207 * value via @p fmt is unsupported.
208 * @retval ERANGE If value coercion of @p value would overflow (or
209 * underflow) the representation defined by @p fmt.
210 */
211 int
212 bhnd_nvram_val_vprintf(bhnd_nvram_val *value, const char *fmt, char *outp,
213 size_t *olen, va_list ap)
214 {
215 const void *elem;
216 size_t elen;
217 size_t limit, nbytes;
218 int error;
219
220 elem = NULL;
221
222 /* Determine output byte limit */
223 nbytes = 0;
224 if (outp != NULL)
225 limit = *olen;
226 else
227 limit = 0;
228
229 #define WRITE_CHAR(_c) do { \
230 if (limit > nbytes) \
231 *(outp + nbytes) = _c; \
232 \
233 if (nbytes == SIZE_MAX) \
234 return (EFTYPE); \
235 nbytes++; \
236 } while (0)
237
238 /* Encode string value as per the format string */
239 for (const char *p = fmt; *p != '\0'; p++) {
240 const char *delim;
241 size_t precision, width, delim_len;
242 u_long repeat, bits;
243 bool alt_form, ladjust, have_precision;
244 char padc, signc, lenc;
245
246 padc = ' ';
247 signc = '\0';
248 lenc = '\0';
249 delim = "";
250 delim_len = 0;
251
252 ladjust = false;
253 alt_form = false;
254
255 have_precision = false;
256 precision = 1;
257 bits = 32;
258 width = 0;
259 repeat = 1;
260
261 /* Copy all input to output until we hit a format specifier */
262 if (*p != '%') {
263 WRITE_CHAR(*p);
264 continue;
265 }
266
267 /* Hit '%' -- is this followed by an escaped '%' literal? */
268 p++;
269 if (*p == '%') {
270 WRITE_CHAR('%');
271 p++;
272 continue;
273 }
274
275 /* Parse repeat specifier */
276 if (*p == '[') {
277 p++;
278
279 /* Determine repeat count */
280 if (*p == ']') {
281 /* Repeat consumes all input */
282 repeat = bhnd_nvram_val_nelem(value);
283 } else if (*p == '*') {
284 /* Repeat is supplied as an argument */
285 repeat = va_arg(ap, size_t);
286 p++;
287 } else {
288 char *endp;
289
290 /* Repeat specified as argument */
291 repeat = strtoul(p, &endp, 10);
292 if (p == endp) {
293 BHND_NV_LOG("error parsing repeat "
294 "count at '%s'", p);
295 return (EINVAL);
296 }
297
298 /* Advance past repeat count */
299 p = endp;
300 }
301
302 /* Advance past terminating ']' */
303 if (*p != ']') {
304 BHND_NV_LOG("error parsing repeat count at "
305 "'%s'", p);
306 return (EINVAL);
307 }
308 p++;
309
310 delim = va_arg(ap, const char *);
311 delim_len = strlen(delim);
312 }
313
314 /* Parse flags */
315 while (*p != '\0') {
316 const char *np;
317 bool stop;
318
319 stop = false;
320 np = p+1;
321
322 switch (*p) {
323 case '#':
324 alt_form = true;
325 break;
326 case '':
327 padc = '';
328 break;
329 case '-':
330 ladjust = true;
331 break;
332 case ' ':
333 /* Must not override '+' */
334 if (signc != '+')
335 signc = ' ';
336 break;
337 case '+':
338 signc = '+';
339 break;
340 default:
341 /* Non-flag character */
342 stop = true;
343 break;
344 }
345
346 if (stop)
347 break;
348 else
349 p = np;
350 }
351
352 /* Parse minimum width */
353 if (*p == '*') {
354 ssize_t arg;
355
356 /* Width is supplied as an argument */
357 arg = va_arg(ap, int);
358
359 /* Negative width argument is interpreted as
360 * '-' flag followed by positive width */
361 if (arg < 0) {
362 ladjust = true;
363 arg = -arg;
364 }
365
366 width = arg;
367 p++;
368 } else if (bhnd_nv_isdigit(*p)) {
369 uint32_t v;
370 size_t len, parsed;
371
372 /* Parse width value */
373 len = sizeof(v);
374 error = bhnd_nvram_parse_int(p, strlen(p), 10, &parsed,
375 &v, &len, BHND_NVRAM_TYPE_UINT32);
376 if (error) {
377 BHND_NV_LOG("error parsing width %s: %d\n", p,
378 error);
379 return (EINVAL);
380 }
381
382 /* Save width and advance input */
383 width = v;
384 p += parsed;
385 }
386
387 /* Parse precision */
388 if (*p == '.') {
389 uint32_t v;
390 size_t len, parsed;
391
392 p++;
393 have_precision = true;
394
395 if (*p == '*') {
396 ssize_t arg;
397
398 /* Precision is specified as an argument */
399 arg = va_arg(ap, int);
400
401 /* Negative precision argument is interpreted
402 * as '-' flag followed by positive
403 * precision */
404 if (arg < 0) {
405 ladjust = true;
406 arg = -arg;
407 }
408
409 precision = arg;
410 } else if (!bhnd_nv_isdigit(*p)) {
411 /* Implicit precision of 0 */
412 precision = 0;
413 } else {
414 /* Parse precision value */
415 len = sizeof(v);
416 error = bhnd_nvram_parse_int(p, strlen(p), 10,
417 &parsed, &v, &len,
418 BHND_NVRAM_TYPE_UINT32);
419 if (error) {
420 BHND_NV_LOG("error parsing width %s: "
421 "%d\n", p, error);
422 return (EINVAL);
423 }
424
425 /* Save precision and advance input */
426 precision = v;
427 p += parsed;
428 }
429 }
430
431 /* Parse length modifiers */
432 while (*p != '\0') {
433 const char *np;
434 bool stop;
435
436 stop = false;
437 np = p+1;
438
439 switch (*p) {
440 case 'h':
441 if (lenc == '\0') {
442 /* Set initial length value */
443 lenc = *p;
444 bits = 16;
445 } else if (lenc == *p && bits == 16) {
446 /* Modify previous length value */
447 bits = 8;
448 } else {
449 BHND_NV_LOG("invalid length modifier "
450 "%c\n", *p);
451 return (EINVAL);
452 }
453 break;
454
455 case 'l':
456 if (lenc == '\0') {
457 /* Set initial length value */
458 lenc = *p;
459 bits = 32;
460 } else if (lenc == *p && bits == 32) {
461 /* Modify previous length value */
462 bits = 64;
463 } else {
464 BHND_NV_LOG("invalid length modifier "
465 "%c\n", *p);
466 return (EINVAL);
467 }
468 break;
469
470 case 'j':
471 /* Conflicts with all other length
472 * specifications, and may only occur once */
473 if (lenc != '\0') {
474 BHND_NV_LOG("invalid length modifier "
475 "%c\n", *p);
476 return (EINVAL);
477 }
478
479 lenc = *p;
480 bits = 64;
481 break;
482
483 case 'I': {
484 char *endp;
485
486 /* Conflicts with all other length
487 * specifications, and may only occur once */
488 if (lenc != '\0') {
489 BHND_NV_LOG("invalid length modifier "
490 "%c\n", *p);
491 return (EINVAL);
492 }
493
494 lenc = *p;
495
496 /* Parse the length specifier value */
497 p++;
498 bits = strtoul(p, &endp, 10);
499 if (p == endp) {
500 BHND_NV_LOG("invalid size specifier: "
501 "%s\n", p);
502 return (EINVAL);
503 }
504
505 /* Advance input past the parsed integer */
506 np = endp;
507 break;
508 }
509 default:
510 /* Non-length modifier character */
511 stop = true;
512 break;
513 }
514
515 if (stop)
516 break;
517 else
518 p = np;
519 }
520
521 /* Parse conversion specifier and format the value(s) */
522 for (u_long n = 0; n < repeat; n++) {
523 bhnd_nvram_type arg_type;
524 size_t arg_size;
525 size_t i;
526 u_long base;
527 bool is_signed, is_upper;
528
529 is_signed = false;
530 is_upper = false;
531 base = 0;
532
533 /* Fetch next element */
534 elem = bhnd_nvram_val_next(value, elem, &elen);
535 if (elem == NULL) {
536 BHND_NV_LOG("format string references more "
537 "than %zu available value elements\n",
538 bhnd_nvram_val_nelem(value));
539 return (EINVAL);
540 }
541
542 /*
543 * If this is not the first value, append the delimiter.
544 */
545 if (n > 0) {
546 size_t nremain = 0;
547 if (limit > nbytes)
548 nremain = limit - nbytes;
549
550 if (nremain >= delim_len)
551 memcpy(outp + nbytes, delim, delim_len);
552
553 /* Add delimiter length to the total byte count */
554 if (SIZE_MAX - nbytes < delim_len)
555 return (EFTYPE); /* overflows size_t */
556
557 nbytes += delim_len;
558 }
559
560 /* Parse integer conversion specifiers */
561 switch (*p) {
562 case 'd':
563 case 'i':
564 base = 10;
565 is_signed = true;
566 break;
567
568 case 'u':
569 base = 10;
570 break;
571
572 case 'o':
573 base = 8;
574 break;
575
576 case 'x':
577 base = 16;
578 break;
579
580 case 'X':
581 base = 16;
582 is_upper = true;
583 break;
584 }
585
586 /* Format argument */
587 switch (*p) {
588 #define NV_ENCODE_INT(_width) do { \
589 arg_type = (is_signed) ? BHND_NVRAM_TYPE_INT ## _width : \
590 BHND_NVRAM_TYPE_UINT ## _width; \
591 arg_size = sizeof(v.u ## _width); \
592 error = bhnd_nvram_val_encode_elem(value, elem, elen, \
593 &v.u ## _width, &arg_size, arg_type); \
594 if (error) { \
595 BHND_NV_LOG("error encoding argument as %s: %d\n", \
596 bhnd_nvram_type_name(arg_type), error); \
597 return (error); \
598 } \
599 \
600 if (is_signed) { \
601 if (v.i ## _width < 0) { \
602 add_neg = true; \
603 numval = (int64_t)-(v.i ## _width); \
604 } else { \
605 numval = (int64_t) (v.i ## _width); \
606 } \
607 } else { \
608 numval = v.u ## _width; \
609 } \
610 } while(0)
611 case 'd':
612 case 'i':
613 case 'u':
614 case 'o':
615 case 'x':
616 case 'X': {
617 char numbuf[NV_NUMSTR_MAX];
618 char *sptr;
619 uint64_t numval;
620 size_t slen;
621 bool add_neg;
622 union {
623 uint8_t u8;
624 uint16_t u16;
625 uint32_t u32;
626 uint64_t u64;
627 int8_t i8;
628 int16_t i16;
629 int32_t i32;
630 int64_t i64;
631 } v;
632
633 add_neg = false;
634
635 /* If precision is specified, it overrides
636 * (and behaves identically) to a zero-prefixed
637 * minimum width */
638 if (have_precision) {
639 padc = '';
640 width = precision;
641 ladjust = false;
642 }
643
644 /* If zero-padding is used, value must be right
645 * adjusted */
646 if (padc == '')
647 ladjust = false;
648
649 /* Request encode to the appropriate integer
650 * type, and then promote to common 64-bit
651 * representation */
652 switch (bits) {
653 case 8:
654 NV_ENCODE_INT(8);
655 break;
656 case 16:
657 NV_ENCODE_INT(16);
658 break;
659 case 32:
660 NV_ENCODE_INT(32);
661 break;
662 case 64:
663 NV_ENCODE_INT(64);
664 break;
665 default:
666 BHND_NV_LOG("invalid length specifier: "
667 "%lu\n", bits);
668 return (EINVAL);
669 }
670 #undef NV_ENCODE_INT
671
672 /* If a precision of 0 is specified and the
673 * value is also zero, no characters should
674 * be produced */
675 if (have_precision && precision == 0 &&
676 numval == 0)
677 {
678 break;
679 }
680
681 /* Emit string representation to local buffer */
682 BHND_NV_ASSERT(base <= 16, ("invalid base"));
683 sptr = numbuf + nitems(numbuf) - 1;
684 for (slen = 0; slen < sizeof(numbuf); slen++) {
685 char c;
686 uint64_t n;
687
688 n = numval % base;
689 c = bhnd_nv_hex2ascii(n);
690 if (is_upper)
691 c = bhnd_nv_toupper(c);
692
693 sptr--;
694 *sptr = c;
695
696 numval /= (uint64_t)base;
697 if (numval == 0) {
698 slen++;
699 break;
700 }
701 }
702
703 arg_size = slen;
704
705 /* Reserve space for 0/0x prefix? */
706 if (alt_form) {
707 if (numval == 0) {
708 /* If 0, no prefix */
709 alt_form = false;
710 } else if (base == 8) {
711 arg_size += 1; /* 0 */
712 } else if (base == 16) {
713 arg_size += 2; /* 0x/0X */
714 }
715 }
716
717 /* Reserve space for ' ', '+', or '-' prefix? */
718 if (add_neg || signc != '\0') {
719 if (add_neg)
720 signc = '-';
721
722 arg_size++;
723 }
724
725 /* Right adjust (if using spaces) */
726 if (!ladjust && padc != '') {
727 for (i = arg_size; i < width; i++)
728 WRITE_CHAR(padc);
729 }
730
731 if (signc != '\0')
732 WRITE_CHAR(signc);
733
734 if (alt_form) {
735 if (base == 8) {
736 WRITE_CHAR('');
737 } else if (base == 16) {
738 WRITE_CHAR('');
739 if (is_upper)
740 WRITE_CHAR('X');
741 else
742 WRITE_CHAR('x');
743 }
744 }
745
746 /* Right adjust (if using zeros) */
747 if (!ladjust && padc == '') {
748 for (i = slen; i < width; i++)
749 WRITE_CHAR(padc);
750 }
751
752 /* Write the string to our output buffer */
753 if (limit > nbytes && limit - nbytes >= slen)
754 memcpy(outp + nbytes, sptr, slen);
755
756 /* Update the total byte count */
757 if (SIZE_MAX - nbytes < arg_size)
758 return (EFTYPE); /* overflows size_t */
759
760 nbytes += arg_size;
761
762 /* Left adjust */
763 for (i = arg_size; ladjust && i < width; i++)
764 WRITE_CHAR(padc);
765
766 break;
767 }
768
769 case 's': {
770 char *s;
771 size_t slen;
772
773 /* Query the total length of the element when
774 * converted to a string */
775 arg_type = BHND_NVRAM_TYPE_STRING;
776 error = bhnd_nvram_val_encode_elem(value, elem,
777 elen, NULL, &arg_size, arg_type);
778 if (error) {
779 BHND_NV_LOG("error encoding argument "
780 "as %s: %d\n",
781 bhnd_nvram_type_name(arg_type),
782 error);
783 return (error);
784 }
785
786 /* Do not include trailing NUL in the string
787 * length */
788 if (arg_size > 0)
789 arg_size--;
790
791 /* Right adjust */
792 for (i = arg_size; !ladjust && i < width; i++)
793 WRITE_CHAR(padc);
794
795 /* Determine output positition and remaining
796 * buffer space */
797 if (limit > nbytes) {
798 s = outp + nbytes;
799 slen = limit - nbytes;
800 } else {
801 s = NULL;
802 slen = 0;
803 }
804
805 /* Encode the string to our output buffer */
806 error = bhnd_nvram_val_encode_elem(value, elem,
807 elen, s, &slen, arg_type);
808 if (error && error != ENOMEM) {
809 BHND_NV_LOG("error encoding argument "
810 "as %s: %d\n",
811 bhnd_nvram_type_name(arg_type),
812 error);
813 return (error);
814 }
815
816 /* Update the total byte count */
817 if (SIZE_MAX - nbytes < arg_size)
818 return (EFTYPE); /* overflows size_t */
819
820 nbytes += arg_size;
821
822 /* Left adjust */
823 for (i = arg_size; ladjust && i < width; i++)
824 WRITE_CHAR(padc);
825
826 break;
827 }
828
829 case 'c': {
830 char c;
831
832 arg_type = BHND_NVRAM_TYPE_CHAR;
833 arg_size = bhnd_nvram_type_width(arg_type);
834
835 /* Encode as single character */
836 error = bhnd_nvram_val_encode_elem(value, elem,
837 elen, &c, &arg_size, arg_type);
838 if (error) {
839 BHND_NV_LOG("error encoding argument "
840 "as %s: %d\n",
841 bhnd_nvram_type_name(arg_type),
842 error);
843 return (error);
844 }
845
846 BHND_NV_ASSERT(arg_size == sizeof(c),
847 ("invalid encoded size"));
848
849 /* Right adjust */
850 for (i = arg_size; !ladjust && i < width; i++)
851 WRITE_CHAR(padc);
852
853 WRITE_CHAR(padc);
854
855 /* Left adjust */
856 for (i = arg_size; ladjust && i < width; i++)
857 WRITE_CHAR(padc);
858
859 break;
860 }
861 }
862 }
863 }
864
865 /* Append terminating NUL */
866 if (limit > nbytes)
867 *(outp + nbytes) = '\0';
868
869 if (nbytes < SIZE_MAX)
870 nbytes++;
871 else
872 return (EFTYPE);
873
874 /* Report required space */
875 *olen = nbytes;
876 if (limit < nbytes) {
877 if (outp != NULL)
878 return (ENOMEM);
879 }
880
881 return (0);
882 }
Cache object: d59b18dc63a4b959b87a5b53ebf89118
|