subr_nvlist.c revision 292973
1/*-
2 * Copyright (c) 2009-2013 The FreeBSD Foundation
3 * All rights reserved.
4 *
5 * This software was developed by Pawel Jakub Dawidek under sponsorship from
6 * the FreeBSD Foundation.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: stable/10/sys/kern/subr_nvlist.c 292973 2015-12-31 03:28:14Z ngie $");
32
33#include <sys/param.h>
34#include <sys/endian.h>
35#include <sys/queue.h>
36
37#ifdef _KERNEL
38
39#include <sys/errno.h>
40#include <sys/kernel.h>
41#include <sys/lock.h>
42#include <sys/malloc.h>
43#include <sys/systm.h>
44
45#include <machine/stdarg.h>
46
47#else
48#include <sys/socket.h>
49
50#include <errno.h>
51#include <stdarg.h>
52#include <stdbool.h>
53#include <stdint.h>
54#define	_WITH_DPRINTF
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#include <sys/nv_impl.h>
69#include <sys/nvlist_impl.h>
70#include <sys/nvpair_impl.h>
71
72#ifndef	HAVE_PJDLOG
73#ifdef _KERNEL
74#define	PJDLOG_ASSERT(...)		MPASS(__VA_ARGS__)
75#define	PJDLOG_RASSERT(expr, ...)	KASSERT(expr, (__VA_ARGS__))
76#define	PJDLOG_ABORT(...)		panic(__VA_ARGS__)
77#else
78#include <assert.h>
79#define	PJDLOG_ASSERT(...)		assert(__VA_ARGS__)
80#define	PJDLOG_RASSERT(expr, ...)	assert(expr)
81#define	PJDLOG_ABORT(...)		do {				\
82	fprintf(stderr, "%s:%u: ", __FILE__, __LINE__);			\
83	fprintf(stderr, __VA_ARGS__);					\
84	fprintf(stderr, "\n");						\
85	abort();							\
86} while (0)
87#endif
88#endif
89
90#define	NV_FLAG_PRIVATE_MASK	(NV_FLAG_BIG_ENDIAN)
91#define	NV_FLAG_PUBLIC_MASK	(NV_FLAG_IGNORE_CASE)
92#define	NV_FLAG_ALL_MASK	(NV_FLAG_PRIVATE_MASK | NV_FLAG_PUBLIC_MASK)
93
94#define	NVLIST_MAGIC	0x6e766c	/* "nvl" */
95struct nvlist {
96	int		 nvl_magic;
97	int		 nvl_error;
98	int		 nvl_flags;
99	nvpair_t	*nvl_parent;
100	struct nvl_head	 nvl_head;
101};
102
103#define	NVLIST_ASSERT(nvl)	do {					\
104	PJDLOG_ASSERT((nvl) != NULL);					\
105	PJDLOG_ASSERT((nvl)->nvl_magic == NVLIST_MAGIC);		\
106} while (0)
107
108#ifdef _KERNEL
109MALLOC_DEFINE(M_NVLIST, "nvlist", "kernel nvlist");
110#endif
111
112#define	NVPAIR_ASSERT(nvp)	nvpair_assert(nvp)
113
114#define	NVLIST_HEADER_MAGIC	0x6c
115#define	NVLIST_HEADER_VERSION	0x00
116struct nvlist_header {
117	uint8_t		nvlh_magic;
118	uint8_t		nvlh_version;
119	uint8_t		nvlh_flags;
120	uint64_t	nvlh_descriptors;
121	uint64_t	nvlh_size;
122} __packed;
123
124nvlist_t *
125nvlist_create(int flags)
126{
127	nvlist_t *nvl;
128
129	PJDLOG_ASSERT((flags & ~(NV_FLAG_PUBLIC_MASK)) == 0);
130
131	nvl = nv_malloc(sizeof(*nvl));
132	nvl->nvl_error = 0;
133	nvl->nvl_flags = flags;
134	nvl->nvl_parent = NULL;
135	TAILQ_INIT(&nvl->nvl_head);
136	nvl->nvl_magic = NVLIST_MAGIC;
137
138	return (nvl);
139}
140
141void
142nvlist_destroy(nvlist_t *nvl)
143{
144	nvpair_t *nvp;
145	int serrno;
146
147	if (nvl == NULL)
148		return;
149
150	SAVE_ERRNO(serrno);
151
152	NVLIST_ASSERT(nvl);
153
154	while ((nvp = nvlist_first_nvpair(nvl)) != NULL) {
155		nvlist_remove_nvpair(nvl, nvp);
156		nvpair_free(nvp);
157	}
158	nvl->nvl_magic = 0;
159	nv_free(nvl);
160
161	RESTORE_ERRNO(serrno);
162}
163
164void
165nvlist_set_error(nvlist_t *nvl, int error)
166{
167
168	PJDLOG_ASSERT(error != 0);
169
170	/*
171	 * Check for error != 0 so that we don't do the wrong thing if somebody
172	 * tries to abuse this API when asserts are disabled.
173	 */
174	if (nvl != NULL && error != 0 && nvl->nvl_error == 0)
175		nvl->nvl_error = error;
176}
177
178int
179nvlist_error(const nvlist_t *nvl)
180{
181
182	if (nvl == NULL)
183		return (ENOMEM);
184
185	NVLIST_ASSERT(nvl);
186
187	return (nvl->nvl_error);
188}
189
190nvpair_t *
191nvlist_get_nvpair_parent(const nvlist_t *nvl)
192{
193
194	NVLIST_ASSERT(nvl);
195
196	return (nvl->nvl_parent);
197}
198
199const nvlist_t *
200nvlist_get_parent(const nvlist_t *nvl, void **cookiep)
201{
202	nvpair_t *nvp;
203
204	NVLIST_ASSERT(nvl);
205
206	nvp = nvl->nvl_parent;
207	if (cookiep != NULL)
208		*cookiep = nvp;
209	if (nvp == NULL)
210		return (NULL);
211
212	return (nvpair_nvlist(nvp));
213}
214
215void
216nvlist_set_parent(nvlist_t *nvl, nvpair_t *parent)
217{
218
219	NVLIST_ASSERT(nvl);
220
221	nvl->nvl_parent = parent;
222}
223
224bool
225nvlist_empty(const nvlist_t *nvl)
226{
227
228	NVLIST_ASSERT(nvl);
229	PJDLOG_ASSERT(nvl->nvl_error == 0);
230
231	return (nvlist_first_nvpair(nvl) == NULL);
232}
233
234int
235nvlist_flags(const nvlist_t *nvl)
236{
237
238	NVLIST_ASSERT(nvl);
239	PJDLOG_ASSERT(nvl->nvl_error == 0);
240	PJDLOG_ASSERT((nvl->nvl_flags & ~(NV_FLAG_PUBLIC_MASK)) == 0);
241
242	return (nvl->nvl_flags);
243}
244
245static void
246nvlist_report_missing(int type, const char *name)
247{
248
249	PJDLOG_ABORT("Element '%s' of type %s doesn't exist.",
250	    name, nvpair_type_string(type));
251}
252
253static nvpair_t *
254nvlist_find(const nvlist_t *nvl, int type, const char *name)
255{
256	nvpair_t *nvp;
257
258	NVLIST_ASSERT(nvl);
259	PJDLOG_ASSERT(nvl->nvl_error == 0);
260	PJDLOG_ASSERT(type == NV_TYPE_NONE ||
261	    (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
262
263	for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
264	    nvp = nvlist_next_nvpair(nvl, nvp)) {
265		if (type != NV_TYPE_NONE && nvpair_type(nvp) != type)
266			continue;
267		if ((nvl->nvl_flags & NV_FLAG_IGNORE_CASE) != 0) {
268			if (strcasecmp(nvpair_name(nvp), name) != 0)
269				continue;
270		} else {
271			if (strcmp(nvpair_name(nvp), name) != 0)
272				continue;
273		}
274		break;
275	}
276
277	if (nvp == NULL)
278		RESTORE_ERRNO(ENOENT);
279
280	return (nvp);
281}
282
283bool
284nvlist_exists_type(const nvlist_t *nvl, const char *name, int type)
285{
286
287	NVLIST_ASSERT(nvl);
288	PJDLOG_ASSERT(nvl->nvl_error == 0);
289	PJDLOG_ASSERT(type == NV_TYPE_NONE ||
290	    (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
291
292	return (nvlist_find(nvl, type, name) != NULL);
293}
294
295void
296nvlist_free_type(nvlist_t *nvl, const char *name, int type)
297{
298	nvpair_t *nvp;
299
300	NVLIST_ASSERT(nvl);
301	PJDLOG_ASSERT(nvl->nvl_error == 0);
302	PJDLOG_ASSERT(type == NV_TYPE_NONE ||
303	    (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
304
305	nvp = nvlist_find(nvl, type, name);
306	if (nvp != NULL)
307		nvlist_free_nvpair(nvl, nvp);
308	else
309		nvlist_report_missing(type, name);
310}
311
312nvlist_t *
313nvlist_clone(const nvlist_t *nvl)
314{
315	nvlist_t *newnvl;
316	nvpair_t *nvp, *newnvp;
317
318	NVLIST_ASSERT(nvl);
319
320	if (nvl->nvl_error != 0) {
321		RESTORE_ERRNO(nvl->nvl_error);
322		return (NULL);
323	}
324
325	newnvl = nvlist_create(nvl->nvl_flags & NV_FLAG_PUBLIC_MASK);
326	for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
327	    nvp = nvlist_next_nvpair(nvl, nvp)) {
328		newnvp = nvpair_clone(nvp);
329		if (newnvp == NULL)
330			break;
331		nvlist_move_nvpair(newnvl, newnvp);
332	}
333	if (nvp != NULL) {
334		nvlist_destroy(newnvl);
335		return (NULL);
336	}
337	return (newnvl);
338}
339
340#ifndef _KERNEL
341static bool
342nvlist_dump_error_check(const nvlist_t *nvl, int fd, int level)
343{
344
345	if (nvlist_error(nvl) != 0) {
346		dprintf(fd, "%*serror: %d\n", level * 4, "",
347		    nvlist_error(nvl));
348		return (true);
349	}
350
351	return (false);
352}
353
354/*
355 * Dump content of nvlist.
356 */
357void
358nvlist_dump(const nvlist_t *nvl, int fd)
359{
360	const nvlist_t *tmpnvl;
361	nvpair_t *nvp, *tmpnvp;
362	void *cookie;
363	int level;
364
365	level = 0;
366	if (nvlist_dump_error_check(nvl, fd, level))
367		return;
368
369	nvp = nvlist_first_nvpair(nvl);
370	while (nvp != NULL) {
371		dprintf(fd, "%*s%s (%s):", level * 4, "", nvpair_name(nvp),
372		    nvpair_type_string(nvpair_type(nvp)));
373		switch (nvpair_type(nvp)) {
374		case NV_TYPE_NULL:
375			dprintf(fd, " null\n");
376			break;
377		case NV_TYPE_BOOL:
378			dprintf(fd, " %s\n", nvpair_get_bool(nvp) ?
379			    "TRUE" : "FALSE");
380			break;
381		case NV_TYPE_NUMBER:
382			dprintf(fd, " %ju (%jd) (0x%jx)\n",
383			    (uintmax_t)nvpair_get_number(nvp),
384			    (intmax_t)nvpair_get_number(nvp),
385			    (uintmax_t)nvpair_get_number(nvp));
386			break;
387		case NV_TYPE_STRING:
388			dprintf(fd, " [%s]\n", nvpair_get_string(nvp));
389			break;
390		case NV_TYPE_NVLIST:
391			dprintf(fd, "\n");
392			tmpnvl = nvpair_get_nvlist(nvp);
393			if (nvlist_dump_error_check(tmpnvl, fd, level + 1))
394				break;
395			tmpnvp = nvlist_first_nvpair(tmpnvl);
396			if (tmpnvp != NULL) {
397				nvl = tmpnvl;
398				nvp = tmpnvp;
399				level++;
400				continue;
401			}
402			break;
403		case NV_TYPE_DESCRIPTOR:
404			dprintf(fd, " %d\n", nvpair_get_descriptor(nvp));
405			break;
406		case NV_TYPE_BINARY:
407		    {
408			const unsigned char *binary;
409			unsigned int ii;
410			size_t size;
411
412			binary = nvpair_get_binary(nvp, &size);
413			dprintf(fd, " %zu ", size);
414			for (ii = 0; ii < size; ii++)
415				dprintf(fd, "%02hhx", binary[ii]);
416			dprintf(fd, "\n");
417			break;
418		    }
419		default:
420			PJDLOG_ABORT("Unknown type: %d.", nvpair_type(nvp));
421		}
422
423		while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
424			cookie = NULL;
425			nvl = nvlist_get_parent(nvl, &cookie);
426			if (nvl == NULL)
427				return;
428			nvp = cookie;
429			level--;
430		}
431	}
432}
433
434void
435nvlist_fdump(const nvlist_t *nvl, FILE *fp)
436{
437
438	fflush(fp);
439	nvlist_dump(nvl, fileno(fp));
440}
441#endif
442
443/*
444 * The function obtains size of the nvlist after nvlist_pack().
445 */
446size_t
447nvlist_size(const nvlist_t *nvl)
448{
449	const nvlist_t *tmpnvl;
450	const nvpair_t *nvp, *tmpnvp;
451	void *cookie;
452	size_t size;
453
454	NVLIST_ASSERT(nvl);
455	PJDLOG_ASSERT(nvl->nvl_error == 0);
456
457	size = sizeof(struct nvlist_header);
458	nvp = nvlist_first_nvpair(nvl);
459	while (nvp != NULL) {
460		size += nvpair_header_size();
461		size += strlen(nvpair_name(nvp)) + 1;
462		if (nvpair_type(nvp) == NV_TYPE_NVLIST) {
463			size += sizeof(struct nvlist_header);
464			size += nvpair_header_size() + 1;
465			tmpnvl = nvpair_get_nvlist(nvp);
466			PJDLOG_ASSERT(tmpnvl->nvl_error == 0);
467			tmpnvp = nvlist_first_nvpair(tmpnvl);
468			if (tmpnvp != NULL) {
469				nvl = tmpnvl;
470				nvp = tmpnvp;
471				continue;
472			}
473		} else {
474			size += nvpair_size(nvp);
475		}
476
477		while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
478			cookie = NULL;
479			nvl = nvlist_get_parent(nvl, &cookie);
480			if (nvl == NULL)
481				goto out;
482			nvp = cookie;
483		}
484	}
485
486out:
487	return (size);
488}
489
490#ifndef _KERNEL
491static int *
492nvlist_xdescriptors(const nvlist_t *nvl, int *descs, int level)
493{
494	const nvpair_t *nvp;
495
496	NVLIST_ASSERT(nvl);
497	PJDLOG_ASSERT(nvl->nvl_error == 0);
498	PJDLOG_ASSERT(level < 3);
499
500	for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
501	    nvp = nvlist_next_nvpair(nvl, nvp)) {
502		switch (nvpair_type(nvp)) {
503		case NV_TYPE_DESCRIPTOR:
504			*descs = nvpair_get_descriptor(nvp);
505			descs++;
506			break;
507		case NV_TYPE_NVLIST:
508			descs = nvlist_xdescriptors(nvpair_get_nvlist(nvp),
509			    descs, level + 1);
510			break;
511		}
512	}
513
514	return (descs);
515}
516#endif
517
518#ifndef _KERNEL
519int *
520nvlist_descriptors(const nvlist_t *nvl, size_t *nitemsp)
521{
522	size_t nitems;
523	int *fds;
524
525	nitems = nvlist_ndescriptors(nvl);
526	fds = nv_malloc(sizeof(fds[0]) * (nitems + 1));
527	if (fds == NULL)
528		return (NULL);
529	if (nitems > 0)
530		nvlist_xdescriptors(nvl, fds, 0);
531	fds[nitems] = -1;
532	if (nitemsp != NULL)
533		*nitemsp = nitems;
534	return (fds);
535}
536#endif
537
538static size_t
539nvlist_xndescriptors(const nvlist_t *nvl, int level)
540{
541#ifndef _KERNEL
542	const nvpair_t *nvp;
543	size_t ndescs;
544
545	NVLIST_ASSERT(nvl);
546	PJDLOG_ASSERT(nvl->nvl_error == 0);
547	PJDLOG_ASSERT(level < 3);
548
549	ndescs = 0;
550	for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
551	    nvp = nvlist_next_nvpair(nvl, nvp)) {
552		switch (nvpair_type(nvp)) {
553		case NV_TYPE_DESCRIPTOR:
554			ndescs++;
555			break;
556		case NV_TYPE_NVLIST:
557			ndescs += nvlist_xndescriptors(nvpair_get_nvlist(nvp),
558			    level + 1);
559			break;
560		}
561	}
562
563	return (ndescs);
564#else
565	return (0);
566#endif
567}
568
569size_t
570nvlist_ndescriptors(const nvlist_t *nvl)
571{
572
573	return (nvlist_xndescriptors(nvl, 0));
574}
575
576static unsigned char *
577nvlist_pack_header(const nvlist_t *nvl, unsigned char *ptr, size_t *leftp)
578{
579	struct nvlist_header nvlhdr;
580
581	NVLIST_ASSERT(nvl);
582
583	nvlhdr.nvlh_magic = NVLIST_HEADER_MAGIC;
584	nvlhdr.nvlh_version = NVLIST_HEADER_VERSION;
585	nvlhdr.nvlh_flags = nvl->nvl_flags;
586#if BYTE_ORDER == BIG_ENDIAN
587	nvlhdr.nvlh_flags |= NV_FLAG_BIG_ENDIAN;
588#endif
589	nvlhdr.nvlh_descriptors = nvlist_ndescriptors(nvl);
590	nvlhdr.nvlh_size = *leftp - sizeof(nvlhdr);
591	PJDLOG_ASSERT(*leftp >= sizeof(nvlhdr));
592	memcpy(ptr, &nvlhdr, sizeof(nvlhdr));
593	ptr += sizeof(nvlhdr);
594	*leftp -= sizeof(nvlhdr);
595
596	return (ptr);
597}
598
599void *
600nvlist_xpack(const nvlist_t *nvl, int64_t *fdidxp, size_t *sizep)
601{
602	unsigned char *buf, *ptr;
603	size_t left, size;
604	const nvlist_t *tmpnvl;
605	nvpair_t *nvp, *tmpnvp;
606	void *cookie;
607
608	NVLIST_ASSERT(nvl);
609
610	if (nvl->nvl_error != 0) {
611		RESTORE_ERRNO(nvl->nvl_error);
612		return (NULL);
613	}
614
615	size = nvlist_size(nvl);
616	buf = nv_malloc(size);
617	if (buf == NULL)
618		return (NULL);
619
620	ptr = buf;
621	left = size;
622
623	ptr = nvlist_pack_header(nvl, ptr, &left);
624
625	nvp = nvlist_first_nvpair(nvl);
626	while (nvp != NULL) {
627		NVPAIR_ASSERT(nvp);
628
629		nvpair_init_datasize(nvp);
630		ptr = nvpair_pack_header(nvp, ptr, &left);
631		if (ptr == NULL) {
632			nv_free(buf);
633			return (NULL);
634		}
635		switch (nvpair_type(nvp)) {
636		case NV_TYPE_NULL:
637			ptr = nvpair_pack_null(nvp, ptr, &left);
638			break;
639		case NV_TYPE_BOOL:
640			ptr = nvpair_pack_bool(nvp, ptr, &left);
641			break;
642		case NV_TYPE_NUMBER:
643			ptr = nvpair_pack_number(nvp, ptr, &left);
644			break;
645		case NV_TYPE_STRING:
646			ptr = nvpair_pack_string(nvp, ptr, &left);
647			break;
648		case NV_TYPE_NVLIST:
649			tmpnvl = nvpair_get_nvlist(nvp);
650			ptr = nvlist_pack_header(tmpnvl, ptr, &left);
651			if (ptr == NULL)
652				goto out;
653			tmpnvp = nvlist_first_nvpair(tmpnvl);
654			if (tmpnvp != NULL) {
655				nvl = tmpnvl;
656				nvp = tmpnvp;
657				continue;
658			}
659			ptr = nvpair_pack_nvlist_up(ptr, &left);
660			break;
661#ifndef _KERNEL
662		case NV_TYPE_DESCRIPTOR:
663			ptr = nvpair_pack_descriptor(nvp, ptr, fdidxp, &left);
664			break;
665#endif
666		case NV_TYPE_BINARY:
667			ptr = nvpair_pack_binary(nvp, ptr, &left);
668			break;
669		default:
670			PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp));
671		}
672		if (ptr == NULL) {
673			nv_free(buf);
674			return (NULL);
675		}
676		while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
677			cookie = NULL;
678			nvl = nvlist_get_parent(nvl, &cookie);
679			if (nvl == NULL)
680				goto out;
681			nvp = cookie;
682			ptr = nvpair_pack_nvlist_up(ptr, &left);
683			if (ptr == NULL)
684				goto out;
685		}
686	}
687
688out:
689	if (sizep != NULL)
690		*sizep = size;
691	return (buf);
692}
693
694void *
695nvlist_pack(const nvlist_t *nvl, size_t *sizep)
696{
697
698	NVLIST_ASSERT(nvl);
699
700	if (nvl->nvl_error != 0) {
701		RESTORE_ERRNO(nvl->nvl_error);
702		return (NULL);
703	}
704
705	if (nvlist_ndescriptors(nvl) > 0) {
706		RESTORE_ERRNO(EOPNOTSUPP);
707		return (NULL);
708	}
709
710	return (nvlist_xpack(nvl, NULL, sizep));
711}
712
713static bool
714nvlist_check_header(struct nvlist_header *nvlhdrp)
715{
716
717	if (nvlhdrp->nvlh_magic != NVLIST_HEADER_MAGIC) {
718		RESTORE_ERRNO(EINVAL);
719		return (false);
720	}
721	if ((nvlhdrp->nvlh_flags & ~NV_FLAG_ALL_MASK) != 0) {
722		RESTORE_ERRNO(EINVAL);
723		return (false);
724	}
725#if BYTE_ORDER == BIG_ENDIAN
726	if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) == 0) {
727		nvlhdrp->nvlh_size = le64toh(nvlhdrp->nvlh_size);
728		nvlhdrp->nvlh_descriptors = le64toh(nvlhdrp->nvlh_descriptors);
729	}
730#else
731	if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0) {
732		nvlhdrp->nvlh_size = be64toh(nvlhdrp->nvlh_size);
733		nvlhdrp->nvlh_descriptors = be64toh(nvlhdrp->nvlh_descriptors);
734	}
735#endif
736	return (true);
737}
738
739const unsigned char *
740nvlist_unpack_header(nvlist_t *nvl, const unsigned char *ptr, size_t nfds,
741    bool *isbep, size_t *leftp)
742{
743	struct nvlist_header nvlhdr;
744
745	if (*leftp < sizeof(nvlhdr))
746		goto failed;
747
748	memcpy(&nvlhdr, ptr, sizeof(nvlhdr));
749
750	if (!nvlist_check_header(&nvlhdr))
751		goto failed;
752
753	if (nvlhdr.nvlh_size != *leftp - sizeof(nvlhdr))
754		goto failed;
755
756	/*
757	 * nvlh_descriptors might be smaller than nfds in embedded nvlists.
758	 */
759	if (nvlhdr.nvlh_descriptors > nfds)
760		goto failed;
761
762	if ((nvlhdr.nvlh_flags & ~NV_FLAG_ALL_MASK) != 0)
763		goto failed;
764
765	nvl->nvl_flags = (nvlhdr.nvlh_flags & NV_FLAG_PUBLIC_MASK);
766
767	ptr += sizeof(nvlhdr);
768	if (isbep != NULL)
769		*isbep = (((int)nvlhdr.nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0);
770	*leftp -= sizeof(nvlhdr);
771
772	return (ptr);
773failed:
774	RESTORE_ERRNO(EINVAL);
775	return (NULL);
776}
777
778nvlist_t *
779nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds)
780{
781	const unsigned char *ptr;
782	nvlist_t *nvl, *retnvl, *tmpnvl;
783	nvpair_t *nvp;
784	size_t left;
785	bool isbe;
786
787	left = size;
788	ptr = buf;
789
790	tmpnvl = NULL;
791	nvl = retnvl = nvlist_create(0);
792	if (nvl == NULL)
793		goto failed;
794
795	ptr = nvlist_unpack_header(nvl, ptr, nfds, &isbe, &left);
796	if (ptr == NULL)
797		goto failed;
798
799	while (left > 0) {
800		ptr = nvpair_unpack(isbe, ptr, &left, &nvp);
801		if (ptr == NULL)
802			goto failed;
803		switch (nvpair_type(nvp)) {
804		case NV_TYPE_NULL:
805			ptr = nvpair_unpack_null(isbe, nvp, ptr, &left);
806			break;
807		case NV_TYPE_BOOL:
808			ptr = nvpair_unpack_bool(isbe, nvp, ptr, &left);
809			break;
810		case NV_TYPE_NUMBER:
811			ptr = nvpair_unpack_number(isbe, nvp, ptr, &left);
812			break;
813		case NV_TYPE_STRING:
814			ptr = nvpair_unpack_string(isbe, nvp, ptr, &left);
815			break;
816		case NV_TYPE_NVLIST:
817			ptr = nvpair_unpack_nvlist(isbe, nvp, ptr, &left, nfds,
818			    &tmpnvl);
819			nvlist_set_parent(tmpnvl, nvp);
820			break;
821#ifndef _KERNEL
822		case NV_TYPE_DESCRIPTOR:
823			ptr = nvpair_unpack_descriptor(isbe, nvp, ptr, &left,
824			    fds, nfds);
825			break;
826#endif
827		case NV_TYPE_BINARY:
828			ptr = nvpair_unpack_binary(isbe, nvp, ptr, &left);
829			break;
830		case NV_TYPE_NVLIST_UP:
831			if (nvl->nvl_parent == NULL)
832				goto failed;
833			nvl = nvpair_nvlist(nvl->nvl_parent);
834			continue;
835		default:
836			PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp));
837		}
838		if (ptr == NULL)
839			goto failed;
840		nvlist_move_nvpair(nvl, nvp);
841		if (tmpnvl != NULL) {
842			nvl = tmpnvl;
843			tmpnvl = NULL;
844		}
845	}
846
847	return (retnvl);
848failed:
849	nvlist_destroy(retnvl);
850	return (NULL);
851}
852
853nvlist_t *
854nvlist_unpack(const void *buf, size_t size)
855{
856
857	return (nvlist_xunpack(buf, size, NULL, 0));
858}
859
860#ifndef _KERNEL
861int
862nvlist_send(int sock, const nvlist_t *nvl)
863{
864	size_t datasize, nfds;
865	int *fds;
866	void *data;
867	int64_t fdidx;
868	int serrno, ret;
869
870	if (nvlist_error(nvl) != 0) {
871		errno = nvlist_error(nvl);
872		return (-1);
873	}
874
875	fds = nvlist_descriptors(nvl, &nfds);
876	if (fds == NULL)
877		return (-1);
878
879	ret = -1;
880	data = NULL;
881	fdidx = 0;
882
883	data = nvlist_xpack(nvl, &fdidx, &datasize);
884	if (data == NULL)
885		goto out;
886
887	if (buf_send(sock, data, datasize) == -1)
888		goto out;
889
890	if (nfds > 0) {
891		if (fd_send(sock, fds, nfds) == -1)
892			goto out;
893	}
894
895	ret = 0;
896out:
897	serrno = errno;
898	free(fds);
899	free(data);
900	errno = serrno;
901	return (ret);
902}
903
904nvlist_t *
905nvlist_recv(int sock)
906{
907	struct nvlist_header nvlhdr;
908	nvlist_t *nvl, *ret;
909	unsigned char *buf;
910	size_t nfds, size, i;
911	int serrno, *fds;
912
913	if (buf_recv(sock, &nvlhdr, sizeof(nvlhdr)) == -1)
914		return (NULL);
915
916	if (!nvlist_check_header(&nvlhdr))
917		return (NULL);
918
919	nfds = (size_t)nvlhdr.nvlh_descriptors;
920	size = sizeof(nvlhdr) + (size_t)nvlhdr.nvlh_size;
921
922	buf = malloc(size);
923	if (buf == NULL)
924		return (NULL);
925
926	memcpy(buf, &nvlhdr, sizeof(nvlhdr));
927
928	ret = NULL;
929	fds = NULL;
930
931	if (buf_recv(sock, buf + sizeof(nvlhdr), size - sizeof(nvlhdr)) == -1)
932		goto out;
933
934	if (nfds > 0) {
935		fds = malloc(nfds * sizeof(fds[0]));
936		if (fds == NULL)
937			goto out;
938		if (fd_recv(sock, fds, nfds) == -1)
939			goto out;
940	}
941
942	nvl = nvlist_xunpack(buf, size, fds, nfds);
943	if (nvl == NULL) {
944		for (i = 0; i < nfds; i++)
945			close(fds[i]);
946		goto out;
947	}
948
949	ret = nvl;
950out:
951	serrno = errno;
952	free(buf);
953	free(fds);
954	errno = serrno;
955
956	return (ret);
957}
958
959nvlist_t *
960nvlist_xfer(int sock, nvlist_t *nvl)
961{
962
963	if (nvlist_send(sock, nvl) < 0) {
964		nvlist_destroy(nvl);
965		return (NULL);
966	}
967	nvlist_destroy(nvl);
968	return (nvlist_recv(sock));
969}
970#endif
971
972nvpair_t *
973nvlist_first_nvpair(const nvlist_t *nvl)
974{
975
976	NVLIST_ASSERT(nvl);
977
978	return (TAILQ_FIRST(&nvl->nvl_head));
979}
980
981nvpair_t *
982nvlist_next_nvpair(const nvlist_t *nvl, const nvpair_t *nvp)
983{
984	nvpair_t *retnvp;
985
986	NVLIST_ASSERT(nvl);
987	NVPAIR_ASSERT(nvp);
988	PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
989
990	retnvp = nvpair_next(nvp);
991	PJDLOG_ASSERT(retnvp == NULL || nvpair_nvlist(retnvp) == nvl);
992
993	return (retnvp);
994
995}
996
997nvpair_t *
998nvlist_prev_nvpair(const nvlist_t *nvl, const nvpair_t *nvp)
999{
1000	nvpair_t *retnvp;
1001
1002	NVLIST_ASSERT(nvl);
1003	NVPAIR_ASSERT(nvp);
1004	PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
1005
1006	retnvp = nvpair_prev(nvp);
1007	PJDLOG_ASSERT(nvpair_nvlist(retnvp) == nvl);
1008
1009	return (retnvp);
1010}
1011
1012const char *
1013nvlist_next(const nvlist_t *nvl, int *typep, void **cookiep)
1014{
1015	nvpair_t *nvp;
1016
1017	NVLIST_ASSERT(nvl);
1018	PJDLOG_ASSERT(cookiep != NULL);
1019
1020	if (*cookiep == NULL)
1021		nvp = nvlist_first_nvpair(nvl);
1022	else
1023		nvp = nvlist_next_nvpair(nvl, *cookiep);
1024	if (nvp == NULL)
1025		return (NULL);
1026	if (typep != NULL)
1027		*typep = nvpair_type(nvp);
1028	*cookiep = nvp;
1029	return (nvpair_name(nvp));
1030}
1031
1032bool
1033nvlist_exists(const nvlist_t *nvl, const char *name)
1034{
1035
1036	return (nvlist_find(nvl, NV_TYPE_NONE, name) != NULL);
1037}
1038
1039#define	NVLIST_EXISTS(type, TYPE)					\
1040bool									\
1041nvlist_exists_##type(const nvlist_t *nvl, const char *name)		\
1042{									\
1043									\
1044	return (nvlist_find(nvl, NV_TYPE_##TYPE, name) != NULL);	\
1045}
1046
1047NVLIST_EXISTS(null, NULL)
1048NVLIST_EXISTS(bool, BOOL)
1049NVLIST_EXISTS(number, NUMBER)
1050NVLIST_EXISTS(string, STRING)
1051NVLIST_EXISTS(nvlist, NVLIST)
1052#ifndef _KERNEL
1053NVLIST_EXISTS(descriptor, DESCRIPTOR)
1054#endif
1055NVLIST_EXISTS(binary, BINARY)
1056
1057#undef	NVLIST_EXISTS
1058
1059void
1060nvlist_add_nvpair(nvlist_t *nvl, const nvpair_t *nvp)
1061{
1062	nvpair_t *newnvp;
1063
1064	NVPAIR_ASSERT(nvp);
1065
1066	if (nvlist_error(nvl) != 0) {
1067		RESTORE_ERRNO(nvlist_error(nvl));
1068		return;
1069	}
1070	if (nvlist_exists(nvl, nvpair_name(nvp))) {
1071		nvl->nvl_error = EEXIST;
1072		RESTORE_ERRNO(nvlist_error(nvl));
1073		return;
1074	}
1075
1076	newnvp = nvpair_clone(nvp);
1077	if (newnvp == NULL) {
1078		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1079		RESTORE_ERRNO(nvlist_error(nvl));
1080		return;
1081	}
1082
1083	nvpair_insert(&nvl->nvl_head, newnvp, nvl);
1084}
1085
1086void
1087nvlist_add_stringf(nvlist_t *nvl, const char *name, const char *valuefmt, ...)
1088{
1089	va_list valueap;
1090
1091	va_start(valueap, valuefmt);
1092	nvlist_add_stringv(nvl, name, valuefmt, valueap);
1093	va_end(valueap);
1094}
1095
1096void
1097nvlist_add_stringv(nvlist_t *nvl, const char *name, const char *valuefmt,
1098    va_list valueap)
1099{
1100	nvpair_t *nvp;
1101
1102	if (nvlist_error(nvl) != 0) {
1103		RESTORE_ERRNO(nvlist_error(nvl));
1104		return;
1105	}
1106
1107	nvp = nvpair_create_stringv(name, valuefmt, valueap);
1108	if (nvp == NULL) {
1109		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1110		RESTORE_ERRNO(nvl->nvl_error);
1111	} else
1112		nvlist_move_nvpair(nvl, nvp);
1113}
1114
1115void
1116nvlist_add_null(nvlist_t *nvl, const char *name)
1117{
1118	nvpair_t *nvp;
1119
1120	if (nvlist_error(nvl) != 0) {
1121		RESTORE_ERRNO(nvlist_error(nvl));
1122		return;
1123	}
1124
1125	nvp = nvpair_create_null(name);
1126	if (nvp == NULL) {
1127		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1128		RESTORE_ERRNO(nvl->nvl_error);
1129	} else
1130		nvlist_move_nvpair(nvl, nvp);
1131}
1132
1133void
1134nvlist_add_bool(nvlist_t *nvl, const char *name, bool value)
1135{
1136	nvpair_t *nvp;
1137
1138	if (nvlist_error(nvl) != 0) {
1139		RESTORE_ERRNO(nvlist_error(nvl));
1140		return;
1141	}
1142
1143	nvp = nvpair_create_bool(name, value);
1144	if (nvp == NULL) {
1145		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1146		RESTORE_ERRNO(nvl->nvl_error);
1147	} else
1148		nvlist_move_nvpair(nvl, nvp);
1149}
1150
1151void
1152nvlist_add_number(nvlist_t *nvl, const char *name, uint64_t value)
1153{
1154	nvpair_t *nvp;
1155
1156	if (nvlist_error(nvl) != 0) {
1157		RESTORE_ERRNO(nvlist_error(nvl));
1158		return;
1159	}
1160
1161	nvp = nvpair_create_number(name, value);
1162	if (nvp == NULL) {
1163		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1164		RESTORE_ERRNO(nvl->nvl_error);
1165	} else
1166		nvlist_move_nvpair(nvl, nvp);
1167}
1168
1169void
1170nvlist_add_string(nvlist_t *nvl, const char *name, const char *value)
1171{
1172	nvpair_t *nvp;
1173
1174	if (nvlist_error(nvl) != 0) {
1175		RESTORE_ERRNO(nvlist_error(nvl));
1176		return;
1177	}
1178
1179	nvp = nvpair_create_string(name, value);
1180	if (nvp == NULL) {
1181		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1182		RESTORE_ERRNO(nvl->nvl_error);
1183	} else
1184		nvlist_move_nvpair(nvl, nvp);
1185}
1186
1187void
1188nvlist_add_nvlist(nvlist_t *nvl, const char *name, const nvlist_t *value)
1189{
1190	nvpair_t *nvp;
1191
1192	if (nvlist_error(nvl) != 0) {
1193		RESTORE_ERRNO(nvlist_error(nvl));
1194		return;
1195	}
1196
1197	nvp = nvpair_create_nvlist(name, value);
1198	if (nvp == NULL) {
1199		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1200		RESTORE_ERRNO(nvl->nvl_error);
1201	} else
1202		nvlist_move_nvpair(nvl, nvp);
1203}
1204
1205#ifndef _KERNEL
1206void
1207nvlist_add_descriptor(nvlist_t *nvl, const char *name, int value)
1208{
1209	nvpair_t *nvp;
1210
1211	if (nvlist_error(nvl) != 0) {
1212		errno = nvlist_error(nvl);
1213		return;
1214	}
1215
1216	nvp = nvpair_create_descriptor(name, value);
1217	if (nvp == NULL)
1218		nvl->nvl_error = errno = (errno != 0 ? errno : ENOMEM);
1219	else
1220		nvlist_move_nvpair(nvl, nvp);
1221}
1222#endif
1223
1224void
1225nvlist_add_binary(nvlist_t *nvl, const char *name, const void *value,
1226    size_t size)
1227{
1228	nvpair_t *nvp;
1229
1230	if (nvlist_error(nvl) != 0) {
1231		RESTORE_ERRNO(nvlist_error(nvl));
1232		return;
1233	}
1234
1235	nvp = nvpair_create_binary(name, value, size);
1236	if (nvp == NULL) {
1237		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1238		RESTORE_ERRNO(nvl->nvl_error);
1239	} else
1240		nvlist_move_nvpair(nvl, nvp);
1241}
1242
1243void
1244nvlist_move_nvpair(nvlist_t *nvl, nvpair_t *nvp)
1245{
1246
1247	NVPAIR_ASSERT(nvp);
1248	PJDLOG_ASSERT(nvpair_nvlist(nvp) == NULL);
1249
1250	if (nvlist_error(nvl) != 0) {
1251		nvpair_free(nvp);
1252		RESTORE_ERRNO(nvlist_error(nvl));
1253		return;
1254	}
1255	if (nvlist_exists(nvl, nvpair_name(nvp))) {
1256		nvpair_free(nvp);
1257		nvl->nvl_error = EEXIST;
1258		RESTORE_ERRNO(nvl->nvl_error);
1259		return;
1260	}
1261
1262	nvpair_insert(&nvl->nvl_head, nvp, nvl);
1263}
1264
1265void
1266nvlist_move_string(nvlist_t *nvl, const char *name, char *value)
1267{
1268	nvpair_t *nvp;
1269
1270	if (nvlist_error(nvl) != 0) {
1271		nv_free(value);
1272		RESTORE_ERRNO(nvlist_error(nvl));
1273		return;
1274	}
1275
1276	nvp = nvpair_move_string(name, value);
1277	if (nvp == NULL) {
1278		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1279		RESTORE_ERRNO(nvl->nvl_error);
1280	} else
1281		nvlist_move_nvpair(nvl, nvp);
1282}
1283
1284void
1285nvlist_move_nvlist(nvlist_t *nvl, const char *name, nvlist_t *value)
1286{
1287	nvpair_t *nvp;
1288
1289	if (nvlist_error(nvl) != 0) {
1290		if (value != NULL && nvlist_get_nvpair_parent(value) != NULL)
1291			nvlist_destroy(value);
1292		RESTORE_ERRNO(nvlist_error(nvl));
1293		return;
1294	}
1295
1296	nvp = nvpair_move_nvlist(name, value);
1297	if (nvp == NULL) {
1298		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1299		RESTORE_ERRNO(nvl->nvl_error);
1300	} else
1301		nvlist_move_nvpair(nvl, nvp);
1302}
1303
1304#ifndef _KERNEL
1305void
1306nvlist_move_descriptor(nvlist_t *nvl, const char *name, int value)
1307{
1308	nvpair_t *nvp;
1309
1310	if (nvlist_error(nvl) != 0) {
1311		close(value);
1312		errno = nvlist_error(nvl);
1313		return;
1314	}
1315
1316	nvp = nvpair_move_descriptor(name, value);
1317	if (nvp == NULL)
1318		nvl->nvl_error = errno = (errno != 0 ? errno : ENOMEM);
1319	else
1320		nvlist_move_nvpair(nvl, nvp);
1321}
1322#endif
1323
1324void
1325nvlist_move_binary(nvlist_t *nvl, const char *name, void *value, size_t size)
1326{
1327	nvpair_t *nvp;
1328
1329	if (nvlist_error(nvl) != 0) {
1330		nv_free(value);
1331		RESTORE_ERRNO(nvlist_error(nvl));
1332		return;
1333	}
1334
1335	nvp = nvpair_move_binary(name, value, size);
1336	if (nvp == NULL) {
1337		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1338		RESTORE_ERRNO(nvl->nvl_error);
1339	} else
1340		nvlist_move_nvpair(nvl, nvp);
1341}
1342
1343const nvpair_t *
1344nvlist_get_nvpair(const nvlist_t *nvl, const char *name)
1345{
1346
1347	return (nvlist_find(nvl, NV_TYPE_NONE, name));
1348}
1349
1350#define	NVLIST_GET(ftype, type, TYPE)					\
1351ftype									\
1352nvlist_get_##type(const nvlist_t *nvl, const char *name)		\
1353{									\
1354	const nvpair_t *nvp;						\
1355									\
1356	nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name);			\
1357	if (nvp == NULL)						\
1358		nvlist_report_missing(NV_TYPE_##TYPE, name);		\
1359	return (nvpair_get_##type(nvp));				\
1360}
1361
1362NVLIST_GET(bool, bool, BOOL)
1363NVLIST_GET(uint64_t, number, NUMBER)
1364NVLIST_GET(const char *, string, STRING)
1365NVLIST_GET(const nvlist_t *, nvlist, NVLIST)
1366#ifndef _KERNEL
1367NVLIST_GET(int, descriptor, DESCRIPTOR)
1368#endif
1369
1370#undef	NVLIST_GET
1371
1372const void *
1373nvlist_get_binary(const nvlist_t *nvl, const char *name, size_t *sizep)
1374{
1375	nvpair_t *nvp;
1376
1377	nvp = nvlist_find(nvl, NV_TYPE_BINARY, name);
1378	if (nvp == NULL)
1379		nvlist_report_missing(NV_TYPE_BINARY, name);
1380
1381	return (nvpair_get_binary(nvp, sizep));
1382}
1383
1384#define	NVLIST_TAKE(ftype, type, TYPE)					\
1385ftype									\
1386nvlist_take_##type(nvlist_t *nvl, const char *name)			\
1387{									\
1388	nvpair_t *nvp;							\
1389	ftype value;							\
1390									\
1391	nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name);			\
1392	if (nvp == NULL)						\
1393		nvlist_report_missing(NV_TYPE_##TYPE, name);		\
1394	value = (ftype)(intptr_t)nvpair_get_##type(nvp);		\
1395	nvlist_remove_nvpair(nvl, nvp);					\
1396	nvpair_free_structure(nvp);					\
1397	return (value);							\
1398}
1399
1400NVLIST_TAKE(bool, bool, BOOL)
1401NVLIST_TAKE(uint64_t, number, NUMBER)
1402NVLIST_TAKE(char *, string, STRING)
1403NVLIST_TAKE(nvlist_t *, nvlist, NVLIST)
1404#ifndef _KERNEL
1405NVLIST_TAKE(int, descriptor, DESCRIPTOR)
1406#endif
1407
1408#undef	NVLIST_TAKE
1409
1410void *
1411nvlist_take_binary(nvlist_t *nvl, const char *name, size_t *sizep)
1412{
1413	nvpair_t *nvp;
1414	void *value;
1415
1416	nvp = nvlist_find(nvl, NV_TYPE_BINARY, name);
1417	if (nvp == NULL)
1418		nvlist_report_missing(NV_TYPE_BINARY, name);
1419
1420	value = (void *)(intptr_t)nvpair_get_binary(nvp, sizep);
1421	nvlist_remove_nvpair(nvl, nvp);
1422	nvpair_free_structure(nvp);
1423	return (value);
1424}
1425
1426void
1427nvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp)
1428{
1429
1430	NVLIST_ASSERT(nvl);
1431	NVPAIR_ASSERT(nvp);
1432	PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
1433
1434	nvpair_remove(&nvl->nvl_head, nvp, nvl);
1435}
1436
1437void
1438nvlist_free(nvlist_t *nvl, const char *name)
1439{
1440
1441	nvlist_free_type(nvl, name, NV_TYPE_NONE);
1442}
1443
1444#define	NVLIST_FREE(type, TYPE)						\
1445void									\
1446nvlist_free_##type(nvlist_t *nvl, const char *name)			\
1447{									\
1448									\
1449	nvlist_free_type(nvl, name, NV_TYPE_##TYPE);			\
1450}
1451
1452NVLIST_FREE(null, NULL)
1453NVLIST_FREE(bool, BOOL)
1454NVLIST_FREE(number, NUMBER)
1455NVLIST_FREE(string, STRING)
1456NVLIST_FREE(nvlist, NVLIST)
1457#ifndef _KERNEL
1458NVLIST_FREE(descriptor, DESCRIPTOR)
1459#endif
1460NVLIST_FREE(binary, BINARY)
1461
1462#undef	NVLIST_FREE
1463
1464void
1465nvlist_free_nvpair(nvlist_t *nvl, nvpair_t *nvp)
1466{
1467
1468	NVLIST_ASSERT(nvl);
1469	NVPAIR_ASSERT(nvp);
1470	PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
1471
1472	nvlist_remove_nvpair(nvl, nvp);
1473	nvpair_free(nvp);
1474}
1475
1476