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