1 /*- 2 * Copyright (c) 2009-2013 The FreeBSD Foundation 3 * All rights reserved. 4 * 5 * This software was developed by Pawel Jakub Dawidek under sponsorship from 6 * the FreeBSD Foundation. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 #include <sys/param.h> 34 #include <sys/endian.h> 35 #include <sys/queue.h> 36 37 #ifdef _KERNEL 38 39 #include <sys/errno.h> 40 #include <sys/kernel.h> 41 #include <sys/lock.h> 42 #include <sys/malloc.h> 43 #include <sys/systm.h> 44 45 #include <machine/stdarg.h> 46 47 #else 48 #include <sys/socket.h> 49 50 #include <errno.h> 51 #include <stdarg.h> 52 #include <stdbool.h> 53 #include <stdint.h> 54 #define _WITH_DPRINTF 55 #include <stdio.h> 56 #include <stdlib.h> 57 #include <string.h> 58 #include <unistd.h> 59 60 #include "msgio.h" 61 #endif 62 63 #ifdef HAVE_PJDLOG 64 #include <pjdlog.h> 65 #endif 66 67 #include <sys/nv.h> 68 69 #include "nv_impl.h" 70 #include "nvlist_impl.h" 71 #include "nvpair_impl.h" 72 73 #ifndef HAVE_PJDLOG 74 #ifdef _KERNEL 75 #define PJDLOG_ASSERT(...) MPASS(__VA_ARGS__) 76 #define PJDLOG_RASSERT(expr, ...) KASSERT(expr, (__VA_ARGS__)) 77 #define PJDLOG_ABORT(...) panic(__VA_ARGS__) 78 #else 79 #include <assert.h> 80 #define PJDLOG_ASSERT(...) assert(__VA_ARGS__) 81 #define PJDLOG_RASSERT(expr, ...) assert(expr) 82 #define PJDLOG_ABORT(...) do { \ 83 fprintf(stderr, "%s:%u: ", __FILE__, __LINE__); \ 84 fprintf(stderr, __VA_ARGS__); \ 85 fprintf(stderr, "\n"); \ 86 abort(); \ 87 } while (0) 88 #endif 89 #endif 90 91 #define NV_FLAG_PRIVATE_MASK (NV_FLAG_BIG_ENDIAN) 92 #define NV_FLAG_PUBLIC_MASK (NV_FLAG_IGNORE_CASE | NV_FLAG_NO_UNIQUE) 93 #define NV_FLAG_ALL_MASK (NV_FLAG_PRIVATE_MASK | NV_FLAG_PUBLIC_MASK) 94 95 #define NVLIST_MAGIC 0x6e766c /* "nvl" */ 96 struct nvlist { 97 int nvl_magic; 98 int nvl_error; 99 int nvl_flags; 100 nvpair_t *nvl_parent; 101 struct nvl_head nvl_head; 102 }; 103 104 #define NVLIST_ASSERT(nvl) do { \ 105 PJDLOG_ASSERT((nvl) != NULL); \ 106 PJDLOG_ASSERT((nvl)->nvl_magic == NVLIST_MAGIC); \ 107 } while (0) 108 109 #ifdef _KERNEL 110 MALLOC_DEFINE(M_NVLIST, "nvlist", "kernel nvlist"); 111 #endif 112 113 #define NVPAIR_ASSERT(nvp) nvpair_assert(nvp) 114 115 #define NVLIST_HEADER_MAGIC 0x6c 116 #define NVLIST_HEADER_VERSION 0x00 117 struct nvlist_header { 118 uint8_t nvlh_magic; 119 uint8_t nvlh_version; 120 uint8_t nvlh_flags; 121 uint64_t nvlh_descriptors; 122 uint64_t nvlh_size; 123 } __packed; 124 125 nvlist_t * 126 nvlist_create(int flags) 127 { 128 nvlist_t *nvl; 129 130 PJDLOG_ASSERT((flags & ~(NV_FLAG_PUBLIC_MASK)) == 0); 131 132 nvl = nv_malloc(sizeof(*nvl)); 133 if (nvl == NULL) 134 return (NULL); 135 nvl->nvl_error = 0; 136 nvl->nvl_flags = flags; 137 nvl->nvl_parent = NULL; 138 TAILQ_INIT(&nvl->nvl_head); 139 nvl->nvl_magic = NVLIST_MAGIC; 140 141 return (nvl); 142 } 143 144 void 145 nvlist_destroy(nvlist_t *nvl) 146 { 147 nvpair_t *nvp; 148 149 if (nvl == NULL) 150 return; 151 152 ERRNO_SAVE(); 153 154 NVLIST_ASSERT(nvl); 155 156 while ((nvp = nvlist_first_nvpair(nvl)) != NULL) { 157 nvlist_remove_nvpair(nvl, nvp); 158 nvpair_free(nvp); 159 } 160 nvl->nvl_magic = 0; 161 nv_free(nvl); 162 163 ERRNO_RESTORE(); 164 } 165 166 void 167 nvlist_set_error(nvlist_t *nvl, int error) 168 { 169 170 PJDLOG_ASSERT(error != 0); 171 172 /* 173 * Check for error != 0 so that we don't do the wrong thing if somebody 174 * tries to abuse this API when asserts are disabled. 175 */ 176 if (nvl != NULL && error != 0 && nvl->nvl_error == 0) 177 nvl->nvl_error = error; 178 } 179 180 int 181 nvlist_error(const nvlist_t *nvl) 182 { 183 184 if (nvl == NULL) 185 return (ENOMEM); 186 187 NVLIST_ASSERT(nvl); 188 189 return (nvl->nvl_error); 190 } 191 192 nvpair_t * 193 nvlist_get_nvpair_parent(const nvlist_t *nvl) 194 { 195 196 NVLIST_ASSERT(nvl); 197 198 return (nvl->nvl_parent); 199 } 200 201 const nvlist_t * 202 nvlist_get_parent(const nvlist_t *nvl, void **cookiep) 203 { 204 nvpair_t *nvp; 205 206 NVLIST_ASSERT(nvl); 207 208 nvp = nvl->nvl_parent; 209 if (cookiep != NULL) 210 *cookiep = nvp; 211 if (nvp == NULL) 212 return (NULL); 213 214 return (nvpair_nvlist(nvp)); 215 } 216 217 void 218 nvlist_set_parent(nvlist_t *nvl, nvpair_t *parent) 219 { 220 221 NVLIST_ASSERT(nvl); 222 223 nvl->nvl_parent = parent; 224 } 225 226 bool 227 nvlist_empty(const nvlist_t *nvl) 228 { 229 230 NVLIST_ASSERT(nvl); 231 PJDLOG_ASSERT(nvl->nvl_error == 0); 232 233 return (nvlist_first_nvpair(nvl) == NULL); 234 } 235 236 int 237 nvlist_flags(const nvlist_t *nvl) 238 { 239 240 NVLIST_ASSERT(nvl); 241 PJDLOG_ASSERT(nvl->nvl_error == 0); 242 PJDLOG_ASSERT((nvl->nvl_flags & ~(NV_FLAG_PUBLIC_MASK)) == 0); 243 244 return (nvl->nvl_flags); 245 } 246 247 static void 248 nvlist_report_missing(int type, const char *name) 249 { 250 251 PJDLOG_ABORT("Element '%s' of type %s doesn't exist.", 252 name, nvpair_type_string(type)); 253 } 254 255 static nvpair_t * 256 nvlist_find(const nvlist_t *nvl, int type, const char *name) 257 { 258 nvpair_t *nvp; 259 260 NVLIST_ASSERT(nvl); 261 PJDLOG_ASSERT(nvl->nvl_error == 0); 262 PJDLOG_ASSERT(type == NV_TYPE_NONE || 263 (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST)); 264 265 for (nvp = nvlist_first_nvpair(nvl); nvp != NULL; 266 nvp = nvlist_next_nvpair(nvl, nvp)) { 267 if (type != NV_TYPE_NONE && nvpair_type(nvp) != type) 268 continue; 269 if ((nvl->nvl_flags & NV_FLAG_IGNORE_CASE) != 0) { 270 if (strcasecmp(nvpair_name(nvp), name) != 0) 271 continue; 272 } else { 273 if (strcmp(nvpair_name(nvp), name) != 0) 274 continue; 275 } 276 break; 277 } 278 279 if (nvp == NULL) 280 ERRNO_SET(ENOENT); 281 282 return (nvp); 283 } 284 285 bool 286 nvlist_exists_type(const nvlist_t *nvl, const char *name, int type) 287 { 288 289 NVLIST_ASSERT(nvl); 290 PJDLOG_ASSERT(nvl->nvl_error == 0); 291 PJDLOG_ASSERT(type == NV_TYPE_NONE || 292 (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST)); 293 294 return (nvlist_find(nvl, type, name) != NULL); 295 } 296 297 void 298 nvlist_free_type(nvlist_t *nvl, const char *name, int type) 299 { 300 nvpair_t *nvp; 301 302 NVLIST_ASSERT(nvl); 303 PJDLOG_ASSERT(nvl->nvl_error == 0); 304 PJDLOG_ASSERT(type == NV_TYPE_NONE || 305 (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST)); 306 307 nvp = nvlist_find(nvl, type, name); 308 if (nvp != NULL) 309 nvlist_free_nvpair(nvl, nvp); 310 else 311 nvlist_report_missing(type, name); 312 } 313 314 nvlist_t * 315 nvlist_clone(const nvlist_t *nvl) 316 { 317 nvlist_t *newnvl; 318 nvpair_t *nvp, *newnvp; 319 320 NVLIST_ASSERT(nvl); 321 322 if (nvl->nvl_error != 0) { 323 ERRNO_SET(nvl->nvl_error); 324 return (NULL); 325 } 326 327 newnvl = nvlist_create(nvl->nvl_flags & NV_FLAG_PUBLIC_MASK); 328 for (nvp = nvlist_first_nvpair(nvl); nvp != NULL; 329 nvp = nvlist_next_nvpair(nvl, nvp)) { 330 newnvp = nvpair_clone(nvp); 331 if (newnvp == NULL) 332 break; 333 nvlist_move_nvpair(newnvl, newnvp); 334 } 335 if (nvp != NULL) { 336 nvlist_destroy(newnvl); 337 return (NULL); 338 } 339 return (newnvl); 340 } 341 342 #ifndef _KERNEL 343 static bool 344 nvlist_dump_error_check(const nvlist_t *nvl, int fd, int level) 345 { 346 347 if (nvlist_error(nvl) != 0) { 348 dprintf(fd, "%*serror: %d\n", level * 4, "", 349 nvlist_error(nvl)); 350 return (true); 351 } 352 353 return (false); 354 } 355 356 /* 357 * Dump content of nvlist. 358 */ 359 void 360 nvlist_dump(const nvlist_t *nvl, int fd) 361 { 362 const nvlist_t *tmpnvl; 363 nvpair_t *nvp, *tmpnvp; 364 void *cookie; 365 int level; 366 367 level = 0; 368 if (nvlist_dump_error_check(nvl, fd, level)) 369 return; 370 371 nvp = nvlist_first_nvpair(nvl); 372 while (nvp != NULL) { 373 dprintf(fd, "%*s%s (%s):", level * 4, "", nvpair_name(nvp), 374 nvpair_type_string(nvpair_type(nvp))); 375 switch (nvpair_type(nvp)) { 376 case NV_TYPE_NULL: 377 dprintf(fd, " null\n"); 378 break; 379 case NV_TYPE_BOOL: 380 dprintf(fd, " %s\n", nvpair_get_bool(nvp) ? 381 "TRUE" : "FALSE"); 382 break; 383 case NV_TYPE_NUMBER: 384 dprintf(fd, " %ju (%jd) (0x%jx)\n", 385 (uintmax_t)nvpair_get_number(nvp), 386 (intmax_t)nvpair_get_number(nvp), 387 (uintmax_t)nvpair_get_number(nvp)); 388 break; 389 case NV_TYPE_STRING: 390 dprintf(fd, " [%s]\n", nvpair_get_string(nvp)); 391 break; 392 case NV_TYPE_NVLIST: 393 dprintf(fd, "\n"); 394 tmpnvl = nvpair_get_nvlist(nvp); 395 if (nvlist_dump_error_check(tmpnvl, fd, level + 1)) 396 break; 397 tmpnvp = nvlist_first_nvpair(tmpnvl); 398 if (tmpnvp != NULL) { 399 nvl = tmpnvl; 400 nvp = tmpnvp; 401 level++; 402 continue; 403 } 404 break; 405 case NV_TYPE_DESCRIPTOR: 406 dprintf(fd, " %d\n", nvpair_get_descriptor(nvp)); 407 break; 408 case NV_TYPE_BINARY: 409 { 410 const unsigned char *binary; 411 unsigned int ii; 412 size_t size; 413 414 binary = nvpair_get_binary(nvp, &size); 415 dprintf(fd, " %zu ", size); 416 for (ii = 0; ii < size; ii++) 417 dprintf(fd, "%02hhx", binary[ii]); 418 dprintf(fd, "\n"); 419 break; 420 } 421 default: 422 PJDLOG_ABORT("Unknown type: %d.", nvpair_type(nvp)); 423 } 424 425 while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) { 426 cookie = NULL; 427 nvl = nvlist_get_parent(nvl, &cookie); 428 if (nvl == NULL) 429 return; 430 nvp = cookie; 431 level--; 432 } 433 } 434 } 435 436 void 437 nvlist_fdump(const nvlist_t *nvl, FILE *fp) 438 { 439 440 fflush(fp); 441 nvlist_dump(nvl, fileno(fp)); 442 } 443 #endif 444 445 /* 446 * The function obtains size of the nvlist after nvlist_pack(). 447 */ 448 size_t 449 nvlist_size(const nvlist_t *nvl) 450 { 451 const nvlist_t *tmpnvl; 452 const nvpair_t *nvp, *tmpnvp; 453 void *cookie; 454 size_t size; 455 456 NVLIST_ASSERT(nvl); 457 PJDLOG_ASSERT(nvl->nvl_error == 0); 458 459 size = sizeof(struct nvlist_header); 460 nvp = nvlist_first_nvpair(nvl); 461 while (nvp != NULL) { 462 size += nvpair_header_size(); 463 size += strlen(nvpair_name(nvp)) + 1; 464 if (nvpair_type(nvp) == NV_TYPE_NVLIST) { 465 size += sizeof(struct nvlist_header); 466 size += nvpair_header_size() + 1; 467 tmpnvl = nvpair_get_nvlist(nvp); 468 PJDLOG_ASSERT(tmpnvl->nvl_error == 0); 469 tmpnvp = nvlist_first_nvpair(tmpnvl); 470 if (tmpnvp != NULL) { 471 nvl = tmpnvl; 472 nvp = tmpnvp; 473 continue; 474 } 475 } else { 476 size += nvpair_size(nvp); 477 } 478 479 while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) { 480 cookie = NULL; 481 nvl = nvlist_get_parent(nvl, &cookie); 482 if (nvl == NULL) 483 goto out; 484 nvp = cookie; 485 } 486 } 487 488 out: 489 return (size); 490 } 491 492 #ifndef _KERNEL 493 static int * 494 nvlist_xdescriptors(const nvlist_t *nvl, int *descs) 495 { 496 nvpair_t *nvp; 497 const char *name; 498 int type; 499 500 NVLIST_ASSERT(nvl); 501 PJDLOG_ASSERT(nvl->nvl_error == 0); 502 503 nvp = NULL; 504 do { 505 while ((name = nvlist_next(nvl, &type, (void**)&nvp)) != NULL) { 506 switch (type) { 507 case NV_TYPE_DESCRIPTOR: 508 *descs = nvpair_get_descriptor(nvp); 509 descs++; 510 break; 511 case NV_TYPE_NVLIST: 512 nvl = nvpair_get_nvlist(nvp); 513 nvp = NULL; 514 break; 515 } 516 } 517 } while ((nvl = nvlist_get_parent(nvl, (void**)&nvp)) != NULL); 518 519 return (descs); 520 } 521 #endif 522 523 #ifndef _KERNEL 524 int * 525 nvlist_descriptors(const nvlist_t *nvl, size_t *nitemsp) 526 { 527 size_t nitems; 528 int *fds; 529 530 nitems = nvlist_ndescriptors(nvl); 531 fds = nv_malloc(sizeof(fds[0]) * (nitems + 1)); 532 if (fds == NULL) 533 return (NULL); 534 if (nitems > 0) 535 nvlist_xdescriptors(nvl, fds); 536 fds[nitems] = -1; 537 if (nitemsp != NULL) 538 *nitemsp = nitems; 539 return (fds); 540 } 541 #endif 542 543 size_t 544 nvlist_ndescriptors(const nvlist_t *nvl) 545 { 546 #ifndef _KERNEL 547 nvpair_t *nvp; 548 const char *name; 549 size_t ndescs; 550 int type; 551 552 NVLIST_ASSERT(nvl); 553 PJDLOG_ASSERT(nvl->nvl_error == 0); 554 555 ndescs = 0; 556 nvp = NULL; 557 do { 558 while ((name = nvlist_next(nvl, &type, (void**)&nvp)) != NULL) { 559 switch (type) { 560 case NV_TYPE_DESCRIPTOR: 561 ndescs++; 562 break; 563 case NV_TYPE_NVLIST: 564 nvl = nvpair_get_nvlist(nvp); 565 nvp = NULL; 566 break; 567 } 568 } 569 } while ((nvl = nvlist_get_parent(nvl, (void**)&nvp)) != NULL); 570 571 return (ndescs); 572 #else 573 return (0); 574 #endif 575 } 576 577 static unsigned char * 578 nvlist_pack_header(const nvlist_t *nvl, unsigned char *ptr, size_t *leftp) 579 { 580 struct nvlist_header nvlhdr; 581 582 NVLIST_ASSERT(nvl); 583 584 nvlhdr.nvlh_magic = NVLIST_HEADER_MAGIC; 585 nvlhdr.nvlh_version = NVLIST_HEADER_VERSION; 586 nvlhdr.nvlh_flags = nvl->nvl_flags; 587 #if BYTE_ORDER == BIG_ENDIAN 588 nvlhdr.nvlh_flags |= NV_FLAG_BIG_ENDIAN; 589 #endif 590 nvlhdr.nvlh_descriptors = nvlist_ndescriptors(nvl); 591 nvlhdr.nvlh_size = *leftp - sizeof(nvlhdr); 592 PJDLOG_ASSERT(*leftp >= sizeof(nvlhdr)); 593 memcpy(ptr, &nvlhdr, sizeof(nvlhdr)); 594 ptr += sizeof(nvlhdr); 595 *leftp -= sizeof(nvlhdr); 596 597 return (ptr); 598 } 599 600 static void * 601 nvlist_xpack(const nvlist_t *nvl, int64_t *fdidxp, size_t *sizep) 602 { 603 unsigned char *buf, *ptr; 604 size_t left, size; 605 const nvlist_t *tmpnvl; 606 nvpair_t *nvp, *tmpnvp; 607 void *cookie; 608 609 NVLIST_ASSERT(nvl); 610 611 if (nvl->nvl_error != 0) { 612 ERRNO_SET(nvl->nvl_error); 613 return (NULL); 614 } 615 616 size = nvlist_size(nvl); 617 buf = nv_malloc(size); 618 if (buf == NULL) 619 return (NULL); 620 621 ptr = buf; 622 left = size; 623 624 ptr = nvlist_pack_header(nvl, ptr, &left); 625 626 nvp = nvlist_first_nvpair(nvl); 627 while (nvp != NULL) { 628 NVPAIR_ASSERT(nvp); 629 630 nvpair_init_datasize(nvp); 631 ptr = nvpair_pack_header(nvp, ptr, &left); 632 if (ptr == NULL) { 633 nv_free(buf); 634 return (NULL); 635 } 636 switch (nvpair_type(nvp)) { 637 case NV_TYPE_NULL: 638 ptr = nvpair_pack_null(nvp, ptr, &left); 639 break; 640 case NV_TYPE_BOOL: 641 ptr = nvpair_pack_bool(nvp, ptr, &left); 642 break; 643 case NV_TYPE_NUMBER: 644 ptr = nvpair_pack_number(nvp, ptr, &left); 645 break; 646 case NV_TYPE_STRING: 647 ptr = nvpair_pack_string(nvp, ptr, &left); 648 break; 649 case NV_TYPE_NVLIST: 650 tmpnvl = nvpair_get_nvlist(nvp); 651 ptr = nvlist_pack_header(tmpnvl, ptr, &left); 652 if (ptr == NULL) 653 goto out; 654 tmpnvp = nvlist_first_nvpair(tmpnvl); 655 if (tmpnvp != NULL) { 656 nvl = tmpnvl; 657 nvp = tmpnvp; 658 continue; 659 } 660 ptr = nvpair_pack_nvlist_up(ptr, &left); 661 break; 662 #ifndef _KERNEL 663 case NV_TYPE_DESCRIPTOR: 664 ptr = nvpair_pack_descriptor(nvp, ptr, fdidxp, &left); 665 break; 666 #endif 667 case NV_TYPE_BINARY: 668 ptr = nvpair_pack_binary(nvp, ptr, &left); 669 break; 670 default: 671 PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp)); 672 } 673 if (ptr == NULL) { 674 nv_free(buf); 675 return (NULL); 676 } 677 while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) { 678 cookie = NULL; 679 nvl = nvlist_get_parent(nvl, &cookie); 680 if (nvl == NULL) 681 goto out; 682 nvp = cookie; 683 ptr = nvpair_pack_nvlist_up(ptr, &left); 684 if (ptr == NULL) 685 goto out; 686 } 687 } 688 689 out: 690 if (sizep != NULL) 691 *sizep = size; 692 return (buf); 693 } 694 695 void * 696 nvlist_pack(const nvlist_t *nvl, size_t *sizep) 697 { 698 699 NVLIST_ASSERT(nvl); 700 701 if (nvl->nvl_error != 0) { 702 ERRNO_SET(nvl->nvl_error); 703 return (NULL); 704 } 705 706 if (nvlist_ndescriptors(nvl) > 0) { 707 ERRNO_SET(EOPNOTSUPP); 708 return (NULL); 709 } 710 711 return (nvlist_xpack(nvl, NULL, sizep)); 712 } 713 714 static bool 715 nvlist_check_header(struct nvlist_header *nvlhdrp) 716 { 717 718 if (nvlhdrp->nvlh_magic != NVLIST_HEADER_MAGIC) { 719 ERRNO_SET(EINVAL); 720 return (false); 721 } 722 if ((nvlhdrp->nvlh_flags & ~NV_FLAG_ALL_MASK) != 0) { 723 ERRNO_SET(EINVAL); 724 return (false); 725 } 726 #if BYTE_ORDER == BIG_ENDIAN 727 if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) == 0) { 728 nvlhdrp->nvlh_size = le64toh(nvlhdrp->nvlh_size); 729 nvlhdrp->nvlh_descriptors = le64toh(nvlhdrp->nvlh_descriptors); 730 } 731 #else 732 if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0) { 733 nvlhdrp->nvlh_size = be64toh(nvlhdrp->nvlh_size); 734 nvlhdrp->nvlh_descriptors = be64toh(nvlhdrp->nvlh_descriptors); 735 } 736 #endif 737 return (true); 738 } 739 740 const unsigned char * 741 nvlist_unpack_header(nvlist_t *nvl, const unsigned char *ptr, size_t nfds, 742 bool *isbep, size_t *leftp) 743 { 744 struct nvlist_header nvlhdr; 745 746 if (*leftp < sizeof(nvlhdr)) 747 goto failed; 748 749 memcpy(&nvlhdr, ptr, sizeof(nvlhdr)); 750 751 if (!nvlist_check_header(&nvlhdr)) 752 goto failed; 753 754 if (nvlhdr.nvlh_size != *leftp - sizeof(nvlhdr)) 755 goto failed; 756 757 /* 758 * nvlh_descriptors might be smaller than nfds in embedded nvlists. 759 */ 760 if (nvlhdr.nvlh_descriptors > nfds) 761 goto failed; 762 763 if ((nvlhdr.nvlh_flags & ~NV_FLAG_ALL_MASK) != 0) 764 goto failed; 765 766 nvl->nvl_flags = (nvlhdr.nvlh_flags & NV_FLAG_PUBLIC_MASK); 767 768 ptr += sizeof(nvlhdr); 769 if (isbep != NULL) 770 *isbep = (((int)nvlhdr.nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0); 771 *leftp -= sizeof(nvlhdr); 772 773 return (ptr); 774 failed: 775 ERRNO_SET(EINVAL); 776 return (NULL); 777 } 778 779 static nvlist_t * 780 nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds, 781 int flags) 782 { 783 const unsigned char *ptr; 784 nvlist_t *nvl, *retnvl, *tmpnvl; 785 nvpair_t *nvp; 786 size_t left; 787 bool isbe; 788 789 PJDLOG_ASSERT((flags & ~(NV_FLAG_PUBLIC_MASK)) == 0); 790 791 left = size; 792 ptr = buf; 793 794 tmpnvl = NULL; 795 nvl = retnvl = nvlist_create(0); 796 if (nvl == NULL) 797 goto failed; 798 799 ptr = nvlist_unpack_header(nvl, ptr, nfds, &isbe, &left); 800 if (ptr == NULL) 801 goto failed; 802 if (nvl->nvl_flags != flags) { 803 ERRNO_SET(EILSEQ); 804 goto failed; 805 } 806 807 while (left > 0) { 808 ptr = nvpair_unpack(isbe, ptr, &left, &nvp); 809 if (ptr == NULL) 810 goto failed; 811 switch (nvpair_type(nvp)) { 812 case NV_TYPE_NULL: 813 ptr = nvpair_unpack_null(isbe, nvp, ptr, &left); 814 break; 815 case NV_TYPE_BOOL: 816 ptr = nvpair_unpack_bool(isbe, nvp, ptr, &left); 817 break; 818 case NV_TYPE_NUMBER: 819 ptr = nvpair_unpack_number(isbe, nvp, ptr, &left); 820 break; 821 case NV_TYPE_STRING: 822 ptr = nvpair_unpack_string(isbe, nvp, ptr, &left); 823 break; 824 case NV_TYPE_NVLIST: 825 ptr = nvpair_unpack_nvlist(isbe, nvp, ptr, &left, nfds, 826 &tmpnvl); 827 nvlist_set_parent(tmpnvl, nvp); 828 break; 829 #ifndef _KERNEL 830 case NV_TYPE_DESCRIPTOR: 831 ptr = nvpair_unpack_descriptor(isbe, nvp, ptr, &left, 832 fds, nfds); 833 break; 834 #endif 835 case NV_TYPE_BINARY: 836 ptr = nvpair_unpack_binary(isbe, nvp, ptr, &left); 837 break; 838 case NV_TYPE_NVLIST_UP: 839 if (nvl->nvl_parent == NULL) 840 goto failed; 841 nvl = nvpair_nvlist(nvl->nvl_parent); 842 nvpair_free_structure(nvp); 843 continue; 844 default: 845 PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp)); 846 } 847 if (ptr == NULL) 848 goto failed; 849 nvlist_move_nvpair(nvl, nvp); 850 if (tmpnvl != NULL) { 851 nvl = tmpnvl; 852 tmpnvl = NULL; 853 } 854 } 855 856 return (retnvl); 857 failed: 858 nvlist_destroy(retnvl); 859 return (NULL); 860 } 861 862 nvlist_t * 863 nvlist_unpack(const void *buf, size_t size, int flags) 864 { 865 866 return (nvlist_xunpack(buf, size, NULL, 0, flags)); 867 } 868 869 #ifndef _KERNEL 870 int 871 nvlist_send(int sock, const nvlist_t *nvl) 872 { 873 size_t datasize, nfds; 874 int *fds; 875 void *data; 876 int64_t fdidx; 877 int ret; 878 879 if (nvlist_error(nvl) != 0) { 880 ERRNO_SET(nvlist_error(nvl)); 881 return (-1); 882 } 883 884 fds = nvlist_descriptors(nvl, &nfds); 885 if (fds == NULL) 886 return (-1); 887 888 ret = -1; 889 data = NULL; 890 fdidx = 0; 891 892 data = nvlist_xpack(nvl, &fdidx, &datasize); 893 if (data == NULL) 894 goto out; 895 896 if (buf_send(sock, data, datasize) == -1) 897 goto out; 898 899 if (nfds > 0) { 900 if (fd_send(sock, fds, nfds) == -1) 901 goto out; 902 } 903 904 ret = 0; 905 out: 906 ERRNO_SAVE(); 907 nv_free(fds); 908 nv_free(data); 909 ERRNO_RESTORE(); 910 return (ret); 911 } 912 913 nvlist_t * 914 nvlist_recv(int sock, int flags) 915 { 916 struct nvlist_header nvlhdr; 917 nvlist_t *nvl, *ret; 918 unsigned char *buf; 919 size_t nfds, size, i; 920 int *fds; 921 922 if (buf_recv(sock, &nvlhdr, sizeof(nvlhdr)) == -1) 923 return (NULL); 924 925 if (!nvlist_check_header(&nvlhdr)) 926 return (NULL); 927 928 nfds = (size_t)nvlhdr.nvlh_descriptors; 929 size = sizeof(nvlhdr) + (size_t)nvlhdr.nvlh_size; 930 931 buf = nv_malloc(size); 932 if (buf == NULL) 933 return (NULL); 934 935 memcpy(buf, &nvlhdr, sizeof(nvlhdr)); 936 937 ret = NULL; 938 fds = NULL; 939 940 if (buf_recv(sock, buf + sizeof(nvlhdr), size - sizeof(nvlhdr)) == -1) 941 goto out; 942 943 if (nfds > 0) { 944 fds = nv_malloc(nfds * sizeof(fds[0])); 945 if (fds == NULL) 946 goto out; 947 if (fd_recv(sock, fds, nfds) == -1) 948 goto out; 949 } 950 951 nvl = nvlist_xunpack(buf, size, fds, nfds, flags); 952 if (nvl == NULL) { 953 ERRNO_SAVE(); 954 for (i = 0; i < nfds; i++) 955 close(fds[i]); 956 ERRNO_RESTORE(); 957 goto out; 958 } 959 960 ret = nvl; 961 out: 962 ERRNO_SAVE(); 963 nv_free(buf); 964 nv_free(fds); 965 ERRNO_RESTORE(); 966 967 return (ret); 968 } 969 970 nvlist_t * 971 nvlist_xfer(int sock, nvlist_t *nvl, int flags) 972 { 973 974 if (nvlist_send(sock, nvl) < 0) { 975 nvlist_destroy(nvl); 976 return (NULL); 977 } 978 nvlist_destroy(nvl); 979 return (nvlist_recv(sock, flags)); 980 } 981 #endif 982 983 nvpair_t * 984 nvlist_first_nvpair(const nvlist_t *nvl) 985 { 986 987 NVLIST_ASSERT(nvl); 988 989 return (TAILQ_FIRST(&nvl->nvl_head)); 990 } 991 992 nvpair_t * 993 nvlist_next_nvpair(const nvlist_t *nvl, const nvpair_t *nvp) 994 { 995 nvpair_t *retnvp; 996 997 NVLIST_ASSERT(nvl); 998 NVPAIR_ASSERT(nvp); 999 PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl); 1000 1001 retnvp = nvpair_next(nvp); 1002 PJDLOG_ASSERT(retnvp == NULL || nvpair_nvlist(retnvp) == nvl); 1003 1004 return (retnvp); 1005 1006 } 1007 1008 nvpair_t * 1009 nvlist_prev_nvpair(const nvlist_t *nvl, const nvpair_t *nvp) 1010 { 1011 nvpair_t *retnvp; 1012 1013 NVLIST_ASSERT(nvl); 1014 NVPAIR_ASSERT(nvp); 1015 PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl); 1016 1017 retnvp = nvpair_prev(nvp); 1018 PJDLOG_ASSERT(nvpair_nvlist(retnvp) == nvl); 1019 1020 return (retnvp); 1021 } 1022 1023 const char * 1024 nvlist_next(const nvlist_t *nvl, int *typep, void **cookiep) 1025 { 1026 nvpair_t *nvp; 1027 1028 NVLIST_ASSERT(nvl); 1029 PJDLOG_ASSERT(cookiep != NULL); 1030 1031 if (*cookiep == NULL) 1032 nvp = nvlist_first_nvpair(nvl); 1033 else 1034 nvp = nvlist_next_nvpair(nvl, *cookiep); 1035 if (nvp == NULL) 1036 return (NULL); 1037 if (typep != NULL) 1038 *typep = nvpair_type(nvp); 1039 *cookiep = nvp; 1040 return (nvpair_name(nvp)); 1041 } 1042 1043 bool 1044 nvlist_exists(const nvlist_t *nvl, const char *name) 1045 { 1046 1047 return (nvlist_find(nvl, NV_TYPE_NONE, name) != NULL); 1048 } 1049 1050 #define NVLIST_EXISTS(type, TYPE) \ 1051 bool \ 1052 nvlist_exists_##type(const nvlist_t *nvl, const char *name) \ 1053 { \ 1054 \ 1055 return (nvlist_find(nvl, NV_TYPE_##TYPE, name) != NULL); \ 1056 } 1057 1058 NVLIST_EXISTS(null, NULL) 1059 NVLIST_EXISTS(bool, BOOL) 1060 NVLIST_EXISTS(number, NUMBER) 1061 NVLIST_EXISTS(string, STRING) 1062 NVLIST_EXISTS(nvlist, NVLIST) 1063 #ifndef _KERNEL 1064 NVLIST_EXISTS(descriptor, DESCRIPTOR) 1065 #endif 1066 NVLIST_EXISTS(binary, BINARY) 1067 1068 #undef NVLIST_EXISTS 1069 1070 void 1071 nvlist_add_nvpair(nvlist_t *nvl, const nvpair_t *nvp) 1072 { 1073 nvpair_t *newnvp; 1074 1075 NVPAIR_ASSERT(nvp); 1076 1077 if (nvlist_error(nvl) != 0) { 1078 ERRNO_SET(nvlist_error(nvl)); 1079 return; 1080 } 1081 if ((nvl->nvl_flags & NV_FLAG_NO_UNIQUE) == 0) { 1082 if (nvlist_exists(nvl, nvpair_name(nvp))) { 1083 nvl->nvl_error = EEXIST; 1084 ERRNO_SET(nvlist_error(nvl)); 1085 return; 1086 } 1087 } 1088 1089 newnvp = nvpair_clone(nvp); 1090 if (newnvp == NULL) { 1091 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1092 ERRNO_SET(nvlist_error(nvl)); 1093 return; 1094 } 1095 1096 nvpair_insert(&nvl->nvl_head, newnvp, nvl); 1097 } 1098 1099 void 1100 nvlist_add_stringf(nvlist_t *nvl, const char *name, const char *valuefmt, ...) 1101 { 1102 va_list valueap; 1103 1104 va_start(valueap, valuefmt); 1105 nvlist_add_stringv(nvl, name, valuefmt, valueap); 1106 va_end(valueap); 1107 } 1108 1109 void 1110 nvlist_add_stringv(nvlist_t *nvl, const char *name, const char *valuefmt, 1111 va_list valueap) 1112 { 1113 nvpair_t *nvp; 1114 1115 if (nvlist_error(nvl) != 0) { 1116 ERRNO_SET(nvlist_error(nvl)); 1117 return; 1118 } 1119 1120 nvp = nvpair_create_stringv(name, valuefmt, valueap); 1121 if (nvp == NULL) { 1122 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1123 ERRNO_SET(nvl->nvl_error); 1124 } else { 1125 nvlist_move_nvpair(nvl, nvp); 1126 } 1127 } 1128 1129 void 1130 nvlist_add_null(nvlist_t *nvl, const char *name) 1131 { 1132 nvpair_t *nvp; 1133 1134 if (nvlist_error(nvl) != 0) { 1135 ERRNO_SET(nvlist_error(nvl)); 1136 return; 1137 } 1138 1139 nvp = nvpair_create_null(name); 1140 if (nvp == NULL) { 1141 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1142 ERRNO_SET(nvl->nvl_error); 1143 } else { 1144 nvlist_move_nvpair(nvl, nvp); 1145 } 1146 } 1147 1148 void 1149 nvlist_add_binary(nvlist_t *nvl, const char *name, const void *value, 1150 size_t size) 1151 { 1152 nvpair_t *nvp; 1153 1154 if (nvlist_error(nvl) != 0) { 1155 ERRNO_SET(nvlist_error(nvl)); 1156 return; 1157 } 1158 1159 nvp = nvpair_create_binary(name, value, size); 1160 if (nvp == NULL) { 1161 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1162 ERRNO_SET(nvl->nvl_error); 1163 } else { 1164 nvlist_move_nvpair(nvl, nvp); 1165 } 1166 } 1167 1168 1169 #define NVLIST_ADD(vtype, type) \ 1170 void \ 1171 nvlist_add_##type(nvlist_t *nvl, const char *name, vtype value) \ 1172 { \ 1173 nvpair_t *nvp; \ 1174 \ 1175 if (nvlist_error(nvl) != 0) { \ 1176 ERRNO_SET(nvlist_error(nvl)); \ 1177 return; \ 1178 } \ 1179 \ 1180 nvp = nvpair_create_##type(name, value); \ 1181 if (nvp == NULL) { \ 1182 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); \ 1183 ERRNO_SET(nvl->nvl_error); \ 1184 } else { \ 1185 nvlist_move_nvpair(nvl, nvp); \ 1186 } \ 1187 } 1188 1189 NVLIST_ADD(bool, bool) 1190 NVLIST_ADD(uint64_t, number) 1191 NVLIST_ADD(const char *, string) 1192 NVLIST_ADD(const nvlist_t *, nvlist) 1193 #ifndef _KERNEL 1194 NVLIST_ADD(int, descriptor); 1195 #endif 1196 1197 #undef NVLIST_ADD 1198 1199 void 1200 nvlist_move_nvpair(nvlist_t *nvl, nvpair_t *nvp) 1201 { 1202 1203 NVPAIR_ASSERT(nvp); 1204 PJDLOG_ASSERT(nvpair_nvlist(nvp) == NULL); 1205 1206 if (nvlist_error(nvl) != 0) { 1207 nvpair_free(nvp); 1208 ERRNO_SET(nvlist_error(nvl)); 1209 return; 1210 } 1211 if ((nvl->nvl_flags & NV_FLAG_NO_UNIQUE) == 0) { 1212 if (nvlist_exists(nvl, nvpair_name(nvp))) { 1213 nvpair_free(nvp); 1214 nvl->nvl_error = EEXIST; 1215 ERRNO_SET(nvl->nvl_error); 1216 return; 1217 } 1218 } 1219 1220 nvpair_insert(&nvl->nvl_head, nvp, nvl); 1221 } 1222 1223 void 1224 nvlist_move_string(nvlist_t *nvl, const char *name, char *value) 1225 { 1226 nvpair_t *nvp; 1227 1228 if (nvlist_error(nvl) != 0) { 1229 nv_free(value); 1230 ERRNO_SET(nvlist_error(nvl)); 1231 return; 1232 } 1233 1234 nvp = nvpair_move_string(name, value); 1235 if (nvp == NULL) { 1236 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1237 ERRNO_SET(nvl->nvl_error); 1238 } else { 1239 nvlist_move_nvpair(nvl, nvp); 1240 } 1241 } 1242 1243 void 1244 nvlist_move_nvlist(nvlist_t *nvl, const char *name, nvlist_t *value) 1245 { 1246 nvpair_t *nvp; 1247 1248 if (nvlist_error(nvl) != 0) { 1249 if (value != NULL && nvlist_get_nvpair_parent(value) != NULL) 1250 nvlist_destroy(value); 1251 ERRNO_SET(nvlist_error(nvl)); 1252 return; 1253 } 1254 1255 nvp = nvpair_move_nvlist(name, value); 1256 if (nvp == NULL) { 1257 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1258 ERRNO_SET(nvl->nvl_error); 1259 } else { 1260 nvlist_move_nvpair(nvl, nvp); 1261 } 1262 } 1263 1264 #ifndef _KERNEL 1265 void 1266 nvlist_move_descriptor(nvlist_t *nvl, const char *name, int value) 1267 { 1268 nvpair_t *nvp; 1269 1270 if (nvlist_error(nvl) != 0) { 1271 close(value); 1272 ERRNO_SET(nvlist_error(nvl)); 1273 return; 1274 } 1275 1276 nvp = nvpair_move_descriptor(name, value); 1277 if (nvp == NULL) { 1278 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1279 ERRNO_SET(nvl->nvl_error); 1280 } else { 1281 nvlist_move_nvpair(nvl, nvp); 1282 } 1283 } 1284 #endif 1285 1286 void 1287 nvlist_move_binary(nvlist_t *nvl, const char *name, void *value, size_t size) 1288 { 1289 nvpair_t *nvp; 1290 1291 if (nvlist_error(nvl) != 0) { 1292 nv_free(value); 1293 ERRNO_SET(nvlist_error(nvl)); 1294 return; 1295 } 1296 1297 nvp = nvpair_move_binary(name, value, size); 1298 if (nvp == NULL) { 1299 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1300 ERRNO_SET(nvl->nvl_error); 1301 } else { 1302 nvlist_move_nvpair(nvl, nvp); 1303 } 1304 } 1305 1306 const nvpair_t * 1307 nvlist_get_nvpair(const nvlist_t *nvl, const char *name) 1308 { 1309 1310 return (nvlist_find(nvl, NV_TYPE_NONE, name)); 1311 } 1312 1313 #define NVLIST_GET(ftype, type, TYPE) \ 1314 ftype \ 1315 nvlist_get_##type(const nvlist_t *nvl, const char *name) \ 1316 { \ 1317 const nvpair_t *nvp; \ 1318 \ 1319 nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name); \ 1320 if (nvp == NULL) \ 1321 nvlist_report_missing(NV_TYPE_##TYPE, name); \ 1322 return (nvpair_get_##type(nvp)); \ 1323 } 1324 1325 NVLIST_GET(bool, bool, BOOL) 1326 NVLIST_GET(uint64_t, number, NUMBER) 1327 NVLIST_GET(const char *, string, STRING) 1328 NVLIST_GET(const nvlist_t *, nvlist, NVLIST) 1329 #ifndef _KERNEL 1330 NVLIST_GET(int, descriptor, DESCRIPTOR) 1331 #endif 1332 1333 #undef NVLIST_GET 1334 1335 const void * 1336 nvlist_get_binary(const nvlist_t *nvl, const char *name, size_t *sizep) 1337 { 1338 nvpair_t *nvp; 1339 1340 nvp = nvlist_find(nvl, NV_TYPE_BINARY, name); 1341 if (nvp == NULL) 1342 nvlist_report_missing(NV_TYPE_BINARY, name); 1343 1344 return (nvpair_get_binary(nvp, sizep)); 1345 } 1346 1347 #define NVLIST_TAKE(ftype, type, TYPE) \ 1348 ftype \ 1349 nvlist_take_##type(nvlist_t *nvl, const char *name) \ 1350 { \ 1351 nvpair_t *nvp; \ 1352 ftype value; \ 1353 \ 1354 nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name); \ 1355 if (nvp == NULL) \ 1356 nvlist_report_missing(NV_TYPE_##TYPE, name); \ 1357 value = (ftype)(intptr_t)nvpair_get_##type(nvp); \ 1358 nvlist_remove_nvpair(nvl, nvp); \ 1359 nvpair_free_structure(nvp); \ 1360 return (value); \ 1361 } 1362 1363 NVLIST_TAKE(bool, bool, BOOL) 1364 NVLIST_TAKE(uint64_t, number, NUMBER) 1365 NVLIST_TAKE(char *, string, STRING) 1366 NVLIST_TAKE(nvlist_t *, nvlist, NVLIST) 1367 #ifndef _KERNEL 1368 NVLIST_TAKE(int, descriptor, DESCRIPTOR) 1369 #endif 1370 1371 #undef NVLIST_TAKE 1372 1373 void * 1374 nvlist_take_binary(nvlist_t *nvl, const char *name, size_t *sizep) 1375 { 1376 nvpair_t *nvp; 1377 void *value; 1378 1379 nvp = nvlist_find(nvl, NV_TYPE_BINARY, name); 1380 if (nvp == NULL) 1381 nvlist_report_missing(NV_TYPE_BINARY, name); 1382 1383 value = (void *)(intptr_t)nvpair_get_binary(nvp, sizep); 1384 nvlist_remove_nvpair(nvl, nvp); 1385 nvpair_free_structure(nvp); 1386 return (value); 1387 } 1388 1389 void 1390 nvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp) 1391 { 1392 1393 NVLIST_ASSERT(nvl); 1394 NVPAIR_ASSERT(nvp); 1395 PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl); 1396 1397 nvpair_remove(&nvl->nvl_head, nvp, nvl); 1398 } 1399 1400 void 1401 nvlist_free(nvlist_t *nvl, const char *name) 1402 { 1403 1404 nvlist_free_type(nvl, name, NV_TYPE_NONE); 1405 } 1406 1407 #define NVLIST_FREE(type, TYPE) \ 1408 void \ 1409 nvlist_free_##type(nvlist_t *nvl, const char *name) \ 1410 { \ 1411 \ 1412 nvlist_free_type(nvl, name, NV_TYPE_##TYPE); \ 1413 } 1414 1415 NVLIST_FREE(null, NULL) 1416 NVLIST_FREE(bool, BOOL) 1417 NVLIST_FREE(number, NUMBER) 1418 NVLIST_FREE(string, STRING) 1419 NVLIST_FREE(nvlist, NVLIST) 1420 #ifndef _KERNEL 1421 NVLIST_FREE(descriptor, DESCRIPTOR) 1422 #endif 1423 NVLIST_FREE(binary, BINARY) 1424 1425 #undef NVLIST_FREE 1426 1427 void 1428 nvlist_free_nvpair(nvlist_t *nvl, nvpair_t *nvp) 1429 { 1430 1431 NVLIST_ASSERT(nvl); 1432 NVPAIR_ASSERT(nvp); 1433 PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl); 1434 1435 nvlist_remove_nvpair(nvl, nvp); 1436 nvpair_free(nvp); 1437 } 1438 1439