xref: /freebsd/sys/contrib/libnv/nvlist.c (revision 1dacabe1)
154f98da9SMariusz Zaborski /*-
254f98da9SMariusz Zaborski  * Copyright (c) 2009-2013 The FreeBSD Foundation
3347a39b4SMariusz Zaborski  * Copyright (c) 2013-2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
454f98da9SMariusz Zaborski  * All rights reserved.
554f98da9SMariusz Zaborski  *
654f98da9SMariusz Zaborski  * This software was developed by Pawel Jakub Dawidek under sponsorship from
754f98da9SMariusz Zaborski  * the FreeBSD Foundation.
854f98da9SMariusz Zaborski  *
954f98da9SMariusz Zaborski  * Redistribution and use in source and binary forms, with or without
1054f98da9SMariusz Zaborski  * modification, are permitted provided that the following conditions
1154f98da9SMariusz Zaborski  * are met:
1254f98da9SMariusz Zaborski  * 1. Redistributions of source code must retain the above copyright
1354f98da9SMariusz Zaborski  *    notice, this list of conditions and the following disclaimer.
1454f98da9SMariusz Zaborski  * 2. Redistributions in binary form must reproduce the above copyright
1554f98da9SMariusz Zaborski  *    notice, this list of conditions and the following disclaimer in the
1654f98da9SMariusz Zaborski  *    documentation and/or other materials provided with the distribution.
1754f98da9SMariusz Zaborski  *
1854f98da9SMariusz Zaborski  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
1954f98da9SMariusz Zaborski  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2054f98da9SMariusz Zaborski  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2154f98da9SMariusz Zaborski  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
2254f98da9SMariusz Zaborski  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2354f98da9SMariusz Zaborski  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2454f98da9SMariusz Zaborski  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2554f98da9SMariusz Zaborski  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2654f98da9SMariusz Zaborski  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2754f98da9SMariusz Zaborski  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2854f98da9SMariusz Zaborski  * SUCH DAMAGE.
2954f98da9SMariusz Zaborski  */
3054f98da9SMariusz Zaborski 
3154f98da9SMariusz Zaborski #include <sys/cdefs.h>
3254f98da9SMariusz Zaborski __FBSDID("$FreeBSD$");
3354f98da9SMariusz Zaborski 
3454f98da9SMariusz Zaborski #include <sys/param.h>
3554f98da9SMariusz Zaborski #include <sys/endian.h>
3654f98da9SMariusz Zaborski #include <sys/queue.h>
3754f98da9SMariusz Zaborski 
3854f98da9SMariusz Zaborski #ifdef _KERNEL
3954f98da9SMariusz Zaborski 
4054f98da9SMariusz Zaborski #include <sys/errno.h>
4154f98da9SMariusz Zaborski #include <sys/kernel.h>
4254f98da9SMariusz Zaborski #include <sys/lock.h>
4354f98da9SMariusz Zaborski #include <sys/malloc.h>
4454f98da9SMariusz Zaborski #include <sys/systm.h>
4554f98da9SMariusz Zaborski 
4654f98da9SMariusz Zaborski #include <machine/stdarg.h>
4754f98da9SMariusz Zaborski 
4854f98da9SMariusz Zaborski #else
4954f98da9SMariusz Zaborski #include <sys/socket.h>
5054f98da9SMariusz Zaborski 
5154f98da9SMariusz Zaborski #include <errno.h>
5254f98da9SMariusz Zaborski #include <stdarg.h>
5354f98da9SMariusz Zaborski #include <stdbool.h>
5454f98da9SMariusz Zaborski #include <stdint.h>
5554f98da9SMariusz Zaborski #include <stdio.h>
5654f98da9SMariusz Zaborski #include <stdlib.h>
5754f98da9SMariusz Zaborski #include <string.h>
5854f98da9SMariusz Zaborski #include <unistd.h>
5954f98da9SMariusz Zaborski 
6054f98da9SMariusz Zaborski #include "msgio.h"
6154f98da9SMariusz Zaborski #endif
6254f98da9SMariusz Zaborski 
6354f98da9SMariusz Zaborski #ifdef HAVE_PJDLOG
6454f98da9SMariusz Zaborski #include <pjdlog.h>
6554f98da9SMariusz Zaborski #endif
6654f98da9SMariusz Zaborski 
6754f98da9SMariusz Zaborski #include <sys/nv.h>
6854f98da9SMariusz Zaborski 
6954f98da9SMariusz Zaborski #include "nv_impl.h"
7054f98da9SMariusz Zaborski #include "nvlist_impl.h"
7154f98da9SMariusz Zaborski #include "nvpair_impl.h"
7254f98da9SMariusz Zaborski 
7354f98da9SMariusz Zaborski #ifndef	HAVE_PJDLOG
7454f98da9SMariusz Zaborski #ifdef _KERNEL
7554f98da9SMariusz Zaborski #define	PJDLOG_ASSERT(...)		MPASS(__VA_ARGS__)
7654f98da9SMariusz Zaborski #define	PJDLOG_RASSERT(expr, ...)	KASSERT(expr, (__VA_ARGS__))
7754f98da9SMariusz Zaborski #define	PJDLOG_ABORT(...)		panic(__VA_ARGS__)
7854f98da9SMariusz Zaborski #else
7954f98da9SMariusz Zaborski #include <assert.h>
8054f98da9SMariusz Zaborski #define	PJDLOG_ASSERT(...)		assert(__VA_ARGS__)
8154f98da9SMariusz Zaborski #define	PJDLOG_RASSERT(expr, ...)	assert(expr)
8254f98da9SMariusz Zaborski #define	PJDLOG_ABORT(...)		do {				\
8354f98da9SMariusz Zaborski 	fprintf(stderr, "%s:%u: ", __FILE__, __LINE__);			\
8454f98da9SMariusz Zaborski 	fprintf(stderr, __VA_ARGS__);					\
8554f98da9SMariusz Zaborski 	fprintf(stderr, "\n");						\
8654f98da9SMariusz Zaborski 	abort();							\
8754f98da9SMariusz Zaborski } while (0)
8854f98da9SMariusz Zaborski #endif
8954f98da9SMariusz Zaborski #endif
9054f98da9SMariusz Zaborski 
91347a39b4SMariusz Zaborski #define	NV_FLAG_PRIVATE_MASK	(NV_FLAG_BIG_ENDIAN | NV_FLAG_IN_ARRAY)
9254f98da9SMariusz Zaborski #define	NV_FLAG_PUBLIC_MASK	(NV_FLAG_IGNORE_CASE | NV_FLAG_NO_UNIQUE)
9354f98da9SMariusz Zaborski #define	NV_FLAG_ALL_MASK	(NV_FLAG_PRIVATE_MASK | NV_FLAG_PUBLIC_MASK)
9454f98da9SMariusz Zaborski 
9554f98da9SMariusz Zaborski #define	NVLIST_MAGIC	0x6e766c	/* "nvl" */
9654f98da9SMariusz Zaborski struct nvlist {
9754f98da9SMariusz Zaborski 	int		 nvl_magic;
9854f98da9SMariusz Zaborski 	int		 nvl_error;
9954f98da9SMariusz Zaborski 	int		 nvl_flags;
10054f98da9SMariusz Zaborski 	nvpair_t	*nvl_parent;
101347a39b4SMariusz Zaborski 	nvpair_t	*nvl_array_next;
10254f98da9SMariusz Zaborski 	struct nvl_head	 nvl_head;
10354f98da9SMariusz Zaborski };
10454f98da9SMariusz Zaborski 
10554f98da9SMariusz Zaborski #define	NVLIST_ASSERT(nvl)	do {					\
10654f98da9SMariusz Zaborski 	PJDLOG_ASSERT((nvl) != NULL);					\
10754f98da9SMariusz Zaborski 	PJDLOG_ASSERT((nvl)->nvl_magic == NVLIST_MAGIC);		\
10854f98da9SMariusz Zaborski } while (0)
10954f98da9SMariusz Zaborski 
11054f98da9SMariusz Zaborski #ifdef _KERNEL
11154f98da9SMariusz Zaborski MALLOC_DEFINE(M_NVLIST, "nvlist", "kernel nvlist");
11254f98da9SMariusz Zaborski #endif
11354f98da9SMariusz Zaborski 
11454f98da9SMariusz Zaborski #define	NVPAIR_ASSERT(nvp)	nvpair_assert(nvp)
11554f98da9SMariusz Zaborski 
11654f98da9SMariusz Zaborski #define	NVLIST_HEADER_MAGIC	0x6c
11754f98da9SMariusz Zaborski #define	NVLIST_HEADER_VERSION	0x00
11854f98da9SMariusz Zaborski struct nvlist_header {
11954f98da9SMariusz Zaborski 	uint8_t		nvlh_magic;
12054f98da9SMariusz Zaborski 	uint8_t		nvlh_version;
12154f98da9SMariusz Zaborski 	uint8_t		nvlh_flags;
12254f98da9SMariusz Zaborski 	uint64_t	nvlh_descriptors;
12354f98da9SMariusz Zaborski 	uint64_t	nvlh_size;
12454f98da9SMariusz Zaborski } __packed;
12554f98da9SMariusz Zaborski 
12654f98da9SMariusz Zaborski nvlist_t *
12754f98da9SMariusz Zaborski nvlist_create(int flags)
12854f98da9SMariusz Zaborski {
12954f98da9SMariusz Zaborski 	nvlist_t *nvl;
13054f98da9SMariusz Zaborski 
13154f98da9SMariusz Zaborski 	PJDLOG_ASSERT((flags & ~(NV_FLAG_PUBLIC_MASK)) == 0);
13254f98da9SMariusz Zaborski 
13354f98da9SMariusz Zaborski 	nvl = nv_malloc(sizeof(*nvl));
13454f98da9SMariusz Zaborski 	if (nvl == NULL)
13554f98da9SMariusz Zaborski 		return (NULL);
13654f98da9SMariusz Zaborski 	nvl->nvl_error = 0;
13754f98da9SMariusz Zaborski 	nvl->nvl_flags = flags;
13854f98da9SMariusz Zaborski 	nvl->nvl_parent = NULL;
139347a39b4SMariusz Zaborski 	nvl->nvl_array_next = NULL;
14054f98da9SMariusz Zaborski 	TAILQ_INIT(&nvl->nvl_head);
14154f98da9SMariusz Zaborski 	nvl->nvl_magic = NVLIST_MAGIC;
14254f98da9SMariusz Zaborski 
14354f98da9SMariusz Zaborski 	return (nvl);
14454f98da9SMariusz Zaborski }
14554f98da9SMariusz Zaborski 
14654f98da9SMariusz Zaborski void
14754f98da9SMariusz Zaborski nvlist_destroy(nvlist_t *nvl)
14854f98da9SMariusz Zaborski {
14954f98da9SMariusz Zaborski 	nvpair_t *nvp;
15054f98da9SMariusz Zaborski 
15154f98da9SMariusz Zaborski 	if (nvl == NULL)
15254f98da9SMariusz Zaborski 		return;
15354f98da9SMariusz Zaborski 
15454f98da9SMariusz Zaborski 	ERRNO_SAVE();
15554f98da9SMariusz Zaborski 
15654f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
15754f98da9SMariusz Zaborski 
15854f98da9SMariusz Zaborski 	while ((nvp = nvlist_first_nvpair(nvl)) != NULL) {
15954f98da9SMariusz Zaborski 		nvlist_remove_nvpair(nvl, nvp);
16054f98da9SMariusz Zaborski 		nvpair_free(nvp);
16154f98da9SMariusz Zaborski 	}
162347a39b4SMariusz Zaborski 	if (nvl->nvl_array_next != NULL)
163347a39b4SMariusz Zaborski 		nvpair_free_structure(nvl->nvl_array_next);
164347a39b4SMariusz Zaborski 	nvl->nvl_array_next = NULL;
165347a39b4SMariusz Zaborski 	nvl->nvl_parent = NULL;
16654f98da9SMariusz Zaborski 	nvl->nvl_magic = 0;
16754f98da9SMariusz Zaborski 	nv_free(nvl);
16854f98da9SMariusz Zaborski 
16954f98da9SMariusz Zaborski 	ERRNO_RESTORE();
17054f98da9SMariusz Zaborski }
17154f98da9SMariusz Zaborski 
17254f98da9SMariusz Zaborski void
17354f98da9SMariusz Zaborski nvlist_set_error(nvlist_t *nvl, int error)
17454f98da9SMariusz Zaborski {
17554f98da9SMariusz Zaborski 
17654f98da9SMariusz Zaborski 	PJDLOG_ASSERT(error != 0);
17754f98da9SMariusz Zaborski 
17854f98da9SMariusz Zaborski 	/*
17954f98da9SMariusz Zaborski 	 * Check for error != 0 so that we don't do the wrong thing if somebody
18054f98da9SMariusz Zaborski 	 * tries to abuse this API when asserts are disabled.
18154f98da9SMariusz Zaborski 	 */
18254f98da9SMariusz Zaborski 	if (nvl != NULL && error != 0 && nvl->nvl_error == 0)
18354f98da9SMariusz Zaborski 		nvl->nvl_error = error;
18454f98da9SMariusz Zaborski }
18554f98da9SMariusz Zaborski 
18654f98da9SMariusz Zaborski int
18754f98da9SMariusz Zaborski nvlist_error(const nvlist_t *nvl)
18854f98da9SMariusz Zaborski {
18954f98da9SMariusz Zaborski 
19054f98da9SMariusz Zaborski 	if (nvl == NULL)
19154f98da9SMariusz Zaborski 		return (ENOMEM);
19254f98da9SMariusz Zaborski 
19354f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
19454f98da9SMariusz Zaborski 
19554f98da9SMariusz Zaborski 	return (nvl->nvl_error);
19654f98da9SMariusz Zaborski }
19754f98da9SMariusz Zaborski 
19854f98da9SMariusz Zaborski nvpair_t *
19954f98da9SMariusz Zaborski nvlist_get_nvpair_parent(const nvlist_t *nvl)
20054f98da9SMariusz Zaborski {
20154f98da9SMariusz Zaborski 
20254f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
20354f98da9SMariusz Zaborski 
20454f98da9SMariusz Zaborski 	return (nvl->nvl_parent);
20554f98da9SMariusz Zaborski }
20654f98da9SMariusz Zaborski 
20754f98da9SMariusz Zaborski const nvlist_t *
20854f98da9SMariusz Zaborski nvlist_get_parent(const nvlist_t *nvl, void **cookiep)
20954f98da9SMariusz Zaborski {
21054f98da9SMariusz Zaborski 	nvpair_t *nvp;
21154f98da9SMariusz Zaborski 
21254f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
21354f98da9SMariusz Zaborski 
21454f98da9SMariusz Zaborski 	nvp = nvl->nvl_parent;
21554f98da9SMariusz Zaborski 	if (cookiep != NULL)
21654f98da9SMariusz Zaborski 		*cookiep = nvp;
21754f98da9SMariusz Zaborski 	if (nvp == NULL)
21854f98da9SMariusz Zaborski 		return (NULL);
21954f98da9SMariusz Zaborski 
22054f98da9SMariusz Zaborski 	return (nvpair_nvlist(nvp));
22154f98da9SMariusz Zaborski }
22254f98da9SMariusz Zaborski 
22354f98da9SMariusz Zaborski void
22454f98da9SMariusz Zaborski nvlist_set_parent(nvlist_t *nvl, nvpair_t *parent)
22554f98da9SMariusz Zaborski {
22654f98da9SMariusz Zaborski 
22754f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
22854f98da9SMariusz Zaborski 
22954f98da9SMariusz Zaborski 	nvl->nvl_parent = parent;
23054f98da9SMariusz Zaborski }
23154f98da9SMariusz Zaborski 
232347a39b4SMariusz Zaborski void
233347a39b4SMariusz Zaborski nvlist_set_array_next(nvlist_t *nvl, nvpair_t *ele)
234347a39b4SMariusz Zaborski {
235347a39b4SMariusz Zaborski 
236347a39b4SMariusz Zaborski 	NVLIST_ASSERT(nvl);
237347a39b4SMariusz Zaborski 
2381b550329SMariusz Zaborski 	if (ele != NULL) {
239347a39b4SMariusz Zaborski 		nvl->nvl_flags |= NV_FLAG_IN_ARRAY;
2401b550329SMariusz Zaborski 	} else {
241347a39b4SMariusz Zaborski 		nvl->nvl_flags &= ~NV_FLAG_IN_ARRAY;
2421b550329SMariusz Zaborski 		nv_free(nvl->nvl_array_next);
2431b550329SMariusz Zaborski 	}
244347a39b4SMariusz Zaborski 
245347a39b4SMariusz Zaborski 	nvl->nvl_array_next = ele;
246347a39b4SMariusz Zaborski }
247347a39b4SMariusz Zaborski 
248347a39b4SMariusz Zaborski bool
249347a39b4SMariusz Zaborski nvlist_in_array(const nvlist_t *nvl)
250347a39b4SMariusz Zaborski {
251347a39b4SMariusz Zaborski 
252347a39b4SMariusz Zaborski 	NVLIST_ASSERT(nvl);
253347a39b4SMariusz Zaborski 
254347a39b4SMariusz Zaborski 	return ((nvl->nvl_flags & NV_FLAG_IN_ARRAY) != 0);
255347a39b4SMariusz Zaborski }
256347a39b4SMariusz Zaborski 
257347a39b4SMariusz Zaborski const nvlist_t *
258347a39b4SMariusz Zaborski nvlist_get_array_next(const nvlist_t *nvl)
259347a39b4SMariusz Zaborski {
260347a39b4SMariusz Zaborski 	nvpair_t *nvp;
261347a39b4SMariusz Zaborski 
262347a39b4SMariusz Zaborski 	NVLIST_ASSERT(nvl);
263347a39b4SMariusz Zaborski 
264347a39b4SMariusz Zaborski 	nvp = nvl->nvl_array_next;
265347a39b4SMariusz Zaborski 	if (nvp == NULL)
266347a39b4SMariusz Zaborski 		return (NULL);
267347a39b4SMariusz Zaborski 
268347a39b4SMariusz Zaborski 	return (nvpair_get_nvlist(nvp));
269347a39b4SMariusz Zaborski }
270347a39b4SMariusz Zaborski 
271347a39b4SMariusz Zaborski const nvlist_t *
272347a39b4SMariusz Zaborski nvlist_get_pararr(const nvlist_t *nvl, void **cookiep)
273347a39b4SMariusz Zaborski {
274347a39b4SMariusz Zaborski 	const nvlist_t *ret;
275347a39b4SMariusz Zaborski 
276347a39b4SMariusz Zaborski 	ret = nvlist_get_array_next(nvl);
277347a39b4SMariusz Zaborski 	if (ret != NULL) {
278347a39b4SMariusz Zaborski 		if (cookiep != NULL)
279347a39b4SMariusz Zaborski 			*cookiep = NULL;
280347a39b4SMariusz Zaborski 		return (ret);
281347a39b4SMariusz Zaborski 	}
282347a39b4SMariusz Zaborski 
28308016b31SMariusz Zaborski 	return (nvlist_get_parent(nvl, cookiep));
284347a39b4SMariusz Zaborski }
285347a39b4SMariusz Zaborski 
28654f98da9SMariusz Zaborski bool
28754f98da9SMariusz Zaborski nvlist_empty(const nvlist_t *nvl)
28854f98da9SMariusz Zaborski {
28954f98da9SMariusz Zaborski 
29054f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
29154f98da9SMariusz Zaborski 	PJDLOG_ASSERT(nvl->nvl_error == 0);
29254f98da9SMariusz Zaborski 
29354f98da9SMariusz Zaborski 	return (nvlist_first_nvpair(nvl) == NULL);
29454f98da9SMariusz Zaborski }
29554f98da9SMariusz Zaborski 
29654f98da9SMariusz Zaborski int
29754f98da9SMariusz Zaborski nvlist_flags(const nvlist_t *nvl)
29854f98da9SMariusz Zaborski {
29954f98da9SMariusz Zaborski 
30054f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
30154f98da9SMariusz Zaborski 	PJDLOG_ASSERT(nvl->nvl_error == 0);
30254f98da9SMariusz Zaborski 
303347a39b4SMariusz Zaborski 	return (nvl->nvl_flags & NV_FLAG_PUBLIC_MASK);
304347a39b4SMariusz Zaborski }
305347a39b4SMariusz Zaborski 
306347a39b4SMariusz Zaborski void
307347a39b4SMariusz Zaborski nvlist_set_flags(nvlist_t *nvl, int flags)
308347a39b4SMariusz Zaborski {
309347a39b4SMariusz Zaborski 
310347a39b4SMariusz Zaborski 	NVLIST_ASSERT(nvl);
311347a39b4SMariusz Zaborski 	PJDLOG_ASSERT(nvl->nvl_error == 0);
312347a39b4SMariusz Zaborski 
313347a39b4SMariusz Zaborski 	nvl->nvl_flags = flags;
31454f98da9SMariusz Zaborski }
31554f98da9SMariusz Zaborski 
3165ef231f6SMariusz Zaborski void
31754f98da9SMariusz Zaborski nvlist_report_missing(int type, const char *name)
31854f98da9SMariusz Zaborski {
31954f98da9SMariusz Zaborski 
32054f98da9SMariusz Zaborski 	PJDLOG_ABORT("Element '%s' of type %s doesn't exist.",
32154f98da9SMariusz Zaborski 	    name, nvpair_type_string(type));
32254f98da9SMariusz Zaborski }
32354f98da9SMariusz Zaborski 
32454f98da9SMariusz Zaborski static nvpair_t *
32554f98da9SMariusz Zaborski nvlist_find(const nvlist_t *nvl, int type, const char *name)
32654f98da9SMariusz Zaborski {
32754f98da9SMariusz Zaborski 	nvpair_t *nvp;
32854f98da9SMariusz Zaborski 
32954f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
33054f98da9SMariusz Zaborski 	PJDLOG_ASSERT(nvl->nvl_error == 0);
33154f98da9SMariusz Zaborski 	PJDLOG_ASSERT(type == NV_TYPE_NONE ||
33254f98da9SMariusz Zaborski 	    (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
33354f98da9SMariusz Zaborski 
33454f98da9SMariusz Zaborski 	for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
33554f98da9SMariusz Zaborski 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
33654f98da9SMariusz Zaborski 		if (type != NV_TYPE_NONE && nvpair_type(nvp) != type)
33754f98da9SMariusz Zaborski 			continue;
33854f98da9SMariusz Zaborski 		if ((nvl->nvl_flags & NV_FLAG_IGNORE_CASE) != 0) {
33954f98da9SMariusz Zaborski 			if (strcasecmp(nvpair_name(nvp), name) != 0)
34054f98da9SMariusz Zaborski 				continue;
34154f98da9SMariusz Zaborski 		} else {
34254f98da9SMariusz Zaborski 			if (strcmp(nvpair_name(nvp), name) != 0)
34354f98da9SMariusz Zaborski 				continue;
34454f98da9SMariusz Zaborski 		}
34554f98da9SMariusz Zaborski 		break;
34654f98da9SMariusz Zaborski 	}
34754f98da9SMariusz Zaborski 
34854f98da9SMariusz Zaborski 	if (nvp == NULL)
34954f98da9SMariusz Zaborski 		ERRNO_SET(ENOENT);
35054f98da9SMariusz Zaborski 
35154f98da9SMariusz Zaborski 	return (nvp);
35254f98da9SMariusz Zaborski }
35354f98da9SMariusz Zaborski 
35454f98da9SMariusz Zaborski bool
35554f98da9SMariusz Zaborski nvlist_exists_type(const nvlist_t *nvl, const char *name, int type)
35654f98da9SMariusz Zaborski {
35754f98da9SMariusz Zaborski 
35854f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
35954f98da9SMariusz Zaborski 	PJDLOG_ASSERT(nvl->nvl_error == 0);
36054f98da9SMariusz Zaborski 	PJDLOG_ASSERT(type == NV_TYPE_NONE ||
36154f98da9SMariusz Zaborski 	    (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
36254f98da9SMariusz Zaborski 
36354f98da9SMariusz Zaborski 	return (nvlist_find(nvl, type, name) != NULL);
36454f98da9SMariusz Zaborski }
36554f98da9SMariusz Zaborski 
36654f98da9SMariusz Zaborski void
36754f98da9SMariusz Zaborski nvlist_free_type(nvlist_t *nvl, const char *name, int type)
36854f98da9SMariusz Zaborski {
36954f98da9SMariusz Zaborski 	nvpair_t *nvp;
37054f98da9SMariusz Zaborski 
37154f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
37254f98da9SMariusz Zaborski 	PJDLOG_ASSERT(nvl->nvl_error == 0);
37354f98da9SMariusz Zaborski 	PJDLOG_ASSERT(type == NV_TYPE_NONE ||
37454f98da9SMariusz Zaborski 	    (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
37554f98da9SMariusz Zaborski 
37654f98da9SMariusz Zaborski 	nvp = nvlist_find(nvl, type, name);
37754f98da9SMariusz Zaborski 	if (nvp != NULL)
37854f98da9SMariusz Zaborski 		nvlist_free_nvpair(nvl, nvp);
37954f98da9SMariusz Zaborski 	else
38054f98da9SMariusz Zaborski 		nvlist_report_missing(type, name);
38154f98da9SMariusz Zaborski }
38254f98da9SMariusz Zaborski 
38354f98da9SMariusz Zaborski nvlist_t *
38454f98da9SMariusz Zaborski nvlist_clone(const nvlist_t *nvl)
38554f98da9SMariusz Zaborski {
38654f98da9SMariusz Zaborski 	nvlist_t *newnvl;
38754f98da9SMariusz Zaborski 	nvpair_t *nvp, *newnvp;
38854f98da9SMariusz Zaborski 
38954f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
39054f98da9SMariusz Zaborski 
39154f98da9SMariusz Zaborski 	if (nvl->nvl_error != 0) {
39254f98da9SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
39354f98da9SMariusz Zaborski 		return (NULL);
39454f98da9SMariusz Zaborski 	}
39554f98da9SMariusz Zaborski 
39654f98da9SMariusz Zaborski 	newnvl = nvlist_create(nvl->nvl_flags & NV_FLAG_PUBLIC_MASK);
39754f98da9SMariusz Zaborski 	for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
39854f98da9SMariusz Zaborski 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
39954f98da9SMariusz Zaborski 		newnvp = nvpair_clone(nvp);
40054f98da9SMariusz Zaborski 		if (newnvp == NULL)
40154f98da9SMariusz Zaborski 			break;
40230740f45SMariusz Zaborski 		(void)nvlist_move_nvpair(newnvl, newnvp);
40354f98da9SMariusz Zaborski 	}
40454f98da9SMariusz Zaborski 	if (nvp != NULL) {
40554f98da9SMariusz Zaborski 		nvlist_destroy(newnvl);
40654f98da9SMariusz Zaborski 		return (NULL);
40754f98da9SMariusz Zaborski 	}
40854f98da9SMariusz Zaborski 	return (newnvl);
40954f98da9SMariusz Zaborski }
41054f98da9SMariusz Zaborski 
41154f98da9SMariusz Zaborski #ifndef _KERNEL
41254f98da9SMariusz Zaborski static bool
41354f98da9SMariusz Zaborski nvlist_dump_error_check(const nvlist_t *nvl, int fd, int level)
41454f98da9SMariusz Zaborski {
41554f98da9SMariusz Zaborski 
41654f98da9SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
41754f98da9SMariusz Zaborski 		dprintf(fd, "%*serror: %d\n", level * 4, "",
41854f98da9SMariusz Zaborski 		    nvlist_error(nvl));
41954f98da9SMariusz Zaborski 		return (true);
42054f98da9SMariusz Zaborski 	}
42154f98da9SMariusz Zaborski 
42254f98da9SMariusz Zaborski 	return (false);
42354f98da9SMariusz Zaborski }
42454f98da9SMariusz Zaborski 
42554f98da9SMariusz Zaborski /*
42654f98da9SMariusz Zaborski  * Dump content of nvlist.
42754f98da9SMariusz Zaborski  */
42854f98da9SMariusz Zaborski void
42954f98da9SMariusz Zaborski nvlist_dump(const nvlist_t *nvl, int fd)
43054f98da9SMariusz Zaborski {
43154f98da9SMariusz Zaborski 	const nvlist_t *tmpnvl;
43254f98da9SMariusz Zaborski 	nvpair_t *nvp, *tmpnvp;
43354f98da9SMariusz Zaborski 	void *cookie;
43454f98da9SMariusz Zaborski 	int level;
43554f98da9SMariusz Zaborski 
43654f98da9SMariusz Zaborski 	level = 0;
43754f98da9SMariusz Zaborski 	if (nvlist_dump_error_check(nvl, fd, level))
43854f98da9SMariusz Zaborski 		return;
43954f98da9SMariusz Zaborski 
44054f98da9SMariusz Zaborski 	nvp = nvlist_first_nvpair(nvl);
44154f98da9SMariusz Zaborski 	while (nvp != NULL) {
44254f98da9SMariusz Zaborski 		dprintf(fd, "%*s%s (%s):", level * 4, "", nvpair_name(nvp),
44354f98da9SMariusz Zaborski 		    nvpair_type_string(nvpair_type(nvp)));
44454f98da9SMariusz Zaborski 		switch (nvpair_type(nvp)) {
44554f98da9SMariusz Zaborski 		case NV_TYPE_NULL:
44654f98da9SMariusz Zaborski 			dprintf(fd, " null\n");
44754f98da9SMariusz Zaborski 			break;
44854f98da9SMariusz Zaborski 		case NV_TYPE_BOOL:
44954f98da9SMariusz Zaborski 			dprintf(fd, " %s\n", nvpair_get_bool(nvp) ?
45054f98da9SMariusz Zaborski 			    "TRUE" : "FALSE");
45154f98da9SMariusz Zaborski 			break;
45254f98da9SMariusz Zaborski 		case NV_TYPE_NUMBER:
45354f98da9SMariusz Zaborski 			dprintf(fd, " %ju (%jd) (0x%jx)\n",
45454f98da9SMariusz Zaborski 			    (uintmax_t)nvpair_get_number(nvp),
45554f98da9SMariusz Zaborski 			    (intmax_t)nvpair_get_number(nvp),
45654f98da9SMariusz Zaborski 			    (uintmax_t)nvpair_get_number(nvp));
45754f98da9SMariusz Zaborski 			break;
45854f98da9SMariusz Zaborski 		case NV_TYPE_STRING:
45954f98da9SMariusz Zaborski 			dprintf(fd, " [%s]\n", nvpair_get_string(nvp));
46054f98da9SMariusz Zaborski 			break;
46154f98da9SMariusz Zaborski 		case NV_TYPE_NVLIST:
46254f98da9SMariusz Zaborski 			dprintf(fd, "\n");
46354f98da9SMariusz Zaborski 			tmpnvl = nvpair_get_nvlist(nvp);
46454f98da9SMariusz Zaborski 			if (nvlist_dump_error_check(tmpnvl, fd, level + 1))
46554f98da9SMariusz Zaborski 				break;
46654f98da9SMariusz Zaborski 			tmpnvp = nvlist_first_nvpair(tmpnvl);
46754f98da9SMariusz Zaborski 			if (tmpnvp != NULL) {
46854f98da9SMariusz Zaborski 				nvl = tmpnvl;
46954f98da9SMariusz Zaborski 				nvp = tmpnvp;
47054f98da9SMariusz Zaborski 				level++;
47154f98da9SMariusz Zaborski 				continue;
47254f98da9SMariusz Zaborski 			}
47354f98da9SMariusz Zaborski 			break;
47454f98da9SMariusz Zaborski 		case NV_TYPE_DESCRIPTOR:
47554f98da9SMariusz Zaborski 			dprintf(fd, " %d\n", nvpair_get_descriptor(nvp));
47654f98da9SMariusz Zaborski 			break;
47754f98da9SMariusz Zaborski 		case NV_TYPE_BINARY:
47854f98da9SMariusz Zaborski 		    {
47954f98da9SMariusz Zaborski 			const unsigned char *binary;
48054f98da9SMariusz Zaborski 			unsigned int ii;
48154f98da9SMariusz Zaborski 			size_t size;
48254f98da9SMariusz Zaborski 
48354f98da9SMariusz Zaborski 			binary = nvpair_get_binary(nvp, &size);
48454f98da9SMariusz Zaborski 			dprintf(fd, " %zu ", size);
48554f98da9SMariusz Zaborski 			for (ii = 0; ii < size; ii++)
48654f98da9SMariusz Zaborski 				dprintf(fd, "%02hhx", binary[ii]);
48754f98da9SMariusz Zaborski 			dprintf(fd, "\n");
48854f98da9SMariusz Zaborski 			break;
48954f98da9SMariusz Zaborski 		    }
490347a39b4SMariusz Zaborski 		case NV_TYPE_BOOL_ARRAY:
491347a39b4SMariusz Zaborski 		    {
492347a39b4SMariusz Zaborski 			const bool *value;
493347a39b4SMariusz Zaborski 			unsigned int ii;
494347a39b4SMariusz Zaborski 			size_t nitems;
495347a39b4SMariusz Zaborski 
496347a39b4SMariusz Zaborski 			value = nvpair_get_bool_array(nvp, &nitems);
497347a39b4SMariusz Zaborski 			dprintf(fd, " [ ");
498347a39b4SMariusz Zaborski 			for (ii = 0; ii < nitems; ii++) {
499347a39b4SMariusz Zaborski 				dprintf(fd, "%s", value[ii] ? "TRUE" : "FALSE");
500347a39b4SMariusz Zaborski 				if (ii != nitems - 1)
501347a39b4SMariusz Zaborski 					dprintf(fd, ", ");
502347a39b4SMariusz Zaborski 			}
503347a39b4SMariusz Zaborski 			dprintf(fd, " ]\n");
504347a39b4SMariusz Zaborski 			break;
505347a39b4SMariusz Zaborski 		    }
506347a39b4SMariusz Zaborski 		case NV_TYPE_STRING_ARRAY:
507347a39b4SMariusz Zaborski 		    {
508347a39b4SMariusz Zaborski 			const char * const *value;
509347a39b4SMariusz Zaborski 			unsigned int ii;
510347a39b4SMariusz Zaborski 			size_t nitems;
511347a39b4SMariusz Zaborski 
512347a39b4SMariusz Zaborski 			value = nvpair_get_string_array(nvp, &nitems);
513347a39b4SMariusz Zaborski 			dprintf(fd, " [ ");
514347a39b4SMariusz Zaborski 			for (ii = 0; ii < nitems; ii++) {
515347a39b4SMariusz Zaborski 				if (value[ii] == NULL)
516347a39b4SMariusz Zaborski 					dprintf(fd, "NULL");
517347a39b4SMariusz Zaborski 				else
518347a39b4SMariusz Zaborski 					dprintf(fd, "\"%s\"", value[ii]);
519347a39b4SMariusz Zaborski 				if (ii != nitems - 1)
520347a39b4SMariusz Zaborski 					dprintf(fd, ", ");
521347a39b4SMariusz Zaborski 			}
522347a39b4SMariusz Zaborski 			dprintf(fd, " ]\n");
523347a39b4SMariusz Zaborski 			break;
524347a39b4SMariusz Zaborski 		    }
525347a39b4SMariusz Zaborski 		case NV_TYPE_NUMBER_ARRAY:
526347a39b4SMariusz Zaborski 		    {
527347a39b4SMariusz Zaborski 			const uint64_t *value;
528347a39b4SMariusz Zaborski 			unsigned int ii;
529347a39b4SMariusz Zaborski 			size_t nitems;
530347a39b4SMariusz Zaborski 
531347a39b4SMariusz Zaborski 			value = nvpair_get_number_array(nvp, &nitems);
532347a39b4SMariusz Zaborski 			dprintf(fd, " [ ");
533347a39b4SMariusz Zaborski 			for (ii = 0; ii < nitems; ii++) {
534347a39b4SMariusz Zaborski 				dprintf(fd, "%ju (%jd) (0x%jx)",
535347a39b4SMariusz Zaborski 				    value[ii], value[ii], value[ii]);
536347a39b4SMariusz Zaborski 				if (ii != nitems - 1)
537347a39b4SMariusz Zaborski 					dprintf(fd, ", ");
538347a39b4SMariusz Zaborski 			}
539347a39b4SMariusz Zaborski 			dprintf(fd, " ]\n");
540347a39b4SMariusz Zaborski 			break;
541347a39b4SMariusz Zaborski 		    }
542347a39b4SMariusz Zaborski 		case NV_TYPE_DESCRIPTOR_ARRAY:
543347a39b4SMariusz Zaborski 		    {
544347a39b4SMariusz Zaborski 			const int *value;
545347a39b4SMariusz Zaborski 			unsigned int ii;
546347a39b4SMariusz Zaborski 			size_t nitems;
547347a39b4SMariusz Zaborski 
548347a39b4SMariusz Zaborski 			value = nvpair_get_descriptor_array(nvp, &nitems);
549347a39b4SMariusz Zaborski 			dprintf(fd, " [ ");
550347a39b4SMariusz Zaborski 			for (ii = 0; ii < nitems; ii++) {
551347a39b4SMariusz Zaborski 				dprintf(fd, "%d", value[ii]);
552347a39b4SMariusz Zaborski 				if (ii != nitems - 1)
553347a39b4SMariusz Zaborski 					dprintf(fd, ", ");
554347a39b4SMariusz Zaborski 			}
555347a39b4SMariusz Zaborski 			dprintf(fd, " ]\n");
556347a39b4SMariusz Zaborski 			break;
557347a39b4SMariusz Zaborski 		    }
558347a39b4SMariusz Zaborski 		case NV_TYPE_NVLIST_ARRAY:
559347a39b4SMariusz Zaborski 		    {
560347a39b4SMariusz Zaborski 			const nvlist_t * const *value;
561347a39b4SMariusz Zaborski 			unsigned int ii;
562347a39b4SMariusz Zaborski 			size_t nitems;
563347a39b4SMariusz Zaborski 
564347a39b4SMariusz Zaborski 			value = nvpair_get_nvlist_array(nvp, &nitems);
565347a39b4SMariusz Zaborski 			dprintf(fd, " %zu\n", nitems);
566347a39b4SMariusz Zaborski 			tmpnvl = NULL;
567347a39b4SMariusz Zaborski 			tmpnvp = NULL;
568347a39b4SMariusz Zaborski 			for (ii = 0; ii < nitems; ii++) {
569347a39b4SMariusz Zaborski 				if (nvlist_dump_error_check(value[ii], fd,
570347a39b4SMariusz Zaborski 				    level + 1)) {
571347a39b4SMariusz Zaborski 					break;
572347a39b4SMariusz Zaborski 				}
573347a39b4SMariusz Zaborski 
574347a39b4SMariusz Zaborski 				if (tmpnvl == NULL) {
575347a39b4SMariusz Zaborski 					tmpnvp = nvlist_first_nvpair(value[ii]);
576347a39b4SMariusz Zaborski 					if (tmpnvp != NULL) {
577347a39b4SMariusz Zaborski 						tmpnvl = value[ii];
578347a39b4SMariusz Zaborski 					} else {
579347a39b4SMariusz Zaborski 						dprintf(fd, "%*s,\n",
580347a39b4SMariusz Zaborski 						    (level + 1) * 4, "");
581347a39b4SMariusz Zaborski 					}
582347a39b4SMariusz Zaborski 				}
583347a39b4SMariusz Zaborski 			}
584347a39b4SMariusz Zaborski 			if (tmpnvp != NULL) {
585347a39b4SMariusz Zaborski 				nvl = tmpnvl;
586347a39b4SMariusz Zaborski 				nvp = tmpnvp;
587347a39b4SMariusz Zaborski 				level++;
588347a39b4SMariusz Zaborski 				continue;
589347a39b4SMariusz Zaborski 			}
590347a39b4SMariusz Zaborski 			break;
591347a39b4SMariusz Zaborski 		    }
59254f98da9SMariusz Zaborski 		default:
59354f98da9SMariusz Zaborski 			PJDLOG_ABORT("Unknown type: %d.", nvpair_type(nvp));
59454f98da9SMariusz Zaborski 		}
59554f98da9SMariusz Zaborski 
59654f98da9SMariusz Zaborski 		while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
597347a39b4SMariusz Zaborski 			do {
59854f98da9SMariusz Zaborski 				cookie = NULL;
599347a39b4SMariusz Zaborski 				if (nvlist_in_array(nvl))
600347a39b4SMariusz Zaborski 					dprintf(fd, "%*s,\n", level * 4, "");
601347a39b4SMariusz Zaborski 				nvl = nvlist_get_pararr(nvl, &cookie);
60254f98da9SMariusz Zaborski 				if (nvl == NULL)
60354f98da9SMariusz Zaborski 					return;
604347a39b4SMariusz Zaborski 				if (nvlist_in_array(nvl) && cookie == NULL) {
605347a39b4SMariusz Zaborski 					nvp = nvlist_first_nvpair(nvl);
606347a39b4SMariusz Zaborski 				} else {
60754f98da9SMariusz Zaborski 					nvp = cookie;
60854f98da9SMariusz Zaborski 					level--;
60954f98da9SMariusz Zaborski 				}
610347a39b4SMariusz Zaborski 			} while (nvp == NULL);
611347a39b4SMariusz Zaborski 			if (nvlist_in_array(nvl) && cookie == NULL)
612347a39b4SMariusz Zaborski 				break;
613347a39b4SMariusz Zaborski 		}
61454f98da9SMariusz Zaborski 	}
61554f98da9SMariusz Zaborski }
61654f98da9SMariusz Zaborski 
61754f98da9SMariusz Zaborski void
61854f98da9SMariusz Zaborski nvlist_fdump(const nvlist_t *nvl, FILE *fp)
61954f98da9SMariusz Zaborski {
62054f98da9SMariusz Zaborski 
62154f98da9SMariusz Zaborski 	fflush(fp);
62254f98da9SMariusz Zaborski 	nvlist_dump(nvl, fileno(fp));
62354f98da9SMariusz Zaborski }
62454f98da9SMariusz Zaborski #endif
62554f98da9SMariusz Zaborski 
62654f98da9SMariusz Zaborski /*
62754f98da9SMariusz Zaborski  * The function obtains size of the nvlist after nvlist_pack().
62854f98da9SMariusz Zaborski  */
62954f98da9SMariusz Zaborski size_t
63054f98da9SMariusz Zaborski nvlist_size(const nvlist_t *nvl)
63154f98da9SMariusz Zaborski {
63254f98da9SMariusz Zaborski 	const nvlist_t *tmpnvl;
633347a39b4SMariusz Zaborski 	const nvlist_t * const *nvlarray;
63454f98da9SMariusz Zaborski 	const nvpair_t *nvp, *tmpnvp;
63554f98da9SMariusz Zaborski 	void *cookie;
636347a39b4SMariusz Zaborski 	size_t size, nitems;
637347a39b4SMariusz Zaborski 	unsigned int ii;
63854f98da9SMariusz Zaborski 
63954f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
64054f98da9SMariusz Zaborski 	PJDLOG_ASSERT(nvl->nvl_error == 0);
64154f98da9SMariusz Zaborski 
64254f98da9SMariusz Zaborski 	size = sizeof(struct nvlist_header);
64354f98da9SMariusz Zaborski 	nvp = nvlist_first_nvpair(nvl);
64454f98da9SMariusz Zaborski 	while (nvp != NULL) {
64554f98da9SMariusz Zaborski 		size += nvpair_header_size();
64654f98da9SMariusz Zaborski 		size += strlen(nvpair_name(nvp)) + 1;
64754f98da9SMariusz Zaborski 		if (nvpair_type(nvp) == NV_TYPE_NVLIST) {
64854f98da9SMariusz Zaborski 			size += sizeof(struct nvlist_header);
64954f98da9SMariusz Zaborski 			size += nvpair_header_size() + 1;
65054f98da9SMariusz Zaborski 			tmpnvl = nvpair_get_nvlist(nvp);
65154f98da9SMariusz Zaborski 			PJDLOG_ASSERT(tmpnvl->nvl_error == 0);
65254f98da9SMariusz Zaborski 			tmpnvp = nvlist_first_nvpair(tmpnvl);
65354f98da9SMariusz Zaborski 			if (tmpnvp != NULL) {
65454f98da9SMariusz Zaborski 				nvl = tmpnvl;
65554f98da9SMariusz Zaborski 				nvp = tmpnvp;
65654f98da9SMariusz Zaborski 				continue;
65754f98da9SMariusz Zaborski 			}
658347a39b4SMariusz Zaborski 		} else if (nvpair_type(nvp) == NV_TYPE_NVLIST_ARRAY) {
659347a39b4SMariusz Zaborski 			nvlarray = nvpair_get_nvlist_array(nvp, &nitems);
660347a39b4SMariusz Zaborski 			PJDLOG_ASSERT(nitems > 0);
661347a39b4SMariusz Zaborski 
662347a39b4SMariusz Zaborski 			size += (nvpair_header_size() + 1) * nitems;
663347a39b4SMariusz Zaborski 			size += sizeof(struct nvlist_header) * nitems;
664347a39b4SMariusz Zaborski 
665347a39b4SMariusz Zaborski 			tmpnvl = NULL;
666347a39b4SMariusz Zaborski 			tmpnvp = NULL;
667347a39b4SMariusz Zaborski 			for (ii = 0; ii < nitems; ii++) {
668347a39b4SMariusz Zaborski 				PJDLOG_ASSERT(nvlarray[ii]->nvl_error == 0);
669347a39b4SMariusz Zaborski 				tmpnvp = nvlist_first_nvpair(nvlarray[ii]);
670347a39b4SMariusz Zaborski 				if (tmpnvp != NULL) {
671347a39b4SMariusz Zaborski 					tmpnvl = nvlarray[ii];
672347a39b4SMariusz Zaborski 					break;
673347a39b4SMariusz Zaborski 				}
674347a39b4SMariusz Zaborski 			}
675347a39b4SMariusz Zaborski 			if (tmpnvp != NULL) {
676347a39b4SMariusz Zaborski 				nvp = tmpnvp;
677347a39b4SMariusz Zaborski 				nvl = tmpnvl;
678347a39b4SMariusz Zaborski 				continue;
679347a39b4SMariusz Zaborski 			}
680347a39b4SMariusz Zaborski 
68154f98da9SMariusz Zaborski 		} else {
68254f98da9SMariusz Zaborski 			size += nvpair_size(nvp);
68354f98da9SMariusz Zaborski 		}
68454f98da9SMariusz Zaborski 
68554f98da9SMariusz Zaborski 		while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
686347a39b4SMariusz Zaborski 			do {
68754f98da9SMariusz Zaborski 				cookie = NULL;
688347a39b4SMariusz Zaborski 				nvl = nvlist_get_pararr(nvl, &cookie);
68954f98da9SMariusz Zaborski 				if (nvl == NULL)
69054f98da9SMariusz Zaborski 					goto out;
691347a39b4SMariusz Zaborski 				if (nvlist_in_array(nvl) && cookie == NULL) {
692347a39b4SMariusz Zaborski 					nvp = nvlist_first_nvpair(nvl);
693347a39b4SMariusz Zaborski 				} else {
69454f98da9SMariusz Zaborski 					nvp = cookie;
69554f98da9SMariusz Zaborski 				}
696347a39b4SMariusz Zaborski 			} while (nvp == NULL);
697347a39b4SMariusz Zaborski 			if (nvlist_in_array(nvl) && cookie == NULL)
698347a39b4SMariusz Zaborski 				break;
699347a39b4SMariusz Zaborski 		}
70054f98da9SMariusz Zaborski 	}
70154f98da9SMariusz Zaborski 
70254f98da9SMariusz Zaborski out:
70354f98da9SMariusz Zaborski 	return (size);
70454f98da9SMariusz Zaborski }
70554f98da9SMariusz Zaborski 
70654f98da9SMariusz Zaborski #ifndef _KERNEL
70754f98da9SMariusz Zaborski static int *
70854f98da9SMariusz Zaborski nvlist_xdescriptors(const nvlist_t *nvl, int *descs)
70954f98da9SMariusz Zaborski {
71054f98da9SMariusz Zaborski 	nvpair_t *nvp;
71154f98da9SMariusz Zaborski 	int type;
71254f98da9SMariusz Zaborski 
71354f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
71454f98da9SMariusz Zaborski 	PJDLOG_ASSERT(nvl->nvl_error == 0);
71554f98da9SMariusz Zaborski 
71654f98da9SMariusz Zaborski 	nvp = NULL;
71754f98da9SMariusz Zaborski 	do {
71808016b31SMariusz Zaborski 		while (nvlist_next(nvl, &type, (void *)&nvp) != NULL) {
71954f98da9SMariusz Zaborski 			switch (type) {
72054f98da9SMariusz Zaborski 			case NV_TYPE_DESCRIPTOR:
72154f98da9SMariusz Zaborski 				*descs = nvpair_get_descriptor(nvp);
72254f98da9SMariusz Zaborski 				descs++;
72354f98da9SMariusz Zaborski 				break;
724347a39b4SMariusz Zaborski 			case NV_TYPE_DESCRIPTOR_ARRAY:
725347a39b4SMariusz Zaborski 			    {
726347a39b4SMariusz Zaborski 				const int *value;
727347a39b4SMariusz Zaborski 				size_t nitems;
728347a39b4SMariusz Zaborski 				unsigned int ii;
729347a39b4SMariusz Zaborski 
730347a39b4SMariusz Zaborski 				value = nvpair_get_descriptor_array(nvp,
731347a39b4SMariusz Zaborski 				    &nitems);
732347a39b4SMariusz Zaborski 				for (ii = 0; ii < nitems; ii++) {
733347a39b4SMariusz Zaborski 					*descs = value[ii];
734347a39b4SMariusz Zaborski 					descs++;
735347a39b4SMariusz Zaborski 				}
736347a39b4SMariusz Zaborski 				break;
737347a39b4SMariusz Zaborski 			    }
73854f98da9SMariusz Zaborski 			case NV_TYPE_NVLIST:
73954f98da9SMariusz Zaborski 				nvl = nvpair_get_nvlist(nvp);
74054f98da9SMariusz Zaborski 				nvp = NULL;
74154f98da9SMariusz Zaborski 				break;
742347a39b4SMariusz Zaborski 			case NV_TYPE_NVLIST_ARRAY:
743347a39b4SMariusz Zaborski 			    {
744347a39b4SMariusz Zaborski 				const nvlist_t * const *value;
745347a39b4SMariusz Zaborski 				size_t nitems;
746347a39b4SMariusz Zaborski 
747347a39b4SMariusz Zaborski 				value = nvpair_get_nvlist_array(nvp, &nitems);
748347a39b4SMariusz Zaborski 				PJDLOG_ASSERT(value != NULL);
749347a39b4SMariusz Zaborski 				PJDLOG_ASSERT(nitems > 0);
750347a39b4SMariusz Zaborski 
751347a39b4SMariusz Zaborski 				nvl = value[0];
752347a39b4SMariusz Zaborski 				nvp = NULL;
753347a39b4SMariusz Zaborski 				break;
75454f98da9SMariusz Zaborski 			    }
75554f98da9SMariusz Zaborski 			}
756347a39b4SMariusz Zaborski 		}
75708016b31SMariusz Zaborski 	} while ((nvl = nvlist_get_pararr(nvl, (void *)&nvp)) != NULL);
75854f98da9SMariusz Zaborski 
75954f98da9SMariusz Zaborski 	return (descs);
76054f98da9SMariusz Zaborski }
76154f98da9SMariusz Zaborski #endif
76254f98da9SMariusz Zaborski 
76354f98da9SMariusz Zaborski #ifndef _KERNEL
76454f98da9SMariusz Zaborski int *
76554f98da9SMariusz Zaborski nvlist_descriptors(const nvlist_t *nvl, size_t *nitemsp)
76654f98da9SMariusz Zaborski {
76754f98da9SMariusz Zaborski 	size_t nitems;
76854f98da9SMariusz Zaborski 	int *fds;
76954f98da9SMariusz Zaborski 
77054f98da9SMariusz Zaborski 	nitems = nvlist_ndescriptors(nvl);
77154f98da9SMariusz Zaborski 	fds = nv_malloc(sizeof(fds[0]) * (nitems + 1));
77254f98da9SMariusz Zaborski 	if (fds == NULL)
77354f98da9SMariusz Zaborski 		return (NULL);
77454f98da9SMariusz Zaborski 	if (nitems > 0)
77554f98da9SMariusz Zaborski 		nvlist_xdescriptors(nvl, fds);
77654f98da9SMariusz Zaborski 	fds[nitems] = -1;
77754f98da9SMariusz Zaborski 	if (nitemsp != NULL)
77854f98da9SMariusz Zaborski 		*nitemsp = nitems;
77954f98da9SMariusz Zaborski 	return (fds);
78054f98da9SMariusz Zaborski }
78154f98da9SMariusz Zaborski #endif
78254f98da9SMariusz Zaborski 
78354f98da9SMariusz Zaborski size_t
78454f98da9SMariusz Zaborski nvlist_ndescriptors(const nvlist_t *nvl)
78554f98da9SMariusz Zaborski {
78654f98da9SMariusz Zaborski #ifndef _KERNEL
78754f98da9SMariusz Zaborski 	nvpair_t *nvp;
78854f98da9SMariusz Zaborski 	size_t ndescs;
78954f98da9SMariusz Zaborski 	int type;
79054f98da9SMariusz Zaborski 
79154f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
79254f98da9SMariusz Zaborski 	PJDLOG_ASSERT(nvl->nvl_error == 0);
79354f98da9SMariusz Zaborski 
79454f98da9SMariusz Zaborski 	ndescs = 0;
79554f98da9SMariusz Zaborski 	nvp = NULL;
79654f98da9SMariusz Zaborski 	do {
79708016b31SMariusz Zaborski 		while (nvlist_next(nvl, &type, (void *)&nvp) != NULL) {
79854f98da9SMariusz Zaborski 			switch (type) {
79954f98da9SMariusz Zaborski 			case NV_TYPE_DESCRIPTOR:
80054f98da9SMariusz Zaborski 				ndescs++;
80154f98da9SMariusz Zaborski 				break;
80254f98da9SMariusz Zaborski 			case NV_TYPE_NVLIST:
80354f98da9SMariusz Zaborski 				nvl = nvpair_get_nvlist(nvp);
80454f98da9SMariusz Zaborski 				nvp = NULL;
80554f98da9SMariusz Zaborski 				break;
806347a39b4SMariusz Zaborski 			case NV_TYPE_NVLIST_ARRAY:
807347a39b4SMariusz Zaborski 			    {
808347a39b4SMariusz Zaborski 				const nvlist_t * const *value;
809347a39b4SMariusz Zaborski 				size_t nitems;
810347a39b4SMariusz Zaborski 
811347a39b4SMariusz Zaborski 				value = nvpair_get_nvlist_array(nvp, &nitems);
812347a39b4SMariusz Zaborski 				PJDLOG_ASSERT(value != NULL);
813347a39b4SMariusz Zaborski 				PJDLOG_ASSERT(nitems > 0);
814347a39b4SMariusz Zaborski 
815347a39b4SMariusz Zaborski 				nvl = value[0];
816347a39b4SMariusz Zaborski 				nvp = NULL;
817347a39b4SMariusz Zaborski 				break;
818347a39b4SMariusz Zaborski 			    }
819347a39b4SMariusz Zaborski 			case NV_TYPE_DESCRIPTOR_ARRAY:
820347a39b4SMariusz Zaborski 			    {
821347a39b4SMariusz Zaborski 				size_t nitems;
822347a39b4SMariusz Zaborski 
823347a39b4SMariusz Zaborski 				(void)nvpair_get_descriptor_array(nvp,
824347a39b4SMariusz Zaborski 				    &nitems);
825347a39b4SMariusz Zaborski 				ndescs += nitems;
826347a39b4SMariusz Zaborski 				break;
82754f98da9SMariusz Zaborski 			    }
82854f98da9SMariusz Zaborski 			}
829347a39b4SMariusz Zaborski 		}
83008016b31SMariusz Zaborski 	} while ((nvl = nvlist_get_pararr(nvl, (void *)&nvp)) != NULL);
83154f98da9SMariusz Zaborski 
83254f98da9SMariusz Zaborski 	return (ndescs);
83354f98da9SMariusz Zaborski #else
83454f98da9SMariusz Zaborski 	return (0);
83554f98da9SMariusz Zaborski #endif
83654f98da9SMariusz Zaborski }
83754f98da9SMariusz Zaborski 
83854f98da9SMariusz Zaborski static unsigned char *
83954f98da9SMariusz Zaborski nvlist_pack_header(const nvlist_t *nvl, unsigned char *ptr, size_t *leftp)
84054f98da9SMariusz Zaborski {
84154f98da9SMariusz Zaborski 	struct nvlist_header nvlhdr;
84254f98da9SMariusz Zaborski 
84354f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
84454f98da9SMariusz Zaborski 
84554f98da9SMariusz Zaborski 	nvlhdr.nvlh_magic = NVLIST_HEADER_MAGIC;
84654f98da9SMariusz Zaborski 	nvlhdr.nvlh_version = NVLIST_HEADER_VERSION;
84754f98da9SMariusz Zaborski 	nvlhdr.nvlh_flags = nvl->nvl_flags;
84854f98da9SMariusz Zaborski #if BYTE_ORDER == BIG_ENDIAN
84954f98da9SMariusz Zaborski 	nvlhdr.nvlh_flags |= NV_FLAG_BIG_ENDIAN;
85054f98da9SMariusz Zaborski #endif
85154f98da9SMariusz Zaborski 	nvlhdr.nvlh_descriptors = nvlist_ndescriptors(nvl);
85254f98da9SMariusz Zaborski 	nvlhdr.nvlh_size = *leftp - sizeof(nvlhdr);
85354f98da9SMariusz Zaborski 	PJDLOG_ASSERT(*leftp >= sizeof(nvlhdr));
85454f98da9SMariusz Zaborski 	memcpy(ptr, &nvlhdr, sizeof(nvlhdr));
85554f98da9SMariusz Zaborski 	ptr += sizeof(nvlhdr);
85654f98da9SMariusz Zaborski 	*leftp -= sizeof(nvlhdr);
85754f98da9SMariusz Zaborski 
85854f98da9SMariusz Zaborski 	return (ptr);
85954f98da9SMariusz Zaborski }
86054f98da9SMariusz Zaborski 
86154f98da9SMariusz Zaborski static void *
86254f98da9SMariusz Zaborski nvlist_xpack(const nvlist_t *nvl, int64_t *fdidxp, size_t *sizep)
86354f98da9SMariusz Zaborski {
86454f98da9SMariusz Zaborski 	unsigned char *buf, *ptr;
86554f98da9SMariusz Zaborski 	size_t left, size;
86654f98da9SMariusz Zaborski 	const nvlist_t *tmpnvl;
86754f98da9SMariusz Zaborski 	nvpair_t *nvp, *tmpnvp;
86854f98da9SMariusz Zaborski 	void *cookie;
86954f98da9SMariusz Zaborski 
87054f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
87154f98da9SMariusz Zaborski 
87254f98da9SMariusz Zaborski 	if (nvl->nvl_error != 0) {
87354f98da9SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
87454f98da9SMariusz Zaborski 		return (NULL);
87554f98da9SMariusz Zaborski 	}
87654f98da9SMariusz Zaborski 
87754f98da9SMariusz Zaborski 	size = nvlist_size(nvl);
87854f98da9SMariusz Zaborski 	buf = nv_malloc(size);
87954f98da9SMariusz Zaborski 	if (buf == NULL)
88054f98da9SMariusz Zaborski 		return (NULL);
88154f98da9SMariusz Zaborski 
88254f98da9SMariusz Zaborski 	ptr = buf;
88354f98da9SMariusz Zaborski 	left = size;
88454f98da9SMariusz Zaborski 
88554f98da9SMariusz Zaborski 	ptr = nvlist_pack_header(nvl, ptr, &left);
88654f98da9SMariusz Zaborski 
88754f98da9SMariusz Zaborski 	nvp = nvlist_first_nvpair(nvl);
88854f98da9SMariusz Zaborski 	while (nvp != NULL) {
88954f98da9SMariusz Zaborski 		NVPAIR_ASSERT(nvp);
89054f98da9SMariusz Zaborski 
89154f98da9SMariusz Zaborski 		nvpair_init_datasize(nvp);
89254f98da9SMariusz Zaborski 		ptr = nvpair_pack_header(nvp, ptr, &left);
893c68f8061SMariusz Zaborski 		if (ptr == NULL)
894c68f8061SMariusz Zaborski 			goto fail;
89554f98da9SMariusz Zaborski 		switch (nvpair_type(nvp)) {
89654f98da9SMariusz Zaborski 		case NV_TYPE_NULL:
89754f98da9SMariusz Zaborski 			ptr = nvpair_pack_null(nvp, ptr, &left);
89854f98da9SMariusz Zaborski 			break;
89954f98da9SMariusz Zaborski 		case NV_TYPE_BOOL:
90054f98da9SMariusz Zaborski 			ptr = nvpair_pack_bool(nvp, ptr, &left);
90154f98da9SMariusz Zaborski 			break;
90254f98da9SMariusz Zaborski 		case NV_TYPE_NUMBER:
90354f98da9SMariusz Zaborski 			ptr = nvpair_pack_number(nvp, ptr, &left);
90454f98da9SMariusz Zaborski 			break;
90554f98da9SMariusz Zaborski 		case NV_TYPE_STRING:
90654f98da9SMariusz Zaborski 			ptr = nvpair_pack_string(nvp, ptr, &left);
90754f98da9SMariusz Zaborski 			break;
90854f98da9SMariusz Zaborski 		case NV_TYPE_NVLIST:
90954f98da9SMariusz Zaborski 			tmpnvl = nvpair_get_nvlist(nvp);
91054f98da9SMariusz Zaborski 			ptr = nvlist_pack_header(tmpnvl, ptr, &left);
91154f98da9SMariusz Zaborski 			if (ptr == NULL)
912c68f8061SMariusz Zaborski 				goto fail;
91354f98da9SMariusz Zaborski 			tmpnvp = nvlist_first_nvpair(tmpnvl);
91454f98da9SMariusz Zaborski 			if (tmpnvp != NULL) {
91554f98da9SMariusz Zaborski 				nvl = tmpnvl;
91654f98da9SMariusz Zaborski 				nvp = tmpnvp;
91754f98da9SMariusz Zaborski 				continue;
91854f98da9SMariusz Zaborski 			}
91954f98da9SMariusz Zaborski 			ptr = nvpair_pack_nvlist_up(ptr, &left);
92054f98da9SMariusz Zaborski 			break;
92154f98da9SMariusz Zaborski #ifndef _KERNEL
92254f98da9SMariusz Zaborski 		case NV_TYPE_DESCRIPTOR:
92354f98da9SMariusz Zaborski 			ptr = nvpair_pack_descriptor(nvp, ptr, fdidxp, &left);
92454f98da9SMariusz Zaborski 			break;
925347a39b4SMariusz Zaborski 		case NV_TYPE_DESCRIPTOR_ARRAY:
926347a39b4SMariusz Zaborski 			ptr = nvpair_pack_descriptor_array(nvp, ptr, fdidxp,
927347a39b4SMariusz Zaborski 			    &left);
928347a39b4SMariusz Zaborski 			break;
92954f98da9SMariusz Zaborski #endif
93054f98da9SMariusz Zaborski 		case NV_TYPE_BINARY:
93154f98da9SMariusz Zaborski 			ptr = nvpair_pack_binary(nvp, ptr, &left);
93254f98da9SMariusz Zaborski 			break;
933347a39b4SMariusz Zaborski 		case NV_TYPE_BOOL_ARRAY:
934347a39b4SMariusz Zaborski 			ptr = nvpair_pack_bool_array(nvp, ptr, &left);
935347a39b4SMariusz Zaborski 			break;
936347a39b4SMariusz Zaborski 		case NV_TYPE_NUMBER_ARRAY:
937347a39b4SMariusz Zaborski 			ptr = nvpair_pack_number_array(nvp, ptr, &left);
938347a39b4SMariusz Zaborski 			break;
939347a39b4SMariusz Zaborski 		case NV_TYPE_STRING_ARRAY:
940347a39b4SMariusz Zaborski 			ptr = nvpair_pack_string_array(nvp, ptr, &left);
941347a39b4SMariusz Zaborski 			break;
942347a39b4SMariusz Zaborski 		case NV_TYPE_NVLIST_ARRAY:
943347a39b4SMariusz Zaborski 		    {
944347a39b4SMariusz Zaborski 			const nvlist_t * const * value;
945347a39b4SMariusz Zaborski 			size_t nitems;
946347a39b4SMariusz Zaborski 			unsigned int ii;
947347a39b4SMariusz Zaborski 
948347a39b4SMariusz Zaborski 			tmpnvl = NULL;
949347a39b4SMariusz Zaborski 			value = nvpair_get_nvlist_array(nvp, &nitems);
950347a39b4SMariusz Zaborski 			for (ii = 0; ii < nitems; ii++) {
951347a39b4SMariusz Zaborski 				ptr = nvlist_pack_header(value[ii], ptr, &left);
952347a39b4SMariusz Zaborski 				if (ptr == NULL)
953347a39b4SMariusz Zaborski 					goto out;
954347a39b4SMariusz Zaborski 				tmpnvp = nvlist_first_nvpair(value[ii]);
955347a39b4SMariusz Zaborski 				if (tmpnvp != NULL) {
956347a39b4SMariusz Zaborski 					tmpnvl = value[ii];
957347a39b4SMariusz Zaborski 					break;
958347a39b4SMariusz Zaborski 				}
959347a39b4SMariusz Zaborski 				ptr = nvpair_pack_nvlist_array_next(ptr, &left);
960347a39b4SMariusz Zaborski 				if (ptr == NULL)
961347a39b4SMariusz Zaborski 					goto out;
962347a39b4SMariusz Zaborski 			}
963347a39b4SMariusz Zaborski 			if (tmpnvl != NULL) {
964347a39b4SMariusz Zaborski 				nvl = tmpnvl;
965347a39b4SMariusz Zaborski 				nvp = tmpnvp;
966347a39b4SMariusz Zaborski 				continue;
967347a39b4SMariusz Zaborski 			}
968347a39b4SMariusz Zaborski 			break;
969347a39b4SMariusz Zaborski 		    }
97054f98da9SMariusz Zaborski 		default:
97154f98da9SMariusz Zaborski 			PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp));
97254f98da9SMariusz Zaborski 		}
973c68f8061SMariusz Zaborski 		if (ptr == NULL)
974c68f8061SMariusz Zaborski 			goto fail;
97554f98da9SMariusz Zaborski 		while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
976347a39b4SMariusz Zaborski 			do {
97754f98da9SMariusz Zaborski 				cookie = NULL;
978347a39b4SMariusz Zaborski 				if (nvlist_in_array(nvl)) {
979347a39b4SMariusz Zaborski 					ptr = nvpair_pack_nvlist_array_next(ptr,
980347a39b4SMariusz Zaborski 					    &left);
981347a39b4SMariusz Zaborski 					if (ptr == NULL)
982347a39b4SMariusz Zaborski 						goto fail;
983347a39b4SMariusz Zaborski 				}
984347a39b4SMariusz Zaborski 				nvl = nvlist_get_pararr(nvl, &cookie);
98554f98da9SMariusz Zaborski 				if (nvl == NULL)
98654f98da9SMariusz Zaborski 					goto out;
987347a39b4SMariusz Zaborski 				if (nvlist_in_array(nvl) && cookie == NULL) {
988347a39b4SMariusz Zaborski 					nvp = nvlist_first_nvpair(nvl);
989347a39b4SMariusz Zaborski 					ptr = nvlist_pack_header(nvl, ptr,
990347a39b4SMariusz Zaborski 					    &left);
991347a39b4SMariusz Zaborski 					if (ptr == NULL)
992347a39b4SMariusz Zaborski 						goto fail;
993347a39b4SMariusz Zaborski 				} else if (nvpair_type((nvpair_t *)cookie) !=
994347a39b4SMariusz Zaborski 				    NV_TYPE_NVLIST_ARRAY) {
99554f98da9SMariusz Zaborski 					ptr = nvpair_pack_nvlist_up(ptr, &left);
99654f98da9SMariusz Zaborski 					if (ptr == NULL)
997c68f8061SMariusz Zaborski 						goto fail;
998347a39b4SMariusz Zaborski 					nvp = cookie;
999347a39b4SMariusz Zaborski 				} else {
1000347a39b4SMariusz Zaborski 					nvp = cookie;
1001347a39b4SMariusz Zaborski 				}
1002347a39b4SMariusz Zaborski 			} while (nvp == NULL);
1003347a39b4SMariusz Zaborski 			if (nvlist_in_array(nvl) && cookie == NULL)
1004347a39b4SMariusz Zaborski 				break;
100554f98da9SMariusz Zaborski 		}
100654f98da9SMariusz Zaborski 	}
100754f98da9SMariusz Zaborski 
100854f98da9SMariusz Zaborski out:
100954f98da9SMariusz Zaborski 	if (sizep != NULL)
101054f98da9SMariusz Zaborski 		*sizep = size;
101154f98da9SMariusz Zaborski 	return (buf);
1012c68f8061SMariusz Zaborski fail:
1013c68f8061SMariusz Zaborski 	nv_free(buf);
1014c68f8061SMariusz Zaborski 	return (NULL);
101554f98da9SMariusz Zaborski }
101654f98da9SMariusz Zaborski 
101754f98da9SMariusz Zaborski void *
101854f98da9SMariusz Zaborski nvlist_pack(const nvlist_t *nvl, size_t *sizep)
101954f98da9SMariusz Zaborski {
102054f98da9SMariusz Zaborski 
102154f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
102254f98da9SMariusz Zaborski 
102354f98da9SMariusz Zaborski 	if (nvl->nvl_error != 0) {
102454f98da9SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
102554f98da9SMariusz Zaborski 		return (NULL);
102654f98da9SMariusz Zaborski 	}
102754f98da9SMariusz Zaborski 
102854f98da9SMariusz Zaborski 	if (nvlist_ndescriptors(nvl) > 0) {
102954f98da9SMariusz Zaborski 		ERRNO_SET(EOPNOTSUPP);
103054f98da9SMariusz Zaborski 		return (NULL);
103154f98da9SMariusz Zaborski 	}
103254f98da9SMariusz Zaborski 
103354f98da9SMariusz Zaborski 	return (nvlist_xpack(nvl, NULL, sizep));
103454f98da9SMariusz Zaborski }
103554f98da9SMariusz Zaborski 
103654f98da9SMariusz Zaborski static bool
103754f98da9SMariusz Zaborski nvlist_check_header(struct nvlist_header *nvlhdrp)
103854f98da9SMariusz Zaborski {
103954f98da9SMariusz Zaborski 
104054f98da9SMariusz Zaborski 	if (nvlhdrp->nvlh_magic != NVLIST_HEADER_MAGIC) {
104154f98da9SMariusz Zaborski 		ERRNO_SET(EINVAL);
104254f98da9SMariusz Zaborski 		return (false);
104354f98da9SMariusz Zaborski 	}
104454f98da9SMariusz Zaborski 	if ((nvlhdrp->nvlh_flags & ~NV_FLAG_ALL_MASK) != 0) {
104554f98da9SMariusz Zaborski 		ERRNO_SET(EINVAL);
104654f98da9SMariusz Zaborski 		return (false);
104754f98da9SMariusz Zaborski 	}
104854f98da9SMariusz Zaborski #if BYTE_ORDER == BIG_ENDIAN
104954f98da9SMariusz Zaborski 	if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) == 0) {
105054f98da9SMariusz Zaborski 		nvlhdrp->nvlh_size = le64toh(nvlhdrp->nvlh_size);
105154f98da9SMariusz Zaborski 		nvlhdrp->nvlh_descriptors = le64toh(nvlhdrp->nvlh_descriptors);
105254f98da9SMariusz Zaborski 	}
105354f98da9SMariusz Zaborski #else
105454f98da9SMariusz Zaborski 	if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0) {
105554f98da9SMariusz Zaborski 		nvlhdrp->nvlh_size = be64toh(nvlhdrp->nvlh_size);
105654f98da9SMariusz Zaborski 		nvlhdrp->nvlh_descriptors = be64toh(nvlhdrp->nvlh_descriptors);
105754f98da9SMariusz Zaborski 	}
105854f98da9SMariusz Zaborski #endif
105954f98da9SMariusz Zaborski 	return (true);
106054f98da9SMariusz Zaborski }
106154f98da9SMariusz Zaborski 
106254f98da9SMariusz Zaborski const unsigned char *
106354f98da9SMariusz Zaborski nvlist_unpack_header(nvlist_t *nvl, const unsigned char *ptr, size_t nfds,
106454f98da9SMariusz Zaborski     bool *isbep, size_t *leftp)
106554f98da9SMariusz Zaborski {
106654f98da9SMariusz Zaborski 	struct nvlist_header nvlhdr;
1067347a39b4SMariusz Zaborski 	int inarrayf;
106854f98da9SMariusz Zaborski 
106954f98da9SMariusz Zaborski 	if (*leftp < sizeof(nvlhdr))
107054f98da9SMariusz Zaborski 		goto failed;
107154f98da9SMariusz Zaborski 
107254f98da9SMariusz Zaborski 	memcpy(&nvlhdr, ptr, sizeof(nvlhdr));
107354f98da9SMariusz Zaborski 
107454f98da9SMariusz Zaborski 	if (!nvlist_check_header(&nvlhdr))
107554f98da9SMariusz Zaborski 		goto failed;
107654f98da9SMariusz Zaborski 
107754f98da9SMariusz Zaborski 	if (nvlhdr.nvlh_size != *leftp - sizeof(nvlhdr))
107854f98da9SMariusz Zaborski 		goto failed;
107954f98da9SMariusz Zaborski 
108054f98da9SMariusz Zaborski 	/*
108154f98da9SMariusz Zaborski 	 * nvlh_descriptors might be smaller than nfds in embedded nvlists.
108254f98da9SMariusz Zaborski 	 */
108354f98da9SMariusz Zaborski 	if (nvlhdr.nvlh_descriptors > nfds)
108454f98da9SMariusz Zaborski 		goto failed;
108554f98da9SMariusz Zaborski 
108654f98da9SMariusz Zaborski 	if ((nvlhdr.nvlh_flags & ~NV_FLAG_ALL_MASK) != 0)
108754f98da9SMariusz Zaborski 		goto failed;
108854f98da9SMariusz Zaborski 
1089347a39b4SMariusz Zaborski 	inarrayf = (nvl->nvl_flags & NV_FLAG_IN_ARRAY);
1090347a39b4SMariusz Zaborski 	nvl->nvl_flags = (nvlhdr.nvlh_flags & NV_FLAG_PUBLIC_MASK) | inarrayf;
109154f98da9SMariusz Zaborski 
109254f98da9SMariusz Zaborski 	ptr += sizeof(nvlhdr);
109354f98da9SMariusz Zaborski 	if (isbep != NULL)
109454f98da9SMariusz Zaborski 		*isbep = (((int)nvlhdr.nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0);
109554f98da9SMariusz Zaborski 	*leftp -= sizeof(nvlhdr);
109654f98da9SMariusz Zaborski 
109754f98da9SMariusz Zaborski 	return (ptr);
109854f98da9SMariusz Zaborski failed:
109954f98da9SMariusz Zaborski 	ERRNO_SET(EINVAL);
110054f98da9SMariusz Zaborski 	return (NULL);
110154f98da9SMariusz Zaborski }
110254f98da9SMariusz Zaborski 
110354f98da9SMariusz Zaborski static nvlist_t *
110454f98da9SMariusz Zaborski nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds,
110554f98da9SMariusz Zaborski     int flags)
110654f98da9SMariusz Zaborski {
110754f98da9SMariusz Zaborski 	const unsigned char *ptr;
1108347a39b4SMariusz Zaborski 	nvlist_t *nvl, *retnvl, *tmpnvl, *array;
110954f98da9SMariusz Zaborski 	nvpair_t *nvp;
111054f98da9SMariusz Zaborski 	size_t left;
111154f98da9SMariusz Zaborski 	bool isbe;
111254f98da9SMariusz Zaborski 
111354f98da9SMariusz Zaborski 	PJDLOG_ASSERT((flags & ~(NV_FLAG_PUBLIC_MASK)) == 0);
111454f98da9SMariusz Zaborski 
111554f98da9SMariusz Zaborski 	left = size;
111654f98da9SMariusz Zaborski 	ptr = buf;
111754f98da9SMariusz Zaborski 
1118347a39b4SMariusz Zaborski 	tmpnvl = array = NULL;
111954f98da9SMariusz Zaborski 	nvl = retnvl = nvlist_create(0);
112054f98da9SMariusz Zaborski 	if (nvl == NULL)
112154f98da9SMariusz Zaborski 		goto failed;
112254f98da9SMariusz Zaborski 
112354f98da9SMariusz Zaborski 	ptr = nvlist_unpack_header(nvl, ptr, nfds, &isbe, &left);
112454f98da9SMariusz Zaborski 	if (ptr == NULL)
112554f98da9SMariusz Zaborski 		goto failed;
112654f98da9SMariusz Zaborski 	if (nvl->nvl_flags != flags) {
112754f98da9SMariusz Zaborski 		ERRNO_SET(EILSEQ);
112854f98da9SMariusz Zaborski 		goto failed;
112954f98da9SMariusz Zaborski 	}
113054f98da9SMariusz Zaborski 
113154f98da9SMariusz Zaborski 	while (left > 0) {
113254f98da9SMariusz Zaborski 		ptr = nvpair_unpack(isbe, ptr, &left, &nvp);
113354f98da9SMariusz Zaborski 		if (ptr == NULL)
113454f98da9SMariusz Zaborski 			goto failed;
113554f98da9SMariusz Zaborski 		switch (nvpair_type(nvp)) {
113654f98da9SMariusz Zaborski 		case NV_TYPE_NULL:
113754f98da9SMariusz Zaborski 			ptr = nvpair_unpack_null(isbe, nvp, ptr, &left);
113854f98da9SMariusz Zaborski 			break;
113954f98da9SMariusz Zaborski 		case NV_TYPE_BOOL:
114054f98da9SMariusz Zaborski 			ptr = nvpair_unpack_bool(isbe, nvp, ptr, &left);
114154f98da9SMariusz Zaborski 			break;
114254f98da9SMariusz Zaborski 		case NV_TYPE_NUMBER:
114354f98da9SMariusz Zaborski 			ptr = nvpair_unpack_number(isbe, nvp, ptr, &left);
114454f98da9SMariusz Zaborski 			break;
114554f98da9SMariusz Zaborski 		case NV_TYPE_STRING:
114654f98da9SMariusz Zaborski 			ptr = nvpair_unpack_string(isbe, nvp, ptr, &left);
114754f98da9SMariusz Zaborski 			break;
114854f98da9SMariusz Zaborski 		case NV_TYPE_NVLIST:
114954f98da9SMariusz Zaborski 			ptr = nvpair_unpack_nvlist(isbe, nvp, ptr, &left, nfds,
115054f98da9SMariusz Zaborski 			    &tmpnvl);
115151dae13fSMariusz Zaborski 			if (tmpnvl == NULL || ptr == NULL)
115251dae13fSMariusz Zaborski 				goto failed;
115354f98da9SMariusz Zaborski 			nvlist_set_parent(tmpnvl, nvp);
115454f98da9SMariusz Zaborski 			break;
115554f98da9SMariusz Zaborski #ifndef _KERNEL
115654f98da9SMariusz Zaborski 		case NV_TYPE_DESCRIPTOR:
115754f98da9SMariusz Zaborski 			ptr = nvpair_unpack_descriptor(isbe, nvp, ptr, &left,
115854f98da9SMariusz Zaborski 			    fds, nfds);
115954f98da9SMariusz Zaborski 			break;
1160347a39b4SMariusz Zaborski 		case NV_TYPE_DESCRIPTOR_ARRAY:
1161347a39b4SMariusz Zaborski 			ptr = nvpair_unpack_descriptor_array(isbe, nvp, ptr,
1162347a39b4SMariusz Zaborski 			    &left, fds, nfds);
1163347a39b4SMariusz Zaborski 			break;
116454f98da9SMariusz Zaborski #endif
116554f98da9SMariusz Zaborski 		case NV_TYPE_BINARY:
116654f98da9SMariusz Zaborski 			ptr = nvpair_unpack_binary(isbe, nvp, ptr, &left);
116754f98da9SMariusz Zaborski 			break;
116854f98da9SMariusz Zaborski 		case NV_TYPE_NVLIST_UP:
116954f98da9SMariusz Zaborski 			if (nvl->nvl_parent == NULL)
117054f98da9SMariusz Zaborski 				goto failed;
117154f98da9SMariusz Zaborski 			nvl = nvpair_nvlist(nvl->nvl_parent);
117254f98da9SMariusz Zaborski 			nvpair_free_structure(nvp);
117354f98da9SMariusz Zaborski 			continue;
1174347a39b4SMariusz Zaborski 		case NV_TYPE_NVLIST_ARRAY_NEXT:
1175347a39b4SMariusz Zaborski 			if (nvl->nvl_array_next == NULL) {
1176347a39b4SMariusz Zaborski 				if (nvl->nvl_parent == NULL)
1177347a39b4SMariusz Zaborski 					goto failed;
1178347a39b4SMariusz Zaborski 				nvl = nvpair_nvlist(nvl->nvl_parent);
1179347a39b4SMariusz Zaborski 			} else {
1180347a39b4SMariusz Zaborski 				nvl = __DECONST(nvlist_t *,
1181347a39b4SMariusz Zaborski 				    nvlist_get_array_next(nvl));
1182347a39b4SMariusz Zaborski 				ptr = nvlist_unpack_header(nvl, ptr, nfds,
1183347a39b4SMariusz Zaborski 				    &isbe, &left);
1184347a39b4SMariusz Zaborski 				if (ptr == NULL)
1185347a39b4SMariusz Zaborski 					goto failed;
1186347a39b4SMariusz Zaborski 			}
1187347a39b4SMariusz Zaborski 			nvpair_free_structure(nvp);
1188347a39b4SMariusz Zaborski 			continue;
1189347a39b4SMariusz Zaborski 		case NV_TYPE_BOOL_ARRAY:
1190347a39b4SMariusz Zaborski 			ptr = nvpair_unpack_bool_array(isbe, nvp, ptr, &left);
1191347a39b4SMariusz Zaborski 			break;
1192347a39b4SMariusz Zaborski 		case NV_TYPE_NUMBER_ARRAY:
1193347a39b4SMariusz Zaborski 			ptr = nvpair_unpack_number_array(isbe, nvp, ptr, &left);
1194347a39b4SMariusz Zaborski 			break;
1195347a39b4SMariusz Zaborski 		case NV_TYPE_STRING_ARRAY:
1196347a39b4SMariusz Zaborski 			ptr = nvpair_unpack_string_array(isbe, nvp, ptr, &left);
1197347a39b4SMariusz Zaborski 			break;
1198347a39b4SMariusz Zaborski 		case NV_TYPE_NVLIST_ARRAY:
1199347a39b4SMariusz Zaborski 			ptr = nvpair_unpack_nvlist_array(isbe, nvp, ptr, &left,
1200347a39b4SMariusz Zaborski 			    &array);
1201347a39b4SMariusz Zaborski 			if (ptr == NULL)
1202347a39b4SMariusz Zaborski 				goto failed;
12031dacabe1SMariusz Zaborski 			PJDLOG_ASSERT(array != NULL);
1204347a39b4SMariusz Zaborski 			tmpnvl = array;
12051dacabe1SMariusz Zaborski 			do {
1206347a39b4SMariusz Zaborski 				nvlist_set_parent(array, nvp);
1207347a39b4SMariusz Zaborski 				array = __DECONST(nvlist_t *,
1208347a39b4SMariusz Zaborski 				    nvlist_get_array_next(array));
12091dacabe1SMariusz Zaborski 			} while (array != NULL);
1210347a39b4SMariusz Zaborski 			ptr = nvlist_unpack_header(tmpnvl, ptr, nfds, &isbe,
1211347a39b4SMariusz Zaborski 			    &left);
1212347a39b4SMariusz Zaborski 			break;
121354f98da9SMariusz Zaborski 		default:
121454f98da9SMariusz Zaborski 			PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp));
121554f98da9SMariusz Zaborski 		}
121654f98da9SMariusz Zaborski 		if (ptr == NULL)
121754f98da9SMariusz Zaborski 			goto failed;
121830740f45SMariusz Zaborski 		if (!nvlist_move_nvpair(nvl, nvp))
121930740f45SMariusz Zaborski 			goto failed;
122054f98da9SMariusz Zaborski 		if (tmpnvl != NULL) {
122154f98da9SMariusz Zaborski 			nvl = tmpnvl;
122254f98da9SMariusz Zaborski 			tmpnvl = NULL;
122354f98da9SMariusz Zaborski 		}
122454f98da9SMariusz Zaborski 	}
122554f98da9SMariusz Zaborski 
122654f98da9SMariusz Zaborski 	return (retnvl);
122754f98da9SMariusz Zaborski failed:
122854f98da9SMariusz Zaborski 	nvlist_destroy(retnvl);
122954f98da9SMariusz Zaborski 	return (NULL);
123054f98da9SMariusz Zaborski }
123154f98da9SMariusz Zaborski 
123254f98da9SMariusz Zaborski nvlist_t *
123354f98da9SMariusz Zaborski nvlist_unpack(const void *buf, size_t size, int flags)
123454f98da9SMariusz Zaborski {
123554f98da9SMariusz Zaborski 
123654f98da9SMariusz Zaborski 	return (nvlist_xunpack(buf, size, NULL, 0, flags));
123754f98da9SMariusz Zaborski }
123854f98da9SMariusz Zaborski 
123954f98da9SMariusz Zaborski #ifndef _KERNEL
124054f98da9SMariusz Zaborski int
124154f98da9SMariusz Zaborski nvlist_send(int sock, const nvlist_t *nvl)
124254f98da9SMariusz Zaborski {
124354f98da9SMariusz Zaborski 	size_t datasize, nfds;
124454f98da9SMariusz Zaborski 	int *fds;
124554f98da9SMariusz Zaborski 	void *data;
124654f98da9SMariusz Zaborski 	int64_t fdidx;
124754f98da9SMariusz Zaborski 	int ret;
124854f98da9SMariusz Zaborski 
124954f98da9SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
125054f98da9SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
125154f98da9SMariusz Zaborski 		return (-1);
125254f98da9SMariusz Zaborski 	}
125354f98da9SMariusz Zaborski 
125454f98da9SMariusz Zaborski 	fds = nvlist_descriptors(nvl, &nfds);
125554f98da9SMariusz Zaborski 	if (fds == NULL)
125654f98da9SMariusz Zaborski 		return (-1);
125754f98da9SMariusz Zaborski 
125854f98da9SMariusz Zaborski 	ret = -1;
125954f98da9SMariusz Zaborski 	fdidx = 0;
126054f98da9SMariusz Zaborski 
126154f98da9SMariusz Zaborski 	data = nvlist_xpack(nvl, &fdidx, &datasize);
126254f98da9SMariusz Zaborski 	if (data == NULL)
126354f98da9SMariusz Zaborski 		goto out;
126454f98da9SMariusz Zaborski 
126554f98da9SMariusz Zaborski 	if (buf_send(sock, data, datasize) == -1)
126654f98da9SMariusz Zaborski 		goto out;
126754f98da9SMariusz Zaborski 
126854f98da9SMariusz Zaborski 	if (nfds > 0) {
126954f98da9SMariusz Zaborski 		if (fd_send(sock, fds, nfds) == -1)
127054f98da9SMariusz Zaborski 			goto out;
127154f98da9SMariusz Zaborski 	}
127254f98da9SMariusz Zaborski 
127354f98da9SMariusz Zaborski 	ret = 0;
127454f98da9SMariusz Zaborski out:
127554f98da9SMariusz Zaborski 	ERRNO_SAVE();
127654f98da9SMariusz Zaborski 	nv_free(fds);
127754f98da9SMariusz Zaborski 	nv_free(data);
127854f98da9SMariusz Zaborski 	ERRNO_RESTORE();
127954f98da9SMariusz Zaborski 	return (ret);
128054f98da9SMariusz Zaborski }
128154f98da9SMariusz Zaborski 
128254f98da9SMariusz Zaborski nvlist_t *
128354f98da9SMariusz Zaborski nvlist_recv(int sock, int flags)
128454f98da9SMariusz Zaborski {
128554f98da9SMariusz Zaborski 	struct nvlist_header nvlhdr;
128654f98da9SMariusz Zaborski 	nvlist_t *nvl, *ret;
128754f98da9SMariusz Zaborski 	unsigned char *buf;
128854f98da9SMariusz Zaborski 	size_t nfds, size, i;
128954f98da9SMariusz Zaborski 	int *fds;
129054f98da9SMariusz Zaborski 
129154f98da9SMariusz Zaborski 	if (buf_recv(sock, &nvlhdr, sizeof(nvlhdr)) == -1)
129254f98da9SMariusz Zaborski 		return (NULL);
129354f98da9SMariusz Zaborski 
129454f98da9SMariusz Zaborski 	if (!nvlist_check_header(&nvlhdr))
129554f98da9SMariusz Zaborski 		return (NULL);
129654f98da9SMariusz Zaborski 
129754f98da9SMariusz Zaborski 	nfds = (size_t)nvlhdr.nvlh_descriptors;
129854f98da9SMariusz Zaborski 	size = sizeof(nvlhdr) + (size_t)nvlhdr.nvlh_size;
129954f98da9SMariusz Zaborski 
130054f98da9SMariusz Zaborski 	buf = nv_malloc(size);
130154f98da9SMariusz Zaborski 	if (buf == NULL)
130254f98da9SMariusz Zaborski 		return (NULL);
130354f98da9SMariusz Zaborski 
130454f98da9SMariusz Zaborski 	memcpy(buf, &nvlhdr, sizeof(nvlhdr));
130554f98da9SMariusz Zaborski 
130654f98da9SMariusz Zaborski 	ret = NULL;
130754f98da9SMariusz Zaborski 	fds = NULL;
130854f98da9SMariusz Zaborski 
130954f98da9SMariusz Zaborski 	if (buf_recv(sock, buf + sizeof(nvlhdr), size - sizeof(nvlhdr)) == -1)
131054f98da9SMariusz Zaborski 		goto out;
131154f98da9SMariusz Zaborski 
131254f98da9SMariusz Zaborski 	if (nfds > 0) {
131354f98da9SMariusz Zaborski 		fds = nv_malloc(nfds * sizeof(fds[0]));
131454f98da9SMariusz Zaborski 		if (fds == NULL)
131554f98da9SMariusz Zaborski 			goto out;
131654f98da9SMariusz Zaborski 		if (fd_recv(sock, fds, nfds) == -1)
131754f98da9SMariusz Zaborski 			goto out;
131854f98da9SMariusz Zaborski 	}
131954f98da9SMariusz Zaborski 
132054f98da9SMariusz Zaborski 	nvl = nvlist_xunpack(buf, size, fds, nfds, flags);
132154f98da9SMariusz Zaborski 	if (nvl == NULL) {
132254f98da9SMariusz Zaborski 		ERRNO_SAVE();
132354f98da9SMariusz Zaborski 		for (i = 0; i < nfds; i++)
132454f98da9SMariusz Zaborski 			close(fds[i]);
132554f98da9SMariusz Zaborski 		ERRNO_RESTORE();
132654f98da9SMariusz Zaborski 		goto out;
132754f98da9SMariusz Zaborski 	}
132854f98da9SMariusz Zaborski 
132954f98da9SMariusz Zaborski 	ret = nvl;
133054f98da9SMariusz Zaborski out:
133154f98da9SMariusz Zaborski 	ERRNO_SAVE();
133254f98da9SMariusz Zaborski 	nv_free(buf);
133354f98da9SMariusz Zaborski 	nv_free(fds);
133454f98da9SMariusz Zaborski 	ERRNO_RESTORE();
133554f98da9SMariusz Zaborski 
133654f98da9SMariusz Zaborski 	return (ret);
133754f98da9SMariusz Zaborski }
133854f98da9SMariusz Zaborski 
133954f98da9SMariusz Zaborski nvlist_t *
134054f98da9SMariusz Zaborski nvlist_xfer(int sock, nvlist_t *nvl, int flags)
134154f98da9SMariusz Zaborski {
134254f98da9SMariusz Zaborski 
134354f98da9SMariusz Zaborski 	if (nvlist_send(sock, nvl) < 0) {
134454f98da9SMariusz Zaborski 		nvlist_destroy(nvl);
134554f98da9SMariusz Zaborski 		return (NULL);
134654f98da9SMariusz Zaborski 	}
134754f98da9SMariusz Zaborski 	nvlist_destroy(nvl);
134854f98da9SMariusz Zaborski 	return (nvlist_recv(sock, flags));
134954f98da9SMariusz Zaborski }
135054f98da9SMariusz Zaborski #endif
135154f98da9SMariusz Zaborski 
135254f98da9SMariusz Zaborski nvpair_t *
135354f98da9SMariusz Zaborski nvlist_first_nvpair(const nvlist_t *nvl)
135454f98da9SMariusz Zaborski {
135554f98da9SMariusz Zaborski 
135654f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
135754f98da9SMariusz Zaborski 
135854f98da9SMariusz Zaborski 	return (TAILQ_FIRST(&nvl->nvl_head));
135954f98da9SMariusz Zaborski }
136054f98da9SMariusz Zaborski 
136154f98da9SMariusz Zaborski nvpair_t *
136254f98da9SMariusz Zaborski nvlist_next_nvpair(const nvlist_t *nvl, const nvpair_t *nvp)
136354f98da9SMariusz Zaborski {
136454f98da9SMariusz Zaborski 	nvpair_t *retnvp;
136554f98da9SMariusz Zaborski 
136654f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
136754f98da9SMariusz Zaborski 	NVPAIR_ASSERT(nvp);
136854f98da9SMariusz Zaborski 	PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
136954f98da9SMariusz Zaborski 
137054f98da9SMariusz Zaborski 	retnvp = nvpair_next(nvp);
137154f98da9SMariusz Zaborski 	PJDLOG_ASSERT(retnvp == NULL || nvpair_nvlist(retnvp) == nvl);
137254f98da9SMariusz Zaborski 
137354f98da9SMariusz Zaborski 	return (retnvp);
137454f98da9SMariusz Zaborski 
137554f98da9SMariusz Zaborski }
137654f98da9SMariusz Zaborski 
137754f98da9SMariusz Zaborski nvpair_t *
137854f98da9SMariusz Zaborski nvlist_prev_nvpair(const nvlist_t *nvl, const nvpair_t *nvp)
137954f98da9SMariusz Zaborski {
138054f98da9SMariusz Zaborski 	nvpair_t *retnvp;
138154f98da9SMariusz Zaborski 
138254f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
138354f98da9SMariusz Zaborski 	NVPAIR_ASSERT(nvp);
138454f98da9SMariusz Zaborski 	PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
138554f98da9SMariusz Zaborski 
138654f98da9SMariusz Zaborski 	retnvp = nvpair_prev(nvp);
138754f98da9SMariusz Zaborski 	PJDLOG_ASSERT(nvpair_nvlist(retnvp) == nvl);
138854f98da9SMariusz Zaborski 
138954f98da9SMariusz Zaborski 	return (retnvp);
139054f98da9SMariusz Zaborski }
139154f98da9SMariusz Zaborski 
139254f98da9SMariusz Zaborski const char *
139354f98da9SMariusz Zaborski nvlist_next(const nvlist_t *nvl, int *typep, void **cookiep)
139454f98da9SMariusz Zaborski {
139554f98da9SMariusz Zaborski 	nvpair_t *nvp;
139654f98da9SMariusz Zaborski 
139754f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
139854f98da9SMariusz Zaborski 
139989ca10c6SMariusz Zaborski 	if (cookiep == NULL || *cookiep == NULL)
140054f98da9SMariusz Zaborski 		nvp = nvlist_first_nvpair(nvl);
140154f98da9SMariusz Zaborski 	else
140254f98da9SMariusz Zaborski 		nvp = nvlist_next_nvpair(nvl, *cookiep);
140354f98da9SMariusz Zaborski 	if (nvp == NULL)
140454f98da9SMariusz Zaborski 		return (NULL);
140554f98da9SMariusz Zaborski 	if (typep != NULL)
140654f98da9SMariusz Zaborski 		*typep = nvpair_type(nvp);
140789ca10c6SMariusz Zaborski 	if (cookiep != NULL)
140854f98da9SMariusz Zaborski 		*cookiep = nvp;
140954f98da9SMariusz Zaborski 	return (nvpair_name(nvp));
141054f98da9SMariusz Zaborski }
141154f98da9SMariusz Zaborski 
141254f98da9SMariusz Zaborski bool
141354f98da9SMariusz Zaborski nvlist_exists(const nvlist_t *nvl, const char *name)
141454f98da9SMariusz Zaborski {
141554f98da9SMariusz Zaborski 
141654f98da9SMariusz Zaborski 	return (nvlist_find(nvl, NV_TYPE_NONE, name) != NULL);
141754f98da9SMariusz Zaborski }
141854f98da9SMariusz Zaborski 
141954f98da9SMariusz Zaborski #define	NVLIST_EXISTS(type, TYPE)					\
142054f98da9SMariusz Zaborski bool									\
142154f98da9SMariusz Zaborski nvlist_exists_##type(const nvlist_t *nvl, const char *name)		\
142254f98da9SMariusz Zaborski {									\
142354f98da9SMariusz Zaborski 									\
142454f98da9SMariusz Zaborski 	return (nvlist_find(nvl, NV_TYPE_##TYPE, name) != NULL);	\
142554f98da9SMariusz Zaborski }
142654f98da9SMariusz Zaborski 
142754f98da9SMariusz Zaborski NVLIST_EXISTS(null, NULL)
142854f98da9SMariusz Zaborski NVLIST_EXISTS(bool, BOOL)
142954f98da9SMariusz Zaborski NVLIST_EXISTS(number, NUMBER)
143054f98da9SMariusz Zaborski NVLIST_EXISTS(string, STRING)
143154f98da9SMariusz Zaborski NVLIST_EXISTS(nvlist, NVLIST)
1432347a39b4SMariusz Zaborski NVLIST_EXISTS(binary, BINARY)
1433347a39b4SMariusz Zaborski NVLIST_EXISTS(bool_array, BOOL_ARRAY)
1434347a39b4SMariusz Zaborski NVLIST_EXISTS(number_array, NUMBER_ARRAY)
1435347a39b4SMariusz Zaborski NVLIST_EXISTS(string_array, STRING_ARRAY)
1436347a39b4SMariusz Zaborski NVLIST_EXISTS(nvlist_array, NVLIST_ARRAY)
143754f98da9SMariusz Zaborski #ifndef _KERNEL
143854f98da9SMariusz Zaborski NVLIST_EXISTS(descriptor, DESCRIPTOR)
1439347a39b4SMariusz Zaborski NVLIST_EXISTS(descriptor_array, DESCRIPTOR_ARRAY)
144054f98da9SMariusz Zaborski #endif
144154f98da9SMariusz Zaborski 
144254f98da9SMariusz Zaborski #undef	NVLIST_EXISTS
144354f98da9SMariusz Zaborski 
144454f98da9SMariusz Zaborski void
144554f98da9SMariusz Zaborski nvlist_add_nvpair(nvlist_t *nvl, const nvpair_t *nvp)
144654f98da9SMariusz Zaborski {
144754f98da9SMariusz Zaborski 	nvpair_t *newnvp;
144854f98da9SMariusz Zaborski 
144954f98da9SMariusz Zaborski 	NVPAIR_ASSERT(nvp);
145054f98da9SMariusz Zaborski 
145154f98da9SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
145254f98da9SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
145354f98da9SMariusz Zaborski 		return;
145454f98da9SMariusz Zaborski 	}
145554f98da9SMariusz Zaborski 	if ((nvl->nvl_flags & NV_FLAG_NO_UNIQUE) == 0) {
145654f98da9SMariusz Zaborski 		if (nvlist_exists(nvl, nvpair_name(nvp))) {
145754f98da9SMariusz Zaborski 			nvl->nvl_error = EEXIST;
145854f98da9SMariusz Zaborski 			ERRNO_SET(nvlist_error(nvl));
145954f98da9SMariusz Zaborski 			return;
146054f98da9SMariusz Zaborski 		}
146154f98da9SMariusz Zaborski 	}
146254f98da9SMariusz Zaborski 
146354f98da9SMariusz Zaborski 	newnvp = nvpair_clone(nvp);
146454f98da9SMariusz Zaborski 	if (newnvp == NULL) {
146554f98da9SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
146654f98da9SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
146754f98da9SMariusz Zaborski 		return;
146854f98da9SMariusz Zaborski 	}
146954f98da9SMariusz Zaborski 
147054f98da9SMariusz Zaborski 	nvpair_insert(&nvl->nvl_head, newnvp, nvl);
147154f98da9SMariusz Zaborski }
147254f98da9SMariusz Zaborski 
147354f98da9SMariusz Zaborski void
147454f98da9SMariusz Zaborski nvlist_add_stringf(nvlist_t *nvl, const char *name, const char *valuefmt, ...)
147554f98da9SMariusz Zaborski {
147654f98da9SMariusz Zaborski 	va_list valueap;
147754f98da9SMariusz Zaborski 
147854f98da9SMariusz Zaborski 	va_start(valueap, valuefmt);
147954f98da9SMariusz Zaborski 	nvlist_add_stringv(nvl, name, valuefmt, valueap);
148054f98da9SMariusz Zaborski 	va_end(valueap);
148154f98da9SMariusz Zaborski }
148254f98da9SMariusz Zaborski 
148354f98da9SMariusz Zaborski void
148454f98da9SMariusz Zaborski nvlist_add_stringv(nvlist_t *nvl, const char *name, const char *valuefmt,
148554f98da9SMariusz Zaborski     va_list valueap)
148654f98da9SMariusz Zaborski {
148754f98da9SMariusz Zaborski 	nvpair_t *nvp;
148854f98da9SMariusz Zaborski 
148954f98da9SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
149054f98da9SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
149154f98da9SMariusz Zaborski 		return;
149254f98da9SMariusz Zaborski 	}
149354f98da9SMariusz Zaborski 
149454f98da9SMariusz Zaborski 	nvp = nvpair_create_stringv(name, valuefmt, valueap);
149554f98da9SMariusz Zaborski 	if (nvp == NULL) {
149654f98da9SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
149754f98da9SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
149854f98da9SMariusz Zaborski 	} else {
149930740f45SMariusz Zaborski 		(void)nvlist_move_nvpair(nvl, nvp);
150054f98da9SMariusz Zaborski 	}
150154f98da9SMariusz Zaborski }
150254f98da9SMariusz Zaborski 
150354f98da9SMariusz Zaborski void
150454f98da9SMariusz Zaborski nvlist_add_null(nvlist_t *nvl, const char *name)
150554f98da9SMariusz Zaborski {
150654f98da9SMariusz Zaborski 	nvpair_t *nvp;
150754f98da9SMariusz Zaborski 
150854f98da9SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
150954f98da9SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
151054f98da9SMariusz Zaborski 		return;
151154f98da9SMariusz Zaborski 	}
151254f98da9SMariusz Zaborski 
151354f98da9SMariusz Zaborski 	nvp = nvpair_create_null(name);
151454f98da9SMariusz Zaborski 	if (nvp == NULL) {
151554f98da9SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
151654f98da9SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
151754f98da9SMariusz Zaborski 	} else {
151830740f45SMariusz Zaborski 		(void)nvlist_move_nvpair(nvl, nvp);
151954f98da9SMariusz Zaborski 	}
152054f98da9SMariusz Zaborski }
152154f98da9SMariusz Zaborski 
152254f98da9SMariusz Zaborski void
152354f98da9SMariusz Zaborski nvlist_add_binary(nvlist_t *nvl, const char *name, const void *value,
152454f98da9SMariusz Zaborski     size_t size)
152554f98da9SMariusz Zaborski {
152654f98da9SMariusz Zaborski 	nvpair_t *nvp;
152754f98da9SMariusz Zaborski 
152854f98da9SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
152954f98da9SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
153054f98da9SMariusz Zaborski 		return;
153154f98da9SMariusz Zaborski 	}
153254f98da9SMariusz Zaborski 
153354f98da9SMariusz Zaborski 	nvp = nvpair_create_binary(name, value, size);
153454f98da9SMariusz Zaborski 	if (nvp == NULL) {
153554f98da9SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
153654f98da9SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
153754f98da9SMariusz Zaborski 	} else {
153830740f45SMariusz Zaborski 		(void)nvlist_move_nvpair(nvl, nvp);
153954f98da9SMariusz Zaborski 	}
154054f98da9SMariusz Zaborski }
154154f98da9SMariusz Zaborski 
154254f98da9SMariusz Zaborski 
154354f98da9SMariusz Zaborski #define	NVLIST_ADD(vtype, type)						\
154454f98da9SMariusz Zaborski void									\
154554f98da9SMariusz Zaborski nvlist_add_##type(nvlist_t *nvl, const char *name, vtype value)		\
154654f98da9SMariusz Zaborski {									\
154754f98da9SMariusz Zaborski 	nvpair_t *nvp;							\
154854f98da9SMariusz Zaborski 									\
154954f98da9SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {					\
155054f98da9SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));				\
155154f98da9SMariusz Zaborski 		return;							\
155254f98da9SMariusz Zaborski 	}								\
155354f98da9SMariusz Zaborski 									\
155454f98da9SMariusz Zaborski 	nvp = nvpair_create_##type(name, value);			\
155554f98da9SMariusz Zaborski 	if (nvp == NULL) {						\
155654f98da9SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);		\
155754f98da9SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);				\
155854f98da9SMariusz Zaborski 	} else {							\
155930740f45SMariusz Zaborski 		(void)nvlist_move_nvpair(nvl, nvp);			\
156054f98da9SMariusz Zaborski 	}								\
156154f98da9SMariusz Zaborski }
156254f98da9SMariusz Zaborski 
156354f98da9SMariusz Zaborski NVLIST_ADD(bool, bool)
156454f98da9SMariusz Zaborski NVLIST_ADD(uint64_t, number)
156554f98da9SMariusz Zaborski NVLIST_ADD(const char *, string)
156654f98da9SMariusz Zaborski NVLIST_ADD(const nvlist_t *, nvlist)
156754f98da9SMariusz Zaborski #ifndef _KERNEL
156854f98da9SMariusz Zaborski NVLIST_ADD(int, descriptor);
156954f98da9SMariusz Zaborski #endif
157054f98da9SMariusz Zaborski 
157154f98da9SMariusz Zaborski #undef	NVLIST_ADD
157254f98da9SMariusz Zaborski 
1573347a39b4SMariusz Zaborski #define	NVLIST_ADD_ARRAY(vtype, type)					\
1574347a39b4SMariusz Zaborski void									\
1575347a39b4SMariusz Zaborski nvlist_add_##type##_array(nvlist_t *nvl, const char *name, vtype value,	\
1576347a39b4SMariusz Zaborski     size_t nitems)							\
1577347a39b4SMariusz Zaborski {									\
1578347a39b4SMariusz Zaborski 	nvpair_t *nvp;							\
1579347a39b4SMariusz Zaborski 									\
1580347a39b4SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {					\
1581347a39b4SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));				\
1582347a39b4SMariusz Zaborski 		return;							\
1583347a39b4SMariusz Zaborski 	}								\
1584347a39b4SMariusz Zaborski 									\
1585347a39b4SMariusz Zaborski 	nvp = nvpair_create_##type##_array(name, value, nitems);	\
1586347a39b4SMariusz Zaborski 	if (nvp == NULL) {						\
1587347a39b4SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);		\
1588347a39b4SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);				\
1589347a39b4SMariusz Zaborski 	} else {							\
1590347a39b4SMariusz Zaborski 		(void)nvlist_move_nvpair(nvl, nvp);			\
1591347a39b4SMariusz Zaborski 	}								\
1592347a39b4SMariusz Zaborski }
1593347a39b4SMariusz Zaborski 
1594347a39b4SMariusz Zaborski NVLIST_ADD_ARRAY(const bool *, bool)
1595347a39b4SMariusz Zaborski NVLIST_ADD_ARRAY(const uint64_t *, number)
1596347a39b4SMariusz Zaborski NVLIST_ADD_ARRAY(const char * const *, string)
1597347a39b4SMariusz Zaborski NVLIST_ADD_ARRAY(const nvlist_t * const *, nvlist)
1598347a39b4SMariusz Zaborski #ifndef _KERNEL
1599347a39b4SMariusz Zaborski NVLIST_ADD_ARRAY(const int *, descriptor)
1600347a39b4SMariusz Zaborski #endif
1601347a39b4SMariusz Zaborski 
1602347a39b4SMariusz Zaborski #undef	NVLIST_ADD_ARRAY
1603347a39b4SMariusz Zaborski 
160430740f45SMariusz Zaborski bool
160554f98da9SMariusz Zaborski nvlist_move_nvpair(nvlist_t *nvl, nvpair_t *nvp)
160654f98da9SMariusz Zaborski {
160754f98da9SMariusz Zaborski 
160854f98da9SMariusz Zaborski 	NVPAIR_ASSERT(nvp);
160954f98da9SMariusz Zaborski 	PJDLOG_ASSERT(nvpair_nvlist(nvp) == NULL);
161054f98da9SMariusz Zaborski 
161154f98da9SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
161254f98da9SMariusz Zaborski 		nvpair_free(nvp);
161354f98da9SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
161430740f45SMariusz Zaborski 		return (false);
161554f98da9SMariusz Zaborski 	}
161654f98da9SMariusz Zaborski 	if ((nvl->nvl_flags & NV_FLAG_NO_UNIQUE) == 0) {
161754f98da9SMariusz Zaborski 		if (nvlist_exists(nvl, nvpair_name(nvp))) {
161854f98da9SMariusz Zaborski 			nvpair_free(nvp);
161954f98da9SMariusz Zaborski 			nvl->nvl_error = EEXIST;
162054f98da9SMariusz Zaborski 			ERRNO_SET(nvl->nvl_error);
162130740f45SMariusz Zaborski 			return (false);
162254f98da9SMariusz Zaborski 		}
162354f98da9SMariusz Zaborski 	}
162454f98da9SMariusz Zaborski 
162554f98da9SMariusz Zaborski 	nvpair_insert(&nvl->nvl_head, nvp, nvl);
162630740f45SMariusz Zaborski 	return (true);
162754f98da9SMariusz Zaborski }
162854f98da9SMariusz Zaborski 
162954f98da9SMariusz Zaborski void
163054f98da9SMariusz Zaborski nvlist_move_string(nvlist_t *nvl, const char *name, char *value)
163154f98da9SMariusz Zaborski {
163254f98da9SMariusz Zaborski 	nvpair_t *nvp;
163354f98da9SMariusz Zaborski 
163454f98da9SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
163554f98da9SMariusz Zaborski 		nv_free(value);
163654f98da9SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
163754f98da9SMariusz Zaborski 		return;
163854f98da9SMariusz Zaborski 	}
163954f98da9SMariusz Zaborski 
164054f98da9SMariusz Zaborski 	nvp = nvpair_move_string(name, value);
164154f98da9SMariusz Zaborski 	if (nvp == NULL) {
164254f98da9SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
164354f98da9SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
164454f98da9SMariusz Zaborski 	} else {
164530740f45SMariusz Zaborski 		(void)nvlist_move_nvpair(nvl, nvp);
164654f98da9SMariusz Zaborski 	}
164754f98da9SMariusz Zaborski }
164854f98da9SMariusz Zaborski 
164954f98da9SMariusz Zaborski void
165054f98da9SMariusz Zaborski nvlist_move_nvlist(nvlist_t *nvl, const char *name, nvlist_t *value)
165154f98da9SMariusz Zaborski {
165254f98da9SMariusz Zaborski 	nvpair_t *nvp;
165354f98da9SMariusz Zaborski 
165454f98da9SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
165554f98da9SMariusz Zaborski 		if (value != NULL && nvlist_get_nvpair_parent(value) != NULL)
165654f98da9SMariusz Zaborski 			nvlist_destroy(value);
165754f98da9SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
165854f98da9SMariusz Zaborski 		return;
165954f98da9SMariusz Zaborski 	}
166054f98da9SMariusz Zaborski 
166154f98da9SMariusz Zaborski 	nvp = nvpair_move_nvlist(name, value);
166254f98da9SMariusz Zaborski 	if (nvp == NULL) {
166354f98da9SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
166454f98da9SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
166554f98da9SMariusz Zaborski 	} else {
166630740f45SMariusz Zaborski 		(void)nvlist_move_nvpair(nvl, nvp);
166754f98da9SMariusz Zaborski 	}
166854f98da9SMariusz Zaborski }
166954f98da9SMariusz Zaborski 
167054f98da9SMariusz Zaborski #ifndef _KERNEL
167154f98da9SMariusz Zaborski void
167254f98da9SMariusz Zaborski nvlist_move_descriptor(nvlist_t *nvl, const char *name, int value)
167354f98da9SMariusz Zaborski {
167454f98da9SMariusz Zaborski 	nvpair_t *nvp;
167554f98da9SMariusz Zaborski 
167654f98da9SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
167754f98da9SMariusz Zaborski 		close(value);
167854f98da9SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
167954f98da9SMariusz Zaborski 		return;
168054f98da9SMariusz Zaborski 	}
168154f98da9SMariusz Zaborski 
168254f98da9SMariusz Zaborski 	nvp = nvpair_move_descriptor(name, value);
168354f98da9SMariusz Zaborski 	if (nvp == NULL) {
168454f98da9SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
168554f98da9SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
168654f98da9SMariusz Zaborski 	} else {
168730740f45SMariusz Zaborski 		(void)nvlist_move_nvpair(nvl, nvp);
168854f98da9SMariusz Zaborski 	}
168954f98da9SMariusz Zaborski }
169054f98da9SMariusz Zaborski #endif
169154f98da9SMariusz Zaborski 
169254f98da9SMariusz Zaborski void
169354f98da9SMariusz Zaborski nvlist_move_binary(nvlist_t *nvl, const char *name, void *value, size_t size)
169454f98da9SMariusz Zaborski {
169554f98da9SMariusz Zaborski 	nvpair_t *nvp;
169654f98da9SMariusz Zaborski 
169754f98da9SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
169854f98da9SMariusz Zaborski 		nv_free(value);
169954f98da9SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
170054f98da9SMariusz Zaborski 		return;
170154f98da9SMariusz Zaborski 	}
170254f98da9SMariusz Zaborski 
170354f98da9SMariusz Zaborski 	nvp = nvpair_move_binary(name, value, size);
170454f98da9SMariusz Zaborski 	if (nvp == NULL) {
170554f98da9SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
170654f98da9SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
170754f98da9SMariusz Zaborski 	} else {
170830740f45SMariusz Zaborski 		(void)nvlist_move_nvpair(nvl, nvp);
170954f98da9SMariusz Zaborski 	}
171054f98da9SMariusz Zaborski }
171154f98da9SMariusz Zaborski 
1712347a39b4SMariusz Zaborski void
1713347a39b4SMariusz Zaborski nvlist_move_bool_array(nvlist_t *nvl, const char *name, bool *value,
1714347a39b4SMariusz Zaborski     size_t nitems)
1715347a39b4SMariusz Zaborski {
1716347a39b4SMariusz Zaborski 	nvpair_t *nvp;
1717347a39b4SMariusz Zaborski 
1718347a39b4SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
1719347a39b4SMariusz Zaborski 		nv_free(value);
1720347a39b4SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
1721347a39b4SMariusz Zaborski 		return;
1722347a39b4SMariusz Zaborski 	}
1723347a39b4SMariusz Zaborski 
1724347a39b4SMariusz Zaborski 	nvp = nvpair_move_bool_array(name, value, nitems);
1725347a39b4SMariusz Zaborski 	if (nvp == NULL) {
1726347a39b4SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1727347a39b4SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
1728347a39b4SMariusz Zaborski 	} else {
1729347a39b4SMariusz Zaborski 		(void)nvlist_move_nvpair(nvl, nvp);
1730347a39b4SMariusz Zaborski 	}
1731347a39b4SMariusz Zaborski }
1732347a39b4SMariusz Zaborski 
1733347a39b4SMariusz Zaborski void
1734347a39b4SMariusz Zaborski nvlist_move_string_array(nvlist_t *nvl, const char *name, char **value,
1735347a39b4SMariusz Zaborski     size_t nitems)
1736347a39b4SMariusz Zaborski {
1737347a39b4SMariusz Zaborski 	nvpair_t *nvp;
1738347a39b4SMariusz Zaborski 	size_t i;
1739347a39b4SMariusz Zaborski 
1740347a39b4SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
1741347a39b4SMariusz Zaborski 		if (value != NULL) {
1742347a39b4SMariusz Zaborski 			for (i = 0; i < nitems; i++)
1743347a39b4SMariusz Zaborski 				nv_free(value[i]);
1744347a39b4SMariusz Zaborski 			nv_free(value);
1745347a39b4SMariusz Zaborski 		}
1746347a39b4SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
1747347a39b4SMariusz Zaborski 		return;
1748347a39b4SMariusz Zaborski 	}
1749347a39b4SMariusz Zaborski 
1750347a39b4SMariusz Zaborski 	nvp = nvpair_move_string_array(name, value, nitems);
1751347a39b4SMariusz Zaborski 	if (nvp == NULL) {
1752347a39b4SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1753347a39b4SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
1754347a39b4SMariusz Zaborski 	} else {
1755347a39b4SMariusz Zaborski 		(void)nvlist_move_nvpair(nvl, nvp);
1756347a39b4SMariusz Zaborski 	}
1757347a39b4SMariusz Zaborski }
1758347a39b4SMariusz Zaborski 
1759347a39b4SMariusz Zaborski void
1760347a39b4SMariusz Zaborski nvlist_move_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **value,
1761347a39b4SMariusz Zaborski     size_t nitems)
1762347a39b4SMariusz Zaborski {
1763347a39b4SMariusz Zaborski 	nvpair_t *nvp;
1764347a39b4SMariusz Zaborski 	size_t i;
1765347a39b4SMariusz Zaborski 
1766347a39b4SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
1767347a39b4SMariusz Zaborski 		if (value != NULL) {
1768347a39b4SMariusz Zaborski 			for (i = 0; i < nitems; i++) {
1769347a39b4SMariusz Zaborski 				if (nvlist_get_pararr(value[i], NULL) == NULL)
1770347a39b4SMariusz Zaborski 					nvlist_destroy(value[i]);
1771347a39b4SMariusz Zaborski 			}
1772347a39b4SMariusz Zaborski 		}
1773347a39b4SMariusz Zaborski 		nv_free(value);
1774347a39b4SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
1775347a39b4SMariusz Zaborski 		return;
1776347a39b4SMariusz Zaborski 	}
1777347a39b4SMariusz Zaborski 
1778347a39b4SMariusz Zaborski 	nvp = nvpair_move_nvlist_array(name, value, nitems);
1779347a39b4SMariusz Zaborski 	if (nvp == NULL) {
1780347a39b4SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1781347a39b4SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
1782347a39b4SMariusz Zaborski 	} else {
1783347a39b4SMariusz Zaborski 		(void)nvlist_move_nvpair(nvl, nvp);
1784347a39b4SMariusz Zaborski 	}
1785347a39b4SMariusz Zaborski }
1786347a39b4SMariusz Zaborski 
1787347a39b4SMariusz Zaborski void
1788347a39b4SMariusz Zaborski nvlist_move_number_array(nvlist_t *nvl, const char *name, uint64_t *value,
1789347a39b4SMariusz Zaborski     size_t nitems)
1790347a39b4SMariusz Zaborski {
1791347a39b4SMariusz Zaborski 	nvpair_t *nvp;
1792347a39b4SMariusz Zaborski 
1793347a39b4SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
1794347a39b4SMariusz Zaborski 		nv_free(value);
1795347a39b4SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
1796347a39b4SMariusz Zaborski 		return;
1797347a39b4SMariusz Zaborski 	}
1798347a39b4SMariusz Zaborski 
1799347a39b4SMariusz Zaborski 	nvp = nvpair_move_number_array(name, value, nitems);
1800347a39b4SMariusz Zaborski 	if (nvp == NULL) {
1801347a39b4SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1802347a39b4SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
1803347a39b4SMariusz Zaborski 	} else {
1804347a39b4SMariusz Zaborski 		(void)nvlist_move_nvpair(nvl, nvp);
1805347a39b4SMariusz Zaborski 	}
1806347a39b4SMariusz Zaborski }
1807347a39b4SMariusz Zaborski 
1808347a39b4SMariusz Zaborski #ifndef _KERNEL
1809347a39b4SMariusz Zaborski void
1810347a39b4SMariusz Zaborski nvlist_move_descriptor_array(nvlist_t *nvl, const char *name, int *value,
1811347a39b4SMariusz Zaborski     size_t nitems)
1812347a39b4SMariusz Zaborski {
1813347a39b4SMariusz Zaborski 	nvpair_t *nvp;
1814347a39b4SMariusz Zaborski 	size_t i;
1815347a39b4SMariusz Zaborski 
1816347a39b4SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
1817347a39b4SMariusz Zaborski 		if (value != 0) {
1818347a39b4SMariusz Zaborski 			for (i = 0; i < nitems; i++)
1819347a39b4SMariusz Zaborski 				close(value[i]);
1820347a39b4SMariusz Zaborski 			nv_free(value);
1821347a39b4SMariusz Zaborski 		}
1822347a39b4SMariusz Zaborski 
1823347a39b4SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
1824347a39b4SMariusz Zaborski 		return;
1825347a39b4SMariusz Zaborski 	}
1826347a39b4SMariusz Zaborski 
1827347a39b4SMariusz Zaborski 	nvp = nvpair_move_descriptor_array(name, value, nitems);
1828347a39b4SMariusz Zaborski 	if (nvp == NULL) {
1829347a39b4SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1830347a39b4SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
1831347a39b4SMariusz Zaborski 	} else {
1832347a39b4SMariusz Zaborski 		(void)nvlist_move_nvpair(nvl, nvp);
1833347a39b4SMariusz Zaborski 	}
1834347a39b4SMariusz Zaborski }
1835347a39b4SMariusz Zaborski #endif
1836347a39b4SMariusz Zaborski 
183754f98da9SMariusz Zaborski const nvpair_t *
183854f98da9SMariusz Zaborski nvlist_get_nvpair(const nvlist_t *nvl, const char *name)
183954f98da9SMariusz Zaborski {
184054f98da9SMariusz Zaborski 
184154f98da9SMariusz Zaborski 	return (nvlist_find(nvl, NV_TYPE_NONE, name));
184254f98da9SMariusz Zaborski }
184354f98da9SMariusz Zaborski 
184454f98da9SMariusz Zaborski #define	NVLIST_GET(ftype, type, TYPE)					\
184554f98da9SMariusz Zaborski ftype									\
184654f98da9SMariusz Zaborski nvlist_get_##type(const nvlist_t *nvl, const char *name)		\
184754f98da9SMariusz Zaborski {									\
184854f98da9SMariusz Zaborski 	const nvpair_t *nvp;						\
184954f98da9SMariusz Zaborski 									\
185054f98da9SMariusz Zaborski 	nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name);			\
185154f98da9SMariusz Zaborski 	if (nvp == NULL)						\
185254f98da9SMariusz Zaborski 		nvlist_report_missing(NV_TYPE_##TYPE, name);		\
185354f98da9SMariusz Zaborski 	return (nvpair_get_##type(nvp));				\
185454f98da9SMariusz Zaborski }
185554f98da9SMariusz Zaborski 
185654f98da9SMariusz Zaborski NVLIST_GET(bool, bool, BOOL)
185754f98da9SMariusz Zaborski NVLIST_GET(uint64_t, number, NUMBER)
185854f98da9SMariusz Zaborski NVLIST_GET(const char *, string, STRING)
185954f98da9SMariusz Zaborski NVLIST_GET(const nvlist_t *, nvlist, NVLIST)
186054f98da9SMariusz Zaborski #ifndef _KERNEL
186154f98da9SMariusz Zaborski NVLIST_GET(int, descriptor, DESCRIPTOR)
186254f98da9SMariusz Zaborski #endif
186354f98da9SMariusz Zaborski 
186454f98da9SMariusz Zaborski #undef	NVLIST_GET
186554f98da9SMariusz Zaborski 
186654f98da9SMariusz Zaborski const void *
186754f98da9SMariusz Zaborski nvlist_get_binary(const nvlist_t *nvl, const char *name, size_t *sizep)
186854f98da9SMariusz Zaborski {
186954f98da9SMariusz Zaborski 	nvpair_t *nvp;
187054f98da9SMariusz Zaborski 
187154f98da9SMariusz Zaborski 	nvp = nvlist_find(nvl, NV_TYPE_BINARY, name);
187254f98da9SMariusz Zaborski 	if (nvp == NULL)
187354f98da9SMariusz Zaborski 		nvlist_report_missing(NV_TYPE_BINARY, name);
187454f98da9SMariusz Zaborski 
187554f98da9SMariusz Zaborski 	return (nvpair_get_binary(nvp, sizep));
187654f98da9SMariusz Zaborski }
187754f98da9SMariusz Zaborski 
1878347a39b4SMariusz Zaborski #define	NVLIST_GET_ARRAY(ftype, type, TYPE)				\
1879347a39b4SMariusz Zaborski ftype									\
1880347a39b4SMariusz Zaborski nvlist_get_##type##_array(const nvlist_t *nvl, const char *name,	\
1881347a39b4SMariusz Zaborski     size_t *nitems)							\
1882347a39b4SMariusz Zaborski {									\
1883347a39b4SMariusz Zaborski 	const nvpair_t *nvp;						\
1884347a39b4SMariusz Zaborski 									\
1885347a39b4SMariusz Zaborski 	nvp = nvlist_find(nvl, NV_TYPE_##TYPE##_ARRAY, name);		\
1886347a39b4SMariusz Zaborski 	if (nvp == NULL)						\
1887347a39b4SMariusz Zaborski 		nvlist_report_missing(NV_TYPE_##TYPE##_ARRAY, name);	\
1888347a39b4SMariusz Zaborski 	return (nvpair_get_##type##_array(nvp, nitems));		\
1889347a39b4SMariusz Zaborski }
1890347a39b4SMariusz Zaborski 
1891347a39b4SMariusz Zaborski NVLIST_GET_ARRAY(const bool *, bool, BOOL)
1892347a39b4SMariusz Zaborski NVLIST_GET_ARRAY(const uint64_t *, number, NUMBER)
1893347a39b4SMariusz Zaborski NVLIST_GET_ARRAY(const char * const *, string, STRING)
1894347a39b4SMariusz Zaborski NVLIST_GET_ARRAY(const nvlist_t * const *, nvlist, NVLIST)
1895347a39b4SMariusz Zaborski #ifndef _KERNEL
1896347a39b4SMariusz Zaborski NVLIST_GET_ARRAY(const int *, descriptor, DESCRIPTOR)
1897347a39b4SMariusz Zaborski #endif
1898347a39b4SMariusz Zaborski 
1899347a39b4SMariusz Zaborski #undef	NVLIST_GET_ARRAY
1900347a39b4SMariusz Zaborski 
190154f98da9SMariusz Zaborski #define	NVLIST_TAKE(ftype, type, TYPE)					\
190254f98da9SMariusz Zaborski ftype									\
190354f98da9SMariusz Zaborski nvlist_take_##type(nvlist_t *nvl, const char *name)			\
190454f98da9SMariusz Zaborski {									\
190554f98da9SMariusz Zaborski 	nvpair_t *nvp;							\
190654f98da9SMariusz Zaborski 	ftype value;							\
190754f98da9SMariusz Zaborski 									\
190854f98da9SMariusz Zaborski 	nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name);			\
190954f98da9SMariusz Zaborski 	if (nvp == NULL)						\
191054f98da9SMariusz Zaborski 		nvlist_report_missing(NV_TYPE_##TYPE, name);		\
191154f98da9SMariusz Zaborski 	value = (ftype)(intptr_t)nvpair_get_##type(nvp);		\
191254f98da9SMariusz Zaborski 	nvlist_remove_nvpair(nvl, nvp);					\
191354f98da9SMariusz Zaborski 	nvpair_free_structure(nvp);					\
191454f98da9SMariusz Zaborski 	return (value);							\
191554f98da9SMariusz Zaborski }
191654f98da9SMariusz Zaborski 
191754f98da9SMariusz Zaborski NVLIST_TAKE(bool, bool, BOOL)
191854f98da9SMariusz Zaborski NVLIST_TAKE(uint64_t, number, NUMBER)
191954f98da9SMariusz Zaborski NVLIST_TAKE(char *, string, STRING)
192054f98da9SMariusz Zaborski NVLIST_TAKE(nvlist_t *, nvlist, NVLIST)
192154f98da9SMariusz Zaborski #ifndef _KERNEL
192254f98da9SMariusz Zaborski NVLIST_TAKE(int, descriptor, DESCRIPTOR)
192354f98da9SMariusz Zaborski #endif
192454f98da9SMariusz Zaborski 
192554f98da9SMariusz Zaborski #undef	NVLIST_TAKE
192654f98da9SMariusz Zaborski 
192754f98da9SMariusz Zaborski void *
192854f98da9SMariusz Zaborski nvlist_take_binary(nvlist_t *nvl, const char *name, size_t *sizep)
192954f98da9SMariusz Zaborski {
193054f98da9SMariusz Zaborski 	nvpair_t *nvp;
193154f98da9SMariusz Zaborski 	void *value;
193254f98da9SMariusz Zaborski 
193354f98da9SMariusz Zaborski 	nvp = nvlist_find(nvl, NV_TYPE_BINARY, name);
193454f98da9SMariusz Zaborski 	if (nvp == NULL)
193554f98da9SMariusz Zaborski 		nvlist_report_missing(NV_TYPE_BINARY, name);
193654f98da9SMariusz Zaborski 
193754f98da9SMariusz Zaborski 	value = (void *)(intptr_t)nvpair_get_binary(nvp, sizep);
193854f98da9SMariusz Zaborski 	nvlist_remove_nvpair(nvl, nvp);
193954f98da9SMariusz Zaborski 	nvpair_free_structure(nvp);
194054f98da9SMariusz Zaborski 	return (value);
194154f98da9SMariusz Zaborski }
194254f98da9SMariusz Zaborski 
1943347a39b4SMariusz Zaborski #define	NVLIST_TAKE_ARRAY(ftype, type, TYPE)				\
1944347a39b4SMariusz Zaborski ftype									\
1945347a39b4SMariusz Zaborski nvlist_take_##type##_array(nvlist_t *nvl, const char *name,		\
1946347a39b4SMariusz Zaborski     size_t *nitems)							\
1947347a39b4SMariusz Zaborski {									\
1948347a39b4SMariusz Zaborski 	nvpair_t *nvp;							\
1949347a39b4SMariusz Zaborski 	ftype value;							\
1950347a39b4SMariusz Zaborski 									\
1951347a39b4SMariusz Zaborski 	nvp = nvlist_find(nvl, NV_TYPE_##TYPE##_ARRAY, name);		\
1952347a39b4SMariusz Zaborski 	if (nvp == NULL)						\
1953347a39b4SMariusz Zaborski 		nvlist_report_missing(NV_TYPE_##TYPE##_ARRAY, name);	\
1954347a39b4SMariusz Zaborski 	value = (ftype)(intptr_t)nvpair_get_##type##_array(nvp, nitems);\
1955347a39b4SMariusz Zaborski 	nvlist_remove_nvpair(nvl, nvp);					\
1956347a39b4SMariusz Zaborski 	nvpair_free_structure(nvp);					\
1957347a39b4SMariusz Zaborski 	return (value);							\
1958347a39b4SMariusz Zaborski }
1959347a39b4SMariusz Zaborski 
1960347a39b4SMariusz Zaborski NVLIST_TAKE_ARRAY(bool *, bool, BOOL)
1961347a39b4SMariusz Zaborski NVLIST_TAKE_ARRAY(uint64_t *, number, NUMBER)
1962347a39b4SMariusz Zaborski NVLIST_TAKE_ARRAY(char **, string, STRING)
1963347a39b4SMariusz Zaborski NVLIST_TAKE_ARRAY(nvlist_t **, nvlist, NVLIST)
1964347a39b4SMariusz Zaborski #ifndef _KERNEL
1965347a39b4SMariusz Zaborski NVLIST_TAKE_ARRAY(int *, descriptor, DESCRIPTOR)
1966347a39b4SMariusz Zaborski #endif
1967347a39b4SMariusz Zaborski 
196854f98da9SMariusz Zaborski void
196954f98da9SMariusz Zaborski nvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp)
197054f98da9SMariusz Zaborski {
197154f98da9SMariusz Zaborski 
197254f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
197354f98da9SMariusz Zaborski 	NVPAIR_ASSERT(nvp);
197454f98da9SMariusz Zaborski 	PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
197554f98da9SMariusz Zaborski 
197654f98da9SMariusz Zaborski 	nvpair_remove(&nvl->nvl_head, nvp, nvl);
197754f98da9SMariusz Zaborski }
197854f98da9SMariusz Zaborski 
197954f98da9SMariusz Zaborski void
198054f98da9SMariusz Zaborski nvlist_free(nvlist_t *nvl, const char *name)
198154f98da9SMariusz Zaborski {
198254f98da9SMariusz Zaborski 
198354f98da9SMariusz Zaborski 	nvlist_free_type(nvl, name, NV_TYPE_NONE);
198454f98da9SMariusz Zaborski }
198554f98da9SMariusz Zaborski 
198654f98da9SMariusz Zaborski #define	NVLIST_FREE(type, TYPE)						\
198754f98da9SMariusz Zaborski void									\
198854f98da9SMariusz Zaborski nvlist_free_##type(nvlist_t *nvl, const char *name)			\
198954f98da9SMariusz Zaborski {									\
199054f98da9SMariusz Zaborski 									\
199154f98da9SMariusz Zaborski 	nvlist_free_type(nvl, name, NV_TYPE_##TYPE);			\
199254f98da9SMariusz Zaborski }
199354f98da9SMariusz Zaborski 
199454f98da9SMariusz Zaborski NVLIST_FREE(null, NULL)
199554f98da9SMariusz Zaborski NVLIST_FREE(bool, BOOL)
199654f98da9SMariusz Zaborski NVLIST_FREE(number, NUMBER)
199754f98da9SMariusz Zaborski NVLIST_FREE(string, STRING)
199854f98da9SMariusz Zaborski NVLIST_FREE(nvlist, NVLIST)
1999347a39b4SMariusz Zaborski NVLIST_FREE(binary, BINARY)
2000347a39b4SMariusz Zaborski NVLIST_FREE(bool_array, BOOL_ARRAY)
2001347a39b4SMariusz Zaborski NVLIST_FREE(number_array, NUMBER_ARRAY)
2002347a39b4SMariusz Zaborski NVLIST_FREE(string_array, STRING_ARRAY)
2003347a39b4SMariusz Zaborski NVLIST_FREE(nvlist_array, NVLIST_ARRAY)
200454f98da9SMariusz Zaborski #ifndef _KERNEL
200554f98da9SMariusz Zaborski NVLIST_FREE(descriptor, DESCRIPTOR)
2006347a39b4SMariusz Zaborski NVLIST_FREE(descriptor_array, DESCRIPTOR_ARRAY)
200754f98da9SMariusz Zaborski #endif
200854f98da9SMariusz Zaborski 
200954f98da9SMariusz Zaborski #undef	NVLIST_FREE
201054f98da9SMariusz Zaborski 
201154f98da9SMariusz Zaborski void
201254f98da9SMariusz Zaborski nvlist_free_nvpair(nvlist_t *nvl, nvpair_t *nvp)
201354f98da9SMariusz Zaborski {
201454f98da9SMariusz Zaborski 
201554f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
201654f98da9SMariusz Zaborski 	NVPAIR_ASSERT(nvp);
201754f98da9SMariusz Zaborski 	PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
201854f98da9SMariusz Zaborski 
201954f98da9SMariusz Zaborski 	nvlist_remove_nvpair(nvl, nvp);
202054f98da9SMariusz Zaborski 	nvpair_free(nvp);
202154f98da9SMariusz Zaborski }
202254f98da9SMariusz Zaborski 
2023