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