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