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_buf_size = nvl->nv_asize; 1213 xdr.xdr_idx = nvl->nv_idx; 1214 1215 xdr.xdr_idx += xdr.xdr_putuint(&xdr, namelen); 1216 strlcpy((char *)xdr.xdr_idx, name, namelen + 1); 1217 xdr.xdr_idx += NV_ALIGN4(namelen); 1218 xdr.xdr_idx += xdr.xdr_putuint(&xdr, type); 1219 xdr.xdr_idx += xdr.xdr_putuint(&xdr, nelem); 1220 1221 switch (type) { 1222 case DATA_TYPE_BOOLEAN: 1223 break; 1224 1225 case DATA_TYPE_BYTE_ARRAY: 1226 xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size); 1227 bcopy(data, xdr.xdr_idx, nelem); 1228 xdr.xdr_idx += NV_ALIGN4(encoded_size); 1229 break; 1230 1231 case DATA_TYPE_STRING: 1232 encoded_size = strlen(data); 1233 xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size); 1234 strlcpy((char *)xdr.xdr_idx, data, encoded_size + 1); 1235 xdr.xdr_idx += NV_ALIGN4(encoded_size); 1236 break; 1237 1238 case DATA_TYPE_STRING_ARRAY: 1239 for (uint32_t i = 0; i < nelem; i++) { 1240 encoded_size = strlen(((char **)data)[i]); 1241 xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size); 1242 strlcpy((char *)xdr.xdr_idx, ((char **)data)[i], 1243 encoded_size + 1); 1244 xdr.xdr_idx += NV_ALIGN4(encoded_size); 1245 } 1246 break; 1247 1248 case DATA_TYPE_BYTE: 1249 case DATA_TYPE_INT8: 1250 case DATA_TYPE_UINT8: 1251 xdr_char(&xdr, (char *)data); 1252 break; 1253 1254 case DATA_TYPE_INT8_ARRAY: 1255 case DATA_TYPE_UINT8_ARRAY: 1256 xdr_array(&xdr, nelem, (xdrproc_t)xdr_char); 1257 break; 1258 1259 case DATA_TYPE_INT16: 1260 xdr_short(&xdr, (short *)data); 1261 break; 1262 1263 case DATA_TYPE_UINT16: 1264 xdr_u_short(&xdr, (unsigned short *)data); 1265 break; 1266 1267 case DATA_TYPE_INT16_ARRAY: 1268 xdr_array(&xdr, nelem, (xdrproc_t)xdr_short); 1269 break; 1270 1271 case DATA_TYPE_UINT16_ARRAY: 1272 xdr_array(&xdr, nelem, (xdrproc_t)xdr_u_short); 1273 break; 1274 1275 case DATA_TYPE_BOOLEAN_VALUE: 1276 case DATA_TYPE_INT32: 1277 xdr_int(&xdr, (int *)data); 1278 break; 1279 1280 case DATA_TYPE_UINT32: 1281 xdr_u_int(&xdr, (unsigned int *)data); 1282 break; 1283 1284 case DATA_TYPE_BOOLEAN_ARRAY: 1285 case DATA_TYPE_INT32_ARRAY: 1286 xdr_array(&xdr, nelem, (xdrproc_t)xdr_int); 1287 break; 1288 1289 case DATA_TYPE_UINT32_ARRAY: 1290 xdr_array(&xdr, nelem, (xdrproc_t)xdr_u_int); 1291 break; 1292 1293 case DATA_TYPE_INT64: 1294 xdr_int64(&xdr, (int64_t *)data); 1295 break; 1296 1297 case DATA_TYPE_UINT64: 1298 xdr_uint64(&xdr, (uint64_t *)data); 1299 break; 1300 1301 case DATA_TYPE_INT64_ARRAY: 1302 xdr_array(&xdr, nelem, (xdrproc_t)xdr_int64); 1303 break; 1304 1305 case DATA_TYPE_UINT64_ARRAY: 1306 xdr_array(&xdr, nelem, (xdrproc_t)xdr_uint64); 1307 break; 1308 1309 case DATA_TYPE_NVLIST: 1310 bcopy(((nvlist_t *)data)->nv_data, xdr.xdr_idx, encoded_size); 1311 break; 1312 1313 case DATA_TYPE_NVLIST_ARRAY: { 1314 size_t size; 1315 xdr_t xdr_nv; 1316 1317 for (uint32_t i = 0; i < nelem; i++) { 1318 xdr_nv.xdr_idx = ((nvlist_t **)data)[i]->nv_data; 1319 xdr_nv.xdr_buf = xdr_nv.xdr_idx; 1320 xdr_nv.xdr_buf_size = ((nvlist_t **)data)[i]->nv_size; 1321 1322 if (!nvlist_size_native(&xdr_nv, &size)) 1323 return (EINVAL); 1324 1325 bcopy(((nvlist_t **)data)[i]->nv_data, xdr.xdr_idx, 1326 size); 1327 xdr.xdr_idx += size; 1328 } 1329 break; 1330 } 1331 1332 default: 1333 bcopy(data, xdr.xdr_idx, encoded_size); 1334 } 1335 1336 nvl->nv_size += head.encoded_size; 1337 1338 return (0); 1339 } 1340 1341 int 1342 nvlist_add_boolean_value(nvlist_t *nvl, const char *name, boolean_t value) 1343 { 1344 return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_VALUE, 1, 1345 &value)); 1346 } 1347 1348 int 1349 nvlist_add_byte(nvlist_t *nvl, const char *name, uint8_t value) 1350 { 1351 return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE, 1, &value)); 1352 } 1353 1354 int 1355 nvlist_add_int8(nvlist_t *nvl, const char *name, int8_t value) 1356 { 1357 return (nvlist_add_common(nvl, name, DATA_TYPE_INT8, 1, &value)); 1358 } 1359 1360 int 1361 nvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t value) 1362 { 1363 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8, 1, &value)); 1364 } 1365 1366 int 1367 nvlist_add_int16(nvlist_t *nvl, const char *name, int16_t value) 1368 { 1369 return (nvlist_add_common(nvl, name, DATA_TYPE_INT16, 1, &value)); 1370 } 1371 1372 int 1373 nvlist_add_uint16(nvlist_t *nvl, const char *name, uint16_t value) 1374 { 1375 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16, 1, &value)); 1376 } 1377 1378 int 1379 nvlist_add_int32(nvlist_t *nvl, const char *name, int32_t value) 1380 { 1381 return (nvlist_add_common(nvl, name, DATA_TYPE_INT32, 1, &value)); 1382 } 1383 1384 int 1385 nvlist_add_uint32(nvlist_t *nvl, const char *name, uint32_t value) 1386 { 1387 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32, 1, &value)); 1388 } 1389 1390 int 1391 nvlist_add_int64(nvlist_t *nvl, const char *name, int64_t value) 1392 { 1393 return (nvlist_add_common(nvl, name, DATA_TYPE_INT64, 1, &value)); 1394 } 1395 1396 int 1397 nvlist_add_uint64(nvlist_t *nvl, const char *name, uint64_t value) 1398 { 1399 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64, 1, &value)); 1400 } 1401 1402 int 1403 nvlist_add_string(nvlist_t *nvl, const char *name, const char *value) 1404 { 1405 return (nvlist_add_common(nvl, name, DATA_TYPE_STRING, 1, value)); 1406 } 1407 1408 int 1409 nvlist_add_boolean_array(nvlist_t *nvl, const char *name, 1410 boolean_t *a, uint32_t n) 1411 { 1412 return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_ARRAY, n, a)); 1413 } 1414 1415 int 1416 nvlist_add_byte_array(nvlist_t *nvl, const char *name, uint8_t *a, uint32_t n) 1417 { 1418 return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a)); 1419 } 1420 1421 int 1422 nvlist_add_int8_array(nvlist_t *nvl, const char *name, int8_t *a, uint32_t n) 1423 { 1424 return (nvlist_add_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a)); 1425 } 1426 1427 int 1428 nvlist_add_uint8_array(nvlist_t *nvl, const char *name, uint8_t *a, uint32_t n) 1429 { 1430 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a)); 1431 } 1432 1433 int 1434 nvlist_add_int16_array(nvlist_t *nvl, const char *name, int16_t *a, uint32_t n) 1435 { 1436 return (nvlist_add_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a)); 1437 } 1438 1439 int 1440 nvlist_add_uint16_array(nvlist_t *nvl, const char *name, uint16_t *a, 1441 uint32_t n) 1442 { 1443 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a)); 1444 } 1445 1446 int 1447 nvlist_add_int32_array(nvlist_t *nvl, const char *name, int32_t *a, uint32_t n) 1448 { 1449 return (nvlist_add_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a)); 1450 } 1451 1452 int 1453 nvlist_add_uint32_array(nvlist_t *nvl, const char *name, uint32_t *a, 1454 uint32_t n) 1455 { 1456 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a)); 1457 } 1458 1459 int 1460 nvlist_add_int64_array(nvlist_t *nvl, const char *name, int64_t *a, uint32_t n) 1461 { 1462 return (nvlist_add_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a)); 1463 } 1464 1465 int 1466 nvlist_add_uint64_array(nvlist_t *nvl, const char *name, uint64_t *a, 1467 uint32_t n) 1468 { 1469 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a)); 1470 } 1471 1472 int 1473 nvlist_add_string_array(nvlist_t *nvl, const char *name, 1474 char * const *a, uint32_t n) 1475 { 1476 return (nvlist_add_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a)); 1477 } 1478 1479 int 1480 nvlist_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val) 1481 { 1482 return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST, 1, val)); 1483 } 1484 1485 int 1486 nvlist_add_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **a, 1487 uint32_t n) 1488 { 1489 return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a)); 1490 } 1491 1492 static const char *typenames[] = { 1493 "DATA_TYPE_UNKNOWN", 1494 "DATA_TYPE_BOOLEAN", 1495 "DATA_TYPE_BYTE", 1496 "DATA_TYPE_INT16", 1497 "DATA_TYPE_UINT16", 1498 "DATA_TYPE_INT32", 1499 "DATA_TYPE_UINT32", 1500 "DATA_TYPE_INT64", 1501 "DATA_TYPE_UINT64", 1502 "DATA_TYPE_STRING", 1503 "DATA_TYPE_BYTE_ARRAY", 1504 "DATA_TYPE_INT16_ARRAY", 1505 "DATA_TYPE_UINT16_ARRAY", 1506 "DATA_TYPE_INT32_ARRAY", 1507 "DATA_TYPE_UINT32_ARRAY", 1508 "DATA_TYPE_INT64_ARRAY", 1509 "DATA_TYPE_UINT64_ARRAY", 1510 "DATA_TYPE_STRING_ARRAY", 1511 "DATA_TYPE_HRTIME", 1512 "DATA_TYPE_NVLIST", 1513 "DATA_TYPE_NVLIST_ARRAY", 1514 "DATA_TYPE_BOOLEAN_VALUE", 1515 "DATA_TYPE_INT8", 1516 "DATA_TYPE_UINT8", 1517 "DATA_TYPE_BOOLEAN_ARRAY", 1518 "DATA_TYPE_INT8_ARRAY", 1519 "DATA_TYPE_UINT8_ARRAY" 1520 }; 1521 1522 int 1523 nvpair_type_from_name(const char *name) 1524 { 1525 unsigned i; 1526 1527 for (i = 0; i < nitems(typenames); i++) { 1528 if (strcmp(name, typenames[i]) == 0) 1529 return (i); 1530 } 1531 return (0); 1532 } 1533 1534 nvp_header_t * 1535 nvpair_find(nvlist_t *nv, const char *name) 1536 { 1537 nvp_header_t *nvh; 1538 1539 nvh = NULL; 1540 while ((nvh = nvlist_next_nvpair(nv, nvh)) != NULL) { 1541 nv_string_t *nvp_name; 1542 1543 nvp_name = (nv_string_t *)(nvh + 1); 1544 if (nvp_name->nv_size == strlen(name) && 1545 memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0) 1546 break; 1547 } 1548 return (nvh); 1549 } 1550 1551 void 1552 nvpair_print(nvp_header_t *nvp, unsigned int indent) 1553 { 1554 nv_string_t *nvp_name; 1555 nv_pair_data_t *nvp_data; 1556 nvlist_t nvlist; 1557 unsigned i, j; 1558 xdr_t xdr = { 1559 .xdr_op = XDR_OP_DECODE, 1560 .xdr_getint = _getint_mem, 1561 .xdr_getuint = _getuint_mem, 1562 .xdr_buf = (const uint8_t *)nvp, 1563 .xdr_idx = NULL, 1564 .xdr_buf_size = nvp->encoded_size 1565 }; 1566 1567 nvp_name = (nv_string_t *)((uintptr_t)nvp + sizeof (*nvp)); 1568 nvp_data = (nv_pair_data_t *) 1569 NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] + nvp_name->nv_size); 1570 1571 for (i = 0; i < indent; i++) 1572 printf(" "); 1573 1574 printf("%s [%d] %.*s", typenames[nvp_data->nv_type], 1575 nvp_data->nv_nelem, nvp_name->nv_size, nvp_name->nv_data); 1576 1577 xdr.xdr_idx = nvp_data->nv_data; 1578 switch (nvp_data->nv_type) { 1579 case DATA_TYPE_BYTE: 1580 case DATA_TYPE_INT8: 1581 case DATA_TYPE_UINT8: { 1582 char c; 1583 1584 if (xdr_char(&xdr, &c)) 1585 printf(" = 0x%x\n", c); 1586 break; 1587 } 1588 1589 case DATA_TYPE_INT16: 1590 case DATA_TYPE_UINT16: { 1591 unsigned short u; 1592 1593 if (xdr_u_short(&xdr, &u)) 1594 printf(" = 0x%hx\n", u); 1595 break; 1596 } 1597 1598 case DATA_TYPE_BOOLEAN_VALUE: 1599 case DATA_TYPE_INT32: 1600 case DATA_TYPE_UINT32: { 1601 unsigned u; 1602 1603 if (xdr_u_int(&xdr, &u)) 1604 printf(" = 0x%x\n", u); 1605 break; 1606 } 1607 1608 case DATA_TYPE_INT64: 1609 case DATA_TYPE_UINT64: { 1610 uint64_t u; 1611 1612 if (xdr_uint64(&xdr, &u)) 1613 printf(" = 0x%jx\n", (uintmax_t)u); 1614 break; 1615 } 1616 1617 case DATA_TYPE_INT64_ARRAY: 1618 case DATA_TYPE_UINT64_ARRAY: { 1619 uint64_t *u; 1620 1621 if (xdr_array(&xdr, nvp_data->nv_nelem, 1622 (xdrproc_t)xdr_uint64)) { 1623 u = (uint64_t *)(nvp_data->nv_data + sizeof (unsigned)); 1624 for (i = 0; i < nvp_data->nv_nelem; i++) 1625 printf(" [%u] = 0x%jx", i, (uintmax_t)u[i]); 1626 printf("\n"); 1627 } 1628 1629 break; 1630 } 1631 1632 case DATA_TYPE_STRING: 1633 case DATA_TYPE_STRING_ARRAY: 1634 nvp_name = (nv_string_t *)&nvp_data->nv_data[0]; 1635 for (i = 0; i < nvp_data->nv_nelem; i++) { 1636 printf(" = \"%.*s\"\n", nvp_name->nv_size, 1637 nvp_name->nv_data); 1638 } 1639 break; 1640 1641 case DATA_TYPE_NVLIST: 1642 printf("\n"); 1643 nvlist.nv_data = &nvp_data->nv_data[0]; 1644 nvlist_print(&nvlist, indent + 2); 1645 break; 1646 1647 case DATA_TYPE_NVLIST_ARRAY: 1648 nvlist.nv_data = &nvp_data->nv_data[0]; 1649 for (j = 0; j < nvp_data->nv_nelem; j++) { 1650 size_t size; 1651 1652 printf("[%d]\n", j); 1653 nvlist_print(&nvlist, indent + 2); 1654 if (j != nvp_data->nv_nelem - 1) { 1655 for (i = 0; i < indent; i++) 1656 printf(" "); 1657 printf("%s %.*s", 1658 typenames[nvp_data->nv_type], 1659 nvp_name->nv_size, 1660 nvp_name->nv_data); 1661 } 1662 xdr.xdr_idx = nvlist.nv_data; 1663 xdr.xdr_buf = xdr.xdr_idx; 1664 xdr.xdr_buf_size = nvp->encoded_size - 1665 (xdr.xdr_idx - (uint8_t *)nvp); 1666 1667 if (!nvlist_size_native(&xdr, &size)) 1668 return; 1669 1670 nvlist.nv_data += size; 1671 } 1672 break; 1673 1674 default: 1675 printf("\n"); 1676 } 1677 } 1678 1679 void 1680 nvlist_print(const nvlist_t *nvl, unsigned int indent) 1681 { 1682 nvs_data_t *data; 1683 nvp_header_t *nvp; 1684 1685 data = (nvs_data_t *)nvl->nv_data; 1686 nvp = &data->nvl_pair; /* first pair in nvlist */ 1687 while (nvp->encoded_size != 0 && nvp->decoded_size != 0) { 1688 nvpair_print(nvp, indent); 1689 nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size); 1690 } 1691 printf("%*s\n", indent + 13, "End of nvlist"); 1692 } 1693