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