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