1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2009-2010 The FreeBSD Foundation 5 * All rights reserved. 6 * 7 * This software was developed by Pawel Jakub Dawidek under sponsorship from 8 * the FreeBSD Foundation. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __FBSDID("$FreeBSD$"); 34 35 #include <sys/param.h> 36 #include <sys/endian.h> 37 38 #include <bitstring.h> 39 #include <errno.h> 40 #include <stdarg.h> 41 #include <stdbool.h> 42 #include <stdint.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <unistd.h> 46 47 #include <ebuf.h> 48 #include <pjdlog.h> 49 50 #include "nv.h" 51 52 #ifndef PJDLOG_ASSERT 53 #include <assert.h> 54 #define PJDLOG_ASSERT(...) assert(__VA_ARGS__) 55 #endif 56 #ifndef PJDLOG_ABORT 57 #define PJDLOG_ABORT(...) abort() 58 #endif 59 60 #define NV_TYPE_NONE 0 61 62 #define NV_TYPE_INT8 1 63 #define NV_TYPE_UINT8 2 64 #define NV_TYPE_INT16 3 65 #define NV_TYPE_UINT16 4 66 #define NV_TYPE_INT32 5 67 #define NV_TYPE_UINT32 6 68 #define NV_TYPE_INT64 7 69 #define NV_TYPE_UINT64 8 70 #define NV_TYPE_INT8_ARRAY 9 71 #define NV_TYPE_UINT8_ARRAY 10 72 #define NV_TYPE_INT16_ARRAY 11 73 #define NV_TYPE_UINT16_ARRAY 12 74 #define NV_TYPE_INT32_ARRAY 13 75 #define NV_TYPE_UINT32_ARRAY 14 76 #define NV_TYPE_INT64_ARRAY 15 77 #define NV_TYPE_UINT64_ARRAY 16 78 #define NV_TYPE_STRING 17 79 80 #define NV_TYPE_MASK 0x7f 81 #define NV_TYPE_FIRST NV_TYPE_INT8 82 #define NV_TYPE_LAST NV_TYPE_STRING 83 84 #define NV_ORDER_NETWORK 0x00 85 #define NV_ORDER_HOST 0x80 86 87 #define NV_ORDER_MASK 0x80 88 89 #define NV_MAGIC 0xaea1e 90 struct nv { 91 int nv_magic; 92 int nv_error; 93 struct ebuf *nv_ebuf; 94 }; 95 96 struct nvhdr { 97 uint8_t nvh_type; 98 uint8_t nvh_namesize; 99 uint32_t nvh_dsize; 100 char nvh_name[0]; 101 } __packed; 102 #define NVH_DATA(nvh) ((unsigned char *)nvh + NVH_HSIZE(nvh)) 103 #define NVH_HSIZE(nvh) \ 104 (sizeof(struct nvhdr) + roundup2((nvh)->nvh_namesize, 8)) 105 #define NVH_DSIZE(nvh) \ 106 (((nvh)->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST ? \ 107 (nvh)->nvh_dsize : \ 108 le32toh((nvh)->nvh_dsize)) 109 #define NVH_SIZE(nvh) (NVH_HSIZE(nvh) + roundup2(NVH_DSIZE(nvh), 8)) 110 111 #define NV_CHECK(nv) do { \ 112 PJDLOG_ASSERT((nv) != NULL); \ 113 PJDLOG_ASSERT((nv)->nv_magic == NV_MAGIC); \ 114 } while (0) 115 116 static void nv_add(struct nv *nv, const unsigned char *value, size_t vsize, 117 int type, const char *name); 118 static void nv_addv(struct nv *nv, const unsigned char *value, size_t vsize, 119 int type, const char *namefmt, va_list nameap); 120 static struct nvhdr *nv_find(struct nv *nv, int type, const char *namefmt, 121 va_list nameap); 122 static void nv_swap(struct nvhdr *nvh, bool tohost); 123 124 /* 125 * Allocate and initialize new nv structure. 126 * Return NULL in case of malloc(3) failure. 127 */ 128 struct nv * 129 nv_alloc(void) 130 { 131 struct nv *nv; 132 133 nv = malloc(sizeof(*nv)); 134 if (nv == NULL) 135 return (NULL); 136 nv->nv_ebuf = ebuf_alloc(0); 137 if (nv->nv_ebuf == NULL) { 138 free(nv); 139 return (NULL); 140 } 141 nv->nv_error = 0; 142 nv->nv_magic = NV_MAGIC; 143 return (nv); 144 } 145 146 /* 147 * Free the given nv structure. 148 */ 149 void 150 nv_free(struct nv *nv) 151 { 152 153 if (nv == NULL) 154 return; 155 156 NV_CHECK(nv); 157 158 nv->nv_magic = 0; 159 ebuf_free(nv->nv_ebuf); 160 free(nv); 161 } 162 163 /* 164 * Return error for the given nv structure. 165 */ 166 int 167 nv_error(const struct nv *nv) 168 { 169 170 if (nv == NULL) 171 return (ENOMEM); 172 173 NV_CHECK(nv); 174 175 return (nv->nv_error); 176 } 177 178 /* 179 * Set error for the given nv structure and return previous error. 180 */ 181 int 182 nv_set_error(struct nv *nv, int error) 183 { 184 int preverr; 185 186 if (nv == NULL) 187 return (ENOMEM); 188 189 NV_CHECK(nv); 190 191 preverr = nv->nv_error; 192 nv->nv_error = error; 193 return (preverr); 194 } 195 196 /* 197 * Validate correctness of the entire nv structure and all its elements. 198 * If extrap is not NULL, store number of extra bytes at the end of the buffer. 199 */ 200 int 201 nv_validate(struct nv *nv, size_t *extrap) 202 { 203 struct nvhdr *nvh; 204 unsigned char *data, *ptr; 205 size_t dsize, size, vsize; 206 int error; 207 208 if (nv == NULL) { 209 errno = ENOMEM; 210 return (-1); 211 } 212 213 NV_CHECK(nv); 214 PJDLOG_ASSERT(nv->nv_error == 0); 215 216 /* TODO: Check that names are unique? */ 217 218 error = 0; 219 ptr = ebuf_data(nv->nv_ebuf, &size); 220 while (size > 0) { 221 /* 222 * Zeros at the end of the buffer are acceptable. 223 */ 224 if (ptr[0] == '\0') 225 break; 226 /* 227 * Minimum size at this point is size of nvhdr structure, one 228 * character long name plus terminating '\0'. 229 */ 230 if (size < sizeof(*nvh) + 2) { 231 error = EINVAL; 232 break; 233 } 234 nvh = (struct nvhdr *)ptr; 235 if (size < NVH_HSIZE(nvh)) { 236 error = EINVAL; 237 break; 238 } 239 if (nvh->nvh_name[nvh->nvh_namesize - 1] != '\0') { 240 error = EINVAL; 241 break; 242 } 243 if (strlen(nvh->nvh_name) != 244 (size_t)(nvh->nvh_namesize - 1)) { 245 error = EINVAL; 246 break; 247 } 248 if ((nvh->nvh_type & NV_TYPE_MASK) < NV_TYPE_FIRST || 249 (nvh->nvh_type & NV_TYPE_MASK) > NV_TYPE_LAST) { 250 error = EINVAL; 251 break; 252 } 253 dsize = NVH_DSIZE(nvh); 254 if (dsize == 0) { 255 error = EINVAL; 256 break; 257 } 258 if (size < NVH_SIZE(nvh)) { 259 error = EINVAL; 260 break; 261 } 262 vsize = 0; 263 switch (nvh->nvh_type & NV_TYPE_MASK) { 264 case NV_TYPE_INT8: 265 case NV_TYPE_UINT8: 266 if (vsize == 0) 267 vsize = 1; 268 /* FALLTHROUGH */ 269 case NV_TYPE_INT16: 270 case NV_TYPE_UINT16: 271 if (vsize == 0) 272 vsize = 2; 273 /* FALLTHROUGH */ 274 case NV_TYPE_INT32: 275 case NV_TYPE_UINT32: 276 if (vsize == 0) 277 vsize = 4; 278 /* FALLTHROUGH */ 279 case NV_TYPE_INT64: 280 case NV_TYPE_UINT64: 281 if (vsize == 0) 282 vsize = 8; 283 if (dsize != vsize) { 284 error = EINVAL; 285 break; 286 } 287 break; 288 case NV_TYPE_INT8_ARRAY: 289 case NV_TYPE_UINT8_ARRAY: 290 break; 291 case NV_TYPE_INT16_ARRAY: 292 case NV_TYPE_UINT16_ARRAY: 293 if (vsize == 0) 294 vsize = 2; 295 /* FALLTHROUGH */ 296 case NV_TYPE_INT32_ARRAY: 297 case NV_TYPE_UINT32_ARRAY: 298 if (vsize == 0) 299 vsize = 4; 300 /* FALLTHROUGH */ 301 case NV_TYPE_INT64_ARRAY: 302 case NV_TYPE_UINT64_ARRAY: 303 if (vsize == 0) 304 vsize = 8; 305 if ((dsize % vsize) != 0) { 306 error = EINVAL; 307 break; 308 } 309 break; 310 case NV_TYPE_STRING: 311 data = NVH_DATA(nvh); 312 if (data[dsize - 1] != '\0') { 313 error = EINVAL; 314 break; 315 } 316 if (strlen((char *)data) != dsize - 1) { 317 error = EINVAL; 318 break; 319 } 320 break; 321 default: 322 PJDLOG_ABORT("invalid condition"); 323 } 324 if (error != 0) 325 break; 326 ptr += NVH_SIZE(nvh); 327 size -= NVH_SIZE(nvh); 328 } 329 if (error != 0) { 330 errno = error; 331 if (nv->nv_error == 0) 332 nv->nv_error = error; 333 return (-1); 334 } 335 if (extrap != NULL) 336 *extrap = size; 337 return (0); 338 } 339 340 /* 341 * Convert the given nv structure to network byte order and return ebuf 342 * structure. 343 */ 344 struct ebuf * 345 nv_hton(struct nv *nv) 346 { 347 struct nvhdr *nvh; 348 unsigned char *ptr; 349 size_t size; 350 351 NV_CHECK(nv); 352 PJDLOG_ASSERT(nv->nv_error == 0); 353 354 ptr = ebuf_data(nv->nv_ebuf, &size); 355 while (size > 0) { 356 /* 357 * Minimum size at this point is size of nvhdr structure, 358 * one character long name plus terminating '\0'. 359 */ 360 PJDLOG_ASSERT(size >= sizeof(*nvh) + 2); 361 nvh = (struct nvhdr *)ptr; 362 PJDLOG_ASSERT(NVH_SIZE(nvh) <= size); 363 nv_swap(nvh, false); 364 ptr += NVH_SIZE(nvh); 365 size -= NVH_SIZE(nvh); 366 } 367 368 return (nv->nv_ebuf); 369 } 370 371 /* 372 * Create nv structure based on ebuf received from the network. 373 */ 374 struct nv * 375 nv_ntoh(struct ebuf *eb) 376 { 377 struct nv *nv; 378 size_t extra; 379 int rerrno; 380 381 PJDLOG_ASSERT(eb != NULL); 382 383 nv = malloc(sizeof(*nv)); 384 if (nv == NULL) 385 return (NULL); 386 nv->nv_error = 0; 387 nv->nv_ebuf = eb; 388 nv->nv_magic = NV_MAGIC; 389 390 if (nv_validate(nv, &extra) == -1) { 391 rerrno = errno; 392 nv->nv_magic = 0; 393 free(nv); 394 errno = rerrno; 395 return (NULL); 396 } 397 /* 398 * Remove extra zeros at the end of the buffer. 399 */ 400 ebuf_del_tail(eb, extra); 401 402 return (nv); 403 } 404 405 #define NV_DEFINE_ADD(type, TYPE) \ 406 void \ 407 nv_add_##type(struct nv *nv, type##_t value, const char *namefmt, ...) \ 408 { \ 409 va_list nameap; \ 410 \ 411 va_start(nameap, namefmt); \ 412 nv_addv(nv, (unsigned char *)&value, sizeof(value), \ 413 NV_TYPE_##TYPE, namefmt, nameap); \ 414 va_end(nameap); \ 415 } 416 417 NV_DEFINE_ADD(int8, INT8) 418 NV_DEFINE_ADD(uint8, UINT8) 419 NV_DEFINE_ADD(int16, INT16) 420 NV_DEFINE_ADD(uint16, UINT16) 421 NV_DEFINE_ADD(int32, INT32) 422 NV_DEFINE_ADD(uint32, UINT32) 423 NV_DEFINE_ADD(int64, INT64) 424 NV_DEFINE_ADD(uint64, UINT64) 425 426 #undef NV_DEFINE_ADD 427 428 #define NV_DEFINE_ADD_ARRAY(type, TYPE) \ 429 void \ 430 nv_add_##type##_array(struct nv *nv, const type##_t *value, \ 431 size_t nsize, const char *namefmt, ...) \ 432 { \ 433 va_list nameap; \ 434 \ 435 va_start(nameap, namefmt); \ 436 nv_addv(nv, (const unsigned char *)value, \ 437 sizeof(value[0]) * nsize, NV_TYPE_##TYPE##_ARRAY, namefmt, \ 438 nameap); \ 439 va_end(nameap); \ 440 } 441 442 NV_DEFINE_ADD_ARRAY(int8, INT8) 443 NV_DEFINE_ADD_ARRAY(uint8, UINT8) 444 NV_DEFINE_ADD_ARRAY(int16, INT16) 445 NV_DEFINE_ADD_ARRAY(uint16, UINT16) 446 NV_DEFINE_ADD_ARRAY(int32, INT32) 447 NV_DEFINE_ADD_ARRAY(uint32, UINT32) 448 NV_DEFINE_ADD_ARRAY(int64, INT64) 449 NV_DEFINE_ADD_ARRAY(uint64, UINT64) 450 451 #undef NV_DEFINE_ADD_ARRAY 452 453 void 454 nv_add_string(struct nv *nv, const char *value, const char *namefmt, ...) 455 { 456 va_list nameap; 457 size_t size; 458 459 size = strlen(value) + 1; 460 461 va_start(nameap, namefmt); 462 nv_addv(nv, (const unsigned char *)value, size, NV_TYPE_STRING, 463 namefmt, nameap); 464 va_end(nameap); 465 } 466 467 void 468 nv_add_stringf(struct nv *nv, const char *name, const char *valuefmt, ...) 469 { 470 va_list valueap; 471 472 va_start(valueap, valuefmt); 473 nv_add_stringv(nv, name, valuefmt, valueap); 474 va_end(valueap); 475 } 476 477 void 478 nv_add_stringv(struct nv *nv, const char *name, const char *valuefmt, 479 va_list valueap) 480 { 481 char *value; 482 ssize_t size; 483 484 size = vasprintf(&value, valuefmt, valueap); 485 if (size == -1) { 486 if (nv->nv_error == 0) 487 nv->nv_error = ENOMEM; 488 return; 489 } 490 size++; 491 nv_add(nv, (const unsigned char *)value, size, NV_TYPE_STRING, name); 492 free(value); 493 } 494 495 #define NV_DEFINE_GET(type, TYPE) \ 496 type##_t \ 497 nv_get_##type(struct nv *nv, const char *namefmt, ...) \ 498 { \ 499 struct nvhdr *nvh; \ 500 va_list nameap; \ 501 type##_t value; \ 502 \ 503 va_start(nameap, namefmt); \ 504 nvh = nv_find(nv, NV_TYPE_##TYPE, namefmt, nameap); \ 505 va_end(nameap); \ 506 if (nvh == NULL) \ 507 return (0); \ 508 PJDLOG_ASSERT((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST);\ 509 PJDLOG_ASSERT(sizeof(value) == nvh->nvh_dsize); \ 510 bcopy(NVH_DATA(nvh), &value, sizeof(value)); \ 511 \ 512 return (value); \ 513 } 514 515 NV_DEFINE_GET(int8, INT8) 516 NV_DEFINE_GET(uint8, UINT8) 517 NV_DEFINE_GET(int16, INT16) 518 NV_DEFINE_GET(uint16, UINT16) 519 NV_DEFINE_GET(int32, INT32) 520 NV_DEFINE_GET(uint32, UINT32) 521 NV_DEFINE_GET(int64, INT64) 522 NV_DEFINE_GET(uint64, UINT64) 523 524 #undef NV_DEFINE_GET 525 526 #define NV_DEFINE_GET_ARRAY(type, TYPE) \ 527 const type##_t * \ 528 nv_get_##type##_array(struct nv *nv, size_t *sizep, \ 529 const char *namefmt, ...) \ 530 { \ 531 struct nvhdr *nvh; \ 532 va_list nameap; \ 533 \ 534 va_start(nameap, namefmt); \ 535 nvh = nv_find(nv, NV_TYPE_##TYPE##_ARRAY, namefmt, nameap); \ 536 va_end(nameap); \ 537 if (nvh == NULL) \ 538 return (NULL); \ 539 PJDLOG_ASSERT((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST);\ 540 PJDLOG_ASSERT((nvh->nvh_dsize % sizeof(type##_t)) == 0); \ 541 if (sizep != NULL) \ 542 *sizep = nvh->nvh_dsize / sizeof(type##_t); \ 543 return ((type##_t *)(void *)NVH_DATA(nvh)); \ 544 } 545 546 NV_DEFINE_GET_ARRAY(int8, INT8) 547 NV_DEFINE_GET_ARRAY(uint8, UINT8) 548 NV_DEFINE_GET_ARRAY(int16, INT16) 549 NV_DEFINE_GET_ARRAY(uint16, UINT16) 550 NV_DEFINE_GET_ARRAY(int32, INT32) 551 NV_DEFINE_GET_ARRAY(uint32, UINT32) 552 NV_DEFINE_GET_ARRAY(int64, INT64) 553 NV_DEFINE_GET_ARRAY(uint64, UINT64) 554 555 #undef NV_DEFINE_GET_ARRAY 556 557 const char * 558 nv_get_string(struct nv *nv, const char *namefmt, ...) 559 { 560 struct nvhdr *nvh; 561 va_list nameap; 562 char *str; 563 564 va_start(nameap, namefmt); 565 nvh = nv_find(nv, NV_TYPE_STRING, namefmt, nameap); 566 va_end(nameap); 567 if (nvh == NULL) 568 return (NULL); 569 PJDLOG_ASSERT((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST); 570 PJDLOG_ASSERT(nvh->nvh_dsize >= 1); 571 str = (char *)NVH_DATA(nvh); 572 PJDLOG_ASSERT(str[nvh->nvh_dsize - 1] == '\0'); 573 PJDLOG_ASSERT(strlen(str) == nvh->nvh_dsize - 1); 574 return (str); 575 } 576 577 static bool 578 nv_vexists(struct nv *nv, const char *namefmt, va_list nameap) 579 { 580 struct nvhdr *nvh; 581 int snverror, serrno; 582 583 if (nv == NULL) 584 return (false); 585 586 serrno = errno; 587 snverror = nv->nv_error; 588 589 nvh = nv_find(nv, NV_TYPE_NONE, namefmt, nameap); 590 591 errno = serrno; 592 nv->nv_error = snverror; 593 594 return (nvh != NULL); 595 } 596 597 bool 598 nv_exists(struct nv *nv, const char *namefmt, ...) 599 { 600 va_list nameap; 601 bool ret; 602 603 va_start(nameap, namefmt); 604 ret = nv_vexists(nv, namefmt, nameap); 605 va_end(nameap); 606 607 return (ret); 608 } 609 610 void 611 nv_assert(struct nv *nv, const char *namefmt, ...) 612 { 613 va_list nameap; 614 615 va_start(nameap, namefmt); 616 PJDLOG_ASSERT(nv_vexists(nv, namefmt, nameap)); 617 va_end(nameap); 618 } 619 620 /* 621 * Dump content of the nv structure. 622 */ 623 void 624 nv_dump(struct nv *nv) 625 { 626 struct nvhdr *nvh; 627 unsigned char *data, *ptr; 628 size_t dsize, size; 629 unsigned int ii; 630 bool swap; 631 632 if (nv_validate(nv, NULL) == -1) { 633 printf("error: %d\n", errno); 634 return; 635 } 636 637 NV_CHECK(nv); 638 PJDLOG_ASSERT(nv->nv_error == 0); 639 640 ptr = ebuf_data(nv->nv_ebuf, &size); 641 while (size > 0) { 642 PJDLOG_ASSERT(size >= sizeof(*nvh) + 2); 643 nvh = (struct nvhdr *)ptr; 644 PJDLOG_ASSERT(size >= NVH_SIZE(nvh)); 645 swap = ((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_NETWORK); 646 dsize = NVH_DSIZE(nvh); 647 data = NVH_DATA(nvh); 648 printf(" %s", nvh->nvh_name); 649 switch (nvh->nvh_type & NV_TYPE_MASK) { 650 case NV_TYPE_INT8: 651 printf("(int8): %jd", (intmax_t)(*(int8_t *)data)); 652 break; 653 case NV_TYPE_UINT8: 654 printf("(uint8): %ju", (uintmax_t)(*(uint8_t *)data)); 655 break; 656 case NV_TYPE_INT16: 657 printf("(int16): %jd", swap ? 658 (intmax_t)le16toh(*(int16_t *)(void *)data) : 659 (intmax_t)*(int16_t *)(void *)data); 660 break; 661 case NV_TYPE_UINT16: 662 printf("(uint16): %ju", swap ? 663 (uintmax_t)le16toh(*(uint16_t *)(void *)data) : 664 (uintmax_t)*(uint16_t *)(void *)data); 665 break; 666 case NV_TYPE_INT32: 667 printf("(int32): %jd", swap ? 668 (intmax_t)le32toh(*(int32_t *)(void *)data) : 669 (intmax_t)*(int32_t *)(void *)data); 670 break; 671 case NV_TYPE_UINT32: 672 printf("(uint32): %ju", swap ? 673 (uintmax_t)le32toh(*(uint32_t *)(void *)data) : 674 (uintmax_t)*(uint32_t *)(void *)data); 675 break; 676 case NV_TYPE_INT64: 677 printf("(int64): %jd", swap ? 678 (intmax_t)le64toh(*(int64_t *)(void *)data) : 679 (intmax_t)*(int64_t *)(void *)data); 680 break; 681 case NV_TYPE_UINT64: 682 printf("(uint64): %ju", swap ? 683 (uintmax_t)le64toh(*(uint64_t *)(void *)data) : 684 (uintmax_t)*(uint64_t *)(void *)data); 685 break; 686 case NV_TYPE_INT8_ARRAY: 687 printf("(int8 array):"); 688 for (ii = 0; ii < dsize; ii++) 689 printf(" %jd", (intmax_t)((int8_t *)data)[ii]); 690 break; 691 case NV_TYPE_UINT8_ARRAY: 692 printf("(uint8 array):"); 693 for (ii = 0; ii < dsize; ii++) 694 printf(" %ju", (uintmax_t)((uint8_t *)data)[ii]); 695 break; 696 case NV_TYPE_INT16_ARRAY: 697 printf("(int16 array):"); 698 for (ii = 0; ii < dsize / 2; ii++) { 699 printf(" %jd", swap ? 700 (intmax_t)le16toh(((int16_t *)(void *)data)[ii]) : 701 (intmax_t)((int16_t *)(void *)data)[ii]); 702 } 703 break; 704 case NV_TYPE_UINT16_ARRAY: 705 printf("(uint16 array):"); 706 for (ii = 0; ii < dsize / 2; ii++) { 707 printf(" %ju", swap ? 708 (uintmax_t)le16toh(((uint16_t *)(void *)data)[ii]) : 709 (uintmax_t)((uint16_t *)(void *)data)[ii]); 710 } 711 break; 712 case NV_TYPE_INT32_ARRAY: 713 printf("(int32 array):"); 714 for (ii = 0; ii < dsize / 4; ii++) { 715 printf(" %jd", swap ? 716 (intmax_t)le32toh(((int32_t *)(void *)data)[ii]) : 717 (intmax_t)((int32_t *)(void *)data)[ii]); 718 } 719 break; 720 case NV_TYPE_UINT32_ARRAY: 721 printf("(uint32 array):"); 722 for (ii = 0; ii < dsize / 4; ii++) { 723 printf(" %ju", swap ? 724 (uintmax_t)le32toh(((uint32_t *)(void *)data)[ii]) : 725 (uintmax_t)((uint32_t *)(void *)data)[ii]); 726 } 727 break; 728 case NV_TYPE_INT64_ARRAY: 729 printf("(int64 array):"); 730 for (ii = 0; ii < dsize / 8; ii++) { 731 printf(" %ju", swap ? 732 (uintmax_t)le64toh(((uint64_t *)(void *)data)[ii]) : 733 (uintmax_t)((uint64_t *)(void *)data)[ii]); 734 } 735 break; 736 case NV_TYPE_UINT64_ARRAY: 737 printf("(uint64 array):"); 738 for (ii = 0; ii < dsize / 8; ii++) { 739 printf(" %ju", swap ? 740 (uintmax_t)le64toh(((uint64_t *)(void *)data)[ii]) : 741 (uintmax_t)((uint64_t *)(void *)data)[ii]); 742 } 743 break; 744 case NV_TYPE_STRING: 745 printf("(string): %s", (char *)data); 746 break; 747 default: 748 PJDLOG_ABORT("invalid condition"); 749 } 750 printf("\n"); 751 ptr += NVH_SIZE(nvh); 752 size -= NVH_SIZE(nvh); 753 } 754 } 755 756 /* 757 * Local routines below. 758 */ 759 760 static void 761 nv_add(struct nv *nv, const unsigned char *value, size_t vsize, int type, 762 const char *name) 763 { 764 static unsigned char align[7]; 765 struct nvhdr *nvh; 766 size_t namesize; 767 768 if (nv == NULL) { 769 errno = ENOMEM; 770 return; 771 } 772 773 NV_CHECK(nv); 774 775 namesize = strlen(name) + 1; 776 777 nvh = malloc(sizeof(*nvh) + roundup2(namesize, 8)); 778 if (nvh == NULL) { 779 if (nv->nv_error == 0) 780 nv->nv_error = ENOMEM; 781 return; 782 } 783 nvh->nvh_type = NV_ORDER_HOST | type; 784 nvh->nvh_namesize = (uint8_t)namesize; 785 nvh->nvh_dsize = (uint32_t)vsize; 786 bcopy(name, nvh->nvh_name, namesize); 787 788 /* Add header first. */ 789 if (ebuf_add_tail(nv->nv_ebuf, nvh, NVH_HSIZE(nvh)) == -1) { 790 PJDLOG_ASSERT(errno != 0); 791 if (nv->nv_error == 0) 792 nv->nv_error = errno; 793 free(nvh); 794 return; 795 } 796 free(nvh); 797 /* Add the actual data. */ 798 if (ebuf_add_tail(nv->nv_ebuf, value, vsize) == -1) { 799 PJDLOG_ASSERT(errno != 0); 800 if (nv->nv_error == 0) 801 nv->nv_error = errno; 802 return; 803 } 804 /* Align the data (if needed). */ 805 vsize = roundup2(vsize, 8) - vsize; 806 if (vsize == 0) 807 return; 808 PJDLOG_ASSERT(vsize > 0 && vsize <= sizeof(align)); 809 if (ebuf_add_tail(nv->nv_ebuf, align, vsize) == -1) { 810 PJDLOG_ASSERT(errno != 0); 811 if (nv->nv_error == 0) 812 nv->nv_error = errno; 813 return; 814 } 815 } 816 817 static void 818 nv_addv(struct nv *nv, const unsigned char *value, size_t vsize, int type, 819 const char *namefmt, va_list nameap) 820 { 821 char name[255]; 822 size_t namesize; 823 824 namesize = vsnprintf(name, sizeof(name), namefmt, nameap); 825 PJDLOG_ASSERT(namesize > 0 && namesize < sizeof(name)); 826 827 nv_add(nv, value, vsize, type, name); 828 } 829 830 static struct nvhdr * 831 nv_find(struct nv *nv, int type, const char *namefmt, va_list nameap) 832 { 833 char name[255]; 834 struct nvhdr *nvh; 835 unsigned char *ptr; 836 size_t size, namesize; 837 838 if (nv == NULL) { 839 errno = ENOMEM; 840 return (NULL); 841 } 842 843 NV_CHECK(nv); 844 845 namesize = vsnprintf(name, sizeof(name), namefmt, nameap); 846 PJDLOG_ASSERT(namesize > 0 && namesize < sizeof(name)); 847 namesize++; 848 849 ptr = ebuf_data(nv->nv_ebuf, &size); 850 while (size > 0) { 851 PJDLOG_ASSERT(size >= sizeof(*nvh) + 2); 852 nvh = (struct nvhdr *)ptr; 853 PJDLOG_ASSERT(size >= NVH_SIZE(nvh)); 854 nv_swap(nvh, true); 855 if (strcmp(nvh->nvh_name, name) == 0) { 856 if (type != NV_TYPE_NONE && 857 (nvh->nvh_type & NV_TYPE_MASK) != type) { 858 errno = EINVAL; 859 if (nv->nv_error == 0) 860 nv->nv_error = EINVAL; 861 return (NULL); 862 } 863 return (nvh); 864 } 865 ptr += NVH_SIZE(nvh); 866 size -= NVH_SIZE(nvh); 867 } 868 errno = ENOENT; 869 if (nv->nv_error == 0) 870 nv->nv_error = ENOENT; 871 return (NULL); 872 } 873 874 static void 875 nv_swap(struct nvhdr *nvh, bool tohost) 876 { 877 unsigned char *data, *end, *p; 878 size_t vsize; 879 880 data = NVH_DATA(nvh); 881 if (tohost) { 882 if ((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST) 883 return; 884 nvh->nvh_dsize = le32toh(nvh->nvh_dsize); 885 end = data + nvh->nvh_dsize; 886 nvh->nvh_type &= ~NV_ORDER_MASK; 887 nvh->nvh_type |= NV_ORDER_HOST; 888 } else { 889 if ((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_NETWORK) 890 return; 891 end = data + nvh->nvh_dsize; 892 nvh->nvh_dsize = htole32(nvh->nvh_dsize); 893 nvh->nvh_type &= ~NV_ORDER_MASK; 894 nvh->nvh_type |= NV_ORDER_NETWORK; 895 } 896 897 vsize = 0; 898 899 switch (nvh->nvh_type & NV_TYPE_MASK) { 900 case NV_TYPE_INT8: 901 case NV_TYPE_UINT8: 902 case NV_TYPE_INT8_ARRAY: 903 case NV_TYPE_UINT8_ARRAY: 904 break; 905 case NV_TYPE_INT16: 906 case NV_TYPE_UINT16: 907 case NV_TYPE_INT16_ARRAY: 908 case NV_TYPE_UINT16_ARRAY: 909 if (vsize == 0) 910 vsize = 2; 911 /* FALLTHROUGH */ 912 case NV_TYPE_INT32: 913 case NV_TYPE_UINT32: 914 case NV_TYPE_INT32_ARRAY: 915 case NV_TYPE_UINT32_ARRAY: 916 if (vsize == 0) 917 vsize = 4; 918 /* FALLTHROUGH */ 919 case NV_TYPE_INT64: 920 case NV_TYPE_UINT64: 921 case NV_TYPE_INT64_ARRAY: 922 case NV_TYPE_UINT64_ARRAY: 923 if (vsize == 0) 924 vsize = 8; 925 for (p = data; p < end; p += vsize) { 926 if (tohost) { 927 switch (vsize) { 928 case 2: 929 *(uint16_t *)(void *)p = 930 le16toh(*(uint16_t *)(void *)p); 931 break; 932 case 4: 933 *(uint32_t *)(void *)p = 934 le32toh(*(uint32_t *)(void *)p); 935 break; 936 case 8: 937 *(uint64_t *)(void *)p = 938 le64toh(*(uint64_t *)(void *)p); 939 break; 940 default: 941 PJDLOG_ABORT("invalid condition"); 942 } 943 } else { 944 switch (vsize) { 945 case 2: 946 *(uint16_t *)(void *)p = 947 htole16(*(uint16_t *)(void *)p); 948 break; 949 case 4: 950 *(uint32_t *)(void *)p = 951 htole32(*(uint32_t *)(void *)p); 952 break; 953 case 8: 954 *(uint64_t *)(void *)p = 955 htole64(*(uint64_t *)(void *)p); 956 break; 957 default: 958 PJDLOG_ABORT("invalid condition"); 959 } 960 } 961 } 962 break; 963 case NV_TYPE_STRING: 964 break; 965 default: 966 PJDLOG_ABORT("unrecognized type"); 967 } 968 } 969