nvpair.c revision 258594
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 258594 2013-11-25 20:45:30Z 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		goto failed;
688	nvp = tmp;
689	/* Update nvp_name after realloc(). */
690	nvp->nvp_name = (char *)(nvp + 1);
691
692	switch (nvp->nvp_type) {
693	case NV_TYPE_NULL:
694		ptr = nvpair_unpack_null(flags, nvp, ptr, leftp);
695		break;
696	case NV_TYPE_BOOL:
697		ptr = nvpair_unpack_bool(flags, nvp, ptr, leftp);
698		break;
699	case NV_TYPE_NUMBER:
700		ptr = nvpair_unpack_number(flags, nvp, ptr, leftp);
701		break;
702	case NV_TYPE_STRING:
703		ptr = nvpair_unpack_string(flags, nvp, ptr, leftp);
704		break;
705	case NV_TYPE_NVLIST:
706		ptr = nvpair_unpack_nvlist(flags, nvp, ptr, leftp, fds,
707		    nfds);
708		break;
709	case NV_TYPE_DESCRIPTOR:
710		ptr = nvpair_unpack_descriptor(flags, nvp, ptr, leftp, fds,
711		    nfds);
712		break;
713	case NV_TYPE_BINARY:
714		ptr = nvpair_unpack_binary(flags, nvp, ptr, leftp);
715		break;
716	default:
717		PJDLOG_ABORT("Invalid type (%d).", nvp->nvp_type);
718	}
719
720	if (ptr == NULL)
721		goto failed;
722
723	nvp->nvp_magic = NVPAIR_MAGIC;
724	*nvpp = nvp;
725	return (ptr);
726failed:
727	free(nvp);
728	return (NULL);
729}
730
731int
732nvpair_type(const nvpair_t *nvp)
733{
734
735	NVPAIR_ASSERT(nvp);
736
737	return (nvp->nvp_type);
738}
739
740const char *
741nvpair_name(const nvpair_t *nvp)
742{
743
744	NVPAIR_ASSERT(nvp);
745
746	return (nvp->nvp_name);
747}
748
749static nvpair_t *
750nvpair_allocv(int type, uint64_t data, size_t datasize, const char *namefmt,
751    va_list nameap)
752{
753	nvpair_t *nvp;
754	char *name;
755	int namelen;
756
757	PJDLOG_ASSERT(type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST);
758
759	namelen = vasprintf(&name, namefmt, nameap);
760	if (namelen < 0)
761		return (NULL);
762
763	PJDLOG_ASSERT(namelen > 0);
764	if (namelen >= NV_NAME_MAX) {
765		free(name);
766		errno = ENAMETOOLONG;
767		return (NULL);
768	}
769
770	nvp = calloc(1, sizeof(*nvp) + namelen + 1);
771	if (nvp != NULL) {
772		nvp->nvp_name = (char *)(nvp + 1);
773		memcpy(nvp->nvp_name, name, namelen + 1);
774		nvp->nvp_type = type;
775		nvp->nvp_data = data;
776		nvp->nvp_datasize = datasize;
777		nvp->nvp_magic = NVPAIR_MAGIC;
778	}
779	free(name);
780
781	return (nvp);
782};
783
784nvpair_t *
785nvpair_create_null(const char *name)
786{
787
788	return (nvpair_createf_null("%s", name));
789}
790
791nvpair_t *
792nvpair_create_bool(const char *name, bool value)
793{
794
795	return (nvpair_createf_bool(value, "%s", name));
796}
797
798nvpair_t *
799nvpair_create_number(const char *name, uint64_t value)
800{
801
802	return (nvpair_createf_number(value, "%s", name));
803}
804
805nvpair_t *
806nvpair_create_string(const char *name, const char *value)
807{
808
809	return (nvpair_createf_string(value, "%s", name));
810}
811
812nvpair_t *
813nvpair_create_stringf(const char *name, const char *valuefmt, ...)
814{
815	va_list valueap;
816	nvpair_t *nvp;
817
818	va_start(valueap, valuefmt);
819	nvp = nvpair_create_stringv(name, valuefmt, valueap);
820	va_end(valueap);
821
822	return (nvp);
823}
824
825nvpair_t *
826nvpair_create_stringv(const char *name, const char *valuefmt, va_list valueap)
827{
828	nvpair_t *nvp;
829	char *str;
830	int len;
831
832	len = vasprintf(&str, valuefmt, valueap);
833	if (len < 0)
834		return (NULL);
835	nvp = nvpair_create_string(name, str);
836	if (nvp == NULL)
837		free(str);
838	return (nvp);
839}
840
841nvpair_t *
842nvpair_create_nvlist(const char *name, const nvlist_t *value)
843{
844
845	return (nvpair_createf_nvlist(value, "%s", name));
846}
847
848nvpair_t *
849nvpair_create_descriptor(const char *name, int value)
850{
851
852	return (nvpair_createf_descriptor(value, "%s", name));
853}
854
855nvpair_t *
856nvpair_create_binary(const char *name, const void *value, size_t size)
857{
858
859	return (nvpair_createf_binary(value, size, "%s", name));
860}
861
862nvpair_t *
863nvpair_createf_null(const char *namefmt, ...)
864{
865	va_list nameap;
866	nvpair_t *nvp;
867
868	va_start(nameap, namefmt);
869	nvp = nvpair_createv_null(namefmt, nameap);
870	va_end(nameap);
871
872	return (nvp);
873}
874
875nvpair_t *
876nvpair_createf_bool(bool value, const char *namefmt, ...)
877{
878	va_list nameap;
879	nvpair_t *nvp;
880
881	va_start(nameap, namefmt);
882	nvp = nvpair_createv_bool(value, namefmt, nameap);
883	va_end(nameap);
884
885	return (nvp);
886}
887
888nvpair_t *
889nvpair_createf_number(uint64_t value, const char *namefmt, ...)
890{
891	va_list nameap;
892	nvpair_t *nvp;
893
894	va_start(nameap, namefmt);
895	nvp = nvpair_createv_number(value, namefmt, nameap);
896	va_end(nameap);
897
898	return (nvp);
899}
900
901nvpair_t *
902nvpair_createf_string(const char *value, const char *namefmt, ...)
903{
904	va_list nameap;
905	nvpair_t *nvp;
906
907	va_start(nameap, namefmt);
908	nvp = nvpair_createv_string(value, namefmt, nameap);
909	va_end(nameap);
910
911	return (nvp);
912}
913
914nvpair_t *
915nvpair_createf_nvlist(const nvlist_t *value, const char *namefmt, ...)
916{
917	va_list nameap;
918	nvpair_t *nvp;
919
920	va_start(nameap, namefmt);
921	nvp = nvpair_createv_nvlist(value, namefmt, nameap);
922	va_end(nameap);
923
924	return (nvp);
925}
926
927nvpair_t *
928nvpair_createf_descriptor(int value, const char *namefmt, ...)
929{
930	va_list nameap;
931	nvpair_t *nvp;
932
933	va_start(nameap, namefmt);
934	nvp = nvpair_createv_descriptor(value, namefmt, nameap);
935	va_end(nameap);
936
937	return (nvp);
938}
939
940nvpair_t *
941nvpair_createf_binary(const void *value, size_t size, const char *namefmt, ...)
942{
943	va_list nameap;
944	nvpair_t *nvp;
945
946	va_start(nameap, namefmt);
947	nvp = nvpair_createv_binary(value, size, namefmt, nameap);
948	va_end(nameap);
949
950	return (nvp);
951}
952
953nvpair_t *
954nvpair_createv_null(const char *namefmt, va_list nameap)
955{
956
957	return (nvpair_allocv(NV_TYPE_NULL, 0, 0, namefmt, nameap));
958}
959
960nvpair_t *
961nvpair_createv_bool(bool value, const char *namefmt, va_list nameap)
962{
963
964	return (nvpair_allocv(NV_TYPE_BOOL, value ? 1 : 0, sizeof(uint8_t),
965	    namefmt, nameap));
966}
967
968nvpair_t *
969nvpair_createv_number(uint64_t value, const char *namefmt, va_list nameap)
970{
971
972	return (nvpair_allocv(NV_TYPE_NUMBER, value, sizeof(value), namefmt,
973	    nameap));
974}
975
976nvpair_t *
977nvpair_createv_string(const char *value, const char *namefmt, va_list nameap)
978{
979	nvpair_t *nvp;
980	size_t size;
981	char *data;
982
983	if (value == NULL) {
984		errno = EINVAL;
985		return (NULL);
986	}
987
988	data = strdup(value);
989	if (data == NULL)
990		return (NULL);
991	size = strlen(value) + 1;
992
993	nvp = nvpair_allocv(NV_TYPE_STRING, (uint64_t)(uintptr_t)data, size,
994	    namefmt, nameap);
995	if (nvp == NULL)
996		free(data);
997
998	return (nvp);
999}
1000
1001nvpair_t *
1002nvpair_createv_nvlist(const nvlist_t *value, const char *namefmt,
1003    va_list nameap)
1004{
1005	nvlist_t *nvl;
1006	nvpair_t *nvp;
1007
1008	if (value == NULL) {
1009		errno = EINVAL;
1010		return (NULL);
1011	}
1012
1013	nvl = nvlist_clone(value);
1014	if (nvl == NULL)
1015		return (NULL);
1016
1017	nvp = nvpair_allocv(NV_TYPE_NVLIST, (uint64_t)(uintptr_t)nvl, 0,
1018	    namefmt, nameap);
1019	if (nvp == NULL)
1020		nvlist_destroy(nvl);
1021
1022	return (nvp);
1023}
1024
1025nvpair_t *
1026nvpair_createv_descriptor(int value, const char *namefmt, va_list nameap)
1027{
1028	nvpair_t *nvp;
1029
1030	if (value < 0 || !fd_is_valid(value)) {
1031		errno = EBADF;
1032		return (NULL);
1033	}
1034
1035	value = fcntl(value, F_DUPFD_CLOEXEC, 0);
1036	if (value < 0)
1037		return (NULL);
1038
1039	nvp = nvpair_allocv(NV_TYPE_DESCRIPTOR, (uint64_t)value,
1040	    sizeof(int64_t), namefmt, nameap);
1041	if (nvp == NULL)
1042		close(value);
1043
1044	return (nvp);
1045}
1046
1047nvpair_t *
1048nvpair_createv_binary(const void *value, size_t size, const char *namefmt,
1049    va_list nameap)
1050{
1051	nvpair_t *nvp;
1052	void *data;
1053
1054	if (value == NULL || size == 0) {
1055		errno = EINVAL;
1056		return (NULL);
1057	}
1058
1059	data = malloc(size);
1060	if (data == NULL)
1061		return (NULL);
1062	memcpy(data, value, size);
1063
1064	nvp = nvpair_allocv(NV_TYPE_BINARY, (uint64_t)(uintptr_t)data, size,
1065	    namefmt, nameap);
1066	if (nvp == NULL)
1067		free(data);
1068
1069	return (nvp);
1070}
1071
1072nvpair_t *
1073nvpair_move_string(const char *name, char *value)
1074{
1075
1076	return (nvpair_movef_string(value, "%s", name));
1077}
1078
1079nvpair_t *
1080nvpair_move_nvlist(const char *name, nvlist_t *value)
1081{
1082
1083	return (nvpair_movef_nvlist(value, "%s", name));
1084}
1085
1086nvpair_t *
1087nvpair_move_descriptor(const char *name, int value)
1088{
1089
1090	return (nvpair_movef_descriptor(value, "%s", name));
1091}
1092
1093nvpair_t *
1094nvpair_move_binary(const char *name, void *value, size_t size)
1095{
1096
1097	return (nvpair_movef_binary(value, size, "%s", name));
1098}
1099
1100nvpair_t *
1101nvpair_movef_string(char *value, const char *namefmt, ...)
1102{
1103	va_list nameap;
1104	nvpair_t *nvp;
1105
1106	va_start(nameap, namefmt);
1107	nvp = nvpair_movev_string(value, namefmt, nameap);
1108	va_end(nameap);
1109
1110	return (nvp);
1111}
1112
1113nvpair_t *
1114nvpair_movef_nvlist(nvlist_t *value, const char *namefmt, ...)
1115{
1116	va_list nameap;
1117	nvpair_t *nvp;
1118
1119	va_start(nameap, namefmt);
1120	nvp = nvpair_movev_nvlist(value, namefmt, nameap);
1121	va_end(nameap);
1122
1123	return (nvp);
1124}
1125
1126nvpair_t *
1127nvpair_movef_descriptor(int value, const char *namefmt, ...)
1128{
1129	va_list nameap;
1130	nvpair_t *nvp;
1131
1132	va_start(nameap, namefmt);
1133	nvp = nvpair_movev_descriptor(value, namefmt, nameap);
1134	va_end(nameap);
1135
1136	return (nvp);
1137}
1138
1139nvpair_t *
1140nvpair_movef_binary(void *value, size_t size, const char *namefmt, ...)
1141{
1142	va_list nameap;
1143	nvpair_t *nvp;
1144
1145	va_start(nameap, namefmt);
1146	nvp = nvpair_movev_binary(value, size, namefmt, nameap);
1147	va_end(nameap);
1148
1149	return (nvp);
1150}
1151
1152nvpair_t *
1153nvpair_movev_string(char *value, const char *namefmt, va_list nameap)
1154{
1155	nvpair_t *nvp;
1156
1157	if (value == NULL) {
1158		errno = EINVAL;
1159		return (NULL);
1160	}
1161
1162	nvp = nvpair_allocv(NV_TYPE_STRING, (uint64_t)(uintptr_t)value,
1163	    strlen(value) + 1, namefmt, nameap);
1164	if (nvp == NULL)
1165		free(value);
1166
1167	return (nvp);
1168}
1169
1170nvpair_t *
1171nvpair_movev_nvlist(nvlist_t *value, const char *namefmt, va_list nameap)
1172{
1173	nvpair_t *nvp;
1174
1175	if (value == NULL) {
1176		errno = EINVAL;
1177		return (NULL);
1178	}
1179
1180	nvp = nvpair_allocv(NV_TYPE_NVLIST, (uint64_t)(uintptr_t)value, 0,
1181	    namefmt, nameap);
1182	if (nvp == NULL)
1183		nvlist_destroy(value);
1184
1185	return (nvp);
1186}
1187
1188nvpair_t *
1189nvpair_movev_descriptor(int value, const char *namefmt, va_list nameap)
1190{
1191
1192	if (value < 0 || !fd_is_valid(value)) {
1193		errno = EBADF;
1194		return (NULL);
1195	}
1196
1197	return (nvpair_allocv(NV_TYPE_DESCRIPTOR, (uint64_t)value,
1198	    sizeof(int64_t), namefmt, nameap));
1199}
1200
1201nvpair_t *
1202nvpair_movev_binary(void *value, size_t size, const char *namefmt,
1203    va_list nameap)
1204{
1205
1206	if (value == NULL || size == 0) {
1207		errno = EINVAL;
1208		return (NULL);
1209	}
1210
1211	return (nvpair_allocv(NV_TYPE_BINARY, (uint64_t)(uintptr_t)value, size,
1212	    namefmt, nameap));
1213}
1214
1215bool
1216nvpair_get_bool(const nvpair_t *nvp)
1217{
1218
1219	NVPAIR_ASSERT(nvp);
1220
1221	return (nvp->nvp_data == 1);
1222}
1223
1224uint64_t
1225nvpair_get_number(const nvpair_t *nvp)
1226{
1227
1228	NVPAIR_ASSERT(nvp);
1229
1230	return (nvp->nvp_data);
1231}
1232
1233const char *
1234nvpair_get_string(const nvpair_t *nvp)
1235{
1236
1237	NVPAIR_ASSERT(nvp);
1238	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
1239
1240	return ((const char *)(intptr_t)nvp->nvp_data);
1241}
1242
1243const nvlist_t *
1244nvpair_get_nvlist(const nvpair_t *nvp)
1245{
1246
1247	NVPAIR_ASSERT(nvp);
1248	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST);
1249
1250	return ((const nvlist_t *)(intptr_t)nvp->nvp_data);
1251}
1252
1253int
1254nvpair_get_descriptor(const nvpair_t *nvp)
1255{
1256
1257	NVPAIR_ASSERT(nvp);
1258	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
1259
1260	return ((int)nvp->nvp_data);
1261}
1262
1263const void *
1264nvpair_get_binary(const nvpair_t *nvp, size_t *sizep)
1265{
1266
1267	NVPAIR_ASSERT(nvp);
1268	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
1269
1270	if (sizep != NULL)
1271		*sizep = nvp->nvp_datasize;
1272	return ((const void *)(intptr_t)nvp->nvp_data);
1273}
1274
1275void
1276nvpair_free(nvpair_t *nvp)
1277{
1278
1279	NVPAIR_ASSERT(nvp);
1280	PJDLOG_ASSERT(nvp->nvp_list == NULL);
1281
1282	nvp->nvp_magic = 0;
1283	switch (nvp->nvp_type) {
1284	case NV_TYPE_DESCRIPTOR:
1285		close((int)nvp->nvp_data);
1286		break;
1287	case NV_TYPE_NVLIST:
1288		nvlist_destroy((nvlist_t *)(intptr_t)nvp->nvp_data);
1289		break;
1290	case NV_TYPE_STRING:
1291		free((char *)(intptr_t)nvp->nvp_data);
1292		break;
1293	case NV_TYPE_BINARY:
1294		free((void *)(intptr_t)nvp->nvp_data);
1295		break;
1296	}
1297	free(nvp);
1298}
1299
1300void
1301nvpair_free_structure(nvpair_t *nvp)
1302{
1303
1304	NVPAIR_ASSERT(nvp);
1305	PJDLOG_ASSERT(nvp->nvp_list == NULL);
1306
1307	nvp->nvp_magic = 0;
1308	free(nvp);
1309}
1310
1311const char *
1312nvpair_type_string(int type)
1313{
1314
1315	switch (type) {
1316	case NV_TYPE_NULL:
1317		return ("NULL");
1318	case NV_TYPE_BOOL:
1319		return ("BOOL");
1320	case NV_TYPE_NUMBER:
1321		return ("NUMBER");
1322	case NV_TYPE_STRING:
1323		return ("STRING");
1324	case NV_TYPE_NVLIST:
1325		return ("NVLIST");
1326	case NV_TYPE_DESCRIPTOR:
1327		return ("DESCRIPTOR");
1328	case NV_TYPE_BINARY:
1329		return ("BINARY");
1330	default:
1331		return ("<UNKNOWN>");
1332	}
1333}
1334