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