xref: /freebsd/sys/contrib/openzfs/module/nvpair/nvpair.c (revision 071ab5a1f3cbfd29c8fbec27f7e619418adaf074)
161145dc2SMartin Matuska // SPDX-License-Identifier: CDDL-1.0
2eda14cbcSMatt Macy /*
3eda14cbcSMatt Macy  * CDDL HEADER START
4eda14cbcSMatt Macy  *
5eda14cbcSMatt Macy  * The contents of this file are subject to the terms of the
6eda14cbcSMatt Macy  * Common Development and Distribution License (the "License").
7eda14cbcSMatt Macy  * You may not use this file except in compliance with the License.
8eda14cbcSMatt Macy  *
9eda14cbcSMatt Macy  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10271171e0SMartin Matuska  * or https://opensource.org/licenses/CDDL-1.0.
11eda14cbcSMatt Macy  * See the License for the specific language governing permissions
12eda14cbcSMatt Macy  * and limitations under the License.
13eda14cbcSMatt Macy  *
14eda14cbcSMatt Macy  * When distributing Covered Code, include this CDDL HEADER in each
15eda14cbcSMatt Macy  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16eda14cbcSMatt Macy  * If applicable, add the following below this CDDL HEADER, with the
17eda14cbcSMatt Macy  * fields enclosed by brackets "[]" replaced with your own identifying
18eda14cbcSMatt Macy  * information: Portions Copyright [yyyy] [name of copyright owner]
19eda14cbcSMatt Macy  *
20eda14cbcSMatt Macy  * CDDL HEADER END
21eda14cbcSMatt Macy  */
22eda14cbcSMatt Macy 
23eda14cbcSMatt Macy /*
24eda14cbcSMatt Macy  * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
25eda14cbcSMatt Macy  * Copyright (c) 2015, 2017 by Delphix. All rights reserved.
26eda14cbcSMatt Macy  * Copyright 2018 RackTop Systems.
27eda14cbcSMatt Macy  */
28eda14cbcSMatt Macy 
29eac7052fSMatt Macy /*
30eac7052fSMatt Macy  * Links to Illumos.org for more information on Interface Libraries:
31eac7052fSMatt Macy  * [1] https://illumos.org/man/3lib/libnvpair
32eac7052fSMatt Macy  * [2] https://illumos.org/man/3nvpair/nvlist_alloc
33eac7052fSMatt Macy  * [3] https://illumos.org/man/9f/nvlist_alloc
34eac7052fSMatt Macy  * [4] https://illumos.org/man/9f/nvlist_next_nvpair
35eac7052fSMatt Macy  * [5] https://illumos.org/man/9f/nvpair_value_byte
36eac7052fSMatt Macy  */
37eac7052fSMatt Macy 
38eda14cbcSMatt Macy #include <sys/debug.h>
39eda14cbcSMatt Macy #include <sys/isa_defs.h>
40eda14cbcSMatt Macy #include <sys/nvpair.h>
41eda14cbcSMatt Macy #include <sys/nvpair_impl.h>
42eda14cbcSMatt Macy #include <sys/types.h>
43eda14cbcSMatt Macy #include <sys/param.h>
44da5137abSMartin Matuska #include <sys/string.h>
451719886fSMartin Matuska #include <rpc/types.h>
46eda14cbcSMatt Macy #include <rpc/xdr.h>
47eda14cbcSMatt Macy #include <sys/mod.h>
48eda14cbcSMatt Macy 
49eda14cbcSMatt Macy #if defined(_KERNEL)
50eda14cbcSMatt Macy #include <sys/sunddi.h>
51eda14cbcSMatt Macy #include <sys/sysmacros.h>
52eda14cbcSMatt Macy #else
53eda14cbcSMatt Macy #include <stdarg.h>
54eda14cbcSMatt Macy #include <stdlib.h>
55eda14cbcSMatt Macy #include <stddef.h>
56eda14cbcSMatt Macy #endif
57eda14cbcSMatt Macy 
58da5137abSMartin Matuska #define	skip_whitespace(p)	while ((*(p) == ' ') || (*(p) == '\t')) (p)++
59eda14cbcSMatt Macy 
60eda14cbcSMatt Macy /*
61eda14cbcSMatt Macy  * nvpair.c - Provides kernel & userland interfaces for manipulating
62eda14cbcSMatt Macy  *	name-value pairs.
63eda14cbcSMatt Macy  *
64eda14cbcSMatt Macy  * Overview Diagram
65eda14cbcSMatt Macy  *
66eda14cbcSMatt Macy  *  +--------------+
67eda14cbcSMatt Macy  *  |  nvlist_t    |
68eda14cbcSMatt Macy  *  |--------------|
69eda14cbcSMatt Macy  *  | nvl_version  |
70eda14cbcSMatt Macy  *  | nvl_nvflag   |
71eda14cbcSMatt Macy  *  | nvl_priv    -+-+
72eda14cbcSMatt Macy  *  | nvl_flag     | |
73eda14cbcSMatt Macy  *  | nvl_pad      | |
74eda14cbcSMatt Macy  *  +--------------+ |
75eda14cbcSMatt Macy  *                   V
76eda14cbcSMatt Macy  *      +--------------+      last i_nvp in list
77eda14cbcSMatt Macy  *      | nvpriv_t     |  +--------------------->
78eda14cbcSMatt Macy  *      |--------------|  |
79eda14cbcSMatt Macy  *   +--+- nvp_list    |  |   +------------+
80eda14cbcSMatt Macy  *   |  |  nvp_last   -+--+   + nv_alloc_t |
81eda14cbcSMatt Macy  *   |  |  nvp_curr    |      |------------|
82eda14cbcSMatt Macy  *   |  |  nvp_nva    -+----> | nva_ops    |
83eda14cbcSMatt Macy  *   |  |  nvp_stat    |      | nva_arg    |
84eda14cbcSMatt Macy  *   |  +--------------+      +------------+
85eda14cbcSMatt Macy  *   |
86eda14cbcSMatt Macy  *   +-------+
87eda14cbcSMatt Macy  *           V
88eda14cbcSMatt Macy  *   +---------------------+      +-------------------+
89eda14cbcSMatt Macy  *   |  i_nvp_t            |  +-->|  i_nvp_t          |  +-->
90eda14cbcSMatt Macy  *   |---------------------|  |   |-------------------|  |
91eda14cbcSMatt Macy  *   | nvi_next           -+--+   | nvi_next         -+--+
92eda14cbcSMatt Macy  *   | nvi_prev (NULL)     | <----+ nvi_prev          |
93eda14cbcSMatt Macy  *   | . . . . . . . . . . |      | . . . . . . . . . |
94eda14cbcSMatt Macy  *   | nvp (nvpair_t)      |      | nvp (nvpair_t)    |
95eda14cbcSMatt Macy  *   |  - nvp_size         |      |  - nvp_size       |
96eda14cbcSMatt Macy  *   |  - nvp_name_sz      |      |  - nvp_name_sz    |
97eda14cbcSMatt Macy  *   |  - nvp_value_elem   |      |  - nvp_value_elem |
98eda14cbcSMatt Macy  *   |  - nvp_type         |      |  - nvp_type       |
99eda14cbcSMatt Macy  *   |  - data ...         |      |  - data ...       |
100eda14cbcSMatt Macy  *   +---------------------+      +-------------------+
101eda14cbcSMatt Macy  *
102eda14cbcSMatt Macy  *
103eda14cbcSMatt Macy  *
104eda14cbcSMatt Macy  *   +---------------------+              +---------------------+
105eda14cbcSMatt Macy  *   |  i_nvp_t            |  +-->    +-->|  i_nvp_t (last)     |
106eda14cbcSMatt Macy  *   |---------------------|  |       |   |---------------------|
107eda14cbcSMatt Macy  *   |  nvi_next          -+--+ ... --+   | nvi_next (NULL)     |
108eda14cbcSMatt Macy  * <-+- nvi_prev           |<-- ...  <----+ nvi_prev            |
109eda14cbcSMatt Macy  *   | . . . . . . . . .   |              | . . . . . . . . .   |
110eda14cbcSMatt Macy  *   | nvp (nvpair_t)      |              | nvp (nvpair_t)      |
111eda14cbcSMatt Macy  *   |  - nvp_size         |              |  - nvp_size         |
112eda14cbcSMatt Macy  *   |  - nvp_name_sz      |              |  - nvp_name_sz      |
113eda14cbcSMatt Macy  *   |  - nvp_value_elem   |              |  - nvp_value_elem   |
114eda14cbcSMatt Macy  *   |  - DATA_TYPE_NVLIST |              |  - nvp_type         |
115eda14cbcSMatt Macy  *   |  - data (embedded)  |              |  - data ...         |
116eda14cbcSMatt Macy  *   |    nvlist name      |              +---------------------+
117eda14cbcSMatt Macy  *   |  +--------------+   |
118eda14cbcSMatt Macy  *   |  |  nvlist_t    |   |
119eda14cbcSMatt Macy  *   |  |--------------|   |
120eda14cbcSMatt Macy  *   |  | nvl_version  |   |
121eda14cbcSMatt Macy  *   |  | nvl_nvflag   |   |
122eda14cbcSMatt Macy  *   |  | nvl_priv   --+---+---->
123eda14cbcSMatt Macy  *   |  | nvl_flag     |   |
124eda14cbcSMatt Macy  *   |  | nvl_pad      |   |
125eda14cbcSMatt Macy  *   |  +--------------+   |
126eda14cbcSMatt Macy  *   +---------------------+
127eda14cbcSMatt Macy  *
128eda14cbcSMatt Macy  *
129eda14cbcSMatt Macy  * N.B. nvpair_t may be aligned on 4 byte boundary, so +4 will
130eda14cbcSMatt Macy  * allow value to be aligned on 8 byte boundary
131eda14cbcSMatt Macy  *
132eda14cbcSMatt Macy  * name_len is the length of the name string including the null terminator
133eda14cbcSMatt Macy  * so it must be >= 1
134eda14cbcSMatt Macy  */
135eda14cbcSMatt Macy #define	NVP_SIZE_CALC(name_len, data_len) \
136eda14cbcSMatt Macy 	(NV_ALIGN((sizeof (nvpair_t)) + name_len) + NV_ALIGN(data_len))
137eda14cbcSMatt Macy 
138eda14cbcSMatt Macy static int i_get_value_size(data_type_t type, const void *data, uint_t nelem);
139eda14cbcSMatt Macy static int nvlist_add_common(nvlist_t *nvl, const char *name, data_type_t type,
140eda14cbcSMatt Macy     uint_t nelem, const void *data);
141eda14cbcSMatt Macy 
142eda14cbcSMatt Macy #define	NV_STAT_EMBEDDED	0x1
143eda14cbcSMatt Macy #define	EMBEDDED_NVL(nvp)	((nvlist_t *)(void *)NVP_VALUE(nvp))
144eda14cbcSMatt Macy #define	EMBEDDED_NVL_ARRAY(nvp)	((nvlist_t **)(void *)NVP_VALUE(nvp))
145eda14cbcSMatt Macy 
146eda14cbcSMatt Macy #define	NVP_VALOFF(nvp)	(NV_ALIGN(sizeof (nvpair_t) + (nvp)->nvp_name_sz))
147eda14cbcSMatt Macy #define	NVPAIR2I_NVP(nvp) \
148eda14cbcSMatt Macy 	((i_nvp_t *)((size_t)(nvp) - offsetof(i_nvp_t, nvi_nvp)))
149eda14cbcSMatt Macy 
150eda14cbcSMatt Macy #ifdef _KERNEL
151e92ffd9bSMartin Matuska static const int nvpair_max_recursion = 20;
152eda14cbcSMatt Macy #else
153e92ffd9bSMartin Matuska static const int nvpair_max_recursion = 100;
154eda14cbcSMatt Macy #endif
155eda14cbcSMatt Macy 
156e92ffd9bSMartin Matuska static const uint64_t nvlist_hashtable_init_size = (1 << 4);
157eda14cbcSMatt Macy 
158eda14cbcSMatt Macy int
nv_alloc_init(nv_alloc_t * nva,const nv_alloc_ops_t * nvo,...)159eda14cbcSMatt Macy nv_alloc_init(nv_alloc_t *nva, const nv_alloc_ops_t *nvo, /* args */ ...)
160eda14cbcSMatt Macy {
161eda14cbcSMatt Macy 	va_list valist;
162eda14cbcSMatt Macy 	int err = 0;
163eda14cbcSMatt Macy 
164eda14cbcSMatt Macy 	nva->nva_ops = nvo;
165eda14cbcSMatt Macy 	nva->nva_arg = NULL;
166eda14cbcSMatt Macy 
167eda14cbcSMatt Macy 	va_start(valist, nvo);
168eda14cbcSMatt Macy 	if (nva->nva_ops->nv_ao_init != NULL)
169eda14cbcSMatt Macy 		err = nva->nva_ops->nv_ao_init(nva, valist);
170eda14cbcSMatt Macy 	va_end(valist);
171eda14cbcSMatt Macy 
172eda14cbcSMatt Macy 	return (err);
173eda14cbcSMatt Macy }
174eda14cbcSMatt Macy 
175eda14cbcSMatt Macy void
nv_alloc_reset(nv_alloc_t * nva)176eda14cbcSMatt Macy nv_alloc_reset(nv_alloc_t *nva)
177eda14cbcSMatt Macy {
178eda14cbcSMatt Macy 	if (nva->nva_ops->nv_ao_reset != NULL)
179eda14cbcSMatt Macy 		nva->nva_ops->nv_ao_reset(nva);
180eda14cbcSMatt Macy }
181eda14cbcSMatt Macy 
182eda14cbcSMatt Macy void
nv_alloc_fini(nv_alloc_t * nva)183eda14cbcSMatt Macy nv_alloc_fini(nv_alloc_t *nva)
184eda14cbcSMatt Macy {
185eda14cbcSMatt Macy 	if (nva->nva_ops->nv_ao_fini != NULL)
186eda14cbcSMatt Macy 		nva->nva_ops->nv_ao_fini(nva);
187eda14cbcSMatt Macy }
188eda14cbcSMatt Macy 
189eda14cbcSMatt Macy nv_alloc_t *
nvlist_lookup_nv_alloc(nvlist_t * nvl)190eda14cbcSMatt Macy nvlist_lookup_nv_alloc(nvlist_t *nvl)
191eda14cbcSMatt Macy {
192eda14cbcSMatt Macy 	nvpriv_t *priv;
193eda14cbcSMatt Macy 
194eda14cbcSMatt Macy 	if (nvl == NULL ||
195eda14cbcSMatt Macy 	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
196eda14cbcSMatt Macy 		return (NULL);
197eda14cbcSMatt Macy 
198eda14cbcSMatt Macy 	return (priv->nvp_nva);
199eda14cbcSMatt Macy }
200eda14cbcSMatt Macy 
201eda14cbcSMatt Macy static void *
nv_mem_zalloc(nvpriv_t * nvp,size_t size)202eda14cbcSMatt Macy nv_mem_zalloc(nvpriv_t *nvp, size_t size)
203eda14cbcSMatt Macy {
204eda14cbcSMatt Macy 	nv_alloc_t *nva = nvp->nvp_nva;
205eda14cbcSMatt Macy 	void *buf;
206eda14cbcSMatt Macy 
207eda14cbcSMatt Macy 	if ((buf = nva->nva_ops->nv_ao_alloc(nva, size)) != NULL)
208da5137abSMartin Matuska 		memset(buf, 0, size);
209eda14cbcSMatt Macy 
210eda14cbcSMatt Macy 	return (buf);
211eda14cbcSMatt Macy }
212eda14cbcSMatt Macy 
213eda14cbcSMatt Macy static void
nv_mem_free(nvpriv_t * nvp,void * buf,size_t size)214eda14cbcSMatt Macy nv_mem_free(nvpriv_t *nvp, void *buf, size_t size)
215eda14cbcSMatt Macy {
216eda14cbcSMatt Macy 	nv_alloc_t *nva = nvp->nvp_nva;
217eda14cbcSMatt Macy 
218eda14cbcSMatt Macy 	nva->nva_ops->nv_ao_free(nva, buf, size);
219eda14cbcSMatt Macy }
220eda14cbcSMatt Macy 
221eda14cbcSMatt Macy static void
nv_priv_init(nvpriv_t * priv,nv_alloc_t * nva,uint32_t stat)222eda14cbcSMatt Macy nv_priv_init(nvpriv_t *priv, nv_alloc_t *nva, uint32_t stat)
223eda14cbcSMatt Macy {
224da5137abSMartin Matuska 	memset(priv, 0, sizeof (nvpriv_t));
225eda14cbcSMatt Macy 
226eda14cbcSMatt Macy 	priv->nvp_nva = nva;
227eda14cbcSMatt Macy 	priv->nvp_stat = stat;
228eda14cbcSMatt Macy }
229eda14cbcSMatt Macy 
230eda14cbcSMatt Macy static nvpriv_t *
nv_priv_alloc(nv_alloc_t * nva)231eda14cbcSMatt Macy nv_priv_alloc(nv_alloc_t *nva)
232eda14cbcSMatt Macy {
233eda14cbcSMatt Macy 	nvpriv_t *priv;
234eda14cbcSMatt Macy 
235eda14cbcSMatt Macy 	/*
236eda14cbcSMatt Macy 	 * nv_mem_alloc() cannot called here because it needs the priv
237eda14cbcSMatt Macy 	 * argument.
238eda14cbcSMatt Macy 	 */
239eda14cbcSMatt Macy 	if ((priv = nva->nva_ops->nv_ao_alloc(nva, sizeof (nvpriv_t))) == NULL)
240eda14cbcSMatt Macy 		return (NULL);
241eda14cbcSMatt Macy 
242eda14cbcSMatt Macy 	nv_priv_init(priv, nva, 0);
243eda14cbcSMatt Macy 
244eda14cbcSMatt Macy 	return (priv);
245eda14cbcSMatt Macy }
246eda14cbcSMatt Macy 
247eda14cbcSMatt Macy /*
248eda14cbcSMatt Macy  * Embedded lists need their own nvpriv_t's.  We create a new
249eda14cbcSMatt Macy  * nvpriv_t using the parameters and allocator from the parent
250eda14cbcSMatt Macy  * list's nvpriv_t.
251eda14cbcSMatt Macy  */
252eda14cbcSMatt Macy static nvpriv_t *
nv_priv_alloc_embedded(nvpriv_t * priv)253eda14cbcSMatt Macy nv_priv_alloc_embedded(nvpriv_t *priv)
254eda14cbcSMatt Macy {
255eda14cbcSMatt Macy 	nvpriv_t *emb_priv;
256eda14cbcSMatt Macy 
257eda14cbcSMatt Macy 	if ((emb_priv = nv_mem_zalloc(priv, sizeof (nvpriv_t))) == NULL)
258eda14cbcSMatt Macy 		return (NULL);
259eda14cbcSMatt Macy 
260eda14cbcSMatt Macy 	nv_priv_init(emb_priv, priv->nvp_nva, NV_STAT_EMBEDDED);
261eda14cbcSMatt Macy 
262eda14cbcSMatt Macy 	return (emb_priv);
263eda14cbcSMatt Macy }
264eda14cbcSMatt Macy 
265eda14cbcSMatt Macy static int
nvt_tab_alloc(nvpriv_t * priv,uint64_t buckets)266eda14cbcSMatt Macy nvt_tab_alloc(nvpriv_t *priv, uint64_t buckets)
267eda14cbcSMatt Macy {
268eda14cbcSMatt Macy 	ASSERT3P(priv->nvp_hashtable, ==, NULL);
269eda14cbcSMatt Macy 	ASSERT0(priv->nvp_nbuckets);
270eda14cbcSMatt Macy 	ASSERT0(priv->nvp_nentries);
271eda14cbcSMatt Macy 
272eda14cbcSMatt Macy 	i_nvp_t **tab = nv_mem_zalloc(priv, buckets * sizeof (i_nvp_t *));
273eda14cbcSMatt Macy 	if (tab == NULL)
274eda14cbcSMatt Macy 		return (ENOMEM);
275eda14cbcSMatt Macy 
276eda14cbcSMatt Macy 	priv->nvp_hashtable = tab;
277eda14cbcSMatt Macy 	priv->nvp_nbuckets = buckets;
278eda14cbcSMatt Macy 	return (0);
279eda14cbcSMatt Macy }
280eda14cbcSMatt Macy 
281eda14cbcSMatt Macy static void
nvt_tab_free(nvpriv_t * priv)282eda14cbcSMatt Macy nvt_tab_free(nvpriv_t *priv)
283eda14cbcSMatt Macy {
284eda14cbcSMatt Macy 	i_nvp_t **tab = priv->nvp_hashtable;
285eda14cbcSMatt Macy 	if (tab == NULL) {
286eda14cbcSMatt Macy 		ASSERT0(priv->nvp_nbuckets);
287eda14cbcSMatt Macy 		ASSERT0(priv->nvp_nentries);
288eda14cbcSMatt Macy 		return;
289eda14cbcSMatt Macy 	}
290eda14cbcSMatt Macy 
291eda14cbcSMatt Macy 	nv_mem_free(priv, tab, priv->nvp_nbuckets * sizeof (i_nvp_t *));
292eda14cbcSMatt Macy 
293eda14cbcSMatt Macy 	priv->nvp_hashtable = NULL;
294eda14cbcSMatt Macy 	priv->nvp_nbuckets = 0;
295eda14cbcSMatt Macy 	priv->nvp_nentries = 0;
296eda14cbcSMatt Macy }
297eda14cbcSMatt Macy 
298eda14cbcSMatt Macy static uint32_t
nvt_hash(const char * p)299eda14cbcSMatt Macy nvt_hash(const char *p)
300eda14cbcSMatt Macy {
301eda14cbcSMatt Macy 	uint32_t g, hval = 0;
302eda14cbcSMatt Macy 
303eda14cbcSMatt Macy 	while (*p) {
304eda14cbcSMatt Macy 		hval = (hval << 4) + *p++;
305eda14cbcSMatt Macy 		if ((g = (hval & 0xf0000000)) != 0)
306eda14cbcSMatt Macy 			hval ^= g >> 24;
307eda14cbcSMatt Macy 		hval &= ~g;
308eda14cbcSMatt Macy 	}
309eda14cbcSMatt Macy 	return (hval);
310eda14cbcSMatt Macy }
311eda14cbcSMatt Macy 
312eda14cbcSMatt Macy static boolean_t
nvt_nvpair_match(const nvpair_t * nvp1,const nvpair_t * nvp2,uint32_t nvflag)313681ce946SMartin Matuska nvt_nvpair_match(const nvpair_t *nvp1, const nvpair_t *nvp2, uint32_t nvflag)
314eda14cbcSMatt Macy {
315eda14cbcSMatt Macy 	boolean_t match = B_FALSE;
316eda14cbcSMatt Macy 	if (nvflag & NV_UNIQUE_NAME_TYPE) {
317eda14cbcSMatt Macy 		if (strcmp(NVP_NAME(nvp1), NVP_NAME(nvp2)) == 0 &&
318eda14cbcSMatt Macy 		    NVP_TYPE(nvp1) == NVP_TYPE(nvp2))
319eda14cbcSMatt Macy 			match = B_TRUE;
320eda14cbcSMatt Macy 	} else {
321eda14cbcSMatt Macy 		ASSERT(nvflag == 0 || nvflag & NV_UNIQUE_NAME);
322eda14cbcSMatt Macy 		if (strcmp(NVP_NAME(nvp1), NVP_NAME(nvp2)) == 0)
323eda14cbcSMatt Macy 			match = B_TRUE;
324eda14cbcSMatt Macy 	}
325eda14cbcSMatt Macy 	return (match);
326eda14cbcSMatt Macy }
327eda14cbcSMatt Macy 
328eda14cbcSMatt Macy static nvpair_t *
nvt_lookup_name_type(const nvlist_t * nvl,const char * name,data_type_t type)329681ce946SMartin Matuska nvt_lookup_name_type(const nvlist_t *nvl, const char *name, data_type_t type)
330eda14cbcSMatt Macy {
331681ce946SMartin Matuska 	const nvpriv_t *priv = (const nvpriv_t *)(uintptr_t)nvl->nvl_priv;
332eda14cbcSMatt Macy 	ASSERT(priv != NULL);
333eda14cbcSMatt Macy 
334eda14cbcSMatt Macy 	i_nvp_t **tab = priv->nvp_hashtable;
335eda14cbcSMatt Macy 
336eda14cbcSMatt Macy 	if (tab == NULL) {
337eda14cbcSMatt Macy 		ASSERT3P(priv->nvp_list, ==, NULL);
338eda14cbcSMatt Macy 		ASSERT0(priv->nvp_nbuckets);
339eda14cbcSMatt Macy 		ASSERT0(priv->nvp_nentries);
340eda14cbcSMatt Macy 		return (NULL);
341eda14cbcSMatt Macy 	} else {
342eda14cbcSMatt Macy 		ASSERT(priv->nvp_nbuckets != 0);
343eda14cbcSMatt Macy 	}
344eda14cbcSMatt Macy 
345eda14cbcSMatt Macy 	uint64_t hash = nvt_hash(name);
346eda14cbcSMatt Macy 	uint64_t index = hash & (priv->nvp_nbuckets - 1);
347eda14cbcSMatt Macy 
348eda14cbcSMatt Macy 	ASSERT3U(index, <, priv->nvp_nbuckets);
349eda14cbcSMatt Macy 	i_nvp_t *entry = tab[index];
350eda14cbcSMatt Macy 
351eda14cbcSMatt Macy 	for (i_nvp_t *e = entry; e != NULL; e = e->nvi_hashtable_next) {
352eda14cbcSMatt Macy 		if (strcmp(NVP_NAME(&e->nvi_nvp), name) == 0 &&
353eda14cbcSMatt Macy 		    (type == DATA_TYPE_DONTCARE ||
354eda14cbcSMatt Macy 		    NVP_TYPE(&e->nvi_nvp) == type))
355eda14cbcSMatt Macy 			return (&e->nvi_nvp);
356eda14cbcSMatt Macy 	}
357eda14cbcSMatt Macy 	return (NULL);
358eda14cbcSMatt Macy }
359eda14cbcSMatt Macy 
360eda14cbcSMatt Macy static nvpair_t *
nvt_lookup_name(const nvlist_t * nvl,const char * name)361681ce946SMartin Matuska nvt_lookup_name(const nvlist_t *nvl, const char *name)
362eda14cbcSMatt Macy {
363eda14cbcSMatt Macy 	return (nvt_lookup_name_type(nvl, name, DATA_TYPE_DONTCARE));
364eda14cbcSMatt Macy }
365eda14cbcSMatt Macy 
366eda14cbcSMatt Macy static int
nvt_resize(nvpriv_t * priv,uint32_t new_size)367eda14cbcSMatt Macy nvt_resize(nvpriv_t *priv, uint32_t new_size)
368eda14cbcSMatt Macy {
369eda14cbcSMatt Macy 	i_nvp_t **tab = priv->nvp_hashtable;
370eda14cbcSMatt Macy 
371eda14cbcSMatt Macy 	/*
372eda14cbcSMatt Macy 	 * Migrate all the entries from the current table
373eda14cbcSMatt Macy 	 * to a newly-allocated table with the new size by
374eda14cbcSMatt Macy 	 * re-adjusting the pointers of their entries.
375eda14cbcSMatt Macy 	 */
376eda14cbcSMatt Macy 	uint32_t size = priv->nvp_nbuckets;
377eda14cbcSMatt Macy 	uint32_t new_mask = new_size - 1;
378eda14cbcSMatt Macy 	ASSERT(ISP2(new_size));
379eda14cbcSMatt Macy 
380eda14cbcSMatt Macy 	i_nvp_t **new_tab = nv_mem_zalloc(priv, new_size * sizeof (i_nvp_t *));
381eda14cbcSMatt Macy 	if (new_tab == NULL)
382eda14cbcSMatt Macy 		return (ENOMEM);
383eda14cbcSMatt Macy 
384eda14cbcSMatt Macy 	uint32_t nentries = 0;
385eda14cbcSMatt Macy 	for (uint32_t i = 0; i < size; i++) {
386eda14cbcSMatt Macy 		i_nvp_t *next, *e = tab[i];
387eda14cbcSMatt Macy 
388eda14cbcSMatt Macy 		while (e != NULL) {
389eda14cbcSMatt Macy 			next = e->nvi_hashtable_next;
390eda14cbcSMatt Macy 
391eda14cbcSMatt Macy 			uint32_t hash = nvt_hash(NVP_NAME(&e->nvi_nvp));
392eda14cbcSMatt Macy 			uint32_t index = hash & new_mask;
393eda14cbcSMatt Macy 
394eda14cbcSMatt Macy 			e->nvi_hashtable_next = new_tab[index];
395eda14cbcSMatt Macy 			new_tab[index] = e;
396eda14cbcSMatt Macy 			nentries++;
397eda14cbcSMatt Macy 
398eda14cbcSMatt Macy 			e = next;
399eda14cbcSMatt Macy 		}
400eda14cbcSMatt Macy 		tab[i] = NULL;
401eda14cbcSMatt Macy 	}
402eda14cbcSMatt Macy 	ASSERT3U(nentries, ==, priv->nvp_nentries);
403eda14cbcSMatt Macy 
404eda14cbcSMatt Macy 	nvt_tab_free(priv);
405eda14cbcSMatt Macy 
406eda14cbcSMatt Macy 	priv->nvp_hashtable = new_tab;
407eda14cbcSMatt Macy 	priv->nvp_nbuckets = new_size;
408eda14cbcSMatt Macy 	priv->nvp_nentries = nentries;
409eda14cbcSMatt Macy 
410eda14cbcSMatt Macy 	return (0);
411eda14cbcSMatt Macy }
412eda14cbcSMatt Macy 
413eda14cbcSMatt Macy static boolean_t
nvt_needs_togrow(nvpriv_t * priv)414eda14cbcSMatt Macy nvt_needs_togrow(nvpriv_t *priv)
415eda14cbcSMatt Macy {
416eda14cbcSMatt Macy 	/*
417eda14cbcSMatt Macy 	 * Grow only when we have more elements than buckets
418eda14cbcSMatt Macy 	 * and the # of buckets doesn't overflow.
419eda14cbcSMatt Macy 	 */
420eda14cbcSMatt Macy 	return (priv->nvp_nentries > priv->nvp_nbuckets &&
421eda14cbcSMatt Macy 	    (UINT32_MAX >> 1) >= priv->nvp_nbuckets);
422eda14cbcSMatt Macy }
423eda14cbcSMatt Macy 
424eda14cbcSMatt Macy /*
425eda14cbcSMatt Macy  * Allocate a new table that's twice the size of the old one,
426eda14cbcSMatt Macy  * and migrate all the entries from the old one to the new
427eda14cbcSMatt Macy  * one by re-adjusting their pointers.
428eda14cbcSMatt Macy  */
429eda14cbcSMatt Macy static int
nvt_grow(nvpriv_t * priv)430eda14cbcSMatt Macy nvt_grow(nvpriv_t *priv)
431eda14cbcSMatt Macy {
432eda14cbcSMatt Macy 	uint32_t current_size = priv->nvp_nbuckets;
433eda14cbcSMatt Macy 	/* ensure we won't overflow */
434eda14cbcSMatt Macy 	ASSERT3U(UINT32_MAX >> 1, >=, current_size);
435eda14cbcSMatt Macy 	return (nvt_resize(priv, current_size << 1));
436eda14cbcSMatt Macy }
437eda14cbcSMatt Macy 
438eda14cbcSMatt Macy static boolean_t
nvt_needs_toshrink(nvpriv_t * priv)439eda14cbcSMatt Macy nvt_needs_toshrink(nvpriv_t *priv)
440eda14cbcSMatt Macy {
441eda14cbcSMatt Macy 	/*
442eda14cbcSMatt Macy 	 * Shrink only when the # of elements is less than or
443eda14cbcSMatt Macy 	 * equal to 1/4 the # of buckets. Never shrink less than
444eda14cbcSMatt Macy 	 * nvlist_hashtable_init_size.
445eda14cbcSMatt Macy 	 */
446eda14cbcSMatt Macy 	ASSERT3U(priv->nvp_nbuckets, >=, nvlist_hashtable_init_size);
447eda14cbcSMatt Macy 	if (priv->nvp_nbuckets == nvlist_hashtable_init_size)
448eda14cbcSMatt Macy 		return (B_FALSE);
449eda14cbcSMatt Macy 	return (priv->nvp_nentries <= (priv->nvp_nbuckets >> 2));
450eda14cbcSMatt Macy }
451eda14cbcSMatt Macy 
452eda14cbcSMatt Macy /*
453eda14cbcSMatt Macy  * Allocate a new table that's half the size of the old one,
454eda14cbcSMatt Macy  * and migrate all the entries from the old one to the new
455eda14cbcSMatt Macy  * one by re-adjusting their pointers.
456eda14cbcSMatt Macy  */
457eda14cbcSMatt Macy static int
nvt_shrink(nvpriv_t * priv)458eda14cbcSMatt Macy nvt_shrink(nvpriv_t *priv)
459eda14cbcSMatt Macy {
460eda14cbcSMatt Macy 	uint32_t current_size = priv->nvp_nbuckets;
461eda14cbcSMatt Macy 	/* ensure we won't overflow */
462eda14cbcSMatt Macy 	ASSERT3U(current_size, >=, nvlist_hashtable_init_size);
463eda14cbcSMatt Macy 	return (nvt_resize(priv, current_size >> 1));
464eda14cbcSMatt Macy }
465eda14cbcSMatt Macy 
466eda14cbcSMatt Macy static int
nvt_remove_nvpair(nvlist_t * nvl,const nvpair_t * nvp)467681ce946SMartin Matuska nvt_remove_nvpair(nvlist_t *nvl, const nvpair_t *nvp)
468eda14cbcSMatt Macy {
469eda14cbcSMatt Macy 	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
470eda14cbcSMatt Macy 
471eda14cbcSMatt Macy 	if (nvt_needs_toshrink(priv)) {
472eda14cbcSMatt Macy 		int err = nvt_shrink(priv);
473eda14cbcSMatt Macy 		if (err != 0)
474eda14cbcSMatt Macy 			return (err);
475eda14cbcSMatt Macy 	}
476eda14cbcSMatt Macy 	i_nvp_t **tab = priv->nvp_hashtable;
477eda14cbcSMatt Macy 
4782a58b312SMartin Matuska 	const char *name = NVP_NAME(nvp);
479eda14cbcSMatt Macy 	uint64_t hash = nvt_hash(name);
480eda14cbcSMatt Macy 	uint64_t index = hash & (priv->nvp_nbuckets - 1);
481eda14cbcSMatt Macy 
482eda14cbcSMatt Macy 	ASSERT3U(index, <, priv->nvp_nbuckets);
483eda14cbcSMatt Macy 	i_nvp_t *bucket = tab[index];
484eda14cbcSMatt Macy 
485eda14cbcSMatt Macy 	for (i_nvp_t *prev = NULL, *e = bucket;
486eda14cbcSMatt Macy 	    e != NULL; prev = e, e = e->nvi_hashtable_next) {
487eda14cbcSMatt Macy 		if (nvt_nvpair_match(&e->nvi_nvp, nvp, nvl->nvl_nvflag)) {
488eda14cbcSMatt Macy 			if (prev != NULL) {
489eda14cbcSMatt Macy 				prev->nvi_hashtable_next =
490eda14cbcSMatt Macy 				    e->nvi_hashtable_next;
491eda14cbcSMatt Macy 			} else {
492eda14cbcSMatt Macy 				ASSERT3P(e, ==, bucket);
493eda14cbcSMatt Macy 				tab[index] = e->nvi_hashtable_next;
494eda14cbcSMatt Macy 			}
495eda14cbcSMatt Macy 			e->nvi_hashtable_next = NULL;
496eda14cbcSMatt Macy 			priv->nvp_nentries--;
497eda14cbcSMatt Macy 			break;
498eda14cbcSMatt Macy 		}
499eda14cbcSMatt Macy 	}
500eda14cbcSMatt Macy 
501eda14cbcSMatt Macy 	return (0);
502eda14cbcSMatt Macy }
503eda14cbcSMatt Macy 
504eda14cbcSMatt Macy static int
nvt_add_nvpair(nvlist_t * nvl,nvpair_t * nvp)505eda14cbcSMatt Macy nvt_add_nvpair(nvlist_t *nvl, nvpair_t *nvp)
506eda14cbcSMatt Macy {
507eda14cbcSMatt Macy 	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
508eda14cbcSMatt Macy 
509eda14cbcSMatt Macy 	/* initialize nvpair table now if it doesn't exist. */
510eda14cbcSMatt Macy 	if (priv->nvp_hashtable == NULL) {
511eda14cbcSMatt Macy 		int err = nvt_tab_alloc(priv, nvlist_hashtable_init_size);
512eda14cbcSMatt Macy 		if (err != 0)
513eda14cbcSMatt Macy 			return (err);
514eda14cbcSMatt Macy 	}
515eda14cbcSMatt Macy 
516eda14cbcSMatt Macy 	/*
517eda14cbcSMatt Macy 	 * if we don't allow duplicate entries, make sure to
518eda14cbcSMatt Macy 	 * unlink any existing entries from the table.
519eda14cbcSMatt Macy 	 */
520eda14cbcSMatt Macy 	if (nvl->nvl_nvflag != 0) {
521eda14cbcSMatt Macy 		int err = nvt_remove_nvpair(nvl, nvp);
522eda14cbcSMatt Macy 		if (err != 0)
523eda14cbcSMatt Macy 			return (err);
524eda14cbcSMatt Macy 	}
525eda14cbcSMatt Macy 
526eda14cbcSMatt Macy 	if (nvt_needs_togrow(priv)) {
527eda14cbcSMatt Macy 		int err = nvt_grow(priv);
528eda14cbcSMatt Macy 		if (err != 0)
529eda14cbcSMatt Macy 			return (err);
530eda14cbcSMatt Macy 	}
531eda14cbcSMatt Macy 	i_nvp_t **tab = priv->nvp_hashtable;
532eda14cbcSMatt Macy 
5332a58b312SMartin Matuska 	const char *name = NVP_NAME(nvp);
534eda14cbcSMatt Macy 	uint64_t hash = nvt_hash(name);
535eda14cbcSMatt Macy 	uint64_t index = hash & (priv->nvp_nbuckets - 1);
536eda14cbcSMatt Macy 
537eda14cbcSMatt Macy 	ASSERT3U(index, <, priv->nvp_nbuckets);
53881b22a98SMartin Matuska 	// cppcheck-suppress nullPointerRedundantCheck
539eda14cbcSMatt Macy 	i_nvp_t *bucket = tab[index];
540eda14cbcSMatt Macy 
541eda14cbcSMatt Macy 	/* insert link at the beginning of the bucket */
542eda14cbcSMatt Macy 	i_nvp_t *new_entry = NVPAIR2I_NVP(nvp);
543eda14cbcSMatt Macy 	ASSERT3P(new_entry->nvi_hashtable_next, ==, NULL);
544eda14cbcSMatt Macy 	new_entry->nvi_hashtable_next = bucket;
54581b22a98SMartin Matuska 	// cppcheck-suppress nullPointerRedundantCheck
546eda14cbcSMatt Macy 	tab[index] = new_entry;
547eda14cbcSMatt Macy 
548eda14cbcSMatt Macy 	priv->nvp_nentries++;
549eda14cbcSMatt Macy 	return (0);
550eda14cbcSMatt Macy }
551eda14cbcSMatt Macy 
552eda14cbcSMatt Macy static void
nvlist_init(nvlist_t * nvl,uint32_t nvflag,nvpriv_t * priv)553eda14cbcSMatt Macy nvlist_init(nvlist_t *nvl, uint32_t nvflag, nvpriv_t *priv)
554eda14cbcSMatt Macy {
555eda14cbcSMatt Macy 	nvl->nvl_version = NV_VERSION;
556eda14cbcSMatt Macy 	nvl->nvl_nvflag = nvflag & (NV_UNIQUE_NAME|NV_UNIQUE_NAME_TYPE);
557eda14cbcSMatt Macy 	nvl->nvl_priv = (uint64_t)(uintptr_t)priv;
558eda14cbcSMatt Macy 	nvl->nvl_flag = 0;
559eda14cbcSMatt Macy 	nvl->nvl_pad = 0;
560eda14cbcSMatt Macy }
561eda14cbcSMatt Macy 
562eda14cbcSMatt Macy uint_t
nvlist_nvflag(nvlist_t * nvl)563eda14cbcSMatt Macy nvlist_nvflag(nvlist_t *nvl)
564eda14cbcSMatt Macy {
565eda14cbcSMatt Macy 	return (nvl->nvl_nvflag);
566eda14cbcSMatt Macy }
567eda14cbcSMatt Macy 
568eda14cbcSMatt Macy static nv_alloc_t *
nvlist_nv_alloc(int kmflag)569eda14cbcSMatt Macy nvlist_nv_alloc(int kmflag)
570eda14cbcSMatt Macy {
571eda14cbcSMatt Macy #if defined(_KERNEL)
572eda14cbcSMatt Macy 	switch (kmflag) {
573eda14cbcSMatt Macy 	case KM_SLEEP:
574eda14cbcSMatt Macy 		return (nv_alloc_sleep);
575eda14cbcSMatt Macy 	case KM_NOSLEEP:
576eda14cbcSMatt Macy 		return (nv_alloc_nosleep);
577eda14cbcSMatt Macy 	default:
578eda14cbcSMatt Macy 		return (nv_alloc_pushpage);
579eda14cbcSMatt Macy 	}
580eda14cbcSMatt Macy #else
581e92ffd9bSMartin Matuska 	(void) kmflag;
582eda14cbcSMatt Macy 	return (nv_alloc_nosleep);
583eda14cbcSMatt Macy #endif /* _KERNEL */
584eda14cbcSMatt Macy }
585eda14cbcSMatt Macy 
586eda14cbcSMatt Macy /*
587eda14cbcSMatt Macy  * nvlist_alloc - Allocate nvlist.
588eda14cbcSMatt Macy  */
589eda14cbcSMatt Macy int
nvlist_alloc(nvlist_t ** nvlp,uint_t nvflag,int kmflag)590eda14cbcSMatt Macy nvlist_alloc(nvlist_t **nvlp, uint_t nvflag, int kmflag)
591eda14cbcSMatt Macy {
592eda14cbcSMatt Macy 	return (nvlist_xalloc(nvlp, nvflag, nvlist_nv_alloc(kmflag)));
593eda14cbcSMatt Macy }
594eda14cbcSMatt Macy 
595eda14cbcSMatt Macy int
nvlist_xalloc(nvlist_t ** nvlp,uint_t nvflag,nv_alloc_t * nva)596eda14cbcSMatt Macy nvlist_xalloc(nvlist_t **nvlp, uint_t nvflag, nv_alloc_t *nva)
597eda14cbcSMatt Macy {
598eda14cbcSMatt Macy 	nvpriv_t *priv;
599eda14cbcSMatt Macy 
600eda14cbcSMatt Macy 	if (nvlp == NULL || nva == NULL)
601eda14cbcSMatt Macy 		return (EINVAL);
602eda14cbcSMatt Macy 
603eda14cbcSMatt Macy 	if ((priv = nv_priv_alloc(nva)) == NULL)
604eda14cbcSMatt Macy 		return (ENOMEM);
605eda14cbcSMatt Macy 
606eda14cbcSMatt Macy 	if ((*nvlp = nv_mem_zalloc(priv,
607eda14cbcSMatt Macy 	    NV_ALIGN(sizeof (nvlist_t)))) == NULL) {
608eda14cbcSMatt Macy 		nv_mem_free(priv, priv, sizeof (nvpriv_t));
609eda14cbcSMatt Macy 		return (ENOMEM);
610eda14cbcSMatt Macy 	}
611eda14cbcSMatt Macy 
612eda14cbcSMatt Macy 	nvlist_init(*nvlp, nvflag, priv);
613eda14cbcSMatt Macy 
614eda14cbcSMatt Macy 	return (0);
615eda14cbcSMatt Macy }
616eda14cbcSMatt Macy 
617eda14cbcSMatt Macy /*
618eda14cbcSMatt Macy  * nvp_buf_alloc - Allocate i_nvp_t for storing a new nv pair.
619eda14cbcSMatt Macy  */
620eda14cbcSMatt Macy static nvpair_t *
nvp_buf_alloc(nvlist_t * nvl,size_t len)621eda14cbcSMatt Macy nvp_buf_alloc(nvlist_t *nvl, size_t len)
622eda14cbcSMatt Macy {
623eda14cbcSMatt Macy 	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
624eda14cbcSMatt Macy 	i_nvp_t *buf;
625eda14cbcSMatt Macy 	nvpair_t *nvp;
626eda14cbcSMatt Macy 	size_t nvsize;
627eda14cbcSMatt Macy 
628eda14cbcSMatt Macy 	/*
629eda14cbcSMatt Macy 	 * Allocate the buffer
630eda14cbcSMatt Macy 	 */
631eda14cbcSMatt Macy 	nvsize = len + offsetof(i_nvp_t, nvi_nvp);
632eda14cbcSMatt Macy 
633eda14cbcSMatt Macy 	if ((buf = nv_mem_zalloc(priv, nvsize)) == NULL)
634eda14cbcSMatt Macy 		return (NULL);
635eda14cbcSMatt Macy 
636eda14cbcSMatt Macy 	nvp = &buf->nvi_nvp;
637eda14cbcSMatt Macy 	nvp->nvp_size = len;
638eda14cbcSMatt Macy 
639eda14cbcSMatt Macy 	return (nvp);
640eda14cbcSMatt Macy }
641eda14cbcSMatt Macy 
642eda14cbcSMatt Macy /*
643eda14cbcSMatt Macy  * nvp_buf_free - de-Allocate an i_nvp_t.
644eda14cbcSMatt Macy  */
645eda14cbcSMatt Macy static void
nvp_buf_free(nvlist_t * nvl,nvpair_t * nvp)646eda14cbcSMatt Macy nvp_buf_free(nvlist_t *nvl, nvpair_t *nvp)
647eda14cbcSMatt Macy {
648eda14cbcSMatt Macy 	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
649eda14cbcSMatt Macy 	size_t nvsize = nvp->nvp_size + offsetof(i_nvp_t, nvi_nvp);
650eda14cbcSMatt Macy 
651eda14cbcSMatt Macy 	nv_mem_free(priv, NVPAIR2I_NVP(nvp), nvsize);
652eda14cbcSMatt Macy }
653eda14cbcSMatt Macy 
654eda14cbcSMatt Macy /*
655eda14cbcSMatt Macy  * nvp_buf_link - link a new nv pair into the nvlist.
656eda14cbcSMatt Macy  */
657eda14cbcSMatt Macy static void
nvp_buf_link(nvlist_t * nvl,nvpair_t * nvp)658eda14cbcSMatt Macy nvp_buf_link(nvlist_t *nvl, nvpair_t *nvp)
659eda14cbcSMatt Macy {
660eda14cbcSMatt Macy 	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
661eda14cbcSMatt Macy 	i_nvp_t *curr = NVPAIR2I_NVP(nvp);
662eda14cbcSMatt Macy 
663eda14cbcSMatt Macy 	/* Put element at end of nvlist */
664eda14cbcSMatt Macy 	if (priv->nvp_list == NULL) {
665eda14cbcSMatt Macy 		priv->nvp_list = priv->nvp_last = curr;
666eda14cbcSMatt Macy 	} else {
667eda14cbcSMatt Macy 		curr->nvi_prev = priv->nvp_last;
668eda14cbcSMatt Macy 		priv->nvp_last->nvi_next = curr;
669eda14cbcSMatt Macy 		priv->nvp_last = curr;
670eda14cbcSMatt Macy 	}
671eda14cbcSMatt Macy }
672eda14cbcSMatt Macy 
673eda14cbcSMatt Macy /*
674eda14cbcSMatt Macy  * nvp_buf_unlink - unlink an removed nvpair out of the nvlist.
675eda14cbcSMatt Macy  */
676eda14cbcSMatt Macy static void
nvp_buf_unlink(nvlist_t * nvl,nvpair_t * nvp)677eda14cbcSMatt Macy nvp_buf_unlink(nvlist_t *nvl, nvpair_t *nvp)
678eda14cbcSMatt Macy {
679eda14cbcSMatt Macy 	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
680eda14cbcSMatt Macy 	i_nvp_t *curr = NVPAIR2I_NVP(nvp);
681eda14cbcSMatt Macy 
682eda14cbcSMatt Macy 	/*
683eda14cbcSMatt Macy 	 * protect nvlist_next_nvpair() against walking on freed memory.
684eda14cbcSMatt Macy 	 */
685eda14cbcSMatt Macy 	if (priv->nvp_curr == curr)
686eda14cbcSMatt Macy 		priv->nvp_curr = curr->nvi_next;
687eda14cbcSMatt Macy 
688eda14cbcSMatt Macy 	if (curr == priv->nvp_list)
689eda14cbcSMatt Macy 		priv->nvp_list = curr->nvi_next;
690eda14cbcSMatt Macy 	else
691eda14cbcSMatt Macy 		curr->nvi_prev->nvi_next = curr->nvi_next;
692eda14cbcSMatt Macy 
693eda14cbcSMatt Macy 	if (curr == priv->nvp_last)
694eda14cbcSMatt Macy 		priv->nvp_last = curr->nvi_prev;
695eda14cbcSMatt Macy 	else
696eda14cbcSMatt Macy 		curr->nvi_next->nvi_prev = curr->nvi_prev;
697eda14cbcSMatt Macy }
698eda14cbcSMatt Macy 
699eda14cbcSMatt Macy /*
700eda14cbcSMatt Macy  * take a nvpair type and number of elements and make sure the are valid
701eda14cbcSMatt Macy  */
702eda14cbcSMatt Macy static int
i_validate_type_nelem(data_type_t type,uint_t nelem)703eda14cbcSMatt Macy i_validate_type_nelem(data_type_t type, uint_t nelem)
704eda14cbcSMatt Macy {
705eda14cbcSMatt Macy 	switch (type) {
706eda14cbcSMatt Macy 	case DATA_TYPE_BOOLEAN:
707eda14cbcSMatt Macy 		if (nelem != 0)
708eda14cbcSMatt Macy 			return (EINVAL);
709eda14cbcSMatt Macy 		break;
710eda14cbcSMatt Macy 	case DATA_TYPE_BOOLEAN_VALUE:
711eda14cbcSMatt Macy 	case DATA_TYPE_BYTE:
712eda14cbcSMatt Macy 	case DATA_TYPE_INT8:
713eda14cbcSMatt Macy 	case DATA_TYPE_UINT8:
714eda14cbcSMatt Macy 	case DATA_TYPE_INT16:
715eda14cbcSMatt Macy 	case DATA_TYPE_UINT16:
716eda14cbcSMatt Macy 	case DATA_TYPE_INT32:
717eda14cbcSMatt Macy 	case DATA_TYPE_UINT32:
718eda14cbcSMatt Macy 	case DATA_TYPE_INT64:
719eda14cbcSMatt Macy 	case DATA_TYPE_UINT64:
720eda14cbcSMatt Macy 	case DATA_TYPE_STRING:
721eda14cbcSMatt Macy 	case DATA_TYPE_HRTIME:
722eda14cbcSMatt Macy 	case DATA_TYPE_NVLIST:
723eda14cbcSMatt Macy #if !defined(_KERNEL)
724eda14cbcSMatt Macy 	case DATA_TYPE_DOUBLE:
725eda14cbcSMatt Macy #endif
726eda14cbcSMatt Macy 		if (nelem != 1)
727eda14cbcSMatt Macy 			return (EINVAL);
728eda14cbcSMatt Macy 		break;
729eda14cbcSMatt Macy 	case DATA_TYPE_BOOLEAN_ARRAY:
730eda14cbcSMatt Macy 	case DATA_TYPE_BYTE_ARRAY:
731eda14cbcSMatt Macy 	case DATA_TYPE_INT8_ARRAY:
732eda14cbcSMatt Macy 	case DATA_TYPE_UINT8_ARRAY:
733eda14cbcSMatt Macy 	case DATA_TYPE_INT16_ARRAY:
734eda14cbcSMatt Macy 	case DATA_TYPE_UINT16_ARRAY:
735eda14cbcSMatt Macy 	case DATA_TYPE_INT32_ARRAY:
736eda14cbcSMatt Macy 	case DATA_TYPE_UINT32_ARRAY:
737eda14cbcSMatt Macy 	case DATA_TYPE_INT64_ARRAY:
738eda14cbcSMatt Macy 	case DATA_TYPE_UINT64_ARRAY:
739eda14cbcSMatt Macy 	case DATA_TYPE_STRING_ARRAY:
740eda14cbcSMatt Macy 	case DATA_TYPE_NVLIST_ARRAY:
741eda14cbcSMatt Macy 		/* we allow arrays with 0 elements */
742eda14cbcSMatt Macy 		break;
743eda14cbcSMatt Macy 	default:
744eda14cbcSMatt Macy 		return (EINVAL);
745eda14cbcSMatt Macy 	}
746eda14cbcSMatt Macy 	return (0);
747eda14cbcSMatt Macy }
748eda14cbcSMatt Macy 
749eda14cbcSMatt Macy /*
750eda14cbcSMatt Macy  * Verify nvp_name_sz and check the name string length.
751eda14cbcSMatt Macy  */
752eda14cbcSMatt Macy static int
i_validate_nvpair_name(nvpair_t * nvp)753eda14cbcSMatt Macy i_validate_nvpair_name(nvpair_t *nvp)
754eda14cbcSMatt Macy {
755eda14cbcSMatt Macy 	if ((nvp->nvp_name_sz <= 0) ||
756eda14cbcSMatt Macy 	    (nvp->nvp_size < NVP_SIZE_CALC(nvp->nvp_name_sz, 0)))
757eda14cbcSMatt Macy 		return (EFAULT);
758eda14cbcSMatt Macy 
759eda14cbcSMatt Macy 	/* verify the name string, make sure its terminated */
760eda14cbcSMatt Macy 	if (NVP_NAME(nvp)[nvp->nvp_name_sz - 1] != '\0')
761eda14cbcSMatt Macy 		return (EFAULT);
762eda14cbcSMatt Macy 
763eda14cbcSMatt Macy 	return (strlen(NVP_NAME(nvp)) == nvp->nvp_name_sz - 1 ? 0 : EFAULT);
764eda14cbcSMatt Macy }
765eda14cbcSMatt Macy 
766eda14cbcSMatt Macy static int
i_validate_nvpair_value(data_type_t type,uint_t nelem,const void * data)767eda14cbcSMatt Macy i_validate_nvpair_value(data_type_t type, uint_t nelem, const void *data)
768eda14cbcSMatt Macy {
769eda14cbcSMatt Macy 	switch (type) {
770eda14cbcSMatt Macy 	case DATA_TYPE_BOOLEAN_VALUE:
771eda14cbcSMatt Macy 		if (*(boolean_t *)data != B_TRUE &&
772eda14cbcSMatt Macy 		    *(boolean_t *)data != B_FALSE)
773eda14cbcSMatt Macy 			return (EINVAL);
774eda14cbcSMatt Macy 		break;
775eda14cbcSMatt Macy 	case DATA_TYPE_BOOLEAN_ARRAY: {
776eda14cbcSMatt Macy 		int i;
777eda14cbcSMatt Macy 
778eda14cbcSMatt Macy 		for (i = 0; i < nelem; i++)
779eda14cbcSMatt Macy 			if (((boolean_t *)data)[i] != B_TRUE &&
780eda14cbcSMatt Macy 			    ((boolean_t *)data)[i] != B_FALSE)
781eda14cbcSMatt Macy 				return (EINVAL);
782eda14cbcSMatt Macy 		break;
783eda14cbcSMatt Macy 	}
784eda14cbcSMatt Macy 	default:
785eda14cbcSMatt Macy 		break;
786eda14cbcSMatt Macy 	}
787eda14cbcSMatt Macy 
788eda14cbcSMatt Macy 	return (0);
789eda14cbcSMatt Macy }
790eda14cbcSMatt Macy 
791eda14cbcSMatt Macy /*
792eda14cbcSMatt Macy  * This function takes a pointer to what should be a nvpair and it's size
793eda14cbcSMatt Macy  * and then verifies that all the nvpair fields make sense and can be
794eda14cbcSMatt Macy  * trusted.  This function is used when decoding packed nvpairs.
795eda14cbcSMatt Macy  */
796eda14cbcSMatt Macy static int
i_validate_nvpair(nvpair_t * nvp)797eda14cbcSMatt Macy i_validate_nvpair(nvpair_t *nvp)
798eda14cbcSMatt Macy {
799eda14cbcSMatt Macy 	data_type_t type = NVP_TYPE(nvp);
800eda14cbcSMatt Macy 	int size1, size2;
801eda14cbcSMatt Macy 
802eda14cbcSMatt Macy 	/* verify nvp_name_sz, check the name string length */
803eda14cbcSMatt Macy 	if (i_validate_nvpair_name(nvp) != 0)
804eda14cbcSMatt Macy 		return (EFAULT);
805eda14cbcSMatt Macy 
806eda14cbcSMatt Macy 	if (i_validate_nvpair_value(type, NVP_NELEM(nvp), NVP_VALUE(nvp)) != 0)
807eda14cbcSMatt Macy 		return (EFAULT);
808eda14cbcSMatt Macy 
809eda14cbcSMatt Macy 	/*
810eda14cbcSMatt Macy 	 * verify nvp_type, nvp_value_elem, and also possibly
811eda14cbcSMatt Macy 	 * verify string values and get the value size.
812eda14cbcSMatt Macy 	 */
813eda14cbcSMatt Macy 	size2 = i_get_value_size(type, NVP_VALUE(nvp), NVP_NELEM(nvp));
814eda14cbcSMatt Macy 	size1 = nvp->nvp_size - NVP_VALOFF(nvp);
815eda14cbcSMatt Macy 	if (size2 < 0 || size1 != NV_ALIGN(size2))
816eda14cbcSMatt Macy 		return (EFAULT);
817eda14cbcSMatt Macy 
818eda14cbcSMatt Macy 	return (0);
819eda14cbcSMatt Macy }
820eda14cbcSMatt Macy 
821eda14cbcSMatt Macy static int
nvlist_copy_pairs(const nvlist_t * snvl,nvlist_t * dnvl)822681ce946SMartin Matuska nvlist_copy_pairs(const nvlist_t *snvl, nvlist_t *dnvl)
823eda14cbcSMatt Macy {
824681ce946SMartin Matuska 	const nvpriv_t *priv;
825681ce946SMartin Matuska 	const i_nvp_t *curr;
826eda14cbcSMatt Macy 
827681ce946SMartin Matuska 	if ((priv = (const nvpriv_t *)(uintptr_t)snvl->nvl_priv) == NULL)
828eda14cbcSMatt Macy 		return (EINVAL);
829eda14cbcSMatt Macy 
830eda14cbcSMatt Macy 	for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
831681ce946SMartin Matuska 		const nvpair_t *nvp = &curr->nvi_nvp;
832eda14cbcSMatt Macy 		int err;
833eda14cbcSMatt Macy 
834eda14cbcSMatt Macy 		if ((err = nvlist_add_common(dnvl, NVP_NAME(nvp), NVP_TYPE(nvp),
835eda14cbcSMatt Macy 		    NVP_NELEM(nvp), NVP_VALUE(nvp))) != 0)
836eda14cbcSMatt Macy 			return (err);
837eda14cbcSMatt Macy 	}
838eda14cbcSMatt Macy 
839eda14cbcSMatt Macy 	return (0);
840eda14cbcSMatt Macy }
841eda14cbcSMatt Macy 
842eda14cbcSMatt Macy /*
843eda14cbcSMatt Macy  * Frees all memory allocated for an nvpair (like embedded lists) with
844eda14cbcSMatt Macy  * the exception of the nvpair buffer itself.
845eda14cbcSMatt Macy  */
846eda14cbcSMatt Macy static void
nvpair_free(nvpair_t * nvp)847eda14cbcSMatt Macy nvpair_free(nvpair_t *nvp)
848eda14cbcSMatt Macy {
849eda14cbcSMatt Macy 	switch (NVP_TYPE(nvp)) {
850eda14cbcSMatt Macy 	case DATA_TYPE_NVLIST:
851eda14cbcSMatt Macy 		nvlist_free(EMBEDDED_NVL(nvp));
852eda14cbcSMatt Macy 		break;
853eda14cbcSMatt Macy 	case DATA_TYPE_NVLIST_ARRAY: {
854eda14cbcSMatt Macy 		nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp);
855eda14cbcSMatt Macy 		int i;
856eda14cbcSMatt Macy 
857eda14cbcSMatt Macy 		for (i = 0; i < NVP_NELEM(nvp); i++)
858eda14cbcSMatt Macy 			if (nvlp[i] != NULL)
859eda14cbcSMatt Macy 				nvlist_free(nvlp[i]);
860eda14cbcSMatt Macy 		break;
861eda14cbcSMatt Macy 	}
862eda14cbcSMatt Macy 	default:
863eda14cbcSMatt Macy 		break;
864eda14cbcSMatt Macy 	}
865eda14cbcSMatt Macy }
866eda14cbcSMatt Macy 
867eda14cbcSMatt Macy /*
868eda14cbcSMatt Macy  * nvlist_free - free an unpacked nvlist
869eda14cbcSMatt Macy  */
870eda14cbcSMatt Macy void
nvlist_free(nvlist_t * nvl)871eda14cbcSMatt Macy nvlist_free(nvlist_t *nvl)
872eda14cbcSMatt Macy {
873eda14cbcSMatt Macy 	nvpriv_t *priv;
874eda14cbcSMatt Macy 	i_nvp_t *curr;
875eda14cbcSMatt Macy 
876eda14cbcSMatt Macy 	if (nvl == NULL ||
877eda14cbcSMatt Macy 	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
878eda14cbcSMatt Macy 		return;
879eda14cbcSMatt Macy 
880eda14cbcSMatt Macy 	/*
881eda14cbcSMatt Macy 	 * Unpacked nvlist are linked through i_nvp_t
882eda14cbcSMatt Macy 	 */
883eda14cbcSMatt Macy 	curr = priv->nvp_list;
884eda14cbcSMatt Macy 	while (curr != NULL) {
885eda14cbcSMatt Macy 		nvpair_t *nvp = &curr->nvi_nvp;
886eda14cbcSMatt Macy 		curr = curr->nvi_next;
887eda14cbcSMatt Macy 
888eda14cbcSMatt Macy 		nvpair_free(nvp);
889eda14cbcSMatt Macy 		nvp_buf_free(nvl, nvp);
890eda14cbcSMatt Macy 	}
891eda14cbcSMatt Macy 
892eda14cbcSMatt Macy 	if (!(priv->nvp_stat & NV_STAT_EMBEDDED))
893eda14cbcSMatt Macy 		nv_mem_free(priv, nvl, NV_ALIGN(sizeof (nvlist_t)));
894eda14cbcSMatt Macy 	else
895eda14cbcSMatt Macy 		nvl->nvl_priv = 0;
896eda14cbcSMatt Macy 
897eda14cbcSMatt Macy 	nvt_tab_free(priv);
898eda14cbcSMatt Macy 	nv_mem_free(priv, priv, sizeof (nvpriv_t));
899eda14cbcSMatt Macy }
900eda14cbcSMatt Macy 
901eda14cbcSMatt Macy static int
nvlist_contains_nvp(const nvlist_t * nvl,const nvpair_t * nvp)902681ce946SMartin Matuska nvlist_contains_nvp(const nvlist_t *nvl, const nvpair_t *nvp)
903eda14cbcSMatt Macy {
904681ce946SMartin Matuska 	const nvpriv_t *priv = (const nvpriv_t *)(uintptr_t)nvl->nvl_priv;
905681ce946SMartin Matuska 	const i_nvp_t *curr;
906eda14cbcSMatt Macy 
907eda14cbcSMatt Macy 	if (nvp == NULL)
908eda14cbcSMatt Macy 		return (0);
909eda14cbcSMatt Macy 
910eda14cbcSMatt Macy 	for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next)
911eda14cbcSMatt Macy 		if (&curr->nvi_nvp == nvp)
912eda14cbcSMatt Macy 			return (1);
913eda14cbcSMatt Macy 
914eda14cbcSMatt Macy 	return (0);
915eda14cbcSMatt Macy }
916eda14cbcSMatt Macy 
917eda14cbcSMatt Macy /*
918eda14cbcSMatt Macy  * Make a copy of nvlist
919eda14cbcSMatt Macy  */
920eda14cbcSMatt Macy int
nvlist_dup(const nvlist_t * nvl,nvlist_t ** nvlp,int kmflag)921681ce946SMartin Matuska nvlist_dup(const nvlist_t *nvl, nvlist_t **nvlp, int kmflag)
922eda14cbcSMatt Macy {
923eda14cbcSMatt Macy 	return (nvlist_xdup(nvl, nvlp, nvlist_nv_alloc(kmflag)));
924eda14cbcSMatt Macy }
925eda14cbcSMatt Macy 
926eda14cbcSMatt Macy int
nvlist_xdup(const nvlist_t * nvl,nvlist_t ** nvlp,nv_alloc_t * nva)927681ce946SMartin Matuska nvlist_xdup(const nvlist_t *nvl, nvlist_t **nvlp, nv_alloc_t *nva)
928eda14cbcSMatt Macy {
929eda14cbcSMatt Macy 	int err;
930eda14cbcSMatt Macy 	nvlist_t *ret;
931eda14cbcSMatt Macy 
932eda14cbcSMatt Macy 	if (nvl == NULL || nvlp == NULL)
933eda14cbcSMatt Macy 		return (EINVAL);
934eda14cbcSMatt Macy 
935eda14cbcSMatt Macy 	if ((err = nvlist_xalloc(&ret, nvl->nvl_nvflag, nva)) != 0)
936eda14cbcSMatt Macy 		return (err);
937eda14cbcSMatt Macy 
938eda14cbcSMatt Macy 	if ((err = nvlist_copy_pairs(nvl, ret)) != 0)
939eda14cbcSMatt Macy 		nvlist_free(ret);
940eda14cbcSMatt Macy 	else
941eda14cbcSMatt Macy 		*nvlp = ret;
942eda14cbcSMatt Macy 
943eda14cbcSMatt Macy 	return (err);
944eda14cbcSMatt Macy }
945eda14cbcSMatt Macy 
946eda14cbcSMatt Macy /*
947eda14cbcSMatt Macy  * Remove all with matching name
948eda14cbcSMatt Macy  */
949eda14cbcSMatt Macy int
nvlist_remove_all(nvlist_t * nvl,const char * name)950eda14cbcSMatt Macy nvlist_remove_all(nvlist_t *nvl, const char *name)
951eda14cbcSMatt Macy {
952eda14cbcSMatt Macy 	int error = ENOENT;
953eda14cbcSMatt Macy 
954eda14cbcSMatt Macy 	if (nvl == NULL || name == NULL || nvl->nvl_priv == 0)
955eda14cbcSMatt Macy 		return (EINVAL);
956eda14cbcSMatt Macy 
957eda14cbcSMatt Macy 	nvpair_t *nvp;
958eda14cbcSMatt Macy 	while ((nvp = nvt_lookup_name(nvl, name)) != NULL) {
959eda14cbcSMatt Macy 		VERIFY0(nvlist_remove_nvpair(nvl, nvp));
960eda14cbcSMatt Macy 		error = 0;
961eda14cbcSMatt Macy 	}
962eda14cbcSMatt Macy 
963eda14cbcSMatt Macy 	return (error);
964eda14cbcSMatt Macy }
965eda14cbcSMatt Macy 
966eda14cbcSMatt Macy /*
967eda14cbcSMatt Macy  * Remove first one with matching name and type
968eda14cbcSMatt Macy  */
969eda14cbcSMatt Macy int
nvlist_remove(nvlist_t * nvl,const char * name,data_type_t type)970eda14cbcSMatt Macy nvlist_remove(nvlist_t *nvl, const char *name, data_type_t type)
971eda14cbcSMatt Macy {
972eda14cbcSMatt Macy 	if (nvl == NULL || name == NULL || nvl->nvl_priv == 0)
973eda14cbcSMatt Macy 		return (EINVAL);
974eda14cbcSMatt Macy 
975eda14cbcSMatt Macy 	nvpair_t *nvp = nvt_lookup_name_type(nvl, name, type);
976eda14cbcSMatt Macy 	if (nvp == NULL)
977eda14cbcSMatt Macy 		return (ENOENT);
978eda14cbcSMatt Macy 
979eda14cbcSMatt Macy 	return (nvlist_remove_nvpair(nvl, nvp));
980eda14cbcSMatt Macy }
981eda14cbcSMatt Macy 
982eda14cbcSMatt Macy int
nvlist_remove_nvpair(nvlist_t * nvl,nvpair_t * nvp)983eda14cbcSMatt Macy nvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp)
984eda14cbcSMatt Macy {
985eda14cbcSMatt Macy 	if (nvl == NULL || nvp == NULL)
986eda14cbcSMatt Macy 		return (EINVAL);
987eda14cbcSMatt Macy 
988eda14cbcSMatt Macy 	int err = nvt_remove_nvpair(nvl, nvp);
989eda14cbcSMatt Macy 	if (err != 0)
990eda14cbcSMatt Macy 		return (err);
991eda14cbcSMatt Macy 
992eda14cbcSMatt Macy 	nvp_buf_unlink(nvl, nvp);
993eda14cbcSMatt Macy 	nvpair_free(nvp);
994eda14cbcSMatt Macy 	nvp_buf_free(nvl, nvp);
995eda14cbcSMatt Macy 	return (0);
996eda14cbcSMatt Macy }
997eda14cbcSMatt Macy 
998eda14cbcSMatt Macy /*
999eda14cbcSMatt Macy  * This function calculates the size of an nvpair value.
1000eda14cbcSMatt Macy  *
1001eda14cbcSMatt Macy  * The data argument controls the behavior in case of the data types
1002eda14cbcSMatt Macy  * 	DATA_TYPE_STRING    	and
1003eda14cbcSMatt Macy  *	DATA_TYPE_STRING_ARRAY
1004eda14cbcSMatt Macy  * Is data == NULL then the size of the string(s) is excluded.
1005eda14cbcSMatt Macy  */
1006eda14cbcSMatt Macy static int
i_get_value_size(data_type_t type,const void * data,uint_t nelem)1007eda14cbcSMatt Macy i_get_value_size(data_type_t type, const void *data, uint_t nelem)
1008eda14cbcSMatt Macy {
1009eda14cbcSMatt Macy 	uint64_t value_sz;
1010eda14cbcSMatt Macy 
1011eda14cbcSMatt Macy 	if (i_validate_type_nelem(type, nelem) != 0)
1012eda14cbcSMatt Macy 		return (-1);
1013eda14cbcSMatt Macy 
1014eda14cbcSMatt Macy 	/* Calculate required size for holding value */
1015eda14cbcSMatt Macy 	switch (type) {
1016eda14cbcSMatt Macy 	case DATA_TYPE_BOOLEAN:
1017eda14cbcSMatt Macy 		value_sz = 0;
1018eda14cbcSMatt Macy 		break;
1019eda14cbcSMatt Macy 	case DATA_TYPE_BOOLEAN_VALUE:
1020eda14cbcSMatt Macy 		value_sz = sizeof (boolean_t);
1021eda14cbcSMatt Macy 		break;
1022eda14cbcSMatt Macy 	case DATA_TYPE_BYTE:
1023eda14cbcSMatt Macy 		value_sz = sizeof (uchar_t);
1024eda14cbcSMatt Macy 		break;
1025eda14cbcSMatt Macy 	case DATA_TYPE_INT8:
1026eda14cbcSMatt Macy 		value_sz = sizeof (int8_t);
1027eda14cbcSMatt Macy 		break;
1028eda14cbcSMatt Macy 	case DATA_TYPE_UINT8:
1029eda14cbcSMatt Macy 		value_sz = sizeof (uint8_t);
1030eda14cbcSMatt Macy 		break;
1031eda14cbcSMatt Macy 	case DATA_TYPE_INT16:
1032eda14cbcSMatt Macy 		value_sz = sizeof (int16_t);
1033eda14cbcSMatt Macy 		break;
1034eda14cbcSMatt Macy 	case DATA_TYPE_UINT16:
1035eda14cbcSMatt Macy 		value_sz = sizeof (uint16_t);
1036eda14cbcSMatt Macy 		break;
1037eda14cbcSMatt Macy 	case DATA_TYPE_INT32:
1038eda14cbcSMatt Macy 		value_sz = sizeof (int32_t);
1039eda14cbcSMatt Macy 		break;
1040eda14cbcSMatt Macy 	case DATA_TYPE_UINT32:
1041eda14cbcSMatt Macy 		value_sz = sizeof (uint32_t);
1042eda14cbcSMatt Macy 		break;
1043eda14cbcSMatt Macy 	case DATA_TYPE_INT64:
1044eda14cbcSMatt Macy 		value_sz = sizeof (int64_t);
1045eda14cbcSMatt Macy 		break;
1046eda14cbcSMatt Macy 	case DATA_TYPE_UINT64:
1047eda14cbcSMatt Macy 		value_sz = sizeof (uint64_t);
1048eda14cbcSMatt Macy 		break;
1049eda14cbcSMatt Macy #if !defined(_KERNEL)
1050eda14cbcSMatt Macy 	case DATA_TYPE_DOUBLE:
1051eda14cbcSMatt Macy 		value_sz = sizeof (double);
1052eda14cbcSMatt Macy 		break;
1053eda14cbcSMatt Macy #endif
1054eda14cbcSMatt Macy 	case DATA_TYPE_STRING:
1055eda14cbcSMatt Macy 		if (data == NULL)
1056eda14cbcSMatt Macy 			value_sz = 0;
1057eda14cbcSMatt Macy 		else
1058eda14cbcSMatt Macy 			value_sz = strlen(data) + 1;
1059eda14cbcSMatt Macy 		break;
1060eda14cbcSMatt Macy 	case DATA_TYPE_BOOLEAN_ARRAY:
1061eda14cbcSMatt Macy 		value_sz = (uint64_t)nelem * sizeof (boolean_t);
1062eda14cbcSMatt Macy 		break;
1063eda14cbcSMatt Macy 	case DATA_TYPE_BYTE_ARRAY:
1064eda14cbcSMatt Macy 		value_sz = (uint64_t)nelem * sizeof (uchar_t);
1065eda14cbcSMatt Macy 		break;
1066eda14cbcSMatt Macy 	case DATA_TYPE_INT8_ARRAY:
1067eda14cbcSMatt Macy 		value_sz = (uint64_t)nelem * sizeof (int8_t);
1068eda14cbcSMatt Macy 		break;
1069eda14cbcSMatt Macy 	case DATA_TYPE_UINT8_ARRAY:
1070eda14cbcSMatt Macy 		value_sz = (uint64_t)nelem * sizeof (uint8_t);
1071eda14cbcSMatt Macy 		break;
1072eda14cbcSMatt Macy 	case DATA_TYPE_INT16_ARRAY:
1073eda14cbcSMatt Macy 		value_sz = (uint64_t)nelem * sizeof (int16_t);
1074eda14cbcSMatt Macy 		break;
1075eda14cbcSMatt Macy 	case DATA_TYPE_UINT16_ARRAY:
1076eda14cbcSMatt Macy 		value_sz = (uint64_t)nelem * sizeof (uint16_t);
1077eda14cbcSMatt Macy 		break;
1078eda14cbcSMatt Macy 	case DATA_TYPE_INT32_ARRAY:
1079eda14cbcSMatt Macy 		value_sz = (uint64_t)nelem * sizeof (int32_t);
1080eda14cbcSMatt Macy 		break;
1081eda14cbcSMatt Macy 	case DATA_TYPE_UINT32_ARRAY:
1082eda14cbcSMatt Macy 		value_sz = (uint64_t)nelem * sizeof (uint32_t);
1083eda14cbcSMatt Macy 		break;
1084eda14cbcSMatt Macy 	case DATA_TYPE_INT64_ARRAY:
1085eda14cbcSMatt Macy 		value_sz = (uint64_t)nelem * sizeof (int64_t);
1086eda14cbcSMatt Macy 		break;
1087eda14cbcSMatt Macy 	case DATA_TYPE_UINT64_ARRAY:
1088eda14cbcSMatt Macy 		value_sz = (uint64_t)nelem * sizeof (uint64_t);
1089eda14cbcSMatt Macy 		break;
1090eda14cbcSMatt Macy 	case DATA_TYPE_STRING_ARRAY:
1091eda14cbcSMatt Macy 		value_sz = (uint64_t)nelem * sizeof (uint64_t);
1092eda14cbcSMatt Macy 
1093eda14cbcSMatt Macy 		if (data != NULL) {
1094eda14cbcSMatt Macy 			char *const *strs = data;
1095eda14cbcSMatt Macy 			uint_t i;
1096eda14cbcSMatt Macy 
1097eda14cbcSMatt Macy 			/* no alignment requirement for strings */
1098eda14cbcSMatt Macy 			for (i = 0; i < nelem; i++) {
1099eda14cbcSMatt Macy 				if (strs[i] == NULL)
1100eda14cbcSMatt Macy 					return (-1);
1101eda14cbcSMatt Macy 				value_sz += strlen(strs[i]) + 1;
1102eda14cbcSMatt Macy 			}
1103eda14cbcSMatt Macy 		}
1104eda14cbcSMatt Macy 		break;
1105eda14cbcSMatt Macy 	case DATA_TYPE_HRTIME:
1106eda14cbcSMatt Macy 		value_sz = sizeof (hrtime_t);
1107eda14cbcSMatt Macy 		break;
1108eda14cbcSMatt Macy 	case DATA_TYPE_NVLIST:
1109eda14cbcSMatt Macy 		value_sz = NV_ALIGN(sizeof (nvlist_t));
1110eda14cbcSMatt Macy 		break;
1111eda14cbcSMatt Macy 	case DATA_TYPE_NVLIST_ARRAY:
1112eda14cbcSMatt Macy 		value_sz = (uint64_t)nelem * sizeof (uint64_t) +
1113eda14cbcSMatt Macy 		    (uint64_t)nelem * NV_ALIGN(sizeof (nvlist_t));
1114eda14cbcSMatt Macy 		break;
1115eda14cbcSMatt Macy 	default:
1116eda14cbcSMatt Macy 		return (-1);
1117eda14cbcSMatt Macy 	}
1118eda14cbcSMatt Macy 
1119eda14cbcSMatt Macy 	return (value_sz > INT32_MAX ? -1 : (int)value_sz);
1120eda14cbcSMatt Macy }
1121eda14cbcSMatt Macy 
1122eda14cbcSMatt Macy static int
nvlist_copy_embedded(nvlist_t * nvl,nvlist_t * onvl,nvlist_t * emb_nvl)1123eda14cbcSMatt Macy nvlist_copy_embedded(nvlist_t *nvl, nvlist_t *onvl, nvlist_t *emb_nvl)
1124eda14cbcSMatt Macy {
1125eda14cbcSMatt Macy 	nvpriv_t *priv;
1126eda14cbcSMatt Macy 	int err;
1127eda14cbcSMatt Macy 
1128eda14cbcSMatt Macy 	if ((priv = nv_priv_alloc_embedded((nvpriv_t *)(uintptr_t)
1129eda14cbcSMatt Macy 	    nvl->nvl_priv)) == NULL)
1130eda14cbcSMatt Macy 		return (ENOMEM);
1131eda14cbcSMatt Macy 
1132eda14cbcSMatt Macy 	nvlist_init(emb_nvl, onvl->nvl_nvflag, priv);
1133eda14cbcSMatt Macy 
1134eda14cbcSMatt Macy 	if ((err = nvlist_copy_pairs(onvl, emb_nvl)) != 0) {
1135eda14cbcSMatt Macy 		nvlist_free(emb_nvl);
1136eda14cbcSMatt Macy 		emb_nvl->nvl_priv = 0;
1137eda14cbcSMatt Macy 	}
1138eda14cbcSMatt Macy 
1139eda14cbcSMatt Macy 	return (err);
1140eda14cbcSMatt Macy }
1141eda14cbcSMatt Macy 
1142eda14cbcSMatt Macy /*
1143eda14cbcSMatt Macy  * nvlist_add_common - Add new <name,value> pair to nvlist
1144eda14cbcSMatt Macy  */
1145eda14cbcSMatt Macy static int
nvlist_add_common(nvlist_t * nvl,const char * name,data_type_t type,uint_t nelem,const void * data)1146eda14cbcSMatt Macy nvlist_add_common(nvlist_t *nvl, const char *name,
1147eda14cbcSMatt Macy     data_type_t type, uint_t nelem, const void *data)
1148eda14cbcSMatt Macy {
1149eda14cbcSMatt Macy 	nvpair_t *nvp;
1150eda14cbcSMatt Macy 	uint_t i;
1151eda14cbcSMatt Macy 
1152eda14cbcSMatt Macy 	int nvp_sz, name_sz, value_sz;
1153eda14cbcSMatt Macy 	int err = 0;
1154eda14cbcSMatt Macy 
1155eda14cbcSMatt Macy 	if (name == NULL || nvl == NULL || nvl->nvl_priv == 0)
1156eda14cbcSMatt Macy 		return (EINVAL);
1157eda14cbcSMatt Macy 
1158eda14cbcSMatt Macy 	if (nelem != 0 && data == NULL)
1159eda14cbcSMatt Macy 		return (EINVAL);
1160eda14cbcSMatt Macy 
1161eda14cbcSMatt Macy 	/*
1162eda14cbcSMatt Macy 	 * Verify type and nelem and get the value size.
1163eda14cbcSMatt Macy 	 * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY
1164eda14cbcSMatt Macy 	 * is the size of the string(s) included.
1165eda14cbcSMatt Macy 	 */
1166eda14cbcSMatt Macy 	if ((value_sz = i_get_value_size(type, data, nelem)) < 0)
1167eda14cbcSMatt Macy 		return (EINVAL);
1168eda14cbcSMatt Macy 
1169eda14cbcSMatt Macy 	if (i_validate_nvpair_value(type, nelem, data) != 0)
1170eda14cbcSMatt Macy 		return (EINVAL);
1171eda14cbcSMatt Macy 
1172eda14cbcSMatt Macy 	/*
1173eda14cbcSMatt Macy 	 * If we're adding an nvlist or nvlist array, ensure that we are not
1174eda14cbcSMatt Macy 	 * adding the input nvlist to itself, which would cause recursion,
1175eda14cbcSMatt Macy 	 * and ensure that no NULL nvlist pointers are present.
1176eda14cbcSMatt Macy 	 */
1177eda14cbcSMatt Macy 	switch (type) {
1178eda14cbcSMatt Macy 	case DATA_TYPE_NVLIST:
1179eda14cbcSMatt Macy 		if (data == nvl || data == NULL)
1180eda14cbcSMatt Macy 			return (EINVAL);
1181eda14cbcSMatt Macy 		break;
1182eda14cbcSMatt Macy 	case DATA_TYPE_NVLIST_ARRAY: {
1183eda14cbcSMatt Macy 		nvlist_t **onvlp = (nvlist_t **)data;
1184eda14cbcSMatt Macy 		for (i = 0; i < nelem; i++) {
1185eda14cbcSMatt Macy 			if (onvlp[i] == nvl || onvlp[i] == NULL)
1186eda14cbcSMatt Macy 				return (EINVAL);
1187eda14cbcSMatt Macy 		}
1188eda14cbcSMatt Macy 		break;
1189eda14cbcSMatt Macy 	}
1190eda14cbcSMatt Macy 	default:
1191eda14cbcSMatt Macy 		break;
1192eda14cbcSMatt Macy 	}
1193eda14cbcSMatt Macy 
1194eda14cbcSMatt Macy 	/* calculate sizes of the nvpair elements and the nvpair itself */
1195eda14cbcSMatt Macy 	name_sz = strlen(name) + 1;
1196eda14cbcSMatt Macy 	if (name_sz >= 1ULL << (sizeof (nvp->nvp_name_sz) * NBBY - 1))
1197eda14cbcSMatt Macy 		return (EINVAL);
1198eda14cbcSMatt Macy 
1199eda14cbcSMatt Macy 	nvp_sz = NVP_SIZE_CALC(name_sz, value_sz);
1200eda14cbcSMatt Macy 
1201eda14cbcSMatt Macy 	if ((nvp = nvp_buf_alloc(nvl, nvp_sz)) == NULL)
1202eda14cbcSMatt Macy 		return (ENOMEM);
1203eda14cbcSMatt Macy 
1204eda14cbcSMatt Macy 	ASSERT(nvp->nvp_size == nvp_sz);
1205eda14cbcSMatt Macy 	nvp->nvp_name_sz = name_sz;
1206eda14cbcSMatt Macy 	nvp->nvp_value_elem = nelem;
1207eda14cbcSMatt Macy 	nvp->nvp_type = type;
1208da5137abSMartin Matuska 	memcpy(NVP_NAME(nvp), name, name_sz);
1209eda14cbcSMatt Macy 
1210eda14cbcSMatt Macy 	switch (type) {
1211eda14cbcSMatt Macy 	case DATA_TYPE_BOOLEAN:
1212eda14cbcSMatt Macy 		break;
1213eda14cbcSMatt Macy 	case DATA_TYPE_STRING_ARRAY: {
1214eda14cbcSMatt Macy 		char *const *strs = data;
1215eda14cbcSMatt Macy 		char *buf = NVP_VALUE(nvp);
1216eda14cbcSMatt Macy 		char **cstrs = (void *)buf;
1217eda14cbcSMatt Macy 
1218eda14cbcSMatt Macy 		/* skip pre-allocated space for pointer array */
1219eda14cbcSMatt Macy 		buf += nelem * sizeof (uint64_t);
1220eda14cbcSMatt Macy 		for (i = 0; i < nelem; i++) {
1221eda14cbcSMatt Macy 			int slen = strlen(strs[i]) + 1;
1222da5137abSMartin Matuska 			memcpy(buf, strs[i], slen);
1223eda14cbcSMatt Macy 			cstrs[i] = buf;
1224eda14cbcSMatt Macy 			buf += slen;
1225eda14cbcSMatt Macy 		}
1226eda14cbcSMatt Macy 		break;
1227eda14cbcSMatt Macy 	}
1228eda14cbcSMatt Macy 	case DATA_TYPE_NVLIST: {
1229eda14cbcSMatt Macy 		nvlist_t *nnvl = EMBEDDED_NVL(nvp);
1230eda14cbcSMatt Macy 		nvlist_t *onvl = (nvlist_t *)data;
1231eda14cbcSMatt Macy 
1232eda14cbcSMatt Macy 		if ((err = nvlist_copy_embedded(nvl, onvl, nnvl)) != 0) {
1233eda14cbcSMatt Macy 			nvp_buf_free(nvl, nvp);
1234eda14cbcSMatt Macy 			return (err);
1235eda14cbcSMatt Macy 		}
1236eda14cbcSMatt Macy 		break;
1237eda14cbcSMatt Macy 	}
1238eda14cbcSMatt Macy 	case DATA_TYPE_NVLIST_ARRAY: {
1239eda14cbcSMatt Macy 		nvlist_t **onvlp = (nvlist_t **)data;
1240eda14cbcSMatt Macy 		nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp);
1241eda14cbcSMatt Macy 		nvlist_t *embedded = (nvlist_t *)
1242eda14cbcSMatt Macy 		    ((uintptr_t)nvlp + nelem * sizeof (uint64_t));
1243eda14cbcSMatt Macy 
1244eda14cbcSMatt Macy 		for (i = 0; i < nelem; i++) {
1245eda14cbcSMatt Macy 			if ((err = nvlist_copy_embedded(nvl,
1246eda14cbcSMatt Macy 			    onvlp[i], embedded)) != 0) {
1247eda14cbcSMatt Macy 				/*
1248eda14cbcSMatt Macy 				 * Free any successfully created lists
1249eda14cbcSMatt Macy 				 */
1250eda14cbcSMatt Macy 				nvpair_free(nvp);
1251eda14cbcSMatt Macy 				nvp_buf_free(nvl, nvp);
1252eda14cbcSMatt Macy 				return (err);
1253eda14cbcSMatt Macy 			}
1254eda14cbcSMatt Macy 
1255eda14cbcSMatt Macy 			nvlp[i] = embedded++;
1256eda14cbcSMatt Macy 		}
1257eda14cbcSMatt Macy 		break;
1258eda14cbcSMatt Macy 	}
1259eda14cbcSMatt Macy 	default:
1260da5137abSMartin Matuska 		memcpy(NVP_VALUE(nvp), data, value_sz);
1261eda14cbcSMatt Macy 	}
1262eda14cbcSMatt Macy 
1263eda14cbcSMatt Macy 	/* if unique name, remove before add */
1264eda14cbcSMatt Macy 	if (nvl->nvl_nvflag & NV_UNIQUE_NAME)
1265eda14cbcSMatt Macy 		(void) nvlist_remove_all(nvl, name);
1266eda14cbcSMatt Macy 	else if (nvl->nvl_nvflag & NV_UNIQUE_NAME_TYPE)
1267eda14cbcSMatt Macy 		(void) nvlist_remove(nvl, name, type);
1268eda14cbcSMatt Macy 
1269eda14cbcSMatt Macy 	err = nvt_add_nvpair(nvl, nvp);
1270eda14cbcSMatt Macy 	if (err != 0) {
1271eda14cbcSMatt Macy 		nvpair_free(nvp);
1272eda14cbcSMatt Macy 		nvp_buf_free(nvl, nvp);
1273eda14cbcSMatt Macy 		return (err);
1274eda14cbcSMatt Macy 	}
1275eda14cbcSMatt Macy 	nvp_buf_link(nvl, nvp);
1276eda14cbcSMatt Macy 
1277eda14cbcSMatt Macy 	return (0);
1278eda14cbcSMatt Macy }
1279eda14cbcSMatt Macy 
1280eda14cbcSMatt Macy int
nvlist_add_boolean(nvlist_t * nvl,const char * name)1281eda14cbcSMatt Macy nvlist_add_boolean(nvlist_t *nvl, const char *name)
1282eda14cbcSMatt Macy {
1283eda14cbcSMatt Macy 	return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN, 0, NULL));
1284eda14cbcSMatt Macy }
1285eda14cbcSMatt Macy 
1286eda14cbcSMatt Macy int
nvlist_add_boolean_value(nvlist_t * nvl,const char * name,boolean_t val)1287eda14cbcSMatt Macy nvlist_add_boolean_value(nvlist_t *nvl, const char *name, boolean_t val)
1288eda14cbcSMatt Macy {
1289eda14cbcSMatt Macy 	return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_VALUE, 1, &val));
1290eda14cbcSMatt Macy }
1291eda14cbcSMatt Macy 
1292eda14cbcSMatt Macy int
nvlist_add_byte(nvlist_t * nvl,const char * name,uchar_t val)1293eda14cbcSMatt Macy nvlist_add_byte(nvlist_t *nvl, const char *name, uchar_t val)
1294eda14cbcSMatt Macy {
1295eda14cbcSMatt Macy 	return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE, 1, &val));
1296eda14cbcSMatt Macy }
1297eda14cbcSMatt Macy 
1298eda14cbcSMatt Macy int
nvlist_add_int8(nvlist_t * nvl,const char * name,int8_t val)1299eda14cbcSMatt Macy nvlist_add_int8(nvlist_t *nvl, const char *name, int8_t val)
1300eda14cbcSMatt Macy {
1301eda14cbcSMatt Macy 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT8, 1, &val));
1302eda14cbcSMatt Macy }
1303eda14cbcSMatt Macy 
1304eda14cbcSMatt Macy int
nvlist_add_uint8(nvlist_t * nvl,const char * name,uint8_t val)1305eda14cbcSMatt Macy nvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t val)
1306eda14cbcSMatt Macy {
1307eda14cbcSMatt Macy 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8, 1, &val));
1308eda14cbcSMatt Macy }
1309eda14cbcSMatt Macy 
1310eda14cbcSMatt Macy int
nvlist_add_int16(nvlist_t * nvl,const char * name,int16_t val)1311eda14cbcSMatt Macy nvlist_add_int16(nvlist_t *nvl, const char *name, int16_t val)
1312eda14cbcSMatt Macy {
1313eda14cbcSMatt Macy 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT16, 1, &val));
1314eda14cbcSMatt Macy }
1315eda14cbcSMatt Macy 
1316eda14cbcSMatt Macy int
nvlist_add_uint16(nvlist_t * nvl,const char * name,uint16_t val)1317eda14cbcSMatt Macy nvlist_add_uint16(nvlist_t *nvl, const char *name, uint16_t val)
1318eda14cbcSMatt Macy {
1319eda14cbcSMatt Macy 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16, 1, &val));
1320eda14cbcSMatt Macy }
1321eda14cbcSMatt Macy 
1322eda14cbcSMatt Macy int
nvlist_add_int32(nvlist_t * nvl,const char * name,int32_t val)1323eda14cbcSMatt Macy nvlist_add_int32(nvlist_t *nvl, const char *name, int32_t val)
1324eda14cbcSMatt Macy {
1325eda14cbcSMatt Macy 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT32, 1, &val));
1326eda14cbcSMatt Macy }
1327eda14cbcSMatt Macy 
1328eda14cbcSMatt Macy int
nvlist_add_uint32(nvlist_t * nvl,const char * name,uint32_t val)1329eda14cbcSMatt Macy nvlist_add_uint32(nvlist_t *nvl, const char *name, uint32_t val)
1330eda14cbcSMatt Macy {
1331eda14cbcSMatt Macy 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32, 1, &val));
1332eda14cbcSMatt Macy }
1333eda14cbcSMatt Macy 
1334eda14cbcSMatt Macy int
nvlist_add_int64(nvlist_t * nvl,const char * name,int64_t val)1335eda14cbcSMatt Macy nvlist_add_int64(nvlist_t *nvl, const char *name, int64_t val)
1336eda14cbcSMatt Macy {
1337eda14cbcSMatt Macy 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT64, 1, &val));
1338eda14cbcSMatt Macy }
1339eda14cbcSMatt Macy 
1340eda14cbcSMatt Macy int
nvlist_add_uint64(nvlist_t * nvl,const char * name,uint64_t val)1341eda14cbcSMatt Macy nvlist_add_uint64(nvlist_t *nvl, const char *name, uint64_t val)
1342eda14cbcSMatt Macy {
1343eda14cbcSMatt Macy 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64, 1, &val));
1344eda14cbcSMatt Macy }
1345eda14cbcSMatt Macy 
1346eda14cbcSMatt Macy #if !defined(_KERNEL)
1347eda14cbcSMatt Macy int
nvlist_add_double(nvlist_t * nvl,const char * name,double val)1348eda14cbcSMatt Macy nvlist_add_double(nvlist_t *nvl, const char *name, double val)
1349eda14cbcSMatt Macy {
1350eda14cbcSMatt Macy 	return (nvlist_add_common(nvl, name, DATA_TYPE_DOUBLE, 1, &val));
1351eda14cbcSMatt Macy }
1352eda14cbcSMatt Macy #endif
1353eda14cbcSMatt Macy 
1354eda14cbcSMatt Macy int
nvlist_add_string(nvlist_t * nvl,const char * name,const char * val)1355eda14cbcSMatt Macy nvlist_add_string(nvlist_t *nvl, const char *name, const char *val)
1356eda14cbcSMatt Macy {
1357eda14cbcSMatt Macy 	return (nvlist_add_common(nvl, name, DATA_TYPE_STRING, 1, (void *)val));
1358eda14cbcSMatt Macy }
1359eda14cbcSMatt Macy 
1360eda14cbcSMatt Macy int
nvlist_add_boolean_array(nvlist_t * nvl,const char * name,const boolean_t * a,uint_t n)1361eda14cbcSMatt Macy nvlist_add_boolean_array(nvlist_t *nvl, const char *name,
1362681ce946SMartin Matuska     const boolean_t *a, uint_t n)
1363eda14cbcSMatt Macy {
1364eda14cbcSMatt Macy 	return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_ARRAY, n, a));
1365eda14cbcSMatt Macy }
1366eda14cbcSMatt Macy 
1367eda14cbcSMatt Macy int
nvlist_add_byte_array(nvlist_t * nvl,const char * name,const uchar_t * a,uint_t n)1368681ce946SMartin Matuska nvlist_add_byte_array(nvlist_t *nvl, const char *name, const uchar_t *a,
1369681ce946SMartin Matuska     uint_t n)
1370eda14cbcSMatt Macy {
1371eda14cbcSMatt Macy 	return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a));
1372eda14cbcSMatt Macy }
1373eda14cbcSMatt Macy 
1374eda14cbcSMatt Macy int
nvlist_add_int8_array(nvlist_t * nvl,const char * name,const int8_t * a,uint_t n)1375681ce946SMartin Matuska nvlist_add_int8_array(nvlist_t *nvl, const char *name, const int8_t *a,
1376681ce946SMartin Matuska     uint_t n)
1377eda14cbcSMatt Macy {
1378eda14cbcSMatt Macy 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a));
1379eda14cbcSMatt Macy }
1380eda14cbcSMatt Macy 
1381eda14cbcSMatt Macy int
nvlist_add_uint8_array(nvlist_t * nvl,const char * name,const uint8_t * a,uint_t n)1382681ce946SMartin Matuska nvlist_add_uint8_array(nvlist_t *nvl, const char *name, const uint8_t *a,
1383681ce946SMartin Matuska     uint_t n)
1384eda14cbcSMatt Macy {
1385eda14cbcSMatt Macy 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a));
1386eda14cbcSMatt Macy }
1387eda14cbcSMatt Macy 
1388eda14cbcSMatt Macy int
nvlist_add_int16_array(nvlist_t * nvl,const char * name,const int16_t * a,uint_t n)1389681ce946SMartin Matuska nvlist_add_int16_array(nvlist_t *nvl, const char *name, const int16_t *a,
1390681ce946SMartin Matuska     uint_t n)
1391eda14cbcSMatt Macy {
1392eda14cbcSMatt Macy 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a));
1393eda14cbcSMatt Macy }
1394eda14cbcSMatt Macy 
1395eda14cbcSMatt Macy int
nvlist_add_uint16_array(nvlist_t * nvl,const char * name,const uint16_t * a,uint_t n)1396681ce946SMartin Matuska nvlist_add_uint16_array(nvlist_t *nvl, const char *name, const uint16_t *a,
1397681ce946SMartin Matuska     uint_t n)
1398eda14cbcSMatt Macy {
1399eda14cbcSMatt Macy 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a));
1400eda14cbcSMatt Macy }
1401eda14cbcSMatt Macy 
1402eda14cbcSMatt Macy int
nvlist_add_int32_array(nvlist_t * nvl,const char * name,const int32_t * a,uint_t n)1403681ce946SMartin Matuska nvlist_add_int32_array(nvlist_t *nvl, const char *name, const int32_t *a,
1404681ce946SMartin Matuska     uint_t n)
1405eda14cbcSMatt Macy {
1406eda14cbcSMatt Macy 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a));
1407eda14cbcSMatt Macy }
1408eda14cbcSMatt Macy 
1409eda14cbcSMatt Macy int
nvlist_add_uint32_array(nvlist_t * nvl,const char * name,const uint32_t * a,uint_t n)1410681ce946SMartin Matuska nvlist_add_uint32_array(nvlist_t *nvl, const char *name, const uint32_t *a,
1411681ce946SMartin Matuska     uint_t n)
1412eda14cbcSMatt Macy {
1413eda14cbcSMatt Macy 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a));
1414eda14cbcSMatt Macy }
1415eda14cbcSMatt Macy 
1416eda14cbcSMatt Macy int
nvlist_add_int64_array(nvlist_t * nvl,const char * name,const int64_t * a,uint_t n)1417681ce946SMartin Matuska nvlist_add_int64_array(nvlist_t *nvl, const char *name, const int64_t *a,
1418681ce946SMartin Matuska     uint_t n)
1419eda14cbcSMatt Macy {
1420eda14cbcSMatt Macy 	return (nvlist_add_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a));
1421eda14cbcSMatt Macy }
1422eda14cbcSMatt Macy 
1423eda14cbcSMatt Macy int
nvlist_add_uint64_array(nvlist_t * nvl,const char * name,const uint64_t * a,uint_t n)1424681ce946SMartin Matuska nvlist_add_uint64_array(nvlist_t *nvl, const char *name, const uint64_t *a,
1425681ce946SMartin Matuska     uint_t n)
1426eda14cbcSMatt Macy {
1427eda14cbcSMatt Macy 	return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a));
1428eda14cbcSMatt Macy }
1429eda14cbcSMatt Macy 
1430eda14cbcSMatt Macy int
nvlist_add_string_array(nvlist_t * nvl,const char * name,const char * const * a,uint_t n)1431eda14cbcSMatt Macy nvlist_add_string_array(nvlist_t *nvl, const char *name,
1432681ce946SMartin Matuska     const char *const *a, uint_t n)
1433eda14cbcSMatt Macy {
1434eda14cbcSMatt Macy 	return (nvlist_add_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a));
1435eda14cbcSMatt Macy }
1436eda14cbcSMatt Macy 
1437eda14cbcSMatt Macy int
nvlist_add_hrtime(nvlist_t * nvl,const char * name,hrtime_t val)1438eda14cbcSMatt Macy nvlist_add_hrtime(nvlist_t *nvl, const char *name, hrtime_t val)
1439eda14cbcSMatt Macy {
1440eda14cbcSMatt Macy 	return (nvlist_add_common(nvl, name, DATA_TYPE_HRTIME, 1, &val));
1441eda14cbcSMatt Macy }
1442eda14cbcSMatt Macy 
1443eda14cbcSMatt Macy int
nvlist_add_nvlist(nvlist_t * nvl,const char * name,const nvlist_t * val)1444681ce946SMartin Matuska nvlist_add_nvlist(nvlist_t *nvl, const char *name, const nvlist_t *val)
1445eda14cbcSMatt Macy {
1446eda14cbcSMatt Macy 	return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST, 1, val));
1447eda14cbcSMatt Macy }
1448eda14cbcSMatt Macy 
1449eda14cbcSMatt Macy int
nvlist_add_nvlist_array(nvlist_t * nvl,const char * name,const nvlist_t * const * a,uint_t n)1450681ce946SMartin Matuska nvlist_add_nvlist_array(nvlist_t *nvl, const char *name,
1451681ce946SMartin Matuska     const nvlist_t * const *a, uint_t n)
1452eda14cbcSMatt Macy {
1453eda14cbcSMatt Macy 	return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a));
1454eda14cbcSMatt Macy }
1455eda14cbcSMatt Macy 
1456eda14cbcSMatt Macy /* reading name-value pairs */
1457eda14cbcSMatt Macy nvpair_t *
nvlist_next_nvpair(nvlist_t * nvl,const nvpair_t * nvp)1458681ce946SMartin Matuska nvlist_next_nvpair(nvlist_t *nvl, const nvpair_t *nvp)
1459eda14cbcSMatt Macy {
1460eda14cbcSMatt Macy 	nvpriv_t *priv;
1461eda14cbcSMatt Macy 	i_nvp_t *curr;
1462eda14cbcSMatt Macy 
1463eda14cbcSMatt Macy 	if (nvl == NULL ||
1464eda14cbcSMatt Macy 	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
1465eda14cbcSMatt Macy 		return (NULL);
1466eda14cbcSMatt Macy 
1467eda14cbcSMatt Macy 	curr = NVPAIR2I_NVP(nvp);
1468eda14cbcSMatt Macy 
1469eda14cbcSMatt Macy 	/*
1470eda14cbcSMatt Macy 	 * Ensure that nvp is a valid nvpair on this nvlist.
1471eda14cbcSMatt Macy 	 * NB: nvp_curr is used only as a hint so that we don't always
1472eda14cbcSMatt Macy 	 * have to walk the list to determine if nvp is still on the list.
1473eda14cbcSMatt Macy 	 */
1474eda14cbcSMatt Macy 	if (nvp == NULL)
1475eda14cbcSMatt Macy 		curr = priv->nvp_list;
1476eda14cbcSMatt Macy 	else if (priv->nvp_curr == curr || nvlist_contains_nvp(nvl, nvp))
1477eda14cbcSMatt Macy 		curr = curr->nvi_next;
1478eda14cbcSMatt Macy 	else
1479eda14cbcSMatt Macy 		curr = NULL;
1480eda14cbcSMatt Macy 
1481eda14cbcSMatt Macy 	priv->nvp_curr = curr;
1482eda14cbcSMatt Macy 
1483eda14cbcSMatt Macy 	return (curr != NULL ? &curr->nvi_nvp : NULL);
1484eda14cbcSMatt Macy }
1485eda14cbcSMatt Macy 
1486eda14cbcSMatt Macy nvpair_t *
nvlist_prev_nvpair(nvlist_t * nvl,const nvpair_t * nvp)1487681ce946SMartin Matuska nvlist_prev_nvpair(nvlist_t *nvl, const nvpair_t *nvp)
1488eda14cbcSMatt Macy {
1489eda14cbcSMatt Macy 	nvpriv_t *priv;
1490eda14cbcSMatt Macy 	i_nvp_t *curr;
1491eda14cbcSMatt Macy 
1492eda14cbcSMatt Macy 	if (nvl == NULL ||
1493eda14cbcSMatt Macy 	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
1494eda14cbcSMatt Macy 		return (NULL);
1495eda14cbcSMatt Macy 
1496eda14cbcSMatt Macy 	curr = NVPAIR2I_NVP(nvp);
1497eda14cbcSMatt Macy 
1498eda14cbcSMatt Macy 	if (nvp == NULL)
1499eda14cbcSMatt Macy 		curr = priv->nvp_last;
1500eda14cbcSMatt Macy 	else if (priv->nvp_curr == curr || nvlist_contains_nvp(nvl, nvp))
1501eda14cbcSMatt Macy 		curr = curr->nvi_prev;
1502eda14cbcSMatt Macy 	else
1503eda14cbcSMatt Macy 		curr = NULL;
1504eda14cbcSMatt Macy 
1505eda14cbcSMatt Macy 	priv->nvp_curr = curr;
1506eda14cbcSMatt Macy 
1507eda14cbcSMatt Macy 	return (curr != NULL ? &curr->nvi_nvp : NULL);
1508eda14cbcSMatt Macy }
1509eda14cbcSMatt Macy 
1510eda14cbcSMatt Macy boolean_t
nvlist_empty(const nvlist_t * nvl)1511681ce946SMartin Matuska nvlist_empty(const nvlist_t *nvl)
1512eda14cbcSMatt Macy {
1513681ce946SMartin Matuska 	const nvpriv_t *priv;
1514eda14cbcSMatt Macy 
1515eda14cbcSMatt Macy 	if (nvl == NULL ||
1516681ce946SMartin Matuska 	    (priv = (const nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
1517eda14cbcSMatt Macy 		return (B_TRUE);
1518eda14cbcSMatt Macy 
1519eda14cbcSMatt Macy 	return (priv->nvp_list == NULL);
1520eda14cbcSMatt Macy }
1521eda14cbcSMatt Macy 
15222a58b312SMartin Matuska const char *
nvpair_name(const nvpair_t * nvp)1523681ce946SMartin Matuska nvpair_name(const nvpair_t *nvp)
1524eda14cbcSMatt Macy {
1525eda14cbcSMatt Macy 	return (NVP_NAME(nvp));
1526eda14cbcSMatt Macy }
1527eda14cbcSMatt Macy 
1528eda14cbcSMatt Macy data_type_t
nvpair_type(const nvpair_t * nvp)1529681ce946SMartin Matuska nvpair_type(const nvpair_t *nvp)
1530eda14cbcSMatt Macy {
1531eda14cbcSMatt Macy 	return (NVP_TYPE(nvp));
1532eda14cbcSMatt Macy }
1533eda14cbcSMatt Macy 
1534eda14cbcSMatt Macy int
nvpair_type_is_array(const nvpair_t * nvp)1535681ce946SMartin Matuska nvpair_type_is_array(const nvpair_t *nvp)
1536eda14cbcSMatt Macy {
1537eda14cbcSMatt Macy 	data_type_t type = NVP_TYPE(nvp);
1538eda14cbcSMatt Macy 
1539eda14cbcSMatt Macy 	if ((type == DATA_TYPE_BYTE_ARRAY) ||
1540eda14cbcSMatt Macy 	    (type == DATA_TYPE_INT8_ARRAY) ||
1541eda14cbcSMatt Macy 	    (type == DATA_TYPE_UINT8_ARRAY) ||
1542eda14cbcSMatt Macy 	    (type == DATA_TYPE_INT16_ARRAY) ||
1543eda14cbcSMatt Macy 	    (type == DATA_TYPE_UINT16_ARRAY) ||
1544eda14cbcSMatt Macy 	    (type == DATA_TYPE_INT32_ARRAY) ||
1545eda14cbcSMatt Macy 	    (type == DATA_TYPE_UINT32_ARRAY) ||
1546eda14cbcSMatt Macy 	    (type == DATA_TYPE_INT64_ARRAY) ||
1547eda14cbcSMatt Macy 	    (type == DATA_TYPE_UINT64_ARRAY) ||
1548eda14cbcSMatt Macy 	    (type == DATA_TYPE_BOOLEAN_ARRAY) ||
1549eda14cbcSMatt Macy 	    (type == DATA_TYPE_STRING_ARRAY) ||
1550eda14cbcSMatt Macy 	    (type == DATA_TYPE_NVLIST_ARRAY))
1551eda14cbcSMatt Macy 		return (1);
1552eda14cbcSMatt Macy 	return (0);
1553eda14cbcSMatt Macy 
1554eda14cbcSMatt Macy }
1555eda14cbcSMatt Macy 
1556eda14cbcSMatt Macy static int
nvpair_value_common(const nvpair_t * nvp,data_type_t type,uint_t * nelem,void * data)1557681ce946SMartin Matuska nvpair_value_common(const nvpair_t *nvp, data_type_t type, uint_t *nelem,
1558681ce946SMartin Matuska     void *data)
1559eda14cbcSMatt Macy {
1560eda14cbcSMatt Macy 	int value_sz;
1561eda14cbcSMatt Macy 
1562eda14cbcSMatt Macy 	if (nvp == NULL || nvpair_type(nvp) != type)
1563eda14cbcSMatt Macy 		return (EINVAL);
1564eda14cbcSMatt Macy 
1565eda14cbcSMatt Macy 	/*
1566eda14cbcSMatt Macy 	 * For non-array types, we copy the data.
1567eda14cbcSMatt Macy 	 * For array types (including string), we set a pointer.
1568eda14cbcSMatt Macy 	 */
1569eda14cbcSMatt Macy 	switch (type) {
1570eda14cbcSMatt Macy 	case DATA_TYPE_BOOLEAN:
1571eda14cbcSMatt Macy 		if (nelem != NULL)
1572eda14cbcSMatt Macy 			*nelem = 0;
1573eda14cbcSMatt Macy 		break;
1574eda14cbcSMatt Macy 
1575eda14cbcSMatt Macy 	case DATA_TYPE_BOOLEAN_VALUE:
1576eda14cbcSMatt Macy 	case DATA_TYPE_BYTE:
1577eda14cbcSMatt Macy 	case DATA_TYPE_INT8:
1578eda14cbcSMatt Macy 	case DATA_TYPE_UINT8:
1579eda14cbcSMatt Macy 	case DATA_TYPE_INT16:
1580eda14cbcSMatt Macy 	case DATA_TYPE_UINT16:
1581eda14cbcSMatt Macy 	case DATA_TYPE_INT32:
1582eda14cbcSMatt Macy 	case DATA_TYPE_UINT32:
1583eda14cbcSMatt Macy 	case DATA_TYPE_INT64:
1584eda14cbcSMatt Macy 	case DATA_TYPE_UINT64:
1585eda14cbcSMatt Macy 	case DATA_TYPE_HRTIME:
1586eda14cbcSMatt Macy #if !defined(_KERNEL)
1587eda14cbcSMatt Macy 	case DATA_TYPE_DOUBLE:
1588eda14cbcSMatt Macy #endif
1589eda14cbcSMatt Macy 		if (data == NULL)
1590eda14cbcSMatt Macy 			return (EINVAL);
1591eda14cbcSMatt Macy 		if ((value_sz = i_get_value_size(type, NULL, 1)) < 0)
1592eda14cbcSMatt Macy 			return (EINVAL);
1593da5137abSMartin Matuska 		memcpy(data, NVP_VALUE(nvp), (size_t)value_sz);
1594eda14cbcSMatt Macy 		if (nelem != NULL)
1595eda14cbcSMatt Macy 			*nelem = 1;
1596eda14cbcSMatt Macy 		break;
1597eda14cbcSMatt Macy 
1598eda14cbcSMatt Macy 	case DATA_TYPE_NVLIST:
1599eda14cbcSMatt Macy 	case DATA_TYPE_STRING:
1600eda14cbcSMatt Macy 		if (data == NULL)
1601eda14cbcSMatt Macy 			return (EINVAL);
1602681ce946SMartin Matuska 		/*
1603681ce946SMartin Matuska 		 * This discards the const from nvp, so all callers for these
1604681ce946SMartin Matuska 		 * types must not accept const nvpairs.
1605681ce946SMartin Matuska 		 */
1606eda14cbcSMatt Macy 		*(void **)data = (void *)NVP_VALUE(nvp);
1607eda14cbcSMatt Macy 		if (nelem != NULL)
1608eda14cbcSMatt Macy 			*nelem = 1;
1609eda14cbcSMatt Macy 		break;
1610eda14cbcSMatt Macy 
1611eda14cbcSMatt Macy 	case DATA_TYPE_BOOLEAN_ARRAY:
1612eda14cbcSMatt Macy 	case DATA_TYPE_BYTE_ARRAY:
1613eda14cbcSMatt Macy 	case DATA_TYPE_INT8_ARRAY:
1614eda14cbcSMatt Macy 	case DATA_TYPE_UINT8_ARRAY:
1615eda14cbcSMatt Macy 	case DATA_TYPE_INT16_ARRAY:
1616eda14cbcSMatt Macy 	case DATA_TYPE_UINT16_ARRAY:
1617eda14cbcSMatt Macy 	case DATA_TYPE_INT32_ARRAY:
1618eda14cbcSMatt Macy 	case DATA_TYPE_UINT32_ARRAY:
1619eda14cbcSMatt Macy 	case DATA_TYPE_INT64_ARRAY:
1620eda14cbcSMatt Macy 	case DATA_TYPE_UINT64_ARRAY:
1621eda14cbcSMatt Macy 	case DATA_TYPE_STRING_ARRAY:
1622eda14cbcSMatt Macy 	case DATA_TYPE_NVLIST_ARRAY:
1623eda14cbcSMatt Macy 		if (nelem == NULL || data == NULL)
1624eda14cbcSMatt Macy 			return (EINVAL);
1625681ce946SMartin Matuska 		/*
1626681ce946SMartin Matuska 		 * This discards the const from nvp, so all callers for these
1627681ce946SMartin Matuska 		 * types must not accept const nvpairs.
1628681ce946SMartin Matuska 		 */
1629eda14cbcSMatt Macy 		if ((*nelem = NVP_NELEM(nvp)) != 0)
1630eda14cbcSMatt Macy 			*(void **)data = (void *)NVP_VALUE(nvp);
1631eda14cbcSMatt Macy 		else
1632eda14cbcSMatt Macy 			*(void **)data = NULL;
1633eda14cbcSMatt Macy 		break;
1634eda14cbcSMatt Macy 
1635eda14cbcSMatt Macy 	default:
1636eda14cbcSMatt Macy 		return (ENOTSUP);
1637eda14cbcSMatt Macy 	}
1638eda14cbcSMatt Macy 
1639eda14cbcSMatt Macy 	return (0);
1640eda14cbcSMatt Macy }
1641eda14cbcSMatt Macy 
1642eda14cbcSMatt Macy static int
nvlist_lookup_common(const nvlist_t * nvl,const char * name,data_type_t type,uint_t * nelem,void * data)1643681ce946SMartin Matuska nvlist_lookup_common(const nvlist_t *nvl, const char *name, data_type_t type,
1644eda14cbcSMatt Macy     uint_t *nelem, void *data)
1645eda14cbcSMatt Macy {
1646eda14cbcSMatt Macy 	if (name == NULL || nvl == NULL || nvl->nvl_priv == 0)
1647eda14cbcSMatt Macy 		return (EINVAL);
1648eda14cbcSMatt Macy 
1649eda14cbcSMatt Macy 	if (!(nvl->nvl_nvflag & (NV_UNIQUE_NAME | NV_UNIQUE_NAME_TYPE)))
1650eda14cbcSMatt Macy 		return (ENOTSUP);
1651eda14cbcSMatt Macy 
1652eda14cbcSMatt Macy 	nvpair_t *nvp = nvt_lookup_name_type(nvl, name, type);
1653eda14cbcSMatt Macy 	if (nvp == NULL)
1654eda14cbcSMatt Macy 		return (ENOENT);
1655eda14cbcSMatt Macy 
1656eda14cbcSMatt Macy 	return (nvpair_value_common(nvp, type, nelem, data));
1657eda14cbcSMatt Macy }
1658eda14cbcSMatt Macy 
1659eda14cbcSMatt Macy int
nvlist_lookup_boolean(const nvlist_t * nvl,const char * name)1660681ce946SMartin Matuska nvlist_lookup_boolean(const nvlist_t *nvl, const char *name)
1661eda14cbcSMatt Macy {
1662eda14cbcSMatt Macy 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_BOOLEAN, NULL, NULL));
1663eda14cbcSMatt Macy }
1664eda14cbcSMatt Macy 
1665eda14cbcSMatt Macy int
nvlist_lookup_boolean_value(const nvlist_t * nvl,const char * name,boolean_t * val)1666681ce946SMartin Matuska nvlist_lookup_boolean_value(const nvlist_t *nvl, const char *name,
1667681ce946SMartin Matuska     boolean_t *val)
1668eda14cbcSMatt Macy {
1669eda14cbcSMatt Macy 	return (nvlist_lookup_common(nvl, name,
1670eda14cbcSMatt Macy 	    DATA_TYPE_BOOLEAN_VALUE, NULL, val));
1671eda14cbcSMatt Macy }
1672eda14cbcSMatt Macy 
1673eda14cbcSMatt Macy int
nvlist_lookup_byte(const nvlist_t * nvl,const char * name,uchar_t * val)1674681ce946SMartin Matuska nvlist_lookup_byte(const nvlist_t *nvl, const char *name, uchar_t *val)
1675eda14cbcSMatt Macy {
1676eda14cbcSMatt Macy 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_BYTE, NULL, val));
1677eda14cbcSMatt Macy }
1678eda14cbcSMatt Macy 
1679eda14cbcSMatt Macy int
nvlist_lookup_int8(const nvlist_t * nvl,const char * name,int8_t * val)1680681ce946SMartin Matuska nvlist_lookup_int8(const nvlist_t *nvl, const char *name, int8_t *val)
1681eda14cbcSMatt Macy {
1682eda14cbcSMatt Macy 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT8, NULL, val));
1683eda14cbcSMatt Macy }
1684eda14cbcSMatt Macy 
1685eda14cbcSMatt Macy int
nvlist_lookup_uint8(const nvlist_t * nvl,const char * name,uint8_t * val)1686681ce946SMartin Matuska nvlist_lookup_uint8(const nvlist_t *nvl, const char *name, uint8_t *val)
1687eda14cbcSMatt Macy {
1688eda14cbcSMatt Macy 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT8, NULL, val));
1689eda14cbcSMatt Macy }
1690eda14cbcSMatt Macy 
1691eda14cbcSMatt Macy int
nvlist_lookup_int16(const nvlist_t * nvl,const char * name,int16_t * val)1692681ce946SMartin Matuska nvlist_lookup_int16(const nvlist_t *nvl, const char *name, int16_t *val)
1693eda14cbcSMatt Macy {
1694eda14cbcSMatt Macy 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT16, NULL, val));
1695eda14cbcSMatt Macy }
1696eda14cbcSMatt Macy 
1697eda14cbcSMatt Macy int
nvlist_lookup_uint16(const nvlist_t * nvl,const char * name,uint16_t * val)1698681ce946SMartin Matuska nvlist_lookup_uint16(const nvlist_t *nvl, const char *name, uint16_t *val)
1699eda14cbcSMatt Macy {
1700eda14cbcSMatt Macy 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT16, NULL, val));
1701eda14cbcSMatt Macy }
1702eda14cbcSMatt Macy 
1703eda14cbcSMatt Macy int
nvlist_lookup_int32(const nvlist_t * nvl,const char * name,int32_t * val)1704681ce946SMartin Matuska nvlist_lookup_int32(const nvlist_t *nvl, const char *name, int32_t *val)
1705eda14cbcSMatt Macy {
1706eda14cbcSMatt Macy 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT32, NULL, val));
1707eda14cbcSMatt Macy }
1708eda14cbcSMatt Macy 
1709eda14cbcSMatt Macy int
nvlist_lookup_uint32(const nvlist_t * nvl,const char * name,uint32_t * val)1710681ce946SMartin Matuska nvlist_lookup_uint32(const nvlist_t *nvl, const char *name, uint32_t *val)
1711eda14cbcSMatt Macy {
1712eda14cbcSMatt Macy 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT32, NULL, val));
1713eda14cbcSMatt Macy }
1714eda14cbcSMatt Macy 
1715eda14cbcSMatt Macy int
nvlist_lookup_int64(const nvlist_t * nvl,const char * name,int64_t * val)1716681ce946SMartin Matuska nvlist_lookup_int64(const nvlist_t *nvl, const char *name, int64_t *val)
1717eda14cbcSMatt Macy {
1718eda14cbcSMatt Macy 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT64, NULL, val));
1719eda14cbcSMatt Macy }
1720eda14cbcSMatt Macy 
1721eda14cbcSMatt Macy int
nvlist_lookup_uint64(const nvlist_t * nvl,const char * name,uint64_t * val)1722681ce946SMartin Matuska nvlist_lookup_uint64(const nvlist_t *nvl, const char *name, uint64_t *val)
1723eda14cbcSMatt Macy {
1724eda14cbcSMatt Macy 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT64, NULL, val));
1725eda14cbcSMatt Macy }
1726eda14cbcSMatt Macy 
1727eda14cbcSMatt Macy #if !defined(_KERNEL)
1728eda14cbcSMatt Macy int
nvlist_lookup_double(const nvlist_t * nvl,const char * name,double * val)1729681ce946SMartin Matuska nvlist_lookup_double(const nvlist_t *nvl, const char *name, double *val)
1730eda14cbcSMatt Macy {
1731eda14cbcSMatt Macy 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_DOUBLE, NULL, val));
1732eda14cbcSMatt Macy }
1733eda14cbcSMatt Macy #endif
1734eda14cbcSMatt Macy 
1735eda14cbcSMatt Macy int
nvlist_lookup_string(const nvlist_t * nvl,const char * name,const char ** val)17362a58b312SMartin Matuska nvlist_lookup_string(const nvlist_t *nvl, const char *name, const char **val)
1737eda14cbcSMatt Macy {
1738eda14cbcSMatt Macy 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_STRING, NULL, val));
1739eda14cbcSMatt Macy }
1740eda14cbcSMatt Macy 
1741eda14cbcSMatt Macy int
nvlist_lookup_nvlist(nvlist_t * nvl,const char * name,nvlist_t ** val)1742eda14cbcSMatt Macy nvlist_lookup_nvlist(nvlist_t *nvl, const char *name, nvlist_t **val)
1743eda14cbcSMatt Macy {
1744eda14cbcSMatt Macy 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_NVLIST, NULL, val));
1745eda14cbcSMatt Macy }
1746eda14cbcSMatt Macy 
1747eda14cbcSMatt Macy int
nvlist_lookup_boolean_array(nvlist_t * nvl,const char * name,boolean_t ** a,uint_t * n)1748eda14cbcSMatt Macy nvlist_lookup_boolean_array(nvlist_t *nvl, const char *name,
1749eda14cbcSMatt Macy     boolean_t **a, uint_t *n)
1750eda14cbcSMatt Macy {
1751eda14cbcSMatt Macy 	return (nvlist_lookup_common(nvl, name,
1752eda14cbcSMatt Macy 	    DATA_TYPE_BOOLEAN_ARRAY, n, a));
1753eda14cbcSMatt Macy }
1754eda14cbcSMatt Macy 
1755eda14cbcSMatt Macy int
nvlist_lookup_byte_array(nvlist_t * nvl,const char * name,uchar_t ** a,uint_t * n)1756eda14cbcSMatt Macy nvlist_lookup_byte_array(nvlist_t *nvl, const char *name,
1757eda14cbcSMatt Macy     uchar_t **a, uint_t *n)
1758eda14cbcSMatt Macy {
1759eda14cbcSMatt Macy 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a));
1760eda14cbcSMatt Macy }
1761eda14cbcSMatt Macy 
1762eda14cbcSMatt Macy int
nvlist_lookup_int8_array(nvlist_t * nvl,const char * name,int8_t ** a,uint_t * n)1763eda14cbcSMatt Macy nvlist_lookup_int8_array(nvlist_t *nvl, const char *name, int8_t **a, uint_t *n)
1764eda14cbcSMatt Macy {
1765eda14cbcSMatt Macy 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a));
1766eda14cbcSMatt Macy }
1767eda14cbcSMatt Macy 
1768eda14cbcSMatt Macy int
nvlist_lookup_uint8_array(nvlist_t * nvl,const char * name,uint8_t ** a,uint_t * n)1769eda14cbcSMatt Macy nvlist_lookup_uint8_array(nvlist_t *nvl, const char *name,
1770eda14cbcSMatt Macy     uint8_t **a, uint_t *n)
1771eda14cbcSMatt Macy {
1772eda14cbcSMatt Macy 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a));
1773eda14cbcSMatt Macy }
1774eda14cbcSMatt Macy 
1775eda14cbcSMatt Macy int
nvlist_lookup_int16_array(nvlist_t * nvl,const char * name,int16_t ** a,uint_t * n)1776eda14cbcSMatt Macy nvlist_lookup_int16_array(nvlist_t *nvl, const char *name,
1777eda14cbcSMatt Macy     int16_t **a, uint_t *n)
1778eda14cbcSMatt Macy {
1779eda14cbcSMatt Macy 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a));
1780eda14cbcSMatt Macy }
1781eda14cbcSMatt Macy 
1782eda14cbcSMatt Macy int
nvlist_lookup_uint16_array(nvlist_t * nvl,const char * name,uint16_t ** a,uint_t * n)1783eda14cbcSMatt Macy nvlist_lookup_uint16_array(nvlist_t *nvl, const char *name,
1784eda14cbcSMatt Macy     uint16_t **a, uint_t *n)
1785eda14cbcSMatt Macy {
1786eda14cbcSMatt Macy 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a));
1787eda14cbcSMatt Macy }
1788eda14cbcSMatt Macy 
1789eda14cbcSMatt Macy int
nvlist_lookup_int32_array(nvlist_t * nvl,const char * name,int32_t ** a,uint_t * n)1790eda14cbcSMatt Macy nvlist_lookup_int32_array(nvlist_t *nvl, const char *name,
1791eda14cbcSMatt Macy     int32_t **a, uint_t *n)
1792eda14cbcSMatt Macy {
1793eda14cbcSMatt Macy 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a));
1794eda14cbcSMatt Macy }
1795eda14cbcSMatt Macy 
1796eda14cbcSMatt Macy int
nvlist_lookup_uint32_array(nvlist_t * nvl,const char * name,uint32_t ** a,uint_t * n)1797eda14cbcSMatt Macy nvlist_lookup_uint32_array(nvlist_t *nvl, const char *name,
1798eda14cbcSMatt Macy     uint32_t **a, uint_t *n)
1799eda14cbcSMatt Macy {
1800eda14cbcSMatt Macy 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a));
1801eda14cbcSMatt Macy }
1802eda14cbcSMatt Macy 
1803eda14cbcSMatt Macy int
nvlist_lookup_int64_array(nvlist_t * nvl,const char * name,int64_t ** a,uint_t * n)1804eda14cbcSMatt Macy nvlist_lookup_int64_array(nvlist_t *nvl, const char *name,
1805eda14cbcSMatt Macy     int64_t **a, uint_t *n)
1806eda14cbcSMatt Macy {
1807eda14cbcSMatt Macy 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a));
1808eda14cbcSMatt Macy }
1809eda14cbcSMatt Macy 
1810eda14cbcSMatt Macy int
nvlist_lookup_uint64_array(nvlist_t * nvl,const char * name,uint64_t ** a,uint_t * n)1811eda14cbcSMatt Macy nvlist_lookup_uint64_array(nvlist_t *nvl, const char *name,
1812eda14cbcSMatt Macy     uint64_t **a, uint_t *n)
1813eda14cbcSMatt Macy {
1814eda14cbcSMatt Macy 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a));
1815eda14cbcSMatt Macy }
1816eda14cbcSMatt Macy 
1817eda14cbcSMatt Macy int
nvlist_lookup_string_array(nvlist_t * nvl,const char * name,char *** a,uint_t * n)1818eda14cbcSMatt Macy nvlist_lookup_string_array(nvlist_t *nvl, const char *name,
1819eda14cbcSMatt Macy     char ***a, uint_t *n)
1820eda14cbcSMatt Macy {
1821eda14cbcSMatt Macy 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a));
1822eda14cbcSMatt Macy }
1823eda14cbcSMatt Macy 
1824eda14cbcSMatt Macy int
nvlist_lookup_nvlist_array(nvlist_t * nvl,const char * name,nvlist_t *** a,uint_t * n)1825eda14cbcSMatt Macy nvlist_lookup_nvlist_array(nvlist_t *nvl, const char *name,
1826eda14cbcSMatt Macy     nvlist_t ***a, uint_t *n)
1827eda14cbcSMatt Macy {
1828eda14cbcSMatt Macy 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a));
1829eda14cbcSMatt Macy }
1830eda14cbcSMatt Macy 
1831eda14cbcSMatt Macy int
nvlist_lookup_hrtime(nvlist_t * nvl,const char * name,hrtime_t * val)1832eda14cbcSMatt Macy nvlist_lookup_hrtime(nvlist_t *nvl, const char *name, hrtime_t *val)
1833eda14cbcSMatt Macy {
1834eda14cbcSMatt Macy 	return (nvlist_lookup_common(nvl, name, DATA_TYPE_HRTIME, NULL, val));
1835eda14cbcSMatt Macy }
1836eda14cbcSMatt Macy 
1837eda14cbcSMatt Macy int
nvlist_lookup_pairs(nvlist_t * nvl,int flag,...)1838eda14cbcSMatt Macy nvlist_lookup_pairs(nvlist_t *nvl, int flag, ...)
1839eda14cbcSMatt Macy {
1840eda14cbcSMatt Macy 	va_list ap;
1841eda14cbcSMatt Macy 	char *name;
1842eda14cbcSMatt Macy 	int noentok = (flag & NV_FLAG_NOENTOK ? 1 : 0);
1843eda14cbcSMatt Macy 	int ret = 0;
1844eda14cbcSMatt Macy 
1845eda14cbcSMatt Macy 	va_start(ap, flag);
1846eda14cbcSMatt Macy 	while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {
1847eda14cbcSMatt Macy 		data_type_t type;
1848eda14cbcSMatt Macy 		void *val;
1849eda14cbcSMatt Macy 		uint_t *nelem;
1850eda14cbcSMatt Macy 
1851eda14cbcSMatt Macy 		switch (type = va_arg(ap, data_type_t)) {
1852eda14cbcSMatt Macy 		case DATA_TYPE_BOOLEAN:
1853eda14cbcSMatt Macy 			ret = nvlist_lookup_common(nvl, name, type, NULL, NULL);
1854eda14cbcSMatt Macy 			break;
1855eda14cbcSMatt Macy 
1856eda14cbcSMatt Macy 		case DATA_TYPE_BOOLEAN_VALUE:
1857eda14cbcSMatt Macy 		case DATA_TYPE_BYTE:
1858eda14cbcSMatt Macy 		case DATA_TYPE_INT8:
1859eda14cbcSMatt Macy 		case DATA_TYPE_UINT8:
1860eda14cbcSMatt Macy 		case DATA_TYPE_INT16:
1861eda14cbcSMatt Macy 		case DATA_TYPE_UINT16:
1862eda14cbcSMatt Macy 		case DATA_TYPE_INT32:
1863eda14cbcSMatt Macy 		case DATA_TYPE_UINT32:
1864eda14cbcSMatt Macy 		case DATA_TYPE_INT64:
1865eda14cbcSMatt Macy 		case DATA_TYPE_UINT64:
1866eda14cbcSMatt Macy 		case DATA_TYPE_HRTIME:
1867eda14cbcSMatt Macy 		case DATA_TYPE_STRING:
1868eda14cbcSMatt Macy 		case DATA_TYPE_NVLIST:
1869eda14cbcSMatt Macy #if !defined(_KERNEL)
1870eda14cbcSMatt Macy 		case DATA_TYPE_DOUBLE:
1871eda14cbcSMatt Macy #endif
1872eda14cbcSMatt Macy 			val = va_arg(ap, void *);
1873eda14cbcSMatt Macy 			ret = nvlist_lookup_common(nvl, name, type, NULL, val);
1874eda14cbcSMatt Macy 			break;
1875eda14cbcSMatt Macy 
1876eda14cbcSMatt Macy 		case DATA_TYPE_BYTE_ARRAY:
1877eda14cbcSMatt Macy 		case DATA_TYPE_BOOLEAN_ARRAY:
1878eda14cbcSMatt Macy 		case DATA_TYPE_INT8_ARRAY:
1879eda14cbcSMatt Macy 		case DATA_TYPE_UINT8_ARRAY:
1880eda14cbcSMatt Macy 		case DATA_TYPE_INT16_ARRAY:
1881eda14cbcSMatt Macy 		case DATA_TYPE_UINT16_ARRAY:
1882eda14cbcSMatt Macy 		case DATA_TYPE_INT32_ARRAY:
1883eda14cbcSMatt Macy 		case DATA_TYPE_UINT32_ARRAY:
1884eda14cbcSMatt Macy 		case DATA_TYPE_INT64_ARRAY:
1885eda14cbcSMatt Macy 		case DATA_TYPE_UINT64_ARRAY:
1886eda14cbcSMatt Macy 		case DATA_TYPE_STRING_ARRAY:
1887eda14cbcSMatt Macy 		case DATA_TYPE_NVLIST_ARRAY:
1888eda14cbcSMatt Macy 			val = va_arg(ap, void *);
1889eda14cbcSMatt Macy 			nelem = va_arg(ap, uint_t *);
1890eda14cbcSMatt Macy 			ret = nvlist_lookup_common(nvl, name, type, nelem, val);
1891eda14cbcSMatt Macy 			break;
1892eda14cbcSMatt Macy 
1893eda14cbcSMatt Macy 		default:
1894eda14cbcSMatt Macy 			ret = EINVAL;
1895eda14cbcSMatt Macy 		}
1896eda14cbcSMatt Macy 
1897eda14cbcSMatt Macy 		if (ret == ENOENT && noentok)
1898eda14cbcSMatt Macy 			ret = 0;
1899eda14cbcSMatt Macy 	}
1900eda14cbcSMatt Macy 	va_end(ap);
1901eda14cbcSMatt Macy 
1902eda14cbcSMatt Macy 	return (ret);
1903eda14cbcSMatt Macy }
1904eda14cbcSMatt Macy 
1905eda14cbcSMatt Macy /*
1906eda14cbcSMatt Macy  * Find the 'name'ed nvpair in the nvlist 'nvl'. If 'name' found, the function
1907eda14cbcSMatt Macy  * returns zero and a pointer to the matching nvpair is returned in '*ret'
1908eda14cbcSMatt Macy  * (given 'ret' is non-NULL). If 'sep' is specified then 'name' will penitrate
1909eda14cbcSMatt Macy  * multiple levels of embedded nvlists, with 'sep' as the separator. As an
1910eda14cbcSMatt Macy  * example, if sep is '.', name might look like: "a" or "a.b" or "a.c[3]" or
1911eda14cbcSMatt Macy  * "a.d[3].e[1]".  This matches the C syntax for array embed (for convenience,
1912eda14cbcSMatt Macy  * code also supports "a.d[3]e[1]" syntax).
1913eda14cbcSMatt Macy  *
1914eda14cbcSMatt Macy  * If 'ip' is non-NULL and the last name component is an array, return the
1915eda14cbcSMatt Macy  * value of the "...[index]" array index in *ip. For an array reference that
1916eda14cbcSMatt Macy  * is not indexed, *ip will be returned as -1. If there is a syntax error in
1917eda14cbcSMatt Macy  * 'name', and 'ep' is non-NULL then *ep will be set to point to the location
1918eda14cbcSMatt Macy  * inside the 'name' string where the syntax error was detected.
1919eda14cbcSMatt Macy  */
1920eda14cbcSMatt Macy static int
nvlist_lookup_nvpair_ei_sep(nvlist_t * nvl,const char * name,const char sep,nvpair_t ** ret,int * ip,const char ** ep)1921eda14cbcSMatt Macy nvlist_lookup_nvpair_ei_sep(nvlist_t *nvl, const char *name, const char sep,
19222a58b312SMartin Matuska     nvpair_t **ret, int *ip, const char **ep)
1923eda14cbcSMatt Macy {
1924eda14cbcSMatt Macy 	nvpair_t	*nvp;
1925eda14cbcSMatt Macy 	const char	*np;
1926eda14cbcSMatt Macy 	char		*sepp = NULL;
1927eda14cbcSMatt Macy 	char		*idxp, *idxep;
1928eda14cbcSMatt Macy 	nvlist_t	**nva;
1929eda14cbcSMatt Macy 	long		idx = 0;
1930eda14cbcSMatt Macy 	int		n;
1931eda14cbcSMatt Macy 
1932eda14cbcSMatt Macy 	if (ip)
1933eda14cbcSMatt Macy 		*ip = -1;			/* not indexed */
1934eda14cbcSMatt Macy 	if (ep)
1935eda14cbcSMatt Macy 		*ep = NULL;
1936eda14cbcSMatt Macy 
1937eda14cbcSMatt Macy 	if ((nvl == NULL) || (name == NULL))
1938eda14cbcSMatt Macy 		return (EINVAL);
1939eda14cbcSMatt Macy 
1940eda14cbcSMatt Macy 	sepp = NULL;
1941eda14cbcSMatt Macy 	idx = 0;
1942eda14cbcSMatt Macy 	/* step through components of name */
1943eda14cbcSMatt Macy 	for (np = name; np && *np; np = sepp) {
1944eda14cbcSMatt Macy 		/* ensure unique names */
1945eda14cbcSMatt Macy 		if (!(nvl->nvl_nvflag & NV_UNIQUE_NAME))
1946eda14cbcSMatt Macy 			return (ENOTSUP);
1947eda14cbcSMatt Macy 
1948eda14cbcSMatt Macy 		/* skip white space */
1949eda14cbcSMatt Macy 		skip_whitespace(np);
1950eda14cbcSMatt Macy 		if (*np == 0)
1951eda14cbcSMatt Macy 			break;
1952eda14cbcSMatt Macy 
1953eda14cbcSMatt Macy 		/* set 'sepp' to end of current component 'np' */
1954eda14cbcSMatt Macy 		if (sep)
1955eda14cbcSMatt Macy 			sepp = strchr(np, sep);
1956eda14cbcSMatt Macy 		else
1957eda14cbcSMatt Macy 			sepp = NULL;
1958eda14cbcSMatt Macy 
1959eda14cbcSMatt Macy 		/* find start of next "[ index ]..." */
1960eda14cbcSMatt Macy 		idxp = strchr(np, '[');
1961eda14cbcSMatt Macy 
1962eda14cbcSMatt Macy 		/* if sepp comes first, set idxp to NULL */
1963eda14cbcSMatt Macy 		if (sepp && idxp && (sepp < idxp))
1964eda14cbcSMatt Macy 			idxp = NULL;
1965eda14cbcSMatt Macy 
1966eda14cbcSMatt Macy 		/*
1967eda14cbcSMatt Macy 		 * At this point 'idxp' is set if there is an index
1968eda14cbcSMatt Macy 		 * expected for the current component.
1969eda14cbcSMatt Macy 		 */
1970eda14cbcSMatt Macy 		if (idxp) {
1971eda14cbcSMatt Macy 			/* set 'n' to length of current 'np' name component */
1972eda14cbcSMatt Macy 			n = idxp++ - np;
1973eda14cbcSMatt Macy 
1974eda14cbcSMatt Macy 			/* keep sepp up to date for *ep use as we advance */
1975eda14cbcSMatt Macy 			skip_whitespace(idxp);
1976eda14cbcSMatt Macy 			sepp = idxp;
1977eda14cbcSMatt Macy 
1978eda14cbcSMatt Macy 			/* determine the index value */
1979eda14cbcSMatt Macy #if defined(_KERNEL)
1980eda14cbcSMatt Macy 			if (ddi_strtol(idxp, &idxep, 0, &idx))
1981eda14cbcSMatt Macy 				goto fail;
1982eda14cbcSMatt Macy #else
1983eda14cbcSMatt Macy 			idx = strtol(idxp, &idxep, 0);
1984eda14cbcSMatt Macy #endif
1985eda14cbcSMatt Macy 			if (idxep == idxp)
1986eda14cbcSMatt Macy 				goto fail;
1987eda14cbcSMatt Macy 
1988eda14cbcSMatt Macy 			/* keep sepp up to date for *ep use as we advance */
1989eda14cbcSMatt Macy 			sepp = idxep;
1990eda14cbcSMatt Macy 
1991eda14cbcSMatt Macy 			/* skip white space index value and check for ']' */
1992eda14cbcSMatt Macy 			skip_whitespace(sepp);
1993eda14cbcSMatt Macy 			if (*sepp++ != ']')
1994eda14cbcSMatt Macy 				goto fail;
1995eda14cbcSMatt Macy 
1996eda14cbcSMatt Macy 			/* for embedded arrays, support C syntax: "a[1].b" */
1997eda14cbcSMatt Macy 			skip_whitespace(sepp);
1998eda14cbcSMatt Macy 			if (sep && (*sepp == sep))
1999eda14cbcSMatt Macy 				sepp++;
2000eda14cbcSMatt Macy 		} else if (sepp) {
2001eda14cbcSMatt Macy 			n = sepp++ - np;
2002eda14cbcSMatt Macy 		} else {
2003eda14cbcSMatt Macy 			n = strlen(np);
2004eda14cbcSMatt Macy 		}
2005eda14cbcSMatt Macy 
2006eda14cbcSMatt Macy 		/* trim trailing whitespace by reducing length of 'np' */
2007eda14cbcSMatt Macy 		if (n == 0)
2008eda14cbcSMatt Macy 			goto fail;
2009eda14cbcSMatt Macy 		for (n--; (np[n] == ' ') || (np[n] == '\t'); n--)
2010eda14cbcSMatt Macy 			;
2011eda14cbcSMatt Macy 		n++;
2012eda14cbcSMatt Macy 
2013eda14cbcSMatt Macy 		/* skip whitespace, and set sepp to NULL if complete */
2014eda14cbcSMatt Macy 		if (sepp) {
2015eda14cbcSMatt Macy 			skip_whitespace(sepp);
2016eda14cbcSMatt Macy 			if (*sepp == 0)
2017eda14cbcSMatt Macy 				sepp = NULL;
2018eda14cbcSMatt Macy 		}
2019eda14cbcSMatt Macy 
2020eda14cbcSMatt Macy 		/*
2021eda14cbcSMatt Macy 		 * At this point:
2022eda14cbcSMatt Macy 		 * o  'n' is the length of current 'np' component.
2023eda14cbcSMatt Macy 		 * o  'idxp' is set if there was an index, and value 'idx'.
2024eda14cbcSMatt Macy 		 * o  'sepp' is set to the beginning of the next component,
2025eda14cbcSMatt Macy 		 *    and set to NULL if we have no more components.
2026eda14cbcSMatt Macy 		 *
2027eda14cbcSMatt Macy 		 * Search for nvpair with matching component name.
2028eda14cbcSMatt Macy 		 */
2029eda14cbcSMatt Macy 		for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
2030eda14cbcSMatt Macy 		    nvp = nvlist_next_nvpair(nvl, nvp)) {
2031eda14cbcSMatt Macy 
2032eda14cbcSMatt Macy 			/* continue if no match on name */
2033eda14cbcSMatt Macy 			if (strncmp(np, nvpair_name(nvp), n) ||
2034eda14cbcSMatt Macy 			    (strlen(nvpair_name(nvp)) != n))
2035eda14cbcSMatt Macy 				continue;
2036eda14cbcSMatt Macy 
2037eda14cbcSMatt Macy 			/* if indexed, verify type is array oriented */
2038eda14cbcSMatt Macy 			if (idxp && !nvpair_type_is_array(nvp))
2039eda14cbcSMatt Macy 				goto fail;
2040eda14cbcSMatt Macy 
2041eda14cbcSMatt Macy 			/*
2042eda14cbcSMatt Macy 			 * Full match found, return nvp and idx if this
2043eda14cbcSMatt Macy 			 * was the last component.
2044eda14cbcSMatt Macy 			 */
2045eda14cbcSMatt Macy 			if (sepp == NULL) {
2046eda14cbcSMatt Macy 				if (ret)
2047eda14cbcSMatt Macy 					*ret = nvp;
2048eda14cbcSMatt Macy 				if (ip && idxp)
2049eda14cbcSMatt Macy 					*ip = (int)idx;	/* return index */
2050eda14cbcSMatt Macy 				return (0);		/* found */
2051eda14cbcSMatt Macy 			}
2052eda14cbcSMatt Macy 
2053eda14cbcSMatt Macy 			/*
2054eda14cbcSMatt Macy 			 * More components: current match must be
2055eda14cbcSMatt Macy 			 * of DATA_TYPE_NVLIST or DATA_TYPE_NVLIST_ARRAY
2056eda14cbcSMatt Macy 			 * to support going deeper.
2057eda14cbcSMatt Macy 			 */
2058eda14cbcSMatt Macy 			if (nvpair_type(nvp) == DATA_TYPE_NVLIST) {
2059eda14cbcSMatt Macy 				nvl = EMBEDDED_NVL(nvp);
2060eda14cbcSMatt Macy 				break;
2061eda14cbcSMatt Macy 			} else if (nvpair_type(nvp) == DATA_TYPE_NVLIST_ARRAY) {
20622a58b312SMartin Matuska 				if (nvpair_value_nvlist_array(nvp,
20632a58b312SMartin Matuska 				    &nva, (uint_t *)&n) != 0)
20642a58b312SMartin Matuska 					goto fail;
20652a58b312SMartin Matuska 				if (nva == NULL)
20662a58b312SMartin Matuska 					goto fail;
2067eda14cbcSMatt Macy 				if ((n < 0) || (idx >= n))
2068eda14cbcSMatt Macy 					goto fail;
2069eda14cbcSMatt Macy 				nvl = nva[idx];
2070eda14cbcSMatt Macy 				break;
2071eda14cbcSMatt Macy 			}
2072eda14cbcSMatt Macy 
2073eda14cbcSMatt Macy 			/* type does not support more levels */
2074eda14cbcSMatt Macy 			goto fail;
2075eda14cbcSMatt Macy 		}
2076eda14cbcSMatt Macy 		if (nvp == NULL)
2077eda14cbcSMatt Macy 			goto fail;		/* 'name' not found */
2078eda14cbcSMatt Macy 
2079eda14cbcSMatt Macy 		/* search for match of next component in embedded 'nvl' list */
2080eda14cbcSMatt Macy 	}
2081eda14cbcSMatt Macy 
2082eda14cbcSMatt Macy fail:	if (ep && sepp)
2083eda14cbcSMatt Macy 		*ep = sepp;
2084eda14cbcSMatt Macy 	return (EINVAL);
2085eda14cbcSMatt Macy }
2086eda14cbcSMatt Macy 
2087eda14cbcSMatt Macy /*
2088eda14cbcSMatt Macy  * Return pointer to nvpair with specified 'name'.
2089eda14cbcSMatt Macy  */
2090eda14cbcSMatt Macy int
nvlist_lookup_nvpair(nvlist_t * nvl,const char * name,nvpair_t ** ret)2091eda14cbcSMatt Macy nvlist_lookup_nvpair(nvlist_t *nvl, const char *name, nvpair_t **ret)
2092eda14cbcSMatt Macy {
2093eda14cbcSMatt Macy 	return (nvlist_lookup_nvpair_ei_sep(nvl, name, 0, ret, NULL, NULL));
2094eda14cbcSMatt Macy }
2095eda14cbcSMatt Macy 
2096eda14cbcSMatt Macy /*
2097eda14cbcSMatt Macy  * Determine if named nvpair exists in nvlist (use embedded separator of '.'
2098eda14cbcSMatt Macy  * and return array index).  See nvlist_lookup_nvpair_ei_sep for more detailed
2099eda14cbcSMatt Macy  * description.
2100eda14cbcSMatt Macy  */
nvlist_lookup_nvpair_embedded_index(nvlist_t * nvl,const char * name,nvpair_t ** ret,int * ip,const char ** ep)2101eda14cbcSMatt Macy int nvlist_lookup_nvpair_embedded_index(nvlist_t *nvl,
21022a58b312SMartin Matuska     const char *name, nvpair_t **ret, int *ip, const char **ep)
2103eda14cbcSMatt Macy {
2104eda14cbcSMatt Macy 	return (nvlist_lookup_nvpair_ei_sep(nvl, name, '.', ret, ip, ep));
2105eda14cbcSMatt Macy }
2106eda14cbcSMatt Macy 
2107eda14cbcSMatt Macy boolean_t
nvlist_exists(const nvlist_t * nvl,const char * name)2108681ce946SMartin Matuska nvlist_exists(const nvlist_t *nvl, const char *name)
2109eda14cbcSMatt Macy {
2110eda14cbcSMatt Macy 	nvpriv_t *priv;
2111eda14cbcSMatt Macy 	nvpair_t *nvp;
2112eda14cbcSMatt Macy 	i_nvp_t *curr;
2113eda14cbcSMatt Macy 
2114eda14cbcSMatt Macy 	if (name == NULL || nvl == NULL ||
2115eda14cbcSMatt Macy 	    (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
2116eda14cbcSMatt Macy 		return (B_FALSE);
2117eda14cbcSMatt Macy 
2118eda14cbcSMatt Macy 	for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
2119eda14cbcSMatt Macy 		nvp = &curr->nvi_nvp;
2120eda14cbcSMatt Macy 
2121eda14cbcSMatt Macy 		if (strcmp(name, NVP_NAME(nvp)) == 0)
2122eda14cbcSMatt Macy 			return (B_TRUE);
2123eda14cbcSMatt Macy 	}
2124eda14cbcSMatt Macy 
2125eda14cbcSMatt Macy 	return (B_FALSE);
2126eda14cbcSMatt Macy }
2127eda14cbcSMatt Macy 
2128eda14cbcSMatt Macy int
nvpair_value_boolean_value(const nvpair_t * nvp,boolean_t * val)2129681ce946SMartin Matuska nvpair_value_boolean_value(const nvpair_t *nvp, boolean_t *val)
2130eda14cbcSMatt Macy {
2131eda14cbcSMatt Macy 	return (nvpair_value_common(nvp, DATA_TYPE_BOOLEAN_VALUE, NULL, val));
2132eda14cbcSMatt Macy }
2133eda14cbcSMatt Macy 
2134eda14cbcSMatt Macy int
nvpair_value_byte(const nvpair_t * nvp,uchar_t * val)2135681ce946SMartin Matuska nvpair_value_byte(const nvpair_t *nvp, uchar_t *val)
2136eda14cbcSMatt Macy {
2137eda14cbcSMatt Macy 	return (nvpair_value_common(nvp, DATA_TYPE_BYTE, NULL, val));
2138eda14cbcSMatt Macy }
2139eda14cbcSMatt Macy 
2140eda14cbcSMatt Macy int
nvpair_value_int8(const nvpair_t * nvp,int8_t * val)2141681ce946SMartin Matuska nvpair_value_int8(const nvpair_t *nvp, int8_t *val)
2142eda14cbcSMatt Macy {
2143eda14cbcSMatt Macy 	return (nvpair_value_common(nvp, DATA_TYPE_INT8, NULL, val));
2144eda14cbcSMatt Macy }
2145eda14cbcSMatt Macy 
2146eda14cbcSMatt Macy int
nvpair_value_uint8(const nvpair_t * nvp,uint8_t * val)2147681ce946SMartin Matuska nvpair_value_uint8(const nvpair_t *nvp, uint8_t *val)
2148eda14cbcSMatt Macy {
2149eda14cbcSMatt Macy 	return (nvpair_value_common(nvp, DATA_TYPE_UINT8, NULL, val));
2150eda14cbcSMatt Macy }
2151eda14cbcSMatt Macy 
2152eda14cbcSMatt Macy int
nvpair_value_int16(const nvpair_t * nvp,int16_t * val)2153681ce946SMartin Matuska nvpair_value_int16(const nvpair_t *nvp, int16_t *val)
2154eda14cbcSMatt Macy {
2155eda14cbcSMatt Macy 	return (nvpair_value_common(nvp, DATA_TYPE_INT16, NULL, val));
2156eda14cbcSMatt Macy }
2157eda14cbcSMatt Macy 
2158eda14cbcSMatt Macy int
nvpair_value_uint16(const nvpair_t * nvp,uint16_t * val)2159681ce946SMartin Matuska nvpair_value_uint16(const nvpair_t *nvp, uint16_t *val)
2160eda14cbcSMatt Macy {
2161eda14cbcSMatt Macy 	return (nvpair_value_common(nvp, DATA_TYPE_UINT16, NULL, val));
2162eda14cbcSMatt Macy }
2163eda14cbcSMatt Macy 
2164eda14cbcSMatt Macy int
nvpair_value_int32(const nvpair_t * nvp,int32_t * val)2165681ce946SMartin Matuska nvpair_value_int32(const nvpair_t *nvp, int32_t *val)
2166eda14cbcSMatt Macy {
2167eda14cbcSMatt Macy 	return (nvpair_value_common(nvp, DATA_TYPE_INT32, NULL, val));
2168eda14cbcSMatt Macy }
2169eda14cbcSMatt Macy 
2170eda14cbcSMatt Macy int
nvpair_value_uint32(const nvpair_t * nvp,uint32_t * val)2171681ce946SMartin Matuska nvpair_value_uint32(const nvpair_t *nvp, uint32_t *val)
2172eda14cbcSMatt Macy {
2173eda14cbcSMatt Macy 	return (nvpair_value_common(nvp, DATA_TYPE_UINT32, NULL, val));
2174eda14cbcSMatt Macy }
2175eda14cbcSMatt Macy 
2176eda14cbcSMatt Macy int
nvpair_value_int64(const nvpair_t * nvp,int64_t * val)2177681ce946SMartin Matuska nvpair_value_int64(const nvpair_t *nvp, int64_t *val)
2178eda14cbcSMatt Macy {
2179eda14cbcSMatt Macy 	return (nvpair_value_common(nvp, DATA_TYPE_INT64, NULL, val));
2180eda14cbcSMatt Macy }
2181eda14cbcSMatt Macy 
2182eda14cbcSMatt Macy int
nvpair_value_uint64(const nvpair_t * nvp,uint64_t * val)2183681ce946SMartin Matuska nvpair_value_uint64(const nvpair_t *nvp, uint64_t *val)
2184eda14cbcSMatt Macy {
2185eda14cbcSMatt Macy 	return (nvpair_value_common(nvp, DATA_TYPE_UINT64, NULL, val));
2186eda14cbcSMatt Macy }
2187eda14cbcSMatt Macy 
2188eda14cbcSMatt Macy #if !defined(_KERNEL)
2189eda14cbcSMatt Macy int
nvpair_value_double(const nvpair_t * nvp,double * val)2190681ce946SMartin Matuska nvpair_value_double(const nvpair_t *nvp, double *val)
2191eda14cbcSMatt Macy {
2192eda14cbcSMatt Macy 	return (nvpair_value_common(nvp, DATA_TYPE_DOUBLE, NULL, val));
2193eda14cbcSMatt Macy }
2194eda14cbcSMatt Macy #endif
2195eda14cbcSMatt Macy 
2196eda14cbcSMatt Macy int
nvpair_value_string(const nvpair_t * nvp,const char ** val)21972a58b312SMartin Matuska nvpair_value_string(const nvpair_t *nvp, const char **val)
2198eda14cbcSMatt Macy {
2199eda14cbcSMatt Macy 	return (nvpair_value_common(nvp, DATA_TYPE_STRING, NULL, val));
2200eda14cbcSMatt Macy }
2201eda14cbcSMatt Macy 
2202eda14cbcSMatt Macy int
nvpair_value_nvlist(nvpair_t * nvp,nvlist_t ** val)2203eda14cbcSMatt Macy nvpair_value_nvlist(nvpair_t *nvp, nvlist_t **val)
2204eda14cbcSMatt Macy {
2205eda14cbcSMatt Macy 	return (nvpair_value_common(nvp, DATA_TYPE_NVLIST, NULL, val));
2206eda14cbcSMatt Macy }
2207eda14cbcSMatt Macy 
2208eda14cbcSMatt Macy int
nvpair_value_boolean_array(nvpair_t * nvp,boolean_t ** val,uint_t * nelem)2209eda14cbcSMatt Macy nvpair_value_boolean_array(nvpair_t *nvp, boolean_t **val, uint_t *nelem)
2210eda14cbcSMatt Macy {
2211eda14cbcSMatt Macy 	return (nvpair_value_common(nvp, DATA_TYPE_BOOLEAN_ARRAY, nelem, val));
2212eda14cbcSMatt Macy }
2213eda14cbcSMatt Macy 
2214eda14cbcSMatt Macy int
nvpair_value_byte_array(nvpair_t * nvp,uchar_t ** val,uint_t * nelem)2215eda14cbcSMatt Macy nvpair_value_byte_array(nvpair_t *nvp, uchar_t **val, uint_t *nelem)
2216eda14cbcSMatt Macy {
2217eda14cbcSMatt Macy 	return (nvpair_value_common(nvp, DATA_TYPE_BYTE_ARRAY, nelem, val));
2218eda14cbcSMatt Macy }
2219eda14cbcSMatt Macy 
2220eda14cbcSMatt Macy int
nvpair_value_int8_array(nvpair_t * nvp,int8_t ** val,uint_t * nelem)2221eda14cbcSMatt Macy nvpair_value_int8_array(nvpair_t *nvp, int8_t **val, uint_t *nelem)
2222eda14cbcSMatt Macy {
2223eda14cbcSMatt Macy 	return (nvpair_value_common(nvp, DATA_TYPE_INT8_ARRAY, nelem, val));
2224eda14cbcSMatt Macy }
2225eda14cbcSMatt Macy 
2226eda14cbcSMatt Macy int
nvpair_value_uint8_array(nvpair_t * nvp,uint8_t ** val,uint_t * nelem)2227eda14cbcSMatt Macy nvpair_value_uint8_array(nvpair_t *nvp, uint8_t **val, uint_t *nelem)
2228eda14cbcSMatt Macy {
2229eda14cbcSMatt Macy 	return (nvpair_value_common(nvp, DATA_TYPE_UINT8_ARRAY, nelem, val));
2230eda14cbcSMatt Macy }
2231eda14cbcSMatt Macy 
2232eda14cbcSMatt Macy int
nvpair_value_int16_array(nvpair_t * nvp,int16_t ** val,uint_t * nelem)2233eda14cbcSMatt Macy nvpair_value_int16_array(nvpair_t *nvp, int16_t **val, uint_t *nelem)
2234eda14cbcSMatt Macy {
2235eda14cbcSMatt Macy 	return (nvpair_value_common(nvp, DATA_TYPE_INT16_ARRAY, nelem, val));
2236eda14cbcSMatt Macy }
2237eda14cbcSMatt Macy 
2238eda14cbcSMatt Macy int
nvpair_value_uint16_array(nvpair_t * nvp,uint16_t ** val,uint_t * nelem)2239eda14cbcSMatt Macy nvpair_value_uint16_array(nvpair_t *nvp, uint16_t **val, uint_t *nelem)
2240eda14cbcSMatt Macy {
2241eda14cbcSMatt Macy 	return (nvpair_value_common(nvp, DATA_TYPE_UINT16_ARRAY, nelem, val));
2242eda14cbcSMatt Macy }
2243eda14cbcSMatt Macy 
2244eda14cbcSMatt Macy int
nvpair_value_int32_array(nvpair_t * nvp,int32_t ** val,uint_t * nelem)2245eda14cbcSMatt Macy nvpair_value_int32_array(nvpair_t *nvp, int32_t **val, uint_t *nelem)
2246eda14cbcSMatt Macy {
2247eda14cbcSMatt Macy 	return (nvpair_value_common(nvp, DATA_TYPE_INT32_ARRAY, nelem, val));
2248eda14cbcSMatt Macy }
2249eda14cbcSMatt Macy 
2250eda14cbcSMatt Macy int
nvpair_value_uint32_array(nvpair_t * nvp,uint32_t ** val,uint_t * nelem)2251eda14cbcSMatt Macy nvpair_value_uint32_array(nvpair_t *nvp, uint32_t **val, uint_t *nelem)
2252eda14cbcSMatt Macy {
2253eda14cbcSMatt Macy 	return (nvpair_value_common(nvp, DATA_TYPE_UINT32_ARRAY, nelem, val));
2254eda14cbcSMatt Macy }
2255eda14cbcSMatt Macy 
2256eda14cbcSMatt Macy int
nvpair_value_int64_array(nvpair_t * nvp,int64_t ** val,uint_t * nelem)2257eda14cbcSMatt Macy nvpair_value_int64_array(nvpair_t *nvp, int64_t **val, uint_t *nelem)
2258eda14cbcSMatt Macy {
2259eda14cbcSMatt Macy 	return (nvpair_value_common(nvp, DATA_TYPE_INT64_ARRAY, nelem, val));
2260eda14cbcSMatt Macy }
2261eda14cbcSMatt Macy 
2262eda14cbcSMatt Macy int
nvpair_value_uint64_array(nvpair_t * nvp,uint64_t ** val,uint_t * nelem)2263eda14cbcSMatt Macy nvpair_value_uint64_array(nvpair_t *nvp, uint64_t **val, uint_t *nelem)
2264eda14cbcSMatt Macy {
2265eda14cbcSMatt Macy 	return (nvpair_value_common(nvp, DATA_TYPE_UINT64_ARRAY, nelem, val));
2266eda14cbcSMatt Macy }
2267eda14cbcSMatt Macy 
2268eda14cbcSMatt Macy int
nvpair_value_string_array(nvpair_t * nvp,const char *** val,uint_t * nelem)22692a58b312SMartin Matuska nvpair_value_string_array(nvpair_t *nvp, const char ***val, uint_t *nelem)
2270eda14cbcSMatt Macy {
2271eda14cbcSMatt Macy 	return (nvpair_value_common(nvp, DATA_TYPE_STRING_ARRAY, nelem, val));
2272eda14cbcSMatt Macy }
2273eda14cbcSMatt Macy 
2274eda14cbcSMatt Macy int
nvpair_value_nvlist_array(nvpair_t * nvp,nvlist_t *** val,uint_t * nelem)2275eda14cbcSMatt Macy nvpair_value_nvlist_array(nvpair_t *nvp, nvlist_t ***val, uint_t *nelem)
2276eda14cbcSMatt Macy {
2277eda14cbcSMatt Macy 	return (nvpair_value_common(nvp, DATA_TYPE_NVLIST_ARRAY, nelem, val));
2278eda14cbcSMatt Macy }
2279eda14cbcSMatt Macy 
2280eda14cbcSMatt Macy int
nvpair_value_hrtime(nvpair_t * nvp,hrtime_t * val)2281eda14cbcSMatt Macy nvpair_value_hrtime(nvpair_t *nvp, hrtime_t *val)
2282eda14cbcSMatt Macy {
2283eda14cbcSMatt Macy 	return (nvpair_value_common(nvp, DATA_TYPE_HRTIME, NULL, val));
2284eda14cbcSMatt Macy }
2285eda14cbcSMatt Macy 
2286eda14cbcSMatt Macy /*
2287eda14cbcSMatt Macy  * Add specified pair to the list.
2288eda14cbcSMatt Macy  */
2289eda14cbcSMatt Macy int
nvlist_add_nvpair(nvlist_t * nvl,nvpair_t * nvp)2290eda14cbcSMatt Macy nvlist_add_nvpair(nvlist_t *nvl, nvpair_t *nvp)
2291eda14cbcSMatt Macy {
2292eda14cbcSMatt Macy 	if (nvl == NULL || nvp == NULL)
2293eda14cbcSMatt Macy 		return (EINVAL);
2294eda14cbcSMatt Macy 
2295eda14cbcSMatt Macy 	return (nvlist_add_common(nvl, NVP_NAME(nvp), NVP_TYPE(nvp),
2296eda14cbcSMatt Macy 	    NVP_NELEM(nvp), NVP_VALUE(nvp)));
2297eda14cbcSMatt Macy }
2298eda14cbcSMatt Macy 
2299eda14cbcSMatt Macy /*
2300eda14cbcSMatt Macy  * Merge the supplied nvlists and put the result in dst.
2301eda14cbcSMatt Macy  * The merged list will contain all names specified in both lists,
2302eda14cbcSMatt Macy  * the values are taken from nvl in the case of duplicates.
2303eda14cbcSMatt Macy  * Return 0 on success.
2304eda14cbcSMatt Macy  */
2305eda14cbcSMatt Macy int
nvlist_merge(nvlist_t * dst,nvlist_t * nvl,int flag)2306eda14cbcSMatt Macy nvlist_merge(nvlist_t *dst, nvlist_t *nvl, int flag)
2307eda14cbcSMatt Macy {
2308e92ffd9bSMartin Matuska 	(void) flag;
2309e92ffd9bSMartin Matuska 
2310eda14cbcSMatt Macy 	if (nvl == NULL || dst == NULL)
2311eda14cbcSMatt Macy 		return (EINVAL);
2312eda14cbcSMatt Macy 
2313eda14cbcSMatt Macy 	if (dst != nvl)
2314eda14cbcSMatt Macy 		return (nvlist_copy_pairs(nvl, dst));
2315eda14cbcSMatt Macy 
2316eda14cbcSMatt Macy 	return (0);
2317eda14cbcSMatt Macy }
2318eda14cbcSMatt Macy 
2319eda14cbcSMatt Macy /*
2320eda14cbcSMatt Macy  * Encoding related routines
2321eda14cbcSMatt Macy  */
2322eda14cbcSMatt Macy #define	NVS_OP_ENCODE	0
2323eda14cbcSMatt Macy #define	NVS_OP_DECODE	1
2324eda14cbcSMatt Macy #define	NVS_OP_GETSIZE	2
2325eda14cbcSMatt Macy 
2326eda14cbcSMatt Macy typedef struct nvs_ops nvs_ops_t;
2327eda14cbcSMatt Macy 
2328eda14cbcSMatt Macy typedef struct {
2329eda14cbcSMatt Macy 	int		nvs_op;
2330eda14cbcSMatt Macy 	const nvs_ops_t	*nvs_ops;
2331eda14cbcSMatt Macy 	void		*nvs_private;
2332eda14cbcSMatt Macy 	nvpriv_t	*nvs_priv;
2333eda14cbcSMatt Macy 	int		nvs_recursion;
2334eda14cbcSMatt Macy } nvstream_t;
2335eda14cbcSMatt Macy 
2336eda14cbcSMatt Macy /*
2337eda14cbcSMatt Macy  * nvs operations are:
2338eda14cbcSMatt Macy  *   - nvs_nvlist
2339eda14cbcSMatt Macy  *     encoding / decoding of an nvlist header (nvlist_t)
2340eda14cbcSMatt Macy  *     calculates the size used for header and end detection
2341eda14cbcSMatt Macy  *
2342eda14cbcSMatt Macy  *   - nvs_nvpair
2343eda14cbcSMatt Macy  *     responsible for the first part of encoding / decoding of an nvpair
2344eda14cbcSMatt Macy  *     calculates the decoded size of an nvpair
2345eda14cbcSMatt Macy  *
2346eda14cbcSMatt Macy  *   - nvs_nvp_op
2347eda14cbcSMatt Macy  *     second part of encoding / decoding of an nvpair
2348eda14cbcSMatt Macy  *
2349eda14cbcSMatt Macy  *   - nvs_nvp_size
2350eda14cbcSMatt Macy  *     calculates the encoding size of an nvpair
2351eda14cbcSMatt Macy  *
2352eda14cbcSMatt Macy  *   - nvs_nvl_fini
2353eda14cbcSMatt Macy  *     encodes the end detection mark (zeros).
2354eda14cbcSMatt Macy  */
2355eda14cbcSMatt Macy struct nvs_ops {
2356eda14cbcSMatt Macy 	int (*nvs_nvlist)(nvstream_t *, nvlist_t *, size_t *);
2357eda14cbcSMatt Macy 	int (*nvs_nvpair)(nvstream_t *, nvpair_t *, size_t *);
2358eda14cbcSMatt Macy 	int (*nvs_nvp_op)(nvstream_t *, nvpair_t *);
2359eda14cbcSMatt Macy 	int (*nvs_nvp_size)(nvstream_t *, nvpair_t *, size_t *);
2360eda14cbcSMatt Macy 	int (*nvs_nvl_fini)(nvstream_t *);
2361eda14cbcSMatt Macy };
2362eda14cbcSMatt Macy 
2363eda14cbcSMatt Macy typedef struct {
2364eda14cbcSMatt Macy 	char	nvh_encoding;	/* nvs encoding method */
2365eda14cbcSMatt Macy 	char	nvh_endian;	/* nvs endian */
2366eda14cbcSMatt Macy 	char	nvh_reserved1;	/* reserved for future use */
2367eda14cbcSMatt Macy 	char	nvh_reserved2;	/* reserved for future use */
2368eda14cbcSMatt Macy } nvs_header_t;
2369eda14cbcSMatt Macy 
2370eda14cbcSMatt Macy static int
nvs_encode_pairs(nvstream_t * nvs,nvlist_t * nvl)2371eda14cbcSMatt Macy nvs_encode_pairs(nvstream_t *nvs, nvlist_t *nvl)
2372eda14cbcSMatt Macy {
2373eda14cbcSMatt Macy 	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
2374eda14cbcSMatt Macy 	i_nvp_t *curr;
2375eda14cbcSMatt Macy 
2376eda14cbcSMatt Macy 	/*
2377eda14cbcSMatt Macy 	 * Walk nvpair in list and encode each nvpair
2378eda14cbcSMatt Macy 	 */
2379eda14cbcSMatt Macy 	for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next)
2380eda14cbcSMatt Macy 		if (nvs->nvs_ops->nvs_nvpair(nvs, &curr->nvi_nvp, NULL) != 0)
2381eda14cbcSMatt Macy 			return (EFAULT);
2382eda14cbcSMatt Macy 
2383eda14cbcSMatt Macy 	return (nvs->nvs_ops->nvs_nvl_fini(nvs));
2384eda14cbcSMatt Macy }
2385eda14cbcSMatt Macy 
2386eda14cbcSMatt Macy static int
nvs_decode_pairs(nvstream_t * nvs,nvlist_t * nvl)2387eda14cbcSMatt Macy nvs_decode_pairs(nvstream_t *nvs, nvlist_t *nvl)
2388eda14cbcSMatt Macy {
2389eda14cbcSMatt Macy 	nvpair_t *nvp;
2390eda14cbcSMatt Macy 	size_t nvsize;
2391eda14cbcSMatt Macy 	int err;
2392eda14cbcSMatt Macy 
2393eda14cbcSMatt Macy 	/*
2394eda14cbcSMatt Macy 	 * Get decoded size of next pair in stream, alloc
2395eda14cbcSMatt Macy 	 * memory for nvpair_t, then decode the nvpair
2396eda14cbcSMatt Macy 	 */
2397eda14cbcSMatt Macy 	while ((err = nvs->nvs_ops->nvs_nvpair(nvs, NULL, &nvsize)) == 0) {
2398eda14cbcSMatt Macy 		if (nvsize == 0) /* end of list */
2399eda14cbcSMatt Macy 			break;
2400eda14cbcSMatt Macy 
2401eda14cbcSMatt Macy 		/* make sure len makes sense */
2402eda14cbcSMatt Macy 		if (nvsize < NVP_SIZE_CALC(1, 0))
2403eda14cbcSMatt Macy 			return (EFAULT);
2404eda14cbcSMatt Macy 
2405eda14cbcSMatt Macy 		if ((nvp = nvp_buf_alloc(nvl, nvsize)) == NULL)
2406eda14cbcSMatt Macy 			return (ENOMEM);
2407eda14cbcSMatt Macy 
2408eda14cbcSMatt Macy 		if ((err = nvs->nvs_ops->nvs_nvp_op(nvs, nvp)) != 0) {
2409eda14cbcSMatt Macy 			nvp_buf_free(nvl, nvp);
2410eda14cbcSMatt Macy 			return (err);
2411eda14cbcSMatt Macy 		}
2412eda14cbcSMatt Macy 
2413eda14cbcSMatt Macy 		if (i_validate_nvpair(nvp) != 0) {
2414eda14cbcSMatt Macy 			nvpair_free(nvp);
2415eda14cbcSMatt Macy 			nvp_buf_free(nvl, nvp);
2416eda14cbcSMatt Macy 			return (EFAULT);
2417eda14cbcSMatt Macy 		}
2418eda14cbcSMatt Macy 
2419eda14cbcSMatt Macy 		err = nvt_add_nvpair(nvl, nvp);
2420eda14cbcSMatt Macy 		if (err != 0) {
2421eda14cbcSMatt Macy 			nvpair_free(nvp);
2422eda14cbcSMatt Macy 			nvp_buf_free(nvl, nvp);
2423eda14cbcSMatt Macy 			return (err);
2424eda14cbcSMatt Macy 		}
2425eda14cbcSMatt Macy 		nvp_buf_link(nvl, nvp);
2426eda14cbcSMatt Macy 	}
2427eda14cbcSMatt Macy 	return (err);
2428eda14cbcSMatt Macy }
2429eda14cbcSMatt Macy 
2430eda14cbcSMatt Macy static int
nvs_getsize_pairs(nvstream_t * nvs,nvlist_t * nvl,size_t * buflen)2431eda14cbcSMatt Macy nvs_getsize_pairs(nvstream_t *nvs, nvlist_t *nvl, size_t *buflen)
2432eda14cbcSMatt Macy {
2433eda14cbcSMatt Macy 	nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
2434eda14cbcSMatt Macy 	i_nvp_t *curr;
2435eda14cbcSMatt Macy 	uint64_t nvsize = *buflen;
2436eda14cbcSMatt Macy 	size_t size;
2437eda14cbcSMatt Macy 
2438eda14cbcSMatt Macy 	/*
2439eda14cbcSMatt Macy 	 * Get encoded size of nvpairs in nvlist
2440eda14cbcSMatt Macy 	 */
2441eda14cbcSMatt Macy 	for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
2442eda14cbcSMatt Macy 		if (nvs->nvs_ops->nvs_nvp_size(nvs, &curr->nvi_nvp, &size) != 0)
2443eda14cbcSMatt Macy 			return (EINVAL);
2444eda14cbcSMatt Macy 
2445eda14cbcSMatt Macy 		if ((nvsize += size) > INT32_MAX)
2446eda14cbcSMatt Macy 			return (EINVAL);
2447eda14cbcSMatt Macy 	}
2448eda14cbcSMatt Macy 
2449eda14cbcSMatt Macy 	*buflen = nvsize;
2450eda14cbcSMatt Macy 	return (0);
2451eda14cbcSMatt Macy }
2452eda14cbcSMatt Macy 
2453eda14cbcSMatt Macy static int
nvs_operation(nvstream_t * nvs,nvlist_t * nvl,size_t * buflen)2454eda14cbcSMatt Macy nvs_operation(nvstream_t *nvs, nvlist_t *nvl, size_t *buflen)
2455eda14cbcSMatt Macy {
2456eda14cbcSMatt Macy 	int err;
2457eda14cbcSMatt Macy 
2458eda14cbcSMatt Macy 	if (nvl->nvl_priv == 0)
2459eda14cbcSMatt Macy 		return (EFAULT);
2460eda14cbcSMatt Macy 
2461eda14cbcSMatt Macy 	/*
2462eda14cbcSMatt Macy 	 * Perform the operation, starting with header, then each nvpair
2463eda14cbcSMatt Macy 	 */
2464eda14cbcSMatt Macy 	if ((err = nvs->nvs_ops->nvs_nvlist(nvs, nvl, buflen)) != 0)
2465eda14cbcSMatt Macy 		return (err);
2466eda14cbcSMatt Macy 
2467eda14cbcSMatt Macy 	switch (nvs->nvs_op) {
2468eda14cbcSMatt Macy 	case NVS_OP_ENCODE:
2469eda14cbcSMatt Macy 		err = nvs_encode_pairs(nvs, nvl);
2470eda14cbcSMatt Macy 		break;
2471eda14cbcSMatt Macy 
2472eda14cbcSMatt Macy 	case NVS_OP_DECODE:
2473eda14cbcSMatt Macy 		err = nvs_decode_pairs(nvs, nvl);
2474eda14cbcSMatt Macy 		break;
2475eda14cbcSMatt Macy 
2476eda14cbcSMatt Macy 	case NVS_OP_GETSIZE:
2477eda14cbcSMatt Macy 		err = nvs_getsize_pairs(nvs, nvl, buflen);
2478eda14cbcSMatt Macy 		break;
2479eda14cbcSMatt Macy 
2480eda14cbcSMatt Macy 	default:
2481eda14cbcSMatt Macy 		err = EINVAL;
2482eda14cbcSMatt Macy 	}
2483eda14cbcSMatt Macy 
2484eda14cbcSMatt Macy 	return (err);
2485eda14cbcSMatt Macy }
2486eda14cbcSMatt Macy 
2487eda14cbcSMatt Macy static int
nvs_embedded(nvstream_t * nvs,nvlist_t * embedded)2488eda14cbcSMatt Macy nvs_embedded(nvstream_t *nvs, nvlist_t *embedded)
2489eda14cbcSMatt Macy {
2490eda14cbcSMatt Macy 	switch (nvs->nvs_op) {
2491eda14cbcSMatt Macy 	case NVS_OP_ENCODE: {
2492eda14cbcSMatt Macy 		int err;
2493eda14cbcSMatt Macy 
2494eda14cbcSMatt Macy 		if (nvs->nvs_recursion >= nvpair_max_recursion)
2495eda14cbcSMatt Macy 			return (EINVAL);
2496eda14cbcSMatt Macy 		nvs->nvs_recursion++;
2497eda14cbcSMatt Macy 		err = nvs_operation(nvs, embedded, NULL);
2498eda14cbcSMatt Macy 		nvs->nvs_recursion--;
2499eda14cbcSMatt Macy 		return (err);
2500eda14cbcSMatt Macy 	}
2501eda14cbcSMatt Macy 	case NVS_OP_DECODE: {
2502eda14cbcSMatt Macy 		nvpriv_t *priv;
2503eda14cbcSMatt Macy 		int err;
2504eda14cbcSMatt Macy 
2505eda14cbcSMatt Macy 		if (embedded->nvl_version != NV_VERSION)
2506eda14cbcSMatt Macy 			return (ENOTSUP);
2507eda14cbcSMatt Macy 
2508eda14cbcSMatt Macy 		if ((priv = nv_priv_alloc_embedded(nvs->nvs_priv)) == NULL)
2509eda14cbcSMatt Macy 			return (ENOMEM);
2510eda14cbcSMatt Macy 
2511eda14cbcSMatt Macy 		nvlist_init(embedded, embedded->nvl_nvflag, priv);
2512eda14cbcSMatt Macy 
2513eda14cbcSMatt Macy 		if (nvs->nvs_recursion >= nvpair_max_recursion) {
2514eda14cbcSMatt Macy 			nvlist_free(embedded);
2515eda14cbcSMatt Macy 			return (EINVAL);
2516eda14cbcSMatt Macy 		}
2517eda14cbcSMatt Macy 		nvs->nvs_recursion++;
2518eda14cbcSMatt Macy 		if ((err = nvs_operation(nvs, embedded, NULL)) != 0)
2519eda14cbcSMatt Macy 			nvlist_free(embedded);
2520eda14cbcSMatt Macy 		nvs->nvs_recursion--;
2521eda14cbcSMatt Macy 		return (err);
2522eda14cbcSMatt Macy 	}
2523eda14cbcSMatt Macy 	default:
2524eda14cbcSMatt Macy 		break;
2525eda14cbcSMatt Macy 	}
2526eda14cbcSMatt Macy 
2527eda14cbcSMatt Macy 	return (EINVAL);
2528eda14cbcSMatt Macy }
2529eda14cbcSMatt Macy 
2530eda14cbcSMatt Macy static int
nvs_embedded_nvl_array(nvstream_t * nvs,nvpair_t * nvp,size_t * size)2531eda14cbcSMatt Macy nvs_embedded_nvl_array(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
2532eda14cbcSMatt Macy {
2533eda14cbcSMatt Macy 	size_t nelem = NVP_NELEM(nvp);
2534eda14cbcSMatt Macy 	nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp);
2535eda14cbcSMatt Macy 	int i;
2536eda14cbcSMatt Macy 
2537eda14cbcSMatt Macy 	switch (nvs->nvs_op) {
2538eda14cbcSMatt Macy 	case NVS_OP_ENCODE:
2539eda14cbcSMatt Macy 		for (i = 0; i < nelem; i++)
2540eda14cbcSMatt Macy 			if (nvs_embedded(nvs, nvlp[i]) != 0)
2541eda14cbcSMatt Macy 				return (EFAULT);
2542eda14cbcSMatt Macy 		break;
2543eda14cbcSMatt Macy 
2544eda14cbcSMatt Macy 	case NVS_OP_DECODE: {
2545eda14cbcSMatt Macy 		size_t len = nelem * sizeof (uint64_t);
2546eda14cbcSMatt Macy 		nvlist_t *embedded = (nvlist_t *)((uintptr_t)nvlp + len);
2547eda14cbcSMatt Macy 
2548da5137abSMartin Matuska 		memset(nvlp, 0, len);	/* don't trust packed data */
2549eda14cbcSMatt Macy 		for (i = 0; i < nelem; i++) {
2550eda14cbcSMatt Macy 			if (nvs_embedded(nvs, embedded) != 0) {
2551eda14cbcSMatt Macy 				nvpair_free(nvp);
2552eda14cbcSMatt Macy 				return (EFAULT);
2553eda14cbcSMatt Macy 			}
2554eda14cbcSMatt Macy 
2555eda14cbcSMatt Macy 			nvlp[i] = embedded++;
2556eda14cbcSMatt Macy 		}
2557eda14cbcSMatt Macy 		break;
2558eda14cbcSMatt Macy 	}
2559eda14cbcSMatt Macy 	case NVS_OP_GETSIZE: {
2560eda14cbcSMatt Macy 		uint64_t nvsize = 0;
2561eda14cbcSMatt Macy 
2562eda14cbcSMatt Macy 		for (i = 0; i < nelem; i++) {
2563eda14cbcSMatt Macy 			size_t nvp_sz = 0;
2564eda14cbcSMatt Macy 
2565eda14cbcSMatt Macy 			if (nvs_operation(nvs, nvlp[i], &nvp_sz) != 0)
2566eda14cbcSMatt Macy 				return (EINVAL);
2567eda14cbcSMatt Macy 
2568eda14cbcSMatt Macy 			if ((nvsize += nvp_sz) > INT32_MAX)
2569eda14cbcSMatt Macy 				return (EINVAL);
2570eda14cbcSMatt Macy 		}
2571eda14cbcSMatt Macy 
2572eda14cbcSMatt Macy 		*size = nvsize;
2573eda14cbcSMatt Macy 		break;
2574eda14cbcSMatt Macy 	}
2575eda14cbcSMatt Macy 	default:
2576eda14cbcSMatt Macy 		return (EINVAL);
2577eda14cbcSMatt Macy 	}
2578eda14cbcSMatt Macy 
2579eda14cbcSMatt Macy 	return (0);
2580eda14cbcSMatt Macy }
2581eda14cbcSMatt Macy 
2582eda14cbcSMatt Macy static int nvs_native(nvstream_t *, nvlist_t *, char *, size_t *);
2583eda14cbcSMatt Macy static int nvs_xdr(nvstream_t *, nvlist_t *, char *, size_t *);
2584eda14cbcSMatt Macy 
2585eda14cbcSMatt Macy /*
2586eda14cbcSMatt Macy  * Common routine for nvlist operations:
2587eda14cbcSMatt Macy  * encode, decode, getsize (encoded size).
2588eda14cbcSMatt Macy  */
2589eda14cbcSMatt Macy static int
nvlist_common(nvlist_t * nvl,char * buf,size_t * buflen,int encoding,int nvs_op)2590eda14cbcSMatt Macy nvlist_common(nvlist_t *nvl, char *buf, size_t *buflen, int encoding,
2591eda14cbcSMatt Macy     int nvs_op)
2592eda14cbcSMatt Macy {
2593eda14cbcSMatt Macy 	int err = 0;
2594eda14cbcSMatt Macy 	nvstream_t nvs;
2595eda14cbcSMatt Macy 	int nvl_endian;
2596eda14cbcSMatt Macy #if defined(_ZFS_LITTLE_ENDIAN)
2597eda14cbcSMatt Macy 	int host_endian = 1;
2598eda14cbcSMatt Macy #elif defined(_ZFS_BIG_ENDIAN)
2599eda14cbcSMatt Macy 	int host_endian = 0;
2600eda14cbcSMatt Macy #else
2601eda14cbcSMatt Macy #error "No endian defined!"
2602eda14cbcSMatt Macy #endif	/* _ZFS_LITTLE_ENDIAN */
2603eda14cbcSMatt Macy 	nvs_header_t *nvh;
2604eda14cbcSMatt Macy 
2605eda14cbcSMatt Macy 	if (buflen == NULL || nvl == NULL ||
2606eda14cbcSMatt Macy 	    (nvs.nvs_priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
2607eda14cbcSMatt Macy 		return (EINVAL);
2608eda14cbcSMatt Macy 
2609eda14cbcSMatt Macy 	nvs.nvs_op = nvs_op;
2610eda14cbcSMatt Macy 	nvs.nvs_recursion = 0;
2611eda14cbcSMatt Macy 
2612eda14cbcSMatt Macy 	/*
2613eda14cbcSMatt Macy 	 * For NVS_OP_ENCODE and NVS_OP_DECODE make sure an nvlist and
2614eda14cbcSMatt Macy 	 * a buffer is allocated.  The first 4 bytes in the buffer are
2615eda14cbcSMatt Macy 	 * used for encoding method and host endian.
2616eda14cbcSMatt Macy 	 */
2617eda14cbcSMatt Macy 	switch (nvs_op) {
2618eda14cbcSMatt Macy 	case NVS_OP_ENCODE:
2619eda14cbcSMatt Macy 		if (buf == NULL || *buflen < sizeof (nvs_header_t))
2620eda14cbcSMatt Macy 			return (EINVAL);
2621eda14cbcSMatt Macy 
2622eda14cbcSMatt Macy 		nvh = (void *)buf;
2623eda14cbcSMatt Macy 		nvh->nvh_encoding = encoding;
2624eda14cbcSMatt Macy 		nvh->nvh_endian = nvl_endian = host_endian;
2625eda14cbcSMatt Macy 		nvh->nvh_reserved1 = 0;
2626eda14cbcSMatt Macy 		nvh->nvh_reserved2 = 0;
2627eda14cbcSMatt Macy 		break;
2628eda14cbcSMatt Macy 
2629eda14cbcSMatt Macy 	case NVS_OP_DECODE:
2630eda14cbcSMatt Macy 		if (buf == NULL || *buflen < sizeof (nvs_header_t))
2631eda14cbcSMatt Macy 			return (EINVAL);
2632eda14cbcSMatt Macy 
2633eda14cbcSMatt Macy 		/* get method of encoding from first byte */
2634eda14cbcSMatt Macy 		nvh = (void *)buf;
2635eda14cbcSMatt Macy 		encoding = nvh->nvh_encoding;
2636eda14cbcSMatt Macy 		nvl_endian = nvh->nvh_endian;
2637eda14cbcSMatt Macy 		break;
2638eda14cbcSMatt Macy 
2639eda14cbcSMatt Macy 	case NVS_OP_GETSIZE:
2640eda14cbcSMatt Macy 		nvl_endian = host_endian;
2641eda14cbcSMatt Macy 
2642eda14cbcSMatt Macy 		/*
2643eda14cbcSMatt Macy 		 * add the size for encoding
2644eda14cbcSMatt Macy 		 */
2645eda14cbcSMatt Macy 		*buflen = sizeof (nvs_header_t);
2646eda14cbcSMatt Macy 		break;
2647eda14cbcSMatt Macy 
2648eda14cbcSMatt Macy 	default:
2649eda14cbcSMatt Macy 		return (ENOTSUP);
2650eda14cbcSMatt Macy 	}
2651eda14cbcSMatt Macy 
2652eda14cbcSMatt Macy 	/*
2653eda14cbcSMatt Macy 	 * Create an nvstream with proper encoding method
2654eda14cbcSMatt Macy 	 */
2655eda14cbcSMatt Macy 	switch (encoding) {
2656eda14cbcSMatt Macy 	case NV_ENCODE_NATIVE:
2657eda14cbcSMatt Macy 		/*
2658eda14cbcSMatt Macy 		 * check endianness, in case we are unpacking
2659eda14cbcSMatt Macy 		 * from a file
2660eda14cbcSMatt Macy 		 */
2661eda14cbcSMatt Macy 		if (nvl_endian != host_endian)
2662eda14cbcSMatt Macy 			return (ENOTSUP);
2663eda14cbcSMatt Macy 		err = nvs_native(&nvs, nvl, buf, buflen);
2664eda14cbcSMatt Macy 		break;
2665eda14cbcSMatt Macy 	case NV_ENCODE_XDR:
2666eda14cbcSMatt Macy 		err = nvs_xdr(&nvs, nvl, buf, buflen);
2667eda14cbcSMatt Macy 		break;
2668eda14cbcSMatt Macy 	default:
2669eda14cbcSMatt Macy 		err = ENOTSUP;
2670eda14cbcSMatt Macy 		break;
2671eda14cbcSMatt Macy 	}
2672eda14cbcSMatt Macy 
2673eda14cbcSMatt Macy 	return (err);
2674eda14cbcSMatt Macy }
2675eda14cbcSMatt Macy 
2676eda14cbcSMatt Macy int
nvlist_size(nvlist_t * nvl,size_t * size,int encoding)2677eda14cbcSMatt Macy nvlist_size(nvlist_t *nvl, size_t *size, int encoding)
2678eda14cbcSMatt Macy {
2679eda14cbcSMatt Macy 	return (nvlist_common(nvl, NULL, size, encoding, NVS_OP_GETSIZE));
2680eda14cbcSMatt Macy }
2681eda14cbcSMatt Macy 
2682eda14cbcSMatt Macy /*
2683eda14cbcSMatt Macy  * Pack nvlist into contiguous memory
2684eda14cbcSMatt Macy  */
2685eda14cbcSMatt Macy int
nvlist_pack(nvlist_t * nvl,char ** bufp,size_t * buflen,int encoding,int kmflag)2686eda14cbcSMatt Macy nvlist_pack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding,
2687eda14cbcSMatt Macy     int kmflag)
2688eda14cbcSMatt Macy {
2689eda14cbcSMatt Macy 	return (nvlist_xpack(nvl, bufp, buflen, encoding,
2690eda14cbcSMatt Macy 	    nvlist_nv_alloc(kmflag)));
2691eda14cbcSMatt Macy }
2692eda14cbcSMatt Macy 
2693eda14cbcSMatt Macy int
nvlist_xpack(nvlist_t * nvl,char ** bufp,size_t * buflen,int encoding,nv_alloc_t * nva)2694eda14cbcSMatt Macy nvlist_xpack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding,
2695eda14cbcSMatt Macy     nv_alloc_t *nva)
2696eda14cbcSMatt Macy {
2697eda14cbcSMatt Macy 	nvpriv_t nvpriv;
2698eda14cbcSMatt Macy 	size_t alloc_size;
2699eda14cbcSMatt Macy 	char *buf;
2700eda14cbcSMatt Macy 	int err;
2701eda14cbcSMatt Macy 
2702eda14cbcSMatt Macy 	if (nva == NULL || nvl == NULL || bufp == NULL || buflen == NULL)
2703eda14cbcSMatt Macy 		return (EINVAL);
2704eda14cbcSMatt Macy 
2705eda14cbcSMatt Macy 	if (*bufp != NULL)
2706eda14cbcSMatt Macy 		return (nvlist_common(nvl, *bufp, buflen, encoding,
2707eda14cbcSMatt Macy 		    NVS_OP_ENCODE));
2708eda14cbcSMatt Macy 
2709eda14cbcSMatt Macy 	/*
2710eda14cbcSMatt Macy 	 * Here is a difficult situation:
2711eda14cbcSMatt Macy 	 * 1. The nvlist has fixed allocator properties.
2712eda14cbcSMatt Macy 	 *    All other nvlist routines (like nvlist_add_*, ...) use
2713eda14cbcSMatt Macy 	 *    these properties.
2714eda14cbcSMatt Macy 	 * 2. When using nvlist_pack() the user can specify their own
2715eda14cbcSMatt Macy 	 *    allocator properties (e.g. by using KM_NOSLEEP).
2716eda14cbcSMatt Macy 	 *
2717eda14cbcSMatt Macy 	 * We use the user specified properties (2). A clearer solution
2718eda14cbcSMatt Macy 	 * will be to remove the kmflag from nvlist_pack(), but we will
2719eda14cbcSMatt Macy 	 * not change the interface.
2720eda14cbcSMatt Macy 	 */
2721eda14cbcSMatt Macy 	nv_priv_init(&nvpriv, nva, 0);
2722eda14cbcSMatt Macy 
2723eda14cbcSMatt Macy 	if ((err = nvlist_size(nvl, &alloc_size, encoding)))
2724eda14cbcSMatt Macy 		return (err);
2725eda14cbcSMatt Macy 
2726eda14cbcSMatt Macy 	if ((buf = nv_mem_zalloc(&nvpriv, alloc_size)) == NULL)
2727eda14cbcSMatt Macy 		return (ENOMEM);
2728eda14cbcSMatt Macy 
2729eda14cbcSMatt Macy 	if ((err = nvlist_common(nvl, buf, &alloc_size, encoding,
2730eda14cbcSMatt Macy 	    NVS_OP_ENCODE)) != 0) {
2731eda14cbcSMatt Macy 		nv_mem_free(&nvpriv, buf, alloc_size);
2732eda14cbcSMatt Macy 	} else {
2733eda14cbcSMatt Macy 		*buflen = alloc_size;
2734eda14cbcSMatt Macy 		*bufp = buf;
2735eda14cbcSMatt Macy 	}
2736eda14cbcSMatt Macy 
2737eda14cbcSMatt Macy 	return (err);
2738eda14cbcSMatt Macy }
2739eda14cbcSMatt Macy 
2740eda14cbcSMatt Macy /*
2741eda14cbcSMatt Macy  * Unpack buf into an nvlist_t
2742eda14cbcSMatt Macy  */
2743eda14cbcSMatt Macy int
nvlist_unpack(char * buf,size_t buflen,nvlist_t ** nvlp,int kmflag)2744eda14cbcSMatt Macy nvlist_unpack(char *buf, size_t buflen, nvlist_t **nvlp, int kmflag)
2745eda14cbcSMatt Macy {
2746eda14cbcSMatt Macy 	return (nvlist_xunpack(buf, buflen, nvlp, nvlist_nv_alloc(kmflag)));
2747eda14cbcSMatt Macy }
2748eda14cbcSMatt Macy 
2749eda14cbcSMatt Macy int
nvlist_xunpack(char * buf,size_t buflen,nvlist_t ** nvlp,nv_alloc_t * nva)2750eda14cbcSMatt Macy nvlist_xunpack(char *buf, size_t buflen, nvlist_t **nvlp, nv_alloc_t *nva)
2751eda14cbcSMatt Macy {
2752eda14cbcSMatt Macy 	nvlist_t *nvl;
2753eda14cbcSMatt Macy 	int err;
2754eda14cbcSMatt Macy 
2755eda14cbcSMatt Macy 	if (nvlp == NULL)
2756eda14cbcSMatt Macy 		return (EINVAL);
2757eda14cbcSMatt Macy 
2758eda14cbcSMatt Macy 	if ((err = nvlist_xalloc(&nvl, 0, nva)) != 0)
2759eda14cbcSMatt Macy 		return (err);
2760eda14cbcSMatt Macy 
2761eda14cbcSMatt Macy 	if ((err = nvlist_common(nvl, buf, &buflen, NV_ENCODE_NATIVE,
2762eda14cbcSMatt Macy 	    NVS_OP_DECODE)) != 0)
2763eda14cbcSMatt Macy 		nvlist_free(nvl);
2764eda14cbcSMatt Macy 	else
2765eda14cbcSMatt Macy 		*nvlp = nvl;
2766eda14cbcSMatt Macy 
2767eda14cbcSMatt Macy 	return (err);
2768eda14cbcSMatt Macy }
2769eda14cbcSMatt Macy 
2770eda14cbcSMatt Macy /*
2771eda14cbcSMatt Macy  * Native encoding functions
2772eda14cbcSMatt Macy  */
2773eda14cbcSMatt Macy typedef struct {
2774eda14cbcSMatt Macy 	/*
2775eda14cbcSMatt Macy 	 * This structure is used when decoding a packed nvpair in
2776eda14cbcSMatt Macy 	 * the native format.  n_base points to a buffer containing the
2777eda14cbcSMatt Macy 	 * packed nvpair.  n_end is a pointer to the end of the buffer.
2778eda14cbcSMatt Macy 	 * (n_end actually points to the first byte past the end of the
2779eda14cbcSMatt Macy 	 * buffer.)  n_curr is a pointer that lies between n_base and n_end.
2780eda14cbcSMatt Macy 	 * It points to the current data that we are decoding.
2781eda14cbcSMatt Macy 	 * The amount of data left in the buffer is equal to n_end - n_curr.
2782eda14cbcSMatt Macy 	 * n_flag is used to recognize a packed embedded list.
2783eda14cbcSMatt Macy 	 */
2784eda14cbcSMatt Macy 	caddr_t n_base;
2785eda14cbcSMatt Macy 	caddr_t n_end;
2786eda14cbcSMatt Macy 	caddr_t n_curr;
2787eda14cbcSMatt Macy 	uint_t  n_flag;
2788eda14cbcSMatt Macy } nvs_native_t;
2789eda14cbcSMatt Macy 
2790eda14cbcSMatt Macy static int
nvs_native_create(nvstream_t * nvs,nvs_native_t * native,char * buf,size_t buflen)2791eda14cbcSMatt Macy nvs_native_create(nvstream_t *nvs, nvs_native_t *native, char *buf,
2792eda14cbcSMatt Macy     size_t buflen)
2793eda14cbcSMatt Macy {
2794eda14cbcSMatt Macy 	switch (nvs->nvs_op) {
2795eda14cbcSMatt Macy 	case NVS_OP_ENCODE:
2796eda14cbcSMatt Macy 	case NVS_OP_DECODE:
2797eda14cbcSMatt Macy 		nvs->nvs_private = native;
2798eda14cbcSMatt Macy 		native->n_curr = native->n_base = buf;
2799eda14cbcSMatt Macy 		native->n_end = buf + buflen;
2800eda14cbcSMatt Macy 		native->n_flag = 0;
2801eda14cbcSMatt Macy 		return (0);
2802eda14cbcSMatt Macy 
2803eda14cbcSMatt Macy 	case NVS_OP_GETSIZE:
2804eda14cbcSMatt Macy 		nvs->nvs_private = native;
2805eda14cbcSMatt Macy 		native->n_curr = native->n_base = native->n_end = NULL;
2806eda14cbcSMatt Macy 		native->n_flag = 0;
2807eda14cbcSMatt Macy 		return (0);
2808eda14cbcSMatt Macy 	default:
2809eda14cbcSMatt Macy 		return (EINVAL);
2810eda14cbcSMatt Macy 	}
2811eda14cbcSMatt Macy }
2812eda14cbcSMatt Macy 
2813eda14cbcSMatt Macy static void
nvs_native_destroy(nvstream_t * nvs)2814eda14cbcSMatt Macy nvs_native_destroy(nvstream_t *nvs)
2815eda14cbcSMatt Macy {
28162a58b312SMartin Matuska 	nvs->nvs_private = NULL;
2817eda14cbcSMatt Macy }
2818eda14cbcSMatt Macy 
2819eda14cbcSMatt Macy static int
native_cp(nvstream_t * nvs,void * buf,size_t size)2820eda14cbcSMatt Macy native_cp(nvstream_t *nvs, void *buf, size_t size)
2821eda14cbcSMatt Macy {
2822eda14cbcSMatt Macy 	nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
2823eda14cbcSMatt Macy 
2824eda14cbcSMatt Macy 	if (native->n_curr + size > native->n_end)
2825eda14cbcSMatt Macy 		return (EFAULT);
2826eda14cbcSMatt Macy 
2827eda14cbcSMatt Macy 	/*
2828da5137abSMartin Matuska 	 * The memcpy() below eliminates alignment requirement
2829eda14cbcSMatt Macy 	 * on the buffer (stream) and is preferred over direct access.
2830eda14cbcSMatt Macy 	 */
2831eda14cbcSMatt Macy 	switch (nvs->nvs_op) {
2832eda14cbcSMatt Macy 	case NVS_OP_ENCODE:
2833da5137abSMartin Matuska 		memcpy(native->n_curr, buf, size);
2834eda14cbcSMatt Macy 		break;
2835eda14cbcSMatt Macy 	case NVS_OP_DECODE:
2836da5137abSMartin Matuska 		memcpy(buf, native->n_curr, size);
2837eda14cbcSMatt Macy 		break;
2838eda14cbcSMatt Macy 	default:
2839eda14cbcSMatt Macy 		return (EINVAL);
2840eda14cbcSMatt Macy 	}
2841eda14cbcSMatt Macy 
2842eda14cbcSMatt Macy 	native->n_curr += size;
2843eda14cbcSMatt Macy 	return (0);
2844eda14cbcSMatt Macy }
2845eda14cbcSMatt Macy 
2846eda14cbcSMatt Macy /*
2847eda14cbcSMatt Macy  * operate on nvlist_t header
2848eda14cbcSMatt Macy  */
2849eda14cbcSMatt Macy static int
nvs_native_nvlist(nvstream_t * nvs,nvlist_t * nvl,size_t * size)2850eda14cbcSMatt Macy nvs_native_nvlist(nvstream_t *nvs, nvlist_t *nvl, size_t *size)
2851eda14cbcSMatt Macy {
2852eda14cbcSMatt Macy 	nvs_native_t *native = nvs->nvs_private;
2853eda14cbcSMatt Macy 
2854eda14cbcSMatt Macy 	switch (nvs->nvs_op) {
2855eda14cbcSMatt Macy 	case NVS_OP_ENCODE:
2856eda14cbcSMatt Macy 	case NVS_OP_DECODE:
2857eda14cbcSMatt Macy 		if (native->n_flag)
2858eda14cbcSMatt Macy 			return (0);	/* packed embedded list */
2859eda14cbcSMatt Macy 
2860eda14cbcSMatt Macy 		native->n_flag = 1;
2861eda14cbcSMatt Macy 
2862eda14cbcSMatt Macy 		/* copy version and nvflag of the nvlist_t */
2863eda14cbcSMatt Macy 		if (native_cp(nvs, &nvl->nvl_version, sizeof (int32_t)) != 0 ||
2864eda14cbcSMatt Macy 		    native_cp(nvs, &nvl->nvl_nvflag, sizeof (int32_t)) != 0)
2865eda14cbcSMatt Macy 			return (EFAULT);
2866eda14cbcSMatt Macy 
2867eda14cbcSMatt Macy 		return (0);
2868eda14cbcSMatt Macy 
2869eda14cbcSMatt Macy 	case NVS_OP_GETSIZE:
2870eda14cbcSMatt Macy 		/*
2871eda14cbcSMatt Macy 		 * if calculate for packed embedded list
2872eda14cbcSMatt Macy 		 * 	4 for end of the embedded list
2873eda14cbcSMatt Macy 		 * else
2874eda14cbcSMatt Macy 		 * 	2 * sizeof (int32_t) for nvl_version and nvl_nvflag
2875eda14cbcSMatt Macy 		 * 	and 4 for end of the entire list
2876eda14cbcSMatt Macy 		 */
2877eda14cbcSMatt Macy 		if (native->n_flag) {
2878eda14cbcSMatt Macy 			*size += 4;
2879eda14cbcSMatt Macy 		} else {
2880eda14cbcSMatt Macy 			native->n_flag = 1;
2881eda14cbcSMatt Macy 			*size += 2 * sizeof (int32_t) + 4;
2882eda14cbcSMatt Macy 		}
2883eda14cbcSMatt Macy 
2884eda14cbcSMatt Macy 		return (0);
2885eda14cbcSMatt Macy 
2886eda14cbcSMatt Macy 	default:
2887eda14cbcSMatt Macy 		return (EINVAL);
2888eda14cbcSMatt Macy 	}
2889eda14cbcSMatt Macy }
2890eda14cbcSMatt Macy 
2891eda14cbcSMatt Macy static int
nvs_native_nvl_fini(nvstream_t * nvs)2892eda14cbcSMatt Macy nvs_native_nvl_fini(nvstream_t *nvs)
2893eda14cbcSMatt Macy {
2894eda14cbcSMatt Macy 	if (nvs->nvs_op == NVS_OP_ENCODE) {
2895eda14cbcSMatt Macy 		nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
2896eda14cbcSMatt Macy 		/*
2897eda14cbcSMatt Macy 		 * Add 4 zero bytes at end of nvlist. They are used
2898eda14cbcSMatt Macy 		 * for end detection by the decode routine.
2899eda14cbcSMatt Macy 		 */
2900eda14cbcSMatt Macy 		if (native->n_curr + sizeof (int) > native->n_end)
2901eda14cbcSMatt Macy 			return (EFAULT);
2902eda14cbcSMatt Macy 
2903da5137abSMartin Matuska 		memset(native->n_curr, 0, sizeof (int));
2904eda14cbcSMatt Macy 		native->n_curr += sizeof (int);
2905eda14cbcSMatt Macy 	}
2906eda14cbcSMatt Macy 
2907eda14cbcSMatt Macy 	return (0);
2908eda14cbcSMatt Macy }
2909eda14cbcSMatt Macy 
2910eda14cbcSMatt Macy static int
nvpair_native_embedded(nvstream_t * nvs,nvpair_t * nvp)2911eda14cbcSMatt Macy nvpair_native_embedded(nvstream_t *nvs, nvpair_t *nvp)
2912eda14cbcSMatt Macy {
2913eda14cbcSMatt Macy 	if (nvs->nvs_op == NVS_OP_ENCODE) {
2914eda14cbcSMatt Macy 		nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
2915eda14cbcSMatt Macy 		nvlist_t *packed = (void *)
2916eda14cbcSMatt Macy 		    (native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp));
2917eda14cbcSMatt Macy 		/*
2918eda14cbcSMatt Macy 		 * Null out the pointer that is meaningless in the packed
2919eda14cbcSMatt Macy 		 * structure. The address may not be aligned, so we have
2920da5137abSMartin Matuska 		 * to use memset.
2921eda14cbcSMatt Macy 		 */
2922da5137abSMartin Matuska 		memset((char *)packed + offsetof(nvlist_t, nvl_priv),
2923da5137abSMartin Matuska 		    0, sizeof (uint64_t));
2924eda14cbcSMatt Macy 	}
2925eda14cbcSMatt Macy 
2926eda14cbcSMatt Macy 	return (nvs_embedded(nvs, EMBEDDED_NVL(nvp)));
2927eda14cbcSMatt Macy }
2928eda14cbcSMatt Macy 
2929eda14cbcSMatt Macy static int
nvpair_native_embedded_array(nvstream_t * nvs,nvpair_t * nvp)2930eda14cbcSMatt Macy nvpair_native_embedded_array(nvstream_t *nvs, nvpair_t *nvp)
2931eda14cbcSMatt Macy {
2932eda14cbcSMatt Macy 	if (nvs->nvs_op == NVS_OP_ENCODE) {
2933eda14cbcSMatt Macy 		nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
2934eda14cbcSMatt Macy 		char *value = native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp);
2935eda14cbcSMatt Macy 		size_t len = NVP_NELEM(nvp) * sizeof (uint64_t);
2936eda14cbcSMatt Macy 		nvlist_t *packed = (nvlist_t *)((uintptr_t)value + len);
2937eda14cbcSMatt Macy 		int i;
2938eda14cbcSMatt Macy 		/*
2939eda14cbcSMatt Macy 		 * Null out pointers that are meaningless in the packed
2940eda14cbcSMatt Macy 		 * structure. The addresses may not be aligned, so we have
2941da5137abSMartin Matuska 		 * to use memset.
2942eda14cbcSMatt Macy 		 */
2943da5137abSMartin Matuska 		memset(value, 0, len);
2944eda14cbcSMatt Macy 
2945eda14cbcSMatt Macy 		for (i = 0; i < NVP_NELEM(nvp); i++, packed++)
2946eda14cbcSMatt Macy 			/*
2947eda14cbcSMatt Macy 			 * Null out the pointer that is meaningless in the
2948eda14cbcSMatt Macy 			 * packed structure. The address may not be aligned,
2949da5137abSMartin Matuska 			 * so we have to use memset.
2950eda14cbcSMatt Macy 			 */
2951da5137abSMartin Matuska 			memset((char *)packed + offsetof(nvlist_t, nvl_priv),
2952da5137abSMartin Matuska 			    0, sizeof (uint64_t));
2953eda14cbcSMatt Macy 	}
2954eda14cbcSMatt Macy 
2955eda14cbcSMatt Macy 	return (nvs_embedded_nvl_array(nvs, nvp, NULL));
2956eda14cbcSMatt Macy }
2957eda14cbcSMatt Macy 
2958eda14cbcSMatt Macy static void
nvpair_native_string_array(nvstream_t * nvs,nvpair_t * nvp)2959eda14cbcSMatt Macy nvpair_native_string_array(nvstream_t *nvs, nvpair_t *nvp)
2960eda14cbcSMatt Macy {
2961eda14cbcSMatt Macy 	switch (nvs->nvs_op) {
2962eda14cbcSMatt Macy 	case NVS_OP_ENCODE: {
2963eda14cbcSMatt Macy 		nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
2964eda14cbcSMatt Macy 		uint64_t *strp = (void *)
2965eda14cbcSMatt Macy 		    (native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp));
2966eda14cbcSMatt Macy 		/*
2967eda14cbcSMatt Macy 		 * Null out pointers that are meaningless in the packed
2968eda14cbcSMatt Macy 		 * structure. The addresses may not be aligned, so we have
2969da5137abSMartin Matuska 		 * to use memset.
2970eda14cbcSMatt Macy 		 */
2971da5137abSMartin Matuska 		memset(strp, 0, NVP_NELEM(nvp) * sizeof (uint64_t));
2972eda14cbcSMatt Macy 		break;
2973eda14cbcSMatt Macy 	}
2974eda14cbcSMatt Macy 	case NVS_OP_DECODE: {
2975eda14cbcSMatt Macy 		char **strp = (void *)NVP_VALUE(nvp);
2976eda14cbcSMatt Macy 		char *buf = ((char *)strp + NVP_NELEM(nvp) * sizeof (uint64_t));
2977eda14cbcSMatt Macy 		int i;
2978eda14cbcSMatt Macy 
2979eda14cbcSMatt Macy 		for (i = 0; i < NVP_NELEM(nvp); i++) {
2980eda14cbcSMatt Macy 			strp[i] = buf;
2981eda14cbcSMatt Macy 			buf += strlen(buf) + 1;
2982eda14cbcSMatt Macy 		}
2983eda14cbcSMatt Macy 		break;
2984eda14cbcSMatt Macy 	}
2985eda14cbcSMatt Macy 	}
2986eda14cbcSMatt Macy }
2987eda14cbcSMatt Macy 
2988eda14cbcSMatt Macy static int
nvs_native_nvp_op(nvstream_t * nvs,nvpair_t * nvp)2989eda14cbcSMatt Macy nvs_native_nvp_op(nvstream_t *nvs, nvpair_t *nvp)
2990eda14cbcSMatt Macy {
2991eda14cbcSMatt Macy 	data_type_t type;
2992eda14cbcSMatt Macy 	int value_sz;
2993eda14cbcSMatt Macy 	int ret = 0;
2994eda14cbcSMatt Macy 
2995eda14cbcSMatt Macy 	/*
2996da5137abSMartin Matuska 	 * We do the initial memcpy of the data before we look at
2997eda14cbcSMatt Macy 	 * the nvpair type, because when we're decoding, we won't
2998da5137abSMartin Matuska 	 * have the correct values for the pair until we do the memcpy.
2999eda14cbcSMatt Macy 	 */
3000eda14cbcSMatt Macy 	switch (nvs->nvs_op) {
3001eda14cbcSMatt Macy 	case NVS_OP_ENCODE:
3002eda14cbcSMatt Macy 	case NVS_OP_DECODE:
3003eda14cbcSMatt Macy 		if (native_cp(nvs, nvp, nvp->nvp_size) != 0)
3004eda14cbcSMatt Macy 			return (EFAULT);
3005eda14cbcSMatt Macy 		break;
3006eda14cbcSMatt Macy 	default:
3007eda14cbcSMatt Macy 		return (EINVAL);
3008eda14cbcSMatt Macy 	}
3009eda14cbcSMatt Macy 
3010eda14cbcSMatt Macy 	/* verify nvp_name_sz, check the name string length */
3011eda14cbcSMatt Macy 	if (i_validate_nvpair_name(nvp) != 0)
3012eda14cbcSMatt Macy 		return (EFAULT);
3013eda14cbcSMatt Macy 
3014eda14cbcSMatt Macy 	type = NVP_TYPE(nvp);
3015eda14cbcSMatt Macy 
3016eda14cbcSMatt Macy 	/*
3017eda14cbcSMatt Macy 	 * Verify type and nelem and get the value size.
3018eda14cbcSMatt Macy 	 * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY
3019eda14cbcSMatt Macy 	 * is the size of the string(s) excluded.
3020eda14cbcSMatt Macy 	 */
3021eda14cbcSMatt Macy 	if ((value_sz = i_get_value_size(type, NULL, NVP_NELEM(nvp))) < 0)
3022eda14cbcSMatt Macy 		return (EFAULT);
3023eda14cbcSMatt Macy 
3024eda14cbcSMatt Macy 	if (NVP_SIZE_CALC(nvp->nvp_name_sz, value_sz) > nvp->nvp_size)
3025eda14cbcSMatt Macy 		return (EFAULT);
3026eda14cbcSMatt Macy 
3027eda14cbcSMatt Macy 	switch (type) {
3028eda14cbcSMatt Macy 	case DATA_TYPE_NVLIST:
3029eda14cbcSMatt Macy 		ret = nvpair_native_embedded(nvs, nvp);
3030eda14cbcSMatt Macy 		break;
3031eda14cbcSMatt Macy 	case DATA_TYPE_NVLIST_ARRAY:
3032eda14cbcSMatt Macy 		ret = nvpair_native_embedded_array(nvs, nvp);
3033eda14cbcSMatt Macy 		break;
3034eda14cbcSMatt Macy 	case DATA_TYPE_STRING_ARRAY:
3035eda14cbcSMatt Macy 		nvpair_native_string_array(nvs, nvp);
3036eda14cbcSMatt Macy 		break;
3037eda14cbcSMatt Macy 	default:
3038eda14cbcSMatt Macy 		break;
3039eda14cbcSMatt Macy 	}
3040eda14cbcSMatt Macy 
3041eda14cbcSMatt Macy 	return (ret);
3042eda14cbcSMatt Macy }
3043eda14cbcSMatt Macy 
3044eda14cbcSMatt Macy static int
nvs_native_nvp_size(nvstream_t * nvs,nvpair_t * nvp,size_t * size)3045eda14cbcSMatt Macy nvs_native_nvp_size(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
3046eda14cbcSMatt Macy {
3047eda14cbcSMatt Macy 	uint64_t nvp_sz = nvp->nvp_size;
3048eda14cbcSMatt Macy 
3049eda14cbcSMatt Macy 	switch (NVP_TYPE(nvp)) {
3050eda14cbcSMatt Macy 	case DATA_TYPE_NVLIST: {
3051eda14cbcSMatt Macy 		size_t nvsize = 0;
3052eda14cbcSMatt Macy 
3053eda14cbcSMatt Macy 		if (nvs_operation(nvs, EMBEDDED_NVL(nvp), &nvsize) != 0)
3054eda14cbcSMatt Macy 			return (EINVAL);
3055eda14cbcSMatt Macy 
3056eda14cbcSMatt Macy 		nvp_sz += nvsize;
3057eda14cbcSMatt Macy 		break;
3058eda14cbcSMatt Macy 	}
3059eda14cbcSMatt Macy 	case DATA_TYPE_NVLIST_ARRAY: {
3060eda14cbcSMatt Macy 		size_t nvsize;
3061eda14cbcSMatt Macy 
3062eda14cbcSMatt Macy 		if (nvs_embedded_nvl_array(nvs, nvp, &nvsize) != 0)
3063eda14cbcSMatt Macy 			return (EINVAL);
3064eda14cbcSMatt Macy 
3065eda14cbcSMatt Macy 		nvp_sz += nvsize;
3066eda14cbcSMatt Macy 		break;
3067eda14cbcSMatt Macy 	}
3068eda14cbcSMatt Macy 	default:
3069eda14cbcSMatt Macy 		break;
3070eda14cbcSMatt Macy 	}
3071eda14cbcSMatt Macy 
3072eda14cbcSMatt Macy 	if (nvp_sz > INT32_MAX)
3073eda14cbcSMatt Macy 		return (EINVAL);
3074eda14cbcSMatt Macy 
3075eda14cbcSMatt Macy 	*size = nvp_sz;
3076eda14cbcSMatt Macy 
3077eda14cbcSMatt Macy 	return (0);
3078eda14cbcSMatt Macy }
3079eda14cbcSMatt Macy 
3080eda14cbcSMatt Macy static int
nvs_native_nvpair(nvstream_t * nvs,nvpair_t * nvp,size_t * size)3081eda14cbcSMatt Macy nvs_native_nvpair(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
3082eda14cbcSMatt Macy {
3083eda14cbcSMatt Macy 	switch (nvs->nvs_op) {
3084eda14cbcSMatt Macy 	case NVS_OP_ENCODE:
3085eda14cbcSMatt Macy 		return (nvs_native_nvp_op(nvs, nvp));
3086eda14cbcSMatt Macy 
3087eda14cbcSMatt Macy 	case NVS_OP_DECODE: {
3088eda14cbcSMatt Macy 		nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
3089eda14cbcSMatt Macy 		int32_t decode_len;
3090eda14cbcSMatt Macy 
3091eda14cbcSMatt Macy 		/* try to read the size value from the stream */
3092eda14cbcSMatt Macy 		if (native->n_curr + sizeof (int32_t) > native->n_end)
3093eda14cbcSMatt Macy 			return (EFAULT);
3094da5137abSMartin Matuska 		memcpy(&decode_len, native->n_curr, sizeof (int32_t));
3095eda14cbcSMatt Macy 
3096eda14cbcSMatt Macy 		/* sanity check the size value */
3097eda14cbcSMatt Macy 		if (decode_len < 0 ||
3098eda14cbcSMatt Macy 		    decode_len > native->n_end - native->n_curr)
3099eda14cbcSMatt Macy 			return (EFAULT);
3100eda14cbcSMatt Macy 
3101eda14cbcSMatt Macy 		*size = decode_len;
3102eda14cbcSMatt Macy 
3103eda14cbcSMatt Macy 		/*
3104eda14cbcSMatt Macy 		 * If at the end of the stream then move the cursor
3105eda14cbcSMatt Macy 		 * forward, otherwise nvpair_native_op() will read
3106eda14cbcSMatt Macy 		 * the entire nvpair at the same cursor position.
3107eda14cbcSMatt Macy 		 */
3108eda14cbcSMatt Macy 		if (*size == 0)
3109eda14cbcSMatt Macy 			native->n_curr += sizeof (int32_t);
3110eda14cbcSMatt Macy 		break;
3111eda14cbcSMatt Macy 	}
3112eda14cbcSMatt Macy 
3113eda14cbcSMatt Macy 	default:
3114eda14cbcSMatt Macy 		return (EINVAL);
3115eda14cbcSMatt Macy 	}
3116eda14cbcSMatt Macy 
3117eda14cbcSMatt Macy 	return (0);
3118eda14cbcSMatt Macy }
3119eda14cbcSMatt Macy 
3120eda14cbcSMatt Macy static const nvs_ops_t nvs_native_ops = {
3121eda14cbcSMatt Macy 	.nvs_nvlist = nvs_native_nvlist,
3122eda14cbcSMatt Macy 	.nvs_nvpair = nvs_native_nvpair,
3123eda14cbcSMatt Macy 	.nvs_nvp_op = nvs_native_nvp_op,
3124eda14cbcSMatt Macy 	.nvs_nvp_size = nvs_native_nvp_size,
3125eda14cbcSMatt Macy 	.nvs_nvl_fini = nvs_native_nvl_fini
3126eda14cbcSMatt Macy };
3127eda14cbcSMatt Macy 
3128eda14cbcSMatt Macy static int
nvs_native(nvstream_t * nvs,nvlist_t * nvl,char * buf,size_t * buflen)3129eda14cbcSMatt Macy nvs_native(nvstream_t *nvs, nvlist_t *nvl, char *buf, size_t *buflen)
3130eda14cbcSMatt Macy {
3131eda14cbcSMatt Macy 	nvs_native_t native;
3132eda14cbcSMatt Macy 	int err;
3133eda14cbcSMatt Macy 
3134eda14cbcSMatt Macy 	nvs->nvs_ops = &nvs_native_ops;
3135eda14cbcSMatt Macy 
3136eda14cbcSMatt Macy 	if ((err = nvs_native_create(nvs, &native, buf + sizeof (nvs_header_t),
3137eda14cbcSMatt Macy 	    *buflen - sizeof (nvs_header_t))) != 0)
3138eda14cbcSMatt Macy 		return (err);
3139eda14cbcSMatt Macy 
3140eda14cbcSMatt Macy 	err = nvs_operation(nvs, nvl, buflen);
3141eda14cbcSMatt Macy 
3142eda14cbcSMatt Macy 	nvs_native_destroy(nvs);
3143eda14cbcSMatt Macy 
3144eda14cbcSMatt Macy 	return (err);
3145eda14cbcSMatt Macy }
3146eda14cbcSMatt Macy 
3147eda14cbcSMatt Macy /*
3148eda14cbcSMatt Macy  * XDR encoding functions
3149eda14cbcSMatt Macy  *
3150eda14cbcSMatt Macy  * An xdr packed nvlist is encoded as:
3151eda14cbcSMatt Macy  *
3152eda14cbcSMatt Macy  *  - encoding method and host endian (4 bytes)
3153eda14cbcSMatt Macy  *  - nvl_version (4 bytes)
3154eda14cbcSMatt Macy  *  - nvl_nvflag (4 bytes)
3155eda14cbcSMatt Macy  *
3156eda14cbcSMatt Macy  *  - encoded nvpairs, the format of one xdr encoded nvpair is:
3157eda14cbcSMatt Macy  *	- encoded size of the nvpair (4 bytes)
3158eda14cbcSMatt Macy  *	- decoded size of the nvpair (4 bytes)
3159eda14cbcSMatt Macy  *	- name string, (4 + sizeof(NV_ALIGN4(string))
3160eda14cbcSMatt Macy  *	  a string is coded as size (4 bytes) and data
3161eda14cbcSMatt Macy  *	- data type (4 bytes)
3162eda14cbcSMatt Macy  *	- number of elements in the nvpair (4 bytes)
3163eda14cbcSMatt Macy  *	- data
3164eda14cbcSMatt Macy  *
3165eda14cbcSMatt Macy  *  - 2 zero's for end of the entire list (8 bytes)
3166eda14cbcSMatt Macy  */
3167eda14cbcSMatt Macy static int
nvs_xdr_create(nvstream_t * nvs,XDR * xdr,char * buf,size_t buflen)3168eda14cbcSMatt Macy nvs_xdr_create(nvstream_t *nvs, XDR *xdr, char *buf, size_t buflen)
3169eda14cbcSMatt Macy {
3170eda14cbcSMatt Macy 	/* xdr data must be 4 byte aligned */
3171eda14cbcSMatt Macy 	if ((ulong_t)buf % 4 != 0)
3172eda14cbcSMatt Macy 		return (EFAULT);
3173eda14cbcSMatt Macy 
3174eda14cbcSMatt Macy 	switch (nvs->nvs_op) {
3175eda14cbcSMatt Macy 	case NVS_OP_ENCODE:
3176eda14cbcSMatt Macy 		xdrmem_create(xdr, buf, (uint_t)buflen, XDR_ENCODE);
3177eda14cbcSMatt Macy 		nvs->nvs_private = xdr;
3178eda14cbcSMatt Macy 		return (0);
3179eda14cbcSMatt Macy 	case NVS_OP_DECODE:
3180eda14cbcSMatt Macy 		xdrmem_create(xdr, buf, (uint_t)buflen, XDR_DECODE);
3181eda14cbcSMatt Macy 		nvs->nvs_private = xdr;
3182eda14cbcSMatt Macy 		return (0);
3183eda14cbcSMatt Macy 	case NVS_OP_GETSIZE:
3184eda14cbcSMatt Macy 		nvs->nvs_private = NULL;
3185eda14cbcSMatt Macy 		return (0);
3186eda14cbcSMatt Macy 	default:
3187eda14cbcSMatt Macy 		return (EINVAL);
3188eda14cbcSMatt Macy 	}
3189eda14cbcSMatt Macy }
3190eda14cbcSMatt Macy 
3191eda14cbcSMatt Macy static void
nvs_xdr_destroy(nvstream_t * nvs)3192eda14cbcSMatt Macy nvs_xdr_destroy(nvstream_t *nvs)
3193eda14cbcSMatt Macy {
3194eda14cbcSMatt Macy 	switch (nvs->nvs_op) {
3195eda14cbcSMatt Macy 	case NVS_OP_ENCODE:
3196eda14cbcSMatt Macy 	case NVS_OP_DECODE:
31972a58b312SMartin Matuska 		nvs->nvs_private = NULL;
3198eda14cbcSMatt Macy 		break;
3199eda14cbcSMatt Macy 	default:
3200eda14cbcSMatt Macy 		break;
3201eda14cbcSMatt Macy 	}
3202eda14cbcSMatt Macy }
3203eda14cbcSMatt Macy 
3204eda14cbcSMatt Macy static int
nvs_xdr_nvlist(nvstream_t * nvs,nvlist_t * nvl,size_t * size)3205eda14cbcSMatt Macy nvs_xdr_nvlist(nvstream_t *nvs, nvlist_t *nvl, size_t *size)
3206eda14cbcSMatt Macy {
3207eda14cbcSMatt Macy 	switch (nvs->nvs_op) {
3208eda14cbcSMatt Macy 	case NVS_OP_ENCODE:
3209eda14cbcSMatt Macy 	case NVS_OP_DECODE: {
3210eda14cbcSMatt Macy 		XDR 	*xdr = nvs->nvs_private;
3211eda14cbcSMatt Macy 
3212eda14cbcSMatt Macy 		if (!xdr_int(xdr, &nvl->nvl_version) ||
3213eda14cbcSMatt Macy 		    !xdr_u_int(xdr, &nvl->nvl_nvflag))
3214eda14cbcSMatt Macy 			return (EFAULT);
3215eda14cbcSMatt Macy 		break;
3216eda14cbcSMatt Macy 	}
3217eda14cbcSMatt Macy 	case NVS_OP_GETSIZE: {
3218eda14cbcSMatt Macy 		/*
3219eda14cbcSMatt Macy 		 * 2 * 4 for nvl_version + nvl_nvflag
3220eda14cbcSMatt Macy 		 * and 8 for end of the entire list
3221eda14cbcSMatt Macy 		 */
3222eda14cbcSMatt Macy 		*size += 2 * 4 + 8;
3223eda14cbcSMatt Macy 		break;
3224eda14cbcSMatt Macy 	}
3225eda14cbcSMatt Macy 	default:
3226eda14cbcSMatt Macy 		return (EINVAL);
3227eda14cbcSMatt Macy 	}
3228eda14cbcSMatt Macy 	return (0);
3229eda14cbcSMatt Macy }
3230eda14cbcSMatt Macy 
3231eda14cbcSMatt Macy static int
nvs_xdr_nvl_fini(nvstream_t * nvs)3232eda14cbcSMatt Macy nvs_xdr_nvl_fini(nvstream_t *nvs)
3233eda14cbcSMatt Macy {
3234eda14cbcSMatt Macy 	if (nvs->nvs_op == NVS_OP_ENCODE) {
3235eda14cbcSMatt Macy 		XDR *xdr = nvs->nvs_private;
3236eda14cbcSMatt Macy 		int zero = 0;
3237eda14cbcSMatt Macy 
3238eda14cbcSMatt Macy 		if (!xdr_int(xdr, &zero) || !xdr_int(xdr, &zero))
3239eda14cbcSMatt Macy 			return (EFAULT);
3240eda14cbcSMatt Macy 	}
3241eda14cbcSMatt Macy 
3242eda14cbcSMatt Macy 	return (0);
3243eda14cbcSMatt Macy }
3244eda14cbcSMatt Macy 
3245eda14cbcSMatt Macy /*
32463f9d360cSMartin Matuska  * xdrproc_t-compatible callbacks for xdr_array()
32473f9d360cSMartin Matuska  */
32483f9d360cSMartin Matuska 
32493f9d360cSMartin Matuska #if defined(_KERNEL) && defined(__linux__) /* Linux kernel */
32503f9d360cSMartin Matuska 
32513f9d360cSMartin Matuska #define	NVS_BUILD_XDRPROC_T(type)		\
32523f9d360cSMartin Matuska static bool_t					\
32533f9d360cSMartin Matuska nvs_xdr_nvp_##type(XDR *xdrs, void *ptr)	\
32543f9d360cSMartin Matuska {						\
32553f9d360cSMartin Matuska 	return (xdr_##type(xdrs, ptr));		\
32563f9d360cSMartin Matuska }
32573f9d360cSMartin Matuska 
32583f9d360cSMartin Matuska #elif !defined(_KERNEL) && defined(XDR_CONTROL) /* tirpc */
32593f9d360cSMartin Matuska 
32603f9d360cSMartin Matuska #define	NVS_BUILD_XDRPROC_T(type)		\
32613f9d360cSMartin Matuska static bool_t					\
32623f9d360cSMartin Matuska nvs_xdr_nvp_##type(XDR *xdrs, ...)		\
32633f9d360cSMartin Matuska {						\
32643f9d360cSMartin Matuska 	va_list args;				\
32653f9d360cSMartin Matuska 	void *ptr;				\
32663f9d360cSMartin Matuska 						\
32673f9d360cSMartin Matuska 	va_start(args, xdrs);			\
32683f9d360cSMartin Matuska 	ptr = va_arg(args, void *);		\
32693f9d360cSMartin Matuska 	va_end(args);				\
32703f9d360cSMartin Matuska 						\
32713f9d360cSMartin Matuska 	return (xdr_##type(xdrs, ptr));		\
32723f9d360cSMartin Matuska }
32733f9d360cSMartin Matuska 
32743f9d360cSMartin Matuska #else /* FreeBSD, sunrpc */
32753f9d360cSMartin Matuska 
32763f9d360cSMartin Matuska #define	NVS_BUILD_XDRPROC_T(type)		\
32773f9d360cSMartin Matuska static bool_t					\
32783f9d360cSMartin Matuska nvs_xdr_nvp_##type(XDR *xdrs, void *ptr, ...)	\
32793f9d360cSMartin Matuska {						\
32803f9d360cSMartin Matuska 	return (xdr_##type(xdrs, ptr));		\
32813f9d360cSMartin Matuska }
32823f9d360cSMartin Matuska 
32833f9d360cSMartin Matuska #endif
32843f9d360cSMartin Matuska 
32853f9d360cSMartin Matuska NVS_BUILD_XDRPROC_T(char);
32863f9d360cSMartin Matuska NVS_BUILD_XDRPROC_T(short);
32873f9d360cSMartin Matuska NVS_BUILD_XDRPROC_T(u_short);
32883f9d360cSMartin Matuska NVS_BUILD_XDRPROC_T(int);
32893f9d360cSMartin Matuska NVS_BUILD_XDRPROC_T(u_int);
32903f9d360cSMartin Matuska NVS_BUILD_XDRPROC_T(longlong_t);
32913f9d360cSMartin Matuska NVS_BUILD_XDRPROC_T(u_longlong_t);
32923f9d360cSMartin Matuska 
32933f9d360cSMartin Matuska /*
3294eda14cbcSMatt Macy  * The format of xdr encoded nvpair is:
3295eda14cbcSMatt Macy  * encode_size, decode_size, name string, data type, nelem, data
3296eda14cbcSMatt Macy  */
3297eda14cbcSMatt Macy static int
nvs_xdr_nvp_op(nvstream_t * nvs,nvpair_t * nvp)3298eda14cbcSMatt Macy nvs_xdr_nvp_op(nvstream_t *nvs, nvpair_t *nvp)
3299eda14cbcSMatt Macy {
330081b22a98SMartin Matuska 	ASSERT(nvs != NULL && nvp != NULL);
330181b22a98SMartin Matuska 
3302eda14cbcSMatt Macy 	data_type_t type;
3303eda14cbcSMatt Macy 	char	*buf;
3304eda14cbcSMatt Macy 	char	*buf_end = (char *)nvp + nvp->nvp_size;
3305eda14cbcSMatt Macy 	int	value_sz;
3306eda14cbcSMatt Macy 	uint_t	nelem, buflen;
3307eda14cbcSMatt Macy 	bool_t	ret = FALSE;
3308eda14cbcSMatt Macy 	XDR	*xdr = nvs->nvs_private;
3309eda14cbcSMatt Macy 
331081b22a98SMartin Matuska 	ASSERT(xdr != NULL);
3311eda14cbcSMatt Macy 
3312eda14cbcSMatt Macy 	/* name string */
3313eda14cbcSMatt Macy 	if ((buf = NVP_NAME(nvp)) >= buf_end)
3314eda14cbcSMatt Macy 		return (EFAULT);
3315eda14cbcSMatt Macy 	buflen = buf_end - buf;
3316eda14cbcSMatt Macy 
3317eda14cbcSMatt Macy 	if (!xdr_string(xdr, &buf, buflen - 1))
3318eda14cbcSMatt Macy 		return (EFAULT);
3319eda14cbcSMatt Macy 	nvp->nvp_name_sz = strlen(buf) + 1;
3320eda14cbcSMatt Macy 
3321eda14cbcSMatt Macy 	/* type and nelem */
3322eda14cbcSMatt Macy 	if (!xdr_int(xdr, (int *)&nvp->nvp_type) ||
3323eda14cbcSMatt Macy 	    !xdr_int(xdr, &nvp->nvp_value_elem))
3324eda14cbcSMatt Macy 		return (EFAULT);
3325eda14cbcSMatt Macy 
3326eda14cbcSMatt Macy 	type = NVP_TYPE(nvp);
3327eda14cbcSMatt Macy 	nelem = nvp->nvp_value_elem;
3328eda14cbcSMatt Macy 
3329eda14cbcSMatt Macy 	/*
3330eda14cbcSMatt Macy 	 * Verify type and nelem and get the value size.
3331eda14cbcSMatt Macy 	 * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY
3332eda14cbcSMatt Macy 	 * is the size of the string(s) excluded.
3333eda14cbcSMatt Macy 	 */
3334eda14cbcSMatt Macy 	if ((value_sz = i_get_value_size(type, NULL, nelem)) < 0)
3335eda14cbcSMatt Macy 		return (EFAULT);
3336eda14cbcSMatt Macy 
3337eda14cbcSMatt Macy 	/* if there is no data to extract then return */
3338eda14cbcSMatt Macy 	if (nelem == 0)
3339eda14cbcSMatt Macy 		return (0);
3340eda14cbcSMatt Macy 
3341eda14cbcSMatt Macy 	/* value */
3342eda14cbcSMatt Macy 	if ((buf = NVP_VALUE(nvp)) >= buf_end)
3343eda14cbcSMatt Macy 		return (EFAULT);
3344eda14cbcSMatt Macy 	buflen = buf_end - buf;
3345eda14cbcSMatt Macy 
3346eda14cbcSMatt Macy 	if (buflen < value_sz)
3347eda14cbcSMatt Macy 		return (EFAULT);
3348eda14cbcSMatt Macy 
3349eda14cbcSMatt Macy 	switch (type) {
3350eda14cbcSMatt Macy 	case DATA_TYPE_NVLIST:
3351eda14cbcSMatt Macy 		if (nvs_embedded(nvs, (void *)buf) == 0)
3352eda14cbcSMatt Macy 			return (0);
3353eda14cbcSMatt Macy 		break;
3354eda14cbcSMatt Macy 
3355eda14cbcSMatt Macy 	case DATA_TYPE_NVLIST_ARRAY:
3356eda14cbcSMatt Macy 		if (nvs_embedded_nvl_array(nvs, nvp, NULL) == 0)
3357eda14cbcSMatt Macy 			return (0);
3358eda14cbcSMatt Macy 		break;
3359eda14cbcSMatt Macy 
3360eda14cbcSMatt Macy 	case DATA_TYPE_BOOLEAN:
3361eda14cbcSMatt Macy 		ret = TRUE;
3362eda14cbcSMatt Macy 		break;
3363eda14cbcSMatt Macy 
3364eda14cbcSMatt Macy 	case DATA_TYPE_BYTE:
3365eda14cbcSMatt Macy 	case DATA_TYPE_INT8:
3366eda14cbcSMatt Macy 	case DATA_TYPE_UINT8:
3367eda14cbcSMatt Macy 		ret = xdr_char(xdr, buf);
3368eda14cbcSMatt Macy 		break;
3369eda14cbcSMatt Macy 
3370eda14cbcSMatt Macy 	case DATA_TYPE_INT16:
3371eda14cbcSMatt Macy 		ret = xdr_short(xdr, (void *)buf);
3372eda14cbcSMatt Macy 		break;
3373eda14cbcSMatt Macy 
3374eda14cbcSMatt Macy 	case DATA_TYPE_UINT16:
3375eda14cbcSMatt Macy 		ret = xdr_u_short(xdr, (void *)buf);
3376eda14cbcSMatt Macy 		break;
3377eda14cbcSMatt Macy 
3378eda14cbcSMatt Macy 	case DATA_TYPE_BOOLEAN_VALUE:
3379eda14cbcSMatt Macy 	case DATA_TYPE_INT32:
3380eda14cbcSMatt Macy 		ret = xdr_int(xdr, (void *)buf);
3381eda14cbcSMatt Macy 		break;
3382eda14cbcSMatt Macy 
3383eda14cbcSMatt Macy 	case DATA_TYPE_UINT32:
3384eda14cbcSMatt Macy 		ret = xdr_u_int(xdr, (void *)buf);
3385eda14cbcSMatt Macy 		break;
3386eda14cbcSMatt Macy 
3387eda14cbcSMatt Macy 	case DATA_TYPE_INT64:
3388eda14cbcSMatt Macy 		ret = xdr_longlong_t(xdr, (void *)buf);
3389eda14cbcSMatt Macy 		break;
3390eda14cbcSMatt Macy 
3391eda14cbcSMatt Macy 	case DATA_TYPE_UINT64:
3392eda14cbcSMatt Macy 		ret = xdr_u_longlong_t(xdr, (void *)buf);
3393eda14cbcSMatt Macy 		break;
3394eda14cbcSMatt Macy 
3395eda14cbcSMatt Macy 	case DATA_TYPE_HRTIME:
3396eda14cbcSMatt Macy 		/*
3397eda14cbcSMatt Macy 		 * NOTE: must expose the definition of hrtime_t here
3398eda14cbcSMatt Macy 		 */
3399eda14cbcSMatt Macy 		ret = xdr_longlong_t(xdr, (void *)buf);
3400eda14cbcSMatt Macy 		break;
3401eda14cbcSMatt Macy #if !defined(_KERNEL)
3402eda14cbcSMatt Macy 	case DATA_TYPE_DOUBLE:
3403eda14cbcSMatt Macy 		ret = xdr_double(xdr, (void *)buf);
3404eda14cbcSMatt Macy 		break;
3405eda14cbcSMatt Macy #endif
3406eda14cbcSMatt Macy 	case DATA_TYPE_STRING:
3407eda14cbcSMatt Macy 		ret = xdr_string(xdr, &buf, buflen - 1);
3408eda14cbcSMatt Macy 		break;
3409eda14cbcSMatt Macy 
3410eda14cbcSMatt Macy 	case DATA_TYPE_BYTE_ARRAY:
3411eda14cbcSMatt Macy 		ret = xdr_opaque(xdr, buf, nelem);
3412eda14cbcSMatt Macy 		break;
3413eda14cbcSMatt Macy 
3414eda14cbcSMatt Macy 	case DATA_TYPE_INT8_ARRAY:
3415eda14cbcSMatt Macy 	case DATA_TYPE_UINT8_ARRAY:
3416eda14cbcSMatt Macy 		ret = xdr_array(xdr, &buf, &nelem, buflen, sizeof (int8_t),
34173f9d360cSMartin Matuska 		    nvs_xdr_nvp_char);
3418eda14cbcSMatt Macy 		break;
3419eda14cbcSMatt Macy 
3420eda14cbcSMatt Macy 	case DATA_TYPE_INT16_ARRAY:
3421eda14cbcSMatt Macy 		ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int16_t),
34223f9d360cSMartin Matuska 		    sizeof (int16_t), nvs_xdr_nvp_short);
3423eda14cbcSMatt Macy 		break;
3424eda14cbcSMatt Macy 
3425eda14cbcSMatt Macy 	case DATA_TYPE_UINT16_ARRAY:
3426eda14cbcSMatt Macy 		ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint16_t),
34273f9d360cSMartin Matuska 		    sizeof (uint16_t), nvs_xdr_nvp_u_short);
3428eda14cbcSMatt Macy 		break;
3429eda14cbcSMatt Macy 
3430eda14cbcSMatt Macy 	case DATA_TYPE_BOOLEAN_ARRAY:
3431eda14cbcSMatt Macy 	case DATA_TYPE_INT32_ARRAY:
3432eda14cbcSMatt Macy 		ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int32_t),
34333f9d360cSMartin Matuska 		    sizeof (int32_t), nvs_xdr_nvp_int);
3434eda14cbcSMatt Macy 		break;
3435eda14cbcSMatt Macy 
3436eda14cbcSMatt Macy 	case DATA_TYPE_UINT32_ARRAY:
3437eda14cbcSMatt Macy 		ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint32_t),
34383f9d360cSMartin Matuska 		    sizeof (uint32_t), nvs_xdr_nvp_u_int);
3439eda14cbcSMatt Macy 		break;
3440eda14cbcSMatt Macy 
3441eda14cbcSMatt Macy 	case DATA_TYPE_INT64_ARRAY:
3442eda14cbcSMatt Macy 		ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int64_t),
34433f9d360cSMartin Matuska 		    sizeof (int64_t), nvs_xdr_nvp_longlong_t);
3444eda14cbcSMatt Macy 		break;
3445eda14cbcSMatt Macy 
3446eda14cbcSMatt Macy 	case DATA_TYPE_UINT64_ARRAY:
3447eda14cbcSMatt Macy 		ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint64_t),
34483f9d360cSMartin Matuska 		    sizeof (uint64_t), nvs_xdr_nvp_u_longlong_t);
3449eda14cbcSMatt Macy 		break;
3450eda14cbcSMatt Macy 
3451eda14cbcSMatt Macy 	case DATA_TYPE_STRING_ARRAY: {
3452eda14cbcSMatt Macy 		size_t len = nelem * sizeof (uint64_t);
3453eda14cbcSMatt Macy 		char **strp = (void *)buf;
3454eda14cbcSMatt Macy 		int i;
3455eda14cbcSMatt Macy 
3456eda14cbcSMatt Macy 		if (nvs->nvs_op == NVS_OP_DECODE)
3457da5137abSMartin Matuska 			memset(buf, 0, len);	/* don't trust packed data */
3458eda14cbcSMatt Macy 
3459eda14cbcSMatt Macy 		for (i = 0; i < nelem; i++) {
3460eda14cbcSMatt Macy 			if (buflen <= len)
3461eda14cbcSMatt Macy 				return (EFAULT);
3462eda14cbcSMatt Macy 
3463eda14cbcSMatt Macy 			buf += len;
3464eda14cbcSMatt Macy 			buflen -= len;
3465eda14cbcSMatt Macy 
3466eda14cbcSMatt Macy 			if (xdr_string(xdr, &buf, buflen - 1) != TRUE)
3467eda14cbcSMatt Macy 				return (EFAULT);
3468eda14cbcSMatt Macy 
3469eda14cbcSMatt Macy 			if (nvs->nvs_op == NVS_OP_DECODE)
3470eda14cbcSMatt Macy 				strp[i] = buf;
3471eda14cbcSMatt Macy 			len = strlen(buf) + 1;
3472eda14cbcSMatt Macy 		}
3473eda14cbcSMatt Macy 		ret = TRUE;
3474eda14cbcSMatt Macy 		break;
3475eda14cbcSMatt Macy 	}
3476eda14cbcSMatt Macy 	default:
3477eda14cbcSMatt Macy 		break;
3478eda14cbcSMatt Macy 	}
3479eda14cbcSMatt Macy 
3480eda14cbcSMatt Macy 	return (ret == TRUE ? 0 : EFAULT);
3481eda14cbcSMatt Macy }
3482eda14cbcSMatt Macy 
3483eda14cbcSMatt Macy static int
nvs_xdr_nvp_size(nvstream_t * nvs,nvpair_t * nvp,size_t * size)3484eda14cbcSMatt Macy nvs_xdr_nvp_size(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
3485eda14cbcSMatt Macy {
3486eda14cbcSMatt Macy 	data_type_t type = NVP_TYPE(nvp);
3487eda14cbcSMatt Macy 	/*
3488eda14cbcSMatt Macy 	 * encode_size + decode_size + name string size + data type + nelem
3489eda14cbcSMatt Macy 	 * where name string size = 4 + NV_ALIGN4(strlen(NVP_NAME(nvp)))
3490eda14cbcSMatt Macy 	 */
3491eda14cbcSMatt Macy 	uint64_t nvp_sz = 4 + 4 + 4 + NV_ALIGN4(strlen(NVP_NAME(nvp))) + 4 + 4;
3492eda14cbcSMatt Macy 
3493eda14cbcSMatt Macy 	switch (type) {
3494eda14cbcSMatt Macy 	case DATA_TYPE_BOOLEAN:
3495eda14cbcSMatt Macy 		break;
3496eda14cbcSMatt Macy 
3497eda14cbcSMatt Macy 	case DATA_TYPE_BOOLEAN_VALUE:
3498eda14cbcSMatt Macy 	case DATA_TYPE_BYTE:
3499eda14cbcSMatt Macy 	case DATA_TYPE_INT8:
3500eda14cbcSMatt Macy 	case DATA_TYPE_UINT8:
3501eda14cbcSMatt Macy 	case DATA_TYPE_INT16:
3502eda14cbcSMatt Macy 	case DATA_TYPE_UINT16:
3503eda14cbcSMatt Macy 	case DATA_TYPE_INT32:
3504eda14cbcSMatt Macy 	case DATA_TYPE_UINT32:
3505eda14cbcSMatt Macy 		nvp_sz += 4;	/* 4 is the minimum xdr unit */
3506eda14cbcSMatt Macy 		break;
3507eda14cbcSMatt Macy 
3508eda14cbcSMatt Macy 	case DATA_TYPE_INT64:
3509eda14cbcSMatt Macy 	case DATA_TYPE_UINT64:
3510eda14cbcSMatt Macy 	case DATA_TYPE_HRTIME:
3511eda14cbcSMatt Macy #if !defined(_KERNEL)
3512eda14cbcSMatt Macy 	case DATA_TYPE_DOUBLE:
3513eda14cbcSMatt Macy #endif
3514eda14cbcSMatt Macy 		nvp_sz += 8;
3515eda14cbcSMatt Macy 		break;
3516eda14cbcSMatt Macy 
3517eda14cbcSMatt Macy 	case DATA_TYPE_STRING:
3518eda14cbcSMatt Macy 		nvp_sz += 4 + NV_ALIGN4(strlen((char *)NVP_VALUE(nvp)));
3519eda14cbcSMatt Macy 		break;
3520eda14cbcSMatt Macy 
3521eda14cbcSMatt Macy 	case DATA_TYPE_BYTE_ARRAY:
3522eda14cbcSMatt Macy 		nvp_sz += NV_ALIGN4(NVP_NELEM(nvp));
3523eda14cbcSMatt Macy 		break;
3524eda14cbcSMatt Macy 
3525eda14cbcSMatt Macy 	case DATA_TYPE_BOOLEAN_ARRAY:
3526eda14cbcSMatt Macy 	case DATA_TYPE_INT8_ARRAY:
3527eda14cbcSMatt Macy 	case DATA_TYPE_UINT8_ARRAY:
3528eda14cbcSMatt Macy 	case DATA_TYPE_INT16_ARRAY:
3529eda14cbcSMatt Macy 	case DATA_TYPE_UINT16_ARRAY:
3530eda14cbcSMatt Macy 	case DATA_TYPE_INT32_ARRAY:
3531eda14cbcSMatt Macy 	case DATA_TYPE_UINT32_ARRAY:
3532eda14cbcSMatt Macy 		nvp_sz += 4 + 4 * (uint64_t)NVP_NELEM(nvp);
3533eda14cbcSMatt Macy 		break;
3534eda14cbcSMatt Macy 
3535eda14cbcSMatt Macy 	case DATA_TYPE_INT64_ARRAY:
3536eda14cbcSMatt Macy 	case DATA_TYPE_UINT64_ARRAY:
3537eda14cbcSMatt Macy 		nvp_sz += 4 + 8 * (uint64_t)NVP_NELEM(nvp);
3538eda14cbcSMatt Macy 		break;
3539eda14cbcSMatt Macy 
3540eda14cbcSMatt Macy 	case DATA_TYPE_STRING_ARRAY: {
3541eda14cbcSMatt Macy 		int i;
3542eda14cbcSMatt Macy 		char **strs = (void *)NVP_VALUE(nvp);
3543eda14cbcSMatt Macy 
3544eda14cbcSMatt Macy 		for (i = 0; i < NVP_NELEM(nvp); i++)
3545eda14cbcSMatt Macy 			nvp_sz += 4 + NV_ALIGN4(strlen(strs[i]));
3546eda14cbcSMatt Macy 
3547eda14cbcSMatt Macy 		break;
3548eda14cbcSMatt Macy 	}
3549eda14cbcSMatt Macy 
3550eda14cbcSMatt Macy 	case DATA_TYPE_NVLIST:
3551eda14cbcSMatt Macy 	case DATA_TYPE_NVLIST_ARRAY: {
3552eda14cbcSMatt Macy 		size_t nvsize = 0;
3553eda14cbcSMatt Macy 		int old_nvs_op = nvs->nvs_op;
3554eda14cbcSMatt Macy 		int err;
3555eda14cbcSMatt Macy 
3556eda14cbcSMatt Macy 		nvs->nvs_op = NVS_OP_GETSIZE;
3557eda14cbcSMatt Macy 		if (type == DATA_TYPE_NVLIST)
3558eda14cbcSMatt Macy 			err = nvs_operation(nvs, EMBEDDED_NVL(nvp), &nvsize);
3559eda14cbcSMatt Macy 		else
3560eda14cbcSMatt Macy 			err = nvs_embedded_nvl_array(nvs, nvp, &nvsize);
3561eda14cbcSMatt Macy 		nvs->nvs_op = old_nvs_op;
3562eda14cbcSMatt Macy 
3563eda14cbcSMatt Macy 		if (err != 0)
3564eda14cbcSMatt Macy 			return (EINVAL);
3565eda14cbcSMatt Macy 
3566eda14cbcSMatt Macy 		nvp_sz += nvsize;
3567eda14cbcSMatt Macy 		break;
3568eda14cbcSMatt Macy 	}
3569eda14cbcSMatt Macy 
3570eda14cbcSMatt Macy 	default:
3571eda14cbcSMatt Macy 		return (EINVAL);
3572eda14cbcSMatt Macy 	}
3573eda14cbcSMatt Macy 
3574eda14cbcSMatt Macy 	if (nvp_sz > INT32_MAX)
3575eda14cbcSMatt Macy 		return (EINVAL);
3576eda14cbcSMatt Macy 
3577eda14cbcSMatt Macy 	*size = nvp_sz;
3578eda14cbcSMatt Macy 
3579eda14cbcSMatt Macy 	return (0);
3580eda14cbcSMatt Macy }
3581eda14cbcSMatt Macy 
3582eda14cbcSMatt Macy 
3583eda14cbcSMatt Macy /*
3584eda14cbcSMatt Macy  * The NVS_XDR_MAX_LEN macro takes a packed xdr buffer of size x and estimates
3585eda14cbcSMatt Macy  * the largest nvpair that could be encoded in the buffer.
3586eda14cbcSMatt Macy  *
3587eda14cbcSMatt Macy  * See comments above nvpair_xdr_op() for the format of xdr encoding.
3588eda14cbcSMatt Macy  * The size of a xdr packed nvpair without any data is 5 words.
3589eda14cbcSMatt Macy  *
3590eda14cbcSMatt Macy  * Using the size of the data directly as an estimate would be ok
3591eda14cbcSMatt Macy  * in all cases except one.  If the data type is of DATA_TYPE_STRING_ARRAY
3592eda14cbcSMatt Macy  * then the actual nvpair has space for an array of pointers to index
3593eda14cbcSMatt Macy  * the strings.  These pointers are not encoded into the packed xdr buffer.
3594eda14cbcSMatt Macy  *
3595eda14cbcSMatt Macy  * If the data is of type DATA_TYPE_STRING_ARRAY and all the strings are
3596eda14cbcSMatt Macy  * of length 0, then each string is encoded in xdr format as a single word.
3597eda14cbcSMatt Macy  * Therefore when expanded to an nvpair there will be 2.25 word used for
3598eda14cbcSMatt Macy  * each string.  (a int64_t allocated for pointer usage, and a single char
3599eda14cbcSMatt Macy  * for the null termination.)
3600eda14cbcSMatt Macy  *
3601eda14cbcSMatt Macy  * This is the calculation performed by the NVS_XDR_MAX_LEN macro.
3602eda14cbcSMatt Macy  */
3603eda14cbcSMatt Macy #define	NVS_XDR_HDR_LEN		((size_t)(5 * 4))
3604eda14cbcSMatt Macy #define	NVS_XDR_DATA_LEN(y)	(((size_t)(y) <= NVS_XDR_HDR_LEN) ? \
3605eda14cbcSMatt Macy 					0 : ((size_t)(y) - NVS_XDR_HDR_LEN))
3606eda14cbcSMatt Macy #define	NVS_XDR_MAX_LEN(x)	(NVP_SIZE_CALC(1, 0) + \
3607eda14cbcSMatt Macy 					(NVS_XDR_DATA_LEN(x) * 2) + \
3608eda14cbcSMatt Macy 					NV_ALIGN4((NVS_XDR_DATA_LEN(x) / 4)))
3609eda14cbcSMatt Macy 
3610eda14cbcSMatt Macy static int
nvs_xdr_nvpair(nvstream_t * nvs,nvpair_t * nvp,size_t * size)3611eda14cbcSMatt Macy nvs_xdr_nvpair(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
3612eda14cbcSMatt Macy {
3613eda14cbcSMatt Macy 	XDR 	*xdr = nvs->nvs_private;
3614eda14cbcSMatt Macy 	int32_t	encode_len, decode_len;
3615eda14cbcSMatt Macy 
3616eda14cbcSMatt Macy 	switch (nvs->nvs_op) {
3617eda14cbcSMatt Macy 	case NVS_OP_ENCODE: {
3618eda14cbcSMatt Macy 		size_t nvsize;
3619eda14cbcSMatt Macy 
3620eda14cbcSMatt Macy 		if (nvs_xdr_nvp_size(nvs, nvp, &nvsize) != 0)
3621eda14cbcSMatt Macy 			return (EFAULT);
3622eda14cbcSMatt Macy 
3623eda14cbcSMatt Macy 		decode_len = nvp->nvp_size;
3624eda14cbcSMatt Macy 		encode_len = nvsize;
3625eda14cbcSMatt Macy 		if (!xdr_int(xdr, &encode_len) || !xdr_int(xdr, &decode_len))
3626eda14cbcSMatt Macy 			return (EFAULT);
3627eda14cbcSMatt Macy 
3628eda14cbcSMatt Macy 		return (nvs_xdr_nvp_op(nvs, nvp));
3629eda14cbcSMatt Macy 	}
3630eda14cbcSMatt Macy 	case NVS_OP_DECODE: {
3631eda14cbcSMatt Macy 		struct xdr_bytesrec bytesrec;
3632eda14cbcSMatt Macy 
3633eda14cbcSMatt Macy 		/* get the encode and decode size */
3634eda14cbcSMatt Macy 		if (!xdr_int(xdr, &encode_len) || !xdr_int(xdr, &decode_len))
3635eda14cbcSMatt Macy 			return (EFAULT);
3636eda14cbcSMatt Macy 		*size = decode_len;
3637eda14cbcSMatt Macy 
3638eda14cbcSMatt Macy 		/* are we at the end of the stream? */
3639eda14cbcSMatt Macy 		if (*size == 0)
3640eda14cbcSMatt Macy 			return (0);
3641eda14cbcSMatt Macy 
3642eda14cbcSMatt Macy 		/* sanity check the size parameter */
3643eda14cbcSMatt Macy 		if (!xdr_control(xdr, XDR_GET_BYTES_AVAIL, &bytesrec))
3644eda14cbcSMatt Macy 			return (EFAULT);
3645eda14cbcSMatt Macy 
3646eda14cbcSMatt Macy 		if (*size > NVS_XDR_MAX_LEN(bytesrec.xc_num_avail))
3647eda14cbcSMatt Macy 			return (EFAULT);
3648eda14cbcSMatt Macy 		break;
3649eda14cbcSMatt Macy 	}
3650eda14cbcSMatt Macy 
3651eda14cbcSMatt Macy 	default:
3652eda14cbcSMatt Macy 		return (EINVAL);
3653eda14cbcSMatt Macy 	}
3654eda14cbcSMatt Macy 	return (0);
3655eda14cbcSMatt Macy }
3656eda14cbcSMatt Macy 
3657eda14cbcSMatt Macy static const struct nvs_ops nvs_xdr_ops = {
3658eda14cbcSMatt Macy 	.nvs_nvlist = nvs_xdr_nvlist,
3659eda14cbcSMatt Macy 	.nvs_nvpair = nvs_xdr_nvpair,
3660eda14cbcSMatt Macy 	.nvs_nvp_op = nvs_xdr_nvp_op,
3661eda14cbcSMatt Macy 	.nvs_nvp_size = nvs_xdr_nvp_size,
3662eda14cbcSMatt Macy 	.nvs_nvl_fini = nvs_xdr_nvl_fini
3663eda14cbcSMatt Macy };
3664eda14cbcSMatt Macy 
3665eda14cbcSMatt Macy static int
nvs_xdr(nvstream_t * nvs,nvlist_t * nvl,char * buf,size_t * buflen)3666eda14cbcSMatt Macy nvs_xdr(nvstream_t *nvs, nvlist_t *nvl, char *buf, size_t *buflen)
3667eda14cbcSMatt Macy {
3668eda14cbcSMatt Macy 	XDR xdr;
3669eda14cbcSMatt Macy 	int err;
3670eda14cbcSMatt Macy 
3671eda14cbcSMatt Macy 	nvs->nvs_ops = &nvs_xdr_ops;
3672eda14cbcSMatt Macy 
3673eda14cbcSMatt Macy 	if ((err = nvs_xdr_create(nvs, &xdr, buf + sizeof (nvs_header_t),
3674eda14cbcSMatt Macy 	    *buflen - sizeof (nvs_header_t))) != 0)
3675eda14cbcSMatt Macy 		return (err);
3676eda14cbcSMatt Macy 
3677eda14cbcSMatt Macy 	err = nvs_operation(nvs, nvl, buflen);
3678eda14cbcSMatt Macy 
3679eda14cbcSMatt Macy 	nvs_xdr_destroy(nvs);
3680eda14cbcSMatt Macy 
3681eda14cbcSMatt Macy 	return (err);
3682eda14cbcSMatt Macy }
3683eda14cbcSMatt Macy 
3684*071ab5a1SMartin Matuska #define	NVP(buf, size, len, buf_end, elem, type, vtype, ptype, format) { \
3685*071ab5a1SMartin Matuska 	vtype	value; \
3686*071ab5a1SMartin Matuska 	int rc; \
3687*071ab5a1SMartin Matuska \
3688*071ab5a1SMartin Matuska 	(void) nvpair_value_##type(elem, &value); \
3689*071ab5a1SMartin Matuska 	rc = snprintf(buf, size, "%*s%s: " format "\n", indent, "", \
3690*071ab5a1SMartin Matuska 	nvpair_name(elem), (ptype)value); \
3691*071ab5a1SMartin Matuska 	if (rc < 0) \
3692*071ab5a1SMartin Matuska 		return (rc); \
3693*071ab5a1SMartin Matuska 	size = MAX((int)size - rc, 0); \
3694*071ab5a1SMartin Matuska 	buf = size == 0 ? NULL : buf_end - size; \
3695*071ab5a1SMartin Matuska 	len += rc; \
3696*071ab5a1SMartin Matuska }
3697*071ab5a1SMartin Matuska 
3698*071ab5a1SMartin Matuska #define	NVPA(buf, size, len, buf_end, elem, type, vtype, ptype, format) \
3699*071ab5a1SMartin Matuska { \
3700*071ab5a1SMartin Matuska 	uint_t	i, count; \
3701*071ab5a1SMartin Matuska 	vtype	*value;  \
3702*071ab5a1SMartin Matuska 	int rc; \
3703*071ab5a1SMartin Matuska \
3704*071ab5a1SMartin Matuska 	(void) nvpair_value_##type(elem, &value, &count); \
3705*071ab5a1SMartin Matuska 	for (i = 0; i < count; i++) { \
3706*071ab5a1SMartin Matuska 		rc = snprintf(buf, size, "%*s%s[%d]: " format "\n", indent, \
3707*071ab5a1SMartin Matuska 		"", nvpair_name(elem), i, (ptype)value[i]); \
3708*071ab5a1SMartin Matuska 		if (rc < 0) \
3709*071ab5a1SMartin Matuska 			return (rc); \
3710*071ab5a1SMartin Matuska 		size = MAX((int)size - rc, 0); \
3711*071ab5a1SMartin Matuska 		buf = size == 0 ? NULL : buf_end - size; \
3712*071ab5a1SMartin Matuska 		len += rc; \
3713*071ab5a1SMartin Matuska 	} \
3714*071ab5a1SMartin Matuska }
3715*071ab5a1SMartin Matuska 
3716*071ab5a1SMartin Matuska /*
3717*071ab5a1SMartin Matuska  * snprintf() version of dump_nvlist()
3718*071ab5a1SMartin Matuska  *
3719*071ab5a1SMartin Matuska  * Works just like snprintf(), but with an nvlist and indent count as args.
3720*071ab5a1SMartin Matuska  *
3721*071ab5a1SMartin Matuska  * Output is similar to nvlist_print() but handles arrays slightly differently.
3722*071ab5a1SMartin Matuska  *
3723*071ab5a1SMartin Matuska  * Return value matches C99 snprintf() return value conventions.
3724*071ab5a1SMartin Matuska  */
3725*071ab5a1SMartin Matuska int
nvlist_snprintf(char * buf,size_t size,nvlist_t * list,int indent)3726*071ab5a1SMartin Matuska nvlist_snprintf(char *buf, size_t size, nvlist_t *list, int indent)
3727*071ab5a1SMartin Matuska {
3728*071ab5a1SMartin Matuska 	nvpair_t	*elem = NULL;
3729*071ab5a1SMartin Matuska 	boolean_t	bool_value;
3730*071ab5a1SMartin Matuska 	nvlist_t	*nvlist_value;
3731*071ab5a1SMartin Matuska 	nvlist_t	**nvlist_array_value;
3732*071ab5a1SMartin Matuska 	uint_t		i, count;
3733*071ab5a1SMartin Matuska 	int len = 0;
3734*071ab5a1SMartin Matuska 	int rc;
3735*071ab5a1SMartin Matuska 	char *buf_end = &buf[size];
3736*071ab5a1SMartin Matuska 
3737*071ab5a1SMartin Matuska 	if (list == NULL)
3738*071ab5a1SMartin Matuska 		return (0);
3739*071ab5a1SMartin Matuska 
3740*071ab5a1SMartin Matuska 	while ((elem = nvlist_next_nvpair(list, elem)) != NULL) {
3741*071ab5a1SMartin Matuska 		switch (nvpair_type(elem)) {
3742*071ab5a1SMartin Matuska 		case DATA_TYPE_BOOLEAN:
3743*071ab5a1SMartin Matuska 			rc = snprintf(buf, size, "%*s%s\n", indent, "",
3744*071ab5a1SMartin Matuska 			    nvpair_name(elem));
3745*071ab5a1SMartin Matuska 			if (rc < 0)
3746*071ab5a1SMartin Matuska 				return (rc);
3747*071ab5a1SMartin Matuska 			size = MAX((int)size - rc, 0);
3748*071ab5a1SMartin Matuska 			buf = size == 0 ? NULL : buf_end - size;
3749*071ab5a1SMartin Matuska 			len += rc;
3750*071ab5a1SMartin Matuska 			break;
3751*071ab5a1SMartin Matuska 
3752*071ab5a1SMartin Matuska 		case DATA_TYPE_BOOLEAN_VALUE:
3753*071ab5a1SMartin Matuska 			(void) nvpair_value_boolean_value(elem, &bool_value);
3754*071ab5a1SMartin Matuska 			rc = snprintf(buf, size, "%*s%s: %s\n", indent, "",
3755*071ab5a1SMartin Matuska 			    nvpair_name(elem), bool_value ? "true" : "false");
3756*071ab5a1SMartin Matuska 			if (rc < 0)
3757*071ab5a1SMartin Matuska 				return (rc);
3758*071ab5a1SMartin Matuska 			size = MAX((int)size - rc, 0);
3759*071ab5a1SMartin Matuska 			buf = size == 0 ? NULL : buf_end - size;
3760*071ab5a1SMartin Matuska 			len += rc;
3761*071ab5a1SMartin Matuska 			break;
3762*071ab5a1SMartin Matuska 
3763*071ab5a1SMartin Matuska 		case DATA_TYPE_BYTE:
3764*071ab5a1SMartin Matuska 			NVP(buf, size, len, buf_end, elem, byte, uchar_t, int,
3765*071ab5a1SMartin Matuska 			    "%u");
3766*071ab5a1SMartin Matuska 			break;
3767*071ab5a1SMartin Matuska 
3768*071ab5a1SMartin Matuska 		case DATA_TYPE_INT8:
3769*071ab5a1SMartin Matuska 			NVP(buf, size, len, buf_end, elem, int8, int8_t, int,
3770*071ab5a1SMartin Matuska 			    "%d");
3771*071ab5a1SMartin Matuska 			break;
3772*071ab5a1SMartin Matuska 
3773*071ab5a1SMartin Matuska 		case DATA_TYPE_UINT8:
3774*071ab5a1SMartin Matuska 			NVP(buf, size, len, buf_end, elem, uint8, uint8_t, int,
3775*071ab5a1SMartin Matuska 			    "%u");
3776*071ab5a1SMartin Matuska 			break;
3777*071ab5a1SMartin Matuska 
3778*071ab5a1SMartin Matuska 		case DATA_TYPE_INT16:
3779*071ab5a1SMartin Matuska 			NVP(buf, size, len, buf_end, elem, int16, int16_t, int,
3780*071ab5a1SMartin Matuska 			    "%d");
3781*071ab5a1SMartin Matuska 			break;
3782*071ab5a1SMartin Matuska 
3783*071ab5a1SMartin Matuska 		case DATA_TYPE_UINT16:
3784*071ab5a1SMartin Matuska 			NVP(buf, size, len, buf_end, elem, uint16, uint16_t,
3785*071ab5a1SMartin Matuska 			    int, "%u");
3786*071ab5a1SMartin Matuska 			break;
3787*071ab5a1SMartin Matuska 
3788*071ab5a1SMartin Matuska 		case DATA_TYPE_INT32:
3789*071ab5a1SMartin Matuska 			NVP(buf, size, len, buf_end, elem, int32, int32_t,
3790*071ab5a1SMartin Matuska 			    long, "%ld");
3791*071ab5a1SMartin Matuska 			break;
3792*071ab5a1SMartin Matuska 
3793*071ab5a1SMartin Matuska 		case DATA_TYPE_UINT32:
3794*071ab5a1SMartin Matuska 			NVP(buf, size, len, buf_end, elem, uint32, uint32_t,
3795*071ab5a1SMartin Matuska 			    ulong_t, "%lu");
3796*071ab5a1SMartin Matuska 			break;
3797*071ab5a1SMartin Matuska 
3798*071ab5a1SMartin Matuska 		case DATA_TYPE_INT64:
3799*071ab5a1SMartin Matuska 			NVP(buf, size, len, buf_end, elem, int64, int64_t,
3800*071ab5a1SMartin Matuska 			    longlong_t, "%lld");
3801*071ab5a1SMartin Matuska 			break;
3802*071ab5a1SMartin Matuska 
3803*071ab5a1SMartin Matuska 		case DATA_TYPE_UINT64:
3804*071ab5a1SMartin Matuska 			NVP(buf, size, len, buf_end, elem, uint64, uint64_t,
3805*071ab5a1SMartin Matuska 			    u_longlong_t, "%llu");
3806*071ab5a1SMartin Matuska 			break;
3807*071ab5a1SMartin Matuska 
3808*071ab5a1SMartin Matuska 		case DATA_TYPE_STRING:
3809*071ab5a1SMartin Matuska 			NVP(buf, size, len, buf_end, elem, string, const char *,
3810*071ab5a1SMartin Matuska 			    const char *, "'%s'");
3811*071ab5a1SMartin Matuska 			break;
3812*071ab5a1SMartin Matuska 
3813*071ab5a1SMartin Matuska 		case DATA_TYPE_BYTE_ARRAY:
3814*071ab5a1SMartin Matuska 			NVPA(buf, size, len, buf_end, elem, byte_array, uchar_t,
3815*071ab5a1SMartin Matuska 			    int, "%u");
3816*071ab5a1SMartin Matuska 			break;
3817*071ab5a1SMartin Matuska 
3818*071ab5a1SMartin Matuska 		case DATA_TYPE_INT8_ARRAY:
3819*071ab5a1SMartin Matuska 			NVPA(buf, size, len, buf_end, elem, int8_array, int8_t,
3820*071ab5a1SMartin Matuska 			    int, "%d");
3821*071ab5a1SMartin Matuska 			break;
3822*071ab5a1SMartin Matuska 
3823*071ab5a1SMartin Matuska 		case DATA_TYPE_UINT8_ARRAY:
3824*071ab5a1SMartin Matuska 			NVPA(buf, size, len, buf_end, elem, uint8_array,
3825*071ab5a1SMartin Matuska 			    uint8_t, int, "%u");
3826*071ab5a1SMartin Matuska 			break;
3827*071ab5a1SMartin Matuska 
3828*071ab5a1SMartin Matuska 		case DATA_TYPE_INT16_ARRAY:
3829*071ab5a1SMartin Matuska 			NVPA(buf, size, len, buf_end, elem, int16_array,
3830*071ab5a1SMartin Matuska 			    int16_t, int, "%d");
3831*071ab5a1SMartin Matuska 			break;
3832*071ab5a1SMartin Matuska 
3833*071ab5a1SMartin Matuska 		case DATA_TYPE_UINT16_ARRAY:
3834*071ab5a1SMartin Matuska 			NVPA(buf, size, len, buf_end, elem, uint16_array,
3835*071ab5a1SMartin Matuska 			    uint16_t, int, "%u");
3836*071ab5a1SMartin Matuska 			break;
3837*071ab5a1SMartin Matuska 
3838*071ab5a1SMartin Matuska 		case DATA_TYPE_INT32_ARRAY:
3839*071ab5a1SMartin Matuska 			NVPA(buf, size, len, buf_end, elem, int32_array,
3840*071ab5a1SMartin Matuska 			    int32_t, long, "%ld");
3841*071ab5a1SMartin Matuska 			break;
3842*071ab5a1SMartin Matuska 
3843*071ab5a1SMartin Matuska 		case DATA_TYPE_UINT32_ARRAY:
3844*071ab5a1SMartin Matuska 			NVPA(buf, size, len, buf_end, elem, uint32_array,
3845*071ab5a1SMartin Matuska 			    uint32_t, ulong_t, "%lu");
3846*071ab5a1SMartin Matuska 			break;
3847*071ab5a1SMartin Matuska 
3848*071ab5a1SMartin Matuska 		case DATA_TYPE_INT64_ARRAY:
3849*071ab5a1SMartin Matuska 			NVPA(buf, size, len, buf_end, elem, int64_array,
3850*071ab5a1SMartin Matuska 			    int64_t, longlong_t, "%lld");
3851*071ab5a1SMartin Matuska 			break;
3852*071ab5a1SMartin Matuska 
3853*071ab5a1SMartin Matuska 		case DATA_TYPE_UINT64_ARRAY:
3854*071ab5a1SMartin Matuska 			NVPA(buf, size, len, buf_end, elem, uint64_array,
3855*071ab5a1SMartin Matuska 			    uint64_t, u_longlong_t, "%llu");
3856*071ab5a1SMartin Matuska 			break;
3857*071ab5a1SMartin Matuska 
3858*071ab5a1SMartin Matuska 		case DATA_TYPE_STRING_ARRAY:
3859*071ab5a1SMartin Matuska 			NVPA(buf, size, len, buf_end, elem, string_array,
3860*071ab5a1SMartin Matuska 			    const char *, const char *, "'%s'");
3861*071ab5a1SMartin Matuska 			break;
3862*071ab5a1SMartin Matuska 
3863*071ab5a1SMartin Matuska 		case DATA_TYPE_NVLIST:
3864*071ab5a1SMartin Matuska 			(void) nvpair_value_nvlist(elem, &nvlist_value);
3865*071ab5a1SMartin Matuska 
3866*071ab5a1SMartin Matuska 			rc = snprintf(buf, size, "%*s%s:\n", indent, "",
3867*071ab5a1SMartin Matuska 			    nvpair_name(elem));
3868*071ab5a1SMartin Matuska 			if (rc < 0)
3869*071ab5a1SMartin Matuska 				return (rc);
3870*071ab5a1SMartin Matuska 			size = MAX((int)size - rc, 0);
3871*071ab5a1SMartin Matuska 			buf = size == 0 ? NULL : buf_end - size;
3872*071ab5a1SMartin Matuska 			len += rc;
3873*071ab5a1SMartin Matuska 
3874*071ab5a1SMartin Matuska 			rc = nvlist_snprintf(buf, size, nvlist_value,
3875*071ab5a1SMartin Matuska 			    indent + 4);
3876*071ab5a1SMartin Matuska 			if (rc < 0)
3877*071ab5a1SMartin Matuska 				return (rc);
3878*071ab5a1SMartin Matuska 			size = MAX((int)size - rc, 0);
3879*071ab5a1SMartin Matuska 			buf = size == 0 ? NULL : buf_end - size;
3880*071ab5a1SMartin Matuska 			len += rc;
3881*071ab5a1SMartin Matuska 			break;
3882*071ab5a1SMartin Matuska 
3883*071ab5a1SMartin Matuska 		case DATA_TYPE_NVLIST_ARRAY:
3884*071ab5a1SMartin Matuska 			(void) nvpair_value_nvlist_array(elem,
3885*071ab5a1SMartin Matuska 			    &nvlist_array_value, &count);
3886*071ab5a1SMartin Matuska 			for (i = 0; i < count; i++) {
3887*071ab5a1SMartin Matuska 				rc = snprintf(buf, size, "%*s%s[%u]:\n",
3888*071ab5a1SMartin Matuska 				    indent, "", nvpair_name(elem), i);
3889*071ab5a1SMartin Matuska 				if (rc < 0)
3890*071ab5a1SMartin Matuska 					return (rc);
3891*071ab5a1SMartin Matuska 				size = MAX((int)size - rc, 0);
3892*071ab5a1SMartin Matuska 				buf = size == 0 ? NULL : buf_end - size;
3893*071ab5a1SMartin Matuska 				len += rc;
3894*071ab5a1SMartin Matuska 
3895*071ab5a1SMartin Matuska 				rc = nvlist_snprintf(buf, size,
3896*071ab5a1SMartin Matuska 				    nvlist_array_value[i], indent + 4);
3897*071ab5a1SMartin Matuska 				if (rc < 0)
3898*071ab5a1SMartin Matuska 					return (rc);
3899*071ab5a1SMartin Matuska 				size = MAX((int)size - rc, 0);
3900*071ab5a1SMartin Matuska 				buf = size == 0 ? NULL : buf_end - size;
3901*071ab5a1SMartin Matuska 				len += rc;
3902*071ab5a1SMartin Matuska 			}
3903*071ab5a1SMartin Matuska 			break;
3904*071ab5a1SMartin Matuska 
3905*071ab5a1SMartin Matuska 		default:
3906*071ab5a1SMartin Matuska 			rc = snprintf(buf, size, "bad config type %d for %s\n",
3907*071ab5a1SMartin Matuska 			    nvpair_type(elem), nvpair_name(elem));
3908*071ab5a1SMartin Matuska 			if (rc < 0)
3909*071ab5a1SMartin Matuska 				return (rc);
3910*071ab5a1SMartin Matuska 			size = MAX((int)size - rc, 0);
3911*071ab5a1SMartin Matuska 			buf = size == 0 ? NULL : buf_end - size;
3912*071ab5a1SMartin Matuska 			len += rc;
3913*071ab5a1SMartin Matuska 		}
3914*071ab5a1SMartin Matuska 	}
3915*071ab5a1SMartin Matuska 	return (len);
3916*071ab5a1SMartin Matuska }
3917*071ab5a1SMartin Matuska 
3918eda14cbcSMatt Macy EXPORT_SYMBOL(nv_alloc_init);
3919eda14cbcSMatt Macy EXPORT_SYMBOL(nv_alloc_reset);
3920eda14cbcSMatt Macy EXPORT_SYMBOL(nv_alloc_fini);
3921eda14cbcSMatt Macy 
3922eda14cbcSMatt Macy /* list management */
3923eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_alloc);
3924eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_free);
3925eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_size);
3926eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_pack);
3927eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_unpack);
3928eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_dup);
3929eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_merge);
3930eda14cbcSMatt Macy 
3931eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_xalloc);
3932eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_xpack);
3933eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_xunpack);
3934eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_xdup);
3935eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_nv_alloc);
3936eda14cbcSMatt Macy 
3937eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_nvpair);
3938eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_boolean);
3939eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_boolean_value);
3940eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_byte);
3941eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_int8);
3942eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_uint8);
3943eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_int16);
3944eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_uint16);
3945eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_int32);
3946eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_uint32);
3947eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_int64);
3948eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_uint64);
3949eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_string);
3950eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_nvlist);
3951eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_boolean_array);
3952eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_byte_array);
3953eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_int8_array);
3954eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_uint8_array);
3955eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_int16_array);
3956eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_uint16_array);
3957eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_int32_array);
3958eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_uint32_array);
3959eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_int64_array);
3960eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_uint64_array);
3961eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_string_array);
3962eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_nvlist_array);
3963eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_next_nvpair);
3964eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_prev_nvpair);
3965eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_empty);
3966eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_add_hrtime);
3967eda14cbcSMatt Macy 
3968eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_remove);
3969eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_remove_nvpair);
3970eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_remove_all);
3971eda14cbcSMatt Macy 
3972eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_boolean);
3973eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_boolean_value);
3974eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_byte);
3975eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_int8);
3976eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_uint8);
3977eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_int16);
3978eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_uint16);
3979eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_int32);
3980eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_uint32);
3981eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_int64);
3982eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_uint64);
3983eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_string);
3984eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_nvlist);
3985eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_boolean_array);
3986eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_byte_array);
3987eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_int8_array);
3988eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_uint8_array);
3989eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_int16_array);
3990eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_uint16_array);
3991eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_int32_array);
3992eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_uint32_array);
3993eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_int64_array);
3994eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_uint64_array);
3995eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_string_array);
3996eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_nvlist_array);
3997eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_hrtime);
3998eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_pairs);
3999eda14cbcSMatt Macy 
4000eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_lookup_nvpair);
4001eda14cbcSMatt Macy EXPORT_SYMBOL(nvlist_exists);
4002eda14cbcSMatt Macy 
4003*071ab5a1SMartin Matuska EXPORT_SYMBOL(nvlist_snprintf);
4004*071ab5a1SMartin Matuska 
4005eda14cbcSMatt Macy /* processing nvpair */
4006eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_name);
4007eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_type);
4008eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_boolean_value);
4009eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_byte);
4010eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_int8);
4011eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_uint8);
4012eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_int16);
4013eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_uint16);
4014eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_int32);
4015eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_uint32);
4016eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_int64);
4017eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_uint64);
4018eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_string);
4019eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_nvlist);
4020eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_boolean_array);
4021eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_byte_array);
4022eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_int8_array);
4023eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_uint8_array);
4024eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_int16_array);
4025eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_uint16_array);
4026eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_int32_array);
4027eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_uint32_array);
4028eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_int64_array);
4029eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_uint64_array);
4030eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_string_array);
4031eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_nvlist_array);
4032eda14cbcSMatt Macy EXPORT_SYMBOL(nvpair_value_hrtime);
4033