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