]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - stand/libsa/zfs/nvlist.c
libsa: Make the nvlist implementation more self-contained
[FreeBSD/FreeBSD.git] / stand / libsa / zfs / nvlist.c
1 /*-
2  * Copyright 2020 Toomas Soome <tsoome@me.com>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 #include <sys/param.h>
30 #include <sys/endian.h>
31 #include <sys/stdint.h>
32 #ifdef _STANDALONE
33 #include <stand.h>
34 #else
35 #include <errno.h>
36 #include <stdbool.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #endif
41
42 #include "nvlist.h"
43
44 enum xdr_op {
45         XDR_OP_ENCODE = 1,
46         XDR_OP_DECODE = 2
47 };
48
49 typedef struct xdr {
50         enum xdr_op xdr_op;
51         int (*xdr_getint)(struct xdr *, int *);
52         int (*xdr_putint)(struct xdr *, int);
53         int (*xdr_getuint)(struct xdr *, unsigned *);
54         int (*xdr_putuint)(struct xdr *, unsigned);
55         const uint8_t *xdr_buf;
56         uint8_t *xdr_idx;
57         size_t xdr_buf_size;
58 } xdr_t;
59
60 static int nvlist_xdr_nvlist(xdr_t *, nvlist_t *);
61 static bool nvlist_size_xdr(xdr_t *, size_t *);
62 static bool nvlist_size_native(xdr_t *, size_t *);
63 static bool xdr_int(xdr_t *, int *);
64 static bool xdr_u_int(xdr_t *, unsigned *);
65
66 typedef bool (*xdrproc_t)(xdr_t *, void *);
67
68 /* Basic primitives for XDR translation operations, getint and putint. */
69 static int
70 _getint(struct xdr *xdr, int *ip)
71 {
72         *ip = be32dec(xdr->xdr_idx);
73         return (sizeof(int));
74 }
75
76 static int
77 _putint(struct xdr *xdr, int i)
78 {
79         int *ip = (int *)xdr->xdr_idx;
80
81         *ip = htobe32(i);
82         return (sizeof(int));
83 }
84
85 static int
86 _getuint(struct xdr *xdr, unsigned *ip)
87 {
88         *ip = be32dec(xdr->xdr_idx);
89         return (sizeof(unsigned));
90 }
91
92 static int
93 _putuint(struct xdr *xdr, unsigned i)
94 {
95         unsigned *up = (unsigned *)xdr->xdr_idx;
96
97         *up = htobe32(i);
98         return (sizeof(int));
99 }
100
101 static int
102 _getint_mem(struct xdr *xdr, int *ip)
103 {
104         *ip = *(int *)xdr->xdr_idx;
105         return (sizeof(int));
106 }
107
108 static int
109 _putint_mem(struct xdr *xdr, int i)
110 {
111         int *ip = (int *)xdr->xdr_idx;
112
113         *ip = i;
114         return (sizeof(int));
115 }
116
117 static int
118 _getuint_mem(struct xdr *xdr, unsigned *ip)
119 {
120         *ip = *(unsigned *)xdr->xdr_idx;
121         return (sizeof(unsigned));
122 }
123
124 static int
125 _putuint_mem(struct xdr *xdr, unsigned i)
126 {
127         unsigned *up = (unsigned *)xdr->xdr_idx;
128
129         *up = i;
130         return (sizeof(int));
131 }
132
133 /*
134  * XDR data translations.
135  */
136 static bool
137 xdr_short(xdr_t *xdr, short *ip)
138 {
139         int i;
140         bool rv;
141
142         i = *ip;
143         if ((rv = xdr_int(xdr, &i))) {
144                 if (xdr->xdr_op == XDR_OP_DECODE)
145                         *ip = i;
146         }
147         return (rv);
148 }
149
150 static bool
151 xdr_u_short(xdr_t *xdr, unsigned short *ip)
152 {
153         unsigned u;
154         bool rv;
155
156         u = *ip;
157         if ((rv = xdr_u_int(xdr, &u))) {
158                 if (xdr->xdr_op == XDR_OP_DECODE)
159                         *ip = u;
160         }
161         return (rv);
162 }
163
164 /*
165  * translate xdr->xdr_idx, increment it by size of int.
166  */
167 static bool
168 xdr_int(xdr_t *xdr, int *ip)
169 {
170         bool rv = false;
171         int *i = (int *)xdr->xdr_idx;
172
173         if (xdr->xdr_idx + sizeof(int) > xdr->xdr_buf + xdr->xdr_buf_size)
174                 return (rv);
175
176         switch (xdr->xdr_op) {
177         case XDR_OP_ENCODE:
178                 /* Encode value *ip, store to buf */
179                 xdr->xdr_idx += xdr->xdr_putint(xdr, *ip);
180                 rv = true;
181                 break;
182
183         case XDR_OP_DECODE:
184                 /* Decode buf, return value to *ip */
185                 xdr->xdr_idx += xdr->xdr_getint(xdr, i);
186                 *ip = *i;
187                 rv = true;
188                 break;
189         }
190         return (rv);
191 }
192
193 /*
194  * translate xdr->xdr_idx, increment it by size of unsigned int.
195  */
196 static bool
197 xdr_u_int(xdr_t *xdr, unsigned *ip)
198 {
199         bool rv = false;
200         unsigned *u = (unsigned *)xdr->xdr_idx;
201
202         if (xdr->xdr_idx + sizeof(unsigned) > xdr->xdr_buf + xdr->xdr_buf_size)
203                 return (rv);
204
205         switch (xdr->xdr_op) {
206         case XDR_OP_ENCODE:
207                 /* Encode value *ip, store to buf */
208                 xdr->xdr_idx += xdr->xdr_putuint(xdr, *ip);
209                 rv = true;
210                 break;
211
212         case XDR_OP_DECODE:
213                 /* Decode buf, return value to *ip */
214                 xdr->xdr_idx += xdr->xdr_getuint(xdr, u);
215                 *ip = *u;
216                 rv = true;
217                 break;
218         }
219         return (rv);
220 }
221
222 static bool
223 xdr_int64(xdr_t *xdr, int64_t *lp)
224 {
225         bool rv = false;
226
227         if (xdr->xdr_idx + sizeof(int64_t) > xdr->xdr_buf + xdr->xdr_buf_size)
228                 return (rv);
229
230         switch (xdr->xdr_op) {
231         case XDR_OP_ENCODE:
232                 /* Encode value *lp, store to buf */
233                 if (xdr->xdr_putint == _putint)
234                         *(int64_t *)xdr->xdr_idx = htobe64(*lp);
235                 else
236                         *(int64_t *)xdr->xdr_idx = *lp;
237                 xdr->xdr_idx += sizeof(int64_t);
238                 rv = true;
239                 break;
240
241         case XDR_OP_DECODE:
242                 /* Decode buf, return value to *ip */
243                 if (xdr->xdr_getint == _getint)
244                         *lp = be64toh(*(int64_t *)xdr->xdr_idx);
245                 else
246                         *lp = *(int64_t *)xdr->xdr_idx;
247                 xdr->xdr_idx += sizeof(int64_t);
248                 rv = true;
249         }
250         return (rv);
251 }
252
253 static bool
254 xdr_uint64(xdr_t *xdr, uint64_t *lp)
255 {
256         bool rv = false;
257
258         if (xdr->xdr_idx + sizeof(uint64_t) > xdr->xdr_buf + xdr->xdr_buf_size)
259                 return (rv);
260
261         switch (xdr->xdr_op) {
262         case XDR_OP_ENCODE:
263                 /* Encode value *ip, store to buf */
264                 if (xdr->xdr_putint == _putint)
265                         *(uint64_t *)xdr->xdr_idx = htobe64(*lp);
266                 else
267                         *(uint64_t *)xdr->xdr_idx = *lp;
268                 xdr->xdr_idx += sizeof(uint64_t);
269                 rv = true;
270                 break;
271
272         case XDR_OP_DECODE:
273                 /* Decode buf, return value to *ip */
274                 if (xdr->xdr_getuint == _getuint)
275                         *lp = be64toh(*(uint64_t *)xdr->xdr_idx);
276                 else
277                         *lp = *(uint64_t *)xdr->xdr_idx;
278                 xdr->xdr_idx += sizeof(uint64_t);
279                 rv = true;
280         }
281         return (rv);
282 }
283
284 static bool
285 xdr_char(xdr_t *xdr, char *cp)
286 {
287         int i;
288         bool rv = false;
289
290         i = *cp;
291         if ((rv = xdr_int(xdr, &i))) {
292                 if (xdr->xdr_op == XDR_OP_DECODE)
293                         *cp = i;
294         }
295         return (rv);
296 }
297
298 static bool
299 xdr_string(xdr_t *xdr, nv_string_t *s)
300 {
301         int size = 0;
302         bool rv = false;
303
304         switch (xdr->xdr_op) {
305         case XDR_OP_ENCODE:
306                 size = s->nv_size;
307                 if (xdr->xdr_idx + sizeof(unsigned) + NV_ALIGN4(size) >
308                     xdr->xdr_buf + xdr->xdr_buf_size)
309                         break;
310                 xdr->xdr_idx += xdr->xdr_putuint(xdr, s->nv_size);
311                 xdr->xdr_idx += NV_ALIGN4(size);
312                 rv = true;
313                 break;
314
315         case XDR_OP_DECODE:
316                 if (xdr->xdr_idx + sizeof(unsigned) >
317                     xdr->xdr_buf + xdr->xdr_buf_size)
318                         break;
319                 size = xdr->xdr_getuint(xdr, &s->nv_size);
320                 size = NV_ALIGN4(size + s->nv_size);
321                 if (xdr->xdr_idx + size > xdr->xdr_buf + xdr->xdr_buf_size)
322                         break;
323                 xdr->xdr_idx += size;
324                 rv = true;
325                 break;
326         }
327         return (rv);
328 }
329
330 static bool
331 xdr_array(xdr_t *xdr, const unsigned nelem, const xdrproc_t elproc)
332 {
333         bool rv = true;
334         unsigned c = nelem;
335
336         if (!xdr_u_int(xdr, &c))
337                 return (false);
338
339         for (unsigned i = 0; i < nelem; i++) {
340                 if (!elproc(xdr, xdr->xdr_idx))
341                         return (false);
342         }
343         return (rv);
344 }
345
346 /*
347  * nvlist management functions.
348  */
349 void
350 nvlist_destroy(nvlist_t *nvl)
351 {
352         if (nvl != NULL) {
353                 /* Free data if it was allocated by us. */
354                 if (nvl->nv_asize > 0)
355                         free(nvl->nv_data);
356         }
357         free(nvl);
358 }
359
360 char *
361 nvstring_get(nv_string_t *nvs)
362 {
363         char *s;
364
365         s = malloc(nvs->nv_size + 1);
366         if (s != NULL) {
367                 bcopy(nvs->nv_data, s, nvs->nv_size);
368                 s[nvs->nv_size] = '\0';
369         }
370         return (s);
371 }
372
373 /*
374  * Create empty nvlist.
375  * The nvlist is terminated by 2x zeros (8 bytes).
376  */
377 nvlist_t *
378 nvlist_create(int flag)
379 {
380         nvlist_t *nvl;
381         nvs_data_t *nvs;
382
383         nvl = calloc(1, sizeof(*nvl));
384         if (nvl == NULL)
385                 return (nvl);
386
387         nvl->nv_header.nvh_encoding = NV_ENCODE_XDR;
388         nvl->nv_header.nvh_endian = _BYTE_ORDER == _LITTLE_ENDIAN;
389
390         nvl->nv_asize = nvl->nv_size = sizeof(*nvs);
391         nvs = calloc(1, nvl->nv_asize);
392         if (nvs == NULL) {
393                 free(nvl);
394                 return (NULL);
395         }
396         /* data in nvlist is byte stream */
397         nvl->nv_data = (uint8_t *)nvs;
398
399         nvs->nvl_version = NV_VERSION;
400         nvs->nvl_nvflag = flag;
401         return (nvl);
402 }
403
404 static bool
405 nvlist_xdr_nvp(xdr_t *xdr, nvlist_t *nvl)
406 {
407         nv_string_t *nv_string;
408         nv_pair_data_t *nvp_data;
409         nvlist_t nvlist;
410         unsigned type, nelem;
411         xdr_t nv_xdr;
412
413         nv_string = (nv_string_t *)xdr->xdr_idx;
414         if (!xdr_string(xdr, nv_string)) {
415                 return (false);
416         }
417         nvp_data = (nv_pair_data_t *)xdr->xdr_idx;
418
419         type = nvp_data->nv_type;
420         nelem = nvp_data->nv_nelem;
421         if (!xdr_u_int(xdr, &type) || !xdr_u_int(xdr, &nelem))
422                 return (false);
423
424         switch (type) {
425         case DATA_TYPE_NVLIST:
426         case DATA_TYPE_NVLIST_ARRAY:
427                 bzero(&nvlist, sizeof(nvlist));
428                 nvlist.nv_data = xdr->xdr_idx;
429                 nvlist.nv_idx = nvlist.nv_data;
430
431                 /* Set up xdr for this nvlist. */
432                 nv_xdr = *xdr;
433                 nv_xdr.xdr_buf = nvlist.nv_data;
434                 nv_xdr.xdr_idx = nvlist.nv_data;
435                 nv_xdr.xdr_buf_size =
436                     nvl->nv_data + nvl->nv_size - nvlist.nv_data;
437
438                 for (unsigned i = 0; i < nelem; i++) {
439                         if (xdr->xdr_op == XDR_OP_ENCODE) {
440                                 if (!nvlist_size_native(&nv_xdr,
441                                     &nvlist.nv_size))
442                                         return (false);
443                         } else {
444                                 if (!nvlist_size_xdr(&nv_xdr,
445                                     &nvlist.nv_size))
446                                         return (false);
447                         }
448                         if (nvlist_xdr_nvlist(xdr, &nvlist) != 0)
449                                 return (false);
450
451                         nvlist.nv_data = nv_xdr.xdr_idx;
452                         nvlist.nv_idx = nv_xdr.xdr_idx;
453
454                         nv_xdr.xdr_buf = nv_xdr.xdr_idx;
455                         nv_xdr.xdr_buf_size =
456                             nvl->nv_data + nvl->nv_size - nvlist.nv_data;
457                 }
458                 break;
459
460         case DATA_TYPE_BOOLEAN:
461                 /* BOOLEAN does not take value space */
462                 break;
463         case DATA_TYPE_BYTE:
464         case DATA_TYPE_INT8:
465         case DATA_TYPE_UINT8:
466                 if (!xdr_char(xdr, (char *)&nvp_data->nv_data[0]))
467                         return (false);
468                 break;
469
470         case DATA_TYPE_INT16:
471                 if (!xdr_short(xdr, (short *)&nvp_data->nv_data[0]))
472                         return (false);
473                 break;
474
475         case DATA_TYPE_UINT16:
476                 if (!xdr_u_short(xdr, (unsigned short *)&nvp_data->nv_data[0]))
477                         return (false);
478                 break;
479
480         case DATA_TYPE_BOOLEAN_VALUE:
481         case DATA_TYPE_INT32:
482                 if (!xdr_int(xdr, (int *)&nvp_data->nv_data[0]))
483                         return (false);
484                 break;
485
486         case DATA_TYPE_UINT32:
487                 if (!xdr_u_int(xdr, (unsigned *)&nvp_data->nv_data[0]))
488                         return (false);
489                 break;
490
491         case DATA_TYPE_HRTIME:
492         case DATA_TYPE_INT64:
493                 if (!xdr_int64(xdr, (int64_t *)&nvp_data->nv_data[0]))
494                         return (false);
495                 break;
496
497         case DATA_TYPE_UINT64:
498                 if (!xdr_uint64(xdr, (uint64_t *)&nvp_data->nv_data[0]))
499                         return (false);
500                 break;
501
502         case DATA_TYPE_BYTE_ARRAY:
503         case DATA_TYPE_STRING:
504                 nv_string = (nv_string_t *)&nvp_data->nv_data[0];
505                 if (!xdr_string(xdr, nv_string))
506                         return (false);
507                 break;
508
509         case DATA_TYPE_STRING_ARRAY:
510                 nv_string = (nv_string_t *)&nvp_data->nv_data[0];
511                 for (unsigned i = 0; i < nelem; i++) {
512                         if (!xdr_string(xdr, nv_string))
513                                 return (false);
514                         nv_string = (nv_string_t *)xdr->xdr_idx;
515                 }
516                 break;
517
518         case DATA_TYPE_INT8_ARRAY:
519         case DATA_TYPE_UINT8_ARRAY:
520         case DATA_TYPE_INT16_ARRAY:
521         case DATA_TYPE_UINT16_ARRAY:
522         case DATA_TYPE_BOOLEAN_ARRAY:
523         case DATA_TYPE_INT32_ARRAY:
524         case DATA_TYPE_UINT32_ARRAY:
525                 if (!xdr_array(xdr, nelem, (xdrproc_t)xdr_u_int))
526                         return (false);
527                 break;
528
529         case DATA_TYPE_INT64_ARRAY:
530         case DATA_TYPE_UINT64_ARRAY:
531                 if (!xdr_array(xdr, nelem, (xdrproc_t)xdr_uint64))
532                         return (false);
533                 break;
534         }
535         return (true);
536 }
537
538 static int
539 nvlist_xdr_nvlist(xdr_t *xdr, nvlist_t *nvl)
540 {
541         nvp_header_t *nvph;
542         nvs_data_t *nvs;
543         unsigned encoded_size, decoded_size;
544         int rv;
545
546         nvs = (nvs_data_t *)xdr->xdr_idx;
547         nvph = &nvs->nvl_pair;
548
549         if (!xdr_u_int(xdr, &nvs->nvl_version))
550                 return (EINVAL);
551         if (!xdr_u_int(xdr, &nvs->nvl_nvflag))
552                 return (EINVAL);
553
554         encoded_size = nvph->encoded_size;
555         decoded_size = nvph->decoded_size;
556
557         if (xdr->xdr_op == XDR_OP_ENCODE) {
558                 if (!xdr_u_int(xdr, &nvph->encoded_size))
559                         return (EINVAL);
560                 if (!xdr_u_int(xdr, &nvph->decoded_size))
561                         return (EINVAL);
562         } else {
563                 xdr->xdr_idx += 2 * sizeof(unsigned);
564         }
565
566         rv = 0;
567         while (encoded_size && decoded_size) {
568                 if (!nvlist_xdr_nvp(xdr, nvl))
569                         return (EINVAL);
570
571                 nvph = (nvp_header_t *)(xdr->xdr_idx);
572                 encoded_size = nvph->encoded_size;
573                 decoded_size = nvph->decoded_size;
574                 if (xdr->xdr_op == XDR_OP_ENCODE) {
575                         if (!xdr_u_int(xdr, &nvph->encoded_size))
576                                 return (EINVAL);
577                         if (!xdr_u_int(xdr, &nvph->decoded_size))
578                                 return (EINVAL);
579                 } else {
580                         xdr->xdr_idx += 2 * sizeof(unsigned);
581                 }
582         }
583         return (rv);
584 }
585
586 /*
587  * Calculate nvlist size, translating encoded_size and decoded_size.
588  */
589 static bool
590 nvlist_size_xdr(xdr_t *xdr, size_t *size)
591 {
592         uint8_t *pair;
593         unsigned encoded_size, decoded_size;
594
595         xdr->xdr_idx += 2 * sizeof(unsigned);
596
597         pair = xdr->xdr_idx;
598         if (!xdr_u_int(xdr, &encoded_size) || !xdr_u_int(xdr, &decoded_size))
599                 return (false);
600
601         while (encoded_size && decoded_size) {
602                 xdr->xdr_idx = pair + encoded_size;
603                 pair = xdr->xdr_idx;
604                 if (!xdr_u_int(xdr, &encoded_size) ||
605                     !xdr_u_int(xdr, &decoded_size))
606                         return (false);
607         }
608         *size = xdr->xdr_idx - xdr->xdr_buf;
609
610         return (true);
611 }
612
613 nvp_header_t *
614 nvlist_next_nvpair(nvlist_t *nvl, nvp_header_t *nvh)
615 {
616         uint8_t *pair;
617         unsigned encoded_size, decoded_size;
618         xdr_t xdr;
619
620         if (nvl == NULL)
621                 return (NULL);
622
623         xdr.xdr_buf = nvl->nv_data;
624         xdr.xdr_idx = nvl->nv_data;
625         xdr.xdr_buf_size = nvl->nv_size;
626
627         xdr.xdr_idx += 2 * sizeof(unsigned);
628
629         /* Skip tp current pair */
630         if (nvh != NULL) {
631                 xdr.xdr_idx = (uint8_t *)nvh;
632         }
633
634         pair = xdr.xdr_idx;
635         if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
636                 return (NULL);
637
638         encoded_size = *(unsigned *)xdr.xdr_idx;
639         xdr.xdr_idx += sizeof(unsigned);
640         if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
641                 return (NULL);
642
643         decoded_size = *(unsigned *)xdr.xdr_idx;
644         xdr.xdr_idx += sizeof(unsigned);
645         if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
646                 return (NULL);
647
648         while (encoded_size && decoded_size) {
649                 if (nvh == NULL)
650                         return ((nvp_header_t *)pair);
651
652                 xdr.xdr_idx = pair + encoded_size;
653                 nvh = (nvp_header_t *)xdr.xdr_idx;
654
655                 if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
656                         return (NULL);
657
658                 encoded_size = *(unsigned *)xdr.xdr_idx;
659                 xdr.xdr_idx += sizeof(unsigned);
660                 if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
661                         return (NULL);
662                 decoded_size = *(unsigned *)xdr.xdr_idx;
663                 xdr.xdr_idx += sizeof(unsigned);
664                 if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
665                         return (NULL);
666
667                 if (encoded_size != 0 && decoded_size != 0) {
668                         return (nvh);
669                 }
670         }
671         return (NULL);
672 }
673
674 /*
675  * Calculate nvlist size by walking in memory data.
676  */
677 static bool
678 nvlist_size_native(xdr_t *xdr, size_t *size)
679 {
680         uint8_t *pair;
681         unsigned encoded_size, decoded_size;
682
683         xdr->xdr_idx += 2 * sizeof(unsigned);
684
685         pair = xdr->xdr_idx;
686         if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size)
687                 return (false);
688
689         encoded_size = *(unsigned *)xdr->xdr_idx;
690         xdr->xdr_idx += sizeof(unsigned);
691         if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size)
692                 return (false);
693         decoded_size = *(unsigned *)xdr->xdr_idx;
694         xdr->xdr_idx += sizeof(unsigned);
695         while (encoded_size && decoded_size) {
696                 xdr->xdr_idx = pair + encoded_size;
697                 pair = xdr->xdr_idx;
698                 if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size)
699                         return (false);
700                 encoded_size = *(unsigned *)xdr->xdr_idx;
701                 xdr->xdr_idx += sizeof(unsigned);
702                 if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size)
703                         return (false);
704                 decoded_size = *(unsigned *)xdr->xdr_idx;
705                 xdr->xdr_idx += sizeof(unsigned);
706         }
707         *size = xdr->xdr_idx - xdr->xdr_buf;
708
709         return (true);
710 }
711
712 /*
713  * Export nvlist to byte stream format.
714  */
715 int
716 nvlist_export(nvlist_t *nvl)
717 {
718         int rv;
719         xdr_t xdr = {
720                 .xdr_op = XDR_OP_ENCODE,
721                 .xdr_putint = _putint,
722                 .xdr_putuint = _putuint,
723                 .xdr_buf = nvl->nv_data,
724                 .xdr_idx = nvl->nv_data,
725                 .xdr_buf_size = nvl->nv_size
726         };
727
728         if (nvl->nv_header.nvh_encoding != NV_ENCODE_XDR)
729                 return (ENOTSUP);
730
731         nvl->nv_idx = nvl->nv_data;
732         rv = nvlist_xdr_nvlist(&xdr, nvl);
733
734         return (rv);
735 }
736
737 /*
738  * Import nvlist from byte stream.
739  * Determine the stream size and allocate private copy.
740  * Then translate the data.
741  */
742 nvlist_t *
743 nvlist_import(const char *stream, size_t size)
744 {
745         nvlist_t *nvl;
746         xdr_t xdr = {
747                 .xdr_op = XDR_OP_DECODE,
748                 .xdr_getint = _getint,
749                 .xdr_getuint = _getuint
750         };
751
752         /* Check the nvlist head. */
753         if (stream[0] != NV_ENCODE_XDR ||
754             (stream[1] != '\0' && stream[1] != '\1') ||
755             stream[2] != '\0' || stream[3] != '\0' ||
756             be32toh(*(uint32_t *)(stream + 4)) != NV_VERSION ||
757             be32toh(*(uint32_t *)(stream + 8)) != NV_UNIQUE_NAME)
758                 return (NULL);
759
760         nvl = malloc(sizeof(*nvl));
761         if (nvl == NULL)
762                 return (nvl);
763
764         nvl->nv_header.nvh_encoding = stream[0];
765         nvl->nv_header.nvh_endian = stream[1];
766         nvl->nv_header.nvh_reserved1 = stream[2];
767         nvl->nv_header.nvh_reserved2 = stream[3];
768
769         xdr.xdr_buf = xdr.xdr_idx = (uint8_t *)stream + 4;
770         xdr.xdr_buf_size = size - 4;
771
772         if (!nvlist_size_xdr(&xdr, &nvl->nv_asize)) {
773                 free(nvl);
774                 return (NULL);
775         }
776         nvl->nv_size = nvl->nv_asize;
777         nvl->nv_data = malloc(nvl->nv_asize);
778         if (nvl->nv_data == NULL) {
779                 free(nvl);
780                 return (NULL);
781         }
782         nvl->nv_idx = nvl->nv_data;
783         bcopy(stream + 4, nvl->nv_data, nvl->nv_asize);
784
785         xdr.xdr_buf = xdr.xdr_idx = nvl->nv_data;
786         xdr.xdr_buf_size = nvl->nv_asize;
787
788         if (nvlist_xdr_nvlist(&xdr, nvl) != 0) {
789                 free(nvl->nv_data);
790                 free(nvl);
791                 nvl = NULL;
792         }
793
794         return (nvl);
795 }
796
797 /*
798  * remove pair from this nvlist.
799  */
800 int
801 nvlist_remove(nvlist_t *nvl, const char *name, data_type_t type)
802 {
803         uint8_t *head, *tail;
804         nvs_data_t *data;
805         nvp_header_t *nvp;
806         nv_string_t *nvp_name;
807         nv_pair_data_t *nvp_data;
808         size_t size;
809         xdr_t xdr;
810
811         if (nvl == NULL || nvl->nv_data == NULL || name == NULL)
812                 return (EINVAL);
813
814         /* Make sure the nvlist size is set correct */
815         xdr.xdr_idx = nvl->nv_data;
816         xdr.xdr_buf = xdr.xdr_idx;
817         xdr.xdr_buf_size = nvl->nv_size;
818         if (!nvlist_size_native(&xdr, &nvl->nv_size))
819                 return (EINVAL);
820
821         data = (nvs_data_t *)nvl->nv_data;
822         nvp = &data->nvl_pair;  /* first pair in nvlist */
823         head = (uint8_t *)nvp;
824
825         while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
826                 nvp_name = (nv_string_t *)(nvp + 1);
827
828                 nvp_data = (nv_pair_data_t *)(&nvp_name->nv_data[0] +
829                     NV_ALIGN4(nvp_name->nv_size));
830
831                 if (strlen(name) == nvp_name->nv_size &&
832                     memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0 &&
833                     (nvp_data->nv_type == type || type == DATA_TYPE_UNKNOWN)) {
834                         /*
835                          * set tail to point to next nvpair and size
836                          * is the length of the tail.
837                          */
838                         tail = head + nvp->encoded_size;
839                         size = nvl->nv_size - (tail - nvl->nv_data);
840
841                         /* adjust the size of the nvlist. */
842                         nvl->nv_size -= nvp->encoded_size;
843                         bcopy(tail, head, size);
844                         return (0);
845                 }
846                 /* Not our pair, skip to next. */
847                 head = head + nvp->encoded_size;
848                 nvp = (nvp_header_t *)head;
849         }
850         return (ENOENT);
851 }
852
853 static int
854 clone_nvlist(const nvlist_t *nvl, const uint8_t *ptr, unsigned size,
855     nvlist_t **nvlist)
856 {
857         nvlist_t *nv;
858
859         nv = calloc(1, sizeof(*nv));
860         if (nv == NULL)
861                 return (ENOMEM);
862
863         nv->nv_header = nvl->nv_header;
864         nv->nv_asize = size;
865         nv->nv_size = size;
866         nv->nv_data = malloc(nv->nv_asize);
867         if (nv->nv_data == NULL) {
868                 free(nv);
869                 return (ENOMEM);
870         }
871
872         bcopy(ptr, nv->nv_data, nv->nv_asize);
873         *nvlist = nv;
874         return (0);
875 }
876
877 /*
878  * Return the next nvlist in an nvlist array.
879  */
880 static uint8_t *
881 nvlist_next(const uint8_t *ptr)
882 {
883         nvs_data_t *data;
884         nvp_header_t *nvp;
885
886         data = (nvs_data_t *)ptr;
887         nvp = &data->nvl_pair;  /* first pair in nvlist */
888
889         while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
890                 nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size);
891         }
892         return ((uint8_t *)nvp + sizeof(*nvp));
893 }
894
895 /*
896  * Note: nvlist and nvlist array must be freed by caller.
897  */
898 int
899 nvlist_find(const nvlist_t *nvl, const char *name, data_type_t type,
900     int *elementsp, void *valuep, int *sizep)
901 {
902         nvs_data_t *data;
903         nvp_header_t *nvp;
904         nv_string_t *nvp_name;
905         nv_pair_data_t *nvp_data;
906         nvlist_t **nvlist, *nv;
907         uint8_t *ptr;
908         int rv;
909
910         if (nvl == NULL || nvl->nv_data == NULL || name == NULL)
911                 return (EINVAL);
912
913         data = (nvs_data_t *)nvl->nv_data;
914         nvp = &data->nvl_pair;  /* first pair in nvlist */
915
916         while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
917                 nvp_name = (nv_string_t *)((uint8_t *)nvp + sizeof(*nvp));
918                 if (nvl->nv_data + nvl->nv_size <
919                     nvp_name->nv_data + nvp_name->nv_size)
920                         return (EIO);
921
922                 nvp_data = (nv_pair_data_t *)
923                     NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] +
924                     nvp_name->nv_size);
925
926                 if (strlen(name) == nvp_name->nv_size &&
927                     memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0 &&
928                     (nvp_data->nv_type == type || type == DATA_TYPE_UNKNOWN)) {
929                         if (elementsp != NULL)
930                                 *elementsp = nvp_data->nv_nelem;
931                         switch (nvp_data->nv_type) {
932                         case DATA_TYPE_UINT64:
933                                 bcopy(nvp_data->nv_data, valuep,
934                                     sizeof(uint64_t));
935                                 return (0);
936                         case DATA_TYPE_STRING:
937                                 nvp_name = (nv_string_t *)nvp_data->nv_data;
938                                 if (sizep != NULL) {
939                                         *sizep = nvp_name->nv_size;
940                                 }
941                                 *(const uint8_t **)valuep =
942                                     &nvp_name->nv_data[0];
943                                 return (0);
944                         case DATA_TYPE_NVLIST:
945                                 ptr = &nvp_data->nv_data[0];
946                                 rv = clone_nvlist(nvl, ptr,
947                                     nvlist_next(ptr) - ptr, &nv);
948                                 if (rv == 0) {
949                                         *(nvlist_t **)valuep = nv;
950                                 }
951                                 return (rv);
952
953                         case DATA_TYPE_NVLIST_ARRAY:
954                                 nvlist = calloc(nvp_data->nv_nelem,
955                                     sizeof(nvlist_t *));
956                                 if (nvlist == NULL)
957                                         return (ENOMEM);
958                                 ptr = &nvp_data->nv_data[0];
959                                 rv = 0;
960                                 for (unsigned i = 0; i < nvp_data->nv_nelem;
961                                     i++) {
962                                         rv = clone_nvlist(nvl, ptr,
963                                             nvlist_next(ptr) - ptr, &nvlist[i]);
964                                         if (rv != 0)
965                                                 goto error;
966                                         ptr = nvlist_next(ptr);
967                                 }
968                                 *(nvlist_t ***)valuep = nvlist;
969                                 return (rv);
970                         }
971                         return (EIO);
972                 }
973                 /* Not our pair, skip to next. */
974                 nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size);
975                 if (nvl->nv_data + nvl->nv_size < (uint8_t *)nvp)
976                         return (EIO);
977         }
978         return (ENOENT);
979 error:
980         for (unsigned i = 0; i < nvp_data->nv_nelem; i++) {
981                 free(nvlist[i]->nv_data);
982                 free(nvlist[i]);
983         }
984         free(nvlist);
985         return (rv);
986 }
987
988 static int
989 get_value_size(data_type_t type, const void *data, uint32_t nelem)
990 {
991         uint64_t value_sz = 0;
992
993         switch (type) {
994         case DATA_TYPE_BOOLEAN:
995                 value_sz = 0;
996                 break;
997         case DATA_TYPE_BOOLEAN_VALUE:
998         case DATA_TYPE_BYTE:
999         case DATA_TYPE_INT8:
1000         case DATA_TYPE_UINT8:
1001         case DATA_TYPE_INT16:
1002         case DATA_TYPE_UINT16:
1003         case DATA_TYPE_INT32:
1004         case DATA_TYPE_UINT32:
1005                 /* Our smallest data unit is 32-bit */
1006                 value_sz = sizeof(uint32_t);
1007                 break;
1008         case DATA_TYPE_HRTIME:
1009         case DATA_TYPE_INT64:
1010                 value_sz = sizeof(int64_t);
1011                 break;
1012         case DATA_TYPE_UINT64:
1013                 value_sz = sizeof(uint64_t);
1014                 break;
1015         case DATA_TYPE_STRING:
1016                 if (data == NULL)
1017                         value_sz = 0;
1018                 else
1019                         value_sz = strlen(data) + 1;
1020                 break;
1021         case DATA_TYPE_BYTE_ARRAY:
1022                 value_sz = nelem * sizeof(uint8_t);
1023                 break;
1024         case DATA_TYPE_BOOLEAN_ARRAY:
1025         case DATA_TYPE_INT8_ARRAY:
1026         case DATA_TYPE_UINT8_ARRAY:
1027         case DATA_TYPE_INT16_ARRAY:
1028         case DATA_TYPE_UINT16_ARRAY:
1029         case DATA_TYPE_INT32_ARRAY:
1030         case DATA_TYPE_UINT32_ARRAY:
1031                 value_sz = (uint64_t)nelem * sizeof(uint32_t);
1032                 break;
1033         case DATA_TYPE_INT64_ARRAY:
1034                 value_sz = (uint64_t)nelem * sizeof(int64_t);
1035                 break;
1036         case DATA_TYPE_UINT64_ARRAY:
1037                 value_sz = (uint64_t)nelem * sizeof(uint64_t);
1038                 break;
1039         case DATA_TYPE_STRING_ARRAY:
1040                 value_sz = (uint64_t)nelem * sizeof(uint64_t);
1041
1042                 if (data != NULL) {
1043                         char *const *strs = data;
1044                         uint32_t i;
1045
1046                         for (i = 0; i < nelem; i++) {
1047                                 if (strs[i] == NULL)
1048                                         return (-1);
1049                                 value_sz += strlen(strs[i]) + 1;
1050                         }
1051                 }
1052                 break;
1053         case DATA_TYPE_NVLIST:
1054                 /*
1055                  * The decoded size of nvlist is constant.
1056                  */
1057                 value_sz = NV_ALIGN(6 * 4); /* sizeof nvlist_t */
1058                 break;
1059         case DATA_TYPE_NVLIST_ARRAY:
1060                 value_sz = (uint64_t)nelem * sizeof(uint64_t) +
1061                     (uint64_t)nelem * NV_ALIGN(6 * 4); /* sizeof nvlist_t */
1062                 break;
1063         default:
1064                 return (-1);
1065         }
1066
1067         return (value_sz > INT32_MAX ? -1 : (int)value_sz);
1068 }
1069
1070 static int
1071 get_nvp_data_size(data_type_t type, const void *data, uint32_t nelem)
1072 {
1073         uint64_t value_sz = 0;
1074         xdr_t xdr;
1075         size_t size;
1076
1077         switch (type) {
1078         case DATA_TYPE_BOOLEAN:
1079                 value_sz = 0;
1080                 break;
1081         case DATA_TYPE_BOOLEAN_VALUE:
1082         case DATA_TYPE_BYTE:
1083         case DATA_TYPE_INT8:
1084         case DATA_TYPE_UINT8:
1085         case DATA_TYPE_INT16:
1086         case DATA_TYPE_UINT16:
1087         case DATA_TYPE_INT32:
1088         case DATA_TYPE_UINT32:
1089                 /* Our smallest data unit is 32-bit */
1090                 value_sz = sizeof(uint32_t);
1091                 break;
1092         case DATA_TYPE_HRTIME:
1093         case DATA_TYPE_INT64:
1094         case DATA_TYPE_UINT64:
1095                 value_sz = sizeof(uint64_t);
1096                 break;
1097         case DATA_TYPE_STRING:
1098                 value_sz = 4 + NV_ALIGN4(strlen(data));
1099                 break;
1100         case DATA_TYPE_BYTE_ARRAY:
1101                 value_sz = NV_ALIGN4(nelem);
1102                 break;
1103         case DATA_TYPE_BOOLEAN_ARRAY:
1104         case DATA_TYPE_INT8_ARRAY:
1105         case DATA_TYPE_UINT8_ARRAY:
1106         case DATA_TYPE_INT16_ARRAY:
1107         case DATA_TYPE_UINT16_ARRAY:
1108         case DATA_TYPE_INT32_ARRAY:
1109         case DATA_TYPE_UINT32_ARRAY:
1110                 value_sz = 4 + (uint64_t)nelem * sizeof(uint32_t);
1111                 break;
1112         case DATA_TYPE_INT64_ARRAY:
1113         case DATA_TYPE_UINT64_ARRAY:
1114                 value_sz = 4 + (uint64_t)nelem * sizeof(uint64_t);
1115                 break;
1116         case DATA_TYPE_STRING_ARRAY:
1117                 if (data != NULL) {
1118                         char *const *strs = data;
1119                         uint32_t i;
1120
1121                         for (i = 0; i < nelem; i++) {
1122                                 value_sz += 4 + NV_ALIGN4(strlen(strs[i]));
1123                         }
1124                 }
1125                 break;
1126         case DATA_TYPE_NVLIST:
1127                 xdr.xdr_idx = ((nvlist_t *)data)->nv_data;
1128                 xdr.xdr_buf = xdr.xdr_idx;
1129                 xdr.xdr_buf_size = ((nvlist_t *)data)->nv_size;
1130
1131                 if (!nvlist_size_native(&xdr, &size))
1132                         return (-1);
1133
1134                 value_sz = size;
1135                 break;
1136         case DATA_TYPE_NVLIST_ARRAY:
1137                 value_sz = 0;
1138                 for (uint32_t i = 0; i < nelem; i++) {
1139                         xdr.xdr_idx = ((nvlist_t **)data)[i]->nv_data;
1140                         xdr.xdr_buf = xdr.xdr_idx;
1141                         xdr.xdr_buf_size = ((nvlist_t **)data)[i]->nv_size;
1142
1143                         if (!nvlist_size_native(&xdr, &size))
1144                                 return (-1);
1145                         value_sz += size;
1146                 }
1147                 break;
1148         default:
1149                 return (-1);
1150         }
1151
1152         return (value_sz > INT32_MAX ? -1 : (int)value_sz);
1153 }
1154
1155 #define NVPE_SIZE(name_len, data_len) \
1156         (4 + 4 + 4 + NV_ALIGN4(name_len) + 4 + 4 + data_len)
1157 #define NVP_SIZE(name_len, data_len) \
1158         (NV_ALIGN((4 * 4) + (name_len)) + NV_ALIGN(data_len))
1159
1160 static int
1161 nvlist_add_common(nvlist_t *nvl, const char *name, data_type_t type,
1162     uint32_t nelem, const void *data)
1163 {
1164         nvs_data_t *nvs;
1165         nvp_header_t head, *hp;
1166         uint8_t *ptr;
1167         size_t namelen;
1168         int decoded_size, encoded_size;
1169         xdr_t xdr = {
1170                 .xdr_op = XDR_OP_ENCODE,
1171                 .xdr_putint = _putint_mem,
1172                 .xdr_putuint = _putuint_mem,
1173                 .xdr_buf = nvl->nv_data,
1174                 .xdr_idx = nvl->nv_data,
1175                 .xdr_buf_size = nvl->nv_size
1176         };
1177
1178         nvs = (nvs_data_t *)nvl->nv_data;
1179         if (nvs->nvl_nvflag & NV_UNIQUE_NAME)
1180                 (void) nvlist_remove(nvl, name, type);
1181
1182         xdr.xdr_buf = nvl->nv_data;
1183         xdr.xdr_idx = nvl->nv_data;
1184         xdr.xdr_buf_size = nvl->nv_size;
1185         if (!nvlist_size_native(&xdr, &nvl->nv_size))
1186                 return (EINVAL);
1187
1188         namelen = strlen(name);
1189         if ((decoded_size = get_value_size(type, data, nelem)) < 0)
1190                 return (EINVAL);
1191         if ((encoded_size = get_nvp_data_size(type, data, nelem)) < 0)
1192                 return (EINVAL);
1193
1194         /*
1195          * The encoded size is calculated as:
1196          * encode_size (4) + decode_size (4) +
1197          * name string size  (4 + NV_ALIGN4(namelen) +
1198          * data type (4) + nelem size (4) + datalen
1199          *
1200          * The decoded size is calculated as:
1201          * Note: namelen is with terminating 0.
1202          * NV_ALIGN(sizeof(nvpair_t) (4 * 4) + namelen + 1) +
1203          * NV_ALIGN(data_len)
1204          */
1205
1206         head.encoded_size = NVPE_SIZE(namelen, encoded_size);
1207         head.decoded_size = NVP_SIZE(namelen + 1, decoded_size);
1208
1209         if (nvl->nv_asize - nvl->nv_size < head.encoded_size + 8) {
1210                 ptr = realloc(nvl->nv_data, nvl->nv_asize + head.encoded_size);
1211                 if (ptr == NULL)
1212                         return (ENOMEM);
1213                 nvl->nv_data = ptr;
1214                 nvl->nv_asize += head.encoded_size;
1215         }
1216         nvl->nv_idx = nvl->nv_data + nvl->nv_size - sizeof(*hp);
1217         bzero(nvl->nv_idx, head.encoded_size + 8);
1218         hp = (nvp_header_t *)nvl->nv_idx;
1219         *hp = head;
1220         nvl->nv_idx += sizeof(*hp);
1221
1222         xdr.xdr_buf = nvl->nv_data;
1223         xdr.xdr_buf_size = nvl->nv_asize;
1224         xdr.xdr_idx = nvl->nv_idx;
1225
1226         xdr.xdr_idx += xdr.xdr_putuint(&xdr, namelen);
1227         strlcpy((char *)xdr.xdr_idx, name, namelen + 1);
1228         xdr.xdr_idx += NV_ALIGN4(namelen);
1229         xdr.xdr_idx += xdr.xdr_putuint(&xdr, type);
1230         xdr.xdr_idx += xdr.xdr_putuint(&xdr, nelem);
1231
1232         switch (type) {
1233         case DATA_TYPE_BOOLEAN:
1234                 break;
1235
1236         case DATA_TYPE_BYTE_ARRAY:
1237                 xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size);
1238                 bcopy(data, xdr.xdr_idx, nelem);
1239                 xdr.xdr_idx += NV_ALIGN4(encoded_size);
1240                 break;
1241
1242         case DATA_TYPE_STRING:
1243                 encoded_size = strlen(data);
1244                 xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size);
1245                 strlcpy((char *)xdr.xdr_idx, data, encoded_size + 1);
1246                 xdr.xdr_idx += NV_ALIGN4(encoded_size);
1247                 break;
1248
1249         case DATA_TYPE_STRING_ARRAY:
1250                 for (uint32_t i = 0; i < nelem; i++) {
1251                         encoded_size = strlen(((char **)data)[i]);
1252                         xdr.xdr_idx += xdr.xdr_putuint(&xdr, encoded_size);
1253                         strlcpy((char *)xdr.xdr_idx, ((char **)data)[i],
1254                             encoded_size + 1);
1255                         xdr.xdr_idx += NV_ALIGN4(encoded_size);
1256                 }
1257                 break;
1258
1259         case DATA_TYPE_BYTE:
1260         case DATA_TYPE_INT8:
1261         case DATA_TYPE_UINT8:
1262                 xdr_char(&xdr, (char *)data);
1263                 break;
1264
1265         case DATA_TYPE_INT8_ARRAY:
1266         case DATA_TYPE_UINT8_ARRAY:
1267                 xdr_array(&xdr, nelem, (xdrproc_t)xdr_char);
1268                 break;
1269
1270         case DATA_TYPE_INT16:
1271                 xdr_short(&xdr, (short *)data);
1272                 break;
1273
1274         case DATA_TYPE_UINT16:
1275                 xdr_u_short(&xdr, (unsigned short *)data);
1276                 break;
1277
1278         case DATA_TYPE_INT16_ARRAY:
1279                 xdr_array(&xdr, nelem, (xdrproc_t)xdr_short);
1280                 break;
1281
1282         case DATA_TYPE_UINT16_ARRAY:
1283                 xdr_array(&xdr, nelem, (xdrproc_t)xdr_u_short);
1284                 break;
1285
1286         case DATA_TYPE_BOOLEAN_VALUE:
1287         case DATA_TYPE_INT32:
1288                 xdr_int(&xdr, (int *)data);
1289                 break;
1290
1291         case DATA_TYPE_UINT32:
1292                 xdr_u_int(&xdr, (unsigned int *)data);
1293                 break;
1294
1295         case DATA_TYPE_BOOLEAN_ARRAY:
1296         case DATA_TYPE_INT32_ARRAY:
1297                 xdr_array(&xdr, nelem, (xdrproc_t)xdr_int);
1298                 break;
1299
1300         case DATA_TYPE_UINT32_ARRAY:
1301                 xdr_array(&xdr, nelem, (xdrproc_t)xdr_u_int);
1302                 break;
1303
1304         case DATA_TYPE_INT64:
1305                 xdr_int64(&xdr, (int64_t *)data);
1306                 break;
1307
1308         case DATA_TYPE_UINT64:
1309                 xdr_uint64(&xdr, (uint64_t *)data);
1310                 break;
1311
1312         case DATA_TYPE_INT64_ARRAY:
1313                 xdr_array(&xdr, nelem, (xdrproc_t)xdr_int64);
1314                 break;
1315
1316         case DATA_TYPE_UINT64_ARRAY:
1317                 xdr_array(&xdr, nelem, (xdrproc_t)xdr_uint64);
1318                 break;
1319
1320         case DATA_TYPE_NVLIST:
1321                 bcopy(((nvlist_t *)data)->nv_data, xdr.xdr_idx, encoded_size);
1322                 break;
1323
1324         case DATA_TYPE_NVLIST_ARRAY: {
1325                 size_t size;
1326                 xdr_t xdr_nv;
1327
1328                 for (uint32_t i = 0; i < nelem; i++) {
1329                         xdr_nv.xdr_idx = ((nvlist_t **)data)[i]->nv_data;
1330                         xdr_nv.xdr_buf = xdr_nv.xdr_idx;
1331                         xdr_nv.xdr_buf_size = ((nvlist_t **)data)[i]->nv_size;
1332
1333                         if (!nvlist_size_native(&xdr_nv, &size))
1334                                 return (EINVAL);
1335
1336                         bcopy(((nvlist_t **)data)[i]->nv_data, xdr.xdr_idx,
1337                             size);
1338                         xdr.xdr_idx += size;
1339                 }
1340                 break;
1341         }
1342         default:
1343                 bcopy(data, xdr.xdr_idx, encoded_size);
1344         }
1345
1346         nvl->nv_size += head.encoded_size;
1347
1348         return (0);
1349 }
1350
1351 int
1352 nvlist_add_boolean_value(nvlist_t *nvl, const char *name, int value)
1353 {
1354         return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_VALUE, 1,
1355             &value));
1356 }
1357
1358 int
1359 nvlist_add_byte(nvlist_t *nvl, const char *name, uint8_t value)
1360 {
1361         return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE, 1, &value));
1362 }
1363
1364 int
1365 nvlist_add_int8(nvlist_t *nvl, const char *name, int8_t value)
1366 {
1367         return (nvlist_add_common(nvl, name, DATA_TYPE_INT8, 1, &value));
1368 }
1369
1370 int
1371 nvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t value)
1372 {
1373         return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8, 1, &value));
1374 }
1375
1376 int
1377 nvlist_add_int16(nvlist_t *nvl, const char *name, int16_t value)
1378 {
1379         return (nvlist_add_common(nvl, name, DATA_TYPE_INT16, 1, &value));
1380 }
1381
1382 int
1383 nvlist_add_uint16(nvlist_t *nvl, const char *name, uint16_t value)
1384 {
1385         return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16, 1, &value));
1386 }
1387
1388 int
1389 nvlist_add_int32(nvlist_t *nvl, const char *name, int32_t value)
1390 {
1391         return (nvlist_add_common(nvl, name, DATA_TYPE_INT32, 1, &value));
1392 }
1393
1394 int
1395 nvlist_add_uint32(nvlist_t *nvl, const char *name, uint32_t value)
1396 {
1397         return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32, 1, &value));
1398 }
1399
1400 int
1401 nvlist_add_int64(nvlist_t *nvl, const char *name, int64_t value)
1402 {
1403         return (nvlist_add_common(nvl, name, DATA_TYPE_INT64, 1, &value));
1404 }
1405
1406 int
1407 nvlist_add_uint64(nvlist_t *nvl, const char *name, uint64_t value)
1408 {
1409         return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64, 1, &value));
1410 }
1411
1412 int
1413 nvlist_add_string(nvlist_t *nvl, const char *name, const char *value)
1414 {
1415         return (nvlist_add_common(nvl, name, DATA_TYPE_STRING, 1, value));
1416 }
1417
1418 int
1419 nvlist_add_boolean_array(nvlist_t *nvl, const char *name, int *a, uint32_t n)
1420 {
1421         return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_ARRAY, n, a));
1422 }
1423
1424 int
1425 nvlist_add_byte_array(nvlist_t *nvl, const char *name, uint8_t *a, uint32_t n)
1426 {
1427         return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a));
1428 }
1429
1430 int
1431 nvlist_add_int8_array(nvlist_t *nvl, const char *name, int8_t *a, uint32_t n)
1432 {
1433         return (nvlist_add_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a));
1434 }
1435
1436 int
1437 nvlist_add_uint8_array(nvlist_t *nvl, const char *name, uint8_t *a, uint32_t n)
1438 {
1439         return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a));
1440 }
1441
1442 int
1443 nvlist_add_int16_array(nvlist_t *nvl, const char *name, int16_t *a, uint32_t n)
1444 {
1445         return (nvlist_add_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a));
1446 }
1447
1448 int
1449 nvlist_add_uint16_array(nvlist_t *nvl, const char *name, uint16_t *a,
1450     uint32_t n)
1451 {
1452         return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a));
1453 }
1454
1455 int
1456 nvlist_add_int32_array(nvlist_t *nvl, const char *name, int32_t *a, uint32_t n)
1457 {
1458         return (nvlist_add_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a));
1459 }
1460
1461 int
1462 nvlist_add_uint32_array(nvlist_t *nvl, const char *name, uint32_t *a,
1463     uint32_t n)
1464 {
1465         return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a));
1466 }
1467
1468 int
1469 nvlist_add_int64_array(nvlist_t *nvl, const char *name, int64_t *a, uint32_t n)
1470 {
1471         return (nvlist_add_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a));
1472 }
1473
1474 int
1475 nvlist_add_uint64_array(nvlist_t *nvl, const char *name, uint64_t *a,
1476     uint32_t n)
1477 {
1478         return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a));
1479 }
1480
1481 int
1482 nvlist_add_string_array(nvlist_t *nvl, const char *name,
1483     char * const *a, uint32_t n)
1484 {
1485         return (nvlist_add_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a));
1486 }
1487
1488 int
1489 nvlist_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val)
1490 {
1491         return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST, 1, val));
1492 }
1493
1494 int
1495 nvlist_add_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **a,
1496     uint32_t n)
1497 {
1498         return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a));
1499 }
1500
1501 static const char *typenames[] = {
1502         "DATA_TYPE_UNKNOWN",
1503         "DATA_TYPE_BOOLEAN",
1504         "DATA_TYPE_BYTE",
1505         "DATA_TYPE_INT16",
1506         "DATA_TYPE_UINT16",
1507         "DATA_TYPE_INT32",
1508         "DATA_TYPE_UINT32",
1509         "DATA_TYPE_INT64",
1510         "DATA_TYPE_UINT64",
1511         "DATA_TYPE_STRING",
1512         "DATA_TYPE_BYTE_ARRAY",
1513         "DATA_TYPE_INT16_ARRAY",
1514         "DATA_TYPE_UINT16_ARRAY",
1515         "DATA_TYPE_INT32_ARRAY",
1516         "DATA_TYPE_UINT32_ARRAY",
1517         "DATA_TYPE_INT64_ARRAY",
1518         "DATA_TYPE_UINT64_ARRAY",
1519         "DATA_TYPE_STRING_ARRAY",
1520         "DATA_TYPE_HRTIME",
1521         "DATA_TYPE_NVLIST",
1522         "DATA_TYPE_NVLIST_ARRAY",
1523         "DATA_TYPE_BOOLEAN_VALUE",
1524         "DATA_TYPE_INT8",
1525         "DATA_TYPE_UINT8",
1526         "DATA_TYPE_BOOLEAN_ARRAY",
1527         "DATA_TYPE_INT8_ARRAY",
1528         "DATA_TYPE_UINT8_ARRAY"
1529 };
1530
1531 int
1532 nvpair_type_from_name(const char *name)
1533 {
1534         unsigned i;
1535
1536         for (i = 0; i < nitems(typenames); i++) {
1537                 if (strcmp(name, typenames[i]) == 0)
1538                         return (i);
1539         }
1540         return (0);
1541 }
1542
1543 nvp_header_t *
1544 nvpair_find(nvlist_t *nv, const char *name)
1545 {
1546         nvp_header_t *nvh;
1547
1548         nvh = NULL;
1549         while ((nvh = nvlist_next_nvpair(nv, nvh)) != NULL) {
1550                 nv_string_t *nvp_name;
1551
1552                 nvp_name = (nv_string_t *)(nvh + 1);
1553                 if (nvp_name->nv_size == strlen(name) &&
1554                     memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0)
1555                         break;
1556         }
1557         return (nvh);
1558 }
1559
1560 void
1561 nvpair_print(nvp_header_t *nvp, unsigned int indent)
1562 {
1563         nv_string_t *nvp_name;
1564         nv_pair_data_t *nvp_data;
1565         nvlist_t nvlist;
1566         unsigned i, j;
1567         xdr_t xdr = {
1568                 .xdr_op = XDR_OP_DECODE,
1569                 .xdr_getint = _getint_mem,
1570                 .xdr_getuint = _getuint_mem,
1571                 .xdr_buf = (const uint8_t *)nvp,
1572                 .xdr_idx = NULL,
1573                 .xdr_buf_size = nvp->encoded_size
1574         };
1575
1576         nvp_name = (nv_string_t *)((uintptr_t)nvp + sizeof(*nvp));
1577         nvp_data = (nv_pair_data_t *)
1578             NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] + nvp_name->nv_size);
1579
1580         for (i = 0; i < indent; i++)
1581                 printf(" ");
1582
1583         printf("%s [%d] %.*s", typenames[nvp_data->nv_type],
1584             nvp_data->nv_nelem, nvp_name->nv_size, nvp_name->nv_data);
1585
1586         xdr.xdr_idx = nvp_data->nv_data;
1587         switch (nvp_data->nv_type) {
1588         case DATA_TYPE_BYTE:
1589         case DATA_TYPE_INT8:
1590         case DATA_TYPE_UINT8: {
1591                 char c;
1592
1593                 if (xdr_char(&xdr, &c))
1594                         printf(" = 0x%x\n", c);
1595                 break;
1596         }
1597
1598         case DATA_TYPE_INT16:
1599         case DATA_TYPE_UINT16: {
1600                 unsigned short u;
1601
1602                 if (xdr_u_short(&xdr, &u))
1603                         printf(" = 0x%hx\n", u);
1604                 break;
1605         }
1606
1607         case DATA_TYPE_BOOLEAN_VALUE:
1608         case DATA_TYPE_INT32:
1609         case DATA_TYPE_UINT32: {
1610                 unsigned u;
1611
1612                 if (xdr_u_int(&xdr, &u))
1613                         printf(" = 0x%x\n", u);
1614                 break;
1615         }
1616
1617         case DATA_TYPE_INT64:
1618         case DATA_TYPE_UINT64: {
1619                 uint64_t u;
1620
1621                 if (xdr_uint64(&xdr, &u))
1622                         printf(" = 0x%jx\n", (uintmax_t)u);
1623                 break;
1624         }
1625
1626         case DATA_TYPE_INT64_ARRAY:
1627         case DATA_TYPE_UINT64_ARRAY: {
1628                 uint64_t *u;
1629
1630                 if (xdr_array(&xdr, nvp_data->nv_nelem,
1631                     (xdrproc_t)xdr_uint64)) {
1632                         u = (uint64_t *)(nvp_data->nv_data + sizeof(unsigned));
1633                         for (i = 0; i < nvp_data->nv_nelem; i++)
1634                                 printf(" [%u] = 0x%jx", i, (uintmax_t)u[i]);
1635                         printf("\n");
1636                 }
1637
1638                 break;
1639         }
1640
1641         case DATA_TYPE_STRING:
1642         case DATA_TYPE_STRING_ARRAY:
1643                 nvp_name = (nv_string_t *)&nvp_data->nv_data[0];
1644                 for (i = 0; i < nvp_data->nv_nelem; i++) {
1645                         printf(" = \"%.*s\"\n", nvp_name->nv_size,
1646                             nvp_name->nv_data);
1647                 }
1648                 break;
1649
1650         case DATA_TYPE_NVLIST:
1651                 printf("\n");
1652                 nvlist.nv_data = &nvp_data->nv_data[0];
1653                 nvlist_print(&nvlist, indent + 2);
1654                 break;
1655
1656         case DATA_TYPE_NVLIST_ARRAY:
1657                 nvlist.nv_data = &nvp_data->nv_data[0];
1658                 for (j = 0; j < nvp_data->nv_nelem; j++) {
1659                         size_t size;
1660
1661                         printf("[%d]\n", j);
1662                         nvlist_print(&nvlist, indent + 2);
1663                         if (j != nvp_data->nv_nelem - 1) {
1664                                 for (i = 0; i < indent; i++)
1665                                         printf(" ");
1666                                 printf("%s %.*s",
1667                                     typenames[nvp_data->nv_type],
1668                                     nvp_name->nv_size,
1669                                     nvp_name->nv_data);
1670                         }
1671                         xdr.xdr_idx = nvlist.nv_data;
1672                         xdr.xdr_buf = xdr.xdr_idx;
1673                         xdr.xdr_buf_size = nvp->encoded_size -
1674                             (xdr.xdr_idx - (uint8_t *)nvp);
1675
1676                         if (!nvlist_size_native(&xdr, &size))
1677                                 return;
1678
1679                         nvlist.nv_data += size;
1680                 }
1681                 break;
1682
1683         default:
1684                 printf("\n");
1685         }
1686 }
1687
1688 void
1689 nvlist_print(const nvlist_t *nvl, unsigned int indent)
1690 {
1691         nvs_data_t *data;
1692         nvp_header_t *nvp;
1693
1694         data = (nvs_data_t *)nvl->nv_data;
1695         nvp = &data->nvl_pair;  /* first pair in nvlist */
1696         while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
1697                 nvpair_print(nvp, indent);
1698                 nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size);
1699         }
1700         printf("%*s\n", indent + 13, "End of nvlist");
1701 }