nvlist.c revision 346905
1178825Sdfr/*- 2233294Sstas * Copyright (c) 2009-2013 The FreeBSD Foundation 3233294Sstas * Copyright (c) 2013-2015 Mariusz Zaborski <oshogbo@FreeBSD.org> 4233294Sstas * All rights reserved. 5178825Sdfr * 6233294Sstas * This software was developed by Pawel Jakub Dawidek under sponsorship from 7233294Sstas * the FreeBSD Foundation. 8233294Sstas * 9178825Sdfr * Redistribution and use in source and binary forms, with or without 10233294Sstas * modification, are permitted provided that the following conditions 11233294Sstas * are met: 12178825Sdfr * 1. Redistributions of source code must retain the above copyright 13233294Sstas * notice, this list of conditions and the following disclaimer. 14233294Sstas * 2. Redistributions in binary form must reproduce the above copyright 15233294Sstas * notice, this list of conditions and the following disclaimer in the 16178825Sdfr * documentation and/or other materials provided with the distribution. 17233294Sstas * 18233294Sstas * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 19233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21233294Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 22233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28233294Sstas * SUCH DAMAGE. 29233294Sstas */ 30233294Sstas 31233294Sstas#include <sys/cdefs.h> 32178825Sdfr__FBSDID("$FreeBSD: stable/11/sys/contrib/libnv/nvlist.c 346905 2019-04-29 18:52:04Z oshogbo $"); 33178825Sdfr 34178825Sdfr#include <sys/param.h> 35178825Sdfr#include <sys/endian.h> 36233294Sstas#include <sys/queue.h> 37178825Sdfr 38233294Sstas#ifdef _KERNEL 39178825Sdfr 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 317void 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 void *cookie; 712 nvpair_t *nvp; 713 int type; 714 715 NVLIST_ASSERT(nvl); 716 PJDLOG_ASSERT(nvl->nvl_error == 0); 717 718 cookie = NULL; 719 do { 720 while (nvlist_next(nvl, &type, &cookie) != NULL) { 721 nvp = cookie; 722 switch (type) { 723 case NV_TYPE_DESCRIPTOR: 724 *descs = nvpair_get_descriptor(nvp); 725 descs++; 726 break; 727 case NV_TYPE_DESCRIPTOR_ARRAY: 728 { 729 const int *value; 730 size_t nitems; 731 unsigned int ii; 732 733 value = nvpair_get_descriptor_array(nvp, 734 &nitems); 735 for (ii = 0; ii < nitems; ii++) { 736 *descs = value[ii]; 737 descs++; 738 } 739 break; 740 } 741 case NV_TYPE_NVLIST: 742 nvl = nvpair_get_nvlist(nvp); 743 cookie = NULL; 744 break; 745 case NV_TYPE_NVLIST_ARRAY: 746 { 747 const nvlist_t * const *value; 748 size_t nitems; 749 750 value = nvpair_get_nvlist_array(nvp, &nitems); 751 PJDLOG_ASSERT(value != NULL); 752 PJDLOG_ASSERT(nitems > 0); 753 754 nvl = value[0]; 755 cookie = NULL; 756 break; 757 } 758 } 759 } 760 } while ((nvl = nvlist_get_pararr(nvl, &cookie)) != NULL); 761 762 return (descs); 763} 764#endif 765 766#ifndef _KERNEL 767int * 768nvlist_descriptors(const nvlist_t *nvl, size_t *nitemsp) 769{ 770 size_t nitems; 771 int *fds; 772 773 nitems = nvlist_ndescriptors(nvl); 774 fds = nv_malloc(sizeof(fds[0]) * (nitems + 1)); 775 if (fds == NULL) 776 return (NULL); 777 if (nitems > 0) 778 nvlist_xdescriptors(nvl, fds); 779 fds[nitems] = -1; 780 if (nitemsp != NULL) 781 *nitemsp = nitems; 782 return (fds); 783} 784#endif 785 786size_t 787nvlist_ndescriptors(const nvlist_t *nvl) 788{ 789#ifndef _KERNEL 790 void *cookie; 791 nvpair_t *nvp; 792 size_t ndescs; 793 int type; 794 795 NVLIST_ASSERT(nvl); 796 PJDLOG_ASSERT(nvl->nvl_error == 0); 797 798 ndescs = 0; 799 cookie = NULL; 800 do { 801 while (nvlist_next(nvl, &type, &cookie) != NULL) { 802 nvp = cookie; 803 switch (type) { 804 case NV_TYPE_DESCRIPTOR: 805 ndescs++; 806 break; 807 case NV_TYPE_NVLIST: 808 nvl = nvpair_get_nvlist(nvp); 809 cookie = NULL; 810 break; 811 case NV_TYPE_NVLIST_ARRAY: 812 { 813 const nvlist_t * const *value; 814 size_t nitems; 815 816 value = nvpair_get_nvlist_array(nvp, &nitems); 817 PJDLOG_ASSERT(value != NULL); 818 PJDLOG_ASSERT(nitems > 0); 819 820 nvl = value[0]; 821 cookie = NULL; 822 break; 823 } 824 case NV_TYPE_DESCRIPTOR_ARRAY: 825 { 826 size_t nitems; 827 828 (void)nvpair_get_descriptor_array(nvp, 829 &nitems); 830 ndescs += nitems; 831 break; 832 } 833 } 834 } 835 } while ((nvl = nvlist_get_pararr(nvl, &cookie)) != NULL); 836 837 return (ndescs); 838#else 839 return (0); 840#endif 841} 842 843static unsigned char * 844nvlist_pack_header(const nvlist_t *nvl, unsigned char *ptr, size_t *leftp) 845{ 846 struct nvlist_header nvlhdr; 847 848 NVLIST_ASSERT(nvl); 849 850 nvlhdr.nvlh_magic = NVLIST_HEADER_MAGIC; 851 nvlhdr.nvlh_version = NVLIST_HEADER_VERSION; 852 nvlhdr.nvlh_flags = nvl->nvl_flags; 853#if BYTE_ORDER == BIG_ENDIAN 854 nvlhdr.nvlh_flags |= NV_FLAG_BIG_ENDIAN; 855#endif 856 nvlhdr.nvlh_descriptors = nvlist_ndescriptors(nvl); 857 nvlhdr.nvlh_size = *leftp - sizeof(nvlhdr); 858 PJDLOG_ASSERT(*leftp >= sizeof(nvlhdr)); 859 memcpy(ptr, &nvlhdr, sizeof(nvlhdr)); 860 ptr += sizeof(nvlhdr); 861 *leftp -= sizeof(nvlhdr); 862 863 return (ptr); 864} 865 866static void * 867nvlist_xpack(const nvlist_t *nvl, int64_t *fdidxp, size_t *sizep) 868{ 869 unsigned char *buf, *ptr; 870 size_t left, size; 871 const nvlist_t *tmpnvl; 872 nvpair_t *nvp, *tmpnvp; 873 void *cookie; 874 875 NVLIST_ASSERT(nvl); 876 877 if (nvl->nvl_error != 0) { 878 ERRNO_SET(nvl->nvl_error); 879 return (NULL); 880 } 881 882 size = nvlist_size(nvl); 883 buf = nv_malloc(size); 884 if (buf == NULL) 885 return (NULL); 886 887 ptr = buf; 888 left = size; 889 890 ptr = nvlist_pack_header(nvl, ptr, &left); 891 892 nvp = nvlist_first_nvpair(nvl); 893 while (nvp != NULL) { 894 NVPAIR_ASSERT(nvp); 895 896 nvpair_init_datasize(nvp); 897 ptr = nvpair_pack_header(nvp, ptr, &left); 898 if (ptr == NULL) 899 goto fail; 900 switch (nvpair_type(nvp)) { 901 case NV_TYPE_NULL: 902 ptr = nvpair_pack_null(nvp, ptr, &left); 903 break; 904 case NV_TYPE_BOOL: 905 ptr = nvpair_pack_bool(nvp, ptr, &left); 906 break; 907 case NV_TYPE_NUMBER: 908 ptr = nvpair_pack_number(nvp, ptr, &left); 909 break; 910 case NV_TYPE_STRING: 911 ptr = nvpair_pack_string(nvp, ptr, &left); 912 break; 913 case NV_TYPE_NVLIST: 914 tmpnvl = nvpair_get_nvlist(nvp); 915 ptr = nvlist_pack_header(tmpnvl, ptr, &left); 916 if (ptr == NULL) 917 goto fail; 918 tmpnvp = nvlist_first_nvpair(tmpnvl); 919 if (tmpnvp != NULL) { 920 nvl = tmpnvl; 921 nvp = tmpnvp; 922 continue; 923 } 924 ptr = nvpair_pack_nvlist_up(ptr, &left); 925 break; 926#ifndef _KERNEL 927 case NV_TYPE_DESCRIPTOR: 928 ptr = nvpair_pack_descriptor(nvp, ptr, fdidxp, &left); 929 break; 930 case NV_TYPE_DESCRIPTOR_ARRAY: 931 ptr = nvpair_pack_descriptor_array(nvp, ptr, fdidxp, 932 &left); 933 break; 934#endif 935 case NV_TYPE_BINARY: 936 ptr = nvpair_pack_binary(nvp, ptr, &left); 937 break; 938 case NV_TYPE_BOOL_ARRAY: 939 ptr = nvpair_pack_bool_array(nvp, ptr, &left); 940 break; 941 case NV_TYPE_NUMBER_ARRAY: 942 ptr = nvpair_pack_number_array(nvp, ptr, &left); 943 break; 944 case NV_TYPE_STRING_ARRAY: 945 ptr = nvpair_pack_string_array(nvp, ptr, &left); 946 break; 947 case NV_TYPE_NVLIST_ARRAY: 948 { 949 const nvlist_t * const * value; 950 size_t nitems; 951 unsigned int ii; 952 953 tmpnvl = NULL; 954 value = nvpair_get_nvlist_array(nvp, &nitems); 955 for (ii = 0; ii < nitems; ii++) { 956 ptr = nvlist_pack_header(value[ii], ptr, &left); 957 if (ptr == NULL) 958 goto out; 959 tmpnvp = nvlist_first_nvpair(value[ii]); 960 if (tmpnvp != NULL) { 961 tmpnvl = value[ii]; 962 break; 963 } 964 ptr = nvpair_pack_nvlist_array_next(ptr, &left); 965 if (ptr == NULL) 966 goto out; 967 } 968 if (tmpnvl != NULL) { 969 nvl = tmpnvl; 970 nvp = tmpnvp; 971 continue; 972 } 973 break; 974 } 975 default: 976 PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp)); 977 } 978 if (ptr == NULL) 979 goto fail; 980 while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) { 981 do { 982 cookie = NULL; 983 if (nvlist_in_array(nvl)) { 984 ptr = nvpair_pack_nvlist_array_next(ptr, 985 &left); 986 if (ptr == NULL) 987 goto fail; 988 } 989 nvl = nvlist_get_pararr(nvl, &cookie); 990 if (nvl == NULL) 991 goto out; 992 if (nvlist_in_array(nvl) && cookie == NULL) { 993 nvp = nvlist_first_nvpair(nvl); 994 ptr = nvlist_pack_header(nvl, ptr, 995 &left); 996 if (ptr == NULL) 997 goto fail; 998 } else if (nvpair_type((nvpair_t *)cookie) != 999 NV_TYPE_NVLIST_ARRAY) { 1000 ptr = nvpair_pack_nvlist_up(ptr, &left); 1001 if (ptr == NULL) 1002 goto fail; 1003 nvp = cookie; 1004 } else { 1005 nvp = cookie; 1006 } 1007 } while (nvp == NULL); 1008 if (nvlist_in_array(nvl) && cookie == NULL) 1009 break; 1010 } 1011 } 1012 1013out: 1014 if (sizep != NULL) 1015 *sizep = size; 1016 return (buf); 1017fail: 1018 nv_free(buf); 1019 return (NULL); 1020} 1021 1022void * 1023nvlist_pack(const nvlist_t *nvl, size_t *sizep) 1024{ 1025 1026 NVLIST_ASSERT(nvl); 1027 1028 if (nvl->nvl_error != 0) { 1029 ERRNO_SET(nvl->nvl_error); 1030 return (NULL); 1031 } 1032 1033 if (nvlist_ndescriptors(nvl) > 0) { 1034 ERRNO_SET(EOPNOTSUPP); 1035 return (NULL); 1036 } 1037 1038 return (nvlist_xpack(nvl, NULL, sizep)); 1039} 1040 1041static bool 1042nvlist_check_header(struct nvlist_header *nvlhdrp) 1043{ 1044 1045 if (nvlhdrp->nvlh_magic != NVLIST_HEADER_MAGIC) { 1046 ERRNO_SET(EINVAL); 1047 return (false); 1048 } 1049 if ((nvlhdrp->nvlh_flags & ~NV_FLAG_ALL_MASK) != 0) { 1050 ERRNO_SET(EINVAL); 1051 return (false); 1052 } 1053#if BYTE_ORDER == BIG_ENDIAN 1054 if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) == 0) { 1055 nvlhdrp->nvlh_size = le64toh(nvlhdrp->nvlh_size); 1056 nvlhdrp->nvlh_descriptors = le64toh(nvlhdrp->nvlh_descriptors); 1057 } 1058#else 1059 if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0) { 1060 nvlhdrp->nvlh_size = be64toh(nvlhdrp->nvlh_size); 1061 nvlhdrp->nvlh_descriptors = be64toh(nvlhdrp->nvlh_descriptors); 1062 } 1063#endif 1064 return (true); 1065} 1066 1067const unsigned char * 1068nvlist_unpack_header(nvlist_t *nvl, const unsigned char *ptr, size_t nfds, 1069 bool *isbep, size_t *leftp) 1070{ 1071 struct nvlist_header nvlhdr; 1072 int inarrayf; 1073 1074 if (*leftp < sizeof(nvlhdr)) 1075 goto fail; 1076 1077 memcpy(&nvlhdr, ptr, sizeof(nvlhdr)); 1078 1079 if (!nvlist_check_header(&nvlhdr)) 1080 goto fail; 1081 1082 if (nvlhdr.nvlh_size != *leftp - sizeof(nvlhdr)) 1083 goto fail; 1084 1085 /* 1086 * nvlh_descriptors might be smaller than nfds in embedded nvlists. 1087 */ 1088 if (nvlhdr.nvlh_descriptors > nfds) 1089 goto fail; 1090 1091 if ((nvlhdr.nvlh_flags & ~NV_FLAG_ALL_MASK) != 0) 1092 goto fail; 1093 1094 inarrayf = (nvl->nvl_flags & NV_FLAG_IN_ARRAY); 1095 nvl->nvl_flags = (nvlhdr.nvlh_flags & NV_FLAG_PUBLIC_MASK) | inarrayf; 1096 1097 ptr += sizeof(nvlhdr); 1098 if (isbep != NULL) 1099 *isbep = (((int)nvlhdr.nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0); 1100 *leftp -= sizeof(nvlhdr); 1101 1102 return (ptr); 1103fail: 1104 ERRNO_SET(EINVAL); 1105 return (NULL); 1106} 1107 1108static nvlist_t * 1109nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds, 1110 int flags) 1111{ 1112 const unsigned char *ptr; 1113 nvlist_t *nvl, *retnvl, *tmpnvl, *array; 1114 nvpair_t *nvp; 1115 size_t left; 1116 bool isbe; 1117 1118 PJDLOG_ASSERT((flags & ~(NV_FLAG_PUBLIC_MASK)) == 0); 1119 1120 left = size; 1121 ptr = buf; 1122 1123 tmpnvl = array = NULL; 1124 nvl = retnvl = nvlist_create(0); 1125 if (nvl == NULL) 1126 goto fail; 1127 1128 ptr = nvlist_unpack_header(nvl, ptr, nfds, &isbe, &left); 1129 if (ptr == NULL) 1130 goto fail; 1131 if (nvl->nvl_flags != flags) { 1132 ERRNO_SET(EILSEQ); 1133 goto fail; 1134 } 1135 1136 while (left > 0) { 1137 ptr = nvpair_unpack(isbe, ptr, &left, &nvp); 1138 if (ptr == NULL) 1139 goto fail; 1140 switch (nvpair_type(nvp)) { 1141 case NV_TYPE_NULL: 1142 ptr = nvpair_unpack_null(isbe, nvp, ptr, &left); 1143 break; 1144 case NV_TYPE_BOOL: 1145 ptr = nvpair_unpack_bool(isbe, nvp, ptr, &left); 1146 break; 1147 case NV_TYPE_NUMBER: 1148 ptr = nvpair_unpack_number(isbe, nvp, ptr, &left); 1149 break; 1150 case NV_TYPE_STRING: 1151 ptr = nvpair_unpack_string(isbe, nvp, ptr, &left); 1152 break; 1153 case NV_TYPE_NVLIST: 1154 ptr = nvpair_unpack_nvlist(isbe, nvp, ptr, &left, nfds, 1155 &tmpnvl); 1156 if (tmpnvl == NULL || ptr == NULL) 1157 goto fail; 1158 nvlist_set_parent(tmpnvl, nvp); 1159 break; 1160#ifndef _KERNEL 1161 case NV_TYPE_DESCRIPTOR: 1162 ptr = nvpair_unpack_descriptor(isbe, nvp, ptr, &left, 1163 fds, nfds); 1164 break; 1165 case NV_TYPE_DESCRIPTOR_ARRAY: 1166 ptr = nvpair_unpack_descriptor_array(isbe, nvp, ptr, 1167 &left, fds, nfds); 1168 break; 1169#endif 1170 case NV_TYPE_BINARY: 1171 ptr = nvpair_unpack_binary(isbe, nvp, ptr, &left); 1172 break; 1173 case NV_TYPE_NVLIST_UP: 1174 if (nvl->nvl_parent == NULL) 1175 goto fail; 1176 nvl = nvpair_nvlist(nvl->nvl_parent); 1177 nvpair_free_structure(nvp); 1178 continue; 1179 case NV_TYPE_NVLIST_ARRAY_NEXT: 1180 if (nvl->nvl_array_next == NULL) { 1181 if (nvl->nvl_parent == NULL) 1182 goto fail; 1183 nvl = nvpair_nvlist(nvl->nvl_parent); 1184 } else { 1185 nvl = __DECONST(nvlist_t *, 1186 nvlist_get_array_next(nvl)); 1187 ptr = nvlist_unpack_header(nvl, ptr, nfds, 1188 &isbe, &left); 1189 if (ptr == NULL) 1190 goto fail; 1191 } 1192 nvpair_free_structure(nvp); 1193 continue; 1194 case NV_TYPE_BOOL_ARRAY: 1195 ptr = nvpair_unpack_bool_array(isbe, nvp, ptr, &left); 1196 break; 1197 case NV_TYPE_NUMBER_ARRAY: 1198 ptr = nvpair_unpack_number_array(isbe, nvp, ptr, &left); 1199 break; 1200 case NV_TYPE_STRING_ARRAY: 1201 ptr = nvpair_unpack_string_array(isbe, nvp, ptr, &left); 1202 break; 1203 case NV_TYPE_NVLIST_ARRAY: 1204 ptr = nvpair_unpack_nvlist_array(isbe, nvp, ptr, &left, 1205 &array); 1206 if (ptr == NULL) 1207 goto fail; 1208 PJDLOG_ASSERT(array != NULL); 1209 tmpnvl = array; 1210 do { 1211 nvlist_set_parent(array, nvp); 1212 array = __DECONST(nvlist_t *, 1213 nvlist_get_array_next(array)); 1214 } while (array != NULL); 1215 ptr = nvlist_unpack_header(tmpnvl, ptr, nfds, &isbe, 1216 &left); 1217 break; 1218 default: 1219 PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp)); 1220 } 1221 if (ptr == NULL) 1222 goto fail; 1223 if (!nvlist_move_nvpair(nvl, nvp)) 1224 goto fail; 1225 if (tmpnvl != NULL) { 1226 nvl = tmpnvl; 1227 tmpnvl = NULL; 1228 } 1229 } 1230 1231 return (retnvl); 1232fail: 1233 nvlist_destroy(retnvl); 1234 return (NULL); 1235} 1236 1237nvlist_t * 1238nvlist_unpack(const void *buf, size_t size, int flags) 1239{ 1240 1241 return (nvlist_xunpack(buf, size, NULL, 0, flags)); 1242} 1243 1244#ifndef _KERNEL 1245int 1246nvlist_send(int sock, const nvlist_t *nvl) 1247{ 1248 size_t datasize, nfds; 1249 int *fds; 1250 void *data; 1251 int64_t fdidx; 1252 int ret; 1253 1254 if (nvlist_error(nvl) != 0) { 1255 ERRNO_SET(nvlist_error(nvl)); 1256 return (-1); 1257 } 1258 1259 fds = nvlist_descriptors(nvl, &nfds); 1260 if (fds == NULL) 1261 return (-1); 1262 1263 ret = -1; 1264 fdidx = 0; 1265 1266 data = nvlist_xpack(nvl, &fdidx, &datasize); 1267 if (data == NULL) 1268 goto out; 1269 1270 if (buf_send(sock, data, datasize) == -1) 1271 goto out; 1272 1273 if (nfds > 0) { 1274 if (fd_send(sock, fds, nfds) == -1) 1275 goto out; 1276 } 1277 1278 ret = 0; 1279out: 1280 ERRNO_SAVE(); 1281 nv_free(fds); 1282 nv_free(data); 1283 ERRNO_RESTORE(); 1284 return (ret); 1285} 1286 1287nvlist_t * 1288nvlist_recv(int sock, int flags) 1289{ 1290 struct nvlist_header nvlhdr; 1291 nvlist_t *nvl, *ret; 1292 unsigned char *buf; 1293 size_t nfds, size, i; 1294 int *fds; 1295 1296 if (buf_recv(sock, &nvlhdr, sizeof(nvlhdr)) == -1) 1297 return (NULL); 1298 1299 if (!nvlist_check_header(&nvlhdr)) 1300 return (NULL); 1301 1302 nfds = (size_t)nvlhdr.nvlh_descriptors; 1303 size = sizeof(nvlhdr) + (size_t)nvlhdr.nvlh_size; 1304 1305 buf = nv_malloc(size); 1306 if (buf == NULL) 1307 return (NULL); 1308 1309 memcpy(buf, &nvlhdr, sizeof(nvlhdr)); 1310 1311 ret = NULL; 1312 fds = NULL; 1313 1314 if (buf_recv(sock, buf + sizeof(nvlhdr), size - sizeof(nvlhdr)) == -1) 1315 goto out; 1316 1317 if (nfds > 0) { 1318 fds = nv_malloc(nfds * sizeof(fds[0])); 1319 if (fds == NULL) 1320 goto out; 1321 if (fd_recv(sock, fds, nfds) == -1) 1322 goto out; 1323 } 1324 1325 nvl = nvlist_xunpack(buf, size, fds, nfds, flags); 1326 if (nvl == NULL) { 1327 ERRNO_SAVE(); 1328 for (i = 0; i < nfds; i++) 1329 close(fds[i]); 1330 ERRNO_RESTORE(); 1331 goto out; 1332 } 1333 1334 ret = nvl; 1335out: 1336 ERRNO_SAVE(); 1337 nv_free(buf); 1338 nv_free(fds); 1339 ERRNO_RESTORE(); 1340 1341 return (ret); 1342} 1343 1344nvlist_t * 1345nvlist_xfer(int sock, nvlist_t *nvl, int flags) 1346{ 1347 1348 if (nvlist_send(sock, nvl) < 0) { 1349 nvlist_destroy(nvl); 1350 return (NULL); 1351 } 1352 nvlist_destroy(nvl); 1353 return (nvlist_recv(sock, flags)); 1354} 1355#endif 1356 1357nvpair_t * 1358nvlist_first_nvpair(const nvlist_t *nvl) 1359{ 1360 1361 NVLIST_ASSERT(nvl); 1362 1363 return (TAILQ_FIRST(&nvl->nvl_head)); 1364} 1365 1366nvpair_t * 1367nvlist_next_nvpair(const nvlist_t *nvl __unused, const nvpair_t *nvp) 1368{ 1369 nvpair_t *retnvp; 1370 1371 NVLIST_ASSERT(nvl); 1372 NVPAIR_ASSERT(nvp); 1373 PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl); 1374 1375 retnvp = nvpair_next(nvp); 1376 PJDLOG_ASSERT(retnvp == NULL || nvpair_nvlist(retnvp) == nvl); 1377 1378 return (retnvp); 1379 1380} 1381 1382nvpair_t * 1383nvlist_prev_nvpair(const nvlist_t *nvl __unused, const nvpair_t *nvp) 1384{ 1385 nvpair_t *retnvp; 1386 1387 NVLIST_ASSERT(nvl); 1388 NVPAIR_ASSERT(nvp); 1389 PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl); 1390 1391 retnvp = nvpair_prev(nvp); 1392 PJDLOG_ASSERT(nvpair_nvlist(retnvp) == nvl); 1393 1394 return (retnvp); 1395} 1396 1397const char * 1398nvlist_next(const nvlist_t *nvl, int *typep, void **cookiep) 1399{ 1400 nvpair_t *nvp; 1401 1402 NVLIST_ASSERT(nvl); 1403 1404 if (cookiep == NULL || *cookiep == NULL) 1405 nvp = nvlist_first_nvpair(nvl); 1406 else 1407 nvp = nvlist_next_nvpair(nvl, *cookiep); 1408 if (nvp == NULL) 1409 return (NULL); 1410 if (typep != NULL) 1411 *typep = nvpair_type(nvp); 1412 if (cookiep != NULL) 1413 *cookiep = nvp; 1414 return (nvpair_name(nvp)); 1415} 1416 1417bool 1418nvlist_exists(const nvlist_t *nvl, const char *name) 1419{ 1420 1421 return (nvlist_find(nvl, NV_TYPE_NONE, name) != NULL); 1422} 1423 1424#define NVLIST_EXISTS(type, TYPE) \ 1425bool \ 1426nvlist_exists_##type(const nvlist_t *nvl, const char *name) \ 1427{ \ 1428 \ 1429 return (nvlist_find(nvl, NV_TYPE_##TYPE, name) != NULL); \ 1430} 1431 1432NVLIST_EXISTS(null, NULL) 1433NVLIST_EXISTS(bool, BOOL) 1434NVLIST_EXISTS(number, NUMBER) 1435NVLIST_EXISTS(string, STRING) 1436NVLIST_EXISTS(nvlist, NVLIST) 1437NVLIST_EXISTS(binary, BINARY) 1438NVLIST_EXISTS(bool_array, BOOL_ARRAY) 1439NVLIST_EXISTS(number_array, NUMBER_ARRAY) 1440NVLIST_EXISTS(string_array, STRING_ARRAY) 1441NVLIST_EXISTS(nvlist_array, NVLIST_ARRAY) 1442#ifndef _KERNEL 1443NVLIST_EXISTS(descriptor, DESCRIPTOR) 1444NVLIST_EXISTS(descriptor_array, DESCRIPTOR_ARRAY) 1445#endif 1446 1447#undef NVLIST_EXISTS 1448 1449void 1450nvlist_add_nvpair(nvlist_t *nvl, const nvpair_t *nvp) 1451{ 1452 nvpair_t *newnvp; 1453 1454 NVPAIR_ASSERT(nvp); 1455 1456 if (nvlist_error(nvl) != 0) { 1457 ERRNO_SET(nvlist_error(nvl)); 1458 return; 1459 } 1460 if ((nvl->nvl_flags & NV_FLAG_NO_UNIQUE) == 0) { 1461 if (nvlist_exists(nvl, nvpair_name(nvp))) { 1462 nvl->nvl_error = EEXIST; 1463 ERRNO_SET(nvlist_error(nvl)); 1464 return; 1465 } 1466 } 1467 1468 newnvp = nvpair_clone(nvp); 1469 if (newnvp == NULL) { 1470 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1471 ERRNO_SET(nvlist_error(nvl)); 1472 return; 1473 } 1474 1475 nvpair_insert(&nvl->nvl_head, newnvp, nvl); 1476} 1477 1478void 1479nvlist_add_stringf(nvlist_t *nvl, const char *name, const char *valuefmt, ...) 1480{ 1481 va_list valueap; 1482 1483 va_start(valueap, valuefmt); 1484 nvlist_add_stringv(nvl, name, valuefmt, valueap); 1485 va_end(valueap); 1486} 1487 1488void 1489nvlist_add_stringv(nvlist_t *nvl, const char *name, const char *valuefmt, 1490 va_list valueap) 1491{ 1492 nvpair_t *nvp; 1493 1494 if (nvlist_error(nvl) != 0) { 1495 ERRNO_SET(nvlist_error(nvl)); 1496 return; 1497 } 1498 1499 nvp = nvpair_create_stringv(name, valuefmt, valueap); 1500 if (nvp == NULL) { 1501 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1502 ERRNO_SET(nvl->nvl_error); 1503 } else { 1504 (void)nvlist_move_nvpair(nvl, nvp); 1505 } 1506} 1507 1508void 1509nvlist_add_null(nvlist_t *nvl, const char *name) 1510{ 1511 nvpair_t *nvp; 1512 1513 if (nvlist_error(nvl) != 0) { 1514 ERRNO_SET(nvlist_error(nvl)); 1515 return; 1516 } 1517 1518 nvp = nvpair_create_null(name); 1519 if (nvp == NULL) { 1520 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1521 ERRNO_SET(nvl->nvl_error); 1522 } else { 1523 (void)nvlist_move_nvpair(nvl, nvp); 1524 } 1525} 1526 1527void 1528nvlist_add_binary(nvlist_t *nvl, const char *name, const void *value, 1529 size_t size) 1530{ 1531 nvpair_t *nvp; 1532 1533 if (nvlist_error(nvl) != 0) { 1534 ERRNO_SET(nvlist_error(nvl)); 1535 return; 1536 } 1537 1538 nvp = nvpair_create_binary(name, value, size); 1539 if (nvp == NULL) { 1540 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1541 ERRNO_SET(nvl->nvl_error); 1542 } else { 1543 (void)nvlist_move_nvpair(nvl, nvp); 1544 } 1545} 1546 1547 1548#define NVLIST_ADD(vtype, type) \ 1549void \ 1550nvlist_add_##type(nvlist_t *nvl, const char *name, vtype value) \ 1551{ \ 1552 nvpair_t *nvp; \ 1553 \ 1554 if (nvlist_error(nvl) != 0) { \ 1555 ERRNO_SET(nvlist_error(nvl)); \ 1556 return; \ 1557 } \ 1558 \ 1559 nvp = nvpair_create_##type(name, value); \ 1560 if (nvp == NULL) { \ 1561 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); \ 1562 ERRNO_SET(nvl->nvl_error); \ 1563 } else { \ 1564 (void)nvlist_move_nvpair(nvl, nvp); \ 1565 } \ 1566} 1567 1568NVLIST_ADD(bool, bool) 1569NVLIST_ADD(uint64_t, number) 1570NVLIST_ADD(const char *, string) 1571NVLIST_ADD(const nvlist_t *, nvlist) 1572#ifndef _KERNEL 1573NVLIST_ADD(int, descriptor); 1574#endif 1575 1576#undef NVLIST_ADD 1577 1578#define NVLIST_ADD_ARRAY(vtype, type) \ 1579void \ 1580nvlist_add_##type##_array(nvlist_t *nvl, const char *name, vtype value, \ 1581 size_t nitems) \ 1582{ \ 1583 nvpair_t *nvp; \ 1584 \ 1585 if (nvlist_error(nvl) != 0) { \ 1586 ERRNO_SET(nvlist_error(nvl)); \ 1587 return; \ 1588 } \ 1589 \ 1590 nvp = nvpair_create_##type##_array(name, value, nitems); \ 1591 if (nvp == NULL) { \ 1592 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); \ 1593 ERRNO_SET(nvl->nvl_error); \ 1594 } else { \ 1595 (void)nvlist_move_nvpair(nvl, nvp); \ 1596 } \ 1597} 1598 1599NVLIST_ADD_ARRAY(const bool *, bool) 1600NVLIST_ADD_ARRAY(const uint64_t *, number) 1601NVLIST_ADD_ARRAY(const char * const *, string) 1602NVLIST_ADD_ARRAY(const nvlist_t * const *, nvlist) 1603#ifndef _KERNEL 1604NVLIST_ADD_ARRAY(const int *, descriptor) 1605#endif 1606 1607#undef NVLIST_ADD_ARRAY 1608 1609#define NVLIST_APPEND_ARRAY(vtype, type, TYPE) \ 1610void \ 1611nvlist_append_##type##_array(nvlist_t *nvl, const char *name, vtype value)\ 1612{ \ 1613 nvpair_t *nvp; \ 1614 \ 1615 if (nvlist_error(nvl) != 0) { \ 1616 ERRNO_SET(nvlist_error(nvl)); \ 1617 return; \ 1618 } \ 1619 nvp = nvlist_find(nvl, NV_TYPE_##TYPE##_ARRAY, name); \ 1620 if (nvp == NULL) { \ 1621 nvlist_add_##type##_array(nvl, name, &value, 1); \ 1622 return; \ 1623 } \ 1624 if (nvpair_append_##type##_array(nvp, value) == -1) { \ 1625 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); \ 1626 ERRNO_SET(nvl->nvl_error); \ 1627 } \ 1628} 1629 1630NVLIST_APPEND_ARRAY(const bool, bool, BOOL) 1631NVLIST_APPEND_ARRAY(const uint64_t, number, NUMBER) 1632NVLIST_APPEND_ARRAY(const char *, string, STRING) 1633NVLIST_APPEND_ARRAY(const nvlist_t *, nvlist, NVLIST) 1634#ifndef _KERNEL 1635NVLIST_APPEND_ARRAY(const int, descriptor, DESCRIPTOR) 1636#endif 1637 1638#undef NVLIST_APPEND_ARRAY 1639 1640bool 1641nvlist_move_nvpair(nvlist_t *nvl, nvpair_t *nvp) 1642{ 1643 1644 NVPAIR_ASSERT(nvp); 1645 PJDLOG_ASSERT(nvpair_nvlist(nvp) == NULL); 1646 1647 if (nvlist_error(nvl) != 0) { 1648 nvpair_free(nvp); 1649 ERRNO_SET(nvlist_error(nvl)); 1650 return (false); 1651 } 1652 if ((nvl->nvl_flags & NV_FLAG_NO_UNIQUE) == 0) { 1653 if (nvlist_exists(nvl, nvpair_name(nvp))) { 1654 nvpair_free(nvp); 1655 nvl->nvl_error = EEXIST; 1656 ERRNO_SET(nvl->nvl_error); 1657 return (false); 1658 } 1659 } 1660 1661 nvpair_insert(&nvl->nvl_head, nvp, nvl); 1662 return (true); 1663} 1664 1665void 1666nvlist_move_string(nvlist_t *nvl, const char *name, char *value) 1667{ 1668 nvpair_t *nvp; 1669 1670 if (nvlist_error(nvl) != 0) { 1671 nv_free(value); 1672 ERRNO_SET(nvlist_error(nvl)); 1673 return; 1674 } 1675 1676 nvp = nvpair_move_string(name, value); 1677 if (nvp == NULL) { 1678 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1679 ERRNO_SET(nvl->nvl_error); 1680 } else { 1681 (void)nvlist_move_nvpair(nvl, nvp); 1682 } 1683} 1684 1685void 1686nvlist_move_nvlist(nvlist_t *nvl, const char *name, nvlist_t *value) 1687{ 1688 nvpair_t *nvp; 1689 1690 if (nvlist_error(nvl) != 0) { 1691 if (value != NULL && nvlist_get_nvpair_parent(value) != NULL) 1692 nvlist_destroy(value); 1693 ERRNO_SET(nvlist_error(nvl)); 1694 return; 1695 } 1696 1697 nvp = nvpair_move_nvlist(name, value); 1698 if (nvp == NULL) { 1699 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1700 ERRNO_SET(nvl->nvl_error); 1701 } else { 1702 (void)nvlist_move_nvpair(nvl, nvp); 1703 } 1704} 1705 1706#ifndef _KERNEL 1707void 1708nvlist_move_descriptor(nvlist_t *nvl, const char *name, int value) 1709{ 1710 nvpair_t *nvp; 1711 1712 if (nvlist_error(nvl) != 0) { 1713 close(value); 1714 ERRNO_SET(nvlist_error(nvl)); 1715 return; 1716 } 1717 1718 nvp = nvpair_move_descriptor(name, value); 1719 if (nvp == NULL) { 1720 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1721 ERRNO_SET(nvl->nvl_error); 1722 } else { 1723 (void)nvlist_move_nvpair(nvl, nvp); 1724 } 1725} 1726#endif 1727 1728void 1729nvlist_move_binary(nvlist_t *nvl, const char *name, void *value, size_t size) 1730{ 1731 nvpair_t *nvp; 1732 1733 if (nvlist_error(nvl) != 0) { 1734 nv_free(value); 1735 ERRNO_SET(nvlist_error(nvl)); 1736 return; 1737 } 1738 1739 nvp = nvpair_move_binary(name, value, size); 1740 if (nvp == NULL) { 1741 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1742 ERRNO_SET(nvl->nvl_error); 1743 } else { 1744 (void)nvlist_move_nvpair(nvl, nvp); 1745 } 1746} 1747 1748void 1749nvlist_move_bool_array(nvlist_t *nvl, const char *name, bool *value, 1750 size_t nitems) 1751{ 1752 nvpair_t *nvp; 1753 1754 if (nvlist_error(nvl) != 0) { 1755 nv_free(value); 1756 ERRNO_SET(nvlist_error(nvl)); 1757 return; 1758 } 1759 1760 nvp = nvpair_move_bool_array(name, value, nitems); 1761 if (nvp == NULL) { 1762 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1763 ERRNO_SET(nvl->nvl_error); 1764 } else { 1765 (void)nvlist_move_nvpair(nvl, nvp); 1766 } 1767} 1768 1769void 1770nvlist_move_string_array(nvlist_t *nvl, const char *name, char **value, 1771 size_t nitems) 1772{ 1773 nvpair_t *nvp; 1774 size_t i; 1775 1776 if (nvlist_error(nvl) != 0) { 1777 if (value != NULL) { 1778 for (i = 0; i < nitems; i++) 1779 nv_free(value[i]); 1780 nv_free(value); 1781 } 1782 ERRNO_SET(nvlist_error(nvl)); 1783 return; 1784 } 1785 1786 nvp = nvpair_move_string_array(name, value, nitems); 1787 if (nvp == NULL) { 1788 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1789 ERRNO_SET(nvl->nvl_error); 1790 } else { 1791 (void)nvlist_move_nvpair(nvl, nvp); 1792 } 1793} 1794 1795void 1796nvlist_move_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **value, 1797 size_t nitems) 1798{ 1799 nvpair_t *nvp; 1800 size_t i; 1801 1802 if (nvlist_error(nvl) != 0) { 1803 if (value != NULL) { 1804 for (i = 0; i < nitems; i++) { 1805 if (nvlist_get_pararr(value[i], NULL) == NULL) 1806 nvlist_destroy(value[i]); 1807 } 1808 } 1809 nv_free(value); 1810 ERRNO_SET(nvlist_error(nvl)); 1811 return; 1812 } 1813 1814 nvp = nvpair_move_nvlist_array(name, value, nitems); 1815 if (nvp == NULL) { 1816 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1817 ERRNO_SET(nvl->nvl_error); 1818 } else { 1819 (void)nvlist_move_nvpair(nvl, nvp); 1820 } 1821} 1822 1823void 1824nvlist_move_number_array(nvlist_t *nvl, const char *name, uint64_t *value, 1825 size_t nitems) 1826{ 1827 nvpair_t *nvp; 1828 1829 if (nvlist_error(nvl) != 0) { 1830 nv_free(value); 1831 ERRNO_SET(nvlist_error(nvl)); 1832 return; 1833 } 1834 1835 nvp = nvpair_move_number_array(name, value, nitems); 1836 if (nvp == NULL) { 1837 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1838 ERRNO_SET(nvl->nvl_error); 1839 } else { 1840 (void)nvlist_move_nvpair(nvl, nvp); 1841 } 1842} 1843 1844#ifndef _KERNEL 1845void 1846nvlist_move_descriptor_array(nvlist_t *nvl, const char *name, int *value, 1847 size_t nitems) 1848{ 1849 nvpair_t *nvp; 1850 size_t i; 1851 1852 if (nvlist_error(nvl) != 0) { 1853 if (value != 0) { 1854 for (i = 0; i < nitems; i++) 1855 close(value[i]); 1856 nv_free(value); 1857 } 1858 1859 ERRNO_SET(nvlist_error(nvl)); 1860 return; 1861 } 1862 1863 nvp = nvpair_move_descriptor_array(name, value, nitems); 1864 if (nvp == NULL) { 1865 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1866 ERRNO_SET(nvl->nvl_error); 1867 } else { 1868 (void)nvlist_move_nvpair(nvl, nvp); 1869 } 1870} 1871#endif 1872 1873const nvpair_t * 1874nvlist_get_nvpair(const nvlist_t *nvl, const char *name) 1875{ 1876 1877 return (nvlist_find(nvl, NV_TYPE_NONE, name)); 1878} 1879 1880#define NVLIST_GET(ftype, type, TYPE) \ 1881ftype \ 1882nvlist_get_##type(const nvlist_t *nvl, const char *name) \ 1883{ \ 1884 const nvpair_t *nvp; \ 1885 \ 1886 nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name); \ 1887 if (nvp == NULL) \ 1888 nvlist_report_missing(NV_TYPE_##TYPE, name); \ 1889 return (nvpair_get_##type(nvp)); \ 1890} 1891 1892NVLIST_GET(bool, bool, BOOL) 1893NVLIST_GET(uint64_t, number, NUMBER) 1894NVLIST_GET(const char *, string, STRING) 1895NVLIST_GET(const nvlist_t *, nvlist, NVLIST) 1896#ifndef _KERNEL 1897NVLIST_GET(int, descriptor, DESCRIPTOR) 1898#endif 1899 1900#undef NVLIST_GET 1901 1902const void * 1903nvlist_get_binary(const nvlist_t *nvl, const char *name, size_t *sizep) 1904{ 1905 nvpair_t *nvp; 1906 1907 nvp = nvlist_find(nvl, NV_TYPE_BINARY, name); 1908 if (nvp == NULL) 1909 nvlist_report_missing(NV_TYPE_BINARY, name); 1910 1911 return (nvpair_get_binary(nvp, sizep)); 1912} 1913 1914#define NVLIST_GET_ARRAY(ftype, type, TYPE) \ 1915ftype \ 1916nvlist_get_##type##_array(const nvlist_t *nvl, const char *name, \ 1917 size_t *nitems) \ 1918{ \ 1919 const nvpair_t *nvp; \ 1920 \ 1921 nvp = nvlist_find(nvl, NV_TYPE_##TYPE##_ARRAY, name); \ 1922 if (nvp == NULL) \ 1923 nvlist_report_missing(NV_TYPE_##TYPE##_ARRAY, name); \ 1924 return (nvpair_get_##type##_array(nvp, nitems)); \ 1925} 1926 1927NVLIST_GET_ARRAY(const bool *, bool, BOOL) 1928NVLIST_GET_ARRAY(const uint64_t *, number, NUMBER) 1929NVLIST_GET_ARRAY(const char * const *, string, STRING) 1930NVLIST_GET_ARRAY(const nvlist_t * const *, nvlist, NVLIST) 1931#ifndef _KERNEL 1932NVLIST_GET_ARRAY(const int *, descriptor, DESCRIPTOR) 1933#endif 1934 1935#undef NVLIST_GET_ARRAY 1936 1937#define NVLIST_TAKE(ftype, type, TYPE) \ 1938ftype \ 1939nvlist_take_##type(nvlist_t *nvl, const char *name) \ 1940{ \ 1941 nvpair_t *nvp; \ 1942 ftype value; \ 1943 \ 1944 nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name); \ 1945 if (nvp == NULL) \ 1946 nvlist_report_missing(NV_TYPE_##TYPE, name); \ 1947 value = (ftype)(intptr_t)nvpair_get_##type(nvp); \ 1948 nvlist_remove_nvpair(nvl, nvp); \ 1949 nvpair_free_structure(nvp); \ 1950 return (value); \ 1951} 1952 1953NVLIST_TAKE(bool, bool, BOOL) 1954NVLIST_TAKE(uint64_t, number, NUMBER) 1955NVLIST_TAKE(char *, string, STRING) 1956NVLIST_TAKE(nvlist_t *, nvlist, NVLIST) 1957#ifndef _KERNEL 1958NVLIST_TAKE(int, descriptor, DESCRIPTOR) 1959#endif 1960 1961#undef NVLIST_TAKE 1962 1963void * 1964nvlist_take_binary(nvlist_t *nvl, const char *name, size_t *sizep) 1965{ 1966 nvpair_t *nvp; 1967 void *value; 1968 1969 nvp = nvlist_find(nvl, NV_TYPE_BINARY, name); 1970 if (nvp == NULL) 1971 nvlist_report_missing(NV_TYPE_BINARY, name); 1972 1973 value = (void *)(intptr_t)nvpair_get_binary(nvp, sizep); 1974 nvlist_remove_nvpair(nvl, nvp); 1975 nvpair_free_structure(nvp); 1976 return (value); 1977} 1978 1979#define NVLIST_TAKE_ARRAY(ftype, type, TYPE) \ 1980ftype \ 1981nvlist_take_##type##_array(nvlist_t *nvl, const char *name, \ 1982 size_t *nitems) \ 1983{ \ 1984 nvpair_t *nvp; \ 1985 ftype value; \ 1986 \ 1987 nvp = nvlist_find(nvl, NV_TYPE_##TYPE##_ARRAY, name); \ 1988 if (nvp == NULL) \ 1989 nvlist_report_missing(NV_TYPE_##TYPE##_ARRAY, name); \ 1990 value = (ftype)(intptr_t)nvpair_get_##type##_array(nvp, nitems);\ 1991 nvlist_remove_nvpair(nvl, nvp); \ 1992 nvpair_free_structure(nvp); \ 1993 return (value); \ 1994} 1995 1996NVLIST_TAKE_ARRAY(bool *, bool, BOOL) 1997NVLIST_TAKE_ARRAY(uint64_t *, number, NUMBER) 1998NVLIST_TAKE_ARRAY(char **, string, STRING) 1999NVLIST_TAKE_ARRAY(nvlist_t **, nvlist, NVLIST) 2000#ifndef _KERNEL 2001NVLIST_TAKE_ARRAY(int *, descriptor, DESCRIPTOR) 2002#endif 2003 2004void 2005nvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp) 2006{ 2007 2008 NVLIST_ASSERT(nvl); 2009 NVPAIR_ASSERT(nvp); 2010 PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl); 2011 2012 nvpair_remove(&nvl->nvl_head, nvp, nvl); 2013} 2014 2015void 2016nvlist_free(nvlist_t *nvl, const char *name) 2017{ 2018 2019 nvlist_free_type(nvl, name, NV_TYPE_NONE); 2020} 2021 2022#define NVLIST_FREE(type, TYPE) \ 2023void \ 2024nvlist_free_##type(nvlist_t *nvl, const char *name) \ 2025{ \ 2026 \ 2027 nvlist_free_type(nvl, name, NV_TYPE_##TYPE); \ 2028} 2029 2030NVLIST_FREE(null, NULL) 2031NVLIST_FREE(bool, BOOL) 2032NVLIST_FREE(number, NUMBER) 2033NVLIST_FREE(string, STRING) 2034NVLIST_FREE(nvlist, NVLIST) 2035NVLIST_FREE(binary, BINARY) 2036NVLIST_FREE(bool_array, BOOL_ARRAY) 2037NVLIST_FREE(number_array, NUMBER_ARRAY) 2038NVLIST_FREE(string_array, STRING_ARRAY) 2039NVLIST_FREE(nvlist_array, NVLIST_ARRAY) 2040#ifndef _KERNEL 2041NVLIST_FREE(descriptor, DESCRIPTOR) 2042NVLIST_FREE(descriptor_array, DESCRIPTOR_ARRAY) 2043#endif 2044 2045#undef NVLIST_FREE 2046 2047void 2048nvlist_free_nvpair(nvlist_t *nvl, nvpair_t *nvp) 2049{ 2050 2051 NVLIST_ASSERT(nvl); 2052 NVPAIR_ASSERT(nvp); 2053 PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl); 2054 2055 nvlist_remove_nvpair(nvl, nvp); 2056 nvpair_free(nvp); 2057} 2058 2059