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