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