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