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