subr_nvpair.c revision 258594
1258065Spjd/*-
2258065Spjd * Copyright (c) 2009-2013 The FreeBSD Foundation
3258065Spjd * All rights reserved.
4258065Spjd *
5258065Spjd * This software was developed by Pawel Jakub Dawidek under sponsorship from
6258065Spjd * the FreeBSD Foundation.
7258065Spjd *
8258065Spjd * Redistribution and use in source and binary forms, with or without
9258065Spjd * modification, are permitted provided that the following conditions
10258065Spjd * are met:
11258065Spjd * 1. Redistributions of source code must retain the above copyright
12258065Spjd *    notice, this list of conditions and the following disclaimer.
13258065Spjd * 2. Redistributions in binary form must reproduce the above copyright
14258065Spjd *    notice, this list of conditions and the following disclaimer in the
15258065Spjd *    documentation and/or other materials provided with the distribution.
16258065Spjd *
17258065Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18258065Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19258065Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20258065Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21258065Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22258065Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23258065Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24258065Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25258065Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26258065Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27258065Spjd * SUCH DAMAGE.
28258065Spjd */
29258065Spjd
30258065Spjd#include <sys/cdefs.h>
31258065Spjd__FBSDID("$FreeBSD: head/lib/libnv/nvpair.c 258594 2013-11-25 20:45:30Z pjd $");
32258065Spjd
33258065Spjd#include <sys/param.h>
34258065Spjd#include <sys/endian.h>
35258065Spjd#include <sys/queue.h>
36258065Spjd
37258065Spjd#include <errno.h>
38258065Spjd#include <fcntl.h>
39258065Spjd#include <stdarg.h>
40258065Spjd#include <stdbool.h>
41258065Spjd#include <stdint.h>
42258065Spjd#include <stdlib.h>
43258065Spjd#include <string.h>
44258065Spjd#include <unistd.h>
45258065Spjd
46258065Spjd#ifdef HAVE_PJDLOG
47258065Spjd#include <pjdlog.h>
48258065Spjd#endif
49258065Spjd
50258065Spjd#include "common_impl.h"
51258065Spjd#include "nv.h"
52258065Spjd#include "nv_impl.h"
53258065Spjd#include "nvlist_impl.h"
54258065Spjd#include "nvpair_impl.h"
55258065Spjd
56258065Spjd#ifndef	HAVE_PJDLOG
57258065Spjd#include <assert.h>
58258065Spjd#define	PJDLOG_ASSERT(...)		assert(__VA_ARGS__)
59258065Spjd#define	PJDLOG_RASSERT(expr, ...)	assert(expr)
60258065Spjd#define	PJDLOG_ABORT(...)		abort()
61258065Spjd#endif
62258065Spjd
63258065Spjd#define	NVPAIR_MAGIC	0x6e7670	/* "nvp" */
64258065Spjdstruct nvpair {
65258065Spjd	int		 nvp_magic;
66258065Spjd	char		*nvp_name;
67258065Spjd	int		 nvp_type;
68258065Spjd	uint64_t	 nvp_data;
69258065Spjd	size_t		 nvp_datasize;
70258065Spjd	nvlist_t	*nvp_list;	/* Used for sanity checks. */
71258065Spjd	TAILQ_ENTRY(nvpair) nvp_next;
72258065Spjd};
73258065Spjd
74258065Spjd#define	NVPAIR_ASSERT(nvp)	do {					\
75258065Spjd	PJDLOG_ASSERT((nvp) != NULL);					\
76258065Spjd	PJDLOG_ASSERT((nvp)->nvp_magic == NVPAIR_MAGIC);		\
77258065Spjd} while (0)
78258065Spjd
79258065Spjdstruct nvpair_header {
80258065Spjd	uint8_t		nvph_type;
81258065Spjd	uint16_t	nvph_namesize;
82258065Spjd	uint64_t	nvph_datasize;
83258065Spjd} __packed;
84258065Spjd
85258065Spjd
86258065Spjdvoid
87258065Spjdnvpair_assert(const nvpair_t *nvp)
88258065Spjd{
89258065Spjd
90258065Spjd	NVPAIR_ASSERT(nvp);
91258065Spjd}
92258065Spjd
93258065Spjdconst nvlist_t *
94258065Spjdnvpair_nvlist(const nvpair_t *nvp)
95258065Spjd{
96258065Spjd
97258065Spjd	NVPAIR_ASSERT(nvp);
98258065Spjd
99258065Spjd	return (nvp->nvp_list);
100258065Spjd}
101258065Spjd
102258065Spjdnvpair_t *
103258065Spjdnvpair_next(const nvpair_t *nvp)
104258065Spjd{
105258065Spjd
106258065Spjd	NVPAIR_ASSERT(nvp);
107258065Spjd	PJDLOG_ASSERT(nvp->nvp_list != NULL);
108258065Spjd
109258065Spjd	return (TAILQ_NEXT(nvp, nvp_next));
110258065Spjd}
111258065Spjd
112258065Spjdnvpair_t *
113258065Spjdnvpair_prev(const nvpair_t *nvp)
114258065Spjd{
115258065Spjd
116258065Spjd	NVPAIR_ASSERT(nvp);
117258065Spjd	PJDLOG_ASSERT(nvp->nvp_list != NULL);
118258065Spjd
119258065Spjd	return (TAILQ_PREV(nvp, nvl_head, nvp_next));
120258065Spjd}
121258065Spjd
122258065Spjdvoid
123258065Spjdnvpair_insert(struct nvl_head *head, nvpair_t *nvp, nvlist_t *nvl)
124258065Spjd{
125258065Spjd
126258065Spjd	NVPAIR_ASSERT(nvp);
127258065Spjd	PJDLOG_ASSERT(nvp->nvp_list == NULL);
128258065Spjd	PJDLOG_ASSERT(!nvlist_exists(nvl, nvpair_name(nvp)));
129258065Spjd
130258065Spjd	TAILQ_INSERT_TAIL(head, nvp, nvp_next);
131258065Spjd	nvp->nvp_list = nvl;
132258065Spjd}
133258065Spjd
134258065Spjdvoid
135258065Spjdnvpair_remove(struct nvl_head *head, nvpair_t *nvp, const nvlist_t *nvl)
136258065Spjd{
137258065Spjd
138258065Spjd	NVPAIR_ASSERT(nvp);
139258065Spjd	PJDLOG_ASSERT(nvp->nvp_list == nvl);
140258065Spjd
141258065Spjd	TAILQ_REMOVE(head, nvp, nvp_next);
142258065Spjd	nvp->nvp_list = NULL;
143258065Spjd}
144258065Spjd
145258065Spjdnvpair_t *
146258065Spjdnvpair_clone(const nvpair_t *nvp)
147258065Spjd{
148258065Spjd	nvpair_t *newnvp;
149258065Spjd	const char *name;
150258065Spjd	const void *data;
151258065Spjd	size_t datasize;
152258065Spjd
153258065Spjd	NVPAIR_ASSERT(nvp);
154258065Spjd
155258065Spjd	name = nvpair_name(nvp);
156258065Spjd
157258065Spjd	switch (nvpair_type(nvp)) {
158258065Spjd	case NV_TYPE_NULL:
159258065Spjd		newnvp = nvpair_create_null(name);
160258065Spjd		break;
161258065Spjd	case NV_TYPE_BOOL:
162258065Spjd		newnvp = nvpair_create_bool(name, nvpair_get_bool(nvp));
163258065Spjd		break;
164258065Spjd	case NV_TYPE_NUMBER:
165258065Spjd		newnvp = nvpair_create_number(name, nvpair_get_number(nvp));
166258065Spjd		break;
167258065Spjd	case NV_TYPE_STRING:
168258065Spjd		newnvp = nvpair_create_string(name, nvpair_get_string(nvp));
169258065Spjd		break;
170258065Spjd	case NV_TYPE_NVLIST:
171258065Spjd		newnvp = nvpair_create_nvlist(name, nvpair_get_nvlist(nvp));
172258065Spjd		break;
173258065Spjd	case NV_TYPE_DESCRIPTOR:
174258065Spjd		newnvp = nvpair_create_descriptor(name,
175258065Spjd		    nvpair_get_descriptor(nvp));
176258065Spjd		break;
177258065Spjd	case NV_TYPE_BINARY:
178258065Spjd		data = nvpair_get_binary(nvp, &datasize);
179258065Spjd		newnvp = nvpair_create_binary(name, data, datasize);
180258065Spjd		break;
181258065Spjd	default:
182258065Spjd		PJDLOG_ABORT("Unknown type: %d.", nvpair_type(nvp));
183258065Spjd	}
184258065Spjd
185258065Spjd	return (newnvp);
186258065Spjd}
187258065Spjd
188258065Spjdsize_t
189258065Spjdnvpair_header_size(void)
190258065Spjd{
191258065Spjd
192258065Spjd	return (sizeof(struct nvpair_header));
193258065Spjd}
194258065Spjd
195258065Spjdsize_t
196258065Spjdnvpair_size(const nvpair_t *nvp)
197258065Spjd{
198258065Spjd
199258065Spjd	NVPAIR_ASSERT(nvp);
200258065Spjd
201258065Spjd	return (nvp->nvp_datasize);
202258065Spjd}
203258065Spjd
204258065Spjdstatic unsigned char *
205258065Spjdnvpair_pack_header(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
206258065Spjd{
207258065Spjd	struct nvpair_header nvphdr;
208258065Spjd	size_t namesize;
209258065Spjd
210258065Spjd	NVPAIR_ASSERT(nvp);
211258065Spjd
212258065Spjd	nvphdr.nvph_type = nvp->nvp_type;
213258065Spjd	namesize = strlen(nvp->nvp_name) + 1;
214258065Spjd	PJDLOG_ASSERT(namesize > 0 && namesize <= UINT16_MAX);
215258065Spjd	nvphdr.nvph_namesize = namesize;
216258065Spjd	nvphdr.nvph_datasize = nvp->nvp_datasize;
217258065Spjd	PJDLOG_ASSERT(*leftp >= sizeof(nvphdr));
218258065Spjd	memcpy(ptr, &nvphdr, sizeof(nvphdr));
219258065Spjd	ptr += sizeof(nvphdr);
220258065Spjd	*leftp -= sizeof(nvphdr);
221258065Spjd
222258065Spjd	PJDLOG_ASSERT(*leftp >= namesize);
223258065Spjd	memcpy(ptr, nvp->nvp_name, namesize);
224258065Spjd	ptr += namesize;
225258065Spjd	*leftp -= namesize;
226258065Spjd
227258065Spjd	return (ptr);
228258065Spjd}
229258065Spjd
230258065Spjdstatic unsigned char *
231258065Spjdnvpair_pack_null(const nvpair_t *nvp, unsigned char *ptr,
232258065Spjd    size_t *leftp __unused)
233258065Spjd{
234258065Spjd
235258065Spjd	NVPAIR_ASSERT(nvp);
236258065Spjd	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NULL);
237258065Spjd
238258065Spjd	return (ptr);
239258065Spjd}
240258065Spjd
241258065Spjdstatic unsigned char *
242258065Spjdnvpair_pack_bool(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
243258065Spjd{
244258065Spjd	uint8_t value;
245258065Spjd
246258065Spjd	NVPAIR_ASSERT(nvp);
247258065Spjd	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL);
248258065Spjd
249258065Spjd	value = (uint8_t)nvp->nvp_data;
250258065Spjd
251258065Spjd	PJDLOG_ASSERT(*leftp >= sizeof(value));
252258065Spjd	memcpy(ptr, &value, sizeof(value));
253258065Spjd	ptr += sizeof(value);
254258065Spjd	*leftp -= sizeof(value);
255258065Spjd
256258065Spjd	return (ptr);
257258065Spjd}
258258065Spjd
259258065Spjdstatic unsigned char *
260258065Spjdnvpair_pack_number(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
261258065Spjd{
262258065Spjd	uint64_t value;
263258065Spjd
264258065Spjd	NVPAIR_ASSERT(nvp);
265258065Spjd	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER);
266258065Spjd
267258065Spjd	value = (uint64_t)nvp->nvp_data;
268258065Spjd
269258065Spjd	PJDLOG_ASSERT(*leftp >= sizeof(value));
270258065Spjd	memcpy(ptr, &value, sizeof(value));
271258065Spjd	ptr += sizeof(value);
272258065Spjd	*leftp -= sizeof(value);
273258065Spjd
274258065Spjd	return (ptr);
275258065Spjd}
276258065Spjd
277258065Spjdstatic unsigned char *
278258065Spjdnvpair_pack_string(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
279258065Spjd{
280258065Spjd
281258065Spjd	NVPAIR_ASSERT(nvp);
282258065Spjd	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
283258065Spjd
284258065Spjd	PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
285258065Spjd	memcpy(ptr, (const void *)(intptr_t)nvp->nvp_data, nvp->nvp_datasize);
286258065Spjd	ptr += nvp->nvp_datasize;
287258065Spjd	*leftp -= nvp->nvp_datasize;
288258065Spjd
289258065Spjd	return (ptr);
290258065Spjd}
291258065Spjd
292258065Spjdstatic unsigned char *
293258065Spjdnvpair_pack_nvlist(const nvpair_t *nvp, unsigned char *ptr, int64_t *fdidxp,
294258065Spjd    size_t *leftp)
295258065Spjd{
296258065Spjd	unsigned char *data;
297258065Spjd	size_t size;
298258065Spjd
299258065Spjd	NVPAIR_ASSERT(nvp);
300258065Spjd	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST);
301258065Spjd
302258065Spjd	if (nvp->nvp_datasize == 0)
303258065Spjd		return (ptr);
304258065Spjd
305258065Spjd	data = nvlist_xpack((const nvlist_t *)(intptr_t)nvp->nvp_data, fdidxp,
306258065Spjd	    &size);
307258065Spjd	if (data == NULL)
308258065Spjd		return (NULL);
309258065Spjd
310258065Spjd	PJDLOG_ASSERT(size == nvp->nvp_datasize);
311258065Spjd	PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
312258065Spjd
313258065Spjd	memcpy(ptr, data, nvp->nvp_datasize);
314258065Spjd	free(data);
315258065Spjd
316258065Spjd	ptr += nvp->nvp_datasize;
317258065Spjd	*leftp -= nvp->nvp_datasize;
318258065Spjd
319258065Spjd	return (ptr);
320258065Spjd}
321258065Spjd
322258065Spjdstatic unsigned char *
323258065Spjdnvpair_pack_descriptor(const nvpair_t *nvp, unsigned char *ptr, int64_t *fdidxp,
324258065Spjd    size_t *leftp)
325258065Spjd{
326258065Spjd	int64_t value;
327258065Spjd
328258065Spjd	NVPAIR_ASSERT(nvp);
329258065Spjd	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
330258065Spjd
331258065Spjd	value = (int64_t)nvp->nvp_data;
332258065Spjd	if (value != -1) {
333258065Spjd		/*
334258065Spjd		 * If there is a real descriptor here, we change its number
335258065Spjd		 * to position in the array of descriptors send via control
336258065Spjd		 * message.
337258065Spjd		 */
338258065Spjd		PJDLOG_ASSERT(fdidxp != NULL);
339258065Spjd
340258065Spjd		value = *fdidxp;
341258065Spjd		(*fdidxp)++;
342258065Spjd	}
343258065Spjd
344258065Spjd	PJDLOG_ASSERT(*leftp >= sizeof(value));
345258065Spjd	memcpy(ptr, &value, sizeof(value));
346258065Spjd	ptr += sizeof(value);
347258065Spjd	*leftp -= sizeof(value);
348258065Spjd
349258065Spjd	return (ptr);
350258065Spjd}
351258065Spjd
352258065Spjdstatic unsigned char *
353258065Spjdnvpair_pack_binary(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
354258065Spjd{
355258065Spjd
356258065Spjd	NVPAIR_ASSERT(nvp);
357258065Spjd	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
358258065Spjd
359258065Spjd	PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
360258065Spjd	memcpy(ptr, (const void *)(intptr_t)nvp->nvp_data, nvp->nvp_datasize);
361258065Spjd	ptr += nvp->nvp_datasize;
362258065Spjd	*leftp -= nvp->nvp_datasize;
363258065Spjd
364258065Spjd	return (ptr);
365258065Spjd}
366258065Spjd
367258065Spjdunsigned char *
368258065Spjdnvpair_pack(nvpair_t *nvp, unsigned char *ptr, int64_t *fdidxp, size_t *leftp)
369258065Spjd{
370258065Spjd
371258065Spjd	NVPAIR_ASSERT(nvp);
372258065Spjd
373258065Spjd	/*
374258065Spjd	 * We have to update datasize for NV_TYPE_NVLIST on every pack,
375258065Spjd	 * so that proper datasize is placed into nvpair_header
376258065Spjd	 * during the nvpair_pack_header() call below.
377258065Spjd	 */
378258065Spjd	if (nvp->nvp_type == NV_TYPE_NVLIST) {
379258065Spjd		if (nvp->nvp_data == 0) {
380258065Spjd			nvp->nvp_datasize = 0;
381258065Spjd		} else {
382258065Spjd			nvp->nvp_datasize =
383258065Spjd			    nvlist_size((const nvlist_t *)(intptr_t)nvp->nvp_data);
384258065Spjd		}
385258065Spjd	}
386258065Spjd
387258065Spjd	ptr = nvpair_pack_header(nvp, ptr, leftp);
388258065Spjd	if (ptr == NULL)
389258065Spjd		return (NULL);
390258065Spjd
391258065Spjd	switch (nvp->nvp_type) {
392258065Spjd	case NV_TYPE_NULL:
393258065Spjd		ptr = nvpair_pack_null(nvp, ptr, leftp);
394258065Spjd		break;
395258065Spjd	case NV_TYPE_BOOL:
396258065Spjd		ptr = nvpair_pack_bool(nvp, ptr, leftp);
397258065Spjd		break;
398258065Spjd	case NV_TYPE_NUMBER:
399258065Spjd		ptr = nvpair_pack_number(nvp, ptr, leftp);
400258065Spjd		break;
401258065Spjd	case NV_TYPE_STRING:
402258065Spjd		ptr = nvpair_pack_string(nvp, ptr, leftp);
403258065Spjd		break;
404258065Spjd	case NV_TYPE_NVLIST:
405258065Spjd		ptr = nvpair_pack_nvlist(nvp, ptr, fdidxp, leftp);
406258065Spjd		break;
407258065Spjd	case NV_TYPE_DESCRIPTOR:
408258065Spjd		ptr = nvpair_pack_descriptor(nvp, ptr, fdidxp, leftp);
409258065Spjd		break;
410258065Spjd	case NV_TYPE_BINARY:
411258065Spjd		ptr = nvpair_pack_binary(nvp, ptr, leftp);
412258065Spjd		break;
413258065Spjd	default:
414258065Spjd		PJDLOG_ABORT("Invalid type (%d).", nvp->nvp_type);
415258065Spjd	}
416258065Spjd
417258065Spjd	return (ptr);
418258065Spjd}
419258065Spjd
420258065Spjdstatic const unsigned char *
421258065Spjdnvpair_unpack_header(int flags, nvpair_t *nvp, const unsigned char *ptr,
422258065Spjd    size_t *leftp)
423258065Spjd{
424258065Spjd	struct nvpair_header nvphdr;
425258065Spjd
426258065Spjd	if (*leftp < sizeof(nvphdr))
427258065Spjd		goto failed;
428258065Spjd
429258065Spjd	memcpy(&nvphdr, ptr, sizeof(nvphdr));
430258065Spjd	ptr += sizeof(nvphdr);
431258065Spjd	*leftp -= sizeof(nvphdr);
432258065Spjd
433258065Spjd#if NV_TYPE_FIRST > 0
434258065Spjd	if (nvphdr.nvph_type < NV_TYPE_FIRST)
435258065Spjd		goto failed;
436258065Spjd#endif
437258065Spjd	if (nvphdr.nvph_type > NV_TYPE_LAST)
438258065Spjd		goto failed;
439258065Spjd
440258065Spjd#if BYTE_ORDER == BIG_ENDIAN
441258065Spjd	if ((flags & NV_FLAG_BIG_ENDIAN) == 0) {
442258065Spjd		nvphdr.nvph_namesize = le16toh(nvphdr.nvph_namesize);
443258065Spjd		nvphdr.nvph_datasize = le64toh(nvphdr.nvph_datasize);
444258065Spjd	}
445258065Spjd#else
446258065Spjd	if ((flags & NV_FLAG_BIG_ENDIAN) != 0) {
447258065Spjd		nvphdr.nvph_namesize = be16toh(nvphdr.nvph_namesize);
448258065Spjd		nvphdr.nvph_datasize = be64toh(nvphdr.nvph_datasize);
449258065Spjd	}
450258065Spjd#endif
451258065Spjd
452258065Spjd	if (nvphdr.nvph_namesize > NV_NAME_MAX)
453258065Spjd		goto failed;
454258065Spjd	if (*leftp < nvphdr.nvph_namesize)
455258065Spjd		goto failed;
456258065Spjd	if (nvphdr.nvph_namesize < 1)
457258065Spjd		goto failed;
458258065Spjd	if (strnlen((const char *)ptr, nvphdr.nvph_namesize) !=
459258065Spjd	    (size_t)(nvphdr.nvph_namesize - 1)) {
460258065Spjd		goto failed;
461258065Spjd	}
462258065Spjd
463258065Spjd	memcpy(nvp->nvp_name, ptr, nvphdr.nvph_namesize);
464258065Spjd	ptr += nvphdr.nvph_namesize;
465258065Spjd	*leftp -= nvphdr.nvph_namesize;
466258065Spjd
467258065Spjd	if (*leftp < nvphdr.nvph_datasize)
468258065Spjd		goto failed;
469258065Spjd
470258065Spjd	nvp->nvp_type = nvphdr.nvph_type;
471258065Spjd	nvp->nvp_data = 0;
472258065Spjd	nvp->nvp_datasize = nvphdr.nvph_datasize;
473258065Spjd
474258065Spjd	return (ptr);
475258065Spjdfailed:
476258065Spjd	errno = EINVAL;
477258065Spjd	return (NULL);
478258065Spjd}
479258065Spjd
480258065Spjdstatic const unsigned char *
481258065Spjdnvpair_unpack_null(int flags __unused, nvpair_t *nvp, const unsigned char *ptr,
482258065Spjd    size_t *leftp __unused)
483258065Spjd{
484258065Spjd
485258065Spjd	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NULL);
486258065Spjd
487258065Spjd	if (nvp->nvp_datasize != 0) {
488258065Spjd		errno = EINVAL;
489258065Spjd		return (NULL);
490258065Spjd	}
491258065Spjd
492258065Spjd	return (ptr);
493258065Spjd}
494258065Spjd
495258065Spjdstatic const unsigned char *
496258065Spjdnvpair_unpack_bool(int flags __unused, nvpair_t *nvp, const unsigned char *ptr,
497258065Spjd    size_t *leftp)
498258065Spjd{
499258065Spjd	uint8_t value;
500258065Spjd
501258065Spjd	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL);
502258065Spjd
503258065Spjd	if (nvp->nvp_datasize != sizeof(value)) {
504258065Spjd		errno = EINVAL;
505258065Spjd		return (NULL);
506258065Spjd	}
507258065Spjd	if (*leftp < sizeof(value)) {
508258065Spjd		errno = EINVAL;
509258065Spjd		return (NULL);
510258065Spjd	}
511258065Spjd
512258065Spjd	memcpy(&value, ptr, sizeof(value));
513258065Spjd	ptr += sizeof(value);
514258065Spjd	*leftp -= sizeof(value);
515258065Spjd
516258065Spjd	if (value != 0 && value != 1) {
517258065Spjd		errno = EINVAL;
518258065Spjd		return (NULL);
519258065Spjd	}
520258065Spjd
521258065Spjd	nvp->nvp_data = (uint64_t)value;
522258065Spjd
523258065Spjd	return (ptr);
524258065Spjd}
525258065Spjd
526258065Spjdstatic const unsigned char *
527258065Spjdnvpair_unpack_number(int flags, nvpair_t *nvp, const unsigned char *ptr,
528258065Spjd    size_t *leftp)
529258065Spjd{
530258065Spjd
531258065Spjd	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER);
532258065Spjd
533258065Spjd	if (nvp->nvp_datasize != sizeof(uint64_t)) {
534258065Spjd		errno = EINVAL;
535258065Spjd		return (NULL);
536258065Spjd	}
537258065Spjd	if (*leftp < sizeof(uint64_t)) {
538258065Spjd		errno = EINVAL;
539258065Spjd		return (NULL);
540258065Spjd	}
541258065Spjd
542258065Spjd	if ((flags & NV_FLAG_BIG_ENDIAN) != 0)
543258065Spjd		nvp->nvp_data = be64dec(ptr);
544258065Spjd	else
545258065Spjd		nvp->nvp_data = le64dec(ptr);
546258065Spjd	ptr += sizeof(uint64_t);
547258065Spjd	*leftp -= sizeof(uint64_t);
548258065Spjd
549258065Spjd	return (ptr);
550258065Spjd}
551258065Spjd
552258065Spjdstatic const unsigned char *
553258065Spjdnvpair_unpack_string(int flags __unused, nvpair_t *nvp,
554258065Spjd    const unsigned char *ptr, size_t *leftp)
555258065Spjd{
556258065Spjd
557258065Spjd	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
558258065Spjd
559258065Spjd	if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
560258065Spjd		errno = EINVAL;
561258065Spjd		return (NULL);
562258065Spjd	}
563258065Spjd
564258065Spjd	if (strnlen((const char *)ptr, nvp->nvp_datasize) !=
565258065Spjd	    nvp->nvp_datasize - 1) {
566258065Spjd		errno = EINVAL;
567258065Spjd		return (NULL);
568258065Spjd	}
569258065Spjd
570258065Spjd	nvp->nvp_data = (uint64_t)(uintptr_t)strdup((const char *)ptr);
571258065Spjd	if (nvp->nvp_data == 0)
572258065Spjd		return (NULL);
573258065Spjd
574258065Spjd	ptr += nvp->nvp_datasize;
575258065Spjd	*leftp -= nvp->nvp_datasize;
576258065Spjd
577258065Spjd	return (ptr);
578258065Spjd}
579258065Spjd
580258065Spjdstatic const unsigned char *
581258065Spjdnvpair_unpack_nvlist(int flags __unused, nvpair_t *nvp,
582258065Spjd    const unsigned char *ptr, size_t *leftp, const int *fds, size_t nfds)
583258065Spjd{
584258065Spjd	nvlist_t *value;
585258065Spjd
586258065Spjd	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST);
587258065Spjd
588258065Spjd	if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
589258065Spjd		errno = EINVAL;
590258065Spjd		return (NULL);
591258065Spjd	}
592258065Spjd
593258065Spjd	value = nvlist_xunpack(ptr, nvp->nvp_datasize, fds, nfds);
594258065Spjd	if (value == NULL)
595258065Spjd		return (NULL);
596258065Spjd
597258065Spjd	nvp->nvp_data = (uint64_t)(uintptr_t)value;
598258065Spjd
599258065Spjd	ptr += nvp->nvp_datasize;
600258065Spjd	*leftp -= nvp->nvp_datasize;
601258065Spjd
602258065Spjd	return (ptr);
603258065Spjd}
604258065Spjd
605258065Spjdstatic const unsigned char *
606258065Spjdnvpair_unpack_descriptor(int flags, nvpair_t *nvp, const unsigned char *ptr,
607258065Spjd    size_t *leftp, const int *fds, size_t nfds)
608258065Spjd{
609258065Spjd	int64_t idx;
610258065Spjd
611258065Spjd	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
612258065Spjd
613258065Spjd	if (nvp->nvp_datasize != sizeof(idx)) {
614258065Spjd		errno = EINVAL;
615258065Spjd		return (NULL);
616258065Spjd	}
617258065Spjd	if (*leftp < sizeof(idx)) {
618258065Spjd		errno = EINVAL;
619258065Spjd		return (NULL);
620258065Spjd	}
621258065Spjd
622258065Spjd	if ((flags & NV_FLAG_BIG_ENDIAN) != 0)
623258065Spjd		idx = be64dec(ptr);
624258065Spjd	else
625258065Spjd		idx = le64dec(ptr);
626258065Spjd
627258065Spjd	if (idx < 0) {
628258065Spjd		errno = EINVAL;
629258065Spjd		return (NULL);
630258065Spjd	}
631258065Spjd
632258065Spjd	if ((size_t)idx >= nfds) {
633258065Spjd		errno = EINVAL;
634258065Spjd		return (NULL);
635258065Spjd	}
636258065Spjd
637258065Spjd	nvp->nvp_data = (uint64_t)fds[idx];
638258065Spjd
639258065Spjd	ptr += sizeof(idx);
640258065Spjd	*leftp -= sizeof(idx);
641258065Spjd
642258065Spjd	return (ptr);
643258065Spjd}
644258065Spjd
645258065Spjdstatic const unsigned char *
646258065Spjdnvpair_unpack_binary(int flags __unused, nvpair_t *nvp,
647258065Spjd    const unsigned char *ptr, size_t *leftp)
648258065Spjd{
649258065Spjd	void *value;
650258065Spjd
651258065Spjd	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
652258065Spjd
653258065Spjd	if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
654258065Spjd		errno = EINVAL;
655258065Spjd		return (NULL);
656258065Spjd	}
657258065Spjd
658258065Spjd	value = malloc(nvp->nvp_datasize);
659258065Spjd	if (value == NULL)
660258065Spjd		return (NULL);
661258065Spjd
662258065Spjd	memcpy(value, ptr, nvp->nvp_datasize);
663258065Spjd	ptr += nvp->nvp_datasize;
664258065Spjd	*leftp -= nvp->nvp_datasize;
665258065Spjd
666258065Spjd	nvp->nvp_data = (uint64_t)(uintptr_t)value;
667258065Spjd
668258065Spjd	return (ptr);
669258065Spjd}
670258065Spjd
671258065Spjdconst unsigned char *
672258065Spjdnvpair_unpack(int flags, const unsigned char *ptr, size_t *leftp,
673258065Spjd    const int *fds, size_t nfds, nvpair_t **nvpp)
674258065Spjd{
675258065Spjd	nvpair_t *nvp, *tmp;
676258065Spjd
677258065Spjd	nvp = calloc(1, sizeof(*nvp) + NV_NAME_MAX);
678258065Spjd	if (nvp == NULL)
679258065Spjd		return (NULL);
680258065Spjd	nvp->nvp_name = (char *)(nvp + 1);
681258065Spjd
682258065Spjd	ptr = nvpair_unpack_header(flags, nvp, ptr, leftp);
683258065Spjd	if (ptr == NULL)
684258065Spjd		goto failed;
685258065Spjd	tmp = realloc(nvp, sizeof(*nvp) + strlen(nvp->nvp_name) + 1);
686258594Spjd	if (tmp == NULL)
687258065Spjd		goto failed;
688258065Spjd	nvp = tmp;
689258065Spjd	/* Update nvp_name after realloc(). */
690258065Spjd	nvp->nvp_name = (char *)(nvp + 1);
691258065Spjd
692258065Spjd	switch (nvp->nvp_type) {
693258065Spjd	case NV_TYPE_NULL:
694258065Spjd		ptr = nvpair_unpack_null(flags, nvp, ptr, leftp);
695258065Spjd		break;
696258065Spjd	case NV_TYPE_BOOL:
697258065Spjd		ptr = nvpair_unpack_bool(flags, nvp, ptr, leftp);
698258065Spjd		break;
699258065Spjd	case NV_TYPE_NUMBER:
700258065Spjd		ptr = nvpair_unpack_number(flags, nvp, ptr, leftp);
701258065Spjd		break;
702258065Spjd	case NV_TYPE_STRING:
703258065Spjd		ptr = nvpair_unpack_string(flags, nvp, ptr, leftp);
704258065Spjd		break;
705258065Spjd	case NV_TYPE_NVLIST:
706258065Spjd		ptr = nvpair_unpack_nvlist(flags, nvp, ptr, leftp, fds,
707258065Spjd		    nfds);
708258065Spjd		break;
709258065Spjd	case NV_TYPE_DESCRIPTOR:
710258065Spjd		ptr = nvpair_unpack_descriptor(flags, nvp, ptr, leftp, fds,
711258065Spjd		    nfds);
712258065Spjd		break;
713258065Spjd	case NV_TYPE_BINARY:
714258065Spjd		ptr = nvpair_unpack_binary(flags, nvp, ptr, leftp);
715258065Spjd		break;
716258065Spjd	default:
717258065Spjd		PJDLOG_ABORT("Invalid type (%d).", nvp->nvp_type);
718258065Spjd	}
719258065Spjd
720258065Spjd	if (ptr == NULL)
721258065Spjd		goto failed;
722258065Spjd
723258065Spjd	nvp->nvp_magic = NVPAIR_MAGIC;
724258065Spjd	*nvpp = nvp;
725258065Spjd	return (ptr);
726258065Spjdfailed:
727258065Spjd	free(nvp);
728258065Spjd	return (NULL);
729258065Spjd}
730258065Spjd
731258065Spjdint
732258065Spjdnvpair_type(const nvpair_t *nvp)
733258065Spjd{
734258065Spjd
735258065Spjd	NVPAIR_ASSERT(nvp);
736258065Spjd
737258065Spjd	return (nvp->nvp_type);
738258065Spjd}
739258065Spjd
740258065Spjdconst char *
741258065Spjdnvpair_name(const nvpair_t *nvp)
742258065Spjd{
743258065Spjd
744258065Spjd	NVPAIR_ASSERT(nvp);
745258065Spjd
746258065Spjd	return (nvp->nvp_name);
747258065Spjd}
748258065Spjd
749258065Spjdstatic nvpair_t *
750258065Spjdnvpair_allocv(int type, uint64_t data, size_t datasize, const char *namefmt,
751258065Spjd    va_list nameap)
752258065Spjd{
753258065Spjd	nvpair_t *nvp;
754258065Spjd	char *name;
755258065Spjd	int namelen;
756258065Spjd
757258065Spjd	PJDLOG_ASSERT(type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST);
758258065Spjd
759258065Spjd	namelen = vasprintf(&name, namefmt, nameap);
760258065Spjd	if (namelen < 0)
761258065Spjd		return (NULL);
762258065Spjd
763258065Spjd	PJDLOG_ASSERT(namelen > 0);
764258065Spjd	if (namelen >= NV_NAME_MAX) {
765258065Spjd		free(name);
766258065Spjd		errno = ENAMETOOLONG;
767258065Spjd		return (NULL);
768258065Spjd	}
769258065Spjd
770258065Spjd	nvp = calloc(1, sizeof(*nvp) + namelen + 1);
771258065Spjd	if (nvp != NULL) {
772258065Spjd		nvp->nvp_name = (char *)(nvp + 1);
773258065Spjd		memcpy(nvp->nvp_name, name, namelen + 1);
774258065Spjd		nvp->nvp_type = type;
775258065Spjd		nvp->nvp_data = data;
776258065Spjd		nvp->nvp_datasize = datasize;
777258065Spjd		nvp->nvp_magic = NVPAIR_MAGIC;
778258065Spjd	}
779258065Spjd	free(name);
780258065Spjd
781258065Spjd	return (nvp);
782258065Spjd};
783258065Spjd
784258065Spjdnvpair_t *
785258065Spjdnvpair_create_null(const char *name)
786258065Spjd{
787258065Spjd
788258065Spjd	return (nvpair_createf_null("%s", name));
789258065Spjd}
790258065Spjd
791258065Spjdnvpair_t *
792258065Spjdnvpair_create_bool(const char *name, bool value)
793258065Spjd{
794258065Spjd
795258065Spjd	return (nvpair_createf_bool(value, "%s", name));
796258065Spjd}
797258065Spjd
798258065Spjdnvpair_t *
799258065Spjdnvpair_create_number(const char *name, uint64_t value)
800258065Spjd{
801258065Spjd
802258065Spjd	return (nvpair_createf_number(value, "%s", name));
803258065Spjd}
804258065Spjd
805258065Spjdnvpair_t *
806258065Spjdnvpair_create_string(const char *name, const char *value)
807258065Spjd{
808258065Spjd
809258065Spjd	return (nvpair_createf_string(value, "%s", name));
810258065Spjd}
811258065Spjd
812258065Spjdnvpair_t *
813258065Spjdnvpair_create_stringf(const char *name, const char *valuefmt, ...)
814258065Spjd{
815258065Spjd	va_list valueap;
816258065Spjd	nvpair_t *nvp;
817258065Spjd
818258065Spjd	va_start(valueap, valuefmt);
819258065Spjd	nvp = nvpair_create_stringv(name, valuefmt, valueap);
820258065Spjd	va_end(valueap);
821258065Spjd
822258065Spjd	return (nvp);
823258065Spjd}
824258065Spjd
825258065Spjdnvpair_t *
826258065Spjdnvpair_create_stringv(const char *name, const char *valuefmt, va_list valueap)
827258065Spjd{
828258065Spjd	nvpair_t *nvp;
829258065Spjd	char *str;
830258065Spjd	int len;
831258065Spjd
832258065Spjd	len = vasprintf(&str, valuefmt, valueap);
833258065Spjd	if (len < 0)
834258065Spjd		return (NULL);
835258065Spjd	nvp = nvpair_create_string(name, str);
836258065Spjd	if (nvp == NULL)
837258065Spjd		free(str);
838258065Spjd	return (nvp);
839258065Spjd}
840258065Spjd
841258065Spjdnvpair_t *
842258065Spjdnvpair_create_nvlist(const char *name, const nvlist_t *value)
843258065Spjd{
844258065Spjd
845258065Spjd	return (nvpair_createf_nvlist(value, "%s", name));
846258065Spjd}
847258065Spjd
848258065Spjdnvpair_t *
849258065Spjdnvpair_create_descriptor(const char *name, int value)
850258065Spjd{
851258065Spjd
852258065Spjd	return (nvpair_createf_descriptor(value, "%s", name));
853258065Spjd}
854258065Spjd
855258065Spjdnvpair_t *
856258065Spjdnvpair_create_binary(const char *name, const void *value, size_t size)
857258065Spjd{
858258065Spjd
859258065Spjd	return (nvpair_createf_binary(value, size, "%s", name));
860258065Spjd}
861258065Spjd
862258065Spjdnvpair_t *
863258065Spjdnvpair_createf_null(const char *namefmt, ...)
864258065Spjd{
865258065Spjd	va_list nameap;
866258065Spjd	nvpair_t *nvp;
867258065Spjd
868258065Spjd	va_start(nameap, namefmt);
869258065Spjd	nvp = nvpair_createv_null(namefmt, nameap);
870258065Spjd	va_end(nameap);
871258065Spjd
872258065Spjd	return (nvp);
873258065Spjd}
874258065Spjd
875258065Spjdnvpair_t *
876258065Spjdnvpair_createf_bool(bool value, const char *namefmt, ...)
877258065Spjd{
878258065Spjd	va_list nameap;
879258065Spjd	nvpair_t *nvp;
880258065Spjd
881258065Spjd	va_start(nameap, namefmt);
882258065Spjd	nvp = nvpair_createv_bool(value, namefmt, nameap);
883258065Spjd	va_end(nameap);
884258065Spjd
885258065Spjd	return (nvp);
886258065Spjd}
887258065Spjd
888258065Spjdnvpair_t *
889258065Spjdnvpair_createf_number(uint64_t value, const char *namefmt, ...)
890258065Spjd{
891258065Spjd	va_list nameap;
892258065Spjd	nvpair_t *nvp;
893258065Spjd
894258065Spjd	va_start(nameap, namefmt);
895258065Spjd	nvp = nvpair_createv_number(value, namefmt, nameap);
896258065Spjd	va_end(nameap);
897258065Spjd
898258065Spjd	return (nvp);
899258065Spjd}
900258065Spjd
901258065Spjdnvpair_t *
902258065Spjdnvpair_createf_string(const char *value, const char *namefmt, ...)
903258065Spjd{
904258065Spjd	va_list nameap;
905258065Spjd	nvpair_t *nvp;
906258065Spjd
907258065Spjd	va_start(nameap, namefmt);
908258065Spjd	nvp = nvpair_createv_string(value, namefmt, nameap);
909258065Spjd	va_end(nameap);
910258065Spjd
911258065Spjd	return (nvp);
912258065Spjd}
913258065Spjd
914258065Spjdnvpair_t *
915258065Spjdnvpair_createf_nvlist(const nvlist_t *value, const char *namefmt, ...)
916258065Spjd{
917258065Spjd	va_list nameap;
918258065Spjd	nvpair_t *nvp;
919258065Spjd
920258065Spjd	va_start(nameap, namefmt);
921258065Spjd	nvp = nvpair_createv_nvlist(value, namefmt, nameap);
922258065Spjd	va_end(nameap);
923258065Spjd
924258065Spjd	return (nvp);
925258065Spjd}
926258065Spjd
927258065Spjdnvpair_t *
928258065Spjdnvpair_createf_descriptor(int value, const char *namefmt, ...)
929258065Spjd{
930258065Spjd	va_list nameap;
931258065Spjd	nvpair_t *nvp;
932258065Spjd
933258065Spjd	va_start(nameap, namefmt);
934258065Spjd	nvp = nvpair_createv_descriptor(value, namefmt, nameap);
935258065Spjd	va_end(nameap);
936258065Spjd
937258065Spjd	return (nvp);
938258065Spjd}
939258065Spjd
940258065Spjdnvpair_t *
941258065Spjdnvpair_createf_binary(const void *value, size_t size, const char *namefmt, ...)
942258065Spjd{
943258065Spjd	va_list nameap;
944258065Spjd	nvpair_t *nvp;
945258065Spjd
946258065Spjd	va_start(nameap, namefmt);
947258065Spjd	nvp = nvpair_createv_binary(value, size, namefmt, nameap);
948258065Spjd	va_end(nameap);
949258065Spjd
950258065Spjd	return (nvp);
951258065Spjd}
952258065Spjd
953258065Spjdnvpair_t *
954258065Spjdnvpair_createv_null(const char *namefmt, va_list nameap)
955258065Spjd{
956258065Spjd
957258065Spjd	return (nvpair_allocv(NV_TYPE_NULL, 0, 0, namefmt, nameap));
958258065Spjd}
959258065Spjd
960258065Spjdnvpair_t *
961258065Spjdnvpair_createv_bool(bool value, const char *namefmt, va_list nameap)
962258065Spjd{
963258065Spjd
964258065Spjd	return (nvpair_allocv(NV_TYPE_BOOL, value ? 1 : 0, sizeof(uint8_t),
965258065Spjd	    namefmt, nameap));
966258065Spjd}
967258065Spjd
968258065Spjdnvpair_t *
969258065Spjdnvpair_createv_number(uint64_t value, const char *namefmt, va_list nameap)
970258065Spjd{
971258065Spjd
972258065Spjd	return (nvpair_allocv(NV_TYPE_NUMBER, value, sizeof(value), namefmt,
973258065Spjd	    nameap));
974258065Spjd}
975258065Spjd
976258065Spjdnvpair_t *
977258065Spjdnvpair_createv_string(const char *value, const char *namefmt, va_list nameap)
978258065Spjd{
979258065Spjd	nvpair_t *nvp;
980258065Spjd	size_t size;
981258065Spjd	char *data;
982258065Spjd
983258065Spjd	if (value == NULL) {
984258065Spjd		errno = EINVAL;
985258065Spjd		return (NULL);
986258065Spjd	}
987258065Spjd
988258065Spjd	data = strdup(value);
989258065Spjd	if (data == NULL)
990258065Spjd		return (NULL);
991258065Spjd	size = strlen(value) + 1;
992258065Spjd
993258065Spjd	nvp = nvpair_allocv(NV_TYPE_STRING, (uint64_t)(uintptr_t)data, size,
994258065Spjd	    namefmt, nameap);
995258065Spjd	if (nvp == NULL)
996258065Spjd		free(data);
997258065Spjd
998258065Spjd	return (nvp);
999258065Spjd}
1000258065Spjd
1001258065Spjdnvpair_t *
1002258065Spjdnvpair_createv_nvlist(const nvlist_t *value, const char *namefmt,
1003258065Spjd    va_list nameap)
1004258065Spjd{
1005258065Spjd	nvlist_t *nvl;
1006258065Spjd	nvpair_t *nvp;
1007258065Spjd
1008258065Spjd	if (value == NULL) {
1009258065Spjd		errno = EINVAL;
1010258065Spjd		return (NULL);
1011258065Spjd	}
1012258065Spjd
1013258065Spjd	nvl = nvlist_clone(value);
1014258065Spjd	if (nvl == NULL)
1015258065Spjd		return (NULL);
1016258065Spjd
1017258065Spjd	nvp = nvpair_allocv(NV_TYPE_NVLIST, (uint64_t)(uintptr_t)nvl, 0,
1018258065Spjd	    namefmt, nameap);
1019258065Spjd	if (nvp == NULL)
1020258065Spjd		nvlist_destroy(nvl);
1021258065Spjd
1022258065Spjd	return (nvp);
1023258065Spjd}
1024258065Spjd
1025258065Spjdnvpair_t *
1026258065Spjdnvpair_createv_descriptor(int value, const char *namefmt, va_list nameap)
1027258065Spjd{
1028258065Spjd	nvpair_t *nvp;
1029258065Spjd
1030258065Spjd	if (value < 0 || !fd_is_valid(value)) {
1031258065Spjd		errno = EBADF;
1032258065Spjd		return (NULL);
1033258065Spjd	}
1034258065Spjd
1035258065Spjd	value = fcntl(value, F_DUPFD_CLOEXEC, 0);
1036258065Spjd	if (value < 0)
1037258065Spjd		return (NULL);
1038258065Spjd
1039258065Spjd	nvp = nvpair_allocv(NV_TYPE_DESCRIPTOR, (uint64_t)value,
1040258065Spjd	    sizeof(int64_t), namefmt, nameap);
1041258065Spjd	if (nvp == NULL)
1042258065Spjd		close(value);
1043258065Spjd
1044258065Spjd	return (nvp);
1045258065Spjd}
1046258065Spjd
1047258065Spjdnvpair_t *
1048258065Spjdnvpair_createv_binary(const void *value, size_t size, const char *namefmt,
1049258065Spjd    va_list nameap)
1050258065Spjd{
1051258065Spjd	nvpair_t *nvp;
1052258065Spjd	void *data;
1053258065Spjd
1054258065Spjd	if (value == NULL || size == 0) {
1055258065Spjd		errno = EINVAL;
1056258065Spjd		return (NULL);
1057258065Spjd	}
1058258065Spjd
1059258065Spjd	data = malloc(size);
1060258065Spjd	if (data == NULL)
1061258065Spjd		return (NULL);
1062258065Spjd	memcpy(data, value, size);
1063258065Spjd
1064258065Spjd	nvp = nvpair_allocv(NV_TYPE_BINARY, (uint64_t)(uintptr_t)data, size,
1065258065Spjd	    namefmt, nameap);
1066258065Spjd	if (nvp == NULL)
1067258065Spjd		free(data);
1068258065Spjd
1069258065Spjd	return (nvp);
1070258065Spjd}
1071258065Spjd
1072258065Spjdnvpair_t *
1073258065Spjdnvpair_move_string(const char *name, char *value)
1074258065Spjd{
1075258065Spjd
1076258065Spjd	return (nvpair_movef_string(value, "%s", name));
1077258065Spjd}
1078258065Spjd
1079258065Spjdnvpair_t *
1080258065Spjdnvpair_move_nvlist(const char *name, nvlist_t *value)
1081258065Spjd{
1082258065Spjd
1083258065Spjd	return (nvpair_movef_nvlist(value, "%s", name));
1084258065Spjd}
1085258065Spjd
1086258065Spjdnvpair_t *
1087258065Spjdnvpair_move_descriptor(const char *name, int value)
1088258065Spjd{
1089258065Spjd
1090258065Spjd	return (nvpair_movef_descriptor(value, "%s", name));
1091258065Spjd}
1092258065Spjd
1093258065Spjdnvpair_t *
1094258065Spjdnvpair_move_binary(const char *name, void *value, size_t size)
1095258065Spjd{
1096258065Spjd
1097258065Spjd	return (nvpair_movef_binary(value, size, "%s", name));
1098258065Spjd}
1099258065Spjd
1100258065Spjdnvpair_t *
1101258065Spjdnvpair_movef_string(char *value, const char *namefmt, ...)
1102258065Spjd{
1103258065Spjd	va_list nameap;
1104258065Spjd	nvpair_t *nvp;
1105258065Spjd
1106258065Spjd	va_start(nameap, namefmt);
1107258065Spjd	nvp = nvpair_movev_string(value, namefmt, nameap);
1108258065Spjd	va_end(nameap);
1109258065Spjd
1110258065Spjd	return (nvp);
1111258065Spjd}
1112258065Spjd
1113258065Spjdnvpair_t *
1114258065Spjdnvpair_movef_nvlist(nvlist_t *value, const char *namefmt, ...)
1115258065Spjd{
1116258065Spjd	va_list nameap;
1117258065Spjd	nvpair_t *nvp;
1118258065Spjd
1119258065Spjd	va_start(nameap, namefmt);
1120258065Spjd	nvp = nvpair_movev_nvlist(value, namefmt, nameap);
1121258065Spjd	va_end(nameap);
1122258065Spjd
1123258065Spjd	return (nvp);
1124258065Spjd}
1125258065Spjd
1126258065Spjdnvpair_t *
1127258065Spjdnvpair_movef_descriptor(int value, const char *namefmt, ...)
1128258065Spjd{
1129258065Spjd	va_list nameap;
1130258065Spjd	nvpair_t *nvp;
1131258065Spjd
1132258065Spjd	va_start(nameap, namefmt);
1133258065Spjd	nvp = nvpair_movev_descriptor(value, namefmt, nameap);
1134258065Spjd	va_end(nameap);
1135258065Spjd
1136258065Spjd	return (nvp);
1137258065Spjd}
1138258065Spjd
1139258065Spjdnvpair_t *
1140258065Spjdnvpair_movef_binary(void *value, size_t size, const char *namefmt, ...)
1141258065Spjd{
1142258065Spjd	va_list nameap;
1143258065Spjd	nvpair_t *nvp;
1144258065Spjd
1145258065Spjd	va_start(nameap, namefmt);
1146258065Spjd	nvp = nvpair_movev_binary(value, size, namefmt, nameap);
1147258065Spjd	va_end(nameap);
1148258065Spjd
1149258065Spjd	return (nvp);
1150258065Spjd}
1151258065Spjd
1152258065Spjdnvpair_t *
1153258065Spjdnvpair_movev_string(char *value, const char *namefmt, va_list nameap)
1154258065Spjd{
1155258065Spjd	nvpair_t *nvp;
1156258065Spjd
1157258065Spjd	if (value == NULL) {
1158258065Spjd		errno = EINVAL;
1159258065Spjd		return (NULL);
1160258065Spjd	}
1161258065Spjd
1162258065Spjd	nvp = nvpair_allocv(NV_TYPE_STRING, (uint64_t)(uintptr_t)value,
1163258065Spjd	    strlen(value) + 1, namefmt, nameap);
1164258065Spjd	if (nvp == NULL)
1165258065Spjd		free(value);
1166258065Spjd
1167258065Spjd	return (nvp);
1168258065Spjd}
1169258065Spjd
1170258065Spjdnvpair_t *
1171258065Spjdnvpair_movev_nvlist(nvlist_t *value, const char *namefmt, va_list nameap)
1172258065Spjd{
1173258065Spjd	nvpair_t *nvp;
1174258065Spjd
1175258065Spjd	if (value == NULL) {
1176258065Spjd		errno = EINVAL;
1177258065Spjd		return (NULL);
1178258065Spjd	}
1179258065Spjd
1180258065Spjd	nvp = nvpair_allocv(NV_TYPE_NVLIST, (uint64_t)(uintptr_t)value, 0,
1181258065Spjd	    namefmt, nameap);
1182258065Spjd	if (nvp == NULL)
1183258065Spjd		nvlist_destroy(value);
1184258065Spjd
1185258065Spjd	return (nvp);
1186258065Spjd}
1187258065Spjd
1188258065Spjdnvpair_t *
1189258065Spjdnvpair_movev_descriptor(int value, const char *namefmt, va_list nameap)
1190258065Spjd{
1191258065Spjd
1192258065Spjd	if (value < 0 || !fd_is_valid(value)) {
1193258065Spjd		errno = EBADF;
1194258065Spjd		return (NULL);
1195258065Spjd	}
1196258065Spjd
1197258065Spjd	return (nvpair_allocv(NV_TYPE_DESCRIPTOR, (uint64_t)value,
1198258065Spjd	    sizeof(int64_t), namefmt, nameap));
1199258065Spjd}
1200258065Spjd
1201258065Spjdnvpair_t *
1202258065Spjdnvpair_movev_binary(void *value, size_t size, const char *namefmt,
1203258065Spjd    va_list nameap)
1204258065Spjd{
1205258065Spjd
1206258065Spjd	if (value == NULL || size == 0) {
1207258065Spjd		errno = EINVAL;
1208258065Spjd		return (NULL);
1209258065Spjd	}
1210258065Spjd
1211258065Spjd	return (nvpair_allocv(NV_TYPE_BINARY, (uint64_t)(uintptr_t)value, size,
1212258065Spjd	    namefmt, nameap));
1213258065Spjd}
1214258065Spjd
1215258065Spjdbool
1216258065Spjdnvpair_get_bool(const nvpair_t *nvp)
1217258065Spjd{
1218258065Spjd
1219258065Spjd	NVPAIR_ASSERT(nvp);
1220258065Spjd
1221258065Spjd	return (nvp->nvp_data == 1);
1222258065Spjd}
1223258065Spjd
1224258065Spjduint64_t
1225258065Spjdnvpair_get_number(const nvpair_t *nvp)
1226258065Spjd{
1227258065Spjd
1228258065Spjd	NVPAIR_ASSERT(nvp);
1229258065Spjd
1230258065Spjd	return (nvp->nvp_data);
1231258065Spjd}
1232258065Spjd
1233258065Spjdconst char *
1234258065Spjdnvpair_get_string(const nvpair_t *nvp)
1235258065Spjd{
1236258065Spjd
1237258065Spjd	NVPAIR_ASSERT(nvp);
1238258065Spjd	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
1239258065Spjd
1240258065Spjd	return ((const char *)(intptr_t)nvp->nvp_data);
1241258065Spjd}
1242258065Spjd
1243258065Spjdconst nvlist_t *
1244258065Spjdnvpair_get_nvlist(const nvpair_t *nvp)
1245258065Spjd{
1246258065Spjd
1247258065Spjd	NVPAIR_ASSERT(nvp);
1248258065Spjd	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST);
1249258065Spjd
1250258065Spjd	return ((const nvlist_t *)(intptr_t)nvp->nvp_data);
1251258065Spjd}
1252258065Spjd
1253258065Spjdint
1254258065Spjdnvpair_get_descriptor(const nvpair_t *nvp)
1255258065Spjd{
1256258065Spjd
1257258065Spjd	NVPAIR_ASSERT(nvp);
1258258065Spjd	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
1259258065Spjd
1260258065Spjd	return ((int)nvp->nvp_data);
1261258065Spjd}
1262258065Spjd
1263258065Spjdconst void *
1264258065Spjdnvpair_get_binary(const nvpair_t *nvp, size_t *sizep)
1265258065Spjd{
1266258065Spjd
1267258065Spjd	NVPAIR_ASSERT(nvp);
1268258065Spjd	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
1269258065Spjd
1270258065Spjd	if (sizep != NULL)
1271258065Spjd		*sizep = nvp->nvp_datasize;
1272258065Spjd	return ((const void *)(intptr_t)nvp->nvp_data);
1273258065Spjd}
1274258065Spjd
1275258065Spjdvoid
1276258065Spjdnvpair_free(nvpair_t *nvp)
1277258065Spjd{
1278258065Spjd
1279258065Spjd	NVPAIR_ASSERT(nvp);
1280258065Spjd	PJDLOG_ASSERT(nvp->nvp_list == NULL);
1281258065Spjd
1282258065Spjd	nvp->nvp_magic = 0;
1283258065Spjd	switch (nvp->nvp_type) {
1284258065Spjd	case NV_TYPE_DESCRIPTOR:
1285258065Spjd		close((int)nvp->nvp_data);
1286258065Spjd		break;
1287258065Spjd	case NV_TYPE_NVLIST:
1288258065Spjd		nvlist_destroy((nvlist_t *)(intptr_t)nvp->nvp_data);
1289258065Spjd		break;
1290258065Spjd	case NV_TYPE_STRING:
1291258065Spjd		free((char *)(intptr_t)nvp->nvp_data);
1292258065Spjd		break;
1293258065Spjd	case NV_TYPE_BINARY:
1294258065Spjd		free((void *)(intptr_t)nvp->nvp_data);
1295258065Spjd		break;
1296258065Spjd	}
1297258065Spjd	free(nvp);
1298258065Spjd}
1299258065Spjd
1300258065Spjdvoid
1301258065Spjdnvpair_free_structure(nvpair_t *nvp)
1302258065Spjd{
1303258065Spjd
1304258065Spjd	NVPAIR_ASSERT(nvp);
1305258065Spjd	PJDLOG_ASSERT(nvp->nvp_list == NULL);
1306258065Spjd
1307258065Spjd	nvp->nvp_magic = 0;
1308258065Spjd	free(nvp);
1309258065Spjd}
1310258065Spjd
1311258065Spjdconst char *
1312258065Spjdnvpair_type_string(int type)
1313258065Spjd{
1314258065Spjd
1315258065Spjd	switch (type) {
1316258065Spjd	case NV_TYPE_NULL:
1317258065Spjd		return ("NULL");
1318258065Spjd	case NV_TYPE_BOOL:
1319258065Spjd		return ("BOOL");
1320258065Spjd	case NV_TYPE_NUMBER:
1321258065Spjd		return ("NUMBER");
1322258065Spjd	case NV_TYPE_STRING:
1323258065Spjd		return ("STRING");
1324258065Spjd	case NV_TYPE_NVLIST:
1325258065Spjd		return ("NVLIST");
1326258065Spjd	case NV_TYPE_DESCRIPTOR:
1327258065Spjd		return ("DESCRIPTOR");
1328258065Spjd	case NV_TYPE_BINARY:
1329258065Spjd		return ("BINARY");
1330258065Spjd	default:
1331258065Spjd		return ("<UNKNOWN>");
1332258065Spjd	}
1333258065Spjd}
1334