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