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