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