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