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_stringv(nvlist_t *nvl, const char *name, const char *valuefmt, 1481 va_list valueap); 1482 1483 void 1484 nvlist_add_stringf(nvlist_t *nvl, const char *name, const char *valuefmt, ...) 1485 { 1486 va_list valueap; 1487 1488 va_start(valueap, valuefmt); 1489 nvlist_add_stringv(nvl, name, valuefmt, valueap); 1490 va_end(valueap); 1491 } 1492 1493 void 1494 nvlist_add_stringv(nvlist_t *nvl, const char *name, const char *valuefmt, 1495 va_list valueap) 1496 { 1497 nvpair_t *nvp; 1498 1499 if (nvlist_error(nvl) != 0) { 1500 ERRNO_SET(nvlist_error(nvl)); 1501 return; 1502 } 1503 1504 nvp = nvpair_create_stringv(name, valuefmt, valueap); 1505 if (nvp == NULL) { 1506 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1507 ERRNO_SET(nvl->nvl_error); 1508 } else { 1509 (void)nvlist_move_nvpair(nvl, nvp); 1510 } 1511 } 1512 1513 void 1514 nvlist_add_null(nvlist_t *nvl, const char *name) 1515 { 1516 nvpair_t *nvp; 1517 1518 if (nvlist_error(nvl) != 0) { 1519 ERRNO_SET(nvlist_error(nvl)); 1520 return; 1521 } 1522 1523 nvp = nvpair_create_null(name); 1524 if (nvp == NULL) { 1525 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1526 ERRNO_SET(nvl->nvl_error); 1527 } else { 1528 (void)nvlist_move_nvpair(nvl, nvp); 1529 } 1530 } 1531 1532 void 1533 nvlist_add_binary(nvlist_t *nvl, const char *name, const void *value, 1534 size_t size) 1535 { 1536 nvpair_t *nvp; 1537 1538 if (nvlist_error(nvl) != 0) { 1539 ERRNO_SET(nvlist_error(nvl)); 1540 return; 1541 } 1542 1543 nvp = nvpair_create_binary(name, value, size); 1544 if (nvp == NULL) { 1545 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1546 ERRNO_SET(nvl->nvl_error); 1547 } else { 1548 (void)nvlist_move_nvpair(nvl, nvp); 1549 } 1550 } 1551 1552 1553 #define NVLIST_ADD(vtype, type) \ 1554 void \ 1555 nvlist_add_##type(nvlist_t *nvl, const char *name, vtype value) \ 1556 { \ 1557 nvpair_t *nvp; \ 1558 \ 1559 if (nvlist_error(nvl) != 0) { \ 1560 ERRNO_SET(nvlist_error(nvl)); \ 1561 return; \ 1562 } \ 1563 \ 1564 nvp = nvpair_create_##type(name, value); \ 1565 if (nvp == NULL) { \ 1566 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); \ 1567 ERRNO_SET(nvl->nvl_error); \ 1568 } else { \ 1569 (void)nvlist_move_nvpair(nvl, nvp); \ 1570 } \ 1571 } 1572 1573 NVLIST_ADD(bool, bool) 1574 NVLIST_ADD(uint64_t, number) 1575 NVLIST_ADD(const char *, string) 1576 NVLIST_ADD(const nvlist_t *, nvlist) 1577 #ifndef _KERNEL 1578 NVLIST_ADD(int, descriptor); 1579 #endif 1580 1581 #undef NVLIST_ADD 1582 1583 #define NVLIST_ADD_ARRAY(vtype, type) \ 1584 void \ 1585 nvlist_add_##type##_array(nvlist_t *nvl, const char *name, vtype value, \ 1586 size_t nitems) \ 1587 { \ 1588 nvpair_t *nvp; \ 1589 \ 1590 if (nvlist_error(nvl) != 0) { \ 1591 ERRNO_SET(nvlist_error(nvl)); \ 1592 return; \ 1593 } \ 1594 \ 1595 nvp = nvpair_create_##type##_array(name, value, nitems); \ 1596 if (nvp == NULL) { \ 1597 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); \ 1598 ERRNO_SET(nvl->nvl_error); \ 1599 } else { \ 1600 (void)nvlist_move_nvpair(nvl, nvp); \ 1601 } \ 1602 } 1603 1604 NVLIST_ADD_ARRAY(const bool *, bool) 1605 NVLIST_ADD_ARRAY(const uint64_t *, number) 1606 NVLIST_ADD_ARRAY(const char * const *, string) 1607 NVLIST_ADD_ARRAY(const nvlist_t * const *, nvlist) 1608 #ifndef _KERNEL 1609 NVLIST_ADD_ARRAY(const int *, descriptor) 1610 #endif 1611 1612 #undef NVLIST_ADD_ARRAY 1613 1614 #define NVLIST_APPEND_ARRAY(vtype, type, TYPE) \ 1615 void \ 1616 nvlist_append_##type##_array(nvlist_t *nvl, const char *name, vtype value)\ 1617 { \ 1618 nvpair_t *nvp; \ 1619 \ 1620 if (nvlist_error(nvl) != 0) { \ 1621 ERRNO_SET(nvlist_error(nvl)); \ 1622 return; \ 1623 } \ 1624 nvp = nvlist_find(nvl, NV_TYPE_##TYPE##_ARRAY, name); \ 1625 if (nvp == NULL) { \ 1626 nvlist_add_##type##_array(nvl, name, &value, 1); \ 1627 return; \ 1628 } \ 1629 if (nvpair_append_##type##_array(nvp, value) == -1) { \ 1630 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); \ 1631 ERRNO_SET(nvl->nvl_error); \ 1632 } \ 1633 } 1634 1635 NVLIST_APPEND_ARRAY(const bool, bool, BOOL) 1636 NVLIST_APPEND_ARRAY(const uint64_t, number, NUMBER) 1637 NVLIST_APPEND_ARRAY(const char *, string, STRING) 1638 NVLIST_APPEND_ARRAY(const nvlist_t *, nvlist, NVLIST) 1639 #ifndef _KERNEL 1640 NVLIST_APPEND_ARRAY(const int, descriptor, DESCRIPTOR) 1641 #endif 1642 1643 #undef NVLIST_APPEND_ARRAY 1644 1645 bool 1646 nvlist_move_nvpair(nvlist_t *nvl, nvpair_t *nvp) 1647 { 1648 1649 NVPAIR_ASSERT(nvp); 1650 PJDLOG_ASSERT(nvpair_nvlist(nvp) == NULL); 1651 1652 if (nvlist_error(nvl) != 0) { 1653 nvpair_free(nvp); 1654 ERRNO_SET(nvlist_error(nvl)); 1655 return (false); 1656 } 1657 if ((nvl->nvl_flags & NV_FLAG_NO_UNIQUE) == 0) { 1658 if (nvlist_exists(nvl, nvpair_name(nvp))) { 1659 nvpair_free(nvp); 1660 nvl->nvl_error = EEXIST; 1661 ERRNO_SET(nvl->nvl_error); 1662 return (false); 1663 } 1664 } 1665 1666 nvpair_insert(&nvl->nvl_head, nvp, nvl); 1667 return (true); 1668 } 1669 1670 void 1671 nvlist_move_string(nvlist_t *nvl, const char *name, char *value) 1672 { 1673 nvpair_t *nvp; 1674 1675 if (nvlist_error(nvl) != 0) { 1676 nv_free(value); 1677 ERRNO_SET(nvlist_error(nvl)); 1678 return; 1679 } 1680 1681 nvp = nvpair_move_string(name, value); 1682 if (nvp == NULL) { 1683 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1684 ERRNO_SET(nvl->nvl_error); 1685 } else { 1686 (void)nvlist_move_nvpair(nvl, nvp); 1687 } 1688 } 1689 1690 void 1691 nvlist_move_nvlist(nvlist_t *nvl, const char *name, nvlist_t *value) 1692 { 1693 nvpair_t *nvp; 1694 1695 if (nvlist_error(nvl) != 0) { 1696 if (value != NULL && nvlist_get_nvpair_parent(value) != NULL) 1697 nvlist_destroy(value); 1698 ERRNO_SET(nvlist_error(nvl)); 1699 return; 1700 } 1701 1702 nvp = nvpair_move_nvlist(name, value); 1703 if (nvp == NULL) { 1704 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1705 ERRNO_SET(nvl->nvl_error); 1706 } else { 1707 (void)nvlist_move_nvpair(nvl, nvp); 1708 } 1709 } 1710 1711 #ifndef _KERNEL 1712 void 1713 nvlist_move_descriptor(nvlist_t *nvl, const char *name, int value) 1714 { 1715 nvpair_t *nvp; 1716 1717 if (nvlist_error(nvl) != 0) { 1718 close(value); 1719 ERRNO_SET(nvlist_error(nvl)); 1720 return; 1721 } 1722 1723 nvp = nvpair_move_descriptor(name, value); 1724 if (nvp == NULL) { 1725 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1726 ERRNO_SET(nvl->nvl_error); 1727 } else { 1728 (void)nvlist_move_nvpair(nvl, nvp); 1729 } 1730 } 1731 #endif 1732 1733 void 1734 nvlist_move_binary(nvlist_t *nvl, const char *name, void *value, size_t size) 1735 { 1736 nvpair_t *nvp; 1737 1738 if (nvlist_error(nvl) != 0) { 1739 nv_free(value); 1740 ERRNO_SET(nvlist_error(nvl)); 1741 return; 1742 } 1743 1744 nvp = nvpair_move_binary(name, value, size); 1745 if (nvp == NULL) { 1746 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1747 ERRNO_SET(nvl->nvl_error); 1748 } else { 1749 (void)nvlist_move_nvpair(nvl, nvp); 1750 } 1751 } 1752 1753 void 1754 nvlist_move_bool_array(nvlist_t *nvl, const char *name, bool *value, 1755 size_t nitems) 1756 { 1757 nvpair_t *nvp; 1758 1759 if (nvlist_error(nvl) != 0) { 1760 nv_free(value); 1761 ERRNO_SET(nvlist_error(nvl)); 1762 return; 1763 } 1764 1765 nvp = nvpair_move_bool_array(name, value, nitems); 1766 if (nvp == NULL) { 1767 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1768 ERRNO_SET(nvl->nvl_error); 1769 } else { 1770 (void)nvlist_move_nvpair(nvl, nvp); 1771 } 1772 } 1773 1774 void 1775 nvlist_move_string_array(nvlist_t *nvl, const char *name, char **value, 1776 size_t nitems) 1777 { 1778 nvpair_t *nvp; 1779 size_t i; 1780 1781 if (nvlist_error(nvl) != 0) { 1782 if (value != NULL) { 1783 for (i = 0; i < nitems; i++) 1784 nv_free(value[i]); 1785 nv_free(value); 1786 } 1787 ERRNO_SET(nvlist_error(nvl)); 1788 return; 1789 } 1790 1791 nvp = nvpair_move_string_array(name, value, nitems); 1792 if (nvp == NULL) { 1793 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1794 ERRNO_SET(nvl->nvl_error); 1795 } else { 1796 (void)nvlist_move_nvpair(nvl, nvp); 1797 } 1798 } 1799 1800 void 1801 nvlist_move_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **value, 1802 size_t nitems) 1803 { 1804 nvpair_t *nvp; 1805 size_t i; 1806 1807 if (nvlist_error(nvl) != 0) { 1808 if (value != NULL) { 1809 for (i = 0; i < nitems; i++) { 1810 if (nvlist_get_pararr(value[i], NULL) == NULL) 1811 nvlist_destroy(value[i]); 1812 } 1813 } 1814 nv_free(value); 1815 ERRNO_SET(nvlist_error(nvl)); 1816 return; 1817 } 1818 1819 nvp = nvpair_move_nvlist_array(name, value, nitems); 1820 if (nvp == NULL) { 1821 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1822 ERRNO_SET(nvl->nvl_error); 1823 } else { 1824 (void)nvlist_move_nvpair(nvl, nvp); 1825 } 1826 } 1827 1828 void 1829 nvlist_move_number_array(nvlist_t *nvl, const char *name, uint64_t *value, 1830 size_t nitems) 1831 { 1832 nvpair_t *nvp; 1833 1834 if (nvlist_error(nvl) != 0) { 1835 nv_free(value); 1836 ERRNO_SET(nvlist_error(nvl)); 1837 return; 1838 } 1839 1840 nvp = nvpair_move_number_array(name, value, nitems); 1841 if (nvp == NULL) { 1842 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1843 ERRNO_SET(nvl->nvl_error); 1844 } else { 1845 (void)nvlist_move_nvpair(nvl, nvp); 1846 } 1847 } 1848 1849 #ifndef _KERNEL 1850 void 1851 nvlist_move_descriptor_array(nvlist_t *nvl, const char *name, int *value, 1852 size_t nitems) 1853 { 1854 nvpair_t *nvp; 1855 size_t i; 1856 1857 if (nvlist_error(nvl) != 0) { 1858 if (value != 0) { 1859 for (i = 0; i < nitems; i++) 1860 close(value[i]); 1861 nv_free(value); 1862 } 1863 1864 ERRNO_SET(nvlist_error(nvl)); 1865 return; 1866 } 1867 1868 nvp = nvpair_move_descriptor_array(name, value, nitems); 1869 if (nvp == NULL) { 1870 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1871 ERRNO_SET(nvl->nvl_error); 1872 } else { 1873 (void)nvlist_move_nvpair(nvl, nvp); 1874 } 1875 } 1876 #endif 1877 1878 const nvpair_t * 1879 nvlist_get_nvpair(const nvlist_t *nvl, const char *name) 1880 { 1881 1882 return (nvlist_find(nvl, NV_TYPE_NONE, name)); 1883 } 1884 1885 #define NVLIST_GET(ftype, type, TYPE) \ 1886 ftype \ 1887 nvlist_get_##type(const nvlist_t *nvl, const char *name) \ 1888 { \ 1889 const nvpair_t *nvp; \ 1890 \ 1891 nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name); \ 1892 if (nvp == NULL) \ 1893 nvlist_report_missing(NV_TYPE_##TYPE, name); \ 1894 return (nvpair_get_##type(nvp)); \ 1895 } 1896 1897 NVLIST_GET(bool, bool, BOOL) 1898 NVLIST_GET(uint64_t, number, NUMBER) 1899 NVLIST_GET(const char *, string, STRING) 1900 NVLIST_GET(const nvlist_t *, nvlist, NVLIST) 1901 #ifndef _KERNEL 1902 NVLIST_GET(int, descriptor, DESCRIPTOR) 1903 #endif 1904 1905 #undef NVLIST_GET 1906 1907 const void * 1908 nvlist_get_binary(const nvlist_t *nvl, const char *name, size_t *sizep) 1909 { 1910 nvpair_t *nvp; 1911 1912 nvp = nvlist_find(nvl, NV_TYPE_BINARY, name); 1913 if (nvp == NULL) 1914 nvlist_report_missing(NV_TYPE_BINARY, name); 1915 1916 return (nvpair_get_binary(nvp, sizep)); 1917 } 1918 1919 #define NVLIST_GET_ARRAY(ftype, type, TYPE) \ 1920 ftype \ 1921 nvlist_get_##type##_array(const nvlist_t *nvl, const char *name, \ 1922 size_t *nitems) \ 1923 { \ 1924 const nvpair_t *nvp; \ 1925 \ 1926 nvp = nvlist_find(nvl, NV_TYPE_##TYPE##_ARRAY, name); \ 1927 if (nvp == NULL) \ 1928 nvlist_report_missing(NV_TYPE_##TYPE##_ARRAY, name); \ 1929 return (nvpair_get_##type##_array(nvp, nitems)); \ 1930 } 1931 1932 NVLIST_GET_ARRAY(const bool *, bool, BOOL) 1933 NVLIST_GET_ARRAY(const uint64_t *, number, NUMBER) 1934 NVLIST_GET_ARRAY(const char * const *, string, STRING) 1935 NVLIST_GET_ARRAY(const nvlist_t * const *, nvlist, NVLIST) 1936 #ifndef _KERNEL 1937 NVLIST_GET_ARRAY(const int *, descriptor, DESCRIPTOR) 1938 #endif 1939 1940 #undef NVLIST_GET_ARRAY 1941 1942 #define NVLIST_TAKE(ftype, type, TYPE) \ 1943 ftype \ 1944 nvlist_take_##type(nvlist_t *nvl, const char *name) \ 1945 { \ 1946 nvpair_t *nvp; \ 1947 ftype value; \ 1948 \ 1949 nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name); \ 1950 if (nvp == NULL) \ 1951 nvlist_report_missing(NV_TYPE_##TYPE, name); \ 1952 value = (ftype)(intptr_t)nvpair_get_##type(nvp); \ 1953 nvlist_remove_nvpair(nvl, nvp); \ 1954 nvpair_free_structure(nvp); \ 1955 return (value); \ 1956 } 1957 1958 NVLIST_TAKE(bool, bool, BOOL) 1959 NVLIST_TAKE(uint64_t, number, NUMBER) 1960 NVLIST_TAKE(char *, string, STRING) 1961 NVLIST_TAKE(nvlist_t *, nvlist, NVLIST) 1962 #ifndef _KERNEL 1963 NVLIST_TAKE(int, descriptor, DESCRIPTOR) 1964 #endif 1965 1966 #undef NVLIST_TAKE 1967 1968 void * 1969 nvlist_take_binary(nvlist_t *nvl, const char *name, size_t *sizep) 1970 { 1971 nvpair_t *nvp; 1972 void *value; 1973 1974 nvp = nvlist_find(nvl, NV_TYPE_BINARY, name); 1975 if (nvp == NULL) 1976 nvlist_report_missing(NV_TYPE_BINARY, name); 1977 1978 value = (void *)(intptr_t)nvpair_get_binary(nvp, sizep); 1979 nvlist_remove_nvpair(nvl, nvp); 1980 nvpair_free_structure(nvp); 1981 return (value); 1982 } 1983 1984 #define NVLIST_TAKE_ARRAY(ftype, type, TYPE) \ 1985 ftype \ 1986 nvlist_take_##type##_array(nvlist_t *nvl, const char *name, \ 1987 size_t *nitems) \ 1988 { \ 1989 nvpair_t *nvp; \ 1990 ftype value; \ 1991 \ 1992 nvp = nvlist_find(nvl, NV_TYPE_##TYPE##_ARRAY, name); \ 1993 if (nvp == NULL) \ 1994 nvlist_report_missing(NV_TYPE_##TYPE##_ARRAY, name); \ 1995 value = (ftype)(intptr_t)nvpair_get_##type##_array(nvp, nitems);\ 1996 nvlist_remove_nvpair(nvl, nvp); \ 1997 nvpair_free_structure(nvp); \ 1998 return (value); \ 1999 } 2000 2001 NVLIST_TAKE_ARRAY(bool *, bool, BOOL) 2002 NVLIST_TAKE_ARRAY(uint64_t *, number, NUMBER) 2003 NVLIST_TAKE_ARRAY(char **, string, STRING) 2004 NVLIST_TAKE_ARRAY(nvlist_t **, nvlist, NVLIST) 2005 #ifndef _KERNEL 2006 NVLIST_TAKE_ARRAY(int *, descriptor, DESCRIPTOR) 2007 #endif 2008 2009 void 2010 nvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp) 2011 { 2012 2013 NVLIST_ASSERT(nvl); 2014 NVPAIR_ASSERT(nvp); 2015 PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl); 2016 2017 nvpair_remove(&nvl->nvl_head, nvp, nvl); 2018 } 2019 2020 void 2021 nvlist_free(nvlist_t *nvl, const char *name) 2022 { 2023 2024 nvlist_free_type(nvl, name, NV_TYPE_NONE); 2025 } 2026 2027 #define NVLIST_FREE(type, TYPE) \ 2028 void \ 2029 nvlist_free_##type(nvlist_t *nvl, const char *name) \ 2030 { \ 2031 \ 2032 nvlist_free_type(nvl, name, NV_TYPE_##TYPE); \ 2033 } 2034 2035 NVLIST_FREE(null, NULL) 2036 NVLIST_FREE(bool, BOOL) 2037 NVLIST_FREE(number, NUMBER) 2038 NVLIST_FREE(string, STRING) 2039 NVLIST_FREE(nvlist, NVLIST) 2040 NVLIST_FREE(binary, BINARY) 2041 NVLIST_FREE(bool_array, BOOL_ARRAY) 2042 NVLIST_FREE(number_array, NUMBER_ARRAY) 2043 NVLIST_FREE(string_array, STRING_ARRAY) 2044 NVLIST_FREE(nvlist_array, NVLIST_ARRAY) 2045 #ifndef _KERNEL 2046 NVLIST_FREE(descriptor, DESCRIPTOR) 2047 NVLIST_FREE(descriptor_array, DESCRIPTOR_ARRAY) 2048 #endif 2049 2050 #undef NVLIST_FREE 2051 2052 void 2053 nvlist_free_nvpair(nvlist_t *nvl, nvpair_t *nvp) 2054 { 2055 2056 NVLIST_ASSERT(nvl); 2057 NVPAIR_ASSERT(nvp); 2058 PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl); 2059 2060 nvlist_remove_nvpair(nvl, nvp); 2061 nvpair_free(nvp); 2062 } 2063 2064