nvlist.c revision 336346
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 336346 2018-07-16 15:02:21Z kevans $");
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
317void
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	void *cookie;
712	nvpair_t *nvp;
713	int type;
714
715	NVLIST_ASSERT(nvl);
716	PJDLOG_ASSERT(nvl->nvl_error == 0);
717
718	cookie = NULL;
719	do {
720		while (nvlist_next(nvl, &type, &cookie) != NULL) {
721			nvp = cookie;
722			switch (type) {
723			case NV_TYPE_DESCRIPTOR:
724				*descs = nvpair_get_descriptor(nvp);
725				descs++;
726				break;
727			case NV_TYPE_DESCRIPTOR_ARRAY:
728			    {
729				const int *value;
730				size_t nitems;
731				unsigned int ii;
732
733				value = nvpair_get_descriptor_array(nvp,
734				    &nitems);
735				for (ii = 0; ii < nitems; ii++) {
736					*descs = value[ii];
737					descs++;
738				}
739				break;
740			    }
741			case NV_TYPE_NVLIST:
742				nvl = nvpair_get_nvlist(nvp);
743				cookie = NULL;
744				break;
745			case NV_TYPE_NVLIST_ARRAY:
746			    {
747				const nvlist_t * const *value;
748				size_t nitems;
749
750				value = nvpair_get_nvlist_array(nvp, &nitems);
751				PJDLOG_ASSERT(value != NULL);
752				PJDLOG_ASSERT(nitems > 0);
753
754				nvl = value[0];
755				cookie = NULL;
756				break;
757			    }
758			}
759		}
760	} while ((nvl = nvlist_get_pararr(nvl, &cookie)) != NULL);
761
762	return (descs);
763}
764#endif
765
766#ifndef _KERNEL
767int *
768nvlist_descriptors(const nvlist_t *nvl, size_t *nitemsp)
769{
770	size_t nitems;
771	int *fds;
772
773	nitems = nvlist_ndescriptors(nvl);
774	fds = nv_malloc(sizeof(fds[0]) * (nitems + 1));
775	if (fds == NULL)
776		return (NULL);
777	if (nitems > 0)
778		nvlist_xdescriptors(nvl, fds);
779	fds[nitems] = -1;
780	if (nitemsp != NULL)
781		*nitemsp = nitems;
782	return (fds);
783}
784#endif
785
786size_t
787nvlist_ndescriptors(const nvlist_t *nvl)
788{
789#ifndef _KERNEL
790	void *cookie;
791	nvpair_t *nvp;
792	size_t ndescs;
793	int type;
794
795	NVLIST_ASSERT(nvl);
796	PJDLOG_ASSERT(nvl->nvl_error == 0);
797
798	ndescs = 0;
799	cookie = NULL;
800	do {
801		while (nvlist_next(nvl, &type, &cookie) != NULL) {
802			nvp = cookie;
803			switch (type) {
804			case NV_TYPE_DESCRIPTOR:
805				ndescs++;
806				break;
807			case NV_TYPE_NVLIST:
808				nvl = nvpair_get_nvlist(nvp);
809				cookie = NULL;
810				break;
811			case NV_TYPE_NVLIST_ARRAY:
812			    {
813				const nvlist_t * const *value;
814				size_t nitems;
815
816				value = nvpair_get_nvlist_array(nvp, &nitems);
817				PJDLOG_ASSERT(value != NULL);
818				PJDLOG_ASSERT(nitems > 0);
819
820				nvl = value[0];
821				cookie = NULL;
822				break;
823			    }
824			case NV_TYPE_DESCRIPTOR_ARRAY:
825			    {
826				size_t nitems;
827
828				(void)nvpair_get_descriptor_array(nvp,
829				    &nitems);
830				ndescs += nitems;
831				break;
832			    }
833			}
834		}
835	} while ((nvl = nvlist_get_pararr(nvl, &cookie)) != NULL);
836
837	return (ndescs);
838#else
839	return (0);
840#endif
841}
842
843static unsigned char *
844nvlist_pack_header(const nvlist_t *nvl, unsigned char *ptr, size_t *leftp)
845{
846	struct nvlist_header nvlhdr;
847
848	NVLIST_ASSERT(nvl);
849
850	nvlhdr.nvlh_magic = NVLIST_HEADER_MAGIC;
851	nvlhdr.nvlh_version = NVLIST_HEADER_VERSION;
852	nvlhdr.nvlh_flags = nvl->nvl_flags;
853#if BYTE_ORDER == BIG_ENDIAN
854	nvlhdr.nvlh_flags |= NV_FLAG_BIG_ENDIAN;
855#endif
856	nvlhdr.nvlh_descriptors = nvlist_ndescriptors(nvl);
857	nvlhdr.nvlh_size = *leftp - sizeof(nvlhdr);
858	PJDLOG_ASSERT(*leftp >= sizeof(nvlhdr));
859	memcpy(ptr, &nvlhdr, sizeof(nvlhdr));
860	ptr += sizeof(nvlhdr);
861	*leftp -= sizeof(nvlhdr);
862
863	return (ptr);
864}
865
866static void *
867nvlist_xpack(const nvlist_t *nvl, int64_t *fdidxp, size_t *sizep)
868{
869	unsigned char *buf, *ptr;
870	size_t left, size;
871	const nvlist_t *tmpnvl;
872	nvpair_t *nvp, *tmpnvp;
873	void *cookie;
874
875	NVLIST_ASSERT(nvl);
876
877	if (nvl->nvl_error != 0) {
878		ERRNO_SET(nvl->nvl_error);
879		return (NULL);
880	}
881
882	size = nvlist_size(nvl);
883	buf = nv_malloc(size);
884	if (buf == NULL)
885		return (NULL);
886
887	ptr = buf;
888	left = size;
889
890	ptr = nvlist_pack_header(nvl, ptr, &left);
891
892	nvp = nvlist_first_nvpair(nvl);
893	while (nvp != NULL) {
894		NVPAIR_ASSERT(nvp);
895
896		nvpair_init_datasize(nvp);
897		ptr = nvpair_pack_header(nvp, ptr, &left);
898		if (ptr == NULL)
899			goto fail;
900		switch (nvpair_type(nvp)) {
901		case NV_TYPE_NULL:
902			ptr = nvpair_pack_null(nvp, ptr, &left);
903			break;
904		case NV_TYPE_BOOL:
905			ptr = nvpair_pack_bool(nvp, ptr, &left);
906			break;
907		case NV_TYPE_NUMBER:
908			ptr = nvpair_pack_number(nvp, ptr, &left);
909			break;
910		case NV_TYPE_STRING:
911			ptr = nvpair_pack_string(nvp, ptr, &left);
912			break;
913		case NV_TYPE_NVLIST:
914			tmpnvl = nvpair_get_nvlist(nvp);
915			ptr = nvlist_pack_header(tmpnvl, ptr, &left);
916			if (ptr == NULL)
917				goto fail;
918			tmpnvp = nvlist_first_nvpair(tmpnvl);
919			if (tmpnvp != NULL) {
920				nvl = tmpnvl;
921				nvp = tmpnvp;
922				continue;
923			}
924			ptr = nvpair_pack_nvlist_up(ptr, &left);
925			break;
926#ifndef _KERNEL
927		case NV_TYPE_DESCRIPTOR:
928			ptr = nvpair_pack_descriptor(nvp, ptr, fdidxp, &left);
929			break;
930		case NV_TYPE_DESCRIPTOR_ARRAY:
931			ptr = nvpair_pack_descriptor_array(nvp, ptr, fdidxp,
932			    &left);
933			break;
934#endif
935		case NV_TYPE_BINARY:
936			ptr = nvpair_pack_binary(nvp, ptr, &left);
937			break;
938		case NV_TYPE_BOOL_ARRAY:
939			ptr = nvpair_pack_bool_array(nvp, ptr, &left);
940			break;
941		case NV_TYPE_NUMBER_ARRAY:
942			ptr = nvpair_pack_number_array(nvp, ptr, &left);
943			break;
944		case NV_TYPE_STRING_ARRAY:
945			ptr = nvpair_pack_string_array(nvp, ptr, &left);
946			break;
947		case NV_TYPE_NVLIST_ARRAY:
948		    {
949			const nvlist_t * const * value;
950			size_t nitems;
951			unsigned int ii;
952
953			tmpnvl = NULL;
954			value = nvpair_get_nvlist_array(nvp, &nitems);
955			for (ii = 0; ii < nitems; ii++) {
956				ptr = nvlist_pack_header(value[ii], ptr, &left);
957				if (ptr == NULL)
958					goto out;
959				tmpnvp = nvlist_first_nvpair(value[ii]);
960				if (tmpnvp != NULL) {
961					tmpnvl = value[ii];
962					break;
963				}
964				ptr = nvpair_pack_nvlist_array_next(ptr, &left);
965				if (ptr == NULL)
966					goto out;
967			}
968			if (tmpnvl != NULL) {
969				nvl = tmpnvl;
970				nvp = tmpnvp;
971				continue;
972			}
973			break;
974		    }
975		default:
976			PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp));
977		}
978		if (ptr == NULL)
979			goto fail;
980		while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
981			do {
982				cookie = NULL;
983				if (nvlist_in_array(nvl)) {
984					ptr = nvpair_pack_nvlist_array_next(ptr,
985					    &left);
986					if (ptr == NULL)
987						goto fail;
988				}
989				nvl = nvlist_get_pararr(nvl, &cookie);
990				if (nvl == NULL)
991					goto out;
992				if (nvlist_in_array(nvl) && cookie == NULL) {
993					nvp = nvlist_first_nvpair(nvl);
994					ptr = nvlist_pack_header(nvl, ptr,
995					    &left);
996					if (ptr == NULL)
997						goto fail;
998				} else if (nvpair_type((nvpair_t *)cookie) !=
999				    NV_TYPE_NVLIST_ARRAY) {
1000					ptr = nvpair_pack_nvlist_up(ptr, &left);
1001					if (ptr == NULL)
1002						goto fail;
1003					nvp = cookie;
1004				} else {
1005					nvp = cookie;
1006				}
1007			} while (nvp == NULL);
1008			if (nvlist_in_array(nvl) && cookie == NULL)
1009				break;
1010		}
1011	}
1012
1013out:
1014	if (sizep != NULL)
1015		*sizep = size;
1016	return (buf);
1017fail:
1018	nv_free(buf);
1019	return (NULL);
1020}
1021
1022void *
1023nvlist_pack(const nvlist_t *nvl, size_t *sizep)
1024{
1025
1026	NVLIST_ASSERT(nvl);
1027
1028	if (nvl->nvl_error != 0) {
1029		ERRNO_SET(nvl->nvl_error);
1030		return (NULL);
1031	}
1032
1033	if (nvlist_ndescriptors(nvl) > 0) {
1034		ERRNO_SET(EOPNOTSUPP);
1035		return (NULL);
1036	}
1037
1038	return (nvlist_xpack(nvl, NULL, sizep));
1039}
1040
1041static bool
1042nvlist_check_header(struct nvlist_header *nvlhdrp)
1043{
1044
1045	if (nvlhdrp->nvlh_magic != NVLIST_HEADER_MAGIC) {
1046		ERRNO_SET(EINVAL);
1047		return (false);
1048	}
1049	if ((nvlhdrp->nvlh_flags & ~NV_FLAG_ALL_MASK) != 0) {
1050		ERRNO_SET(EINVAL);
1051		return (false);
1052	}
1053#if BYTE_ORDER == BIG_ENDIAN
1054	if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) == 0) {
1055		nvlhdrp->nvlh_size = le64toh(nvlhdrp->nvlh_size);
1056		nvlhdrp->nvlh_descriptors = le64toh(nvlhdrp->nvlh_descriptors);
1057	}
1058#else
1059	if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0) {
1060		nvlhdrp->nvlh_size = be64toh(nvlhdrp->nvlh_size);
1061		nvlhdrp->nvlh_descriptors = be64toh(nvlhdrp->nvlh_descriptors);
1062	}
1063#endif
1064	return (true);
1065}
1066
1067const unsigned char *
1068nvlist_unpack_header(nvlist_t *nvl, const unsigned char *ptr, size_t nfds,
1069    bool *isbep, size_t *leftp)
1070{
1071	struct nvlist_header nvlhdr;
1072	int inarrayf;
1073
1074	if (*leftp < sizeof(nvlhdr))
1075		goto fail;
1076
1077	memcpy(&nvlhdr, ptr, sizeof(nvlhdr));
1078
1079	if (!nvlist_check_header(&nvlhdr))
1080		goto fail;
1081
1082	if (nvlhdr.nvlh_size != *leftp - sizeof(nvlhdr))
1083		goto fail;
1084
1085	/*
1086	 * nvlh_descriptors might be smaller than nfds in embedded nvlists.
1087	 */
1088	if (nvlhdr.nvlh_descriptors > nfds)
1089		goto fail;
1090
1091	if ((nvlhdr.nvlh_flags & ~NV_FLAG_ALL_MASK) != 0)
1092		goto fail;
1093
1094	inarrayf = (nvl->nvl_flags & NV_FLAG_IN_ARRAY);
1095	nvl->nvl_flags = (nvlhdr.nvlh_flags & NV_FLAG_PUBLIC_MASK) | inarrayf;
1096
1097	ptr += sizeof(nvlhdr);
1098	if (isbep != NULL)
1099		*isbep = (((int)nvlhdr.nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0);
1100	*leftp -= sizeof(nvlhdr);
1101
1102	return (ptr);
1103fail:
1104	ERRNO_SET(EINVAL);
1105	return (NULL);
1106}
1107
1108static nvlist_t *
1109nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds,
1110    int flags)
1111{
1112	const unsigned char *ptr;
1113	nvlist_t *nvl, *retnvl, *tmpnvl, *array;
1114	nvpair_t *nvp;
1115	size_t left;
1116	bool isbe;
1117
1118	PJDLOG_ASSERT((flags & ~(NV_FLAG_PUBLIC_MASK)) == 0);
1119
1120	left = size;
1121	ptr = buf;
1122
1123	tmpnvl = array = NULL;
1124	nvl = retnvl = nvlist_create(0);
1125	if (nvl == NULL)
1126		goto fail;
1127
1128	ptr = nvlist_unpack_header(nvl, ptr, nfds, &isbe, &left);
1129	if (ptr == NULL)
1130		goto fail;
1131	if (nvl->nvl_flags != flags) {
1132		ERRNO_SET(EILSEQ);
1133		goto fail;
1134	}
1135
1136	while (left > 0) {
1137		ptr = nvpair_unpack(isbe, ptr, &left, &nvp);
1138		if (ptr == NULL)
1139			goto fail;
1140		switch (nvpair_type(nvp)) {
1141		case NV_TYPE_NULL:
1142			ptr = nvpair_unpack_null(isbe, nvp, ptr, &left);
1143			break;
1144		case NV_TYPE_BOOL:
1145			ptr = nvpair_unpack_bool(isbe, nvp, ptr, &left);
1146			break;
1147		case NV_TYPE_NUMBER:
1148			ptr = nvpair_unpack_number(isbe, nvp, ptr, &left);
1149			break;
1150		case NV_TYPE_STRING:
1151			ptr = nvpair_unpack_string(isbe, nvp, ptr, &left);
1152			break;
1153		case NV_TYPE_NVLIST:
1154			ptr = nvpair_unpack_nvlist(isbe, nvp, ptr, &left, nfds,
1155			    &tmpnvl);
1156			if (tmpnvl == NULL || ptr == NULL)
1157				goto fail;
1158			nvlist_set_parent(tmpnvl, nvp);
1159			break;
1160#ifndef _KERNEL
1161		case NV_TYPE_DESCRIPTOR:
1162			ptr = nvpair_unpack_descriptor(isbe, nvp, ptr, &left,
1163			    fds, nfds);
1164			break;
1165		case NV_TYPE_DESCRIPTOR_ARRAY:
1166			ptr = nvpair_unpack_descriptor_array(isbe, nvp, ptr,
1167			    &left, fds, nfds);
1168			break;
1169#endif
1170		case NV_TYPE_BINARY:
1171			ptr = nvpair_unpack_binary(isbe, nvp, ptr, &left);
1172			break;
1173		case NV_TYPE_NVLIST_UP:
1174			if (nvl->nvl_parent == NULL)
1175				goto fail;
1176			nvl = nvpair_nvlist(nvl->nvl_parent);
1177			nvpair_free_structure(nvp);
1178			continue;
1179		case NV_TYPE_NVLIST_ARRAY_NEXT:
1180			if (nvl->nvl_array_next == NULL) {
1181				if (nvl->nvl_parent == NULL)
1182					goto fail;
1183				nvl = nvpair_nvlist(nvl->nvl_parent);
1184			} else {
1185				nvl = __DECONST(nvlist_t *,
1186				    nvlist_get_array_next(nvl));
1187				ptr = nvlist_unpack_header(nvl, ptr, nfds,
1188				    &isbe, &left);
1189				if (ptr == NULL)
1190					goto fail;
1191			}
1192			nvpair_free_structure(nvp);
1193			continue;
1194		case NV_TYPE_BOOL_ARRAY:
1195			ptr = nvpair_unpack_bool_array(isbe, nvp, ptr, &left);
1196			break;
1197		case NV_TYPE_NUMBER_ARRAY:
1198			ptr = nvpair_unpack_number_array(isbe, nvp, ptr, &left);
1199			break;
1200		case NV_TYPE_STRING_ARRAY:
1201			ptr = nvpair_unpack_string_array(isbe, nvp, ptr, &left);
1202			break;
1203		case NV_TYPE_NVLIST_ARRAY:
1204			ptr = nvpair_unpack_nvlist_array(isbe, nvp, ptr, &left,
1205			    &array);
1206			if (ptr == NULL)
1207				goto fail;
1208			PJDLOG_ASSERT(array != NULL);
1209			tmpnvl = array;
1210			do {
1211				nvlist_set_parent(array, nvp);
1212				array = __DECONST(nvlist_t *,
1213				    nvlist_get_array_next(array));
1214			} while (array != NULL);
1215			ptr = nvlist_unpack_header(tmpnvl, ptr, nfds, &isbe,
1216			    &left);
1217			break;
1218		default:
1219			PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp));
1220		}
1221		if (ptr == NULL)
1222			goto fail;
1223		if (!nvlist_move_nvpair(nvl, nvp))
1224			goto fail;
1225		if (tmpnvl != NULL) {
1226			nvl = tmpnvl;
1227			tmpnvl = NULL;
1228		}
1229	}
1230
1231	return (retnvl);
1232fail:
1233	nvlist_destroy(retnvl);
1234	return (NULL);
1235}
1236
1237nvlist_t *
1238nvlist_unpack(const void *buf, size_t size, int flags)
1239{
1240
1241	return (nvlist_xunpack(buf, size, NULL, 0, flags));
1242}
1243
1244#ifndef _KERNEL
1245int
1246nvlist_send(int sock, const nvlist_t *nvl)
1247{
1248	size_t datasize, nfds;
1249	int *fds;
1250	void *data;
1251	int64_t fdidx;
1252	int ret;
1253
1254	if (nvlist_error(nvl) != 0) {
1255		ERRNO_SET(nvlist_error(nvl));
1256		return (-1);
1257	}
1258
1259	fds = nvlist_descriptors(nvl, &nfds);
1260	if (fds == NULL)
1261		return (-1);
1262
1263	ret = -1;
1264	fdidx = 0;
1265
1266	data = nvlist_xpack(nvl, &fdidx, &datasize);
1267	if (data == NULL)
1268		goto out;
1269
1270	if (buf_send(sock, data, datasize) == -1)
1271		goto out;
1272
1273	if (nfds > 0) {
1274		if (fd_send(sock, fds, nfds) == -1)
1275			goto out;
1276	}
1277
1278	ret = 0;
1279out:
1280	ERRNO_SAVE();
1281	nv_free(fds);
1282	nv_free(data);
1283	ERRNO_RESTORE();
1284	return (ret);
1285}
1286
1287nvlist_t *
1288nvlist_recv(int sock, int flags)
1289{
1290	struct nvlist_header nvlhdr;
1291	nvlist_t *nvl, *ret;
1292	unsigned char *buf;
1293	size_t nfds, size, i;
1294	int *fds;
1295
1296	if (buf_recv(sock, &nvlhdr, sizeof(nvlhdr)) == -1)
1297		return (NULL);
1298
1299	if (!nvlist_check_header(&nvlhdr))
1300		return (NULL);
1301
1302	nfds = (size_t)nvlhdr.nvlh_descriptors;
1303	size = sizeof(nvlhdr) + (size_t)nvlhdr.nvlh_size;
1304
1305	buf = nv_malloc(size);
1306	if (buf == NULL)
1307		return (NULL);
1308
1309	memcpy(buf, &nvlhdr, sizeof(nvlhdr));
1310
1311	ret = NULL;
1312	fds = NULL;
1313
1314	if (buf_recv(sock, buf + sizeof(nvlhdr), size - sizeof(nvlhdr)) == -1)
1315		goto out;
1316
1317	if (nfds > 0) {
1318		fds = nv_malloc(nfds * sizeof(fds[0]));
1319		if (fds == NULL)
1320			goto out;
1321		if (fd_recv(sock, fds, nfds) == -1)
1322			goto out;
1323	}
1324
1325	nvl = nvlist_xunpack(buf, size, fds, nfds, flags);
1326	if (nvl == NULL) {
1327		ERRNO_SAVE();
1328		for (i = 0; i < nfds; i++)
1329			close(fds[i]);
1330		ERRNO_RESTORE();
1331		goto out;
1332	}
1333
1334	ret = nvl;
1335out:
1336	ERRNO_SAVE();
1337	nv_free(buf);
1338	nv_free(fds);
1339	ERRNO_RESTORE();
1340
1341	return (ret);
1342}
1343
1344nvlist_t *
1345nvlist_xfer(int sock, nvlist_t *nvl, int flags)
1346{
1347
1348	if (nvlist_send(sock, nvl) < 0) {
1349		nvlist_destroy(nvl);
1350		return (NULL);
1351	}
1352	nvlist_destroy(nvl);
1353	return (nvlist_recv(sock, flags));
1354}
1355#endif
1356
1357nvpair_t *
1358nvlist_first_nvpair(const nvlist_t *nvl)
1359{
1360
1361	NVLIST_ASSERT(nvl);
1362
1363	return (TAILQ_FIRST(&nvl->nvl_head));
1364}
1365
1366nvpair_t *
1367nvlist_next_nvpair(const nvlist_t *nvl, const nvpair_t *nvp)
1368{
1369	nvpair_t *retnvp;
1370
1371	NVLIST_ASSERT(nvl);
1372	NVPAIR_ASSERT(nvp);
1373	PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
1374
1375	retnvp = nvpair_next(nvp);
1376	PJDLOG_ASSERT(retnvp == NULL || nvpair_nvlist(retnvp) == nvl);
1377
1378	return (retnvp);
1379
1380}
1381
1382nvpair_t *
1383nvlist_prev_nvpair(const nvlist_t *nvl, const nvpair_t *nvp)
1384{
1385	nvpair_t *retnvp;
1386
1387	NVLIST_ASSERT(nvl);
1388	NVPAIR_ASSERT(nvp);
1389	PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
1390
1391	retnvp = nvpair_prev(nvp);
1392	PJDLOG_ASSERT(nvpair_nvlist(retnvp) == nvl);
1393
1394	return (retnvp);
1395}
1396
1397const char *
1398nvlist_next(const nvlist_t *nvl, int *typep, void **cookiep)
1399{
1400	nvpair_t *nvp;
1401
1402	NVLIST_ASSERT(nvl);
1403
1404	if (cookiep == NULL || *cookiep == NULL)
1405		nvp = nvlist_first_nvpair(nvl);
1406	else
1407		nvp = nvlist_next_nvpair(nvl, *cookiep);
1408	if (nvp == NULL)
1409		return (NULL);
1410	if (typep != NULL)
1411		*typep = nvpair_type(nvp);
1412	if (cookiep != NULL)
1413		*cookiep = nvp;
1414	return (nvpair_name(nvp));
1415}
1416
1417bool
1418nvlist_exists(const nvlist_t *nvl, const char *name)
1419{
1420
1421	return (nvlist_find(nvl, NV_TYPE_NONE, name) != NULL);
1422}
1423
1424#define	NVLIST_EXISTS(type, TYPE)					\
1425bool									\
1426nvlist_exists_##type(const nvlist_t *nvl, const char *name)		\
1427{									\
1428									\
1429	return (nvlist_find(nvl, NV_TYPE_##TYPE, name) != NULL);	\
1430}
1431
1432NVLIST_EXISTS(null, NULL)
1433NVLIST_EXISTS(bool, BOOL)
1434NVLIST_EXISTS(number, NUMBER)
1435NVLIST_EXISTS(string, STRING)
1436NVLIST_EXISTS(nvlist, NVLIST)
1437NVLIST_EXISTS(binary, BINARY)
1438NVLIST_EXISTS(bool_array, BOOL_ARRAY)
1439NVLIST_EXISTS(number_array, NUMBER_ARRAY)
1440NVLIST_EXISTS(string_array, STRING_ARRAY)
1441NVLIST_EXISTS(nvlist_array, NVLIST_ARRAY)
1442#ifndef _KERNEL
1443NVLIST_EXISTS(descriptor, DESCRIPTOR)
1444NVLIST_EXISTS(descriptor_array, DESCRIPTOR_ARRAY)
1445#endif
1446
1447#undef	NVLIST_EXISTS
1448
1449void
1450nvlist_add_nvpair(nvlist_t *nvl, const nvpair_t *nvp)
1451{
1452	nvpair_t *newnvp;
1453
1454	NVPAIR_ASSERT(nvp);
1455
1456	if (nvlist_error(nvl) != 0) {
1457		ERRNO_SET(nvlist_error(nvl));
1458		return;
1459	}
1460	if ((nvl->nvl_flags & NV_FLAG_NO_UNIQUE) == 0) {
1461		if (nvlist_exists(nvl, nvpair_name(nvp))) {
1462			nvl->nvl_error = EEXIST;
1463			ERRNO_SET(nvlist_error(nvl));
1464			return;
1465		}
1466	}
1467
1468	newnvp = nvpair_clone(nvp);
1469	if (newnvp == NULL) {
1470		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1471		ERRNO_SET(nvlist_error(nvl));
1472		return;
1473	}
1474
1475	nvpair_insert(&nvl->nvl_head, newnvp, nvl);
1476}
1477
1478void
1479nvlist_add_stringf(nvlist_t *nvl, const char *name, const char *valuefmt, ...)
1480{
1481	va_list valueap;
1482
1483	va_start(valueap, valuefmt);
1484	nvlist_add_stringv(nvl, name, valuefmt, valueap);
1485	va_end(valueap);
1486}
1487
1488void
1489nvlist_add_stringv(nvlist_t *nvl, const char *name, const char *valuefmt,
1490    va_list valueap)
1491{
1492	nvpair_t *nvp;
1493
1494	if (nvlist_error(nvl) != 0) {
1495		ERRNO_SET(nvlist_error(nvl));
1496		return;
1497	}
1498
1499	nvp = nvpair_create_stringv(name, valuefmt, valueap);
1500	if (nvp == NULL) {
1501		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1502		ERRNO_SET(nvl->nvl_error);
1503	} else {
1504		(void)nvlist_move_nvpair(nvl, nvp);
1505	}
1506}
1507
1508void
1509nvlist_add_null(nvlist_t *nvl, const char *name)
1510{
1511	nvpair_t *nvp;
1512
1513	if (nvlist_error(nvl) != 0) {
1514		ERRNO_SET(nvlist_error(nvl));
1515		return;
1516	}
1517
1518	nvp = nvpair_create_null(name);
1519	if (nvp == NULL) {
1520		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1521		ERRNO_SET(nvl->nvl_error);
1522	} else {
1523		(void)nvlist_move_nvpair(nvl, nvp);
1524	}
1525}
1526
1527void
1528nvlist_add_binary(nvlist_t *nvl, const char *name, const void *value,
1529    size_t size)
1530{
1531	nvpair_t *nvp;
1532
1533	if (nvlist_error(nvl) != 0) {
1534		ERRNO_SET(nvlist_error(nvl));
1535		return;
1536	}
1537
1538	nvp = nvpair_create_binary(name, value, size);
1539	if (nvp == NULL) {
1540		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1541		ERRNO_SET(nvl->nvl_error);
1542	} else {
1543		(void)nvlist_move_nvpair(nvl, nvp);
1544	}
1545}
1546
1547
1548#define	NVLIST_ADD(vtype, type)						\
1549void									\
1550nvlist_add_##type(nvlist_t *nvl, const char *name, vtype value)		\
1551{									\
1552	nvpair_t *nvp;							\
1553									\
1554	if (nvlist_error(nvl) != 0) {					\
1555		ERRNO_SET(nvlist_error(nvl));				\
1556		return;							\
1557	}								\
1558									\
1559	nvp = nvpair_create_##type(name, value);			\
1560	if (nvp == NULL) {						\
1561		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);		\
1562		ERRNO_SET(nvl->nvl_error);				\
1563	} else {							\
1564		(void)nvlist_move_nvpair(nvl, nvp);			\
1565	}								\
1566}
1567
1568NVLIST_ADD(bool, bool)
1569NVLIST_ADD(uint64_t, number)
1570NVLIST_ADD(const char *, string)
1571NVLIST_ADD(const nvlist_t *, nvlist)
1572#ifndef _KERNEL
1573NVLIST_ADD(int, descriptor);
1574#endif
1575
1576#undef	NVLIST_ADD
1577
1578#define	NVLIST_ADD_ARRAY(vtype, type)					\
1579void									\
1580nvlist_add_##type##_array(nvlist_t *nvl, const char *name, vtype value,	\
1581    size_t nitems)							\
1582{									\
1583	nvpair_t *nvp;							\
1584									\
1585	if (nvlist_error(nvl) != 0) {					\
1586		ERRNO_SET(nvlist_error(nvl));				\
1587		return;							\
1588	}								\
1589									\
1590	nvp = nvpair_create_##type##_array(name, value, nitems);	\
1591	if (nvp == NULL) {						\
1592		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);		\
1593		ERRNO_SET(nvl->nvl_error);				\
1594	} else {							\
1595		(void)nvlist_move_nvpair(nvl, nvp);			\
1596	}								\
1597}
1598
1599NVLIST_ADD_ARRAY(const bool *, bool)
1600NVLIST_ADD_ARRAY(const uint64_t *, number)
1601NVLIST_ADD_ARRAY(const char * const *, string)
1602NVLIST_ADD_ARRAY(const nvlist_t * const *, nvlist)
1603#ifndef _KERNEL
1604NVLIST_ADD_ARRAY(const int *, descriptor)
1605#endif
1606
1607#undef	NVLIST_ADD_ARRAY
1608
1609#define	NVLIST_APPEND_ARRAY(vtype, type, TYPE)				\
1610void									\
1611nvlist_append_##type##_array(nvlist_t *nvl, const char *name, vtype value)\
1612{									\
1613	nvpair_t *nvp;							\
1614									\
1615	if (nvlist_error(nvl) != 0) {					\
1616		ERRNO_SET(nvlist_error(nvl));				\
1617		return;							\
1618	}								\
1619	nvp = nvlist_find(nvl, NV_TYPE_##TYPE##_ARRAY, name);		\
1620	if (nvp == NULL) {						\
1621		nvlist_add_##type##_array(nvl, name, &value, 1);	\
1622		return;							\
1623	}								\
1624	if (nvpair_append_##type##_array(nvp, value) == -1) {		\
1625		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);		\
1626		ERRNO_SET(nvl->nvl_error);				\
1627	}								\
1628}
1629
1630NVLIST_APPEND_ARRAY(const bool, bool, BOOL)
1631NVLIST_APPEND_ARRAY(const uint64_t, number, NUMBER)
1632NVLIST_APPEND_ARRAY(const char *, string, STRING)
1633NVLIST_APPEND_ARRAY(const nvlist_t *, nvlist, NVLIST)
1634#ifndef _KERNEL
1635NVLIST_APPEND_ARRAY(const int, descriptor, DESCRIPTOR)
1636#endif
1637
1638#undef	NVLIST_APPEND_ARRAY
1639
1640bool
1641nvlist_move_nvpair(nvlist_t *nvl, nvpair_t *nvp)
1642{
1643
1644	NVPAIR_ASSERT(nvp);
1645	PJDLOG_ASSERT(nvpair_nvlist(nvp) == NULL);
1646
1647	if (nvlist_error(nvl) != 0) {
1648		nvpair_free(nvp);
1649		ERRNO_SET(nvlist_error(nvl));
1650		return (false);
1651	}
1652	if ((nvl->nvl_flags & NV_FLAG_NO_UNIQUE) == 0) {
1653		if (nvlist_exists(nvl, nvpair_name(nvp))) {
1654			nvpair_free(nvp);
1655			nvl->nvl_error = EEXIST;
1656			ERRNO_SET(nvl->nvl_error);
1657			return (false);
1658		}
1659	}
1660
1661	nvpair_insert(&nvl->nvl_head, nvp, nvl);
1662	return (true);
1663}
1664
1665void
1666nvlist_move_string(nvlist_t *nvl, const char *name, char *value)
1667{
1668	nvpair_t *nvp;
1669
1670	if (nvlist_error(nvl) != 0) {
1671		nv_free(value);
1672		ERRNO_SET(nvlist_error(nvl));
1673		return;
1674	}
1675
1676	nvp = nvpair_move_string(name, value);
1677	if (nvp == NULL) {
1678		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1679		ERRNO_SET(nvl->nvl_error);
1680	} else {
1681		(void)nvlist_move_nvpair(nvl, nvp);
1682	}
1683}
1684
1685void
1686nvlist_move_nvlist(nvlist_t *nvl, const char *name, nvlist_t *value)
1687{
1688	nvpair_t *nvp;
1689
1690	if (nvlist_error(nvl) != 0) {
1691		if (value != NULL && nvlist_get_nvpair_parent(value) != NULL)
1692			nvlist_destroy(value);
1693		ERRNO_SET(nvlist_error(nvl));
1694		return;
1695	}
1696
1697	nvp = nvpair_move_nvlist(name, value);
1698	if (nvp == NULL) {
1699		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1700		ERRNO_SET(nvl->nvl_error);
1701	} else {
1702		(void)nvlist_move_nvpair(nvl, nvp);
1703	}
1704}
1705
1706#ifndef _KERNEL
1707void
1708nvlist_move_descriptor(nvlist_t *nvl, const char *name, int value)
1709{
1710	nvpair_t *nvp;
1711
1712	if (nvlist_error(nvl) != 0) {
1713		close(value);
1714		ERRNO_SET(nvlist_error(nvl));
1715		return;
1716	}
1717
1718	nvp = nvpair_move_descriptor(name, value);
1719	if (nvp == NULL) {
1720		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1721		ERRNO_SET(nvl->nvl_error);
1722	} else {
1723		(void)nvlist_move_nvpair(nvl, nvp);
1724	}
1725}
1726#endif
1727
1728void
1729nvlist_move_binary(nvlist_t *nvl, const char *name, void *value, size_t size)
1730{
1731	nvpair_t *nvp;
1732
1733	if (nvlist_error(nvl) != 0) {
1734		nv_free(value);
1735		ERRNO_SET(nvlist_error(nvl));
1736		return;
1737	}
1738
1739	nvp = nvpair_move_binary(name, value, size);
1740	if (nvp == NULL) {
1741		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1742		ERRNO_SET(nvl->nvl_error);
1743	} else {
1744		(void)nvlist_move_nvpair(nvl, nvp);
1745	}
1746}
1747
1748void
1749nvlist_move_bool_array(nvlist_t *nvl, const char *name, bool *value,
1750    size_t nitems)
1751{
1752	nvpair_t *nvp;
1753
1754	if (nvlist_error(nvl) != 0) {
1755		nv_free(value);
1756		ERRNO_SET(nvlist_error(nvl));
1757		return;
1758	}
1759
1760	nvp = nvpair_move_bool_array(name, value, nitems);
1761	if (nvp == NULL) {
1762		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1763		ERRNO_SET(nvl->nvl_error);
1764	} else {
1765		(void)nvlist_move_nvpair(nvl, nvp);
1766	}
1767}
1768
1769void
1770nvlist_move_string_array(nvlist_t *nvl, const char *name, char **value,
1771    size_t nitems)
1772{
1773	nvpair_t *nvp;
1774	size_t i;
1775
1776	if (nvlist_error(nvl) != 0) {
1777		if (value != NULL) {
1778			for (i = 0; i < nitems; i++)
1779				nv_free(value[i]);
1780			nv_free(value);
1781		}
1782		ERRNO_SET(nvlist_error(nvl));
1783		return;
1784	}
1785
1786	nvp = nvpair_move_string_array(name, value, nitems);
1787	if (nvp == NULL) {
1788		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1789		ERRNO_SET(nvl->nvl_error);
1790	} else {
1791		(void)nvlist_move_nvpair(nvl, nvp);
1792	}
1793}
1794
1795void
1796nvlist_move_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **value,
1797    size_t nitems)
1798{
1799	nvpair_t *nvp;
1800	size_t i;
1801
1802	if (nvlist_error(nvl) != 0) {
1803		if (value != NULL) {
1804			for (i = 0; i < nitems; i++) {
1805				if (nvlist_get_pararr(value[i], NULL) == NULL)
1806					nvlist_destroy(value[i]);
1807			}
1808		}
1809		nv_free(value);
1810		ERRNO_SET(nvlist_error(nvl));
1811		return;
1812	}
1813
1814	nvp = nvpair_move_nvlist_array(name, value, nitems);
1815	if (nvp == NULL) {
1816		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1817		ERRNO_SET(nvl->nvl_error);
1818	} else {
1819		(void)nvlist_move_nvpair(nvl, nvp);
1820	}
1821}
1822
1823void
1824nvlist_move_number_array(nvlist_t *nvl, const char *name, uint64_t *value,
1825    size_t nitems)
1826{
1827	nvpair_t *nvp;
1828
1829	if (nvlist_error(nvl) != 0) {
1830		nv_free(value);
1831		ERRNO_SET(nvlist_error(nvl));
1832		return;
1833	}
1834
1835	nvp = nvpair_move_number_array(name, value, nitems);
1836	if (nvp == NULL) {
1837		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1838		ERRNO_SET(nvl->nvl_error);
1839	} else {
1840		(void)nvlist_move_nvpair(nvl, nvp);
1841	}
1842}
1843
1844#ifndef _KERNEL
1845void
1846nvlist_move_descriptor_array(nvlist_t *nvl, const char *name, int *value,
1847    size_t nitems)
1848{
1849	nvpair_t *nvp;
1850	size_t i;
1851
1852	if (nvlist_error(nvl) != 0) {
1853		if (value != 0) {
1854			for (i = 0; i < nitems; i++)
1855				close(value[i]);
1856			nv_free(value);
1857		}
1858
1859		ERRNO_SET(nvlist_error(nvl));
1860		return;
1861	}
1862
1863	nvp = nvpair_move_descriptor_array(name, value, nitems);
1864	if (nvp == NULL) {
1865		nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1866		ERRNO_SET(nvl->nvl_error);
1867	} else {
1868		(void)nvlist_move_nvpair(nvl, nvp);
1869	}
1870}
1871#endif
1872
1873const nvpair_t *
1874nvlist_get_nvpair(const nvlist_t *nvl, const char *name)
1875{
1876
1877	return (nvlist_find(nvl, NV_TYPE_NONE, name));
1878}
1879
1880#define	NVLIST_GET(ftype, type, TYPE)					\
1881ftype									\
1882nvlist_get_##type(const nvlist_t *nvl, const char *name)		\
1883{									\
1884	const nvpair_t *nvp;						\
1885									\
1886	nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name);			\
1887	if (nvp == NULL)						\
1888		nvlist_report_missing(NV_TYPE_##TYPE, name);		\
1889	return (nvpair_get_##type(nvp));				\
1890}
1891
1892NVLIST_GET(bool, bool, BOOL)
1893NVLIST_GET(uint64_t, number, NUMBER)
1894NVLIST_GET(const char *, string, STRING)
1895NVLIST_GET(const nvlist_t *, nvlist, NVLIST)
1896#ifndef _KERNEL
1897NVLIST_GET(int, descriptor, DESCRIPTOR)
1898#endif
1899
1900#undef	NVLIST_GET
1901
1902const void *
1903nvlist_get_binary(const nvlist_t *nvl, const char *name, size_t *sizep)
1904{
1905	nvpair_t *nvp;
1906
1907	nvp = nvlist_find(nvl, NV_TYPE_BINARY, name);
1908	if (nvp == NULL)
1909		nvlist_report_missing(NV_TYPE_BINARY, name);
1910
1911	return (nvpair_get_binary(nvp, sizep));
1912}
1913
1914#define	NVLIST_GET_ARRAY(ftype, type, TYPE)				\
1915ftype									\
1916nvlist_get_##type##_array(const nvlist_t *nvl, const char *name,	\
1917    size_t *nitems)							\
1918{									\
1919	const nvpair_t *nvp;						\
1920									\
1921	nvp = nvlist_find(nvl, NV_TYPE_##TYPE##_ARRAY, name);		\
1922	if (nvp == NULL)						\
1923		nvlist_report_missing(NV_TYPE_##TYPE##_ARRAY, name);	\
1924	return (nvpair_get_##type##_array(nvp, nitems));		\
1925}
1926
1927NVLIST_GET_ARRAY(const bool *, bool, BOOL)
1928NVLIST_GET_ARRAY(const uint64_t *, number, NUMBER)
1929NVLIST_GET_ARRAY(const char * const *, string, STRING)
1930NVLIST_GET_ARRAY(const nvlist_t * const *, nvlist, NVLIST)
1931#ifndef _KERNEL
1932NVLIST_GET_ARRAY(const int *, descriptor, DESCRIPTOR)
1933#endif
1934
1935#undef	NVLIST_GET_ARRAY
1936
1937#define	NVLIST_TAKE(ftype, type, TYPE)					\
1938ftype									\
1939nvlist_take_##type(nvlist_t *nvl, const char *name)			\
1940{									\
1941	nvpair_t *nvp;							\
1942	ftype value;							\
1943									\
1944	nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name);			\
1945	if (nvp == NULL)						\
1946		nvlist_report_missing(NV_TYPE_##TYPE, name);		\
1947	value = (ftype)(intptr_t)nvpair_get_##type(nvp);		\
1948	nvlist_remove_nvpair(nvl, nvp);					\
1949	nvpair_free_structure(nvp);					\
1950	return (value);							\
1951}
1952
1953NVLIST_TAKE(bool, bool, BOOL)
1954NVLIST_TAKE(uint64_t, number, NUMBER)
1955NVLIST_TAKE(char *, string, STRING)
1956NVLIST_TAKE(nvlist_t *, nvlist, NVLIST)
1957#ifndef _KERNEL
1958NVLIST_TAKE(int, descriptor, DESCRIPTOR)
1959#endif
1960
1961#undef	NVLIST_TAKE
1962
1963void *
1964nvlist_take_binary(nvlist_t *nvl, const char *name, size_t *sizep)
1965{
1966	nvpair_t *nvp;
1967	void *value;
1968
1969	nvp = nvlist_find(nvl, NV_TYPE_BINARY, name);
1970	if (nvp == NULL)
1971		nvlist_report_missing(NV_TYPE_BINARY, name);
1972
1973	value = (void *)(intptr_t)nvpair_get_binary(nvp, sizep);
1974	nvlist_remove_nvpair(nvl, nvp);
1975	nvpair_free_structure(nvp);
1976	return (value);
1977}
1978
1979#define	NVLIST_TAKE_ARRAY(ftype, type, TYPE)				\
1980ftype									\
1981nvlist_take_##type##_array(nvlist_t *nvl, const char *name,		\
1982    size_t *nitems)							\
1983{									\
1984	nvpair_t *nvp;							\
1985	ftype value;							\
1986									\
1987	nvp = nvlist_find(nvl, NV_TYPE_##TYPE##_ARRAY, name);		\
1988	if (nvp == NULL)						\
1989		nvlist_report_missing(NV_TYPE_##TYPE##_ARRAY, name);	\
1990	value = (ftype)(intptr_t)nvpair_get_##type##_array(nvp, nitems);\
1991	nvlist_remove_nvpair(nvl, nvp);					\
1992	nvpair_free_structure(nvp);					\
1993	return (value);							\
1994}
1995
1996NVLIST_TAKE_ARRAY(bool *, bool, BOOL)
1997NVLIST_TAKE_ARRAY(uint64_t *, number, NUMBER)
1998NVLIST_TAKE_ARRAY(char **, string, STRING)
1999NVLIST_TAKE_ARRAY(nvlist_t **, nvlist, NVLIST)
2000#ifndef _KERNEL
2001NVLIST_TAKE_ARRAY(int *, descriptor, DESCRIPTOR)
2002#endif
2003
2004void
2005nvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp)
2006{
2007
2008	NVLIST_ASSERT(nvl);
2009	NVPAIR_ASSERT(nvp);
2010	PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
2011
2012	nvpair_remove(&nvl->nvl_head, nvp, nvl);
2013}
2014
2015void
2016nvlist_free(nvlist_t *nvl, const char *name)
2017{
2018
2019	nvlist_free_type(nvl, name, NV_TYPE_NONE);
2020}
2021
2022#define	NVLIST_FREE(type, TYPE)						\
2023void									\
2024nvlist_free_##type(nvlist_t *nvl, const char *name)			\
2025{									\
2026									\
2027	nvlist_free_type(nvl, name, NV_TYPE_##TYPE);			\
2028}
2029
2030NVLIST_FREE(null, NULL)
2031NVLIST_FREE(bool, BOOL)
2032NVLIST_FREE(number, NUMBER)
2033NVLIST_FREE(string, STRING)
2034NVLIST_FREE(nvlist, NVLIST)
2035NVLIST_FREE(binary, BINARY)
2036NVLIST_FREE(bool_array, BOOL_ARRAY)
2037NVLIST_FREE(number_array, NUMBER_ARRAY)
2038NVLIST_FREE(string_array, STRING_ARRAY)
2039NVLIST_FREE(nvlist_array, NVLIST_ARRAY)
2040#ifndef _KERNEL
2041NVLIST_FREE(descriptor, DESCRIPTOR)
2042NVLIST_FREE(descriptor_array, DESCRIPTOR_ARRAY)
2043#endif
2044
2045#undef	NVLIST_FREE
2046
2047void
2048nvlist_free_nvpair(nvlist_t *nvl, nvpair_t *nvp)
2049{
2050
2051	NVLIST_ASSERT(nvl);
2052	NVPAIR_ASSERT(nvp);
2053	PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
2054
2055	nvlist_remove_nvpair(nvl, nvp);
2056	nvpair_free(nvp);
2057}
2058
2059