2 * Copyright 2020 Toomas Soome <tsoome@me.com>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
31 #include <sys/endian.h>
32 #include <sys/stdint.h>
33 #include <sys/param.h>
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;
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 *);
59 typedef int (*xdrproc_t)(xdr_t *, void *);
61 /* Basic primitives for XDR translation operations, getint and putint. */
63 _getint(struct xdr *xdr, int *ip)
65 *ip = be32dec(xdr->xdr_idx);
66 return (sizeof (int));
70 _putint(struct xdr *xdr, int i)
72 int *ip = (int *)xdr->xdr_idx;
75 return (sizeof (int));
79 _getuint(struct xdr *xdr, unsigned *ip)
81 *ip = be32dec(xdr->xdr_idx);
82 return (sizeof (unsigned));
86 _putuint(struct xdr *xdr, unsigned i)
88 unsigned *up = (unsigned *)xdr->xdr_idx;
91 return (sizeof (int));
95 * XDR data translations.
98 xdr_short(xdr_t *xdr, short *ip)
104 if ((rv = xdr_int(xdr, &i))) {
105 if (xdr->xdr_op == XDR_OP_DECODE)
112 xdr_u_short(xdr_t *xdr, unsigned short *ip)
118 if ((rv = xdr_u_int(xdr, &u))) {
119 if (xdr->xdr_op == XDR_OP_DECODE)
126 * translate xdr->xdr_idx, increment it by size of int.
129 xdr_int(xdr_t *xdr, int *ip)
132 int *i = (int *)xdr->xdr_idx;
134 if (xdr->xdr_idx + sizeof (int) > xdr->xdr_buf + xdr->xdr_buf_size)
137 switch (xdr->xdr_op) {
139 /* Encode value *ip, store to buf */
140 xdr->xdr_idx += xdr->xdr_putint(xdr, *ip);
145 /* Decode buf, return value to *ip */
146 xdr->xdr_idx += xdr->xdr_getint(xdr, i);
155 * translate xdr->xdr_idx, increment it by size of unsigned int.
158 xdr_u_int(xdr_t *xdr, unsigned *ip)
161 unsigned *u = (unsigned *)xdr->xdr_idx;
163 if (xdr->xdr_idx + sizeof (unsigned) > xdr->xdr_buf + xdr->xdr_buf_size)
166 switch (xdr->xdr_op) {
168 /* Encode value *ip, store to buf */
169 xdr->xdr_idx += xdr->xdr_putuint(xdr, *ip);
174 /* Decode buf, return value to *ip */
175 xdr->xdr_idx += xdr->xdr_getuint(xdr, u);
184 xdr_int64(xdr_t *xdr, int64_t *lp)
190 if (xdr->xdr_idx + sizeof (int64_t) > xdr->xdr_buf + xdr->xdr_buf_size)
193 switch (xdr->xdr_op) {
195 /* Encode value *lp, store to buf */
197 lo = *lp & UINT32_MAX;
198 xdr->xdr_idx += xdr->xdr_putint(xdr, hi);
199 xdr->xdr_idx += xdr->xdr_putint(xdr, lo);
204 /* Decode buf, return value to *ip */
205 xdr->xdr_idx += xdr->xdr_getint(xdr, &hi);
206 xdr->xdr_idx += xdr->xdr_getuint(xdr, &lo);
207 *lp = (((int64_t)hi) << 32) | lo;
214 xdr_uint64(xdr_t *xdr, uint64_t *lp)
219 if (xdr->xdr_idx + sizeof (uint64_t) > xdr->xdr_buf + xdr->xdr_buf_size)
222 switch (xdr->xdr_op) {
224 /* Encode value *ip, store to buf */
226 lo = *lp & UINT32_MAX;
227 xdr->xdr_idx += xdr->xdr_putint(xdr, hi);
228 xdr->xdr_idx += xdr->xdr_putint(xdr, lo);
233 /* Decode buf, return value to *ip */
234 xdr->xdr_idx += xdr->xdr_getuint(xdr, &hi);
235 xdr->xdr_idx += xdr->xdr_getuint(xdr, &lo);
236 *lp = (((uint64_t)hi) << 32) | lo;
243 xdr_char(xdr_t *xdr, char *cp)
249 if ((rv = xdr_int(xdr, &i))) {
250 if (xdr->xdr_op == XDR_OP_DECODE)
257 xdr_string(xdr_t *xdr, nv_string_t *s)
262 switch (xdr->xdr_op) {
265 if (xdr->xdr_idx + sizeof (unsigned) + NV_ALIGN4(size) >
266 xdr->xdr_buf + xdr->xdr_buf_size)
268 xdr->xdr_idx += xdr->xdr_putuint(xdr, s->nv_size);
269 xdr->xdr_idx += NV_ALIGN4(size);
274 if (xdr->xdr_idx + sizeof (unsigned) >
275 xdr->xdr_buf + xdr->xdr_buf_size)
277 size = xdr->xdr_getuint(xdr, &s->nv_size);
278 size = NV_ALIGN4(size + s->nv_size);
279 if (xdr->xdr_idx + size > xdr->xdr_buf + xdr->xdr_buf_size)
281 xdr->xdr_idx += size;
289 xdr_array(xdr_t *xdr, const unsigned nelem, const xdrproc_t elproc)
293 for (unsigned i = 0; i < nelem; i++) {
294 if (!elproc(xdr, xdr->xdr_idx))
301 * nvlist management functions.
304 nvlist_destroy(nvlist_t *nvl)
307 /* Free data if it was allocated by us. */
308 if (nvl->nv_asize > 0)
315 nvstring_get(nv_string_t *nvs)
319 s = malloc(nvs->nv_size + 1);
321 bcopy(nvs->nv_data, s, nvs->nv_size);
322 s[nvs->nv_size] = '\0';
328 * Create empty nvlist.
329 * The nvlist is terminated by 2x zeros (8 bytes).
332 nvlist_create(int flag)
337 nvl = calloc(1, sizeof (*nvl));
341 nvl->nv_header.nvh_encoding = NV_ENCODE_XDR;
342 nvl->nv_header.nvh_endian = _BYTE_ORDER == _LITTLE_ENDIAN;
344 nvl->nv_asize = nvl->nv_size = sizeof (*nvs);
345 nvs = calloc(1, nvl->nv_asize);
350 /* data in nvlist is byte stream */
351 nvl->nv_data = (uint8_t *)nvs;
353 nvs->nvl_version = NV_VERSION;
354 nvs->nvl_nvflag = flag;
359 nvlist_xdr_nvp(xdr_t *xdr, nvlist_t *nvl)
361 nv_string_t *nv_string;
362 nv_pair_data_t *nvp_data;
364 unsigned type, nelem;
367 nv_string = (nv_string_t *)xdr->xdr_idx;
368 if (!xdr_string(xdr, nv_string)) {
371 nvp_data = (nv_pair_data_t *)xdr->xdr_idx;
373 type = nvp_data->nv_type;
374 nelem = nvp_data->nv_nelem;
375 if (!xdr_u_int(xdr, &type) || !xdr_u_int(xdr, &nelem))
379 case DATA_TYPE_NVLIST:
380 case DATA_TYPE_NVLIST_ARRAY:
381 bzero(&nvlist, sizeof (nvlist));
382 nvlist.nv_data = xdr->xdr_idx;
383 nvlist.nv_idx = nvlist.nv_data;
385 /* Set up xdr for this nvlist. */
387 nv_xdr.xdr_buf = nvlist.nv_data;
388 nv_xdr.xdr_idx = nvlist.nv_data;
389 nv_xdr.xdr_buf_size =
390 nvl->nv_data + nvl->nv_size - nvlist.nv_data;
392 for (unsigned i = 0; i < nelem; i++) {
393 if (xdr->xdr_op == XDR_OP_ENCODE) {
394 if (!nvlist_size_native(&nv_xdr,
398 if (!nvlist_size_xdr(&nv_xdr,
402 if (nvlist_xdr_nvlist(xdr, &nvlist) != 0)
405 nvlist.nv_data = nv_xdr.xdr_idx;
406 nvlist.nv_idx = nv_xdr.xdr_idx;
408 nv_xdr.xdr_buf = nv_xdr.xdr_idx;
409 nv_xdr.xdr_buf_size =
410 nvl->nv_data + nvl->nv_size - nvlist.nv_data;
414 case DATA_TYPE_BOOLEAN:
415 /* BOOLEAN does not take value space */
419 case DATA_TYPE_UINT8:
420 if (!xdr_char(xdr, (char *)&nvp_data->nv_data[0]))
424 case DATA_TYPE_INT16:
425 if (!xdr_short(xdr, (short *)&nvp_data->nv_data[0]))
429 case DATA_TYPE_UINT16:
430 if (!xdr_u_short(xdr, (unsigned short *)&nvp_data->nv_data[0]))
434 case DATA_TYPE_BOOLEAN_VALUE:
435 case DATA_TYPE_INT32:
436 if (!xdr_int(xdr, (int *)&nvp_data->nv_data[0]))
440 case DATA_TYPE_UINT32:
441 if (!xdr_u_int(xdr, (unsigned *)&nvp_data->nv_data[0]))
445 case DATA_TYPE_HRTIME:
446 case DATA_TYPE_INT64:
447 if (!xdr_int64(xdr, (int64_t *)&nvp_data->nv_data[0]))
451 case DATA_TYPE_UINT64:
452 if (!xdr_uint64(xdr, (uint64_t *)&nvp_data->nv_data[0]))
456 case DATA_TYPE_BYTE_ARRAY:
457 case DATA_TYPE_STRING:
458 nv_string = (nv_string_t *)&nvp_data->nv_data[0];
459 if (!xdr_string(xdr, nv_string))
463 case DATA_TYPE_STRING_ARRAY:
464 nv_string = (nv_string_t *)&nvp_data->nv_data[0];
465 for (unsigned i = 0; i < nelem; i++) {
466 if (!xdr_string(xdr, nv_string))
468 nv_string = (nv_string_t *)xdr->xdr_idx;
472 case DATA_TYPE_INT8_ARRAY:
473 case DATA_TYPE_UINT8_ARRAY:
474 case DATA_TYPE_INT16_ARRAY:
475 case DATA_TYPE_UINT16_ARRAY:
476 case DATA_TYPE_BOOLEAN_ARRAY:
477 case DATA_TYPE_INT32_ARRAY:
478 case DATA_TYPE_UINT32_ARRAY:
479 if (!xdr_array(xdr, nelem, (xdrproc_t)xdr_u_int))
483 case DATA_TYPE_INT64_ARRAY:
484 case DATA_TYPE_UINT64_ARRAY:
485 if (!xdr_array(xdr, nelem, (xdrproc_t)xdr_uint64))
493 nvlist_xdr_nvlist(xdr_t *xdr, nvlist_t *nvl)
497 unsigned encoded_size, decoded_size;
500 nvs = (nvs_data_t *)xdr->xdr_idx;
501 nvph = &nvs->nvl_pair;
503 if (!xdr_u_int(xdr, &nvs->nvl_version))
505 if (!xdr_u_int(xdr, &nvs->nvl_nvflag))
508 encoded_size = nvph->encoded_size;
509 decoded_size = nvph->decoded_size;
511 if (xdr->xdr_op == XDR_OP_ENCODE) {
512 if (!xdr_u_int(xdr, &nvph->encoded_size))
514 if (!xdr_u_int(xdr, &nvph->decoded_size))
517 xdr->xdr_idx += 2 * sizeof (unsigned);
521 while (encoded_size && decoded_size) {
522 if (!nvlist_xdr_nvp(xdr, nvl))
525 nvph = (nvp_header_t *)(xdr->xdr_idx);
526 encoded_size = nvph->encoded_size;
527 decoded_size = nvph->decoded_size;
528 if (xdr->xdr_op == XDR_OP_ENCODE) {
529 if (!xdr_u_int(xdr, &nvph->encoded_size))
531 if (!xdr_u_int(xdr, &nvph->decoded_size))
534 xdr->xdr_idx += 2 * sizeof (unsigned);
541 * Calculate nvlist size, translating encoded_size and decoded_size.
544 nvlist_size_xdr(xdr_t *xdr, size_t *size)
547 unsigned encoded_size, decoded_size;
549 xdr->xdr_idx += 2 * sizeof (unsigned);
552 if (!xdr_u_int(xdr, &encoded_size) || !xdr_u_int(xdr, &decoded_size))
555 while (encoded_size && decoded_size) {
556 xdr->xdr_idx = pair + encoded_size;
558 if (!xdr_u_int(xdr, &encoded_size) ||
559 !xdr_u_int(xdr, &decoded_size))
562 *size = xdr->xdr_idx - xdr->xdr_buf;
568 nvlist_next_nvpair(nvlist_t *nvl, nvp_header_t *nvh)
571 unsigned encoded_size, decoded_size;
577 xdr.xdr_buf = nvl->nv_data;
578 xdr.xdr_idx = nvl->nv_data;
579 xdr.xdr_buf_size = nvl->nv_size;
581 xdr.xdr_idx += 2 * sizeof (unsigned);
583 /* Skip tp current pair */
585 xdr.xdr_idx = (uint8_t *)nvh;
589 if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
592 encoded_size = *(unsigned *)xdr.xdr_idx;
593 xdr.xdr_idx += sizeof (unsigned);
594 if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
597 decoded_size = *(unsigned *)xdr.xdr_idx;
598 xdr.xdr_idx += sizeof (unsigned);
599 if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
602 while (encoded_size && decoded_size) {
604 return ((nvp_header_t *)pair);
606 xdr.xdr_idx = pair + encoded_size;
607 nvh = (nvp_header_t *)xdr.xdr_idx;
609 if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
612 encoded_size = *(unsigned *)xdr.xdr_idx;
613 xdr.xdr_idx += sizeof (unsigned);
614 if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
616 decoded_size = *(unsigned *)xdr.xdr_idx;
617 xdr.xdr_idx += sizeof (unsigned);
618 if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size)
621 if (encoded_size != 0 && decoded_size != 0) {
629 * Calculate nvlist size by walking in memory data.
632 nvlist_size_native(xdr_t *xdr, size_t *size)
635 unsigned encoded_size, decoded_size;
637 xdr->xdr_idx += 2 * sizeof (unsigned);
640 if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size)
643 encoded_size = *(unsigned *)xdr->xdr_idx;
644 xdr->xdr_idx += sizeof (unsigned);
645 if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size)
647 decoded_size = *(unsigned *)xdr->xdr_idx;
648 xdr->xdr_idx += sizeof (unsigned);
649 while (encoded_size && decoded_size) {
650 xdr->xdr_idx = pair + encoded_size;
652 if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size)
654 encoded_size = *(unsigned *)xdr->xdr_idx;
655 xdr->xdr_idx += sizeof (unsigned);
656 if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size)
658 decoded_size = *(unsigned *)xdr->xdr_idx;
659 xdr->xdr_idx += sizeof (unsigned);
661 *size = xdr->xdr_idx - xdr->xdr_buf;
667 * Export nvlist to byte stream format.
670 nvlist_export(nvlist_t *nvl)
674 .xdr_op = XDR_OP_ENCODE,
675 .xdr_putint = _putint,
676 .xdr_putuint = _putuint,
677 .xdr_buf = nvl->nv_data,
678 .xdr_idx = nvl->nv_data,
679 .xdr_buf_size = nvl->nv_size
682 if (nvl->nv_header.nvh_encoding != NV_ENCODE_XDR)
685 nvl->nv_idx = nvl->nv_data;
686 rv = nvlist_xdr_nvlist(&xdr, nvl);
692 * Import nvlist from byte stream.
693 * Determine the stream size and allocate private copy.
694 * Then translate the data.
697 nvlist_import(const char *stream, size_t size)
701 .xdr_op = XDR_OP_DECODE,
702 .xdr_getint = _getint,
703 .xdr_getuint = _getuint
706 /* Check the nvlist head. */
707 if (stream[0] != NV_ENCODE_XDR ||
708 (stream[1] != '\0' && stream[1] != '\1') ||
709 stream[2] != '\0' || stream[3] != '\0' ||
710 be32toh(*(uint32_t *)(stream + 4)) != NV_VERSION ||
711 be32toh(*(uint32_t *)(stream + 8)) != NV_UNIQUE_NAME)
714 nvl = malloc(sizeof (*nvl));
718 nvl->nv_header.nvh_encoding = stream[0];
719 nvl->nv_header.nvh_endian = stream[1];
720 nvl->nv_header.nvh_reserved1 = stream[2];
721 nvl->nv_header.nvh_reserved2 = stream[3];
723 xdr.xdr_buf = xdr.xdr_idx = (uint8_t *)stream + 4;
724 xdr.xdr_buf_size = size - 4;
726 if (!nvlist_size_xdr(&xdr, &nvl->nv_asize)) {
730 nvl->nv_size = nvl->nv_asize;
731 nvl->nv_data = malloc(nvl->nv_asize);
732 if (nvl->nv_data == NULL) {
736 nvl->nv_idx = nvl->nv_data;
737 bcopy(stream + 4, nvl->nv_data, nvl->nv_asize);
739 xdr.xdr_buf = xdr.xdr_idx = nvl->nv_data;
740 xdr.xdr_buf_size = nvl->nv_asize;
742 if (nvlist_xdr_nvlist(&xdr, nvl) != 0) {
752 * remove pair from this nvlist.
755 nvlist_remove(nvlist_t *nvl, const char *name, data_type_t type)
757 uint8_t *head, *tail;
760 nv_string_t *nvp_name;
761 nv_pair_data_t *nvp_data;
765 if (nvl == NULL || nvl->nv_data == NULL || name == NULL)
768 /* Make sure the nvlist size is set correct */
769 xdr.xdr_idx = nvl->nv_data;
770 xdr.xdr_buf = xdr.xdr_idx;
771 xdr.xdr_buf_size = nvl->nv_size;
772 if (!nvlist_size_native(&xdr, &nvl->nv_size))
775 data = (nvs_data_t *)nvl->nv_data;
776 nvp = &data->nvl_pair; /* first pair in nvlist */
777 head = (uint8_t *)nvp;
779 while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
780 nvp_name = (nv_string_t *)(nvp + 1);
782 nvp_data = (nv_pair_data_t *)(&nvp_name->nv_data[0] +
783 NV_ALIGN4(nvp_name->nv_size));
785 if (strlen(name) == nvp_name->nv_size &&
786 memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0 &&
787 (nvp_data->nv_type == type || type == DATA_TYPE_UNKNOWN)) {
789 * set tail to point to next nvpair and size
790 * is the length of the tail.
792 tail = head + nvp->encoded_size;
793 size = nvl->nv_size - (tail - nvl->nv_data);
795 /* adjust the size of the nvlist. */
796 nvl->nv_size -= nvp->encoded_size;
797 bcopy(tail, head, size);
800 /* Not our pair, skip to next. */
801 head = head + nvp->encoded_size;
802 nvp = (nvp_header_t *)head;
808 clone_nvlist(const nvlist_t *nvl, const uint8_t *ptr, unsigned size,
813 nv = calloc(1, sizeof (*nv));
817 nv->nv_header = nvl->nv_header;
820 nv->nv_data = malloc(nv->nv_asize);
821 if (nv->nv_data == NULL) {
826 bcopy(ptr, nv->nv_data, nv->nv_asize);
832 * Return the next nvlist in an nvlist array.
835 nvlist_next(const uint8_t *ptr)
840 data = (nvs_data_t *)ptr;
841 nvp = &data->nvl_pair; /* first pair in nvlist */
843 while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
844 nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size);
846 return ((uint8_t *)nvp + sizeof (*nvp));
850 * Note: nvlist and nvlist array must be freed by caller.
853 nvlist_find(const nvlist_t *nvl, const char *name, data_type_t type,
854 int *elementsp, void *valuep, int *sizep)
858 nv_string_t *nvp_name;
859 nv_pair_data_t *nvp_data;
860 nvlist_t **nvlist, *nv;
864 if (nvl == NULL || nvl->nv_data == NULL || name == NULL)
867 data = (nvs_data_t *)nvl->nv_data;
868 nvp = &data->nvl_pair; /* first pair in nvlist */
870 while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
871 nvp_name = (nv_string_t *)((uint8_t *)nvp + sizeof (*nvp));
872 if (nvl->nv_data + nvl->nv_size <
873 nvp_name->nv_data + nvp_name->nv_size)
876 nvp_data = (nv_pair_data_t *)
877 NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] +
880 if (strlen(name) == nvp_name->nv_size &&
881 memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0 &&
882 (nvp_data->nv_type == type || type == DATA_TYPE_UNKNOWN)) {
883 if (elementsp != NULL)
884 *elementsp = nvp_data->nv_nelem;
885 switch (nvp_data->nv_type) {
886 case DATA_TYPE_UINT64:
887 bcopy(nvp_data->nv_data, valuep,
890 case DATA_TYPE_STRING:
891 nvp_name = (nv_string_t *)nvp_data->nv_data;
893 *sizep = nvp_name->nv_size;
895 *(const uint8_t **)valuep =
896 &nvp_name->nv_data[0];
898 case DATA_TYPE_NVLIST:
899 ptr = &nvp_data->nv_data[0];
900 rv = clone_nvlist(nvl, ptr,
901 nvlist_next(ptr) - ptr, &nv);
903 *(nvlist_t **)valuep = nv;
907 case DATA_TYPE_NVLIST_ARRAY:
908 nvlist = calloc(nvp_data->nv_nelem,
909 sizeof (nvlist_t *));
912 ptr = &nvp_data->nv_data[0];
914 for (unsigned i = 0; i < nvp_data->nv_nelem;
916 rv = clone_nvlist(nvl, ptr,
917 nvlist_next(ptr) - ptr, &nvlist[i]);
920 ptr = nvlist_next(ptr);
922 *(nvlist_t ***)valuep = nvlist;
927 /* Not our pair, skip to next. */
928 nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size);
929 if (nvl->nv_data + nvl->nv_size < (uint8_t *)nvp)
934 for (unsigned i = 0; i < nvp_data->nv_nelem; i++) {
935 free(nvlist[i]->nv_data);
943 get_value_size(data_type_t type, const void *data, uint32_t nelem)
945 uint64_t value_sz = 0;
948 case DATA_TYPE_BOOLEAN:
951 case DATA_TYPE_BOOLEAN_VALUE:
954 case DATA_TYPE_UINT8:
955 case DATA_TYPE_INT16:
956 case DATA_TYPE_UINT16:
957 case DATA_TYPE_INT32:
958 case DATA_TYPE_UINT32:
959 /* Our smallest data unit is 32-bit */
960 value_sz = sizeof (uint32_t);
962 case DATA_TYPE_HRTIME:
963 case DATA_TYPE_INT64:
964 value_sz = sizeof (int64_t);
966 case DATA_TYPE_UINT64:
967 value_sz = sizeof (uint64_t);
969 case DATA_TYPE_STRING:
973 value_sz = strlen(data) + 1;
975 case DATA_TYPE_BYTE_ARRAY:
976 value_sz = nelem * sizeof (uint8_t);
978 case DATA_TYPE_BOOLEAN_ARRAY:
979 case DATA_TYPE_INT8_ARRAY:
980 case DATA_TYPE_UINT8_ARRAY:
981 case DATA_TYPE_INT16_ARRAY:
982 case DATA_TYPE_UINT16_ARRAY:
983 case DATA_TYPE_INT32_ARRAY:
984 case DATA_TYPE_UINT32_ARRAY:
985 value_sz = (uint64_t)nelem * sizeof (uint32_t);
987 case DATA_TYPE_INT64_ARRAY:
988 value_sz = (uint64_t)nelem * sizeof (int64_t);
990 case DATA_TYPE_UINT64_ARRAY:
991 value_sz = (uint64_t)nelem * sizeof (uint64_t);
993 case DATA_TYPE_STRING_ARRAY:
994 value_sz = (uint64_t)nelem * sizeof (uint64_t);
997 char *const *strs = data;
1000 for (i = 0; i < nelem; i++) {
1001 if (strs[i] == NULL)
1003 value_sz += strlen(strs[i]) + 1;
1007 case DATA_TYPE_NVLIST:
1009 * The decoded size of nvlist is constant.
1011 value_sz = NV_ALIGN(6 * 4); /* sizeof nvlist_t */
1013 case DATA_TYPE_NVLIST_ARRAY:
1014 value_sz = (uint64_t)nelem * sizeof (uint64_t) +
1015 (uint64_t)nelem * NV_ALIGN(6 * 4); /* sizeof nvlist_t */
1021 return (value_sz > INT32_MAX ? -1 : (int)value_sz);
1025 get_nvp_data_size(data_type_t type, const void *data, uint32_t nelem)
1027 uint64_t value_sz = 0;
1032 case DATA_TYPE_BOOLEAN:
1035 case DATA_TYPE_BOOLEAN_VALUE:
1036 case DATA_TYPE_BYTE:
1037 case DATA_TYPE_INT8:
1038 case DATA_TYPE_UINT8:
1039 case DATA_TYPE_INT16:
1040 case DATA_TYPE_UINT16:
1041 case DATA_TYPE_INT32:
1042 case DATA_TYPE_UINT32:
1043 /* Our smallest data unit is 32-bit */
1044 value_sz = sizeof (uint32_t);
1046 case DATA_TYPE_HRTIME:
1047 case DATA_TYPE_INT64:
1048 case DATA_TYPE_UINT64:
1049 value_sz = sizeof (uint64_t);
1051 case DATA_TYPE_STRING:
1052 value_sz = 4 + NV_ALIGN4(strlen(data));
1054 case DATA_TYPE_BYTE_ARRAY:
1055 value_sz = NV_ALIGN4(nelem);
1057 case DATA_TYPE_BOOLEAN_ARRAY:
1058 case DATA_TYPE_INT8_ARRAY:
1059 case DATA_TYPE_UINT8_ARRAY:
1060 case DATA_TYPE_INT16_ARRAY:
1061 case DATA_TYPE_UINT16_ARRAY:
1062 case DATA_TYPE_INT32_ARRAY:
1063 case DATA_TYPE_UINT32_ARRAY:
1064 value_sz = 4 + (uint64_t)nelem * sizeof (uint32_t);
1066 case DATA_TYPE_INT64_ARRAY:
1067 case DATA_TYPE_UINT64_ARRAY:
1068 value_sz = 4 + (uint64_t)nelem * sizeof (uint64_t);
1070 case DATA_TYPE_STRING_ARRAY:
1072 char *const *strs = data;
1075 for (i = 0; i < nelem; i++) {
1076 value_sz += 4 + NV_ALIGN4(strlen(strs[i]));
1080 case DATA_TYPE_NVLIST:
1081 xdr.xdr_idx = ((nvlist_t *)data)->nv_data;
1082 xdr.xdr_buf = xdr.xdr_idx;
1083 xdr.xdr_buf_size = ((nvlist_t *)data)->nv_size;
1085 if (!nvlist_size_native(&xdr, &size))
1090 case DATA_TYPE_NVLIST_ARRAY:
1092 for (uint32_t i = 0; i < nelem; i++) {
1093 xdr.xdr_idx = ((nvlist_t **)data)[i]->nv_data;
1094 xdr.xdr_buf = xdr.xdr_idx;
1095 xdr.xdr_buf_size = ((nvlist_t **)data)[i]->nv_size;
1097 if (!nvlist_size_native(&xdr, &size))
1106 return (value_sz > INT32_MAX ? -1 : (int)value_sz);
1109 #define NVPE_SIZE(name_len, data_len) \
1110 (4 + 4 + 4 + NV_ALIGN4(name_len) + 4 + 4 + data_len)
1111 #define NVP_SIZE(name_len, data_len) \
1112 (NV_ALIGN((4 * 4) + (name_len)) + NV_ALIGN(data_len))
1115 nvlist_add_common(nvlist_t *nvl, const char *name, data_type_t type,
1116 uint32_t nelem, const void *data)
1119 nvp_header_t head, *hp;
1122 int decoded_size, encoded_size;
1125 nvs = (nvs_data_t *)nvl->nv_data;
1126 if (nvs->nvl_nvflag & NV_UNIQUE_NAME)
1127 (void) nvlist_remove(nvl, name, type);
1129 xdr.xdr_buf = nvl->nv_data;
1130 xdr.xdr_idx = nvl->nv_data;
1131 xdr.xdr_buf_size = nvl->nv_size;
1132 if (!nvlist_size_native(&xdr, &nvl->nv_size))
1135 namelen = strlen(name);
1136 if ((decoded_size = get_value_size(type, data, nelem)) < 0)
1138 if ((encoded_size = get_nvp_data_size(type, data, nelem)) < 0)
1142 * The encoded size is calculated as:
1143 * encode_size (4) + decode_size (4) +
1144 * name string size (4 + NV_ALIGN4(namelen) +
1145 * data type (4) + nelem size (4) + datalen
1147 * The decoded size is calculated as:
1148 * Note: namelen is with terminating 0.
1149 * NV_ALIGN(sizeof (nvpair_t) (4 * 4) + namelen + 1) +
1150 * NV_ALIGN(data_len)
1153 head.encoded_size = NVPE_SIZE(namelen, encoded_size);
1154 head.decoded_size = NVP_SIZE(namelen + 1, decoded_size);
1156 if (nvl->nv_asize - nvl->nv_size < head.encoded_size + 8) {
1157 ptr = realloc(nvl->nv_data, nvl->nv_asize + head.encoded_size);
1161 nvl->nv_asize += head.encoded_size;
1163 nvl->nv_idx = nvl->nv_data + nvl->nv_size - sizeof (*hp);
1164 bzero(nvl->nv_idx, head.encoded_size + 8);
1165 hp = (nvp_header_t *)nvl->nv_idx;
1167 nvl->nv_idx += sizeof (*hp);
1168 *(unsigned *)nvl->nv_idx = namelen;
1169 nvl->nv_idx += sizeof (unsigned);
1170 strlcpy((char *)nvl->nv_idx, name, namelen + 1);
1171 nvl->nv_idx += NV_ALIGN4(namelen);
1172 *(unsigned *)nvl->nv_idx = type;
1173 nvl->nv_idx += sizeof (unsigned);
1174 *(unsigned *)nvl->nv_idx = nelem;
1175 nvl->nv_idx += sizeof (unsigned);
1178 case DATA_TYPE_BOOLEAN:
1180 case DATA_TYPE_BYTE_ARRAY:
1181 *(unsigned *)nvl->nv_idx = encoded_size;
1182 nvl->nv_idx += sizeof (unsigned);
1183 bcopy(data, nvl->nv_idx, nelem);
1184 nvl->nv_idx += encoded_size;
1186 case DATA_TYPE_STRING:
1187 encoded_size = strlen(data);
1188 *(unsigned *)nvl->nv_idx = encoded_size;
1189 nvl->nv_idx += sizeof (unsigned);
1190 strlcpy((char *)nvl->nv_idx, data, encoded_size + 1);
1191 nvl->nv_idx += NV_ALIGN4(encoded_size);
1193 case DATA_TYPE_STRING_ARRAY:
1194 for (uint32_t i = 0; i < nelem; i++) {
1195 encoded_size = strlen(((char **)data)[i]);
1196 *(unsigned *)nvl->nv_idx = encoded_size;
1197 nvl->nv_idx += sizeof (unsigned);
1198 strlcpy((char *)nvl->nv_idx, ((char **)data)[i],
1200 nvl->nv_idx += NV_ALIGN4(encoded_size);
1203 case DATA_TYPE_BYTE:
1204 case DATA_TYPE_INT8:
1205 case DATA_TYPE_UINT8:
1206 case DATA_TYPE_INT8_ARRAY:
1207 case DATA_TYPE_UINT8_ARRAY:
1208 for (uint32_t i = 0; i < nelem; i++) {
1209 *(unsigned *)nvl->nv_idx = ((uint8_t *)data)[i];
1210 nvl->nv_idx += sizeof (unsigned);
1213 case DATA_TYPE_INT16:
1214 case DATA_TYPE_UINT16:
1215 case DATA_TYPE_INT16_ARRAY:
1216 case DATA_TYPE_UINT16_ARRAY:
1217 for (uint32_t i = 0; i < nelem; i++) {
1218 *(unsigned *)nvl->nv_idx = ((uint16_t *)data)[i];
1219 nvl->nv_idx += sizeof (unsigned);
1222 case DATA_TYPE_NVLIST:
1223 bcopy(((nvlist_t *)data)->nv_data, nvl->nv_idx, encoded_size);
1225 case DATA_TYPE_NVLIST_ARRAY: {
1226 uint8_t *buf = nvl->nv_idx;
1230 for (uint32_t i = 0; i < nelem; i++) {
1231 xdr.xdr_idx = ((nvlist_t **)data)[i]->nv_data;
1232 xdr.xdr_buf = xdr.xdr_idx;
1233 xdr.xdr_buf_size = ((nvlist_t **)data)[i]->nv_size;
1235 if (!nvlist_size_native(&xdr, &size))
1238 bcopy(((nvlist_t **)data)[i]->nv_data, buf, size);
1244 bcopy(data, nvl->nv_idx, encoded_size);
1247 nvl->nv_size += head.encoded_size;
1253 nvlist_add_boolean_value(nvlist_t *nvl, const char *name, boolean_t value)
1255 return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_VALUE, 1,
1260 nvlist_add_byte(nvlist_t *nvl, const char *name, uint8_t value)
1262 return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE, 1, &value));
1266 nvlist_add_int8(nvlist_t *nvl, const char *name, int8_t value)
1268 return (nvlist_add_common(nvl, name, DATA_TYPE_INT8, 1, &value));
1272 nvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t value)
1274 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8, 1, &value));
1278 nvlist_add_int16(nvlist_t *nvl, const char *name, int16_t value)
1280 return (nvlist_add_common(nvl, name, DATA_TYPE_INT16, 1, &value));
1284 nvlist_add_uint16(nvlist_t *nvl, const char *name, uint16_t value)
1286 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16, 1, &value));
1290 nvlist_add_int32(nvlist_t *nvl, const char *name, int32_t value)
1292 return (nvlist_add_common(nvl, name, DATA_TYPE_INT32, 1, &value));
1296 nvlist_add_uint32(nvlist_t *nvl, const char *name, uint32_t value)
1298 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32, 1, &value));
1302 nvlist_add_int64(nvlist_t *nvl, const char *name, int64_t value)
1304 return (nvlist_add_common(nvl, name, DATA_TYPE_INT64, 1, &value));
1308 nvlist_add_uint64(nvlist_t *nvl, const char *name, uint64_t value)
1310 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64, 1, &value));
1314 nvlist_add_string(nvlist_t *nvl, const char *name, const char *value)
1316 return (nvlist_add_common(nvl, name, DATA_TYPE_STRING, 1, value));
1320 nvlist_add_boolean_array(nvlist_t *nvl, const char *name,
1321 boolean_t *a, uint32_t n)
1323 return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_ARRAY, n, a));
1327 nvlist_add_byte_array(nvlist_t *nvl, const char *name, uint8_t *a, uint32_t n)
1329 return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a));
1333 nvlist_add_int8_array(nvlist_t *nvl, const char *name, int8_t *a, uint32_t n)
1335 return (nvlist_add_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a));
1339 nvlist_add_uint8_array(nvlist_t *nvl, const char *name, uint8_t *a, uint32_t n)
1341 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a));
1345 nvlist_add_int16_array(nvlist_t *nvl, const char *name, int16_t *a, uint32_t n)
1347 return (nvlist_add_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a));
1351 nvlist_add_uint16_array(nvlist_t *nvl, const char *name, uint16_t *a,
1354 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a));
1358 nvlist_add_int32_array(nvlist_t *nvl, const char *name, int32_t *a, uint32_t n)
1360 return (nvlist_add_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a));
1364 nvlist_add_uint32_array(nvlist_t *nvl, const char *name, uint32_t *a,
1367 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a));
1371 nvlist_add_int64_array(nvlist_t *nvl, const char *name, int64_t *a, uint32_t n)
1373 return (nvlist_add_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a));
1377 nvlist_add_uint64_array(nvlist_t *nvl, const char *name, uint64_t *a,
1380 return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a));
1384 nvlist_add_string_array(nvlist_t *nvl, const char *name,
1385 char * const *a, uint32_t n)
1387 return (nvlist_add_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a));
1391 nvlist_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val)
1393 return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST, 1, val));
1397 nvlist_add_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **a,
1400 return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a));
1403 static const char *typenames[] = {
1404 "DATA_TYPE_UNKNOWN",
1405 "DATA_TYPE_BOOLEAN",
1414 "DATA_TYPE_BYTE_ARRAY",
1415 "DATA_TYPE_INT16_ARRAY",
1416 "DATA_TYPE_UINT16_ARRAY",
1417 "DATA_TYPE_INT32_ARRAY",
1418 "DATA_TYPE_UINT32_ARRAY",
1419 "DATA_TYPE_INT64_ARRAY",
1420 "DATA_TYPE_UINT64_ARRAY",
1421 "DATA_TYPE_STRING_ARRAY",
1424 "DATA_TYPE_NVLIST_ARRAY",
1425 "DATA_TYPE_BOOLEAN_VALUE",
1428 "DATA_TYPE_BOOLEAN_ARRAY",
1429 "DATA_TYPE_INT8_ARRAY",
1430 "DATA_TYPE_UINT8_ARRAY"
1434 nvpair_type_from_name(const char *name)
1438 for (i = 0; i < nitems(typenames); i++) {
1439 if (strcmp(name, typenames[i]) == 0)
1446 nvpair_find(nvlist_t *nv, const char *name)
1451 while ((nvh = nvlist_next_nvpair(nv, nvh)) != NULL) {
1452 nv_string_t *nvp_name;
1454 nvp_name = (nv_string_t *)(nvh + 1);
1455 if (nvp_name->nv_size == strlen(name) &&
1456 memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0)
1463 nvpair_print(nvp_header_t *nvp, unsigned int indent)
1465 nv_string_t *nvp_name;
1466 nv_pair_data_t *nvp_data;
1472 nvp_name = (nv_string_t *)((uintptr_t)nvp + sizeof (*nvp));
1473 nvp_data = (nv_pair_data_t *)
1474 NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] + nvp_name->nv_size);
1476 for (i = 0; i < indent; i++)
1479 printf("%s [%d] %.*s", typenames[nvp_data->nv_type],
1480 nvp_data->nv_nelem, nvp_name->nv_size, nvp_name->nv_data);
1482 switch (nvp_data->nv_type) {
1483 case DATA_TYPE_BYTE:
1484 case DATA_TYPE_INT8:
1485 case DATA_TYPE_UINT8:
1486 bcopy(nvp_data->nv_data, &u, sizeof (u));
1487 printf(" = 0x%x\n", (unsigned char)u);
1490 case DATA_TYPE_INT16:
1491 case DATA_TYPE_UINT16:
1492 bcopy(nvp_data->nv_data, &u, sizeof (u));
1493 printf(" = 0x%hx\n", (unsigned short)u);
1496 case DATA_TYPE_BOOLEAN_VALUE:
1497 case DATA_TYPE_INT32:
1498 case DATA_TYPE_UINT32:
1499 bcopy(nvp_data->nv_data, &u, sizeof (u));
1500 printf(" = 0x%x\n", u);
1503 case DATA_TYPE_INT64:
1504 case DATA_TYPE_UINT64:
1505 bcopy(nvp_data->nv_data, &u64, sizeof (u64));
1506 printf(" = 0x%jx\n", (uintmax_t)u64);
1509 case DATA_TYPE_STRING:
1510 case DATA_TYPE_STRING_ARRAY:
1511 nvp_name = (nv_string_t *)&nvp_data->nv_data[0];
1512 for (i = 0; i < nvp_data->nv_nelem; i++) {
1513 printf(" = \"%.*s\"\n", nvp_name->nv_size,
1518 case DATA_TYPE_NVLIST:
1520 nvlist.nv_data = &nvp_data->nv_data[0];
1521 nvlist_print(&nvlist, indent + 2);
1524 case DATA_TYPE_NVLIST_ARRAY:
1525 nvlist.nv_data = &nvp_data->nv_data[0];
1526 for (j = 0; j < nvp_data->nv_nelem; j++) {
1529 printf("[%d]\n", j);
1530 nvlist_print(&nvlist, indent + 2);
1531 if (j != nvp_data->nv_nelem - 1) {
1532 for (i = 0; i < indent; i++)
1535 typenames[nvp_data->nv_type],
1539 xdr.xdr_idx = nvlist.nv_data;
1540 xdr.xdr_buf = xdr.xdr_idx;
1541 xdr.xdr_buf_size = nvp->encoded_size -
1542 (xdr.xdr_idx - (uint8_t *)nvp);
1544 if (!nvlist_size_native(&xdr, &size))
1547 nvlist.nv_data += size;
1557 nvlist_print(const nvlist_t *nvl, unsigned int indent)
1562 data = (nvs_data_t *)nvl->nv_data;
1563 nvp = &data->nvl_pair; /* first pair in nvlist */
1564 while (nvp->encoded_size != 0 && nvp->decoded_size != 0) {
1565 nvpair_print(nvp, indent);
1566 nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size);
1568 printf("%*s\n", indent + 13, "End of nvlist");