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