subr_nvpair.c revision 292973
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: stable/10/sys/kern/subr_nvpair.c 292973 2015-12-31 03:28:14Z ngie $");
32
33#include <sys/param.h>
34#include <sys/endian.h>
35#include <sys/queue.h>
36
37#ifdef _KERNEL
38
39#include <sys/errno.h>
40#include <sys/lock.h>
41#include <sys/malloc.h>
42#include <sys/systm.h>
43
44#include <machine/stdarg.h>
45
46#else
47#include <errno.h>
48#include <fcntl.h>
49#include <stdarg.h>
50#include <stdbool.h>
51#include <stdint.h>
52#include <stdlib.h>
53#include <string.h>
54#include <unistd.h>
55
56#include "common_impl.h"
57#endif
58
59#ifdef HAVE_PJDLOG
60#include <pjdlog.h>
61#endif
62
63#include <sys/nv.h>
64#include <sys/nv_impl.h>
65#include <sys/nvlist_impl.h>
66#include <sys/nvpair_impl.h>
67
68#ifndef	HAVE_PJDLOG
69#ifdef _KERNEL
70#define	PJDLOG_ASSERT(...)		MPASS(__VA_ARGS__)
71#define	PJDLOG_RASSERT(expr, ...)	KASSERT(expr, (__VA_ARGS__))
72#define	PJDLOG_ABORT(...)		panic(__VA_ARGS__)
73#else
74#include <assert.h>
75#define	PJDLOG_ASSERT(...)		assert(__VA_ARGS__)
76#define	PJDLOG_RASSERT(expr, ...)	assert(expr)
77#define	PJDLOG_ABORT(...)		abort()
78#endif
79#endif
80
81#define	NVPAIR_MAGIC	0x6e7670	/* "nvp" */
82struct nvpair {
83	int		 nvp_magic;
84	char		*nvp_name;
85	int		 nvp_type;
86	uint64_t	 nvp_data;
87	size_t		 nvp_datasize;
88	nvlist_t	*nvp_list;
89	TAILQ_ENTRY(nvpair) nvp_next;
90};
91
92#define	NVPAIR_ASSERT(nvp)	do {					\
93	PJDLOG_ASSERT((nvp) != NULL);					\
94	PJDLOG_ASSERT((nvp)->nvp_magic == NVPAIR_MAGIC);		\
95} while (0)
96
97struct nvpair_header {
98	uint8_t		nvph_type;
99	uint16_t	nvph_namesize;
100	uint64_t	nvph_datasize;
101} __packed;
102
103
104void
105nvpair_assert(const nvpair_t *nvp)
106{
107
108	NVPAIR_ASSERT(nvp);
109}
110
111nvlist_t *
112nvpair_nvlist(const nvpair_t *nvp)
113{
114
115	NVPAIR_ASSERT(nvp);
116
117	return (nvp->nvp_list);
118}
119
120nvpair_t *
121nvpair_next(const nvpair_t *nvp)
122{
123
124	NVPAIR_ASSERT(nvp);
125	PJDLOG_ASSERT(nvp->nvp_list != NULL);
126
127	return (TAILQ_NEXT(nvp, nvp_next));
128}
129
130nvpair_t *
131nvpair_prev(const nvpair_t *nvp)
132{
133
134	NVPAIR_ASSERT(nvp);
135	PJDLOG_ASSERT(nvp->nvp_list != NULL);
136
137	return (TAILQ_PREV(nvp, nvl_head, nvp_next));
138}
139
140void
141nvpair_insert(struct nvl_head *head, nvpair_t *nvp, nvlist_t *nvl)
142{
143
144	NVPAIR_ASSERT(nvp);
145	PJDLOG_ASSERT(nvp->nvp_list == NULL);
146	PJDLOG_ASSERT(!nvlist_exists(nvl, nvpair_name(nvp)));
147
148	TAILQ_INSERT_TAIL(head, nvp, nvp_next);
149	nvp->nvp_list = nvl;
150}
151
152static void
153nvpair_remove_nvlist(nvpair_t *nvp)
154{
155	nvlist_t *nvl;
156
157	/* XXX: DECONST is bad, mkay? */
158	nvl = __DECONST(nvlist_t *, nvpair_get_nvlist(nvp));
159	PJDLOG_ASSERT(nvl != NULL);
160	nvlist_set_parent(nvl, NULL);
161}
162
163void
164nvpair_remove(struct nvl_head *head, nvpair_t *nvp, const nvlist_t *nvl)
165{
166
167	NVPAIR_ASSERT(nvp);
168	PJDLOG_ASSERT(nvp->nvp_list == nvl);
169
170	if (nvpair_type(nvp) == NV_TYPE_NVLIST)
171		nvpair_remove_nvlist(nvp);
172
173	TAILQ_REMOVE(head, nvp, nvp_next);
174	nvp->nvp_list = NULL;
175}
176
177nvpair_t *
178nvpair_clone(const nvpair_t *nvp)
179{
180	nvpair_t *newnvp;
181	const char *name;
182	const void *data;
183	size_t datasize;
184
185	NVPAIR_ASSERT(nvp);
186
187	name = nvpair_name(nvp);
188
189	switch (nvpair_type(nvp)) {
190	case NV_TYPE_NULL:
191		newnvp = nvpair_create_null(name);
192		break;
193	case NV_TYPE_BOOL:
194		newnvp = nvpair_create_bool(name, nvpair_get_bool(nvp));
195		break;
196	case NV_TYPE_NUMBER:
197		newnvp = nvpair_create_number(name, nvpair_get_number(nvp));
198		break;
199	case NV_TYPE_STRING:
200		newnvp = nvpair_create_string(name, nvpair_get_string(nvp));
201		break;
202	case NV_TYPE_NVLIST:
203		newnvp = nvpair_create_nvlist(name, nvpair_get_nvlist(nvp));
204		break;
205#ifndef _KERNEL
206	case NV_TYPE_DESCRIPTOR:
207		newnvp = nvpair_create_descriptor(name,
208		    nvpair_get_descriptor(nvp));
209		break;
210#endif
211	case NV_TYPE_BINARY:
212		data = nvpair_get_binary(nvp, &datasize);
213		newnvp = nvpair_create_binary(name, data, datasize);
214		break;
215	default:
216		PJDLOG_ABORT("Unknown type: %d.", nvpair_type(nvp));
217	}
218
219	return (newnvp);
220}
221
222size_t
223nvpair_header_size(void)
224{
225
226	return (sizeof(struct nvpair_header));
227}
228
229size_t
230nvpair_size(const nvpair_t *nvp)
231{
232
233	NVPAIR_ASSERT(nvp);
234
235	return (nvp->nvp_datasize);
236}
237
238unsigned char *
239nvpair_pack_header(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
240{
241	struct nvpair_header nvphdr;
242	size_t namesize;
243
244	NVPAIR_ASSERT(nvp);
245
246	nvphdr.nvph_type = nvp->nvp_type;
247	namesize = strlen(nvp->nvp_name) + 1;
248	PJDLOG_ASSERT(namesize > 0 && namesize <= UINT16_MAX);
249	nvphdr.nvph_namesize = namesize;
250	nvphdr.nvph_datasize = nvp->nvp_datasize;
251	PJDLOG_ASSERT(*leftp >= sizeof(nvphdr));
252	memcpy(ptr, &nvphdr, sizeof(nvphdr));
253	ptr += sizeof(nvphdr);
254	*leftp -= sizeof(nvphdr);
255
256	PJDLOG_ASSERT(*leftp >= namesize);
257	memcpy(ptr, nvp->nvp_name, namesize);
258	ptr += namesize;
259	*leftp -= namesize;
260
261	return (ptr);
262}
263
264unsigned char *
265nvpair_pack_null(const nvpair_t *nvp, unsigned char *ptr,
266    size_t *leftp __unused)
267{
268
269	NVPAIR_ASSERT(nvp);
270	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NULL);
271
272	return (ptr);
273}
274
275unsigned char *
276nvpair_pack_bool(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
277{
278	uint8_t value;
279
280	NVPAIR_ASSERT(nvp);
281	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL);
282
283	value = (uint8_t)nvp->nvp_data;
284
285	PJDLOG_ASSERT(*leftp >= sizeof(value));
286	memcpy(ptr, &value, sizeof(value));
287	ptr += sizeof(value);
288	*leftp -= sizeof(value);
289
290	return (ptr);
291}
292
293unsigned char *
294nvpair_pack_number(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
295{
296	uint64_t value;
297
298	NVPAIR_ASSERT(nvp);
299	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER);
300
301	value = (uint64_t)nvp->nvp_data;
302
303	PJDLOG_ASSERT(*leftp >= sizeof(value));
304	memcpy(ptr, &value, sizeof(value));
305	ptr += sizeof(value);
306	*leftp -= sizeof(value);
307
308	return (ptr);
309}
310
311unsigned char *
312nvpair_pack_string(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
313{
314
315	NVPAIR_ASSERT(nvp);
316	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
317
318	PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
319	memcpy(ptr, (const void *)(intptr_t)nvp->nvp_data, nvp->nvp_datasize);
320	ptr += nvp->nvp_datasize;
321	*leftp -= nvp->nvp_datasize;
322
323	return (ptr);
324}
325
326unsigned char *
327nvpair_pack_nvlist_up(unsigned char *ptr, size_t *leftp)
328{
329	struct nvpair_header nvphdr;
330	size_t namesize;
331	const char *name = "";
332
333	namesize = 1;
334	nvphdr.nvph_type = NV_TYPE_NVLIST_UP;
335	nvphdr.nvph_namesize = namesize;
336	nvphdr.nvph_datasize = 0;
337	PJDLOG_ASSERT(*leftp >= sizeof(nvphdr));
338	memcpy(ptr, &nvphdr, sizeof(nvphdr));
339	ptr += sizeof(nvphdr);
340	*leftp -= sizeof(nvphdr);
341
342	PJDLOG_ASSERT(*leftp >= namesize);
343	memcpy(ptr, name, namesize);
344	ptr += namesize;
345	*leftp -= namesize;
346
347	return (ptr);
348}
349
350#ifndef _KERNEL
351unsigned char *
352nvpair_pack_descriptor(const nvpair_t *nvp, unsigned char *ptr, int64_t *fdidxp,
353    size_t *leftp)
354{
355	int64_t value;
356
357	NVPAIR_ASSERT(nvp);
358	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
359
360	value = (int64_t)nvp->nvp_data;
361	if (value != -1) {
362		/*
363		 * If there is a real descriptor here, we change its number
364		 * to position in the array of descriptors send via control
365		 * message.
366		 */
367		PJDLOG_ASSERT(fdidxp != NULL);
368
369		value = *fdidxp;
370		(*fdidxp)++;
371	}
372
373	PJDLOG_ASSERT(*leftp >= sizeof(value));
374	memcpy(ptr, &value, sizeof(value));
375	ptr += sizeof(value);
376	*leftp -= sizeof(value);
377
378	return (ptr);
379}
380#endif
381
382unsigned char *
383nvpair_pack_binary(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
384{
385
386	NVPAIR_ASSERT(nvp);
387	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
388
389	PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
390	memcpy(ptr, (const void *)(intptr_t)nvp->nvp_data, nvp->nvp_datasize);
391	ptr += nvp->nvp_datasize;
392	*leftp -= nvp->nvp_datasize;
393
394	return (ptr);
395}
396
397void
398nvpair_init_datasize(nvpair_t *nvp)
399{
400
401	NVPAIR_ASSERT(nvp);
402
403	if (nvp->nvp_type == NV_TYPE_NVLIST) {
404		if (nvp->nvp_data == 0) {
405			nvp->nvp_datasize = 0;
406		} else {
407			nvp->nvp_datasize =
408			    nvlist_size((const nvlist_t *)(intptr_t)nvp->nvp_data);
409		}
410	}
411}
412
413const unsigned char *
414nvpair_unpack_header(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
415    size_t *leftp)
416{
417	struct nvpair_header nvphdr;
418
419	if (*leftp < sizeof(nvphdr))
420		goto failed;
421
422	memcpy(&nvphdr, ptr, sizeof(nvphdr));
423	ptr += sizeof(nvphdr);
424	*leftp -= sizeof(nvphdr);
425
426#if NV_TYPE_FIRST > 0
427	if (nvphdr.nvph_type < NV_TYPE_FIRST)
428		goto failed;
429#endif
430	if (nvphdr.nvph_type > NV_TYPE_LAST &&
431	    nvphdr.nvph_type != NV_TYPE_NVLIST_UP) {
432		goto failed;
433	}
434
435#if BYTE_ORDER == BIG_ENDIAN
436	if (!isbe) {
437		nvphdr.nvph_namesize = le16toh(nvphdr.nvph_namesize);
438		nvphdr.nvph_datasize = le64toh(nvphdr.nvph_datasize);
439	}
440#else
441	if (isbe) {
442		nvphdr.nvph_namesize = be16toh(nvphdr.nvph_namesize);
443		nvphdr.nvph_datasize = be64toh(nvphdr.nvph_datasize);
444	}
445#endif
446
447	if (nvphdr.nvph_namesize > NV_NAME_MAX)
448		goto failed;
449	if (*leftp < nvphdr.nvph_namesize)
450		goto failed;
451	if (nvphdr.nvph_namesize < 1)
452		goto failed;
453	if (strnlen((const char *)ptr, nvphdr.nvph_namesize) !=
454	    (size_t)(nvphdr.nvph_namesize - 1)) {
455		goto failed;
456	}
457
458	memcpy(nvp->nvp_name, ptr, nvphdr.nvph_namesize);
459	ptr += nvphdr.nvph_namesize;
460	*leftp -= nvphdr.nvph_namesize;
461
462	if (*leftp < nvphdr.nvph_datasize)
463		goto failed;
464
465	nvp->nvp_type = nvphdr.nvph_type;
466	nvp->nvp_data = 0;
467	nvp->nvp_datasize = nvphdr.nvph_datasize;
468
469	return (ptr);
470failed:
471	RESTORE_ERRNO(EINVAL);
472	return (NULL);
473}
474
475const unsigned char *
476nvpair_unpack_null(bool isbe __unused, nvpair_t *nvp, const unsigned char *ptr,
477    size_t *leftp __unused)
478{
479
480	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NULL);
481
482	if (nvp->nvp_datasize != 0) {
483		RESTORE_ERRNO(EINVAL);
484		return (NULL);
485	}
486
487	return (ptr);
488}
489
490const unsigned char *
491nvpair_unpack_bool(bool isbe __unused, nvpair_t *nvp, const unsigned char *ptr,
492    size_t *leftp)
493{
494	uint8_t value;
495
496	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL);
497
498	if (nvp->nvp_datasize != sizeof(value)) {
499		RESTORE_ERRNO(EINVAL);
500		return (NULL);
501	}
502	if (*leftp < sizeof(value)) {
503		RESTORE_ERRNO(EINVAL);
504		return (NULL);
505	}
506
507	memcpy(&value, ptr, sizeof(value));
508	ptr += sizeof(value);
509	*leftp -= sizeof(value);
510
511	if (value != 0 && value != 1) {
512		RESTORE_ERRNO(EINVAL);
513		return (NULL);
514	}
515
516	nvp->nvp_data = (uint64_t)value;
517
518	return (ptr);
519}
520
521const unsigned char *
522nvpair_unpack_number(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
523     size_t *leftp)
524{
525
526	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER);
527
528	if (nvp->nvp_datasize != sizeof(uint64_t)) {
529		RESTORE_ERRNO(EINVAL);
530		return (NULL);
531	}
532	if (*leftp < sizeof(uint64_t)) {
533		RESTORE_ERRNO(EINVAL);
534		return (NULL);
535	}
536
537	if (isbe)
538		nvp->nvp_data = be64dec(ptr);
539	else
540		nvp->nvp_data = le64dec(ptr);
541	ptr += sizeof(uint64_t);
542	*leftp -= sizeof(uint64_t);
543
544	return (ptr);
545}
546
547const unsigned char *
548nvpair_unpack_string(bool isbe __unused, nvpair_t *nvp,
549    const unsigned char *ptr, size_t *leftp)
550{
551
552	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
553
554	if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
555		RESTORE_ERRNO(EINVAL);
556		return (NULL);
557	}
558
559	if (strnlen((const char *)ptr, nvp->nvp_datasize) !=
560	    nvp->nvp_datasize - 1) {
561		RESTORE_ERRNO(EINVAL);
562		return (NULL);
563	}
564
565	nvp->nvp_data = (uint64_t)(uintptr_t)nv_strdup((const char *)ptr);
566	if (nvp->nvp_data == 0)
567		return (NULL);
568
569	ptr += nvp->nvp_datasize;
570	*leftp -= nvp->nvp_datasize;
571
572	return (ptr);
573}
574
575const unsigned char *
576nvpair_unpack_nvlist(bool isbe __unused, nvpair_t *nvp,
577    const unsigned char *ptr, size_t *leftp, size_t nfds, nvlist_t **child)
578{
579	nvlist_t *value;
580
581	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST);
582
583	if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
584		RESTORE_ERRNO(EINVAL);
585		return (NULL);
586	}
587
588	value = nvlist_create(0);
589	if (value == NULL)
590		return (NULL);
591
592	ptr = nvlist_unpack_header(value, ptr, nfds, NULL, leftp);
593	if (ptr == NULL)
594		return (NULL);
595
596	nvp->nvp_data = (uint64_t)(uintptr_t)value;
597	*child = value;
598
599	return (ptr);
600}
601
602#ifndef _KERNEL
603const unsigned char *
604nvpair_unpack_descriptor(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
605    size_t *leftp, const int *fds, size_t nfds)
606{
607	int64_t idx;
608
609	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
610
611	if (nvp->nvp_datasize != sizeof(idx)) {
612		errno = EINVAL;
613		return (NULL);
614	}
615	if (*leftp < sizeof(idx)) {
616		errno = EINVAL;
617		return (NULL);
618	}
619
620	if (isbe)
621		idx = be64dec(ptr);
622	else
623		idx = le64dec(ptr);
624
625	if (idx < 0) {
626		errno = EINVAL;
627		return (NULL);
628	}
629
630	if ((size_t)idx >= nfds) {
631		errno = EINVAL;
632		return (NULL);
633	}
634
635	nvp->nvp_data = (uint64_t)fds[idx];
636
637	ptr += sizeof(idx);
638	*leftp -= sizeof(idx);
639
640	return (ptr);
641}
642#endif
643
644const unsigned char *
645nvpair_unpack_binary(bool isbe __unused, nvpair_t *nvp,
646    const unsigned char *ptr, size_t *leftp)
647{
648	void *value;
649
650	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
651
652	if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
653		RESTORE_ERRNO(EINVAL);
654		return (NULL);
655	}
656
657	value = nv_malloc(nvp->nvp_datasize);
658	if (value == NULL)
659		return (NULL);
660
661	memcpy(value, ptr, nvp->nvp_datasize);
662	ptr += nvp->nvp_datasize;
663	*leftp -= nvp->nvp_datasize;
664
665	nvp->nvp_data = (uint64_t)(uintptr_t)value;
666
667	return (ptr);
668}
669
670const unsigned char *
671nvpair_unpack(bool isbe, const unsigned char *ptr, size_t *leftp,
672    nvpair_t **nvpp)
673{
674	nvpair_t *nvp, *tmp;
675
676	nvp = nv_calloc(1, sizeof(*nvp) + NV_NAME_MAX);
677	if (nvp == NULL)
678		return (NULL);
679	nvp->nvp_name = (char *)(nvp + 1);
680
681	ptr = nvpair_unpack_header(isbe, nvp, ptr, leftp);
682	if (ptr == NULL)
683		goto failed;
684	tmp = nv_realloc(nvp, sizeof(*nvp) + strlen(nvp->nvp_name) + 1);
685	if (tmp == NULL)
686		goto failed;
687	nvp = tmp;
688
689	/* Update nvp_name after realloc(). */
690	nvp->nvp_name = (char *)(nvp + 1);
691	nvp->nvp_data = 0x00;
692	nvp->nvp_magic = NVPAIR_MAGIC;
693	*nvpp = nvp;
694	return (ptr);
695failed:
696	nv_free(nvp);
697	return (NULL);
698}
699
700int
701nvpair_type(const nvpair_t *nvp)
702{
703
704	NVPAIR_ASSERT(nvp);
705
706	return (nvp->nvp_type);
707}
708
709const char *
710nvpair_name(const nvpair_t *nvp)
711{
712
713	NVPAIR_ASSERT(nvp);
714
715	return (nvp->nvp_name);
716}
717
718static nvpair_t *
719nvpair_allocv(const char *name, int type, uint64_t data, size_t datasize)
720{
721	nvpair_t *nvp;
722	size_t namelen;
723
724	PJDLOG_ASSERT(type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST);
725
726	namelen = strlen(name);
727	if (namelen >= NV_NAME_MAX) {
728		RESTORE_ERRNO(ENAMETOOLONG);
729		return (NULL);
730	}
731
732	nvp = nv_calloc(1, sizeof(*nvp) + namelen + 1);
733	if (nvp != NULL) {
734		nvp->nvp_name = (char *)(nvp + 1);
735		memcpy(nvp->nvp_name, name, namelen);
736		nvp->nvp_name[namelen + 1] = '\0';
737		nvp->nvp_type = type;
738		nvp->nvp_data = data;
739		nvp->nvp_datasize = datasize;
740		nvp->nvp_magic = NVPAIR_MAGIC;
741	}
742
743	return (nvp);
744};
745
746nvpair_t *
747nvpair_create_stringf(const char *name, const char *valuefmt, ...)
748{
749	va_list valueap;
750	nvpair_t *nvp;
751
752	va_start(valueap, valuefmt);
753	nvp = nvpair_create_stringv(name, valuefmt, valueap);
754	va_end(valueap);
755
756	return (nvp);
757}
758
759nvpair_t *
760nvpair_create_stringv(const char *name, const char *valuefmt, va_list valueap)
761{
762	nvpair_t *nvp;
763	char *str;
764	int len;
765
766	len = nv_vasprintf(&str, valuefmt, valueap);
767	if (len < 0)
768		return (NULL);
769	nvp = nvpair_create_string(name, str);
770	if (nvp == NULL)
771		nv_free(str);
772	return (nvp);
773}
774
775nvpair_t *
776nvpair_create_null(const char *name)
777{
778
779	return (nvpair_allocv(name, NV_TYPE_NULL, 0, 0));
780}
781
782nvpair_t *
783nvpair_create_bool(const char *name, bool value)
784{
785
786	return (nvpair_allocv(name, NV_TYPE_BOOL, value ? 1 : 0,
787	    sizeof(uint8_t)));
788}
789
790nvpair_t *
791nvpair_create_number(const char *name, uint64_t value)
792{
793
794	return (nvpair_allocv(name, NV_TYPE_NUMBER, value, sizeof(value)));
795}
796
797nvpair_t *
798nvpair_create_string(const char *name, const char *value)
799{
800	nvpair_t *nvp;
801	size_t size;
802	char *data;
803
804	if (value == NULL) {
805		RESTORE_ERRNO(EINVAL);
806		return (NULL);
807	}
808
809	data = nv_strdup(value);
810	if (data == NULL)
811		return (NULL);
812	size = strlen(value) + 1;
813
814	nvp = nvpair_allocv(name, NV_TYPE_STRING, (uint64_t)(uintptr_t)data,
815	    size);
816	if (nvp == NULL)
817		nv_free(data);
818
819	return (nvp);
820}
821
822nvpair_t *
823nvpair_create_nvlist(const char *name, const nvlist_t *value)
824{
825	nvlist_t *nvl;
826	nvpair_t *nvp;
827
828	if (value == NULL) {
829		RESTORE_ERRNO(EINVAL);
830		return (NULL);
831	}
832
833	nvl = nvlist_clone(value);
834	if (nvl == NULL)
835		return (NULL);
836
837	nvp = nvpair_allocv(name, NV_TYPE_NVLIST, (uint64_t)(uintptr_t)nvl, 0);
838	if (nvp == NULL)
839		nvlist_destroy(nvl);
840	else
841		nvlist_set_parent(nvl, nvp);
842
843	return (nvp);
844}
845
846#ifndef _KERNEL
847nvpair_t *
848nvpair_create_descriptor(const char *name, int value)
849{
850	nvpair_t *nvp;
851
852	if (value < 0 || !fd_is_valid(value)) {
853		errno = EBADF;
854		return (NULL);
855	}
856
857	value = fcntl(value, F_DUPFD_CLOEXEC, 0);
858	if (value < 0)
859		return (NULL);
860
861	nvp = nvpair_allocv(name, NV_TYPE_DESCRIPTOR, (uint64_t)value,
862	    sizeof(int64_t));
863	if (nvp == NULL)
864		close(value);
865
866	return (nvp);
867}
868#endif
869
870nvpair_t *
871nvpair_create_binary(const char *name, const void *value, size_t size)
872{
873	nvpair_t *nvp;
874	void *data;
875
876	if (value == NULL || size == 0) {
877		RESTORE_ERRNO(EINVAL);
878		return (NULL);
879	}
880
881	data = nv_malloc(size);
882	if (data == NULL)
883		return (NULL);
884	memcpy(data, value, size);
885
886	nvp = nvpair_allocv(name, NV_TYPE_BINARY, (uint64_t)(uintptr_t)data,
887	    size);
888	if (nvp == NULL)
889		nv_free(data);
890
891	return (nvp);
892}
893
894nvpair_t *
895nvpair_move_string(const char *name, char *value)
896{
897	nvpair_t *nvp;
898	int serrno;
899
900	if (value == NULL) {
901		RESTORE_ERRNO(EINVAL);
902		return (NULL);
903	}
904
905	nvp = nvpair_allocv(name, NV_TYPE_STRING, (uint64_t)(uintptr_t)value,
906	    strlen(value) + 1);
907	if (nvp == NULL) {
908		SAVE_ERRNO(serrno);
909		nv_free(value);
910		RESTORE_ERRNO(serrno);
911	}
912
913	return (nvp);
914}
915
916nvpair_t *
917nvpair_move_nvlist(const char *name, nvlist_t *value)
918{
919	nvpair_t *nvp;
920
921	if (value == NULL || nvlist_get_nvpair_parent(value) != NULL) {
922		RESTORE_ERRNO(EINVAL);
923		return (NULL);
924	}
925
926	if (nvlist_error(value) != 0) {
927		RESTORE_ERRNO(nvlist_error(value));
928		nvlist_destroy(value);
929		return (NULL);
930	}
931
932	nvp = nvpair_allocv(name, NV_TYPE_NVLIST, (uint64_t)(uintptr_t)value,
933	    0);
934	if (nvp == NULL)
935		nvlist_destroy(value);
936	else
937		nvlist_set_parent(value, nvp);
938
939	return (nvp);
940}
941
942#ifndef _KERNEL
943nvpair_t *
944nvpair_move_descriptor(const char *name, int value)
945{
946	nvpair_t *nvp;
947	int serrno;
948
949	if (value < 0 || !fd_is_valid(value)) {
950		errno = EBADF;
951		return (NULL);
952	}
953
954	nvp = nvpair_allocv(name, NV_TYPE_DESCRIPTOR, (uint64_t)value,
955	    sizeof(int64_t));
956	if (nvp == NULL) {
957		serrno = errno;
958		close(value);
959		errno = serrno;
960	}
961
962	return (nvp);
963}
964#endif
965
966nvpair_t *
967nvpair_move_binary(const char *name, void *value, size_t size)
968{
969	nvpair_t *nvp;
970	int serrno;
971
972	if (value == NULL || size == 0) {
973		RESTORE_ERRNO(EINVAL);
974		return (NULL);
975	}
976
977	nvp = nvpair_allocv(name, NV_TYPE_BINARY, (uint64_t)(uintptr_t)value,
978	    size);
979	if (nvp == NULL) {
980		SAVE_ERRNO(serrno);
981		nv_free(value);
982		RESTORE_ERRNO(serrno);
983	}
984
985	return (nvp);
986}
987
988bool
989nvpair_get_bool(const nvpair_t *nvp)
990{
991
992	NVPAIR_ASSERT(nvp);
993
994	return (nvp->nvp_data == 1);
995}
996
997uint64_t
998nvpair_get_number(const nvpair_t *nvp)
999{
1000
1001	NVPAIR_ASSERT(nvp);
1002
1003	return (nvp->nvp_data);
1004}
1005
1006const char *
1007nvpair_get_string(const nvpair_t *nvp)
1008{
1009
1010	NVPAIR_ASSERT(nvp);
1011	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
1012
1013	return ((const char *)(intptr_t)nvp->nvp_data);
1014}
1015
1016const nvlist_t *
1017nvpair_get_nvlist(const nvpair_t *nvp)
1018{
1019
1020	NVPAIR_ASSERT(nvp);
1021	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST);
1022
1023	return ((const nvlist_t *)(intptr_t)nvp->nvp_data);
1024}
1025
1026#ifndef _KERNEL
1027int
1028nvpair_get_descriptor(const nvpair_t *nvp)
1029{
1030
1031	NVPAIR_ASSERT(nvp);
1032	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
1033
1034	return ((int)nvp->nvp_data);
1035}
1036#endif
1037
1038const void *
1039nvpair_get_binary(const nvpair_t *nvp, size_t *sizep)
1040{
1041
1042	NVPAIR_ASSERT(nvp);
1043	PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
1044
1045	if (sizep != NULL)
1046		*sizep = nvp->nvp_datasize;
1047	return ((const void *)(intptr_t)nvp->nvp_data);
1048}
1049
1050void
1051nvpair_free(nvpair_t *nvp)
1052{
1053
1054	NVPAIR_ASSERT(nvp);
1055	PJDLOG_ASSERT(nvp->nvp_list == NULL);
1056
1057	nvp->nvp_magic = 0;
1058	switch (nvp->nvp_type) {
1059#ifndef _KERNEL
1060	case NV_TYPE_DESCRIPTOR:
1061		close((int)nvp->nvp_data);
1062		break;
1063#endif
1064	case NV_TYPE_NVLIST:
1065		nvlist_destroy((nvlist_t *)(intptr_t)nvp->nvp_data);
1066		break;
1067	case NV_TYPE_STRING:
1068		nv_free((char *)(intptr_t)nvp->nvp_data);
1069		break;
1070	case NV_TYPE_BINARY:
1071		nv_free((void *)(intptr_t)nvp->nvp_data);
1072		break;
1073	}
1074	nv_free(nvp);
1075}
1076
1077void
1078nvpair_free_structure(nvpair_t *nvp)
1079{
1080
1081	NVPAIR_ASSERT(nvp);
1082	PJDLOG_ASSERT(nvp->nvp_list == NULL);
1083
1084	nvp->nvp_magic = 0;
1085	nv_free(nvp);
1086}
1087
1088const char *
1089nvpair_type_string(int type)
1090{
1091
1092	switch (type) {
1093	case NV_TYPE_NULL:
1094		return ("NULL");
1095	case NV_TYPE_BOOL:
1096		return ("BOOL");
1097	case NV_TYPE_NUMBER:
1098		return ("NUMBER");
1099	case NV_TYPE_STRING:
1100		return ("STRING");
1101	case NV_TYPE_NVLIST:
1102		return ("NVLIST");
1103	case NV_TYPE_DESCRIPTOR:
1104		return ("DESCRIPTOR");
1105	case NV_TYPE_BINARY:
1106		return ("BINARY");
1107	default:
1108		return ("<UNKNOWN>");
1109	}
1110}
1111
1112