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