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