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