subr_nvpair.c revision 258065
1/*-
2 * Copyright (c) 2009-2013 The FreeBSD Foundation
3 * All rights reserved.
4 *
5 * This software was developed by Pawel Jakub Dawidek under sponsorship from
6 * the FreeBSD Foundation.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: head/lib/libnv/nvpair.c 258065 2013-11-12 19:39:14Z pjd $");
32
33#include <sys/param.h>
34#include <sys/endian.h>
35#include <sys/queue.h>
36
37#include <errno.h>
38#include <fcntl.h>
39#include <stdarg.h>
40#include <stdbool.h>
41#include <stdint.h>
42#include <stdlib.h>
43#include <string.h>
44#include <unistd.h>
45
46#ifdef HAVE_PJDLOG
47#include <pjdlog.h>
48#endif
49
50#include "common_impl.h"
51#include "nv.h"
52#include "nv_impl.h"
53#include "nvlist_impl.h"
54#include "nvpair_impl.h"
55
56#ifndef	HAVE_PJDLOG
57#include <assert.h>
58#define	PJDLOG_ASSERT(...)		assert(__VA_ARGS__)
59#define	PJDLOG_RASSERT(expr, ...)	assert(expr)
60#define	PJDLOG_ABORT(...)		abort()
61#endif
62
63#define	NVPAIR_MAGIC	0x6e7670	/* "nvp" */
64struct nvpair {
65	int		 nvp_magic;
66	char		*nvp_name;
67	int		 nvp_type;
68	uint64_t	 nvp_data;
69	size_t		 nvp_datasize;
70	nvlist_t	*nvp_list;	/* Used for sanity checks. */
71	TAILQ_ENTRY(nvpair) nvp_next;
72};
73
74#define	NVPAIR_ASSERT(nvp)	do {					\
75	PJDLOG_ASSERT((nvp) != NULL);					\
76	PJDLOG_ASSERT((nvp)->nvp_magic == NVPAIR_MAGIC);		\
77} while (0)
78
79struct nvpair_header {
80	uint8_t		nvph_type;
81	uint16_t	nvph_namesize;
82	uint64_t	nvph_datasize;
83} __packed;
84
85
86void
87nvpair_assert(const nvpair_t *nvp)
88{
89
90	NVPAIR_ASSERT(nvp);
91}
92
93const nvlist_t *
94nvpair_nvlist(const nvpair_t *nvp)
95{
96
97	NVPAIR_ASSERT(nvp);
98
99	return (nvp->nvp_list);
100}
101
102nvpair_t *
103nvpair_next(const nvpair_t *nvp)
104{
105
106	NVPAIR_ASSERT(nvp);
107	PJDLOG_ASSERT(nvp->nvp_list != NULL);
108
109	return (TAILQ_NEXT(nvp, nvp_next));
110}
111
112nvpair_t *
113nvpair_prev(const nvpair_t *nvp)
114{
115
116	NVPAIR_ASSERT(nvp);
117	PJDLOG_ASSERT(nvp->nvp_list != NULL);
118
119	return (TAILQ_PREV(nvp, nvl_head, nvp_next));
120}
121
122void
123nvpair_insert(struct nvl_head *head, nvpair_t *nvp, nvlist_t *nvl)
124{
125
126	NVPAIR_ASSERT(nvp);
127	PJDLOG_ASSERT(nvp->nvp_list == NULL);
128	PJDLOG_ASSERT(!nvlist_exists(nvl, nvpair_name(nvp)));
129
130	TAILQ_INSERT_TAIL(head, nvp, nvp_next);
131	nvp->nvp_list = nvl;
132}
133
134void
135nvpair_remove(struct nvl_head *head, nvpair_t *nvp, const nvlist_t *nvl)
136{
137
138	NVPAIR_ASSERT(nvp);
139	PJDLOG_ASSERT(nvp->nvp_list == nvl);
140
141	TAILQ_REMOVE(head, nvp, nvp_next);
142	nvp->nvp_list = NULL;
143}
144
145nvpair_t *
146nvpair_clone(const nvpair_t *nvp)
147{
148	nvpair_t *newnvp;
149	const char *name;
150	const void *data;
151	size_t datasize;
152
153	NVPAIR_ASSERT(nvp);
154
155	name = nvpair_name(nvp);
156
157	switch (nvpair_type(nvp)) {
158	case NV_TYPE_NULL:
159		newnvp = nvpair_create_null(name);
160		break;
161	case NV_TYPE_BOOL:
162		newnvp = nvpair_create_bool(name, nvpair_get_bool(nvp));
163		break;
164	case NV_TYPE_NUMBER:
165		newnvp = nvpair_create_number(name, nvpair_get_number(nvp));
166		break;
167	case NV_TYPE_STRING:
168		newnvp = nvpair_create_string(name, nvpair_get_string(nvp));
169		break;
170	case NV_TYPE_NVLIST:
171		newnvp = nvpair_create_nvlist(name, nvpair_get_nvlist(nvp));
172		break;
173	case NV_TYPE_DESCRIPTOR:
174		newnvp = nvpair_create_descriptor(name,
175		    nvpair_get_descriptor(nvp));
176		break;
177	case NV_TYPE_BINARY:
178		data = nvpair_get_binary(nvp, &datasize);
179		newnvp = nvpair_create_binary(name, data, datasize);
180		break;
181	default:
182		PJDLOG_ABORT("Unknown type: %d.", nvpair_type(nvp));
183	}
184
185	return (newnvp);
186}
187
188size_t
189nvpair_header_size(void)
190{
191
192	return (sizeof(struct nvpair_header));
193}
194
195size_t
196nvpair_size(const nvpair_t *nvp)
197{
198
199	NVPAIR_ASSERT(nvp);
200
201	return (nvp->nvp_datasize);
202}
203
204static unsigned char *
205nvpair_pack_header(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
206{
207	struct nvpair_header nvphdr;
208	size_t namesize;
209
210	NVPAIR_ASSERT(nvp);
211
212	nvphdr.nvph_type = nvp->nvp_type;
213	namesize = strlen(nvp->nvp_name) + 1;
214	PJDLOG_ASSERT(namesize > 0 && namesize <= UINT16_MAX);
215	nvphdr.nvph_namesize = namesize;
216	nvphdr.nvph_datasize = nvp->nvp_datasize;
217	PJDLOG_ASSERT(*leftp >= sizeof(nvphdr));
218	memcpy(ptr, &nvphdr, sizeof(nvphdr));
219	ptr += sizeof(nvphdr);
220	*leftp -= sizeof(nvphdr);
221
222	PJDLOG_ASSERT(*leftp >= namesize);
223	memcpy(ptr, nvp->nvp_name, namesize);
224	ptr += namesize;
225	*leftp -= namesize;
226
227	return (ptr);
228}
229
230static unsigned char *
231nvpair_pack_null(const nvpair_t *nvp, unsigned char *ptr,
232    size_t *leftp __unused)
233{
234
235	NVPAIR_ASSERT(nvp);
236	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NULL);
237
238	return (ptr);
239}
240
241static unsigned char *
242nvpair_pack_bool(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
243{
244	uint8_t value;
245
246	NVPAIR_ASSERT(nvp);
247	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL);
248
249	value = (uint8_t)nvp->nvp_data;
250
251	PJDLOG_ASSERT(*leftp >= sizeof(value));
252	memcpy(ptr, &value, sizeof(value));
253	ptr += sizeof(value);
254	*leftp -= sizeof(value);
255
256	return (ptr);
257}
258
259static unsigned char *
260nvpair_pack_number(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
261{
262	uint64_t value;
263
264	NVPAIR_ASSERT(nvp);
265	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER);
266
267	value = (uint64_t)nvp->nvp_data;
268
269	PJDLOG_ASSERT(*leftp >= sizeof(value));
270	memcpy(ptr, &value, sizeof(value));
271	ptr += sizeof(value);
272	*leftp -= sizeof(value);
273
274	return (ptr);
275}
276
277static unsigned char *
278nvpair_pack_string(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
279{
280
281	NVPAIR_ASSERT(nvp);
282	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
283
284	PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
285	memcpy(ptr, (const void *)(intptr_t)nvp->nvp_data, nvp->nvp_datasize);
286	ptr += nvp->nvp_datasize;
287	*leftp -= nvp->nvp_datasize;
288
289	return (ptr);
290}
291
292static unsigned char *
293nvpair_pack_nvlist(const nvpair_t *nvp, unsigned char *ptr, int64_t *fdidxp,
294    size_t *leftp)
295{
296	unsigned char *data;
297	size_t size;
298
299	NVPAIR_ASSERT(nvp);
300	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST);
301
302	if (nvp->nvp_datasize == 0)
303		return (ptr);
304
305	data = nvlist_xpack((const nvlist_t *)(intptr_t)nvp->nvp_data, fdidxp,
306	    &size);
307	if (data == NULL)
308		return (NULL);
309
310	PJDLOG_ASSERT(size == nvp->nvp_datasize);
311	PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
312
313	memcpy(ptr, data, nvp->nvp_datasize);
314	free(data);
315
316	ptr += nvp->nvp_datasize;
317	*leftp -= nvp->nvp_datasize;
318
319	return (ptr);
320}
321
322static unsigned char *
323nvpair_pack_descriptor(const nvpair_t *nvp, unsigned char *ptr, int64_t *fdidxp,
324    size_t *leftp)
325{
326	int64_t value;
327
328	NVPAIR_ASSERT(nvp);
329	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
330
331	value = (int64_t)nvp->nvp_data;
332	if (value != -1) {
333		/*
334		 * If there is a real descriptor here, we change its number
335		 * to position in the array of descriptors send via control
336		 * message.
337		 */
338		PJDLOG_ASSERT(fdidxp != NULL);
339
340		value = *fdidxp;
341		(*fdidxp)++;
342	}
343
344	PJDLOG_ASSERT(*leftp >= sizeof(value));
345	memcpy(ptr, &value, sizeof(value));
346	ptr += sizeof(value);
347	*leftp -= sizeof(value);
348
349	return (ptr);
350}
351
352static unsigned char *
353nvpair_pack_binary(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
354{
355
356	NVPAIR_ASSERT(nvp);
357	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
358
359	PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
360	memcpy(ptr, (const void *)(intptr_t)nvp->nvp_data, nvp->nvp_datasize);
361	ptr += nvp->nvp_datasize;
362	*leftp -= nvp->nvp_datasize;
363
364	return (ptr);
365}
366
367unsigned char *
368nvpair_pack(nvpair_t *nvp, unsigned char *ptr, int64_t *fdidxp, size_t *leftp)
369{
370
371	NVPAIR_ASSERT(nvp);
372
373	/*
374	 * We have to update datasize for NV_TYPE_NVLIST on every pack,
375	 * so that proper datasize is placed into nvpair_header
376	 * during the nvpair_pack_header() call below.
377	 */
378	if (nvp->nvp_type == NV_TYPE_NVLIST) {
379		if (nvp->nvp_data == 0) {
380			nvp->nvp_datasize = 0;
381		} else {
382			nvp->nvp_datasize =
383			    nvlist_size((const nvlist_t *)(intptr_t)nvp->nvp_data);
384		}
385	}
386
387	ptr = nvpair_pack_header(nvp, ptr, leftp);
388	if (ptr == NULL)
389		return (NULL);
390
391	switch (nvp->nvp_type) {
392	case NV_TYPE_NULL:
393		ptr = nvpair_pack_null(nvp, ptr, leftp);
394		break;
395	case NV_TYPE_BOOL:
396		ptr = nvpair_pack_bool(nvp, ptr, leftp);
397		break;
398	case NV_TYPE_NUMBER:
399		ptr = nvpair_pack_number(nvp, ptr, leftp);
400		break;
401	case NV_TYPE_STRING:
402		ptr = nvpair_pack_string(nvp, ptr, leftp);
403		break;
404	case NV_TYPE_NVLIST:
405		ptr = nvpair_pack_nvlist(nvp, ptr, fdidxp, leftp);
406		break;
407	case NV_TYPE_DESCRIPTOR:
408		ptr = nvpair_pack_descriptor(nvp, ptr, fdidxp, leftp);
409		break;
410	case NV_TYPE_BINARY:
411		ptr = nvpair_pack_binary(nvp, ptr, leftp);
412		break;
413	default:
414		PJDLOG_ABORT("Invalid type (%d).", nvp->nvp_type);
415	}
416
417	return (ptr);
418}
419
420static const unsigned char *
421nvpair_unpack_header(int flags, nvpair_t *nvp, const unsigned char *ptr,
422    size_t *leftp)
423{
424	struct nvpair_header nvphdr;
425
426	if (*leftp < sizeof(nvphdr))
427		goto failed;
428
429	memcpy(&nvphdr, ptr, sizeof(nvphdr));
430	ptr += sizeof(nvphdr);
431	*leftp -= sizeof(nvphdr);
432
433#if NV_TYPE_FIRST > 0
434	if (nvphdr.nvph_type < NV_TYPE_FIRST)
435		goto failed;
436#endif
437	if (nvphdr.nvph_type > NV_TYPE_LAST)
438		goto failed;
439
440#if BYTE_ORDER == BIG_ENDIAN
441	if ((flags & NV_FLAG_BIG_ENDIAN) == 0) {
442		nvphdr.nvph_namesize = le16toh(nvphdr.nvph_namesize);
443		nvphdr.nvph_datasize = le64toh(nvphdr.nvph_datasize);
444	}
445#else
446	if ((flags & NV_FLAG_BIG_ENDIAN) != 0) {
447		nvphdr.nvph_namesize = be16toh(nvphdr.nvph_namesize);
448		nvphdr.nvph_datasize = be64toh(nvphdr.nvph_datasize);
449	}
450#endif
451
452	if (nvphdr.nvph_namesize > NV_NAME_MAX)
453		goto failed;
454	if (*leftp < nvphdr.nvph_namesize)
455		goto failed;
456	if (nvphdr.nvph_namesize < 1)
457		goto failed;
458	if (strnlen((const char *)ptr, nvphdr.nvph_namesize) !=
459	    (size_t)(nvphdr.nvph_namesize - 1)) {
460		goto failed;
461	}
462
463	memcpy(nvp->nvp_name, ptr, nvphdr.nvph_namesize);
464	ptr += nvphdr.nvph_namesize;
465	*leftp -= nvphdr.nvph_namesize;
466
467	if (*leftp < nvphdr.nvph_datasize)
468		goto failed;
469
470	nvp->nvp_type = nvphdr.nvph_type;
471	nvp->nvp_data = 0;
472	nvp->nvp_datasize = nvphdr.nvph_datasize;
473
474	return (ptr);
475failed:
476	errno = EINVAL;
477	return (NULL);
478}
479
480static const unsigned char *
481nvpair_unpack_null(int flags __unused, nvpair_t *nvp, const unsigned char *ptr,
482    size_t *leftp __unused)
483{
484
485	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NULL);
486
487	if (nvp->nvp_datasize != 0) {
488		errno = EINVAL;
489		return (NULL);
490	}
491
492	return (ptr);
493}
494
495static const unsigned char *
496nvpair_unpack_bool(int flags __unused, nvpair_t *nvp, const unsigned char *ptr,
497    size_t *leftp)
498{
499	uint8_t value;
500
501	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL);
502
503	if (nvp->nvp_datasize != sizeof(value)) {
504		errno = EINVAL;
505		return (NULL);
506	}
507	if (*leftp < sizeof(value)) {
508		errno = EINVAL;
509		return (NULL);
510	}
511
512	memcpy(&value, ptr, sizeof(value));
513	ptr += sizeof(value);
514	*leftp -= sizeof(value);
515
516	if (value != 0 && value != 1) {
517		errno = EINVAL;
518		return (NULL);
519	}
520
521	nvp->nvp_data = (uint64_t)value;
522
523	return (ptr);
524}
525
526static const unsigned char *
527nvpair_unpack_number(int flags, nvpair_t *nvp, const unsigned char *ptr,
528    size_t *leftp)
529{
530
531	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER);
532
533	if (nvp->nvp_datasize != sizeof(uint64_t)) {
534		errno = EINVAL;
535		return (NULL);
536	}
537	if (*leftp < sizeof(uint64_t)) {
538		errno = EINVAL;
539		return (NULL);
540	}
541
542	if ((flags & NV_FLAG_BIG_ENDIAN) != 0)
543		nvp->nvp_data = be64dec(ptr);
544	else
545		nvp->nvp_data = le64dec(ptr);
546	ptr += sizeof(uint64_t);
547	*leftp -= sizeof(uint64_t);
548
549	return (ptr);
550}
551
552static const unsigned char *
553nvpair_unpack_string(int flags __unused, nvpair_t *nvp,
554    const unsigned char *ptr, size_t *leftp)
555{
556
557	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
558
559	if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
560		errno = EINVAL;
561		return (NULL);
562	}
563
564	if (strnlen((const char *)ptr, nvp->nvp_datasize) !=
565	    nvp->nvp_datasize - 1) {
566		errno = EINVAL;
567		return (NULL);
568	}
569
570	nvp->nvp_data = (uint64_t)(uintptr_t)strdup((const char *)ptr);
571	if (nvp->nvp_data == 0)
572		return (NULL);
573
574	ptr += nvp->nvp_datasize;
575	*leftp -= nvp->nvp_datasize;
576
577	return (ptr);
578}
579
580static const unsigned char *
581nvpair_unpack_nvlist(int flags __unused, nvpair_t *nvp,
582    const unsigned char *ptr, size_t *leftp, const int *fds, size_t nfds)
583{
584	nvlist_t *value;
585
586	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST);
587
588	if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
589		errno = EINVAL;
590		return (NULL);
591	}
592
593	value = nvlist_xunpack(ptr, nvp->nvp_datasize, fds, nfds);
594	if (value == NULL)
595		return (NULL);
596
597	nvp->nvp_data = (uint64_t)(uintptr_t)value;
598
599	ptr += nvp->nvp_datasize;
600	*leftp -= nvp->nvp_datasize;
601
602	return (ptr);
603}
604
605static const unsigned char *
606nvpair_unpack_descriptor(int flags, nvpair_t *nvp, const unsigned char *ptr,
607    size_t *leftp, const int *fds, size_t nfds)
608{
609	int64_t idx;
610
611	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
612
613	if (nvp->nvp_datasize != sizeof(idx)) {
614		errno = EINVAL;
615		return (NULL);
616	}
617	if (*leftp < sizeof(idx)) {
618		errno = EINVAL;
619		return (NULL);
620	}
621
622	if ((flags & NV_FLAG_BIG_ENDIAN) != 0)
623		idx = be64dec(ptr);
624	else
625		idx = le64dec(ptr);
626
627	if (idx < 0) {
628		errno = EINVAL;
629		return (NULL);
630	}
631
632	if ((size_t)idx >= nfds) {
633		errno = EINVAL;
634		return (NULL);
635	}
636
637	nvp->nvp_data = (uint64_t)fds[idx];
638
639	ptr += sizeof(idx);
640	*leftp -= sizeof(idx);
641
642	return (ptr);
643}
644
645static const unsigned char *
646nvpair_unpack_binary(int flags __unused, nvpair_t *nvp,
647    const unsigned char *ptr, size_t *leftp)
648{
649	void *value;
650
651	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
652
653	if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
654		errno = EINVAL;
655		return (NULL);
656	}
657
658	value = malloc(nvp->nvp_datasize);
659	if (value == NULL)
660		return (NULL);
661
662	memcpy(value, ptr, nvp->nvp_datasize);
663	ptr += nvp->nvp_datasize;
664	*leftp -= nvp->nvp_datasize;
665
666	nvp->nvp_data = (uint64_t)(uintptr_t)value;
667
668	return (ptr);
669}
670
671const unsigned char *
672nvpair_unpack(int flags, const unsigned char *ptr, size_t *leftp,
673    const int *fds, size_t nfds, nvpair_t **nvpp)
674{
675	nvpair_t *nvp, *tmp;
676
677	nvp = calloc(1, sizeof(*nvp) + NV_NAME_MAX);
678	if (nvp == NULL)
679		return (NULL);
680	nvp->nvp_name = (char *)(nvp + 1);
681
682	ptr = nvpair_unpack_header(flags, nvp, ptr, leftp);
683	if (ptr == NULL)
684		goto failed;
685	tmp = realloc(nvp, sizeof(*nvp) + strlen(nvp->nvp_name) + 1);
686	if (tmp == NULL) {
687		free(nvp);
688		goto failed;
689	}
690	nvp = tmp;
691	/* Update nvp_name after realloc(). */
692	nvp->nvp_name = (char *)(nvp + 1);
693
694	switch (nvp->nvp_type) {
695	case NV_TYPE_NULL:
696		ptr = nvpair_unpack_null(flags, nvp, ptr, leftp);
697		break;
698	case NV_TYPE_BOOL:
699		ptr = nvpair_unpack_bool(flags, nvp, ptr, leftp);
700		break;
701	case NV_TYPE_NUMBER:
702		ptr = nvpair_unpack_number(flags, nvp, ptr, leftp);
703		break;
704	case NV_TYPE_STRING:
705		ptr = nvpair_unpack_string(flags, nvp, ptr, leftp);
706		break;
707	case NV_TYPE_NVLIST:
708		ptr = nvpair_unpack_nvlist(flags, nvp, ptr, leftp, fds,
709		    nfds);
710		break;
711	case NV_TYPE_DESCRIPTOR:
712		ptr = nvpair_unpack_descriptor(flags, nvp, ptr, leftp, fds,
713		    nfds);
714		break;
715	case NV_TYPE_BINARY:
716		ptr = nvpair_unpack_binary(flags, nvp, ptr, leftp);
717		break;
718	default:
719		PJDLOG_ABORT("Invalid type (%d).", nvp->nvp_type);
720	}
721
722	if (ptr == NULL)
723		goto failed;
724
725	nvp->nvp_magic = NVPAIR_MAGIC;
726	*nvpp = nvp;
727	return (ptr);
728failed:
729	free(nvp);
730	return (NULL);
731}
732
733int
734nvpair_type(const nvpair_t *nvp)
735{
736
737	NVPAIR_ASSERT(nvp);
738
739	return (nvp->nvp_type);
740}
741
742const char *
743nvpair_name(const nvpair_t *nvp)
744{
745
746	NVPAIR_ASSERT(nvp);
747
748	return (nvp->nvp_name);
749}
750
751static nvpair_t *
752nvpair_allocv(int type, uint64_t data, size_t datasize, const char *namefmt,
753    va_list nameap)
754{
755	nvpair_t *nvp;
756	char *name;
757	int namelen;
758
759	PJDLOG_ASSERT(type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST);
760
761	namelen = vasprintf(&name, namefmt, nameap);
762	if (namelen < 0)
763		return (NULL);
764
765	PJDLOG_ASSERT(namelen > 0);
766	if (namelen >= NV_NAME_MAX) {
767		free(name);
768		errno = ENAMETOOLONG;
769		return (NULL);
770	}
771
772	nvp = calloc(1, sizeof(*nvp) + namelen + 1);
773	if (nvp != NULL) {
774		nvp->nvp_name = (char *)(nvp + 1);
775		memcpy(nvp->nvp_name, name, namelen + 1);
776		nvp->nvp_type = type;
777		nvp->nvp_data = data;
778		nvp->nvp_datasize = datasize;
779		nvp->nvp_magic = NVPAIR_MAGIC;
780	}
781	free(name);
782
783	return (nvp);
784};
785
786nvpair_t *
787nvpair_create_null(const char *name)
788{
789
790	return (nvpair_createf_null("%s", name));
791}
792
793nvpair_t *
794nvpair_create_bool(const char *name, bool value)
795{
796
797	return (nvpair_createf_bool(value, "%s", name));
798}
799
800nvpair_t *
801nvpair_create_number(const char *name, uint64_t value)
802{
803
804	return (nvpair_createf_number(value, "%s", name));
805}
806
807nvpair_t *
808nvpair_create_string(const char *name, const char *value)
809{
810
811	return (nvpair_createf_string(value, "%s", name));
812}
813
814nvpair_t *
815nvpair_create_stringf(const char *name, const char *valuefmt, ...)
816{
817	va_list valueap;
818	nvpair_t *nvp;
819
820	va_start(valueap, valuefmt);
821	nvp = nvpair_create_stringv(name, valuefmt, valueap);
822	va_end(valueap);
823
824	return (nvp);
825}
826
827nvpair_t *
828nvpair_create_stringv(const char *name, const char *valuefmt, va_list valueap)
829{
830	nvpair_t *nvp;
831	char *str;
832	int len;
833
834	len = vasprintf(&str, valuefmt, valueap);
835	if (len < 0)
836		return (NULL);
837	nvp = nvpair_create_string(name, str);
838	if (nvp == NULL)
839		free(str);
840	return (nvp);
841}
842
843nvpair_t *
844nvpair_create_nvlist(const char *name, const nvlist_t *value)
845{
846
847	return (nvpair_createf_nvlist(value, "%s", name));
848}
849
850nvpair_t *
851nvpair_create_descriptor(const char *name, int value)
852{
853
854	return (nvpair_createf_descriptor(value, "%s", name));
855}
856
857nvpair_t *
858nvpair_create_binary(const char *name, const void *value, size_t size)
859{
860
861	return (nvpair_createf_binary(value, size, "%s", name));
862}
863
864nvpair_t *
865nvpair_createf_null(const char *namefmt, ...)
866{
867	va_list nameap;
868	nvpair_t *nvp;
869
870	va_start(nameap, namefmt);
871	nvp = nvpair_createv_null(namefmt, nameap);
872	va_end(nameap);
873
874	return (nvp);
875}
876
877nvpair_t *
878nvpair_createf_bool(bool value, const char *namefmt, ...)
879{
880	va_list nameap;
881	nvpair_t *nvp;
882
883	va_start(nameap, namefmt);
884	nvp = nvpair_createv_bool(value, namefmt, nameap);
885	va_end(nameap);
886
887	return (nvp);
888}
889
890nvpair_t *
891nvpair_createf_number(uint64_t value, const char *namefmt, ...)
892{
893	va_list nameap;
894	nvpair_t *nvp;
895
896	va_start(nameap, namefmt);
897	nvp = nvpair_createv_number(value, namefmt, nameap);
898	va_end(nameap);
899
900	return (nvp);
901}
902
903nvpair_t *
904nvpair_createf_string(const char *value, const char *namefmt, ...)
905{
906	va_list nameap;
907	nvpair_t *nvp;
908
909	va_start(nameap, namefmt);
910	nvp = nvpair_createv_string(value, namefmt, nameap);
911	va_end(nameap);
912
913	return (nvp);
914}
915
916nvpair_t *
917nvpair_createf_nvlist(const nvlist_t *value, const char *namefmt, ...)
918{
919	va_list nameap;
920	nvpair_t *nvp;
921
922	va_start(nameap, namefmt);
923	nvp = nvpair_createv_nvlist(value, namefmt, nameap);
924	va_end(nameap);
925
926	return (nvp);
927}
928
929nvpair_t *
930nvpair_createf_descriptor(int value, const char *namefmt, ...)
931{
932	va_list nameap;
933	nvpair_t *nvp;
934
935	va_start(nameap, namefmt);
936	nvp = nvpair_createv_descriptor(value, namefmt, nameap);
937	va_end(nameap);
938
939	return (nvp);
940}
941
942nvpair_t *
943nvpair_createf_binary(const void *value, size_t size, const char *namefmt, ...)
944{
945	va_list nameap;
946	nvpair_t *nvp;
947
948	va_start(nameap, namefmt);
949	nvp = nvpair_createv_binary(value, size, namefmt, nameap);
950	va_end(nameap);
951
952	return (nvp);
953}
954
955nvpair_t *
956nvpair_createv_null(const char *namefmt, va_list nameap)
957{
958
959	return (nvpair_allocv(NV_TYPE_NULL, 0, 0, namefmt, nameap));
960}
961
962nvpair_t *
963nvpair_createv_bool(bool value, const char *namefmt, va_list nameap)
964{
965
966	return (nvpair_allocv(NV_TYPE_BOOL, value ? 1 : 0, sizeof(uint8_t),
967	    namefmt, nameap));
968}
969
970nvpair_t *
971nvpair_createv_number(uint64_t value, const char *namefmt, va_list nameap)
972{
973
974	return (nvpair_allocv(NV_TYPE_NUMBER, value, sizeof(value), namefmt,
975	    nameap));
976}
977
978nvpair_t *
979nvpair_createv_string(const char *value, const char *namefmt, va_list nameap)
980{
981	nvpair_t *nvp;
982	size_t size;
983	char *data;
984
985	if (value == NULL) {
986		errno = EINVAL;
987		return (NULL);
988	}
989
990	data = strdup(value);
991	if (data == NULL)
992		return (NULL);
993	size = strlen(value) + 1;
994
995	nvp = nvpair_allocv(NV_TYPE_STRING, (uint64_t)(uintptr_t)data, size,
996	    namefmt, nameap);
997	if (nvp == NULL)
998		free(data);
999
1000	return (nvp);
1001}
1002
1003nvpair_t *
1004nvpair_createv_nvlist(const nvlist_t *value, const char *namefmt,
1005    va_list nameap)
1006{
1007	nvlist_t *nvl;
1008	nvpair_t *nvp;
1009
1010	if (value == NULL) {
1011		errno = EINVAL;
1012		return (NULL);
1013	}
1014
1015	nvl = nvlist_clone(value);
1016	if (nvl == NULL)
1017		return (NULL);
1018
1019	nvp = nvpair_allocv(NV_TYPE_NVLIST, (uint64_t)(uintptr_t)nvl, 0,
1020	    namefmt, nameap);
1021	if (nvp == NULL)
1022		nvlist_destroy(nvl);
1023
1024	return (nvp);
1025}
1026
1027nvpair_t *
1028nvpair_createv_descriptor(int value, const char *namefmt, va_list nameap)
1029{
1030	nvpair_t *nvp;
1031
1032	if (value < 0 || !fd_is_valid(value)) {
1033		errno = EBADF;
1034		return (NULL);
1035	}
1036
1037	value = fcntl(value, F_DUPFD_CLOEXEC, 0);
1038	if (value < 0)
1039		return (NULL);
1040
1041	nvp = nvpair_allocv(NV_TYPE_DESCRIPTOR, (uint64_t)value,
1042	    sizeof(int64_t), namefmt, nameap);
1043	if (nvp == NULL)
1044		close(value);
1045
1046	return (nvp);
1047}
1048
1049nvpair_t *
1050nvpair_createv_binary(const void *value, size_t size, const char *namefmt,
1051    va_list nameap)
1052{
1053	nvpair_t *nvp;
1054	void *data;
1055
1056	if (value == NULL || size == 0) {
1057		errno = EINVAL;
1058		return (NULL);
1059	}
1060
1061	data = malloc(size);
1062	if (data == NULL)
1063		return (NULL);
1064	memcpy(data, value, size);
1065
1066	nvp = nvpair_allocv(NV_TYPE_BINARY, (uint64_t)(uintptr_t)data, size,
1067	    namefmt, nameap);
1068	if (nvp == NULL)
1069		free(data);
1070
1071	return (nvp);
1072}
1073
1074nvpair_t *
1075nvpair_move_string(const char *name, char *value)
1076{
1077
1078	return (nvpair_movef_string(value, "%s", name));
1079}
1080
1081nvpair_t *
1082nvpair_move_nvlist(const char *name, nvlist_t *value)
1083{
1084
1085	return (nvpair_movef_nvlist(value, "%s", name));
1086}
1087
1088nvpair_t *
1089nvpair_move_descriptor(const char *name, int value)
1090{
1091
1092	return (nvpair_movef_descriptor(value, "%s", name));
1093}
1094
1095nvpair_t *
1096nvpair_move_binary(const char *name, void *value, size_t size)
1097{
1098
1099	return (nvpair_movef_binary(value, size, "%s", name));
1100}
1101
1102nvpair_t *
1103nvpair_movef_string(char *value, const char *namefmt, ...)
1104{
1105	va_list nameap;
1106	nvpair_t *nvp;
1107
1108	va_start(nameap, namefmt);
1109	nvp = nvpair_movev_string(value, namefmt, nameap);
1110	va_end(nameap);
1111
1112	return (nvp);
1113}
1114
1115nvpair_t *
1116nvpair_movef_nvlist(nvlist_t *value, const char *namefmt, ...)
1117{
1118	va_list nameap;
1119	nvpair_t *nvp;
1120
1121	va_start(nameap, namefmt);
1122	nvp = nvpair_movev_nvlist(value, namefmt, nameap);
1123	va_end(nameap);
1124
1125	return (nvp);
1126}
1127
1128nvpair_t *
1129nvpair_movef_descriptor(int value, const char *namefmt, ...)
1130{
1131	va_list nameap;
1132	nvpair_t *nvp;
1133
1134	va_start(nameap, namefmt);
1135	nvp = nvpair_movev_descriptor(value, namefmt, nameap);
1136	va_end(nameap);
1137
1138	return (nvp);
1139}
1140
1141nvpair_t *
1142nvpair_movef_binary(void *value, size_t size, const char *namefmt, ...)
1143{
1144	va_list nameap;
1145	nvpair_t *nvp;
1146
1147	va_start(nameap, namefmt);
1148	nvp = nvpair_movev_binary(value, size, namefmt, nameap);
1149	va_end(nameap);
1150
1151	return (nvp);
1152}
1153
1154nvpair_t *
1155nvpair_movev_string(char *value, const char *namefmt, va_list nameap)
1156{
1157	nvpair_t *nvp;
1158
1159	if (value == NULL) {
1160		errno = EINVAL;
1161		return (NULL);
1162	}
1163
1164	nvp = nvpair_allocv(NV_TYPE_STRING, (uint64_t)(uintptr_t)value,
1165	    strlen(value) + 1, namefmt, nameap);
1166	if (nvp == NULL)
1167		free(value);
1168
1169	return (nvp);
1170}
1171
1172nvpair_t *
1173nvpair_movev_nvlist(nvlist_t *value, const char *namefmt, va_list nameap)
1174{
1175	nvpair_t *nvp;
1176
1177	if (value == NULL) {
1178		errno = EINVAL;
1179		return (NULL);
1180	}
1181
1182	nvp = nvpair_allocv(NV_TYPE_NVLIST, (uint64_t)(uintptr_t)value, 0,
1183	    namefmt, nameap);
1184	if (nvp == NULL)
1185		nvlist_destroy(value);
1186
1187	return (nvp);
1188}
1189
1190nvpair_t *
1191nvpair_movev_descriptor(int value, const char *namefmt, va_list nameap)
1192{
1193
1194	if (value < 0 || !fd_is_valid(value)) {
1195		errno = EBADF;
1196		return (NULL);
1197	}
1198
1199	return (nvpair_allocv(NV_TYPE_DESCRIPTOR, (uint64_t)value,
1200	    sizeof(int64_t), namefmt, nameap));
1201}
1202
1203nvpair_t *
1204nvpair_movev_binary(void *value, size_t size, const char *namefmt,
1205    va_list nameap)
1206{
1207
1208	if (value == NULL || size == 0) {
1209		errno = EINVAL;
1210		return (NULL);
1211	}
1212
1213	return (nvpair_allocv(NV_TYPE_BINARY, (uint64_t)(uintptr_t)value, size,
1214	    namefmt, nameap));
1215}
1216
1217bool
1218nvpair_get_bool(const nvpair_t *nvp)
1219{
1220
1221	NVPAIR_ASSERT(nvp);
1222
1223	return (nvp->nvp_data == 1);
1224}
1225
1226uint64_t
1227nvpair_get_number(const nvpair_t *nvp)
1228{
1229
1230	NVPAIR_ASSERT(nvp);
1231
1232	return (nvp->nvp_data);
1233}
1234
1235const char *
1236nvpair_get_string(const nvpair_t *nvp)
1237{
1238
1239	NVPAIR_ASSERT(nvp);
1240	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
1241
1242	return ((const char *)(intptr_t)nvp->nvp_data);
1243}
1244
1245const nvlist_t *
1246nvpair_get_nvlist(const nvpair_t *nvp)
1247{
1248
1249	NVPAIR_ASSERT(nvp);
1250	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST);
1251
1252	return ((const nvlist_t *)(intptr_t)nvp->nvp_data);
1253}
1254
1255int
1256nvpair_get_descriptor(const nvpair_t *nvp)
1257{
1258
1259	NVPAIR_ASSERT(nvp);
1260	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
1261
1262	return ((int)nvp->nvp_data);
1263}
1264
1265const void *
1266nvpair_get_binary(const nvpair_t *nvp, size_t *sizep)
1267{
1268
1269	NVPAIR_ASSERT(nvp);
1270	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
1271
1272	if (sizep != NULL)
1273		*sizep = nvp->nvp_datasize;
1274	return ((const void *)(intptr_t)nvp->nvp_data);
1275}
1276
1277void
1278nvpair_free(nvpair_t *nvp)
1279{
1280
1281	NVPAIR_ASSERT(nvp);
1282	PJDLOG_ASSERT(nvp->nvp_list == NULL);
1283
1284	nvp->nvp_magic = 0;
1285	switch (nvp->nvp_type) {
1286	case NV_TYPE_DESCRIPTOR:
1287		close((int)nvp->nvp_data);
1288		break;
1289	case NV_TYPE_NVLIST:
1290		nvlist_destroy((nvlist_t *)(intptr_t)nvp->nvp_data);
1291		break;
1292	case NV_TYPE_STRING:
1293		free((char *)(intptr_t)nvp->nvp_data);
1294		break;
1295	case NV_TYPE_BINARY:
1296		free((void *)(intptr_t)nvp->nvp_data);
1297		break;
1298	}
1299	free(nvp);
1300}
1301
1302void
1303nvpair_free_structure(nvpair_t *nvp)
1304{
1305
1306	NVPAIR_ASSERT(nvp);
1307	PJDLOG_ASSERT(nvp->nvp_list == NULL);
1308
1309	nvp->nvp_magic = 0;
1310	free(nvp);
1311}
1312
1313const char *
1314nvpair_type_string(int type)
1315{
1316
1317	switch (type) {
1318	case NV_TYPE_NULL:
1319		return ("NULL");
1320	case NV_TYPE_BOOL:
1321		return ("BOOL");
1322	case NV_TYPE_NUMBER:
1323		return ("NUMBER");
1324	case NV_TYPE_STRING:
1325		return ("STRING");
1326	case NV_TYPE_NVLIST:
1327		return ("NVLIST");
1328	case NV_TYPE_DESCRIPTOR:
1329		return ("DESCRIPTOR");
1330	case NV_TYPE_BINARY:
1331		return ("BINARY");
1332	default:
1333		return ("<UNKNOWN>");
1334	}
1335}
1336