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