xref: /freebsd/sys/contrib/libnv/nvlist.c (revision 1b550329)
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 #define	_WITH_DPRINTF
5654f98da9SMariusz Zaborski #include <stdio.h>
5754f98da9SMariusz Zaborski #include <stdlib.h>
5854f98da9SMariusz Zaborski #include <string.h>
5954f98da9SMariusz Zaborski #include <unistd.h>
6054f98da9SMariusz Zaborski 
6154f98da9SMariusz Zaborski #include "msgio.h"
6254f98da9SMariusz Zaborski #endif
6354f98da9SMariusz Zaborski 
6454f98da9SMariusz Zaborski #ifdef HAVE_PJDLOG
6554f98da9SMariusz Zaborski #include <pjdlog.h>
6654f98da9SMariusz Zaborski #endif
6754f98da9SMariusz Zaborski 
6854f98da9SMariusz Zaborski #include <sys/nv.h>
6954f98da9SMariusz Zaborski 
7054f98da9SMariusz Zaborski #include "nv_impl.h"
7154f98da9SMariusz Zaborski #include "nvlist_impl.h"
7254f98da9SMariusz Zaborski #include "nvpair_impl.h"
7354f98da9SMariusz Zaborski 
7454f98da9SMariusz Zaborski #ifndef	HAVE_PJDLOG
7554f98da9SMariusz Zaborski #ifdef _KERNEL
7654f98da9SMariusz Zaborski #define	PJDLOG_ASSERT(...)		MPASS(__VA_ARGS__)
7754f98da9SMariusz Zaborski #define	PJDLOG_RASSERT(expr, ...)	KASSERT(expr, (__VA_ARGS__))
7854f98da9SMariusz Zaborski #define	PJDLOG_ABORT(...)		panic(__VA_ARGS__)
7954f98da9SMariusz Zaborski #else
8054f98da9SMariusz Zaborski #include <assert.h>
8154f98da9SMariusz Zaborski #define	PJDLOG_ASSERT(...)		assert(__VA_ARGS__)
8254f98da9SMariusz Zaborski #define	PJDLOG_RASSERT(expr, ...)	assert(expr)
8354f98da9SMariusz Zaborski #define	PJDLOG_ABORT(...)		do {				\
8454f98da9SMariusz Zaborski 	fprintf(stderr, "%s:%u: ", __FILE__, __LINE__);			\
8554f98da9SMariusz Zaborski 	fprintf(stderr, __VA_ARGS__);					\
8654f98da9SMariusz Zaborski 	fprintf(stderr, "\n");						\
8754f98da9SMariusz Zaborski 	abort();							\
8854f98da9SMariusz Zaborski } while (0)
8954f98da9SMariusz Zaborski #endif
9054f98da9SMariusz Zaborski #endif
9154f98da9SMariusz Zaborski 
92347a39b4SMariusz Zaborski #define	NV_FLAG_PRIVATE_MASK	(NV_FLAG_BIG_ENDIAN | NV_FLAG_IN_ARRAY)
9354f98da9SMariusz Zaborski #define	NV_FLAG_PUBLIC_MASK	(NV_FLAG_IGNORE_CASE | NV_FLAG_NO_UNIQUE)
9454f98da9SMariusz Zaborski #define	NV_FLAG_ALL_MASK	(NV_FLAG_PRIVATE_MASK | NV_FLAG_PUBLIC_MASK)
9554f98da9SMariusz Zaborski 
9654f98da9SMariusz Zaborski #define	NVLIST_MAGIC	0x6e766c	/* "nvl" */
9754f98da9SMariusz Zaborski struct nvlist {
9854f98da9SMariusz Zaborski 	int		 nvl_magic;
9954f98da9SMariusz Zaborski 	int		 nvl_error;
10054f98da9SMariusz Zaborski 	int		 nvl_flags;
10154f98da9SMariusz Zaborski 	nvpair_t	*nvl_parent;
102347a39b4SMariusz Zaborski 	nvpair_t	*nvl_array_next;
10354f98da9SMariusz Zaborski 	struct nvl_head	 nvl_head;
10454f98da9SMariusz Zaborski };
10554f98da9SMariusz Zaborski 
10654f98da9SMariusz Zaborski #define	NVLIST_ASSERT(nvl)	do {					\
10754f98da9SMariusz Zaborski 	PJDLOG_ASSERT((nvl) != NULL);					\
10854f98da9SMariusz Zaborski 	PJDLOG_ASSERT((nvl)->nvl_magic == NVLIST_MAGIC);		\
10954f98da9SMariusz Zaborski } while (0)
11054f98da9SMariusz Zaborski 
11154f98da9SMariusz Zaborski #ifdef _KERNEL
11254f98da9SMariusz Zaborski MALLOC_DEFINE(M_NVLIST, "nvlist", "kernel nvlist");
11354f98da9SMariusz Zaborski #endif
11454f98da9SMariusz Zaborski 
11554f98da9SMariusz Zaborski #define	NVPAIR_ASSERT(nvp)	nvpair_assert(nvp)
11654f98da9SMariusz Zaborski 
11754f98da9SMariusz Zaborski #define	NVLIST_HEADER_MAGIC	0x6c
11854f98da9SMariusz Zaborski #define	NVLIST_HEADER_VERSION	0x00
11954f98da9SMariusz Zaborski struct nvlist_header {
12054f98da9SMariusz Zaborski 	uint8_t		nvlh_magic;
12154f98da9SMariusz Zaborski 	uint8_t		nvlh_version;
12254f98da9SMariusz Zaborski 	uint8_t		nvlh_flags;
12354f98da9SMariusz Zaborski 	uint64_t	nvlh_descriptors;
12454f98da9SMariusz Zaborski 	uint64_t	nvlh_size;
12554f98da9SMariusz Zaborski } __packed;
12654f98da9SMariusz Zaborski 
12754f98da9SMariusz Zaborski nvlist_t *
12854f98da9SMariusz Zaborski nvlist_create(int flags)
12954f98da9SMariusz Zaborski {
13054f98da9SMariusz Zaborski 	nvlist_t *nvl;
13154f98da9SMariusz Zaborski 
13254f98da9SMariusz Zaborski 	PJDLOG_ASSERT((flags & ~(NV_FLAG_PUBLIC_MASK)) == 0);
13354f98da9SMariusz Zaborski 
13454f98da9SMariusz Zaborski 	nvl = nv_malloc(sizeof(*nvl));
13554f98da9SMariusz Zaborski 	if (nvl == NULL)
13654f98da9SMariusz Zaborski 		return (NULL);
13754f98da9SMariusz Zaborski 	nvl->nvl_error = 0;
13854f98da9SMariusz Zaborski 	nvl->nvl_flags = flags;
13954f98da9SMariusz Zaborski 	nvl->nvl_parent = NULL;
140347a39b4SMariusz Zaborski 	nvl->nvl_array_next = NULL;
14154f98da9SMariusz Zaborski 	TAILQ_INIT(&nvl->nvl_head);
14254f98da9SMariusz Zaborski 	nvl->nvl_magic = NVLIST_MAGIC;
14354f98da9SMariusz Zaborski 
14454f98da9SMariusz Zaborski 	return (nvl);
14554f98da9SMariusz Zaborski }
14654f98da9SMariusz Zaborski 
14754f98da9SMariusz Zaborski void
14854f98da9SMariusz Zaborski nvlist_destroy(nvlist_t *nvl)
14954f98da9SMariusz Zaborski {
15054f98da9SMariusz Zaborski 	nvpair_t *nvp;
15154f98da9SMariusz Zaborski 
15254f98da9SMariusz Zaborski 	if (nvl == NULL)
15354f98da9SMariusz Zaborski 		return;
15454f98da9SMariusz Zaborski 
15554f98da9SMariusz Zaborski 	ERRNO_SAVE();
15654f98da9SMariusz Zaborski 
15754f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
15854f98da9SMariusz Zaborski 
15954f98da9SMariusz Zaborski 	while ((nvp = nvlist_first_nvpair(nvl)) != NULL) {
16054f98da9SMariusz Zaborski 		nvlist_remove_nvpair(nvl, nvp);
16154f98da9SMariusz Zaborski 		nvpair_free(nvp);
16254f98da9SMariusz Zaborski 	}
163347a39b4SMariusz Zaborski 	if (nvl->nvl_array_next != NULL)
164347a39b4SMariusz Zaborski 		nvpair_free_structure(nvl->nvl_array_next);
165347a39b4SMariusz Zaborski 	nvl->nvl_array_next = NULL;
166347a39b4SMariusz Zaborski 	nvl->nvl_parent = NULL;
16754f98da9SMariusz Zaborski 	nvl->nvl_magic = 0;
16854f98da9SMariusz Zaborski 	nv_free(nvl);
16954f98da9SMariusz Zaborski 
17054f98da9SMariusz Zaborski 	ERRNO_RESTORE();
17154f98da9SMariusz Zaborski }
17254f98da9SMariusz Zaborski 
17354f98da9SMariusz Zaborski void
17454f98da9SMariusz Zaborski nvlist_set_error(nvlist_t *nvl, int error)
17554f98da9SMariusz Zaborski {
17654f98da9SMariusz Zaborski 
17754f98da9SMariusz Zaborski 	PJDLOG_ASSERT(error != 0);
17854f98da9SMariusz Zaborski 
17954f98da9SMariusz Zaborski 	/*
18054f98da9SMariusz Zaborski 	 * Check for error != 0 so that we don't do the wrong thing if somebody
18154f98da9SMariusz Zaborski 	 * tries to abuse this API when asserts are disabled.
18254f98da9SMariusz Zaborski 	 */
18354f98da9SMariusz Zaborski 	if (nvl != NULL && error != 0 && nvl->nvl_error == 0)
18454f98da9SMariusz Zaborski 		nvl->nvl_error = error;
18554f98da9SMariusz Zaborski }
18654f98da9SMariusz Zaborski 
18754f98da9SMariusz Zaborski int
18854f98da9SMariusz Zaborski nvlist_error(const nvlist_t *nvl)
18954f98da9SMariusz Zaborski {
19054f98da9SMariusz Zaborski 
19154f98da9SMariusz Zaborski 	if (nvl == NULL)
19254f98da9SMariusz Zaborski 		return (ENOMEM);
19354f98da9SMariusz Zaborski 
19454f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
19554f98da9SMariusz Zaborski 
19654f98da9SMariusz Zaborski 	return (nvl->nvl_error);
19754f98da9SMariusz Zaborski }
19854f98da9SMariusz Zaborski 
19954f98da9SMariusz Zaborski nvpair_t *
20054f98da9SMariusz Zaborski nvlist_get_nvpair_parent(const nvlist_t *nvl)
20154f98da9SMariusz Zaborski {
20254f98da9SMariusz Zaborski 
20354f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
20454f98da9SMariusz Zaborski 
20554f98da9SMariusz Zaborski 	return (nvl->nvl_parent);
20654f98da9SMariusz Zaborski }
20754f98da9SMariusz Zaborski 
20854f98da9SMariusz Zaborski const nvlist_t *
20954f98da9SMariusz Zaborski nvlist_get_parent(const nvlist_t *nvl, void **cookiep)
21054f98da9SMariusz Zaborski {
21154f98da9SMariusz Zaborski 	nvpair_t *nvp;
21254f98da9SMariusz Zaborski 
21354f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
21454f98da9SMariusz Zaborski 
21554f98da9SMariusz Zaborski 	nvp = nvl->nvl_parent;
21654f98da9SMariusz Zaborski 	if (cookiep != NULL)
21754f98da9SMariusz Zaborski 		*cookiep = nvp;
21854f98da9SMariusz Zaborski 	if (nvp == NULL)
21954f98da9SMariusz Zaborski 		return (NULL);
22054f98da9SMariusz Zaborski 
22154f98da9SMariusz Zaborski 	return (nvpair_nvlist(nvp));
22254f98da9SMariusz Zaborski }
22354f98da9SMariusz Zaborski 
22454f98da9SMariusz Zaborski void
22554f98da9SMariusz Zaborski nvlist_set_parent(nvlist_t *nvl, nvpair_t *parent)
22654f98da9SMariusz Zaborski {
22754f98da9SMariusz Zaborski 
22854f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
22954f98da9SMariusz Zaborski 
23054f98da9SMariusz Zaborski 	nvl->nvl_parent = parent;
23154f98da9SMariusz Zaborski }
23254f98da9SMariusz Zaborski 
233347a39b4SMariusz Zaborski void
234347a39b4SMariusz Zaborski nvlist_set_array_next(nvlist_t *nvl, nvpair_t *ele)
235347a39b4SMariusz Zaborski {
236347a39b4SMariusz Zaborski 
237347a39b4SMariusz Zaborski 	NVLIST_ASSERT(nvl);
238347a39b4SMariusz Zaborski 
2391b550329SMariusz Zaborski 	if (ele != NULL) {
240347a39b4SMariusz Zaborski 		nvl->nvl_flags |= NV_FLAG_IN_ARRAY;
2411b550329SMariusz Zaborski 	} else {
242347a39b4SMariusz Zaborski 		nvl->nvl_flags &= ~NV_FLAG_IN_ARRAY;
2431b550329SMariusz Zaborski 		nv_free(nvl->nvl_array_next);
2441b550329SMariusz Zaborski 	}
245347a39b4SMariusz Zaborski 
246347a39b4SMariusz Zaborski 	nvl->nvl_array_next = ele;
247347a39b4SMariusz Zaborski }
248347a39b4SMariusz Zaborski 
249347a39b4SMariusz Zaborski bool
250347a39b4SMariusz Zaborski nvlist_in_array(const nvlist_t *nvl)
251347a39b4SMariusz Zaborski {
252347a39b4SMariusz Zaborski 
253347a39b4SMariusz Zaborski 	NVLIST_ASSERT(nvl);
254347a39b4SMariusz Zaborski 
255347a39b4SMariusz Zaborski 	return ((nvl->nvl_flags & NV_FLAG_IN_ARRAY) != 0);
256347a39b4SMariusz Zaborski }
257347a39b4SMariusz Zaborski 
258347a39b4SMariusz Zaborski const nvlist_t *
259347a39b4SMariusz Zaborski nvlist_get_array_next(const nvlist_t *nvl)
260347a39b4SMariusz Zaborski {
261347a39b4SMariusz Zaborski 	nvpair_t *nvp;
262347a39b4SMariusz Zaborski 
263347a39b4SMariusz Zaborski 	NVLIST_ASSERT(nvl);
264347a39b4SMariusz Zaborski 
265347a39b4SMariusz Zaborski 	nvp = nvl->nvl_array_next;
266347a39b4SMariusz Zaborski 	if (nvp == NULL)
267347a39b4SMariusz Zaborski 		return (NULL);
268347a39b4SMariusz Zaborski 
269347a39b4SMariusz Zaborski 	return (nvpair_get_nvlist(nvp));
270347a39b4SMariusz Zaborski }
271347a39b4SMariusz Zaborski 
272347a39b4SMariusz Zaborski const nvlist_t *
273347a39b4SMariusz Zaborski nvlist_get_pararr(const nvlist_t *nvl, void **cookiep)
274347a39b4SMariusz Zaborski {
275347a39b4SMariusz Zaborski 	const nvlist_t *ret;
276347a39b4SMariusz Zaborski 
277347a39b4SMariusz Zaborski 	ret = nvlist_get_array_next(nvl);
278347a39b4SMariusz Zaborski 	if (ret != NULL) {
279347a39b4SMariusz Zaborski 		if (cookiep != NULL)
280347a39b4SMariusz Zaborski 			*cookiep = NULL;
281347a39b4SMariusz Zaborski 		return (ret);
282347a39b4SMariusz Zaborski 	}
283347a39b4SMariusz Zaborski 
284347a39b4SMariusz Zaborski 	ret = nvlist_get_parent(nvl, cookiep);
285347a39b4SMariusz Zaborski 	return (ret);
286347a39b4SMariusz Zaborski }
287347a39b4SMariusz Zaborski 
28854f98da9SMariusz Zaborski bool
28954f98da9SMariusz Zaborski nvlist_empty(const nvlist_t *nvl)
29054f98da9SMariusz Zaborski {
29154f98da9SMariusz Zaborski 
29254f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
29354f98da9SMariusz Zaborski 	PJDLOG_ASSERT(nvl->nvl_error == 0);
29454f98da9SMariusz Zaborski 
29554f98da9SMariusz Zaborski 	return (nvlist_first_nvpair(nvl) == NULL);
29654f98da9SMariusz Zaborski }
29754f98da9SMariusz Zaborski 
29854f98da9SMariusz Zaborski int
29954f98da9SMariusz Zaborski nvlist_flags(const nvlist_t *nvl)
30054f98da9SMariusz Zaborski {
30154f98da9SMariusz Zaborski 
30254f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
30354f98da9SMariusz Zaborski 	PJDLOG_ASSERT(nvl->nvl_error == 0);
30454f98da9SMariusz Zaborski 
305347a39b4SMariusz Zaborski 	return (nvl->nvl_flags & NV_FLAG_PUBLIC_MASK);
306347a39b4SMariusz Zaborski }
307347a39b4SMariusz Zaborski 
308347a39b4SMariusz Zaborski void
309347a39b4SMariusz Zaborski nvlist_set_flags(nvlist_t *nvl, int flags)
310347a39b4SMariusz Zaborski {
311347a39b4SMariusz Zaborski 
312347a39b4SMariusz Zaborski 	NVLIST_ASSERT(nvl);
313347a39b4SMariusz Zaborski 	PJDLOG_ASSERT(nvl->nvl_error == 0);
314347a39b4SMariusz Zaborski 
315347a39b4SMariusz Zaborski 	nvl->nvl_flags = flags;
31654f98da9SMariusz Zaborski }
31754f98da9SMariusz Zaborski 
31854f98da9SMariusz Zaborski static void
31954f98da9SMariusz Zaborski nvlist_report_missing(int type, const char *name)
32054f98da9SMariusz Zaborski {
32154f98da9SMariusz Zaborski 
32254f98da9SMariusz Zaborski 	PJDLOG_ABORT("Element '%s' of type %s doesn't exist.",
32354f98da9SMariusz Zaborski 	    name, nvpair_type_string(type));
32454f98da9SMariusz Zaborski }
32554f98da9SMariusz Zaborski 
32654f98da9SMariusz Zaborski static nvpair_t *
32754f98da9SMariusz Zaborski nvlist_find(const nvlist_t *nvl, int type, const char *name)
32854f98da9SMariusz Zaborski {
32954f98da9SMariusz Zaborski 	nvpair_t *nvp;
33054f98da9SMariusz Zaborski 
33154f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
33254f98da9SMariusz Zaborski 	PJDLOG_ASSERT(nvl->nvl_error == 0);
33354f98da9SMariusz Zaborski 	PJDLOG_ASSERT(type == NV_TYPE_NONE ||
33454f98da9SMariusz Zaborski 	    (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
33554f98da9SMariusz Zaborski 
33654f98da9SMariusz Zaborski 	for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
33754f98da9SMariusz Zaborski 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
33854f98da9SMariusz Zaborski 		if (type != NV_TYPE_NONE && nvpair_type(nvp) != type)
33954f98da9SMariusz Zaborski 			continue;
34054f98da9SMariusz Zaborski 		if ((nvl->nvl_flags & NV_FLAG_IGNORE_CASE) != 0) {
34154f98da9SMariusz Zaborski 			if (strcasecmp(nvpair_name(nvp), name) != 0)
34254f98da9SMariusz Zaborski 				continue;
34354f98da9SMariusz Zaborski 		} else {
34454f98da9SMariusz Zaborski 			if (strcmp(nvpair_name(nvp), name) != 0)
34554f98da9SMariusz Zaborski 				continue;
34654f98da9SMariusz Zaborski 		}
34754f98da9SMariusz Zaborski 		break;
34854f98da9SMariusz Zaborski 	}
34954f98da9SMariusz Zaborski 
35054f98da9SMariusz Zaborski 	if (nvp == NULL)
35154f98da9SMariusz Zaborski 		ERRNO_SET(ENOENT);
35254f98da9SMariusz Zaborski 
35354f98da9SMariusz Zaborski 	return (nvp);
35454f98da9SMariusz Zaborski }
35554f98da9SMariusz Zaborski 
35654f98da9SMariusz Zaborski bool
35754f98da9SMariusz Zaborski nvlist_exists_type(const nvlist_t *nvl, const char *name, int type)
35854f98da9SMariusz Zaborski {
35954f98da9SMariusz Zaborski 
36054f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
36154f98da9SMariusz Zaborski 	PJDLOG_ASSERT(nvl->nvl_error == 0);
36254f98da9SMariusz Zaborski 	PJDLOG_ASSERT(type == NV_TYPE_NONE ||
36354f98da9SMariusz Zaborski 	    (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
36454f98da9SMariusz Zaborski 
36554f98da9SMariusz Zaborski 	return (nvlist_find(nvl, type, name) != NULL);
36654f98da9SMariusz Zaborski }
36754f98da9SMariusz Zaborski 
36854f98da9SMariusz Zaborski void
36954f98da9SMariusz Zaborski nvlist_free_type(nvlist_t *nvl, const char *name, int type)
37054f98da9SMariusz Zaborski {
37154f98da9SMariusz Zaborski 	nvpair_t *nvp;
37254f98da9SMariusz Zaborski 
37354f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
37454f98da9SMariusz Zaborski 	PJDLOG_ASSERT(nvl->nvl_error == 0);
37554f98da9SMariusz Zaborski 	PJDLOG_ASSERT(type == NV_TYPE_NONE ||
37654f98da9SMariusz Zaborski 	    (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
37754f98da9SMariusz Zaborski 
37854f98da9SMariusz Zaborski 	nvp = nvlist_find(nvl, type, name);
37954f98da9SMariusz Zaborski 	if (nvp != NULL)
38054f98da9SMariusz Zaborski 		nvlist_free_nvpair(nvl, nvp);
38154f98da9SMariusz Zaborski 	else
38254f98da9SMariusz Zaborski 		nvlist_report_missing(type, name);
38354f98da9SMariusz Zaborski }
38454f98da9SMariusz Zaborski 
38554f98da9SMariusz Zaborski nvlist_t *
38654f98da9SMariusz Zaborski nvlist_clone(const nvlist_t *nvl)
38754f98da9SMariusz Zaborski {
38854f98da9SMariusz Zaborski 	nvlist_t *newnvl;
38954f98da9SMariusz Zaborski 	nvpair_t *nvp, *newnvp;
39054f98da9SMariusz Zaborski 
39154f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
39254f98da9SMariusz Zaborski 
39354f98da9SMariusz Zaborski 	if (nvl->nvl_error != 0) {
39454f98da9SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
39554f98da9SMariusz Zaborski 		return (NULL);
39654f98da9SMariusz Zaborski 	}
39754f98da9SMariusz Zaborski 
39854f98da9SMariusz Zaborski 	newnvl = nvlist_create(nvl->nvl_flags & NV_FLAG_PUBLIC_MASK);
39954f98da9SMariusz Zaborski 	for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
40054f98da9SMariusz Zaborski 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
40154f98da9SMariusz Zaborski 		newnvp = nvpair_clone(nvp);
40254f98da9SMariusz Zaborski 		if (newnvp == NULL)
40354f98da9SMariusz Zaborski 			break;
40430740f45SMariusz Zaborski 		(void)nvlist_move_nvpair(newnvl, newnvp);
40554f98da9SMariusz Zaborski 	}
40654f98da9SMariusz Zaborski 	if (nvp != NULL) {
40754f98da9SMariusz Zaborski 		nvlist_destroy(newnvl);
40854f98da9SMariusz Zaborski 		return (NULL);
40954f98da9SMariusz Zaborski 	}
41054f98da9SMariusz Zaborski 	return (newnvl);
41154f98da9SMariusz Zaborski }
41254f98da9SMariusz Zaborski 
41354f98da9SMariusz Zaborski #ifndef _KERNEL
41454f98da9SMariusz Zaborski static bool
41554f98da9SMariusz Zaborski nvlist_dump_error_check(const nvlist_t *nvl, int fd, int level)
41654f98da9SMariusz Zaborski {
41754f98da9SMariusz Zaborski 
41854f98da9SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
41954f98da9SMariusz Zaborski 		dprintf(fd, "%*serror: %d\n", level * 4, "",
42054f98da9SMariusz Zaborski 		    nvlist_error(nvl));
42154f98da9SMariusz Zaborski 		return (true);
42254f98da9SMariusz Zaborski 	}
42354f98da9SMariusz Zaborski 
42454f98da9SMariusz Zaborski 	return (false);
42554f98da9SMariusz Zaborski }
42654f98da9SMariusz Zaborski 
42754f98da9SMariusz Zaborski /*
42854f98da9SMariusz Zaborski  * Dump content of nvlist.
42954f98da9SMariusz Zaborski  */
43054f98da9SMariusz Zaborski void
43154f98da9SMariusz Zaborski nvlist_dump(const nvlist_t *nvl, int fd)
43254f98da9SMariusz Zaborski {
43354f98da9SMariusz Zaborski 	const nvlist_t *tmpnvl;
43454f98da9SMariusz Zaborski 	nvpair_t *nvp, *tmpnvp;
43554f98da9SMariusz Zaborski 	void *cookie;
43654f98da9SMariusz Zaborski 	int level;
43754f98da9SMariusz Zaborski 
43854f98da9SMariusz Zaborski 	level = 0;
43954f98da9SMariusz Zaborski 	if (nvlist_dump_error_check(nvl, fd, level))
44054f98da9SMariusz Zaborski 		return;
44154f98da9SMariusz Zaborski 
44254f98da9SMariusz Zaborski 	nvp = nvlist_first_nvpair(nvl);
44354f98da9SMariusz Zaborski 	while (nvp != NULL) {
44454f98da9SMariusz Zaborski 		dprintf(fd, "%*s%s (%s):", level * 4, "", nvpair_name(nvp),
44554f98da9SMariusz Zaborski 		    nvpair_type_string(nvpair_type(nvp)));
44654f98da9SMariusz Zaborski 		switch (nvpair_type(nvp)) {
44754f98da9SMariusz Zaborski 		case NV_TYPE_NULL:
44854f98da9SMariusz Zaborski 			dprintf(fd, " null\n");
44954f98da9SMariusz Zaborski 			break;
45054f98da9SMariusz Zaborski 		case NV_TYPE_BOOL:
45154f98da9SMariusz Zaborski 			dprintf(fd, " %s\n", nvpair_get_bool(nvp) ?
45254f98da9SMariusz Zaborski 			    "TRUE" : "FALSE");
45354f98da9SMariusz Zaborski 			break;
45454f98da9SMariusz Zaborski 		case NV_TYPE_NUMBER:
45554f98da9SMariusz Zaborski 			dprintf(fd, " %ju (%jd) (0x%jx)\n",
45654f98da9SMariusz Zaborski 			    (uintmax_t)nvpair_get_number(nvp),
45754f98da9SMariusz Zaborski 			    (intmax_t)nvpair_get_number(nvp),
45854f98da9SMariusz Zaborski 			    (uintmax_t)nvpair_get_number(nvp));
45954f98da9SMariusz Zaborski 			break;
46054f98da9SMariusz Zaborski 		case NV_TYPE_STRING:
46154f98da9SMariusz Zaborski 			dprintf(fd, " [%s]\n", nvpair_get_string(nvp));
46254f98da9SMariusz Zaborski 			break;
46354f98da9SMariusz Zaborski 		case NV_TYPE_NVLIST:
46454f98da9SMariusz Zaborski 			dprintf(fd, "\n");
46554f98da9SMariusz Zaborski 			tmpnvl = nvpair_get_nvlist(nvp);
46654f98da9SMariusz Zaborski 			if (nvlist_dump_error_check(tmpnvl, fd, level + 1))
46754f98da9SMariusz Zaborski 				break;
46854f98da9SMariusz Zaborski 			tmpnvp = nvlist_first_nvpair(tmpnvl);
46954f98da9SMariusz Zaborski 			if (tmpnvp != NULL) {
47054f98da9SMariusz Zaborski 				nvl = tmpnvl;
47154f98da9SMariusz Zaborski 				nvp = tmpnvp;
47254f98da9SMariusz Zaborski 				level++;
47354f98da9SMariusz Zaborski 				continue;
47454f98da9SMariusz Zaborski 			}
47554f98da9SMariusz Zaborski 			break;
47654f98da9SMariusz Zaborski 		case NV_TYPE_DESCRIPTOR:
47754f98da9SMariusz Zaborski 			dprintf(fd, " %d\n", nvpair_get_descriptor(nvp));
47854f98da9SMariusz Zaborski 			break;
47954f98da9SMariusz Zaborski 		case NV_TYPE_BINARY:
48054f98da9SMariusz Zaborski 		    {
48154f98da9SMariusz Zaborski 			const unsigned char *binary;
48254f98da9SMariusz Zaborski 			unsigned int ii;
48354f98da9SMariusz Zaborski 			size_t size;
48454f98da9SMariusz Zaborski 
48554f98da9SMariusz Zaborski 			binary = nvpair_get_binary(nvp, &size);
48654f98da9SMariusz Zaborski 			dprintf(fd, " %zu ", size);
48754f98da9SMariusz Zaborski 			for (ii = 0; ii < size; ii++)
48854f98da9SMariusz Zaborski 				dprintf(fd, "%02hhx", binary[ii]);
48954f98da9SMariusz Zaborski 			dprintf(fd, "\n");
49054f98da9SMariusz Zaborski 			break;
49154f98da9SMariusz Zaborski 		    }
492347a39b4SMariusz Zaborski 		case NV_TYPE_BOOL_ARRAY:
493347a39b4SMariusz Zaborski 		    {
494347a39b4SMariusz Zaborski 			const bool *value;
495347a39b4SMariusz Zaborski 			unsigned int ii;
496347a39b4SMariusz Zaborski 			size_t nitems;
497347a39b4SMariusz Zaborski 
498347a39b4SMariusz Zaborski 			value = nvpair_get_bool_array(nvp, &nitems);
499347a39b4SMariusz Zaborski 			dprintf(fd, " [ ");
500347a39b4SMariusz Zaborski 			for (ii = 0; ii < nitems; ii++) {
501347a39b4SMariusz Zaborski 				dprintf(fd, "%s", value[ii] ? "TRUE" : "FALSE");
502347a39b4SMariusz Zaborski 				if (ii != nitems - 1)
503347a39b4SMariusz Zaborski 					dprintf(fd, ", ");
504347a39b4SMariusz Zaborski 			}
505347a39b4SMariusz Zaborski 			dprintf(fd, " ]\n");
506347a39b4SMariusz Zaborski 			break;
507347a39b4SMariusz Zaborski 		    }
508347a39b4SMariusz Zaborski 		case NV_TYPE_STRING_ARRAY:
509347a39b4SMariusz Zaborski 		    {
510347a39b4SMariusz Zaborski 			const char * const *value;
511347a39b4SMariusz Zaborski 			unsigned int ii;
512347a39b4SMariusz Zaborski 			size_t nitems;
513347a39b4SMariusz Zaborski 
514347a39b4SMariusz Zaborski 			value = nvpair_get_string_array(nvp, &nitems);
515347a39b4SMariusz Zaborski 			dprintf(fd, " [ ");
516347a39b4SMariusz Zaborski 			for (ii = 0; ii < nitems; ii++) {
517347a39b4SMariusz Zaborski 				if (value[ii] == NULL)
518347a39b4SMariusz Zaborski 					dprintf(fd, "NULL");
519347a39b4SMariusz Zaborski 				else
520347a39b4SMariusz Zaborski 					dprintf(fd, "\"%s\"", value[ii]);
521347a39b4SMariusz Zaborski 				if (ii != nitems - 1)
522347a39b4SMariusz Zaborski 					dprintf(fd, ", ");
523347a39b4SMariusz Zaborski 			}
524347a39b4SMariusz Zaborski 			dprintf(fd, " ]\n");
525347a39b4SMariusz Zaborski 			break;
526347a39b4SMariusz Zaborski 		    }
527347a39b4SMariusz Zaborski 		case NV_TYPE_NUMBER_ARRAY:
528347a39b4SMariusz Zaborski 		    {
529347a39b4SMariusz Zaborski 			const uint64_t *value;
530347a39b4SMariusz Zaborski 			unsigned int ii;
531347a39b4SMariusz Zaborski 			size_t nitems;
532347a39b4SMariusz Zaborski 
533347a39b4SMariusz Zaborski 			value = nvpair_get_number_array(nvp, &nitems);
534347a39b4SMariusz Zaborski 			dprintf(fd, " [ ");
535347a39b4SMariusz Zaborski 			for (ii = 0; ii < nitems; ii++) {
536347a39b4SMariusz Zaborski 				dprintf(fd, "%ju (%jd) (0x%jx)",
537347a39b4SMariusz Zaborski 				    value[ii], value[ii], value[ii]);
538347a39b4SMariusz Zaborski 				if (ii != nitems - 1)
539347a39b4SMariusz Zaborski 					dprintf(fd, ", ");
540347a39b4SMariusz Zaborski 			}
541347a39b4SMariusz Zaborski 			dprintf(fd, " ]\n");
542347a39b4SMariusz Zaborski 			break;
543347a39b4SMariusz Zaborski 		    }
544347a39b4SMariusz Zaborski 		case NV_TYPE_DESCRIPTOR_ARRAY:
545347a39b4SMariusz Zaborski 		    {
546347a39b4SMariusz Zaborski 			const int *value;
547347a39b4SMariusz Zaborski 			unsigned int ii;
548347a39b4SMariusz Zaborski 			size_t nitems;
549347a39b4SMariusz Zaborski 
550347a39b4SMariusz Zaborski 			value = nvpair_get_descriptor_array(nvp, &nitems);
551347a39b4SMariusz Zaborski 			dprintf(fd, " [ ");
552347a39b4SMariusz Zaborski 			for (ii = 0; ii < nitems; ii++) {
553347a39b4SMariusz Zaborski 				dprintf(fd, "%d", value[ii]);
554347a39b4SMariusz Zaborski 				if (ii != nitems - 1)
555347a39b4SMariusz Zaborski 					dprintf(fd, ", ");
556347a39b4SMariusz Zaborski 			}
557347a39b4SMariusz Zaborski 			dprintf(fd, " ]\n");
558347a39b4SMariusz Zaborski 			break;
559347a39b4SMariusz Zaborski 		    }
560347a39b4SMariusz Zaborski 		case NV_TYPE_NVLIST_ARRAY:
561347a39b4SMariusz Zaborski 		    {
562347a39b4SMariusz Zaborski 			const nvlist_t * const *value;
563347a39b4SMariusz Zaborski 			unsigned int ii;
564347a39b4SMariusz Zaborski 			size_t nitems;
565347a39b4SMariusz Zaborski 
566347a39b4SMariusz Zaborski 			value = nvpair_get_nvlist_array(nvp, &nitems);
567347a39b4SMariusz Zaborski 			dprintf(fd, " %zu\n", nitems);
568347a39b4SMariusz Zaborski 			tmpnvl = NULL;
569347a39b4SMariusz Zaborski 			tmpnvp = NULL;
570347a39b4SMariusz Zaborski 			for (ii = 0; ii < nitems; ii++) {
571347a39b4SMariusz Zaborski 				if (nvlist_dump_error_check(value[ii], fd,
572347a39b4SMariusz Zaborski 				    level + 1)) {
573347a39b4SMariusz Zaborski 					break;
574347a39b4SMariusz Zaborski 				}
575347a39b4SMariusz Zaborski 
576347a39b4SMariusz Zaborski 				if (tmpnvl == NULL) {
577347a39b4SMariusz Zaborski 					tmpnvp = nvlist_first_nvpair(value[ii]);
578347a39b4SMariusz Zaborski 					if (tmpnvp != NULL) {
579347a39b4SMariusz Zaborski 						tmpnvl = value[ii];
580347a39b4SMariusz Zaborski 					} else {
581347a39b4SMariusz Zaborski 						dprintf(fd, "%*s,\n",
582347a39b4SMariusz Zaborski 						    (level + 1) * 4, "");
583347a39b4SMariusz Zaborski 					}
584347a39b4SMariusz Zaborski 				}
585347a39b4SMariusz Zaborski 			}
586347a39b4SMariusz Zaborski 			if (tmpnvp != NULL) {
587347a39b4SMariusz Zaborski 				nvl = tmpnvl;
588347a39b4SMariusz Zaborski 				nvp = tmpnvp;
589347a39b4SMariusz Zaborski 				level++;
590347a39b4SMariusz Zaborski 				continue;
591347a39b4SMariusz Zaborski 			}
592347a39b4SMariusz Zaborski 			break;
593347a39b4SMariusz Zaborski 		    }
59454f98da9SMariusz Zaborski 		default:
59554f98da9SMariusz Zaborski 			PJDLOG_ABORT("Unknown type: %d.", nvpair_type(nvp));
59654f98da9SMariusz Zaborski 		}
59754f98da9SMariusz Zaborski 
59854f98da9SMariusz Zaborski 		while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
599347a39b4SMariusz Zaborski 			do {
60054f98da9SMariusz Zaborski 				cookie = NULL;
601347a39b4SMariusz Zaborski 				if (nvlist_in_array(nvl))
602347a39b4SMariusz Zaborski 					dprintf(fd, "%*s,\n", level * 4, "");
603347a39b4SMariusz Zaborski 				nvl = nvlist_get_pararr(nvl, &cookie);
60454f98da9SMariusz Zaborski 				if (nvl == NULL)
60554f98da9SMariusz Zaborski 					return;
606347a39b4SMariusz Zaborski 				if (nvlist_in_array(nvl) && cookie == NULL) {
607347a39b4SMariusz Zaborski 					nvp = nvlist_first_nvpair(nvl);
608347a39b4SMariusz Zaborski 				} else {
60954f98da9SMariusz Zaborski 					nvp = cookie;
61054f98da9SMariusz Zaborski 					level--;
61154f98da9SMariusz Zaborski 				}
612347a39b4SMariusz Zaborski 			} while (nvp == NULL);
613347a39b4SMariusz Zaborski 			if (nvlist_in_array(nvl) && cookie == NULL)
614347a39b4SMariusz Zaborski 				break;
615347a39b4SMariusz Zaborski 		}
61654f98da9SMariusz Zaborski 	}
61754f98da9SMariusz Zaborski }
61854f98da9SMariusz Zaborski 
61954f98da9SMariusz Zaborski void
62054f98da9SMariusz Zaborski nvlist_fdump(const nvlist_t *nvl, FILE *fp)
62154f98da9SMariusz Zaborski {
62254f98da9SMariusz Zaborski 
62354f98da9SMariusz Zaborski 	fflush(fp);
62454f98da9SMariusz Zaborski 	nvlist_dump(nvl, fileno(fp));
62554f98da9SMariusz Zaborski }
62654f98da9SMariusz Zaborski #endif
62754f98da9SMariusz Zaborski 
62854f98da9SMariusz Zaborski /*
62954f98da9SMariusz Zaborski  * The function obtains size of the nvlist after nvlist_pack().
63054f98da9SMariusz Zaborski  */
63154f98da9SMariusz Zaborski size_t
63254f98da9SMariusz Zaborski nvlist_size(const nvlist_t *nvl)
63354f98da9SMariusz Zaborski {
63454f98da9SMariusz Zaborski 	const nvlist_t *tmpnvl;
635347a39b4SMariusz Zaborski 	const nvlist_t * const *nvlarray;
63654f98da9SMariusz Zaborski 	const nvpair_t *nvp, *tmpnvp;
63754f98da9SMariusz Zaborski 	void *cookie;
638347a39b4SMariusz Zaborski 	size_t size, nitems;
639347a39b4SMariusz Zaborski 	unsigned int ii;
64054f98da9SMariusz Zaborski 
64154f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
64254f98da9SMariusz Zaborski 	PJDLOG_ASSERT(nvl->nvl_error == 0);
64354f98da9SMariusz Zaborski 
64454f98da9SMariusz Zaborski 	size = sizeof(struct nvlist_header);
64554f98da9SMariusz Zaborski 	nvp = nvlist_first_nvpair(nvl);
64654f98da9SMariusz Zaborski 	while (nvp != NULL) {
64754f98da9SMariusz Zaborski 		size += nvpair_header_size();
64854f98da9SMariusz Zaborski 		size += strlen(nvpair_name(nvp)) + 1;
64954f98da9SMariusz Zaborski 		if (nvpair_type(nvp) == NV_TYPE_NVLIST) {
65054f98da9SMariusz Zaborski 			size += sizeof(struct nvlist_header);
65154f98da9SMariusz Zaborski 			size += nvpair_header_size() + 1;
65254f98da9SMariusz Zaborski 			tmpnvl = nvpair_get_nvlist(nvp);
65354f98da9SMariusz Zaborski 			PJDLOG_ASSERT(tmpnvl->nvl_error == 0);
65454f98da9SMariusz Zaborski 			tmpnvp = nvlist_first_nvpair(tmpnvl);
65554f98da9SMariusz Zaborski 			if (tmpnvp != NULL) {
65654f98da9SMariusz Zaborski 				nvl = tmpnvl;
65754f98da9SMariusz Zaborski 				nvp = tmpnvp;
65854f98da9SMariusz Zaborski 				continue;
65954f98da9SMariusz Zaborski 			}
660347a39b4SMariusz Zaborski 		} else if (nvpair_type(nvp) == NV_TYPE_NVLIST_ARRAY) {
661347a39b4SMariusz Zaborski 			nvlarray = nvpair_get_nvlist_array(nvp, &nitems);
662347a39b4SMariusz Zaborski 			PJDLOG_ASSERT(nitems > 0);
663347a39b4SMariusz Zaborski 
664347a39b4SMariusz Zaborski 			size += (nvpair_header_size() + 1) * nitems;
665347a39b4SMariusz Zaborski 			size += sizeof(struct nvlist_header) * nitems;
666347a39b4SMariusz Zaborski 
667347a39b4SMariusz Zaborski 			tmpnvl = NULL;
668347a39b4SMariusz Zaborski 			tmpnvp = NULL;
669347a39b4SMariusz Zaborski 			for (ii = 0; ii < nitems; ii++) {
670347a39b4SMariusz Zaborski 				PJDLOG_ASSERT(nvlarray[ii]->nvl_error == 0);
671347a39b4SMariusz Zaborski 				tmpnvp = nvlist_first_nvpair(nvlarray[ii]);
672347a39b4SMariusz Zaborski 				if (tmpnvp != NULL) {
673347a39b4SMariusz Zaborski 					tmpnvl = nvlarray[ii];
674347a39b4SMariusz Zaborski 					break;
675347a39b4SMariusz Zaborski 				}
676347a39b4SMariusz Zaborski 			}
677347a39b4SMariusz Zaborski 			if (tmpnvp != NULL) {
678347a39b4SMariusz Zaborski 				nvp = tmpnvp;
679347a39b4SMariusz Zaborski 				nvl = tmpnvl;
680347a39b4SMariusz Zaborski 				continue;
681347a39b4SMariusz Zaborski 			}
682347a39b4SMariusz Zaborski 
68354f98da9SMariusz Zaborski 		} else {
68454f98da9SMariusz Zaborski 			size += nvpair_size(nvp);
68554f98da9SMariusz Zaborski 		}
68654f98da9SMariusz Zaborski 
68754f98da9SMariusz Zaborski 		while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
688347a39b4SMariusz Zaborski 			do {
68954f98da9SMariusz Zaborski 				cookie = NULL;
690347a39b4SMariusz Zaborski 				nvl = nvlist_get_pararr(nvl, &cookie);
69154f98da9SMariusz Zaborski 				if (nvl == NULL)
69254f98da9SMariusz Zaborski 					goto out;
693347a39b4SMariusz Zaborski 				if (nvlist_in_array(nvl) && cookie == NULL) {
694347a39b4SMariusz Zaborski 					nvp = nvlist_first_nvpair(nvl);
695347a39b4SMariusz Zaborski 				} else {
69654f98da9SMariusz Zaborski 					nvp = cookie;
69754f98da9SMariusz Zaborski 				}
698347a39b4SMariusz Zaborski 			} while (nvp == NULL);
699347a39b4SMariusz Zaborski 			if (nvlist_in_array(nvl) && cookie == NULL)
700347a39b4SMariusz Zaborski 				break;
701347a39b4SMariusz Zaborski 		}
70254f98da9SMariusz Zaborski 	}
70354f98da9SMariusz Zaborski 
70454f98da9SMariusz Zaborski out:
70554f98da9SMariusz Zaborski 	return (size);
70654f98da9SMariusz Zaborski }
70754f98da9SMariusz Zaborski 
70854f98da9SMariusz Zaborski #ifndef _KERNEL
70954f98da9SMariusz Zaborski static int *
71054f98da9SMariusz Zaborski nvlist_xdescriptors(const nvlist_t *nvl, int *descs)
71154f98da9SMariusz Zaborski {
71254f98da9SMariusz Zaborski 	nvpair_t *nvp;
71354f98da9SMariusz Zaborski 	const char *name;
71454f98da9SMariusz Zaborski 	int type;
71554f98da9SMariusz Zaborski 
71654f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
71754f98da9SMariusz Zaborski 	PJDLOG_ASSERT(nvl->nvl_error == 0);
71854f98da9SMariusz Zaborski 
71954f98da9SMariusz Zaborski 	nvp = NULL;
72054f98da9SMariusz Zaborski 	do {
72154f98da9SMariusz Zaborski 		while ((name = nvlist_next(nvl, &type, (void**)&nvp)) != NULL) {
72254f98da9SMariusz Zaborski 			switch (type) {
72354f98da9SMariusz Zaborski 			case NV_TYPE_DESCRIPTOR:
72454f98da9SMariusz Zaborski 				*descs = nvpair_get_descriptor(nvp);
72554f98da9SMariusz Zaborski 				descs++;
72654f98da9SMariusz Zaborski 				break;
727347a39b4SMariusz Zaborski 			case NV_TYPE_DESCRIPTOR_ARRAY:
728347a39b4SMariusz Zaborski 			    {
729347a39b4SMariusz Zaborski 				const int *value;
730347a39b4SMariusz Zaborski 				size_t nitems;
731347a39b4SMariusz Zaborski 				unsigned int ii;
732347a39b4SMariusz Zaborski 
733347a39b4SMariusz Zaborski 				value = nvpair_get_descriptor_array(nvp,
734347a39b4SMariusz Zaborski 				    &nitems);
735347a39b4SMariusz Zaborski 				for (ii = 0; ii < nitems; ii++) {
736347a39b4SMariusz Zaborski 					*descs = value[ii];
737347a39b4SMariusz Zaborski 					descs++;
738347a39b4SMariusz Zaborski 				}
739347a39b4SMariusz Zaborski 				break;
740347a39b4SMariusz Zaborski 			    }
74154f98da9SMariusz Zaborski 			case NV_TYPE_NVLIST:
74254f98da9SMariusz Zaborski 				nvl = nvpair_get_nvlist(nvp);
74354f98da9SMariusz Zaborski 				nvp = NULL;
74454f98da9SMariusz Zaborski 				break;
745347a39b4SMariusz Zaborski 			case NV_TYPE_NVLIST_ARRAY:
746347a39b4SMariusz Zaborski 			    {
747347a39b4SMariusz Zaborski 				const nvlist_t * const *value;
748347a39b4SMariusz Zaborski 				size_t nitems;
749347a39b4SMariusz Zaborski 
750347a39b4SMariusz Zaborski 				value = nvpair_get_nvlist_array(nvp, &nitems);
751347a39b4SMariusz Zaborski 				PJDLOG_ASSERT(value != NULL);
752347a39b4SMariusz Zaborski 				PJDLOG_ASSERT(nitems > 0);
753347a39b4SMariusz Zaborski 
754347a39b4SMariusz Zaborski 				nvl = value[0];
755347a39b4SMariusz Zaborski 				nvp = NULL;
756347a39b4SMariusz Zaborski 				break;
75754f98da9SMariusz Zaborski 			    }
75854f98da9SMariusz Zaborski 			}
759347a39b4SMariusz Zaborski 		}
760347a39b4SMariusz Zaborski 	} while ((nvl = nvlist_get_pararr(nvl, (void**)&nvp)) != NULL);
76154f98da9SMariusz Zaborski 
76254f98da9SMariusz Zaborski 	return (descs);
76354f98da9SMariusz Zaborski }
76454f98da9SMariusz Zaborski #endif
76554f98da9SMariusz Zaborski 
76654f98da9SMariusz Zaborski #ifndef _KERNEL
76754f98da9SMariusz Zaborski int *
76854f98da9SMariusz Zaborski nvlist_descriptors(const nvlist_t *nvl, size_t *nitemsp)
76954f98da9SMariusz Zaborski {
77054f98da9SMariusz Zaborski 	size_t nitems;
77154f98da9SMariusz Zaborski 	int *fds;
77254f98da9SMariusz Zaborski 
77354f98da9SMariusz Zaborski 	nitems = nvlist_ndescriptors(nvl);
77454f98da9SMariusz Zaborski 	fds = nv_malloc(sizeof(fds[0]) * (nitems + 1));
77554f98da9SMariusz Zaborski 	if (fds == NULL)
77654f98da9SMariusz Zaborski 		return (NULL);
77754f98da9SMariusz Zaborski 	if (nitems > 0)
77854f98da9SMariusz Zaborski 		nvlist_xdescriptors(nvl, fds);
77954f98da9SMariusz Zaborski 	fds[nitems] = -1;
78054f98da9SMariusz Zaborski 	if (nitemsp != NULL)
78154f98da9SMariusz Zaborski 		*nitemsp = nitems;
78254f98da9SMariusz Zaborski 	return (fds);
78354f98da9SMariusz Zaborski }
78454f98da9SMariusz Zaborski #endif
78554f98da9SMariusz Zaborski 
78654f98da9SMariusz Zaborski size_t
78754f98da9SMariusz Zaborski nvlist_ndescriptors(const nvlist_t *nvl)
78854f98da9SMariusz Zaborski {
78954f98da9SMariusz Zaborski #ifndef _KERNEL
79054f98da9SMariusz Zaborski 	nvpair_t *nvp;
79154f98da9SMariusz Zaborski 	const char *name;
79254f98da9SMariusz Zaborski 	size_t ndescs;
79354f98da9SMariusz Zaborski 	int type;
79454f98da9SMariusz Zaborski 
79554f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
79654f98da9SMariusz Zaborski 	PJDLOG_ASSERT(nvl->nvl_error == 0);
79754f98da9SMariusz Zaborski 
79854f98da9SMariusz Zaborski 	ndescs = 0;
79954f98da9SMariusz Zaborski 	nvp = NULL;
80054f98da9SMariusz Zaborski 	do {
80154f98da9SMariusz Zaborski 		while ((name = nvlist_next(nvl, &type, (void**)&nvp)) != NULL) {
80254f98da9SMariusz Zaborski 			switch (type) {
80354f98da9SMariusz Zaborski 			case NV_TYPE_DESCRIPTOR:
80454f98da9SMariusz Zaborski 				ndescs++;
80554f98da9SMariusz Zaborski 				break;
80654f98da9SMariusz Zaborski 			case NV_TYPE_NVLIST:
80754f98da9SMariusz Zaborski 				nvl = nvpair_get_nvlist(nvp);
80854f98da9SMariusz Zaborski 				nvp = NULL;
80954f98da9SMariusz Zaborski 				break;
810347a39b4SMariusz Zaborski 			case NV_TYPE_NVLIST_ARRAY:
811347a39b4SMariusz Zaborski 			    {
812347a39b4SMariusz Zaborski 				const nvlist_t * const *value;
813347a39b4SMariusz Zaborski 				size_t nitems;
814347a39b4SMariusz Zaborski 
815347a39b4SMariusz Zaborski 				value = nvpair_get_nvlist_array(nvp, &nitems);
816347a39b4SMariusz Zaborski 				PJDLOG_ASSERT(value != NULL);
817347a39b4SMariusz Zaborski 				PJDLOG_ASSERT(nitems > 0);
818347a39b4SMariusz Zaborski 
819347a39b4SMariusz Zaborski 				nvl = value[0];
820347a39b4SMariusz Zaborski 				nvp = NULL;
821347a39b4SMariusz Zaborski 				break;
822347a39b4SMariusz Zaborski 			    }
823347a39b4SMariusz Zaborski 			case NV_TYPE_DESCRIPTOR_ARRAY:
824347a39b4SMariusz Zaborski 			    {
825347a39b4SMariusz Zaborski 				size_t nitems;
826347a39b4SMariusz Zaborski 
827347a39b4SMariusz Zaborski 				(void)nvpair_get_descriptor_array(nvp,
828347a39b4SMariusz Zaborski 				    &nitems);
829347a39b4SMariusz Zaborski 				ndescs += nitems;
830347a39b4SMariusz Zaborski 				break;
83154f98da9SMariusz Zaborski 			    }
83254f98da9SMariusz Zaborski 			}
833347a39b4SMariusz Zaborski 		}
834347a39b4SMariusz Zaborski 	} while ((nvl = nvlist_get_pararr(nvl, (void**)&nvp)) != NULL);
83554f98da9SMariusz Zaborski 
83654f98da9SMariusz Zaborski 	return (ndescs);
83754f98da9SMariusz Zaborski #else
83854f98da9SMariusz Zaborski 	return (0);
83954f98da9SMariusz Zaborski #endif
84054f98da9SMariusz Zaborski }
84154f98da9SMariusz Zaborski 
84254f98da9SMariusz Zaborski static unsigned char *
84354f98da9SMariusz Zaborski nvlist_pack_header(const nvlist_t *nvl, unsigned char *ptr, size_t *leftp)
84454f98da9SMariusz Zaborski {
84554f98da9SMariusz Zaborski 	struct nvlist_header nvlhdr;
84654f98da9SMariusz Zaborski 
84754f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
84854f98da9SMariusz Zaborski 
84954f98da9SMariusz Zaborski 	nvlhdr.nvlh_magic = NVLIST_HEADER_MAGIC;
85054f98da9SMariusz Zaborski 	nvlhdr.nvlh_version = NVLIST_HEADER_VERSION;
85154f98da9SMariusz Zaborski 	nvlhdr.nvlh_flags = nvl->nvl_flags;
85254f98da9SMariusz Zaborski #if BYTE_ORDER == BIG_ENDIAN
85354f98da9SMariusz Zaborski 	nvlhdr.nvlh_flags |= NV_FLAG_BIG_ENDIAN;
85454f98da9SMariusz Zaborski #endif
85554f98da9SMariusz Zaborski 	nvlhdr.nvlh_descriptors = nvlist_ndescriptors(nvl);
85654f98da9SMariusz Zaborski 	nvlhdr.nvlh_size = *leftp - sizeof(nvlhdr);
85754f98da9SMariusz Zaborski 	PJDLOG_ASSERT(*leftp >= sizeof(nvlhdr));
85854f98da9SMariusz Zaborski 	memcpy(ptr, &nvlhdr, sizeof(nvlhdr));
85954f98da9SMariusz Zaborski 	ptr += sizeof(nvlhdr);
86054f98da9SMariusz Zaborski 	*leftp -= sizeof(nvlhdr);
86154f98da9SMariusz Zaborski 
86254f98da9SMariusz Zaborski 	return (ptr);
86354f98da9SMariusz Zaborski }
86454f98da9SMariusz Zaborski 
86554f98da9SMariusz Zaborski static void *
86654f98da9SMariusz Zaborski nvlist_xpack(const nvlist_t *nvl, int64_t *fdidxp, size_t *sizep)
86754f98da9SMariusz Zaborski {
86854f98da9SMariusz Zaborski 	unsigned char *buf, *ptr;
86954f98da9SMariusz Zaborski 	size_t left, size;
87054f98da9SMariusz Zaborski 	const nvlist_t *tmpnvl;
87154f98da9SMariusz Zaborski 	nvpair_t *nvp, *tmpnvp;
87254f98da9SMariusz Zaborski 	void *cookie;
87354f98da9SMariusz Zaborski 
87454f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
87554f98da9SMariusz Zaborski 
87654f98da9SMariusz Zaborski 	if (nvl->nvl_error != 0) {
87754f98da9SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
87854f98da9SMariusz Zaborski 		return (NULL);
87954f98da9SMariusz Zaborski 	}
88054f98da9SMariusz Zaborski 
88154f98da9SMariusz Zaborski 	size = nvlist_size(nvl);
88254f98da9SMariusz Zaborski 	buf = nv_malloc(size);
88354f98da9SMariusz Zaborski 	if (buf == NULL)
88454f98da9SMariusz Zaborski 		return (NULL);
88554f98da9SMariusz Zaborski 
88654f98da9SMariusz Zaborski 	ptr = buf;
88754f98da9SMariusz Zaborski 	left = size;
88854f98da9SMariusz Zaborski 
88954f98da9SMariusz Zaborski 	ptr = nvlist_pack_header(nvl, ptr, &left);
89054f98da9SMariusz Zaborski 
89154f98da9SMariusz Zaborski 	nvp = nvlist_first_nvpair(nvl);
89254f98da9SMariusz Zaborski 	while (nvp != NULL) {
89354f98da9SMariusz Zaborski 		NVPAIR_ASSERT(nvp);
89454f98da9SMariusz Zaborski 
89554f98da9SMariusz Zaborski 		nvpair_init_datasize(nvp);
89654f98da9SMariusz Zaborski 		ptr = nvpair_pack_header(nvp, ptr, &left);
897c68f8061SMariusz Zaborski 		if (ptr == NULL)
898c68f8061SMariusz Zaborski 			goto fail;
89954f98da9SMariusz Zaborski 		switch (nvpair_type(nvp)) {
90054f98da9SMariusz Zaborski 		case NV_TYPE_NULL:
90154f98da9SMariusz Zaborski 			ptr = nvpair_pack_null(nvp, ptr, &left);
90254f98da9SMariusz Zaborski 			break;
90354f98da9SMariusz Zaborski 		case NV_TYPE_BOOL:
90454f98da9SMariusz Zaborski 			ptr = nvpair_pack_bool(nvp, ptr, &left);
90554f98da9SMariusz Zaborski 			break;
90654f98da9SMariusz Zaborski 		case NV_TYPE_NUMBER:
90754f98da9SMariusz Zaborski 			ptr = nvpair_pack_number(nvp, ptr, &left);
90854f98da9SMariusz Zaborski 			break;
90954f98da9SMariusz Zaborski 		case NV_TYPE_STRING:
91054f98da9SMariusz Zaborski 			ptr = nvpair_pack_string(nvp, ptr, &left);
91154f98da9SMariusz Zaborski 			break;
91254f98da9SMariusz Zaborski 		case NV_TYPE_NVLIST:
91354f98da9SMariusz Zaborski 			tmpnvl = nvpair_get_nvlist(nvp);
91454f98da9SMariusz Zaborski 			ptr = nvlist_pack_header(tmpnvl, ptr, &left);
91554f98da9SMariusz Zaborski 			if (ptr == NULL)
916c68f8061SMariusz Zaborski 				goto fail;
91754f98da9SMariusz Zaborski 			tmpnvp = nvlist_first_nvpair(tmpnvl);
91854f98da9SMariusz Zaborski 			if (tmpnvp != NULL) {
91954f98da9SMariusz Zaborski 				nvl = tmpnvl;
92054f98da9SMariusz Zaborski 				nvp = tmpnvp;
92154f98da9SMariusz Zaborski 				continue;
92254f98da9SMariusz Zaborski 			}
92354f98da9SMariusz Zaborski 			ptr = nvpair_pack_nvlist_up(ptr, &left);
92454f98da9SMariusz Zaborski 			break;
92554f98da9SMariusz Zaborski #ifndef _KERNEL
92654f98da9SMariusz Zaborski 		case NV_TYPE_DESCRIPTOR:
92754f98da9SMariusz Zaborski 			ptr = nvpair_pack_descriptor(nvp, ptr, fdidxp, &left);
92854f98da9SMariusz Zaborski 			break;
929347a39b4SMariusz Zaborski 		case NV_TYPE_DESCRIPTOR_ARRAY:
930347a39b4SMariusz Zaborski 			ptr = nvpair_pack_descriptor_array(nvp, ptr, fdidxp,
931347a39b4SMariusz Zaborski 			    &left);
932347a39b4SMariusz Zaborski 			break;
93354f98da9SMariusz Zaborski #endif
93454f98da9SMariusz Zaborski 		case NV_TYPE_BINARY:
93554f98da9SMariusz Zaborski 			ptr = nvpair_pack_binary(nvp, ptr, &left);
93654f98da9SMariusz Zaborski 			break;
937347a39b4SMariusz Zaborski 		case NV_TYPE_BOOL_ARRAY:
938347a39b4SMariusz Zaborski 			ptr = nvpair_pack_bool_array(nvp, ptr, &left);
939347a39b4SMariusz Zaborski 			break;
940347a39b4SMariusz Zaborski 		case NV_TYPE_NUMBER_ARRAY:
941347a39b4SMariusz Zaborski 			ptr = nvpair_pack_number_array(nvp, ptr, &left);
942347a39b4SMariusz Zaborski 			break;
943347a39b4SMariusz Zaborski 		case NV_TYPE_STRING_ARRAY:
944347a39b4SMariusz Zaborski 			ptr = nvpair_pack_string_array(nvp, ptr, &left);
945347a39b4SMariusz Zaborski 			break;
946347a39b4SMariusz Zaborski 		case NV_TYPE_NVLIST_ARRAY:
947347a39b4SMariusz Zaborski 		    {
948347a39b4SMariusz Zaborski 			const nvlist_t * const * value;
949347a39b4SMariusz Zaborski 			size_t nitems;
950347a39b4SMariusz Zaborski 			unsigned int ii;
951347a39b4SMariusz Zaborski 
952347a39b4SMariusz Zaborski 			tmpnvl = NULL;
953347a39b4SMariusz Zaborski 			value = nvpair_get_nvlist_array(nvp, &nitems);
954347a39b4SMariusz Zaborski 			for (ii = 0; ii < nitems; ii++) {
955347a39b4SMariusz Zaborski 				ptr = nvlist_pack_header(value[ii], ptr, &left);
956347a39b4SMariusz Zaborski 				if (ptr == NULL)
957347a39b4SMariusz Zaborski 					goto out;
958347a39b4SMariusz Zaborski 				tmpnvp = nvlist_first_nvpair(value[ii]);
959347a39b4SMariusz Zaborski 				if (tmpnvp != NULL) {
960347a39b4SMariusz Zaborski 					tmpnvl = value[ii];
961347a39b4SMariusz Zaborski 					break;
962347a39b4SMariusz Zaborski 				}
963347a39b4SMariusz Zaborski 				ptr = nvpair_pack_nvlist_array_next(ptr, &left);
964347a39b4SMariusz Zaborski 				if (ptr == NULL)
965347a39b4SMariusz Zaborski 					goto out;
966347a39b4SMariusz Zaborski 			}
967347a39b4SMariusz Zaborski 			if (tmpnvl != NULL) {
968347a39b4SMariusz Zaborski 				nvl = tmpnvl;
969347a39b4SMariusz Zaborski 				nvp = tmpnvp;
970347a39b4SMariusz Zaborski 				continue;
971347a39b4SMariusz Zaborski 			}
972347a39b4SMariusz Zaborski 			break;
973347a39b4SMariusz Zaborski 		    }
97454f98da9SMariusz Zaborski 		default:
97554f98da9SMariusz Zaborski 			PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp));
97654f98da9SMariusz Zaborski 		}
977c68f8061SMariusz Zaborski 		if (ptr == NULL)
978c68f8061SMariusz Zaborski 			goto fail;
97954f98da9SMariusz Zaborski 		while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
980347a39b4SMariusz Zaborski 			do {
98154f98da9SMariusz Zaborski 				cookie = NULL;
982347a39b4SMariusz Zaborski 				if (nvlist_in_array(nvl)) {
983347a39b4SMariusz Zaborski 					ptr = nvpair_pack_nvlist_array_next(ptr,
984347a39b4SMariusz Zaborski 					    &left);
985347a39b4SMariusz Zaborski 					if (ptr == NULL)
986347a39b4SMariusz Zaborski 						goto fail;
987347a39b4SMariusz Zaborski 				}
988347a39b4SMariusz Zaborski 				nvl = nvlist_get_pararr(nvl, &cookie);
98954f98da9SMariusz Zaborski 				if (nvl == NULL)
99054f98da9SMariusz Zaborski 					goto out;
991347a39b4SMariusz Zaborski 				if (nvlist_in_array(nvl) && cookie == NULL) {
992347a39b4SMariusz Zaborski 					nvp = nvlist_first_nvpair(nvl);
993347a39b4SMariusz Zaborski 					ptr = nvlist_pack_header(nvl, ptr,
994347a39b4SMariusz Zaborski 					    &left);
995347a39b4SMariusz Zaborski 					if (ptr == NULL)
996347a39b4SMariusz Zaborski 						goto fail;
997347a39b4SMariusz Zaborski 				} else if (nvpair_type((nvpair_t *)cookie) !=
998347a39b4SMariusz Zaborski 				    NV_TYPE_NVLIST_ARRAY) {
99954f98da9SMariusz Zaborski 					ptr = nvpair_pack_nvlist_up(ptr, &left);
100054f98da9SMariusz Zaborski 					if (ptr == NULL)
1001c68f8061SMariusz Zaborski 						goto fail;
1002347a39b4SMariusz Zaborski 					nvp = cookie;
1003347a39b4SMariusz Zaborski 				} else {
1004347a39b4SMariusz Zaborski 					nvp = cookie;
1005347a39b4SMariusz Zaborski 				}
1006347a39b4SMariusz Zaborski 			} while (nvp == NULL);
1007347a39b4SMariusz Zaborski 			if (nvlist_in_array(nvl) && cookie == NULL)
1008347a39b4SMariusz Zaborski 				break;
100954f98da9SMariusz Zaborski 		}
101054f98da9SMariusz Zaborski 	}
101154f98da9SMariusz Zaborski 
101254f98da9SMariusz Zaborski out:
101354f98da9SMariusz Zaborski 	if (sizep != NULL)
101454f98da9SMariusz Zaborski 		*sizep = size;
101554f98da9SMariusz Zaborski 	return (buf);
1016c68f8061SMariusz Zaborski fail:
1017c68f8061SMariusz Zaborski 	nv_free(buf);
1018c68f8061SMariusz Zaborski 	return (NULL);
101954f98da9SMariusz Zaborski }
102054f98da9SMariusz Zaborski 
102154f98da9SMariusz Zaborski void *
102254f98da9SMariusz Zaborski nvlist_pack(const nvlist_t *nvl, size_t *sizep)
102354f98da9SMariusz Zaborski {
102454f98da9SMariusz Zaborski 
102554f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
102654f98da9SMariusz Zaborski 
102754f98da9SMariusz Zaborski 	if (nvl->nvl_error != 0) {
102854f98da9SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
102954f98da9SMariusz Zaborski 		return (NULL);
103054f98da9SMariusz Zaborski 	}
103154f98da9SMariusz Zaborski 
103254f98da9SMariusz Zaborski 	if (nvlist_ndescriptors(nvl) > 0) {
103354f98da9SMariusz Zaborski 		ERRNO_SET(EOPNOTSUPP);
103454f98da9SMariusz Zaborski 		return (NULL);
103554f98da9SMariusz Zaborski 	}
103654f98da9SMariusz Zaborski 
103754f98da9SMariusz Zaborski 	return (nvlist_xpack(nvl, NULL, sizep));
103854f98da9SMariusz Zaborski }
103954f98da9SMariusz Zaborski 
104054f98da9SMariusz Zaborski static bool
104154f98da9SMariusz Zaborski nvlist_check_header(struct nvlist_header *nvlhdrp)
104254f98da9SMariusz Zaborski {
104354f98da9SMariusz Zaborski 
104454f98da9SMariusz Zaborski 	if (nvlhdrp->nvlh_magic != NVLIST_HEADER_MAGIC) {
104554f98da9SMariusz Zaborski 		ERRNO_SET(EINVAL);
104654f98da9SMariusz Zaborski 		return (false);
104754f98da9SMariusz Zaborski 	}
104854f98da9SMariusz Zaborski 	if ((nvlhdrp->nvlh_flags & ~NV_FLAG_ALL_MASK) != 0) {
104954f98da9SMariusz Zaborski 		ERRNO_SET(EINVAL);
105054f98da9SMariusz Zaborski 		return (false);
105154f98da9SMariusz Zaborski 	}
105254f98da9SMariusz Zaborski #if BYTE_ORDER == BIG_ENDIAN
105354f98da9SMariusz Zaborski 	if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) == 0) {
105454f98da9SMariusz Zaborski 		nvlhdrp->nvlh_size = le64toh(nvlhdrp->nvlh_size);
105554f98da9SMariusz Zaborski 		nvlhdrp->nvlh_descriptors = le64toh(nvlhdrp->nvlh_descriptors);
105654f98da9SMariusz Zaborski 	}
105754f98da9SMariusz Zaborski #else
105854f98da9SMariusz Zaborski 	if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0) {
105954f98da9SMariusz Zaborski 		nvlhdrp->nvlh_size = be64toh(nvlhdrp->nvlh_size);
106054f98da9SMariusz Zaborski 		nvlhdrp->nvlh_descriptors = be64toh(nvlhdrp->nvlh_descriptors);
106154f98da9SMariusz Zaborski 	}
106254f98da9SMariusz Zaborski #endif
106354f98da9SMariusz Zaborski 	return (true);
106454f98da9SMariusz Zaborski }
106554f98da9SMariusz Zaborski 
106654f98da9SMariusz Zaborski const unsigned char *
106754f98da9SMariusz Zaborski nvlist_unpack_header(nvlist_t *nvl, const unsigned char *ptr, size_t nfds,
106854f98da9SMariusz Zaborski     bool *isbep, size_t *leftp)
106954f98da9SMariusz Zaborski {
107054f98da9SMariusz Zaborski 	struct nvlist_header nvlhdr;
1071347a39b4SMariusz Zaborski 	int inarrayf;
107254f98da9SMariusz Zaborski 
107354f98da9SMariusz Zaborski 	if (*leftp < sizeof(nvlhdr))
107454f98da9SMariusz Zaborski 		goto failed;
107554f98da9SMariusz Zaborski 
107654f98da9SMariusz Zaborski 	memcpy(&nvlhdr, ptr, sizeof(nvlhdr));
107754f98da9SMariusz Zaborski 
107854f98da9SMariusz Zaborski 	if (!nvlist_check_header(&nvlhdr))
107954f98da9SMariusz Zaborski 		goto failed;
108054f98da9SMariusz Zaborski 
108154f98da9SMariusz Zaborski 	if (nvlhdr.nvlh_size != *leftp - sizeof(nvlhdr))
108254f98da9SMariusz Zaborski 		goto failed;
108354f98da9SMariusz Zaborski 
108454f98da9SMariusz Zaborski 	/*
108554f98da9SMariusz Zaborski 	 * nvlh_descriptors might be smaller than nfds in embedded nvlists.
108654f98da9SMariusz Zaborski 	 */
108754f98da9SMariusz Zaborski 	if (nvlhdr.nvlh_descriptors > nfds)
108854f98da9SMariusz Zaborski 		goto failed;
108954f98da9SMariusz Zaborski 
109054f98da9SMariusz Zaborski 	if ((nvlhdr.nvlh_flags & ~NV_FLAG_ALL_MASK) != 0)
109154f98da9SMariusz Zaborski 		goto failed;
109254f98da9SMariusz Zaborski 
1093347a39b4SMariusz Zaborski 	inarrayf = (nvl->nvl_flags & NV_FLAG_IN_ARRAY);
1094347a39b4SMariusz Zaborski 	nvl->nvl_flags = (nvlhdr.nvlh_flags & NV_FLAG_PUBLIC_MASK) | inarrayf;
109554f98da9SMariusz Zaborski 
109654f98da9SMariusz Zaborski 	ptr += sizeof(nvlhdr);
109754f98da9SMariusz Zaborski 	if (isbep != NULL)
109854f98da9SMariusz Zaborski 		*isbep = (((int)nvlhdr.nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0);
109954f98da9SMariusz Zaborski 	*leftp -= sizeof(nvlhdr);
110054f98da9SMariusz Zaborski 
110154f98da9SMariusz Zaborski 	return (ptr);
110254f98da9SMariusz Zaborski failed:
110354f98da9SMariusz Zaborski 	ERRNO_SET(EINVAL);
110454f98da9SMariusz Zaborski 	return (NULL);
110554f98da9SMariusz Zaborski }
110654f98da9SMariusz Zaborski 
110754f98da9SMariusz Zaborski static nvlist_t *
110854f98da9SMariusz Zaborski nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds,
110954f98da9SMariusz Zaborski     int flags)
111054f98da9SMariusz Zaborski {
111154f98da9SMariusz Zaborski 	const unsigned char *ptr;
1112347a39b4SMariusz Zaborski 	nvlist_t *nvl, *retnvl, *tmpnvl, *array;
111354f98da9SMariusz Zaborski 	nvpair_t *nvp;
111454f98da9SMariusz Zaborski 	size_t left;
111554f98da9SMariusz Zaborski 	bool isbe;
111654f98da9SMariusz Zaborski 
111754f98da9SMariusz Zaborski 	PJDLOG_ASSERT((flags & ~(NV_FLAG_PUBLIC_MASK)) == 0);
111854f98da9SMariusz Zaborski 
111954f98da9SMariusz Zaborski 	left = size;
112054f98da9SMariusz Zaborski 	ptr = buf;
112154f98da9SMariusz Zaborski 
1122347a39b4SMariusz Zaborski 	tmpnvl = array = NULL;
112354f98da9SMariusz Zaborski 	nvl = retnvl = nvlist_create(0);
112454f98da9SMariusz Zaborski 	if (nvl == NULL)
112554f98da9SMariusz Zaborski 		goto failed;
112654f98da9SMariusz Zaborski 
112754f98da9SMariusz Zaborski 	ptr = nvlist_unpack_header(nvl, ptr, nfds, &isbe, &left);
112854f98da9SMariusz Zaborski 	if (ptr == NULL)
112954f98da9SMariusz Zaborski 		goto failed;
113054f98da9SMariusz Zaborski 	if (nvl->nvl_flags != flags) {
113154f98da9SMariusz Zaborski 		ERRNO_SET(EILSEQ);
113254f98da9SMariusz Zaborski 		goto failed;
113354f98da9SMariusz Zaborski 	}
113454f98da9SMariusz Zaborski 
113554f98da9SMariusz Zaborski 	while (left > 0) {
113654f98da9SMariusz Zaborski 		ptr = nvpair_unpack(isbe, ptr, &left, &nvp);
113754f98da9SMariusz Zaborski 		if (ptr == NULL)
113854f98da9SMariusz Zaborski 			goto failed;
113954f98da9SMariusz Zaborski 		switch (nvpair_type(nvp)) {
114054f98da9SMariusz Zaborski 		case NV_TYPE_NULL:
114154f98da9SMariusz Zaborski 			ptr = nvpair_unpack_null(isbe, nvp, ptr, &left);
114254f98da9SMariusz Zaborski 			break;
114354f98da9SMariusz Zaborski 		case NV_TYPE_BOOL:
114454f98da9SMariusz Zaborski 			ptr = nvpair_unpack_bool(isbe, nvp, ptr, &left);
114554f98da9SMariusz Zaborski 			break;
114654f98da9SMariusz Zaborski 		case NV_TYPE_NUMBER:
114754f98da9SMariusz Zaborski 			ptr = nvpair_unpack_number(isbe, nvp, ptr, &left);
114854f98da9SMariusz Zaborski 			break;
114954f98da9SMariusz Zaborski 		case NV_TYPE_STRING:
115054f98da9SMariusz Zaborski 			ptr = nvpair_unpack_string(isbe, nvp, ptr, &left);
115154f98da9SMariusz Zaborski 			break;
115254f98da9SMariusz Zaborski 		case NV_TYPE_NVLIST:
115354f98da9SMariusz Zaborski 			ptr = nvpair_unpack_nvlist(isbe, nvp, ptr, &left, nfds,
115454f98da9SMariusz Zaborski 			    &tmpnvl);
115551dae13fSMariusz Zaborski 			if (tmpnvl == NULL || ptr == NULL)
115651dae13fSMariusz Zaborski 				goto failed;
115754f98da9SMariusz Zaborski 			nvlist_set_parent(tmpnvl, nvp);
115854f98da9SMariusz Zaborski 			break;
115954f98da9SMariusz Zaborski #ifndef _KERNEL
116054f98da9SMariusz Zaborski 		case NV_TYPE_DESCRIPTOR:
116154f98da9SMariusz Zaborski 			ptr = nvpair_unpack_descriptor(isbe, nvp, ptr, &left,
116254f98da9SMariusz Zaborski 			    fds, nfds);
116354f98da9SMariusz Zaborski 			break;
1164347a39b4SMariusz Zaborski 		case NV_TYPE_DESCRIPTOR_ARRAY:
1165347a39b4SMariusz Zaborski 			ptr = nvpair_unpack_descriptor_array(isbe, nvp, ptr,
1166347a39b4SMariusz Zaborski 			    &left, fds, nfds);
1167347a39b4SMariusz Zaborski 			break;
116854f98da9SMariusz Zaborski #endif
116954f98da9SMariusz Zaborski 		case NV_TYPE_BINARY:
117054f98da9SMariusz Zaborski 			ptr = nvpair_unpack_binary(isbe, nvp, ptr, &left);
117154f98da9SMariusz Zaborski 			break;
117254f98da9SMariusz Zaborski 		case NV_TYPE_NVLIST_UP:
117354f98da9SMariusz Zaborski 			if (nvl->nvl_parent == NULL)
117454f98da9SMariusz Zaborski 				goto failed;
117554f98da9SMariusz Zaborski 			nvl = nvpair_nvlist(nvl->nvl_parent);
117654f98da9SMariusz Zaborski 			nvpair_free_structure(nvp);
117754f98da9SMariusz Zaborski 			continue;
1178347a39b4SMariusz Zaborski 		case NV_TYPE_NVLIST_ARRAY_NEXT:
1179347a39b4SMariusz Zaborski 			if (nvl->nvl_array_next == NULL) {
1180347a39b4SMariusz Zaborski 				if (nvl->nvl_parent == NULL)
1181347a39b4SMariusz Zaborski 					goto failed;
1182347a39b4SMariusz Zaborski 				nvl = nvpair_nvlist(nvl->nvl_parent);
1183347a39b4SMariusz Zaborski 			} else {
1184347a39b4SMariusz Zaborski 				nvl = __DECONST(nvlist_t *,
1185347a39b4SMariusz Zaborski 				    nvlist_get_array_next(nvl));
1186347a39b4SMariusz Zaborski 				ptr = nvlist_unpack_header(nvl, ptr, nfds,
1187347a39b4SMariusz Zaborski 				    &isbe, &left);
1188347a39b4SMariusz Zaborski 				if (ptr == NULL)
1189347a39b4SMariusz Zaborski 					goto failed;
1190347a39b4SMariusz Zaborski 			}
1191347a39b4SMariusz Zaborski 			nvpair_free_structure(nvp);
1192347a39b4SMariusz Zaborski 			continue;
1193347a39b4SMariusz Zaborski 		case NV_TYPE_BOOL_ARRAY:
1194347a39b4SMariusz Zaborski 			ptr = nvpair_unpack_bool_array(isbe, nvp, ptr, &left);
1195347a39b4SMariusz Zaborski 			break;
1196347a39b4SMariusz Zaborski 		case NV_TYPE_NUMBER_ARRAY:
1197347a39b4SMariusz Zaborski 			ptr = nvpair_unpack_number_array(isbe, nvp, ptr, &left);
1198347a39b4SMariusz Zaborski 			break;
1199347a39b4SMariusz Zaborski 		case NV_TYPE_STRING_ARRAY:
1200347a39b4SMariusz Zaborski 			ptr = nvpair_unpack_string_array(isbe, nvp, ptr, &left);
1201347a39b4SMariusz Zaborski 			break;
1202347a39b4SMariusz Zaborski 		case NV_TYPE_NVLIST_ARRAY:
1203347a39b4SMariusz Zaborski 			ptr = nvpair_unpack_nvlist_array(isbe, nvp, ptr, &left,
1204347a39b4SMariusz Zaborski 			    &array);
1205347a39b4SMariusz Zaborski 			if (ptr == NULL)
1206347a39b4SMariusz Zaborski 				goto failed;
1207347a39b4SMariusz Zaborski 			tmpnvl = array;
1208347a39b4SMariusz Zaborski 			while (array != NULL) {
1209347a39b4SMariusz Zaborski 				nvlist_set_parent(array, nvp);
1210347a39b4SMariusz Zaborski 				array = __DECONST(nvlist_t *,
1211347a39b4SMariusz Zaborski 				    nvlist_get_array_next(array));
1212347a39b4SMariusz Zaborski 			}
1213347a39b4SMariusz Zaborski 			ptr = nvlist_unpack_header(tmpnvl, ptr, nfds, &isbe,
1214347a39b4SMariusz Zaborski 			    &left);
1215347a39b4SMariusz Zaborski 			break;
121654f98da9SMariusz Zaborski 		default:
121754f98da9SMariusz Zaborski 			PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp));
121854f98da9SMariusz Zaborski 		}
121954f98da9SMariusz Zaborski 		if (ptr == NULL)
122054f98da9SMariusz Zaborski 			goto failed;
122130740f45SMariusz Zaborski 		if (!nvlist_move_nvpair(nvl, nvp))
122230740f45SMariusz Zaborski 			goto failed;
122354f98da9SMariusz Zaborski 		if (tmpnvl != NULL) {
122454f98da9SMariusz Zaborski 			nvl = tmpnvl;
122554f98da9SMariusz Zaborski 			tmpnvl = NULL;
122654f98da9SMariusz Zaborski 		}
122754f98da9SMariusz Zaborski 	}
122854f98da9SMariusz Zaborski 
122954f98da9SMariusz Zaborski 	return (retnvl);
123054f98da9SMariusz Zaborski failed:
123154f98da9SMariusz Zaborski 	nvlist_destroy(retnvl);
123254f98da9SMariusz Zaborski 	return (NULL);
123354f98da9SMariusz Zaborski }
123454f98da9SMariusz Zaborski 
123554f98da9SMariusz Zaborski nvlist_t *
123654f98da9SMariusz Zaborski nvlist_unpack(const void *buf, size_t size, int flags)
123754f98da9SMariusz Zaborski {
123854f98da9SMariusz Zaborski 
123954f98da9SMariusz Zaborski 	return (nvlist_xunpack(buf, size, NULL, 0, flags));
124054f98da9SMariusz Zaborski }
124154f98da9SMariusz Zaborski 
124254f98da9SMariusz Zaborski #ifndef _KERNEL
124354f98da9SMariusz Zaborski int
124454f98da9SMariusz Zaborski nvlist_send(int sock, const nvlist_t *nvl)
124554f98da9SMariusz Zaborski {
124654f98da9SMariusz Zaborski 	size_t datasize, nfds;
124754f98da9SMariusz Zaborski 	int *fds;
124854f98da9SMariusz Zaborski 	void *data;
124954f98da9SMariusz Zaborski 	int64_t fdidx;
125054f98da9SMariusz Zaborski 	int ret;
125154f98da9SMariusz Zaborski 
125254f98da9SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
125354f98da9SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
125454f98da9SMariusz Zaborski 		return (-1);
125554f98da9SMariusz Zaborski 	}
125654f98da9SMariusz Zaborski 
125754f98da9SMariusz Zaborski 	fds = nvlist_descriptors(nvl, &nfds);
125854f98da9SMariusz Zaborski 	if (fds == NULL)
125954f98da9SMariusz Zaborski 		return (-1);
126054f98da9SMariusz Zaborski 
126154f98da9SMariusz Zaborski 	ret = -1;
126254f98da9SMariusz Zaborski 	data = NULL;
126354f98da9SMariusz Zaborski 	fdidx = 0;
126454f98da9SMariusz Zaborski 
126554f98da9SMariusz Zaborski 	data = nvlist_xpack(nvl, &fdidx, &datasize);
126654f98da9SMariusz Zaborski 	if (data == NULL)
126754f98da9SMariusz Zaborski 		goto out;
126854f98da9SMariusz Zaborski 
126954f98da9SMariusz Zaborski 	if (buf_send(sock, data, datasize) == -1)
127054f98da9SMariusz Zaborski 		goto out;
127154f98da9SMariusz Zaborski 
127254f98da9SMariusz Zaborski 	if (nfds > 0) {
127354f98da9SMariusz Zaborski 		if (fd_send(sock, fds, nfds) == -1)
127454f98da9SMariusz Zaborski 			goto out;
127554f98da9SMariusz Zaborski 	}
127654f98da9SMariusz Zaborski 
127754f98da9SMariusz Zaborski 	ret = 0;
127854f98da9SMariusz Zaborski out:
127954f98da9SMariusz Zaborski 	ERRNO_SAVE();
128054f98da9SMariusz Zaborski 	nv_free(fds);
128154f98da9SMariusz Zaborski 	nv_free(data);
128254f98da9SMariusz Zaborski 	ERRNO_RESTORE();
128354f98da9SMariusz Zaborski 	return (ret);
128454f98da9SMariusz Zaborski }
128554f98da9SMariusz Zaborski 
128654f98da9SMariusz Zaborski nvlist_t *
128754f98da9SMariusz Zaborski nvlist_recv(int sock, int flags)
128854f98da9SMariusz Zaborski {
128954f98da9SMariusz Zaborski 	struct nvlist_header nvlhdr;
129054f98da9SMariusz Zaborski 	nvlist_t *nvl, *ret;
129154f98da9SMariusz Zaborski 	unsigned char *buf;
129254f98da9SMariusz Zaborski 	size_t nfds, size, i;
129354f98da9SMariusz Zaborski 	int *fds;
129454f98da9SMariusz Zaborski 
129554f98da9SMariusz Zaborski 	if (buf_recv(sock, &nvlhdr, sizeof(nvlhdr)) == -1)
129654f98da9SMariusz Zaborski 		return (NULL);
129754f98da9SMariusz Zaborski 
129854f98da9SMariusz Zaborski 	if (!nvlist_check_header(&nvlhdr))
129954f98da9SMariusz Zaborski 		return (NULL);
130054f98da9SMariusz Zaborski 
130154f98da9SMariusz Zaborski 	nfds = (size_t)nvlhdr.nvlh_descriptors;
130254f98da9SMariusz Zaborski 	size = sizeof(nvlhdr) + (size_t)nvlhdr.nvlh_size;
130354f98da9SMariusz Zaborski 
130454f98da9SMariusz Zaborski 	buf = nv_malloc(size);
130554f98da9SMariusz Zaborski 	if (buf == NULL)
130654f98da9SMariusz Zaborski 		return (NULL);
130754f98da9SMariusz Zaborski 
130854f98da9SMariusz Zaborski 	memcpy(buf, &nvlhdr, sizeof(nvlhdr));
130954f98da9SMariusz Zaborski 
131054f98da9SMariusz Zaborski 	ret = NULL;
131154f98da9SMariusz Zaborski 	fds = NULL;
131254f98da9SMariusz Zaborski 
131354f98da9SMariusz Zaborski 	if (buf_recv(sock, buf + sizeof(nvlhdr), size - sizeof(nvlhdr)) == -1)
131454f98da9SMariusz Zaborski 		goto out;
131554f98da9SMariusz Zaborski 
131654f98da9SMariusz Zaborski 	if (nfds > 0) {
131754f98da9SMariusz Zaborski 		fds = nv_malloc(nfds * sizeof(fds[0]));
131854f98da9SMariusz Zaborski 		if (fds == NULL)
131954f98da9SMariusz Zaborski 			goto out;
132054f98da9SMariusz Zaborski 		if (fd_recv(sock, fds, nfds) == -1)
132154f98da9SMariusz Zaborski 			goto out;
132254f98da9SMariusz Zaborski 	}
132354f98da9SMariusz Zaborski 
132454f98da9SMariusz Zaborski 	nvl = nvlist_xunpack(buf, size, fds, nfds, flags);
132554f98da9SMariusz Zaborski 	if (nvl == NULL) {
132654f98da9SMariusz Zaborski 		ERRNO_SAVE();
132754f98da9SMariusz Zaborski 		for (i = 0; i < nfds; i++)
132854f98da9SMariusz Zaborski 			close(fds[i]);
132954f98da9SMariusz Zaborski 		ERRNO_RESTORE();
133054f98da9SMariusz Zaborski 		goto out;
133154f98da9SMariusz Zaborski 	}
133254f98da9SMariusz Zaborski 
133354f98da9SMariusz Zaborski 	ret = nvl;
133454f98da9SMariusz Zaborski out:
133554f98da9SMariusz Zaborski 	ERRNO_SAVE();
133654f98da9SMariusz Zaborski 	nv_free(buf);
133754f98da9SMariusz Zaborski 	nv_free(fds);
133854f98da9SMariusz Zaborski 	ERRNO_RESTORE();
133954f98da9SMariusz Zaborski 
134054f98da9SMariusz Zaborski 	return (ret);
134154f98da9SMariusz Zaborski }
134254f98da9SMariusz Zaborski 
134354f98da9SMariusz Zaborski nvlist_t *
134454f98da9SMariusz Zaborski nvlist_xfer(int sock, nvlist_t *nvl, int flags)
134554f98da9SMariusz Zaborski {
134654f98da9SMariusz Zaborski 
134754f98da9SMariusz Zaborski 	if (nvlist_send(sock, nvl) < 0) {
134854f98da9SMariusz Zaborski 		nvlist_destroy(nvl);
134954f98da9SMariusz Zaborski 		return (NULL);
135054f98da9SMariusz Zaborski 	}
135154f98da9SMariusz Zaborski 	nvlist_destroy(nvl);
135254f98da9SMariusz Zaborski 	return (nvlist_recv(sock, flags));
135354f98da9SMariusz Zaborski }
135454f98da9SMariusz Zaborski #endif
135554f98da9SMariusz Zaborski 
135654f98da9SMariusz Zaborski nvpair_t *
135754f98da9SMariusz Zaborski nvlist_first_nvpair(const nvlist_t *nvl)
135854f98da9SMariusz Zaborski {
135954f98da9SMariusz Zaborski 
136054f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
136154f98da9SMariusz Zaborski 
136254f98da9SMariusz Zaborski 	return (TAILQ_FIRST(&nvl->nvl_head));
136354f98da9SMariusz Zaborski }
136454f98da9SMariusz Zaborski 
136554f98da9SMariusz Zaborski nvpair_t *
136654f98da9SMariusz Zaborski nvlist_next_nvpair(const nvlist_t *nvl, const nvpair_t *nvp)
136754f98da9SMariusz Zaborski {
136854f98da9SMariusz Zaborski 	nvpair_t *retnvp;
136954f98da9SMariusz Zaborski 
137054f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
137154f98da9SMariusz Zaborski 	NVPAIR_ASSERT(nvp);
137254f98da9SMariusz Zaborski 	PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
137354f98da9SMariusz Zaborski 
137454f98da9SMariusz Zaborski 	retnvp = nvpair_next(nvp);
137554f98da9SMariusz Zaborski 	PJDLOG_ASSERT(retnvp == NULL || nvpair_nvlist(retnvp) == nvl);
137654f98da9SMariusz Zaborski 
137754f98da9SMariusz Zaborski 	return (retnvp);
137854f98da9SMariusz Zaborski 
137954f98da9SMariusz Zaborski }
138054f98da9SMariusz Zaborski 
138154f98da9SMariusz Zaborski nvpair_t *
138254f98da9SMariusz Zaborski nvlist_prev_nvpair(const nvlist_t *nvl, const nvpair_t *nvp)
138354f98da9SMariusz Zaborski {
138454f98da9SMariusz Zaborski 	nvpair_t *retnvp;
138554f98da9SMariusz Zaborski 
138654f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
138754f98da9SMariusz Zaborski 	NVPAIR_ASSERT(nvp);
138854f98da9SMariusz Zaborski 	PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
138954f98da9SMariusz Zaborski 
139054f98da9SMariusz Zaborski 	retnvp = nvpair_prev(nvp);
139154f98da9SMariusz Zaborski 	PJDLOG_ASSERT(nvpair_nvlist(retnvp) == nvl);
139254f98da9SMariusz Zaborski 
139354f98da9SMariusz Zaborski 	return (retnvp);
139454f98da9SMariusz Zaborski }
139554f98da9SMariusz Zaborski 
139654f98da9SMariusz Zaborski const char *
139754f98da9SMariusz Zaborski nvlist_next(const nvlist_t *nvl, int *typep, void **cookiep)
139854f98da9SMariusz Zaborski {
139954f98da9SMariusz Zaborski 	nvpair_t *nvp;
140054f98da9SMariusz Zaborski 
140154f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
140254f98da9SMariusz Zaborski 
140389ca10c6SMariusz Zaborski 	if (cookiep == NULL || *cookiep == NULL)
140454f98da9SMariusz Zaborski 		nvp = nvlist_first_nvpair(nvl);
140554f98da9SMariusz Zaborski 	else
140654f98da9SMariusz Zaborski 		nvp = nvlist_next_nvpair(nvl, *cookiep);
140754f98da9SMariusz Zaborski 	if (nvp == NULL)
140854f98da9SMariusz Zaborski 		return (NULL);
140954f98da9SMariusz Zaborski 	if (typep != NULL)
141054f98da9SMariusz Zaborski 		*typep = nvpair_type(nvp);
141189ca10c6SMariusz Zaborski 	if (cookiep != NULL)
141254f98da9SMariusz Zaborski 		*cookiep = nvp;
141354f98da9SMariusz Zaborski 	return (nvpair_name(nvp));
141454f98da9SMariusz Zaborski }
141554f98da9SMariusz Zaborski 
141654f98da9SMariusz Zaborski bool
141754f98da9SMariusz Zaborski nvlist_exists(const nvlist_t *nvl, const char *name)
141854f98da9SMariusz Zaborski {
141954f98da9SMariusz Zaborski 
142054f98da9SMariusz Zaborski 	return (nvlist_find(nvl, NV_TYPE_NONE, name) != NULL);
142154f98da9SMariusz Zaborski }
142254f98da9SMariusz Zaborski 
142354f98da9SMariusz Zaborski #define	NVLIST_EXISTS(type, TYPE)					\
142454f98da9SMariusz Zaborski bool									\
142554f98da9SMariusz Zaborski nvlist_exists_##type(const nvlist_t *nvl, const char *name)		\
142654f98da9SMariusz Zaborski {									\
142754f98da9SMariusz Zaborski 									\
142854f98da9SMariusz Zaborski 	return (nvlist_find(nvl, NV_TYPE_##TYPE, name) != NULL);	\
142954f98da9SMariusz Zaborski }
143054f98da9SMariusz Zaborski 
143154f98da9SMariusz Zaborski NVLIST_EXISTS(null, NULL)
143254f98da9SMariusz Zaborski NVLIST_EXISTS(bool, BOOL)
143354f98da9SMariusz Zaborski NVLIST_EXISTS(number, NUMBER)
143454f98da9SMariusz Zaborski NVLIST_EXISTS(string, STRING)
143554f98da9SMariusz Zaborski NVLIST_EXISTS(nvlist, NVLIST)
1436347a39b4SMariusz Zaborski NVLIST_EXISTS(binary, BINARY)
1437347a39b4SMariusz Zaborski NVLIST_EXISTS(bool_array, BOOL_ARRAY)
1438347a39b4SMariusz Zaborski NVLIST_EXISTS(number_array, NUMBER_ARRAY)
1439347a39b4SMariusz Zaborski NVLIST_EXISTS(string_array, STRING_ARRAY)
1440347a39b4SMariusz Zaborski NVLIST_EXISTS(nvlist_array, NVLIST_ARRAY)
144154f98da9SMariusz Zaborski #ifndef _KERNEL
144254f98da9SMariusz Zaborski NVLIST_EXISTS(descriptor, DESCRIPTOR)
1443347a39b4SMariusz Zaborski NVLIST_EXISTS(descriptor_array, DESCRIPTOR_ARRAY)
144454f98da9SMariusz Zaborski #endif
144554f98da9SMariusz Zaborski 
144654f98da9SMariusz Zaborski #undef	NVLIST_EXISTS
144754f98da9SMariusz Zaborski 
144854f98da9SMariusz Zaborski void
144954f98da9SMariusz Zaborski nvlist_add_nvpair(nvlist_t *nvl, const nvpair_t *nvp)
145054f98da9SMariusz Zaborski {
145154f98da9SMariusz Zaborski 	nvpair_t *newnvp;
145254f98da9SMariusz Zaborski 
145354f98da9SMariusz Zaborski 	NVPAIR_ASSERT(nvp);
145454f98da9SMariusz Zaborski 
145554f98da9SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
145654f98da9SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
145754f98da9SMariusz Zaborski 		return;
145854f98da9SMariusz Zaborski 	}
145954f98da9SMariusz Zaborski 	if ((nvl->nvl_flags & NV_FLAG_NO_UNIQUE) == 0) {
146054f98da9SMariusz Zaborski 		if (nvlist_exists(nvl, nvpair_name(nvp))) {
146154f98da9SMariusz Zaborski 			nvl->nvl_error = EEXIST;
146254f98da9SMariusz Zaborski 			ERRNO_SET(nvlist_error(nvl));
146354f98da9SMariusz Zaborski 			return;
146454f98da9SMariusz Zaborski 		}
146554f98da9SMariusz Zaborski 	}
146654f98da9SMariusz Zaborski 
146754f98da9SMariusz Zaborski 	newnvp = nvpair_clone(nvp);
146854f98da9SMariusz Zaborski 	if (newnvp == NULL) {
146954f98da9SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
147054f98da9SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
147154f98da9SMariusz Zaborski 		return;
147254f98da9SMariusz Zaborski 	}
147354f98da9SMariusz Zaborski 
147454f98da9SMariusz Zaborski 	nvpair_insert(&nvl->nvl_head, newnvp, nvl);
147554f98da9SMariusz Zaborski }
147654f98da9SMariusz Zaborski 
147754f98da9SMariusz Zaborski void
147854f98da9SMariusz Zaborski nvlist_add_stringf(nvlist_t *nvl, const char *name, const char *valuefmt, ...)
147954f98da9SMariusz Zaborski {
148054f98da9SMariusz Zaborski 	va_list valueap;
148154f98da9SMariusz Zaborski 
148254f98da9SMariusz Zaborski 	va_start(valueap, valuefmt);
148354f98da9SMariusz Zaborski 	nvlist_add_stringv(nvl, name, valuefmt, valueap);
148454f98da9SMariusz Zaborski 	va_end(valueap);
148554f98da9SMariusz Zaborski }
148654f98da9SMariusz Zaborski 
148754f98da9SMariusz Zaborski void
148854f98da9SMariusz Zaborski nvlist_add_stringv(nvlist_t *nvl, const char *name, const char *valuefmt,
148954f98da9SMariusz Zaborski     va_list valueap)
149054f98da9SMariusz Zaborski {
149154f98da9SMariusz Zaborski 	nvpair_t *nvp;
149254f98da9SMariusz Zaborski 
149354f98da9SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
149454f98da9SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
149554f98da9SMariusz Zaborski 		return;
149654f98da9SMariusz Zaborski 	}
149754f98da9SMariusz Zaborski 
149854f98da9SMariusz Zaborski 	nvp = nvpair_create_stringv(name, valuefmt, valueap);
149954f98da9SMariusz Zaborski 	if (nvp == NULL) {
150054f98da9SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
150154f98da9SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
150254f98da9SMariusz Zaborski 	} else {
150330740f45SMariusz Zaborski 		(void)nvlist_move_nvpair(nvl, nvp);
150454f98da9SMariusz Zaborski 	}
150554f98da9SMariusz Zaborski }
150654f98da9SMariusz Zaborski 
150754f98da9SMariusz Zaborski void
150854f98da9SMariusz Zaborski nvlist_add_null(nvlist_t *nvl, const char *name)
150954f98da9SMariusz Zaborski {
151054f98da9SMariusz Zaborski 	nvpair_t *nvp;
151154f98da9SMariusz Zaborski 
151254f98da9SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
151354f98da9SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
151454f98da9SMariusz Zaborski 		return;
151554f98da9SMariusz Zaborski 	}
151654f98da9SMariusz Zaborski 
151754f98da9SMariusz Zaborski 	nvp = nvpair_create_null(name);
151854f98da9SMariusz Zaborski 	if (nvp == NULL) {
151954f98da9SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
152054f98da9SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
152154f98da9SMariusz Zaborski 	} else {
152230740f45SMariusz Zaborski 		(void)nvlist_move_nvpair(nvl, nvp);
152354f98da9SMariusz Zaborski 	}
152454f98da9SMariusz Zaborski }
152554f98da9SMariusz Zaborski 
152654f98da9SMariusz Zaborski void
152754f98da9SMariusz Zaborski nvlist_add_binary(nvlist_t *nvl, const char *name, const void *value,
152854f98da9SMariusz Zaborski     size_t size)
152954f98da9SMariusz Zaborski {
153054f98da9SMariusz Zaborski 	nvpair_t *nvp;
153154f98da9SMariusz Zaborski 
153254f98da9SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
153354f98da9SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
153454f98da9SMariusz Zaborski 		return;
153554f98da9SMariusz Zaborski 	}
153654f98da9SMariusz Zaborski 
153754f98da9SMariusz Zaborski 	nvp = nvpair_create_binary(name, value, size);
153854f98da9SMariusz Zaborski 	if (nvp == NULL) {
153954f98da9SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
154054f98da9SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
154154f98da9SMariusz Zaborski 	} else {
154230740f45SMariusz Zaborski 		(void)nvlist_move_nvpair(nvl, nvp);
154354f98da9SMariusz Zaborski 	}
154454f98da9SMariusz Zaborski }
154554f98da9SMariusz Zaborski 
154654f98da9SMariusz Zaborski 
154754f98da9SMariusz Zaborski #define	NVLIST_ADD(vtype, type)						\
154854f98da9SMariusz Zaborski void									\
154954f98da9SMariusz Zaborski nvlist_add_##type(nvlist_t *nvl, const char *name, vtype value)		\
155054f98da9SMariusz Zaborski {									\
155154f98da9SMariusz Zaborski 	nvpair_t *nvp;							\
155254f98da9SMariusz Zaborski 									\
155354f98da9SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {					\
155454f98da9SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));				\
155554f98da9SMariusz Zaborski 		return;							\
155654f98da9SMariusz Zaborski 	}								\
155754f98da9SMariusz Zaborski 									\
155854f98da9SMariusz Zaborski 	nvp = nvpair_create_##type(name, value);			\
155954f98da9SMariusz Zaborski 	if (nvp == NULL) {						\
156054f98da9SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);		\
156154f98da9SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);				\
156254f98da9SMariusz Zaborski 	} else {							\
156330740f45SMariusz Zaborski 		(void)nvlist_move_nvpair(nvl, nvp);			\
156454f98da9SMariusz Zaborski 	}								\
156554f98da9SMariusz Zaborski }
156654f98da9SMariusz Zaborski 
156754f98da9SMariusz Zaborski NVLIST_ADD(bool, bool)
156854f98da9SMariusz Zaborski NVLIST_ADD(uint64_t, number)
156954f98da9SMariusz Zaborski NVLIST_ADD(const char *, string)
157054f98da9SMariusz Zaborski NVLIST_ADD(const nvlist_t *, nvlist)
157154f98da9SMariusz Zaborski #ifndef _KERNEL
157254f98da9SMariusz Zaborski NVLIST_ADD(int, descriptor);
157354f98da9SMariusz Zaborski #endif
157454f98da9SMariusz Zaborski 
157554f98da9SMariusz Zaborski #undef	NVLIST_ADD
157654f98da9SMariusz Zaborski 
1577347a39b4SMariusz Zaborski #define	NVLIST_ADD_ARRAY(vtype, type)					\
1578347a39b4SMariusz Zaborski void									\
1579347a39b4SMariusz Zaborski nvlist_add_##type##_array(nvlist_t *nvl, const char *name, vtype value,	\
1580347a39b4SMariusz Zaborski     size_t nitems)							\
1581347a39b4SMariusz Zaborski {									\
1582347a39b4SMariusz Zaborski 	nvpair_t *nvp;							\
1583347a39b4SMariusz Zaborski 									\
1584347a39b4SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {					\
1585347a39b4SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));				\
1586347a39b4SMariusz Zaborski 		return;							\
1587347a39b4SMariusz Zaborski 	}								\
1588347a39b4SMariusz Zaborski 									\
1589347a39b4SMariusz Zaborski 	nvp = nvpair_create_##type##_array(name, value, nitems);	\
1590347a39b4SMariusz Zaborski 	if (nvp == NULL) {						\
1591347a39b4SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);		\
1592347a39b4SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);				\
1593347a39b4SMariusz Zaborski 	} else {							\
1594347a39b4SMariusz Zaborski 		(void)nvlist_move_nvpair(nvl, nvp);			\
1595347a39b4SMariusz Zaborski 	}								\
1596347a39b4SMariusz Zaborski }
1597347a39b4SMariusz Zaborski 
1598347a39b4SMariusz Zaborski NVLIST_ADD_ARRAY(const bool *, bool)
1599347a39b4SMariusz Zaborski NVLIST_ADD_ARRAY(const uint64_t *, number)
1600347a39b4SMariusz Zaborski NVLIST_ADD_ARRAY(const char * const *, string)
1601347a39b4SMariusz Zaborski NVLIST_ADD_ARRAY(const nvlist_t * const *, nvlist)
1602347a39b4SMariusz Zaborski #ifndef _KERNEL
1603347a39b4SMariusz Zaborski NVLIST_ADD_ARRAY(const int *, descriptor)
1604347a39b4SMariusz Zaborski #endif
1605347a39b4SMariusz Zaborski 
1606347a39b4SMariusz Zaborski #undef	NVLIST_ADD_ARRAY
1607347a39b4SMariusz Zaborski 
160830740f45SMariusz Zaborski bool
160954f98da9SMariusz Zaborski nvlist_move_nvpair(nvlist_t *nvl, nvpair_t *nvp)
161054f98da9SMariusz Zaborski {
161154f98da9SMariusz Zaborski 
161254f98da9SMariusz Zaborski 	NVPAIR_ASSERT(nvp);
161354f98da9SMariusz Zaborski 	PJDLOG_ASSERT(nvpair_nvlist(nvp) == NULL);
161454f98da9SMariusz Zaborski 
161554f98da9SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
161654f98da9SMariusz Zaborski 		nvpair_free(nvp);
161754f98da9SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
161830740f45SMariusz Zaborski 		return (false);
161954f98da9SMariusz Zaborski 	}
162054f98da9SMariusz Zaborski 	if ((nvl->nvl_flags & NV_FLAG_NO_UNIQUE) == 0) {
162154f98da9SMariusz Zaborski 		if (nvlist_exists(nvl, nvpair_name(nvp))) {
162254f98da9SMariusz Zaborski 			nvpair_free(nvp);
162354f98da9SMariusz Zaborski 			nvl->nvl_error = EEXIST;
162454f98da9SMariusz Zaborski 			ERRNO_SET(nvl->nvl_error);
162530740f45SMariusz Zaborski 			return (false);
162654f98da9SMariusz Zaborski 		}
162754f98da9SMariusz Zaborski 	}
162854f98da9SMariusz Zaborski 
162954f98da9SMariusz Zaborski 	nvpair_insert(&nvl->nvl_head, nvp, nvl);
163030740f45SMariusz Zaborski 	return (true);
163154f98da9SMariusz Zaborski }
163254f98da9SMariusz Zaborski 
163354f98da9SMariusz Zaborski void
163454f98da9SMariusz Zaborski nvlist_move_string(nvlist_t *nvl, const char *name, char *value)
163554f98da9SMariusz Zaborski {
163654f98da9SMariusz Zaborski 	nvpair_t *nvp;
163754f98da9SMariusz Zaborski 
163854f98da9SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
163954f98da9SMariusz Zaborski 		nv_free(value);
164054f98da9SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
164154f98da9SMariusz Zaborski 		return;
164254f98da9SMariusz Zaborski 	}
164354f98da9SMariusz Zaborski 
164454f98da9SMariusz Zaborski 	nvp = nvpair_move_string(name, value);
164554f98da9SMariusz Zaborski 	if (nvp == NULL) {
164654f98da9SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
164754f98da9SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
164854f98da9SMariusz Zaborski 	} else {
164930740f45SMariusz Zaborski 		(void)nvlist_move_nvpair(nvl, nvp);
165054f98da9SMariusz Zaborski 	}
165154f98da9SMariusz Zaborski }
165254f98da9SMariusz Zaborski 
165354f98da9SMariusz Zaborski void
165454f98da9SMariusz Zaborski nvlist_move_nvlist(nvlist_t *nvl, const char *name, nvlist_t *value)
165554f98da9SMariusz Zaborski {
165654f98da9SMariusz Zaborski 	nvpair_t *nvp;
165754f98da9SMariusz Zaborski 
165854f98da9SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
165954f98da9SMariusz Zaborski 		if (value != NULL && nvlist_get_nvpair_parent(value) != NULL)
166054f98da9SMariusz Zaborski 			nvlist_destroy(value);
166154f98da9SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
166254f98da9SMariusz Zaborski 		return;
166354f98da9SMariusz Zaborski 	}
166454f98da9SMariusz Zaborski 
166554f98da9SMariusz Zaborski 	nvp = nvpair_move_nvlist(name, value);
166654f98da9SMariusz Zaborski 	if (nvp == NULL) {
166754f98da9SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
166854f98da9SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
166954f98da9SMariusz Zaborski 	} else {
167030740f45SMariusz Zaborski 		(void)nvlist_move_nvpair(nvl, nvp);
167154f98da9SMariusz Zaborski 	}
167254f98da9SMariusz Zaborski }
167354f98da9SMariusz Zaborski 
167454f98da9SMariusz Zaborski #ifndef _KERNEL
167554f98da9SMariusz Zaborski void
167654f98da9SMariusz Zaborski nvlist_move_descriptor(nvlist_t *nvl, const char *name, int value)
167754f98da9SMariusz Zaborski {
167854f98da9SMariusz Zaborski 	nvpair_t *nvp;
167954f98da9SMariusz Zaborski 
168054f98da9SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
168154f98da9SMariusz Zaborski 		close(value);
168254f98da9SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
168354f98da9SMariusz Zaborski 		return;
168454f98da9SMariusz Zaborski 	}
168554f98da9SMariusz Zaborski 
168654f98da9SMariusz Zaborski 	nvp = nvpair_move_descriptor(name, value);
168754f98da9SMariusz Zaborski 	if (nvp == NULL) {
168854f98da9SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
168954f98da9SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
169054f98da9SMariusz Zaborski 	} else {
169130740f45SMariusz Zaborski 		(void)nvlist_move_nvpair(nvl, nvp);
169254f98da9SMariusz Zaborski 	}
169354f98da9SMariusz Zaborski }
169454f98da9SMariusz Zaborski #endif
169554f98da9SMariusz Zaborski 
169654f98da9SMariusz Zaborski void
169754f98da9SMariusz Zaborski nvlist_move_binary(nvlist_t *nvl, const char *name, void *value, size_t size)
169854f98da9SMariusz Zaborski {
169954f98da9SMariusz Zaborski 	nvpair_t *nvp;
170054f98da9SMariusz Zaborski 
170154f98da9SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
170254f98da9SMariusz Zaborski 		nv_free(value);
170354f98da9SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
170454f98da9SMariusz Zaborski 		return;
170554f98da9SMariusz Zaborski 	}
170654f98da9SMariusz Zaborski 
170754f98da9SMariusz Zaborski 	nvp = nvpair_move_binary(name, value, size);
170854f98da9SMariusz Zaborski 	if (nvp == NULL) {
170954f98da9SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
171054f98da9SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
171154f98da9SMariusz Zaborski 	} else {
171230740f45SMariusz Zaborski 		(void)nvlist_move_nvpair(nvl, nvp);
171354f98da9SMariusz Zaborski 	}
171454f98da9SMariusz Zaborski }
171554f98da9SMariusz Zaborski 
1716347a39b4SMariusz Zaborski void
1717347a39b4SMariusz Zaborski nvlist_move_bool_array(nvlist_t *nvl, const char *name, bool *value,
1718347a39b4SMariusz Zaborski     size_t nitems)
1719347a39b4SMariusz Zaborski {
1720347a39b4SMariusz Zaborski 	nvpair_t *nvp;
1721347a39b4SMariusz Zaborski 
1722347a39b4SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
1723347a39b4SMariusz Zaborski 		nv_free(value);
1724347a39b4SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
1725347a39b4SMariusz Zaborski 		return;
1726347a39b4SMariusz Zaborski 	}
1727347a39b4SMariusz Zaborski 
1728347a39b4SMariusz Zaborski 	nvp = nvpair_move_bool_array(name, value, nitems);
1729347a39b4SMariusz Zaborski 	if (nvp == NULL) {
1730347a39b4SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1731347a39b4SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
1732347a39b4SMariusz Zaborski 	} else {
1733347a39b4SMariusz Zaborski 		(void)nvlist_move_nvpair(nvl, nvp);
1734347a39b4SMariusz Zaborski 	}
1735347a39b4SMariusz Zaborski }
1736347a39b4SMariusz Zaborski 
1737347a39b4SMariusz Zaborski void
1738347a39b4SMariusz Zaborski nvlist_move_string_array(nvlist_t *nvl, const char *name, char **value,
1739347a39b4SMariusz Zaborski     size_t nitems)
1740347a39b4SMariusz Zaborski {
1741347a39b4SMariusz Zaborski 	nvpair_t *nvp;
1742347a39b4SMariusz Zaborski 	size_t i;
1743347a39b4SMariusz Zaborski 
1744347a39b4SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
1745347a39b4SMariusz Zaborski 		if (value != NULL) {
1746347a39b4SMariusz Zaborski 			for (i = 0; i < nitems; i++)
1747347a39b4SMariusz Zaborski 				nv_free(value[i]);
1748347a39b4SMariusz Zaborski 			nv_free(value);
1749347a39b4SMariusz Zaborski 		}
1750347a39b4SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
1751347a39b4SMariusz Zaborski 		return;
1752347a39b4SMariusz Zaborski 	}
1753347a39b4SMariusz Zaborski 
1754347a39b4SMariusz Zaborski 	nvp = nvpair_move_string_array(name, value, nitems);
1755347a39b4SMariusz Zaborski 	if (nvp == NULL) {
1756347a39b4SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1757347a39b4SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
1758347a39b4SMariusz Zaborski 	} else {
1759347a39b4SMariusz Zaborski 		(void)nvlist_move_nvpair(nvl, nvp);
1760347a39b4SMariusz Zaborski 	}
1761347a39b4SMariusz Zaborski }
1762347a39b4SMariusz Zaborski 
1763347a39b4SMariusz Zaborski void
1764347a39b4SMariusz Zaborski nvlist_move_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **value,
1765347a39b4SMariusz Zaborski     size_t nitems)
1766347a39b4SMariusz Zaborski {
1767347a39b4SMariusz Zaborski 	nvpair_t *nvp;
1768347a39b4SMariusz Zaborski 	size_t i;
1769347a39b4SMariusz Zaborski 
1770347a39b4SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
1771347a39b4SMariusz Zaborski 		if (value != NULL) {
1772347a39b4SMariusz Zaborski 			for (i = 0; i < nitems; i++) {
1773347a39b4SMariusz Zaborski 				if (nvlist_get_pararr(value[i], NULL) == NULL)
1774347a39b4SMariusz Zaborski 					nvlist_destroy(value[i]);
1775347a39b4SMariusz Zaborski 			}
1776347a39b4SMariusz Zaborski 		}
1777347a39b4SMariusz Zaborski 		nv_free(value);
1778347a39b4SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
1779347a39b4SMariusz Zaborski 		return;
1780347a39b4SMariusz Zaborski 	}
1781347a39b4SMariusz Zaborski 
1782347a39b4SMariusz Zaborski 	nvp = nvpair_move_nvlist_array(name, value, nitems);
1783347a39b4SMariusz Zaborski 	if (nvp == NULL) {
1784347a39b4SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1785347a39b4SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
1786347a39b4SMariusz Zaborski 	} else {
1787347a39b4SMariusz Zaborski 		(void)nvlist_move_nvpair(nvl, nvp);
1788347a39b4SMariusz Zaborski 	}
1789347a39b4SMariusz Zaborski }
1790347a39b4SMariusz Zaborski 
1791347a39b4SMariusz Zaborski void
1792347a39b4SMariusz Zaborski nvlist_move_number_array(nvlist_t *nvl, const char *name, uint64_t *value,
1793347a39b4SMariusz Zaborski     size_t nitems)
1794347a39b4SMariusz Zaborski {
1795347a39b4SMariusz Zaborski 	nvpair_t *nvp;
1796347a39b4SMariusz Zaborski 
1797347a39b4SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
1798347a39b4SMariusz Zaborski 		nv_free(value);
1799347a39b4SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
1800347a39b4SMariusz Zaborski 		return;
1801347a39b4SMariusz Zaborski 	}
1802347a39b4SMariusz Zaborski 
1803347a39b4SMariusz Zaborski 	nvp = nvpair_move_number_array(name, value, nitems);
1804347a39b4SMariusz Zaborski 	if (nvp == NULL) {
1805347a39b4SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1806347a39b4SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
1807347a39b4SMariusz Zaborski 	} else {
1808347a39b4SMariusz Zaborski 		(void)nvlist_move_nvpair(nvl, nvp);
1809347a39b4SMariusz Zaborski 	}
1810347a39b4SMariusz Zaborski }
1811347a39b4SMariusz Zaborski 
1812347a39b4SMariusz Zaborski #ifndef _KERNEL
1813347a39b4SMariusz Zaborski void
1814347a39b4SMariusz Zaborski nvlist_move_descriptor_array(nvlist_t *nvl, const char *name, int *value,
1815347a39b4SMariusz Zaborski     size_t nitems)
1816347a39b4SMariusz Zaborski {
1817347a39b4SMariusz Zaborski 	nvpair_t *nvp;
1818347a39b4SMariusz Zaborski 	size_t i;
1819347a39b4SMariusz Zaborski 
1820347a39b4SMariusz Zaborski 	if (nvlist_error(nvl) != 0) {
1821347a39b4SMariusz Zaborski 		if (value != 0) {
1822347a39b4SMariusz Zaborski 			for (i = 0; i < nitems; i++)
1823347a39b4SMariusz Zaborski 				close(value[i]);
1824347a39b4SMariusz Zaborski 			nv_free(value);
1825347a39b4SMariusz Zaborski 		}
1826347a39b4SMariusz Zaborski 
1827347a39b4SMariusz Zaborski 		ERRNO_SET(nvlist_error(nvl));
1828347a39b4SMariusz Zaborski 		return;
1829347a39b4SMariusz Zaborski 	}
1830347a39b4SMariusz Zaborski 
1831347a39b4SMariusz Zaborski 	nvp = nvpair_move_descriptor_array(name, value, nitems);
1832347a39b4SMariusz Zaborski 	if (nvp == NULL) {
1833347a39b4SMariusz Zaborski 		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1834347a39b4SMariusz Zaborski 		ERRNO_SET(nvl->nvl_error);
1835347a39b4SMariusz Zaborski 	} else {
1836347a39b4SMariusz Zaborski 		(void)nvlist_move_nvpair(nvl, nvp);
1837347a39b4SMariusz Zaborski 	}
1838347a39b4SMariusz Zaborski }
1839347a39b4SMariusz Zaborski #endif
1840347a39b4SMariusz Zaborski 
184154f98da9SMariusz Zaborski const nvpair_t *
184254f98da9SMariusz Zaborski nvlist_get_nvpair(const nvlist_t *nvl, const char *name)
184354f98da9SMariusz Zaborski {
184454f98da9SMariusz Zaborski 
184554f98da9SMariusz Zaborski 	return (nvlist_find(nvl, NV_TYPE_NONE, name));
184654f98da9SMariusz Zaborski }
184754f98da9SMariusz Zaborski 
184854f98da9SMariusz Zaborski #define	NVLIST_GET(ftype, type, TYPE)					\
184954f98da9SMariusz Zaborski ftype									\
185054f98da9SMariusz Zaborski nvlist_get_##type(const nvlist_t *nvl, const char *name)		\
185154f98da9SMariusz Zaborski {									\
185254f98da9SMariusz Zaborski 	const nvpair_t *nvp;						\
185354f98da9SMariusz Zaborski 									\
185454f98da9SMariusz Zaborski 	nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name);			\
185554f98da9SMariusz Zaborski 	if (nvp == NULL)						\
185654f98da9SMariusz Zaborski 		nvlist_report_missing(NV_TYPE_##TYPE, name);		\
185754f98da9SMariusz Zaborski 	return (nvpair_get_##type(nvp));				\
185854f98da9SMariusz Zaborski }
185954f98da9SMariusz Zaborski 
186054f98da9SMariusz Zaborski NVLIST_GET(bool, bool, BOOL)
186154f98da9SMariusz Zaborski NVLIST_GET(uint64_t, number, NUMBER)
186254f98da9SMariusz Zaborski NVLIST_GET(const char *, string, STRING)
186354f98da9SMariusz Zaborski NVLIST_GET(const nvlist_t *, nvlist, NVLIST)
186454f98da9SMariusz Zaborski #ifndef _KERNEL
186554f98da9SMariusz Zaborski NVLIST_GET(int, descriptor, DESCRIPTOR)
186654f98da9SMariusz Zaborski #endif
186754f98da9SMariusz Zaborski 
186854f98da9SMariusz Zaborski #undef	NVLIST_GET
186954f98da9SMariusz Zaborski 
187054f98da9SMariusz Zaborski const void *
187154f98da9SMariusz Zaborski nvlist_get_binary(const nvlist_t *nvl, const char *name, size_t *sizep)
187254f98da9SMariusz Zaborski {
187354f98da9SMariusz Zaborski 	nvpair_t *nvp;
187454f98da9SMariusz Zaborski 
187554f98da9SMariusz Zaborski 	nvp = nvlist_find(nvl, NV_TYPE_BINARY, name);
187654f98da9SMariusz Zaborski 	if (nvp == NULL)
187754f98da9SMariusz Zaborski 		nvlist_report_missing(NV_TYPE_BINARY, name);
187854f98da9SMariusz Zaborski 
187954f98da9SMariusz Zaborski 	return (nvpair_get_binary(nvp, sizep));
188054f98da9SMariusz Zaborski }
188154f98da9SMariusz Zaborski 
1882347a39b4SMariusz Zaborski #define	NVLIST_GET_ARRAY(ftype, type, TYPE)				\
1883347a39b4SMariusz Zaborski ftype									\
1884347a39b4SMariusz Zaborski nvlist_get_##type##_array(const nvlist_t *nvl, const char *name,	\
1885347a39b4SMariusz Zaborski     size_t *nitems)							\
1886347a39b4SMariusz Zaborski {									\
1887347a39b4SMariusz Zaborski 	const nvpair_t *nvp;						\
1888347a39b4SMariusz Zaborski 									\
1889347a39b4SMariusz Zaborski 	nvp = nvlist_find(nvl, NV_TYPE_##TYPE##_ARRAY, name);		\
1890347a39b4SMariusz Zaborski 	if (nvp == NULL)						\
1891347a39b4SMariusz Zaborski 		nvlist_report_missing(NV_TYPE_##TYPE##_ARRAY, name);	\
1892347a39b4SMariusz Zaborski 	return (nvpair_get_##type##_array(nvp, nitems));		\
1893347a39b4SMariusz Zaborski }
1894347a39b4SMariusz Zaborski 
1895347a39b4SMariusz Zaborski NVLIST_GET_ARRAY(const bool *, bool, BOOL)
1896347a39b4SMariusz Zaborski NVLIST_GET_ARRAY(const uint64_t *, number, NUMBER)
1897347a39b4SMariusz Zaborski NVLIST_GET_ARRAY(const char * const *, string, STRING)
1898347a39b4SMariusz Zaborski NVLIST_GET_ARRAY(const nvlist_t * const *, nvlist, NVLIST)
1899347a39b4SMariusz Zaborski #ifndef _KERNEL
1900347a39b4SMariusz Zaborski NVLIST_GET_ARRAY(const int *, descriptor, DESCRIPTOR)
1901347a39b4SMariusz Zaborski #endif
1902347a39b4SMariusz Zaborski 
1903347a39b4SMariusz Zaborski #undef	NVLIST_GET_ARRAY
1904347a39b4SMariusz Zaborski 
190554f98da9SMariusz Zaborski #define	NVLIST_TAKE(ftype, type, TYPE)					\
190654f98da9SMariusz Zaborski ftype									\
190754f98da9SMariusz Zaborski nvlist_take_##type(nvlist_t *nvl, const char *name)			\
190854f98da9SMariusz Zaborski {									\
190954f98da9SMariusz Zaborski 	nvpair_t *nvp;							\
191054f98da9SMariusz Zaborski 	ftype value;							\
191154f98da9SMariusz Zaborski 									\
191254f98da9SMariusz Zaborski 	nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name);			\
191354f98da9SMariusz Zaborski 	if (nvp == NULL)						\
191454f98da9SMariusz Zaborski 		nvlist_report_missing(NV_TYPE_##TYPE, name);		\
191554f98da9SMariusz Zaborski 	value = (ftype)(intptr_t)nvpair_get_##type(nvp);		\
191654f98da9SMariusz Zaborski 	nvlist_remove_nvpair(nvl, nvp);					\
191754f98da9SMariusz Zaborski 	nvpair_free_structure(nvp);					\
191854f98da9SMariusz Zaborski 	return (value);							\
191954f98da9SMariusz Zaborski }
192054f98da9SMariusz Zaborski 
192154f98da9SMariusz Zaborski NVLIST_TAKE(bool, bool, BOOL)
192254f98da9SMariusz Zaborski NVLIST_TAKE(uint64_t, number, NUMBER)
192354f98da9SMariusz Zaborski NVLIST_TAKE(char *, string, STRING)
192454f98da9SMariusz Zaborski NVLIST_TAKE(nvlist_t *, nvlist, NVLIST)
192554f98da9SMariusz Zaborski #ifndef _KERNEL
192654f98da9SMariusz Zaborski NVLIST_TAKE(int, descriptor, DESCRIPTOR)
192754f98da9SMariusz Zaborski #endif
192854f98da9SMariusz Zaborski 
192954f98da9SMariusz Zaborski #undef	NVLIST_TAKE
193054f98da9SMariusz Zaborski 
193154f98da9SMariusz Zaborski void *
193254f98da9SMariusz Zaborski nvlist_take_binary(nvlist_t *nvl, const char *name, size_t *sizep)
193354f98da9SMariusz Zaborski {
193454f98da9SMariusz Zaborski 	nvpair_t *nvp;
193554f98da9SMariusz Zaborski 	void *value;
193654f98da9SMariusz Zaborski 
193754f98da9SMariusz Zaborski 	nvp = nvlist_find(nvl, NV_TYPE_BINARY, name);
193854f98da9SMariusz Zaborski 	if (nvp == NULL)
193954f98da9SMariusz Zaborski 		nvlist_report_missing(NV_TYPE_BINARY, name);
194054f98da9SMariusz Zaborski 
194154f98da9SMariusz Zaborski 	value = (void *)(intptr_t)nvpair_get_binary(nvp, sizep);
194254f98da9SMariusz Zaborski 	nvlist_remove_nvpair(nvl, nvp);
194354f98da9SMariusz Zaborski 	nvpair_free_structure(nvp);
194454f98da9SMariusz Zaborski 	return (value);
194554f98da9SMariusz Zaborski }
194654f98da9SMariusz Zaborski 
1947347a39b4SMariusz Zaborski #define	NVLIST_TAKE_ARRAY(ftype, type, TYPE)				\
1948347a39b4SMariusz Zaborski ftype									\
1949347a39b4SMariusz Zaborski nvlist_take_##type##_array(nvlist_t *nvl, const char *name,		\
1950347a39b4SMariusz Zaborski     size_t *nitems)							\
1951347a39b4SMariusz Zaborski {									\
1952347a39b4SMariusz Zaborski 	nvpair_t *nvp;							\
1953347a39b4SMariusz Zaborski 	ftype value;							\
1954347a39b4SMariusz Zaborski 									\
1955347a39b4SMariusz Zaborski 	nvp = nvlist_find(nvl, NV_TYPE_##TYPE##_ARRAY, name);		\
1956347a39b4SMariusz Zaborski 	if (nvp == NULL)						\
1957347a39b4SMariusz Zaborski 		nvlist_report_missing(NV_TYPE_##TYPE##_ARRAY, name);	\
1958347a39b4SMariusz Zaborski 	value = (ftype)(intptr_t)nvpair_get_##type##_array(nvp, nitems);\
1959347a39b4SMariusz Zaborski 	nvlist_remove_nvpair(nvl, nvp);					\
1960347a39b4SMariusz Zaborski 	nvpair_free_structure(nvp);					\
1961347a39b4SMariusz Zaborski 	return (value);							\
1962347a39b4SMariusz Zaborski }
1963347a39b4SMariusz Zaborski 
1964347a39b4SMariusz Zaborski NVLIST_TAKE_ARRAY(bool *, bool, BOOL)
1965347a39b4SMariusz Zaborski NVLIST_TAKE_ARRAY(uint64_t *, number, NUMBER)
1966347a39b4SMariusz Zaborski NVLIST_TAKE_ARRAY(char **, string, STRING)
1967347a39b4SMariusz Zaborski NVLIST_TAKE_ARRAY(nvlist_t **, nvlist, NVLIST)
1968347a39b4SMariusz Zaborski #ifndef _KERNEL
1969347a39b4SMariusz Zaborski NVLIST_TAKE_ARRAY(int *, descriptor, DESCRIPTOR)
1970347a39b4SMariusz Zaborski #endif
1971347a39b4SMariusz Zaborski 
197254f98da9SMariusz Zaborski void
197354f98da9SMariusz Zaborski nvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp)
197454f98da9SMariusz Zaborski {
197554f98da9SMariusz Zaborski 
197654f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
197754f98da9SMariusz Zaborski 	NVPAIR_ASSERT(nvp);
197854f98da9SMariusz Zaborski 	PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
197954f98da9SMariusz Zaborski 
198054f98da9SMariusz Zaborski 	nvpair_remove(&nvl->nvl_head, nvp, nvl);
198154f98da9SMariusz Zaborski }
198254f98da9SMariusz Zaborski 
198354f98da9SMariusz Zaborski void
198454f98da9SMariusz Zaborski nvlist_free(nvlist_t *nvl, const char *name)
198554f98da9SMariusz Zaborski {
198654f98da9SMariusz Zaborski 
198754f98da9SMariusz Zaborski 	nvlist_free_type(nvl, name, NV_TYPE_NONE);
198854f98da9SMariusz Zaborski }
198954f98da9SMariusz Zaborski 
199054f98da9SMariusz Zaborski #define	NVLIST_FREE(type, TYPE)						\
199154f98da9SMariusz Zaborski void									\
199254f98da9SMariusz Zaborski nvlist_free_##type(nvlist_t *nvl, const char *name)			\
199354f98da9SMariusz Zaborski {									\
199454f98da9SMariusz Zaborski 									\
199554f98da9SMariusz Zaborski 	nvlist_free_type(nvl, name, NV_TYPE_##TYPE);			\
199654f98da9SMariusz Zaborski }
199754f98da9SMariusz Zaborski 
199854f98da9SMariusz Zaborski NVLIST_FREE(null, NULL)
199954f98da9SMariusz Zaborski NVLIST_FREE(bool, BOOL)
200054f98da9SMariusz Zaborski NVLIST_FREE(number, NUMBER)
200154f98da9SMariusz Zaborski NVLIST_FREE(string, STRING)
200254f98da9SMariusz Zaborski NVLIST_FREE(nvlist, NVLIST)
2003347a39b4SMariusz Zaborski NVLIST_FREE(binary, BINARY)
2004347a39b4SMariusz Zaborski NVLIST_FREE(bool_array, BOOL_ARRAY)
2005347a39b4SMariusz Zaborski NVLIST_FREE(number_array, NUMBER_ARRAY)
2006347a39b4SMariusz Zaborski NVLIST_FREE(string_array, STRING_ARRAY)
2007347a39b4SMariusz Zaborski NVLIST_FREE(nvlist_array, NVLIST_ARRAY)
200854f98da9SMariusz Zaborski #ifndef _KERNEL
200954f98da9SMariusz Zaborski NVLIST_FREE(descriptor, DESCRIPTOR)
2010347a39b4SMariusz Zaborski NVLIST_FREE(descriptor_array, DESCRIPTOR_ARRAY)
201154f98da9SMariusz Zaborski #endif
201254f98da9SMariusz Zaborski 
201354f98da9SMariusz Zaborski #undef	NVLIST_FREE
201454f98da9SMariusz Zaborski 
201554f98da9SMariusz Zaborski void
201654f98da9SMariusz Zaborski nvlist_free_nvpair(nvlist_t *nvl, nvpair_t *nvp)
201754f98da9SMariusz Zaborski {
201854f98da9SMariusz Zaborski 
201954f98da9SMariusz Zaborski 	NVLIST_ASSERT(nvl);
202054f98da9SMariusz Zaborski 	NVPAIR_ASSERT(nvp);
202154f98da9SMariusz Zaborski 	PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
202254f98da9SMariusz Zaborski 
202354f98da9SMariusz Zaborski 	nvlist_remove_nvpair(nvl, nvp);
202454f98da9SMariusz Zaborski 	nvpair_free(nvp);
202554f98da9SMariusz Zaborski }
202654f98da9SMariusz Zaborski 
2027