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