summaryrefslogtreecommitdiffstats
path: root/sys/contrib
diff options
context:
space:
mode:
authoroshogbo <oshogbo@FreeBSD.org>2015-08-15 06:34:49 +0000
committeroshogbo <oshogbo@FreeBSD.org>2015-08-15 06:34:49 +0000
commitfe707ca6b5c69e935fa7a2b439769a39a9886247 (patch)
tree23c94ea4e2c954c18093feba6f3be3530fd33213 /sys/contrib
parentd47d0c107187fca9965346606d70000542f92cd8 (diff)
downloadFreeBSD-src-fe707ca6b5c69e935fa7a2b439769a39a9886247.zip
FreeBSD-src-fe707ca6b5c69e935fa7a2b439769a39a9886247.tar.gz
Add support for the arrays in nvlist library.
- Add nvlist_{add,get,take,move,exists,free}_{number,bool,string,nvlist, descriptor} functions. - Add support for (un)packing arrays. - Add the nvl_array_next field to the nvlist structure. If an array is added by the nvlist_{move,add}_nvlist_array function this field will contains next element in the array. - Add the nitems field to the nvpair and nvpair_header structure. This field contains number of elements in the array. - Add special flag (NV_FLAG_IN_ARRAY) which is set if nvlist is a part of an array. - Add special type (NV_TYPE_NVLIST_ARRAY_NEXT).This type is used only on packing/unpacking. - Add new API for traversing arrays (nvlist_get_array_next). - Add the nvlist_get_pararr function which combines the nvlist_get_array_next and nvlist_get_parent functions. If nvlist is in the array it will return next element from array. If nvlist is last element in array or it isn't in array it will return his container (parent). This function should simplify traveling over nvlist. - Add tests for new features. - Add documentation for new functions. - Add my copyright. - Regenerate the sys/cddl/compat/opensolaris/sys/nvpair.h file. PR: 191083 Reviewed by: allanjude (doc) Approved by: pjd (mentor)
Diffstat (limited to 'sys/contrib')
-rw-r--r--sys/contrib/libnv/nv_impl.h38
-rw-r--r--sys/contrib/libnv/nvlist.c643
-rw-r--r--sys/contrib/libnv/nvlist_impl.h1
-rw-r--r--sys/contrib/libnv/nvpair.c972
-rw-r--r--sys/contrib/libnv/nvpair_impl.h20
5 files changed, 1591 insertions, 83 deletions
diff --git a/sys/contrib/libnv/nv_impl.h b/sys/contrib/libnv/nv_impl.h
index 7928431..b50bdf7 100644
--- a/sys/contrib/libnv/nv_impl.h
+++ b/sys/contrib/libnv/nv_impl.h
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2013 The FreeBSD Foundation
+ * Copyright (c) 2013-2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
* All rights reserved.
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
@@ -39,12 +40,14 @@ struct nvpair;
typedef struct nvpair nvpair_t;
#endif
+#define NV_TYPE_NVLIST_ARRAY_NEXT 254
#define NV_TYPE_NVLIST_UP 255
#define NV_TYPE_FIRST NV_TYPE_NULL
-#define NV_TYPE_LAST NV_TYPE_BINARY
+#define NV_TYPE_LAST NV_TYPE_DESCRIPTOR_ARRAY
-#define NV_FLAG_BIG_ENDIAN 0x80
+#define NV_FLAG_BIG_ENDIAN 0x080
+#define NV_FLAG_IN_ARRAY 0x100
#ifdef _KERNEL
#define nv_malloc(size) malloc((size), M_NVLIST, M_WAITOK)
@@ -86,6 +89,7 @@ typedef struct nvpair nvpair_t;
int *nvlist_descriptors(const nvlist_t *nvl, size_t *nitemsp);
size_t nvlist_ndescriptors(const nvlist_t *nvl);
+void nvlist_set_flags(nvlist_t *nvl, int flags);
nvpair_t *nvlist_first_nvpair(const nvlist_t *nvl);
nvpair_t *nvlist_next_nvpair(const nvlist_t *nvl, const nvpair_t *nvp);
@@ -96,6 +100,7 @@ void nvlist_add_nvpair(nvlist_t *nvl, const nvpair_t *nvp);
bool nvlist_move_nvpair(nvlist_t *nvl, nvpair_t *nvp);
void nvlist_set_parent(nvlist_t *nvl, nvpair_t *parent);
+void nvlist_set_array_next(nvlist_t *nvl, nvpair_t *ele);
const nvpair_t *nvlist_get_nvpair(const nvlist_t *nvl, const char *name);
@@ -120,18 +125,33 @@ nvpair_t *nvpair_create_stringv(const char *name, const char *valuefmt, va_list
nvpair_t *nvpair_create_nvlist(const char *name, const nvlist_t *value);
nvpair_t *nvpair_create_descriptor(const char *name, int value);
nvpair_t *nvpair_create_binary(const char *name, const void *value, size_t size);
+nvpair_t *nvpair_create_bool_array(const char *name, const bool *value, size_t nitems);
+nvpair_t *nvpair_create_number_array(const char *name, const uint64_t *value, size_t nitems);
+nvpair_t *nvpair_create_string_array(const char *name, const char * const *value, size_t nitems);
+nvpair_t *nvpair_create_nvlist_array(const char *name, const nvlist_t * const *value, size_t nitems);
+nvpair_t *nvpair_create_descriptor_array(const char *name, const int *value, size_t nitems);
nvpair_t *nvpair_move_string(const char *name, char *value);
nvpair_t *nvpair_move_nvlist(const char *name, nvlist_t *value);
nvpair_t *nvpair_move_descriptor(const char *name, int value);
nvpair_t *nvpair_move_binary(const char *name, void *value, size_t size);
-
-bool nvpair_get_bool(const nvpair_t *nvp);
-uint64_t nvpair_get_number(const nvpair_t *nvp);
-const char *nvpair_get_string(const nvpair_t *nvp);
-const nvlist_t *nvpair_get_nvlist(const nvpair_t *nvp);
-int nvpair_get_descriptor(const nvpair_t *nvp);
-const void *nvpair_get_binary(const nvpair_t *nvp, size_t *sizep);
+nvpair_t *nvpair_move_bool_array(const char *name, bool *value, size_t nitems);
+nvpair_t *nvpair_move_nvlist_array(const char *name, nvlist_t **value, size_t nitems);
+nvpair_t *nvpair_move_descriptor_array(const char *name, int *value, size_t nitems);
+nvpair_t *nvpair_move_number_array(const char *name, uint64_t *value, size_t nitems);
+nvpair_t *nvpair_move_string_array(const char *name, char **value, size_t nitems);
+
+bool nvpair_get_bool(const nvpair_t *nvp);
+uint64_t nvpair_get_number(const nvpair_t *nvp);
+const char *nvpair_get_string(const nvpair_t *nvp);
+const nvlist_t *nvpair_get_nvlist(const nvpair_t *nvp);
+int nvpair_get_descriptor(const nvpair_t *nvp);
+const void *nvpair_get_binary(const nvpair_t *nvp, size_t *sizep);
+const bool *nvpair_get_bool_array(const nvpair_t *nvp, size_t *nitemsp);
+const uint64_t *nvpair_get_number_array(const nvpair_t *nvp, size_t *nitemsp);
+const char * const *nvpair_get_string_array(const nvpair_t *nvp, size_t *nitemsp);
+const nvlist_t * const *nvpair_get_nvlist_array(const nvpair_t *nvp, size_t *nitemsp);
+const int *nvpair_get_descriptor_array(const nvpair_t *nvp, size_t *nitemsp);
void nvpair_free(nvpair_t *nvp);
diff --git a/sys/contrib/libnv/nvlist.c b/sys/contrib/libnv/nvlist.c
index edcd074..cf8281e 100644
--- a/sys/contrib/libnv/nvlist.c
+++ b/sys/contrib/libnv/nvlist.c
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2009-2013 The FreeBSD Foundation
+ * Copyright (c) 2013-2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
* All rights reserved.
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
@@ -88,7 +89,7 @@ __FBSDID("$FreeBSD$");
#endif
#endif
-#define NV_FLAG_PRIVATE_MASK (NV_FLAG_BIG_ENDIAN)
+#define NV_FLAG_PRIVATE_MASK (NV_FLAG_BIG_ENDIAN | NV_FLAG_IN_ARRAY)
#define NV_FLAG_PUBLIC_MASK (NV_FLAG_IGNORE_CASE | NV_FLAG_NO_UNIQUE)
#define NV_FLAG_ALL_MASK (NV_FLAG_PRIVATE_MASK | NV_FLAG_PUBLIC_MASK)
@@ -98,6 +99,7 @@ struct nvlist {
int nvl_error;
int nvl_flags;
nvpair_t *nvl_parent;
+ nvpair_t *nvl_array_next;
struct nvl_head nvl_head;
};
@@ -135,6 +137,7 @@ nvlist_create(int flags)
nvl->nvl_error = 0;
nvl->nvl_flags = flags;
nvl->nvl_parent = NULL;
+ nvl->nvl_array_next = NULL;
TAILQ_INIT(&nvl->nvl_head);
nvl->nvl_magic = NVLIST_MAGIC;
@@ -157,6 +160,10 @@ nvlist_destroy(nvlist_t *nvl)
nvlist_remove_nvpair(nvl, nvp);
nvpair_free(nvp);
}
+ if (nvl->nvl_array_next != NULL)
+ nvpair_free_structure(nvl->nvl_array_next);
+ nvl->nvl_array_next = NULL;
+ nvl->nvl_parent = NULL;
nvl->nvl_magic = 0;
nv_free(nvl);
@@ -223,6 +230,59 @@ nvlist_set_parent(nvlist_t *nvl, nvpair_t *parent)
nvl->nvl_parent = parent;
}
+void
+nvlist_set_array_next(nvlist_t *nvl, nvpair_t *ele)
+{
+
+ NVLIST_ASSERT(nvl);
+
+ if (ele != NULL)
+ nvl->nvl_flags |= NV_FLAG_IN_ARRAY;
+ else
+ nvl->nvl_flags &= ~NV_FLAG_IN_ARRAY;
+
+ nvl->nvl_array_next = ele;
+}
+
+bool
+nvlist_in_array(const nvlist_t *nvl)
+{
+
+ NVLIST_ASSERT(nvl);
+
+ return ((nvl->nvl_flags & NV_FLAG_IN_ARRAY) != 0);
+}
+
+const nvlist_t *
+nvlist_get_array_next(const nvlist_t *nvl)
+{
+ nvpair_t *nvp;
+
+ NVLIST_ASSERT(nvl);
+
+ nvp = nvl->nvl_array_next;
+ if (nvp == NULL)
+ return (NULL);
+
+ return (nvpair_get_nvlist(nvp));
+}
+
+const nvlist_t *
+nvlist_get_pararr(const nvlist_t *nvl, void **cookiep)
+{
+ const nvlist_t *ret;
+
+ ret = nvlist_get_array_next(nvl);
+ if (ret != NULL) {
+ if (cookiep != NULL)
+ *cookiep = NULL;
+ return (ret);
+ }
+
+ ret = nvlist_get_parent(nvl, cookiep);
+ return (ret);
+}
+
bool
nvlist_empty(const nvlist_t *nvl)
{
@@ -239,9 +299,18 @@ nvlist_flags(const nvlist_t *nvl)
NVLIST_ASSERT(nvl);
PJDLOG_ASSERT(nvl->nvl_error == 0);
- PJDLOG_ASSERT((nvl->nvl_flags & ~(NV_FLAG_PUBLIC_MASK)) == 0);
- return (nvl->nvl_flags);
+ return (nvl->nvl_flags & NV_FLAG_PUBLIC_MASK);
+}
+
+void
+nvlist_set_flags(nvlist_t *nvl, int flags)
+{
+
+ NVLIST_ASSERT(nvl);
+ PJDLOG_ASSERT(nvl->nvl_error == 0);
+
+ nvl->nvl_flags = flags;
}
static void
@@ -418,17 +487,129 @@ nvlist_dump(const nvlist_t *nvl, int fd)
dprintf(fd, "\n");
break;
}
+ case NV_TYPE_BOOL_ARRAY:
+ {
+ const bool *value;
+ unsigned int ii;
+ size_t nitems;
+
+ value = nvpair_get_bool_array(nvp, &nitems);
+ dprintf(fd, " [ ");
+ for (ii = 0; ii < nitems; ii++) {
+ dprintf(fd, "%s", value[ii] ? "TRUE" : "FALSE");
+ if (ii != nitems - 1)
+ dprintf(fd, ", ");
+ }
+ dprintf(fd, " ]\n");
+ break;
+ }
+ case NV_TYPE_STRING_ARRAY:
+ {
+ const char * const *value;
+ unsigned int ii;
+ size_t nitems;
+
+ value = nvpair_get_string_array(nvp, &nitems);
+ dprintf(fd, " [ ");
+ for (ii = 0; ii < nitems; ii++) {
+ if (value[ii] == NULL)
+ dprintf(fd, "NULL");
+ else
+ dprintf(fd, "\"%s\"", value[ii]);
+ if (ii != nitems - 1)
+ dprintf(fd, ", ");
+ }
+ dprintf(fd, " ]\n");
+ break;
+ }
+ case NV_TYPE_NUMBER_ARRAY:
+ {
+ const uint64_t *value;
+ unsigned int ii;
+ size_t nitems;
+
+ value = nvpair_get_number_array(nvp, &nitems);
+ dprintf(fd, " [ ");
+ for (ii = 0; ii < nitems; ii++) {
+ dprintf(fd, "%ju (%jd) (0x%jx)",
+ value[ii], value[ii], value[ii]);
+ if (ii != nitems - 1)
+ dprintf(fd, ", ");
+ }
+ dprintf(fd, " ]\n");
+ break;
+ }
+ case NV_TYPE_DESCRIPTOR_ARRAY:
+ {
+ const int *value;
+ unsigned int ii;
+ size_t nitems;
+
+ value = nvpair_get_descriptor_array(nvp, &nitems);
+ dprintf(fd, " [ ");
+ for (ii = 0; ii < nitems; ii++) {
+ dprintf(fd, "%d", value[ii]);
+ if (ii != nitems - 1)
+ dprintf(fd, ", ");
+ }
+ dprintf(fd, " ]\n");
+ break;
+ }
+ case NV_TYPE_NVLIST_ARRAY:
+ {
+ const nvlist_t * const *value;
+ unsigned int ii;
+ size_t nitems;
+
+ value = nvpair_get_nvlist_array(nvp, &nitems);
+ dprintf(fd, " %zu\n", nitems);
+ tmpnvl = NULL;
+ tmpnvp = NULL;
+ for (ii = 0; ii < nitems; ii++) {
+ if (nvlist_dump_error_check(value[ii], fd,
+ level + 1)) {
+ break;
+ }
+
+ if (tmpnvl == NULL) {
+ tmpnvp = nvlist_first_nvpair(value[ii]);
+ if (tmpnvp != NULL) {
+ tmpnvl = value[ii];
+ } else {
+ dprintf(fd, "%*s,\n",
+ (level + 1) * 4, "");
+ }
+ }
+ }
+ if (tmpnvp != NULL) {
+ nvl = tmpnvl;
+ nvp = tmpnvp;
+ level++;
+ continue;
+ }
+ break;
+ }
default:
PJDLOG_ABORT("Unknown type: %d.", nvpair_type(nvp));
}
while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
- cookie = NULL;
- nvl = nvlist_get_parent(nvl, &cookie);
- if (nvl == NULL)
- return;
- nvp = cookie;
- level--;
+ do {
+ cookie = NULL;
+ if (nvlist_in_array(nvl))
+ dprintf(fd, "%*s,\n", level * 4, "");
+ nvl = nvlist_get_pararr(nvl, &cookie);
+ if (nvl == NULL)
+ return;
+ if (nvlist_in_array(nvl) && cookie == NULL) {
+ nvp = nvlist_first_nvpair(nvl);
+ } else {
+ nvp = cookie;
+ level--;
+ }
+ } while (nvp == NULL);
+ if (nvlist_in_array(nvl) && cookie == NULL)
+ break;
}
}
}
@@ -449,9 +630,11 @@ size_t
nvlist_size(const nvlist_t *nvl)
{
const nvlist_t *tmpnvl;
+ const nvlist_t * const *nvlarray;
const nvpair_t *nvp, *tmpnvp;
void *cookie;
- size_t size;
+ size_t size, nitems;
+ unsigned int ii;
NVLIST_ASSERT(nvl);
PJDLOG_ASSERT(nvl->nvl_error == 0);
@@ -472,16 +655,47 @@ nvlist_size(const nvlist_t *nvl)
nvp = tmpnvp;
continue;
}
+ } else if (nvpair_type(nvp) == NV_TYPE_NVLIST_ARRAY) {
+ nvlarray = nvpair_get_nvlist_array(nvp, &nitems);
+ PJDLOG_ASSERT(nitems > 0);
+
+ size += (nvpair_header_size() + 1) * nitems;
+ size += sizeof(struct nvlist_header) * nitems;
+
+ tmpnvl = NULL;
+ tmpnvp = NULL;
+ for (ii = 0; ii < nitems; ii++) {
+ PJDLOG_ASSERT(nvlarray[ii]->nvl_error == 0);
+ tmpnvp = nvlist_first_nvpair(nvlarray[ii]);
+ if (tmpnvp != NULL) {
+ tmpnvl = nvlarray[ii];
+ break;
+ }
+ }
+ if (tmpnvp != NULL) {
+ nvp = tmpnvp;
+ nvl = tmpnvl;
+ continue;
+ }
+
} else {
size += nvpair_size(nvp);
}
while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
- cookie = NULL;
- nvl = nvlist_get_parent(nvl, &cookie);
- if (nvl == NULL)
- goto out;
- nvp = cookie;
+ do {
+ cookie = NULL;
+ nvl = nvlist_get_pararr(nvl, &cookie);
+ if (nvl == NULL)
+ goto out;
+ if (nvlist_in_array(nvl) && cookie == NULL) {
+ nvp = nvlist_first_nvpair(nvl);
+ } else {
+ nvp = cookie;
+ }
+ } while (nvp == NULL);
+ if (nvlist_in_array(nvl) && cookie == NULL)
+ break;
}
}
@@ -508,13 +722,40 @@ nvlist_xdescriptors(const nvlist_t *nvl, int *descs)
*descs = nvpair_get_descriptor(nvp);
descs++;
break;
+ case NV_TYPE_DESCRIPTOR_ARRAY:
+ {
+ const int *value;
+ size_t nitems;
+ unsigned int ii;
+
+ value = nvpair_get_descriptor_array(nvp,
+ &nitems);
+ for (ii = 0; ii < nitems; ii++) {
+ *descs = value[ii];
+ descs++;
+ }
+ break;
+ }
case NV_TYPE_NVLIST:
nvl = nvpair_get_nvlist(nvp);
nvp = NULL;
break;
+ case NV_TYPE_NVLIST_ARRAY:
+ {
+ const nvlist_t * const *value;
+ size_t nitems;
+
+ value = nvpair_get_nvlist_array(nvp, &nitems);
+ PJDLOG_ASSERT(value != NULL);
+ PJDLOG_ASSERT(nitems > 0);
+
+ nvl = value[0];
+ nvp = NULL;
+ break;
+ }
}
}
- } while ((nvl = nvlist_get_parent(nvl, (void**)&nvp)) != NULL);
+ } while ((nvl = nvlist_get_pararr(nvl, (void**)&nvp)) != NULL);
return (descs);
}
@@ -564,9 +805,31 @@ nvlist_ndescriptors(const nvlist_t *nvl)
nvl = nvpair_get_nvlist(nvp);
nvp = NULL;
break;
+ case NV_TYPE_NVLIST_ARRAY:
+ {
+ const nvlist_t * const *value;
+ size_t nitems;
+
+ value = nvpair_get_nvlist_array(nvp, &nitems);
+ PJDLOG_ASSERT(value != NULL);
+ PJDLOG_ASSERT(nitems > 0);
+
+ nvl = value[0];
+ nvp = NULL;
+ break;
+ }
+ case NV_TYPE_DESCRIPTOR_ARRAY:
+ {
+ size_t nitems;
+
+ (void)nvpair_get_descriptor_array(nvp,
+ &nitems);
+ ndescs += nitems;
+ break;
+ }
}
}
- } while ((nvl = nvlist_get_parent(nvl, (void**)&nvp)) != NULL);
+ } while ((nvl = nvlist_get_pararr(nvl, (void**)&nvp)) != NULL);
return (ndescs);
#else
@@ -661,24 +924,86 @@ nvlist_xpack(const nvlist_t *nvl, int64_t *fdidxp, size_t *sizep)
case NV_TYPE_DESCRIPTOR:
ptr = nvpair_pack_descriptor(nvp, ptr, fdidxp, &left);
break;
+ case NV_TYPE_DESCRIPTOR_ARRAY:
+ ptr = nvpair_pack_descriptor_array(nvp, ptr, fdidxp,
+ &left);
+ break;
#endif
case NV_TYPE_BINARY:
ptr = nvpair_pack_binary(nvp, ptr, &left);
break;
+ case NV_TYPE_BOOL_ARRAY:
+ ptr = nvpair_pack_bool_array(nvp, ptr, &left);
+ break;
+ case NV_TYPE_NUMBER_ARRAY:
+ ptr = nvpair_pack_number_array(nvp, ptr, &left);
+ break;
+ case NV_TYPE_STRING_ARRAY:
+ ptr = nvpair_pack_string_array(nvp, ptr, &left);
+ break;
+ case NV_TYPE_NVLIST_ARRAY:
+ {
+ const nvlist_t * const * value;
+ size_t nitems;
+ unsigned int ii;
+
+ tmpnvl = NULL;
+ value = nvpair_get_nvlist_array(nvp, &nitems);
+ for (ii = 0; ii < nitems; ii++) {
+ ptr = nvlist_pack_header(value[ii], ptr, &left);
+ if (ptr == NULL)
+ goto out;
+ tmpnvp = nvlist_first_nvpair(value[ii]);
+ if (tmpnvp != NULL) {
+ tmpnvl = value[ii];
+ break;
+ }
+ ptr = nvpair_pack_nvlist_array_next(ptr, &left);
+ if (ptr == NULL)
+ goto out;
+ }
+ if (tmpnvl != NULL) {
+ nvl = tmpnvl;
+ nvp = tmpnvp;
+ continue;
+ }
+ break;
+ }
default:
PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp));
}
if (ptr == NULL)
goto fail;
while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
- cookie = NULL;
- nvl = nvlist_get_parent(nvl, &cookie);
- if (nvl == NULL)
- goto out;
- nvp = cookie;
- ptr = nvpair_pack_nvlist_up(ptr, &left);
- if (ptr == NULL)
- goto fail;
+ do {
+ cookie = NULL;
+ if (nvlist_in_array(nvl)) {
+ ptr = nvpair_pack_nvlist_array_next(ptr,
+ &left);
+ if (ptr == NULL)
+ goto fail;
+ }
+ nvl = nvlist_get_pararr(nvl, &cookie);
+ if (nvl == NULL)
+ goto out;
+ if (nvlist_in_array(nvl) && cookie == NULL) {
+ nvp = nvlist_first_nvpair(nvl);
+ ptr = nvlist_pack_header(nvl, ptr,
+ &left);
+ if (ptr == NULL)
+ goto fail;
+ } else if (nvpair_type((nvpair_t *)cookie) !=
+ NV_TYPE_NVLIST_ARRAY) {
+ ptr = nvpair_pack_nvlist_up(ptr, &left);
+ if (ptr == NULL)
+ goto fail;
+ nvp = cookie;
+ } else {
+ nvp = cookie;
+ }
+ } while (nvp == NULL);
+ if (nvlist_in_array(nvl) && cookie == NULL)
+ break;
}
}
@@ -741,6 +1066,7 @@ nvlist_unpack_header(nvlist_t *nvl, const unsigned char *ptr, size_t nfds,
bool *isbep, size_t *leftp)
{
struct nvlist_header nvlhdr;
+ int inarrayf;
if (*leftp < sizeof(nvlhdr))
goto failed;
@@ -762,7 +1088,8 @@ nvlist_unpack_header(nvlist_t *nvl, const unsigned char *ptr, size_t nfds,
if ((nvlhdr.nvlh_flags & ~NV_FLAG_ALL_MASK) != 0)
goto failed;
- nvl->nvl_flags = (nvlhdr.nvlh_flags & NV_FLAG_PUBLIC_MASK);
+ inarrayf = (nvl->nvl_flags & NV_FLAG_IN_ARRAY);
+ nvl->nvl_flags = (nvlhdr.nvlh_flags & NV_FLAG_PUBLIC_MASK) | inarrayf;
ptr += sizeof(nvlhdr);
if (isbep != NULL)
@@ -780,7 +1107,7 @@ nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds,
int flags)
{
const unsigned char *ptr;
- nvlist_t *nvl, *retnvl, *tmpnvl;
+ nvlist_t *nvl, *retnvl, *tmpnvl, *array;
nvpair_t *nvp;
size_t left;
bool isbe;
@@ -790,7 +1117,7 @@ nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds,
left = size;
ptr = buf;
- tmpnvl = NULL;
+ tmpnvl = array = NULL;
nvl = retnvl = nvlist_create(0);
if (nvl == NULL)
goto failed;
@@ -832,6 +1159,10 @@ nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds,
ptr = nvpair_unpack_descriptor(isbe, nvp, ptr, &left,
fds, nfds);
break;
+ case NV_TYPE_DESCRIPTOR_ARRAY:
+ ptr = nvpair_unpack_descriptor_array(isbe, nvp, ptr,
+ &left, fds, nfds);
+ break;
#endif
case NV_TYPE_BINARY:
ptr = nvpair_unpack_binary(isbe, nvp, ptr, &left);
@@ -842,6 +1173,44 @@ nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds,
nvl = nvpair_nvlist(nvl->nvl_parent);
nvpair_free_structure(nvp);
continue;
+ case NV_TYPE_NVLIST_ARRAY_NEXT:
+ if (nvl->nvl_array_next == NULL) {
+ if (nvl->nvl_parent == NULL)
+ goto failed;
+ nvl = nvpair_nvlist(nvl->nvl_parent);
+ } else {
+ nvl = __DECONST(nvlist_t *,
+ nvlist_get_array_next(nvl));
+ ptr = nvlist_unpack_header(nvl, ptr, nfds,
+ &isbe, &left);
+ if (ptr == NULL)
+ goto failed;
+ }
+ nvpair_free_structure(nvp);
+ continue;
+ case NV_TYPE_BOOL_ARRAY:
+ ptr = nvpair_unpack_bool_array(isbe, nvp, ptr, &left);
+ break;
+ case NV_TYPE_NUMBER_ARRAY:
+ ptr = nvpair_unpack_number_array(isbe, nvp, ptr, &left);
+ break;
+ case NV_TYPE_STRING_ARRAY:
+ ptr = nvpair_unpack_string_array(isbe, nvp, ptr, &left);
+ break;
+ case NV_TYPE_NVLIST_ARRAY:
+ ptr = nvpair_unpack_nvlist_array(isbe, nvp, ptr, &left,
+ &array);
+ if (ptr == NULL)
+ goto failed;
+ tmpnvl = array;
+ while (array != NULL) {
+ nvlist_set_parent(array, nvp);
+ array = __DECONST(nvlist_t *,
+ nvlist_get_array_next(array));
+ }
+ ptr = nvlist_unpack_header(tmpnvl, ptr, nfds, &isbe,
+ &left);
+ break;
default:
PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp));
}
@@ -1062,10 +1431,15 @@ NVLIST_EXISTS(bool, BOOL)
NVLIST_EXISTS(number, NUMBER)
NVLIST_EXISTS(string, STRING)
NVLIST_EXISTS(nvlist, NVLIST)
+NVLIST_EXISTS(binary, BINARY)
+NVLIST_EXISTS(bool_array, BOOL_ARRAY)
+NVLIST_EXISTS(number_array, NUMBER_ARRAY)
+NVLIST_EXISTS(string_array, STRING_ARRAY)
+NVLIST_EXISTS(nvlist_array, NVLIST_ARRAY)
#ifndef _KERNEL
NVLIST_EXISTS(descriptor, DESCRIPTOR)
+NVLIST_EXISTS(descriptor_array, DESCRIPTOR_ARRAY)
#endif
-NVLIST_EXISTS(binary, BINARY)
#undef NVLIST_EXISTS
@@ -1198,6 +1572,37 @@ NVLIST_ADD(int, descriptor);
#undef NVLIST_ADD
+#define NVLIST_ADD_ARRAY(vtype, type) \
+void \
+nvlist_add_##type##_array(nvlist_t *nvl, const char *name, vtype value, \
+ size_t nitems) \
+{ \
+ nvpair_t *nvp; \
+ \
+ if (nvlist_error(nvl) != 0) { \
+ ERRNO_SET(nvlist_error(nvl)); \
+ return; \
+ } \
+ \
+ nvp = nvpair_create_##type##_array(name, value, nitems); \
+ if (nvp == NULL) { \
+ nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); \
+ ERRNO_SET(nvl->nvl_error); \
+ } else { \
+ (void)nvlist_move_nvpair(nvl, nvp); \
+ } \
+}
+
+NVLIST_ADD_ARRAY(const bool *, bool)
+NVLIST_ADD_ARRAY(const uint64_t *, number)
+NVLIST_ADD_ARRAY(const char * const *, string)
+NVLIST_ADD_ARRAY(const nvlist_t * const *, nvlist)
+#ifndef _KERNEL
+NVLIST_ADD_ARRAY(const int *, descriptor)
+#endif
+
+#undef NVLIST_ADD_ARRAY
+
bool
nvlist_move_nvpair(nvlist_t *nvl, nvpair_t *nvp)
{
@@ -1306,6 +1711,131 @@ nvlist_move_binary(nvlist_t *nvl, const char *name, void *value, size_t size)
}
}
+void
+nvlist_move_bool_array(nvlist_t *nvl, const char *name, bool *value,
+ size_t nitems)
+{
+ nvpair_t *nvp;
+
+ if (nvlist_error(nvl) != 0) {
+ nv_free(value);
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+
+ nvp = nvpair_move_bool_array(name, value, nitems);
+ if (nvp == NULL) {
+ nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
+ ERRNO_SET(nvl->nvl_error);
+ } else {
+ (void)nvlist_move_nvpair(nvl, nvp);
+ }
+}
+
+void
+nvlist_move_string_array(nvlist_t *nvl, const char *name, char **value,
+ size_t nitems)
+{
+ nvpair_t *nvp;
+ size_t i;
+
+ if (nvlist_error(nvl) != 0) {
+ if (value != NULL) {
+ for (i = 0; i < nitems; i++)
+ nv_free(value[i]);
+ nv_free(value);
+ }
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+
+ nvp = nvpair_move_string_array(name, value, nitems);
+ if (nvp == NULL) {
+ nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
+ ERRNO_SET(nvl->nvl_error);
+ } else {
+ (void)nvlist_move_nvpair(nvl, nvp);
+ }
+}
+
+void
+nvlist_move_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **value,
+ size_t nitems)
+{
+ nvpair_t *nvp;
+ size_t i;
+
+ if (nvlist_error(nvl) != 0) {
+ if (value != NULL) {
+ for (i = 0; i < nitems; i++) {
+ if (nvlist_get_pararr(value[i], NULL) == NULL)
+ nvlist_destroy(value[i]);
+ }
+ }
+ nv_free(value);
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+
+ nvp = nvpair_move_nvlist_array(name, value, nitems);
+ if (nvp == NULL) {
+ nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
+ ERRNO_SET(nvl->nvl_error);
+ } else {
+ (void)nvlist_move_nvpair(nvl, nvp);
+ }
+}
+
+void
+nvlist_move_number_array(nvlist_t *nvl, const char *name, uint64_t *value,
+ size_t nitems)
+{
+ nvpair_t *nvp;
+
+ if (nvlist_error(nvl) != 0) {
+ nv_free(value);
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+
+ nvp = nvpair_move_number_array(name, value, nitems);
+ if (nvp == NULL) {
+ nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
+ ERRNO_SET(nvl->nvl_error);
+ } else {
+ (void)nvlist_move_nvpair(nvl, nvp);
+ }
+}
+
+#ifndef _KERNEL
+void
+nvlist_move_descriptor_array(nvlist_t *nvl, const char *name, int *value,
+ size_t nitems)
+{
+ nvpair_t *nvp;
+ size_t i;
+
+ if (nvlist_error(nvl) != 0) {
+ if (value != 0) {
+ for (i = 0; i < nitems; i++)
+ close(value[i]);
+ nv_free(value);
+ }
+
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+
+ nvp = nvpair_move_descriptor_array(name, value, nitems);
+ if (nvp == NULL) {
+ nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
+ ERRNO_SET(nvl->nvl_error);
+ } else {
+ (void)nvlist_move_nvpair(nvl, nvp);
+ }
+}
+#endif
+
const nvpair_t *
nvlist_get_nvpair(const nvlist_t *nvl, const char *name)
{
@@ -1347,6 +1877,29 @@ nvlist_get_binary(const nvlist_t *nvl, const char *name, size_t *sizep)
return (nvpair_get_binary(nvp, sizep));
}
+#define NVLIST_GET_ARRAY(ftype, type, TYPE) \
+ftype \
+nvlist_get_##type##_array(const nvlist_t *nvl, const char *name, \
+ size_t *nitems) \
+{ \
+ const nvpair_t *nvp; \
+ \
+ nvp = nvlist_find(nvl, NV_TYPE_##TYPE##_ARRAY, name); \
+ if (nvp == NULL) \
+ nvlist_report_missing(NV_TYPE_##TYPE##_ARRAY, name); \
+ return (nvpair_get_##type##_array(nvp, nitems)); \
+}
+
+NVLIST_GET_ARRAY(const bool *, bool, BOOL)
+NVLIST_GET_ARRAY(const uint64_t *, number, NUMBER)
+NVLIST_GET_ARRAY(const char * const *, string, STRING)
+NVLIST_GET_ARRAY(const nvlist_t * const *, nvlist, NVLIST)
+#ifndef _KERNEL
+NVLIST_GET_ARRAY(const int *, descriptor, DESCRIPTOR)
+#endif
+
+#undef NVLIST_GET_ARRAY
+
#define NVLIST_TAKE(ftype, type, TYPE) \
ftype \
nvlist_take_##type(nvlist_t *nvl, const char *name) \
@@ -1389,6 +1942,31 @@ nvlist_take_binary(nvlist_t *nvl, const char *name, size_t *sizep)
return (value);
}
+#define NVLIST_TAKE_ARRAY(ftype, type, TYPE) \
+ftype \
+nvlist_take_##type##_array(nvlist_t *nvl, const char *name, \
+ size_t *nitems) \
+{ \
+ nvpair_t *nvp; \
+ ftype value; \
+ \
+ nvp = nvlist_find(nvl, NV_TYPE_##TYPE##_ARRAY, name); \
+ if (nvp == NULL) \
+ nvlist_report_missing(NV_TYPE_##TYPE##_ARRAY, name); \
+ value = (ftype)(intptr_t)nvpair_get_##type##_array(nvp, nitems);\
+ nvlist_remove_nvpair(nvl, nvp); \
+ nvpair_free_structure(nvp); \
+ return (value); \
+}
+
+NVLIST_TAKE_ARRAY(bool *, bool, BOOL)
+NVLIST_TAKE_ARRAY(uint64_t *, number, NUMBER)
+NVLIST_TAKE_ARRAY(char **, string, STRING)
+NVLIST_TAKE_ARRAY(nvlist_t **, nvlist, NVLIST)
+#ifndef _KERNEL
+NVLIST_TAKE_ARRAY(int *, descriptor, DESCRIPTOR)
+#endif
+
void
nvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp)
{
@@ -1420,10 +1998,15 @@ NVLIST_FREE(bool, BOOL)
NVLIST_FREE(number, NUMBER)
NVLIST_FREE(string, STRING)
NVLIST_FREE(nvlist, NVLIST)
+NVLIST_FREE(binary, BINARY)
+NVLIST_FREE(bool_array, BOOL_ARRAY)
+NVLIST_FREE(number_array, NUMBER_ARRAY)
+NVLIST_FREE(string_array, STRING_ARRAY)
+NVLIST_FREE(nvlist_array, NVLIST_ARRAY)
#ifndef _KERNEL
NVLIST_FREE(descriptor, DESCRIPTOR)
+NVLIST_FREE(descriptor_array, DESCRIPTOR_ARRAY)
#endif
-NVLIST_FREE(binary, BINARY)
#undef NVLIST_FREE
diff --git a/sys/contrib/libnv/nvlist_impl.h b/sys/contrib/libnv/nvlist_impl.h
index 18ccebf..9952db8 100644
--- a/sys/contrib/libnv/nvlist_impl.h
+++ b/sys/contrib/libnv/nvlist_impl.h
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2013 The FreeBSD Foundation
+ * Copyright (c) 2013-2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
* All rights reserved.
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
diff --git a/sys/contrib/libnv/nvpair.c b/sys/contrib/libnv/nvpair.c
index 7146767..1e3bd0e 100644
--- a/sys/contrib/libnv/nvpair.c
+++ b/sys/contrib/libnv/nvpair.c
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2009-2013 The FreeBSD Foundation
+ * Copyright (c) 2013-2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
* All rights reserved.
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
@@ -86,6 +87,7 @@ struct nvpair {
int nvp_type;
uint64_t nvp_data;
size_t nvp_datasize;
+ size_t nvp_nitems; /* Used only for array types. */
nvlist_t *nvp_list;
TAILQ_ENTRY(nvpair) nvp_next;
};
@@ -99,6 +101,7 @@ struct nvpair_header {
uint8_t nvph_type;
uint16_t nvph_namesize;
uint64_t nvph_datasize;
+ uint64_t nvph_nitems;
} __packed;
@@ -109,6 +112,36 @@ nvpair_assert(const nvpair_t *nvp)
NVPAIR_ASSERT(nvp);
}
+static nvpair_t *
+nvpair_allocv(const char *name, int type, uint64_t data, size_t datasize,
+ size_t nitems)
+{
+ nvpair_t *nvp;
+ size_t namelen;
+
+ PJDLOG_ASSERT(type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST);
+
+ namelen = strlen(name);
+ if (namelen >= NV_NAME_MAX) {
+ ERRNO_SET(ENAMETOOLONG);
+ return (NULL);
+ }
+
+ nvp = nv_calloc(1, sizeof(*nvp) + namelen + 1);
+ if (nvp != NULL) {
+ nvp->nvp_name = (char *)(nvp + 1);
+ memcpy(nvp->nvp_name, name, namelen);
+ nvp->nvp_name[namelen] = '\0';
+ nvp->nvp_type = type;
+ nvp->nvp_data = data;
+ nvp->nvp_datasize = datasize;
+ nvp->nvp_nitems = nitems;
+ nvp->nvp_magic = NVPAIR_MAGIC;
+ }
+
+ return (nvp);
+}
+
nvlist_t *
nvpair_nvlist(const nvpair_t *nvp)
{
@@ -162,6 +195,19 @@ nvpair_remove_nvlist(nvpair_t *nvp)
nvlist_set_parent(nvl, NULL);
}
+static void
+nvpair_remove_nvlist_array(nvpair_t *nvp)
+{
+ nvlist_t **nvlarray;
+ size_t count, i;
+
+ /* XXX: DECONST is bad, mkay? */
+ nvlarray = __DECONST(nvlist_t **,
+ nvpair_get_nvlist_array(nvp, &count));
+ for (i = 0; i < count; i++)
+ nvlist_set_array_next(nvlarray[i], NULL);
+}
+
void
nvpair_remove(struct nvl_head *head, nvpair_t *nvp, const nvlist_t *nvl)
{
@@ -171,6 +217,8 @@ nvpair_remove(struct nvl_head *head, nvpair_t *nvp, const nvlist_t *nvl)
if (nvpair_type(nvp) == NV_TYPE_NVLIST)
nvpair_remove_nvlist(nvp);
+ else if (nvpair_type(nvp) == NV_TYPE_NVLIST_ARRAY)
+ nvpair_remove_nvlist_array(nvp);
TAILQ_REMOVE(head, nvp, nvp_next);
nvp->nvp_list = NULL;
@@ -204,16 +252,36 @@ nvpair_clone(const nvpair_t *nvp)
case NV_TYPE_NVLIST:
newnvp = nvpair_create_nvlist(name, nvpair_get_nvlist(nvp));
break;
+ case NV_TYPE_BINARY:
+ data = nvpair_get_binary(nvp, &datasize);
+ newnvp = nvpair_create_binary(name, data, datasize);
+ break;
+ case NV_TYPE_BOOL_ARRAY:
+ data = nvpair_get_bool_array(nvp, &datasize);
+ newnvp = nvpair_create_bool_array(name, data, datasize);
+ break;
+ case NV_TYPE_NUMBER_ARRAY:
+ data = nvpair_get_number_array(nvp, &datasize);
+ newnvp = nvpair_create_number_array(name, data, datasize);
+ break;
+ case NV_TYPE_STRING_ARRAY:
+ data = nvpair_get_string_array(nvp, &datasize);
+ newnvp = nvpair_create_string_array(name, data, datasize);
+ break;
+ case NV_TYPE_NVLIST_ARRAY:
+ data = nvpair_get_nvlist_array(nvp, &datasize);
+ newnvp = nvpair_create_nvlist_array(name, data, datasize);
+ break;
#ifndef _KERNEL
case NV_TYPE_DESCRIPTOR:
newnvp = nvpair_create_descriptor(name,
nvpair_get_descriptor(nvp));
break;
-#endif
- case NV_TYPE_BINARY:
- data = nvpair_get_binary(nvp, &datasize);
- newnvp = nvpair_create_binary(name, data, datasize);
+ case NV_TYPE_DESCRIPTOR_ARRAY:
+ data = nvpair_get_descriptor_array(nvp, &datasize);
+ newnvp = nvpair_create_descriptor_array(name, data, datasize);
break;
+#endif
default:
PJDLOG_ABORT("Unknown type: %d.", nvpair_type(nvp));
}
@@ -250,6 +318,7 @@ nvpair_pack_header(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
PJDLOG_ASSERT(namesize > 0 && namesize <= UINT16_MAX);
nvphdr.nvph_namesize = namesize;
nvphdr.nvph_datasize = nvp->nvp_datasize;
+ nvphdr.nvph_nitems = nvp->nvp_nitems;
PJDLOG_ASSERT(*leftp >= sizeof(nvphdr));
memcpy(ptr, &nvphdr, sizeof(nvphdr));
ptr += sizeof(nvphdr);
@@ -336,6 +405,32 @@ nvpair_pack_nvlist_up(unsigned char *ptr, size_t *leftp)
nvphdr.nvph_type = NV_TYPE_NVLIST_UP;
nvphdr.nvph_namesize = namesize;
nvphdr.nvph_datasize = 0;
+ nvphdr.nvph_nitems = 0;
+ PJDLOG_ASSERT(*leftp >= sizeof(nvphdr));
+ memcpy(ptr, &nvphdr, sizeof(nvphdr));
+ ptr += sizeof(nvphdr);
+ *leftp -= sizeof(nvphdr);
+
+ PJDLOG_ASSERT(*leftp >= namesize);
+ memcpy(ptr, name, namesize);
+ ptr += namesize;
+ *leftp -= namesize;
+
+ return (ptr);
+}
+
+unsigned char *
+nvpair_pack_nvlist_array_next(unsigned char *ptr, size_t *leftp)
+{
+ struct nvpair_header nvphdr;
+ size_t namesize;
+ const char *name = "";
+
+ namesize = 1;
+ nvphdr.nvph_type = NV_TYPE_NVLIST_ARRAY_NEXT;
+ nvphdr.nvph_namesize = namesize;
+ nvphdr.nvph_datasize = 0;
+ nvphdr.nvph_nitems = 0;
PJDLOG_ASSERT(*leftp >= sizeof(nvphdr));
memcpy(ptr, &nvphdr, sizeof(nvphdr));
ptr += sizeof(nvphdr);
@@ -396,6 +491,106 @@ nvpair_pack_binary(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
return (ptr);
}
+unsigned char *
+nvpair_pack_bool_array(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL_ARRAY);
+ PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
+
+ memcpy(ptr, (const void *)(intptr_t)nvp->nvp_data, nvp->nvp_datasize);
+ ptr += nvp->nvp_datasize;
+ *leftp -= nvp->nvp_datasize;
+
+ return (ptr);
+}
+
+unsigned char *
+nvpair_pack_number_array(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER_ARRAY);
+ PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
+
+ memcpy(ptr, (const void *)(intptr_t)nvp->nvp_data, nvp->nvp_datasize);
+ ptr += nvp->nvp_datasize;
+ *leftp -= nvp->nvp_datasize;
+
+ return (ptr);
+}
+
+unsigned char *
+nvpair_pack_string_array(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
+{
+ unsigned int ii;
+ size_t size, len;
+ const char * const *array;
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING_ARRAY);
+ PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
+
+ size = 0;
+ array = nvpair_get_string_array(nvp, NULL);
+ PJDLOG_ASSERT(array != NULL);
+
+ for (ii = 0; ii < nvp->nvp_nitems; ii++) {
+ len = strlen(array[ii]) + 1;
+ PJDLOG_ASSERT(*leftp >= len);
+
+ memcpy(ptr, (const void *)array[ii], len);
+ size += len;
+ ptr += len;
+ *leftp -= len;
+ }
+
+ PJDLOG_ASSERT(size == nvp->nvp_datasize);
+
+ return (ptr);
+}
+
+#ifndef _KERNEL
+unsigned char *
+nvpair_pack_descriptor_array(const nvpair_t *nvp, unsigned char *ptr,
+ int64_t *fdidxp, size_t *leftp)
+{
+ int64_t value;
+ const int *array;
+ unsigned int ii;
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR_ARRAY);
+ PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
+
+ array = nvpair_get_descriptor_array(nvp, NULL);
+ PJDLOG_ASSERT(array != NULL);
+
+ for (ii = 0; ii < nvp->nvp_nitems; ii++) {
+ PJDLOG_ASSERT(*leftp >= sizeof(value));
+
+ value = array[ii];
+ if (value != -1) {
+ /*
+ * If there is a real descriptor here, we change its
+ * number to position in the array of descriptors send
+ * via control message.
+ */
+ PJDLOG_ASSERT(fdidxp != NULL);
+
+ value = *fdidxp;
+ (*fdidxp)++;
+ }
+ memcpy(ptr, &value, sizeof(value));
+ ptr += sizeof(value);
+ *leftp -= sizeof(value);
+ }
+
+ return (ptr);
+}
+#endif
+
void
nvpair_init_datasize(nvpair_t *nvp)
{
@@ -430,7 +625,8 @@ nvpair_unpack_header(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
goto failed;
#endif
if (nvphdr.nvph_type > NV_TYPE_LAST &&
- nvphdr.nvph_type != NV_TYPE_NVLIST_UP) {
+ nvphdr.nvph_type != NV_TYPE_NVLIST_UP &&
+ nvphdr.nvph_type != NV_TYPE_NVLIST_ARRAY_NEXT) {
goto failed;
}
@@ -467,6 +663,7 @@ nvpair_unpack_header(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
nvp->nvp_type = nvphdr.nvph_type;
nvp->nvp_data = 0;
nvp->nvp_datasize = nvphdr.nvph_datasize;
+ nvp->nvp_nitems = nvphdr.nvph_nitems;
return (ptr);
failed:
@@ -540,6 +737,7 @@ nvpair_unpack_number(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
nvp->nvp_data = be64dec(ptr);
else
nvp->nvp_data = le64dec(ptr);
+
ptr += sizeof(uint64_t);
*leftp -= sizeof(uint64_t);
@@ -670,6 +868,234 @@ nvpair_unpack_binary(bool isbe __unused, nvpair_t *nvp,
}
const unsigned char *
+nvpair_unpack_bool_array(bool isbe __unused, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp)
+{
+ uint8_t *value;
+ size_t size;
+ unsigned int i;
+
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL_ARRAY);
+
+ size = sizeof(*value) * nvp->nvp_nitems;
+ if (nvp->nvp_datasize != size || *leftp < size ||
+ nvp->nvp_nitems == 0 || size < nvp->nvp_nitems) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ value = nv_malloc(size);
+ if (value == NULL)
+ return (NULL);
+
+ for (i = 0; i < nvp->nvp_nitems; i++) {
+ value[i] = *(const uint8_t *)ptr;
+
+ ptr += sizeof(*value);
+ *leftp -= sizeof(*value);
+ }
+
+ nvp->nvp_data = (uint64_t)(uintptr_t)value;
+
+ return (ptr);
+}
+
+const unsigned char *
+nvpair_unpack_number_array(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
+ size_t *leftp)
+{
+ uint64_t *value;
+ size_t size;
+ unsigned int i;
+
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER_ARRAY);
+
+ size = sizeof(*value) * nvp->nvp_nitems;
+ if (nvp->nvp_datasize != size || *leftp < size ||
+ nvp->nvp_nitems == 0 || size < nvp->nvp_nitems) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ value = nv_malloc(size);
+ if (value == NULL)
+ return (NULL);
+
+ for (i = 0; i < nvp->nvp_nitems; i++) {
+ if (isbe)
+ value[i] = be64dec(ptr);
+ else
+ value[i] = le64dec(ptr);
+
+ ptr += sizeof(*value);
+ *leftp -= sizeof(*value);
+ }
+
+ nvp->nvp_data = (uint64_t)(uintptr_t)value;
+
+ return (ptr);
+}
+
+const unsigned char *
+nvpair_unpack_string_array(bool isbe __unused, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp)
+{
+ ssize_t size;
+ size_t len;
+ const char *tmp;
+ char **value;
+ unsigned int ii, j;
+
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING_ARRAY);
+
+ if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0 ||
+ nvp->nvp_nitems == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ size = nvp->nvp_datasize;
+ tmp = (const char *)ptr;
+ for (ii = 0; ii < nvp->nvp_nitems; ii++) {
+ len = strnlen(tmp, size - 1) + 1;
+ size -= len;
+ if (size < 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+ tmp += len;
+ }
+ if (size != 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ value = nv_malloc(sizeof(*value) * nvp->nvp_nitems);
+ if (value == NULL)
+ return (NULL);
+
+ for (ii = 0; ii < nvp->nvp_nitems; ii++) {
+ value[ii] = nv_strdup((const char *)ptr);
+ if (value[ii] == NULL)
+ goto out;
+ len = strlen(value[ii]) + 1;
+ ptr += len;
+ *leftp -= len;
+ }
+ nvp->nvp_data = (uint64_t)(uintptr_t)value;
+
+ return (ptr);
+out:
+ for (j = 0; j < ii; j++)
+ nv_free(value[j]);
+ nv_free(value);
+ return (NULL);
+}
+
+#ifndef _KERNEL
+const unsigned char *
+nvpair_unpack_descriptor_array(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp, const int *fds, size_t nfds)
+{
+ int64_t idx;
+ size_t size;
+ unsigned int ii;
+ int *array;
+
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR_ARRAY);
+
+ size = sizeof(idx) * nvp->nvp_nitems;
+ if (nvp->nvp_datasize != size || *leftp < size ||
+ nvp->nvp_nitems == 0 || size < nvp->nvp_nitems) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ array = (int *)nv_malloc(size);
+ if (array == NULL)
+ return (NULL);
+
+ for (ii = 0; ii < nvp->nvp_nitems; ii++) {
+ if (isbe)
+ idx = be64dec(ptr);
+ else
+ idx = le64dec(ptr);
+
+ if (idx < 0) {
+ ERRNO_SET(EINVAL);
+ nv_free(array);
+ return (NULL);
+ }
+
+ if ((size_t)idx >= nfds) {
+ ERRNO_SET(EINVAL);
+ nv_free(array);
+ return (NULL);
+ }
+
+ array[ii] = (uint64_t)fds[idx];
+
+ ptr += sizeof(idx);
+ *leftp -= sizeof(idx);
+ }
+
+ nvp->nvp_data = (uint64_t)(uintptr_t)array;
+
+ return (ptr);
+}
+#endif
+
+const unsigned char *
+nvpair_unpack_nvlist_array(bool isbe __unused, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp, nvlist_t **firstel)
+{
+ nvlist_t **value;
+ nvpair_t *tmpnvp;
+ unsigned int ii, j;
+ size_t sizeup;
+
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST_ARRAY);
+
+ sizeup = sizeof(struct nvpair_header) * nvp->nvp_nitems;
+ if (nvp->nvp_nitems == 0 || sizeup < nvp->nvp_nitems ||
+ sizeup > *leftp) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ value = nv_malloc(nvp->nvp_nitems * sizeof(*value));
+ if (value == NULL)
+ return (NULL);
+
+ for (ii = 0; ii < nvp->nvp_nitems; ii++) {
+ value[ii] = nvlist_create(0);
+ if (value[ii] == NULL)
+ goto fail;
+ if (ii > 0) {
+ tmpnvp = nvpair_allocv(" ", NV_TYPE_NVLIST,
+ (uint64_t)(uintptr_t)value[ii], 0, 0);
+ if (tmpnvp == NULL)
+ goto fail;
+ nvlist_set_array_next(value[ii - 1], tmpnvp);
+ }
+ }
+ nvlist_set_flags(value[nvp->nvp_nitems - 1], NV_FLAG_IN_ARRAY);
+
+ nvp->nvp_data = (uint64_t)(uintptr_t)value;
+ *firstel = value[0];
+
+ return (ptr);
+fail:
+ ERRNO_SAVE();
+ for (j = 0; j < ii; j++)
+ nvlist_destroy(value[j]);
+ nv_free(value);
+ ERRNO_RESTORE();
+
+ return (NULL);
+}
+
+const unsigned char *
nvpair_unpack(bool isbe, const unsigned char *ptr, size_t *leftp,
nvpair_t **nvpp)
{
@@ -717,34 +1143,6 @@ nvpair_name(const nvpair_t *nvp)
return (nvp->nvp_name);
}
-static nvpair_t *
-nvpair_allocv(const char *name, int type, uint64_t data, size_t datasize)
-{
- nvpair_t *nvp;
- size_t namelen;
-
- PJDLOG_ASSERT(type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST);
-
- namelen = strlen(name);
- if (namelen >= NV_NAME_MAX) {
- ERRNO_SET(ENAMETOOLONG);
- return (NULL);
- }
-
- nvp = nv_calloc(1, sizeof(*nvp) + namelen + 1);
- if (nvp != NULL) {
- nvp->nvp_name = (char *)(nvp + 1);
- memcpy(nvp->nvp_name, name, namelen);
- nvp->nvp_name[namelen] = '\0';
- nvp->nvp_type = type;
- nvp->nvp_data = data;
- nvp->nvp_datasize = datasize;
- nvp->nvp_magic = NVPAIR_MAGIC;
- }
-
- return (nvp);
-}
-
nvpair_t *
nvpair_create_stringf(const char *name, const char *valuefmt, ...)
{
@@ -778,7 +1176,7 @@ nvpair_t *
nvpair_create_null(const char *name)
{
- return (nvpair_allocv(name, NV_TYPE_NULL, 0, 0));
+ return (nvpair_allocv(name, NV_TYPE_NULL, 0, 0, 0));
}
nvpair_t *
@@ -786,14 +1184,14 @@ nvpair_create_bool(const char *name, bool value)
{
return (nvpair_allocv(name, NV_TYPE_BOOL, value ? 1 : 0,
- sizeof(uint8_t)));
+ sizeof(uint8_t), 0));
}
nvpair_t *
nvpair_create_number(const char *name, uint64_t value)
{
- return (nvpair_allocv(name, NV_TYPE_NUMBER, value, sizeof(value)));
+ return (nvpair_allocv(name, NV_TYPE_NUMBER, value, sizeof(value), 0));
}
nvpair_t *
@@ -814,7 +1212,7 @@ nvpair_create_string(const char *name, const char *value)
size = strlen(value) + 1;
nvp = nvpair_allocv(name, NV_TYPE_STRING, (uint64_t)(uintptr_t)data,
- size);
+ size, 0);
if (nvp == NULL)
nv_free(data);
@@ -836,7 +1234,8 @@ nvpair_create_nvlist(const char *name, const nvlist_t *value)
if (nvl == NULL)
return (NULL);
- nvp = nvpair_allocv(name, NV_TYPE_NVLIST, (uint64_t)(uintptr_t)nvl, 0);
+ nvp = nvpair_allocv(name, NV_TYPE_NVLIST, (uint64_t)(uintptr_t)nvl, 0,
+ 0);
if (nvp == NULL)
nvlist_destroy(nvl);
else
@@ -861,7 +1260,7 @@ nvpair_create_descriptor(const char *name, int value)
return (NULL);
nvp = nvpair_allocv(name, NV_TYPE_DESCRIPTOR, (uint64_t)value,
- sizeof(int64_t));
+ sizeof(int64_t), 0);
if (nvp == NULL) {
ERRNO_SAVE();
close(value);
@@ -889,7 +1288,7 @@ nvpair_create_binary(const char *name, const void *value, size_t size)
memcpy(data, value, size);
nvp = nvpair_allocv(name, NV_TYPE_BINARY, (uint64_t)(uintptr_t)data,
- size);
+ size, 0);
if (nvp == NULL)
nv_free(data);
@@ -897,6 +1296,226 @@ nvpair_create_binary(const char *name, const void *value, size_t size)
}
nvpair_t *
+nvpair_create_bool_array(const char *name, const bool *value, size_t nitems)
+{
+ nvpair_t *nvp;
+ size_t size;
+ void *data;
+
+ if (value == NULL || nitems == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ size = sizeof(value[0]) * nitems;
+ data = nv_malloc(size);
+ if (data == NULL)
+ return (NULL);
+
+ memcpy(data, value, size);
+ nvp = nvpair_allocv(name, NV_TYPE_BOOL_ARRAY, (uint64_t)(uintptr_t)data,
+ size, nitems);
+ if (nvp == NULL) {
+ ERRNO_SAVE();
+ nv_free(data);
+ ERRNO_RESTORE();
+ }
+
+ return (nvp);
+}
+
+nvpair_t *
+nvpair_create_number_array(const char *name, const uint64_t *value,
+ size_t nitems)
+{
+ nvpair_t *nvp;
+ size_t size;
+ void *data;
+
+ if (value == NULL || nitems == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ size = sizeof(value[0]) * nitems;
+ data = nv_malloc(size);
+ if (data == NULL)
+ return (NULL);
+
+ memcpy(data, value, size);
+ nvp = nvpair_allocv(name, NV_TYPE_NUMBER_ARRAY,
+ (uint64_t)(uintptr_t)data, size, nitems);
+ if (nvp == NULL) {
+ ERRNO_SAVE();
+ nv_free(data);
+ ERRNO_RESTORE();
+ }
+
+ return (nvp);
+}
+
+nvpair_t *
+nvpair_create_string_array(const char *name, const char * const *value,
+ size_t nitems)
+{
+ nvpair_t *nvp;
+ unsigned int ii;
+ size_t datasize, size;
+ char **data;
+
+ if (value == NULL || nitems == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ nvp = NULL;
+ datasize = 0;
+ data = nv_malloc(sizeof(value[0]) * nitems);
+ if (data == NULL)
+ return (NULL);
+
+ for (ii = 0; ii < nitems; ii++) {
+ if (value[ii] == NULL) {
+ ERRNO_SET(EINVAL);
+ goto fail;
+ }
+
+ size = strlen(value[ii]) + 1;
+ datasize += size;
+ data[ii] = nv_strdup(value[ii]);
+ if (data[ii] == NULL)
+ goto fail;
+ }
+ nvp = nvpair_allocv(name, NV_TYPE_STRING_ARRAY,
+ (uint64_t)(uintptr_t)data, datasize, nitems);
+
+fail:
+ if (nvp == NULL) {
+ ERRNO_SAVE();
+ for (; ii > 0; ii--)
+ nv_free(data[ii - 1]);
+ nv_free(data);
+ ERRNO_RESTORE();
+ }
+
+ return (nvp);
+}
+
+nvpair_t *
+nvpair_create_nvlist_array(const char *name, const nvlist_t * const *value,
+ size_t nitems)
+{
+ unsigned int ii;
+ nvlist_t **nvls;
+ nvpair_t *nvp;
+ int flags;
+
+ nvp = NULL;
+ nvls = NULL;
+ ii = 0;
+
+ if (value == NULL || nitems == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ nvls = nv_malloc(sizeof(value[0]) * nitems);
+ if (nvls == NULL)
+ return (NULL);
+
+ for (ii = 0; ii < nitems; ii++) {
+ if (value[ii] == NULL) {
+ ERRNO_SET(EINVAL);
+ goto fail;
+ }
+
+ nvls[ii] = nvlist_clone(value[ii]);
+ if (nvls[ii] == NULL)
+ goto fail;
+
+ if (ii > 0) {
+ nvp = nvpair_allocv(" ", NV_TYPE_NVLIST,
+ (uint64_t)(uintptr_t)nvls[ii], 0, 0);
+ if (nvp == NULL)
+ goto fail;
+ nvlist_set_array_next(nvls[ii - 1], nvp);
+ }
+ }
+ flags = nvlist_flags(nvls[nitems - 1]) | NV_FLAG_IN_ARRAY;
+ nvlist_set_flags(nvls[nitems - 1], flags);
+
+ nvp = nvpair_allocv(name, NV_TYPE_NVLIST_ARRAY,
+ (uint64_t)(uintptr_t)nvls, 0, nitems);
+
+fail:
+ if (nvp == NULL) {
+ ERRNO_SAVE();
+ for (; ii > 0; ii--)
+ nvlist_destroy(nvls[ii - 1]);
+
+ nv_free(nvls);
+ ERRNO_RESTORE();
+ } else {
+ for (ii = 0; ii < nitems; ii++)
+ nvlist_set_parent(nvls[ii], nvp);
+ }
+
+ return (nvp);
+}
+
+#ifndef _KERNEL
+nvpair_t *
+nvpair_create_descriptor_array(const char *name, const int *value,
+ size_t nitems)
+{
+ unsigned int ii;
+ nvpair_t *nvp;
+ int *fds;
+
+ if (value == NULL) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ nvp = NULL;
+
+ fds = nv_malloc(sizeof(value[0]) * nitems);
+ if (fds == NULL)
+ return (NULL);
+ for (ii = 0; ii < nitems; ii++) {
+ if (value[ii] == -1) {
+ fds[ii] = -1;
+ } else {
+ if (!fd_is_valid(value[ii])) {
+ ERRNO_SET(EBADF);
+ goto fail;
+ }
+
+ fds[ii] = fcntl(value[ii], F_DUPFD_CLOEXEC, 0);
+ if (fds[ii] == -1)
+ goto fail;
+ }
+ }
+
+ nvp = nvpair_allocv(name, NV_TYPE_DESCRIPTOR_ARRAY,
+ (uint64_t)(uintptr_t)fds, sizeof(int64_t) * nitems, nitems);
+
+fail:
+ if (nvp == NULL) {
+ ERRNO_SAVE();
+ for (; ii > 0; ii--) {
+ if (fds[ii - 1] != -1)
+ close(fds[ii - 1]);
+ }
+ nv_free(fds);
+ ERRNO_RESTORE();
+ }
+
+ return (nvp);
+}
+#endif
+
+nvpair_t *
nvpair_move_string(const char *name, char *value)
{
nvpair_t *nvp;
@@ -907,7 +1526,7 @@ nvpair_move_string(const char *name, char *value)
}
nvp = nvpair_allocv(name, NV_TYPE_STRING, (uint64_t)(uintptr_t)value,
- strlen(value) + 1);
+ strlen(value) + 1, 0);
if (nvp == NULL) {
ERRNO_SAVE();
nv_free(value);
@@ -934,7 +1553,7 @@ nvpair_move_nvlist(const char *name, nvlist_t *value)
}
nvp = nvpair_allocv(name, NV_TYPE_NVLIST, (uint64_t)(uintptr_t)value,
- 0);
+ 0, 0);
if (nvp == NULL)
nvlist_destroy(value);
else
@@ -955,7 +1574,7 @@ nvpair_move_descriptor(const char *name, int value)
}
nvp = nvpair_allocv(name, NV_TYPE_DESCRIPTOR, (uint64_t)value,
- sizeof(int64_t));
+ sizeof(int64_t), 0);
if (nvp == NULL) {
ERRNO_SAVE();
close(value);
@@ -977,7 +1596,83 @@ nvpair_move_binary(const char *name, void *value, size_t size)
}
nvp = nvpair_allocv(name, NV_TYPE_BINARY, (uint64_t)(uintptr_t)value,
- size);
+ size, 0);
+ if (nvp == NULL) {
+ ERRNO_SAVE();
+ nv_free(value);
+ ERRNO_RESTORE();
+ }
+
+ return (nvp);
+}
+
+nvpair_t *
+nvpair_move_bool_array(const char *name, bool *value, size_t nitems)
+{
+ nvpair_t *nvp;
+
+ if (value == NULL || nitems == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ nvp = nvpair_allocv(name, NV_TYPE_BOOL_ARRAY,
+ (uint64_t)(uintptr_t)value, sizeof(value[0]) * nitems, nitems);
+ if (nvp == NULL) {
+ ERRNO_SAVE();
+ nv_free(value);
+ ERRNO_RESTORE();
+ }
+
+ return (nvp);
+}
+
+nvpair_t *
+nvpair_move_string_array(const char *name, char **value, size_t nitems)
+{
+ nvpair_t *nvp;
+ size_t i, size;
+
+ if (value == NULL || nitems == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ size = 0;
+ for (i = 0; i < nitems; i++) {
+ if (value[i] == NULL) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ size += strlen(value[i]) + 1;
+ }
+
+ nvp = nvpair_allocv(name, NV_TYPE_STRING_ARRAY,
+ (uint64_t)(uintptr_t)value, size, nitems);
+ if (nvp == NULL) {
+ ERRNO_SAVE();
+ for (i = 0; i < nitems; i++)
+ nv_free(value[i]);
+ nv_free(value);
+ ERRNO_RESTORE();
+ }
+
+ return (nvp);
+}
+
+nvpair_t *
+nvpair_move_number_array(const char *name, uint64_t *value, size_t nitems)
+{
+ nvpair_t *nvp;
+
+ if (value == NULL || nitems == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ nvp = nvpair_allocv(name, NV_TYPE_NUMBER_ARRAY,
+ (uint64_t)(uintptr_t)value, sizeof(value[0]) * nitems, nitems);
if (nvp == NULL) {
ERRNO_SAVE();
nv_free(value);
@@ -987,6 +1682,95 @@ nvpair_move_binary(const char *name, void *value, size_t size)
return (nvp);
}
+nvpair_t *
+nvpair_move_nvlist_array(const char *name, nvlist_t **value, size_t nitems)
+{
+ unsigned int ii;
+ nvpair_t *nvp;
+ int flags;
+
+ nvp = NULL;
+ if (value == NULL || nitems == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ for (ii = 0; ii < nitems; ii++) {
+ if (value == NULL || nvlist_error(value[ii]) != 0 ||
+ nvlist_get_pararr(value[ii], NULL) != NULL) {
+ ERRNO_SET(EINVAL);
+ goto fail;
+ }
+ if (ii > 0) {
+ nvp = nvpair_allocv(" ", NV_TYPE_NVLIST,
+ (uint64_t)(uintptr_t)value[ii], 0, 0);
+ if (nvp == NULL)
+ goto fail;
+ nvlist_set_array_next(value[ii - 1], nvp);
+ }
+ }
+ flags = nvlist_flags(value[nitems - 1]) | NV_FLAG_IN_ARRAY;
+ nvlist_set_flags(value[nitems - 1], flags);
+
+ nvp = nvpair_allocv(name, NV_TYPE_NVLIST_ARRAY,
+ (uint64_t)(uintptr_t)value, 0, nitems);
+fail:
+ if (nvp == NULL) {
+ ERRNO_SAVE();
+ for (ii = 0; ii < nitems; ii++) {
+ if (value[ii] != NULL &&
+ nvlist_get_pararr(value[ii], NULL) != NULL) {
+ nvlist_destroy(value[ii]);
+ }
+ nv_free(value);
+ }
+ ERRNO_RESTORE();
+ } else {
+ for (ii = 0; ii < nitems; ii++)
+ nvlist_set_parent(value[ii], nvp);
+ }
+
+ return (nvp);
+}
+
+#ifndef _KERNEL
+nvpair_t *
+nvpair_move_descriptor_array(const char *name, int *value, size_t nitems)
+{
+ nvpair_t *nvp;
+ size_t i;
+
+ nvp = NULL;
+ if (value == NULL || nitems == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ for (i = 0; i < nitems; i++) {
+ if (value[i] != -1 && !fd_is_valid(value[i])) {
+ ERRNO_SET(EBADF);
+ goto fail;
+ }
+ }
+
+ nvp = nvpair_allocv(name, NV_TYPE_DESCRIPTOR_ARRAY,
+ (uint64_t)(uintptr_t)value, sizeof(value[0]) * nitems, nitems);
+
+fail:
+ if (nvp == NULL) {
+ ERRNO_SAVE();
+ for (i = 0; i < nitems; i++) {
+ if (fd_is_valid(value[i]))
+ close(value[i]);
+ }
+ nv_free(value);
+ ERRNO_RESTORE();
+ }
+
+ return (nvp);
+}
+#endif
+
bool
nvpair_get_bool(const nvpair_t *nvp)
{
@@ -1046,12 +1830,81 @@ nvpair_get_binary(const nvpair_t *nvp, size_t *sizep)
if (sizep != NULL)
*sizep = nvp->nvp_datasize;
+
return ((const void *)(intptr_t)nvp->nvp_data);
}
+const bool *
+nvpair_get_bool_array(const nvpair_t *nvp, size_t *nitems)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL_ARRAY);
+
+ if (nitems != NULL)
+ *nitems = nvp->nvp_nitems;
+
+ return ((const bool *)(intptr_t)nvp->nvp_data);
+}
+
+const uint64_t *
+nvpair_get_number_array(const nvpair_t *nvp, size_t *nitems)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER_ARRAY);
+
+ if (nitems != NULL)
+ *nitems = nvp->nvp_nitems;
+
+ return ((const uint64_t *)(intptr_t)nvp->nvp_data);
+}
+
+const char * const *
+nvpair_get_string_array(const nvpair_t *nvp, size_t *nitems)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING_ARRAY);
+
+ if (nitems != NULL)
+ *nitems = nvp->nvp_nitems;
+
+ return ((const char * const *)(intptr_t)nvp->nvp_data);
+}
+
+const nvlist_t * const *
+nvpair_get_nvlist_array(const nvpair_t *nvp, size_t *nitems)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST_ARRAY);
+
+ if (nitems != NULL)
+ *nitems = nvp->nvp_nitems;
+
+ return ((const nvlist_t * const *)((intptr_t)nvp->nvp_data));
+}
+
+#ifndef _KERNEL
+const int *
+nvpair_get_descriptor_array(const nvpair_t *nvp, size_t *nitems)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR_ARRAY);
+
+ if (nitems != NULL)
+ *nitems = nvp->nvp_nitems;
+
+ return ((const int *)(intptr_t)nvp->nvp_data);
+}
+#endif
+
void
nvpair_free(nvpair_t *nvp)
{
+ size_t i;
NVPAIR_ASSERT(nvp);
PJDLOG_ASSERT(nvp->nvp_list == NULL);
@@ -1062,6 +1915,10 @@ nvpair_free(nvpair_t *nvp)
case NV_TYPE_DESCRIPTOR:
close((int)nvp->nvp_data);
break;
+ case NV_TYPE_DESCRIPTOR_ARRAY:
+ for (i = 0; i < nvp->nvp_nitems; i++)
+ close(((int *)(intptr_t)nvp->nvp_data)[i]);
+ break;
#endif
case NV_TYPE_NVLIST:
nvlist_destroy((nvlist_t *)(intptr_t)nvp->nvp_data);
@@ -1072,6 +1929,23 @@ nvpair_free(nvpair_t *nvp)
case NV_TYPE_BINARY:
nv_free((void *)(intptr_t)nvp->nvp_data);
break;
+ case NV_TYPE_NVLIST_ARRAY:
+ for (i = 0; i < nvp->nvp_nitems; i++) {
+ nvlist_destroy(
+ ((nvlist_t **)(intptr_t)nvp->nvp_data)[i]);
+ }
+ nv_free(((nvlist_t **)(intptr_t)nvp->nvp_data));
+ break;
+ case NV_TYPE_NUMBER_ARRAY:
+ nv_free((uint64_t *)(intptr_t)nvp->nvp_data);
+ break;
+ case NV_TYPE_BOOL_ARRAY:
+ nv_free((bool *)(intptr_t)nvp->nvp_data);
+ break;
+ case NV_TYPE_STRING_ARRAY:
+ for (i = 0; i < nvp->nvp_nitems; i++)
+ nv_free(((char **)(intptr_t)nvp->nvp_data)[i]);
+ break;
}
nv_free(nvp);
}
@@ -1106,6 +1980,16 @@ nvpair_type_string(int type)
return ("DESCRIPTOR");
case NV_TYPE_BINARY:
return ("BINARY");
+ case NV_TYPE_BOOL_ARRAY:
+ return ("BOOL ARRAY");
+ case NV_TYPE_NUMBER_ARRAY:
+ return ("NUMBER ARRAY");
+ case NV_TYPE_STRING_ARRAY:
+ return ("STRING ARRAY");
+ case NV_TYPE_NVLIST_ARRAY:
+ return ("NVLIST ARRAY");
+ case NV_TYPE_DESCRIPTOR_ARRAY:
+ return ("DESCRIPTOR ARRAY");
default:
return ("<UNKNOWN>");
}
diff --git a/sys/contrib/libnv/nvpair_impl.h b/sys/contrib/libnv/nvpair_impl.h
index fed7725..0350b1c 100644
--- a/sys/contrib/libnv/nvpair_impl.h
+++ b/sys/contrib/libnv/nvpair_impl.h
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2009-2013 The FreeBSD Foundation
+ * Copyright (c) 2013-2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
* All rights reserved.
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
@@ -71,6 +72,15 @@ unsigned char *nvpair_pack_descriptor(const nvpair_t *nvp, unsigned char *ptr,
unsigned char *nvpair_pack_binary(const nvpair_t *nvp, unsigned char *ptr,
size_t *leftp);
unsigned char *nvpair_pack_nvlist_up(unsigned char *ptr, size_t *leftp);
+unsigned char *nvpair_pack_bool_array(const nvpair_t *nvp, unsigned char *ptr,
+ size_t *leftp);
+unsigned char *nvpair_pack_number_array(const nvpair_t *nvp, unsigned char *ptr,
+ size_t *leftp);
+unsigned char *nvpair_pack_string_array(const nvpair_t *nvp, unsigned char *ptr,
+ size_t *leftp);
+unsigned char *nvpair_pack_descriptor_array(const nvpair_t *nvp,
+ unsigned char *ptr, int64_t *fdidxp, size_t *leftp);
+unsigned char *nvpair_pack_nvlist_array_next(unsigned char *ptr, size_t *leftp);
/* Unpack data functions. */
const unsigned char *nvpair_unpack_header(bool isbe, nvpair_t *nvp,
@@ -89,5 +99,15 @@ const unsigned char *nvpair_unpack_descriptor(bool isbe, nvpair_t *nvp,
const unsigned char *ptr, size_t *leftp, const int *fds, size_t nfds);
const unsigned char *nvpair_unpack_binary(bool isbe, nvpair_t *nvp,
const unsigned char *ptr, size_t *leftp);
+const unsigned char *nvpair_unpack_bool_array(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp);
+const unsigned char *nvpair_unpack_number_array(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp);
+const unsigned char *nvpair_unpack_string_array(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp);
+const unsigned char *nvpair_unpack_descriptor_array(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp, const int *fds, size_t nfds);
+const unsigned char *nvpair_unpack_nvlist_array(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp, nvlist_t **firstel);
#endif /* !_NVPAIR_IMPL_H_ */
OpenPOWER on IntegriCloud