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 #define _WITH_DPRINTF 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #include <unistd.h> 60 61 #include "msgio.h" 62 #endif 63 64 #ifdef HAVE_PJDLOG 65 #include <pjdlog.h> 66 #endif 67 68 #include <sys/nv.h> 69 70 #include "nv_impl.h" 71 #include "nvlist_impl.h" 72 #include "nvpair_impl.h" 73 74 #ifndef HAVE_PJDLOG 75 #ifdef _KERNEL 76 #define PJDLOG_ASSERT(...) MPASS(__VA_ARGS__) 77 #define PJDLOG_RASSERT(expr, ...) KASSERT(expr, (__VA_ARGS__)) 78 #define PJDLOG_ABORT(...) panic(__VA_ARGS__) 79 #else 80 #include <assert.h> 81 #define PJDLOG_ASSERT(...) assert(__VA_ARGS__) 82 #define PJDLOG_RASSERT(expr, ...) assert(expr) 83 #define PJDLOG_ABORT(...) do { \ 84 fprintf(stderr, "%s:%u: ", __FILE__, __LINE__); \ 85 fprintf(stderr, __VA_ARGS__); \ 86 fprintf(stderr, "\n"); \ 87 abort(); \ 88 } while (0) 89 #endif 90 #endif 91 92 #define NV_FLAG_PRIVATE_MASK (NV_FLAG_BIG_ENDIAN | NV_FLAG_IN_ARRAY) 93 #define NV_FLAG_PUBLIC_MASK (NV_FLAG_IGNORE_CASE | NV_FLAG_NO_UNIQUE) 94 #define NV_FLAG_ALL_MASK (NV_FLAG_PRIVATE_MASK | NV_FLAG_PUBLIC_MASK) 95 96 #define NVLIST_MAGIC 0x6e766c /* "nvl" */ 97 struct nvlist { 98 int nvl_magic; 99 int nvl_error; 100 int nvl_flags; 101 nvpair_t *nvl_parent; 102 nvpair_t *nvl_array_next; 103 struct nvl_head nvl_head; 104 }; 105 106 #define NVLIST_ASSERT(nvl) do { \ 107 PJDLOG_ASSERT((nvl) != NULL); \ 108 PJDLOG_ASSERT((nvl)->nvl_magic == NVLIST_MAGIC); \ 109 } while (0) 110 111 #ifdef _KERNEL 112 MALLOC_DEFINE(M_NVLIST, "nvlist", "kernel nvlist"); 113 #endif 114 115 #define NVPAIR_ASSERT(nvp) nvpair_assert(nvp) 116 117 #define NVLIST_HEADER_MAGIC 0x6c 118 #define NVLIST_HEADER_VERSION 0x00 119 struct nvlist_header { 120 uint8_t nvlh_magic; 121 uint8_t nvlh_version; 122 uint8_t nvlh_flags; 123 uint64_t nvlh_descriptors; 124 uint64_t nvlh_size; 125 } __packed; 126 127 nvlist_t * 128 nvlist_create(int flags) 129 { 130 nvlist_t *nvl; 131 132 PJDLOG_ASSERT((flags & ~(NV_FLAG_PUBLIC_MASK)) == 0); 133 134 nvl = nv_malloc(sizeof(*nvl)); 135 if (nvl == NULL) 136 return (NULL); 137 nvl->nvl_error = 0; 138 nvl->nvl_flags = flags; 139 nvl->nvl_parent = NULL; 140 nvl->nvl_array_next = NULL; 141 TAILQ_INIT(&nvl->nvl_head); 142 nvl->nvl_magic = NVLIST_MAGIC; 143 144 return (nvl); 145 } 146 147 void 148 nvlist_destroy(nvlist_t *nvl) 149 { 150 nvpair_t *nvp; 151 152 if (nvl == NULL) 153 return; 154 155 ERRNO_SAVE(); 156 157 NVLIST_ASSERT(nvl); 158 159 while ((nvp = nvlist_first_nvpair(nvl)) != NULL) { 160 nvlist_remove_nvpair(nvl, nvp); 161 nvpair_free(nvp); 162 } 163 if (nvl->nvl_array_next != NULL) 164 nvpair_free_structure(nvl->nvl_array_next); 165 nvl->nvl_array_next = NULL; 166 nvl->nvl_parent = NULL; 167 nvl->nvl_magic = 0; 168 nv_free(nvl); 169 170 ERRNO_RESTORE(); 171 } 172 173 void 174 nvlist_set_error(nvlist_t *nvl, int error) 175 { 176 177 PJDLOG_ASSERT(error != 0); 178 179 /* 180 * Check for error != 0 so that we don't do the wrong thing if somebody 181 * tries to abuse this API when asserts are disabled. 182 */ 183 if (nvl != NULL && error != 0 && nvl->nvl_error == 0) 184 nvl->nvl_error = error; 185 } 186 187 int 188 nvlist_error(const nvlist_t *nvl) 189 { 190 191 if (nvl == NULL) 192 return (ENOMEM); 193 194 NVLIST_ASSERT(nvl); 195 196 return (nvl->nvl_error); 197 } 198 199 nvpair_t * 200 nvlist_get_nvpair_parent(const nvlist_t *nvl) 201 { 202 203 NVLIST_ASSERT(nvl); 204 205 return (nvl->nvl_parent); 206 } 207 208 const nvlist_t * 209 nvlist_get_parent(const nvlist_t *nvl, void **cookiep) 210 { 211 nvpair_t *nvp; 212 213 NVLIST_ASSERT(nvl); 214 215 nvp = nvl->nvl_parent; 216 if (cookiep != NULL) 217 *cookiep = nvp; 218 if (nvp == NULL) 219 return (NULL); 220 221 return (nvpair_nvlist(nvp)); 222 } 223 224 void 225 nvlist_set_parent(nvlist_t *nvl, nvpair_t *parent) 226 { 227 228 NVLIST_ASSERT(nvl); 229 230 nvl->nvl_parent = parent; 231 } 232 233 void 234 nvlist_set_array_next(nvlist_t *nvl, nvpair_t *ele) 235 { 236 237 NVLIST_ASSERT(nvl); 238 239 if (ele != NULL) { 240 nvl->nvl_flags |= NV_FLAG_IN_ARRAY; 241 } else { 242 nvl->nvl_flags &= ~NV_FLAG_IN_ARRAY; 243 nv_free(nvl->nvl_array_next); 244 } 245 246 nvl->nvl_array_next = ele; 247 } 248 249 bool 250 nvlist_in_array(const nvlist_t *nvl) 251 { 252 253 NVLIST_ASSERT(nvl); 254 255 return ((nvl->nvl_flags & NV_FLAG_IN_ARRAY) != 0); 256 } 257 258 const nvlist_t * 259 nvlist_get_array_next(const nvlist_t *nvl) 260 { 261 nvpair_t *nvp; 262 263 NVLIST_ASSERT(nvl); 264 265 nvp = nvl->nvl_array_next; 266 if (nvp == NULL) 267 return (NULL); 268 269 return (nvpair_get_nvlist(nvp)); 270 } 271 272 const nvlist_t * 273 nvlist_get_pararr(const nvlist_t *nvl, void **cookiep) 274 { 275 const nvlist_t *ret; 276 277 ret = nvlist_get_array_next(nvl); 278 if (ret != NULL) { 279 if (cookiep != NULL) 280 *cookiep = NULL; 281 return (ret); 282 } 283 284 ret = nvlist_get_parent(nvl, cookiep); 285 return (ret); 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 static 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 nvpair_t *nvp; 713 const char *name; 714 int type; 715 716 NVLIST_ASSERT(nvl); 717 PJDLOG_ASSERT(nvl->nvl_error == 0); 718 719 nvp = NULL; 720 do { 721 while ((name = nvlist_next(nvl, &type, (void**)&nvp)) != NULL) { 722 switch (type) { 723 case NV_TYPE_DESCRIPTOR: 724 *descs = nvpair_get_descriptor(nvp); 725 descs++; 726 break; 727 case NV_TYPE_DESCRIPTOR_ARRAY: 728 { 729 const int *value; 730 size_t nitems; 731 unsigned int ii; 732 733 value = nvpair_get_descriptor_array(nvp, 734 &nitems); 735 for (ii = 0; ii < nitems; ii++) { 736 *descs = value[ii]; 737 descs++; 738 } 739 break; 740 } 741 case NV_TYPE_NVLIST: 742 nvl = nvpair_get_nvlist(nvp); 743 nvp = NULL; 744 break; 745 case NV_TYPE_NVLIST_ARRAY: 746 { 747 const nvlist_t * const *value; 748 size_t nitems; 749 750 value = nvpair_get_nvlist_array(nvp, &nitems); 751 PJDLOG_ASSERT(value != NULL); 752 PJDLOG_ASSERT(nitems > 0); 753 754 nvl = value[0]; 755 nvp = NULL; 756 break; 757 } 758 } 759 } 760 } while ((nvl = nvlist_get_pararr(nvl, (void**)&nvp)) != NULL); 761 762 return (descs); 763 } 764 #endif 765 766 #ifndef _KERNEL 767 int * 768 nvlist_descriptors(const nvlist_t *nvl, size_t *nitemsp) 769 { 770 size_t nitems; 771 int *fds; 772 773 nitems = nvlist_ndescriptors(nvl); 774 fds = nv_malloc(sizeof(fds[0]) * (nitems + 1)); 775 if (fds == NULL) 776 return (NULL); 777 if (nitems > 0) 778 nvlist_xdescriptors(nvl, fds); 779 fds[nitems] = -1; 780 if (nitemsp != NULL) 781 *nitemsp = nitems; 782 return (fds); 783 } 784 #endif 785 786 size_t 787 nvlist_ndescriptors(const nvlist_t *nvl) 788 { 789 #ifndef _KERNEL 790 nvpair_t *nvp; 791 const char *name; 792 size_t ndescs; 793 int type; 794 795 NVLIST_ASSERT(nvl); 796 PJDLOG_ASSERT(nvl->nvl_error == 0); 797 798 ndescs = 0; 799 nvp = NULL; 800 do { 801 while ((name = nvlist_next(nvl, &type, (void**)&nvp)) != NULL) { 802 switch (type) { 803 case NV_TYPE_DESCRIPTOR: 804 ndescs++; 805 break; 806 case NV_TYPE_NVLIST: 807 nvl = nvpair_get_nvlist(nvp); 808 nvp = NULL; 809 break; 810 case NV_TYPE_NVLIST_ARRAY: 811 { 812 const nvlist_t * const *value; 813 size_t nitems; 814 815 value = nvpair_get_nvlist_array(nvp, &nitems); 816 PJDLOG_ASSERT(value != NULL); 817 PJDLOG_ASSERT(nitems > 0); 818 819 nvl = value[0]; 820 nvp = NULL; 821 break; 822 } 823 case NV_TYPE_DESCRIPTOR_ARRAY: 824 { 825 size_t nitems; 826 827 (void)nvpair_get_descriptor_array(nvp, 828 &nitems); 829 ndescs += nitems; 830 break; 831 } 832 } 833 } 834 } while ((nvl = nvlist_get_pararr(nvl, (void**)&nvp)) != NULL); 835 836 return (ndescs); 837 #else 838 return (0); 839 #endif 840 } 841 842 static unsigned char * 843 nvlist_pack_header(const nvlist_t *nvl, unsigned char *ptr, size_t *leftp) 844 { 845 struct nvlist_header nvlhdr; 846 847 NVLIST_ASSERT(nvl); 848 849 nvlhdr.nvlh_magic = NVLIST_HEADER_MAGIC; 850 nvlhdr.nvlh_version = NVLIST_HEADER_VERSION; 851 nvlhdr.nvlh_flags = nvl->nvl_flags; 852 #if BYTE_ORDER == BIG_ENDIAN 853 nvlhdr.nvlh_flags |= NV_FLAG_BIG_ENDIAN; 854 #endif 855 nvlhdr.nvlh_descriptors = nvlist_ndescriptors(nvl); 856 nvlhdr.nvlh_size = *leftp - sizeof(nvlhdr); 857 PJDLOG_ASSERT(*leftp >= sizeof(nvlhdr)); 858 memcpy(ptr, &nvlhdr, sizeof(nvlhdr)); 859 ptr += sizeof(nvlhdr); 860 *leftp -= sizeof(nvlhdr); 861 862 return (ptr); 863 } 864 865 static void * 866 nvlist_xpack(const nvlist_t *nvl, int64_t *fdidxp, size_t *sizep) 867 { 868 unsigned char *buf, *ptr; 869 size_t left, size; 870 const nvlist_t *tmpnvl; 871 nvpair_t *nvp, *tmpnvp; 872 void *cookie; 873 874 NVLIST_ASSERT(nvl); 875 876 if (nvl->nvl_error != 0) { 877 ERRNO_SET(nvl->nvl_error); 878 return (NULL); 879 } 880 881 size = nvlist_size(nvl); 882 buf = nv_malloc(size); 883 if (buf == NULL) 884 return (NULL); 885 886 ptr = buf; 887 left = size; 888 889 ptr = nvlist_pack_header(nvl, ptr, &left); 890 891 nvp = nvlist_first_nvpair(nvl); 892 while (nvp != NULL) { 893 NVPAIR_ASSERT(nvp); 894 895 nvpair_init_datasize(nvp); 896 ptr = nvpair_pack_header(nvp, ptr, &left); 897 if (ptr == NULL) 898 goto fail; 899 switch (nvpair_type(nvp)) { 900 case NV_TYPE_NULL: 901 ptr = nvpair_pack_null(nvp, ptr, &left); 902 break; 903 case NV_TYPE_BOOL: 904 ptr = nvpair_pack_bool(nvp, ptr, &left); 905 break; 906 case NV_TYPE_NUMBER: 907 ptr = nvpair_pack_number(nvp, ptr, &left); 908 break; 909 case NV_TYPE_STRING: 910 ptr = nvpair_pack_string(nvp, ptr, &left); 911 break; 912 case NV_TYPE_NVLIST: 913 tmpnvl = nvpair_get_nvlist(nvp); 914 ptr = nvlist_pack_header(tmpnvl, ptr, &left); 915 if (ptr == NULL) 916 goto fail; 917 tmpnvp = nvlist_first_nvpair(tmpnvl); 918 if (tmpnvp != NULL) { 919 nvl = tmpnvl; 920 nvp = tmpnvp; 921 continue; 922 } 923 ptr = nvpair_pack_nvlist_up(ptr, &left); 924 break; 925 #ifndef _KERNEL 926 case NV_TYPE_DESCRIPTOR: 927 ptr = nvpair_pack_descriptor(nvp, ptr, fdidxp, &left); 928 break; 929 case NV_TYPE_DESCRIPTOR_ARRAY: 930 ptr = nvpair_pack_descriptor_array(nvp, ptr, fdidxp, 931 &left); 932 break; 933 #endif 934 case NV_TYPE_BINARY: 935 ptr = nvpair_pack_binary(nvp, ptr, &left); 936 break; 937 case NV_TYPE_BOOL_ARRAY: 938 ptr = nvpair_pack_bool_array(nvp, ptr, &left); 939 break; 940 case NV_TYPE_NUMBER_ARRAY: 941 ptr = nvpair_pack_number_array(nvp, ptr, &left); 942 break; 943 case NV_TYPE_STRING_ARRAY: 944 ptr = nvpair_pack_string_array(nvp, ptr, &left); 945 break; 946 case NV_TYPE_NVLIST_ARRAY: 947 { 948 const nvlist_t * const * value; 949 size_t nitems; 950 unsigned int ii; 951 952 tmpnvl = NULL; 953 value = nvpair_get_nvlist_array(nvp, &nitems); 954 for (ii = 0; ii < nitems; ii++) { 955 ptr = nvlist_pack_header(value[ii], ptr, &left); 956 if (ptr == NULL) 957 goto out; 958 tmpnvp = nvlist_first_nvpair(value[ii]); 959 if (tmpnvp != NULL) { 960 tmpnvl = value[ii]; 961 break; 962 } 963 ptr = nvpair_pack_nvlist_array_next(ptr, &left); 964 if (ptr == NULL) 965 goto out; 966 } 967 if (tmpnvl != NULL) { 968 nvl = tmpnvl; 969 nvp = tmpnvp; 970 continue; 971 } 972 break; 973 } 974 default: 975 PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp)); 976 } 977 if (ptr == NULL) 978 goto fail; 979 while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) { 980 do { 981 cookie = NULL; 982 if (nvlist_in_array(nvl)) { 983 ptr = nvpair_pack_nvlist_array_next(ptr, 984 &left); 985 if (ptr == NULL) 986 goto fail; 987 } 988 nvl = nvlist_get_pararr(nvl, &cookie); 989 if (nvl == NULL) 990 goto out; 991 if (nvlist_in_array(nvl) && cookie == NULL) { 992 nvp = nvlist_first_nvpair(nvl); 993 ptr = nvlist_pack_header(nvl, ptr, 994 &left); 995 if (ptr == NULL) 996 goto fail; 997 } else if (nvpair_type((nvpair_t *)cookie) != 998 NV_TYPE_NVLIST_ARRAY) { 999 ptr = nvpair_pack_nvlist_up(ptr, &left); 1000 if (ptr == NULL) 1001 goto fail; 1002 nvp = cookie; 1003 } else { 1004 nvp = cookie; 1005 } 1006 } while (nvp == NULL); 1007 if (nvlist_in_array(nvl) && cookie == NULL) 1008 break; 1009 } 1010 } 1011 1012 out: 1013 if (sizep != NULL) 1014 *sizep = size; 1015 return (buf); 1016 fail: 1017 nv_free(buf); 1018 return (NULL); 1019 } 1020 1021 void * 1022 nvlist_pack(const nvlist_t *nvl, size_t *sizep) 1023 { 1024 1025 NVLIST_ASSERT(nvl); 1026 1027 if (nvl->nvl_error != 0) { 1028 ERRNO_SET(nvl->nvl_error); 1029 return (NULL); 1030 } 1031 1032 if (nvlist_ndescriptors(nvl) > 0) { 1033 ERRNO_SET(EOPNOTSUPP); 1034 return (NULL); 1035 } 1036 1037 return (nvlist_xpack(nvl, NULL, sizep)); 1038 } 1039 1040 static bool 1041 nvlist_check_header(struct nvlist_header *nvlhdrp) 1042 { 1043 1044 if (nvlhdrp->nvlh_magic != NVLIST_HEADER_MAGIC) { 1045 ERRNO_SET(EINVAL); 1046 return (false); 1047 } 1048 if ((nvlhdrp->nvlh_flags & ~NV_FLAG_ALL_MASK) != 0) { 1049 ERRNO_SET(EINVAL); 1050 return (false); 1051 } 1052 #if BYTE_ORDER == BIG_ENDIAN 1053 if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) == 0) { 1054 nvlhdrp->nvlh_size = le64toh(nvlhdrp->nvlh_size); 1055 nvlhdrp->nvlh_descriptors = le64toh(nvlhdrp->nvlh_descriptors); 1056 } 1057 #else 1058 if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0) { 1059 nvlhdrp->nvlh_size = be64toh(nvlhdrp->nvlh_size); 1060 nvlhdrp->nvlh_descriptors = be64toh(nvlhdrp->nvlh_descriptors); 1061 } 1062 #endif 1063 return (true); 1064 } 1065 1066 const unsigned char * 1067 nvlist_unpack_header(nvlist_t *nvl, const unsigned char *ptr, size_t nfds, 1068 bool *isbep, size_t *leftp) 1069 { 1070 struct nvlist_header nvlhdr; 1071 int inarrayf; 1072 1073 if (*leftp < sizeof(nvlhdr)) 1074 goto failed; 1075 1076 memcpy(&nvlhdr, ptr, sizeof(nvlhdr)); 1077 1078 if (!nvlist_check_header(&nvlhdr)) 1079 goto failed; 1080 1081 if (nvlhdr.nvlh_size != *leftp - sizeof(nvlhdr)) 1082 goto failed; 1083 1084 /* 1085 * nvlh_descriptors might be smaller than nfds in embedded nvlists. 1086 */ 1087 if (nvlhdr.nvlh_descriptors > nfds) 1088 goto failed; 1089 1090 if ((nvlhdr.nvlh_flags & ~NV_FLAG_ALL_MASK) != 0) 1091 goto failed; 1092 1093 inarrayf = (nvl->nvl_flags & NV_FLAG_IN_ARRAY); 1094 nvl->nvl_flags = (nvlhdr.nvlh_flags & NV_FLAG_PUBLIC_MASK) | inarrayf; 1095 1096 ptr += sizeof(nvlhdr); 1097 if (isbep != NULL) 1098 *isbep = (((int)nvlhdr.nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0); 1099 *leftp -= sizeof(nvlhdr); 1100 1101 return (ptr); 1102 failed: 1103 ERRNO_SET(EINVAL); 1104 return (NULL); 1105 } 1106 1107 static nvlist_t * 1108 nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds, 1109 int flags) 1110 { 1111 const unsigned char *ptr; 1112 nvlist_t *nvl, *retnvl, *tmpnvl, *array; 1113 nvpair_t *nvp; 1114 size_t left; 1115 bool isbe; 1116 1117 PJDLOG_ASSERT((flags & ~(NV_FLAG_PUBLIC_MASK)) == 0); 1118 1119 left = size; 1120 ptr = buf; 1121 1122 tmpnvl = array = NULL; 1123 nvl = retnvl = nvlist_create(0); 1124 if (nvl == NULL) 1125 goto failed; 1126 1127 ptr = nvlist_unpack_header(nvl, ptr, nfds, &isbe, &left); 1128 if (ptr == NULL) 1129 goto failed; 1130 if (nvl->nvl_flags != flags) { 1131 ERRNO_SET(EILSEQ); 1132 goto failed; 1133 } 1134 1135 while (left > 0) { 1136 ptr = nvpair_unpack(isbe, ptr, &left, &nvp); 1137 if (ptr == NULL) 1138 goto failed; 1139 switch (nvpair_type(nvp)) { 1140 case NV_TYPE_NULL: 1141 ptr = nvpair_unpack_null(isbe, nvp, ptr, &left); 1142 break; 1143 case NV_TYPE_BOOL: 1144 ptr = nvpair_unpack_bool(isbe, nvp, ptr, &left); 1145 break; 1146 case NV_TYPE_NUMBER: 1147 ptr = nvpair_unpack_number(isbe, nvp, ptr, &left); 1148 break; 1149 case NV_TYPE_STRING: 1150 ptr = nvpair_unpack_string(isbe, nvp, ptr, &left); 1151 break; 1152 case NV_TYPE_NVLIST: 1153 ptr = nvpair_unpack_nvlist(isbe, nvp, ptr, &left, nfds, 1154 &tmpnvl); 1155 if (tmpnvl == NULL || ptr == NULL) 1156 goto failed; 1157 nvlist_set_parent(tmpnvl, nvp); 1158 break; 1159 #ifndef _KERNEL 1160 case NV_TYPE_DESCRIPTOR: 1161 ptr = nvpair_unpack_descriptor(isbe, nvp, ptr, &left, 1162 fds, nfds); 1163 break; 1164 case NV_TYPE_DESCRIPTOR_ARRAY: 1165 ptr = nvpair_unpack_descriptor_array(isbe, nvp, ptr, 1166 &left, fds, nfds); 1167 break; 1168 #endif 1169 case NV_TYPE_BINARY: 1170 ptr = nvpair_unpack_binary(isbe, nvp, ptr, &left); 1171 break; 1172 case NV_TYPE_NVLIST_UP: 1173 if (nvl->nvl_parent == NULL) 1174 goto failed; 1175 nvl = nvpair_nvlist(nvl->nvl_parent); 1176 nvpair_free_structure(nvp); 1177 continue; 1178 case NV_TYPE_NVLIST_ARRAY_NEXT: 1179 if (nvl->nvl_array_next == NULL) { 1180 if (nvl->nvl_parent == NULL) 1181 goto failed; 1182 nvl = nvpair_nvlist(nvl->nvl_parent); 1183 } else { 1184 nvl = __DECONST(nvlist_t *, 1185 nvlist_get_array_next(nvl)); 1186 ptr = nvlist_unpack_header(nvl, ptr, nfds, 1187 &isbe, &left); 1188 if (ptr == NULL) 1189 goto failed; 1190 } 1191 nvpair_free_structure(nvp); 1192 continue; 1193 case NV_TYPE_BOOL_ARRAY: 1194 ptr = nvpair_unpack_bool_array(isbe, nvp, ptr, &left); 1195 break; 1196 case NV_TYPE_NUMBER_ARRAY: 1197 ptr = nvpair_unpack_number_array(isbe, nvp, ptr, &left); 1198 break; 1199 case NV_TYPE_STRING_ARRAY: 1200 ptr = nvpair_unpack_string_array(isbe, nvp, ptr, &left); 1201 break; 1202 case NV_TYPE_NVLIST_ARRAY: 1203 ptr = nvpair_unpack_nvlist_array(isbe, nvp, ptr, &left, 1204 &array); 1205 if (ptr == NULL) 1206 goto failed; 1207 tmpnvl = array; 1208 while (array != NULL) { 1209 nvlist_set_parent(array, nvp); 1210 array = __DECONST(nvlist_t *, 1211 nvlist_get_array_next(array)); 1212 } 1213 ptr = nvlist_unpack_header(tmpnvl, ptr, nfds, &isbe, 1214 &left); 1215 break; 1216 default: 1217 PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp)); 1218 } 1219 if (ptr == NULL) 1220 goto failed; 1221 if (!nvlist_move_nvpair(nvl, nvp)) 1222 goto failed; 1223 if (tmpnvl != NULL) { 1224 nvl = tmpnvl; 1225 tmpnvl = NULL; 1226 } 1227 } 1228 1229 return (retnvl); 1230 failed: 1231 nvlist_destroy(retnvl); 1232 return (NULL); 1233 } 1234 1235 nvlist_t * 1236 nvlist_unpack(const void *buf, size_t size, int flags) 1237 { 1238 1239 return (nvlist_xunpack(buf, size, NULL, 0, flags)); 1240 } 1241 1242 #ifndef _KERNEL 1243 int 1244 nvlist_send(int sock, const nvlist_t *nvl) 1245 { 1246 size_t datasize, nfds; 1247 int *fds; 1248 void *data; 1249 int64_t fdidx; 1250 int ret; 1251 1252 if (nvlist_error(nvl) != 0) { 1253 ERRNO_SET(nvlist_error(nvl)); 1254 return (-1); 1255 } 1256 1257 fds = nvlist_descriptors(nvl, &nfds); 1258 if (fds == NULL) 1259 return (-1); 1260 1261 ret = -1; 1262 data = NULL; 1263 fdidx = 0; 1264 1265 data = nvlist_xpack(nvl, &fdidx, &datasize); 1266 if (data == NULL) 1267 goto out; 1268 1269 if (buf_send(sock, data, datasize) == -1) 1270 goto out; 1271 1272 if (nfds > 0) { 1273 if (fd_send(sock, fds, nfds) == -1) 1274 goto out; 1275 } 1276 1277 ret = 0; 1278 out: 1279 ERRNO_SAVE(); 1280 nv_free(fds); 1281 nv_free(data); 1282 ERRNO_RESTORE(); 1283 return (ret); 1284 } 1285 1286 nvlist_t * 1287 nvlist_recv(int sock, int flags) 1288 { 1289 struct nvlist_header nvlhdr; 1290 nvlist_t *nvl, *ret; 1291 unsigned char *buf; 1292 size_t nfds, size, i; 1293 int *fds; 1294 1295 if (buf_recv(sock, &nvlhdr, sizeof(nvlhdr)) == -1) 1296 return (NULL); 1297 1298 if (!nvlist_check_header(&nvlhdr)) 1299 return (NULL); 1300 1301 nfds = (size_t)nvlhdr.nvlh_descriptors; 1302 size = sizeof(nvlhdr) + (size_t)nvlhdr.nvlh_size; 1303 1304 buf = nv_malloc(size); 1305 if (buf == NULL) 1306 return (NULL); 1307 1308 memcpy(buf, &nvlhdr, sizeof(nvlhdr)); 1309 1310 ret = NULL; 1311 fds = NULL; 1312 1313 if (buf_recv(sock, buf + sizeof(nvlhdr), size - sizeof(nvlhdr)) == -1) 1314 goto out; 1315 1316 if (nfds > 0) { 1317 fds = nv_malloc(nfds * sizeof(fds[0])); 1318 if (fds == NULL) 1319 goto out; 1320 if (fd_recv(sock, fds, nfds) == -1) 1321 goto out; 1322 } 1323 1324 nvl = nvlist_xunpack(buf, size, fds, nfds, flags); 1325 if (nvl == NULL) { 1326 ERRNO_SAVE(); 1327 for (i = 0; i < nfds; i++) 1328 close(fds[i]); 1329 ERRNO_RESTORE(); 1330 goto out; 1331 } 1332 1333 ret = nvl; 1334 out: 1335 ERRNO_SAVE(); 1336 nv_free(buf); 1337 nv_free(fds); 1338 ERRNO_RESTORE(); 1339 1340 return (ret); 1341 } 1342 1343 nvlist_t * 1344 nvlist_xfer(int sock, nvlist_t *nvl, int flags) 1345 { 1346 1347 if (nvlist_send(sock, nvl) < 0) { 1348 nvlist_destroy(nvl); 1349 return (NULL); 1350 } 1351 nvlist_destroy(nvl); 1352 return (nvlist_recv(sock, flags)); 1353 } 1354 #endif 1355 1356 nvpair_t * 1357 nvlist_first_nvpair(const nvlist_t *nvl) 1358 { 1359 1360 NVLIST_ASSERT(nvl); 1361 1362 return (TAILQ_FIRST(&nvl->nvl_head)); 1363 } 1364 1365 nvpair_t * 1366 nvlist_next_nvpair(const nvlist_t *nvl, const nvpair_t *nvp) 1367 { 1368 nvpair_t *retnvp; 1369 1370 NVLIST_ASSERT(nvl); 1371 NVPAIR_ASSERT(nvp); 1372 PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl); 1373 1374 retnvp = nvpair_next(nvp); 1375 PJDLOG_ASSERT(retnvp == NULL || nvpair_nvlist(retnvp) == nvl); 1376 1377 return (retnvp); 1378 1379 } 1380 1381 nvpair_t * 1382 nvlist_prev_nvpair(const nvlist_t *nvl, const nvpair_t *nvp) 1383 { 1384 nvpair_t *retnvp; 1385 1386 NVLIST_ASSERT(nvl); 1387 NVPAIR_ASSERT(nvp); 1388 PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl); 1389 1390 retnvp = nvpair_prev(nvp); 1391 PJDLOG_ASSERT(nvpair_nvlist(retnvp) == nvl); 1392 1393 return (retnvp); 1394 } 1395 1396 const char * 1397 nvlist_next(const nvlist_t *nvl, int *typep, void **cookiep) 1398 { 1399 nvpair_t *nvp; 1400 1401 NVLIST_ASSERT(nvl); 1402 1403 if (cookiep == NULL || *cookiep == NULL) 1404 nvp = nvlist_first_nvpair(nvl); 1405 else 1406 nvp = nvlist_next_nvpair(nvl, *cookiep); 1407 if (nvp == NULL) 1408 return (NULL); 1409 if (typep != NULL) 1410 *typep = nvpair_type(nvp); 1411 if (cookiep != NULL) 1412 *cookiep = nvp; 1413 return (nvpair_name(nvp)); 1414 } 1415 1416 bool 1417 nvlist_exists(const nvlist_t *nvl, const char *name) 1418 { 1419 1420 return (nvlist_find(nvl, NV_TYPE_NONE, name) != NULL); 1421 } 1422 1423 #define NVLIST_EXISTS(type, TYPE) \ 1424 bool \ 1425 nvlist_exists_##type(const nvlist_t *nvl, const char *name) \ 1426 { \ 1427 \ 1428 return (nvlist_find(nvl, NV_TYPE_##TYPE, name) != NULL); \ 1429 } 1430 1431 NVLIST_EXISTS(null, NULL) 1432 NVLIST_EXISTS(bool, BOOL) 1433 NVLIST_EXISTS(number, NUMBER) 1434 NVLIST_EXISTS(string, STRING) 1435 NVLIST_EXISTS(nvlist, NVLIST) 1436 NVLIST_EXISTS(binary, BINARY) 1437 NVLIST_EXISTS(bool_array, BOOL_ARRAY) 1438 NVLIST_EXISTS(number_array, NUMBER_ARRAY) 1439 NVLIST_EXISTS(string_array, STRING_ARRAY) 1440 NVLIST_EXISTS(nvlist_array, NVLIST_ARRAY) 1441 #ifndef _KERNEL 1442 NVLIST_EXISTS(descriptor, DESCRIPTOR) 1443 NVLIST_EXISTS(descriptor_array, DESCRIPTOR_ARRAY) 1444 #endif 1445 1446 #undef NVLIST_EXISTS 1447 1448 void 1449 nvlist_add_nvpair(nvlist_t *nvl, const nvpair_t *nvp) 1450 { 1451 nvpair_t *newnvp; 1452 1453 NVPAIR_ASSERT(nvp); 1454 1455 if (nvlist_error(nvl) != 0) { 1456 ERRNO_SET(nvlist_error(nvl)); 1457 return; 1458 } 1459 if ((nvl->nvl_flags & NV_FLAG_NO_UNIQUE) == 0) { 1460 if (nvlist_exists(nvl, nvpair_name(nvp))) { 1461 nvl->nvl_error = EEXIST; 1462 ERRNO_SET(nvlist_error(nvl)); 1463 return; 1464 } 1465 } 1466 1467 newnvp = nvpair_clone(nvp); 1468 if (newnvp == NULL) { 1469 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1470 ERRNO_SET(nvlist_error(nvl)); 1471 return; 1472 } 1473 1474 nvpair_insert(&nvl->nvl_head, newnvp, nvl); 1475 } 1476 1477 void 1478 nvlist_add_stringf(nvlist_t *nvl, const char *name, const char *valuefmt, ...) 1479 { 1480 va_list valueap; 1481 1482 va_start(valueap, valuefmt); 1483 nvlist_add_stringv(nvl, name, valuefmt, valueap); 1484 va_end(valueap); 1485 } 1486 1487 void 1488 nvlist_add_stringv(nvlist_t *nvl, const char *name, const char *valuefmt, 1489 va_list valueap) 1490 { 1491 nvpair_t *nvp; 1492 1493 if (nvlist_error(nvl) != 0) { 1494 ERRNO_SET(nvlist_error(nvl)); 1495 return; 1496 } 1497 1498 nvp = nvpair_create_stringv(name, valuefmt, valueap); 1499 if (nvp == NULL) { 1500 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1501 ERRNO_SET(nvl->nvl_error); 1502 } else { 1503 (void)nvlist_move_nvpair(nvl, nvp); 1504 } 1505 } 1506 1507 void 1508 nvlist_add_null(nvlist_t *nvl, const char *name) 1509 { 1510 nvpair_t *nvp; 1511 1512 if (nvlist_error(nvl) != 0) { 1513 ERRNO_SET(nvlist_error(nvl)); 1514 return; 1515 } 1516 1517 nvp = nvpair_create_null(name); 1518 if (nvp == NULL) { 1519 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1520 ERRNO_SET(nvl->nvl_error); 1521 } else { 1522 (void)nvlist_move_nvpair(nvl, nvp); 1523 } 1524 } 1525 1526 void 1527 nvlist_add_binary(nvlist_t *nvl, const char *name, const void *value, 1528 size_t size) 1529 { 1530 nvpair_t *nvp; 1531 1532 if (nvlist_error(nvl) != 0) { 1533 ERRNO_SET(nvlist_error(nvl)); 1534 return; 1535 } 1536 1537 nvp = nvpair_create_binary(name, value, size); 1538 if (nvp == NULL) { 1539 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1540 ERRNO_SET(nvl->nvl_error); 1541 } else { 1542 (void)nvlist_move_nvpair(nvl, nvp); 1543 } 1544 } 1545 1546 1547 #define NVLIST_ADD(vtype, type) \ 1548 void \ 1549 nvlist_add_##type(nvlist_t *nvl, const char *name, vtype value) \ 1550 { \ 1551 nvpair_t *nvp; \ 1552 \ 1553 if (nvlist_error(nvl) != 0) { \ 1554 ERRNO_SET(nvlist_error(nvl)); \ 1555 return; \ 1556 } \ 1557 \ 1558 nvp = nvpair_create_##type(name, value); \ 1559 if (nvp == NULL) { \ 1560 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); \ 1561 ERRNO_SET(nvl->nvl_error); \ 1562 } else { \ 1563 (void)nvlist_move_nvpair(nvl, nvp); \ 1564 } \ 1565 } 1566 1567 NVLIST_ADD(bool, bool) 1568 NVLIST_ADD(uint64_t, number) 1569 NVLIST_ADD(const char *, string) 1570 NVLIST_ADD(const nvlist_t *, nvlist) 1571 #ifndef _KERNEL 1572 NVLIST_ADD(int, descriptor); 1573 #endif 1574 1575 #undef NVLIST_ADD 1576 1577 #define NVLIST_ADD_ARRAY(vtype, type) \ 1578 void \ 1579 nvlist_add_##type##_array(nvlist_t *nvl, const char *name, vtype value, \ 1580 size_t nitems) \ 1581 { \ 1582 nvpair_t *nvp; \ 1583 \ 1584 if (nvlist_error(nvl) != 0) { \ 1585 ERRNO_SET(nvlist_error(nvl)); \ 1586 return; \ 1587 } \ 1588 \ 1589 nvp = nvpair_create_##type##_array(name, value, nitems); \ 1590 if (nvp == NULL) { \ 1591 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); \ 1592 ERRNO_SET(nvl->nvl_error); \ 1593 } else { \ 1594 (void)nvlist_move_nvpair(nvl, nvp); \ 1595 } \ 1596 } 1597 1598 NVLIST_ADD_ARRAY(const bool *, bool) 1599 NVLIST_ADD_ARRAY(const uint64_t *, number) 1600 NVLIST_ADD_ARRAY(const char * const *, string) 1601 NVLIST_ADD_ARRAY(const nvlist_t * const *, nvlist) 1602 #ifndef _KERNEL 1603 NVLIST_ADD_ARRAY(const int *, descriptor) 1604 #endif 1605 1606 #undef NVLIST_ADD_ARRAY 1607 1608 bool 1609 nvlist_move_nvpair(nvlist_t *nvl, nvpair_t *nvp) 1610 { 1611 1612 NVPAIR_ASSERT(nvp); 1613 PJDLOG_ASSERT(nvpair_nvlist(nvp) == NULL); 1614 1615 if (nvlist_error(nvl) != 0) { 1616 nvpair_free(nvp); 1617 ERRNO_SET(nvlist_error(nvl)); 1618 return (false); 1619 } 1620 if ((nvl->nvl_flags & NV_FLAG_NO_UNIQUE) == 0) { 1621 if (nvlist_exists(nvl, nvpair_name(nvp))) { 1622 nvpair_free(nvp); 1623 nvl->nvl_error = EEXIST; 1624 ERRNO_SET(nvl->nvl_error); 1625 return (false); 1626 } 1627 } 1628 1629 nvpair_insert(&nvl->nvl_head, nvp, nvl); 1630 return (true); 1631 } 1632 1633 void 1634 nvlist_move_string(nvlist_t *nvl, const char *name, char *value) 1635 { 1636 nvpair_t *nvp; 1637 1638 if (nvlist_error(nvl) != 0) { 1639 nv_free(value); 1640 ERRNO_SET(nvlist_error(nvl)); 1641 return; 1642 } 1643 1644 nvp = nvpair_move_string(name, value); 1645 if (nvp == NULL) { 1646 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1647 ERRNO_SET(nvl->nvl_error); 1648 } else { 1649 (void)nvlist_move_nvpair(nvl, nvp); 1650 } 1651 } 1652 1653 void 1654 nvlist_move_nvlist(nvlist_t *nvl, const char *name, nvlist_t *value) 1655 { 1656 nvpair_t *nvp; 1657 1658 if (nvlist_error(nvl) != 0) { 1659 if (value != NULL && nvlist_get_nvpair_parent(value) != NULL) 1660 nvlist_destroy(value); 1661 ERRNO_SET(nvlist_error(nvl)); 1662 return; 1663 } 1664 1665 nvp = nvpair_move_nvlist(name, value); 1666 if (nvp == NULL) { 1667 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1668 ERRNO_SET(nvl->nvl_error); 1669 } else { 1670 (void)nvlist_move_nvpair(nvl, nvp); 1671 } 1672 } 1673 1674 #ifndef _KERNEL 1675 void 1676 nvlist_move_descriptor(nvlist_t *nvl, const char *name, int value) 1677 { 1678 nvpair_t *nvp; 1679 1680 if (nvlist_error(nvl) != 0) { 1681 close(value); 1682 ERRNO_SET(nvlist_error(nvl)); 1683 return; 1684 } 1685 1686 nvp = nvpair_move_descriptor(name, value); 1687 if (nvp == NULL) { 1688 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1689 ERRNO_SET(nvl->nvl_error); 1690 } else { 1691 (void)nvlist_move_nvpair(nvl, nvp); 1692 } 1693 } 1694 #endif 1695 1696 void 1697 nvlist_move_binary(nvlist_t *nvl, const char *name, void *value, size_t size) 1698 { 1699 nvpair_t *nvp; 1700 1701 if (nvlist_error(nvl) != 0) { 1702 nv_free(value); 1703 ERRNO_SET(nvlist_error(nvl)); 1704 return; 1705 } 1706 1707 nvp = nvpair_move_binary(name, value, size); 1708 if (nvp == NULL) { 1709 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1710 ERRNO_SET(nvl->nvl_error); 1711 } else { 1712 (void)nvlist_move_nvpair(nvl, nvp); 1713 } 1714 } 1715 1716 void 1717 nvlist_move_bool_array(nvlist_t *nvl, const char *name, bool *value, 1718 size_t nitems) 1719 { 1720 nvpair_t *nvp; 1721 1722 if (nvlist_error(nvl) != 0) { 1723 nv_free(value); 1724 ERRNO_SET(nvlist_error(nvl)); 1725 return; 1726 } 1727 1728 nvp = nvpair_move_bool_array(name, value, nitems); 1729 if (nvp == NULL) { 1730 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1731 ERRNO_SET(nvl->nvl_error); 1732 } else { 1733 (void)nvlist_move_nvpair(nvl, nvp); 1734 } 1735 } 1736 1737 void 1738 nvlist_move_string_array(nvlist_t *nvl, const char *name, char **value, 1739 size_t nitems) 1740 { 1741 nvpair_t *nvp; 1742 size_t i; 1743 1744 if (nvlist_error(nvl) != 0) { 1745 if (value != NULL) { 1746 for (i = 0; i < nitems; i++) 1747 nv_free(value[i]); 1748 nv_free(value); 1749 } 1750 ERRNO_SET(nvlist_error(nvl)); 1751 return; 1752 } 1753 1754 nvp = nvpair_move_string_array(name, value, nitems); 1755 if (nvp == NULL) { 1756 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1757 ERRNO_SET(nvl->nvl_error); 1758 } else { 1759 (void)nvlist_move_nvpair(nvl, nvp); 1760 } 1761 } 1762 1763 void 1764 nvlist_move_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **value, 1765 size_t nitems) 1766 { 1767 nvpair_t *nvp; 1768 size_t i; 1769 1770 if (nvlist_error(nvl) != 0) { 1771 if (value != NULL) { 1772 for (i = 0; i < nitems; i++) { 1773 if (nvlist_get_pararr(value[i], NULL) == NULL) 1774 nvlist_destroy(value[i]); 1775 } 1776 } 1777 nv_free(value); 1778 ERRNO_SET(nvlist_error(nvl)); 1779 return; 1780 } 1781 1782 nvp = nvpair_move_nvlist_array(name, value, nitems); 1783 if (nvp == NULL) { 1784 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1785 ERRNO_SET(nvl->nvl_error); 1786 } else { 1787 (void)nvlist_move_nvpair(nvl, nvp); 1788 } 1789 } 1790 1791 void 1792 nvlist_move_number_array(nvlist_t *nvl, const char *name, uint64_t *value, 1793 size_t nitems) 1794 { 1795 nvpair_t *nvp; 1796 1797 if (nvlist_error(nvl) != 0) { 1798 nv_free(value); 1799 ERRNO_SET(nvlist_error(nvl)); 1800 return; 1801 } 1802 1803 nvp = nvpair_move_number_array(name, value, nitems); 1804 if (nvp == NULL) { 1805 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1806 ERRNO_SET(nvl->nvl_error); 1807 } else { 1808 (void)nvlist_move_nvpair(nvl, nvp); 1809 } 1810 } 1811 1812 #ifndef _KERNEL 1813 void 1814 nvlist_move_descriptor_array(nvlist_t *nvl, const char *name, int *value, 1815 size_t nitems) 1816 { 1817 nvpair_t *nvp; 1818 size_t i; 1819 1820 if (nvlist_error(nvl) != 0) { 1821 if (value != 0) { 1822 for (i = 0; i < nitems; i++) 1823 close(value[i]); 1824 nv_free(value); 1825 } 1826 1827 ERRNO_SET(nvlist_error(nvl)); 1828 return; 1829 } 1830 1831 nvp = nvpair_move_descriptor_array(name, value, nitems); 1832 if (nvp == NULL) { 1833 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1834 ERRNO_SET(nvl->nvl_error); 1835 } else { 1836 (void)nvlist_move_nvpair(nvl, nvp); 1837 } 1838 } 1839 #endif 1840 1841 const nvpair_t * 1842 nvlist_get_nvpair(const nvlist_t *nvl, const char *name) 1843 { 1844 1845 return (nvlist_find(nvl, NV_TYPE_NONE, name)); 1846 } 1847 1848 #define NVLIST_GET(ftype, type, TYPE) \ 1849 ftype \ 1850 nvlist_get_##type(const nvlist_t *nvl, const char *name) \ 1851 { \ 1852 const nvpair_t *nvp; \ 1853 \ 1854 nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name); \ 1855 if (nvp == NULL) \ 1856 nvlist_report_missing(NV_TYPE_##TYPE, name); \ 1857 return (nvpair_get_##type(nvp)); \ 1858 } 1859 1860 NVLIST_GET(bool, bool, BOOL) 1861 NVLIST_GET(uint64_t, number, NUMBER) 1862 NVLIST_GET(const char *, string, STRING) 1863 NVLIST_GET(const nvlist_t *, nvlist, NVLIST) 1864 #ifndef _KERNEL 1865 NVLIST_GET(int, descriptor, DESCRIPTOR) 1866 #endif 1867 1868 #undef NVLIST_GET 1869 1870 const void * 1871 nvlist_get_binary(const nvlist_t *nvl, const char *name, size_t *sizep) 1872 { 1873 nvpair_t *nvp; 1874 1875 nvp = nvlist_find(nvl, NV_TYPE_BINARY, name); 1876 if (nvp == NULL) 1877 nvlist_report_missing(NV_TYPE_BINARY, name); 1878 1879 return (nvpair_get_binary(nvp, sizep)); 1880 } 1881 1882 #define NVLIST_GET_ARRAY(ftype, type, TYPE) \ 1883 ftype \ 1884 nvlist_get_##type##_array(const nvlist_t *nvl, const char *name, \ 1885 size_t *nitems) \ 1886 { \ 1887 const nvpair_t *nvp; \ 1888 \ 1889 nvp = nvlist_find(nvl, NV_TYPE_##TYPE##_ARRAY, name); \ 1890 if (nvp == NULL) \ 1891 nvlist_report_missing(NV_TYPE_##TYPE##_ARRAY, name); \ 1892 return (nvpair_get_##type##_array(nvp, nitems)); \ 1893 } 1894 1895 NVLIST_GET_ARRAY(const bool *, bool, BOOL) 1896 NVLIST_GET_ARRAY(const uint64_t *, number, NUMBER) 1897 NVLIST_GET_ARRAY(const char * const *, string, STRING) 1898 NVLIST_GET_ARRAY(const nvlist_t * const *, nvlist, NVLIST) 1899 #ifndef _KERNEL 1900 NVLIST_GET_ARRAY(const int *, descriptor, DESCRIPTOR) 1901 #endif 1902 1903 #undef NVLIST_GET_ARRAY 1904 1905 #define NVLIST_TAKE(ftype, type, TYPE) \ 1906 ftype \ 1907 nvlist_take_##type(nvlist_t *nvl, const char *name) \ 1908 { \ 1909 nvpair_t *nvp; \ 1910 ftype value; \ 1911 \ 1912 nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name); \ 1913 if (nvp == NULL) \ 1914 nvlist_report_missing(NV_TYPE_##TYPE, name); \ 1915 value = (ftype)(intptr_t)nvpair_get_##type(nvp); \ 1916 nvlist_remove_nvpair(nvl, nvp); \ 1917 nvpair_free_structure(nvp); \ 1918 return (value); \ 1919 } 1920 1921 NVLIST_TAKE(bool, bool, BOOL) 1922 NVLIST_TAKE(uint64_t, number, NUMBER) 1923 NVLIST_TAKE(char *, string, STRING) 1924 NVLIST_TAKE(nvlist_t *, nvlist, NVLIST) 1925 #ifndef _KERNEL 1926 NVLIST_TAKE(int, descriptor, DESCRIPTOR) 1927 #endif 1928 1929 #undef NVLIST_TAKE 1930 1931 void * 1932 nvlist_take_binary(nvlist_t *nvl, const char *name, size_t *sizep) 1933 { 1934 nvpair_t *nvp; 1935 void *value; 1936 1937 nvp = nvlist_find(nvl, NV_TYPE_BINARY, name); 1938 if (nvp == NULL) 1939 nvlist_report_missing(NV_TYPE_BINARY, name); 1940 1941 value = (void *)(intptr_t)nvpair_get_binary(nvp, sizep); 1942 nvlist_remove_nvpair(nvl, nvp); 1943 nvpair_free_structure(nvp); 1944 return (value); 1945 } 1946 1947 #define NVLIST_TAKE_ARRAY(ftype, type, TYPE) \ 1948 ftype \ 1949 nvlist_take_##type##_array(nvlist_t *nvl, const char *name, \ 1950 size_t *nitems) \ 1951 { \ 1952 nvpair_t *nvp; \ 1953 ftype value; \ 1954 \ 1955 nvp = nvlist_find(nvl, NV_TYPE_##TYPE##_ARRAY, name); \ 1956 if (nvp == NULL) \ 1957 nvlist_report_missing(NV_TYPE_##TYPE##_ARRAY, name); \ 1958 value = (ftype)(intptr_t)nvpair_get_##type##_array(nvp, nitems);\ 1959 nvlist_remove_nvpair(nvl, nvp); \ 1960 nvpair_free_structure(nvp); \ 1961 return (value); \ 1962 } 1963 1964 NVLIST_TAKE_ARRAY(bool *, bool, BOOL) 1965 NVLIST_TAKE_ARRAY(uint64_t *, number, NUMBER) 1966 NVLIST_TAKE_ARRAY(char **, string, STRING) 1967 NVLIST_TAKE_ARRAY(nvlist_t **, nvlist, NVLIST) 1968 #ifndef _KERNEL 1969 NVLIST_TAKE_ARRAY(int *, descriptor, DESCRIPTOR) 1970 #endif 1971 1972 void 1973 nvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp) 1974 { 1975 1976 NVLIST_ASSERT(nvl); 1977 NVPAIR_ASSERT(nvp); 1978 PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl); 1979 1980 nvpair_remove(&nvl->nvl_head, nvp, nvl); 1981 } 1982 1983 void 1984 nvlist_free(nvlist_t *nvl, const char *name) 1985 { 1986 1987 nvlist_free_type(nvl, name, NV_TYPE_NONE); 1988 } 1989 1990 #define NVLIST_FREE(type, TYPE) \ 1991 void \ 1992 nvlist_free_##type(nvlist_t *nvl, const char *name) \ 1993 { \ 1994 \ 1995 nvlist_free_type(nvl, name, NV_TYPE_##TYPE); \ 1996 } 1997 1998 NVLIST_FREE(null, NULL) 1999 NVLIST_FREE(bool, BOOL) 2000 NVLIST_FREE(number, NUMBER) 2001 NVLIST_FREE(string, STRING) 2002 NVLIST_FREE(nvlist, NVLIST) 2003 NVLIST_FREE(binary, BINARY) 2004 NVLIST_FREE(bool_array, BOOL_ARRAY) 2005 NVLIST_FREE(number_array, NUMBER_ARRAY) 2006 NVLIST_FREE(string_array, STRING_ARRAY) 2007 NVLIST_FREE(nvlist_array, NVLIST_ARRAY) 2008 #ifndef _KERNEL 2009 NVLIST_FREE(descriptor, DESCRIPTOR) 2010 NVLIST_FREE(descriptor_array, DESCRIPTOR_ARRAY) 2011 #endif 2012 2013 #undef NVLIST_FREE 2014 2015 void 2016 nvlist_free_nvpair(nvlist_t *nvl, nvpair_t *nvp) 2017 { 2018 2019 NVLIST_ASSERT(nvl); 2020 NVPAIR_ASSERT(nvp); 2021 PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl); 2022 2023 nvlist_remove_nvpair(nvl, nvp); 2024 nvpair_free(nvp); 2025 } 2026 2027