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