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