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