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