Changeset View
Changeset View
Standalone View
Standalone View
stand/libsa/zfs/nvlist.c
Show All 21 Lines | |||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||||
* SUCH DAMAGE. | * SUCH DAMAGE. | ||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <stand.h> | #include <stand.h> | ||||
#include <stdbool.h> | |||||
#include <sys/endian.h> | #include <sys/endian.h> | ||||
#include <sys/stdint.h> | |||||
#include <zfsimpl.h> | #include <zfsimpl.h> | ||||
#include "libzfs.h" | #include "libzfs.h" | ||||
enum xdr_op { | |||||
XDR_OP_ENCODE = 1, | |||||
XDR_OP_DECODE = 2 | |||||
}; | |||||
typedef struct xdr { | typedef struct xdr { | ||||
int (*xdr_getint)(const struct xdr *, const void *, int *); | enum xdr_op xdr_op; | ||||
int (*xdr_getint)(struct xdr *, int *); | |||||
int (*xdr_putint)(struct xdr *, int); | |||||
int (*xdr_getuint)(struct xdr *, unsigned *); | |||||
int (*xdr_putuint)(struct xdr *, unsigned); | |||||
const uint8_t *xdr_buf; | |||||
uint8_t *xdr_idx; | |||||
size_t xdr_buf_size; | |||||
} xdr_t; | } xdr_t; | ||||
static int xdr_int(const xdr_t *, const void *, int *); | static int nvlist_xdr_nvlist(xdr_t *, nvlist_t *); | ||||
static int mem_int(const xdr_t *, const void *, int *); | static bool nvlist_size_xdr(xdr_t *, size_t *); | ||||
static void nvlist_decode_nvlist(const xdr_t *, nvlist_t *); | static bool nvlist_size_native(xdr_t *, size_t *); | ||||
static int nvlist_size(const xdr_t *, const uint8_t *); | static bool xdr_int(xdr_t *, int *); | ||||
static bool xdr_u_int(xdr_t *, unsigned *); | |||||
/* | typedef int (*xdrproc_t)(xdr_t *, void *); | ||||
* transform data from network to host. | |||||
*/ | |||||
xdr_t ntoh = { | |||||
.xdr_getint = xdr_int | |||||
}; | |||||
/* | /* Basic primitives for XDR translation operations, getint and putint. */ | ||||
* transform data from host to host. | static int | ||||
*/ | _getint(struct xdr *xdr, int *ip) | ||||
xdr_t native = { | { | ||||
.xdr_getint = mem_int | *ip = be32dec(xdr->xdr_idx); | ||||
}; | return (sizeof (int)); | ||||
} | |||||
/* | static int | ||||
* transform data from host to network. | _putint(struct xdr *xdr, int i) | ||||
*/ | { | ||||
xdr_t hton = { | int *ip = (int *)xdr->xdr_idx; | ||||
.xdr_getint = xdr_int | |||||
}; | |||||
*ip = htobe32(i); | |||||
return (sizeof (int)); | |||||
} | |||||
static int | static int | ||||
xdr_short(const xdr_t *xdr, const uint8_t *buf, short *ip) | _getuint(struct xdr *xdr, unsigned *ip) | ||||
{ | { | ||||
int i, rv; | *ip = be32dec(xdr->xdr_idx); | ||||
return (sizeof (unsigned)); | |||||
} | |||||
rv = xdr->xdr_getint(xdr, buf, &i); | static int | ||||
_putuint(struct xdr *xdr, unsigned i) | |||||
{ | |||||
unsigned *up = (unsigned *)xdr->xdr_idx; | |||||
*up = htobe32(i); | |||||
return (sizeof (int)); | |||||
} | |||||
/* | |||||
* XDR data translations. | |||||
*/ | |||||
static bool | |||||
xdr_short(xdr_t *xdr, short *ip) | |||||
{ | |||||
int i; | |||||
bool rv; | |||||
i = *ip; | |||||
if ((rv = xdr_int(xdr, &i))) { | |||||
if (xdr->xdr_op == XDR_OP_DECODE) | |||||
*ip = i; | *ip = i; | ||||
} | |||||
return (rv); | return (rv); | ||||
} | } | ||||
static int | static bool | ||||
xdr_u_short(const xdr_t *xdr, const uint8_t *buf, unsigned short *ip) | xdr_u_short(xdr_t *xdr, unsigned short *ip) | ||||
{ | { | ||||
unsigned u; | unsigned u; | ||||
int rv; | bool rv; | ||||
rv = xdr->xdr_getint(xdr, buf, &u); | u = *ip; | ||||
if ((rv = xdr_u_int(xdr, &u))) { | |||||
if (xdr->xdr_op == XDR_OP_DECODE) | |||||
*ip = u; | *ip = u; | ||||
} | |||||
return (rv); | return (rv); | ||||
} | } | ||||
static int | /* | ||||
xdr_int(const xdr_t *xdr __unused, const void *buf, int *ip) | * translate xdr->xdr_idx, increment it by size of int. | ||||
*/ | |||||
static bool | |||||
xdr_int(xdr_t *xdr, int *ip) | |||||
{ | { | ||||
*ip = be32dec(buf); | bool rv = false; | ||||
return (sizeof(int)); | int *i = (int *)xdr->xdr_idx; | ||||
} | |||||
static int | if (xdr->xdr_idx + sizeof (int) > xdr->xdr_buf + xdr->xdr_buf_size) | ||||
xdr_u_int(const xdr_t *xdr __unused, const void *buf, unsigned *ip) | return (rv); | ||||
{ | |||||
*ip = be32dec(buf); | switch (xdr->xdr_op) { | ||||
return (sizeof(unsigned)); | case XDR_OP_ENCODE: | ||||
/* Encode value *ip, store to buf */ | |||||
xdr->xdr_idx += xdr->xdr_putint(xdr, *ip); | |||||
rv = true; | |||||
break; | |||||
case XDR_OP_DECODE: | |||||
/* Decode buf, return value to *ip */ | |||||
xdr->xdr_idx += xdr->xdr_getint(xdr, i); | |||||
*ip = *i; | |||||
rv = true; | |||||
break; | |||||
} | } | ||||
return (rv); | |||||
} | |||||
static int | /* | ||||
xdr_string(const xdr_t *xdr, const void *buf, nv_string_t *s) | * translate xdr->xdr_idx, increment it by size of unsigned int. | ||||
*/ | |||||
static bool | |||||
xdr_u_int(xdr_t *xdr, unsigned *ip) | |||||
{ | { | ||||
int size; | bool rv = false; | ||||
unsigned *u = (unsigned *)xdr->xdr_idx; | |||||
size = xdr->xdr_getint(xdr, buf, &s->nv_size); | if (xdr->xdr_idx + sizeof (unsigned) > xdr->xdr_buf + xdr->xdr_buf_size) | ||||
size = NV_ALIGN4(size + s->nv_size); | return (rv); | ||||
return (size); | |||||
switch (xdr->xdr_op) { | |||||
case XDR_OP_ENCODE: | |||||
/* Encode value *ip, store to buf */ | |||||
xdr->xdr_idx += xdr->xdr_putuint(xdr, *ip); | |||||
rv = true; | |||||
break; | |||||
case XDR_OP_DECODE: | |||||
/* Decode buf, return value to *ip */ | |||||
xdr->xdr_idx += xdr->xdr_getuint(xdr, u); | |||||
*ip = *u; | |||||
rv = true; | |||||
break; | |||||
} | } | ||||
return (rv); | |||||
} | |||||
static int | static bool | ||||
xdr_int64(const xdr_t *xdr, const uint8_t *buf, int64_t *lp) | xdr_int64(xdr_t *xdr, int64_t *lp) | ||||
{ | { | ||||
int hi, rv; | int hi; | ||||
unsigned lo; | unsigned lo; | ||||
bool rv = false; | |||||
rv = xdr->xdr_getint(xdr, buf, &hi); | if (xdr->xdr_idx + sizeof (int64_t) > xdr->xdr_buf + xdr->xdr_buf_size) | ||||
rv += xdr->xdr_getint(xdr, buf + rv, &lo); | return (rv); | ||||
switch (xdr->xdr_op) { | |||||
case XDR_OP_ENCODE: | |||||
/* Encode value *lp, store to buf */ | |||||
hi = *lp >> 32; | |||||
lo = *lp & UINT32_MAX; | |||||
xdr->xdr_idx += xdr->xdr_putint(xdr, hi); | |||||
xdr->xdr_idx += xdr->xdr_putint(xdr, lo); | |||||
rv = true; | |||||
break; | |||||
case XDR_OP_DECODE: | |||||
/* Decode buf, return value to *ip */ | |||||
xdr->xdr_idx += xdr->xdr_getint(xdr, &hi); | |||||
xdr->xdr_idx += xdr->xdr_getuint(xdr, &lo); | |||||
*lp = (((int64_t)hi) << 32) | lo; | *lp = (((int64_t)hi) << 32) | lo; | ||||
rv = true; | |||||
} | |||||
return (rv); | return (rv); | ||||
} | } | ||||
static int | static bool | ||||
xdr_uint64(const xdr_t *xdr, const uint8_t *buf, uint64_t *lp) | xdr_uint64(xdr_t *xdr, uint64_t *lp) | ||||
{ | { | ||||
unsigned hi, lo; | unsigned hi, lo; | ||||
int rv; | bool rv = false; | ||||
rv = xdr->xdr_getint(xdr, buf, &hi); | if (xdr->xdr_idx + sizeof (uint64_t) > xdr->xdr_buf + xdr->xdr_buf_size) | ||||
rv += xdr->xdr_getint(xdr, buf + rv, &lo); | |||||
*lp = (((int64_t)hi) << 32) | lo; | |||||
return (rv); | return (rv); | ||||
switch (xdr->xdr_op) { | |||||
case XDR_OP_ENCODE: | |||||
/* Encode value *ip, store to buf */ | |||||
hi = *lp >> 32; | |||||
lo = *lp & UINT32_MAX; | |||||
xdr->xdr_idx += xdr->xdr_putint(xdr, hi); | |||||
xdr->xdr_idx += xdr->xdr_putint(xdr, lo); | |||||
rv = true; | |||||
break; | |||||
case XDR_OP_DECODE: | |||||
/* Decode buf, return value to *ip */ | |||||
xdr->xdr_idx += xdr->xdr_getuint(xdr, &hi); | |||||
xdr->xdr_idx += xdr->xdr_getuint(xdr, &lo); | |||||
*lp = (((uint64_t)hi) << 32) | lo; | |||||
rv = true; | |||||
} | } | ||||
return (rv); | |||||
} | |||||
static int | static bool | ||||
xdr_char(const xdr_t *xdr, const uint8_t *buf, char *cp) | xdr_char(xdr_t *xdr, char *cp) | ||||
{ | { | ||||
int i, rv; | int i; | ||||
bool rv = false; | |||||
rv = xdr->xdr_getint(xdr, buf, &i); | i = *cp; | ||||
if ((rv = xdr_int(xdr, &i))) { | |||||
if (xdr->xdr_op == XDR_OP_DECODE) | |||||
*cp = i; | *cp = i; | ||||
} | |||||
return (rv); | return (rv); | ||||
} | } | ||||
/* | static bool | ||||
* read native data. | xdr_string(xdr_t *xdr, nv_string_t *s) | ||||
*/ | |||||
static int | |||||
mem_int(const xdr_t *xdr, const void *buf, int *i) | |||||
{ | { | ||||
*i = *(int *)buf; | int size = 0; | ||||
return (sizeof(int)); | bool rv = false; | ||||
switch (xdr->xdr_op) { | |||||
case XDR_OP_ENCODE: | |||||
size = s->nv_size; | |||||
if (xdr->xdr_idx + sizeof (unsigned) + NV_ALIGN4(size) > | |||||
xdr->xdr_buf + xdr->xdr_buf_size) | |||||
break; | |||||
xdr->xdr_idx += xdr->xdr_putuint(xdr, s->nv_size); | |||||
xdr->xdr_idx += NV_ALIGN4(size); | |||||
rv = true; | |||||
break; | |||||
case XDR_OP_DECODE: | |||||
if (xdr->xdr_idx + sizeof (unsigned) > | |||||
xdr->xdr_buf + xdr->xdr_buf_size) | |||||
break; | |||||
size = xdr->xdr_getuint(xdr, &s->nv_size); | |||||
size = NV_ALIGN4(size + s->nv_size); | |||||
if (xdr->xdr_idx + size > xdr->xdr_buf + xdr->xdr_buf_size) | |||||
break; | |||||
xdr->xdr_idx += size; | |||||
rv = true; | |||||
break; | |||||
} | } | ||||
return (rv); | |||||
} | |||||
static bool | |||||
xdr_array(xdr_t *xdr, const unsigned nelem, const xdrproc_t elproc) | |||||
{ | |||||
bool rv = true; | |||||
for (unsigned i = 0; i < nelem; i++) { | |||||
if (!elproc(xdr, xdr->xdr_idx)) | |||||
return (false); | |||||
} | |||||
return (rv); | |||||
} | |||||
/* | |||||
* nvlist management functions. | |||||
*/ | |||||
void | void | ||||
nvlist_destroy(nvlist_t *nvl) | nvlist_destroy(nvlist_t *nvl) | ||||
{ | { | ||||
if (nvl != NULL) { | if (nvl != NULL) { | ||||
/* Free data if it was allocated by us. */ | /* Free data if it was allocated by us. */ | ||||
if (nvl->nv_asize > 0) | if (nvl->nv_asize > 0) | ||||
free(nvl->nv_data); | free(nvl->nv_data); | ||||
} | } | ||||
Show All 18 Lines | |||||
* The nvlist is terminated by 2x zeros (8 bytes). | * The nvlist is terminated by 2x zeros (8 bytes). | ||||
*/ | */ | ||||
nvlist_t * | nvlist_t * | ||||
nvlist_create(int flag) | nvlist_create(int flag) | ||||
{ | { | ||||
nvlist_t *nvl; | nvlist_t *nvl; | ||||
nvs_data_t *nvs; | nvs_data_t *nvs; | ||||
nvl = calloc(1, sizeof(*nvl)); | nvl = calloc(1, sizeof (*nvl)); | ||||
if (nvl == NULL) | if (nvl == NULL) | ||||
return (nvl); | return (nvl); | ||||
nvl->nv_header.nvh_encoding = NV_ENCODE_XDR; | nvl->nv_header.nvh_encoding = NV_ENCODE_XDR; | ||||
nvl->nv_header.nvh_endian = _BYTE_ORDER == _LITTLE_ENDIAN; | nvl->nv_header.nvh_endian = _BYTE_ORDER == _LITTLE_ENDIAN; | ||||
nvl->nv_asize = nvl->nv_size = sizeof(*nvs); | nvl->nv_asize = nvl->nv_size = sizeof (*nvs); | ||||
nvs = calloc(1, nvl->nv_asize); | nvs = calloc(1, nvl->nv_asize); | ||||
if (nvs == NULL) { | if (nvs == NULL) { | ||||
free(nvl); | free(nvl); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
/* data in nvlist is byte stream */ | /* data in nvlist is byte stream */ | ||||
nvl->nv_data = (uint8_t *)nvs; | nvl->nv_data = (uint8_t *)nvs; | ||||
nvs->nvl_version = NV_VERSION; | nvs->nvl_version = NV_VERSION; | ||||
nvs->nvl_nvflag = flag; | nvs->nvl_nvflag = flag; | ||||
return (nvl); | return (nvl); | ||||
} | } | ||||
static void | static bool | ||||
nvlist_nvp_decode(const xdr_t *xdr, nvlist_t *nvl, nvp_header_t *nvph) | nvlist_xdr_nvp(xdr_t *xdr, nvlist_t *nvl) | ||||
{ | { | ||||
nv_string_t *nv_string; | nv_string_t *nv_string; | ||||
nv_pair_data_t *nvp_data; | nv_pair_data_t *nvp_data; | ||||
nvlist_t nvlist; | nvlist_t nvlist; | ||||
unsigned type, nelem; | |||||
xdr_t nv_xdr; | |||||
nv_string = (nv_string_t *)nvl->nv_idx; | nv_string = (nv_string_t *)xdr->xdr_idx; | ||||
nvl->nv_idx += xdr_string(xdr, &nv_string->nv_size, nv_string); | if (!xdr_string(xdr, nv_string)) { | ||||
nvp_data = (nv_pair_data_t *)nvl->nv_idx; | return (false); | ||||
} | |||||
nvp_data = (nv_pair_data_t *)xdr->xdr_idx; | |||||
nvl->nv_idx += xdr_u_int(xdr, &nvp_data->nv_type, &nvp_data->nv_type); | type = nvp_data->nv_type; | ||||
nvl->nv_idx += xdr_u_int(xdr, &nvp_data->nv_nelem, &nvp_data->nv_nelem); | nelem = nvp_data->nv_nelem; | ||||
if (!xdr_u_int(xdr, &type) || !xdr_u_int(xdr, &nelem)) | |||||
return (false); | |||||
switch (nvp_data->nv_type) { | switch (type) { | ||||
case DATA_TYPE_NVLIST: | case DATA_TYPE_NVLIST: | ||||
case DATA_TYPE_NVLIST_ARRAY: | case DATA_TYPE_NVLIST_ARRAY: | ||||
bzero(&nvlist, sizeof (nvlist)); | bzero(&nvlist, sizeof (nvlist)); | ||||
nvlist.nv_data = &nvp_data->nv_data[0]; | nvlist.nv_data = xdr->xdr_idx; | ||||
nvlist.nv_idx = nvlist.nv_data; | nvlist.nv_idx = nvlist.nv_data; | ||||
for (int i = 0; i < nvp_data->nv_nelem; i++) { | |||||
nvlist.nv_asize = | /* Set up xdr for this nvlist. */ | ||||
nvlist_size(xdr, nvlist.nv_data); | nv_xdr = *xdr; | ||||
nvlist_decode_nvlist(xdr, &nvlist); | nv_xdr.xdr_buf = nvlist.nv_data; | ||||
nvl->nv_idx = nvlist.nv_idx; | nv_xdr.xdr_idx = nvlist.nv_data; | ||||
nvlist.nv_data = nvlist.nv_idx; | nv_xdr.xdr_buf_size = | ||||
nvl->nv_data + nvl->nv_size - nvlist.nv_data; | |||||
for (unsigned i = 0; i < nelem; i++) { | |||||
if (xdr->xdr_op == XDR_OP_ENCODE) { | |||||
if (!nvlist_size_native(&nv_xdr, | |||||
&nvlist.nv_size)) | |||||
return (false); | |||||
} else { | |||||
if (!nvlist_size_xdr(&nv_xdr, | |||||
&nvlist.nv_size)) | |||||
return (false); | |||||
} | } | ||||
if (nvlist_xdr_nvlist(xdr, &nvlist) != 0) | |||||
return (false); | |||||
nvlist.nv_data = nv_xdr.xdr_idx; | |||||
nvlist.nv_idx = nv_xdr.xdr_idx; | |||||
nv_xdr.xdr_buf = nv_xdr.xdr_idx; | |||||
nv_xdr.xdr_buf_size = | |||||
nvl->nv_data + nvl->nv_size - nvlist.nv_data; | |||||
} | |||||
break; | break; | ||||
case DATA_TYPE_BOOLEAN: | case DATA_TYPE_BOOLEAN: | ||||
/* BOOLEAN does not take value space */ | /* BOOLEAN does not take value space */ | ||||
break; | break; | ||||
case DATA_TYPE_BYTE: | case DATA_TYPE_BYTE: | ||||
case DATA_TYPE_INT8: | case DATA_TYPE_INT8: | ||||
case DATA_TYPE_UINT8: | case DATA_TYPE_UINT8: | ||||
nvl->nv_idx += xdr_char(xdr, &nvp_data->nv_data[0], | if (!xdr_char(xdr, (char *)&nvp_data->nv_data[0])) | ||||
(char *)&nvp_data->nv_data[0]); | return (false); | ||||
break; | break; | ||||
case DATA_TYPE_INT16: | case DATA_TYPE_INT16: | ||||
nvl->nv_idx += xdr_short(xdr, &nvp_data->nv_data[0], | if (!xdr_short(xdr, (short *)&nvp_data->nv_data[0])) | ||||
(short *)&nvp_data->nv_data[0]); | return (false); | ||||
break; | break; | ||||
case DATA_TYPE_UINT16: | case DATA_TYPE_UINT16: | ||||
nvl->nv_idx += xdr_u_short(xdr, &nvp_data->nv_data[0], | if (!xdr_u_short(xdr, (unsigned short *)&nvp_data->nv_data[0])) | ||||
(unsigned short *)&nvp_data->nv_data[0]); | return (false); | ||||
break; | break; | ||||
case DATA_TYPE_BOOLEAN_VALUE: | case DATA_TYPE_BOOLEAN_VALUE: | ||||
case DATA_TYPE_INT32: | case DATA_TYPE_INT32: | ||||
nvl->nv_idx += xdr_int(xdr, &nvp_data->nv_data[0], | if (!xdr_int(xdr, (int *)&nvp_data->nv_data[0])) | ||||
(int *)&nvp_data->nv_data[0]); | return (false); | ||||
break; | break; | ||||
case DATA_TYPE_UINT32: | case DATA_TYPE_UINT32: | ||||
nvl->nv_idx += xdr_u_int(xdr, &nvp_data->nv_data[0], | if (!xdr_u_int(xdr, (unsigned *)&nvp_data->nv_data[0])) | ||||
(unsigned *)&nvp_data->nv_data[0]); | return (false); | ||||
break; | break; | ||||
case DATA_TYPE_HRTIME: | |||||
case DATA_TYPE_INT64: | case DATA_TYPE_INT64: | ||||
nvl->nv_idx += xdr_int64(xdr, &nvp_data->nv_data[0], | if (!xdr_int64(xdr, (int64_t *)&nvp_data->nv_data[0])) | ||||
(int64_t *)&nvp_data->nv_data[0]); | return (false); | ||||
break; | break; | ||||
case DATA_TYPE_UINT64: | case DATA_TYPE_UINT64: | ||||
nvl->nv_idx += xdr_uint64(xdr, &nvp_data->nv_data[0], | if (!xdr_uint64(xdr, (uint64_t *)&nvp_data->nv_data[0])) | ||||
(uint64_t *)&nvp_data->nv_data[0]); | return (false); | ||||
break; | break; | ||||
case DATA_TYPE_BYTE_ARRAY: | |||||
case DATA_TYPE_STRING: | case DATA_TYPE_STRING: | ||||
nv_string = (nv_string_t *)&nvp_data->nv_data[0]; | nv_string = (nv_string_t *)&nvp_data->nv_data[0]; | ||||
nvl->nv_idx += xdr_string(xdr, &nvp_data->nv_data[0], | if (!xdr_string(xdr, nv_string)) | ||||
nv_string); | return (false); | ||||
break; | |||||
case DATA_TYPE_STRING_ARRAY: | |||||
nv_string = (nv_string_t *)&nvp_data->nv_data[0]; | |||||
for (unsigned i = 0; i < nelem; i++) { | |||||
if (!xdr_string(xdr, nv_string)) | |||||
return (false); | |||||
nv_string = (nv_string_t *)xdr->xdr_idx; | |||||
} | |||||
break; | break; | ||||
case DATA_TYPE_INT8_ARRAY: | |||||
case DATA_TYPE_UINT8_ARRAY: | |||||
case DATA_TYPE_INT16_ARRAY: | |||||
case DATA_TYPE_UINT16_ARRAY: | |||||
case DATA_TYPE_BOOLEAN_ARRAY: | |||||
case DATA_TYPE_INT32_ARRAY: | |||||
case DATA_TYPE_UINT32_ARRAY: | |||||
if (!xdr_array(xdr, nelem, (xdrproc_t)xdr_u_int)) | |||||
return (false); | |||||
break; | |||||
case DATA_TYPE_INT64_ARRAY: | |||||
case DATA_TYPE_UINT64_ARRAY: | |||||
if (!xdr_array(xdr, nelem, (xdrproc_t)xdr_uint64)) | |||||
return (false); | |||||
break; | |||||
} | } | ||||
return (true); | |||||
} | } | ||||
static void | static int | ||||
nvlist_decode_nvlist(const xdr_t *xdr, nvlist_t *nvl) | nvlist_xdr_nvlist(xdr_t *xdr, nvlist_t *nvl) | ||||
{ | { | ||||
nvp_header_t *nvph; | nvp_header_t *nvph; | ||||
nvs_data_t *nvs = (nvs_data_t *)nvl->nv_data; | nvs_data_t *nvs; | ||||
unsigned encoded_size, decoded_size; | |||||
int rv; | |||||
nvl->nv_idx = nvl->nv_data; | nvs = (nvs_data_t *)xdr->xdr_idx; | ||||
nvl->nv_idx += xdr->xdr_getint(xdr, (const uint8_t *)&nvs->nvl_version, | |||||
&nvs->nvl_version); | |||||
nvl->nv_idx += xdr->xdr_getint(xdr, (const uint8_t *)&nvs->nvl_nvflag, | |||||
&nvs->nvl_nvflag); | |||||
nvph = &nvs->nvl_pair; | nvph = &nvs->nvl_pair; | ||||
nvl->nv_idx += xdr->xdr_getint(xdr, | |||||
(const uint8_t *)&nvph->encoded_size, &nvph->encoded_size); | |||||
nvl->nv_idx += xdr->xdr_getint(xdr, | |||||
(const uint8_t *)&nvph->decoded_size, &nvph->decoded_size); | |||||
while (nvph->encoded_size && nvph->decoded_size) { | if (!xdr_u_int(xdr, &nvs->nvl_version)) | ||||
nvlist_nvp_decode(xdr, nvl, nvph); | return (EINVAL); | ||||
if (!xdr_u_int(xdr, &nvs->nvl_nvflag)) | |||||
return (EINVAL); | |||||
nvph = (nvp_header_t *)(nvl->nv_idx); | encoded_size = nvph->encoded_size; | ||||
nvl->nv_idx += xdr->xdr_getint(xdr, &nvph->encoded_size, | decoded_size = nvph->decoded_size; | ||||
&nvph->encoded_size); | |||||
nvl->nv_idx += xdr->xdr_getint(xdr, &nvph->decoded_size, | if (xdr->xdr_op == XDR_OP_ENCODE) { | ||||
&nvph->decoded_size); | if (!xdr_u_int(xdr, &nvph->encoded_size)) | ||||
return (EINVAL); | |||||
if (!xdr_u_int(xdr, &nvph->decoded_size)) | |||||
return (EINVAL); | |||||
} else { | |||||
xdr->xdr_idx += 2 * sizeof (unsigned); | |||||
} | } | ||||
rv = 0; | |||||
while (encoded_size && decoded_size) { | |||||
if (!nvlist_xdr_nvp(xdr, nvl)) | |||||
return (EINVAL); | |||||
nvph = (nvp_header_t *)(xdr->xdr_idx); | |||||
encoded_size = nvph->encoded_size; | |||||
decoded_size = nvph->decoded_size; | |||||
if (xdr->xdr_op == XDR_OP_ENCODE) { | |||||
if (!xdr_u_int(xdr, &nvph->encoded_size)) | |||||
return (EINVAL); | |||||
if (!xdr_u_int(xdr, &nvph->decoded_size)) | |||||
return (EINVAL); | |||||
} else { | |||||
xdr->xdr_idx += 2 * sizeof (unsigned); | |||||
} | } | ||||
} | |||||
return (rv); | |||||
} | |||||
static int | /* | ||||
nvlist_size(const xdr_t *xdr, const uint8_t *stream) | * Calculate nvlist size, translating encoded_size and decoded_size. | ||||
*/ | |||||
static bool | |||||
nvlist_size_xdr(xdr_t *xdr, size_t *size) | |||||
{ | { | ||||
const uint8_t *p, *pair; | uint8_t *pair; | ||||
unsigned encoded_size, decoded_size; | unsigned encoded_size, decoded_size; | ||||
p = stream; | xdr->xdr_idx += 2 * sizeof (unsigned); | ||||
p += 2 * sizeof(unsigned); | |||||
pair = p; | pair = xdr->xdr_idx; | ||||
p += xdr->xdr_getint(xdr, p, &encoded_size); | if (!xdr_u_int(xdr, &encoded_size) || !xdr_u_int(xdr, &decoded_size)) | ||||
p += xdr->xdr_getint(xdr, p, &decoded_size); | return (false); | ||||
while (encoded_size && decoded_size) { | while (encoded_size && decoded_size) { | ||||
p = pair + encoded_size; | xdr->xdr_idx = pair + encoded_size; | ||||
pair = p; | pair = xdr->xdr_idx; | ||||
p += xdr->xdr_getint(xdr, p, &encoded_size); | if (!xdr_u_int(xdr, &encoded_size) || | ||||
p += xdr->xdr_getint(xdr, p, &decoded_size); | !xdr_u_int(xdr, &decoded_size)) | ||||
return (false); | |||||
} | } | ||||
return (p - stream); | *size = xdr->xdr_idx - xdr->xdr_buf; | ||||
return (true); | |||||
} | } | ||||
nvp_header_t * | |||||
nvlist_next_nvpair(nvlist_t *nvl, nvp_header_t *nvh) | |||||
{ | |||||
uint8_t *pair; | |||||
unsigned encoded_size, decoded_size; | |||||
xdr_t xdr; | |||||
if (nvl == NULL) | |||||
return (NULL); | |||||
xdr.xdr_buf = nvl->nv_data; | |||||
xdr.xdr_idx = nvl->nv_data; | |||||
xdr.xdr_buf_size = nvl->nv_size; | |||||
xdr.xdr_idx += 2 * sizeof (unsigned); | |||||
/* Skip tp current pair */ | |||||
if (nvh != NULL) { | |||||
xdr.xdr_idx = (uint8_t *)nvh; | |||||
} | |||||
pair = xdr.xdr_idx; | |||||
if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size) | |||||
return (NULL); | |||||
encoded_size = *(unsigned *)xdr.xdr_idx; | |||||
xdr.xdr_idx += sizeof (unsigned); | |||||
if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size) | |||||
return (NULL); | |||||
decoded_size = *(unsigned *)xdr.xdr_idx; | |||||
xdr.xdr_idx += sizeof (unsigned); | |||||
if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size) | |||||
return (NULL); | |||||
while (encoded_size && decoded_size) { | |||||
if (nvh == NULL) | |||||
return ((nvp_header_t *)pair); | |||||
xdr.xdr_idx = pair + encoded_size; | |||||
nvh = (nvp_header_t *)xdr.xdr_idx; | |||||
if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size) | |||||
return (NULL); | |||||
encoded_size = *(unsigned *)xdr.xdr_idx; | |||||
xdr.xdr_idx += sizeof (unsigned); | |||||
if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size) | |||||
return (NULL); | |||||
decoded_size = *(unsigned *)xdr.xdr_idx; | |||||
xdr.xdr_idx += sizeof (unsigned); | |||||
if (xdr.xdr_idx > xdr.xdr_buf + xdr.xdr_buf_size) | |||||
return (NULL); | |||||
if (encoded_size != 0 && decoded_size != 0) { | |||||
return (nvh); | |||||
} | |||||
} | |||||
return (NULL); | |||||
} | |||||
/* | /* | ||||
* Calculate nvlist size by walking in memory data. | |||||
*/ | |||||
static bool | |||||
nvlist_size_native(xdr_t *xdr, size_t *size) | |||||
{ | |||||
uint8_t *pair; | |||||
unsigned encoded_size, decoded_size; | |||||
xdr->xdr_idx += 2 * sizeof (unsigned); | |||||
pair = xdr->xdr_idx; | |||||
if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size) | |||||
return (false); | |||||
encoded_size = *(unsigned *)xdr->xdr_idx; | |||||
xdr->xdr_idx += sizeof (unsigned); | |||||
if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size) | |||||
return (false); | |||||
decoded_size = *(unsigned *)xdr->xdr_idx; | |||||
xdr->xdr_idx += sizeof (unsigned); | |||||
while (encoded_size && decoded_size) { | |||||
xdr->xdr_idx = pair + encoded_size; | |||||
pair = xdr->xdr_idx; | |||||
if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size) | |||||
return (false); | |||||
encoded_size = *(unsigned *)xdr->xdr_idx; | |||||
xdr->xdr_idx += sizeof (unsigned); | |||||
if (xdr->xdr_idx > xdr->xdr_buf + xdr->xdr_buf_size) | |||||
return (false); | |||||
decoded_size = *(unsigned *)xdr->xdr_idx; | |||||
xdr->xdr_idx += sizeof (unsigned); | |||||
} | |||||
*size = xdr->xdr_idx - xdr->xdr_buf; | |||||
return (true); | |||||
} | |||||
/* | |||||
* Export nvlist to byte stream format. | |||||
*/ | |||||
int | |||||
nvlist_export(nvlist_t *nvl) | |||||
{ | |||||
int rv; | |||||
xdr_t xdr = { | |||||
.xdr_op = XDR_OP_ENCODE, | |||||
.xdr_putint = _putint, | |||||
.xdr_putuint = _putuint, | |||||
.xdr_buf = nvl->nv_data, | |||||
.xdr_idx = nvl->nv_data, | |||||
.xdr_buf_size = nvl->nv_size | |||||
}; | |||||
if (nvl->nv_header.nvh_encoding != NV_ENCODE_XDR) | |||||
return (ENOTSUP); | |||||
nvl->nv_idx = nvl->nv_data; | |||||
rv = nvlist_xdr_nvlist(&xdr, nvl); | |||||
return (rv); | |||||
} | |||||
/* | |||||
* Import nvlist from byte stream. | * Import nvlist from byte stream. | ||||
* Determine the stream size and allocate private copy. | * Determine the stream size and allocate private copy. | ||||
* Then translate the data. | * Then translate the data. | ||||
*/ | */ | ||||
nvlist_t * | nvlist_t * | ||||
nvlist_import(const uint8_t *stream, char encoding, char endian) | nvlist_import(const char *stream, size_t size) | ||||
{ | { | ||||
nvlist_t *nvl; | nvlist_t *nvl; | ||||
xdr_t xdr = { | |||||
.xdr_op = XDR_OP_DECODE, | |||||
.xdr_getint = _getint, | |||||
.xdr_getuint = _getuint | |||||
}; | |||||
if (encoding != NV_ENCODE_XDR) | /* Check the nvlist head. */ | ||||
if (stream[0] != NV_ENCODE_XDR || | |||||
(stream[1] != '\0' && stream[1] != '\1') || | |||||
stream[2] != '\0' || stream[3] != '\0' || | |||||
be32toh(*(uint32_t *)(stream + 4)) != NV_VERSION || | |||||
be32toh(*(uint32_t *)(stream + 8)) != NV_UNIQUE_NAME) | |||||
return (NULL); | return (NULL); | ||||
nvl = malloc(sizeof(*nvl)); | nvl = malloc(sizeof (*nvl)); | ||||
if (nvl == NULL) | if (nvl == NULL) | ||||
return (nvl); | return (nvl); | ||||
nvl->nv_asize = nvl->nv_size = nvlist_size(&ntoh, stream); | nvl->nv_header.nvh_encoding = stream[0]; | ||||
nvl->nv_header.nvh_endian = stream[1]; | |||||
nvl->nv_header.nvh_reserved1 = stream[2]; | |||||
nvl->nv_header.nvh_reserved2 = stream[3]; | |||||
xdr.xdr_buf = xdr.xdr_idx = (uint8_t *)stream + 4; | |||||
xdr.xdr_buf_size = size - 4; | |||||
if (!nvlist_size_xdr(&xdr, &nvl->nv_asize)) { | |||||
free(nvl); | |||||
return (NULL); | |||||
} | |||||
nvl->nv_size = nvl->nv_asize; | |||||
nvl->nv_data = malloc(nvl->nv_asize); | nvl->nv_data = malloc(nvl->nv_asize); | ||||
if (nvl->nv_data == NULL) { | if (nvl->nv_data == NULL) { | ||||
free(nvl); | free(nvl); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
nvl->nv_idx = nvl->nv_data; | nvl->nv_idx = nvl->nv_data; | ||||
bcopy(stream, nvl->nv_data, nvl->nv_asize); | bcopy(stream + 4, nvl->nv_data, nvl->nv_asize); | ||||
nvlist_decode_nvlist(&ntoh, nvl); | xdr.xdr_buf = xdr.xdr_idx = nvl->nv_data; | ||||
nvl->nv_idx = nvl->nv_data; | xdr.xdr_buf_size = nvl->nv_asize; | ||||
if (nvlist_xdr_nvlist(&xdr, nvl) != 0) { | |||||
free(nvl->nv_data); | |||||
free(nvl); | |||||
nvl = NULL; | |||||
} | |||||
return (nvl); | return (nvl); | ||||
} | } | ||||
/* | /* | ||||
* remove pair from this nvlist. | * remove pair from this nvlist. | ||||
*/ | */ | ||||
int | int | ||||
nvlist_remove(nvlist_t *nvl, const char *name, data_type_t type) | nvlist_remove(nvlist_t *nvl, const char *name, data_type_t type) | ||||
{ | { | ||||
uint8_t *head, *tail; | uint8_t *head, *tail; | ||||
nvs_data_t *data; | nvs_data_t *data; | ||||
nvp_header_t *nvp; | nvp_header_t *nvp; | ||||
nv_string_t *nvp_name; | nv_string_t *nvp_name; | ||||
nv_pair_data_t *nvp_data; | nv_pair_data_t *nvp_data; | ||||
size_t size; | size_t size; | ||||
xdr_t xdr; | |||||
if (nvl == NULL || nvl->nv_data == NULL || name == NULL) | if (nvl == NULL || nvl->nv_data == NULL || name == NULL) | ||||
return (EINVAL); | return (EINVAL); | ||||
head = nvl->nv_data; | /* Make sure the nvlist size is set correct */ | ||||
data = (nvs_data_t *)head; | xdr.xdr_idx = nvl->nv_data; | ||||
xdr.xdr_buf = xdr.xdr_idx; | |||||
xdr.xdr_buf_size = nvl->nv_size; | |||||
if (!nvlist_size_native(&xdr, &nvl->nv_size)) | |||||
return (EINVAL); | |||||
data = (nvs_data_t *)nvl->nv_data; | |||||
nvp = &data->nvl_pair; /* first pair in nvlist */ | nvp = &data->nvl_pair; /* first pair in nvlist */ | ||||
head = (uint8_t *)nvp; | head = (uint8_t *)nvp; | ||||
while (nvp->encoded_size != 0 && nvp->decoded_size != 0) { | while (nvp->encoded_size != 0 && nvp->decoded_size != 0) { | ||||
nvp_name = (nv_string_t *)(head + sizeof(*nvp)); | nvp_name = (nv_string_t *)(nvp + 1); | ||||
nvp_data = (nv_pair_data_t *) | nvp_data = (nv_pair_data_t *)(&nvp_name->nv_data[0] + | ||||
NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] + | NV_ALIGN4(nvp_name->nv_size)); | ||||
nvp_name->nv_size); | |||||
if (memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0 && | if (strlen(name) == nvp_name->nv_size && | ||||
nvp_data->nv_type == type) { | memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0 && | ||||
(nvp_data->nv_type == type || type == DATA_TYPE_UNKNOWN)) { | |||||
/* | /* | ||||
* set tail to point to next nvpair and size | * set tail to point to next nvpair and size | ||||
* is the length of the tail. | * is the length of the tail. | ||||
*/ | */ | ||||
tail = head + nvp->encoded_size; | tail = head + nvp->encoded_size; | ||||
size = nvl->nv_data + nvl->nv_size - tail; | size = nvl->nv_size - (tail - nvl->nv_data); | ||||
/* adjust the size of the nvlist. */ | /* adjust the size of the nvlist. */ | ||||
nvl->nv_size -= nvp->encoded_size; | nvl->nv_size -= nvp->encoded_size; | ||||
bcopy(tail, head, size); | bcopy(tail, head, size); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* Not our pair, skip to next. */ | /* Not our pair, skip to next. */ | ||||
head = head + nvp->encoded_size; | head = head + nvp->encoded_size; | ||||
nvp = (nvp_header_t *)head; | nvp = (nvp_header_t *)head; | ||||
} | } | ||||
return (ENOENT); | return (ENOENT); | ||||
} | } | ||||
static int | |||||
clone_nvlist(const nvlist_t *nvl, const uint8_t *ptr, unsigned size, | |||||
nvlist_t **nvlist) | |||||
{ | |||||
nvlist_t *nv; | |||||
nv = calloc(1, sizeof (*nv)); | |||||
if (nv == NULL) | |||||
return (ENOMEM); | |||||
nv->nv_header = nvl->nv_header; | |||||
nv->nv_asize = size; | |||||
nv->nv_size = size; | |||||
nv->nv_data = malloc(nv->nv_asize); | |||||
if (nv->nv_data == NULL) { | |||||
free(nv); | |||||
return (ENOMEM); | |||||
} | |||||
bcopy(ptr, nv->nv_data, nv->nv_asize); | |||||
*nvlist = nv; | |||||
return (0); | |||||
} | |||||
/* | |||||
* Return the next nvlist in an nvlist array. | |||||
*/ | |||||
static uint8_t * | |||||
nvlist_next(const uint8_t *ptr) | |||||
{ | |||||
nvs_data_t *data; | |||||
nvp_header_t *nvp; | |||||
data = (nvs_data_t *)ptr; | |||||
nvp = &data->nvl_pair; /* first pair in nvlist */ | |||||
while (nvp->encoded_size != 0 && nvp->decoded_size != 0) { | |||||
nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size); | |||||
} | |||||
return ((uint8_t *)nvp + sizeof (*nvp)); | |||||
} | |||||
/* | |||||
* Note: nvlist and nvlist array must be freed by caller. | |||||
*/ | |||||
int | int | ||||
nvlist_find(const nvlist_t *nvl, const char *name, data_type_t type, | nvlist_find(const nvlist_t *nvl, const char *name, data_type_t type, | ||||
int *elementsp, void *valuep, int *sizep) | int *elementsp, void *valuep, int *sizep) | ||||
{ | { | ||||
nvs_data_t *data; | nvs_data_t *data; | ||||
nvp_header_t *nvp; | nvp_header_t *nvp; | ||||
nv_string_t *nvp_name; | nv_string_t *nvp_name; | ||||
nv_pair_data_t *nvp_data; | nv_pair_data_t *nvp_data; | ||||
nvlist_t *nvlist; | nvlist_t **nvlist, *nv; | ||||
uint8_t *ptr; | |||||
int rv; | |||||
if (nvl == NULL || nvl->nv_data == NULL || name == NULL) | if (nvl == NULL || nvl->nv_data == NULL || name == NULL) | ||||
return (EINVAL); | return (EINVAL); | ||||
data = (nvs_data_t *)nvl->nv_data; | data = (nvs_data_t *)nvl->nv_data; | ||||
nvp = &data->nvl_pair; /* first pair in nvlist */ | nvp = &data->nvl_pair; /* first pair in nvlist */ | ||||
while (nvp->encoded_size != 0 && nvp->decoded_size != 0) { | while (nvp->encoded_size != 0 && nvp->decoded_size != 0) { | ||||
nvp_name = (nv_string_t *)((uint8_t *)nvp + sizeof(*nvp)); | nvp_name = (nv_string_t *)((uint8_t *)nvp + sizeof (*nvp)); | ||||
if (nvl->nv_data + nvl->nv_size < | |||||
nvp_name->nv_data + nvp_name->nv_size) | |||||
return (EIO); | |||||
nvp_data = (nv_pair_data_t *) | nvp_data = (nv_pair_data_t *) | ||||
NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] + | NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] + | ||||
nvp_name->nv_size); | nvp_name->nv_size); | ||||
if (memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0 && | if (strlen(name) == nvp_name->nv_size && | ||||
nvp_data->nv_type == type) { | memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0 && | ||||
(nvp_data->nv_type == type || type == DATA_TYPE_UNKNOWN)) { | |||||
if (elementsp != NULL) | if (elementsp != NULL) | ||||
*elementsp = nvp_data->nv_nelem; | *elementsp = nvp_data->nv_nelem; | ||||
switch (nvp_data->nv_type) { | switch (nvp_data->nv_type) { | ||||
case DATA_TYPE_UINT64: | case DATA_TYPE_UINT64: | ||||
*(uint64_t *)valuep = | *(uint64_t *)valuep = | ||||
*(uint64_t *)nvp_data->nv_data; | *(uint64_t *)nvp_data->nv_data; | ||||
return (0); | return (0); | ||||
case DATA_TYPE_STRING: | case DATA_TYPE_STRING: | ||||
nvp_name = (nv_string_t *)nvp_data->nv_data; | nvp_name = (nv_string_t *)nvp_data->nv_data; | ||||
if (sizep != NULL) { | if (sizep != NULL) { | ||||
*sizep = nvp_name->nv_size; | *sizep = nvp_name->nv_size; | ||||
} | } | ||||
*(const uint8_t **)valuep = | *(const uint8_t **)valuep = | ||||
&nvp_name->nv_data[0]; | &nvp_name->nv_data[0]; | ||||
return (0); | return (0); | ||||
case DATA_TYPE_NVLIST: | case DATA_TYPE_NVLIST: | ||||
case DATA_TYPE_NVLIST_ARRAY: | ptr = &nvp_data->nv_data[0]; | ||||
nvlist = malloc(sizeof(*nvlist)); | rv = clone_nvlist(nvl, ptr, | ||||
if (nvlist != NULL) { | nvlist_next(ptr) - ptr, &nv); | ||||
nvlist->nv_header = nvl->nv_header; | if (rv == 0) { | ||||
nvlist->nv_asize = 0; | *(nvlist_t **)valuep = nv; | ||||
nvlist->nv_size = 0; | |||||
nvlist->nv_idx = NULL; | |||||
nvlist->nv_data = &nvp_data->nv_data[0]; | |||||
*(nvlist_t **)valuep = nvlist; | |||||
return (0); | |||||
} | } | ||||
return (rv); | |||||
case DATA_TYPE_NVLIST_ARRAY: | |||||
nvlist = calloc(nvp_data->nv_nelem, | |||||
sizeof (nvlist_t *)); | |||||
if (nvlist == NULL) | |||||
return (ENOMEM); | return (ENOMEM); | ||||
ptr = &nvp_data->nv_data[0]; | |||||
rv = 0; | |||||
for (unsigned i = 0; i < nvp_data->nv_nelem; | |||||
i++) { | |||||
rv = clone_nvlist(nvl, ptr, | |||||
nvlist_next(ptr) - ptr, &nvlist[i]); | |||||
if (rv != 0) | |||||
goto error; | |||||
ptr = nvlist_next(ptr); | |||||
} | } | ||||
*(nvlist_t ***)valuep = nvlist; | |||||
return (rv); | |||||
} | |||||
return (EIO); | return (EIO); | ||||
} | } | ||||
/* Not our pair, skip to next. */ | /* Not our pair, skip to next. */ | ||||
nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size); | nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size); | ||||
if (nvl->nv_data + nvl->nv_size < (uint8_t *)nvp) | |||||
return (EIO); | |||||
} | } | ||||
return (ENOENT); | return (ENOENT); | ||||
error: | |||||
for (unsigned i = 0; i < nvp_data->nv_nelem; i++) { | |||||
free(nvlist[i]->nv_data); | |||||
free(nvlist[i]); | |||||
} | } | ||||
free(nvlist); | |||||
return (rv); | |||||
} | |||||
static int | |||||
get_value_size(data_type_t type, const void *data, uint32_t nelem) | |||||
{ | |||||
uint64_t value_sz = 0; | |||||
switch (type) { | |||||
case DATA_TYPE_BOOLEAN: | |||||
value_sz = 0; | |||||
break; | |||||
case DATA_TYPE_BOOLEAN_VALUE: | |||||
case DATA_TYPE_BYTE: | |||||
case DATA_TYPE_INT8: | |||||
case DATA_TYPE_UINT8: | |||||
case DATA_TYPE_INT16: | |||||
case DATA_TYPE_UINT16: | |||||
case DATA_TYPE_INT32: | |||||
case DATA_TYPE_UINT32: | |||||
/* Our smallest data unit is 32-bit */ | |||||
value_sz = sizeof (uint32_t); | |||||
break; | |||||
case DATA_TYPE_HRTIME: | |||||
case DATA_TYPE_INT64: | |||||
value_sz = sizeof (int64_t); | |||||
break; | |||||
case DATA_TYPE_UINT64: | |||||
value_sz = sizeof (uint64_t); | |||||
break; | |||||
case DATA_TYPE_STRING: | |||||
if (data == NULL) | |||||
value_sz = 0; | |||||
else | |||||
value_sz = strlen(data) + 1; | |||||
break; | |||||
case DATA_TYPE_BYTE_ARRAY: | |||||
value_sz = nelem * sizeof (uint8_t); | |||||
break; | |||||
case DATA_TYPE_BOOLEAN_ARRAY: | |||||
case DATA_TYPE_INT8_ARRAY: | |||||
case DATA_TYPE_UINT8_ARRAY: | |||||
case DATA_TYPE_INT16_ARRAY: | |||||
case DATA_TYPE_UINT16_ARRAY: | |||||
case DATA_TYPE_INT32_ARRAY: | |||||
case DATA_TYPE_UINT32_ARRAY: | |||||
value_sz = (uint64_t)nelem * sizeof (uint32_t); | |||||
break; | |||||
case DATA_TYPE_INT64_ARRAY: | |||||
value_sz = (uint64_t)nelem * sizeof (int64_t); | |||||
break; | |||||
case DATA_TYPE_UINT64_ARRAY: | |||||
value_sz = (uint64_t)nelem * sizeof (uint64_t); | |||||
break; | |||||
case DATA_TYPE_STRING_ARRAY: | |||||
value_sz = (uint64_t)nelem * sizeof (uint64_t); | |||||
if (data != NULL) { | |||||
char *const *strs = data; | |||||
uint32_t i; | |||||
for (i = 0; i < nelem; i++) { | |||||
if (strs[i] == NULL) | |||||
return (-1); | |||||
value_sz += strlen(strs[i]) + 1; | |||||
} | |||||
} | |||||
break; | |||||
case DATA_TYPE_NVLIST: | |||||
/* | /* | ||||
* Return the next nvlist in an nvlist array. | * The decoded size of nvlist is constant. | ||||
*/ | */ | ||||
int | value_sz = NV_ALIGN(6 * 4); /* sizeof nvlist_t */ | ||||
nvlist_next(nvlist_t *nvl) | break; | ||||
case DATA_TYPE_NVLIST_ARRAY: | |||||
value_sz = (uint64_t)nelem * sizeof (uint64_t) + | |||||
(uint64_t)nelem * NV_ALIGN(6 * 4); /* sizeof nvlist_t */ | |||||
break; | |||||
default: | |||||
return (-1); | |||||
} | |||||
return (value_sz > INT32_MAX ? -1 : (int)value_sz); | |||||
} | |||||
static int | |||||
get_nvp_data_size(data_type_t type, const void *data, uint32_t nelem) | |||||
{ | { | ||||
nvs_data_t *data; | uint64_t value_sz = 0; | ||||
nvp_header_t *nvp; | xdr_t xdr; | ||||
size_t size; | |||||
if (nvl == NULL || nvl->nv_data == NULL || nvl->nv_asize != 0) | switch (type) { | ||||
case DATA_TYPE_BOOLEAN: | |||||
value_sz = 0; | |||||
break; | |||||
case DATA_TYPE_BOOLEAN_VALUE: | |||||
case DATA_TYPE_BYTE: | |||||
case DATA_TYPE_INT8: | |||||
case DATA_TYPE_UINT8: | |||||
case DATA_TYPE_INT16: | |||||
case DATA_TYPE_UINT16: | |||||
case DATA_TYPE_INT32: | |||||
case DATA_TYPE_UINT32: | |||||
/* Our smallest data unit is 32-bit */ | |||||
value_sz = sizeof (uint32_t); | |||||
break; | |||||
case DATA_TYPE_HRTIME: | |||||
case DATA_TYPE_INT64: | |||||
case DATA_TYPE_UINT64: | |||||
value_sz = sizeof (uint64_t); | |||||
break; | |||||
case DATA_TYPE_STRING: | |||||
value_sz = 4 + NV_ALIGN4(strlen(data)); | |||||
break; | |||||
case DATA_TYPE_BYTE_ARRAY: | |||||
value_sz = NV_ALIGN4(nelem); | |||||
break; | |||||
case DATA_TYPE_BOOLEAN_ARRAY: | |||||
case DATA_TYPE_INT8_ARRAY: | |||||
case DATA_TYPE_UINT8_ARRAY: | |||||
case DATA_TYPE_INT16_ARRAY: | |||||
case DATA_TYPE_UINT16_ARRAY: | |||||
case DATA_TYPE_INT32_ARRAY: | |||||
case DATA_TYPE_UINT32_ARRAY: | |||||
value_sz = 4 + (uint64_t)nelem * sizeof (uint32_t); | |||||
break; | |||||
case DATA_TYPE_INT64_ARRAY: | |||||
case DATA_TYPE_UINT64_ARRAY: | |||||
value_sz = 4 + (uint64_t)nelem * sizeof (uint64_t); | |||||
break; | |||||
case DATA_TYPE_STRING_ARRAY: | |||||
if (data != NULL) { | |||||
char *const *strs = data; | |||||
uint32_t i; | |||||
for (i = 0; i < nelem; i++) { | |||||
value_sz += 4 + NV_ALIGN4(strlen(strs[i])); | |||||
} | |||||
} | |||||
break; | |||||
case DATA_TYPE_NVLIST: | |||||
xdr.xdr_idx = ((nvlist_t *)data)->nv_data; | |||||
xdr.xdr_buf = xdr.xdr_idx; | |||||
xdr.xdr_buf_size = ((nvlist_t *)data)->nv_size; | |||||
if (!nvlist_size_native(&xdr, &size)) | |||||
return (-1); | |||||
value_sz = size; | |||||
break; | |||||
case DATA_TYPE_NVLIST_ARRAY: | |||||
value_sz = 0; | |||||
for (uint32_t i = 0; i < nelem; i++) { | |||||
xdr.xdr_idx = ((nvlist_t **)data)[i]->nv_data; | |||||
xdr.xdr_buf = xdr.xdr_idx; | |||||
xdr.xdr_buf_size = ((nvlist_t **)data)[i]->nv_size; | |||||
if (!nvlist_size_native(&xdr, &size)) | |||||
return (-1); | |||||
value_sz += size; | |||||
} | |||||
break; | |||||
default: | |||||
return (-1); | |||||
} | |||||
return (value_sz > INT32_MAX ? -1 : (int)value_sz); | |||||
} | |||||
#define NVPE_SIZE(name_len, data_len) \ | |||||
(4 + 4 + 4 + NV_ALIGN4(name_len) + 4 + 4 + data_len) | |||||
#define NVP_SIZE(name_len, data_len) \ | |||||
(NV_ALIGN((4 * 4) + (name_len)) + NV_ALIGN(data_len)) | |||||
static int | |||||
nvlist_add_common(nvlist_t *nvl, const char *name, data_type_t type, | |||||
uint32_t nelem, const void *data) | |||||
{ | |||||
nvs_data_t *nvs; | |||||
nvp_header_t head, *hp; | |||||
uint8_t *ptr; | |||||
size_t namelen; | |||||
int decoded_size, encoded_size; | |||||
xdr_t xdr; | |||||
nvs = (nvs_data_t *)nvl->nv_data; | |||||
if (nvs->nvl_nvflag & NV_UNIQUE_NAME) | |||||
(void) nvlist_remove(nvl, name, type); | |||||
xdr.xdr_buf = nvl->nv_data; | |||||
xdr.xdr_idx = nvl->nv_data; | |||||
xdr.xdr_buf_size = nvl->nv_size; | |||||
if (!nvlist_size_native(&xdr, &nvl->nv_size)) | |||||
return (EINVAL); | return (EINVAL); | ||||
data = (nvs_data_t *)nvl->nv_data; | namelen = strlen(name); | ||||
nvp = &data->nvl_pair; /* first pair in nvlist */ | if ((decoded_size = get_value_size(type, data, nelem)) < 0) | ||||
return (EINVAL); | |||||
if ((encoded_size = get_nvp_data_size(type, data, nelem)) < 0) | |||||
return (EINVAL); | |||||
while (nvp->encoded_size != 0 && nvp->decoded_size != 0) { | /* | ||||
nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size); | * The encoded size is calculated as: | ||||
* encode_size (4) + decode_size (4) + | |||||
* name string size (4 + NV_ALIGN4(namelen) + | |||||
* data type (4) + nelem size (4) + datalen | |||||
* | |||||
* The decoded size is calculated as: | |||||
* Note: namelen is with terminating 0. | |||||
* NV_ALIGN(sizeof (nvpair_t) (4 * 4) + namelen + 1) + | |||||
* NV_ALIGN(data_len) | |||||
*/ | |||||
head.encoded_size = NVPE_SIZE(namelen, encoded_size); | |||||
head.decoded_size = NVP_SIZE(namelen + 1, decoded_size); | |||||
if (nvl->nv_asize - nvl->nv_size < head.encoded_size + 8) { | |||||
ptr = realloc(nvl->nv_data, nvl->nv_asize + head.encoded_size); | |||||
if (ptr == NULL) | |||||
return (ENOMEM); | |||||
nvl->nv_data = ptr; | |||||
nvl->nv_asize += head.encoded_size; | |||||
} | } | ||||
nvl->nv_data = (uint8_t *)nvp + sizeof(*nvp); | nvl->nv_idx = nvl->nv_data + nvl->nv_size - sizeof (*hp); | ||||
bzero(nvl->nv_idx, head.encoded_size + 8); | |||||
hp = (nvp_header_t *)nvl->nv_idx; | |||||
*hp = head; | |||||
nvl->nv_idx += sizeof (*hp); | |||||
*(unsigned *)nvl->nv_idx = namelen; | |||||
nvl->nv_idx += sizeof (unsigned); | |||||
strlcpy((char *)nvl->nv_idx, name, namelen + 1); | |||||
nvl->nv_idx += NV_ALIGN4(namelen); | |||||
*(unsigned *)nvl->nv_idx = type; | |||||
nvl->nv_idx += sizeof (unsigned); | |||||
*(unsigned *)nvl->nv_idx = nelem; | |||||
nvl->nv_idx += sizeof (unsigned); | |||||
switch (type) { | |||||
case DATA_TYPE_BOOLEAN: | |||||
break; | |||||
case DATA_TYPE_BYTE_ARRAY: | |||||
*(unsigned *)nvl->nv_idx = encoded_size; | |||||
nvl->nv_idx += sizeof (unsigned); | |||||
bcopy(data, nvl->nv_idx, nelem); | |||||
nvl->nv_idx += encoded_size; | |||||
break; | |||||
case DATA_TYPE_STRING: | |||||
encoded_size = strlen(data); | |||||
*(unsigned *)nvl->nv_idx = encoded_size; | |||||
nvl->nv_idx += sizeof (unsigned); | |||||
strlcpy((char *)nvl->nv_idx, data, encoded_size + 1); | |||||
nvl->nv_idx += NV_ALIGN4(encoded_size); | |||||
break; | |||||
case DATA_TYPE_STRING_ARRAY: | |||||
for (uint32_t i = 0; i < nelem; i++) { | |||||
encoded_size = strlen(((char **)data)[i]); | |||||
*(unsigned *)nvl->nv_idx = encoded_size; | |||||
nvl->nv_idx += sizeof (unsigned); | |||||
strlcpy((char *)nvl->nv_idx, ((char **)data)[i], | |||||
encoded_size + 1); | |||||
nvl->nv_idx += NV_ALIGN4(encoded_size); | |||||
} | |||||
break; | |||||
case DATA_TYPE_BYTE: | |||||
case DATA_TYPE_INT8: | |||||
case DATA_TYPE_UINT8: | |||||
case DATA_TYPE_INT8_ARRAY: | |||||
case DATA_TYPE_UINT8_ARRAY: | |||||
for (uint32_t i = 0; i < nelem; i++) { | |||||
*(unsigned *)nvl->nv_idx = ((uint8_t *)data)[i]; | |||||
nvl->nv_idx += sizeof (unsigned); | |||||
} | |||||
break; | |||||
case DATA_TYPE_INT16: | |||||
case DATA_TYPE_UINT16: | |||||
case DATA_TYPE_INT16_ARRAY: | |||||
case DATA_TYPE_UINT16_ARRAY: | |||||
for (uint32_t i = 0; i < nelem; i++) { | |||||
*(unsigned *)nvl->nv_idx = ((uint16_t *)data)[i]; | |||||
nvl->nv_idx += sizeof (unsigned); | |||||
} | |||||
break; | |||||
case DATA_TYPE_NVLIST: | |||||
bcopy(((nvlist_t *)data)->nv_data, nvl->nv_idx, encoded_size); | |||||
break; | |||||
case DATA_TYPE_NVLIST_ARRAY: { | |||||
uint8_t *buf = nvl->nv_idx; | |||||
size_t size; | |||||
xdr_t xdr; | |||||
for (uint32_t i = 0; i < nelem; i++) { | |||||
xdr.xdr_idx = ((nvlist_t **)data)[i]->nv_data; | |||||
xdr.xdr_buf = xdr.xdr_idx; | |||||
xdr.xdr_buf_size = ((nvlist_t **)data)[i]->nv_size; | |||||
if (!nvlist_size_native(&xdr, &size)) | |||||
return (EINVAL); | |||||
bcopy(((nvlist_t **)data)[i]->nv_data, buf, size); | |||||
buf += size; | |||||
} | |||||
break; | |||||
} | |||||
default: | |||||
bcopy(data, nvl->nv_idx, encoded_size); | |||||
} | |||||
nvl->nv_size += head.encoded_size; | |||||
return (0); | return (0); | ||||
} | } | ||||
void | int | ||||
nvlist_print(nvlist_t *nvl, unsigned int indent) | nvlist_add_boolean_value(nvlist_t *nvl, const char *name, boolean_t value) | ||||
{ | { | ||||
return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_VALUE, 1, | |||||
&value)); | |||||
} | |||||
int | |||||
nvlist_add_byte(nvlist_t *nvl, const char *name, uint8_t value) | |||||
{ | |||||
return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE, 1, &value)); | |||||
} | |||||
int | |||||
nvlist_add_int8(nvlist_t *nvl, const char *name, int8_t value) | |||||
{ | |||||
return (nvlist_add_common(nvl, name, DATA_TYPE_INT8, 1, &value)); | |||||
} | |||||
int | |||||
nvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t value) | |||||
{ | |||||
return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8, 1, &value)); | |||||
} | |||||
int | |||||
nvlist_add_int16(nvlist_t *nvl, const char *name, int16_t value) | |||||
{ | |||||
return (nvlist_add_common(nvl, name, DATA_TYPE_INT16, 1, &value)); | |||||
} | |||||
int | |||||
nvlist_add_uint16(nvlist_t *nvl, const char *name, uint16_t value) | |||||
{ | |||||
return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16, 1, &value)); | |||||
} | |||||
int | |||||
nvlist_add_int32(nvlist_t *nvl, const char *name, int32_t value) | |||||
{ | |||||
return (nvlist_add_common(nvl, name, DATA_TYPE_INT32, 1, &value)); | |||||
} | |||||
int | |||||
nvlist_add_uint32(nvlist_t *nvl, const char *name, uint32_t value) | |||||
{ | |||||
return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32, 1, &value)); | |||||
} | |||||
int | |||||
nvlist_add_int64(nvlist_t *nvl, const char *name, int64_t value) | |||||
{ | |||||
return (nvlist_add_common(nvl, name, DATA_TYPE_INT64, 1, &value)); | |||||
} | |||||
int | |||||
nvlist_add_uint64(nvlist_t *nvl, const char *name, uint64_t value) | |||||
{ | |||||
return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64, 1, &value)); | |||||
} | |||||
int | |||||
nvlist_add_string(nvlist_t *nvl, const char *name, const char *value) | |||||
{ | |||||
return (nvlist_add_common(nvl, name, DATA_TYPE_STRING, 1, value)); | |||||
} | |||||
int | |||||
nvlist_add_boolean_array(nvlist_t *nvl, const char *name, | |||||
boolean_t *a, uint32_t n) | |||||
{ | |||||
return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_ARRAY, n, a)); | |||||
} | |||||
int | |||||
nvlist_add_byte_array(nvlist_t *nvl, const char *name, uint8_t *a, uint32_t n) | |||||
{ | |||||
return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a)); | |||||
} | |||||
int | |||||
nvlist_add_int8_array(nvlist_t *nvl, const char *name, int8_t *a, uint32_t n) | |||||
{ | |||||
return (nvlist_add_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a)); | |||||
} | |||||
int | |||||
nvlist_add_uint8_array(nvlist_t *nvl, const char *name, uint8_t *a, uint32_t n) | |||||
{ | |||||
return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a)); | |||||
} | |||||
int | |||||
nvlist_add_int16_array(nvlist_t *nvl, const char *name, int16_t *a, uint32_t n) | |||||
{ | |||||
return (nvlist_add_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a)); | |||||
} | |||||
int | |||||
nvlist_add_uint16_array(nvlist_t *nvl, const char *name, uint16_t *a, | |||||
uint32_t n) | |||||
{ | |||||
return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a)); | |||||
} | |||||
int | |||||
nvlist_add_int32_array(nvlist_t *nvl, const char *name, int32_t *a, uint32_t n) | |||||
{ | |||||
return (nvlist_add_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a)); | |||||
} | |||||
int | |||||
nvlist_add_uint32_array(nvlist_t *nvl, const char *name, uint32_t *a, | |||||
uint32_t n) | |||||
{ | |||||
return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a)); | |||||
} | |||||
int | |||||
nvlist_add_int64_array(nvlist_t *nvl, const char *name, int64_t *a, uint32_t n) | |||||
{ | |||||
return (nvlist_add_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a)); | |||||
} | |||||
int | |||||
nvlist_add_uint64_array(nvlist_t *nvl, const char *name, uint64_t *a, | |||||
uint32_t n) | |||||
{ | |||||
return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a)); | |||||
} | |||||
int | |||||
nvlist_add_string_array(nvlist_t *nvl, const char *name, | |||||
char * const *a, uint32_t n) | |||||
{ | |||||
return (nvlist_add_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a)); | |||||
} | |||||
int | |||||
nvlist_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val) | |||||
{ | |||||
return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST, 1, val)); | |||||
} | |||||
int | |||||
nvlist_add_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **a, | |||||
uint32_t n) | |||||
{ | |||||
return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a)); | |||||
} | |||||
static const char *typenames[] = { | static const char *typenames[] = { | ||||
"DATA_TYPE_UNKNOWN", | "DATA_TYPE_UNKNOWN", | ||||
"DATA_TYPE_BOOLEAN", | "DATA_TYPE_BOOLEAN", | ||||
"DATA_TYPE_BYTE", | "DATA_TYPE_BYTE", | ||||
"DATA_TYPE_INT16", | "DATA_TYPE_INT16", | ||||
"DATA_TYPE_UINT16", | "DATA_TYPE_UINT16", | ||||
"DATA_TYPE_INT32", | "DATA_TYPE_INT32", | ||||
"DATA_TYPE_UINT32", | "DATA_TYPE_UINT32", | ||||
"DATA_TYPE_INT64", | "DATA_TYPE_INT64", | ||||
"DATA_TYPE_UINT64", | "DATA_TYPE_UINT64", | ||||
"DATA_TYPE_STRING", | "DATA_TYPE_STRING", | ||||
"DATA_TYPE_BYTE_ARRAY", | "DATA_TYPE_BYTE_ARRAY", | ||||
"DATA_TYPE_INT16_ARRAY", | "DATA_TYPE_INT16_ARRAY", | ||||
"DATA_TYPE_UINT16_ARRAY", | "DATA_TYPE_UINT16_ARRAY", | ||||
"DATA_TYPE_INT32_ARRAY", | "DATA_TYPE_INT32_ARRAY", | ||||
"DATA_TYPE_UINT32_ARRAY", | "DATA_TYPE_UINT32_ARRAY", | ||||
"DATA_TYPE_INT64_ARRAY", | "DATA_TYPE_INT64_ARRAY", | ||||
"DATA_TYPE_UINT64_ARRAY", | "DATA_TYPE_UINT64_ARRAY", | ||||
"DATA_TYPE_STRING_ARRAY", | "DATA_TYPE_STRING_ARRAY", | ||||
"DATA_TYPE_HRTIME", | "DATA_TYPE_HRTIME", | ||||
"DATA_TYPE_NVLIST", | "DATA_TYPE_NVLIST", | ||||
"DATA_TYPE_NVLIST_ARRAY", | "DATA_TYPE_NVLIST_ARRAY", | ||||
"DATA_TYPE_BOOLEAN_VALUE", | "DATA_TYPE_BOOLEAN_VALUE", | ||||
"DATA_TYPE_INT8", | "DATA_TYPE_INT8", | ||||
"DATA_TYPE_UINT8", | "DATA_TYPE_UINT8", | ||||
"DATA_TYPE_BOOLEAN_ARRAY", | "DATA_TYPE_BOOLEAN_ARRAY", | ||||
"DATA_TYPE_INT8_ARRAY", | "DATA_TYPE_INT8_ARRAY", | ||||
"DATA_TYPE_UINT8_ARRAY" | "DATA_TYPE_UINT8_ARRAY" | ||||
}; | }; | ||||
nvs_data_t *data; | |||||
nvp_header_t *nvp; | int | ||||
nvpair_type_from_name(const char *name) | |||||
{ | |||||
unsigned i; | |||||
for (i = 0; i < nitems(typenames); i++) { | |||||
if (strcmp(name, typenames[i]) == 0) | |||||
return (i); | |||||
} | |||||
return (0); | |||||
} | |||||
nvp_header_t * | |||||
nvpair_find(nvlist_t *nv, const char *name) | |||||
{ | |||||
nvp_header_t *nvh; | |||||
nvh = NULL; | |||||
while ((nvh = nvlist_next_nvpair(nv, nvh)) != NULL) { | |||||
nv_string_t *nvp_name; | nv_string_t *nvp_name; | ||||
nvp_name = (nv_string_t *)(nvh + 1); | |||||
if (nvp_name->nv_size == strlen(name) && | |||||
memcmp(nvp_name->nv_data, name, nvp_name->nv_size) == 0) | |||||
break; | |||||
} | |||||
return (nvh); | |||||
} | |||||
void | |||||
nvpair_print(nvp_header_t *nvp, unsigned int indent) | |||||
{ | |||||
nv_string_t *nvp_name; | |||||
nv_pair_data_t *nvp_data; | nv_pair_data_t *nvp_data; | ||||
nvlist_t nvlist; | nvlist_t nvlist; | ||||
int i, j; | xdr_t xdr; | ||||
unsigned i, j; | |||||
data = (nvs_data_t *)nvl->nv_data; | |||||
nvp = &data->nvl_pair; /* first pair in nvlist */ | |||||
while (nvp->encoded_size != 0 && nvp->decoded_size != 0) { | |||||
nvp_name = (nv_string_t *)((uintptr_t)nvp + sizeof(*nvp)); | nvp_name = (nv_string_t *)((uintptr_t)nvp + sizeof (*nvp)); | ||||
nvp_data = (nv_pair_data_t *) | nvp_data = (nv_pair_data_t *) | ||||
NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] + | NV_ALIGN4((uintptr_t)&nvp_name->nv_data[0] + nvp_name->nv_size); | ||||
nvp_name->nv_size); | |||||
for (int i = 0; i < indent; i++) | for (i = 0; i < indent; i++) | ||||
printf(" "); | printf(" "); | ||||
printf("%s [%d] %.*s", typenames[nvp_data->nv_type], | printf("%s [%d] %.*s", typenames[nvp_data->nv_type], | ||||
nvp_data->nv_nelem, nvp_name->nv_size, nvp_name->nv_data); | nvp_data->nv_nelem, nvp_name->nv_size, nvp_name->nv_data); | ||||
switch (nvp_data->nv_type) { | switch (nvp_data->nv_type) { | ||||
case DATA_TYPE_UINT64: { | case DATA_TYPE_BYTE: | ||||
uint64_t val; | case DATA_TYPE_INT8: | ||||
case DATA_TYPE_UINT8: | |||||
printf(" = 0x%x\n", | |||||
(unsigned char)*(uint32_t *)nvp_data->nv_data); | |||||
break; | |||||
val = *(uint64_t *)nvp_data->nv_data; | case DATA_TYPE_INT16: | ||||
printf(" = 0x%jx\n", (uintmax_t)val); | case DATA_TYPE_UINT16: | ||||
printf(" = 0x%hx\n", | |||||
(unsigned short)*(uint32_t *)nvp_data->nv_data); | |||||
break; | break; | ||||
} | |||||
case DATA_TYPE_STRING: { | case DATA_TYPE_BOOLEAN_VALUE: | ||||
case DATA_TYPE_INT32: | |||||
case DATA_TYPE_UINT32: | |||||
printf(" = 0x%x\n", *(uint32_t *)nvp_data->nv_data); | |||||
break; | |||||
case DATA_TYPE_INT64: | |||||
case DATA_TYPE_UINT64: | |||||
printf(" = 0x%jx\n", (uintmax_t)*(uint64_t *)nvp_data->nv_data); | |||||
break; | |||||
case DATA_TYPE_STRING: | |||||
case DATA_TYPE_STRING_ARRAY: | |||||
nvp_name = (nv_string_t *)&nvp_data->nv_data[0]; | nvp_name = (nv_string_t *)&nvp_data->nv_data[0]; | ||||
for (i = 0; i < nvp_data->nv_nelem; i++) { | |||||
printf(" = \"%.*s\"\n", nvp_name->nv_size, | printf(" = \"%.*s\"\n", nvp_name->nv_size, | ||||
nvp_name->nv_data ); | nvp_name->nv_data); | ||||
break; | |||||
} | } | ||||
break; | |||||
case DATA_TYPE_NVLIST: | case DATA_TYPE_NVLIST: | ||||
printf("\n"); | printf("\n"); | ||||
nvlist.nv_data = &nvp_data->nv_data[0]; | nvlist.nv_data = &nvp_data->nv_data[0]; | ||||
nvlist_print(&nvlist, indent + 2); | nvlist_print(&nvlist, indent + 2); | ||||
break; | break; | ||||
case DATA_TYPE_NVLIST_ARRAY: | case DATA_TYPE_NVLIST_ARRAY: | ||||
nvlist.nv_data = &nvp_data->nv_data[0]; | nvlist.nv_data = &nvp_data->nv_data[0]; | ||||
for (j = 0; j < nvp_data->nv_nelem; j++) { | for (j = 0; j < nvp_data->nv_nelem; j++) { | ||||
data = (nvs_data_t *)nvlist.nv_data; | size_t size; | ||||
printf("[%d]\n", j); | printf("[%d]\n", j); | ||||
nvlist_print(&nvlist, indent + 2); | nvlist_print(&nvlist, indent + 2); | ||||
if (j != nvp_data->nv_nelem - 1) { | if (j != nvp_data->nv_nelem - 1) { | ||||
for (i = 0; i < indent; i++) | for (i = 0; i < indent; i++) | ||||
printf(" "); | printf(" "); | ||||
printf("%s %.*s", | printf("%s %.*s", | ||||
typenames[nvp_data->nv_type], | typenames[nvp_data->nv_type], | ||||
nvp_name->nv_size, | nvp_name->nv_size, | ||||
nvp_name->nv_data); | nvp_name->nv_data); | ||||
} | } | ||||
nvlist.nv_data = (uint8_t *)data + | xdr.xdr_idx = nvlist.nv_data; | ||||
nvlist_size(&native, nvlist.nv_data); | xdr.xdr_buf = xdr.xdr_idx; | ||||
xdr.xdr_buf_size = nvp->encoded_size - | |||||
(xdr.xdr_idx - (uint8_t *)nvp); | |||||
if (!nvlist_size_native(&xdr, &size)) | |||||
return; | |||||
nvlist.nv_data += size; | |||||
} | } | ||||
break; | break; | ||||
default: | default: | ||||
printf("\n"); | printf("\n"); | ||||
} | } | ||||
} | |||||
void | |||||
nvlist_print(const nvlist_t *nvl, unsigned int indent) | |||||
{ | |||||
nvs_data_t *data; | |||||
nvp_header_t *nvp; | |||||
data = (nvs_data_t *)nvl->nv_data; | |||||
nvp = &data->nvl_pair; /* first pair in nvlist */ | |||||
while (nvp->encoded_size != 0 && nvp->decoded_size != 0) { | |||||
nvpair_print(nvp, indent); | |||||
nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size); | nvp = (nvp_header_t *)((uint8_t *)nvp + nvp->encoded_size); | ||||
} | } | ||||
printf("%*s\n", indent + 13, "End of nvlist"); | printf("%*s\n", indent + 13, "End of nvlist"); | ||||
} | } |