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