1 /*- 2 * Copyright 2020 Toomas Soome <tsoome@me.com> 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 #include <sys/param.h> 27 #include <sys/endian.h> 28 #include <sys/stdint.h> 29 #ifdef _STANDALONE 30 #include <stand.h> 31 #else 32 #include <errno.h> 33 #include <stdbool.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #endif 38 39 #include "nvlist.h" 40 41 enum xdr_op { 42 XDR_OP_ENCODE = 1, 43 XDR_OP_DECODE = 2 44 }; 45 46 typedef struct xdr { 47 enum xdr_op xdr_op; 48 int (*xdr_getint)(struct xdr *, int *); 49 int (*xdr_putint)(struct xdr *, int); 50 int (*xdr_getuint)(struct xdr *, unsigned *); 51 int (*xdr_putuint)(struct xdr *, unsigned); 52 const uint8_t *xdr_buf; 53 uint8_t *xdr_idx; 54 size_t xdr_buf_size; 55 } xdr_t; 56 57 static int nvlist_xdr_nvlist(xdr_t *, nvlist_t *); 58 static bool nvlist_size_xdr(xdr_t *, size_t *); 59 static bool nvlist_size_native(xdr_t *, size_t *); 60 static bool xdr_int(xdr_t *, int *); 61 static bool xdr_u_int(xdr_t *, unsigned *); 62 63 typedef bool (*xdrproc_t)(xdr_t *, void *); 64 65 /* Basic primitives for XDR translation operations, getint and putint. */ 66 static int 67 _getint(struct xdr *xdr, int *ip) 68 { 69 *ip = be32dec(xdr->xdr_idx); 70 return (sizeof(int)); 71 } 72 73 static int 74 _putint(struct xdr *xdr, int i) 75 { 76 int *ip = (int *)xdr->xdr_idx; 77 78 *ip = htobe32(i); 79 return (sizeof(int)); 80 } 81 82 static int 83 _getuint(struct xdr *xdr, unsigned *ip) 84 { 85 *ip = be32dec(xdr->xdr_idx); 86 return (sizeof(unsigned)); 87 } 88 89 static int 90 _putuint(struct xdr *xdr, unsigned i) 91 { 92 unsigned *up = (unsigned *)xdr->xdr_idx; 93 94 *up = htobe32(i); 95 return (sizeof(int)); 96 } 97 98 static int 99 _getint_mem(struct xdr *xdr, int *ip) 100 { 101 *ip = *(int *)xdr->xdr_idx; 102 return (sizeof(int)); 103 } 104 105 static int 106 _putint_mem(struct xdr *xdr, int i) 107 { 108 int *ip = (int *)xdr->xdr_idx; 109 110 *ip = i; 111 return (sizeof(int)); 112 } 113 114 static int 115 _getuint_mem(struct xdr *xdr, unsigned *ip) 116 { 117 *ip = *(unsigned *)xdr->xdr_idx; 118 return (sizeof(unsigned)); 119 } 120 121 static int 122 _putuint_mem(struct xdr *xdr, unsigned i) 123 { 124 unsigned *up = (unsigned *)xdr->xdr_idx; 125 126 *up = i; 127 return (sizeof(int)); 128 } 129 130 /* 131 * XDR data translations. 132 */ 133 static bool 134 xdr_short(xdr_t *xdr, short *ip) 135 { 136 int i; 137 bool rv; 138 139 i = *ip; 140 if ((rv = xdr_int(xdr, &i))) { 141 if (xdr->xdr_op == XDR_OP_DECODE) 142 *ip = i; 143 } 144 return (rv); 145 } 146 147 static bool 148 xdr_u_short(xdr_t *xdr, unsigned short *ip) 149 { 150 unsigned u; 151 bool rv; 152 153 u = *ip; 154 if ((rv = xdr_u_int(xdr, &u))) { 155 if (xdr->xdr_op == XDR_OP_DECODE) 156 *ip = u; 157 } 158 return (rv); 159 } 160 161 /* 162 * translate xdr->xdr_idx, increment it by size of int. 163 */ 164 static bool 165 xdr_int(xdr_t *xdr, int *ip) 166 { 167 bool rv = false; 168 int *i = (int *)xdr->xdr_idx; 169 170 if (xdr->xdr_idx + sizeof(int) > xdr->xdr_buf + xdr->xdr_buf_size) 171 return (rv); 172 173 switch (xdr->xdr_op) { 174 case XDR_OP_ENCODE: 175 /* Encode value *ip, store to buf */ 176 xdr->xdr_idx += xdr->xdr_putint(xdr, *ip); 177 rv = true; 178 break; 179 180 case XDR_OP_DECODE: 181 /* Decode buf, return value to *ip */ 182 xdr->xdr_idx += xdr->xdr_getint(xdr, i); 183 *ip = *i; 184 rv = true; 185 break; 186 } 187 return (rv); 188 } 189 190 /* 191 * translate xdr->xdr_idx, increment it by size of unsigned int. 192 */ 193 static bool 194 xdr_u_int(xdr_t *xdr, unsigned *ip) 195 { 196 bool rv = false; 197 unsigned *u = (unsigned *)xdr->xdr_idx; 198 199 if (xdr->xdr_idx + sizeof(unsigned) > xdr->xdr_buf + xdr->xdr_buf_size) 200 return (rv); 201 202 switch (xdr->xdr_op) { 203 case XDR_OP_ENCODE: 204 /* Encode value *ip, store to buf */ 205 xdr->xdr_idx += xdr->xdr_putuint(xdr, *ip); 206 rv = true; 207 break; 208 209 case XDR_OP_DECODE: 210 /* Decode buf, return value to *ip */ 211 xdr->xdr_idx += xdr->xdr_getuint(xdr, u); 212 *ip = *u; 213 rv = true; 214 break; 215 } 216 return (rv); 217 } 218 219 static bool 220 xdr_int64(xdr_t *xdr, int64_t *lp) 221 { 222 bool rv = false; 223 224 if (xdr->xdr_idx + sizeof(int64_t) > xdr->xdr_buf + xdr->xdr_buf_size) 225 return (rv); 226 227 switch (xdr->xdr_op) { 228 case XDR_OP_ENCODE: 229 /* Encode value *lp, store to buf */ 230 if (xdr->xdr_putint == _putint) 231 *(int64_t *)xdr->xdr_idx = htobe64(*lp); 232 else 233 *(int64_t *)xdr->xdr_idx = *lp; 234 xdr->xdr_idx += sizeof(int64_t); 235 rv = true; 236 break; 237 238 case XDR_OP_DECODE: 239 /* Decode buf, return value to *ip */ 240 if (xdr->xdr_getint == _getint) 241 *lp = be64toh(*(int64_t *)xdr->xdr_idx); 242 else 243 *lp = *(int64_t *)xdr->xdr_idx; 244 xdr->xdr_idx += sizeof(int64_t); 245 rv = true; 246 } 247 return (rv); 248 } 249 250 static bool 251 xdr_uint64(xdr_t *xdr, uint64_t *lp) 252 { 253 bool rv = false; 254 255 if (xdr->xdr_idx + sizeof(uint64_t) > xdr->xdr_buf + xdr->xdr_buf_size) 256 return (rv); 257 258 switch (xdr->xdr_op) { 259 case XDR_OP_ENCODE: 260 /* Encode value *ip, store to buf */ 261 if (xdr->xdr_putint == _putint) 262 *(uint64_t *)xdr->xdr_idx = htobe64(*lp); 263 else 264 *(uint64_t *)xdr->xdr_idx = *lp; 265 xdr->xdr_idx += sizeof(uint64_t); 266 rv = true; 267 break; 268 269 case XDR_OP_DECODE: 270 /* Decode buf, return value to *ip */ 271 if (xdr->xdr_getuint == _getuint) 272 *lp = be64toh(*(uint64_t *)xdr->xdr_idx); 273 else 274 *lp = *(uint64_t *)xdr->xdr_idx; 275 xdr->xdr_idx += sizeof(uint64_t); 276 rv = true; 277 } 278 return (rv); 279 } 280 281 static bool 282 xdr_char(xdr_t *xdr, char *cp) 283 { 284 int i; 285 bool rv = false; 286 287 i = *cp; 288 if ((rv = xdr_int(xdr, &i))) { 289 if (xdr->xdr_op == XDR_OP_DECODE) 290 *cp = i; 291 } 292 return (rv); 293 } 294 295 static bool 296 xdr_string(xdr_t *xdr, nv_string_t *s) 297 { 298 int size = 0; 299 bool rv = false; 300 301 switch (xdr->xdr_op) { 302 case XDR_OP_ENCODE: 303 size = s->nv_size; 304 if (xdr->xdr_idx + sizeof(unsigned) + NV_ALIGN4(size) > 305 xdr->xdr_buf + xdr->xdr_buf_size) 306 break; 307 xdr->xdr_idx += xdr->xdr_putuint(xdr, s->nv_size); 308 xdr->xdr_idx += NV_ALIGN4(size); 309 rv = true; 310 break; 311 312 case XDR_OP_DECODE: 313 if (xdr->xdr_idx + sizeof(unsigned) > 314 xdr->xdr_buf + xdr->xdr_buf_size) 315 break; 316 size = xdr->xdr_getuint(xdr, &s->nv_size); 317 size = NV_ALIGN4(size + s->nv_size); 318 if (xdr->xdr_idx + size > xdr->xdr_buf + xdr->xdr_buf_size) 319 break; 320 xdr->xdr_idx += size; 321 rv = true; 322 break; 323 } 324 return (rv); 325 } 326 327 static bool 328 xdr_array(xdr_t *xdr, const unsigned nelem, const xdrproc_t elproc) 329 { 330 bool rv = true; 331 unsigned c = nelem; 332 333 if (!xdr_u_int(xdr, &c)) 334 return (false); 335 336 for (unsigned i = 0; i < nelem; i++) { 337 if (!elproc(xdr, xdr->xdr_idx)) 338 return (false); 339 } 340 return (rv); 341 } 342 343 /* 344 * nvlist management functions. 345 */ 346 void 347 nvlist_destroy(nvlist_t *nvl) 348 { 349 if (nvl != NULL) { 350 /* Free data if it was allocated by us. */ 351 if (nvl->nv_asize > 0) 352 free(nvl->nv_data); 353 } 354 free(nvl); 355 } 356 357 char * 358 nvstring_get(nv_string_t *nvs) 359 { 360 char *s; 361 362 s = malloc(nvs->nv_size + 1); 363 if (s != NULL) { 364 bcopy(nvs->nv_data, s, nvs->nv_size); 365 s[nvs->nv_size] = '\0'; 366 } 367 return (s); 368 } 369 370 /* 371 * Create empty nvlist. 372 * The nvlist is terminated by 2x zeros (8 bytes). 373 */ 374 nvlist_t * 375 nvlist_create(int flag) 376 { 377 nvlist_t *nvl; 378 nvs_data_t *nvs; 379 380 nvl = calloc(1, sizeof(*nvl)); 381 if (nvl == NULL) 382 return (nvl); 383 384 nvl->nv_header.nvh_encoding = NV_ENCODE_XDR; 385 nvl->nv_header.nvh_endian = _BYTE_ORDER == _LITTLE_ENDIAN; 386 387 nvl->nv_asize = nvl->nv_size = sizeof(*nvs); 388 nvs = calloc(1, nvl->nv_asize); 389 if (nvs == NULL) { 390 free(nvl); 391 return (NULL); 392 } 393 /* data in nvlist is byte stream */ 394 nvl->nv_data = (uint8_t *)nvs; 395 396 nvs->nvl_version = NV_VERSION; 397 nvs->nvl_nvflag = flag; 398 return (nvl); 399 } 400 401 static bool 402 nvlist_xdr_nvp(xdr_t *xdr, nvlist_t *nvl) 403 { 404 nv_string_t *nv_string; 405 nv_pair_data_t *nvp_data; 406 nvlist_t nvlist; 407 unsigned type, nelem; 408 xdr_t nv_xdr; 409 410 nv_string = (nv_string_t *)xdr->xdr_idx; 411 if (!xdr_string(xdr, nv_string)) { 412 return (false); 413 } 414 nvp_data = (nv_pair_data_t *)xdr->xdr_idx; 415 416 type = nvp_data->nv_type; 417 nelem = nvp_data->nv_nelem; 418 if (!xdr_u_int(xdr, &type) || !xdr_u_int(xdr, &nelem)) 419 return (false); 420 421 switch (type) { 422 case DATA_TYPE_NVLIST: 423 case DATA_TYPE_NVLIST_ARRAY: 424 bzero(&nvlist, sizeof(nvlist)); 425 nvlist.nv_data = xdr->xdr_idx; 426 nvlist.nv_idx = nvlist.nv_data; 427 428 /* Set up xdr for this nvlist. */ 429 nv_xdr = *xdr; 430 nv_xdr.xdr_buf = nvlist.nv_data; 431 nv_xdr.xdr_idx = nvlist.nv_data; 432 nv_xdr.xdr_buf_size = 433 nvl->nv_data + nvl->nv_size - nvlist.nv_data; 434 435 for (unsigned i = 0; i < nelem; i++) { 436 if (xdr->xdr_op == XDR_OP_ENCODE) { 437 if (!nvlist_size_native(&nv_xdr, 438 &nvlist.nv_size)) 439 return (false); 440 } else { 441 if (!nvlist_size_xdr(&nv_xdr, 442 &nvlist.nv_size)) 443 return (false); 444 } 445 if (nvlist_xdr_nvlist(xdr, &nvlist) != 0) 446 return (false); 447 448 nvlist.nv_data = nv_xdr.xdr_idx; 449 nvlist.nv_idx = nv_xdr.xdr_idx; 450 451 nv_xdr.xdr_buf = nv_xdr.xdr_idx; 452 nv_xdr.xdr_buf_size = 453 nvl->nv_data + nvl->nv_size - nvlist.nv_data; 454 } 455 break; 456 457 case DATA_TYPE_BOOLEAN: 458 /* BOOLEAN does not take value space */ 459 break; 460 case DATA_TYPE_BYTE: 461 case DATA_TYPE_INT8: 462 case DATA_TYPE_UINT8: 463 if (!xdr_char(xdr, (char *)&nvp_data->nv_data[0])) 464 return (false); 465 break; 466 467 case DATA_TYPE_INT16: 468 if (!xdr_short(xdr, (short *)&nvp_data->nv_data[0])) 469 return (false); 470 break; 471 472 case DATA_TYPE_UINT16: 473 if (!xdr_u_short(xdr, (unsigned short *)&nvp_data->nv_data[0])) 474 return (false); 475 break; 476 477 case DATA_TYPE_BOOLEAN_VALUE: 478 case DATA_TYPE_INT32: 479 if (!xdr_int(xdr, (int *)&nvp_data->nv_data[0])) 480 return (false); 481 break; 482 483 case DATA_TYPE_UINT32: 484 if (!xdr_u_int(xdr, (unsigned *)&nvp_data->nv_data[0])) 485 return (false); 486 break; 487 488 case DATA_TYPE_HRTIME: 489 case DATA_TYPE_INT64: 490 if (!xdr_int64(xdr, (int64_t *)&nvp_data->nv_data[0])) 491 return (false); 492 break; 493 494 case DATA_TYPE_UINT64: 495 if (!xdr_uint64(xdr, (uint64_t *)&nvp_data->nv_data[0])) 496 return (false); 497 break; 498 499 case DATA_TYPE_BYTE_ARRAY: 500 case DATA_TYPE_STRING: 501 nv_string = (nv_string_t *)&nvp_data->nv_data[0]; 502 if (!xdr_string(xdr, nv_string)) 503 return (false); 504 break; 505 506 case DATA_TYPE_STRING_ARRAY: 507 nv_string = (nv_string_t *)&nvp_data->nv_data[0]; 508 for (unsigned i = 0; i < nelem; i++) { 509 if (!xdr_string(xdr, nv_string)) 510 return (false); 511 nv_string = (nv_string_t *)xdr->xdr_idx; 512 } 513 break; 514 515 case DATA_TYPE_INT8_ARRAY: 516 case DATA_TYPE_UINT8_ARRAY: 517 case DATA_TYPE_INT16_ARRAY: 518 case DATA_TYPE_UINT16_ARRAY: 519 case DATA_TYPE_BOOLEAN_ARRAY: 520 case DATA_TYPE_INT32_ARRAY: 521 case DATA_TYPE_UINT32_ARRAY: 522 if (!xdr_array(xdr, nelem, (xdrproc_t)xdr_u_int)) 523 return (false); 524 break; 525 526 case DATA_TYPE_INT64_ARRAY: 527 case DATA_TYPE_UINT64_ARRAY: 528 if (!xdr_array(xdr, nelem, (xdrproc_t)xdr_uint64)) 529 return (false); 530 break; 531 } 532 return (true); 533 } 534 535 static int 536 nvlist_xdr_nvlist(xdr_t *xdr, nvlist_t *nvl) 537 { 538 nvp_header_t *nvph; 539 nvs_data_t *nvs; 540 unsigned encoded_size, decoded_size; 541 int rv; 542 543 nvs = (nvs_data_t *)xdr->xdr_idx; 544 nvph = &nvs->nvl_pair; 545 546 if (!xdr_u_int(xdr, &nvs->nvl_version)) 547 return (EINVAL); 548 if (!xdr_u_int(xdr, &nvs->nvl_nvflag)) 549 return (EINVAL); 550 551 encoded_size = nvph->encoded_size; 552 decoded_size = nvph->decoded_size; 553 554 if (xdr->xdr_op == XDR_OP_ENCODE) { 555 if (!xdr_u_int(xdr, &nvph->encoded_size)) 556 return (EINVAL); 557 if (!xdr_u_int(xdr, &nvph->decoded_size)) 558 return (EINVAL); 559 } else { 560 xdr->xdr_idx += 2 * sizeof(unsigned); 561 } 562 563 rv = 0; 564 while (encoded_size && decoded_size) { 565 if (!nvlist_xdr_nvp(xdr, nvl)) 566 return (EINVAL); 567 568 nvph = (nvp_header_t *)(xdr->xdr_idx); 569 encoded_size = nvph->encoded_size; 570 decoded_size = nvph->decoded_size; 571 if (xdr->xdr_op == XDR_OP_ENCODE) { 572 if (!xdr_u_int(xdr, &nvph->encoded_size)) 573 return (EINVAL); 574 if (!xdr_u_int(xdr, &nvph->decoded_size)) 575 return (EINVAL); 576 } else { 577 xdr->xdr_idx += 2 * sizeof(unsigned); 578 } 579 } 580 return (rv); 581 } 582 583 /* 584 * Calculate nvlist size, translating encoded_size and decoded_size. 585 */ 586 static bool 587 nvlist_size_xdr(xdr_t *xdr, size_t *size) 588 { 589 uint8_t *pair; 590 unsigned encoded_size, decoded_size; 591 592 xdr->xdr_idx += 2 * sizeof(unsigned); 593 594 pair = xdr->xdr_idx; 595 if (!xdr_u_int(xdr, &encoded_size) || !xdr_u_int(xdr, &decoded_size)) 596 return (false); 597 598 while (encoded_size && decoded_size) { 599 xdr->xdr_idx = pair + encoded_size; 600 pair = xdr->xdr_idx; 601 if (!xdr_u_int(xdr, &encoded_size) || 602 !xdr_u_int(xdr, &decoded_size)) 603 return (false); 604 } 605 *size = xdr->xdr_idx - xdr->xdr_buf; 606 607 return (true); 608 } 609 610 nvp_header_t * 611 nvlist_next_nvpair(nvlist_t *nvl, nvp_header_t *nvh) 612 { 613 uint8_t *pair; 614 unsigned encoded_size, decoded_size; 615 xdr_t xdr; 616 617 if (nvl == NULL) 618 return (NULL); 619 620 xdr.xdr_buf = nvl->nv_data; 621 xdr.xdr_idx = nvl->nv_data; 622 xdr.xdr_buf_size = nvl->nv_size; 623 624 xdr.xdr_idx += 2 * sizeof(unsigned); 625 626 /* Skip tp current pair */ 627 if (nvh != NULL) { 628 xdr.xdr_idx = (uint8_t *)nvh; 629 } 630 631 pair = xdr.xdr_idx; 632 if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size) 633 return (NULL); 634 635 encoded_size = *(unsigned *)xdr.xdr_idx; 636 xdr.xdr_idx += sizeof(unsigned); 637 if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size) 638 return (NULL); 639 640 decoded_size = *(unsigned *)xdr.xdr_idx; 641 xdr.xdr_idx += sizeof(unsigned); 642 if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size) 643 return (NULL); 644 645 while (encoded_size && decoded_size) { 646 if (nvh == NULL) 647 return ((nvp_header_t *)pair); 648 649 xdr.xdr_idx = pair + encoded_size; 650 nvh = (nvp_header_t *)xdr.xdr_idx; 651 652 if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size) 653 return (NULL); 654 655 encoded_size = *(unsigned *)xdr.xdr_idx; 656 xdr.xdr_idx += sizeof(unsigned); 657 if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size) 658 return (NULL); 659 decoded_size = *(unsigned *)xdr.xdr_idx; 660 xdr.xdr_idx += sizeof(unsigned); 661 if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size) 662 return (NULL); 663 664 if (encoded_size != 0 && decoded_size != 0) { 665 return (nvh); 666 } 667 } 668 return (NULL); 669 } 670 671 /* 672 * Calculate nvlist size by walking in memory data. 673 */ 674 static bool 675 nvlist_size_native(xdr_t *xdr, size_t *size) 676 { 677 uint8_t *pair; 678 unsigned encoded_size, decoded_size; 679 680 xdr->xdr_idx += 2 * sizeof(unsigned); 681 682 pair = xdr->xdr_idx; 683 if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size) 684 return (false); 685 686 encoded_size = *(unsigned *)xdr->xdr_idx; 687 xdr->xdr_idx += sizeof(unsigned); 688 if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size) 689 return (false); 690 decoded_size = *(unsigned *)xdr->xdr_idx; 691 xdr->xdr_idx += sizeof(unsigned); 692 while (encoded_size && decoded_size) { 693 xdr->xdr_idx = pair + encoded_size; 694 pair = xdr->xdr_idx; 695 if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size) 696 return (false); 697 encoded_size = *(unsigned *)xdr->xdr_idx; 698 xdr->xdr_idx += sizeof(unsigned); 699 if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size) 700 return (false); 701 decoded_size = *(unsigned *)xdr->xdr_idx; 702 xdr->xdr_idx += sizeof(unsigned); 703 } 704 *size = xdr->xdr_idx - xdr->xdr_buf; 705 706 return (true); 707 } 708 709 /* 710 * Export nvlist to byte stream format. 711 */ 712 int 713 nvlist_export(nvlist_t *nvl) 714 { 715 int rv; 716 xdr_t xdr = { 717 .xdr_op = XDR_OP_ENCODE, 718 .xdr_putint = _putint, 719 .xdr_putuint = _putuint, 720 .xdr_buf = nvl->nv_data, 721 .xdr_idx = nvl->nv_data, 722 .xdr_buf_size = nvl->nv_size 723 }; 724 725 if (nvl->nv_header.nvh_encoding != NV_ENCODE_XDR) 726 return (ENOTSUP); 727 728 nvl->nv_idx = nvl->nv_data; 729 rv = nvlist_xdr_nvlist(&xdr, nvl); 730 731 return (rv); 732 } 733 734 /* 735 * Import nvlist from byte stream. 736 * Determine the stream size and allocate private copy. 737 * Then translate the data. 738 */ 739 nvlist_t * 740 nvlist_import(const char *stream, size_t size) 741 { 742 nvlist_t *nvl; 743 xdr_t xdr = { 744 .xdr_op = XDR_OP_DECODE, 745 .xdr_getint = _getint, 746 .xdr_getuint = _getuint 747 }; 748 749 /* Check the nvlist head. */ 750 if (stream[0] != NV_ENCODE_XDR || 751 (stream[1] != '\0' && stream[1] != '\1') || 752 stream[2] != '\0' || stream[3] != '\0' || 753 be32toh(*(uint32_t *)(stream + 4)) != NV_VERSION || 754 be32toh(*(uint32_t *)(stream + 8)) != NV_UNIQUE_NAME) 755 return (NULL); 756 757 nvl = malloc(sizeof(*nvl)); 758 if (nvl == NULL) 759 return (nvl); 760 761 nvl->nv_header.nvh_encoding = stream[0]; 762 nvl->nv_header.nvh_endian = stream[1]; 763 nvl->nv_header.nvh_reserved1 = stream[2]; 764 nvl->nv_header.nvh_reserved2 = stream[3]; 765 766 xdr.xdr_buf = xdr.xdr_idx = (uint8_t *)stream + 4; 767 xdr.xdr_buf_size = size - 4; 768 769 if (!nvlist_size_xdr(&xdr, &nvl->nv_asize)) { 770 free(nvl); 771 return (NULL); 772 } 773 nvl->nv_size = nvl->nv_asize; 774 nvl->nv_data = malloc(nvl->nv_asize); 775 if (nvl->nv_data == NULL) { 776 free(nvl); 777 return (NULL); 778 } 779 nvl->nv_idx = nvl->nv_data; 780 bcopy(stream + 4, nvl->nv_data, nvl->nv_asize); 781 782 xdr.xdr_buf = xdr.xdr_idx = nvl->nv_data; 783 xdr.xdr_buf_size = nvl->nv_asize; 784 785 if (nvlist_xdr_nvlist(&xdr, nvl) != 0) { 786 free(nvl->nv_data); 787 free(nvl); 788 nvl = NULL; 789 } 790 791 return (nvl); 792 } 793 794 /* 795 * remove pair from this nvlist. 796 */ 797 int 798 nvlist_remove(nvlist_t *nvl, const char *name, data_type_t type) 799 { 800 uint8_t *head, *tail; 801 nvs_data_t *data; 802 nvp_header_t *nvp; 803 nv_string_t *nvp_name; 804 nv_pair_data_t *nvp_data; 805 size_t size; 806 xdr_t xdr; 807 808 if (nvl == NULL || nvl->nv_data == NULL || name == NULL) 809 return (EINVAL); 810 811 /* Make sure the nvlist size is set correct */ 812 xdr.xdr_idx = nvl->nv_data; 813 xdr.xdr_buf = xdr.xdr_idx; 814 xdr.xdr_buf_size = nvl->nv_size; 815 if (!nvlist_size_native(&xdr, &nvl->nv_size)) 816 return (EINVAL); 817 818 data = (nvs_data_t *)nvl->nv_data; 819 nvp = &data->nvl_pair; /* first pair in nvlist */ 820 head = (uint8_t *)nvp; 821 822 while (nvp->encoded_size != 0 && nvp->decoded_size != 0) { 823 nvp_name = (nv_string_t *)(nvp + 1); 824 825 nvp_data = (nv_pair_data_t *)(&nvp_name->nv_data[0] + 826 NV_ALIGN4(nvp_name->nv_size)); 827 828 if (strlen(name) == nvp_name->nv_size && 829 memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0 && 830 (nvp_data->nv_type == type || type == DATA_TYPE_UNKNOWN)) { 831 /* 832 * set tail to point to next nvpair and size 833 * is the length of the tail. 834 */ 835 tail = head + nvp->encoded_size; 836 size = nvl->nv_size - (tail - nvl->nv_data); 837 838 /* adjust the size of the nvlist. */ 839 nvl->nv_size -= nvp->encoded_size; 840 bcopy(tail, head, size); 841 return (0); 842 } 843 /* Not our pair, skip to next. */ 844 head = head + nvp->encoded_size; 845 nvp = (nvp_header_t *)head; 846 } 847 return (ENOENT); 848 } 849 850 static int 851 clone_nvlist(const nvlist_t *nvl, const uint8_t *ptr, unsigned size, 852 nvlist_t **nvlist) 853 { 854 nvlist_t *nv; 855 856 nv = calloc(1, sizeof(*nv)); 857 if (nv == NULL) 858 return (ENOMEM); 859 860 nv->nv_header = nvl->nv_header; 861 nv->nv_asize = size; 862 nv->nv_size = size; 863 nv->nv_data = malloc(nv->nv_asize); 864 if (nv->nv_data == NULL) { 865 free(nv); 866 return (ENOMEM); 867 } 868 869 bcopy(ptr, nv->nv_data, nv->nv_asize); 870 *nvlist = nv; 871 return (0); 872 } 873 874 /* 875 * Return the next nvlist in an nvlist array. 876 */ 877 static uint8_t * 878 nvlist_next(const uint8_t *ptr) 879 { 880 nvs_data_t *data; 881 nvp_header_t *nvp; 882 883 data = (nvs_data_t *)ptr; 884 nvp = &data->nvl_pair; /* first pair in nvlist */ 885 886 while (nvp->encoded_size != 0 && nvp->decoded_size != 0) { 887 nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size); 888 } 889 return ((uint8_t *)nvp + sizeof(*nvp)); 890 } 891 892 /* 893 * Note: nvlist and nvlist array must be freed by caller. 894 */ 895 int 896 nvlist_find(const nvlist_t *nvl, const char *name, data_type_t type, 897 int *elementsp, void *valuep, int *sizep) 898 { 899 nvs_data_t *data; 900 nvp_header_t *nvp; 901 nv_string_t *nvp_name; 902 nv_pair_data_t *nvp_data; 903 nvlist_t **nvlist, *nv; 904 uint8_t *ptr; 905 int rv; 906 907 if (nvl == NULL || nvl->nv_data == NULL || name == NULL) 908 return (EINVAL); 909 910 data = (nvs_data_t *)nvl->nv_data; 911 nvp = &data->nvl_pair; /* first pair in nvlist */ 912 913 while (nvp->encoded_size != 0 && nvp->decoded_size != 0) { 914 nvp_name = (nv_string_t *)((uint8_t *)nvp + sizeof(*nvp)); 915 if (nvl->nv_data + nvl->nv_size < 916 nvp_name->nv_data + nvp_name->nv_size) 917 return (EIO); 918 919 nvp_data = (nv_pair_data_t *) 920 NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] + 921 nvp_name->nv_size); 922 923 if (strlen(name) == nvp_name->nv_size && 924 memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0 && 925 (nvp_data->nv_type == type || type == DATA_TYPE_UNKNOWN)) { 926 if (elementsp != NULL) 927 *elementsp = nvp_data->nv_nelem; 928 switch (nvp_data->nv_type) { 929 case DATA_TYPE_UINT64: 930 bcopy(nvp_data->nv_data, valuep, 931 sizeof(uint64_t)); 932 return (0); 933 case DATA_TYPE_STRING: 934 nvp_name = (nv_string_t *)nvp_data->nv_data; 935 if (sizep != NULL) { 936 *sizep = nvp_name->nv_size; 937 } 938 *(const uint8_t **)valuep = 939 &nvp_name->nv_data[0]; 940 return (0); 941 case DATA_TYPE_NVLIST: 942 ptr = &nvp_data->nv_data[0]; 943 rv = clone_nvlist(nvl, ptr, 944 nvlist_next(ptr) - ptr, &nv); 945 if (rv == 0) { 946 *(nvlist_t **)valuep = nv; 947 } 948 return (rv); 949 950 case DATA_TYPE_NVLIST_ARRAY: 951 nvlist = calloc(nvp_data->nv_nelem, 952 sizeof(nvlist_t *)); 953 if (nvlist == NULL) 954 return (ENOMEM); 955 ptr = &nvp_data->nv_data[0]; 956 rv = 0; 957 for (unsigned i = 0; i < nvp_data->nv_nelem; 958 i++) { 959 rv = clone_nvlist(nvl, ptr, 960 nvlist_next(ptr) - ptr, &nvlist[i]); 961 if (rv != 0) 962 goto error; 963 ptr = nvlist_next(ptr); 964 } 965 *(nvlist_t ***)valuep = nvlist; 966 return (rv); 967 } 968 return (EIO); 969 } 970 /* Not our pair, skip to next. */ 971 nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size); 972 if (nvl->nv_data + nvl->nv_size < (uint8_t *)nvp) 973 return (EIO); 974 } 975 return (ENOENT); 976 error: 977 for (unsigned i = 0; i < nvp_data->nv_nelem; i++) { 978 free(nvlist[i]->nv_data); 979 free(nvlist[i]); 980 } 981 free(nvlist); 982 return (rv); 983 } 984 985 static int 986 get_value_size(data_type_t type, const void *data, uint32_t nelem) 987 { 988 uint64_t value_sz = 0; 989 990 switch (type) { 991 case DATA_TYPE_BOOLEAN: 992 value_sz = 0; 993 break; 994 case DATA_TYPE_BOOLEAN_VALUE: 995 case DATA_TYPE_BYTE: 996 case DATA_TYPE_INT8: 997 case DATA_TYPE_UINT8: 998 case DATA_TYPE_INT16: 999 case DATA_TYPE_UINT16: 1000 case DATA_TYPE_INT32: 1001 case DATA_TYPE_UINT32: 1002 /* Our smallest data unit is 32-bit */ 1003 value_sz = sizeof(uint32_t); 1004 break; 1005 case DATA_TYPE_HRTIME: 1006 case DATA_TYPE_INT64: 1007 value_sz = sizeof(int64_t); 1008 break; 1009 case DATA_TYPE_UINT64: 1010 value_sz = sizeof(uint64_t); 1011 break; 1012 case DATA_TYPE_STRING: 1013 if (data == NULL) 1014 value_sz = 0; 1015 else 1016 value_sz = strlen(data) + 1; 1017 break; 1018 case DATA_TYPE_BYTE_ARRAY: 1019 value_sz = nelem * sizeof(uint8_t); 1020 break; 1021 case DATA_TYPE_BOOLEAN_ARRAY: 1022 case DATA_TYPE_INT8_ARRAY: 1023 case DATA_TYPE_UINT8_ARRAY: 1024 case DATA_TYPE_INT16_ARRAY: 1025 case DATA_TYPE_UINT16_ARRAY: 1026 case DATA_TYPE_INT32_ARRAY: 1027 case DATA_TYPE_UINT32_ARRAY: 1028 value_sz = (uint64_t)nelem * sizeof(uint32_t); 1029 break; 1030 case DATA_TYPE_INT64_ARRAY: 1031 value_sz = (uint64_t)nelem * sizeof(int64_t); 1032 break; 1033 case DATA_TYPE_UINT64_ARRAY: 1034 value_sz = (uint64_t)nelem * sizeof(uint64_t); 1035 break; 1036 case DATA_TYPE_STRING_ARRAY: 1037 value_sz = (uint64_t)nelem * sizeof(uint64_t); 1038 1039 if (data != NULL) { 1040 char *const *strs = data; 1041 uint32_t i; 1042 1043 for (i = 0; i < nelem; i++) { 1044 if (strs[i] == NULL) 1045 return (-1); 1046 value_sz += strlen(strs[i]) + 1; 1047 } 1048 } 1049 break; 1050 case DATA_TYPE_NVLIST: 1051 /* 1052 * The decoded size of nvlist is constant. 1053 */ 1054 value_sz = NV_ALIGN(6 * 4); /* sizeof nvlist_t */ 1055 break; 1056 case DATA_TYPE_NVLIST_ARRAY: 1057 value_sz = (uint64_t)nelem * sizeof(uint64_t) + 1058 (uint64_t)nelem * NV_ALIGN(6 * 4); /* sizeof nvlist_t */ 1059 break; 1060 default: 1061 return (-1); 1062 } 1063 1064 return (value_sz > INT32_MAX ? -1 : (int)value_sz); 1065 } 1066 1067 static int 1068 get_nvp_data_size(data_type_t type, const void *data, uint32_t nelem) 1069 { 1070 uint64_t value_sz = 0; 1071 xdr_t xdr; 1072 size_t size; 1073 1074 switch (type) { 1075 case DATA_TYPE_BOOLEAN: 1076 value_sz = 0; 1077 break; 1078 case DATA_TYPE_BOOLEAN_VALUE: 1079 case DATA_TYPE_BYTE: 1080 case DATA_TYPE_INT8: 1081 case DATA_TYPE_UINT8: 1082 case DATA_TYPE_INT16: 1083 case DATA_TYPE_UINT16: 1084 case DATA_TYPE_INT32: 1085 case DATA_TYPE_UINT32: 1086 /* Our smallest data unit is 32-bit */ 1087 value_sz = sizeof(uint32_t); 1088 break; 1089 case DATA_TYPE_HRTIME: 1090 case DATA_TYPE_INT64: 1091 case DATA_TYPE_UINT64: 1092 value_sz = sizeof(uint64_t); 1093 break; 1094 case DATA_TYPE_STRING: 1095 value_sz = 4 + NV_ALIGN4(strlen(data)); 1096 break; 1097 case DATA_TYPE_BYTE_ARRAY: 1098 value_sz = NV_ALIGN4(nelem); 1099 break; 1100 case DATA_TYPE_BOOLEAN_ARRAY: 1101 case DATA_TYPE_INT8_ARRAY: 1102 case DATA_TYPE_UINT8_ARRAY: 1103 case DATA_TYPE_INT16_ARRAY: 1104 case DATA_TYPE_UINT16_ARRAY: 1105 case DATA_TYPE_INT32_ARRAY: 1106 case DATA_TYPE_UINT32_ARRAY: 1107 value_sz = 4 + (uint64_t)nelem * sizeof(uint32_t); 1108 break; 1109 case DATA_TYPE_INT64_ARRAY: 1110 case DATA_TYPE_UINT64_ARRAY: 1111 value_sz = 4 + (uint64_t)nelem * sizeof(uint64_t); 1112 break; 1113 case DATA_TYPE_STRING_ARRAY: 1114 if (data != NULL) { 1115 char *const *strs = data; 1116 uint32_t i; 1117 1118 for (i = 0; i < nelem; i++) { 1119 value_sz += 4 + NV_ALIGN4(strlen(strs[i])); 1120 } 1121 } 1122 break; 1123 case DATA_TYPE_NVLIST: 1124 xdr.xdr_idx = ((nvlist_t *)data)->nv_data; 1125 xdr.xdr_buf = xdr.xdr_idx; 1126 xdr.xdr_buf_size = ((nvlist_t *)data)->nv_size; 1127 1128 if (!nvlist_size_native(&xdr, &size)) 1129 return (-1); 1130 1131 value_sz = size; 1132 break; 1133 case DATA_TYPE_NVLIST_ARRAY: 1134 value_sz = 0; 1135 for (uint32_t i = 0; i < nelem; i++) { 1136 xdr.xdr_idx = ((nvlist_t **)data)[i]->nv_data; 1137 xdr.xdr_buf = xdr.xdr_idx; 1138 xdr.xdr_buf_size = ((nvlist_t **)data)[i]->nv_size; 1139 1140 if (!nvlist_size_native(&xdr, &size)) 1141 return (-1); 1142 value_sz += size; 1143 } 1144 break; 1145 default: 1146 return (-1); 1147 } 1148 1149 return (value_sz > INT32_MAX ? -1 : (int)value_sz); 1150 } 1151 1152 #define NVPE_SIZE(name_len, data_len) \ 1153 (4 + 4 + 4 + NV_ALIGN4(name_len) + 4 + 4 + data_len) 1154 #define NVP_SIZE(name_len, data_len) \ 1155 (NV_ALIGN((4 * 4) + (name_len)) + NV_ALIGN(data_len)) 1156 1157 static int 1158 nvlist_add_common(nvlist_t *nvl, const char *name, data_type_t type, 1159 uint32_t nelem, const void *data) 1160 { 1161 nvs_data_t *nvs; 1162 nvp_header_t head, *hp; 1163 uint8_t *ptr; 1164 size_t namelen; 1165 int decoded_size, encoded_size; 1166 xdr_t xdr = { 1167 .xdr_op = XDR_OP_ENCODE, 1168 .xdr_putint = _putint_mem, 1169 .xdr_putuint = _putuint_mem, 1170 .xdr_buf = nvl->nv_data, 1171 .xdr_idx = nvl->nv_data, 1172 .xdr_buf_size = nvl->nv_size 1173 }; 1174 1175 nvs = (nvs_data_t *)nvl->nv_data; 1176 if (nvs->nvl_nvflag & NV_UNIQUE_NAME) 1177 (void) nvlist_remove(nvl, name, type); 1178 1179 xdr.xdr_buf = nvl->nv_data; 1180 xdr.xdr_idx = nvl->nv_data; 1181 xdr.xdr_buf_size = nvl->nv_size; 1182 if (!nvlist_size_native(&xdr, &nvl->nv_size)) 1183 return (EINVAL); 1184 1185 namelen = strlen(name); 1186 if ((decoded_size = get_value_size(type, data, nelem)) < 0) 1187 return (EINVAL); 1188 if ((encoded_size = get_nvp_data_size(type, data, nelem)) < 0) 1189 return (EINVAL); 1190 1191 /* 1192 * The encoded size is calculated as: 1193 * encode_size (4) + decode_size (4) + 1194 * name string size (4 + NV_ALIGN4(namelen) + 1195 * data type (4) + nelem size (4) + datalen 1196 * 1197 * The decoded size is calculated as: 1198 * Note: namelen is with terminating 0. 1199 * NV_ALIGN(sizeof(nvpair_t) (4 * 4) + namelen + 1) + 1200 * NV_ALIGN(data_len) 1201 */ 1202 1203 head.encoded_size = NVPE_SIZE(namelen, encoded_size); 1204 head.decoded_size = NVP_SIZE(namelen + 1, decoded_size); 1205 1206 if (nvl->nv_asize - nvl->nv_size < head.encoded_size + 8) { 1207 ptr = realloc(nvl->nv_data, nvl->nv_asize + head.encoded_size); 1208 if (ptr == NULL) 1209 return (ENOMEM); 1210 nvl->nv_data = ptr; 1211 nvl->nv_asize += head.encoded_size; 1212 } 1213 nvl->nv_idx = nvl->nv_data + nvl->nv_size - sizeof(*hp); 1214 bzero(nvl->nv_idx, head.encoded_size + 8); 1215 hp = (nvp_header_t *)nvl->nv_idx; 1216 *hp = head; 1217 nvl->nv_idx += sizeof(*hp); 1218 1219 xdr.xdr_buf = nvl->nv_data; 1220 xdr.xdr_buf_size = nvl->nv_asize; 1221 xdr.xdr_idx = nvl->nv_idx; 1222 1223 xdr.xdr_idx += xdr.xdr_putuint(&xdr, namelen); 1224 strlcpy((char *)xdr.xdr_idx, name, namelen + 1); 1225 xdr.xdr_idx += NV_ALIGN4(namelen); 1226 xdr.xdr_idx += xdr.xdr_putuint(&xdr, type); 1227 xdr.xdr_idx += xdr.xdr_putuint(&xdr, nelem); 1228 1229 switch (type) { 1230 case DATA_TYPE_BOOLEAN: 1231 break; 1232 1233 case DATA_TYPE_BYTE_ARRAY: 1234 xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size); 1235 bcopy(data, xdr.xdr_idx, nelem); 1236 xdr.xdr_idx += NV_ALIGN4(encoded_size); 1237 break; 1238 1239 case DATA_TYPE_STRING: 1240 encoded_size = strlen(data); 1241 xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size); 1242 strlcpy((char *)xdr.xdr_idx, data, encoded_size + 1); 1243 xdr.xdr_idx += NV_ALIGN4(encoded_size); 1244 break; 1245 1246 case DATA_TYPE_STRING_ARRAY: 1247 for (uint32_t i = 0; i < nelem; i++) { 1248 encoded_size = strlen(((char **)data)[i]); 1249 xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size); 1250 strlcpy((char *)xdr.xdr_idx, ((char **)data)[i], 1251 encoded_size + 1); 1252 xdr.xdr_idx += NV_ALIGN4(encoded_size); 1253 } 1254 break; 1255 1256 case DATA_TYPE_BYTE: 1257 case DATA_TYPE_INT8: 1258 case DATA_TYPE_UINT8: 1259 xdr_char(&xdr, (char *)data); 1260 break; 1261 1262 case DATA_TYPE_INT8_ARRAY: 1263 case DATA_TYPE_UINT8_ARRAY: 1264 xdr_array(&xdr, nelem, (xdrproc_t)xdr_char); 1265 break; 1266 1267 case DATA_TYPE_INT16: 1268 xdr_short(&xdr, (short *)data); 1269 break; 1270 1271 case DATA_TYPE_UINT16: 1272 xdr_u_short(&xdr, (unsigned short *)data); 1273 break; 1274 1275 case DATA_TYPE_INT16_ARRAY: 1276 xdr_array(&xdr, nelem, (xdrproc_t)xdr_short); 1277 break; 1278 1279 case DATA_TYPE_UINT16_ARRAY: 1280 xdr_array(&xdr, nelem, (xdrproc_t)xdr_u_short); 1281 break; 1282 1283 case DATA_TYPE_BOOLEAN_VALUE: 1284 case DATA_TYPE_INT32: 1285 xdr_int(&xdr, (int *)data); 1286 break; 1287 1288 case DATA_TYPE_UINT32: 1289 xdr_u_int(&xdr, (unsigned int *)data); 1290 break; 1291 1292 case DATA_TYPE_BOOLEAN_ARRAY: 1293 case DATA_TYPE_INT32_ARRAY: 1294 xdr_array(&xdr, nelem, (xdrproc_t)xdr_int); 1295 break; 1296 1297 case DATA_TYPE_UINT32_ARRAY: 1298 xdr_array(&xdr, nelem, (xdrproc_t)xdr_u_int); 1299 break; 1300 1301 case DATA_TYPE_INT64: 1302 xdr_int64(&xdr, (int64_t *)data); 1303 break; 1304 1305 case DATA_TYPE_UINT64: 1306 xdr_uint64(&xdr, (uint64_t *)data); 1307 break; 1308 1309 case DATA_TYPE_INT64_ARRAY: 1310 xdr_array(&xdr, nelem, (xdrproc_t)xdr_int64); 1311 break; 1312 1313 case DATA_TYPE_UINT64_ARRAY: 1314 xdr_array(&xdr, nelem, (xdrproc_t)xdr_uint64); 1315 break; 1316 1317 case DATA_TYPE_NVLIST: 1318 bcopy(((nvlist_t *)data)->nv_data, xdr.xdr_idx, encoded_size); 1319 break; 1320 1321 case DATA_TYPE_NVLIST_ARRAY: { 1322 size_t size; 1323 xdr_t xdr_nv; 1324 1325 for (uint32_t i = 0; i < nelem; i++) { 1326 xdr_nv.xdr_idx = ((nvlist_t **)data)[i]->nv_data; 1327 xdr_nv.xdr_buf = xdr_nv.xdr_idx; 1328 xdr_nv.xdr_buf_size = ((nvlist_t **)data)[i]->nv_size; 1329 1330 if (!nvlist_size_native(&xdr_nv, &size)) 1331 return (EINVAL); 1332 1333 bcopy(((nvlist_t **)data)[i]->nv_data, xdr.xdr_idx, 1334 size); 1335 xdr.xdr_idx += size; 1336 } 1337 break; 1338 } 1339 default: 1340 bcopy(data, xdr.xdr_idx, encoded_size); 1341 } 1342 1343 nvl->nv_size += head.encoded_size; 1344 1345 return (0); 1346 } 1347 1348 int 1349 nvlist_add_boolean_value(nvlist_t *nvl, const char *name, int value) 1350 { 1351 return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_VALUE, 1, 1352 &value)); 1353 } 1354 1355 int 1356 nvlist_add_byte(nvlist_t *nvl, const char *name, uint8_t value) 1357 { 1358 return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE, 1, &value)); 1359 } 1360 1361 int 1362 nvlist_add_int8(nvlist_t *nvl, const char *name, int8_t value) 1363 { 1364 return (nvlist_add_common(nvl, name, DATA_TYPE_INT8, 1, &value)); 1365 } 1366 1367 int 1368 nvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t value) 1369 { 1370 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8, 1, &value)); 1371 } 1372 1373 int 1374 nvlist_add_int16(nvlist_t *nvl, const char *name, int16_t value) 1375 { 1376 return (nvlist_add_common(nvl, name, DATA_TYPE_INT16, 1, &value)); 1377 } 1378 1379 int 1380 nvlist_add_uint16(nvlist_t *nvl, const char *name, uint16_t value) 1381 { 1382 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16, 1, &value)); 1383 } 1384 1385 int 1386 nvlist_add_int32(nvlist_t *nvl, const char *name, int32_t value) 1387 { 1388 return (nvlist_add_common(nvl, name, DATA_TYPE_INT32, 1, &value)); 1389 } 1390 1391 int 1392 nvlist_add_uint32(nvlist_t *nvl, const char *name, uint32_t value) 1393 { 1394 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32, 1, &value)); 1395 } 1396 1397 int 1398 nvlist_add_int64(nvlist_t *nvl, const char *name, int64_t value) 1399 { 1400 return (nvlist_add_common(nvl, name, DATA_TYPE_INT64, 1, &value)); 1401 } 1402 1403 int 1404 nvlist_add_uint64(nvlist_t *nvl, const char *name, uint64_t value) 1405 { 1406 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64, 1, &value)); 1407 } 1408 1409 int 1410 nvlist_add_string(nvlist_t *nvl, const char *name, const char *value) 1411 { 1412 return (nvlist_add_common(nvl, name, DATA_TYPE_STRING, 1, value)); 1413 } 1414 1415 int 1416 nvlist_add_boolean_array(nvlist_t *nvl, const char *name, int *a, uint32_t n) 1417 { 1418 return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_ARRAY, n, a)); 1419 } 1420 1421 int 1422 nvlist_add_byte_array(nvlist_t *nvl, const char *name, uint8_t *a, uint32_t n) 1423 { 1424 return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a)); 1425 } 1426 1427 int 1428 nvlist_add_int8_array(nvlist_t *nvl, const char *name, int8_t *a, uint32_t n) 1429 { 1430 return (nvlist_add_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a)); 1431 } 1432 1433 int 1434 nvlist_add_uint8_array(nvlist_t *nvl, const char *name, uint8_t *a, uint32_t n) 1435 { 1436 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a)); 1437 } 1438 1439 int 1440 nvlist_add_int16_array(nvlist_t *nvl, const char *name, int16_t *a, uint32_t n) 1441 { 1442 return (nvlist_add_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a)); 1443 } 1444 1445 int 1446 nvlist_add_uint16_array(nvlist_t *nvl, const char *name, uint16_t *a, 1447 uint32_t n) 1448 { 1449 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a)); 1450 } 1451 1452 int 1453 nvlist_add_int32_array(nvlist_t *nvl, const char *name, int32_t *a, uint32_t n) 1454 { 1455 return (nvlist_add_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a)); 1456 } 1457 1458 int 1459 nvlist_add_uint32_array(nvlist_t *nvl, const char *name, uint32_t *a, 1460 uint32_t n) 1461 { 1462 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a)); 1463 } 1464 1465 int 1466 nvlist_add_int64_array(nvlist_t *nvl, const char *name, int64_t *a, uint32_t n) 1467 { 1468 return (nvlist_add_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a)); 1469 } 1470 1471 int 1472 nvlist_add_uint64_array(nvlist_t *nvl, const char *name, uint64_t *a, 1473 uint32_t n) 1474 { 1475 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a)); 1476 } 1477 1478 int 1479 nvlist_add_string_array(nvlist_t *nvl, const char *name, 1480 char * const *a, uint32_t n) 1481 { 1482 return (nvlist_add_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a)); 1483 } 1484 1485 int 1486 nvlist_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val) 1487 { 1488 return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST, 1, val)); 1489 } 1490 1491 int 1492 nvlist_add_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **a, 1493 uint32_t n) 1494 { 1495 return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a)); 1496 } 1497 1498 static const char *typenames[] = { 1499 "DATA_TYPE_UNKNOWN", 1500 "DATA_TYPE_BOOLEAN", 1501 "DATA_TYPE_BYTE", 1502 "DATA_TYPE_INT16", 1503 "DATA_TYPE_UINT16", 1504 "DATA_TYPE_INT32", 1505 "DATA_TYPE_UINT32", 1506 "DATA_TYPE_INT64", 1507 "DATA_TYPE_UINT64", 1508 "DATA_TYPE_STRING", 1509 "DATA_TYPE_BYTE_ARRAY", 1510 "DATA_TYPE_INT16_ARRAY", 1511 "DATA_TYPE_UINT16_ARRAY", 1512 "DATA_TYPE_INT32_ARRAY", 1513 "DATA_TYPE_UINT32_ARRAY", 1514 "DATA_TYPE_INT64_ARRAY", 1515 "DATA_TYPE_UINT64_ARRAY", 1516 "DATA_TYPE_STRING_ARRAY", 1517 "DATA_TYPE_HRTIME", 1518 "DATA_TYPE_NVLIST", 1519 "DATA_TYPE_NVLIST_ARRAY", 1520 "DATA_TYPE_BOOLEAN_VALUE", 1521 "DATA_TYPE_INT8", 1522 "DATA_TYPE_UINT8", 1523 "DATA_TYPE_BOOLEAN_ARRAY", 1524 "DATA_TYPE_INT8_ARRAY", 1525 "DATA_TYPE_UINT8_ARRAY" 1526 }; 1527 1528 int 1529 nvpair_type_from_name(const char *name) 1530 { 1531 unsigned i; 1532 1533 for (i = 0; i < nitems(typenames); i++) { 1534 if (strcmp(name, typenames[i]) == 0) 1535 return (i); 1536 } 1537 return (0); 1538 } 1539 1540 nvp_header_t * 1541 nvpair_find(nvlist_t *nv, const char *name) 1542 { 1543 nvp_header_t *nvh; 1544 1545 nvh = NULL; 1546 while ((nvh = nvlist_next_nvpair(nv, nvh)) != NULL) { 1547 nv_string_t *nvp_name; 1548 1549 nvp_name = (nv_string_t *)(nvh + 1); 1550 if (nvp_name->nv_size == strlen(name) && 1551 memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0) 1552 break; 1553 } 1554 return (nvh); 1555 } 1556 1557 void 1558 nvpair_print(nvp_header_t *nvp, unsigned int indent) 1559 { 1560 nv_string_t *nvp_name; 1561 nv_pair_data_t *nvp_data; 1562 nvlist_t nvlist; 1563 unsigned i, j; 1564 xdr_t xdr = { 1565 .xdr_op = XDR_OP_DECODE, 1566 .xdr_getint = _getint_mem, 1567 .xdr_getuint = _getuint_mem, 1568 .xdr_buf = (const uint8_t *)nvp, 1569 .xdr_idx = NULL, 1570 .xdr_buf_size = nvp->encoded_size 1571 }; 1572 1573 nvp_name = (nv_string_t *)((uintptr_t)nvp + sizeof(*nvp)); 1574 nvp_data = (nv_pair_data_t *) 1575 NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] + nvp_name->nv_size); 1576 1577 for (i = 0; i < indent; i++) 1578 printf(" "); 1579 1580 printf("%s [%d] %.*s", typenames[nvp_data->nv_type], 1581 nvp_data->nv_nelem, nvp_name->nv_size, nvp_name->nv_data); 1582 1583 xdr.xdr_idx = nvp_data->nv_data; 1584 switch (nvp_data->nv_type) { 1585 case DATA_TYPE_BYTE: 1586 case DATA_TYPE_INT8: 1587 case DATA_TYPE_UINT8: { 1588 char c; 1589 1590 if (xdr_char(&xdr, &c)) 1591 printf(" = 0x%x\n", c); 1592 break; 1593 } 1594 1595 case DATA_TYPE_INT16: 1596 case DATA_TYPE_UINT16: { 1597 unsigned short u; 1598 1599 if (xdr_u_short(&xdr, &u)) 1600 printf(" = 0x%hx\n", u); 1601 break; 1602 } 1603 1604 case DATA_TYPE_BOOLEAN_VALUE: 1605 case DATA_TYPE_INT32: 1606 case DATA_TYPE_UINT32: { 1607 unsigned u; 1608 1609 if (xdr_u_int(&xdr, &u)) 1610 printf(" = 0x%x\n", u); 1611 break; 1612 } 1613 1614 case DATA_TYPE_INT64: 1615 case DATA_TYPE_UINT64: { 1616 uint64_t u; 1617 1618 if (xdr_uint64(&xdr, &u)) 1619 printf(" = 0x%jx\n", (uintmax_t)u); 1620 break; 1621 } 1622 1623 case DATA_TYPE_INT64_ARRAY: 1624 case DATA_TYPE_UINT64_ARRAY: { 1625 uint64_t *u; 1626 1627 if (xdr_array(&xdr, nvp_data->nv_nelem, 1628 (xdrproc_t)xdr_uint64)) { 1629 u = (uint64_t *)(nvp_data->nv_data + sizeof(unsigned)); 1630 for (i = 0; i < nvp_data->nv_nelem; i++) 1631 printf(" [%u] = 0x%jx", i, (uintmax_t)u[i]); 1632 printf("\n"); 1633 } 1634 1635 break; 1636 } 1637 1638 case DATA_TYPE_STRING: 1639 case DATA_TYPE_STRING_ARRAY: 1640 nvp_name = (nv_string_t *)&nvp_data->nv_data[0]; 1641 for (i = 0; i < nvp_data->nv_nelem; i++) { 1642 printf(" = \"%.*s\"\n", nvp_name->nv_size, 1643 nvp_name->nv_data); 1644 } 1645 break; 1646 1647 case DATA_TYPE_NVLIST: 1648 printf("\n"); 1649 nvlist.nv_data = &nvp_data->nv_data[0]; 1650 nvlist_print(&nvlist, indent + 2); 1651 break; 1652 1653 case DATA_TYPE_NVLIST_ARRAY: 1654 nvlist.nv_data = &nvp_data->nv_data[0]; 1655 for (j = 0; j < nvp_data->nv_nelem; j++) { 1656 size_t size; 1657 1658 printf("[%d]\n", j); 1659 nvlist_print(&nvlist, indent + 2); 1660 if (j != nvp_data->nv_nelem - 1) { 1661 for (i = 0; i < indent; i++) 1662 printf(" "); 1663 printf("%s %.*s", 1664 typenames[nvp_data->nv_type], 1665 nvp_name->nv_size, 1666 nvp_name->nv_data); 1667 } 1668 xdr.xdr_idx = nvlist.nv_data; 1669 xdr.xdr_buf = xdr.xdr_idx; 1670 xdr.xdr_buf_size = nvp->encoded_size - 1671 (xdr.xdr_idx - (uint8_t *)nvp); 1672 1673 if (!nvlist_size_native(&xdr, &size)) 1674 return; 1675 1676 nvlist.nv_data += size; 1677 } 1678 break; 1679 1680 default: 1681 printf("\n"); 1682 } 1683 } 1684 1685 void 1686 nvlist_print(const nvlist_t *nvl, unsigned int indent) 1687 { 1688 nvs_data_t *data; 1689 nvp_header_t *nvp; 1690 1691 data = (nvs_data_t *)nvl->nv_data; 1692 nvp = &data->nvl_pair; /* first pair in nvlist */ 1693 while (nvp->encoded_size != 0 && nvp->decoded_size != 0) { 1694 nvpair_print(nvp, indent); 1695 nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size); 1696 } 1697 printf("%*s\n", indent + 13, "End of nvlist"); 1698 } 1699