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