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