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