1/* $NetBSD: nvlist.c,v 1.8 2019/07/23 00:49:16 rmind Exp $ */ 2 3/*- 4 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 5 * 6 * Copyright (c) 2009-2013 The FreeBSD Foundation 7 * Copyright (c) 2013-2015 Mariusz Zaborski <oshogbo@FreeBSD.org> 8 * All rights reserved. 9 * 10 * This software was developed by Pawel Jakub Dawidek under sponsorship from 11 * the FreeBSD Foundation. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35#include <sys/cdefs.h> 36#ifdef __FreeBSD__ 37__FBSDID("$FreeBSD: head/sys/contrib/libnv/nvlist.c 335347 2018-06-18 22:57:32Z oshogbo $"); 38#else 39__RCSID("$NetBSD: nvlist.c,v 1.8 2019/07/23 00:49:16 rmind Exp $"); 40#endif 41 42#include <sys/param.h> 43#include <sys/endian.h> 44#include <sys/queue.h> 45 46#if defined(_KERNEL) || defined(_STANDALONE) 47 48#include <sys/errno.h> 49#include <sys/kernel.h> 50#include <sys/lock.h> 51#include <sys/malloc.h> 52#include <sys/systm.h> 53 54#ifdef __FreeBSD__ 55#include <machine/stdarg.h> 56#endif 57 58#else 59#include <sys/socket.h> 60 61#include <errno.h> 62#include <stdarg.h> 63#include <stdbool.h> 64#include <stdint.h> 65#include <stdio.h> 66#include <stdlib.h> 67#include <string.h> 68#include <unistd.h> 69 70#include "msgio.h" 71#endif 72 73#ifdef HAVE_PJDLOG 74#include <pjdlog.h> 75#endif 76 77#ifdef __FreeBSD__ 78#include <sys/nv.h> 79#else 80#include "nv.h" 81#endif 82 83#include "nv_impl.h" 84#include "nvlist_impl.h" 85#include "nvpair_impl.h" 86 87#ifndef HAVE_PJDLOG 88#if defined(_KERNEL) || defined(_STANDALONE) 89#ifdef __FreeBSD__ 90#define PJDLOG_ASSERT(...) MPASS(__VA_ARGS__) 91#else 92#define PJDLOG_ASSERT(...) KASSERT(__VA_ARGS__) 93#endif 94#define PJDLOG_RASSERT(expr, ...) KASSERT(expr, (__VA_ARGS__)) 95#define PJDLOG_ABORT(...) panic(__VA_ARGS__) 96#else 97#ifndef __lint__ 98#include <assert.h> 99#define PJDLOG_ASSERT(...) assert(__VA_ARGS__) 100#define PJDLOG_RASSERT(expr, ...) assert(expr) 101#define PJDLOG_ABORT(...) do { \ 102 fprintf(stderr, "%s:%u: ", __FILE__, __LINE__); \ 103 fprintf(stderr, __VA_ARGS__); \ 104 fprintf(stderr, "\n"); \ 105 abort(); \ 106} while (/*CONSTCOND*/0) 107#else 108#define PJDLOG_ASSERT(...) 109#define PJDLOG_RASSERT(expr, ...) 110#define PJDLOG_ABORT(...) 111#endif 112#endif 113#endif 114 115#define NV_FLAG_PRIVATE_MASK (NV_FLAG_BIG_ENDIAN | NV_FLAG_IN_ARRAY) 116#define NV_FLAG_PUBLIC_MASK (NV_FLAG_IGNORE_CASE | NV_FLAG_NO_UNIQUE) 117#define NV_FLAG_ALL_MASK (NV_FLAG_PRIVATE_MASK | NV_FLAG_PUBLIC_MASK) 118 119#define NVLIST_MAGIC 0x6e766c /* "nvl" */ 120struct nvlist { 121 int nvl_magic; 122 int nvl_error; 123 int nvl_flags; 124 nvpair_t *nvl_parent; 125 nvpair_t *nvl_array_next; 126 struct nvl_head nvl_head; 127}; 128 129#define NVLIST_ASSERT(nvl) do { \ 130 PJDLOG_ASSERT((nvl) != NULL); \ 131 PJDLOG_ASSERT((nvl)->nvl_magic == NVLIST_MAGIC); \ 132} while (/*CONSTCOND*/0) 133 134#ifdef _KERNEL 135MALLOC_DEFINE(M_NVLIST, "nvlist", "kernel nvlist"); 136#endif 137 138#define NVPAIR_ASSERT(nvp) nvpair_assert(nvp) 139 140#define NVLIST_HEADER_MAGIC 0x6c 141#define NVLIST_HEADER_VERSION 0x00 142struct nvlist_header { 143 uint8_t nvlh_magic; 144 uint8_t nvlh_version; 145 uint8_t nvlh_flags; 146 uint64_t nvlh_descriptors; 147 uint64_t nvlh_size; 148} __packed; 149 150nvlist_t * 151nvlist_create(int flags) 152{ 153 nvlist_t *nvl; 154 155 PJDLOG_ASSERT((flags & ~(NV_FLAG_PUBLIC_MASK)) == 0); 156 157 nvl = nv_malloc(sizeof(*nvl)); 158 if (nvl == NULL) 159 return (NULL); 160 nvl->nvl_error = 0; 161 nvl->nvl_flags = flags; 162 nvl->nvl_parent = NULL; 163 nvl->nvl_array_next = NULL; 164 TAILQ_INIT(&nvl->nvl_head); 165 nvl->nvl_magic = NVLIST_MAGIC; 166 167 return (nvl); 168} 169 170void 171nvlist_destroy(nvlist_t *nvl) 172{ 173 nvpair_t *nvp; 174 175 if (nvl == NULL) 176 return; 177 178 ERRNO_SAVE(); 179 180 NVLIST_ASSERT(nvl); 181 182 while ((nvp = nvlist_first_nvpair(nvl)) != NULL) { 183 nvlist_remove_nvpair(nvl, nvp); 184 nvpair_free(nvp); 185 } 186 if (nvl->nvl_array_next != NULL) 187 nvpair_free_structure(nvl->nvl_array_next); 188 nvl->nvl_array_next = NULL; 189 nvl->nvl_parent = NULL; 190 nvl->nvl_magic = 0; 191 nv_free(nvl); 192 193 ERRNO_RESTORE(); 194} 195 196void 197nvlist_set_error(nvlist_t *nvl, int error) 198{ 199 200 PJDLOG_ASSERT(error != 0); 201 202 /* 203 * Check for error != 0 so that we don't do the wrong thing if somebody 204 * tries to abuse this API when asserts are disabled. 205 */ 206 if (nvl != NULL && error != 0 && nvl->nvl_error == 0) 207 nvl->nvl_error = error; 208} 209 210int 211nvlist_error(const nvlist_t *nvl) 212{ 213 214 if (nvl == NULL) 215 return (ENOMEM); 216 217 NVLIST_ASSERT(nvl); 218 219 return (nvl->nvl_error); 220} 221 222nvpair_t * 223nvlist_get_nvpair_parent(const nvlist_t *nvl) 224{ 225 226 NVLIST_ASSERT(nvl); 227 228 return (nvl->nvl_parent); 229} 230 231const nvlist_t * 232nvlist_get_parent(const nvlist_t *nvl, void **cookiep) 233{ 234 nvpair_t *nvp; 235 236 NVLIST_ASSERT(nvl); 237 238 nvp = nvl->nvl_parent; 239 if (cookiep != NULL) 240 *cookiep = nvp; 241 if (nvp == NULL) 242 return (NULL); 243 244 return (nvpair_nvlist(nvp)); 245} 246 247void 248nvlist_set_parent(nvlist_t *nvl, nvpair_t *parent) 249{ 250 251 NVLIST_ASSERT(nvl); 252 253 nvl->nvl_parent = parent; 254} 255 256void 257nvlist_set_array_next(nvlist_t *nvl, nvpair_t *ele) 258{ 259 260 NVLIST_ASSERT(nvl); 261 262 if (ele != NULL) { 263 nvl->nvl_flags |= NV_FLAG_IN_ARRAY; 264 } else { 265 nvl->nvl_flags &= ~NV_FLAG_IN_ARRAY; 266 nv_free(nvl->nvl_array_next); 267 } 268 269 nvl->nvl_array_next = ele; 270} 271 272nvpair_t * 273nvlist_get_array_next_nvpair(nvlist_t *nvl) 274{ 275 276 NVLIST_ASSERT(nvl); 277 278 return (nvl->nvl_array_next); 279} 280 281bool 282nvlist_in_array(const nvlist_t *nvl) 283{ 284 285 NVLIST_ASSERT(nvl); 286 287 return ((nvl->nvl_flags & NV_FLAG_IN_ARRAY) != 0); 288} 289 290const nvlist_t * 291nvlist_get_array_next(const nvlist_t *nvl) 292{ 293 nvpair_t *nvp; 294 295 NVLIST_ASSERT(nvl); 296 297 nvp = nvl->nvl_array_next; 298 if (nvp == NULL) 299 return (NULL); 300 301 return (nvpair_get_nvlist(nvp)); 302} 303 304const nvlist_t * 305nvlist_get_pararr(const nvlist_t *nvl, void **cookiep) 306{ 307 const nvlist_t *ret; 308 309 ret = nvlist_get_array_next(nvl); 310 if (ret != NULL) { 311 if (cookiep != NULL) 312 *cookiep = NULL; 313 return (ret); 314 } 315 316 return (nvlist_get_parent(nvl, cookiep)); 317} 318 319bool 320nvlist_empty(const nvlist_t *nvl) 321{ 322 323 NVLIST_ASSERT(nvl); 324 PJDLOG_ASSERT(nvl->nvl_error == 0); 325 326 return (nvlist_first_nvpair(nvl) == NULL); 327} 328 329int 330nvlist_flags(const nvlist_t *nvl) 331{ 332 333 NVLIST_ASSERT(nvl); 334 PJDLOG_ASSERT(nvl->nvl_error == 0); 335 336 return (nvl->nvl_flags & NV_FLAG_PUBLIC_MASK); 337} 338 339void 340nvlist_set_flags(nvlist_t *nvl, int flags) 341{ 342 343 NVLIST_ASSERT(nvl); 344 PJDLOG_ASSERT(nvl->nvl_error == 0); 345 346 nvl->nvl_flags = flags; 347} 348 349__dead void 350nvlist_report_missing(int type, const char *name) 351{ 352 353 PJDLOG_ABORT("Element '%s' of type %s doesn't exist.", 354 name, nvpair_type_string(type)); 355} 356 357static nvpair_t * 358nvlist_find(const nvlist_t *nvl, int type, const char *name) 359{ 360 nvpair_t *nvp; 361 362 NVLIST_ASSERT(nvl); 363 PJDLOG_ASSERT(nvl->nvl_error == 0); 364 PJDLOG_ASSERT(type == NV_TYPE_NONE || 365 (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST)); 366 367 for (nvp = nvlist_first_nvpair(nvl); nvp != NULL; 368 nvp = nvlist_next_nvpair(nvl, nvp)) { 369 if (type != NV_TYPE_NONE && nvpair_type(nvp) != type) 370 continue; 371 if ((nvl->nvl_flags & NV_FLAG_IGNORE_CASE) != 0) { 372 if (strcasecmp(nvpair_name(nvp), name) != 0) 373 continue; 374 } else { 375 if (strcmp(nvpair_name(nvp), name) != 0) 376 continue; 377 } 378 break; 379 } 380 381 if (nvp == NULL) 382 ERRNO_SET(ENOENT); 383 384 return (nvp); 385} 386 387bool 388nvlist_exists_type(const nvlist_t *nvl, const char *name, int type) 389{ 390 391 NVLIST_ASSERT(nvl); 392 PJDLOG_ASSERT(nvl->nvl_error == 0); 393 PJDLOG_ASSERT(type == NV_TYPE_NONE || 394 (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST)); 395 396 return (nvlist_find(nvl, type, name) != NULL); 397} 398 399void 400nvlist_free_type(nvlist_t *nvl, const char *name, int type) 401{ 402 nvpair_t *nvp; 403 404 NVLIST_ASSERT(nvl); 405 PJDLOG_ASSERT(nvl->nvl_error == 0); 406 PJDLOG_ASSERT(type == NV_TYPE_NONE || 407 (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST)); 408 409 nvp = nvlist_find(nvl, type, name); 410 if (nvp != NULL) 411 nvlist_free_nvpair(nvl, nvp); 412 else 413 nvlist_report_missing(type, name); 414} 415 416nvlist_t * 417nvlist_clone(const nvlist_t *nvl) 418{ 419 nvlist_t *newnvl; 420 nvpair_t *nvp, *newnvp; 421 422 NVLIST_ASSERT(nvl); 423 424 if (nvl->nvl_error != 0) { 425 ERRNO_SET(nvl->nvl_error); 426 return (NULL); 427 } 428 429 newnvl = nvlist_create(nvl->nvl_flags & NV_FLAG_PUBLIC_MASK); 430 for (nvp = nvlist_first_nvpair(nvl); nvp != NULL; 431 nvp = nvlist_next_nvpair(nvl, nvp)) { 432 newnvp = nvpair_clone(nvp); 433 if (newnvp == NULL) 434 break; 435 (void)nvlist_move_nvpair(newnvl, newnvp); 436 } 437 if (nvp != NULL) { 438 nvlist_destroy(newnvl); 439 return (NULL); 440 } 441 return (newnvl); 442} 443 444#if !defined(_KERNEL) && !defined(_STANDALONE) 445static bool 446nvlist_dump_error_check(const nvlist_t *nvl, int fd, int level) 447{ 448 449 if (nvlist_error(nvl) != 0) { 450 dprintf(fd, "%*serror: %d\n", level * 4, "", 451 nvlist_error(nvl)); 452 return (true); 453 } 454 455 return (false); 456} 457 458/* 459 * Dump content of nvlist. 460 */ 461void 462nvlist_dump(const nvlist_t *nvl, int fd) 463{ 464 const nvlist_t *tmpnvl; 465 nvpair_t *nvp, *tmpnvp; 466 void *cookie; 467 int level; 468 469 level = 0; 470 if (nvlist_dump_error_check(nvl, fd, level)) 471 return; 472 473 nvp = nvlist_first_nvpair(nvl); 474 while (nvp != NULL) { 475 dprintf(fd, "%*s%s (%s):", level * 4, "", nvpair_name(nvp), 476 nvpair_type_string(nvpair_type(nvp))); 477 switch (nvpair_type(nvp)) { 478 case NV_TYPE_NULL: 479 dprintf(fd, " null\n"); 480 break; 481 case NV_TYPE_BOOL: 482 dprintf(fd, " %s\n", nvpair_get_bool(nvp) ? 483 "TRUE" : "FALSE"); 484 break; 485 case NV_TYPE_NUMBER: 486 dprintf(fd, " %ju (%jd) (0x%jx)\n", 487 (uintmax_t)nvpair_get_number(nvp), 488 (intmax_t)nvpair_get_number(nvp), 489 (uintmax_t)nvpair_get_number(nvp)); 490 break; 491 case NV_TYPE_STRING: 492 dprintf(fd, " [%s]\n", nvpair_get_string(nvp)); 493 break; 494 case NV_TYPE_NVLIST: 495 dprintf(fd, "\n"); 496 tmpnvl = nvpair_get_nvlist(nvp); 497 if (nvlist_dump_error_check(tmpnvl, fd, level + 1)) 498 break; 499 tmpnvp = nvlist_first_nvpair(tmpnvl); 500 if (tmpnvp != NULL) { 501 nvl = tmpnvl; 502 nvp = tmpnvp; 503 level++; 504 continue; 505 } 506 break; 507 case NV_TYPE_DESCRIPTOR: 508 dprintf(fd, " %d\n", nvpair_get_descriptor(nvp)); 509 break; 510 case NV_TYPE_BINARY: 511 { 512 const unsigned char *binary; 513 unsigned int ii; 514 size_t size; 515 516 binary = nvpair_get_binary(nvp, &size); 517 dprintf(fd, " %zu ", size); 518 for (ii = 0; ii < size; ii++) 519 dprintf(fd, "%02hhx", binary[ii]); 520 dprintf(fd, "\n"); 521 break; 522 } 523 case NV_TYPE_BOOL_ARRAY: 524 { 525 const bool *value; 526 unsigned int ii; 527 size_t nitems; 528 529 value = nvpair_get_bool_array(nvp, &nitems); 530 dprintf(fd, " [ "); 531 for (ii = 0; ii < nitems; ii++) { 532 dprintf(fd, "%s", value[ii] ? "TRUE" : "FALSE"); 533 if (ii != nitems - 1) 534 dprintf(fd, ", "); 535 } 536 dprintf(fd, " ]\n"); 537 break; 538 } 539 case NV_TYPE_STRING_ARRAY: 540 { 541 const char * const *value; 542 unsigned int ii; 543 size_t nitems; 544 545 value = nvpair_get_string_array(nvp, &nitems); 546 dprintf(fd, " [ "); 547 for (ii = 0; ii < nitems; ii++) { 548 if (value[ii] == NULL) 549 dprintf(fd, "NULL"); 550 else 551 dprintf(fd, "\"%s\"", value[ii]); 552 if (ii != nitems - 1) 553 dprintf(fd, ", "); 554 } 555 dprintf(fd, " ]\n"); 556 break; 557 } 558 case NV_TYPE_NUMBER_ARRAY: 559 { 560 const uint64_t *value; 561 unsigned int ii; 562 size_t nitems; 563 564 value = nvpair_get_number_array(nvp, &nitems); 565 dprintf(fd, " [ "); 566 for (ii = 0; ii < nitems; ii++) { 567 dprintf(fd, "%ju (%jd) (0x%jx)", 568 value[ii], value[ii], value[ii]); 569 if (ii != nitems - 1) 570 dprintf(fd, ", "); 571 } 572 dprintf(fd, " ]\n"); 573 break; 574 } 575 case NV_TYPE_DESCRIPTOR_ARRAY: 576 { 577 const int *value; 578 unsigned int ii; 579 size_t nitems; 580 581 value = nvpair_get_descriptor_array(nvp, &nitems); 582 dprintf(fd, " [ "); 583 for (ii = 0; ii < nitems; ii++) { 584 dprintf(fd, "%d", value[ii]); 585 if (ii != nitems - 1) 586 dprintf(fd, ", "); 587 } 588 dprintf(fd, " ]\n"); 589 break; 590 } 591 case NV_TYPE_NVLIST_ARRAY: 592 { 593 const nvlist_t * const *value; 594 unsigned int ii; 595 size_t nitems; 596 597 value = nvpair_get_nvlist_array(nvp, &nitems); 598 dprintf(fd, " %zu\n", nitems); 599 tmpnvl = NULL; 600 tmpnvp = NULL; 601 for (ii = 0; ii < nitems; ii++) { 602 if (nvlist_dump_error_check(value[ii], fd, 603 level + 1)) { 604 break; 605 } 606 607 if (tmpnvl == NULL) { 608 tmpnvp = nvlist_first_nvpair(value[ii]); 609 if (tmpnvp != NULL) { 610 tmpnvl = value[ii]; 611 } else { 612 dprintf(fd, "%*s,\n", 613 (level + 1) * 4, ""); 614 } 615 } 616 } 617 if (tmpnvp != NULL) { 618 nvl = tmpnvl; 619 nvp = tmpnvp; 620 level++; 621 continue; 622 } 623 break; 624 } 625 default: 626 PJDLOG_ABORT("Unknown type: %d.", nvpair_type(nvp)); 627 } 628 629 while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) { 630 do { 631 cookie = NULL; 632 if (nvlist_in_array(nvl)) 633 dprintf(fd, "%*s,\n", level * 4, ""); 634 nvl = nvlist_get_pararr(nvl, &cookie); 635 if (nvl == NULL) 636 return; 637 if (nvlist_in_array(nvl) && cookie == NULL) { 638 nvp = nvlist_first_nvpair(nvl); 639 } else { 640 nvp = cookie; 641 level--; 642 } 643 } while (nvp == NULL); 644 if (nvlist_in_array(nvl) && cookie == NULL) 645 break; 646 } 647 } 648} 649 650void 651nvlist_fdump(const nvlist_t *nvl, FILE *fp) 652{ 653 654 fflush(fp); 655 nvlist_dump(nvl, fileno(fp)); 656} 657#endif 658 659/* 660 * The function obtains size of the nvlist after nvlist_pack(). 661 */ 662size_t 663nvlist_size(const nvlist_t *nvl) 664{ 665 const nvlist_t *tmpnvl; 666 const nvlist_t * const *nvlarray; 667 const nvpair_t *nvp, *tmpnvp; 668 void *cookie; 669 size_t size, nitems; 670 unsigned int ii; 671 672 NVLIST_ASSERT(nvl); 673 PJDLOG_ASSERT(nvl->nvl_error == 0); 674 675 size = sizeof(struct nvlist_header); 676 nvp = nvlist_first_nvpair(nvl); 677 while (nvp != NULL) { 678 size += nvpair_header_size(); 679 size += strlen(nvpair_name(nvp)) + 1; 680 if (nvpair_type(nvp) == NV_TYPE_NVLIST) { 681 size += sizeof(struct nvlist_header); 682 size += nvpair_header_size() + 1; 683 tmpnvl = nvpair_get_nvlist(nvp); 684 PJDLOG_ASSERT(tmpnvl->nvl_error == 0); 685 tmpnvp = nvlist_first_nvpair(tmpnvl); 686 if (tmpnvp != NULL) { 687 nvl = tmpnvl; 688 nvp = tmpnvp; 689 continue; 690 } 691 } else if (nvpair_type(nvp) == NV_TYPE_NVLIST_ARRAY) { 692 nvlarray = nvpair_get_nvlist_array(nvp, &nitems); 693 PJDLOG_ASSERT(nitems > 0); 694 695 size += (nvpair_header_size() + 1) * nitems; 696 size += sizeof(struct nvlist_header) * nitems; 697 698 tmpnvl = NULL; 699 tmpnvp = NULL; 700 for (ii = 0; ii < nitems; ii++) { 701 PJDLOG_ASSERT(nvlarray[ii]->nvl_error == 0); 702 tmpnvp = nvlist_first_nvpair(nvlarray[ii]); 703 if (tmpnvp != NULL) { 704 tmpnvl = nvlarray[ii]; 705 break; 706 } 707 } 708 if (tmpnvp != NULL) { 709 nvp = tmpnvp; 710 nvl = tmpnvl; 711 continue; 712 } 713 714 } else { 715 size += nvpair_size(nvp); 716 } 717 718 while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) { 719 do { 720 cookie = NULL; 721 nvl = nvlist_get_pararr(nvl, &cookie); 722 if (nvl == NULL) 723 goto out; 724 if (nvlist_in_array(nvl) && cookie == NULL) { 725 nvp = nvlist_first_nvpair(nvl); 726 } else { 727 nvp = cookie; 728 } 729 } while (nvp == NULL); 730 if (nvlist_in_array(nvl) && cookie == NULL) 731 break; 732 } 733 } 734 735out: 736 return (size); 737} 738 739#if !defined(_KERNEL) && !defined(_STANDALONE) 740static int * 741nvlist_xdescriptors(const nvlist_t *nvl, int *descs) 742{ 743 void *cookie; 744 nvpair_t *nvp; 745 int type; 746 747 NVLIST_ASSERT(nvl); 748 PJDLOG_ASSERT(nvl->nvl_error == 0); 749 750 cookie = NULL; 751 do { 752 while (nvlist_next(nvl, &type, &cookie) != NULL) { 753 nvp = cookie; 754 switch (type) { 755 case NV_TYPE_DESCRIPTOR: 756 *descs = nvpair_get_descriptor(nvp); 757 descs++; 758 break; 759 case NV_TYPE_DESCRIPTOR_ARRAY: 760 { 761 const int *value; 762 size_t nitems; 763 unsigned int ii; 764 765 value = nvpair_get_descriptor_array(nvp, 766 &nitems); 767 for (ii = 0; ii < nitems; ii++) { 768 *descs = value[ii]; 769 descs++; 770 } 771 break; 772 } 773 case NV_TYPE_NVLIST: 774 nvl = nvpair_get_nvlist(nvp); 775 cookie = NULL; 776 break; 777 case NV_TYPE_NVLIST_ARRAY: 778 { 779 const nvlist_t * const *value; 780 size_t nitems; 781 782 value = nvpair_get_nvlist_array(nvp, &nitems); 783 PJDLOG_ASSERT(value != NULL); 784 PJDLOG_ASSERT(nitems > 0); 785 786 nvl = value[0]; 787 cookie = NULL; 788 break; 789 } 790 } 791 } 792 } while ((nvl = nvlist_get_pararr(nvl, &cookie)) != NULL); 793 794 return (descs); 795} 796#endif 797 798#if !defined(_KERNEL) && !defined(_STANDALONE) 799int * 800nvlist_descriptors(const nvlist_t *nvl, size_t *nitemsp) 801{ 802 size_t nitems; 803 int *fds; 804 805 nitems = nvlist_ndescriptors(nvl); 806 fds = nv_malloc(sizeof(fds[0]) * (nitems + 1)); 807 if (fds == NULL) 808 return (NULL); 809 if (nitems > 0) 810 nvlist_xdescriptors(nvl, fds); 811 fds[nitems] = -1; 812 if (nitemsp != NULL) 813 *nitemsp = nitems; 814 return (fds); 815} 816#endif 817 818size_t 819nvlist_ndescriptors(const nvlist_t *nvl) 820{ 821#if !defined(_KERNEL) && !defined(_STANDALONE) 822 void *cookie; 823 nvpair_t *nvp; 824 size_t ndescs; 825 int type; 826 827 NVLIST_ASSERT(nvl); 828 PJDLOG_ASSERT(nvl->nvl_error == 0); 829 830 ndescs = 0; 831 cookie = NULL; 832 do { 833 while (nvlist_next(nvl, &type, &cookie) != NULL) { 834 nvp = cookie; 835 switch (type) { 836 case NV_TYPE_DESCRIPTOR: 837 ndescs++; 838 break; 839 case NV_TYPE_NVLIST: 840 nvl = nvpair_get_nvlist(nvp); 841 cookie = NULL; 842 break; 843 case NV_TYPE_NVLIST_ARRAY: 844 { 845 const nvlist_t * const *value; 846 size_t nitems; 847 848 value = nvpair_get_nvlist_array(nvp, &nitems); 849 PJDLOG_ASSERT(value != NULL); 850 PJDLOG_ASSERT(nitems > 0); 851 852 nvl = value[0]; 853 cookie = NULL; 854 break; 855 } 856 case NV_TYPE_DESCRIPTOR_ARRAY: 857 { 858 size_t nitems; 859 860 (void)nvpair_get_descriptor_array(nvp, 861 &nitems); 862 ndescs += nitems; 863 break; 864 } 865 } 866 } 867 } while ((nvl = nvlist_get_pararr(nvl, &cookie)) != NULL); 868 869 return (ndescs); 870#else 871 return (0); 872#endif 873} 874 875static unsigned char * 876nvlist_pack_header(const nvlist_t *nvl, unsigned char *ptr, size_t *leftp) 877{ 878 struct nvlist_header nvlhdr; 879 880 NVLIST_ASSERT(nvl); 881 882 nvlhdr.nvlh_magic = NVLIST_HEADER_MAGIC; 883 nvlhdr.nvlh_version = NVLIST_HEADER_VERSION; 884 nvlhdr.nvlh_flags = nvl->nvl_flags; 885#if BYTE_ORDER == BIG_ENDIAN 886 nvlhdr.nvlh_flags |= NV_FLAG_BIG_ENDIAN; 887#endif 888 nvlhdr.nvlh_descriptors = nvlist_ndescriptors(nvl); 889 nvlhdr.nvlh_size = *leftp - sizeof(nvlhdr); 890 PJDLOG_ASSERT(*leftp >= sizeof(nvlhdr)); 891 memcpy(ptr, &nvlhdr, sizeof(nvlhdr)); 892 ptr += sizeof(nvlhdr); 893 *leftp -= sizeof(nvlhdr); 894 895 return (ptr); 896} 897 898static void * 899nvlist_xpack(const nvlist_t *nvl, int64_t *fdidxp, size_t *sizep) 900{ 901 unsigned char *buf, *ptr; 902 size_t left, size; 903 const nvlist_t *tmpnvl; 904 nvpair_t *nvp, *tmpnvp; 905 void *cookie; 906 907 NVLIST_ASSERT(nvl); 908 909 if (nvl->nvl_error != 0) { 910 ERRNO_SET(nvl->nvl_error); 911 return (NULL); 912 } 913 914 size = nvlist_size(nvl); 915 buf = nv_malloc(size); 916 if (buf == NULL) 917 return (NULL); 918 919 ptr = buf; 920 left = size; 921 922 ptr = nvlist_pack_header(nvl, ptr, &left); 923 924 nvp = nvlist_first_nvpair(nvl); 925 while (nvp != NULL) { 926 NVPAIR_ASSERT(nvp); 927 928 nvpair_init_datasize(nvp); 929 ptr = nvpair_pack_header(nvp, ptr, &left); 930 if (ptr == NULL) 931 goto fail; 932 switch (nvpair_type(nvp)) { 933 case NV_TYPE_NULL: 934 ptr = nvpair_pack_null(nvp, ptr, &left); 935 break; 936 case NV_TYPE_BOOL: 937 ptr = nvpair_pack_bool(nvp, ptr, &left); 938 break; 939 case NV_TYPE_NUMBER: 940 ptr = nvpair_pack_number(nvp, ptr, &left); 941 break; 942 case NV_TYPE_STRING: 943 ptr = nvpair_pack_string(nvp, ptr, &left); 944 break; 945 case NV_TYPE_NVLIST: 946 tmpnvl = nvpair_get_nvlist(nvp); 947 ptr = nvlist_pack_header(tmpnvl, ptr, &left); 948 if (ptr == NULL) 949 goto fail; 950 tmpnvp = nvlist_first_nvpair(tmpnvl); 951 if (tmpnvp != NULL) { 952 nvl = tmpnvl; 953 nvp = tmpnvp; 954 continue; 955 } 956 ptr = nvpair_pack_nvlist_up(ptr, &left); 957 break; 958#if !defined(_KERNEL) && !defined(_STANDALONE) 959 case NV_TYPE_DESCRIPTOR: 960 ptr = nvpair_pack_descriptor(nvp, ptr, fdidxp, &left); 961 break; 962 case NV_TYPE_DESCRIPTOR_ARRAY: 963 ptr = nvpair_pack_descriptor_array(nvp, ptr, fdidxp, 964 &left); 965 break; 966#endif 967 case NV_TYPE_BINARY: 968 ptr = nvpair_pack_binary(nvp, ptr, &left); 969 break; 970 case NV_TYPE_BOOL_ARRAY: 971 ptr = nvpair_pack_bool_array(nvp, ptr, &left); 972 break; 973 case NV_TYPE_NUMBER_ARRAY: 974 ptr = nvpair_pack_number_array(nvp, ptr, &left); 975 break; 976 case NV_TYPE_STRING_ARRAY: 977 ptr = nvpair_pack_string_array(nvp, ptr, &left); 978 break; 979 case NV_TYPE_NVLIST_ARRAY: 980 { 981 const nvlist_t * const * value; 982 size_t nitems; 983 unsigned int ii; 984 985 tmpnvl = NULL; 986 value = nvpair_get_nvlist_array(nvp, &nitems); 987 for (ii = 0; ii < nitems; ii++) { 988 ptr = nvlist_pack_header(value[ii], ptr, &left); 989 if (ptr == NULL) 990 goto out; 991 tmpnvp = nvlist_first_nvpair(value[ii]); 992 if (tmpnvp != NULL) { 993 tmpnvl = value[ii]; 994 break; 995 } 996 ptr = nvpair_pack_nvlist_array_next(ptr, &left); 997 if (ptr == NULL) 998 goto out; 999 } 1000 if (tmpnvl != NULL) { 1001 nvl = tmpnvl; 1002 nvp = tmpnvp; 1003 continue; 1004 } 1005 break; 1006 } 1007 default: 1008 PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp)); 1009 } 1010 if (ptr == NULL) 1011 goto fail; 1012 while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) { 1013 do { 1014 cookie = NULL; 1015 if (nvlist_in_array(nvl)) { 1016 ptr = nvpair_pack_nvlist_array_next(ptr, 1017 &left); 1018 if (ptr == NULL) 1019 goto fail; 1020 } 1021 nvl = nvlist_get_pararr(nvl, &cookie); 1022 if (nvl == NULL) 1023 goto out; 1024 if (nvlist_in_array(nvl) && cookie == NULL) { 1025 nvp = nvlist_first_nvpair(nvl); 1026 ptr = nvlist_pack_header(nvl, ptr, 1027 &left); 1028 if (ptr == NULL) 1029 goto fail; 1030 } else if (nvpair_type((nvpair_t *)cookie) != 1031 NV_TYPE_NVLIST_ARRAY) { 1032 ptr = nvpair_pack_nvlist_up(ptr, &left); 1033 if (ptr == NULL) 1034 goto fail; 1035 nvp = cookie; 1036 } else { 1037 nvp = cookie; 1038 } 1039 } while (nvp == NULL); 1040 if (nvlist_in_array(nvl) && cookie == NULL) 1041 break; 1042 } 1043 } 1044 1045out: 1046 if (sizep != NULL) 1047 *sizep = size; 1048 return (buf); 1049fail: 1050 nv_free(buf); 1051 return (NULL); 1052} 1053 1054void * 1055nvlist_pack(const nvlist_t *nvl, size_t *sizep) 1056{ 1057 1058 NVLIST_ASSERT(nvl); 1059 1060 if (nvl->nvl_error != 0) { 1061 ERRNO_SET(nvl->nvl_error); 1062 return (NULL); 1063 } 1064 1065 if (nvlist_ndescriptors(nvl) > 0) { 1066 ERRNO_SET(EOPNOTSUPP); 1067 return (NULL); 1068 } 1069 1070 return (nvlist_xpack(nvl, NULL, sizep)); 1071} 1072 1073static bool 1074nvlist_check_header(struct nvlist_header *nvlhdrp) 1075{ 1076 1077 if (nvlhdrp->nvlh_magic != NVLIST_HEADER_MAGIC) { 1078 ERRNO_SET(EINVAL); 1079 return (false); 1080 } 1081 if ((nvlhdrp->nvlh_flags & ~NV_FLAG_ALL_MASK) != 0) { 1082 ERRNO_SET(EINVAL); 1083 return (false); 1084 } 1085#if BYTE_ORDER == BIG_ENDIAN 1086 if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) == 0) { 1087 nvlhdrp->nvlh_size = le64toh(nvlhdrp->nvlh_size); 1088 nvlhdrp->nvlh_descriptors = le64toh(nvlhdrp->nvlh_descriptors); 1089 } 1090#else 1091 if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0) { 1092 nvlhdrp->nvlh_size = be64toh(nvlhdrp->nvlh_size); 1093 nvlhdrp->nvlh_descriptors = be64toh(nvlhdrp->nvlh_descriptors); 1094 } 1095#endif 1096 return (true); 1097} 1098 1099const unsigned char * 1100nvlist_unpack_header(nvlist_t *nvl, const unsigned char *ptr, size_t nfds, 1101 bool *isbep, size_t *leftp) 1102{ 1103 struct nvlist_header nvlhdr; 1104 int inarrayf; 1105 1106 if (*leftp < sizeof(nvlhdr)) 1107 goto fail; 1108 1109 memcpy(&nvlhdr, ptr, sizeof(nvlhdr)); 1110 1111 if (!nvlist_check_header(&nvlhdr)) 1112 goto fail; 1113 1114 if (nvlhdr.nvlh_size != *leftp - sizeof(nvlhdr)) 1115 goto fail; 1116 1117 /* 1118 * nvlh_descriptors might be smaller than nfds in embedded nvlists. 1119 */ 1120 if (nvlhdr.nvlh_descriptors > nfds) 1121 goto fail; 1122 1123 if ((nvlhdr.nvlh_flags & ~NV_FLAG_ALL_MASK) != 0) 1124 goto fail; 1125 1126 inarrayf = (nvl->nvl_flags & NV_FLAG_IN_ARRAY); 1127 nvl->nvl_flags = (nvlhdr.nvlh_flags & NV_FLAG_PUBLIC_MASK) | inarrayf; 1128 1129 ptr += sizeof(nvlhdr); 1130 if (isbep != NULL) 1131 *isbep = (((int)nvlhdr.nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0); 1132 *leftp -= sizeof(nvlhdr); 1133 1134 return (ptr); 1135fail: 1136 ERRNO_SET(EINVAL); 1137 return (NULL); 1138} 1139 1140static nvlist_t * 1141nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds, 1142 int flags) 1143{ 1144 const unsigned char *ptr; 1145 nvlist_t *nvl, *retnvl, *tmpnvl, *array; 1146 nvpair_t *nvp; 1147 size_t left; 1148 bool isbe; 1149 1150 PJDLOG_ASSERT((flags & ~(NV_FLAG_PUBLIC_MASK)) == 0); 1151 1152 left = size; 1153 ptr = buf; 1154 1155 tmpnvl = array = NULL; 1156 nvl = retnvl = nvlist_create(0); 1157 if (nvl == NULL) 1158 goto fail; 1159 1160 ptr = nvlist_unpack_header(nvl, ptr, nfds, &isbe, &left); 1161 if (ptr == NULL) 1162 goto fail; 1163 if (nvl->nvl_flags != flags) { 1164 ERRNO_SET(EILSEQ); 1165 goto fail; 1166 } 1167 1168 while (left > 0) { 1169 ptr = nvpair_unpack(isbe, ptr, &left, &nvp); 1170 if (ptr == NULL) 1171 goto fail; 1172 switch (nvpair_type(nvp)) { 1173 case NV_TYPE_NULL: 1174 ptr = nvpair_unpack_null(isbe, nvp, ptr, &left); 1175 break; 1176 case NV_TYPE_BOOL: 1177 ptr = nvpair_unpack_bool(isbe, nvp, ptr, &left); 1178 break; 1179 case NV_TYPE_NUMBER: 1180 ptr = nvpair_unpack_number(isbe, nvp, ptr, &left); 1181 break; 1182 case NV_TYPE_STRING: 1183 ptr = nvpair_unpack_string(isbe, nvp, ptr, &left); 1184 break; 1185 case NV_TYPE_NVLIST: 1186 ptr = nvpair_unpack_nvlist(isbe, nvp, ptr, &left, nfds, 1187 &tmpnvl); 1188 if (tmpnvl == NULL || ptr == NULL) 1189 goto fail; 1190 nvlist_set_parent(tmpnvl, nvp); 1191 break; 1192#if !defined(_KERNEL) && !defined(_STANDALONE) && !defined(__NetBSD__) 1193 case NV_TYPE_DESCRIPTOR: 1194 ptr = nvpair_unpack_descriptor(isbe, nvp, ptr, &left, 1195 fds, nfds); 1196 break; 1197 case NV_TYPE_DESCRIPTOR_ARRAY: 1198 ptr = nvpair_unpack_descriptor_array(isbe, nvp, ptr, 1199 &left, fds, nfds); 1200 break; 1201#endif 1202 case NV_TYPE_BINARY: 1203 ptr = nvpair_unpack_binary(isbe, nvp, ptr, &left); 1204 break; 1205 case NV_TYPE_NVLIST_UP: 1206 if (nvl->nvl_parent == NULL) 1207 goto fail; 1208 nvl = nvpair_nvlist(nvl->nvl_parent); 1209 nvpair_free_structure(nvp); 1210 continue; 1211 case NV_TYPE_NVLIST_ARRAY_NEXT: 1212 if (nvl->nvl_array_next == NULL) { 1213 if (nvl->nvl_parent == NULL) 1214 goto fail; 1215 nvl = nvpair_nvlist(nvl->nvl_parent); 1216 } else { 1217 nvl = __DECONST(nvlist_t *, 1218 nvlist_get_array_next(nvl)); 1219 ptr = nvlist_unpack_header(nvl, ptr, nfds, 1220 &isbe, &left); 1221 if (ptr == NULL) 1222 goto fail; 1223 } 1224 nvpair_free_structure(nvp); 1225 continue; 1226 case NV_TYPE_BOOL_ARRAY: 1227 ptr = nvpair_unpack_bool_array(isbe, nvp, ptr, &left); 1228 break; 1229 case NV_TYPE_NUMBER_ARRAY: 1230 ptr = nvpair_unpack_number_array(isbe, nvp, ptr, &left); 1231 break; 1232 case NV_TYPE_STRING_ARRAY: 1233 ptr = nvpair_unpack_string_array(isbe, nvp, ptr, &left); 1234 break; 1235 case NV_TYPE_NVLIST_ARRAY: 1236 ptr = nvpair_unpack_nvlist_array(isbe, nvp, ptr, &left, 1237 &array); 1238 if (ptr == NULL) 1239 goto fail; 1240 PJDLOG_ASSERT(array != NULL); 1241 tmpnvl = array; 1242 do { 1243 nvlist_set_parent(array, nvp); 1244 array = __DECONST(nvlist_t *, 1245 nvlist_get_array_next(array)); 1246 } while (array != NULL); 1247 ptr = nvlist_unpack_header(tmpnvl, ptr, nfds, &isbe, 1248 &left); 1249 break; 1250 default: 1251 PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp)); 1252 } 1253 if (ptr == NULL) 1254 goto fail; 1255 if (!nvlist_move_nvpair(nvl, nvp)) 1256 goto fail; 1257 if (tmpnvl != NULL) { 1258 nvl = tmpnvl; 1259 tmpnvl = NULL; 1260 } 1261 } 1262 1263 return (retnvl); 1264fail: 1265 nvlist_destroy(retnvl); 1266 return (NULL); 1267} 1268 1269nvlist_t * 1270nvlist_unpack(const void *buf, size_t size, int flags) 1271{ 1272 1273 return (nvlist_xunpack(buf, size, NULL, 0, flags)); 1274} 1275 1276#if !defined(_KERNEL) && !defined(_STANDALONE) && defined(WITH_MSGIO) 1277int 1278nvlist_send(int sock, const nvlist_t *nvl) 1279{ 1280 size_t datasize, nfds; 1281 int *fds; 1282 void *data; 1283 int64_t fdidx; 1284 int ret; 1285 1286 if (nvlist_error(nvl) != 0) { 1287 ERRNO_SET(nvlist_error(nvl)); 1288 return (-1); 1289 } 1290 1291 fds = nvlist_descriptors(nvl, &nfds); 1292 if (fds == NULL) 1293 return (-1); 1294 1295 ret = -1; 1296 fdidx = 0; 1297 1298 data = nvlist_xpack(nvl, &fdidx, &datasize); 1299 if (data == NULL) 1300 goto out; 1301 1302 if (buf_send(sock, data, datasize) == -1) 1303 goto out; 1304 1305 if (nfds > 0) { 1306 if (fd_send(sock, fds, nfds) == -1) 1307 goto out; 1308 } 1309 1310 ret = 0; 1311out: 1312 ERRNO_SAVE(); 1313 nv_free(fds); 1314 nv_free(data); 1315 ERRNO_RESTORE(); 1316 return (ret); 1317} 1318 1319nvlist_t * 1320nvlist_recv(int sock, int flags) 1321{ 1322 struct nvlist_header nvlhdr; 1323 nvlist_t *nvl, *ret; 1324 unsigned char *buf; 1325 size_t nfds, size, i; 1326 int *fds; 1327 1328 if (buf_recv(sock, &nvlhdr, sizeof(nvlhdr)) == -1) 1329 return (NULL); 1330 1331 if (!nvlist_check_header(&nvlhdr)) 1332 return (NULL); 1333 1334 nfds = (size_t)nvlhdr.nvlh_descriptors; 1335 size = sizeof(nvlhdr) + (size_t)nvlhdr.nvlh_size; 1336 1337 buf = nv_malloc(size); 1338 if (buf == NULL) 1339 return (NULL); 1340 1341 memcpy(buf, &nvlhdr, sizeof(nvlhdr)); 1342 1343 ret = NULL; 1344 fds = NULL; 1345 1346 if (buf_recv(sock, buf + sizeof(nvlhdr), size - sizeof(nvlhdr)) == -1) 1347 goto out; 1348 1349 if (nfds > 0) { 1350 fds = nv_malloc(nfds * sizeof(fds[0])); 1351 if (fds == NULL) 1352 goto out; 1353 if (fd_recv(sock, fds, nfds) == -1) 1354 goto out; 1355 } 1356 1357 nvl = nvlist_xunpack(buf, size, fds, nfds, flags); 1358 if (nvl == NULL) { 1359 ERRNO_SAVE(); 1360 for (i = 0; i < nfds; i++) 1361 close(fds[i]); 1362 ERRNO_RESTORE(); 1363 goto out; 1364 } 1365 1366 ret = nvl; 1367out: 1368 ERRNO_SAVE(); 1369 nv_free(buf); 1370 nv_free(fds); 1371 ERRNO_RESTORE(); 1372 1373 return (ret); 1374} 1375 1376nvlist_t * 1377nvlist_xfer(int sock, nvlist_t *nvl, int flags) 1378{ 1379 1380 if (nvlist_send(sock, nvl) < 0) { 1381 nvlist_destroy(nvl); 1382 return (NULL); 1383 } 1384 nvlist_destroy(nvl); 1385 return (nvlist_recv(sock, flags)); 1386} 1387#endif 1388 1389nvpair_t * 1390nvlist_first_nvpair(const nvlist_t *nvl) 1391{ 1392 1393 NVLIST_ASSERT(nvl); 1394 1395 return (TAILQ_FIRST(&nvl->nvl_head)); 1396} 1397 1398nvpair_t * 1399nvlist_next_nvpair(const nvlist_t *nvl, const nvpair_t *nvp) 1400{ 1401 nvpair_t *retnvp; 1402 1403 NVLIST_ASSERT(nvl); 1404 NVPAIR_ASSERT(nvp); 1405 PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl); 1406 1407 retnvp = nvpair_next(nvp); 1408 PJDLOG_ASSERT(retnvp == NULL || nvpair_nvlist(retnvp) == nvl); 1409 1410 return (retnvp); 1411 1412} 1413 1414nvpair_t * 1415nvlist_prev_nvpair(const nvlist_t *nvl, const nvpair_t *nvp) 1416{ 1417 nvpair_t *retnvp; 1418 1419 NVLIST_ASSERT(nvl); 1420 NVPAIR_ASSERT(nvp); 1421 PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl); 1422 1423 retnvp = nvpair_prev(nvp); 1424 PJDLOG_ASSERT(nvpair_nvlist(retnvp) == nvl); 1425 1426 return (retnvp); 1427} 1428 1429const char * 1430nvlist_next(const nvlist_t *nvl, int *typep, void **cookiep) 1431{ 1432 nvpair_t *nvp; 1433 1434 NVLIST_ASSERT(nvl); 1435 1436 if (cookiep == NULL || *cookiep == NULL) 1437 nvp = nvlist_first_nvpair(nvl); 1438 else 1439 nvp = nvlist_next_nvpair(nvl, *cookiep); 1440 if (nvp == NULL) 1441 return (NULL); 1442 if (typep != NULL) 1443 *typep = nvpair_type(nvp); 1444 if (cookiep != NULL) 1445 *cookiep = nvp; 1446 return (nvpair_name(nvp)); 1447} 1448 1449bool 1450nvlist_exists(const nvlist_t *nvl, const char *name) 1451{ 1452 1453 return (nvlist_find(nvl, NV_TYPE_NONE, name) != NULL); 1454} 1455 1456#define NVLIST_EXISTS(type, TYPE) \ 1457bool \ 1458nvlist_exists_##type(const nvlist_t *nvl, const char *name) \ 1459{ \ 1460 \ 1461 return (nvlist_find(nvl, NV_TYPE_##TYPE, name) != NULL); \ 1462} 1463 1464NVLIST_EXISTS(null, NULL) 1465NVLIST_EXISTS(bool, BOOL) 1466NVLIST_EXISTS(number, NUMBER) 1467NVLIST_EXISTS(string, STRING) 1468NVLIST_EXISTS(nvlist, NVLIST) 1469NVLIST_EXISTS(binary, BINARY) 1470NVLIST_EXISTS(bool_array, BOOL_ARRAY) 1471NVLIST_EXISTS(number_array, NUMBER_ARRAY) 1472NVLIST_EXISTS(string_array, STRING_ARRAY) 1473NVLIST_EXISTS(nvlist_array, NVLIST_ARRAY) 1474#if !defined(_KERNEL) && !defined(_STANDALONE) 1475NVLIST_EXISTS(descriptor, DESCRIPTOR) 1476NVLIST_EXISTS(descriptor_array, DESCRIPTOR_ARRAY) 1477#endif 1478 1479#undef NVLIST_EXISTS 1480 1481void 1482nvlist_add_nvpair(nvlist_t *nvl, const nvpair_t *nvp) 1483{ 1484 nvpair_t *newnvp; 1485 1486 NVPAIR_ASSERT(nvp); 1487 1488 if (nvlist_error(nvl) != 0) { 1489 ERRNO_SET(nvlist_error(nvl)); 1490 return; 1491 } 1492 if ((nvl->nvl_flags & NV_FLAG_NO_UNIQUE) == 0) { 1493 if (nvlist_exists(nvl, nvpair_name(nvp))) { 1494 nvl->nvl_error = EEXIST; 1495 ERRNO_SET(nvlist_error(nvl)); 1496 return; 1497 } 1498 } 1499 1500 newnvp = nvpair_clone(nvp); 1501 if (newnvp == NULL) { 1502 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1503 ERRNO_SET(nvlist_error(nvl)); 1504 return; 1505 } 1506 1507 nvpair_insert(&nvl->nvl_head, newnvp, nvl); 1508} 1509 1510#if !defined(_STANDALONE) 1511void 1512nvlist_add_stringf(nvlist_t *nvl, const char *name, const char *valuefmt, ...) 1513{ 1514 va_list valueap; 1515 1516 va_start(valueap, valuefmt); 1517 nvlist_add_stringv(nvl, name, valuefmt, valueap); 1518 va_end(valueap); 1519} 1520 1521void 1522nvlist_add_stringv(nvlist_t *nvl, const char *name, const char *valuefmt, 1523 va_list valueap) 1524{ 1525 nvpair_t *nvp; 1526 1527 if (nvlist_error(nvl) != 0) { 1528 ERRNO_SET(nvlist_error(nvl)); 1529 return; 1530 } 1531 1532 nvp = nvpair_create_stringv(name, valuefmt, valueap); 1533 if (nvp == NULL) { 1534 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1535 ERRNO_SET(nvl->nvl_error); 1536 } else { 1537 (void)nvlist_move_nvpair(nvl, nvp); 1538 } 1539} 1540#endif 1541 1542void 1543nvlist_add_null(nvlist_t *nvl, const char *name) 1544{ 1545 nvpair_t *nvp; 1546 1547 if (nvlist_error(nvl) != 0) { 1548 ERRNO_SET(nvlist_error(nvl)); 1549 return; 1550 } 1551 1552 nvp = nvpair_create_null(name); 1553 if (nvp == NULL) { 1554 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1555 ERRNO_SET(nvl->nvl_error); 1556 } else { 1557 (void)nvlist_move_nvpair(nvl, nvp); 1558 } 1559} 1560 1561void 1562nvlist_add_binary(nvlist_t *nvl, const char *name, const void *value, 1563 size_t size) 1564{ 1565 nvpair_t *nvp; 1566 1567 if (nvlist_error(nvl) != 0) { 1568 ERRNO_SET(nvlist_error(nvl)); 1569 return; 1570 } 1571 1572 nvp = nvpair_create_binary(name, value, size); 1573 if (nvp == NULL) { 1574 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1575 ERRNO_SET(nvl->nvl_error); 1576 } else { 1577 (void)nvlist_move_nvpair(nvl, nvp); 1578 } 1579} 1580 1581 1582#define NVLIST_ADD(vtype, type) \ 1583void \ 1584nvlist_add_##type(nvlist_t *nvl, const char *name, vtype value) \ 1585{ \ 1586 nvpair_t *nvp; \ 1587 \ 1588 if (nvlist_error(nvl) != 0) { \ 1589 ERRNO_SET(nvlist_error(nvl)); \ 1590 return; \ 1591 } \ 1592 \ 1593 nvp = nvpair_create_##type(name, value); \ 1594 if (nvp == NULL) { \ 1595 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); \ 1596 ERRNO_SET(nvl->nvl_error); \ 1597 } else { \ 1598 (void)nvlist_move_nvpair(nvl, nvp); \ 1599 } \ 1600} 1601 1602NVLIST_ADD(bool, bool) 1603NVLIST_ADD(uint64_t, number) 1604NVLIST_ADD(const char *, string) 1605NVLIST_ADD(const nvlist_t *, nvlist) 1606#if !defined(_KERNEL) && !defined(_STANDALONE) 1607NVLIST_ADD(int, descriptor); 1608#endif 1609 1610#undef NVLIST_ADD 1611 1612#define NVLIST_ADD_ARRAY(vtype, type) \ 1613void \ 1614nvlist_add_##type##_array(nvlist_t *nvl, const char *name, vtype value, \ 1615 size_t nitems) \ 1616{ \ 1617 nvpair_t *nvp; \ 1618 \ 1619 if (nvlist_error(nvl) != 0) { \ 1620 ERRNO_SET(nvlist_error(nvl)); \ 1621 return; \ 1622 } \ 1623 \ 1624 nvp = nvpair_create_##type##_array(name, value, nitems); \ 1625 if (nvp == NULL) { \ 1626 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); \ 1627 ERRNO_SET(nvl->nvl_error); \ 1628 } else { \ 1629 (void)nvlist_move_nvpair(nvl, nvp); \ 1630 } \ 1631} 1632 1633NVLIST_ADD_ARRAY(const bool *, bool) 1634NVLIST_ADD_ARRAY(const uint64_t *, number) 1635NVLIST_ADD_ARRAY(const char * const *, string) 1636NVLIST_ADD_ARRAY(const nvlist_t * const *, nvlist) 1637#if !defined(_KERNEL) && !defined(_STANDALONE) 1638NVLIST_ADD_ARRAY(const int *, descriptor) 1639#endif 1640 1641#undef NVLIST_ADD_ARRAY 1642 1643#define NVLIST_APPEND_ARRAY(vtype, type, TYPE) \ 1644void \ 1645nvlist_append_##type##_array(nvlist_t *nvl, const char *name, vtype value)\ 1646{ \ 1647 nvpair_t *nvp; \ 1648 \ 1649 if (nvlist_error(nvl) != 0) { \ 1650 ERRNO_SET(nvlist_error(nvl)); \ 1651 return; \ 1652 } \ 1653 nvp = nvlist_find(nvl, NV_TYPE_##TYPE##_ARRAY, name); \ 1654 if (nvp == NULL) { \ 1655 nvlist_add_##type##_array(nvl, name, &value, 1); \ 1656 return; \ 1657 } \ 1658 if (nvpair_append_##type##_array(nvp, value) == -1) { \ 1659 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); \ 1660 ERRNO_SET(nvl->nvl_error); \ 1661 } \ 1662} 1663 1664NVLIST_APPEND_ARRAY(const bool, bool, BOOL) 1665NVLIST_APPEND_ARRAY(const uint64_t, number, NUMBER) 1666NVLIST_APPEND_ARRAY(const char *, string, STRING) 1667NVLIST_APPEND_ARRAY(const nvlist_t *, nvlist, NVLIST) 1668#if !defined(_KERNEL) && !defined(_STANDALONE) 1669NVLIST_APPEND_ARRAY(const int, descriptor, DESCRIPTOR) 1670#endif 1671 1672#undef NVLIST_APPEND_ARRAY 1673 1674bool 1675nvlist_move_nvpair(nvlist_t *nvl, nvpair_t *nvp) 1676{ 1677 1678 NVPAIR_ASSERT(nvp); 1679 PJDLOG_ASSERT(nvpair_nvlist(nvp) == NULL); 1680 1681 if (nvlist_error(nvl) != 0) { 1682 nvpair_free(nvp); 1683 ERRNO_SET(nvlist_error(nvl)); 1684 return (false); 1685 } 1686 if ((nvl->nvl_flags & NV_FLAG_NO_UNIQUE) == 0) { 1687 if (nvlist_exists(nvl, nvpair_name(nvp))) { 1688 nvpair_free(nvp); 1689 nvl->nvl_error = EEXIST; 1690 ERRNO_SET(nvl->nvl_error); 1691 return (false); 1692 } 1693 } 1694 1695 nvpair_insert(&nvl->nvl_head, nvp, nvl); 1696 return (true); 1697} 1698 1699void 1700nvlist_move_string(nvlist_t *nvl, const char *name, char *value) 1701{ 1702 nvpair_t *nvp; 1703 1704 if (nvlist_error(nvl) != 0) { 1705 nv_free(value); 1706 ERRNO_SET(nvlist_error(nvl)); 1707 return; 1708 } 1709 1710 nvp = nvpair_move_string(name, value); 1711 if (nvp == NULL) { 1712 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1713 ERRNO_SET(nvl->nvl_error); 1714 } else { 1715 (void)nvlist_move_nvpair(nvl, nvp); 1716 } 1717} 1718 1719void 1720nvlist_move_nvlist(nvlist_t *nvl, const char *name, nvlist_t *value) 1721{ 1722 nvpair_t *nvp; 1723 1724 if (nvlist_error(nvl) != 0) { 1725 if (value != NULL && nvlist_get_nvpair_parent(value) != NULL) 1726 nvlist_destroy(value); 1727 ERRNO_SET(nvlist_error(nvl)); 1728 return; 1729 } 1730 1731 nvp = nvpair_move_nvlist(name, value); 1732 if (nvp == NULL) { 1733 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1734 ERRNO_SET(nvl->nvl_error); 1735 } else { 1736 (void)nvlist_move_nvpair(nvl, nvp); 1737 } 1738} 1739 1740#if !defined(_KERNEL) && !defined(_STANDALONE) 1741void 1742nvlist_move_descriptor(nvlist_t *nvl, const char *name, int value) 1743{ 1744 nvpair_t *nvp; 1745 1746 if (nvlist_error(nvl) != 0) { 1747 close(value); 1748 ERRNO_SET(nvlist_error(nvl)); 1749 return; 1750 } 1751 1752 nvp = nvpair_move_descriptor(name, value); 1753 if (nvp == NULL) { 1754 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1755 ERRNO_SET(nvl->nvl_error); 1756 } else { 1757 (void)nvlist_move_nvpair(nvl, nvp); 1758 } 1759} 1760#endif 1761 1762void 1763nvlist_move_binary(nvlist_t *nvl, const char *name, void *value, size_t size) 1764{ 1765 nvpair_t *nvp; 1766 1767 if (nvlist_error(nvl) != 0) { 1768 nv_free(value); 1769 ERRNO_SET(nvlist_error(nvl)); 1770 return; 1771 } 1772 1773 nvp = nvpair_move_binary(name, value, size); 1774 if (nvp == NULL) { 1775 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1776 ERRNO_SET(nvl->nvl_error); 1777 } else { 1778 (void)nvlist_move_nvpair(nvl, nvp); 1779 } 1780} 1781 1782void 1783nvlist_move_bool_array(nvlist_t *nvl, const char *name, bool *value, 1784 size_t nitems) 1785{ 1786 nvpair_t *nvp; 1787 1788 if (nvlist_error(nvl) != 0) { 1789 nv_free(value); 1790 ERRNO_SET(nvlist_error(nvl)); 1791 return; 1792 } 1793 1794 nvp = nvpair_move_bool_array(name, value, nitems); 1795 if (nvp == NULL) { 1796 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1797 ERRNO_SET(nvl->nvl_error); 1798 } else { 1799 (void)nvlist_move_nvpair(nvl, nvp); 1800 } 1801} 1802 1803void 1804nvlist_move_string_array(nvlist_t *nvl, const char *name, char **value, 1805 size_t nitems) 1806{ 1807 nvpair_t *nvp; 1808 size_t i; 1809 1810 if (nvlist_error(nvl) != 0) { 1811 if (value != NULL) { 1812 for (i = 0; i < nitems; i++) 1813 nv_free(value[i]); 1814 nv_free(value); 1815 } 1816 ERRNO_SET(nvlist_error(nvl)); 1817 return; 1818 } 1819 1820 nvp = nvpair_move_string_array(name, value, nitems); 1821 if (nvp == NULL) { 1822 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1823 ERRNO_SET(nvl->nvl_error); 1824 } else { 1825 (void)nvlist_move_nvpair(nvl, nvp); 1826 } 1827} 1828 1829void 1830nvlist_move_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **value, 1831 size_t nitems) 1832{ 1833 nvpair_t *nvp; 1834 size_t i; 1835 1836 if (nvlist_error(nvl) != 0) { 1837 if (value != NULL) { 1838 for (i = 0; i < nitems; i++) { 1839 if (nvlist_get_pararr(value[i], NULL) == NULL) 1840 nvlist_destroy(value[i]); 1841 } 1842 } 1843 nv_free(value); 1844 ERRNO_SET(nvlist_error(nvl)); 1845 return; 1846 } 1847 1848 nvp = nvpair_move_nvlist_array(name, value, nitems); 1849 if (nvp == NULL) { 1850 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1851 ERRNO_SET(nvl->nvl_error); 1852 } else { 1853 (void)nvlist_move_nvpair(nvl, nvp); 1854 } 1855} 1856 1857void 1858nvlist_move_number_array(nvlist_t *nvl, const char *name, uint64_t *value, 1859 size_t nitems) 1860{ 1861 nvpair_t *nvp; 1862 1863 if (nvlist_error(nvl) != 0) { 1864 nv_free(value); 1865 ERRNO_SET(nvlist_error(nvl)); 1866 return; 1867 } 1868 1869 nvp = nvpair_move_number_array(name, value, nitems); 1870 if (nvp == NULL) { 1871 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1872 ERRNO_SET(nvl->nvl_error); 1873 } else { 1874 (void)nvlist_move_nvpair(nvl, nvp); 1875 } 1876} 1877 1878#if !defined(_KERNEL) && !defined(_STANDALONE) 1879void 1880nvlist_move_descriptor_array(nvlist_t *nvl, const char *name, int *value, 1881 size_t nitems) 1882{ 1883 nvpair_t *nvp; 1884 size_t i; 1885 1886 if (nvlist_error(nvl) != 0) { 1887 if (value != 0) { 1888 for (i = 0; i < nitems; i++) 1889 close(value[i]); 1890 nv_free(value); 1891 } 1892 1893 ERRNO_SET(nvlist_error(nvl)); 1894 return; 1895 } 1896 1897 nvp = nvpair_move_descriptor_array(name, value, nitems); 1898 if (nvp == NULL) { 1899 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1900 ERRNO_SET(nvl->nvl_error); 1901 } else { 1902 (void)nvlist_move_nvpair(nvl, nvp); 1903 } 1904} 1905#endif 1906 1907const nvpair_t * 1908nvlist_get_nvpair(const nvlist_t *nvl, const char *name) 1909{ 1910 1911 return (nvlist_find(nvl, NV_TYPE_NONE, name)); 1912} 1913 1914#define NVLIST_GET(ftype, type, TYPE) \ 1915ftype \ 1916nvlist_get_##type(const nvlist_t *nvl, const char *name) \ 1917{ \ 1918 const nvpair_t *nvp; \ 1919 \ 1920 nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name); \ 1921 if (nvp == NULL) \ 1922 nvlist_report_missing(NV_TYPE_##TYPE, name); \ 1923 return (nvpair_get_##type(nvp)); \ 1924} 1925 1926NVLIST_GET(bool, bool, BOOL) 1927NVLIST_GET(uint64_t, number, NUMBER) 1928NVLIST_GET(const char *, string, STRING) 1929NVLIST_GET(const nvlist_t *, nvlist, NVLIST) 1930#if !defined(_KERNEL) && !defined(_STANDALONE) 1931NVLIST_GET(int, descriptor, DESCRIPTOR) 1932#endif 1933 1934#undef NVLIST_GET 1935 1936const void * 1937nvlist_get_binary(const nvlist_t *nvl, const char *name, size_t *sizep) 1938{ 1939 nvpair_t *nvp; 1940 1941 nvp = nvlist_find(nvl, NV_TYPE_BINARY, name); 1942 if (nvp == NULL) 1943 nvlist_report_missing(NV_TYPE_BINARY, name); 1944 1945 return (nvpair_get_binary(nvp, sizep)); 1946} 1947 1948#define NVLIST_GET_ARRAY(ftype, type, TYPE) \ 1949ftype \ 1950nvlist_get_##type##_array(const nvlist_t *nvl, const char *name, \ 1951 size_t *nitems) \ 1952{ \ 1953 const nvpair_t *nvp; \ 1954 \ 1955 nvp = nvlist_find(nvl, NV_TYPE_##TYPE##_ARRAY, name); \ 1956 if (nvp == NULL) \ 1957 nvlist_report_missing(NV_TYPE_##TYPE##_ARRAY, name); \ 1958 return (nvpair_get_##type##_array(nvp, nitems)); \ 1959} 1960 1961NVLIST_GET_ARRAY(const bool *, bool, BOOL) 1962NVLIST_GET_ARRAY(const uint64_t *, number, NUMBER) 1963NVLIST_GET_ARRAY(const char * const *, string, STRING) 1964NVLIST_GET_ARRAY(const nvlist_t * const *, nvlist, NVLIST) 1965#if !defined(_KERNEL) && !defined(_STANDALONE) 1966NVLIST_GET_ARRAY(const int *, descriptor, DESCRIPTOR) 1967#endif 1968 1969#undef NVLIST_GET_ARRAY 1970 1971#define NVLIST_TAKE(ftype, type, TYPE) \ 1972ftype \ 1973nvlist_take_##type(nvlist_t *nvl, const char *name) \ 1974{ \ 1975 nvpair_t *nvp; \ 1976 ftype value; \ 1977 \ 1978 nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name); \ 1979 if (nvp == NULL) \ 1980 nvlist_report_missing(NV_TYPE_##TYPE, name); \ 1981 value = (ftype)(intptr_t)nvpair_get_##type(nvp); \ 1982 nvlist_remove_nvpair(nvl, nvp); \ 1983 nvpair_free_structure(nvp); \ 1984 return (value); \ 1985} 1986 1987NVLIST_TAKE(bool, bool, BOOL) 1988NVLIST_TAKE(uint64_t, number, NUMBER) 1989NVLIST_TAKE(char *, string, STRING) 1990NVLIST_TAKE(nvlist_t *, nvlist, NVLIST) 1991#if !defined(_KERNEL) && !defined(_STANDALONE) 1992NVLIST_TAKE(int, descriptor, DESCRIPTOR) 1993#endif 1994 1995#undef NVLIST_TAKE 1996 1997void * 1998nvlist_take_binary(nvlist_t *nvl, const char *name, size_t *sizep) 1999{ 2000 nvpair_t *nvp; 2001 void *value; 2002 2003 nvp = nvlist_find(nvl, NV_TYPE_BINARY, name); 2004 if (nvp == NULL) 2005 nvlist_report_missing(NV_TYPE_BINARY, name); 2006 2007 value = (void *)(intptr_t)nvpair_get_binary(nvp, sizep); 2008 nvlist_remove_nvpair(nvl, nvp); 2009 nvpair_free_structure(nvp); 2010 return (value); 2011} 2012 2013#define NVLIST_TAKE_ARRAY(ftype, type, TYPE) \ 2014ftype \ 2015nvlist_take_##type##_array(nvlist_t *nvl, const char *name, \ 2016 size_t *nitems) \ 2017{ \ 2018 nvpair_t *nvp; \ 2019 ftype value; \ 2020 \ 2021 nvp = nvlist_find(nvl, NV_TYPE_##TYPE##_ARRAY, name); \ 2022 if (nvp == NULL) \ 2023 nvlist_report_missing(NV_TYPE_##TYPE##_ARRAY, name); \ 2024 value = (ftype)(intptr_t)nvpair_get_##type##_array(nvp, nitems);\ 2025 nvlist_remove_nvpair(nvl, nvp); \ 2026 nvpair_free_structure(nvp); \ 2027 return (value); \ 2028} 2029 2030NVLIST_TAKE_ARRAY(bool *, bool, BOOL) 2031NVLIST_TAKE_ARRAY(uint64_t *, number, NUMBER) 2032NVLIST_TAKE_ARRAY(char **, string, STRING) 2033NVLIST_TAKE_ARRAY(nvlist_t **, nvlist, NVLIST) 2034#if !defined(_KERNEL) && !defined(_STANDALONE) 2035NVLIST_TAKE_ARRAY(int *, descriptor, DESCRIPTOR) 2036#endif 2037 2038void 2039nvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp) 2040{ 2041 2042 NVLIST_ASSERT(nvl); 2043 NVPAIR_ASSERT(nvp); 2044 PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl); 2045 2046 nvpair_remove(&nvl->nvl_head, nvp, nvl); 2047} 2048 2049void 2050nvlist_free(nvlist_t *nvl, const char *name) 2051{ 2052 2053 nvlist_free_type(nvl, name, NV_TYPE_NONE); 2054} 2055 2056#define NVLIST_FREE(type, TYPE) \ 2057void \ 2058nvlist_free_##type(nvlist_t *nvl, const char *name) \ 2059{ \ 2060 \ 2061 nvlist_free_type(nvl, name, NV_TYPE_##TYPE); \ 2062} 2063 2064NVLIST_FREE(null, NULL) 2065NVLIST_FREE(bool, BOOL) 2066NVLIST_FREE(number, NUMBER) 2067NVLIST_FREE(string, STRING) 2068NVLIST_FREE(nvlist, NVLIST) 2069NVLIST_FREE(binary, BINARY) 2070NVLIST_FREE(bool_array, BOOL_ARRAY) 2071NVLIST_FREE(number_array, NUMBER_ARRAY) 2072NVLIST_FREE(string_array, STRING_ARRAY) 2073NVLIST_FREE(nvlist_array, NVLIST_ARRAY) 2074#if !defined(_KERNEL) && !defined(_STANDALONE) 2075NVLIST_FREE(descriptor, DESCRIPTOR) 2076NVLIST_FREE(descriptor_array, DESCRIPTOR_ARRAY) 2077#endif 2078 2079#undef NVLIST_FREE 2080 2081void 2082nvlist_free_nvpair(nvlist_t *nvl, nvpair_t *nvp) 2083{ 2084 2085 NVLIST_ASSERT(nvl); 2086 NVPAIR_ASSERT(nvp); 2087 PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl); 2088 2089 nvlist_remove_nvpair(nvl, nvp); 2090 nvpair_free(nvp); 2091} 2092 2093