1258065Spjd/*-
2258065Spjd * Copyright (c) 2009-2013 The FreeBSD Foundation
3258065Spjd * All rights reserved.
4258065Spjd *
5258065Spjd * This software was developed by Pawel Jakub Dawidek under sponsorship from
6258065Spjd * the FreeBSD Foundation.
7258065Spjd *
8258065Spjd * Redistribution and use in source and binary forms, with or without
9258065Spjd * modification, are permitted provided that the following conditions
10258065Spjd * are met:
11258065Spjd * 1. Redistributions of source code must retain the above copyright
12258065Spjd *    notice, this list of conditions and the following disclaimer.
13258065Spjd * 2. Redistributions in binary form must reproduce the above copyright
14258065Spjd *    notice, this list of conditions and the following disclaimer in the
15258065Spjd *    documentation and/or other materials provided with the distribution.
16258065Spjd *
17258065Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18258065Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19258065Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20258065Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21258065Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22258065Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23258065Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24258065Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25258065Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26258065Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27258065Spjd * SUCH DAMAGE.
28258065Spjd */
29258065Spjd
30258065Spjd#include <sys/cdefs.h>
31258065Spjd__FBSDID("$FreeBSD$");
32258065Spjd
33258065Spjd#include <sys/param.h>
34258065Spjd#include <sys/endian.h>
35258065Spjd#include <sys/queue.h>
36279438Srstone
37279438Srstone#ifdef _KERNEL
38279438Srstone
39279438Srstone#include <sys/errno.h>
40279438Srstone#include <sys/kernel.h>
41279438Srstone#include <sys/lock.h>
42279438Srstone#include <sys/malloc.h>
43279438Srstone#include <sys/systm.h>
44279438Srstone
45279438Srstone#include <machine/stdarg.h>
46279438Srstone
47279438Srstone#else
48258065Spjd#include <sys/socket.h>
49258065Spjd
50258065Spjd#include <errno.h>
51258065Spjd#include <stdarg.h>
52258065Spjd#include <stdbool.h>
53258065Spjd#include <stdint.h>
54258065Spjd#define	_WITH_DPRINTF
55258065Spjd#include <stdio.h>
56258065Spjd#include <stdlib.h>
57258065Spjd#include <string.h>
58258065Spjd#include <unistd.h>
59279439Srstone
60279439Srstone#include "msgio.h"
61279438Srstone#endif
62258065Spjd
63258065Spjd#ifdef HAVE_PJDLOG
64258065Spjd#include <pjdlog.h>
65258065Spjd#endif
66258065Spjd
67279439Srstone#include <sys/nv.h>
68279439Srstone#include <sys/nv_impl.h>
69279439Srstone#include <sys/nvlist_impl.h>
70279439Srstone#include <sys/nvpair_impl.h>
71258065Spjd
72258065Spjd#ifndef	HAVE_PJDLOG
73279438Srstone#ifdef _KERNEL
74279438Srstone#define	PJDLOG_ASSERT(...)		MPASS(__VA_ARGS__)
75279438Srstone#define	PJDLOG_RASSERT(expr, ...)	KASSERT(expr, (__VA_ARGS__))
76279438Srstone#define	PJDLOG_ABORT(...)		panic(__VA_ARGS__)
77279438Srstone#else
78258065Spjd#include <assert.h>
79258065Spjd#define	PJDLOG_ASSERT(...)		assert(__VA_ARGS__)
80258065Spjd#define	PJDLOG_RASSERT(expr, ...)	assert(expr)
81258065Spjd#define	PJDLOG_ABORT(...)		do {				\
82258065Spjd	fprintf(stderr, "%s:%u: ", __FILE__, __LINE__);			\
83258065Spjd	fprintf(stderr, __VA_ARGS__);					\
84258065Spjd	fprintf(stderr, "\n");						\
85258065Spjd	abort();							\
86258065Spjd} while (0)
87258065Spjd#endif
88279438Srstone#endif
89258065Spjd
90258065Spjd#define	NV_FLAG_PRIVATE_MASK	(NV_FLAG_BIG_ENDIAN)
91258065Spjd#define	NV_FLAG_PUBLIC_MASK	(NV_FLAG_IGNORE_CASE)
92258065Spjd#define	NV_FLAG_ALL_MASK	(NV_FLAG_PRIVATE_MASK | NV_FLAG_PUBLIC_MASK)
93258065Spjd
94258065Spjd#define	NVLIST_MAGIC	0x6e766c	/* "nvl" */
95258065Spjdstruct nvlist {
96271579Spjd	int		 nvl_magic;
97271579Spjd	int		 nvl_error;
98271579Spjd	int		 nvl_flags;
99271579Spjd	nvpair_t	*nvl_parent;
100271579Spjd	struct nvl_head	 nvl_head;
101258065Spjd};
102258065Spjd
103258065Spjd#define	NVLIST_ASSERT(nvl)	do {					\
104258065Spjd	PJDLOG_ASSERT((nvl) != NULL);					\
105258065Spjd	PJDLOG_ASSERT((nvl)->nvl_magic == NVLIST_MAGIC);		\
106258065Spjd} while (0)
107258065Spjd
108279438Srstone#ifdef _KERNEL
109279438SrstoneMALLOC_DEFINE(M_NVLIST, "nvlist", "kernel nvlist");
110279438Srstone#endif
111279438Srstone
112258065Spjd#define	NVPAIR_ASSERT(nvp)	nvpair_assert(nvp)
113258065Spjd
114258065Spjd#define	NVLIST_HEADER_MAGIC	0x6c
115258065Spjd#define	NVLIST_HEADER_VERSION	0x00
116258065Spjdstruct nvlist_header {
117258065Spjd	uint8_t		nvlh_magic;
118258065Spjd	uint8_t		nvlh_version;
119258065Spjd	uint8_t		nvlh_flags;
120258065Spjd	uint64_t	nvlh_descriptors;
121258065Spjd	uint64_t	nvlh_size;
122258065Spjd} __packed;
123258065Spjd
124258065Spjdnvlist_t *
125258065Spjdnvlist_create(int flags)
126258065Spjd{
127258065Spjd	nvlist_t *nvl;
128258065Spjd
129258065Spjd	PJDLOG_ASSERT((flags & ~(NV_FLAG_PUBLIC_MASK)) == 0);
130258065Spjd
131279438Srstone	nvl = nv_malloc(sizeof(*nvl));
132258065Spjd	nvl->nvl_error = 0;
133258065Spjd	nvl->nvl_flags = flags;
134271579Spjd	nvl->nvl_parent = NULL;
135258065Spjd	TAILQ_INIT(&nvl->nvl_head);
136258065Spjd	nvl->nvl_magic = NVLIST_MAGIC;
137258065Spjd
138258065Spjd	return (nvl);
139258065Spjd}
140258065Spjd
141258065Spjdvoid
142258065Spjdnvlist_destroy(nvlist_t *nvl)
143258065Spjd{
144258065Spjd	nvpair_t *nvp;
145258065Spjd	int serrno;
146258065Spjd
147258065Spjd	if (nvl == NULL)
148258065Spjd		return;
149258065Spjd
150279438Srstone	SAVE_ERRNO(serrno);
151258065Spjd
152258065Spjd	NVLIST_ASSERT(nvl);
153258065Spjd
154260222Spjd	while ((nvp = nvlist_first_nvpair(nvl)) != NULL) {
155258065Spjd		nvlist_remove_nvpair(nvl, nvp);
156260222Spjd		nvpair_free(nvp);
157260222Spjd	}
158258065Spjd	nvl->nvl_magic = 0;
159279438Srstone	nv_free(nvl);
160258065Spjd
161279438Srstone	RESTORE_ERRNO(serrno);
162258065Spjd}
163258065Spjd
164279434Srstonevoid
165279434Srstonenvlist_set_error(nvlist_t *nvl, int error)
166279434Srstone{
167279434Srstone
168279434Srstone	PJDLOG_ASSERT(error != 0);
169279434Srstone
170279434Srstone	/*
171279434Srstone	 * Check for error != 0 so that we don't do the wrong thing if somebody
172279434Srstone	 * tries to abuse this API when asserts are disabled.
173279434Srstone	 */
174279434Srstone	if (nvl != NULL && error != 0 && nvl->nvl_error == 0)
175279434Srstone		nvl->nvl_error = error;
176279434Srstone}
177279434Srstone
178258065Spjdint
179258065Spjdnvlist_error(const nvlist_t *nvl)
180258065Spjd{
181258065Spjd
182258065Spjd	if (nvl == NULL)
183258065Spjd		return (ENOMEM);
184258065Spjd
185258065Spjd	NVLIST_ASSERT(nvl);
186258065Spjd
187258065Spjd	return (nvl->nvl_error);
188258065Spjd}
189258065Spjd
190271579Spjdnvpair_t *
191271579Spjdnvlist_get_nvpair_parent(const nvlist_t *nvl)
192271579Spjd{
193271579Spjd
194271579Spjd	NVLIST_ASSERT(nvl);
195271579Spjd
196271579Spjd	return (nvl->nvl_parent);
197271579Spjd}
198271579Spjd
199271579Spjdconst nvlist_t *
200277921Spjdnvlist_get_parent(const nvlist_t *nvl, void **cookiep)
201271579Spjd{
202277921Spjd	nvpair_t *nvp;
203271579Spjd
204271579Spjd	NVLIST_ASSERT(nvl);
205271579Spjd
206277921Spjd	nvp = nvl->nvl_parent;
207277921Spjd	if (cookiep != NULL)
208277921Spjd		*cookiep = nvp;
209277921Spjd	if (nvp == NULL)
210271579Spjd		return (NULL);
211271579Spjd
212277921Spjd	return (nvpair_nvlist(nvp));
213271579Spjd}
214271579Spjd
215271579Spjdvoid
216271579Spjdnvlist_set_parent(nvlist_t *nvl, nvpair_t *parent)
217271579Spjd{
218271579Spjd
219271579Spjd	NVLIST_ASSERT(nvl);
220271579Spjd
221271579Spjd	nvl->nvl_parent = parent;
222271579Spjd}
223271579Spjd
224258065Spjdbool
225258065Spjdnvlist_empty(const nvlist_t *nvl)
226258065Spjd{
227258065Spjd
228258065Spjd	NVLIST_ASSERT(nvl);
229258065Spjd	PJDLOG_ASSERT(nvl->nvl_error == 0);
230258065Spjd
231258065Spjd	return (nvlist_first_nvpair(nvl) == NULL);
232258065Spjd}
233258065Spjd
234292637Sngieint
235292637Sngienvlist_flags(const nvlist_t *nvl)
236292637Sngie{
237292637Sngie
238292637Sngie	NVLIST_ASSERT(nvl);
239292637Sngie	PJDLOG_ASSERT(nvl->nvl_error == 0);
240292637Sngie	PJDLOG_ASSERT((nvl->nvl_flags & ~(NV_FLAG_PUBLIC_MASK)) == 0);
241292637Sngie
242292637Sngie	return (nvl->nvl_flags);
243292637Sngie}
244292637Sngie
245258065Spjdstatic void
246279435Srstonenvlist_report_missing(int type, const char *name)
247258065Spjd{
248258065Spjd
249258065Spjd	PJDLOG_ABORT("Element '%s' of type %s doesn't exist.",
250279435Srstone	    name, nvpair_type_string(type));
251258065Spjd}
252258065Spjd
253258065Spjdstatic nvpair_t *
254279435Srstonenvlist_find(const nvlist_t *nvl, int type, const char *name)
255258065Spjd{
256258065Spjd	nvpair_t *nvp;
257258065Spjd
258258065Spjd	NVLIST_ASSERT(nvl);
259258065Spjd	PJDLOG_ASSERT(nvl->nvl_error == 0);
260258065Spjd	PJDLOG_ASSERT(type == NV_TYPE_NONE ||
261258065Spjd	    (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
262258065Spjd
263258065Spjd	for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
264258065Spjd	    nvp = nvlist_next_nvpair(nvl, nvp)) {
265258065Spjd		if (type != NV_TYPE_NONE && nvpair_type(nvp) != type)
266258065Spjd			continue;
267258065Spjd		if ((nvl->nvl_flags & NV_FLAG_IGNORE_CASE) != 0) {
268258065Spjd			if (strcasecmp(nvpair_name(nvp), name) != 0)
269258065Spjd				continue;
270258065Spjd		} else {
271258065Spjd			if (strcmp(nvpair_name(nvp), name) != 0)
272258065Spjd				continue;
273258065Spjd		}
274258065Spjd		break;
275258065Spjd	}
276258065Spjd
277258065Spjd	if (nvp == NULL)
278279438Srstone		RESTORE_ERRNO(ENOENT);
279258065Spjd
280258065Spjd	return (nvp);
281258065Spjd}
282258065Spjd
283258065Spjdbool
284258065Spjdnvlist_exists_type(const nvlist_t *nvl, const char *name, int type)
285258065Spjd{
286258065Spjd
287279435Srstone	NVLIST_ASSERT(nvl);
288279435Srstone	PJDLOG_ASSERT(nvl->nvl_error == 0);
289279435Srstone	PJDLOG_ASSERT(type == NV_TYPE_NONE ||
290279435Srstone	    (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
291279435Srstone
292279435Srstone	return (nvlist_find(nvl, type, name) != NULL);
293258065Spjd}
294258065Spjd
295258065Spjdvoid
296258065Spjdnvlist_free_type(nvlist_t *nvl, const char *name, int type)
297258065Spjd{
298279435Srstone	nvpair_t *nvp;
299258065Spjd
300279435Srstone	NVLIST_ASSERT(nvl);
301279435Srstone	PJDLOG_ASSERT(nvl->nvl_error == 0);
302279435Srstone	PJDLOG_ASSERT(type == NV_TYPE_NONE ||
303279435Srstone	    (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
304279435Srstone
305279435Srstone	nvp = nvlist_find(nvl, type, name);
306279435Srstone	if (nvp != NULL)
307279435Srstone		nvlist_free_nvpair(nvl, nvp);
308279435Srstone	else
309279435Srstone		nvlist_report_missing(type, name);
310258065Spjd}
311258065Spjd
312258065Spjdnvlist_t *
313258065Spjdnvlist_clone(const nvlist_t *nvl)
314258065Spjd{
315258065Spjd	nvlist_t *newnvl;
316258065Spjd	nvpair_t *nvp, *newnvp;
317258065Spjd
318258065Spjd	NVLIST_ASSERT(nvl);
319258065Spjd
320258065Spjd	if (nvl->nvl_error != 0) {
321279438Srstone		RESTORE_ERRNO(nvl->nvl_error);
322258065Spjd		return (NULL);
323258065Spjd	}
324258065Spjd
325258065Spjd	newnvl = nvlist_create(nvl->nvl_flags & NV_FLAG_PUBLIC_MASK);
326258065Spjd	for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
327258065Spjd	    nvp = nvlist_next_nvpair(nvl, nvp)) {
328258065Spjd		newnvp = nvpair_clone(nvp);
329258065Spjd		if (newnvp == NULL)
330258065Spjd			break;
331258065Spjd		nvlist_move_nvpair(newnvl, newnvp);
332258065Spjd	}
333258065Spjd	if (nvp != NULL) {
334258065Spjd		nvlist_destroy(newnvl);
335258065Spjd		return (NULL);
336258065Spjd	}
337258065Spjd	return (newnvl);
338258065Spjd}
339258065Spjd
340279438Srstone#ifndef _KERNEL
341271579Spjdstatic bool
342271579Spjdnvlist_dump_error_check(const nvlist_t *nvl, int fd, int level)
343271579Spjd{
344271579Spjd
345271579Spjd	if (nvlist_error(nvl) != 0) {
346271579Spjd		dprintf(fd, "%*serror: %d\n", level * 4, "",
347271579Spjd		    nvlist_error(nvl));
348271579Spjd		return (true);
349271579Spjd	}
350271579Spjd
351271579Spjd	return (false);
352271579Spjd}
353271579Spjd
354258065Spjd/*
355258065Spjd * Dump content of nvlist.
356258065Spjd */
357271579Spjdvoid
358271579Spjdnvlist_dump(const nvlist_t *nvl, int fd)
359258065Spjd{
360277925Spjd	const nvlist_t *tmpnvl;
361277925Spjd	nvpair_t *nvp, *tmpnvp;
362277927Spjd	void *cookie;
363271579Spjd	int level;
364258065Spjd
365271579Spjd	level = 0;
366271579Spjd	if (nvlist_dump_error_check(nvl, fd, level))
367258065Spjd		return;
368258065Spjd
369271579Spjd	nvp = nvlist_first_nvpair(nvl);
370271579Spjd	while (nvp != NULL) {
371258065Spjd		dprintf(fd, "%*s%s (%s):", level * 4, "", nvpair_name(nvp),
372258065Spjd		    nvpair_type_string(nvpair_type(nvp)));
373258065Spjd		switch (nvpair_type(nvp)) {
374258065Spjd		case NV_TYPE_NULL:
375258065Spjd			dprintf(fd, " null\n");
376258065Spjd			break;
377258065Spjd		case NV_TYPE_BOOL:
378258065Spjd			dprintf(fd, " %s\n", nvpair_get_bool(nvp) ?
379258065Spjd			    "TRUE" : "FALSE");
380258065Spjd			break;
381258065Spjd		case NV_TYPE_NUMBER:
382258065Spjd			dprintf(fd, " %ju (%jd) (0x%jx)\n",
383258065Spjd			    (uintmax_t)nvpair_get_number(nvp),
384258065Spjd			    (intmax_t)nvpair_get_number(nvp),
385258065Spjd			    (uintmax_t)nvpair_get_number(nvp));
386258065Spjd			break;
387258065Spjd		case NV_TYPE_STRING:
388258065Spjd			dprintf(fd, " [%s]\n", nvpair_get_string(nvp));
389258065Spjd			break;
390258065Spjd		case NV_TYPE_NVLIST:
391258065Spjd			dprintf(fd, "\n");
392277925Spjd			tmpnvl = nvpair_get_nvlist(nvp);
393277925Spjd			if (nvlist_dump_error_check(tmpnvl, fd, level + 1))
394271579Spjd				break;
395277925Spjd			tmpnvp = nvlist_first_nvpair(tmpnvl);
396277925Spjd			if (tmpnvp != NULL) {
397277925Spjd				nvl = tmpnvl;
398277925Spjd				nvp = tmpnvp;
399277925Spjd				level++;
400277925Spjd				continue;
401271579Spjd			}
402277925Spjd			break;
403258065Spjd		case NV_TYPE_DESCRIPTOR:
404258065Spjd			dprintf(fd, " %d\n", nvpair_get_descriptor(nvp));
405258065Spjd			break;
406258065Spjd		case NV_TYPE_BINARY:
407258065Spjd		    {
408258065Spjd			const unsigned char *binary;
409258065Spjd			unsigned int ii;
410258065Spjd			size_t size;
411258065Spjd
412258065Spjd			binary = nvpair_get_binary(nvp, &size);
413258065Spjd			dprintf(fd, " %zu ", size);
414258065Spjd			for (ii = 0; ii < size; ii++)
415258065Spjd				dprintf(fd, "%02hhx", binary[ii]);
416258065Spjd			dprintf(fd, "\n");
417258065Spjd			break;
418258065Spjd		    }
419258065Spjd		default:
420258065Spjd			PJDLOG_ABORT("Unknown type: %d.", nvpair_type(nvp));
421258065Spjd		}
422271579Spjd
423271579Spjd		while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
424277927Spjd			cookie = NULL;
425277927Spjd			nvl = nvlist_get_parent(nvl, &cookie);
426277921Spjd			if (nvl == NULL)
427271579Spjd				return;
428277927Spjd			nvp = cookie;
429277921Spjd			level--;
430271579Spjd		}
431258065Spjd	}
432258065Spjd}
433258065Spjd
434258065Spjdvoid
435258065Spjdnvlist_fdump(const nvlist_t *nvl, FILE *fp)
436258065Spjd{
437258065Spjd
438258065Spjd	fflush(fp);
439258065Spjd	nvlist_dump(nvl, fileno(fp));
440258065Spjd}
441279438Srstone#endif
442258065Spjd
443258065Spjd/*
444258065Spjd * The function obtains size of the nvlist after nvlist_pack().
445258065Spjd */
446271579Spjdsize_t
447271579Spjdnvlist_size(const nvlist_t *nvl)
448258065Spjd{
449277925Spjd	const nvlist_t *tmpnvl;
450277925Spjd	const nvpair_t *nvp, *tmpnvp;
451277927Spjd	void *cookie;
452258065Spjd	size_t size;
453258065Spjd
454258065Spjd	NVLIST_ASSERT(nvl);
455258065Spjd	PJDLOG_ASSERT(nvl->nvl_error == 0);
456258065Spjd
457258065Spjd	size = sizeof(struct nvlist_header);
458271579Spjd	nvp = nvlist_first_nvpair(nvl);
459271579Spjd	while (nvp != NULL) {
460258065Spjd		size += nvpair_header_size();
461258065Spjd		size += strlen(nvpair_name(nvp)) + 1;
462271579Spjd		if (nvpair_type(nvp) == NV_TYPE_NVLIST) {
463271579Spjd			size += sizeof(struct nvlist_header);
464271579Spjd			size += nvpair_header_size() + 1;
465277925Spjd			tmpnvl = nvpair_get_nvlist(nvp);
466277925Spjd			PJDLOG_ASSERT(tmpnvl->nvl_error == 0);
467277925Spjd			tmpnvp = nvlist_first_nvpair(tmpnvl);
468277925Spjd			if (tmpnvp != NULL) {
469277925Spjd				nvl = tmpnvl;
470277925Spjd				nvp = tmpnvp;
471277925Spjd				continue;
472277925Spjd			}
473271579Spjd		} else {
474258065Spjd			size += nvpair_size(nvp);
475271579Spjd		}
476271579Spjd
477271579Spjd		while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
478277927Spjd			cookie = NULL;
479277927Spjd			nvl = nvlist_get_parent(nvl, &cookie);
480277921Spjd			if (nvl == NULL)
481271579Spjd				goto out;
482277927Spjd			nvp = cookie;
483271579Spjd		}
484258065Spjd	}
485258065Spjd
486271579Spjdout:
487258065Spjd	return (size);
488258065Spjd}
489258065Spjd
490279438Srstone#ifndef _KERNEL
491258065Spjdstatic int *
492258065Spjdnvlist_xdescriptors(const nvlist_t *nvl, int *descs, int level)
493258065Spjd{
494258065Spjd	const nvpair_t *nvp;
495258065Spjd
496258065Spjd	NVLIST_ASSERT(nvl);
497258065Spjd	PJDLOG_ASSERT(nvl->nvl_error == 0);
498258065Spjd	PJDLOG_ASSERT(level < 3);
499258065Spjd
500258065Spjd	for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
501258065Spjd	    nvp = nvlist_next_nvpair(nvl, nvp)) {
502258065Spjd		switch (nvpair_type(nvp)) {
503258065Spjd		case NV_TYPE_DESCRIPTOR:
504258065Spjd			*descs = nvpair_get_descriptor(nvp);
505258065Spjd			descs++;
506258065Spjd			break;
507258065Spjd		case NV_TYPE_NVLIST:
508258065Spjd			descs = nvlist_xdescriptors(nvpair_get_nvlist(nvp),
509258065Spjd			    descs, level + 1);
510258065Spjd			break;
511258065Spjd		}
512258065Spjd	}
513258065Spjd
514258065Spjd	return (descs);
515258065Spjd}
516279438Srstone#endif
517258065Spjd
518279438Srstone#ifndef _KERNEL
519258065Spjdint *
520258065Spjdnvlist_descriptors(const nvlist_t *nvl, size_t *nitemsp)
521258065Spjd{
522258065Spjd	size_t nitems;
523258065Spjd	int *fds;
524258065Spjd
525258065Spjd	nitems = nvlist_ndescriptors(nvl);
526279438Srstone	fds = nv_malloc(sizeof(fds[0]) * (nitems + 1));
527258065Spjd	if (fds == NULL)
528258065Spjd		return (NULL);
529258065Spjd	if (nitems > 0)
530258065Spjd		nvlist_xdescriptors(nvl, fds, 0);
531258065Spjd	fds[nitems] = -1;
532258065Spjd	if (nitemsp != NULL)
533258065Spjd		*nitemsp = nitems;
534258065Spjd	return (fds);
535258065Spjd}
536279438Srstone#endif
537258065Spjd
538258065Spjdstatic size_t
539258065Spjdnvlist_xndescriptors(const nvlist_t *nvl, int level)
540258065Spjd{
541279438Srstone#ifndef _KERNEL
542258065Spjd	const nvpair_t *nvp;
543258065Spjd	size_t ndescs;
544258065Spjd
545258065Spjd	NVLIST_ASSERT(nvl);
546258065Spjd	PJDLOG_ASSERT(nvl->nvl_error == 0);
547258065Spjd	PJDLOG_ASSERT(level < 3);
548258065Spjd
549258065Spjd	ndescs = 0;
550258065Spjd	for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
551258065Spjd	    nvp = nvlist_next_nvpair(nvl, nvp)) {
552258065Spjd		switch (nvpair_type(nvp)) {
553258065Spjd		case NV_TYPE_DESCRIPTOR:
554258065Spjd			ndescs++;
555258065Spjd			break;
556258065Spjd		case NV_TYPE_NVLIST:
557258065Spjd			ndescs += nvlist_xndescriptors(nvpair_get_nvlist(nvp),
558258065Spjd			    level + 1);
559258065Spjd			break;
560258065Spjd		}
561258065Spjd	}
562258065Spjd
563258065Spjd	return (ndescs);
564279438Srstone#else
565279438Srstone	return (0);
566279438Srstone#endif
567258065Spjd}
568258065Spjd
569258065Spjdsize_t
570258065Spjdnvlist_ndescriptors(const nvlist_t *nvl)
571258065Spjd{
572258065Spjd
573258065Spjd	return (nvlist_xndescriptors(nvl, 0));
574258065Spjd}
575258065Spjd
576258065Spjdstatic unsigned char *
577258065Spjdnvlist_pack_header(const nvlist_t *nvl, unsigned char *ptr, size_t *leftp)
578258065Spjd{
579258065Spjd	struct nvlist_header nvlhdr;
580258065Spjd
581258065Spjd	NVLIST_ASSERT(nvl);
582258065Spjd
583258065Spjd	nvlhdr.nvlh_magic = NVLIST_HEADER_MAGIC;
584258065Spjd	nvlhdr.nvlh_version = NVLIST_HEADER_VERSION;
585258065Spjd	nvlhdr.nvlh_flags = nvl->nvl_flags;
586258065Spjd#if BYTE_ORDER == BIG_ENDIAN
587258065Spjd	nvlhdr.nvlh_flags |= NV_FLAG_BIG_ENDIAN;
588258065Spjd#endif
589258065Spjd	nvlhdr.nvlh_descriptors = nvlist_ndescriptors(nvl);
590258065Spjd	nvlhdr.nvlh_size = *leftp - sizeof(nvlhdr);
591258065Spjd	PJDLOG_ASSERT(*leftp >= sizeof(nvlhdr));
592258065Spjd	memcpy(ptr, &nvlhdr, sizeof(nvlhdr));
593258065Spjd	ptr += sizeof(nvlhdr);
594258065Spjd	*leftp -= sizeof(nvlhdr);
595258065Spjd
596258065Spjd	return (ptr);
597258065Spjd}
598258065Spjd
599258065Spjdvoid *
600258065Spjdnvlist_xpack(const nvlist_t *nvl, int64_t *fdidxp, size_t *sizep)
601258065Spjd{
602258065Spjd	unsigned char *buf, *ptr;
603258065Spjd	size_t left, size;
604277925Spjd	const nvlist_t *tmpnvl;
605277925Spjd	nvpair_t *nvp, *tmpnvp;
606277927Spjd	void *cookie;
607258065Spjd
608258065Spjd	NVLIST_ASSERT(nvl);
609258065Spjd
610258065Spjd	if (nvl->nvl_error != 0) {
611279438Srstone		RESTORE_ERRNO(nvl->nvl_error);
612258065Spjd		return (NULL);
613258065Spjd	}
614258065Spjd
615258065Spjd	size = nvlist_size(nvl);
616279438Srstone	buf = nv_malloc(size);
617258065Spjd	if (buf == NULL)
618258065Spjd		return (NULL);
619258065Spjd
620258065Spjd	ptr = buf;
621258065Spjd	left = size;
622258065Spjd
623258065Spjd	ptr = nvlist_pack_header(nvl, ptr, &left);
624258065Spjd
625271579Spjd	nvp = nvlist_first_nvpair(nvl);
626271579Spjd	while (nvp != NULL) {
627271579Spjd		NVPAIR_ASSERT(nvp);
628271579Spjd
629271579Spjd		nvpair_init_datasize(nvp);
630271579Spjd		ptr = nvpair_pack_header(nvp, ptr, &left);
631258065Spjd		if (ptr == NULL) {
632279438Srstone			nv_free(buf);
633258065Spjd			return (NULL);
634258065Spjd		}
635271579Spjd		switch (nvpair_type(nvp)) {
636271579Spjd		case NV_TYPE_NULL:
637271579Spjd			ptr = nvpair_pack_null(nvp, ptr, &left);
638271579Spjd			break;
639271579Spjd		case NV_TYPE_BOOL:
640271579Spjd			ptr = nvpair_pack_bool(nvp, ptr, &left);
641271579Spjd			break;
642271579Spjd		case NV_TYPE_NUMBER:
643271579Spjd			ptr = nvpair_pack_number(nvp, ptr, &left);
644271579Spjd			break;
645271579Spjd		case NV_TYPE_STRING:
646271579Spjd			ptr = nvpair_pack_string(nvp, ptr, &left);
647271579Spjd			break;
648271579Spjd		case NV_TYPE_NVLIST:
649277925Spjd			tmpnvl = nvpair_get_nvlist(nvp);
650277925Spjd			ptr = nvlist_pack_header(tmpnvl, ptr, &left);
651277925Spjd			if (ptr == NULL)
652277925Spjd				goto out;
653277925Spjd			tmpnvp = nvlist_first_nvpair(tmpnvl);
654277925Spjd			if (tmpnvp != NULL) {
655277925Spjd				nvl = tmpnvl;
656277925Spjd				nvp = tmpnvp;
657277925Spjd				continue;
658277925Spjd			}
659277925Spjd			ptr = nvpair_pack_nvlist_up(ptr, &left);
660277925Spjd			break;
661279438Srstone#ifndef _KERNEL
662271579Spjd		case NV_TYPE_DESCRIPTOR:
663271579Spjd			ptr = nvpair_pack_descriptor(nvp, ptr, fdidxp, &left);
664271579Spjd			break;
665279438Srstone#endif
666271579Spjd		case NV_TYPE_BINARY:
667271579Spjd			ptr = nvpair_pack_binary(nvp, ptr, &left);
668271579Spjd			break;
669271579Spjd		default:
670271579Spjd			PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp));
671271579Spjd		}
672271579Spjd		if (ptr == NULL) {
673279438Srstone			nv_free(buf);
674271579Spjd			return (NULL);
675271579Spjd		}
676271579Spjd		while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
677277927Spjd			cookie = NULL;
678277927Spjd			nvl = nvlist_get_parent(nvl, &cookie);
679277921Spjd			if (nvl == NULL)
680271579Spjd				goto out;
681277927Spjd			nvp = cookie;
682271579Spjd			ptr = nvpair_pack_nvlist_up(ptr, &left);
683271579Spjd			if (ptr == NULL)
684271579Spjd				goto out;
685271579Spjd		}
686258065Spjd	}
687258065Spjd
688271579Spjdout:
689258065Spjd	if (sizep != NULL)
690258065Spjd		*sizep = size;
691258065Spjd	return (buf);
692258065Spjd}
693258065Spjd
694258065Spjdvoid *
695258065Spjdnvlist_pack(const nvlist_t *nvl, size_t *sizep)
696258065Spjd{
697258065Spjd
698258065Spjd	NVLIST_ASSERT(nvl);
699258065Spjd
700258065Spjd	if (nvl->nvl_error != 0) {
701279438Srstone		RESTORE_ERRNO(nvl->nvl_error);
702258065Spjd		return (NULL);
703258065Spjd	}
704258065Spjd
705258065Spjd	if (nvlist_ndescriptors(nvl) > 0) {
706279438Srstone		RESTORE_ERRNO(EOPNOTSUPP);
707258065Spjd		return (NULL);
708258065Spjd	}
709258065Spjd
710258065Spjd	return (nvlist_xpack(nvl, NULL, sizep));
711258065Spjd}
712258065Spjd
713258065Spjdstatic bool
714258065Spjdnvlist_check_header(struct nvlist_header *nvlhdrp)
715258065Spjd{
716258065Spjd
717258065Spjd	if (nvlhdrp->nvlh_magic != NVLIST_HEADER_MAGIC) {
718279438Srstone		RESTORE_ERRNO(EINVAL);
719258065Spjd		return (false);
720258065Spjd	}
721264021Sjilles	if ((nvlhdrp->nvlh_flags & ~NV_FLAG_ALL_MASK) != 0) {
722279438Srstone		RESTORE_ERRNO(EINVAL);
723258065Spjd		return (false);
724258065Spjd	}
725258065Spjd#if BYTE_ORDER == BIG_ENDIAN
726258065Spjd	if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) == 0) {
727258065Spjd		nvlhdrp->nvlh_size = le64toh(nvlhdrp->nvlh_size);
728258065Spjd		nvlhdrp->nvlh_descriptors = le64toh(nvlhdrp->nvlh_descriptors);
729258065Spjd	}
730258065Spjd#else
731258065Spjd	if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0) {
732258065Spjd		nvlhdrp->nvlh_size = be64toh(nvlhdrp->nvlh_size);
733258065Spjd		nvlhdrp->nvlh_descriptors = be64toh(nvlhdrp->nvlh_descriptors);
734258065Spjd	}
735258065Spjd#endif
736258065Spjd	return (true);
737258065Spjd}
738258065Spjd
739271579Spjdconst unsigned char *
740258065Spjdnvlist_unpack_header(nvlist_t *nvl, const unsigned char *ptr, size_t nfds,
741272843Spjd    bool *isbep, size_t *leftp)
742258065Spjd{
743258065Spjd	struct nvlist_header nvlhdr;
744258065Spjd
745258065Spjd	if (*leftp < sizeof(nvlhdr))
746258065Spjd		goto failed;
747258065Spjd
748258065Spjd	memcpy(&nvlhdr, ptr, sizeof(nvlhdr));
749258065Spjd
750258065Spjd	if (!nvlist_check_header(&nvlhdr))
751258065Spjd		goto failed;
752258065Spjd
753258065Spjd	if (nvlhdr.nvlh_size != *leftp - sizeof(nvlhdr))
754258065Spjd		goto failed;
755258065Spjd
756258065Spjd	/*
757258065Spjd	 * nvlh_descriptors might be smaller than nfds in embedded nvlists.
758258065Spjd	 */
759258065Spjd	if (nvlhdr.nvlh_descriptors > nfds)
760258065Spjd		goto failed;
761258065Spjd
762258065Spjd	if ((nvlhdr.nvlh_flags & ~NV_FLAG_ALL_MASK) != 0)
763258065Spjd		goto failed;
764258065Spjd
765258065Spjd	nvl->nvl_flags = (nvlhdr.nvlh_flags & NV_FLAG_PUBLIC_MASK);
766258065Spjd
767258065Spjd	ptr += sizeof(nvlhdr);
768272843Spjd	if (isbep != NULL)
769272843Spjd		*isbep = (((int)nvlhdr.nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0);
770258065Spjd	*leftp -= sizeof(nvlhdr);
771258065Spjd
772258065Spjd	return (ptr);
773258065Spjdfailed:
774279438Srstone	RESTORE_ERRNO(EINVAL);
775258065Spjd	return (NULL);
776258065Spjd}
777258065Spjd
778258065Spjdnvlist_t *
779258065Spjdnvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds)
780258065Spjd{
781258065Spjd	const unsigned char *ptr;
782271579Spjd	nvlist_t *nvl, *retnvl, *tmpnvl;
783258065Spjd	nvpair_t *nvp;
784258065Spjd	size_t left;
785272843Spjd	bool isbe;
786258065Spjd
787258065Spjd	left = size;
788258065Spjd	ptr = buf;
789258065Spjd
790271579Spjd	tmpnvl = NULL;
791271579Spjd	nvl = retnvl = nvlist_create(0);
792258065Spjd	if (nvl == NULL)
793258065Spjd		goto failed;
794258065Spjd
795272843Spjd	ptr = nvlist_unpack_header(nvl, ptr, nfds, &isbe, &left);
796258065Spjd	if (ptr == NULL)
797258065Spjd		goto failed;
798258065Spjd
799258065Spjd	while (left > 0) {
800272843Spjd		ptr = nvpair_unpack(isbe, ptr, &left, &nvp);
801258065Spjd		if (ptr == NULL)
802258065Spjd			goto failed;
803271579Spjd		switch (nvpair_type(nvp)) {
804271579Spjd		case NV_TYPE_NULL:
805272843Spjd			ptr = nvpair_unpack_null(isbe, nvp, ptr, &left);
806271579Spjd			break;
807271579Spjd		case NV_TYPE_BOOL:
808272843Spjd			ptr = nvpair_unpack_bool(isbe, nvp, ptr, &left);
809271579Spjd			break;
810271579Spjd		case NV_TYPE_NUMBER:
811272843Spjd			ptr = nvpair_unpack_number(isbe, nvp, ptr, &left);
812271579Spjd			break;
813271579Spjd		case NV_TYPE_STRING:
814272843Spjd			ptr = nvpair_unpack_string(isbe, nvp, ptr, &left);
815271579Spjd			break;
816271579Spjd		case NV_TYPE_NVLIST:
817272843Spjd			ptr = nvpair_unpack_nvlist(isbe, nvp, ptr, &left, nfds,
818272843Spjd			    &tmpnvl);
819271579Spjd			nvlist_set_parent(tmpnvl, nvp);
820271579Spjd			break;
821279438Srstone#ifndef _KERNEL
822271579Spjd		case NV_TYPE_DESCRIPTOR:
823272843Spjd			ptr = nvpair_unpack_descriptor(isbe, nvp, ptr, &left,
824271579Spjd			    fds, nfds);
825271579Spjd			break;
826279438Srstone#endif
827271579Spjd		case NV_TYPE_BINARY:
828272843Spjd			ptr = nvpair_unpack_binary(isbe, nvp, ptr, &left);
829271579Spjd			break;
830271579Spjd		case NV_TYPE_NVLIST_UP:
831271579Spjd			if (nvl->nvl_parent == NULL)
832271579Spjd				goto failed;
833271579Spjd			nvl = nvpair_nvlist(nvl->nvl_parent);
834271579Spjd			continue;
835271579Spjd		default:
836271579Spjd			PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp));
837271579Spjd		}
838271579Spjd		if (ptr == NULL)
839271579Spjd			goto failed;
840258065Spjd		nvlist_move_nvpair(nvl, nvp);
841271579Spjd		if (tmpnvl != NULL) {
842271579Spjd			nvl = tmpnvl;
843271579Spjd			tmpnvl = NULL;
844271579Spjd		}
845258065Spjd	}
846258065Spjd
847271579Spjd	return (retnvl);
848258065Spjdfailed:
849271579Spjd	nvlist_destroy(retnvl);
850258065Spjd	return (NULL);
851258065Spjd}
852258065Spjd
853258065Spjdnvlist_t *
854258065Spjdnvlist_unpack(const void *buf, size_t size)
855258065Spjd{
856258065Spjd
857258065Spjd	return (nvlist_xunpack(buf, size, NULL, 0));
858258065Spjd}
859258065Spjd
860279438Srstone#ifndef _KERNEL
861258065Spjdint
862258065Spjdnvlist_send(int sock, const nvlist_t *nvl)
863258065Spjd{
864258065Spjd	size_t datasize, nfds;
865258065Spjd	int *fds;
866258065Spjd	void *data;
867258065Spjd	int64_t fdidx;
868258065Spjd	int serrno, ret;
869258065Spjd
870258065Spjd	if (nvlist_error(nvl) != 0) {
871258065Spjd		errno = nvlist_error(nvl);
872258065Spjd		return (-1);
873258065Spjd	}
874258065Spjd
875258065Spjd	fds = nvlist_descriptors(nvl, &nfds);
876258065Spjd	if (fds == NULL)
877258065Spjd		return (-1);
878258065Spjd
879258065Spjd	ret = -1;
880258065Spjd	data = NULL;
881258065Spjd	fdidx = 0;
882258065Spjd
883258065Spjd	data = nvlist_xpack(nvl, &fdidx, &datasize);
884258065Spjd	if (data == NULL)
885258065Spjd		goto out;
886258065Spjd
887258065Spjd	if (buf_send(sock, data, datasize) == -1)
888258065Spjd		goto out;
889258065Spjd
890258065Spjd	if (nfds > 0) {
891258065Spjd		if (fd_send(sock, fds, nfds) == -1)
892258065Spjd			goto out;
893258065Spjd	}
894258065Spjd
895258065Spjd	ret = 0;
896258065Spjdout:
897258065Spjd	serrno = errno;
898258065Spjd	free(fds);
899258065Spjd	free(data);
900258065Spjd	errno = serrno;
901258065Spjd	return (ret);
902258065Spjd}
903258065Spjd
904258065Spjdnvlist_t *
905258065Spjdnvlist_recv(int sock)
906258065Spjd{
907258065Spjd	struct nvlist_header nvlhdr;
908258065Spjd	nvlist_t *nvl, *ret;
909259430Spjd	unsigned char *buf;
910271028Spjd	size_t nfds, size, i;
911271028Spjd	int serrno, *fds;
912258065Spjd
913259430Spjd	if (buf_recv(sock, &nvlhdr, sizeof(nvlhdr)) == -1)
914258065Spjd		return (NULL);
915258065Spjd
916258065Spjd	if (!nvlist_check_header(&nvlhdr))
917258065Spjd		return (NULL);
918258065Spjd
919258065Spjd	nfds = (size_t)nvlhdr.nvlh_descriptors;
920258065Spjd	size = sizeof(nvlhdr) + (size_t)nvlhdr.nvlh_size;
921258065Spjd
922258065Spjd	buf = malloc(size);
923258065Spjd	if (buf == NULL)
924258065Spjd		return (NULL);
925258065Spjd
926259430Spjd	memcpy(buf, &nvlhdr, sizeof(nvlhdr));
927259430Spjd
928258065Spjd	ret = NULL;
929258065Spjd	fds = NULL;
930258065Spjd
931259430Spjd	if (buf_recv(sock, buf + sizeof(nvlhdr), size - sizeof(nvlhdr)) == -1)
932258065Spjd		goto out;
933258065Spjd
934258065Spjd	if (nfds > 0) {
935258065Spjd		fds = malloc(nfds * sizeof(fds[0]));
936258065Spjd		if (fds == NULL)
937258065Spjd			goto out;
938258065Spjd		if (fd_recv(sock, fds, nfds) == -1)
939258065Spjd			goto out;
940258065Spjd	}
941258065Spjd
942258065Spjd	nvl = nvlist_xunpack(buf, size, fds, nfds);
943271026Spjd	if (nvl == NULL) {
944271026Spjd		for (i = 0; i < nfds; i++)
945271026Spjd			close(fds[i]);
946258065Spjd		goto out;
947271026Spjd	}
948258065Spjd
949258065Spjd	ret = nvl;
950258065Spjdout:
951258065Spjd	serrno = errno;
952258065Spjd	free(buf);
953258065Spjd	free(fds);
954258065Spjd	errno = serrno;
955258065Spjd
956258065Spjd	return (ret);
957258065Spjd}
958258065Spjd
959258065Spjdnvlist_t *
960258065Spjdnvlist_xfer(int sock, nvlist_t *nvl)
961258065Spjd{
962258065Spjd
963258065Spjd	if (nvlist_send(sock, nvl) < 0) {
964258065Spjd		nvlist_destroy(nvl);
965258065Spjd		return (NULL);
966258065Spjd	}
967258065Spjd	nvlist_destroy(nvl);
968258065Spjd	return (nvlist_recv(sock));
969258065Spjd}
970279438Srstone#endif
971258065Spjd
972258065Spjdnvpair_t *
973258065Spjdnvlist_first_nvpair(const nvlist_t *nvl)
974258065Spjd{
975258065Spjd
976258065Spjd	NVLIST_ASSERT(nvl);
977258065Spjd
978258065Spjd	return (TAILQ_FIRST(&nvl->nvl_head));
979258065Spjd}
980258065Spjd
981258065Spjdnvpair_t *
982258065Spjdnvlist_next_nvpair(const nvlist_t *nvl, const nvpair_t *nvp)
983258065Spjd{
984258065Spjd	nvpair_t *retnvp;
985258065Spjd
986258065Spjd	NVLIST_ASSERT(nvl);
987258065Spjd	NVPAIR_ASSERT(nvp);
988258065Spjd	PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
989258065Spjd
990258065Spjd	retnvp = nvpair_next(nvp);
991258065Spjd	PJDLOG_ASSERT(retnvp == NULL || nvpair_nvlist(retnvp) == nvl);
992258065Spjd
993258065Spjd	return (retnvp);
994258065Spjd
995258065Spjd}
996258065Spjd
997258065Spjdnvpair_t *
998258065Spjdnvlist_prev_nvpair(const nvlist_t *nvl, const nvpair_t *nvp)
999258065Spjd{
1000258065Spjd	nvpair_t *retnvp;
1001258065Spjd
1002258065Spjd	NVLIST_ASSERT(nvl);
1003258065Spjd	NVPAIR_ASSERT(nvp);
1004258065Spjd	PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
1005258065Spjd
1006258065Spjd	retnvp = nvpair_prev(nvp);
1007258065Spjd	PJDLOG_ASSERT(nvpair_nvlist(retnvp) == nvl);
1008258065Spjd
1009258065Spjd	return (retnvp);
1010258065Spjd}
1011258065Spjd
1012258065Spjdconst char *
1013258065Spjdnvlist_next(const nvlist_t *nvl, int *typep, void **cookiep)
1014258065Spjd{
1015258065Spjd	nvpair_t *nvp;
1016258065Spjd
1017258065Spjd	NVLIST_ASSERT(nvl);
1018258065Spjd	PJDLOG_ASSERT(cookiep != NULL);
1019258065Spjd
1020258065Spjd	if (*cookiep == NULL)
1021258065Spjd		nvp = nvlist_first_nvpair(nvl);
1022258065Spjd	else
1023258065Spjd		nvp = nvlist_next_nvpair(nvl, *cookiep);
1024258065Spjd	if (nvp == NULL)
1025258065Spjd		return (NULL);
1026258065Spjd	if (typep != NULL)
1027258065Spjd		*typep = nvpair_type(nvp);
1028258065Spjd	*cookiep = nvp;
1029258065Spjd	return (nvpair_name(nvp));
1030258065Spjd}
1031258065Spjd
1032258065Spjdbool
1033258065Spjdnvlist_exists(const nvlist_t *nvl, const char *name)
1034258065Spjd{
1035258065Spjd
1036279435Srstone	return (nvlist_find(nvl, NV_TYPE_NONE, name) != NULL);
1037258065Spjd}
1038258065Spjd
1039279435Srstone#define	NVLIST_EXISTS(type, TYPE)					\
1040258065Spjdbool									\
1041258065Spjdnvlist_exists_##type(const nvlist_t *nvl, const char *name)		\
1042258065Spjd{									\
1043258065Spjd									\
1044279435Srstone	return (nvlist_find(nvl, NV_TYPE_##TYPE, name) != NULL);	\
1045258065Spjd}
1046258065Spjd
1047279435SrstoneNVLIST_EXISTS(null, NULL)
1048279435SrstoneNVLIST_EXISTS(bool, BOOL)
1049279435SrstoneNVLIST_EXISTS(number, NUMBER)
1050279435SrstoneNVLIST_EXISTS(string, STRING)
1051279435SrstoneNVLIST_EXISTS(nvlist, NVLIST)
1052279438Srstone#ifndef _KERNEL
1053279435SrstoneNVLIST_EXISTS(descriptor, DESCRIPTOR)
1054279438Srstone#endif
1055279435SrstoneNVLIST_EXISTS(binary, BINARY)
1056258065Spjd
1057258065Spjd#undef	NVLIST_EXISTS
1058258065Spjd
1059258065Spjdvoid
1060258065Spjdnvlist_add_nvpair(nvlist_t *nvl, const nvpair_t *nvp)
1061258065Spjd{
1062258065Spjd	nvpair_t *newnvp;
1063258065Spjd
1064258065Spjd	NVPAIR_ASSERT(nvp);
1065258065Spjd
1066258065Spjd	if (nvlist_error(nvl) != 0) {
1067279438Srstone		RESTORE_ERRNO(nvlist_error(nvl));
1068258065Spjd		return;
1069258065Spjd	}
1070258065Spjd	if (nvlist_exists(nvl, nvpair_name(nvp))) {
1071279438Srstone		nvl->nvl_error = EEXIST;
1072279438Srstone		RESTORE_ERRNO(nvlist_error(nvl));
1073258065Spjd		return;
1074258065Spjd	}
1075258065Spjd
1076258065Spjd	newnvp = nvpair_clone(nvp);
1077258065Spjd	if (newnvp == NULL) {
1078279438Srstone		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1079279438Srstone		RESTORE_ERRNO(nvlist_error(nvl));
1080258065Spjd		return;
1081258065Spjd	}
1082258065Spjd
1083258065Spjd	nvpair_insert(&nvl->nvl_head, newnvp, nvl);
1084258065Spjd}
1085258065Spjd
1086258065Spjdvoid
1087258065Spjdnvlist_add_stringf(nvlist_t *nvl, const char *name, const char *valuefmt, ...)
1088258065Spjd{
1089258065Spjd	va_list valueap;
1090258065Spjd
1091258065Spjd	va_start(valueap, valuefmt);
1092258065Spjd	nvlist_add_stringv(nvl, name, valuefmt, valueap);
1093258065Spjd	va_end(valueap);
1094258065Spjd}
1095258065Spjd
1096258065Spjdvoid
1097258065Spjdnvlist_add_stringv(nvlist_t *nvl, const char *name, const char *valuefmt,
1098258065Spjd    va_list valueap)
1099258065Spjd{
1100258065Spjd	nvpair_t *nvp;
1101258065Spjd
1102258065Spjd	if (nvlist_error(nvl) != 0) {
1103279438Srstone		RESTORE_ERRNO(nvlist_error(nvl));
1104258065Spjd		return;
1105258065Spjd	}
1106258065Spjd
1107258065Spjd	nvp = nvpair_create_stringv(name, valuefmt, valueap);
1108279438Srstone	if (nvp == NULL) {
1109279438Srstone		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1110279438Srstone		RESTORE_ERRNO(nvl->nvl_error);
1111279438Srstone	} else
1112258065Spjd		nvlist_move_nvpair(nvl, nvp);
1113258065Spjd}
1114258065Spjd
1115258065Spjdvoid
1116292637Sngienvlist_add_null(nvlist_t *nvl, const char *name)
1117258065Spjd{
1118258065Spjd	nvpair_t *nvp;
1119258065Spjd
1120258065Spjd	if (nvlist_error(nvl) != 0) {
1121279438Srstone		RESTORE_ERRNO(nvlist_error(nvl));
1122258065Spjd		return;
1123258065Spjd	}
1124258065Spjd
1125292637Sngie	nvp = nvpair_create_null(name);
1126279438Srstone	if (nvp == NULL) {
1127279438Srstone		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1128279438Srstone		RESTORE_ERRNO(nvl->nvl_error);
1129279438Srstone	} else
1130258065Spjd		nvlist_move_nvpair(nvl, nvp);
1131258065Spjd}
1132258065Spjd
1133258065Spjdvoid
1134292637Sngienvlist_add_bool(nvlist_t *nvl, const char *name, bool value)
1135258065Spjd{
1136258065Spjd	nvpair_t *nvp;
1137258065Spjd
1138258065Spjd	if (nvlist_error(nvl) != 0) {
1139279438Srstone		RESTORE_ERRNO(nvlist_error(nvl));
1140258065Spjd		return;
1141258065Spjd	}
1142258065Spjd
1143292637Sngie	nvp = nvpair_create_bool(name, value);
1144279438Srstone	if (nvp == NULL) {
1145279438Srstone		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1146279438Srstone		RESTORE_ERRNO(nvl->nvl_error);
1147279438Srstone	} else
1148258065Spjd		nvlist_move_nvpair(nvl, nvp);
1149258065Spjd}
1150258065Spjd
1151258065Spjdvoid
1152292637Sngienvlist_add_number(nvlist_t *nvl, const char *name, uint64_t value)
1153258065Spjd{
1154258065Spjd	nvpair_t *nvp;
1155258065Spjd
1156258065Spjd	if (nvlist_error(nvl) != 0) {
1157279438Srstone		RESTORE_ERRNO(nvlist_error(nvl));
1158258065Spjd		return;
1159258065Spjd	}
1160258065Spjd
1161292637Sngie	nvp = nvpair_create_number(name, value);
1162279438Srstone	if (nvp == NULL) {
1163279438Srstone		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1164279438Srstone		RESTORE_ERRNO(nvl->nvl_error);
1165279438Srstone	} else
1166258065Spjd		nvlist_move_nvpair(nvl, nvp);
1167258065Spjd}
1168258065Spjd
1169258065Spjdvoid
1170292637Sngienvlist_add_string(nvlist_t *nvl, const char *name, const char *value)
1171258065Spjd{
1172258065Spjd	nvpair_t *nvp;
1173258065Spjd
1174258065Spjd	if (nvlist_error(nvl) != 0) {
1175279438Srstone		RESTORE_ERRNO(nvlist_error(nvl));
1176258065Spjd		return;
1177258065Spjd	}
1178258065Spjd
1179292637Sngie	nvp = nvpair_create_string(name, value);
1180279438Srstone	if (nvp == NULL) {
1181279438Srstone		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1182279438Srstone		RESTORE_ERRNO(nvl->nvl_error);
1183279438Srstone	} else
1184258065Spjd		nvlist_move_nvpair(nvl, nvp);
1185258065Spjd}
1186258065Spjd
1187258065Spjdvoid
1188292637Sngienvlist_add_nvlist(nvlist_t *nvl, const char *name, const nvlist_t *value)
1189258065Spjd{
1190258065Spjd	nvpair_t *nvp;
1191258065Spjd
1192258065Spjd	if (nvlist_error(nvl) != 0) {
1193279438Srstone		RESTORE_ERRNO(nvlist_error(nvl));
1194258065Spjd		return;
1195258065Spjd	}
1196258065Spjd
1197292637Sngie	nvp = nvpair_create_nvlist(name, value);
1198279438Srstone	if (nvp == NULL) {
1199279438Srstone		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1200279438Srstone		RESTORE_ERRNO(nvl->nvl_error);
1201279438Srstone	} else
1202258065Spjd		nvlist_move_nvpair(nvl, nvp);
1203258065Spjd}
1204258065Spjd
1205279438Srstone#ifndef _KERNEL
1206258065Spjdvoid
1207292637Sngienvlist_add_descriptor(nvlist_t *nvl, const char *name, int value)
1208258065Spjd{
1209258065Spjd	nvpair_t *nvp;
1210258065Spjd
1211258065Spjd	if (nvlist_error(nvl) != 0) {
1212258065Spjd		errno = nvlist_error(nvl);
1213258065Spjd		return;
1214258065Spjd	}
1215258065Spjd
1216292637Sngie	nvp = nvpair_create_descriptor(name, value);
1217258065Spjd	if (nvp == NULL)
1218258065Spjd		nvl->nvl_error = errno = (errno != 0 ? errno : ENOMEM);
1219258065Spjd	else
1220258065Spjd		nvlist_move_nvpair(nvl, nvp);
1221258065Spjd}
1222279438Srstone#endif
1223258065Spjd
1224258065Spjdvoid
1225292637Sngienvlist_add_binary(nvlist_t *nvl, const char *name, const void *value,
1226292637Sngie    size_t size)
1227258065Spjd{
1228258065Spjd	nvpair_t *nvp;
1229258065Spjd
1230258065Spjd	if (nvlist_error(nvl) != 0) {
1231279438Srstone		RESTORE_ERRNO(nvlist_error(nvl));
1232258065Spjd		return;
1233258065Spjd	}
1234258065Spjd
1235292637Sngie	nvp = nvpair_create_binary(name, value, size);
1236279438Srstone	if (nvp == NULL) {
1237279438Srstone		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1238279438Srstone		RESTORE_ERRNO(nvl->nvl_error);
1239279438Srstone	} else
1240258065Spjd		nvlist_move_nvpair(nvl, nvp);
1241258065Spjd}
1242258065Spjd
1243258065Spjdvoid
1244258065Spjdnvlist_move_nvpair(nvlist_t *nvl, nvpair_t *nvp)
1245258065Spjd{
1246258065Spjd
1247258065Spjd	NVPAIR_ASSERT(nvp);
1248258065Spjd	PJDLOG_ASSERT(nvpair_nvlist(nvp) == NULL);
1249258065Spjd
1250258065Spjd	if (nvlist_error(nvl) != 0) {
1251258065Spjd		nvpair_free(nvp);
1252279438Srstone		RESTORE_ERRNO(nvlist_error(nvl));
1253258065Spjd		return;
1254258065Spjd	}
1255258065Spjd	if (nvlist_exists(nvl, nvpair_name(nvp))) {
1256258065Spjd		nvpair_free(nvp);
1257279438Srstone		nvl->nvl_error = EEXIST;
1258279438Srstone		RESTORE_ERRNO(nvl->nvl_error);
1259258065Spjd		return;
1260258065Spjd	}
1261258065Spjd
1262258065Spjd	nvpair_insert(&nvl->nvl_head, nvp, nvl);
1263258065Spjd}
1264258065Spjd
1265258065Spjdvoid
1266292637Sngienvlist_move_string(nvlist_t *nvl, const char *name, char *value)
1267258065Spjd{
1268258065Spjd	nvpair_t *nvp;
1269258065Spjd
1270258065Spjd	if (nvlist_error(nvl) != 0) {
1271279438Srstone		nv_free(value);
1272279438Srstone		RESTORE_ERRNO(nvlist_error(nvl));
1273258065Spjd		return;
1274258065Spjd	}
1275258065Spjd
1276292637Sngie	nvp = nvpair_move_string(name, value);
1277279438Srstone	if (nvp == NULL) {
1278279438Srstone		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1279279438Srstone		RESTORE_ERRNO(nvl->nvl_error);
1280279438Srstone	} else
1281258065Spjd		nvlist_move_nvpair(nvl, nvp);
1282258065Spjd}
1283258065Spjd
1284258065Spjdvoid
1285292637Sngienvlist_move_nvlist(nvlist_t *nvl, const char *name, nvlist_t *value)
1286258065Spjd{
1287258065Spjd	nvpair_t *nvp;
1288258065Spjd
1289258065Spjd	if (nvlist_error(nvl) != 0) {
1290271579Spjd		if (value != NULL && nvlist_get_nvpair_parent(value) != NULL)
1291271579Spjd			nvlist_destroy(value);
1292279438Srstone		RESTORE_ERRNO(nvlist_error(nvl));
1293258065Spjd		return;
1294258065Spjd	}
1295258065Spjd
1296292637Sngie	nvp = nvpair_move_nvlist(name, value);
1297279438Srstone	if (nvp == NULL) {
1298279438Srstone		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1299279438Srstone		RESTORE_ERRNO(nvl->nvl_error);
1300279438Srstone	} else
1301258065Spjd		nvlist_move_nvpair(nvl, nvp);
1302258065Spjd}
1303258065Spjd
1304279438Srstone#ifndef _KERNEL
1305258065Spjdvoid
1306292637Sngienvlist_move_descriptor(nvlist_t *nvl, const char *name, int value)
1307258065Spjd{
1308258065Spjd	nvpair_t *nvp;
1309258065Spjd
1310258065Spjd	if (nvlist_error(nvl) != 0) {
1311258065Spjd		close(value);
1312258065Spjd		errno = nvlist_error(nvl);
1313258065Spjd		return;
1314258065Spjd	}
1315258065Spjd
1316292637Sngie	nvp = nvpair_move_descriptor(name, value);
1317258065Spjd	if (nvp == NULL)
1318258065Spjd		nvl->nvl_error = errno = (errno != 0 ? errno : ENOMEM);
1319258065Spjd	else
1320258065Spjd		nvlist_move_nvpair(nvl, nvp);
1321258065Spjd}
1322279438Srstone#endif
1323258065Spjd
1324258065Spjdvoid
1325292637Sngienvlist_move_binary(nvlist_t *nvl, const char *name, void *value, size_t size)
1326258065Spjd{
1327258065Spjd	nvpair_t *nvp;
1328258065Spjd
1329258065Spjd	if (nvlist_error(nvl) != 0) {
1330279438Srstone		nv_free(value);
1331279438Srstone		RESTORE_ERRNO(nvlist_error(nvl));
1332258065Spjd		return;
1333258065Spjd	}
1334258065Spjd
1335292637Sngie	nvp = nvpair_move_binary(name, value, size);
1336279438Srstone	if (nvp == NULL) {
1337279438Srstone		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1338279438Srstone		RESTORE_ERRNO(nvl->nvl_error);
1339279438Srstone	} else
1340258065Spjd		nvlist_move_nvpair(nvl, nvp);
1341258065Spjd}
1342258065Spjd
1343279435Srstoneconst nvpair_t *
1344279435Srstonenvlist_get_nvpair(const nvlist_t *nvl, const char *name)
1345279435Srstone{
1346279435Srstone
1347279435Srstone	return (nvlist_find(nvl, NV_TYPE_NONE, name));
1348279435Srstone}
1349279435Srstone
1350279435Srstone#define	NVLIST_GET(ftype, type, TYPE)					\
1351258065Spjdftype									\
1352258065Spjdnvlist_get_##type(const nvlist_t *nvl, const char *name)		\
1353258065Spjd{									\
1354279435Srstone	const nvpair_t *nvp;						\
1355258065Spjd									\
1356279435Srstone	nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name);			\
1357279435Srstone	if (nvp == NULL)						\
1358279435Srstone		nvlist_report_missing(NV_TYPE_##TYPE, name);		\
1359279435Srstone	return (nvpair_get_##type(nvp));				\
1360258065Spjd}
1361258065Spjd
1362279435SrstoneNVLIST_GET(bool, bool, BOOL)
1363279435SrstoneNVLIST_GET(uint64_t, number, NUMBER)
1364279435SrstoneNVLIST_GET(const char *, string, STRING)
1365279435SrstoneNVLIST_GET(const nvlist_t *, nvlist, NVLIST)
1366279438Srstone#ifndef _KERNEL
1367279435SrstoneNVLIST_GET(int, descriptor, DESCRIPTOR)
1368279438Srstone#endif
1369258065Spjd
1370258065Spjd#undef	NVLIST_GET
1371258065Spjd
1372258065Spjdconst void *
1373258065Spjdnvlist_get_binary(const nvlist_t *nvl, const char *name, size_t *sizep)
1374258065Spjd{
1375279435Srstone	nvpair_t *nvp;
1376258065Spjd
1377279435Srstone	nvp = nvlist_find(nvl, NV_TYPE_BINARY, name);
1378279435Srstone	if (nvp == NULL)
1379279435Srstone		nvlist_report_missing(NV_TYPE_BINARY, name);
1380279435Srstone
1381279435Srstone	return (nvpair_get_binary(nvp, sizep));
1382258065Spjd}
1383258065Spjd
1384279435Srstone#define	NVLIST_TAKE(ftype, type, TYPE)					\
1385258065Spjdftype									\
1386258065Spjdnvlist_take_##type(nvlist_t *nvl, const char *name)			\
1387258065Spjd{									\
1388279435Srstone	nvpair_t *nvp;							\
1389279435Srstone	ftype value;							\
1390258065Spjd									\
1391279435Srstone	nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name);			\
1392279435Srstone	if (nvp == NULL)						\
1393279435Srstone		nvlist_report_missing(NV_TYPE_##TYPE, name);		\
1394279435Srstone	value = (ftype)(intptr_t)nvpair_get_##type(nvp);		\
1395279435Srstone	nvlist_remove_nvpair(nvl, nvp);					\
1396279435Srstone	nvpair_free_structure(nvp);					\
1397279435Srstone	return (value);							\
1398258065Spjd}
1399258065Spjd
1400279435SrstoneNVLIST_TAKE(bool, bool, BOOL)
1401279435SrstoneNVLIST_TAKE(uint64_t, number, NUMBER)
1402279435SrstoneNVLIST_TAKE(char *, string, STRING)
1403279435SrstoneNVLIST_TAKE(nvlist_t *, nvlist, NVLIST)
1404279438Srstone#ifndef _KERNEL
1405279435SrstoneNVLIST_TAKE(int, descriptor, DESCRIPTOR)
1406279438Srstone#endif
1407258065Spjd
1408258065Spjd#undef	NVLIST_TAKE
1409258065Spjd
1410258065Spjdvoid *
1411258065Spjdnvlist_take_binary(nvlist_t *nvl, const char *name, size_t *sizep)
1412258065Spjd{
1413279435Srstone	nvpair_t *nvp;
1414279435Srstone	void *value;
1415258065Spjd
1416279435Srstone	nvp = nvlist_find(nvl, NV_TYPE_BINARY, name);
1417279435Srstone	if (nvp == NULL)
1418279435Srstone		nvlist_report_missing(NV_TYPE_BINARY, name);
1419279435Srstone
1420279435Srstone	value = (void *)(intptr_t)nvpair_get_binary(nvp, sizep);
1421279435Srstone	nvlist_remove_nvpair(nvl, nvp);
1422279435Srstone	nvpair_free_structure(nvp);
1423279435Srstone	return (value);
1424258065Spjd}
1425258065Spjd
1426258065Spjdvoid
1427258065Spjdnvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp)
1428258065Spjd{
1429258065Spjd
1430258065Spjd	NVLIST_ASSERT(nvl);
1431258065Spjd	NVPAIR_ASSERT(nvp);
1432258065Spjd	PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
1433258065Spjd
1434258065Spjd	nvpair_remove(&nvl->nvl_head, nvp, nvl);
1435258065Spjd}
1436258065Spjd
1437258065Spjdvoid
1438258065Spjdnvlist_free(nvlist_t *nvl, const char *name)
1439258065Spjd{
1440258065Spjd
1441279435Srstone	nvlist_free_type(nvl, name, NV_TYPE_NONE);
1442258065Spjd}
1443258065Spjd
1444279435Srstone#define	NVLIST_FREE(type, TYPE)						\
1445258065Spjdvoid									\
1446258065Spjdnvlist_free_##type(nvlist_t *nvl, const char *name)			\
1447258065Spjd{									\
1448258065Spjd									\
1449279435Srstone	nvlist_free_type(nvl, name, NV_TYPE_##TYPE);			\
1450258065Spjd}
1451258065Spjd
1452279435SrstoneNVLIST_FREE(null, NULL)
1453279435SrstoneNVLIST_FREE(bool, BOOL)
1454279435SrstoneNVLIST_FREE(number, NUMBER)
1455279435SrstoneNVLIST_FREE(string, STRING)
1456279435SrstoneNVLIST_FREE(nvlist, NVLIST)
1457279438Srstone#ifndef _KERNEL
1458279435SrstoneNVLIST_FREE(descriptor, DESCRIPTOR)
1459279438Srstone#endif
1460279435SrstoneNVLIST_FREE(binary, BINARY)
1461258065Spjd
1462258065Spjd#undef	NVLIST_FREE
1463258065Spjd
1464258065Spjdvoid
1465258065Spjdnvlist_free_nvpair(nvlist_t *nvl, nvpair_t *nvp)
1466258065Spjd{
1467258065Spjd
1468258065Spjd	NVLIST_ASSERT(nvl);
1469258065Spjd	NVPAIR_ASSERT(nvp);
1470258065Spjd	PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
1471258065Spjd
1472258065Spjd	nvlist_remove_nvpair(nvl, nvp);
1473258065Spjd	nvpair_free(nvp);
1474258065Spjd}
1475292637Sngie
1476