/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2015, 2016 by Delphix. All rights reserved.
*/
#include <sys/isa_defs.h>
#include <sys/int_limits.h>
#include <sys/nvpair_impl.h>
#include <sys/sysmacros.h>
#else
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <stddef.h>
#endif
/*
* nvpair.c - Provides kernel & userland interfaces for manipulating
* name-value pairs.
*
* Overview Diagram
*
* +--------------+
* | nvlist_t |
* |--------------|
* | nvl_version |
* | nvl_nvflag |
* | nvl_priv -+-+
* | nvl_flag | |
* | nvl_pad | |
* +--------------+ |
* V
* +--------------+ last i_nvp in list
* | nvpriv_t | +--------------------->
* |--------------| |
* +--+- nvp_list | | +------------+
* | | nvp_last -+--+ + nv_alloc_t |
* | | nvp_curr | |------------|
* | | nvp_nva -+----> | nva_ops |
* | | nvp_stat | | nva_arg |
* | +--------------+ +------------+
* |
* +-------+
* V
* +---------------------+ +-------------------+
* | i_nvp_t | +-->| i_nvp_t | +-->
* |---------------------| | |-------------------| |
* | nvi_next -+--+ | nvi_next -+--+
* | nvi_prev (NULL) | <----+ nvi_prev |
* | . . . . . . . . . . | | . . . . . . . . . |
* | nvp (nvpair_t) | | nvp (nvpair_t) |
* | - nvp_size | | - nvp_size |
* | - nvp_name_sz | | - nvp_name_sz |
* | - nvp_value_elem | | - nvp_value_elem |
* | - nvp_type | | - nvp_type |
* | - data ... | | - data ... |
* +---------------------+ +-------------------+
*
*
*
* +---------------------+ +---------------------+
* | i_nvp_t | +--> +-->| i_nvp_t (last) |
* |---------------------| | | |---------------------|
* | nvi_next -+--+ ... --+ | nvi_next (NULL) |
* <-+- nvi_prev |<-- ... <----+ nvi_prev |
* | . . . . . . . . . | | . . . . . . . . . |
* | nvp (nvpair_t) | | nvp (nvpair_t) |
* | - nvp_size | | - nvp_size |
* | - nvp_name_sz | | - nvp_name_sz |
* | - nvp_value_elem | | - nvp_value_elem |
* | - DATA_TYPE_NVLIST | | - nvp_type |
* | - data (embedded) | | - data ... |
* | nvlist name | +---------------------+
* | +--------------+ |
* | | nvlist_t | |
* | |--------------| |
* | | nvl_version | |
* | | nvl_nvflag | |
* | | nvl_priv --+---+---->
* | | nvl_flag | |
* | | nvl_pad | |
* | +--------------+ |
* +---------------------+
*
*
* N.B. nvpair_t may be aligned on 4 byte boundary, so +4 will
* allow value to be aligned on 8 byte boundary
*
* name_len is the length of the name string including the null terminator
* so it must be >= 1
*/
#ifdef _KERNEL
#else
#endif
int
{
int err = 0;
return (err);
}
void
{
}
void
{
}
{
return (NULL);
}
static void *
{
void *buf;
return (buf);
}
static void
{
}
static void
{
}
static nvpriv_t *
{
/*
* nv_mem_alloc() cannot called here because it needs the priv
* argument.
*/
return (NULL);
return (priv);
}
/*
* Embedded lists need their own nvpriv_t's. We create a new
* nvpriv_t using the parameters and allocator from the parent
* list's nvpriv_t.
*/
static nvpriv_t *
{
return (NULL);
return (emb_priv);
}
static void
{
}
{
return (nvl->nvl_nvflag);
}
/*
* nvlist_alloc - Allocate nvlist.
*/
/*ARGSUSED1*/
int
{
#else
#endif
}
int
{
return (EINVAL);
return (ENOMEM);
return (ENOMEM);
}
return (0);
}
/*
* nvp_buf_alloc - Allocate i_nvp_t for storing a new nv pair.
*/
static nvpair_t *
{
/*
* Allocate the buffer
*/
return (NULL);
return (nvp);
}
/*
* nvp_buf_free - de-Allocate an i_nvp_t.
*/
static void
{
}
/*
* nvp_buf_link - link a new nv pair into the nvlist.
*/
static void
{
/* Put element at end of nvlist */
} else {
}
}
/*
* nvp_buf_unlink - unlink an removed nvpair out of the nvlist.
*/
static void
{
/*
* protect nvlist_next_nvpair() against walking on freed memory.
*/
else
else
}
/*
* take a nvpair type and number of elements and make sure the are valid
*/
static int
{
switch (type) {
case DATA_TYPE_BOOLEAN:
if (nelem != 0)
return (EINVAL);
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:
case DATA_TYPE_INT64:
case DATA_TYPE_UINT64:
case DATA_TYPE_STRING:
case DATA_TYPE_HRTIME:
case DATA_TYPE_NVLIST:
#if !defined(_KERNEL)
case DATA_TYPE_DOUBLE:
#endif
if (nelem != 1)
return (EINVAL);
break;
case DATA_TYPE_BOOLEAN_ARRAY:
case DATA_TYPE_BYTE_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:
case DATA_TYPE_INT64_ARRAY:
case DATA_TYPE_UINT64_ARRAY:
case DATA_TYPE_STRING_ARRAY:
case DATA_TYPE_NVLIST_ARRAY:
/* we allow arrays with 0 elements */
break;
default:
return (EINVAL);
}
return (0);
}
/*
* Verify nvp_name_sz and check the name string length.
*/
static int
{
if ((nvp->nvp_name_sz <= 0) ||
return (EFAULT);
/* verify the name string, make sure its terminated */
return (EFAULT);
}
static int
{
switch (type) {
case DATA_TYPE_BOOLEAN_VALUE:
return (EINVAL);
break;
case DATA_TYPE_BOOLEAN_ARRAY: {
int i;
for (i = 0; i < nelem; i++)
return (EINVAL);
break;
}
default:
break;
}
return (0);
}
/*
* This function takes a pointer to what should be a nvpair and it's size
* and then verifies that all the nvpair fields make sense and can be
* trusted. This function is used when decoding packed nvpairs.
*/
static int
{
/* verify nvp_name_sz, check the name string length */
if (i_validate_nvpair_name(nvp) != 0)
return (EFAULT);
return (EFAULT);
/*
* verify nvp_type, nvp_value_elem, and also possibly
* verify string values and get the value size.
*/
return (EFAULT);
return (0);
}
static int
{
return (EINVAL);
int err;
return (err);
}
return (0);
}
/*
* Frees all memory allocated for an nvpair (like embedded lists) with
* the exception of the nvpair buffer itself.
*/
static void
{
case DATA_TYPE_NVLIST:
break;
case DATA_TYPE_NVLIST_ARRAY: {
int i;
nvlist_free(nvlp[i]);
break;
}
default:
break;
}
}
/*
* nvlist_free - free an unpacked nvlist
*/
void
{
return;
/*
* Unpacked nvlist are linked through i_nvp_t
*/
}
else
}
static int
{
return (0);
return (1);
return (0);
}
/*
* Make a copy of nvlist
*/
/*ARGSUSED1*/
int
{
#else
#endif
}
int
{
int err;
return (EINVAL);
return (err);
else
return (err);
}
/*
* Remove all with matching name
*/
int
{
return (EINVAL);
continue;
error = 0;
}
return (error);
}
/*
* Remove first one with matching name and type
*/
int
{
return (EINVAL);
return (0);
}
}
return (ENOENT);
}
int
{
return (EINVAL);
return (0);
}
/*
* This function calculates the size of an nvpair value.
*
* The data argument controls the behavior in case of the data types
* DATA_TYPE_STRING and
* DATA_TYPE_STRING_ARRAY
* Is data == NULL then the size of the string(s) is excluded.
*/
static int
{
return (-1);
/* Calculate required size for holding value */
switch (type) {
case DATA_TYPE_BOOLEAN:
value_sz = 0;
break;
case DATA_TYPE_BOOLEAN_VALUE:
break;
case DATA_TYPE_BYTE:
break;
case DATA_TYPE_INT8:
break;
case DATA_TYPE_UINT8:
break;
case DATA_TYPE_INT16:
break;
case DATA_TYPE_UINT16:
break;
case DATA_TYPE_INT32:
break;
case DATA_TYPE_UINT32:
break;
case DATA_TYPE_INT64:
break;
case DATA_TYPE_UINT64:
break;
#if !defined(_KERNEL)
case DATA_TYPE_DOUBLE:
value_sz = sizeof (double);
break;
#endif
case DATA_TYPE_STRING:
value_sz = 0;
else
break;
case DATA_TYPE_BOOLEAN_ARRAY:
break;
case DATA_TYPE_BYTE_ARRAY:
break;
case DATA_TYPE_INT8_ARRAY:
break;
case DATA_TYPE_UINT8_ARRAY:
break;
case DATA_TYPE_INT16_ARRAY:
break;
case DATA_TYPE_UINT16_ARRAY:
break;
case DATA_TYPE_INT32_ARRAY:
break;
case DATA_TYPE_UINT32_ARRAY:
break;
case DATA_TYPE_INT64_ARRAY:
break;
case DATA_TYPE_UINT64_ARRAY:
break;
case DATA_TYPE_STRING_ARRAY:
uint_t i;
/* no alignment requirement for strings */
for (i = 0; i < nelem; i++) {
return (-1);
}
}
break;
case DATA_TYPE_HRTIME:
break;
case DATA_TYPE_NVLIST:
break;
case DATA_TYPE_NVLIST_ARRAY:
break;
default:
return (-1);
}
}
static int
{
int err;
return (ENOMEM);
}
return (err);
}
/*
* nvlist_add_common - Add new <name,value> pair to nvlist
*/
static int
{
uint_t i;
int err = 0;
return (EINVAL);
return (EINVAL);
/*
* Verify type and nelem and get the value size.
* In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY
* is the size of the string(s) included.
*/
return (EINVAL);
return (EINVAL);
/*
* If we're adding an nvlist or nvlist array, ensure that we are not
* adding the input nvlist to itself, which would cause recursion,
* and ensure that no NULL nvlist pointers are present.
*/
switch (type) {
case DATA_TYPE_NVLIST:
return (EINVAL);
break;
case DATA_TYPE_NVLIST_ARRAY: {
for (i = 0; i < nelem; i++) {
return (EINVAL);
}
break;
}
default:
break;
}
/* calculate sizes of the nvpair elements and the nvpair itself */
return (EINVAL);
return (ENOMEM);
switch (type) {
case DATA_TYPE_BOOLEAN:
break;
case DATA_TYPE_STRING_ARRAY: {
/* skip pre-allocated space for pointer array */
for (i = 0; i < nelem; i++) {
}
break;
}
case DATA_TYPE_NVLIST: {
return (err);
}
break;
}
case DATA_TYPE_NVLIST_ARRAY: {
for (i = 0; i < nelem; i++) {
/*
* Free any successfully created lists
*/
return (err);
}
}
break;
}
default:
}
/* if unique name, remove before add */
return (0);
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
#if !defined(_KERNEL)
int
{
}
#endif
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
char *const *a, uint_t n)
{
}
int
{
}
int
{
}
int
{
}
/* reading name-value pairs */
nvpair_t *
{
return (NULL);
/*
* Ensure that nvp is a valid nvpair on this nvlist.
* NB: nvp_curr is used only as a hint so that we don't always
* have to walk the list to determine if nvp is still on the list.
*/
else
}
nvpair_t *
{
return (NULL);
else
}
{
return (B_TRUE);
}
char *
{
}
{
}
int
{
if ((type == DATA_TYPE_BYTE_ARRAY) ||
(type == DATA_TYPE_INT8_ARRAY) ||
(type == DATA_TYPE_UINT8_ARRAY) ||
(type == DATA_TYPE_INT16_ARRAY) ||
(type == DATA_TYPE_UINT16_ARRAY) ||
(type == DATA_TYPE_INT32_ARRAY) ||
(type == DATA_TYPE_UINT32_ARRAY) ||
(type == DATA_TYPE_INT64_ARRAY) ||
(type == DATA_TYPE_UINT64_ARRAY) ||
(type == DATA_TYPE_BOOLEAN_ARRAY) ||
(type == DATA_TYPE_STRING_ARRAY) ||
(type == DATA_TYPE_NVLIST_ARRAY))
return (1);
return (0);
}
static int
{
return (EINVAL);
/*
* For non-array types, we copy the data.
* For array types (including string), we set a pointer.
*/
switch (type) {
case DATA_TYPE_BOOLEAN:
*nelem = 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:
case DATA_TYPE_INT64:
case DATA_TYPE_UINT64:
case DATA_TYPE_HRTIME:
#if !defined(_KERNEL)
case DATA_TYPE_DOUBLE:
#endif
return (EINVAL);
*nelem = 1;
break;
case DATA_TYPE_NVLIST:
case DATA_TYPE_STRING:
return (EINVAL);
*nelem = 1;
break;
case DATA_TYPE_BOOLEAN_ARRAY:
case DATA_TYPE_BYTE_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:
case DATA_TYPE_INT64_ARRAY:
case DATA_TYPE_UINT64_ARRAY:
case DATA_TYPE_STRING_ARRAY:
case DATA_TYPE_NVLIST_ARRAY:
return (EINVAL);
else
break;
default:
return (ENOTSUP);
}
return (0);
}
static int
{
return (EINVAL);
return (ENOTSUP);
}
return (ENOENT);
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
#if !defined(_KERNEL)
int
{
}
#endif
int
{
}
int
{
}
int
{
DATA_TYPE_BOOLEAN_ARRAY, n, a));
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
char ***a, uint_t *n)
{
}
int
{
}
int
{
}
int
{
char *name;
int ret = 0;
void *val;
case DATA_TYPE_BOOLEAN:
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:
case DATA_TYPE_INT64:
case DATA_TYPE_UINT64:
case DATA_TYPE_HRTIME:
case DATA_TYPE_STRING:
case DATA_TYPE_NVLIST:
#if !defined(_KERNEL)
case DATA_TYPE_DOUBLE:
#endif
break;
case DATA_TYPE_BYTE_ARRAY:
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:
case DATA_TYPE_INT64_ARRAY:
case DATA_TYPE_UINT64_ARRAY:
case DATA_TYPE_STRING_ARRAY:
case DATA_TYPE_NVLIST_ARRAY:
break;
default:
}
ret = 0;
}
return (ret);
}
/*
* Find the 'name'ed nvpair in the nvlist 'nvl'. If 'name' found, the function
* returns zero and a pointer to the matching nvpair is returned in '*ret'
* (given 'ret' is non-NULL). If 'sep' is specified then 'name' will penitrate
* multiple levels of embedded nvlists, with 'sep' as the separator. As an
* example, if sep is '.', name might look like: "a" or "a.b" or "a.c[3]" or
* "a.d[3].e[1]". This matches the C syntax for array embed (for convience,
* code also supports "a.d[3]e[1]" syntax).
*
* If 'ip' is non-NULL and the last name component is an array, return the
* value of the "...[index]" array index in *ip. For an array reference that
* is not indexed, *ip will be returned as -1. If there is a syntax error in
* 'name', and 'ep' is non-NULL then *ep will be set to point to the location
* inside the 'name' string where the syntax error was detected.
*/
static int
{
const char *np;
char *sepp;
long idx;
int n;
if (ip)
if (ep)
return (EINVAL);
idx = 0;
/* step through components of name */
/* ensure unique names */
return (ENOTSUP);
/* skip white space */
if (*np == 0)
break;
/* set 'sepp' to end of current component 'np' */
if (sep)
else
/* find start of next "[ index ]..." */
/* if sepp comes first, set idxp to NULL */
/*
* At this point 'idxp' is set if there is an index
* expected for the current component.
*/
if (idxp) {
/* set 'n' to length of current 'np' name component */
/* keep sepp up to date for *ep use as we advance */
/* determine the index value */
goto fail;
#else
#endif
goto fail;
/* keep sepp up to date for *ep use as we advance */
/* skip white space index value and check for ']' */
if (*sepp++ != ']')
goto fail;
/* for embedded arrays, support C syntax: "a[1].b" */
sepp++;
} else if (sepp) {
} else {
}
/* trim trailing whitespace by reducing length of 'np' */
if (n == 0)
goto fail;
;
n++;
/* skip whitespace, and set sepp to NULL if complete */
if (sepp) {
if (*sepp == 0)
}
/*
* At this point:
* o 'n' is the length of current 'np' component.
* o 'idxp' is set if there was an index, and value 'idx'.
* o 'sepp' is set to the beginning of the next component,
* and set to NULL if we have no more components.
*
* Search for nvpair with matching component name.
*/
/* continue if no match on name */
continue;
/* if indexed, verify type is array oriented */
goto fail;
/*
* Full match found, return nvp and idx if this
* was the last component.
*/
if (ret)
return (0); /* found */
}
/*
* More components: current match must be
* of DATA_TYPE_NVLIST or DATA_TYPE_NVLIST_ARRAY
* to support going deeper.
*/
break;
(void) nvpair_value_nvlist_array(nvp,
if ((n < 0) || (idx >= n))
goto fail;
break;
}
/* type does not support more levels */
goto fail;
}
goto fail; /* 'name' not found */
/* search for match of next component in embedded 'nvl' list */
}
return (EINVAL);
}
/*
* Return pointer to nvpair with specified 'name'.
*/
int
{
}
/*
* Determine if named nvpair exists in nvlist (use embedded separator of '.'
* and return array index). See nvlist_lookup_nvpair_ei_sep for more detailed
* description.
*/
{
}
{
return (B_FALSE);
return (B_TRUE);
}
return (B_FALSE);
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
#if !defined(_KERNEL)
int
{
}
#endif
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
/*
* Add specified pair to the list.
*/
int
{
return (EINVAL);
}
/*
* Merge the supplied nvlists and put the result in dst.
* The merged list will contain all names specified in both lists,
* the values are taken from nvl in the case of duplicates.
* Return 0 on success.
*/
/*ARGSUSED*/
int
{
return (EINVAL);
return (0);
}
/*
* Encoding related routines
*/
#define NVS_OP_ENCODE 0
typedef struct {
int nvs_op;
void *nvs_private;
int nvs_recursion;
} nvstream_t;
/*
* nvs operations are:
* - nvs_nvlist
* encoding / decoding of a nvlist header (nvlist_t)
* calculates the size used for header and end detection
*
* - nvs_nvpair
* responsible for the first part of encoding / decoding of an nvpair
* calculates the decoded size of an nvpair
*
* - nvs_nvp_op
* second part of encoding / decoding of an nvpair
*
* - nvs_nvp_size
* calculates the encoding size of an nvpair
*
* - nvs_nvl_fini
* encodes the end detection mark (zeros).
*/
struct nvs_ops {
};
typedef struct {
} nvs_header_t;
static int
{
/*
* Walk nvpair in list and encode each nvpair
*/
return (EFAULT);
}
static int
{
int err;
/*
* Get decoded size of next pair in stream, alloc
* memory for nvpair_t, then decode the nvpair
*/
if (nvsize == 0) /* end of list */
break;
/* make sure len makes sense */
return (EFAULT);
return (ENOMEM);
return (err);
}
if (i_validate_nvpair(nvp) != 0) {
return (EFAULT);
}
}
return (err);
}
static int
{
/*
* Get encoded size of nvpairs in nvlist
*/
return (EINVAL);
return (EINVAL);
}
return (0);
}
static int
{
int err;
return (EFAULT);
/*
* Perform the operation, starting with header, then each nvpair
*/
return (err);
case NVS_OP_ENCODE:
break;
case NVS_OP_DECODE:
break;
case NVS_OP_GETSIZE:
break;
default:
}
return (err);
}
static int
{
case NVS_OP_ENCODE: {
int err;
return (EINVAL);
nvs->nvs_recursion++;
nvs->nvs_recursion--;
return (err);
}
case NVS_OP_DECODE: {
int err;
return (ENOTSUP);
return (ENOMEM);
return (EINVAL);
nvs->nvs_recursion++;
nvs->nvs_recursion--;
return (err);
}
default:
break;
}
return (EINVAL);
}
static int
{
int i;
case NVS_OP_ENCODE:
for (i = 0; i < nelem; i++)
return (EFAULT);
break;
case NVS_OP_DECODE: {
for (i = 0; i < nelem; i++) {
return (EFAULT);
}
}
break;
}
case NVS_OP_GETSIZE: {
for (i = 0; i < nelem; i++) {
return (EINVAL);
return (EINVAL);
}
break;
}
default:
return (EINVAL);
}
return (0);
}
/*
* Common routine for nvlist operations:
* encode, decode, getsize (encoded size).
*/
static int
int nvs_op)
{
int err = 0;
int nvl_endian;
#ifdef _LITTLE_ENDIAN
#else
int host_endian = 0;
#endif /* _LITTLE_ENDIAN */
return (EINVAL);
nvs.nvs_recursion = 0;
/*
* For NVS_OP_ENCODE and NVS_OP_DECODE make sure an nvlist and
* a buffer is allocated. The first 4 bytes in the buffer are
* used for encoding method and host endian.
*/
switch (nvs_op) {
case NVS_OP_ENCODE:
return (EINVAL);
nvh->nvh_reserved1 = 0;
nvh->nvh_reserved2 = 0;
break;
case NVS_OP_DECODE:
return (EINVAL);
/* get method of encoding from first byte */
break;
case NVS_OP_GETSIZE:
/*
* add the size for encoding
*/
*buflen = sizeof (nvs_header_t);
break;
default:
return (ENOTSUP);
}
/*
* Create an nvstream with proper encoding method
*/
switch (encoding) {
case NV_ENCODE_NATIVE:
/*
* check endianness, in case we are unpacking
* from a file
*/
if (nvl_endian != host_endian)
return (ENOTSUP);
break;
case NV_ENCODE_XDR:
break;
default:
break;
}
return (err);
}
int
{
}
/*
* Pack nvlist into contiguous memory
*/
/*ARGSUSED1*/
int
int kmflag)
{
#else
#endif
}
int
{
char *buf;
int err;
return (EINVAL);
/*
* Here is a difficult situation:
* 1. The nvlist has fixed allocator properties.
* All other nvlist routines (like nvlist_add_*, ...) use
* these properties.
* 2. When using nvlist_pack() the user can specify his own
* allocator properties (e.g. by using KM_NOSLEEP).
*
* We use the user specified properties (2). A clearer solution
* will be to remove the kmflag from nvlist_pack(), but we will
* not change the interface.
*/
return (err);
return (ENOMEM);
NVS_OP_ENCODE)) != 0) {
} else {
*buflen = alloc_size;
}
return (err);
}
/*
* Unpack buf into an nvlist_t
*/
/*ARGSUSED1*/
int
{
#else
#endif
}
int
{
int err;
return (EINVAL);
return (err);
else
return (err);
}
/*
* Native encoding functions
*/
typedef struct {
/*
* This structure is used when decoding a packed nvpair in
* the native format. n_base points to a buffer containing the
* packed nvpair. n_end is a pointer to the end of the buffer.
* (n_end actually points to the first byte past the end of the
* buffer.) n_curr is a pointer that lies between n_base and n_end.
* It points to the current data that we are decoding.
* The amount of data left in the buffer is equal to n_end - n_curr.
* n_flag is used to recognize a packed embedded list.
*/
} nvs_native_t;
static int
{
case NVS_OP_ENCODE:
case NVS_OP_DECODE:
return (0);
case NVS_OP_GETSIZE:
return (0);
default:
return (EINVAL);
}
}
/*ARGSUSED*/
static void
{
}
static int
{
return (EFAULT);
/*
* The bcopy() below eliminates alignment requirement
* on the buffer (stream) and is preferred over direct access.
*/
case NVS_OP_ENCODE:
break;
case NVS_OP_DECODE:
break;
default:
return (EINVAL);
}
return (0);
}
/*
* operate on nvlist_t header
*/
static int
{
case NVS_OP_ENCODE:
case NVS_OP_DECODE:
return (0); /* packed embedded list */
/* copy version and nvflag of the nvlist_t */
return (EFAULT);
return (0);
case NVS_OP_GETSIZE:
/*
* if calculate for packed embedded list
* 4 for end of the embedded list
* else
* 2 * sizeof (int32_t) for nvl_version and nvl_nvflag
* and 4 for end of the entire list
*/
*size += 4;
} else {
}
return (0);
default:
return (EINVAL);
}
}
static int
{
/*
* Add 4 zero bytes at end of nvlist. They are used
* for end detection by the decode routine.
*/
return (EFAULT);
}
return (0);
}
static int
{
/*
* Null out the pointer that is meaningless in the packed
* structure. The address may not be aligned, so we have
* to use bzero.
*/
}
}
static int
{
int i;
/*
* Null out pointers that are meaningless in the packed
* structure. The addresses may not be aligned, so we have
* to use bzero.
*/
/*
* Null out the pointer that is meaningless in the
* packed structure. The address may not be aligned,
* so we have to use bzero.
*/
}
}
static void
{
case NVS_OP_ENCODE: {
/*
* Null out pointers that are meaningless in the packed
* structure. The addresses may not be aligned, so we have
* to use bzero.
*/
break;
}
case NVS_OP_DECODE: {
int i;
}
break;
}
}
}
static int
{
int value_sz;
int ret = 0;
/*
* We do the initial bcopy of the data before we look at
* the nvpair type, because when we're decoding, we won't
* have the correct values for the pair until we do the bcopy.
*/
case NVS_OP_ENCODE:
case NVS_OP_DECODE:
return (EFAULT);
break;
default:
return (EINVAL);
}
/* verify nvp_name_sz, check the name string length */
if (i_validate_nvpair_name(nvp) != 0)
return (EFAULT);
/*
* Verify type and nelem and get the value size.
* In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY
* is the size of the string(s) excluded.
*/
return (EFAULT);
return (EFAULT);
switch (type) {
case DATA_TYPE_NVLIST:
break;
case DATA_TYPE_NVLIST_ARRAY:
break;
case DATA_TYPE_STRING_ARRAY:
break;
default:
break;
}
return (ret);
}
static int
{
case DATA_TYPE_NVLIST: {
return (EINVAL);
break;
}
case DATA_TYPE_NVLIST_ARRAY: {
return (EINVAL);
break;
}
default:
break;
}
return (EINVAL);
return (0);
}
static int
{
case NVS_OP_ENCODE:
case NVS_OP_DECODE: {
/* try to read the size value from the stream */
return (EFAULT);
/* sanity check the size value */
if (decode_len < 0 ||
return (EFAULT);
*size = decode_len;
/*
* If at the end of the stream then move the cursor
* forward, otherwise nvpair_native_op() will read
* the entire nvpair at the same cursor position.
*/
if (*size == 0)
break;
}
default:
return (EINVAL);
}
return (0);
}
};
static int
{
int err;
*buflen - sizeof (nvs_header_t))) != 0)
return (err);
return (err);
}
/*
* XDR encoding functions
*
* An xdr packed nvlist is encoded as:
*
* - encoding methode and host endian (4 bytes)
* - nvl_version (4 bytes)
* - nvl_nvflag (4 bytes)
*
* - encoded nvpairs, the format of one xdr encoded nvpair is:
* - encoded size of the nvpair (4 bytes)
* - decoded size of the nvpair (4 bytes)
* - name string, (4 + sizeof(NV_ALIGN4(string))
* a string is coded as size (4 bytes) and data
* - data type (4 bytes)
* - number of elements in the nvpair (4 bytes)
* - data
*
* - 2 zero's for end of the entire list (8 bytes)
*/
static int
{
/* xdr data must be 4 byte aligned */
return (EFAULT);
case NVS_OP_ENCODE:
return (0);
case NVS_OP_DECODE:
return (0);
case NVS_OP_GETSIZE:
return (0);
default:
return (EINVAL);
}
}
static void
{
case NVS_OP_ENCODE:
case NVS_OP_DECODE:
break;
default:
break;
}
}
static int
{
case NVS_OP_ENCODE:
case NVS_OP_DECODE: {
return (EFAULT);
break;
}
case NVS_OP_GETSIZE: {
/*
* 2 * 4 for nvl_version + nvl_nvflag
* and 8 for end of the entire list
*/
break;
}
default:
return (EINVAL);
}
return (0);
}
static int
{
int zero = 0;
return (EFAULT);
}
return (0);
}
/*
* The format of xdr encoded nvpair is:
* encode_size, decode_size, name string, data type, nelem, data
*/
static int
{
char *buf;
int value_sz;
/* name string */
return (EFAULT);
return (EFAULT);
/* type and nelem */
return (EFAULT);
/*
* Verify type and nelem and get the value size.
* In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY
* is the size of the string(s) excluded.
*/
return (EFAULT);
/* if there is no data to extract then return */
if (nelem == 0)
return (0);
/* value */
return (EFAULT);
return (EFAULT);
switch (type) {
case DATA_TYPE_NVLIST:
return (0);
break;
case DATA_TYPE_NVLIST_ARRAY:
return (0);
break;
case DATA_TYPE_BOOLEAN:
break;
case DATA_TYPE_BYTE:
case DATA_TYPE_INT8:
case DATA_TYPE_UINT8:
break;
case DATA_TYPE_INT16:
break;
case DATA_TYPE_UINT16:
break;
case DATA_TYPE_BOOLEAN_VALUE:
case DATA_TYPE_INT32:
break;
case DATA_TYPE_UINT32:
break;
case DATA_TYPE_INT64:
break;
case DATA_TYPE_UINT64:
break;
case DATA_TYPE_HRTIME:
/*
* NOTE: must expose the definition of hrtime_t here
*/
break;
#if !defined(_KERNEL)
case DATA_TYPE_DOUBLE:
break;
#endif
case DATA_TYPE_STRING:
break;
case DATA_TYPE_BYTE_ARRAY:
break;
case DATA_TYPE_INT8_ARRAY:
case DATA_TYPE_UINT8_ARRAY:
break;
case DATA_TYPE_INT16_ARRAY:
break;
case DATA_TYPE_UINT16_ARRAY:
break;
case DATA_TYPE_BOOLEAN_ARRAY:
case DATA_TYPE_INT32_ARRAY:
break;
case DATA_TYPE_UINT32_ARRAY:
break;
case DATA_TYPE_INT64_ARRAY:
break;
case DATA_TYPE_UINT64_ARRAY:
break;
case DATA_TYPE_STRING_ARRAY: {
int i;
for (i = 0; i < nelem; i++) {
return (EFAULT);
return (EFAULT);
}
break;
}
default:
break;
}
}
static int
{
/*
* encode_size + decode_size + name string size + data type + nelem
* where name string size = 4 + NV_ALIGN4(strlen(NVP_NAME(nvp)))
*/
switch (type) {
case DATA_TYPE_BOOLEAN:
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:
break;
case DATA_TYPE_INT64:
case DATA_TYPE_UINT64:
case DATA_TYPE_HRTIME:
#if !defined(_KERNEL)
case DATA_TYPE_DOUBLE:
#endif
nvp_sz += 8;
break;
case DATA_TYPE_STRING:
break;
case DATA_TYPE_BYTE_ARRAY:
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:
break;
case DATA_TYPE_INT64_ARRAY:
case DATA_TYPE_UINT64_ARRAY:
break;
case DATA_TYPE_STRING_ARRAY: {
int i;
break;
}
case DATA_TYPE_NVLIST:
case DATA_TYPE_NVLIST_ARRAY: {
int err;
if (type == DATA_TYPE_NVLIST)
else
if (err != 0)
return (EINVAL);
break;
}
default:
return (EINVAL);
}
return (EINVAL);
return (0);
}
/*
* The NVS_XDR_MAX_LEN macro takes a packed xdr buffer of size x and estimates
* the largest nvpair that could be encoded in the buffer.
*
* See comments above nvpair_xdr_op() for the format of xdr encoding.
* The size of a xdr packed nvpair without any data is 5 words.
*
* Using the size of the data directly as an estimate would be ok
* in all cases except one. If the data type is of DATA_TYPE_STRING_ARRAY
* then the actual nvpair has space for an array of pointers to index
* the strings. These pointers are not encoded into the packed xdr buffer.
*
* If the data is of type DATA_TYPE_STRING_ARRAY and all the strings are
* of length 0, then each string is endcoded in xdr format as a single word.
* Therefore when expanded to an nvpair there will be 2.25 word used for
* each string. (a int64_t allocated for pointer usage, and a single char
* for the null termination.)
*
* This is the calculation performed by the NVS_XDR_MAX_LEN macro.
*/
0 : ((size_t)(y) - NVS_XDR_HDR_LEN))
(NVS_XDR_DATA_LEN(x) * 2) + \
static int
{
case NVS_OP_ENCODE: {
return (EFAULT);
encode_len = nvsize;
return (EFAULT);
}
case NVS_OP_DECODE: {
/* get the encode and decode size */
return (EFAULT);
*size = decode_len;
/* are we at the end of the stream? */
if (*size == 0)
return (0);
/* sanity check the size parameter */
return (EFAULT);
return (EFAULT);
break;
}
default:
return (EINVAL);
}
return (0);
}
};
static int
{
int err;
*buflen - sizeof (nvs_header_t))) != 0)
return (err);
return (err);
}