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