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