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