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