subr_nvlist.c revision 279438
1/*-
2 * Copyright (c) 2009-2013 The FreeBSD Foundation
3 * All rights reserved.
4 *
5 * This software was developed by Pawel Jakub Dawidek under sponsorship from
6 * the FreeBSD Foundation.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: head/lib/libnv/nvlist.c 279438 2015-03-01 00:22:53Z rstone $");
32
33#include <sys/param.h>
34#include <sys/endian.h>
35#include <sys/queue.h>
36
37#ifdef _KERNEL
38
39#include <sys/errno.h>
40#include <sys/kernel.h>
41#include <sys/lock.h>
42#include <sys/malloc.h>
43#include <sys/systm.h>
44
45#include <machine/stdarg.h>
46
47#else
48#include <sys/socket.h>
49
50#include <errno.h>
51#include <stdarg.h>
52#include <stdbool.h>
53#include <stdint.h>
54#define	_WITH_DPRINTF
55#include <stdio.h>
56#include <stdlib.h>
57#include <string.h>
58#include <unistd.h>
59#endif
60
61#ifdef HAVE_PJDLOG
62#include <pjdlog.h>
63#endif
64
65#include "msgio.h"
66#include "nv.h"
67#include "nv_impl.h"
68#include "nvlist_impl.h"
69#include "nvpair_impl.h"
70
71#ifndef	HAVE_PJDLOG
72#ifdef _KERNEL
73#define	PJDLOG_ASSERT(...)		MPASS(__VA_ARGS__)
74#define	PJDLOG_RASSERT(expr, ...)	KASSERT(expr, (__VA_ARGS__))
75#define	PJDLOG_ABORT(...)		panic(__VA_ARGS__)
76#else
77#include <assert.h>
78#define	PJDLOG_ASSERT(...)		assert(__VA_ARGS__)
79#define	PJDLOG_RASSERT(expr, ...)	assert(expr)
80#define	PJDLOG_ABORT(...)		do {				\
81	fprintf(stderr, "%s:%u: ", __FILE__, __LINE__);			\
82	fprintf(stderr, __VA_ARGS__);					\
83	fprintf(stderr, "\n");						\
84	abort();							\
85} while (0)
86#endif
87#endif
88
89#define	NV_FLAG_PRIVATE_MASK	(NV_FLAG_BIG_ENDIAN)
90#define	NV_FLAG_PUBLIC_MASK	(NV_FLAG_IGNORE_CASE)
91#define	NV_FLAG_ALL_MASK	(NV_FLAG_PRIVATE_MASK | NV_FLAG_PUBLIC_MASK)
92
93#define	NVLIST_MAGIC	0x6e766c	/* "nvl" */
94struct nvlist {
95	int		 nvl_magic;
96	int		 nvl_error;
97	int		 nvl_flags;
98	nvpair_t	*nvl_parent;
99	struct nvl_head	 nvl_head;
100};
101
102#define	NVLIST_ASSERT(nvl)	do {					\
103	PJDLOG_ASSERT((nvl) != NULL);					\
104	PJDLOG_ASSERT((nvl)->nvl_magic == NVLIST_MAGIC);		\
105} while (0)
106
107#ifdef _KERNEL
108MALLOC_DEFINE(M_NVLIST, "nvlist", "kernel nvlist");
109#endif
110
111#define	NVPAIR_ASSERT(nvp)	nvpair_assert(nvp)
112
113#define	NVLIST_HEADER_MAGIC	0x6c
114#define	NVLIST_HEADER_VERSION	0x00
115struct nvlist_header {
116	uint8_t		nvlh_magic;
117	uint8_t		nvlh_version;
118	uint8_t		nvlh_flags;
119	uint64_t	nvlh_descriptors;
120	uint64_t	nvlh_size;
121} __packed;
122
123nvlist_t *
124nvlist_create(int flags)
125{
126	nvlist_t *nvl;
127
128	PJDLOG_ASSERT((flags & ~(NV_FLAG_PUBLIC_MASK)) == 0);
129
130	nvl = nv_malloc(sizeof(*nvl));
131	nvl->nvl_error = 0;
132	nvl->nvl_flags = flags;
133	nvl->nvl_parent = NULL;
134	TAILQ_INIT(&nvl->nvl_head);
135	nvl->nvl_magic = NVLIST_MAGIC;
136
137	return (nvl);
138}
139
140void
141nvlist_destroy(nvlist_t *nvl)
142{
143	nvpair_t *nvp;
144	int serrno;
145
146	if (nvl == NULL)
147		return;
148
149	SAVE_ERRNO(serrno);
150
151	NVLIST_ASSERT(nvl);
152
153	while ((nvp = nvlist_first_nvpair(nvl)) != NULL) {
154		nvlist_remove_nvpair(nvl, nvp);
155		nvpair_free(nvp);
156	}
157	nvl->nvl_magic = 0;
158	nv_free(nvl);
159
160	RESTORE_ERRNO(serrno);
161}
162
163void
164nvlist_set_error(nvlist_t *nvl, int error)
165{
166
167	PJDLOG_ASSERT(error != 0);
168
169	/*
170	 * Check for error != 0 so that we don't do the wrong thing if somebody
171	 * tries to abuse this API when asserts are disabled.
172	 */
173	if (nvl != NULL && error != 0 && nvl->nvl_error == 0)
174		nvl->nvl_error = error;
175}
176
177int
178nvlist_error(const nvlist_t *nvl)
179{
180
181	if (nvl == NULL)
182		return (ENOMEM);
183
184	NVLIST_ASSERT(nvl);
185
186	return (nvl->nvl_error);
187}
188
189nvpair_t *
190nvlist_get_nvpair_parent(const nvlist_t *nvl)
191{
192
193	NVLIST_ASSERT(nvl);
194
195	return (nvl->nvl_parent);
196}
197
198const nvlist_t *
199nvlist_get_parent(const nvlist_t *nvl, void **cookiep)
200{
201	nvpair_t *nvp;
202
203	NVLIST_ASSERT(nvl);
204
205	nvp = nvl->nvl_parent;
206	if (cookiep != NULL)
207		*cookiep = nvp;
208	if (nvp == NULL)
209		return (NULL);
210
211	return (nvpair_nvlist(nvp));
212}
213
214void
215nvlist_set_parent(nvlist_t *nvl, nvpair_t *parent)
216{
217
218	NVLIST_ASSERT(nvl);
219
220	nvl->nvl_parent = parent;
221}
222
223bool
224nvlist_empty(const nvlist_t *nvl)
225{
226
227	NVLIST_ASSERT(nvl);
228	PJDLOG_ASSERT(nvl->nvl_error == 0);
229
230	return (nvlist_first_nvpair(nvl) == NULL);
231}
232
233static void
234nvlist_report_missing(int type, const char *name)
235{
236
237	PJDLOG_ABORT("Element '%s' of type %s doesn't exist.",
238	    name, nvpair_type_string(type));
239}
240
241static nvpair_t *
242nvlist_find(const nvlist_t *nvl, int type, const char *name)
243{
244	nvpair_t *nvp;
245
246	NVLIST_ASSERT(nvl);
247	PJDLOG_ASSERT(nvl->nvl_error == 0);
248	PJDLOG_ASSERT(type == NV_TYPE_NONE ||
249	    (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
250
251	for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
252	    nvp = nvlist_next_nvpair(nvl, nvp)) {
253		if (type != NV_TYPE_NONE && nvpair_type(nvp) != type)
254			continue;
255		if ((nvl->nvl_flags & NV_FLAG_IGNORE_CASE) != 0) {
256			if (strcasecmp(nvpair_name(nvp), name) != 0)
257				continue;
258		} else {
259			if (strcmp(nvpair_name(nvp), name) != 0)
260				continue;
261		}
262		break;
263	}
264
265	if (nvp == NULL)
266		RESTORE_ERRNO(ENOENT);
267
268	return (nvp);
269}
270
271bool
272nvlist_exists_type(const nvlist_t *nvl, const char *name, int type)
273{
274
275	NVLIST_ASSERT(nvl);
276	PJDLOG_ASSERT(nvl->nvl_error == 0);
277	PJDLOG_ASSERT(type == NV_TYPE_NONE ||
278	    (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
279
280	return (nvlist_find(nvl, type, name) != NULL);
281}
282
283#ifndef _KERNEL
284bool
285nvlist_existsf_type(const nvlist_t *nvl, int type, const char *namefmt, ...)
286{
287	va_list nameap;
288	bool ret;
289
290	va_start(nameap, namefmt);
291	ret = nvlist_existsv_type(nvl, type, namefmt, nameap);
292	va_end(nameap);
293
294	return (ret);
295}
296
297bool
298nvlist_existsv_type(const nvlist_t *nvl, int type, const char *namefmt,
299    va_list nameap)
300{
301	char *name;
302	bool exists;
303
304	nv_vasprintf(&name, namefmt, nameap);
305	if (name == NULL)
306		return (false);
307
308	exists = nvlist_exists_type(nvl, name, type);
309	nv_free(name);
310	return (exists);
311}
312#endif
313
314void
315nvlist_free_type(nvlist_t *nvl, const char *name, int type)
316{
317	nvpair_t *nvp;
318
319	NVLIST_ASSERT(nvl);
320	PJDLOG_ASSERT(nvl->nvl_error == 0);
321	PJDLOG_ASSERT(type == NV_TYPE_NONE ||
322	    (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
323
324	nvp = nvlist_find(nvl, type, name);
325	if (nvp != NULL)
326		nvlist_free_nvpair(nvl, nvp);
327	else
328		nvlist_report_missing(type, name);
329}
330
331#ifndef _KERNEL
332void
333nvlist_freef_type(nvlist_t *nvl, int type, const char *namefmt, ...)
334{
335	va_list nameap;
336
337	va_start(nameap, namefmt);
338	nvlist_freev_type(nvl, type, namefmt, nameap);
339	va_end(nameap);
340}
341
342void
343nvlist_freev_type(nvlist_t *nvl, int type, const char *namefmt, va_list nameap)
344{
345	char *name;
346
347	nv_vasprintf(&name, namefmt, nameap);
348	if (name == NULL)
349		nvlist_report_missing(type, "<unknown>");
350	nvlist_free_type(nvl, name, type);
351	nv_free(name);
352}
353#endif
354
355nvlist_t *
356nvlist_clone(const nvlist_t *nvl)
357{
358	nvlist_t *newnvl;
359	nvpair_t *nvp, *newnvp;
360
361	NVLIST_ASSERT(nvl);
362
363	if (nvl->nvl_error != 0) {
364		RESTORE_ERRNO(nvl->nvl_error);
365		return (NULL);
366	}
367
368	newnvl = nvlist_create(nvl->nvl_flags & NV_FLAG_PUBLIC_MASK);
369	for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
370	    nvp = nvlist_next_nvpair(nvl, nvp)) {
371		newnvp = nvpair_clone(nvp);
372		if (newnvp == NULL)
373			break;
374		nvlist_move_nvpair(newnvl, newnvp);
375	}
376	if (nvp != NULL) {
377		nvlist_destroy(newnvl);
378		return (NULL);
379	}
380	return (newnvl);
381}
382
383#ifndef _KERNEL
384static bool
385nvlist_dump_error_check(const nvlist_t *nvl, int fd, int level)
386{
387
388	if (nvlist_error(nvl) != 0) {
389		dprintf(fd, "%*serror: %d\n", level * 4, "",
390		    nvlist_error(nvl));
391		return (true);
392	}
393
394	return (false);
395}
396
397/*
398 * Dump content of nvlist.
399 */
400void
401nvlist_dump(const nvlist_t *nvl, int fd)
402{
403	const nvlist_t *tmpnvl;
404	nvpair_t *nvp, *tmpnvp;
405	void *cookie;
406	int level;
407
408	level = 0;
409	if (nvlist_dump_error_check(nvl, fd, level))
410		return;
411
412	nvp = nvlist_first_nvpair(nvl);
413	while (nvp != NULL) {
414		dprintf(fd, "%*s%s (%s):", level * 4, "", nvpair_name(nvp),
415		    nvpair_type_string(nvpair_type(nvp)));
416		switch (nvpair_type(nvp)) {
417		case NV_TYPE_NULL:
418			dprintf(fd, " null\n");
419			break;
420		case NV_TYPE_BOOL:
421			dprintf(fd, " %s\n", nvpair_get_bool(nvp) ?
422			    "TRUE" : "FALSE");
423			break;
424		case NV_TYPE_NUMBER:
425			dprintf(fd, " %ju (%jd) (0x%jx)\n",
426			    (uintmax_t)nvpair_get_number(nvp),
427			    (intmax_t)nvpair_get_number(nvp),
428			    (uintmax_t)nvpair_get_number(nvp));
429			break;
430		case NV_TYPE_STRING:
431			dprintf(fd, " [%s]\n", nvpair_get_string(nvp));
432			break;
433		case NV_TYPE_NVLIST:
434			dprintf(fd, "\n");
435			tmpnvl = nvpair_get_nvlist(nvp);
436			if (nvlist_dump_error_check(tmpnvl, fd, level + 1))
437				break;
438			tmpnvp = nvlist_first_nvpair(tmpnvl);
439			if (tmpnvp != NULL) {
440				nvl = tmpnvl;
441				nvp = tmpnvp;
442				level++;
443				continue;
444			}
445			break;
446		case NV_TYPE_DESCRIPTOR:
447			dprintf(fd, " %d\n", nvpair_get_descriptor(nvp));
448			break;
449		case NV_TYPE_BINARY:
450		    {
451			const unsigned char *binary;
452			unsigned int ii;
453			size_t size;
454
455			binary = nvpair_get_binary(nvp, &size);
456			dprintf(fd, " %zu ", size);
457			for (ii = 0; ii < size; ii++)
458				dprintf(fd, "%02hhx", binary[ii]);
459			dprintf(fd, "\n");
460			break;
461		    }
462		default:
463			PJDLOG_ABORT("Unknown type: %d.", nvpair_type(nvp));
464		}
465
466		while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
467			cookie = NULL;
468			nvl = nvlist_get_parent(nvl, &cookie);
469			if (nvl == NULL)
470				return;
471			nvp = cookie;
472			level--;
473		}
474	}
475}
476
477void
478nvlist_fdump(const nvlist_t *nvl, FILE *fp)
479{
480
481	fflush(fp);
482	nvlist_dump(nvl, fileno(fp));
483}
484#endif
485
486/*
487 * The function obtains size of the nvlist after nvlist_pack().
488 */
489size_t
490nvlist_size(const nvlist_t *nvl)
491{
492	const nvlist_t *tmpnvl;
493	const nvpair_t *nvp, *tmpnvp;
494	void *cookie;
495	size_t size;
496
497	NVLIST_ASSERT(nvl);
498	PJDLOG_ASSERT(nvl->nvl_error == 0);
499
500	size = sizeof(struct nvlist_header);
501	nvp = nvlist_first_nvpair(nvl);
502	while (nvp != NULL) {
503		size += nvpair_header_size();
504		size += strlen(nvpair_name(nvp)) + 1;
505		if (nvpair_type(nvp) == NV_TYPE_NVLIST) {
506			size += sizeof(struct nvlist_header);
507			size += nvpair_header_size() + 1;
508			tmpnvl = nvpair_get_nvlist(nvp);
509			PJDLOG_ASSERT(tmpnvl->nvl_error == 0);
510			tmpnvp = nvlist_first_nvpair(tmpnvl);
511			if (tmpnvp != NULL) {
512				nvl = tmpnvl;
513				nvp = tmpnvp;
514				continue;
515			}
516		} else {
517			size += nvpair_size(nvp);
518		}
519
520		while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
521			cookie = NULL;
522			nvl = nvlist_get_parent(nvl, &cookie);
523			if (nvl == NULL)
524				goto out;
525			nvp = cookie;
526		}
527	}
528
529out:
530	return (size);
531}
532
533#ifndef _KERNEL
534static int *
535nvlist_xdescriptors(const nvlist_t *nvl, int *descs, int level)
536{
537	const nvpair_t *nvp;
538
539	NVLIST_ASSERT(nvl);
540	PJDLOG_ASSERT(nvl->nvl_error == 0);
541	PJDLOG_ASSERT(level < 3);
542
543	for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
544	    nvp = nvlist_next_nvpair(nvl, nvp)) {
545		switch (nvpair_type(nvp)) {
546		case NV_TYPE_DESCRIPTOR:
547			*descs = nvpair_get_descriptor(nvp);
548			descs++;
549			break;
550		case NV_TYPE_NVLIST:
551			descs = nvlist_xdescriptors(nvpair_get_nvlist(nvp),
552			    descs, level + 1);
553			break;
554		}
555	}
556
557	return (descs);
558}
559#endif
560
561#ifndef _KERNEL
562int *
563nvlist_descriptors(const nvlist_t *nvl, size_t *nitemsp)
564{
565	size_t nitems;
566	int *fds;
567
568	nitems = nvlist_ndescriptors(nvl);
569	fds = nv_malloc(sizeof(fds[0]) * (nitems + 1));
570	if (fds == NULL)
571		return (NULL);
572	if (nitems > 0)
573		nvlist_xdescriptors(nvl, fds, 0);
574	fds[nitems] = -1;
575	if (nitemsp != NULL)
576		*nitemsp = nitems;
577	return (fds);
578}
579#endif
580
581static size_t
582nvlist_xndescriptors(const nvlist_t *nvl, int level)
583{
584#ifndef _KERNEL
585	const nvpair_t *nvp;
586	size_t ndescs;
587
588	NVLIST_ASSERT(nvl);
589	PJDLOG_ASSERT(nvl->nvl_error == 0);
590	PJDLOG_ASSERT(level < 3);
591
592	ndescs = 0;
593	for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
594	    nvp = nvlist_next_nvpair(nvl, nvp)) {
595		switch (nvpair_type(nvp)) {
596		case NV_TYPE_DESCRIPTOR:
597			ndescs++;
598			break;
599		case NV_TYPE_NVLIST:
600			ndescs += nvlist_xndescriptors(nvpair_get_nvlist(nvp),
601			    level + 1);
602			break;
603		}
604	}
605
606	return (ndescs);
607#else
608	return (0);
609#endif
610}
611
612size_t
613nvlist_ndescriptors(const nvlist_t *nvl)
614{
615
616	return (nvlist_xndescriptors(nvl, 0));
617}
618
619static unsigned char *
620nvlist_pack_header(const nvlist_t *nvl, unsigned char *ptr, size_t *leftp)
621{
622	struct nvlist_header nvlhdr;
623
624	NVLIST_ASSERT(nvl);
625
626	nvlhdr.nvlh_magic = NVLIST_HEADER_MAGIC;
627	nvlhdr.nvlh_version = NVLIST_HEADER_VERSION;
628	nvlhdr.nvlh_flags = nvl->nvl_flags;
629#if BYTE_ORDER == BIG_ENDIAN
630	nvlhdr.nvlh_flags |= NV_FLAG_BIG_ENDIAN;
631#endif
632	nvlhdr.nvlh_descriptors = nvlist_ndescriptors(nvl);
633	nvlhdr.nvlh_size = *leftp - sizeof(nvlhdr);
634	PJDLOG_ASSERT(*leftp >= sizeof(nvlhdr));
635	memcpy(ptr, &nvlhdr, sizeof(nvlhdr));
636	ptr += sizeof(nvlhdr);
637	*leftp -= sizeof(nvlhdr);
638
639	return (ptr);
640}
641
642void *
643nvlist_xpack(const nvlist_t *nvl, int64_t *fdidxp, size_t *sizep)
644{
645	unsigned char *buf, *ptr;
646	size_t left, size;
647	const nvlist_t *tmpnvl;
648	nvpair_t *nvp, *tmpnvp;
649	void *cookie;
650
651	NVLIST_ASSERT(nvl);
652
653	if (nvl->nvl_error != 0) {
654		RESTORE_ERRNO(nvl->nvl_error);
655		return (NULL);
656	}
657
658	size = nvlist_size(nvl);
659	buf = nv_malloc(size);
660	if (buf == NULL)
661		return (NULL);
662
663	ptr = buf;
664	left = size;
665
666	ptr = nvlist_pack_header(nvl, ptr, &left);
667
668	nvp = nvlist_first_nvpair(nvl);
669	while (nvp != NULL) {
670		NVPAIR_ASSERT(nvp);
671
672		nvpair_init_datasize(nvp);
673		ptr = nvpair_pack_header(nvp, ptr, &left);
674		if (ptr == NULL) {
675			nv_free(buf);
676			return (NULL);
677		}
678		switch (nvpair_type(nvp)) {
679		case NV_TYPE_NULL:
680			ptr = nvpair_pack_null(nvp, ptr, &left);
681			break;
682		case NV_TYPE_BOOL:
683			ptr = nvpair_pack_bool(nvp, ptr, &left);
684			break;
685		case NV_TYPE_NUMBER:
686			ptr = nvpair_pack_number(nvp, ptr, &left);
687			break;
688		case NV_TYPE_STRING:
689			ptr = nvpair_pack_string(nvp, ptr, &left);
690			break;
691		case NV_TYPE_NVLIST:
692			tmpnvl = nvpair_get_nvlist(nvp);
693			ptr = nvlist_pack_header(tmpnvl, ptr, &left);
694			if (ptr == NULL)
695				goto out;
696			tmpnvp = nvlist_first_nvpair(tmpnvl);
697			if (tmpnvp != NULL) {
698				nvl = tmpnvl;
699				nvp = tmpnvp;
700				continue;
701			}
702			ptr = nvpair_pack_nvlist_up(ptr, &left);
703			break;
704#ifndef _KERNEL
705		case NV_TYPE_DESCRIPTOR:
706			ptr = nvpair_pack_descriptor(nvp, ptr, fdidxp, &left);
707			break;
708#endif
709		case NV_TYPE_BINARY:
710			ptr = nvpair_pack_binary(nvp, ptr, &left);
711			break;
712		default:
713			PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp));
714		}
715		if (ptr == NULL) {
716			nv_free(buf);
717			return (NULL);
718		}
719		while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
720			cookie = NULL;
721			nvl = nvlist_get_parent(nvl, &cookie);
722			if (nvl == NULL)
723				goto out;
724			nvp = cookie;
725			ptr = nvpair_pack_nvlist_up(ptr, &left);
726			if (ptr == NULL)
727				goto out;
728		}
729	}
730
731out:
732	if (sizep != NULL)
733		*sizep = size;
734	return (buf);
735}
736
737void *
738nvlist_pack(const nvlist_t *nvl, size_t *sizep)
739{
740
741	NVLIST_ASSERT(nvl);
742
743	if (nvl->nvl_error != 0) {
744		RESTORE_ERRNO(nvl->nvl_error);
745		return (NULL);
746	}
747
748	if (nvlist_ndescriptors(nvl) > 0) {
749		RESTORE_ERRNO(EOPNOTSUPP);
750		return (NULL);
751	}
752
753	return (nvlist_xpack(nvl, NULL, sizep));
754}
755
756static bool
757nvlist_check_header(struct nvlist_header *nvlhdrp)
758{
759
760	if (nvlhdrp->nvlh_magic != NVLIST_HEADER_MAGIC) {
761		RESTORE_ERRNO(EINVAL);
762		return (false);
763	}
764	if ((nvlhdrp->nvlh_flags & ~NV_FLAG_ALL_MASK) != 0) {
765		RESTORE_ERRNO(EINVAL);
766		return (false);
767	}
768#if BYTE_ORDER == BIG_ENDIAN
769	if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) == 0) {
770		nvlhdrp->nvlh_size = le64toh(nvlhdrp->nvlh_size);
771		nvlhdrp->nvlh_descriptors = le64toh(nvlhdrp->nvlh_descriptors);
772	}
773#else
774	if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0) {
775		nvlhdrp->nvlh_size = be64toh(nvlhdrp->nvlh_size);
776		nvlhdrp->nvlh_descriptors = be64toh(nvlhdrp->nvlh_descriptors);
777	}
778#endif
779	return (true);
780}
781
782const unsigned char *
783nvlist_unpack_header(nvlist_t *nvl, const unsigned char *ptr, size_t nfds,
784    bool *isbep, size_t *leftp)
785{
786	struct nvlist_header nvlhdr;
787
788	if (*leftp < sizeof(nvlhdr))
789		goto failed;
790
791	memcpy(&nvlhdr, ptr, sizeof(nvlhdr));
792
793	if (!nvlist_check_header(&nvlhdr))
794		goto failed;
795
796	if (nvlhdr.nvlh_size != *leftp - sizeof(nvlhdr))
797		goto failed;
798
799	/*
800	 * nvlh_descriptors might be smaller than nfds in embedded nvlists.
801	 */
802	if (nvlhdr.nvlh_descriptors > nfds)
803		goto failed;
804
805	if ((nvlhdr.nvlh_flags & ~NV_FLAG_ALL_MASK) != 0)
806		goto failed;
807
808	nvl->nvl_flags = (nvlhdr.nvlh_flags & NV_FLAG_PUBLIC_MASK);
809
810	ptr += sizeof(nvlhdr);
811	if (isbep != NULL)
812		*isbep = (((int)nvlhdr.nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0);
813	*leftp -= sizeof(nvlhdr);
814
815	return (ptr);
816failed:
817	RESTORE_ERRNO(EINVAL);
818	return (NULL);
819}
820
821nvlist_t *
822nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds)
823{
824	const unsigned char *ptr;
825	nvlist_t *nvl, *retnvl, *tmpnvl;
826	nvpair_t *nvp;
827	size_t left;
828	bool isbe;
829
830	left = size;
831	ptr = buf;
832
833	tmpnvl = NULL;
834	nvl = retnvl = nvlist_create(0);
835	if (nvl == NULL)
836		goto failed;
837
838	ptr = nvlist_unpack_header(nvl, ptr, nfds, &isbe, &left);
839	if (ptr == NULL)
840		goto failed;
841
842	while (left > 0) {
843		ptr = nvpair_unpack(isbe, ptr, &left, &nvp);
844		if (ptr == NULL)
845			goto failed;
846		switch (nvpair_type(nvp)) {
847		case NV_TYPE_NULL:
848			ptr = nvpair_unpack_null(isbe, nvp, ptr, &left);
849			break;
850		case NV_TYPE_BOOL:
851			ptr = nvpair_unpack_bool(isbe, nvp, ptr, &left);
852			break;
853		case NV_TYPE_NUMBER:
854			ptr = nvpair_unpack_number(isbe, nvp, ptr, &left);
855			break;
856		case NV_TYPE_STRING:
857			ptr = nvpair_unpack_string(isbe, nvp, ptr, &left);
858			break;
859		case NV_TYPE_NVLIST:
860			ptr = nvpair_unpack_nvlist(isbe, nvp, ptr, &left, nfds,
861			    &tmpnvl);
862			nvlist_set_parent(tmpnvl, nvp);
863			break;
864#ifndef _KERNEL
865		case NV_TYPE_DESCRIPTOR:
866			ptr = nvpair_unpack_descriptor(isbe, nvp, ptr, &left,
867			    fds, nfds);
868			break;
869#endif
870		case NV_TYPE_BINARY:
871			ptr = nvpair_unpack_binary(isbe, nvp, ptr, &left);
872			break;
873		case NV_TYPE_NVLIST_UP:
874			if (nvl->nvl_parent == NULL)
875				goto failed;
876			nvl = nvpair_nvlist(nvl->nvl_parent);
877			continue;
878		default:
879			PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp));
880		}
881		if (ptr == NULL)
882			goto failed;
883		nvlist_move_nvpair(nvl, nvp);
884		if (tmpnvl != NULL) {
885			nvl = tmpnvl;
886			tmpnvl = NULL;
887		}
888	}
889
890	return (retnvl);
891failed:
892	nvlist_destroy(retnvl);
893	return (NULL);
894}
895
896nvlist_t *
897nvlist_unpack(const void *buf, size_t size)
898{
899
900	return (nvlist_xunpack(buf, size, NULL, 0));
901}
902
903#ifndef _KERNEL
904int
905nvlist_send(int sock, const nvlist_t *nvl)
906{
907	size_t datasize, nfds;
908	int *fds;
909	void *data;
910	int64_t fdidx;
911	int serrno, ret;
912
913	if (nvlist_error(nvl) != 0) {
914		errno = nvlist_error(nvl);
915		return (-1);
916	}
917
918	fds = nvlist_descriptors(nvl, &nfds);
919	if (fds == NULL)
920		return (-1);
921
922	ret = -1;
923	data = NULL;
924	fdidx = 0;
925
926	data = nvlist_xpack(nvl, &fdidx, &datasize);
927	if (data == NULL)
928		goto out;
929
930	if (buf_send(sock, data, datasize) == -1)
931		goto out;
932
933	if (nfds > 0) {
934		if (fd_send(sock, fds, nfds) == -1)
935			goto out;
936	}
937
938	ret = 0;
939out:
940	serrno = errno;
941	free(fds);
942	free(data);
943	errno = serrno;
944	return (ret);
945}
946
947nvlist_t *
948nvlist_recv(int sock)
949{
950	struct nvlist_header nvlhdr;
951	nvlist_t *nvl, *ret;
952	unsigned char *buf;
953	size_t nfds, size, i;
954	int serrno, *fds;
955
956	if (buf_recv(sock, &nvlhdr, sizeof(nvlhdr)) == -1)
957		return (NULL);
958
959	if (!nvlist_check_header(&nvlhdr))
960		return (NULL);
961
962	nfds = (size_t)nvlhdr.nvlh_descriptors;
963	size = sizeof(nvlhdr) + (size_t)nvlhdr.nvlh_size;
964
965	buf = malloc(size);
966	if (buf == NULL)
967		return (NULL);
968
969	memcpy(buf, &nvlhdr, sizeof(nvlhdr));
970
971	ret = NULL;
972	fds = NULL;
973
974	if (buf_recv(sock, buf + sizeof(nvlhdr), size - sizeof(nvlhdr)) == -1)
975		goto out;
976
977	if (nfds > 0) {
978		fds = malloc(nfds * sizeof(fds[0]));
979		if (fds == NULL)
980			goto out;
981		if (fd_recv(sock, fds, nfds) == -1)
982			goto out;
983	}
984
985	nvl = nvlist_xunpack(buf, size, fds, nfds);
986	if (nvl == NULL) {
987		for (i = 0; i < nfds; i++)
988			close(fds[i]);
989		goto out;
990	}
991
992	ret = nvl;
993out:
994	serrno = errno;
995	free(buf);
996	free(fds);
997	errno = serrno;
998
999	return (ret);
1000}
1001
1002nvlist_t *
1003nvlist_xfer(int sock, nvlist_t *nvl)
1004{
1005
1006	if (nvlist_send(sock, nvl) < 0) {
1007		nvlist_destroy(nvl);
1008		return (NULL);
1009	}
1010	nvlist_destroy(nvl);
1011	return (nvlist_recv(sock));
1012}
1013#endif
1014
1015nvpair_t *
1016nvlist_first_nvpair(const nvlist_t *nvl)
1017{
1018
1019	NVLIST_ASSERT(nvl);
1020
1021	return (TAILQ_FIRST(&nvl->nvl_head));
1022}
1023
1024nvpair_t *
1025nvlist_next_nvpair(const nvlist_t *nvl, const nvpair_t *nvp)
1026{
1027	nvpair_t *retnvp;
1028
1029	NVLIST_ASSERT(nvl);
1030	NVPAIR_ASSERT(nvp);
1031	PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
1032
1033	retnvp = nvpair_next(nvp);
1034	PJDLOG_ASSERT(retnvp == NULL || nvpair_nvlist(retnvp) == nvl);
1035
1036	return (retnvp);
1037
1038}
1039
1040nvpair_t *
1041nvlist_prev_nvpair(const nvlist_t *nvl, const nvpair_t *nvp)
1042{
1043	nvpair_t *retnvp;
1044
1045	NVLIST_ASSERT(nvl);
1046	NVPAIR_ASSERT(nvp);
1047	PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
1048
1049	retnvp = nvpair_prev(nvp);
1050	PJDLOG_ASSERT(nvpair_nvlist(retnvp) == nvl);
1051
1052	return (retnvp);
1053}
1054
1055const char *
1056nvlist_next(const nvlist_t *nvl, int *typep, void **cookiep)
1057{
1058	nvpair_t *nvp;
1059
1060	NVLIST_ASSERT(nvl);
1061	PJDLOG_ASSERT(cookiep != NULL);
1062
1063	if (*cookiep == NULL)
1064		nvp = nvlist_first_nvpair(nvl);
1065	else
1066		nvp = nvlist_next_nvpair(nvl, *cookiep);
1067	if (nvp == NULL)
1068		return (NULL);
1069	if (typep != NULL)
1070		*typep = nvpair_type(nvp);
1071	*cookiep = nvp;
1072	return (nvpair_name(nvp));
1073}
1074
1075bool
1076nvlist_exists(const nvlist_t *nvl, const char *name)
1077{
1078
1079	return (nvlist_find(nvl, NV_TYPE_NONE, name) != NULL);
1080}
1081
1082#define	NVLIST_EXISTS(type, TYPE)					\
1083bool									\
1084nvlist_exists_##type(const nvlist_t *nvl, const char *name)		\
1085{									\
1086									\
1087	return (nvlist_find(nvl, NV_TYPE_##TYPE, name) != NULL);	\
1088}
1089
1090NVLIST_EXISTS(null, NULL)
1091NVLIST_EXISTS(bool, BOOL)
1092NVLIST_EXISTS(number, NUMBER)
1093NVLIST_EXISTS(string, STRING)
1094NVLIST_EXISTS(nvlist, NVLIST)
1095#ifndef _KERNEL
1096NVLIST_EXISTS(descriptor, DESCRIPTOR)
1097#endif
1098NVLIST_EXISTS(binary, BINARY)
1099
1100#undef	NVLIST_EXISTS
1101
1102#ifndef _KERNEL
1103bool
1104nvlist_existsf(const nvlist_t *nvl, const char *namefmt, ...)
1105{
1106	va_list nameap;
1107	bool ret;
1108
1109	va_start(nameap, namefmt);
1110	ret = nvlist_existsv(nvl, namefmt, nameap);
1111	va_end(nameap);
1112	return (ret);
1113}
1114
1115#define	NVLIST_EXISTSF(type)						\
1116bool									\
1117nvlist_existsf_##type(const nvlist_t *nvl, const char *namefmt, ...)	\
1118{									\
1119	va_list nameap;							\
1120	bool ret;							\
1121									\
1122	va_start(nameap, namefmt);					\
1123	ret = nvlist_existsv_##type(nvl, namefmt, nameap);		\
1124	va_end(nameap);							\
1125	return (ret);							\
1126}
1127
1128NVLIST_EXISTSF(null)
1129NVLIST_EXISTSF(bool)
1130NVLIST_EXISTSF(number)
1131NVLIST_EXISTSF(string)
1132NVLIST_EXISTSF(nvlist)
1133#ifndef _KERNEL
1134NVLIST_EXISTSF(descriptor)
1135#endif
1136NVLIST_EXISTSF(binary)
1137
1138#undef	NVLIST_EXISTSF
1139
1140bool
1141nvlist_existsv(const nvlist_t *nvl, const char *namefmt, va_list nameap)
1142{
1143	char *name;
1144	bool exists;
1145
1146	nv_vasprintf(&name, namefmt, nameap);
1147	if (name == NULL)
1148		return (false);
1149
1150	exists = nvlist_exists(nvl, name);
1151	nv_free(name);
1152	return (exists);
1153}
1154
1155#define	NVLIST_EXISTSV(type)						\
1156bool									\
1157nvlist_existsv_##type(const nvlist_t *nvl, const char *namefmt,		\
1158    va_list nameap)							\
1159{									\
1160	char *name;							\
1161	bool exists;							\
1162									\
1163	vasprintf(&name, namefmt, nameap);				\
1164	if (name == NULL)						\
1165		return (false);						\
1166	exists = nvlist_exists_##type(nvl, name);			\
1167	free(name);							\
1168	return (exists);						\
1169}
1170
1171NVLIST_EXISTSV(null)
1172NVLIST_EXISTSV(bool)
1173NVLIST_EXISTSV(number)
1174NVLIST_EXISTSV(string)
1175NVLIST_EXISTSV(nvlist)
1176NVLIST_EXISTSV(descriptor)
1177NVLIST_EXISTSV(binary)
1178
1179#undef	NVLIST_EXISTSV
1180#endif
1181
1182void
1183nvlist_add_nvpair(nvlist_t *nvl, const nvpair_t *nvp)
1184{
1185	nvpair_t *newnvp;
1186
1187	NVPAIR_ASSERT(nvp);
1188
1189	if (nvlist_error(nvl) != 0) {
1190		RESTORE_ERRNO(nvlist_error(nvl));
1191		return;
1192	}
1193	if (nvlist_exists(nvl, nvpair_name(nvp))) {
1194		nvl->nvl_error = EEXIST;
1195		RESTORE_ERRNO(nvlist_error(nvl));
1196		return;
1197	}
1198
1199	newnvp = nvpair_clone(nvp);
1200	if (newnvp == NULL) {
1201		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1202		RESTORE_ERRNO(nvlist_error(nvl));
1203		return;
1204	}
1205
1206	nvpair_insert(&nvl->nvl_head, newnvp, nvl);
1207}
1208
1209void
1210nvlist_add_null(nvlist_t *nvl, const char *name)
1211{
1212
1213	nvlist_addf_null(nvl, "%s", name);
1214}
1215
1216void
1217nvlist_add_bool(nvlist_t *nvl, const char *name, bool value)
1218{
1219
1220	nvlist_addf_bool(nvl, value, "%s", name);
1221}
1222
1223void
1224nvlist_add_number(nvlist_t *nvl, const char *name, uint64_t value)
1225{
1226
1227	nvlist_addf_number(nvl, value, "%s", name);
1228}
1229
1230void
1231nvlist_add_string(nvlist_t *nvl, const char *name, const char *value)
1232{
1233
1234	nvlist_addf_string(nvl, value, "%s", name);
1235}
1236
1237void
1238nvlist_add_stringf(nvlist_t *nvl, const char *name, const char *valuefmt, ...)
1239{
1240	va_list valueap;
1241
1242	va_start(valueap, valuefmt);
1243	nvlist_add_stringv(nvl, name, valuefmt, valueap);
1244	va_end(valueap);
1245}
1246
1247void
1248nvlist_add_stringv(nvlist_t *nvl, const char *name, const char *valuefmt,
1249    va_list valueap)
1250{
1251	nvpair_t *nvp;
1252
1253	if (nvlist_error(nvl) != 0) {
1254		RESTORE_ERRNO(nvlist_error(nvl));
1255		return;
1256	}
1257
1258	nvp = nvpair_create_stringv(name, valuefmt, valueap);
1259	if (nvp == NULL) {
1260		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1261		RESTORE_ERRNO(nvl->nvl_error);
1262	} else
1263		nvlist_move_nvpair(nvl, nvp);
1264}
1265
1266void
1267nvlist_add_nvlist(nvlist_t *nvl, const char *name, const nvlist_t *value)
1268{
1269
1270	nvlist_addf_nvlist(nvl, value, "%s", name);
1271}
1272
1273#ifndef _KERNEL
1274void
1275nvlist_add_descriptor(nvlist_t *nvl, const char *name, int value)
1276{
1277
1278	nvlist_addf_descriptor(nvl, value, "%s", name);
1279}
1280#endif
1281
1282void
1283nvlist_add_binary(nvlist_t *nvl, const char *name, const void *value,
1284    size_t size)
1285{
1286
1287	nvlist_addf_binary(nvl, value, size, "%s", name);
1288}
1289
1290void
1291nvlist_addf_null(nvlist_t *nvl, const char *namefmt, ...)
1292{
1293	va_list nameap;
1294
1295	va_start(nameap, namefmt);
1296	nvlist_addv_null(nvl, namefmt, nameap);
1297	va_end(nameap);
1298}
1299
1300void
1301nvlist_addf_bool(nvlist_t *nvl, bool value, const char *namefmt, ...)
1302{
1303	va_list nameap;
1304
1305	va_start(nameap, namefmt);
1306	nvlist_addv_bool(nvl, value, namefmt, nameap);
1307	va_end(nameap);
1308}
1309
1310void
1311nvlist_addf_number(nvlist_t *nvl, uint64_t value, const char *namefmt, ...)
1312{
1313	va_list nameap;
1314
1315	va_start(nameap, namefmt);
1316	nvlist_addv_number(nvl, value, namefmt, nameap);
1317	va_end(nameap);
1318}
1319
1320void
1321nvlist_addf_string(nvlist_t *nvl, const char *value, const char *namefmt, ...)
1322{
1323	va_list nameap;
1324
1325	va_start(nameap, namefmt);
1326	nvlist_addv_string(nvl, value, namefmt, nameap);
1327	va_end(nameap);
1328}
1329
1330void
1331nvlist_addf_nvlist(nvlist_t *nvl, const nvlist_t *value, const char *namefmt,
1332    ...)
1333{
1334	va_list nameap;
1335
1336	va_start(nameap, namefmt);
1337	nvlist_addv_nvlist(nvl, value, namefmt, nameap);
1338	va_end(nameap);
1339}
1340
1341#ifndef _KERNEL
1342void
1343nvlist_addf_descriptor(nvlist_t *nvl, int value, const char *namefmt, ...)
1344{
1345	va_list nameap;
1346
1347	va_start(nameap, namefmt);
1348	nvlist_addv_descriptor(nvl, value, namefmt, nameap);
1349	va_end(nameap);
1350}
1351#endif
1352
1353void
1354nvlist_addf_binary(nvlist_t *nvl, const void *value, size_t size,
1355    const char *namefmt, ...)
1356{
1357	va_list nameap;
1358
1359	va_start(nameap, namefmt);
1360	nvlist_addv_binary(nvl, value, size, namefmt, nameap);
1361	va_end(nameap);
1362}
1363
1364void
1365nvlist_addv_null(nvlist_t *nvl, const char *namefmt, va_list nameap)
1366{
1367	nvpair_t *nvp;
1368
1369	if (nvlist_error(nvl) != 0) {
1370		RESTORE_ERRNO(nvlist_error(nvl));
1371		return;
1372	}
1373
1374	nvp = nvpair_createv_null(namefmt, nameap);
1375	if (nvp == NULL) {
1376		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1377		RESTORE_ERRNO(nvl->nvl_error);
1378	} else
1379		nvlist_move_nvpair(nvl, nvp);
1380}
1381
1382void
1383nvlist_addv_bool(nvlist_t *nvl, bool value, const char *namefmt, va_list nameap)
1384{
1385	nvpair_t *nvp;
1386
1387	if (nvlist_error(nvl) != 0) {
1388		RESTORE_ERRNO(nvlist_error(nvl));
1389		return;
1390	}
1391
1392	nvp = nvpair_createv_bool(value, namefmt, nameap);
1393	if (nvp == NULL) {
1394		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1395		RESTORE_ERRNO(nvl->nvl_error);
1396	} else
1397		nvlist_move_nvpair(nvl, nvp);
1398}
1399
1400void
1401nvlist_addv_number(nvlist_t *nvl, uint64_t value, const char *namefmt,
1402    va_list nameap)
1403{
1404	nvpair_t *nvp;
1405
1406	if (nvlist_error(nvl) != 0) {
1407		RESTORE_ERRNO(nvlist_error(nvl));
1408		return;
1409	}
1410
1411	nvp = nvpair_createv_number(value, namefmt, nameap);
1412	if (nvp == NULL) {
1413		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1414		RESTORE_ERRNO(nvl->nvl_error);
1415	} else
1416		nvlist_move_nvpair(nvl, nvp);
1417}
1418
1419void
1420nvlist_addv_string(nvlist_t *nvl, const char *value, const char *namefmt,
1421    va_list nameap)
1422{
1423	nvpair_t *nvp;
1424
1425	if (nvlist_error(nvl) != 0) {
1426		RESTORE_ERRNO(nvlist_error(nvl));
1427		return;
1428	}
1429
1430	nvp = nvpair_createv_string(value, namefmt, nameap);
1431	if (nvp == NULL) {
1432		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1433		RESTORE_ERRNO(nvl->nvl_error);
1434	} else
1435		nvlist_move_nvpair(nvl, nvp);
1436}
1437
1438void
1439nvlist_addv_nvlist(nvlist_t *nvl, const nvlist_t *value, const char *namefmt,
1440    va_list nameap)
1441{
1442	nvpair_t *nvp;
1443
1444	if (nvlist_error(nvl) != 0) {
1445		RESTORE_ERRNO(nvlist_error(nvl));
1446		return;
1447	}
1448
1449	nvp = nvpair_createv_nvlist(value, namefmt, nameap);
1450	if (nvp == NULL) {
1451		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1452		RESTORE_ERRNO(nvl->nvl_error);
1453	} else
1454		nvlist_move_nvpair(nvl, nvp);
1455}
1456
1457#ifndef _KERNEL
1458void
1459nvlist_addv_descriptor(nvlist_t *nvl, int value, const char *namefmt,
1460    va_list nameap)
1461{
1462	nvpair_t *nvp;
1463
1464	if (nvlist_error(nvl) != 0) {
1465		errno = nvlist_error(nvl);
1466		return;
1467	}
1468
1469	nvp = nvpair_createv_descriptor(value, namefmt, nameap);
1470	if (nvp == NULL)
1471		nvl->nvl_error = errno = (errno != 0 ? errno : ENOMEM);
1472	else
1473		nvlist_move_nvpair(nvl, nvp);
1474}
1475#endif
1476
1477void
1478nvlist_addv_binary(nvlist_t *nvl, const void *value, size_t size,
1479    const char *namefmt, va_list nameap)
1480{
1481	nvpair_t *nvp;
1482
1483	if (nvlist_error(nvl) != 0) {
1484		RESTORE_ERRNO(nvlist_error(nvl));
1485		return;
1486	}
1487
1488	nvp = nvpair_createv_binary(value, size, namefmt, nameap);
1489	if (nvp == NULL) {
1490		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1491		RESTORE_ERRNO(nvl->nvl_error);
1492	} else
1493		nvlist_move_nvpair(nvl, nvp);
1494}
1495
1496void
1497nvlist_move_nvpair(nvlist_t *nvl, nvpair_t *nvp)
1498{
1499
1500	NVPAIR_ASSERT(nvp);
1501	PJDLOG_ASSERT(nvpair_nvlist(nvp) == NULL);
1502
1503	if (nvlist_error(nvl) != 0) {
1504		nvpair_free(nvp);
1505		RESTORE_ERRNO(nvlist_error(nvl));
1506		return;
1507	}
1508	if (nvlist_exists(nvl, nvpair_name(nvp))) {
1509		nvpair_free(nvp);
1510		nvl->nvl_error = EEXIST;
1511		RESTORE_ERRNO(nvl->nvl_error);
1512		return;
1513	}
1514
1515	nvpair_insert(&nvl->nvl_head, nvp, nvl);
1516}
1517
1518#define	NVLIST_MOVE(vtype, type)					\
1519void									\
1520nvlist_move_##type(nvlist_t *nvl, const char *name, vtype value)	\
1521{									\
1522									\
1523	nvlist_movef_##type(nvl, value, "%s", name);			\
1524}
1525
1526NVLIST_MOVE(char *, string)
1527NVLIST_MOVE(nvlist_t *, nvlist)
1528#ifndef _KERNEL
1529NVLIST_MOVE(int, descriptor)
1530#endif
1531
1532#undef	NVLIST_MOVE
1533
1534void
1535nvlist_move_binary(nvlist_t *nvl, const char *name, void *value, size_t size)
1536{
1537
1538	nvlist_movef_binary(nvl, value, size, "%s", name);
1539}
1540
1541#define	NVLIST_MOVEF(vtype, type)					\
1542void									\
1543nvlist_movef_##type(nvlist_t *nvl, vtype value, const char *namefmt,	\
1544    ...)								\
1545{									\
1546	va_list nameap;							\
1547									\
1548	va_start(nameap, namefmt);					\
1549	nvlist_movev_##type(nvl, value, namefmt, nameap);		\
1550	va_end(nameap);							\
1551}
1552
1553NVLIST_MOVEF(char *, string)
1554NVLIST_MOVEF(nvlist_t *, nvlist)
1555#ifndef _KERNEL
1556NVLIST_MOVEF(int, descriptor)
1557#endif
1558
1559#undef	NVLIST_MOVEF
1560
1561void
1562nvlist_movef_binary(nvlist_t *nvl, void *value, size_t size,
1563    const char *namefmt, ...)
1564{
1565	va_list nameap;
1566
1567	va_start(nameap, namefmt);
1568	nvlist_movev_binary(nvl, value, size, namefmt, nameap);
1569	va_end(nameap);
1570}
1571
1572void
1573nvlist_movev_string(nvlist_t *nvl, char *value, const char *namefmt,
1574    va_list nameap)
1575{
1576	nvpair_t *nvp;
1577
1578	if (nvlist_error(nvl) != 0) {
1579		nv_free(value);
1580		RESTORE_ERRNO(nvlist_error(nvl));
1581		return;
1582	}
1583
1584	nvp = nvpair_movev_string(value, namefmt, nameap);
1585	if (nvp == NULL) {
1586		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1587		RESTORE_ERRNO(nvl->nvl_error);
1588	} else
1589		nvlist_move_nvpair(nvl, nvp);
1590}
1591
1592void
1593nvlist_movev_nvlist(nvlist_t *nvl, nvlist_t *value, const char *namefmt,
1594    va_list nameap)
1595{
1596	nvpair_t *nvp;
1597
1598	if (nvlist_error(nvl) != 0) {
1599		if (value != NULL && nvlist_get_nvpair_parent(value) != NULL)
1600			nvlist_destroy(value);
1601		RESTORE_ERRNO(nvlist_error(nvl));
1602		return;
1603	}
1604
1605	nvp = nvpair_movev_nvlist(value, namefmt, nameap);
1606	if (nvp == NULL) {
1607		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1608		RESTORE_ERRNO(nvl->nvl_error);
1609	} else
1610		nvlist_move_nvpair(nvl, nvp);
1611}
1612
1613#ifndef _KERNEL
1614void
1615nvlist_movev_descriptor(nvlist_t *nvl, int value, const char *namefmt,
1616    va_list nameap)
1617{
1618	nvpair_t *nvp;
1619
1620	if (nvlist_error(nvl) != 0) {
1621		close(value);
1622		errno = nvlist_error(nvl);
1623		return;
1624	}
1625
1626	nvp = nvpair_movev_descriptor(value, namefmt, nameap);
1627	if (nvp == NULL)
1628		nvl->nvl_error = errno = (errno != 0 ? errno : ENOMEM);
1629	else
1630		nvlist_move_nvpair(nvl, nvp);
1631}
1632#endif
1633
1634void
1635nvlist_movev_binary(nvlist_t *nvl, void *value, size_t size,
1636    const char *namefmt, va_list nameap)
1637{
1638	nvpair_t *nvp;
1639
1640	if (nvlist_error(nvl) != 0) {
1641		nv_free(value);
1642		RESTORE_ERRNO(nvlist_error(nvl));
1643		return;
1644	}
1645
1646	nvp = nvpair_movev_binary(value, size, namefmt, nameap);
1647	if (nvp == NULL) {
1648		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1649		RESTORE_ERRNO(nvl->nvl_error);
1650	} else
1651		nvlist_move_nvpair(nvl, nvp);
1652}
1653
1654const nvpair_t *
1655nvlist_get_nvpair(const nvlist_t *nvl, const char *name)
1656{
1657
1658	return (nvlist_find(nvl, NV_TYPE_NONE, name));
1659}
1660
1661#define	NVLIST_GET(ftype, type, TYPE)					\
1662ftype									\
1663nvlist_get_##type(const nvlist_t *nvl, const char *name)		\
1664{									\
1665	const nvpair_t *nvp;						\
1666									\
1667	nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name);			\
1668	if (nvp == NULL)						\
1669		nvlist_report_missing(NV_TYPE_##TYPE, name);		\
1670	return (nvpair_get_##type(nvp));				\
1671}
1672
1673NVLIST_GET(bool, bool, BOOL)
1674NVLIST_GET(uint64_t, number, NUMBER)
1675NVLIST_GET(const char *, string, STRING)
1676NVLIST_GET(const nvlist_t *, nvlist, NVLIST)
1677#ifndef _KERNEL
1678NVLIST_GET(int, descriptor, DESCRIPTOR)
1679#endif
1680
1681#undef	NVLIST_GET
1682
1683const void *
1684nvlist_get_binary(const nvlist_t *nvl, const char *name, size_t *sizep)
1685{
1686	nvpair_t *nvp;
1687
1688	nvp = nvlist_find(nvl, NV_TYPE_BINARY, name);
1689	if (nvp == NULL)
1690		nvlist_report_missing(NV_TYPE_BINARY, name);
1691
1692	return (nvpair_get_binary(nvp, sizep));
1693}
1694
1695#define	NVLIST_GETF(ftype, type)					\
1696ftype									\
1697nvlist_getf_##type(const nvlist_t *nvl, const char *namefmt, ...)	\
1698{									\
1699	va_list nameap;							\
1700	ftype value;							\
1701									\
1702	va_start(nameap, namefmt);					\
1703	value = nvlist_getv_##type(nvl, namefmt, nameap);		\
1704	va_end(nameap);							\
1705									\
1706	return (value);							\
1707}
1708
1709#ifndef _KERNEL
1710NVLIST_GETF(bool, bool)
1711NVLIST_GETF(uint64_t, number)
1712NVLIST_GETF(const char *, string)
1713NVLIST_GETF(const nvlist_t *, nvlist)
1714NVLIST_GETF(int, descriptor)
1715
1716#undef	NVLIST_GETF
1717
1718const void *
1719nvlist_getf_binary(const nvlist_t *nvl, size_t *sizep, const char *namefmt, ...)
1720{
1721	va_list nameap;
1722	const void *value;
1723
1724	va_start(nameap, namefmt);
1725	value = nvlist_getv_binary(nvl, sizep, namefmt, nameap);
1726	va_end(nameap);
1727
1728	return (value);
1729}
1730
1731#define	NVLIST_GETV(ftype, type, TYPE)					\
1732ftype									\
1733nvlist_getv_##type(const nvlist_t *nvl, const char *namefmt,		\
1734    va_list nameap)							\
1735{									\
1736	char *name;							\
1737	ftype value;							\
1738									\
1739	vasprintf(&name, namefmt, nameap);				\
1740	if (name == NULL)						\
1741		nvlist_report_missing(NV_TYPE_##TYPE, "<unknown>");	\
1742	value = nvlist_get_##type(nvl, name);				\
1743	free(name);							\
1744									\
1745	return (value);							\
1746}
1747
1748NVLIST_GETV(bool, bool, BOOL)
1749NVLIST_GETV(uint64_t, number, NUMBER)
1750NVLIST_GETV(const char *, string, STRING)
1751NVLIST_GETV(const nvlist_t *, nvlist, NVLIST)
1752NVLIST_GETV(int, descriptor, DESCRIPTOR)
1753
1754#undef	NVLIST_GETV
1755
1756const void *
1757nvlist_getv_binary(const nvlist_t *nvl, size_t *sizep, const char *namefmt,
1758    va_list nameap)
1759{
1760	char *name;
1761	const void *binary;
1762
1763	nv_vasprintf(&name, namefmt, nameap);
1764	if (name == NULL)
1765		nvlist_report_missing(NV_TYPE_BINARY, "<unknown>");
1766
1767	binary = nvlist_get_binary(nvl, name, sizep);
1768	nv_free(name);
1769	return (binary);
1770}
1771#endif
1772
1773#define	NVLIST_TAKE(ftype, type, TYPE)					\
1774ftype									\
1775nvlist_take_##type(nvlist_t *nvl, const char *name)			\
1776{									\
1777	nvpair_t *nvp;							\
1778	ftype value;							\
1779									\
1780	nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name);			\
1781	if (nvp == NULL)						\
1782		nvlist_report_missing(NV_TYPE_##TYPE, name);		\
1783	value = (ftype)(intptr_t)nvpair_get_##type(nvp);		\
1784	nvlist_remove_nvpair(nvl, nvp);					\
1785	nvpair_free_structure(nvp);					\
1786	return (value);							\
1787}
1788
1789NVLIST_TAKE(bool, bool, BOOL)
1790NVLIST_TAKE(uint64_t, number, NUMBER)
1791NVLIST_TAKE(char *, string, STRING)
1792NVLIST_TAKE(nvlist_t *, nvlist, NVLIST)
1793#ifndef _KERNEL
1794NVLIST_TAKE(int, descriptor, DESCRIPTOR)
1795#endif
1796
1797#undef	NVLIST_TAKE
1798
1799void *
1800nvlist_take_binary(nvlist_t *nvl, const char *name, size_t *sizep)
1801{
1802	nvpair_t *nvp;
1803	void *value;
1804
1805	nvp = nvlist_find(nvl, NV_TYPE_BINARY, name);
1806	if (nvp == NULL)
1807		nvlist_report_missing(NV_TYPE_BINARY, name);
1808
1809	value = (void *)(intptr_t)nvpair_get_binary(nvp, sizep);
1810	nvlist_remove_nvpair(nvl, nvp);
1811	nvpair_free_structure(nvp);
1812	return (value);
1813}
1814
1815#define	NVLIST_TAKEF(ftype, type)					\
1816ftype									\
1817nvlist_takef_##type(nvlist_t *nvl, const char *namefmt, ...)		\
1818{									\
1819	va_list nameap;							\
1820	ftype value;							\
1821									\
1822	va_start(nameap, namefmt);					\
1823	value = nvlist_takev_##type(nvl, namefmt, nameap);		\
1824	va_end(nameap);							\
1825									\
1826	return (value);							\
1827}
1828
1829#ifndef _KERNEL
1830NVLIST_TAKEF(bool, bool)
1831NVLIST_TAKEF(uint64_t, number)
1832NVLIST_TAKEF(char *, string)
1833NVLIST_TAKEF(nvlist_t *, nvlist)
1834NVLIST_TAKEF(int, descriptor)
1835
1836#undef	NVLIST_TAKEF
1837
1838void *
1839nvlist_takef_binary(nvlist_t *nvl, size_t *sizep, const char *namefmt, ...)
1840{
1841	va_list nameap;
1842	void *value;
1843
1844	va_start(nameap, namefmt);
1845	value = nvlist_takev_binary(nvl, sizep, namefmt, nameap);
1846	va_end(nameap);
1847
1848	return (value);
1849}
1850
1851#define	NVLIST_TAKEV(ftype, type, TYPE)					\
1852ftype									\
1853nvlist_takev_##type(nvlist_t *nvl, const char *namefmt, va_list nameap)	\
1854{									\
1855	char *name;							\
1856	ftype value;							\
1857									\
1858	vasprintf(&name, namefmt, nameap);				\
1859	if (name == NULL)						\
1860		nvlist_report_missing(NV_TYPE_##TYPE, "<unknown>");	\
1861	value = nvlist_take_##type(nvl, name);				\
1862	free(name);							\
1863	return (value);							\
1864}
1865
1866NVLIST_TAKEV(bool, bool, BOOL)
1867NVLIST_TAKEV(uint64_t, number, NUMBER)
1868NVLIST_TAKEV(char *, string, STRING)
1869NVLIST_TAKEV(nvlist_t *, nvlist, NVLIST)
1870NVLIST_TAKEV(int, descriptor, DESCRIPTOR)
1871
1872#undef	NVLIST_TAKEV
1873
1874void *
1875nvlist_takev_binary(nvlist_t *nvl, size_t *sizep, const char *namefmt,
1876    va_list nameap)
1877{
1878	char *name;
1879	void *binary;
1880
1881	nv_vasprintf(&name, namefmt, nameap);
1882	if (name == NULL)
1883		nvlist_report_missing(NV_TYPE_BINARY, "<unknown>");
1884
1885	binary = nvlist_take_binary(nvl, name, sizep);
1886	nv_free(name);
1887	return (binary);
1888}
1889#endif
1890
1891void
1892nvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp)
1893{
1894
1895	NVLIST_ASSERT(nvl);
1896	NVPAIR_ASSERT(nvp);
1897	PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
1898
1899	nvpair_remove(&nvl->nvl_head, nvp, nvl);
1900}
1901
1902void
1903nvlist_free(nvlist_t *nvl, const char *name)
1904{
1905
1906	nvlist_free_type(nvl, name, NV_TYPE_NONE);
1907}
1908
1909#define	NVLIST_FREE(type, TYPE)						\
1910void									\
1911nvlist_free_##type(nvlist_t *nvl, const char *name)			\
1912{									\
1913									\
1914	nvlist_free_type(nvl, name, NV_TYPE_##TYPE);			\
1915}
1916
1917NVLIST_FREE(null, NULL)
1918NVLIST_FREE(bool, BOOL)
1919NVLIST_FREE(number, NUMBER)
1920NVLIST_FREE(string, STRING)
1921NVLIST_FREE(nvlist, NVLIST)
1922#ifndef _KERNEL
1923NVLIST_FREE(descriptor, DESCRIPTOR)
1924#endif
1925NVLIST_FREE(binary, BINARY)
1926
1927#undef	NVLIST_FREE
1928
1929#ifndef _KERNEL
1930void
1931nvlist_freef(nvlist_t *nvl, const char *namefmt, ...)
1932{
1933	va_list nameap;
1934
1935	va_start(nameap, namefmt);
1936	nvlist_freev(nvl, namefmt, nameap);
1937	va_end(nameap);
1938}
1939
1940#define	NVLIST_FREEF(type)						\
1941void									\
1942nvlist_freef_##type(nvlist_t *nvl, const char *namefmt, ...)		\
1943{									\
1944	va_list nameap;							\
1945									\
1946	va_start(nameap, namefmt);					\
1947	nvlist_freev_##type(nvl, namefmt, nameap);			\
1948	va_end(nameap);							\
1949}
1950
1951NVLIST_FREEF(null)
1952NVLIST_FREEF(bool)
1953NVLIST_FREEF(number)
1954NVLIST_FREEF(string)
1955NVLIST_FREEF(nvlist)
1956NVLIST_FREEF(descriptor)
1957NVLIST_FREEF(binary)
1958
1959#undef	NVLIST_FREEF
1960
1961void
1962nvlist_freev(nvlist_t *nvl, const char *namefmt, va_list nameap)
1963{
1964
1965	nvlist_freev_type(nvl, NV_TYPE_NONE, namefmt, nameap);
1966}
1967
1968#define	NVLIST_FREEV(type, TYPE)					\
1969void									\
1970nvlist_freev_##type(nvlist_t *nvl, const char *namefmt, va_list nameap)	\
1971{									\
1972	char *name;							\
1973									\
1974	vasprintf(&name, namefmt, nameap);				\
1975	if (name == NULL)						\
1976		nvlist_report_missing(NV_TYPE_##TYPE, "<unknown>");	\
1977	nvlist_free_##type(nvl, name);					\
1978	free(name);							\
1979}
1980
1981NVLIST_FREEV(null, NULL)
1982NVLIST_FREEV(bool, BOOL)
1983NVLIST_FREEV(number, NUMBER)
1984NVLIST_FREEV(string, STRING)
1985NVLIST_FREEV(nvlist, NVLIST)
1986NVLIST_FREEV(descriptor, DESCRIPTOR)
1987NVLIST_FREEV(binary, BINARY)
1988#undef	NVLIST_FREEV
1989#endif
1990
1991void
1992nvlist_free_nvpair(nvlist_t *nvl, nvpair_t *nvp)
1993{
1994
1995	NVLIST_ASSERT(nvl);
1996	NVPAIR_ASSERT(nvp);
1997	PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
1998
1999	nvlist_remove_nvpair(nvl, nvp);
2000	nvpair_free(nvp);
2001}
2002