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