Page MenuHomeFreeBSD

D4249.id10445.diff
No OneTemporary

D4249.id10445.diff

This file is larger than 256 KB, so syntax highlighting was skipped.
Index: Makefile.inc1
===================================================================
--- Makefile.inc1
+++ Makefile.inc1
@@ -1652,7 +1652,7 @@
lib/libelf lib/libexpat \
lib/libfigpar \
${_lib_libgssapi} ${_lib_libipx} \
- lib/libkiconv lib/libkvm lib/liblzma lib/libmd \
+ lib/libkiconv lib/libkvm lib/liblzma lib/libmd lib/libnv \
lib/ncurses/ncurses lib/ncurses/ncursesw \
lib/libopie lib/libpam ${_lib_libthr} \
${_lib_libradius} lib/libsbuf lib/libtacplus \
Index: cddl/lib/libnvpair/Makefile
===================================================================
--- cddl/lib/libnvpair/Makefile
+++ cddl/lib/libnvpair/Makefile
@@ -7,10 +7,10 @@
SRCS= libnvpair.c \
nvpair_alloc_system.c \
- nvpair_alloc_fixed.c \
- nvpair.c \
nvpair_json.c \
- fnvpair.c
+ opensolaris_fnvpair.c \
+ opensolaris_nvpair.c \
+ opensolaris_nvpair_alloc_fixed.c
WARNS?= 0
CFLAGS+= -I${.CURDIR}/../../../cddl/compat/opensolaris/include
Index: contrib/mdocml/lib.in
===================================================================
--- contrib/mdocml/lib.in
+++ contrib/mdocml/lib.in
@@ -67,6 +67,7 @@
LINE("libmenu", "Curses Menu Library (libmenu, \\-lmenu)")
LINE("libnetgraph", "Netgraph User Library (libnetgraph, \\-lnetgraph)")
LINE("libnetpgp", "Netpgp signing, verification, encryption and decryption (libnetpgp, \\-lnetpgp)")
+LINE("libnv", "Name/value pairs library (libnv, \\-lnv)")
LINE("libossaudio", "OSS Audio Emulation Library (libossaudio, \\-lossaudio)")
LINE("libpam", "Pluggable Authentication Module Library (libpam, \\-lpam)")
LINE("libpcap", "Packet Capture Library (libpcap, \\-lpcap)")
Index: etc/mtree/BSD.tests.dist
===================================================================
--- etc/mtree/BSD.tests.dist
+++ etc/mtree/BSD.tests.dist
@@ -138,6 +138,8 @@
..
libmp
..
+ libnv
+ ..
librt
..
libthr
Index: lib/Makefile
===================================================================
--- lib/Makefile
+++ lib/Makefile
@@ -70,6 +70,7 @@
libnetbsd \
${_libnetgraph} \
${_libngatm} \
+ libnv \
libopie \
libpam \
libpcap \
Index: lib/libnv/Makefile
===================================================================
--- /dev/null
+++ lib/libnv/Makefile
@@ -0,0 +1,24 @@
+# $FreeBSD: head/lib/libnv/Makefile 285139 2015-07-04 16:33:37Z oshogbo $
+
+SHLIBDIR?= /lib
+
+.include <src.opts.mk>
+
+LIB= nv
+SHLIB_MAJOR= 0
+
+.PATH: ${.CURDIR}/../../sys/contrib/libnv ${.CURDIR}/../../sys/sys
+CFLAGS+=-I${.CURDIR}/../../sys -I${.CURDIR}
+
+SRCS= dnvlist.c
+SRCS+= msgio.c
+SRCS+= nvlist.c
+SRCS+= nvpair.c
+
+WARNS?= 6
+
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
+.include <bsd.lib.mk>
Index: lib/libnv/Makefile.depend
===================================================================
--- /dev/null
+++ lib/libnv/Makefile.depend
@@ -0,0 +1,19 @@
+# $FreeBSD: head/lib/libnv/Makefile.depend 284345 2015-06-13 19:20:56Z sjg $
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ usr.bin/xinstall.host \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
Index: lib/libnv/common_impl.h
===================================================================
--- /dev/null
+++ lib/libnv/common_impl.h
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: head/lib/libnv/common_impl.h 258065 2013-11-12 19:39:14Z pjd $
+ */
+
+#ifndef _COMMON_IMPL_H_
+#define _COMMON_IMPL_H_
+
+#define fd_is_valid(fd) (fcntl((fd), F_GETFL) != -1 || errno != EBADF)
+
+#endif /* !_COMMON_IMPL_H_ */
Index: lib/libnv/msgio.h
===================================================================
--- /dev/null
+++ lib/libnv/msgio.h
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Copyright (c) 2013 Mariusz Zaborski <oshogbo@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: head/lib/libnv/msgio.h 259430 2013-12-15 22:58:09Z pjd $
+ */
+
+#ifndef _MSGIO_H_
+#define _MSGIO_H_
+
+struct cmsgcred;
+struct iovec;
+struct msghdr;
+
+int cred_send(int sock);
+int cred_recv(int sock, struct cmsgcred *cred);
+
+int fd_send(int sock, const int *fds, size_t nfds);
+int fd_recv(int sock, int *fds, size_t nfds);
+
+int buf_send(int sock, void *buf, size_t size);
+int buf_recv(int sock, void *buf, size_t size);
+
+#endif /* !_MSGIO_H_ */
Index: lib/libnv/msgio.c
===================================================================
--- /dev/null
+++ lib/libnv/msgio.c
@@ -0,0 +1,469 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * Copyright (c) 2013 Mariusz Zaborski <oshogbo@FreeBSD.org>
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/lib/libnv/msgio.c 271578 2014-09-14 09:27:12Z pjd $");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef HAVE_PJDLOG
+#include <pjdlog.h>
+#endif
+
+#include "common_impl.h"
+#include "msgio.h"
+
+#ifndef HAVE_PJDLOG
+#include <assert.h>
+#define PJDLOG_ASSERT(...) assert(__VA_ARGS__)
+#define PJDLOG_RASSERT(expr, ...) assert(expr)
+#define PJDLOG_ABORT(...) abort()
+#endif
+
+#define PKG_MAX_SIZE (MCLBYTES / CMSG_SPACE(sizeof(int)) - 1)
+
+static int
+msghdr_add_fd(struct cmsghdr *cmsg, int fd)
+{
+
+ PJDLOG_ASSERT(fd >= 0);
+
+ if (!fd_is_valid(fd)) {
+ errno = EBADF;
+ return (-1);
+ }
+
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
+ bcopy(&fd, CMSG_DATA(cmsg), sizeof(fd));
+
+ return (0);
+}
+
+static int
+msghdr_get_fd(struct cmsghdr *cmsg)
+{
+ int fd;
+
+ if (cmsg == NULL || cmsg->cmsg_level != SOL_SOCKET ||
+ cmsg->cmsg_type != SCM_RIGHTS ||
+ cmsg->cmsg_len != CMSG_LEN(sizeof(fd))) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ bcopy(CMSG_DATA(cmsg), &fd, sizeof(fd));
+#ifndef MSG_CMSG_CLOEXEC
+ /*
+ * If the MSG_CMSG_CLOEXEC flag is not available we cannot set the
+ * close-on-exec flag atomically, but we still want to set it for
+ * consistency.
+ */
+ (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
+#endif
+
+ return (fd);
+}
+
+static void
+fd_wait(int fd, bool doread)
+{
+ fd_set fds;
+
+ PJDLOG_ASSERT(fd >= 0);
+
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ (void)select(fd + 1, doread ? &fds : NULL, doread ? NULL : &fds,
+ NULL, NULL);
+}
+
+static int
+msg_recv(int sock, struct msghdr *msg)
+{
+ int flags;
+
+ PJDLOG_ASSERT(sock >= 0);
+
+#ifdef MSG_CMSG_CLOEXEC
+ flags = MSG_CMSG_CLOEXEC;
+#else
+ flags = 0;
+#endif
+
+ for (;;) {
+ fd_wait(sock, true);
+ if (recvmsg(sock, msg, flags) == -1) {
+ if (errno == EINTR)
+ continue;
+ return (-1);
+ }
+ break;
+ }
+
+ return (0);
+}
+
+static int
+msg_send(int sock, const struct msghdr *msg)
+{
+
+ PJDLOG_ASSERT(sock >= 0);
+
+ for (;;) {
+ fd_wait(sock, false);
+ if (sendmsg(sock, msg, 0) == -1) {
+ if (errno == EINTR)
+ continue;
+ return (-1);
+ }
+ break;
+ }
+
+ return (0);
+}
+
+int
+cred_send(int sock)
+{
+ unsigned char credbuf[CMSG_SPACE(sizeof(struct cmsgcred))];
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ struct iovec iov;
+ uint8_t dummy;
+
+ bzero(credbuf, sizeof(credbuf));
+ bzero(&msg, sizeof(msg));
+ bzero(&iov, sizeof(iov));
+
+ /*
+ * XXX: We send one byte along with the control message, because
+ * setting msg_iov to NULL only works if this is the first
+ * packet send over the socket. Once we send some data we
+ * won't be able to send credentials anymore. This is most
+ * likely a kernel bug.
+ */
+ dummy = 0;
+ iov.iov_base = &dummy;
+ iov.iov_len = sizeof(dummy);
+
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = credbuf;
+ msg.msg_controllen = sizeof(credbuf);
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_CREDS;
+
+ if (msg_send(sock, &msg) == -1)
+ return (-1);
+
+ return (0);
+}
+
+int
+cred_recv(int sock, struct cmsgcred *cred)
+{
+ unsigned char credbuf[CMSG_SPACE(sizeof(struct cmsgcred))];
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ struct iovec iov;
+ uint8_t dummy;
+
+ bzero(credbuf, sizeof(credbuf));
+ bzero(&msg, sizeof(msg));
+ bzero(&iov, sizeof(iov));
+
+ iov.iov_base = &dummy;
+ iov.iov_len = sizeof(dummy);
+
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = credbuf;
+ msg.msg_controllen = sizeof(credbuf);
+
+ if (msg_recv(sock, &msg) == -1)
+ return (-1);
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ if (cmsg == NULL ||
+ cmsg->cmsg_len != CMSG_LEN(sizeof(struct cmsgcred)) ||
+ cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_CREDS) {
+ errno = EINVAL;
+ return (-1);
+ }
+ bcopy(CMSG_DATA(cmsg), cred, sizeof(*cred));
+
+ return (0);
+}
+
+static int
+fd_package_send(int sock, const int *fds, size_t nfds)
+{
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ struct iovec iov;
+ unsigned int i;
+ int serrno, ret;
+ uint8_t dummy;
+
+ PJDLOG_ASSERT(sock >= 0);
+ PJDLOG_ASSERT(fds != NULL);
+ PJDLOG_ASSERT(nfds > 0);
+
+ bzero(&msg, sizeof(msg));
+
+ /*
+ * XXX: Look into cred_send function for more details.
+ */
+ dummy = 0;
+ iov.iov_base = &dummy;
+ iov.iov_len = sizeof(dummy);
+
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_controllen = nfds * CMSG_SPACE(sizeof(int));
+ msg.msg_control = calloc(1, msg.msg_controllen);
+ if (msg.msg_control == NULL)
+ return (-1);
+
+ ret = -1;
+
+ for (i = 0, cmsg = CMSG_FIRSTHDR(&msg); i < nfds && cmsg != NULL;
+ i++, cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (msghdr_add_fd(cmsg, fds[i]) == -1)
+ goto end;
+ }
+
+ if (msg_send(sock, &msg) == -1)
+ goto end;
+
+ ret = 0;
+end:
+ serrno = errno;
+ free(msg.msg_control);
+ errno = serrno;
+ return (ret);
+}
+
+static int
+fd_package_recv(int sock, int *fds, size_t nfds)
+{
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ unsigned int i;
+ int serrno, ret;
+ struct iovec iov;
+ uint8_t dummy;
+
+ PJDLOG_ASSERT(sock >= 0);
+ PJDLOG_ASSERT(nfds > 0);
+ PJDLOG_ASSERT(fds != NULL);
+
+ i = 0;
+ bzero(&msg, sizeof(msg));
+ bzero(&iov, sizeof(iov));
+
+ /*
+ * XXX: Look into cred_send function for more details.
+ */
+ iov.iov_base = &dummy;
+ iov.iov_len = sizeof(dummy);
+
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_controllen = nfds * CMSG_SPACE(sizeof(int));
+ msg.msg_control = calloc(1, msg.msg_controllen);
+ if (msg.msg_control == NULL)
+ return (-1);
+
+ ret = -1;
+
+ if (msg_recv(sock, &msg) == -1)
+ goto end;
+
+ for (i = 0, cmsg = CMSG_FIRSTHDR(&msg); i < nfds && cmsg != NULL;
+ i++, cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ fds[i] = msghdr_get_fd(cmsg);
+ if (fds[i] < 0)
+ break;
+ }
+
+ if (cmsg != NULL || i < nfds) {
+ int fd;
+
+ /*
+ * We need to close all received descriptors, even if we have
+ * different control message (eg. SCM_CREDS) in between.
+ */
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ fd = msghdr_get_fd(cmsg);
+ if (fd >= 0)
+ close(fd);
+ }
+ errno = EINVAL;
+ goto end;
+ }
+
+ ret = 0;
+end:
+ serrno = errno;
+ free(msg.msg_control);
+ errno = serrno;
+ return (ret);
+}
+
+int
+fd_recv(int sock, int *fds, size_t nfds)
+{
+ unsigned int i, step, j;
+ int ret, serrno;
+
+ if (nfds == 0 || fds == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ ret = i = step = 0;
+ while (i < nfds) {
+ if (PKG_MAX_SIZE < nfds - i)
+ step = PKG_MAX_SIZE;
+ else
+ step = nfds - i;
+ ret = fd_package_recv(sock, fds + i, step);
+ if (ret != 0) {
+ /* Close all received descriptors. */
+ serrno = errno;
+ for (j = 0; j < i; j++)
+ close(fds[j]);
+ errno = serrno;
+ break;
+ }
+ i += step;
+ }
+
+ return (ret);
+}
+
+int
+fd_send(int sock, const int *fds, size_t nfds)
+{
+ unsigned int i, step;
+ int ret;
+
+ if (nfds == 0 || fds == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ ret = i = step = 0;
+ while (i < nfds) {
+ if (PKG_MAX_SIZE < nfds - i)
+ step = PKG_MAX_SIZE;
+ else
+ step = nfds - i;
+ ret = fd_package_send(sock, fds + i, step);
+ if (ret != 0)
+ break;
+ i += step;
+ }
+
+ return (ret);
+}
+
+int
+buf_send(int sock, void *buf, size_t size)
+{
+ ssize_t done;
+ unsigned char *ptr;
+
+ PJDLOG_ASSERT(sock >= 0);
+ PJDLOG_ASSERT(size > 0);
+ PJDLOG_ASSERT(buf != NULL);
+
+ ptr = buf;
+ do {
+ fd_wait(sock, false);
+ done = send(sock, ptr, size, 0);
+ if (done == -1) {
+ if (errno == EINTR)
+ continue;
+ return (-1);
+ } else if (done == 0) {
+ errno = ENOTCONN;
+ return (-1);
+ }
+ size -= done;
+ ptr += done;
+ } while (size > 0);
+
+ return (0);
+}
+
+int
+buf_recv(int sock, void *buf, size_t size)
+{
+ ssize_t done;
+ unsigned char *ptr;
+
+ PJDLOG_ASSERT(sock >= 0);
+ PJDLOG_ASSERT(buf != NULL);
+
+ ptr = buf;
+ while (size > 0) {
+ fd_wait(sock, true);
+ done = recv(sock, ptr, size, 0);
+ if (done == -1) {
+ if (errno == EINTR)
+ continue;
+ return (-1);
+ } else if (done == 0) {
+ errno = ENOTCONN;
+ return (-1);
+ }
+ size -= done;
+ ptr += done;
+ }
+
+ return (0);
+}
Index: lib/libnv/tests/Makefile
===================================================================
--- /dev/null
+++ lib/libnv/tests/Makefile
@@ -0,0 +1,19 @@
+# $FreeBSD: head/lib/libnv/tests/Makefile 289172 2015-10-12 08:16:03Z ngie $
+
+ATF_TESTS_CXX= \
+ dnv_tests \
+ nv_array_tests \
+ nv_tests \
+
+TAP_TESTS_C+= nvlist_add_test
+TAP_TESTS_C+= nvlist_exists_test
+TAP_TESTS_C+= nvlist_free_test
+TAP_TESTS_C+= nvlist_get_test
+TAP_TESTS_C+= nvlist_move_test
+TAP_TESTS_C+= nvlist_send_recv_test
+
+LIBADD+= nv
+
+WARNS?= 3
+
+.include <bsd.test.mk>
Index: lib/libnv/tests/dnv_tests.cc
===================================================================
--- /dev/null
+++ lib/libnv/tests/dnv_tests.cc
@@ -0,0 +1,568 @@
+/*-
+ * Copyright (c) 2014-2015 Sandvine Inc. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/lib/libnv/tests/dnv_tests.cc 285063 2015-07-02 21:58:10Z oshogbo $");
+
+#include <sys/dnv.h>
+#include <sys/nv.h>
+
+#include <atf-c++.hpp>
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_get_bool__present);
+ATF_TEST_CASE_BODY(dnvlist_get_bool__present)
+{
+ nvlist_t *nvl;
+ const char *key;
+ bool value;
+
+ nvl = nvlist_create(0);
+
+ key = "name";
+ value = true;
+ nvlist_add_bool(nvl, key, value);
+
+ ATF_REQUIRE_EQ(dnvlist_get_bool(nvl, key, false), value);
+ ATF_REQUIRE_EQ(dnvlist_get_bool(nvl, "name", false), value);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_get_bool__default_value);
+ATF_TEST_CASE_BODY(dnvlist_get_bool__default_value)
+{
+ nvlist_t *nvl;
+ const char *key;
+
+ key = "123";
+ nvl = nvlist_create(0);
+
+ ATF_REQUIRE_EQ(dnvlist_get_bool(nvl, key, false), false);
+ ATF_REQUIRE_EQ(dnvlist_get_bool(nvl, "123", true), true);
+
+ nvlist_add_bool(nvl, key, true);
+
+ ATF_REQUIRE_EQ(dnvlist_get_bool(nvl, "otherkey", true), true);
+ ATF_REQUIRE_EQ(dnvlist_get_bool(nvl, "12c", false), false);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_get_number__present);
+ATF_TEST_CASE_BODY(dnvlist_get_number__present)
+{
+ nvlist_t *nvl;
+ const char *key;
+ uint64_t value;
+
+ nvl = nvlist_create(0);
+
+ key = "key";
+ value = 48952;
+ nvlist_add_number(nvl, key, value);
+
+ ATF_REQUIRE_EQ(dnvlist_get_number(nvl, key, 19), value);
+ ATF_REQUIRE_EQ(dnvlist_get_number(nvl, "key", 65), value);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_get_number__default_value);
+ATF_TEST_CASE_BODY(dnvlist_get_number__default_value)
+{
+ nvlist_t *nvl;
+ const char *key;
+
+ key = "123";
+ nvl = nvlist_create(0);
+
+ ATF_REQUIRE_EQ(dnvlist_get_number(nvl, key, 5), 5);
+ ATF_REQUIRE_EQ(dnvlist_get_number(nvl, "1234", 5), 5);
+
+ nvlist_add_number(nvl, key, 24841);
+
+ ATF_REQUIRE_EQ(dnvlist_get_number(nvl, "1234", 5641), 5641);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_get_string__present);
+ATF_TEST_CASE_BODY(dnvlist_get_string__present)
+{
+ nvlist_t *nvl;
+ const char *key;
+ const char *value, *actual_value;
+
+ nvl = nvlist_create(0);
+
+ key = "string";
+ value = "fjdojfdi";
+ nvlist_add_string(nvl, key, value);
+
+ ATF_REQUIRE_EQ(strcmp(dnvlist_get_string(nvl, key, "g"), value), 0);
+
+ actual_value = dnvlist_get_string(nvl, key, "rs");
+ ATF_REQUIRE_EQ(strcmp(actual_value, value), 0);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_get_string__default_value);
+ATF_TEST_CASE_BODY(dnvlist_get_string__default_value)
+{
+ nvlist_t *nvl;
+ const char *key;
+ const char *actual_value;
+
+ key = "123";
+ nvl = nvlist_create(0);
+
+ ATF_REQUIRE_EQ(strcmp(dnvlist_get_string(nvl, key, "bar"), "bar"), 0);
+
+ actual_value = dnvlist_get_string(nvl, key, "d");
+ ATF_REQUIRE_EQ(strcmp(actual_value, "d"), 0);
+
+ nvlist_add_string(nvl, key, "cxhweh");
+
+ ATF_REQUIRE_EQ(strcmp(dnvlist_get_string(nvl, "hthth", "fd"), "fd"), 0);
+ actual_value = dnvlist_get_string(nvl, "5", "5");
+ ATF_REQUIRE_EQ(strcmp("5", "5"), 0);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_get_nvlist__present);
+ATF_TEST_CASE_BODY(dnvlist_get_nvlist__present)
+{
+ nvlist_t *nvl;
+ const char *key;
+ nvlist_t *value;
+ const nvlist_t *actual_value;
+
+ nvl = nvlist_create(0);
+
+ key = "nvlist";
+ value = nvlist_create(0);
+ nvlist_move_nvlist(nvl, key, value);
+
+ actual_value = dnvlist_get_nvlist(nvl, key, NULL);
+ ATF_REQUIRE(actual_value != NULL);
+ ATF_REQUIRE(nvlist_empty(actual_value));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_get_nvlist__default_value);
+ATF_TEST_CASE_BODY(dnvlist_get_nvlist__default_value)
+{
+ nvlist_t *nvl;
+ const char *key;
+ nvlist_t *dummy;
+
+ key = "123";
+ nvl = nvlist_create(0);
+ dummy = nvlist_create(0);
+
+ ATF_REQUIRE_EQ(dnvlist_get_nvlist(nvl, key, dummy), dummy);
+
+ nvlist_move_nvlist(nvl, key, nvlist_create(0));
+ ATF_REQUIRE_EQ(dnvlist_get_nvlist(nvl, "456", dummy), dummy);
+ ATF_REQUIRE_EQ(dnvlist_get_nvlist(nvl, "gh", dummy), dummy);
+
+ nvlist_destroy(nvl);
+}
+
+static void
+set_const_binary_value(const void *&value, size_t &size, const char *str)
+{
+
+ value = str;
+ size = strlen(str) + 1; /* +1 to include '\0' */
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_get_binary__present);
+ATF_TEST_CASE_BODY(dnvlist_get_binary__present)
+{
+ nvlist_t *nvl;
+ const char *k;
+ const void *value, *actual_value;
+ size_t value_size, actual_size;
+
+ nvl = nvlist_create(0);
+
+ k = "binary";
+ set_const_binary_value(value, value_size, "fjdojfdi");
+ nvlist_add_binary(nvl, k, value, value_size);
+
+ actual_value = dnvlist_get_binary(nvl, k, &actual_size, "g", 1);
+ ATF_REQUIRE_EQ(value_size, actual_size);
+ ATF_REQUIRE_EQ(memcmp(actual_value, value, actual_size), 0);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_get_binary__default_value);
+ATF_TEST_CASE_BODY(dnvlist_get_binary__default_value)
+{
+ nvlist_t *nvl;
+ const char *key;
+ const void *default_value, *actual_value;
+ size_t default_size, actual_size;
+
+ key = "123";
+ nvl = nvlist_create(0);
+
+ set_const_binary_value(default_value, default_size, "bar");
+ actual_value = dnvlist_get_binary(nvl, key, &actual_size, default_value,
+ default_size);
+ ATF_REQUIRE_EQ(default_size, actual_size);
+ ATF_REQUIRE_EQ(memcmp(actual_value, default_value, actual_size), 0);
+
+ set_const_binary_value(default_value, default_size, "atf");
+ actual_value = dnvlist_get_binary(nvl, key, &actual_size, default_value,
+ default_size);
+ ATF_REQUIRE_EQ(default_size, actual_size);
+ ATF_REQUIRE_EQ(memcmp(actual_value, default_value, actual_size), 0);
+
+ nvlist_add_binary(nvl, key, "test", 4);
+
+ set_const_binary_value(default_value, default_size, "bthrg");
+ actual_value = dnvlist_get_binary(nvl, "k", &actual_size, default_value,
+ default_size);
+ ATF_REQUIRE_EQ(default_size, actual_size);
+ ATF_REQUIRE_EQ(memcmp(actual_value, default_value, actual_size), 0);
+
+ set_const_binary_value(default_value, default_size,
+ "rrhgrythtyrtgbrhgrtdsvdfbtjlkul");
+ actual_value = dnvlist_get_binary(nvl, "s", &actual_size, default_value,
+ default_size);
+ ATF_REQUIRE_EQ(default_size, actual_size);
+ ATF_REQUIRE_EQ(memcmp(actual_value, default_value, actual_size), 0);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_bool__present);
+ATF_TEST_CASE_BODY(dnvlist_take_bool__present)
+{
+ nvlist_t *nvl;
+ const char *key;
+ bool value;
+
+ nvl = nvlist_create(0);
+
+ key = "name";
+ value = true;
+ nvlist_add_bool(nvl, key, value);
+
+ ATF_REQUIRE_EQ(dnvlist_take_bool(nvl, key, false), value);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_bool__empty);
+ATF_TEST_CASE_BODY(dnvlist_take_bool__empty)
+{
+ nvlist_t *nvl;
+
+ nvl = nvlist_create(0);
+
+ ATF_REQUIRE_EQ(dnvlist_take_bool(nvl, "123", false), false);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_bool__default_value);
+ATF_TEST_CASE_BODY(dnvlist_take_bool__default_value)
+{
+ nvlist_t *nvl;
+
+ nvl = nvlist_create(0);
+ nvlist_add_bool(nvl, "key", true);
+
+ ATF_REQUIRE_EQ(dnvlist_take_bool(nvl, "otherkey", true), true);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_number__present);
+ATF_TEST_CASE_BODY(dnvlist_take_number__present)
+{
+ nvlist_t *nvl;
+ const char *key;
+ uint64_t value;
+
+ nvl = nvlist_create(0);
+
+ key = "name";
+ value = 194154;
+ nvlist_add_number(nvl, key, value);
+
+ ATF_REQUIRE_EQ(dnvlist_take_number(nvl, key, 2), value);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_number__empty);
+ATF_TEST_CASE_BODY(dnvlist_take_number__empty)
+{
+ nvlist_t *nvl;
+
+ nvl = nvlist_create(0);
+
+ ATF_REQUIRE_EQ(dnvlist_take_number(nvl, "123", 126484), 126484);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_number__default_value);
+ATF_TEST_CASE_BODY(dnvlist_take_number__default_value)
+{
+ nvlist_t *nvl;
+
+ nvl = nvlist_create(0);
+ nvlist_add_number(nvl, "key", 12);
+
+ ATF_REQUIRE_EQ(dnvlist_take_number(nvl, "otherkey", 13), 13);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_string__present);
+ATF_TEST_CASE_BODY(dnvlist_take_string__present)
+{
+ nvlist_t *nvl;
+ const char *key;
+ const char *value;
+ char *default_val, *actual_val;
+
+ nvl = nvlist_create(0);
+
+ key = "name";
+ value = "wrowm";
+ default_val = strdup("default");
+ nvlist_add_string(nvl, key, value);
+
+ actual_val = dnvlist_take_string(nvl, key, default_val);
+ ATF_REQUIRE_EQ(strcmp(actual_val, value), 0);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ free(actual_val);
+ free(default_val);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_string__empty);
+ATF_TEST_CASE_BODY(dnvlist_take_string__empty)
+{
+ nvlist_t *nvl;
+ char *default_val, *actual_val;
+
+ nvl = nvlist_create(0);
+ default_val = strdup("");
+
+ actual_val = dnvlist_take_string(nvl, "123", default_val);
+ ATF_REQUIRE_EQ(strcmp(actual_val, default_val), 0);
+
+ free(actual_val);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_string__default_value);
+ATF_TEST_CASE_BODY(dnvlist_take_string__default_value)
+{
+ nvlist_t *nvl;
+ char *default_val, *actual_val;
+
+ nvl = nvlist_create(0);
+ nvlist_add_string(nvl, "key", "foobar");
+ default_val = strdup("other");
+
+ actual_val = dnvlist_take_string(nvl, "otherkey", default_val);
+ ATF_REQUIRE_EQ(strcmp(actual_val, default_val), 0);
+
+ free(actual_val);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_nvlist__present);
+ATF_TEST_CASE_BODY(dnvlist_take_nvlist__present)
+{
+ nvlist_t *nvl;
+ const char *key;
+ nvlist_t *value, *default_val, *actual_val;
+
+ nvl = nvlist_create(0);
+
+ key = "name";
+ value = nvlist_create(0);
+ default_val = nvlist_create(0);
+ nvlist_move_nvlist(nvl, key, value);
+
+ actual_val = dnvlist_take_nvlist(nvl, key, default_val);
+ ATF_REQUIRE_EQ(actual_val, value);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ free(actual_val);
+ free(default_val);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_nvlist__empty);
+ATF_TEST_CASE_BODY(dnvlist_take_nvlist__empty)
+{
+ nvlist_t *nvl, *actual_val;
+
+ nvl = nvlist_create(0);
+
+ actual_val = dnvlist_take_nvlist(nvl, "123", NULL);
+ ATF_REQUIRE_EQ(actual_val, static_cast<nvlist_t *>(NULL));
+
+ free(actual_val);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_nvlist__default_value);
+ATF_TEST_CASE_BODY(dnvlist_take_nvlist__default_value)
+{
+ nvlist_t *nvl;
+ nvlist_t *default_val, *actual_val;
+
+ nvl = nvlist_create(0);
+ nvlist_move_nvlist(nvl, "key", nvlist_create(0));
+ default_val = nvlist_create(0);
+
+ actual_val = dnvlist_take_nvlist(nvl, "otherkey", default_val);
+ ATF_REQUIRE_EQ(actual_val, default_val);
+
+ free(actual_val);
+ nvlist_destroy(nvl);
+}
+
+static void
+set_binary_value(void *&value, size_t &size, const char *str)
+{
+
+ value = strdup(str);
+ size = strlen(str) + 1; /* +1 to include '\0' */
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_binary__present);
+ATF_TEST_CASE_BODY(dnvlist_take_binary__present)
+{
+ nvlist_t *nvl;
+ const char *key;
+ void *value, *default_val, *actual_val;
+ size_t value_size, default_size, actual_size;
+
+ nvl = nvlist_create(0);
+
+ key = "name";
+ set_binary_value(value, value_size, "fkdojvmo908");
+ set_binary_value(default_val, default_size, "16546");
+ nvlist_add_binary(nvl, key, value, value_size);
+
+ actual_val = dnvlist_take_binary(nvl, key, &actual_size, default_val,
+ default_size);
+ ATF_REQUIRE_EQ(value_size, actual_size);
+ ATF_REQUIRE_EQ(memcmp(actual_val, value, value_size), 0);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ free(actual_val);
+ free(default_val);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_binary__empty);
+ATF_TEST_CASE_BODY(dnvlist_take_binary__empty)
+{
+ nvlist_t *nvl;
+ void *default_val, *actual_val;
+ size_t default_size, actual_size;
+
+ nvl = nvlist_create(0);
+ set_binary_value(default_val, default_size, "\xa8\x89\x49\xff\xe2\x08");
+
+ actual_val = dnvlist_take_binary(nvl, "123", &actual_size, default_val,
+ default_size);
+ ATF_REQUIRE_EQ(default_size, actual_size);
+ ATF_REQUIRE_EQ(memcmp(actual_val, default_val, actual_size), 0);
+
+ free(actual_val);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(dnvlist_take_binary__default_value);
+ATF_TEST_CASE_BODY(dnvlist_take_binary__default_value)
+{
+ nvlist_t *nvl;
+ void *default_val, *actual_val;
+ size_t default_size, actual_size;
+
+ nvl = nvlist_create(0);
+ nvlist_add_binary(nvl, "key", "foobar", 6);
+ set_binary_value(default_val, default_size, "vbhag");
+
+ actual_val = dnvlist_take_binary(nvl, "otherkey", &actual_size,
+ default_val, default_size);
+ ATF_REQUIRE_EQ(default_size, actual_size);
+ ATF_REQUIRE_EQ(memcmp(actual_val, default_val, default_size), 0);
+
+ free(actual_val);
+ nvlist_destroy(nvl);
+}
+
+ATF_INIT_TEST_CASES(tp)
+{
+ ATF_ADD_TEST_CASE(tp, dnvlist_get_bool__present);
+ ATF_ADD_TEST_CASE(tp, dnvlist_get_bool__default_value);
+ ATF_ADD_TEST_CASE(tp, dnvlist_get_number__present);
+ ATF_ADD_TEST_CASE(tp, dnvlist_get_number__default_value);
+ ATF_ADD_TEST_CASE(tp, dnvlist_get_string__present);
+ ATF_ADD_TEST_CASE(tp, dnvlist_get_string__default_value);
+ ATF_ADD_TEST_CASE(tp, dnvlist_get_nvlist__present);
+ ATF_ADD_TEST_CASE(tp, dnvlist_get_nvlist__default_value);
+ ATF_ADD_TEST_CASE(tp, dnvlist_get_binary__present);
+ ATF_ADD_TEST_CASE(tp, dnvlist_get_binary__default_value);
+
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_bool__present);
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_bool__empty);
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_bool__default_value);
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_number__present);
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_number__empty);
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_number__default_value);
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_string__present);
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_string__empty);
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_string__default_value);
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_nvlist__present);
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_nvlist__empty);
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_nvlist__default_value);
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_binary__present);
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_binary__empty);
+ ATF_ADD_TEST_CASE(tp, dnvlist_take_binary__default_value);
+}
Index: lib/libnv/tests/nv_array_tests.cc
===================================================================
--- /dev/null
+++ lib/libnv/tests/nv_array_tests.cc
@@ -0,0 +1,1191 @@
+/*-
+ * Copyright (c) 2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/lib/libnv/tests/nv_array_tests.cc 286796 2015-08-15 06:34:49Z oshogbo $");
+
+#include <sys/nv.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <atf-c++.hpp>
+
+#include <cstdio>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits>
+#include <set>
+#include <sstream>
+#include <string>
+
+#define fd_is_valid(fd) (fcntl((fd), F_GETFL) != -1 || errno != EBADF)
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_bool_array__basic);
+ATF_TEST_CASE_BODY(nvlist_bool_array__basic)
+{
+ bool testbool[16];
+ const bool *const_result;
+ bool *result;
+ nvlist_t *nvl;
+ size_t nitems;
+ unsigned int i;
+ const char *key;
+
+ key = "nvl/bool";
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+
+ for (i = 0; i < 16; i++)
+ testbool[i] = (i % 2 == 0);
+
+ nvlist_add_bool_array(nvl, key, testbool, 16);
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_bool_array(nvl, key));
+ ATF_REQUIRE(nvlist_exists_bool_array(nvl, "nvl/bool"));
+
+ const_result = nvlist_get_bool_array(nvl, key, &nitems);
+ ATF_REQUIRE_EQ(nitems, 16);
+ ATF_REQUIRE(const_result != NULL);
+ for (i = 0; i < nitems; i++)
+ ATF_REQUIRE_EQ(const_result[i], testbool[i]);
+
+ result = nvlist_take_bool_array(nvl, key, &nitems);
+ ATF_REQUIRE_EQ(nitems, 16);
+ ATF_REQUIRE(const_result != NULL);
+ for (i = 0; i < nitems; i++)
+ ATF_REQUIRE_EQ(result[i], testbool[i]);
+
+ ATF_REQUIRE(!nvlist_exists_bool_array(nvl, key));
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+
+ free(result);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_string_array__basic);
+ATF_TEST_CASE_BODY(nvlist_string_array__basic)
+{
+ const char * const *const_result;
+ char **result;
+ nvlist_t *nvl;
+ size_t nitems;
+ unsigned int i;
+ const char *key;
+ const char *string[8] = { "a", "b", "kot", "foo",
+ "tests", "nice test", "", "abcdef" };
+
+ key = "nvl/string";
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+
+ nvlist_add_string_array(nvl, key, string, 8);
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_string_array(nvl, key));
+ ATF_REQUIRE(nvlist_exists_string_array(nvl, "nvl/string"));
+
+ const_result = nvlist_get_string_array(nvl, key, &nitems);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(const_result != NULL);
+ ATF_REQUIRE(nitems == 8);
+ for (i = 0; i < nitems; i++) {
+ if (string[i] != NULL) {
+ ATF_REQUIRE(strcmp(const_result[i], string[i]) == 0);
+ } else {
+ ATF_REQUIRE(const_result[i] == string[i]);
+ }
+ }
+
+ result = nvlist_take_string_array(nvl, key, &nitems);
+ ATF_REQUIRE(result != NULL);
+ ATF_REQUIRE_EQ(nitems, 8);
+ for (i = 0; i < nitems; i++) {
+ if (string[i] != NULL) {
+ ATF_REQUIRE_EQ(strcmp(result[i], string[i]), 0);
+ } else {
+ ATF_REQUIRE_EQ(result[i], string[i]);
+ }
+ }
+
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+
+ for (i = 0; i < 8; i++)
+ free(result[i]);
+ free(result);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_descriptor_array__basic);
+ATF_TEST_CASE_BODY(nvlist_descriptor_array__basic)
+{
+ int fd[32], *result;
+ const int *const_result;
+ nvlist_t *nvl;
+ size_t nitems;
+ unsigned int i;
+ const char *key;
+
+ for (i = 0; i < 32; i++) {
+ fd[i] = dup(STDERR_FILENO);
+ ATF_REQUIRE(fd_is_valid(fd[i]));
+ }
+
+ key = "nvl/descriptor";
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_descriptor_array(nvl, key));
+
+ nvlist_add_descriptor_array(nvl, key, fd, 32);
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_descriptor_array(nvl, key));
+ ATF_REQUIRE(nvlist_exists_descriptor_array(nvl, "nvl/descriptor"));
+
+ const_result = nvlist_get_descriptor_array(nvl, key, &nitems);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(const_result != NULL);
+ ATF_REQUIRE(nitems == 32);
+ for (i = 0; i < nitems; i++) {
+ ATF_REQUIRE(fd_is_valid(const_result[i]));
+ if (i > 0)
+ ATF_REQUIRE(const_result[i] != const_result[i - 1]);
+ }
+
+ result = nvlist_take_descriptor_array(nvl, key, &nitems);
+ ATF_REQUIRE(result != NULL);
+ ATF_REQUIRE_EQ(nitems, 32);
+ for (i = 0; i < nitems; i++) {
+ ATF_REQUIRE(fd_is_valid(result[i]));
+ if (i > 0)
+ ATF_REQUIRE(const_result[i] != const_result[i - 1]);
+ }
+
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+
+ for (i = 0; i < nitems; i++) {
+ close(result[i]);
+ close(fd[i]);
+ }
+ free(result);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_number_array__basic);
+ATF_TEST_CASE_BODY(nvlist_number_array__basic)
+{
+ const uint64_t *const_result;
+ uint64_t *result;
+ nvlist_t *nvl;
+ size_t nitems;
+ unsigned int i;
+ const char *key;
+ const uint64_t number[8] = { 0, UINT_MAX, 7, 123, 90,
+ 100000, 8, 1 };
+
+ key = "nvl/number";
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+
+ nvlist_add_number_array(nvl, key, number, 8);
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_number_array(nvl, key));
+ ATF_REQUIRE(nvlist_exists_number_array(nvl, "nvl/number"));
+
+ const_result = nvlist_get_number_array(nvl, key, &nitems);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(const_result != NULL);
+ ATF_REQUIRE(nitems == 8);
+ for (i = 0; i < nitems; i++)
+ ATF_REQUIRE_EQ(const_result[i], number[i]);
+
+ result = nvlist_take_number_array(nvl, key, &nitems);
+ ATF_REQUIRE(result != NULL);
+ ATF_REQUIRE_EQ(nitems, 8);
+ for (i = 0; i < nitems; i++)
+ ATF_REQUIRE_EQ(result[i], number[i]);
+
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+
+ free(result);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_nvlist_array__basic);
+ATF_TEST_CASE_BODY(nvlist_nvlist_array__basic)
+{
+ nvlist_t *testnvl[8];
+ const nvlist_t * const *const_result;
+ nvlist_t **result;
+ nvlist_t *nvl;
+ size_t nitems;
+ unsigned int i;
+ const char *somestr[8] = { "a", "b", "c", "d", "e", "f", "g", "h" };
+ const char *key;
+
+ for (i = 0; i < 8; i++) {
+ testnvl[i] = nvlist_create(0);
+ ATF_REQUIRE(testnvl[i] != NULL);
+ ATF_REQUIRE_EQ(nvlist_error(testnvl[i]), 0);
+ nvlist_add_string(testnvl[i], "nvl/string", somestr[i]);
+ ATF_REQUIRE_EQ(nvlist_error(testnvl[i]), 0);
+ ATF_REQUIRE(nvlist_exists_string(testnvl[i], "nvl/string"));
+ }
+
+ key = "nvl/nvlist";
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+
+ nvlist_add_nvlist_array(nvl, key, (const nvlist_t * const *)testnvl, 8);
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_nvlist_array(nvl, key));
+ ATF_REQUIRE(nvlist_exists_nvlist_array(nvl, "nvl/nvlist"));
+
+ const_result = nvlist_get_nvlist_array(nvl, key, &nitems);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(const_result != NULL);
+ ATF_REQUIRE(nitems == 8);
+
+ for (i = 0; i < nitems; i++) {
+ ATF_REQUIRE_EQ(nvlist_error(const_result[i]), 0);
+ if (i < nitems - 1) {
+ ATF_REQUIRE(nvlist_get_array_next(const_result[i]) ==
+ const_result[i + 1]);
+ } else {
+ ATF_REQUIRE(nvlist_get_array_next(const_result[i]) ==
+ NULL);
+ }
+ ATF_REQUIRE(nvlist_get_parent(const_result[i], NULL) == nvl);
+ ATF_REQUIRE(nvlist_in_array(const_result[i]));
+ ATF_REQUIRE(nvlist_exists_string(const_result[i],
+ "nvl/string"));
+ ATF_REQUIRE(strcmp(nvlist_get_string(const_result[i],
+ "nvl/string"), somestr[i]) == 0);
+ }
+
+ result = nvlist_take_nvlist_array(nvl, key, &nitems);
+ ATF_REQUIRE(result != NULL);
+ ATF_REQUIRE_EQ(nitems, 8);
+ for (i = 0; i < nitems; i++) {
+ ATF_REQUIRE_EQ(nvlist_error(result[i]), 0);
+ ATF_REQUIRE(nvlist_get_array_next(result[i]) == NULL);
+ ATF_REQUIRE(nvlist_get_array_next(const_result[i]) == NULL);
+ ATF_REQUIRE(!nvlist_in_array(const_result[i]));
+ }
+
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+
+ for (i = 0; i < 8; i++) {
+ nvlist_destroy(result[i]);
+ nvlist_destroy(testnvl[i]);
+ }
+
+ free(result);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_clone_array);
+ATF_TEST_CASE_BODY(nvlist_clone_array)
+{
+ nvlist_t *testnvl[8];
+ nvlist_t *src, *dst;
+ const nvlist_t *nvl;
+ bool testbool[16];
+ int testfd[16];
+ size_t i, nitems;
+ const char *string[8] = { "a", "b", "kot", "foo",
+ "tests", "nice test", "", "abcdef" };
+ const char *somestr[8] = { "a", "b", "c", "d", "e", "f", "g", "h" };
+ const uint64_t number[8] = { 0, UINT_MAX, 7, 123, 90,
+ 100000, 8, 1 };
+
+ for (i = 0; i < 16; i++) {
+ testbool[i] = (i % 2 == 0);
+ testfd[i] = dup(STDERR_FILENO);
+ ATF_REQUIRE(fd_is_valid(testfd[i]));
+ }
+ for (i = 0; i < 8; i++) {
+ testnvl[i] = nvlist_create(0);
+ ATF_REQUIRE(nvlist_error(testnvl[i]) == 0);
+ nvlist_add_string(testnvl[i], "nvl/nvl/teststr", somestr[i]);
+ ATF_REQUIRE(nvlist_error(testnvl[i]) == 0);
+ }
+
+ src = nvlist_create(0);
+ ATF_REQUIRE(nvlist_error(src) == 0);
+
+ ATF_REQUIRE(!nvlist_exists_bool_array(src, "nvl/bool"));
+ nvlist_add_bool_array(src, "nvl/bool", testbool, 16);
+ ATF_REQUIRE_EQ(nvlist_error(src), 0);
+ ATF_REQUIRE(nvlist_exists_bool_array(src, "nvl/bool"));
+
+ ATF_REQUIRE(!nvlist_exists_string_array(src, "nvl/string"));
+ nvlist_add_string_array(src, "nvl/string", string, 8);
+ ATF_REQUIRE_EQ(nvlist_error(src), 0);
+ ATF_REQUIRE(nvlist_exists_string_array(src, "nvl/string"));
+
+ ATF_REQUIRE(!nvlist_exists_descriptor_array(src, "nvl/fd"));
+ nvlist_add_descriptor_array(src, "nvl/fd", testfd, 16);
+ ATF_REQUIRE_EQ(nvlist_error(src), 0);
+ ATF_REQUIRE(nvlist_exists_descriptor_array(src, "nvl/fd"));
+
+ ATF_REQUIRE(!nvlist_exists_number_array(src, "nvl/number"));
+ nvlist_add_number_array(src, "nvl/number", number, 8);
+ ATF_REQUIRE_EQ(nvlist_error(src), 0);
+ ATF_REQUIRE(nvlist_exists_number_array(src, "nvl/number"));
+
+ ATF_REQUIRE(!nvlist_exists_nvlist_array(src, "nvl/array"));
+ nvlist_add_nvlist_array(src, "nvl/array",
+ (const nvlist_t * const *)testnvl, 8);
+ ATF_REQUIRE_EQ(nvlist_error(src), 0);
+ ATF_REQUIRE(nvlist_exists_nvlist_array(src, "nvl/array"));
+
+ dst = nvlist_clone(src);
+ ATF_REQUIRE(dst != NULL);
+
+ ATF_REQUIRE(nvlist_exists_bool_array(dst, "nvl/bool"));
+ (void) nvlist_get_bool_array(dst, "nvl/bool", &nitems);
+ ATF_REQUIRE_EQ(nitems, 16);
+ for (i = 0; i < nitems; i++) {
+ ATF_REQUIRE(
+ nvlist_get_bool_array(dst, "nvl/bool", &nitems)[i] ==
+ nvlist_get_bool_array(src, "nvl/bool", &nitems)[i]);
+ }
+
+ ATF_REQUIRE(nvlist_exists_string_array(dst, "nvl/string"));
+ (void) nvlist_get_string_array(dst, "nvl/string", &nitems);
+ ATF_REQUIRE_EQ(nitems, 8);
+ for (i = 0; i < nitems; i++) {
+ if (nvlist_get_string_array(dst, "nvl/string",
+ &nitems)[i] == NULL) {
+ ATF_REQUIRE(nvlist_get_string_array(dst, "nvl/string",
+ &nitems)[i] == nvlist_get_string_array(src,
+ "nvl/string", &nitems)[i]);
+ } else {
+ ATF_REQUIRE(strcmp(nvlist_get_string_array(dst,
+ "nvl/string", &nitems)[i], nvlist_get_string_array(
+ src, "nvl/string", &nitems)[i]) == 0);
+ }
+ }
+
+ ATF_REQUIRE(nvlist_exists_descriptor_array(dst, "nvl/fd"));
+ (void) nvlist_get_descriptor_array(dst, "nvl/fd", &nitems);
+ ATF_REQUIRE_EQ(nitems, 16);
+ for (i = 0; i < nitems; i++) {
+ ATF_REQUIRE(fd_is_valid(
+ nvlist_get_descriptor_array(dst, "nvl/fd", &nitems)[i]));
+ }
+ ATF_REQUIRE(nvlist_exists_number_array(dst, "nvl/number"));
+ (void) nvlist_get_number_array(dst, "nvl/number", &nitems);
+ ATF_REQUIRE_EQ(nitems, 8);
+
+ for (i = 0; i < nitems; i++) {
+ ATF_REQUIRE(
+ nvlist_get_number_array(dst, "nvl/number", &nitems)[i] ==
+ nvlist_get_number_array(src, "nvl/number", &nitems)[i]);
+ }
+
+ ATF_REQUIRE(nvlist_exists_nvlist_array(dst, "nvl/array"));
+ (void) nvlist_get_nvlist_array(dst, "nvl/array", &nitems);
+ ATF_REQUIRE_EQ(nitems, 8);
+ for (i = 0; i < nitems; i++) {
+ nvl = nvlist_get_nvlist_array(dst, "nvl/array", &nitems)[i];
+ ATF_REQUIRE(nvlist_exists_string(nvl, "nvl/nvl/teststr"));
+ ATF_REQUIRE(strcmp(nvlist_get_string(nvl, "nvl/nvl/teststr"),
+ somestr[i]) == 0);
+ }
+
+ for (i = 0; i < 16; i++) {
+ close(testfd[i]);
+ if (i < 8) {
+ nvlist_destroy(testnvl[i]);
+ }
+ }
+ nvlist_destroy(src);
+ nvlist_destroy(dst);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_bool_array__move);
+ATF_TEST_CASE_BODY(nvlist_bool_array__move)
+{
+ bool *testbool;
+ const bool *const_result;
+ nvlist_t *nvl;
+ size_t nitems, count;
+ unsigned int i;
+ const char *key;
+
+ key = "nvl/bool";
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+
+ count = 16;
+ testbool = (bool*)malloc(sizeof(*testbool) * count);
+ ATF_REQUIRE(testbool != NULL);
+ for (i = 0; i < count; i++)
+ testbool[i] = (i % 2 == 0);
+
+ nvlist_move_bool_array(nvl, key, testbool, count);
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_bool_array(nvl, key));
+
+ const_result = nvlist_get_bool_array(nvl, key, &nitems);
+ ATF_REQUIRE_EQ(nitems, count);
+ ATF_REQUIRE(const_result != NULL);
+ ATF_REQUIRE(const_result == testbool);
+ for (i = 0; i < nitems; i++)
+ ATF_REQUIRE_EQ(const_result[i], (i % 2 == 0));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_string_array__move);
+ATF_TEST_CASE_BODY(nvlist_string_array__move)
+{
+ char **teststr;
+ const char * const *const_result;
+ nvlist_t *nvl;
+ size_t nitems, count;
+ unsigned int i;
+ const char *key;
+
+ key = "nvl/string";
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+
+ count = 26;
+ teststr = (char**)malloc(sizeof(*teststr) * count);
+ ATF_REQUIRE(teststr != NULL);
+ for (i = 0; i < count; i++) {
+ teststr[i] = (char*)malloc(sizeof(**teststr) * 2);
+ ATF_REQUIRE(teststr[i] != NULL);
+ teststr[i][0] = 'a' + i;
+ teststr[i][1] = '\0';
+ }
+
+ nvlist_move_string_array(nvl, key, teststr, count);
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_string_array(nvl, key));
+
+ const_result = nvlist_get_string_array(nvl, key, &nitems);
+ ATF_REQUIRE_EQ(nitems, count);
+ ATF_REQUIRE(const_result != NULL);
+ ATF_REQUIRE((intptr_t)const_result == (intptr_t)teststr);
+ for (i = 0; i < nitems; i++) {
+ ATF_REQUIRE_EQ(const_result[i][0], (char)('a' + i));
+ ATF_REQUIRE_EQ(const_result[i][1], '\0');
+ }
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_nvlist_array__move);
+ATF_TEST_CASE_BODY(nvlist_nvlist_array__move)
+{
+ nvlist **testnv;
+ const nvlist * const *const_result;
+ nvlist_t *nvl;
+ size_t nitems, count;
+ unsigned int i;
+ const char *key;
+
+ key = "nvl/nvlist";
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_nvlist_array(nvl, key));
+
+ count = 26;
+ testnv = (nvlist**)malloc(sizeof(*testnv) * count);
+ ATF_REQUIRE(testnv != NULL);
+ for (i = 0; i < count; i++) {
+ testnv[i] = nvlist_create(0);
+ ATF_REQUIRE(testnv[i] != NULL);
+ }
+
+ nvlist_move_nvlist_array(nvl, key, testnv, count);
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_nvlist_array(nvl, key));
+
+ const_result = nvlist_get_nvlist_array(nvl, key, &nitems);
+ ATF_REQUIRE_EQ(nitems, count);
+ ATF_REQUIRE(const_result != NULL);
+ ATF_REQUIRE((intptr_t)const_result == (intptr_t)testnv);
+ for (i = 0; i < nitems; i++) {
+ ATF_REQUIRE_EQ(nvlist_error(const_result[i]), 0);
+ ATF_REQUIRE(nvlist_empty(const_result[i]));
+ if (i < nitems - 1) {
+ ATF_REQUIRE(nvlist_get_array_next(const_result[i]) ==
+ const_result[i + 1]);
+ } else {
+ ATF_REQUIRE(nvlist_get_array_next(const_result[i]) ==
+ NULL);
+ }
+ ATF_REQUIRE(nvlist_get_parent(const_result[i], NULL) == nvl);
+ ATF_REQUIRE(nvlist_in_array(const_result[i]));
+ }
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_number_array__move);
+ATF_TEST_CASE_BODY(nvlist_number_array__move)
+{
+ uint64_t *testnumber;
+ const uint64_t *const_result;
+ nvlist_t *nvl;
+ size_t nitems, count;
+ unsigned int i;
+ const char *key;
+
+ key = "nvl/number";
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+
+ count = 1000;
+ testnumber = (uint64_t*)malloc(sizeof(*testnumber) * count);
+ ATF_REQUIRE(testnumber != NULL);
+ for (i = 0; i < count; i++)
+ testnumber[i] = i;
+
+ nvlist_move_number_array(nvl, key, testnumber, count);
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_number_array(nvl, key));
+
+ const_result = nvlist_get_number_array(nvl, key, &nitems);
+ ATF_REQUIRE_EQ(nitems, count);
+ ATF_REQUIRE(const_result != NULL);
+ ATF_REQUIRE(const_result == testnumber);
+ for (i = 0; i < nitems; i++)
+ ATF_REQUIRE_EQ(const_result[i], i);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_descriptor_array__move);
+ATF_TEST_CASE_BODY(nvlist_descriptor_array__move)
+{
+ int *testfd;
+ const int *const_result;
+ nvlist_t *nvl;
+ size_t nitems, count;
+ unsigned int i;
+ const char *key;
+
+ key = "nvl/fd";
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+
+ count = 50;
+ testfd = (int*)malloc(sizeof(*testfd) * count);
+ ATF_REQUIRE(testfd != NULL);
+ for (i = 0; i < count; i++) {
+ testfd[i] = dup(STDERR_FILENO);
+ ATF_REQUIRE(fd_is_valid(testfd[i]));
+ }
+
+ nvlist_move_descriptor_array(nvl, key, testfd, count);
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_descriptor_array(nvl, key));
+
+ const_result = nvlist_get_descriptor_array(nvl, key, &nitems);
+ ATF_REQUIRE_EQ(nitems, count);
+ ATF_REQUIRE(const_result != NULL);
+ ATF_REQUIRE(const_result == testfd);
+ for (i = 0; i < nitems; i++)
+ ATF_REQUIRE(fd_is_valid(const_result[i]));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_arrays__error_null);
+ATF_TEST_CASE_BODY(nvlist_arrays__error_null)
+{
+ nvlist_t *nvl;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_add_number_array(nvl, "nvl/number", NULL, 0);
+ ATF_REQUIRE(nvlist_error(nvl) != 0);
+ nvlist_destroy(nvl);
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_move_number_array(nvl, "nvl/number", NULL, 0);
+ ATF_REQUIRE(nvlist_error(nvl) != 0);
+ nvlist_destroy(nvl);
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_add_descriptor_array(nvl, "nvl/fd", NULL, 0);
+ ATF_REQUIRE(nvlist_error(nvl) != 0);
+ nvlist_destroy(nvl);
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_move_descriptor_array(nvl, "nvl/fd", NULL, 0);
+ ATF_REQUIRE(nvlist_error(nvl) != 0);
+ nvlist_destroy(nvl);
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_add_string_array(nvl, "nvl/string", NULL, 0);
+ ATF_REQUIRE(nvlist_error(nvl) != 0);
+ nvlist_destroy(nvl);
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_move_string_array(nvl, "nvl/string", NULL, 0);
+ ATF_REQUIRE(nvlist_error(nvl) != 0);
+ nvlist_destroy(nvl);
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_add_nvlist_array(nvl, "nvl/nvlist", NULL, 0);
+ ATF_REQUIRE(nvlist_error(nvl) != 0);
+ nvlist_destroy(nvl);
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_move_nvlist_array(nvl, "nvl/nvlist", NULL, 0);
+ ATF_REQUIRE(nvlist_error(nvl) != 0);
+ nvlist_destroy(nvl);
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_add_bool_array(nvl, "nvl/bool", NULL, 0);
+ ATF_REQUIRE(nvlist_error(nvl) != 0);
+ nvlist_destroy(nvl);
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_move_bool_array(nvl, "nvl/bool", NULL, 0);
+ ATF_REQUIRE(nvlist_error(nvl) != 0);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_arrays__bad_value);
+ATF_TEST_CASE_BODY(nvlist_arrays__bad_value)
+{
+ nvlist_t *nvl, *nvladd[1], **nvlmove;
+ int fdadd[1], *fdmove;
+
+ nvladd[0] = NULL;
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_add_nvlist_array(nvl, "nvl/nvlist", nvladd, 1);
+ ATF_REQUIRE(nvlist_error(nvl) != 0);
+ nvlist_destroy(nvl);
+
+ nvlmove = (nvlist_t**)malloc(sizeof(*nvlmove));
+ ATF_REQUIRE(nvlmove != NULL);
+ nvlmove[0] = NULL;
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_move_nvlist_array(nvl, "nvl/nvlist", nvlmove, 1);
+ ATF_REQUIRE(nvlist_error(nvl) != 0);
+ nvlist_destroy(nvl);
+
+ fdadd[0] = -2;
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_add_descriptor_array(nvl, "nvl/fd", fdadd, 1);
+ ATF_REQUIRE(nvlist_error(nvl) != 0);
+ nvlist_destroy(nvl);
+
+ fdmove = (int*)malloc(sizeof(*fdmove));
+ ATF_REQUIRE(fdmove != NULL);
+ fdmove[0] = -2;
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_move_descriptor_array(nvl, "nvl/fd", fdmove, 1);
+ ATF_REQUIRE(nvlist_error(nvl) != 0);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_nvlist_array__travel);
+ATF_TEST_CASE_BODY(nvlist_nvlist_array__travel)
+{
+ nvlist_t *nvl, *test[5], *nasted;
+ const nvlist_t *travel;
+ void *cookie;
+ int index, i, type;
+ const char *name;
+
+ for (i = 0; i < 5; i++) {
+ test[i] = nvlist_create(0);
+ ATF_REQUIRE(test[i] != NULL);
+ nvlist_add_number(test[i], "nvl/number", i);
+ ATF_REQUIRE(nvlist_error(test[i]) == 0);
+ }
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_add_nvlist_array(nvl, "nvl/nvlist_array", test, 5);
+ ATF_REQUIRE(nvlist_error(nvl) == 0);
+ nasted = nvlist_create(0);
+ ATF_REQUIRE(nasted != NULL);
+ nvlist_add_nvlist_array(nasted, "nvl/nvl/nvlist_array", test, 5);
+ ATF_REQUIRE(nvlist_error(nasted) == 0);
+ nvlist_move_nvlist(nvl, "nvl/nvl", nasted);
+ ATF_REQUIRE(nvlist_error(nvl) == 0);
+ nvlist_add_string(nvl, "nvl/string", "END");
+ ATF_REQUIRE(nvlist_error(nvl) == 0);
+
+ cookie = NULL;
+ index = 0;
+ travel = nvl;
+ do {
+ while ((name = nvlist_next(travel, &type, &cookie)) != NULL) {
+ if (index == 0) {
+ ATF_REQUIRE(type == NV_TYPE_NVLIST_ARRAY);
+ } else if (index >= 1 && index <= 5) {
+ ATF_REQUIRE(type == NV_TYPE_NUMBER);
+ } else if (index == 6) {
+ ATF_REQUIRE(type == NV_TYPE_NVLIST);
+ } else if (index == 7) {
+ ATF_REQUIRE(type == NV_TYPE_NVLIST_ARRAY);
+ } else if (index >= 8 && index <= 12) {
+ ATF_REQUIRE(type == NV_TYPE_NUMBER);
+ } else if (index == 13) {
+ ATF_REQUIRE(type == NV_TYPE_STRING);
+ }
+
+ if (type == NV_TYPE_NVLIST) {
+ travel = nvlist_get_nvlist(travel, name);
+ cookie = NULL;
+ } else if (type == NV_TYPE_NVLIST_ARRAY) {
+ travel = nvlist_get_nvlist_array(travel, name,
+ NULL)[0];
+ cookie = NULL;
+ }
+ index ++;
+ }
+ } while ((travel = nvlist_get_pararr(travel, &cookie)) != NULL);
+
+ for (i = 0; i < 5; i++)
+ nvlist_destroy(test[i]);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_nvlist_array__travel_alternative);
+ATF_TEST_CASE_BODY(nvlist_nvlist_array__travel_alternative)
+{
+ nvlist_t *nvl, *test[5], *nasted;
+ const nvlist_t *travel, *tmp;
+ void *cookie;
+ int index, i, type;
+ const char *name;
+
+ for (i = 0; i < 5; i++) {
+ test[i] = nvlist_create(0);
+ ATF_REQUIRE(test[i] != NULL);
+ nvlist_add_number(test[i], "nvl/number", i);
+ ATF_REQUIRE(nvlist_error(test[i]) == 0);
+ }
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ nvlist_add_nvlist_array(nvl, "nvl/nvlist_array", test, 5);
+ ATF_REQUIRE(nvlist_error(nvl) == 0);
+ nasted = nvlist_create(0);
+ ATF_REQUIRE(nasted != NULL);
+ nvlist_add_nvlist_array(nasted, "nvl/nvl/nvlist_array", test, 5);
+ ATF_REQUIRE(nvlist_error(nasted) == 0);
+ nvlist_move_nvlist(nvl, "nvl/nvl", nasted);
+ ATF_REQUIRE(nvlist_error(nvl) == 0);
+ nvlist_add_string(nvl, "nvl/string", "END");
+ ATF_REQUIRE(nvlist_error(nvl) == 0);
+
+ cookie = NULL;
+ index = 0;
+ tmp = travel = nvl;
+ do {
+ do {
+ travel = tmp;
+ while ((name = nvlist_next(travel, &type, &cookie)) !=
+ NULL) {
+ if (index == 0) {
+ ATF_REQUIRE(type ==
+ NV_TYPE_NVLIST_ARRAY);
+ } else if (index >= 1 && index <= 5) {
+ ATF_REQUIRE(type == NV_TYPE_NUMBER);
+ } else if (index == 6) {
+ ATF_REQUIRE(type == NV_TYPE_NVLIST);
+ } else if (index == 7) {
+ ATF_REQUIRE(type ==
+ NV_TYPE_NVLIST_ARRAY);
+ } else if (index >= 8 && index <= 12) {
+ ATF_REQUIRE(type == NV_TYPE_NUMBER);
+ } else if (index == 13) {
+ ATF_REQUIRE(type == NV_TYPE_STRING);
+ }
+
+ if (type == NV_TYPE_NVLIST) {
+ travel = nvlist_get_nvlist(travel,
+ name);
+ cookie = NULL;
+ } else if (type == NV_TYPE_NVLIST_ARRAY) {
+ travel = nvlist_get_nvlist_array(travel,
+ name, NULL)[0];
+ cookie = NULL;
+ }
+ index ++;
+ }
+ cookie = NULL;
+ } while ((tmp = nvlist_get_array_next(travel)) != NULL);
+ } while ((tmp = nvlist_get_parent(travel, &cookie)) != NULL);
+
+ for (i = 0; i < 5; i++)
+ nvlist_destroy(test[i]);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_bool_array__pack);
+ATF_TEST_CASE_BODY(nvlist_bool_array__pack)
+{
+ nvlist_t *nvl, *unpacked;
+ const char *key;
+ size_t packed_size, count;
+ void *packed;
+ unsigned int i;
+ const bool *const_result;
+ bool testbool[16];
+
+ for (i = 0; i < 16; i++)
+ testbool[i] = (i % 2 == 0);
+
+ key = "nvl/bool";
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+
+ nvlist_add_bool_array(nvl, key, testbool, 16);
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_bool_array(nvl, key));
+
+ packed = nvlist_pack(nvl, &packed_size);
+ ATF_REQUIRE(packed != NULL);
+
+ unpacked = nvlist_unpack(packed, packed_size, 0);
+ ATF_REQUIRE(unpacked != NULL);
+ ATF_REQUIRE_EQ(nvlist_error(unpacked), 0);
+ ATF_REQUIRE(nvlist_exists_bool_array(unpacked, key));
+
+ const_result = nvlist_get_bool_array(unpacked, key, &count);
+ ATF_REQUIRE_EQ(count, 16);
+ for (i = 0; i < count; i++) {
+ ATF_REQUIRE_EQ(testbool[i], const_result[i]);
+ }
+
+ nvlist_destroy(nvl);
+ nvlist_destroy(unpacked);
+ free(packed);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_number_array__pack);
+ATF_TEST_CASE_BODY(nvlist_number_array__pack)
+{
+ nvlist_t *nvl, *unpacked;
+ const char *key;
+ size_t packed_size, count;
+ void *packed;
+ unsigned int i;
+ const uint64_t *const_result;
+ const uint64_t number[8] = { 0, UINT_MAX, 7, 123, 90,
+ 100000, 8, 1 };
+
+ key = "nvl/number";
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+
+ nvlist_add_number_array(nvl, key, number, 8);
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_number_array(nvl, key));
+
+ packed = nvlist_pack(nvl, &packed_size);
+ ATF_REQUIRE(packed != NULL);
+
+ unpacked = nvlist_unpack(packed, packed_size, 0);
+ ATF_REQUIRE(unpacked != NULL);
+ ATF_REQUIRE_EQ(nvlist_error(unpacked), 0);
+ ATF_REQUIRE(nvlist_exists_number_array(unpacked, key));
+
+ const_result = nvlist_get_number_array(unpacked, key, &count);
+ ATF_REQUIRE_EQ(count, 8);
+ for (i = 0; i < count; i++) {
+ ATF_REQUIRE_EQ(number[i], const_result[i]);
+ }
+
+ nvlist_destroy(nvl);
+ nvlist_destroy(unpacked);
+ free(packed);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_descriptor_array__pack);
+ATF_TEST_CASE_BODY(nvlist_descriptor_array__pack)
+{
+ nvlist_t *nvl;
+ const char *key;
+ size_t nitems;
+ unsigned int i;
+ const int *const_result;
+ int desc[32], fd, socks[2];
+ pid_t pid;
+
+ key = "nvl/descriptor";
+
+ ATF_REQUIRE_EQ(socketpair(PF_UNIX, SOCK_STREAM, 0, socks), 0);
+
+ pid = atf::utils::fork();
+ ATF_REQUIRE(pid >= 0);
+ if (pid == 0) {
+ /* Child. */
+ fd = socks[0];
+ close(socks[1]);
+ for (i = 0; i < 32; i++) {
+ desc[i] = dup(STDERR_FILENO);
+ ATF_REQUIRE(fd_is_valid(desc[i]));
+ }
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_descriptor_array(nvl, key));
+
+ nvlist_add_descriptor_array(nvl, key, desc, 32);
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_descriptor_array(nvl, key));
+
+ ATF_REQUIRE(nvlist_send(fd, nvl) >= 0);
+
+ for (i = 0; i < nitems; i++)
+ close(desc[i]);
+ } else {
+ /* Parent */
+ fd = socks[1];
+ close(socks[0]);
+
+ errno = 0;
+ nvl = nvlist_recv(fd, 0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(nvlist_exists_descriptor_array(nvl, key));
+
+ const_result = nvlist_get_descriptor_array(nvl, key, &nitems);
+ ATF_REQUIRE(const_result != NULL);
+ ATF_REQUIRE_EQ(nitems, 32);
+ for (i = 0; i < nitems; i++)
+ ATF_REQUIRE(fd_is_valid(const_result[i]));
+
+ atf::utils::wait(pid, 0, "", "");
+ }
+
+ nvlist_destroy(nvl);
+ close(fd);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_string_array__pack);
+ATF_TEST_CASE_BODY(nvlist_string_array__pack)
+{
+ nvlist_t *nvl, *unpacked;
+ const char *key;
+ size_t packed_size, count;
+ void *packed;
+ unsigned int i;
+ const char * const *const_result;
+ const char *string[8] = { "a", "b", "kot", "foo",
+ "tests", "nice test", "", "abcdef" };
+
+ key = "nvl/string";
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+
+ nvlist_add_string_array(nvl, key, string, 8);
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_string_array(nvl, key));
+
+ packed = nvlist_pack(nvl, &packed_size);
+ ATF_REQUIRE(packed != NULL);
+
+ unpacked = nvlist_unpack(packed, packed_size, 0);
+ ATF_REQUIRE(unpacked != NULL);
+ ATF_REQUIRE_EQ(nvlist_error(unpacked), 0);
+ ATF_REQUIRE(nvlist_exists_string_array(unpacked, key));
+
+ const_result = nvlist_get_string_array(unpacked, key, &count);
+ ATF_REQUIRE_EQ(count, 8);
+ for (i = 0; i < count; i++) {
+ ATF_REQUIRE_EQ(strcmp(string[i], const_result[i]), 0);
+ }
+
+ nvlist_destroy(nvl);
+ nvlist_destroy(unpacked);
+ free(packed);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_nvlist_array__pack);
+ATF_TEST_CASE_BODY(nvlist_nvlist_array__pack)
+{
+ nvlist_t *testnvl[8], *unpacked;
+ const nvlist_t * const *const_result;
+ nvlist_t **result;
+ nvlist_t *nvl;
+ size_t nitems, packed_size;
+ unsigned int i;
+ void *packed;
+ const char *somestr[8] = { "a", "b", "c", "d", "e", "f", "g", "h" };
+ const char *key;
+
+ for (i = 0; i < 8; i++) {
+ testnvl[i] = nvlist_create(0);
+ ATF_REQUIRE(testnvl[i] != NULL);
+ ATF_REQUIRE_EQ(nvlist_error(testnvl[i]), 0);
+ nvlist_add_string(testnvl[i], "nvl/string", somestr[i]);
+ ATF_REQUIRE_EQ(nvlist_error(testnvl[i]), 0);
+ ATF_REQUIRE(nvlist_exists_string(testnvl[i], "nvl/string"));
+ }
+
+ key = "nvl/nvlist";
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(nvlist_empty(nvl));
+ ATF_REQUIRE(!nvlist_exists_string_array(nvl, key));
+
+ nvlist_add_nvlist_array(nvl, key, (const nvlist_t * const *)testnvl, 8);
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_nvlist_array(nvl, key));
+ ATF_REQUIRE(nvlist_exists_nvlist_array(nvl, "nvl/nvlist"));
+ packed = nvlist_pack(nvl, &packed_size);
+ ATF_REQUIRE(packed != NULL);
+
+ unpacked = nvlist_unpack(packed, packed_size, 0);
+ ATF_REQUIRE(unpacked != NULL);
+ ATF_REQUIRE_EQ(nvlist_error(unpacked), 0);
+ ATF_REQUIRE(nvlist_exists_nvlist_array(unpacked, key));
+
+ const_result = nvlist_get_nvlist_array(unpacked, key, &nitems);
+ ATF_REQUIRE(const_result != NULL);
+ ATF_REQUIRE_EQ(nitems, 8);
+ for (i = 0; i < nitems; i++) {
+ ATF_REQUIRE_EQ(nvlist_error(const_result[i]), 0);
+ if (i < nitems - 1) {
+ ATF_REQUIRE(nvlist_get_array_next(const_result[i]) ==
+ const_result[i + 1]);
+ } else {
+ ATF_REQUIRE(nvlist_get_array_next(const_result[i]) ==
+ NULL);
+ }
+ ATF_REQUIRE(nvlist_get_parent(const_result[i], NULL) == unpacked);
+ ATF_REQUIRE(nvlist_in_array(const_result[i]));
+ ATF_REQUIRE(nvlist_exists_string(const_result[i],
+ "nvl/string"));
+ ATF_REQUIRE(strcmp(nvlist_get_string(const_result[i],
+ "nvl/string"), somestr[i]) == 0);
+ }
+
+ for (i = 0; i < 8; i++)
+ nvlist_destroy(testnvl[i]);
+ free(result);
+ nvlist_destroy(nvl);
+ nvlist_destroy(unpacked);
+ free(packed);
+}
+
+ATF_INIT_TEST_CASES(tp)
+{
+
+ ATF_ADD_TEST_CASE(tp, nvlist_bool_array__basic);
+ ATF_ADD_TEST_CASE(tp, nvlist_string_array__basic);
+ ATF_ADD_TEST_CASE(tp, nvlist_descriptor_array__basic);
+ ATF_ADD_TEST_CASE(tp, nvlist_number_array__basic);
+ ATF_ADD_TEST_CASE(tp, nvlist_nvlist_array__basic)
+
+ ATF_ADD_TEST_CASE(tp, nvlist_clone_array)
+
+ ATF_ADD_TEST_CASE(tp, nvlist_bool_array__move);
+ ATF_ADD_TEST_CASE(tp, nvlist_string_array__move);
+ ATF_ADD_TEST_CASE(tp, nvlist_nvlist_array__move);
+ ATF_ADD_TEST_CASE(tp, nvlist_number_array__move);
+ ATF_ADD_TEST_CASE(tp, nvlist_descriptor_array__move);
+
+ ATF_ADD_TEST_CASE(tp, nvlist_arrays__error_null);
+
+ ATF_ADD_TEST_CASE(tp, nvlist_arrays__bad_value)
+
+ ATF_ADD_TEST_CASE(tp, nvlist_nvlist_array__travel)
+ ATF_ADD_TEST_CASE(tp, nvlist_nvlist_array__travel_alternative)
+
+ ATF_ADD_TEST_CASE(tp, nvlist_bool_array__pack)
+ ATF_ADD_TEST_CASE(tp, nvlist_number_array__pack)
+ ATF_ADD_TEST_CASE(tp, nvlist_descriptor_array__pack)
+ ATF_ADD_TEST_CASE(tp, nvlist_string_array__pack)
+ ATF_ADD_TEST_CASE(tp, nvlist_nvlist_array__pack)
+}
+
Index: lib/libnv/tests/nv_tests.cc
===================================================================
--- /dev/null
+++ lib/libnv/tests/nv_tests.cc
@@ -0,0 +1,1276 @@
+/*-
+ * Copyright (c) 2014-2015 Sandvine Inc. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/lib/libnv/tests/nv_tests.cc 285063 2015-07-02 21:58:10Z oshogbo $");
+
+#include <sys/nv.h>
+
+#include <atf-c++.hpp>
+
+#include <errno.h>
+#include <limits>
+#include <set>
+#include <sstream>
+#include <string>
+
+/*
+ * Test that a newly created nvlist has no errors, and is empty.
+ */
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_create__is_empty);
+ATF_TEST_CASE_BODY(nvlist_create__is_empty)
+{
+ nvlist_t *nvl;
+ int type;
+ void *it;
+
+ nvl = nvlist_create(0);
+
+ ATF_REQUIRE(nvl != NULL);
+
+ ATF_REQUIRE_EQ(nvlist_error(nvl), 0);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ it = NULL;
+ ATF_REQUIRE_EQ(nvlist_next(nvl, &type, &it), static_cast<const char *>(NULL));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_add_null__single_insert);
+ATF_TEST_CASE_BODY(nvlist_add_null__single_insert)
+{
+ nvlist_t *nvl;
+ void *it;
+ const char *key;
+ int type;
+
+ key = "key";
+ nvl = nvlist_create(0);
+
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(!nvlist_exists(nvl, key));
+
+ nvlist_add_null(nvl, key);
+
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists(nvl, key));
+ ATF_REQUIRE(nvlist_exists_null(nvl, key));
+ ATF_REQUIRE(nvlist_exists_null(nvl, "key"));
+
+ /* Iterate over the nvlist; ensure that it has only our one key. */
+ it = NULL;
+ ATF_REQUIRE_EQ(strcmp(nvlist_next(nvl, &type, &it), key), 0);
+ ATF_REQUIRE_EQ(type, NV_TYPE_NULL);
+ ATF_REQUIRE_EQ(nvlist_next(nvl, &type,&it), static_cast<const char *>(NULL));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_add_bool__single_insert);
+ATF_TEST_CASE_BODY(nvlist_add_bool__single_insert)
+{
+ nvlist_t *nvl;
+ void *it;
+ const char *key;
+ int type;
+
+ key = "name";
+ nvl = nvlist_create(0);
+
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(!nvlist_exists(nvl, key));
+
+ nvlist_add_bool(nvl, key, true);
+
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists(nvl, key));
+ ATF_REQUIRE(nvlist_exists(nvl, "name"));
+ ATF_REQUIRE(nvlist_exists_bool(nvl, key));
+ ATF_REQUIRE(nvlist_exists_bool(nvl, "name"));
+ ATF_REQUIRE_EQ(nvlist_get_bool(nvl, key), true);
+
+ /* Iterate over the nvlist; ensure that it has only our one key. */
+ it = NULL;
+ ATF_REQUIRE_EQ(strcmp(nvlist_next(nvl, &type, &it), key), 0);
+ ATF_REQUIRE_EQ(type, NV_TYPE_BOOL);
+ ATF_REQUIRE_EQ(nvlist_next(nvl, &type,&it), static_cast<const char *>(NULL));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_add_number__single_insert);
+ATF_TEST_CASE_BODY(nvlist_add_number__single_insert)
+{
+ nvlist_t *nvl;
+ void *it;
+ const char *key;
+ uint64_t value;
+ int type;
+
+ key = "foo123";
+ value = 71965;
+ nvl = nvlist_create(0);
+
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(!nvlist_exists(nvl, key));
+
+ nvlist_add_number(nvl, key, value);
+
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists(nvl, key));
+ ATF_REQUIRE(nvlist_exists(nvl, "foo123"));
+ ATF_REQUIRE(nvlist_exists_number(nvl, key));
+ ATF_REQUIRE_EQ(nvlist_get_number(nvl, key), value);
+
+ /* Iterate over the nvlist; ensure that it has only our one key. */
+ it = NULL;
+ ATF_REQUIRE_EQ(strcmp(nvlist_next(nvl, &type, &it), key), 0);
+ ATF_REQUIRE_EQ(type, NV_TYPE_NUMBER);
+ ATF_REQUIRE_EQ(nvlist_next(nvl, &type,&it), static_cast<const char *>(NULL));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_add_string__single_insert);
+ATF_TEST_CASE_BODY(nvlist_add_string__single_insert)
+{
+ nvlist_t *nvl;
+ void *it;
+ const char *key;
+ const char *value;
+ int type;
+
+ key = "test";
+ value = "fgjdkgjdk";
+ nvl = nvlist_create(0);
+
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(!nvlist_exists(nvl, key));
+
+ nvlist_add_string(nvl, key, value);
+
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists(nvl, key));
+ ATF_REQUIRE(nvlist_exists(nvl, "test"));
+ ATF_REQUIRE(nvlist_exists_string(nvl, key));
+ ATF_REQUIRE(nvlist_exists_string(nvl, "test"));
+ ATF_REQUIRE_EQ(strcmp(nvlist_get_string(nvl, key), value), 0);
+
+ /* nvlist_add_* is required to clone the value, so check for that. */
+ ATF_REQUIRE(nvlist_get_string(nvl, key) != value);
+
+ /* Iterate over the nvlist; ensure that it has only our one key. */
+ it = NULL;
+ ATF_REQUIRE_EQ(strcmp(nvlist_next(nvl, &type, &it), key), 0);
+ ATF_REQUIRE_EQ(type, NV_TYPE_STRING);
+ ATF_REQUIRE_EQ(nvlist_next(nvl, &type,&it), static_cast<const char *>(NULL));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_add_nvlist__single_insert);
+ATF_TEST_CASE_BODY(nvlist_add_nvlist__single_insert)
+{
+ nvlist_t *nvl;
+ void *it;
+ const char *key, *subkey;
+ nvlist_t *sublist;
+ const nvlist_t *value;
+ int type;
+
+ key = "test";
+ subkey = "subkey";
+ sublist = nvlist_create(0);
+ nvl = nvlist_create(0);
+
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(!nvlist_exists(nvl, key));
+
+ nvlist_add_null(sublist, subkey);
+ nvlist_add_nvlist(nvl, key, sublist);
+
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists(nvl, key));
+ ATF_REQUIRE(nvlist_exists(nvl, "test"));
+ ATF_REQUIRE(nvlist_exists_nvlist(nvl, key));
+ ATF_REQUIRE(nvlist_exists_nvlist(nvl, "test"));
+
+ value = nvlist_get_nvlist(nvl, key);
+ ATF_REQUIRE(nvlist_exists_null(value, subkey));
+
+ /* nvlist_add_* is required to clone the value, so check for that. */
+ ATF_REQUIRE(sublist != value);
+
+ /* Iterate over the nvlist; ensure that it has only our one key. */
+ it = NULL;
+ ATF_REQUIRE_EQ(strcmp(nvlist_next(nvl, &type, &it), key), 0);
+ ATF_REQUIRE_EQ(type, NV_TYPE_NVLIST);
+ ATF_REQUIRE_EQ(nvlist_next(nvl, &type,&it), static_cast<const char *>(NULL));
+
+ nvlist_destroy(sublist);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_add_nvlist__child_with_error);
+ATF_TEST_CASE_BODY(nvlist_add_nvlist__child_with_error)
+{
+ nvlist_t *nvl, *parent;
+
+ nvl = nvlist_create(0);
+ parent = nvlist_create(0);
+
+ nvlist_set_error(nvl, EBADF);
+ nvlist_add_nvlist(parent, "test", nvl);
+ ATF_REQUIRE_EQ(nvlist_error(parent), EBADF);
+
+ nvlist_destroy(nvl);
+ nvlist_destroy(parent);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_add_binary__single_insert);
+ATF_TEST_CASE_BODY(nvlist_add_binary__single_insert)
+{
+ nvlist_t *nvl;
+ void *it;
+ const char *key;
+ void *value;
+ const void *ret_value;
+ size_t value_size, ret_size;
+ int type;
+
+ key = "binary";
+ value_size = 13;
+ value = malloc(value_size);
+ memset(value, 0xa5, value_size);
+ nvl = nvlist_create(0);
+
+ ATF_REQUIRE(nvl != NULL);
+ ATF_REQUIRE(!nvlist_exists(nvl, key));
+
+ nvlist_add_binary(nvl, key, value, value_size);
+
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists(nvl, key));
+ ATF_REQUIRE(nvlist_exists(nvl, "binary"));
+ ATF_REQUIRE(nvlist_exists_binary(nvl, key));
+ ATF_REQUIRE(nvlist_exists_binary(nvl, "binary"));
+
+ ret_value = nvlist_get_binary(nvl, key, &ret_size);
+ ATF_REQUIRE_EQ(value_size, ret_size);
+ ATF_REQUIRE_EQ(memcmp(value, ret_value, ret_size), 0);
+
+ /* nvlist_add_* is required to clone the value, so check for that. */
+ ATF_REQUIRE(value != ret_value);
+
+ /* Iterate over the nvlist; ensure that it has only our one key. */
+ it = NULL;
+ ATF_REQUIRE_EQ(strcmp(nvlist_next(nvl, &type, &it), key), 0);
+ ATF_REQUIRE_EQ(type, NV_TYPE_BINARY);
+ ATF_REQUIRE_EQ(nvlist_next(nvl, &type,&it), static_cast<const char *>(NULL));
+
+ nvlist_destroy(nvl);
+ free(value);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_clone__empty_nvlist);
+ATF_TEST_CASE_BODY(nvlist_clone__empty_nvlist)
+{
+ nvlist_t *nvl, *clone;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ clone = nvlist_clone(nvl);
+ ATF_REQUIRE(clone != NULL);
+ ATF_REQUIRE(clone != nvl);
+ ATF_REQUIRE(nvlist_empty(clone));
+
+ nvlist_destroy(clone);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_clone__nonempty_nvlist);
+ATF_TEST_CASE_BODY(nvlist_clone__nonempty_nvlist)
+{
+ nvlist_t *nvl, *clone;
+ const char *key;
+ void *it;
+ uint64_t value;
+ int type;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ key = "testkey";
+ value = 684874;
+ nvlist_add_number(nvl, key, value);
+
+ clone = nvlist_clone(nvl);
+ ATF_REQUIRE(clone != NULL);
+ ATF_REQUIRE(clone != nvl);
+ ATF_REQUIRE(nvlist_exists_number(clone, key));
+ ATF_REQUIRE_EQ(nvlist_get_number(clone, key), value);
+
+ /* Iterate over the nvlist; ensure that it has only our one key. */
+ it = NULL;
+ ATF_REQUIRE_EQ(strcmp(nvlist_next(clone, &type, &it), key), 0);
+ ATF_REQUIRE_EQ(type, NV_TYPE_NUMBER);
+ ATF_REQUIRE_EQ(nvlist_next(clone, &type, &it), static_cast<const char *>(NULL));
+
+ nvlist_destroy(clone);
+ nvlist_destroy(nvl);
+}
+
+static const char * const test_subnvlist_key = "nvlist";
+
+static const char * const test_string_key = "string";
+static const char * const test_string_val = "59525";
+
+static nvlist_t*
+create_test_nvlist(void)
+{
+ nvlist_t *nvl, *sublist;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ sublist = nvlist_create(0);
+ ATF_REQUIRE(sublist != NULL);
+
+ nvlist_add_string(sublist, test_string_key, test_string_val);
+ nvlist_move_nvlist(nvl, test_subnvlist_key, sublist);
+
+ return (nvl);
+}
+
+static void
+verify_test_nvlist(const nvlist_t *nvl)
+{
+ void *it;
+ const nvlist_t *value;
+ int type;
+
+ ATF_REQUIRE(nvlist_exists_nvlist(nvl, test_subnvlist_key));
+
+ value = nvlist_get_nvlist(nvl, test_subnvlist_key);
+
+ ATF_REQUIRE(nvlist_exists_string(value, test_string_key));
+ ATF_REQUIRE_EQ(strcmp(nvlist_get_string(value, test_string_key), test_string_val), 0);
+ ATF_REQUIRE(nvlist_get_string(value, test_string_key) != test_string_val);
+
+ /* Iterate over both nvlists; ensure that each has only the one key. */
+ it = NULL;
+ ATF_REQUIRE_EQ(strcmp(nvlist_next(value, &type, &it),
+ test_string_key), 0);
+ ATF_REQUIRE_EQ(type, NV_TYPE_STRING);
+ ATF_REQUIRE_EQ(nvlist_next(value, &type, &it), static_cast<const char *>(NULL));
+
+ it = NULL;
+ ATF_REQUIRE_EQ(strcmp(nvlist_next(nvl, &type, &it),
+ test_subnvlist_key), 0);
+ ATF_REQUIRE_EQ(type, NV_TYPE_NVLIST);
+ ATF_REQUIRE_EQ(nvlist_next(nvl, &type, &it), static_cast<const char *>(NULL));
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_clone__nested_nvlist);
+ATF_TEST_CASE_BODY(nvlist_clone__nested_nvlist)
+{
+ nvlist_t *nvl, *clone;
+
+ nvl = create_test_nvlist();
+ clone = nvlist_clone(nvl);
+
+ ATF_REQUIRE(clone != NULL);
+ ATF_REQUIRE(clone != nvl);
+ verify_test_nvlist(clone);
+
+ nvlist_destroy(clone);
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_clone__error_nvlist);
+ATF_TEST_CASE_BODY(nvlist_clone__error_nvlist)
+{
+ nvlist_t *nvl, *clone;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ nvlist_set_error(nvl, ENOMEM);
+
+ clone = nvlist_clone(nvl);
+ ATF_REQUIRE(clone == NULL);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_pack__empty_nvlist);
+ATF_TEST_CASE_BODY(nvlist_pack__empty_nvlist)
+{
+ nvlist_t *nvl, *unpacked;
+ void *packed;
+ size_t packed_size;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ packed = nvlist_pack(nvl, &packed_size);
+ ATF_REQUIRE(packed != NULL);
+
+ unpacked = nvlist_unpack(packed, packed_size, 0);
+ ATF_REQUIRE(unpacked != NULL);
+ ATF_REQUIRE(unpacked != nvl);
+ ATF_REQUIRE(nvlist_empty(unpacked));
+
+ nvlist_destroy(unpacked);
+ nvlist_destroy(nvl);
+ free(packed);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_unpack__flags_nvlist);
+ATF_TEST_CASE_BODY(nvlist_unpack__flags_nvlist)
+{
+ nvlist_t *nvl, *unpacked;
+ void *packed;
+ size_t packed_size;
+
+ nvl = nvlist_create(NV_FLAG_NO_UNIQUE);
+ ATF_REQUIRE(nvl != NULL);
+
+ nvlist_add_bool(nvl, "name", true);
+ ATF_REQUIRE(!nvlist_empty(nvl));
+ ATF_REQUIRE(nvlist_exists_bool(nvl, "name"));
+
+ packed = nvlist_pack(nvl, &packed_size);
+ ATF_REQUIRE(packed != NULL);
+
+ unpacked = nvlist_unpack(packed, packed_size, 0);
+ ATF_REQUIRE(unpacked == NULL);
+
+ unpacked = nvlist_unpack(packed, packed_size, NV_FLAG_IGNORE_CASE);
+ ATF_REQUIRE(unpacked == NULL);
+
+ unpacked = nvlist_unpack(packed, packed_size, NV_FLAG_NO_UNIQUE);
+ ATF_REQUIRE(unpacked != NULL);
+ ATF_REQUIRE(unpacked != nvl);
+ ATF_REQUIRE(!nvlist_empty(unpacked));
+ ATF_REQUIRE(nvlist_exists_bool(unpacked, "name"));
+
+ nvlist_destroy(unpacked);
+ nvlist_destroy(nvl);
+ free(packed);
+}
+
+static void
+verify_null(const nvlist_t *nvl, int type)
+{
+
+ ATF_REQUIRE_EQ(type, NV_TYPE_NULL);
+}
+
+static void
+verify_number(const nvlist_t *nvl, const char *name, int type, uint64_t value)
+{
+
+ ATF_REQUIRE_EQ(type, NV_TYPE_NUMBER);
+ ATF_REQUIRE_EQ(nvlist_get_number(nvl, name), value);
+}
+
+static void
+verify_string(const nvlist_t *nvl, const char *name, int type,
+ const char * value)
+{
+
+ ATF_REQUIRE_EQ(type, NV_TYPE_STRING);
+ ATF_REQUIRE_EQ(strcmp(nvlist_get_string(nvl, name), value), 0);
+}
+
+static void
+verify_nvlist(const nvlist_t *nvl, const char *name, int type)
+{
+
+ ATF_REQUIRE_EQ(type, NV_TYPE_NVLIST);
+ verify_test_nvlist(nvlist_get_nvlist(nvl, name));
+}
+
+static void
+verify_binary(const nvlist_t *nvl, const char *name, int type,
+ const void * value, size_t size)
+{
+ const void *actual_value;
+ size_t actual_size;
+
+ ATF_REQUIRE_EQ(type, NV_TYPE_BINARY);
+ actual_value = nvlist_get_binary(nvl, name, &actual_size);
+ ATF_REQUIRE_EQ(size, actual_size);
+ ATF_REQUIRE_EQ(memcmp(value, actual_value, size), 0);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_pack__multiple_values);
+ATF_TEST_CASE_BODY(nvlist_pack__multiple_values)
+{
+ std::ostringstream msg;
+ std::set<std::string> keys_seen;
+ nvlist_t *nvl, *unpacked, *nvvalue;
+ const char *nullkey, *numkey, *strkey, *nvkey, *binkey, *name;
+ int numvalue;
+ const char * strvalue;
+ void *binvalue, *packed, *it;
+ size_t binsize, packed_size;
+ int type;
+
+ nvl = nvlist_create(0);
+
+ nullkey = "null";
+ nvlist_add_null(nvl, nullkey);
+
+ numkey = "number";
+ numvalue = 939853984;
+ nvlist_add_number(nvl, numkey, numvalue);
+
+ strkey = "string";
+ strvalue = "jfieutijf";
+ nvlist_add_string(nvl, strkey, strvalue);
+
+ nvkey = "nvlist";
+ nvvalue = create_test_nvlist();
+ nvlist_move_nvlist(nvl, nvkey, nvvalue);
+
+ binkey = "binary";
+ binsize = 4;
+ binvalue = malloc(binsize);
+ memset(binvalue, 'b', binsize);
+ nvlist_move_binary(nvl, binkey, binvalue, binsize);
+
+ packed = nvlist_pack(nvl, &packed_size);
+ ATF_REQUIRE(packed != NULL);
+
+ unpacked = nvlist_unpack(packed, packed_size, 0);
+ ATF_REQUIRE(unpacked != 0);
+
+ it = NULL;
+ while ((name = nvlist_next(unpacked, &type, &it)) != NULL) {
+ /* Ensure that we see every key only once. */
+ ATF_REQUIRE_EQ(keys_seen.count(name), 0);
+
+ if (strcmp(name, nullkey) == 0)
+ verify_null(unpacked, type);
+ else if (strcmp(name, numkey) == 0)
+ verify_number(unpacked, name, type, numvalue);
+ else if (strcmp(name, strkey) == 0)
+ verify_string(unpacked, name, type, strvalue);
+ else if (strcmp(name, nvkey) == 0)
+ verify_nvlist(unpacked, name, type);
+ else if (strcmp(name, binkey) == 0)
+ verify_binary(unpacked, name, type, binvalue, binsize);
+ else {
+ msg << "Unexpected key :'" << name << "'";
+ ATF_FAIL(msg.str().c_str());
+ }
+
+ keys_seen.insert(name);
+ }
+
+ /* Ensure that we saw every key. */
+ ATF_REQUIRE_EQ(keys_seen.size(), 5);
+
+ nvlist_destroy(nvl);
+ nvlist_destroy(unpacked);
+ free(packed);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_pack__error_nvlist);
+ATF_TEST_CASE_BODY(nvlist_pack__error_nvlist)
+{
+ nvlist_t *nvl;
+ void *packed;
+ size_t size;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ nvlist_set_error(nvl, ENOMEM);
+
+ packed = nvlist_pack(nvl, &size);
+ ATF_REQUIRE(packed == NULL);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_unpack__duplicate_key);
+ATF_TEST_CASE_BODY(nvlist_unpack__duplicate_key)
+{
+ nvlist_t *nvl, *unpacked;
+ const char *key1, *key2;
+ void *packed, *keypos;
+ size_t size, keylen;
+
+ nvl = nvlist_create(0);
+
+ key1 = "key1";
+ keylen = strlen(key1);
+ nvlist_add_number(nvl, key1, 5);
+
+ key2 = "key2";
+ ATF_REQUIRE_EQ(keylen, strlen(key2));
+ nvlist_add_number(nvl, key2, 10);
+
+ packed = nvlist_pack(nvl, &size);
+
+ /*
+ * Mangle the packed nvlist by replacing key1 with key2, creating a
+ * packed nvlist with a duplicate key.
+ */
+ keypos = memmem(packed, size, key1, keylen);
+ ATF_REQUIRE(keypos != NULL);
+ memcpy(keypos, key2, keylen);
+
+ unpacked = nvlist_unpack(packed, size, 0);
+ ATF_REQUIRE(nvlist_error(unpacked) != 0);
+
+ free(packed);
+ nvlist_destroy(nvl);
+ nvlist_destroy(unpacked);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_move_string__single_insert);
+ATF_TEST_CASE_BODY(nvlist_move_string__single_insert)
+{
+ nvlist_t *nvl;
+ const char *key;
+ char *value;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ key = "testkey";
+ value = strdup("testval");
+ ATF_REQUIRE(value != NULL);
+
+ nvlist_move_string(nvl, key, value);
+ ATF_REQUIRE_EQ(nvlist_get_string(nvl, key), value);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_move_nvlist__null_child);
+ATF_TEST_CASE_BODY(nvlist_move_nvlist__null_child)
+{
+ nvlist_t *parent;
+
+ parent = nvlist_create(0);
+
+ nvlist_move_nvlist(parent, "test", NULL);
+
+ ATF_REQUIRE(nvlist_error(parent) != 0);
+
+ nvlist_destroy(parent);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_move_nvlist__child_with_error);
+ATF_TEST_CASE_BODY(nvlist_move_nvlist__child_with_error)
+{
+ nvlist_t *nvl, *parent;
+
+ nvl = nvlist_create(0);
+ parent = nvlist_create(0);
+
+ nvlist_set_error(nvl, EBADF);
+ nvlist_move_nvlist(parent, "test", nvl);
+ ATF_REQUIRE_EQ(nvlist_error(parent), EBADF);
+
+ nvlist_destroy(parent);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_move_nvlist__single_insert);
+ATF_TEST_CASE_BODY(nvlist_move_nvlist__single_insert)
+{
+ nvlist_t *nvl;
+ const char *key;
+ nvlist_t *value;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ key = "testkey";
+ value = nvlist_create(0);
+ ATF_REQUIRE(value != NULL);
+
+ nvlist_move_nvlist(nvl, key, value);
+ ATF_REQUIRE_EQ(nvlist_get_nvlist(nvl, key), value);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_move_binary__single_insert);
+ATF_TEST_CASE_BODY(nvlist_move_binary__single_insert)
+{
+ nvlist_t *nvl;
+ const char *key;
+ void *value;
+ size_t size, actual_size;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ key = "testkey";
+ size = 73;
+ value = malloc(size);
+ ATF_REQUIRE(value != NULL);
+
+ nvlist_move_binary(nvl, key, value, size);
+ ATF_REQUIRE_EQ(nvlist_get_binary(nvl, key, &actual_size), value);
+ ATF_REQUIRE_EQ(size, actual_size);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_take_bool__single_remove);
+ATF_TEST_CASE_BODY(nvlist_take_bool__single_remove)
+{
+ nvlist_t *nvl;
+ const char *testkey;
+ bool testval;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ testkey = "boolkey";
+ testval = false;
+ nvlist_add_bool(nvl, testkey, testval);
+
+ ATF_REQUIRE_EQ(nvlist_take_bool(nvl, testkey), testval);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_take_bool__other_keys_unchanged);
+ATF_TEST_CASE_BODY(nvlist_take_bool__other_keys_unchanged)
+{
+ nvlist_t *nvl;
+ const char *testkey, *otherkey1, *otherkey2;
+ bool testval, otherval1;
+ nvlist_t *otherval2;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ testkey = "boolkey";
+ testval = true;
+ nvlist_add_bool(nvl, testkey, testval);
+
+ otherkey1 = "key1";
+ otherval1 = false;
+ nvlist_add_bool(nvl, otherkey1, otherval1);
+
+ otherkey2 = "key2";
+ otherval2 = create_test_nvlist();
+ nvlist_move_nvlist(nvl, otherkey2, otherval2);
+
+ ATF_REQUIRE_EQ(nvlist_take_bool(nvl, testkey), testval);
+
+ ATF_REQUIRE(nvlist_exists_bool(nvl, otherkey1));
+ ATF_REQUIRE_EQ(nvlist_get_bool(nvl, otherkey1), otherval1);
+
+ ATF_REQUIRE(nvlist_exists_nvlist(nvl, otherkey2));
+ verify_test_nvlist(nvlist_get_nvlist(nvl, otherkey2));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_take_number__single_remove);
+ATF_TEST_CASE_BODY(nvlist_take_number__single_remove)
+{
+ nvlist_t *nvl;
+ const char *testkey;
+ uint64_t testval;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ testkey = "numkey";
+ testval = std::numeric_limits<uint64_t>::max();
+ nvlist_add_number(nvl, testkey, testval);
+
+ ATF_REQUIRE_EQ(nvlist_take_number(nvl, testkey), testval);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_take_number__other_keys_unchanged);
+ATF_TEST_CASE_BODY(nvlist_take_number__other_keys_unchanged)
+{
+ nvlist_t *nvl;
+ const char *testkey, *otherkey1, *otherkey2;
+ uint64_t testval, otherval1;
+ const char *otherval2;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ otherkey1 = "key1";
+ otherval1 = 5;
+ nvlist_add_number(nvl, otherkey1, otherval1);
+
+ testkey = "numkey";
+ testval = 1654;
+ nvlist_add_number(nvl, testkey, testval);
+
+ otherkey2 = "key2";
+ otherval2 = "string";
+ nvlist_add_string(nvl, otherkey2, otherval2);
+
+ ATF_REQUIRE_EQ(nvlist_take_number(nvl, testkey), testval);
+
+ ATF_REQUIRE(nvlist_exists_number(nvl, otherkey1));
+ ATF_REQUIRE_EQ(nvlist_get_number(nvl, otherkey1), otherval1);
+
+ ATF_REQUIRE(nvlist_exists_string(nvl, otherkey2));
+ ATF_REQUIRE_EQ(strcmp(nvlist_get_string(nvl, otherkey2), otherval2), 0);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_take_string__single_remove);
+ATF_TEST_CASE_BODY(nvlist_take_string__single_remove)
+{
+ nvlist_t *nvl;
+ const char *testkey;
+ const char *testval;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ testkey = "numkey";
+ testval = "nvlist";
+ nvlist_add_string(nvl, testkey, testval);
+
+ ATF_REQUIRE_EQ(strcmp(nvlist_take_string(nvl, testkey), testval), 0);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_take_string__other_keys_unchanged);
+ATF_TEST_CASE_BODY(nvlist_take_string__other_keys_unchanged)
+{
+ nvlist_t *nvl;
+ const char *testkey, *otherkey1, *otherkey2;
+ const char *testval, *otherval1;
+ bool otherval2;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ otherkey1 = "key1";
+ otherval1 = "fjdifjdk";
+ nvlist_add_string(nvl, otherkey1, otherval1);
+
+ otherkey2 = "key2";
+ otherval2 = true;
+ nvlist_add_bool(nvl, otherkey2, otherval2);
+
+ testkey = "strkey";
+ testval = "1654";
+ nvlist_add_string(nvl, testkey, testval);
+
+ ATF_REQUIRE_EQ(strcmp(nvlist_take_string(nvl, testkey), testval), 0);
+
+ ATF_REQUIRE(nvlist_exists_string(nvl, otherkey1));
+ ATF_REQUIRE_EQ(strcmp(nvlist_get_string(nvl, otherkey1), otherval1), 0);
+
+ ATF_REQUIRE(nvlist_exists_bool(nvl, otherkey2));
+ ATF_REQUIRE_EQ(nvlist_get_bool(nvl, otherkey2), otherval2);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_take_nvlist__single_remove);
+ATF_TEST_CASE_BODY(nvlist_take_nvlist__single_remove)
+{
+ nvlist_t *nvl;
+ const char *testkey;
+ nvlist_t *testval;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ testkey = "numkey";
+ testval = create_test_nvlist();
+ nvlist_move_nvlist(nvl, testkey, testval);
+
+ verify_test_nvlist(nvlist_take_nvlist(nvl, testkey));
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_take_nvlist__other_keys_unchanged);
+ATF_TEST_CASE_BODY(nvlist_take_nvlist__other_keys_unchanged)
+{
+ nvlist_t *nvl;
+ const char *testkey, *otherkey1, *otherkey2;
+ nvlist_t *testval, *otherval1;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ testkey = "strkey";
+ testval = create_test_nvlist();
+ nvlist_move_nvlist(nvl, testkey, testval);
+
+ otherkey1 = "key1";
+ otherval1 = nvlist_create(0);
+ nvlist_move_nvlist(nvl, otherkey1, otherval1);
+
+ otherkey2 = "key2";
+ nvlist_add_null(nvl, otherkey2);
+
+ verify_test_nvlist(nvlist_take_nvlist(nvl, testkey));
+
+ ATF_REQUIRE(nvlist_exists_nvlist(nvl, otherkey1));
+ ATF_REQUIRE(nvlist_empty(nvlist_get_nvlist(nvl, otherkey1)));
+
+ ATF_REQUIRE(nvlist_exists_null(nvl, otherkey2));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_take_binary__single_remove);
+ATF_TEST_CASE_BODY(nvlist_take_binary__single_remove)
+{
+ nvlist_t *nvl;
+ const char *testkey;
+ void *testval;
+ const void *actual_val;
+ size_t testsize, actual_size;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ testkey = "numkey";
+ testsize = 457;
+ testval = malloc(testsize);
+ memset(testval, '5', testsize);
+ nvlist_move_binary(nvl, testkey, testval, testsize);
+
+ actual_val = nvlist_take_binary(nvl, testkey, &actual_size);
+ ATF_REQUIRE_EQ(testsize, actual_size);
+ ATF_REQUIRE_EQ(memcmp(actual_val, testval, testsize), 0);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_take_binary__other_keys_unchanged);
+ATF_TEST_CASE_BODY(nvlist_take_binary__other_keys_unchanged)
+{
+ nvlist_t *nvl;
+ const char *testkey, *otherkey1, *otherkey2;
+ const void *actual_value;
+ char testval[] = "gjiertj";
+ char otherval1[] = "fdreg";
+ size_t testsize, othersize, actual_size;
+ bool otherval2;
+
+ nvl = nvlist_create(0);
+ ATF_REQUIRE(nvl != NULL);
+
+ otherkey1 = "key1";
+ othersize = sizeof(otherval1);
+ nvlist_add_binary(nvl, otherkey1, otherval1, othersize);
+
+ otherkey2 = "key2";
+ otherval2 = true;
+ nvlist_add_bool(nvl, otherkey2, otherval2);
+
+ testkey = "strkey";
+ testsize = sizeof(testval);
+ nvlist_add_binary(nvl, testkey, testval, testsize);
+
+ actual_value = nvlist_take_binary(nvl, testkey, &actual_size);
+ ATF_REQUIRE_EQ(testsize, actual_size);
+ ATF_REQUIRE_EQ(memcmp(actual_value, testval, testsize), 0);
+
+ ATF_REQUIRE(nvlist_exists_binary(nvl, otherkey1));
+ actual_value = nvlist_get_binary(nvl, otherkey1, &actual_size);
+ ATF_REQUIRE_EQ(othersize, actual_size);
+ ATF_REQUIRE_EQ(memcmp(actual_value, otherval1, othersize), 0);
+
+ ATF_REQUIRE(nvlist_exists_bool(nvl, otherkey2));
+ ATF_REQUIRE_EQ(nvlist_get_bool(nvl, otherkey2), otherval2);
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_free__single_null);
+ATF_TEST_CASE_BODY(nvlist_free__single_null)
+{
+ nvlist_t *nvl;
+ const char *key;
+
+ nvl = nvlist_create(0);
+ key = "test";
+ nvlist_add_null(nvl, key);
+
+ nvlist_free(nvl, key);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_free__single_bool);
+ATF_TEST_CASE_BODY(nvlist_free__single_bool)
+{
+ nvlist_t *nvl;
+ const char *key;
+
+ nvl = nvlist_create(0);
+ key = "test";
+ nvlist_add_bool(nvl, key, true);
+
+ nvlist_free(nvl, key);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_free__single_number);
+ATF_TEST_CASE_BODY(nvlist_free__single_number)
+{
+ nvlist_t *nvl;
+ const char *key;
+
+ nvl = nvlist_create(0);
+ key = "test";
+ nvlist_add_number(nvl, key, 584);
+
+ nvlist_free(nvl, key);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_free__single_string);
+ATF_TEST_CASE_BODY(nvlist_free__single_string)
+{
+ nvlist_t *nvl;
+ const char *key;
+
+ nvl = nvlist_create(0);
+ key = "test";
+ nvlist_add_string(nvl, key, "gjkfkjd");
+
+ nvlist_free(nvl, key);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_free__single_nvlist);
+ATF_TEST_CASE_BODY(nvlist_free__single_nvlist)
+{
+ nvlist_t *nvl;
+ const char *key;
+
+ nvl = nvlist_create(0);
+ key = "test";
+ nvlist_add_nvlist(nvl, key, nvlist_create(0));
+
+ nvlist_free(nvl, key);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_free__single_binary);
+ATF_TEST_CASE_BODY(nvlist_free__single_binary)
+{
+ nvlist_t *nvl;
+ const char *key;
+
+ nvl = nvlist_create(0);
+ key = "test";
+ nvlist_add_binary(nvl, key, "jgjgfd", 6);
+
+ nvlist_free(nvl, key);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_free_null__single_null);
+ATF_TEST_CASE_BODY(nvlist_free_null__single_null)
+{
+ nvlist_t *nvl;
+ const char *key;
+
+ nvl = nvlist_create(0);
+ key = "test";
+ nvlist_add_null(nvl, key);
+
+ nvlist_free_null(nvl, key);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_free_bool__single_bool);
+ATF_TEST_CASE_BODY(nvlist_free_bool__single_bool)
+{
+ nvlist_t *nvl;
+ const char *key;
+
+ nvl = nvlist_create(0);
+ key = "test";
+ nvlist_add_bool(nvl, key, true);
+
+ nvlist_free_bool(nvl, key);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_free_number__single_number);
+ATF_TEST_CASE_BODY(nvlist_free_number__single_number)
+{
+ nvlist_t *nvl;
+ const char *key;
+
+ nvl = nvlist_create(0);
+ key = "test";
+ nvlist_add_number(nvl, key, 584);
+
+ nvlist_free_number(nvl, key);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_free_string__single_string);
+ATF_TEST_CASE_BODY(nvlist_free_string__single_string)
+{
+ nvlist_t *nvl;
+ const char *key;
+
+ nvl = nvlist_create(0);
+ key = "test";
+ nvlist_add_string(nvl, key, "gjkfkjd");
+
+ nvlist_free_string(nvl, key);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_free_nvlist__single_nvlist);
+ATF_TEST_CASE_BODY(nvlist_free_nvlist__single_nvlist)
+{
+ nvlist_t *nvl;
+ const char *key;
+
+ nvl = nvlist_create(0);
+ key = "test";
+ nvlist_add_nvlist(nvl, key, nvlist_create(0));
+
+ nvlist_free_nvlist(nvl, key);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_TEST_CASE_WITHOUT_HEAD(nvlist_free_binary__single_binary);
+ATF_TEST_CASE_BODY(nvlist_free_binary__single_binary)
+{
+ nvlist_t *nvl;
+ const char *key;
+
+ nvl = nvlist_create(0);
+ key = "test";
+ nvlist_add_binary(nvl, key, "jgjgfd", 6);
+
+ nvlist_free_binary(nvl, key);
+ ATF_REQUIRE(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+}
+
+ATF_INIT_TEST_CASES(tp)
+{
+ ATF_ADD_TEST_CASE(tp, nvlist_create__is_empty);
+ ATF_ADD_TEST_CASE(tp, nvlist_add_null__single_insert);
+ ATF_ADD_TEST_CASE(tp, nvlist_add_bool__single_insert);
+ ATF_ADD_TEST_CASE(tp, nvlist_add_number__single_insert);
+ ATF_ADD_TEST_CASE(tp, nvlist_add_string__single_insert);
+ ATF_ADD_TEST_CASE(tp, nvlist_add_nvlist__single_insert);
+ ATF_ADD_TEST_CASE(tp, nvlist_add_nvlist__child_with_error);
+ ATF_ADD_TEST_CASE(tp, nvlist_add_binary__single_insert);
+
+ ATF_ADD_TEST_CASE(tp, nvlist_clone__empty_nvlist);
+ ATF_ADD_TEST_CASE(tp, nvlist_clone__nonempty_nvlist);
+ ATF_ADD_TEST_CASE(tp, nvlist_clone__nested_nvlist);
+ ATF_ADD_TEST_CASE(tp, nvlist_clone__error_nvlist);
+
+ ATF_ADD_TEST_CASE(tp, nvlist_pack__empty_nvlist);
+ ATF_ADD_TEST_CASE(tp, nvlist_pack__multiple_values);
+ ATF_ADD_TEST_CASE(tp, nvlist_pack__error_nvlist);
+ ATF_ADD_TEST_CASE(tp, nvlist_unpack__duplicate_key);
+ ATF_ADD_TEST_CASE(tp, nvlist_unpack__flags_nvlist);
+
+ ATF_ADD_TEST_CASE(tp, nvlist_move_string__single_insert);
+ ATF_ADD_TEST_CASE(tp, nvlist_move_nvlist__single_insert);
+ ATF_ADD_TEST_CASE(tp, nvlist_move_nvlist__null_child);
+ ATF_ADD_TEST_CASE(tp, nvlist_move_nvlist__child_with_error);
+ ATF_ADD_TEST_CASE(tp, nvlist_move_binary__single_insert);
+
+ ATF_ADD_TEST_CASE(tp, nvlist_take_bool__single_remove);
+ ATF_ADD_TEST_CASE(tp, nvlist_take_bool__other_keys_unchanged);
+ ATF_ADD_TEST_CASE(tp, nvlist_take_number__single_remove);
+ ATF_ADD_TEST_CASE(tp, nvlist_take_number__other_keys_unchanged);
+ ATF_ADD_TEST_CASE(tp, nvlist_take_string__single_remove);
+ ATF_ADD_TEST_CASE(tp, nvlist_take_string__other_keys_unchanged);
+ ATF_ADD_TEST_CASE(tp, nvlist_take_nvlist__single_remove);
+ ATF_ADD_TEST_CASE(tp, nvlist_take_nvlist__other_keys_unchanged);
+ ATF_ADD_TEST_CASE(tp, nvlist_take_binary__single_remove);
+ ATF_ADD_TEST_CASE(tp, nvlist_take_binary__other_keys_unchanged);
+
+ ATF_ADD_TEST_CASE(tp, nvlist_free__single_null);
+ ATF_ADD_TEST_CASE(tp, nvlist_free__single_bool);
+ ATF_ADD_TEST_CASE(tp, nvlist_free__single_number);
+ ATF_ADD_TEST_CASE(tp, nvlist_free__single_string);
+ ATF_ADD_TEST_CASE(tp, nvlist_free__single_nvlist);
+ ATF_ADD_TEST_CASE(tp, nvlist_free__single_binary);
+
+ ATF_ADD_TEST_CASE(tp, nvlist_free_null__single_null);
+ ATF_ADD_TEST_CASE(tp, nvlist_free_bool__single_bool);
+ ATF_ADD_TEST_CASE(tp, nvlist_free_number__single_number);
+ ATF_ADD_TEST_CASE(tp, nvlist_free_string__single_string);
+ ATF_ADD_TEST_CASE(tp, nvlist_free_nvlist__single_nvlist);
+ ATF_ADD_TEST_CASE(tp, nvlist_free_binary__single_binary);
+}
Index: lib/libnv/tests/nvlist_add_test.c
===================================================================
--- /dev/null
+++ lib/libnv/tests/nvlist_add_test.c
@@ -0,0 +1,196 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: head/lib/libnv/tests/nvlist_add_test.c 285063 2015-07-02 21:58:10Z oshogbo $
+ */
+
+#include <sys/nv.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+static int ntest = 1;
+
+#define CHECK(expr) do { \
+ if ((expr)) \
+ printf("ok # %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ else \
+ printf("not ok # %d %s:%u\n", ntest, __FILE__, __LINE__);\
+ ntest++; \
+} while (0)
+
+int
+main(void)
+{
+ const nvlist_t *cnvl;
+ nvlist_t *nvl;
+
+ printf("1..94\n");
+
+ nvl = nvlist_create(0);
+
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ nvlist_add_null(nvl, "nvlist/null");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_null(nvl, "nvlist/null"));
+
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool/true"));
+ nvlist_add_bool(nvl, "nvlist/bool/true", true);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool/true"));
+
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool/false"));
+ nvlist_add_bool(nvl, "nvlist/bool/false", false);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool/false"));
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/0"));
+ nvlist_add_number(nvl, "nvlist/number/0", 0);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/0"));
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/1"));
+ nvlist_add_number(nvl, "nvlist/number/1", 1);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/1"));
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/-1"));
+ nvlist_add_number(nvl, "nvlist/number/-1", -1);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/-1"));
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/UINT64_MAX"));
+ nvlist_add_number(nvl, "nvlist/number/UINT64_MAX", UINT64_MAX);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/UINT64_MAX"));
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/INT64_MIN"));
+ nvlist_add_number(nvl, "nvlist/number/INT64_MIN", INT64_MIN);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/INT64_MIN"));
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/INT64_MAX"));
+ nvlist_add_number(nvl, "nvlist/number/INT64_MAX", INT64_MAX);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/INT64_MAX"));
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string/"));
+ nvlist_add_string(nvl, "nvlist/string/", "");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/"));
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string/x"));
+ nvlist_add_string(nvl, "nvlist/string/x", "x");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/x"));
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+ nvlist_add_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/stringf/"));
+ nvlist_add_stringf(nvl, "nvlist/stringf/", "%s", "");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_string(nvl, "nvlist/stringf/"));
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/stringf/x"));
+ nvlist_add_stringf(nvl, "nvlist/stringf/x", "%s", "x");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_string(nvl, "nvlist/stringf/x"));
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/stringf/666Xabc"));
+ nvlist_add_stringf(nvl, "nvlist/stringf/666Xabc", "%d%c%s", 666, 'X', "abc");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_string(nvl, "nvlist/stringf/666Xabc"));
+
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO"));
+ nvlist_add_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO", STDERR_FILENO);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO"));
+
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/binary/x"));
+ nvlist_add_binary(nvl, "nvlist/binary/x", "x", 1);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary/x"));
+
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz"));
+ nvlist_add_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz"));
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz"));
+
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ nvlist_add_nvlist(nvl, "nvlist/nvlist", nvl);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+
+ CHECK(nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool/true"));
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool/false"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/0"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/1"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/-1"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/UINT64_MAX"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/INT64_MIN"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/INT64_MAX"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/x"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/stringf/"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/stringf/x"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/stringf/666Xabc"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary/x"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+
+ cnvl = nvlist_get_nvlist(nvl, "nvlist/nvlist");
+ CHECK(nvlist_exists_null(cnvl, "nvlist/null"));
+ CHECK(nvlist_exists_bool(cnvl, "nvlist/bool/true"));
+ CHECK(nvlist_exists_bool(cnvl, "nvlist/bool/false"));
+ CHECK(nvlist_exists_number(cnvl, "nvlist/number/0"));
+ CHECK(nvlist_exists_number(cnvl, "nvlist/number/1"));
+ CHECK(nvlist_exists_number(cnvl, "nvlist/number/-1"));
+ CHECK(nvlist_exists_number(cnvl, "nvlist/number/UINT64_MAX"));
+ CHECK(nvlist_exists_number(cnvl, "nvlist/number/INT64_MIN"));
+ CHECK(nvlist_exists_number(cnvl, "nvlist/number/INT64_MAX"));
+ CHECK(nvlist_exists_string(cnvl, "nvlist/string/"));
+ CHECK(nvlist_exists_string(cnvl, "nvlist/string/x"));
+ CHECK(nvlist_exists_string(cnvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+ CHECK(nvlist_exists_string(cnvl, "nvlist/stringf/"));
+ CHECK(nvlist_exists_string(cnvl, "nvlist/stringf/x"));
+ CHECK(nvlist_exists_string(cnvl, "nvlist/stringf/666Xabc"));
+ CHECK(nvlist_exists_descriptor(cnvl, "nvlist/descriptor/STDERR_FILENO"));
+ CHECK(nvlist_exists_binary(cnvl, "nvlist/binary/x"));
+ CHECK(nvlist_exists_binary(cnvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz"));
+
+ nvlist_destroy(nvl);
+
+ return (0);
+}
Index: lib/libnv/tests/nvlist_exists_test.c
===================================================================
--- /dev/null
+++ lib/libnv/tests/nvlist_exists_test.c
@@ -0,0 +1,321 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: head/lib/libnv/tests/nvlist_exists_test.c 285063 2015-07-02 21:58:10Z oshogbo $
+ */
+
+#include <sys/nv.h>
+
+#include <stdio.h>
+#include <unistd.h>
+
+static int ntest = 1;
+
+#define CHECK(expr) do { \
+ if ((expr)) \
+ printf("ok # %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ else \
+ printf("not ok # %d %s:%u\n", ntest, __FILE__, __LINE__);\
+ ntest++; \
+} while (0)
+
+int
+main(void)
+{
+ nvlist_t *nvl;
+
+ printf("1..232\n");
+
+ nvl = nvlist_create(0);
+
+ CHECK(!nvlist_exists(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/null"));
+ nvlist_add_null(nvl, "nvlist/null");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists(nvl, "nvlist/null"));
+ CHECK(nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/null"));
+
+ CHECK(!nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/bool"));
+ nvlist_add_bool(nvl, "nvlist/bool", true);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/bool"));
+
+ CHECK(!nvlist_exists(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/number"));
+ nvlist_add_number(nvl, "nvlist/number", 0);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/number"));
+
+ CHECK(!nvlist_exists(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/string"));
+ nvlist_add_string(nvl, "nvlist/string", "test");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/string"));
+
+ CHECK(!nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/nvlist"));
+ nvlist_add_nvlist(nvl, "nvlist/nvlist", nvl);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/nvlist"));
+
+ CHECK(!nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/descriptor"));
+ nvlist_add_descriptor(nvl, "nvlist/descriptor", STDERR_FILENO);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/descriptor"));
+
+ CHECK(!nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/binary"));
+ nvlist_add_binary(nvl, "nvlist/binary", "test", 4);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/binary"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ CHECK(nvlist_exists(nvl, "nvlist/null"));
+ CHECK(nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists(nvl, "nvlist/number"));
+ CHECK(nvlist_exists(nvl, "nvlist/string"));
+ CHECK(nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_null(nvl, "nvlist/null");
+ CHECK(!nvlist_exists(nvl, "nvlist/null"));
+ CHECK(nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists(nvl, "nvlist/number"));
+ CHECK(nvlist_exists(nvl, "nvlist/string"));
+ CHECK(nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_bool(nvl, "nvlist/bool");
+ CHECK(!nvlist_exists(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists(nvl, "nvlist/number"));
+ CHECK(nvlist_exists(nvl, "nvlist/string"));
+ CHECK(nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_number(nvl, "nvlist/number");
+ CHECK(!nvlist_exists(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists(nvl, "nvlist/number"));
+ CHECK(nvlist_exists(nvl, "nvlist/string"));
+ CHECK(nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_string(nvl, "nvlist/string");
+ CHECK(!nvlist_exists(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists(nvl, "nvlist/string"));
+ CHECK(nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_nvlist(nvl, "nvlist/nvlist");
+ CHECK(!nvlist_exists(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_descriptor(nvl, "nvlist/descriptor");
+ CHECK(!nvlist_exists(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_binary(nvl, "nvlist/binary");
+ CHECK(!nvlist_exists(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ CHECK(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+
+ return (0);
+}
Index: lib/libnv/tests/nvlist_free_test.c
===================================================================
--- /dev/null
+++ lib/libnv/tests/nvlist_free_test.c
@@ -0,0 +1,221 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: head/lib/libnv/tests/nvlist_free_test.c 285063 2015-07-02 21:58:10Z oshogbo $
+ */
+
+#include <sys/nv.h>
+
+#include <stdio.h>
+#include <unistd.h>
+
+static int ntest = 1;
+
+#define CHECK(expr) do { \
+ if ((expr)) \
+ printf("ok # %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ else \
+ printf("not ok # %d %s:%u\n", ntest, __FILE__, __LINE__);\
+ ntest++; \
+} while (0)
+
+int
+main(void)
+{
+ nvlist_t *nvl;
+
+ printf("1..114\n");
+
+ nvl = nvlist_create(0);
+
+ nvlist_add_null(nvl, "nvlist/null");
+ nvlist_add_bool(nvl, "nvlist/bool", true);
+ nvlist_add_number(nvl, "nvlist/number", 0);
+ nvlist_add_string(nvl, "nvlist/string", "test");
+ nvlist_add_nvlist(nvl, "nvlist/nvlist", nvl);
+ nvlist_add_descriptor(nvl, "nvlist/descriptor", STDERR_FILENO);
+ nvlist_add_binary(nvl, "nvlist/binary", "test", 4);
+
+ CHECK(nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_null(nvl, "nvlist/null");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_bool(nvl, "nvlist/bool");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_number(nvl, "nvlist/number");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_string(nvl, "nvlist/string");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_nvlist(nvl, "nvlist/nvlist");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_descriptor(nvl, "nvlist/descriptor");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_binary(nvl, "nvlist/binary");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ CHECK(nvlist_empty(nvl));
+
+ nvlist_add_null(nvl, "nvlist/null");
+ nvlist_add_bool(nvl, "nvlist/bool", true);
+ nvlist_add_number(nvl, "nvlist/number", 0);
+ nvlist_add_string(nvl, "nvlist/string", "test");
+ nvlist_add_nvlist(nvl, "nvlist/nvlist", nvl);
+ nvlist_add_descriptor(nvl, "nvlist/descriptor", STDERR_FILENO);
+ nvlist_add_binary(nvl, "nvlist/binary", "test", 4);
+
+ CHECK(nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free(nvl, "nvlist/null");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free(nvl, "nvlist/bool");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free(nvl, "nvlist/number");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free(nvl, "nvlist/string");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free(nvl, "nvlist/nvlist");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free(nvl, "nvlist/descriptor");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free(nvl, "nvlist/binary");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ CHECK(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+
+ return (0);
+}
Index: lib/libnv/tests/nvlist_get_test.c
===================================================================
--- /dev/null
+++ lib/libnv/tests/nvlist_get_test.c
@@ -0,0 +1,181 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: head/lib/libnv/tests/nvlist_get_test.c 285063 2015-07-02 21:58:10Z oshogbo $
+ */
+#include <sys/nv.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+static int ntest = 1;
+
+#define CHECK(expr) do { \
+ if ((expr)) \
+ printf("ok # %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ else \
+ printf("not ok # %d %s:%u\n", ntest, __FILE__, __LINE__);\
+ ntest++; \
+} while (0)
+
+#define fd_is_valid(fd) (fcntl((fd), F_GETFL) != -1 || errno != EBADF)
+
+int
+main(void)
+{
+ const nvlist_t *cnvl;
+ nvlist_t *nvl;
+ size_t size;
+
+ printf("1..83\n");
+
+ nvl = nvlist_create(0);
+
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool/true"));
+ nvlist_add_bool(nvl, "nvlist/bool/true", true);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_get_bool(nvl, "nvlist/bool/true") == true);
+
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool/false"));
+ nvlist_add_bool(nvl, "nvlist/bool/false", false);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_get_bool(nvl, "nvlist/bool/false") == false);
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/0"));
+ nvlist_add_number(nvl, "nvlist/number/0", 0);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_get_number(nvl, "nvlist/number/0") == 0);
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/1"));
+ nvlist_add_number(nvl, "nvlist/number/1", 1);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_get_number(nvl, "nvlist/number/1") == 1);
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/-1"));
+ nvlist_add_number(nvl, "nvlist/number/-1", -1);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK((int)nvlist_get_number(nvl, "nvlist/number/-1") == -1);
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/UINT64_MAX"));
+ nvlist_add_number(nvl, "nvlist/number/UINT64_MAX", UINT64_MAX);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_get_number(nvl, "nvlist/number/UINT64_MAX") == UINT64_MAX);
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/INT64_MIN"));
+ nvlist_add_number(nvl, "nvlist/number/INT64_MIN", INT64_MIN);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK((int64_t)nvlist_get_number(nvl, "nvlist/number/INT64_MIN") == INT64_MIN);
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/INT64_MAX"));
+ nvlist_add_number(nvl, "nvlist/number/INT64_MAX", INT64_MAX);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK((int64_t)nvlist_get_number(nvl, "nvlist/number/INT64_MAX") == INT64_MAX);
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string/"));
+ nvlist_add_string(nvl, "nvlist/string/", "");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(strcmp(nvlist_get_string(nvl, "nvlist/string/"), "") == 0);
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string/x"));
+ nvlist_add_string(nvl, "nvlist/string/x", "x");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(strcmp(nvlist_get_string(nvl, "nvlist/string/x"), "x") == 0);
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+ nvlist_add_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(strcmp(nvlist_get_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz"), "abcdefghijklmnopqrstuvwxyz") == 0);
+
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO"));
+ nvlist_add_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO", STDERR_FILENO);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(fd_is_valid(nvlist_get_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO")));
+
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/binary/x"));
+ nvlist_add_binary(nvl, "nvlist/binary/x", "x", 1);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, "nvlist/binary/x", NULL), "x", 1) == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, "nvlist/binary/x", &size), "x", 1) == 0);
+ CHECK(size == 1);
+
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz"));
+ nvlist_add_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz"));
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz", NULL), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz", &size), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(size == sizeof("abcdefghijklmnopqrstuvwxyz"));
+
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ nvlist_add_nvlist(nvl, "nvlist/nvlist", nvl);
+ CHECK(nvlist_error(nvl) == 0);
+ cnvl = nvlist_get_nvlist(nvl, "nvlist/nvlist");
+ CHECK(nvlist_get_bool(cnvl, "nvlist/bool/true") == true);
+ CHECK(nvlist_get_bool(cnvl, "nvlist/bool/false") == false);
+ CHECK(nvlist_get_number(cnvl, "nvlist/number/0") == 0);
+ CHECK(nvlist_get_number(cnvl, "nvlist/number/1") == 1);
+ CHECK((int)nvlist_get_number(cnvl, "nvlist/number/-1") == -1);
+ CHECK(nvlist_get_number(cnvl, "nvlist/number/UINT64_MAX") == UINT64_MAX);
+ CHECK((int64_t)nvlist_get_number(cnvl, "nvlist/number/INT64_MIN") == INT64_MIN);
+ CHECK((int64_t)nvlist_get_number(cnvl, "nvlist/number/INT64_MAX") == INT64_MAX);
+ CHECK(strcmp(nvlist_get_string(cnvl, "nvlist/string/"), "") == 0);
+ CHECK(strcmp(nvlist_get_string(cnvl, "nvlist/string/x"), "x") == 0);
+ CHECK(strcmp(nvlist_get_string(cnvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz"), "abcdefghijklmnopqrstuvwxyz") == 0);
+ /* TODO */
+ CHECK(memcmp(nvlist_get_binary(cnvl, "nvlist/binary/x", NULL), "x", 1) == 0);
+ CHECK(memcmp(nvlist_get_binary(cnvl, "nvlist/binary/x", &size), "x", 1) == 0);
+ CHECK(size == 1);
+ CHECK(memcmp(nvlist_get_binary(cnvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz", NULL), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(memcmp(nvlist_get_binary(cnvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz", &size), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(size == sizeof("abcdefghijklmnopqrstuvwxyz"));
+
+ CHECK(nvlist_get_bool(nvl, "nvlist/bool/true") == true);
+ CHECK(nvlist_get_bool(nvl, "nvlist/bool/false") == false);
+ CHECK(nvlist_get_number(nvl, "nvlist/number/0") == 0);
+ CHECK(nvlist_get_number(nvl, "nvlist/number/1") == 1);
+ CHECK((int)nvlist_get_number(nvl, "nvlist/number/-1") == -1);
+ CHECK(nvlist_get_number(nvl, "nvlist/number/UINT64_MAX") == UINT64_MAX);
+ CHECK((int64_t)nvlist_get_number(nvl, "nvlist/number/INT64_MIN") == INT64_MIN);
+ CHECK((int64_t)nvlist_get_number(nvl, "nvlist/number/INT64_MAX") == INT64_MAX);
+ CHECK(strcmp(nvlist_get_string(nvl, "nvlist/string/"), "") == 0);
+ CHECK(strcmp(nvlist_get_string(nvl, "nvlist/string/x"), "x") == 0);
+ CHECK(strcmp(nvlist_get_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz"), "abcdefghijklmnopqrstuvwxyz") == 0);
+ CHECK(fd_is_valid(nvlist_get_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO")));
+ CHECK(memcmp(nvlist_get_binary(nvl, "nvlist/binary/x", NULL), "x", 1) == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, "nvlist/binary/x", &size), "x", 1) == 0);
+ CHECK(size == 1);
+ CHECK(memcmp(nvlist_get_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz", NULL), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz", &size), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(size == sizeof("abcdefghijklmnopqrstuvwxyz"));
+
+ nvlist_destroy(nvl);
+
+ return (0);
+}
Index: lib/libnv/tests/nvlist_move_test.c
===================================================================
--- /dev/null
+++ lib/libnv/tests/nvlist_move_test.c
@@ -0,0 +1,161 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: head/lib/libnv/tests/nvlist_move_test.c 285063 2015-07-02 21:58:10Z oshogbo $
+ */
+
+#include <sys/nv.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static int ntest = 1;
+
+#define CHECK(expr) do { \
+ if ((expr)) \
+ printf("ok # %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ else \
+ printf("not ok # %d %s:%u\n", ntest, __FILE__, __LINE__);\
+ ntest++; \
+} while (0)
+
+int
+main(void)
+{
+ const nvlist_t *cnvl;
+ nvlist_t *nvl;
+ void *ptr;
+ size_t size;
+ int fd;
+
+ printf("1..52\n");
+
+ nvl = nvlist_create(0);
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string/"));
+ ptr = strdup("");
+ CHECK(ptr != NULL);
+ nvlist_move_string(nvl, "nvlist/string/", ptr);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/"));
+ CHECK(ptr == nvlist_get_string(nvl, "nvlist/string/"));
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string/x"));
+ ptr = strdup("x");
+ CHECK(ptr != NULL);
+ nvlist_move_string(nvl, "nvlist/string/x", ptr);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/x"));
+ CHECK(ptr == nvlist_get_string(nvl, "nvlist/string/x"));
+
+ CHECK(!nvlist_exists_string(nvl,
+ "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+ ptr = strdup("abcdefghijklmnopqrstuvwxyz");
+ CHECK(ptr != NULL);
+ nvlist_move_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz",
+ ptr);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_string(nvl,
+ "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+ CHECK(ptr ==
+ nvlist_get_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+
+ CHECK(!nvlist_exists_descriptor(nvl,
+ "nvlist/descriptor/STDERR_FILENO"));
+ fd = dup(STDERR_FILENO);
+ CHECK(fd >= 0);
+ nvlist_move_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO", fd);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO"));
+ CHECK(fd ==
+ nvlist_get_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO"));
+
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/binary/x"));
+ ptr = malloc(1);
+ CHECK(ptr != NULL);
+ memcpy(ptr, "x", 1);
+ nvlist_move_binary(nvl, "nvlist/binary/x", ptr, 1);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary/x"));
+ CHECK(ptr == nvlist_get_binary(nvl, "nvlist/binary/x", NULL));
+ CHECK(ptr == nvlist_get_binary(nvl, "nvlist/binary/x", &size));
+ CHECK(size == 1);
+
+ CHECK(!nvlist_exists_binary(nvl,
+ "nvlist/binary/abcdefghijklmnopqrstuvwxyz"));
+ ptr = malloc(sizeof("abcdefghijklmnopqrstuvwxyz"));
+ CHECK(ptr != NULL);
+ memcpy(ptr, "abcdefghijklmnopqrstuvwxyz",
+ sizeof("abcdefghijklmnopqrstuvwxyz"));
+ nvlist_move_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz",
+ ptr, sizeof("abcdefghijklmnopqrstuvwxyz"));
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_binary(nvl,
+ "nvlist/binary/abcdefghijklmnopqrstuvwxyz"));
+ CHECK(ptr == nvlist_get_binary(nvl,
+ "nvlist/binary/abcdefghijklmnopqrstuvwxyz", NULL));
+ CHECK(ptr == nvlist_get_binary(nvl,
+ "nvlist/binary/abcdefghijklmnopqrstuvwxyz", &size));
+ CHECK(size == sizeof("abcdefghijklmnopqrstuvwxyz"));
+
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ ptr = nvlist_clone(nvl);
+ CHECK(ptr != NULL);
+ nvlist_move_nvlist(nvl, "nvlist/nvlist", ptr);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(ptr == nvlist_get_nvlist(nvl, "nvlist/nvlist"));
+
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/x"));
+ CHECK(nvlist_exists_string(nvl,
+ "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary/x"));
+ CHECK(nvlist_exists_binary(nvl,
+ "nvlist/binary/abcdefghijklmnopqrstuvwxyz"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+
+ cnvl = nvlist_get_nvlist(nvl, "nvlist/nvlist");
+ CHECK(nvlist_exists_string(cnvl, "nvlist/string/"));
+ CHECK(nvlist_exists_string(cnvl, "nvlist/string/x"));
+ CHECK(nvlist_exists_string(cnvl,
+ "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+ CHECK(nvlist_exists_descriptor(cnvl,
+ "nvlist/descriptor/STDERR_FILENO"));
+ CHECK(nvlist_exists_binary(cnvl, "nvlist/binary/x"));
+ CHECK(nvlist_exists_binary(cnvl,
+ "nvlist/binary/abcdefghijklmnopqrstuvwxyz"));
+
+ nvlist_destroy(nvl);
+
+ return (0);
+}
Index: lib/libnv/tests/nvlist_send_recv_test.c
===================================================================
--- /dev/null
+++ lib/libnv/tests/nvlist_send_recv_test.c
@@ -0,0 +1,341 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: head/lib/libnv/tests/nvlist_send_recv_test.c 285063 2015-07-02 21:58:10Z oshogbo $
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/nv.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+static int ntest = 1;
+
+#define CHECK(expr) do { \
+ if ((expr)) \
+ printf("ok # %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ else \
+ printf("not ok # %d %s:%u\n", ntest, __FILE__, __LINE__);\
+ ntest++; \
+} while (0)
+
+#define fd_is_valid(fd) (fcntl((fd), F_GETFL) != -1 || errno != EBADF)
+
+static void
+child(int sock)
+{
+ nvlist_t *nvl;
+ nvlist_t *empty;
+
+ nvl = nvlist_create(0);
+ empty = nvlist_create(0);
+
+ nvlist_add_bool(nvl, "nvlist/bool/true", true);
+ nvlist_add_bool(nvl, "nvlist/bool/false", false);
+ nvlist_add_number(nvl, "nvlist/number/0", 0);
+ nvlist_add_number(nvl, "nvlist/number/1", 1);
+ nvlist_add_number(nvl, "nvlist/number/-1", -1);
+ nvlist_add_number(nvl, "nvlist/number/UINT64_MAX", UINT64_MAX);
+ nvlist_add_number(nvl, "nvlist/number/INT64_MIN", INT64_MIN);
+ nvlist_add_number(nvl, "nvlist/number/INT64_MAX", INT64_MAX);
+ nvlist_add_string(nvl, "nvlist/string/", "");
+ nvlist_add_string(nvl, "nvlist/string/x", "x");
+ nvlist_add_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz");
+ nvlist_add_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO", STDERR_FILENO);
+ nvlist_add_binary(nvl, "nvlist/binary/x", "x", 1);
+ nvlist_add_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz"));
+ nvlist_move_nvlist(nvl, "nvlist/nvlist/empty", empty);
+ nvlist_add_nvlist(nvl, "nvlist/nvlist", nvl);
+
+ nvlist_send(sock, nvl);
+
+ nvlist_destroy(nvl);
+}
+
+static void
+parent(int sock)
+{
+ nvlist_t *nvl;
+ const nvlist_t *cnvl, *empty;
+ const char *name, *cname;
+ void *cookie, *ccookie;
+ int type, ctype;
+ size_t size;
+
+ nvl = nvlist_recv(sock, 0);
+ CHECK(nvlist_error(nvl) == 0);
+ if (nvlist_error(nvl) != 0)
+ err(1, "nvlist_recv() failed");
+
+ cookie = NULL;
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_BOOL);
+ CHECK(strcmp(name, "nvlist/bool/true") == 0);
+ CHECK(nvlist_get_bool(nvl, name) == true);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_BOOL);
+ CHECK(strcmp(name, "nvlist/bool/false") == 0);
+ CHECK(nvlist_get_bool(nvl, name) == false);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_NUMBER);
+ CHECK(strcmp(name, "nvlist/number/0") == 0);
+ CHECK(nvlist_get_number(nvl, name) == 0);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_NUMBER);
+ CHECK(strcmp(name, "nvlist/number/1") == 0);
+ CHECK(nvlist_get_number(nvl, name) == 1);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_NUMBER);
+ CHECK(strcmp(name, "nvlist/number/-1") == 0);
+ CHECK((int)nvlist_get_number(nvl, name) == -1);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_NUMBER);
+ CHECK(strcmp(name, "nvlist/number/UINT64_MAX") == 0);
+ CHECK(nvlist_get_number(nvl, name) == UINT64_MAX);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_NUMBER);
+ CHECK(strcmp(name, "nvlist/number/INT64_MIN") == 0);
+ CHECK((int64_t)nvlist_get_number(nvl, name) == INT64_MIN);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_NUMBER);
+ CHECK(strcmp(name, "nvlist/number/INT64_MAX") == 0);
+ CHECK((int64_t)nvlist_get_number(nvl, name) == INT64_MAX);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_STRING);
+ CHECK(strcmp(name, "nvlist/string/") == 0);
+ CHECK(strcmp(nvlist_get_string(nvl, name), "") == 0);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_STRING);
+ CHECK(strcmp(name, "nvlist/string/x") == 0);
+ CHECK(strcmp(nvlist_get_string(nvl, name), "x") == 0);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_STRING);
+ CHECK(strcmp(name, "nvlist/string/abcdefghijklmnopqrstuvwxyz") == 0);
+ CHECK(strcmp(nvlist_get_string(nvl, name), "abcdefghijklmnopqrstuvwxyz") == 0);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_DESCRIPTOR);
+ CHECK(strcmp(name, "nvlist/descriptor/STDERR_FILENO") == 0);
+ CHECK(fd_is_valid(nvlist_get_descriptor(nvl, name)));
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_BINARY);
+ CHECK(strcmp(name, "nvlist/binary/x") == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, name, NULL), "x", 1) == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, name, &size), "x", 1) == 0);
+ CHECK(size == 1);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_BINARY);
+ CHECK(strcmp(name, "nvlist/binary/abcdefghijklmnopqrstuvwxyz") == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, name, NULL), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, name, &size), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(size == sizeof("abcdefghijklmnopqrstuvwxyz"));
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_NVLIST);
+ CHECK(strcmp(name, "nvlist/nvlist/empty") == 0);
+ cnvl = nvlist_get_nvlist(nvl, name);
+ CHECK(nvlist_empty(cnvl));
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_NVLIST);
+ CHECK(strcmp(name, "nvlist/nvlist") == 0);
+ cnvl = nvlist_get_nvlist(nvl, name);
+
+ ccookie = NULL;
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_BOOL);
+ CHECK(strcmp(cname, "nvlist/bool/true") == 0);
+ CHECK(nvlist_get_bool(cnvl, cname) == true);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_BOOL);
+ CHECK(strcmp(cname, "nvlist/bool/false") == 0);
+ CHECK(nvlist_get_bool(cnvl, cname) == false);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_NUMBER);
+ CHECK(strcmp(cname, "nvlist/number/0") == 0);
+ CHECK(nvlist_get_number(cnvl, cname) == 0);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_NUMBER);
+ CHECK(strcmp(cname, "nvlist/number/1") == 0);
+ CHECK(nvlist_get_number(cnvl, cname) == 1);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_NUMBER);
+ CHECK(strcmp(cname, "nvlist/number/-1") == 0);
+ CHECK((int)nvlist_get_number(cnvl, cname) == -1);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_NUMBER);
+ CHECK(strcmp(cname, "nvlist/number/UINT64_MAX") == 0);
+ CHECK(nvlist_get_number(cnvl, cname) == UINT64_MAX);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_NUMBER);
+ CHECK(strcmp(cname, "nvlist/number/INT64_MIN") == 0);
+ CHECK((int64_t)nvlist_get_number(cnvl, cname) == INT64_MIN);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_NUMBER);
+ CHECK(strcmp(cname, "nvlist/number/INT64_MAX") == 0);
+ CHECK((int64_t)nvlist_get_number(cnvl, cname) == INT64_MAX);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_STRING);
+ CHECK(strcmp(cname, "nvlist/string/") == 0);
+ CHECK(strcmp(nvlist_get_string(cnvl, cname), "") == 0);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_STRING);
+ CHECK(strcmp(cname, "nvlist/string/x") == 0);
+ CHECK(strcmp(nvlist_get_string(cnvl, cname), "x") == 0);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_STRING);
+ CHECK(strcmp(cname, "nvlist/string/abcdefghijklmnopqrstuvwxyz") == 0);
+ CHECK(strcmp(nvlist_get_string(cnvl, cname), "abcdefghijklmnopqrstuvwxyz") == 0);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_DESCRIPTOR);
+ CHECK(strcmp(cname, "nvlist/descriptor/STDERR_FILENO") == 0);
+ CHECK(fd_is_valid(nvlist_get_descriptor(cnvl, cname)));
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_BINARY);
+ CHECK(strcmp(cname, "nvlist/binary/x") == 0);
+ CHECK(memcmp(nvlist_get_binary(cnvl, cname, NULL), "x", 1) == 0);
+ CHECK(memcmp(nvlist_get_binary(cnvl, cname, &size), "x", 1) == 0);
+ CHECK(size == 1);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_BINARY);
+ CHECK(strcmp(cname, "nvlist/binary/abcdefghijklmnopqrstuvwxyz") == 0);
+ CHECK(memcmp(nvlist_get_binary(cnvl, cname, NULL), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(memcmp(nvlist_get_binary(cnvl, cname, &size), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(size == sizeof("abcdefghijklmnopqrstuvwxyz"));
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_NVLIST);
+ CHECK(strcmp(cname, "nvlist/nvlist/empty") == 0);
+ empty = nvlist_get_nvlist(cnvl, cname);
+ CHECK(nvlist_empty(empty));
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname == NULL);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name == NULL);
+}
+
+int
+main(void)
+{
+ int status, socks[2];
+ pid_t pid;
+
+ printf("1..134\n");
+ fflush(stdout);
+
+ if (socketpair(PF_UNIX, SOCK_STREAM, 0, socks) < 0)
+ err(1, "socketpair() failed");
+ pid = fork();
+ switch (pid) {
+ case -1:
+ /* Failure. */
+ err(1, "unable to fork");
+ case 0:
+ /* Child. */
+ close(socks[0]);
+ child(socks[1]);
+ return (0);
+ default:
+ /* Parent. */
+ close(socks[1]);
+ parent(socks[0]);
+ break;
+ }
+
+ if (waitpid(pid, &status, 0) < 0)
+ err(1, "waitpid() failed");
+
+ return (0);
+}
Index: nvpair.h
===================================================================
--- /dev/null
+++ nvpair.h
@@ -0,0 +1,230 @@
+/*-
+ * Copyright (c) 2014 Sandvine Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: head/sys/cddl/compat/opensolaris/sys/nvpair.h 286796 2015-08-15 06:34:49Z oshogbo $
+ */
+
+#ifndef _OPENSOLARIS_SYS_NVPAIR_H_
+#define _OPENSOLARIS_SYS_NVPAIR_H_
+
+#ifdef _KERNEL
+
+/*
+ * Some of the symbols in the Illumos nvpair library conflict with symbols
+ * provided by nv(9), so we use this preprocessor hack to avoid the conflict.
+ *
+ * This list was generated by:
+ * cat nv.h nv_impl.h nvlist_* nvpair_impl.h | \
+ * sed -nE 's/^[[:alnum:]_][[:alnum:]_ ]*[[:space:]]+[*]*([[:alnum:]_]+)\(.*$/#define \1 illumos_\1/p' | \
+ * sort -u
+ */
+#define nvlist_add_binary illumos_nvlist_add_binary
+#define nvlist_add_bool illumos_nvlist_add_bool
+#define nvlist_add_bool_array illumos_nvlist_add_bool_array
+#define nvlist_add_descriptor illumos_nvlist_add_descriptor
+#define nvlist_add_descriptor_array illumos_nvlist_add_descriptor_array
+#define nvlist_add_null illumos_nvlist_add_null
+#define nvlist_add_number illumos_nvlist_add_number
+#define nvlist_add_number_array illumos_nvlist_add_number_array
+#define nvlist_add_nvlist illumos_nvlist_add_nvlist
+#define nvlist_add_nvlist_array illumos_nvlist_add_nvlist_array
+#define nvlist_add_nvpair illumos_nvlist_add_nvpair
+#define nvlist_add_string illumos_nvlist_add_string
+#define nvlist_add_string_array illumos_nvlist_add_string_array
+#define nvlist_add_stringf illumos_nvlist_add_stringf
+#define nvlist_add_stringv illumos_nvlist_add_stringv
+#define nvlist_clone illumos_nvlist_clone
+#define nvlist_create illumos_nvlist_create
+#define nvlist_descriptors illumos_nvlist_descriptors
+#define nvlist_destroy illumos_nvlist_destroy
+#define nvlist_dump illumos_nvlist_dump
+#define nvlist_empty illumos_nvlist_empty
+#define nvlist_error illumos_nvlist_error
+#define nvlist_exists illumos_nvlist_exists
+#define nvlist_exists_binary illumos_nvlist_exists_binary
+#define nvlist_exists_bool illumos_nvlist_exists_bool
+#define nvlist_exists_bool_array illumos_nvlist_exists_bool_array
+#define nvlist_exists_descriptor illumos_nvlist_exists_descriptor
+#define nvlist_exists_descriptor_array illumos_nvlist_exists_descriptor_array
+#define nvlist_exists_null illumos_nvlist_exists_null
+#define nvlist_exists_number illumos_nvlist_exists_number
+#define nvlist_exists_number_array illumos_nvlist_exists_number_array
+#define nvlist_exists_nvlist illumos_nvlist_exists_nvlist
+#define nvlist_exists_nvlist_array illumos_nvlist_exists_nvlist_array
+#define nvlist_exists_string illumos_nvlist_exists_string
+#define nvlist_exists_string_array illumos_nvlist_exists_string_array
+#define nvlist_exists_type illumos_nvlist_exists_type
+#define nvlist_fdump illumos_nvlist_fdump
+#define nvlist_first_nvpair illumos_nvlist_first_nvpair
+#define nvlist_flags illumos_nvlist_flags
+#define nvlist_free illumos_nvlist_free
+#define nvlist_free_binary illumos_nvlist_free_binary
+#define nvlist_free_binary_array illumos_nvlist_free_binary_array
+#define nvlist_free_bool illumos_nvlist_free_bool
+#define nvlist_free_bool_array illumos_nvlist_free_bool_array
+#define nvlist_free_descriptor illumos_nvlist_free_descriptor
+#define nvlist_free_descriptor_array illumos_nvlist_free_descriptor_array
+#define nvlist_free_null illumos_nvlist_free_null
+#define nvlist_free_number illumos_nvlist_free_number
+#define nvlist_free_number_array illumos_nvlist_free_number_array
+#define nvlist_free_nvlist illumos_nvlist_free_nvlist
+#define nvlist_free_nvlist_array illumos_nvlist_free_nvlist_array
+#define nvlist_free_nvpair illumos_nvlist_free_nvpair
+#define nvlist_free_string illumos_nvlist_free_string
+#define nvlist_free_string_array illumos_nvlist_free_string_array
+#define nvlist_free_type illumos_nvlist_free_type
+#define nvlist_get_array_next illumos_nvlist_get_array_next
+#define nvlist_get_binary illumos_nvlist_get_binary
+#define nvlist_get_bool illumos_nvlist_get_bool
+#define nvlist_get_bool_array illumos_nvlist_get_bool_array
+#define nvlist_get_descriptor illumos_nvlist_get_descriptor
+#define nvlist_get_descriptor_array illumos_nvlist_get_descriptor_array
+#define nvlist_get_number illumos_nvlist_get_number
+#define nvlist_get_number_array illumos_nvlist_get_number_array
+#define nvlist_get_nvlist illumos_nvlist_get_nvlist
+#define nvlist_get_nvpair illumos_nvlist_get_nvpair
+#define nvlist_get_nvpair_parent illumos_nvlist_get_nvpair_parent
+#define nvlist_get_pararr illumos_nvlist_get_pararr
+#define nvlist_get_parent illumos_nvlist_get_parent
+#define nvlist_get_string illumos_nvlist_get_string
+#define nvlist_in_array illumos_nvlist_in_array
+#define nvlist_move_binary illumos_nvlist_move_binary
+#define nvlist_move_bool_array illumos_nvlist_move_bool_array
+#define nvlist_move_descriptor illumos_nvlist_move_descriptor
+#define nvlist_move_descriptor_array illumos_nvlist_move_descriptor_array
+#define nvlist_move_number_array illumos_nvlist_move_number_array
+#define nvlist_move_nvlist illumos_nvlist_move_nvlist
+#define nvlist_move_nvlist_array illumos_nvlist_move_nvlist_array
+#define nvlist_move_nvpair illumos_nvlist_move_nvpair
+#define nvlist_move_string illumos_nvlist_move_string
+#define nvlist_move_string_array illumos_nvlist_move_string_array
+#define nvlist_ndescriptors illumos_nvlist_ndescriptors
+#define nvlist_next illumos_nvlist_next
+#define nvlist_next_nvpair illumos_nvlist_next_nvpair
+#define nvlist_pack illumos_nvlist_pack
+#define nvlist_prev_nvpair illumos_nvlist_prev_nvpair
+#define nvlist_recv illumos_nvlist_recv
+#define nvlist_remove_nvpair illumos_nvlist_remove_nvpair
+#define nvlist_send illumos_nvlist_send
+#define nvlist_set_array_next illumos_nvlist_set_array_next
+#define nvlist_set_error illumos_nvlist_set_error
+#define nvlist_set_flags illumos_nvlist_set_flags
+#define nvlist_set_parent illumos_nvlist_set_parent
+#define nvlist_size illumos_nvlist_size
+#define nvlist_take_binary illumos_nvlist_take_binary
+#define nvlist_take_bool illumos_nvlist_take_bool
+#define nvlist_take_bool_array illumos_nvlist_take_bool_array
+#define nvlist_take_descriptor illumos_nvlist_take_descriptor
+#define nvlist_take_descriptor_array illumos_nvlist_take_descriptor_array
+#define nvlist_take_number illumos_nvlist_take_number
+#define nvlist_take_number_array illumos_nvlist_take_number_array
+#define nvlist_take_nvlist illumos_nvlist_take_nvlist
+#define nvlist_take_nvlist_array illumos_nvlist_take_nvlist_array
+#define nvlist_take_nvpair illumos_nvlist_take_nvpair
+#define nvlist_take_string illumos_nvlist_take_string
+#define nvlist_take_string_array illumos_nvlist_take_string_array
+#define nvlist_unpack illumos_nvlist_unpack
+#define nvlist_unpack_header illumos_nvlist_unpack_header
+#define nvlist_xfer illumos_nvlist_xfer
+#define nvpair_assert illumos_nvpair_assert
+#define nvpair_clone illumos_nvpair_clone
+#define nvpair_create_binary illumos_nvpair_create_binary
+#define nvpair_create_bool illumos_nvpair_create_bool
+#define nvpair_create_bool_array illumos_nvpair_create_bool_array
+#define nvpair_create_descriptor illumos_nvpair_create_descriptor
+#define nvpair_create_descriptor_array illumos_nvpair_create_descriptor_array
+#define nvpair_create_null illumos_nvpair_create_null
+#define nvpair_create_number illumos_nvpair_create_number
+#define nvpair_create_number_array illumos_nvpair_create_number_array
+#define nvpair_create_nvlist illumos_nvpair_create_nvlist
+#define nvpair_create_nvlist_array illumos_nvpair_create_nvlist_array
+#define nvpair_create_string illumos_nvpair_create_string
+#define nvpair_create_string_array illumos_nvpair_create_string_array
+#define nvpair_create_stringf illumos_nvpair_create_stringf
+#define nvpair_create_stringv illumos_nvpair_create_stringv
+#define nvpair_free illumos_nvpair_free
+#define nvpair_free_structure illumos_nvpair_free_structure
+#define nvpair_get_binary illumos_nvpair_get_binary
+#define nvpair_get_bool illumos_nvpair_get_bool
+#define nvpair_get_bool_array illumos_nvpair_get_bool_array
+#define nvpair_get_descriptor illumos_nvpair_get_descriptor
+#define nvpair_get_descriptor_array illumos_nvpair_get_descriptor_array
+#define nvpair_get_number illumos_nvpair_get_number
+#define nvpair_get_number_array illumos_nvpair_get_number_array
+#define nvpair_get_nvlist illumos_nvpair_get_nvlist
+#define nvpair_get_string illumos_nvpair_get_string
+#define nvpair_header_size illumos_nvpair_header_size
+#define nvpair_init_datasize illumos_nvpair_init_datasize
+#define nvpair_insert illumos_nvpair_insert
+#define nvpair_move_binary illumos_nvpair_move_binary
+#define nvpair_move_bool_array illumos_nvpair_move_bool_array
+#define nvpair_move_descriptor illumos_nvpair_move_descriptor
+#define nvpair_move_descriptor_array illumos_nvpair_move_descriptor_array
+#define nvpair_move_number_array illumos_nvpair_move_number_array
+#define nvpair_move_nvlist illumos_nvpair_move_nvlist
+#define nvpair_move_nvlist_array illumos_nvpair_move_nvlist_array
+#define nvpair_move_string illumos_nvpair_move_string
+#define nvpair_move_string_array illumos_nvpair_move_string_array
+#define nvpair_name illumos_nvpair_name
+#define nvpair_next illumos_nvpair_next
+#define nvpair_nvlist illumos_nvpair_nvlist
+#define nvpair_pack_binary illumos_nvpair_pack_binary
+#define nvpair_pack_bool illumos_nvpair_pack_bool
+#define nvpair_pack_bool_array illumos_nvpair_pack_bool_array
+#define nvpair_pack_descriptor illumos_nvpair_pack_descriptor
+#define nvpair_pack_descriptor_array illumos_nvpair_pack_descriptor_array
+#define nvpair_pack_header illumos_nvpair_pack_header
+#define nvpair_pack_null illumos_nvpair_pack_null
+#define nvpair_pack_number illumos_nvpair_pack_number
+#define nvpair_pack_number_array illumos_nvpair_pack_number_array
+#define nvpair_pack_nvlist_array_next illumos_nvpair_pack_nvlist_array_next
+#define nvpair_pack_nvlist_up illumos_nvpair_pack_nvlist_up
+#define nvpair_pack_string illumos_nvpair_pack_string
+#define nvpair_pack_string_array illumos_nvpair_pack_string_array
+#define nvpair_prev illumos_nvpair_prev
+#define nvpair_remove illumos_nvpair_remove
+#define nvpair_size illumos_nvpair_size
+#define nvpair_type illumos_nvpair_type
+#define nvpair_type_string illumos_nvpair_type_string
+#define nvpair_unpack illumos_nvpair_unpack
+#define nvpair_unpack_binary illumos_nvpair_unpack_binary
+#define nvpair_unpack_bool illumos_nvpair_unpack_bool
+#define nvpair_unpack_bool_array illumos_nvpair_unpack_bool_array
+#define nvpair_unpack_descriptor illumos_nvpair_unpack_descriptor
+#define nvpair_unpack_descriptor_array illumos_nvpair_unpack_descriptor_array
+#define nvpair_unpack_header illumos_nvpair_unpack_header
+#define nvpair_unpack_null illumos_nvpair_unpack_null
+#define nvpair_unpack_number illumos_nvpair_unpack_number
+#define nvpair_unpack_number_array illumos_nvpair_unpack_number_array
+#define nvpair_unpack_nvlist illumos_nvpair_unpack_nvlist
+#define nvpair_unpack_nvlist_array illumos_nvpair_unpack_nvlist_array
+#define nvpair_unpack_string illumos_nvpair_unpack_string
+#define nvpair_unpack_string_array illumos_nvpair_unpack_string_array
+
+#endif /* _KERNEL */
+
+#include_next <sys/nvpair.h>
+
+#endif
Index: share/man/man9/Makefile
===================================================================
--- share/man/man9/Makefile
+++ share/man/man9/Makefile
@@ -188,6 +188,7 @@
mutex.9 \
namei.9 \
netisr.9 \
+ nv.9 \
osd.9 \
panic.9 \
pbuf.9 \
@@ -998,6 +999,68 @@
mutex.9 mtx_unlock_spin_flags.9
MLINKS+=namei.9 NDFREE.9 \
namei.9 NDINIT.9
+MLINKS+=nv.9 libnv.9 \
+ nv.9 nvlist.9 \
+ nv.9 nvlist_add_binary.9 \
+ nv.9 nvlist_add_bool.9 \
+ nv.9 nvlist_add_descriptor.9 \
+ nv.9 nvlist_add_null.9 \
+ nv.9 nvlist_add_number.9 \
+ nv.9 nvlist_add_nvlist.9 \
+ nv.9 nvlist_add_string.9 \
+ nv.9 nvlist_add_stringf.9 \
+ nv.9 nvlist_add_stringv.9 \
+ nv.9 nvlist_clone.9 \
+ nv.9 nvlist_create.9 \
+ nv.9 nvlist_destroy.9 \
+ nv.9 nvlist_dump.9 \
+ nv.9 nvlist_empty.9 \
+ nv.9 nvlist_error.9 \
+ nv.9 nvlist_exists.9 \
+ nv.9 nvlist_exists_binary.9 \
+ nv.9 nvlist_exists_bool.9 \
+ nv.9 nvlist_exists_descriptor.9 \
+ nv.9 nvlist_exists_null.9 \
+ nv.9 nvlist_exists_number.9 \
+ nv.9 nvlist_exists_nvlist.9 \
+ nv.9 nvlist_exists_string.9 \
+ nv.9 nvlist_exists_type.9 \
+ nv.9 nvlist_fdump.9 \
+ nv.9 nvlist_flags.9 \
+ nv.9 nvlist_free.9 \
+ nv.9 nvlist_free_binary.9 \
+ nv.9 nvlist_free_bool.9 \
+ nv.9 nvlist_free_descriptor.9 \
+ nv.9 nvlist_free_null.9 \
+ nv.9 nvlist_free_number.9 \
+ nv.9 nvlist_free_nvlist.9 \
+ nv.9 nvlist_free_string.9 \
+ nv.9 nvlist_free_type.9 \
+ nv.9 nvlist_get_binary.9 \
+ nv.9 nvlist_get_bool.9 \
+ nv.9 nvlist_get_descriptor.9 \
+ nv.9 nvlist_get_number.9 \
+ nv.9 nvlist_get_nvlist.9 \
+ nv.9 nvlist_get_parent.9 \
+ nv.9 nvlist_get_string.9 \
+ nv.9 nvlist_move_binary.9 \
+ nv.9 nvlist_move_descriptor.9 \
+ nv.9 nvlist_move_nvlist.9 \
+ nv.9 nvlist_move_string.9 \
+ nv.9 nvlist_next.9 \
+ nv.9 nvlist_pack.9 \
+ nv.9 nvlist_recv.9 \
+ nv.9 nvlist_send.9 \
+ nv.9 nvlist_set_error.9 \
+ nv.9 nvlist_size.9 \
+ nv.9 nvlist_take_binary.9 \
+ nv.9 nvlist_take_bool.9 \
+ nv.9 nvlist_take_descriptor.9 \
+ nv.9 nvlist_take_number.9 \
+ nv.9 nvlist_take_nvlist.9 \
+ nv.9 nvlist_take_string.9 \
+ nv.9 nvlist_unpack.9 \
+ nv.9 nvlist_xfer.9
MLINKS+=panic.9 vpanic.9
MLINKS+=pbuf.9 getpbuf.9 \
pbuf.9 relpbuf.9 \
Index: share/man/man9/nv.9
===================================================================
--- /dev/null
+++ share/man/man9/nv.9
@@ -0,0 +1,935 @@
+.\"
+.\" Copyright (c) 2013 The FreeBSD Foundation
+.\" Copyright (c) 2013-2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" This documentation was written by Pawel Jakub Dawidek under sponsorship
+.\" the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: head/share/man/man9/nv.9 287232 2015-08-28 00:12:59Z markj $
+.\"
+.Dd August 15, 2015
+.Dt NV 9
+.Os
+.Sh NAME
+.Nm nvlist_create ,
+.Nm nvlist_destroy ,
+.Nm nvlist_error ,
+.Nm nvlist_set_error ,
+.Nm nvlist_empty ,
+.Nm nvlist_flags ,
+.Nm nvlist_exists ,
+.Nm nvlist_free ,
+.Nm nvlist_clone ,
+.Nm nvlist_dump ,
+.Nm nvlist_fdump ,
+.Nm nvlist_size ,
+.Nm nvlist_pack ,
+.Nm nvlist_unpack ,
+.Nm nvlist_send ,
+.Nm nvlist_recv ,
+.Nm nvlist_xfer ,
+.Nm nvlist_in_array ,
+.Nm nvlist_next ,
+.Nm nvlist_add ,
+.Nm nvlist_move ,
+.Nm nvlist_get ,
+.Nm nvlist_take
+.Nd "library for name/value pairs"
+.Sh LIBRARY
+.Lb libnv
+.Sh SYNOPSIS
+.In sys/nv.h
+.Ft "nvlist_t *"
+.Fn nvlist_create "int flags"
+.Ft void
+.Fn nvlist_destroy "nvlist_t *nvl"
+.Ft int
+.Fn nvlist_error "const nvlist_t *nvl"
+.Ft void
+.Fn nvlist_set_error "nvlist_t *nvl" "int error"
+.Ft bool
+.Fn nvlist_empty "const nvlist_t *nvl"
+.Ft int
+.Fn nvlist_flags "const nvlist_t *nvl"
+.Ft bool
+.Fn nvlist_in_array "const nvlist_t *nvl"
+.\"
+.Ft "nvlist_t *"
+.Fn nvlist_clone "const nvlist_t *nvl"
+.\"
+.Ft void
+.Fn nvlist_dump "const nvlist_t *nvl" "int fd"
+.Ft void
+.Fn nvlist_fdump "const nvlist_t *nvl" "FILE *fp"
+.\"
+.Ft size_t
+.Fn nvlist_size "const nvlist_t *nvl"
+.Ft "void *"
+.Fn nvlist_pack "const nvlist_t *nvl" "size_t *sizep"
+.Ft "nvlist_t *"
+.Fn nvlist_unpack "const void *buf" "size_t size" "int flags"
+.\"
+.Ft int
+.Fn nvlist_send "int sock" "const nvlist_t *nvl"
+.Ft "nvlist_t *"
+.Fn nvlist_recv "int sock" "int flags"
+.Ft "nvlist_t *"
+.Fn nvlist_xfer "int sock" "nvlist_t *nvl" "int flags"
+.\"
+.Ft "const char *"
+.Fn nvlist_next "const nvlist_t *nvl" "int *typep" "void **cookiep"
+.\"
+.Ft bool
+.Fn nvlist_exists "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_type "const nvlist_t *nvl" "const char *name" "int type"
+.Ft bool
+.Fn nvlist_exists_null "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_bool "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_number "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_string "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_nvlist "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_descriptor "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_binary "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_bool_array "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_number_array "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_string_array "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_nvlist_array "const nvlist_t *nvl" "const char *name"
+.Ft bool
+.Fn nvlist_exists_descriptor_array "const nvlist_t *nvl" "const char *name"
+.\"
+.Ft void
+.Fn nvlist_add_null "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_add_bool "nvlist_t *nvl" "const char *name" "bool value"
+.Ft void
+.Fn nvlist_add_number "nvlist_t *nvl" "const char *name" "uint64_t value"
+.Ft void
+.Fn nvlist_add_string "nvlist_t *nvl" "const char *name" "const char *value"
+.Ft void
+.Fn nvlist_add_stringf "nvlist_t *nvl" "const char *name" "const char *valuefmt" "..."
+.Ft void
+.Fn nvlist_add_stringv "nvlist_t *nvl" "const char *name" "const char *valuefmt" "va_list valueap"
+.Ft void
+.Fn nvlist_add_nvlist "nvlist_t *nvl" "const char *name" "const nvlist_t *value"
+.Ft void
+.Fn nvlist_add_descriptor "nvlist_t *nvl" "const char *name" "int value"
+.Ft void
+.Fn nvlist_add_binary "nvlist_t *nvl" "const char *name" "const void *value" "size_t size"
+.Ft void
+.Fn nvlist_add_bool_array "nvlist_t *nvl" "const char *name" "const bool *value" "size_t nitems"
+.
+.Ft void
+.Fn nvlist_add_number_array "nvlist_t *nvl" "const char *name" "const uint64_t *value" "size_t nitems"
+.
+.Ft void
+.Fn nvlist_add_string_array "nvlist_t *nvl" "const char *name" "const char * const * value" "size_t nitems"
+.
+.Ft void
+.Fn nvlist_add_nvlist_array "nvlist_t *nvl" "const char *name" "const nvlist_t * const * value" "size_t nitems"
+.
+.Ft void
+.Fn nvlist_add_descriptor_array "nvlist_t *nvl" "const char *name" "const int *value" "size_t nitems"
+.\"
+.Ft void
+.Fn nvlist_move_string "nvlist_t *nvl" "const char *name" "char *value"
+.Ft void
+.Fn nvlist_move_nvlist "nvlist_t *nvl" "const char *name" "nvlist_t *value"
+.Ft void
+.Fn nvlist_move_descriptor "nvlist_t *nvl" "const char *name" "int value"
+.Ft void
+.Fn nvlist_move_binary "nvlist_t *nvl" "const char *name" "void *value" "size_t size"
+.Ft void
+.Fn nvlist_move_bool_array "nvlist_t *nvl" "const char *name" "bool *value" "size_t nitems"
+.
+.Ft void
+.Fn nvlist_move_number_array "nvlist_t *nvl" "const char *name" "uint64_t *value" "size_t nitems"
+.
+.Ft void
+.Fn nvlist_move_string_array "nvlist_t *nvl" "const char *name" "char **value" "size_t nitems"
+.
+.Ft void
+.Fn nvlist_move_nvlist_array "nvlist_t *nvl" "const char *name" "nvlist_t **value" "size_t nitems"
+.
+.Ft void
+.Fn nvlist_move_descriptor_array "nvlist_t *nvl" "const char *name" "int *value" "size_t nitems"
+.\"
+.Ft bool
+.Fn nvlist_get_bool "const nvlist_t *nvl" "const char *name"
+.Ft uint64_t
+.Fn nvlist_get_number "const nvlist_t *nvl" "const char *name"
+.Ft "const char *"
+.Fn nvlist_get_string "const nvlist_t *nvl" "const char *name"
+.Ft "const nvlist_t *"
+.Fn nvlist_get_nvlist "const nvlist_t *nvl" "const char *name"
+.Ft int
+.Fn nvlist_get_descriptor "const nvlist_t *nvl" "const char *name"
+.Ft "const void *"
+.Fn nvlist_get_binary "const nvlist_t *nvl" "const char *name" "size_t *sizep"
+.Ft "const bool *"
+.Fn nvlist_get_bool_array "const nvlist_t *nvl" "const char *name" "size_t *nitems"
+.Ft "const uint64_t *"
+.Fn nvlist_get_number "const nvlist_t *nvl" "const char *name" "size_t *nitems"
+.Ft "const char * const *"
+.Fn nvlist_get_string "const nvlist_t *nvl" "const char *name" "size_t *nitems"
+.Ft "const nvlist_t * const *"
+.Fn nvlist_get_nvlist "const nvlist_t *nvl" "const char *name" "size_t *nitems"
+.Ft "const int *"
+.Fn nvlist_get_descriptor_array "const nvlist_t *nvl" "const char *name" "size_t *nitems"
+.Ft "const nvlist_t *"
+.Fn nvlist_get_parent "const nvlist_t *nvl" "void **cookiep"
+.Ft "const nvlist_t *"
+.Fn nvlist_get_array_next "const nvlist_t *nvl"
+.Ft "const nvlist_t *"
+.Fn nvlist_get_pararr "const nvlist_t *nvl" "void **cookiep"
+.\"
+.Ft bool
+.Fn nvlist_take_bool "nvlist_t *nvl" "const char *name"
+.Ft uint64_t
+.Fn nvlist_take_number "nvlist_t *nvl" "const char *name"
+.Ft "char *"
+.Fn nvlist_take_string "nvlist_t *nvl" "const char *name"
+.Ft "nvlist_t *"
+.Fn nvlist_take_nvlist "nvlist_t *nvl" "const char *name"
+.Ft int
+.Fn nvlist_take_descriptor "nvlist_t *nvl" "const char *name"
+.Ft "void *"
+.Fn nvlist_take_binary "nvlist_t *nvl" "const char *name" "size_t *sizep"
+.Ft "bool *"
+.Fn nvlist_take_bool_array "nvlist_t *nvl" "const char *name" "size_t *nitems"
+.Ft "uint64_t **"
+.Fn nvlist_take_number "nvlist_t *nvl" "const char *name" "size_t *nitems"
+.Ft "char **"
+.Fn nvlist_take_string "nvlist_t *nvl" "const char *name" "size_t *nitems"
+.Ft "nvlist_t **"
+.Fn nvlist_take_nvlist "nvlist_t *nvl" "const char *name" "size_t *nitems"
+.Ft "int *"
+.Fn nvlist_take_descriptor "nvlist_t *nvl" "const char *name" "size_t *nitems"
+.\"
+.Ft void
+.Fn nvlist_free "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_type "nvlist_t *nvl" "const char *name" "int type"
+.\"
+.Ft void
+.Fn nvlist_free_null "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_bool "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_number "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_string "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_nvlist "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_descriptor "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_binary "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_bool_array "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_number_array "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_string_array "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_nvlist_array "nvlist_t *nvl" "const char *name"
+.Ft void
+.Fn nvlist_free_descriptor_array "nvlist_t *nvl" "const char *name"
+.Sh DESCRIPTION
+The
+.Nm libnv
+library allows to easily manage name value pairs as well as send and receive
+them over sockets.
+A group (list) of name value pairs is called an
+.Nm nvlist .
+The API supports the following data types:
+.Bl -ohang -offset indent
+.It Sy null ( NV_TYPE_NULL )
+There is no data associated with the name.
+.It Sy bool ( NV_TYPE_BOOL )
+The value can be either
+.Dv true
+or
+.Dv false .
+.It Sy number ( NV_TYPE_NUMBER )
+The value is a number stored as
+.Vt uint64_t .
+.It Sy string ( NV_TYPE_STRING )
+The value is a C string.
+.It Sy nvlist ( NV_TYPE_NVLIST )
+The value is a nested nvlist.
+.It Sy descriptor ( NV_TYPE_DESCRIPTOR )
+The value is a file descriptor.
+Note that file descriptors can be sent only over
+.Xr unix 4
+domain sockets.
+.It Sy binary ( NV_TYPE_BINARY )
+The value is a binary buffer.
+.It Sy bool array ( NV_TYPE_BOOL_ARRAY )
+The value is an array of boolean values.
+.It Sy number array ( NV_TYPE_NUMBER_ARRAY )
+The value is an array of numbers, each stored as
+.Vt uint64_t .
+.It Sy string array ( NV_TYPE_STRING_ARRAY )
+The value is an array of C strings.
+.It Sy nvlist array ( NV_TYPE_NVLIST_ARRAY )
+The value is an array of nvlists.
+When an nvlist is added to an array, it becomes part of the primary nvlist.
+Traversing these arrays can be done using the
+.Fn nvlist_get_array_next
+and
+.Fn nvlist_get_pararr
+functions.
+.It Sy descriptor array ( NV_TYPE_DESCRIPTOR_ARRAY )
+The value is an array of files descriptors.
+.El
+.Pp
+The
+.Fn nvlist_create
+function allocates memory and initializes an nvlist.
+.Pp
+The following flag can be provided:
+.Pp
+.Bl -tag -width "NV_FLAG_IGNORE_CASE" -compact -offset indent
+.It Dv NV_FLAG_IGNORE_CASE
+Perform case-insensitive lookups of provided names.
+.It Dv NV_FLAG_NO_UNIQUE
+Names in the nvlist do not have to be unique.
+.El
+.Pp
+The
+.Fn nvlist_destroy
+function destroys the given nvlist.
+Function does nothing if
+.Dv NULL
+nvlist is provided.
+Function never modifies the
+.Va errno
+global variable.
+.Pp
+The
+.Fn nvlist_error
+function returns any error value that the nvlist accumulated.
+If the given nvlist is
+.Dv NULL
+the
+.Er ENOMEM
+error will be returned.
+.Pp
+The
+.Fn nvlist_set_error
+function sets an nvlist to be in the error state.
+Subsequent calls to
+.Fn nvlist_error
+will return the given error value.
+This function cannot be used to clear the error state from an nvlist.
+This function does nothing if the nvlist is already in the error state.
+.Pp
+The
+.Fn nvlist_empty
+function returns
+.Dv true
+if the given nvlist is empty and
+.Dv false
+otherwise.
+The nvlist must not be in error state.
+.Pp
+The
+.Fn nvlist_flags
+function returns flags used to create the nvlist with the
+.Fn nvlist_create
+function.
+.Pp
+The
+.Fn nvlist_in_array
+function returns
+.Dv true
+if
+.Fa nvl
+is part of an array that is a member of another nvlist.
+.Pp
+The
+.Fn nvlist_clone
+functions clones the given nvlist.
+The clone shares no resources with its origin.
+This also means that all file descriptors that are part of the nvlist will be
+duplicated with the
+.Xr dup 2
+system call before placing them in the clone.
+.Pp
+The
+.Fn nvlist_dump
+dumps nvlist content for debugging purposes to the given file descriptor
+.Fa fd .
+.Pp
+The
+.Fn nvlist_fdump
+dumps nvlist content for debugging purposes to the given file stream
+.Fa fp .
+.Pp
+The
+.Fn nvlist_size
+function returns the size of the given nvlist after converting it to binary
+buffer with the
+.Fn nvlist_pack
+function.
+.Pp
+The
+.Fn nvlist_pack
+function converts the given nvlist to a binary buffer.
+The function allocates memory for the buffer, which should be freed with the
+.Xr free 3
+function.
+If the
+.Fa sizep
+argument is not
+.Dv NULL ,
+the size of the buffer will be stored there.
+The function returns
+.Dv NULL
+in case of an error (allocation failure).
+If the nvlist contains any file descriptors
+.Dv NULL
+will be returned.
+The nvlist must not be in error state.
+.Pp
+The
+.Fn nvlist_unpack
+function converts the given buffer to the nvlist.
+The
+.Fa flags
+argument defines what type of the top level nvlist is expected to be.
+Flags are set up using the
+.Fn nvlist_create
+function.
+If the nvlist flags do not match the flags passed to
+.Fn nvlist_unpack ,
+the nvlist will not be returned.
+Every nested nvlist list should be checked using
+.Fn nvlist_flags
+function.
+The function returns
+.Dv NULL
+in case of an error.
+.Pp
+The
+.Fn nvlist_send
+function sends the given nvlist over the socket given by the
+.Fa sock
+argument.
+Note that nvlist that contains file descriptors can only be send over
+.Xr unix 4
+domain sockets.
+.Pp
+The
+.Fn nvlist_recv
+function receives nvlist over the socket given by the
+.Fa sock
+argument.
+The
+.Fa flags
+argument defines what type of the top level nvlist is expected to be.
+Flags are set up using the
+.Fn nvlist_create
+function.
+If the nvlist flags do not match the flags passed to
+.Fn nvlist_recv ,
+the nvlist will not be returned.
+Every nested nvlist list should be checked using
+.Fn nvlist_flags
+function.
+.Pp
+The
+.Fn nvlist_xfer
+function sends the given nvlist over the socket given by the
+.Fa sock
+argument and receives nvlist over the same socket.
+The
+.Fa flags
+argument defines what type of the top level nvlist is expected to be.
+Flags are set up using the
+.Fn nvlist_create
+function.
+If the nvlist flags do not match the flags passed to
+.Fn nvlist_xfer ,
+the nvlist will not be returned.
+Every nested nvlist list should be checked using
+.Fn nvlist_flags
+function.
+The given nvlist is always destroyed.
+.Pp
+The
+.Fn nvlist_next
+function iterates over the given nvlist returning names and types of subsequent
+elements.
+The
+.Fa cookiep
+argument allows the function to figure out which element should be returned
+next.
+The
+.Va *cookiep
+should be set to
+.Dv NULL
+for the first call and should not be changed later.
+Returning
+.Dv NULL
+means there are no more elements on the nvlist.
+The
+.Fa typep
+argument can be NULL.
+Elements may not be removed from the nvlist while traversing it.
+The nvlist must not be in error state.
+Note that
+.Fn nvlist_next
+will handle
+.Va cookiep
+being set to
+.Dv NULL .
+In this case first element is returned or
+.Dv NULL
+if nvlist is empty.
+This behavior simplifies removing the first element from the list.
+.Pp
+The
+.Fn nvlist_exists
+function returns
+.Dv true
+if element of the given name exists (besides of its type) or
+.Dv false
+otherwise.
+The nvlist must not be in error state.
+.Pp
+The
+.Fn nvlist_exists_type
+function returns
+.Dv true
+if element of the given name and the given type exists or
+.Dv false
+otherwise.
+The nvlist must not be in error state.
+.Pp
+The
+.Fn nvlist_exists_null ,
+.Fn nvlist_exists_bool ,
+.Fn nvlist_exists_number ,
+.Fn nvlist_exists_string ,
+.Fn nvlist_exists_nvlist ,
+.Fn nvlist_exists_descriptor ,
+.Fn nvlist_exists_binary ,
+.Fn nvlist_exists_bool_array ,
+.Fn nvlist_exists_number_array ,
+.Fn nvlist_exists_string_array ,
+.Fn nvlist_exists_nvlist_array ,
+.Fn nvlist_exists_descriptor_array
+functions return
+.Dv true
+if element of the given name and the given type determined by the function name
+exists or
+.Dv false
+otherwise.
+The nvlist must not be in error state.
+.Pp
+The
+.Fn nvlist_add_null ,
+.Fn nvlist_add_bool ,
+.Fn nvlist_add_number ,
+.Fn nvlist_add_string ,
+.Fn nvlist_add_stringf ,
+.Fn nvlist_add_stringv ,
+.Fn nvlist_add_nvlist ,
+.Fn nvlist_add_descriptor ,
+.Fn nvlist_add_binary ,
+.Fn nvlist_add_bool_array ,
+.Fn nvlist_add_number_array ,
+.Fn nvlist_add_string_array ,
+.Fn nvlist_add_nvlist_array ,
+.Fn nvlist_add_descriptor_array
+functions add element to the given nvlist.
+When adding string or binary buffor the functions will allocate memory
+and copy the data over.
+When adding nvlist, the nvlist will be cloned and clone will be added.
+When adding descriptor, the descriptor will be duplicated using the
+.Xr dup 2
+system call and the new descriptor will be added.
+The array functions will fail if there are any
+.Dv NULL
+elements in the array, or if the array pointer is
+.Dv NULL .
+If an error occurs while adding new element, internal error is set which can be
+examined using the
+.Fn nvlist_error
+function.
+.Pp
+The
+.Fn nvlist_move_string ,
+.Fn nvlist_move_nvlist ,
+.Fn nvlist_move_descriptor ,
+.Fn nvlist_move_binary ,
+.Fn nvlist_move_bool_array ,
+.Fn nvlist_move_number_array ,
+.Fn nvlist_move_string_array ,
+.Fn nvlist_move_nvlist_array ,
+.Fn nvlist_move_descriptor_array
+functions add new element to the given nvlist, but unlike
+.Fn nvlist_add_<type>
+functions they will consume the given resource.
+In the case of strings, descriptors, or nvlists every elements must be
+unique, or it could cause a double free.
+The array functions will fail if there are any
+.Dv NULL
+elements, or if the array pointer is
+.Dv NULL .
+If an error occurs while adding new element, the resource is destroyed and
+internal error is set which can be examined using the
+.Fn nvlist_error
+function.
+.Pp
+The
+.Fn nvlist_get_bool ,
+.Fn nvlist_get_number ,
+.Fn nvlist_get_string ,
+.Fn nvlist_get_nvlist ,
+.Fn nvlist_get_descriptor ,
+.Fn nvlist_get_binary ,
+.Fn nvlist_get_bool_array ,
+.Fn nvlist_get_number_array ,
+.Fn nvlist_get_string_array ,
+.Fn nvlist_get_nvlist_array ,
+.Fn nvlist_get_descriptor_array
+functions return the value that corresponds to the given key name.
+In the case of strings, nvlists, descriptors, binary, or arrays, the returned
+resource should not be modified - they still belong to the nvlist.
+If an element of the given name does not exist, the program will be aborted.
+To avoid this, the caller should check for the existence of the name before
+trying to obtain the value, or use the
+.Xr dnvlist 3
+extension, which can provide a default value in the case of a missing element.
+The nvlist must not be in error state.
+.Pp
+The
+.Fn nvlist_get_parent
+function returns the parent nvlist of the nested nvlist.
+.Pp
+The
+.Fn nvlist_get_array_next
+function returns the next element from the array or
+.Dv NULL
+if the nvlist is not in array or it is the last element.
+Note that
+.Fn nvlist_get_array_next
+only works if you added the nvlist array using the
+.Fn nvlist_move_nvlist_array
+or
+.Fn nvlist_add_nvlist_array
+functions.
+.Pp
+The
+.Fn nvlist_get_pararr
+function returns the next element in the array, or if not available
+the parent of the nested nvlist.
+.Pp
+The
+.Fn nvlist_take_bool ,
+.Fn nvlist_take_number ,
+.Fn nvlist_take_string ,
+.Fn nvlist_take_nvlist ,
+.Fn nvlist_take_descriptor ,
+.Fn nvlist_take_binary ,
+.Fn nvlist_take_bool_array ,
+.Fn nvlist_take_number_array ,
+.Fn nvlist_take_string_array ,
+.Fn nvlist_take_nvlist_array ,
+.Fn nvlist_take_descriptor_array
+functions return value associated with the given name and remove the element
+from the nvlist.
+In case of string and binary values, the caller is responsible for free returned
+memory using the
+.Xr free 3
+function.
+In case of nvlist, the caller is responsible for destroying returned nvlist
+using the
+.Fn nvlist_destroy
+function.
+In case of descriptor, the caller is responsible for closing returned descriptor
+using the
+.Fn close 2
+system call.
+If an element of the given name does not exist, the program will be aborted.
+To avoid that the caller should check for the existence of the given name
+before trying to obtain the value, or use the
+.Xr dnvlist 3
+extension, which can provide a default value in the case of a missing element.
+In the case of an array of strings or binary values, the caller is responsible
+for freeing every element of the array using the
+.Xr free 3
+function.
+In the case of an array of nvlists, the caller is responsible for destroying
+every element of array using the
+.Fn nvlist_destroy
+function.
+In the case of descriptors, the caller is responsible for closing every
+element of array using the
+.Fn close 2
+system call.
+In every case involving an array, the caller must also free the pointer to
+the array using the
+.Xr free 3
+function.
+The nvlist must not be in error state.
+.Pp
+The
+.Fn nvlist_free
+function removes element of the given name from the nvlist (besides of its type)
+and frees all resources associated with it.
+If element of the given name does not exist, the program will be aborted.
+The nvlist must not be in error state.
+.Pp
+The
+.Fn nvlist_free_type
+function removes element of the given name and the given type from the nvlist
+and frees all resources associated with it.
+If element of the given name and the given type does not exist, the program
+will be aborted.
+The nvlist must not be in error state.
+.Pp
+The
+.Fn nvlist_free_null ,
+.Fn nvlist_free_bool ,
+.Fn nvlist_free_number ,
+.Fn nvlist_free_string ,
+.Fn nvlist_free_nvlist ,
+.Fn nvlist_free_descriptor ,
+.Fn nvlist_free_binary ,
+.Fn nvlist_free_bool_array ,
+.Fn nvlist_free_number_array ,
+.Fn nvlist_free_string_array ,
+.Fn nvlist_free_nvlist_array ,
+.Fn nvlist_free_descriptor_array
+functions remove element of the given name and the given type determined by the
+function name from the nvlist and free all resources associated with it.
+If element of the given name and the given type does not exist, the program
+will be aborted.
+The nvlist must not be in error state.
+.Sh EXAMPLES
+The following example demonstrates how to prepare an nvlist and send it over
+.Xr unix 4
+domain socket.
+.Bd -literal
+nvlist_t *nvl;
+int fd;
+
+fd = open("/tmp/foo", O_RDONLY);
+if (fd < 0)
+ err(1, "open(\\"/tmp/foo\\") failed");
+
+nvl = nvlist_create(0);
+/*
+ * There is no need to check if nvlist_create() succeeded,
+ * as the nvlist_add_<type>() functions can cope.
+ * If it failed, nvlist_send() will fail.
+ */
+nvlist_add_string(nvl, "filename", "/tmp/foo");
+nvlist_add_number(nvl, "flags", O_RDONLY);
+/*
+ * We just want to send the descriptor, so we can give it
+ * for the nvlist to consume (that's why we use nvlist_move
+ * not nvlist_add).
+ */
+nvlist_move_descriptor(nvl, "fd", fd);
+if (nvlist_send(sock, nvl) < 0) {
+ nvlist_destroy(nvl);
+ err(1, "nvlist_send() failed");
+}
+nvlist_destroy(nvl);
+.Ed
+.Pp
+Receiving nvlist and getting data:
+.Bd -literal
+nvlist_t *nvl;
+const char *command;
+char *filename;
+int fd;
+
+nvl = nvlist_recv(sock, 0);
+if (nvl == NULL)
+ err(1, "nvlist_recv() failed");
+
+/* For command we take pointer to nvlist's buffer. */
+command = nvlist_get_string(nvl, "command");
+/*
+ * For filename we remove it from the nvlist and take
+ * ownership of the buffer.
+ */
+filename = nvlist_take_string(nvl, "filename");
+/* The same for the descriptor. */
+fd = nvlist_take_descriptor(nvl, "fd");
+
+printf("command=%s filename=%s fd=%d\n", command, filename, fd);
+
+nvlist_destroy(nvl);
+free(filename);
+close(fd);
+/* command was freed by nvlist_destroy() */
+.Ed
+.Pp
+Iterating over nvlist:
+.Bd -literal
+nvlist_t *nvl;
+const char *name;
+void *cookie;
+int type;
+
+nvl = nvlist_recv(sock, 0);
+if (nvl == NULL)
+ err(1, "nvlist_recv() failed");
+
+cookie = NULL;
+while ((name = nvlist_next(nvl, &type, &cookie)) != NULL) {
+ printf("%s=", name);
+ switch (type) {
+ case NV_TYPE_NUMBER:
+ printf("%ju", (uintmax_t)nvlist_get_number(nvl, name));
+ break;
+ case NV_TYPE_STRING:
+ printf("%s", nvlist_get_string(nvl, name));
+ break;
+ default:
+ printf("N/A");
+ break;
+ }
+ printf("\\n");
+}
+.Ed
+.Pp
+Iterating over every nested nvlist:
+.Bd -literal
+nvlist_t *nvl;
+const char *name;
+void *cookie;
+int type;
+
+nvl = nvlist_recv(sock, 0);
+if (nvl == NULL)
+ err(1, "nvlist_recv() failed");
+
+cookie = NULL;
+do {
+ while ((name = nvlist_next(nvl, &type, &cookie)) != NULL) {
+ if (type == NV_TYPE_NVLIST) {
+ nvl = nvlist_get_nvlist(nvl, name);
+ cookie = NULL;
+ }
+ }
+} while ((nvl = nvlist_get_parent(nvl, &cookie)) != NULL);
+.Ed
+.Pp
+Iterating over every nested nvlist and every nvlist element:
+.Bd -literal
+nvlist_t *nvl;
+const nvlist_t * const *array;
+const char *name;
+void *cookie;
+int type;
+
+nvl = nvlist_recv(sock, 0);
+if (nvl == null)
+ err(1, "nvlist_recv() failed");
+
+cookie = null;
+do {
+ while ((name = nvlist_next(nvl, &type, &cookie)) != NULL) {
+ if (type == NV_TYPE_NVLIST) {
+ nvl = nvlist_get_nvlist(nvl, name);
+ cookie = NULL;
+ } else if (type == NV_TYPE_NVLIST_ARRAY) {
+ nvl = nvlist_get_nvlist_array(nvl, name, NULL)[0];
+ cookie = NULL;
+ }
+ }
+} while ((nvl = nvlist_get_pararr(nvl, &cookie)) != NULL);
+.Ed
+.Pp
+Or alternatively:
+.Bd -literal
+nvlist_t *nvl, *tmp;
+const nvlist_t * const *array;
+const char *name;
+void *cookie;
+int type;
+
+nvl = nvlist_recv(sock, 0);
+if (nvl == null)
+ err(1, "nvlist_recv() failed");
+
+cooke = NULL;
+tmp = nvl;
+do {
+ do {
+ nvl = tmp;
+ while ((name = nvlist_next(nvl, &type, &cookie)) != NULL) {
+ if (type == NV_TYPE_NVLIST) {
+ nvl = nvlist_get_nvlist(nvl,
+ name);
+ cookie = NULL;
+ } else if (type == NV_TYPE_NVLIST_ARRAY) {
+ nvl = nvlist_get_nvlist_array(nvl, name,
+ NULL)[0];
+ cookie = NULL;
+ }
+ }
+ cookie = NULL;
+ } while ((tmp = nvlist_get_array_next(nvl)) != NULL);
+} while ((tmp = nvlist_get_parent(nvl, &cookie)) != NULL);
+.Ed
+.Sh SEE ALSO
+.Xr close 2 ,
+.Xr dup 2 ,
+.Xr open 2 ,
+.Xr err 3 ,
+.Xr free 3 ,
+.Xr printf 3 ,
+.Xr unix 4
+.Sh HISTORY
+The
+.Nm libnv
+library appeared in
+.Fx 11.0 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm libnv
+library was implemented by
+.An Pawel Jakub Dawidek Aq Mt pawel@dawidek.net
+under sponsorship from the FreeBSD Foundation.
Index: share/mk/bsd.libnames.mk
===================================================================
--- share/mk/bsd.libnames.mk
+++ share/mk/bsd.libnames.mk
@@ -100,6 +100,7 @@
LIBNCURSESW?= ${DESTDIR}${LIBDIR}/libncursesw.a
LIBNETGRAPH?= ${DESTDIR}${LIBDIR}/libnetgraph.a
LIBNGATM?= ${DESTDIR}${LIBDIR}/libngatm.a
+LIBNV?= ${DESTDIR}${LIBDIR}/libnv.a
LIBNVPAIR?= ${DESTDIR}${LIBDIR}/libnvpair.a
LIBOPIE?= ${DESTDIR}${LIBDIR}/libopie.a
Index: sys/cddl/contrib/opensolaris/common/nvpair/fnvpair.c
===================================================================
--- sys/cddl/contrib/opensolaris/common/nvpair/fnvpair.c
+++ /dev/null
@@ -1,512 +0,0 @@
-
-/*
- * 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
- * or http://www.opensolaris.org/os/licensing.
- * 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) 2012 by Delphix. All rights reserved.
- */
-
-#include <sys/nvpair.h>
-#ifndef _KERNEL
-#include <sys/zfs_context.h>
-#else
-#include <sys/debug.h>
-#include <sys/kmem.h>
-#include <sys/param.h>
-#include <sys/debug.h>
-#endif
-
-/*
- * "Force" nvlist wrapper.
- *
- * These functions wrap the nvlist_* functions with assertions that assume
- * the operation is successful. This allows the caller's code to be much
- * more readable, especially for the fnvlist_lookup_* and fnvpair_value_*
- * functions, which can return the requested value (rather than filling in
- * a pointer).
- *
- * These functions use NV_UNIQUE_NAME, encoding NV_ENCODE_NATIVE, and allocate
- * with KM_SLEEP.
- *
- * More wrappers should be added as needed -- for example
- * nvlist_lookup_*_array and nvpair_value_*_array.
- */
-
-nvlist_t *
-fnvlist_alloc(void)
-{
- nvlist_t *nvl;
- VERIFY0(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP));
- return (nvl);
-}
-
-void
-fnvlist_free(nvlist_t *nvl)
-{
- nvlist_free(nvl);
-}
-
-size_t
-fnvlist_size(nvlist_t *nvl)
-{
- size_t size;
- VERIFY0(nvlist_size(nvl, &size, NV_ENCODE_NATIVE));
- return (size);
-}
-
-/*
- * Returns allocated buffer of size *sizep. Caller must free the buffer with
- * fnvlist_pack_free().
- */
-char *
-fnvlist_pack(nvlist_t *nvl, size_t *sizep)
-{
- char *packed = 0;
- VERIFY3U(nvlist_pack(nvl, &packed, sizep, NV_ENCODE_NATIVE,
- KM_SLEEP), ==, 0);
- return (packed);
-}
-
-/*ARGSUSED*/
-void
-fnvlist_pack_free(char *pack, size_t size)
-{
-#ifdef _KERNEL
- kmem_free(pack, size);
-#else
- free(pack);
-#endif
-}
-
-nvlist_t *
-fnvlist_unpack(char *buf, size_t buflen)
-{
- nvlist_t *rv;
- VERIFY0(nvlist_unpack(buf, buflen, &rv, KM_SLEEP));
- return (rv);
-}
-
-nvlist_t *
-fnvlist_dup(nvlist_t *nvl)
-{
- nvlist_t *rv;
- VERIFY0(nvlist_dup(nvl, &rv, KM_SLEEP));
- return (rv);
-}
-
-void
-fnvlist_merge(nvlist_t *dst, nvlist_t *src)
-{
- VERIFY0(nvlist_merge(dst, src, KM_SLEEP));
-}
-
-size_t
-fnvlist_num_pairs(nvlist_t *nvl)
-{
- size_t count = 0;
- nvpair_t *pair;
-
- for (pair = nvlist_next_nvpair(nvl, 0); pair != NULL;
- pair = nvlist_next_nvpair(nvl, pair))
- count++;
- return (count);
-}
-
-void
-fnvlist_add_boolean(nvlist_t *nvl, const char *name)
-{
- VERIFY0(nvlist_add_boolean(nvl, name));
-}
-
-void
-fnvlist_add_boolean_value(nvlist_t *nvl, const char *name, boolean_t val)
-{
- VERIFY0(nvlist_add_boolean_value(nvl, name, val));
-}
-
-void
-fnvlist_add_byte(nvlist_t *nvl, const char *name, uchar_t val)
-{
- VERIFY0(nvlist_add_byte(nvl, name, val));
-}
-
-void
-fnvlist_add_int8(nvlist_t *nvl, const char *name, int8_t val)
-{
- VERIFY0(nvlist_add_int8(nvl, name, val));
-}
-
-void
-fnvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t val)
-{
- VERIFY0(nvlist_add_uint8(nvl, name, val));
-}
-
-void
-fnvlist_add_int16(nvlist_t *nvl, const char *name, int16_t val)
-{
- VERIFY0(nvlist_add_int16(nvl, name, val));
-}
-
-void
-fnvlist_add_uint16(nvlist_t *nvl, const char *name, uint16_t val)
-{
- VERIFY0(nvlist_add_uint16(nvl, name, val));
-}
-
-void
-fnvlist_add_int32(nvlist_t *nvl, const char *name, int32_t val)
-{
- VERIFY0(nvlist_add_int32(nvl, name, val));
-}
-
-void
-fnvlist_add_uint32(nvlist_t *nvl, const char *name, uint32_t val)
-{
- VERIFY0(nvlist_add_uint32(nvl, name, val));
-}
-
-void
-fnvlist_add_int64(nvlist_t *nvl, const char *name, int64_t val)
-{
- VERIFY0(nvlist_add_int64(nvl, name, val));
-}
-
-void
-fnvlist_add_uint64(nvlist_t *nvl, const char *name, uint64_t val)
-{
- VERIFY0(nvlist_add_uint64(nvl, name, val));
-}
-
-void
-fnvlist_add_string(nvlist_t *nvl, const char *name, const char *val)
-{
- VERIFY0(nvlist_add_string(nvl, name, val));
-}
-
-void
-fnvlist_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val)
-{
- VERIFY0(nvlist_add_nvlist(nvl, name, val));
-}
-
-void
-fnvlist_add_nvpair(nvlist_t *nvl, nvpair_t *pair)
-{
- VERIFY0(nvlist_add_nvpair(nvl, pair));
-}
-
-void
-fnvlist_add_boolean_array(nvlist_t *nvl, const char *name,
- boolean_t *val, uint_t n)
-{
- VERIFY0(nvlist_add_boolean_array(nvl, name, val, n));
-}
-
-void
-fnvlist_add_byte_array(nvlist_t *nvl, const char *name, uchar_t *val, uint_t n)
-{
- VERIFY0(nvlist_add_byte_array(nvl, name, val, n));
-}
-
-void
-fnvlist_add_int8_array(nvlist_t *nvl, const char *name, int8_t *val, uint_t n)
-{
- VERIFY0(nvlist_add_int8_array(nvl, name, val, n));
-}
-
-void
-fnvlist_add_uint8_array(nvlist_t *nvl, const char *name, uint8_t *val, uint_t n)
-{
- VERIFY0(nvlist_add_uint8_array(nvl, name, val, n));
-}
-
-void
-fnvlist_add_int16_array(nvlist_t *nvl, const char *name, int16_t *val, uint_t n)
-{
- VERIFY0(nvlist_add_int16_array(nvl, name, val, n));
-}
-
-void
-fnvlist_add_uint16_array(nvlist_t *nvl, const char *name,
- uint16_t *val, uint_t n)
-{
- VERIFY0(nvlist_add_uint16_array(nvl, name, val, n));
-}
-
-void
-fnvlist_add_int32_array(nvlist_t *nvl, const char *name, int32_t *val, uint_t n)
-{
- VERIFY0(nvlist_add_int32_array(nvl, name, val, n));
-}
-
-void
-fnvlist_add_uint32_array(nvlist_t *nvl, const char *name,
- uint32_t *val, uint_t n)
-{
- VERIFY0(nvlist_add_uint32_array(nvl, name, val, n));
-}
-
-void
-fnvlist_add_int64_array(nvlist_t *nvl, const char *name, int64_t *val, uint_t n)
-{
- VERIFY0(nvlist_add_int64_array(nvl, name, val, n));
-}
-
-void
-fnvlist_add_uint64_array(nvlist_t *nvl, const char *name,
- uint64_t *val, uint_t n)
-{
- VERIFY0(nvlist_add_uint64_array(nvl, name, val, n));
-}
-
-void
-fnvlist_add_string_array(nvlist_t *nvl, const char *name,
- char * const *val, uint_t n)
-{
- VERIFY0(nvlist_add_string_array(nvl, name, val, n));
-}
-
-void
-fnvlist_add_nvlist_array(nvlist_t *nvl, const char *name,
- nvlist_t **val, uint_t n)
-{
- VERIFY0(nvlist_add_nvlist_array(nvl, name, val, n));
-}
-
-void
-fnvlist_remove(nvlist_t *nvl, const char *name)
-{
- VERIFY0(nvlist_remove_all(nvl, name));
-}
-
-void
-fnvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *pair)
-{
- VERIFY0(nvlist_remove_nvpair(nvl, pair));
-}
-
-nvpair_t *
-fnvlist_lookup_nvpair(nvlist_t *nvl, const char *name)
-{
- nvpair_t *rv;
- VERIFY0(nvlist_lookup_nvpair(nvl, name, &rv));
- return (rv);
-}
-
-/* returns B_TRUE if the entry exists */
-boolean_t
-fnvlist_lookup_boolean(nvlist_t *nvl, const char *name)
-{
- return (nvlist_lookup_boolean(nvl, name) == 0);
-}
-
-boolean_t
-fnvlist_lookup_boolean_value(nvlist_t *nvl, const char *name)
-{
- boolean_t rv;
- VERIFY0(nvlist_lookup_boolean_value(nvl, name, &rv));
- return (rv);
-}
-
-uchar_t
-fnvlist_lookup_byte(nvlist_t *nvl, const char *name)
-{
- uchar_t rv;
- VERIFY0(nvlist_lookup_byte(nvl, name, &rv));
- return (rv);
-}
-
-int8_t
-fnvlist_lookup_int8(nvlist_t *nvl, const char *name)
-{
- int8_t rv;
- VERIFY0(nvlist_lookup_int8(nvl, name, &rv));
- return (rv);
-}
-
-int16_t
-fnvlist_lookup_int16(nvlist_t *nvl, const char *name)
-{
- int16_t rv;
- VERIFY0(nvlist_lookup_int16(nvl, name, &rv));
- return (rv);
-}
-
-int32_t
-fnvlist_lookup_int32(nvlist_t *nvl, const char *name)
-{
- int32_t rv;
- VERIFY0(nvlist_lookup_int32(nvl, name, &rv));
- return (rv);
-}
-
-int64_t
-fnvlist_lookup_int64(nvlist_t *nvl, const char *name)
-{
- int64_t rv;
- VERIFY0(nvlist_lookup_int64(nvl, name, &rv));
- return (rv);
-}
-
-uint8_t
-fnvlist_lookup_uint8_t(nvlist_t *nvl, const char *name)
-{
- uint8_t rv;
- VERIFY0(nvlist_lookup_uint8(nvl, name, &rv));
- return (rv);
-}
-
-uint16_t
-fnvlist_lookup_uint16(nvlist_t *nvl, const char *name)
-{
- uint16_t rv;
- VERIFY0(nvlist_lookup_uint16(nvl, name, &rv));
- return (rv);
-}
-
-uint32_t
-fnvlist_lookup_uint32(nvlist_t *nvl, const char *name)
-{
- uint32_t rv;
- VERIFY0(nvlist_lookup_uint32(nvl, name, &rv));
- return (rv);
-}
-
-uint64_t
-fnvlist_lookup_uint64(nvlist_t *nvl, const char *name)
-{
- uint64_t rv;
- VERIFY0(nvlist_lookup_uint64(nvl, name, &rv));
- return (rv);
-}
-
-char *
-fnvlist_lookup_string(nvlist_t *nvl, const char *name)
-{
- char *rv;
- VERIFY0(nvlist_lookup_string(nvl, name, &rv));
- return (rv);
-}
-
-nvlist_t *
-fnvlist_lookup_nvlist(nvlist_t *nvl, const char *name)
-{
- nvlist_t *rv;
- VERIFY0(nvlist_lookup_nvlist(nvl, name, &rv));
- return (rv);
-}
-
-boolean_t
-fnvpair_value_boolean_value(nvpair_t *nvp)
-{
- boolean_t rv;
- VERIFY0(nvpair_value_boolean_value(nvp, &rv));
- return (rv);
-}
-
-uchar_t
-fnvpair_value_byte(nvpair_t *nvp)
-{
- uchar_t rv;
- VERIFY0(nvpair_value_byte(nvp, &rv));
- return (rv);
-}
-
-int8_t
-fnvpair_value_int8(nvpair_t *nvp)
-{
- int8_t rv;
- VERIFY0(nvpair_value_int8(nvp, &rv));
- return (rv);
-}
-
-int16_t
-fnvpair_value_int16(nvpair_t *nvp)
-{
- int16_t rv;
- VERIFY0(nvpair_value_int16(nvp, &rv));
- return (rv);
-}
-
-int32_t
-fnvpair_value_int32(nvpair_t *nvp)
-{
- int32_t rv;
- VERIFY0(nvpair_value_int32(nvp, &rv));
- return (rv);
-}
-
-int64_t
-fnvpair_value_int64(nvpair_t *nvp)
-{
- int64_t rv;
- VERIFY0(nvpair_value_int64(nvp, &rv));
- return (rv);
-}
-
-uint8_t
-fnvpair_value_uint8_t(nvpair_t *nvp)
-{
- uint8_t rv;
- VERIFY0(nvpair_value_uint8(nvp, &rv));
- return (rv);
-}
-
-uint16_t
-fnvpair_value_uint16(nvpair_t *nvp)
-{
- uint16_t rv;
- VERIFY0(nvpair_value_uint16(nvp, &rv));
- return (rv);
-}
-
-uint32_t
-fnvpair_value_uint32(nvpair_t *nvp)
-{
- uint32_t rv;
- VERIFY0(nvpair_value_uint32(nvp, &rv));
- return (rv);
-}
-
-uint64_t
-fnvpair_value_uint64(nvpair_t *nvp)
-{
- uint64_t rv;
- VERIFY0(nvpair_value_uint64(nvp, &rv));
- return (rv);
-}
-
-char *
-fnvpair_value_string(nvpair_t *nvp)
-{
- char *rv;
- VERIFY0(nvpair_value_string(nvp, &rv));
- return (rv);
-}
-
-nvlist_t *
-fnvpair_value_nvlist(nvpair_t *nvp)
-{
- nvlist_t *rv;
- VERIFY0(nvpair_value_nvlist(nvp, &rv));
- return (rv);
-}
Index: sys/cddl/contrib/opensolaris/common/nvpair/nvpair.c
===================================================================
--- sys/cddl/contrib/opensolaris/common/nvpair/nvpair.c
+++ /dev/null
@@ -1,3306 +0,0 @@
-/*
- * 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
- * or http://www.opensolaris.org/os/licensing.
- * 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) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
- */
-
-#include <sys/debug.h>
-#include <sys/nvpair.h>
-#include <sys/nvpair_impl.h>
-#include <rpc/types.h>
-#include <rpc/xdr.h>
-
-#if defined(_KERNEL) && !defined(_BOOT)
-#include <sys/varargs.h>
-#include <sys/sunddi.h>
-#else
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#endif
-
-#ifndef offsetof
-#define offsetof(s, m) ((size_t)(&(((s *)0)->m)))
-#endif
-#define skip_whitespace(p) while ((*(p) == ' ') || (*(p) == '\t')) p++
-
-#if defined(__FreeBSD__) && !defined(_KERNEL)
-/*
- * libnvpair is the lowest commen denominator for ZFS related libraries,
- * defining aok here makes it usable by all ZFS related libraries
- */
-int aok;
-#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
- */
-#define NVP_SIZE_CALC(name_len, data_len) \
- (NV_ALIGN((sizeof (nvpair_t)) + name_len) + NV_ALIGN(data_len))
-
-static int i_get_value_size(data_type_t type, const void *data, uint_t nelem);
-static int nvlist_add_common(nvlist_t *nvl, const char *name, data_type_t type,
- uint_t nelem, const void *data);
-
-#define NV_STAT_EMBEDDED 0x1
-#define EMBEDDED_NVL(nvp) ((nvlist_t *)(void *)NVP_VALUE(nvp))
-#define EMBEDDED_NVL_ARRAY(nvp) ((nvlist_t **)(void *)NVP_VALUE(nvp))
-
-#define NVP_VALOFF(nvp) (NV_ALIGN(sizeof (nvpair_t) + (nvp)->nvp_name_sz))
-#define NVPAIR2I_NVP(nvp) \
- ((i_nvp_t *)((size_t)(nvp) - offsetof(i_nvp_t, nvi_nvp)))
-
-
-int
-nv_alloc_init(nv_alloc_t *nva, const nv_alloc_ops_t *nvo, /* args */ ...)
-{
- va_list valist;
- int err = 0;
-
- nva->nva_ops = nvo;
- nva->nva_arg = NULL;
-
- va_start(valist, nvo);
- if (nva->nva_ops->nv_ao_init != NULL)
- err = nva->nva_ops->nv_ao_init(nva, valist);
- va_end(valist);
-
- return (err);
-}
-
-void
-nv_alloc_reset(nv_alloc_t *nva)
-{
- if (nva->nva_ops->nv_ao_reset != NULL)
- nva->nva_ops->nv_ao_reset(nva);
-}
-
-void
-nv_alloc_fini(nv_alloc_t *nva)
-{
- if (nva->nva_ops->nv_ao_fini != NULL)
- nva->nva_ops->nv_ao_fini(nva);
-}
-
-nv_alloc_t *
-nvlist_lookup_nv_alloc(nvlist_t *nvl)
-{
- nvpriv_t *priv;
-
- if (nvl == NULL ||
- (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
- return (NULL);
-
- return (priv->nvp_nva);
-}
-
-static void *
-nv_mem_zalloc(nvpriv_t *nvp, size_t size)
-{
- nv_alloc_t *nva = nvp->nvp_nva;
- void *buf;
-
- if ((buf = nva->nva_ops->nv_ao_alloc(nva, size)) != NULL)
- bzero(buf, size);
-
- return (buf);
-}
-
-static void
-nv_mem_free(nvpriv_t *nvp, void *buf, size_t size)
-{
- nv_alloc_t *nva = nvp->nvp_nva;
-
- nva->nva_ops->nv_ao_free(nva, buf, size);
-}
-
-static void
-nv_priv_init(nvpriv_t *priv, nv_alloc_t *nva, uint32_t stat)
-{
- bzero(priv, sizeof (nvpriv_t));
-
- priv->nvp_nva = nva;
- priv->nvp_stat = stat;
-}
-
-static nvpriv_t *
-nv_priv_alloc(nv_alloc_t *nva)
-{
- nvpriv_t *priv;
-
- /*
- * nv_mem_alloc() cannot called here because it needs the priv
- * argument.
- */
- if ((priv = nva->nva_ops->nv_ao_alloc(nva, sizeof (nvpriv_t))) == NULL)
- return (NULL);
-
- nv_priv_init(priv, nva, 0);
-
- 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 *
-nv_priv_alloc_embedded(nvpriv_t *priv)
-{
- nvpriv_t *emb_priv;
-
- if ((emb_priv = nv_mem_zalloc(priv, sizeof (nvpriv_t))) == NULL)
- return (NULL);
-
- nv_priv_init(emb_priv, priv->nvp_nva, NV_STAT_EMBEDDED);
-
- return (emb_priv);
-}
-
-static void
-nvlist_init(nvlist_t *nvl, uint32_t nvflag, nvpriv_t *priv)
-{
- nvl->nvl_version = NV_VERSION;
- nvl->nvl_nvflag = nvflag & (NV_UNIQUE_NAME|NV_UNIQUE_NAME_TYPE);
- nvl->nvl_priv = (uint64_t)(uintptr_t)priv;
- nvl->nvl_flag = 0;
- nvl->nvl_pad = 0;
-}
-
-uint_t
-nvlist_nvflag(nvlist_t *nvl)
-{
- return (nvl->nvl_nvflag);
-}
-
-/*
- * nvlist_alloc - Allocate nvlist.
- */
-/*ARGSUSED1*/
-int
-nvlist_alloc(nvlist_t **nvlp, uint_t nvflag, int kmflag)
-{
-#if defined(_KERNEL) && !defined(_BOOT)
- return (nvlist_xalloc(nvlp, nvflag,
- (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep)));
-#else
- return (nvlist_xalloc(nvlp, nvflag, nv_alloc_nosleep));
-#endif
-}
-
-int
-nvlist_xalloc(nvlist_t **nvlp, uint_t nvflag, nv_alloc_t *nva)
-{
- nvpriv_t *priv;
-
- if (nvlp == NULL || nva == NULL)
- return (EINVAL);
-
- if ((priv = nv_priv_alloc(nva)) == NULL)
- return (ENOMEM);
-
- if ((*nvlp = nv_mem_zalloc(priv,
- NV_ALIGN(sizeof (nvlist_t)))) == NULL) {
- nv_mem_free(priv, priv, sizeof (nvpriv_t));
- return (ENOMEM);
- }
-
- nvlist_init(*nvlp, nvflag, priv);
-
- return (0);
-}
-
-/*
- * nvp_buf_alloc - Allocate i_nvp_t for storing a new nv pair.
- */
-static nvpair_t *
-nvp_buf_alloc(nvlist_t *nvl, size_t len)
-{
- nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
- i_nvp_t *buf;
- nvpair_t *nvp;
- size_t nvsize;
-
- /*
- * Allocate the buffer
- */
- nvsize = len + offsetof(i_nvp_t, nvi_nvp);
-
- if ((buf = nv_mem_zalloc(priv, nvsize)) == NULL)
- return (NULL);
-
- nvp = &buf->nvi_nvp;
- nvp->nvp_size = len;
-
- return (nvp);
-}
-
-/*
- * nvp_buf_free - de-Allocate an i_nvp_t.
- */
-static void
-nvp_buf_free(nvlist_t *nvl, nvpair_t *nvp)
-{
- nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
- size_t nvsize = nvp->nvp_size + offsetof(i_nvp_t, nvi_nvp);
-
- nv_mem_free(priv, NVPAIR2I_NVP(nvp), nvsize);
-}
-
-/*
- * nvp_buf_link - link a new nv pair into the nvlist.
- */
-static void
-nvp_buf_link(nvlist_t *nvl, nvpair_t *nvp)
-{
- nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
- i_nvp_t *curr = NVPAIR2I_NVP(nvp);
-
- /* Put element at end of nvlist */
- if (priv->nvp_list == NULL) {
- priv->nvp_list = priv->nvp_last = curr;
- } else {
- curr->nvi_prev = priv->nvp_last;
- priv->nvp_last->nvi_next = curr;
- priv->nvp_last = curr;
- }
-}
-
-/*
- * nvp_buf_unlink - unlink an removed nvpair out of the nvlist.
- */
-static void
-nvp_buf_unlink(nvlist_t *nvl, nvpair_t *nvp)
-{
- nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
- i_nvp_t *curr = NVPAIR2I_NVP(nvp);
-
- /*
- * protect nvlist_next_nvpair() against walking on freed memory.
- */
- if (priv->nvp_curr == curr)
- priv->nvp_curr = curr->nvi_next;
-
- if (curr == priv->nvp_list)
- priv->nvp_list = curr->nvi_next;
- else
- curr->nvi_prev->nvi_next = curr->nvi_next;
-
- if (curr == priv->nvp_last)
- priv->nvp_last = curr->nvi_prev;
- else
- curr->nvi_next->nvi_prev = curr->nvi_prev;
-}
-
-/*
- * take a nvpair type and number of elements and make sure the are valid
- */
-static int
-i_validate_type_nelem(data_type_t type, uint_t nelem)
-{
- 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
-i_validate_nvpair_name(nvpair_t *nvp)
-{
- if ((nvp->nvp_name_sz <= 0) ||
- (nvp->nvp_size < NVP_SIZE_CALC(nvp->nvp_name_sz, 0)))
- return (EFAULT);
-
- /* verify the name string, make sure its terminated */
- if (NVP_NAME(nvp)[nvp->nvp_name_sz - 1] != '\0')
- return (EFAULT);
-
- return (strlen(NVP_NAME(nvp)) == nvp->nvp_name_sz - 1 ? 0 : EFAULT);
-}
-
-static int
-i_validate_nvpair_value(data_type_t type, uint_t nelem, const void *data)
-{
- switch (type) {
- case DATA_TYPE_BOOLEAN_VALUE:
- if (*(boolean_t *)data != B_TRUE &&
- *(boolean_t *)data != B_FALSE)
- return (EINVAL);
- break;
- case DATA_TYPE_BOOLEAN_ARRAY: {
- int i;
-
- for (i = 0; i < nelem; i++)
- if (((boolean_t *)data)[i] != B_TRUE &&
- ((boolean_t *)data)[i] != B_FALSE)
- 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
-i_validate_nvpair(nvpair_t *nvp)
-{
- data_type_t type = NVP_TYPE(nvp);
- int size1, size2;
-
- /* verify nvp_name_sz, check the name string length */
- if (i_validate_nvpair_name(nvp) != 0)
- return (EFAULT);
-
- if (i_validate_nvpair_value(type, NVP_NELEM(nvp), NVP_VALUE(nvp)) != 0)
- return (EFAULT);
-
- /*
- * verify nvp_type, nvp_value_elem, and also possibly
- * verify string values and get the value size.
- */
- size2 = i_get_value_size(type, NVP_VALUE(nvp), NVP_NELEM(nvp));
- size1 = nvp->nvp_size - NVP_VALOFF(nvp);
- if (size2 < 0 || size1 != NV_ALIGN(size2))
- return (EFAULT);
-
- return (0);
-}
-
-static int
-nvlist_copy_pairs(nvlist_t *snvl, nvlist_t *dnvl)
-{
- nvpriv_t *priv;
- i_nvp_t *curr;
-
- if ((priv = (nvpriv_t *)(uintptr_t)snvl->nvl_priv) == NULL)
- return (EINVAL);
-
- for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
- nvpair_t *nvp = &curr->nvi_nvp;
- int err;
-
- if ((err = nvlist_add_common(dnvl, NVP_NAME(nvp), NVP_TYPE(nvp),
- NVP_NELEM(nvp), NVP_VALUE(nvp))) != 0)
- return (err);
- }
-
- return (0);
-}
-
-/*
- * Frees all memory allocated for an nvpair (like embedded lists) with
- * the exception of the nvpair buffer itself.
- */
-static void
-nvpair_free(nvpair_t *nvp)
-{
- switch (NVP_TYPE(nvp)) {
- case DATA_TYPE_NVLIST:
- nvlist_free(EMBEDDED_NVL(nvp));
- break;
- case DATA_TYPE_NVLIST_ARRAY: {
- nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp);
- int i;
-
- for (i = 0; i < NVP_NELEM(nvp); i++)
- if (nvlp[i] != NULL)
- nvlist_free(nvlp[i]);
- break;
- }
- default:
- break;
- }
-}
-
-/*
- * nvlist_free - free an unpacked nvlist
- */
-void
-nvlist_free(nvlist_t *nvl)
-{
- nvpriv_t *priv;
- i_nvp_t *curr;
-
- if (nvl == NULL ||
- (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
- return;
-
- /*
- * Unpacked nvlist are linked through i_nvp_t
- */
- curr = priv->nvp_list;
- while (curr != NULL) {
- nvpair_t *nvp = &curr->nvi_nvp;
- curr = curr->nvi_next;
-
- nvpair_free(nvp);
- nvp_buf_free(nvl, nvp);
- }
-
- if (!(priv->nvp_stat & NV_STAT_EMBEDDED))
- nv_mem_free(priv, nvl, NV_ALIGN(sizeof (nvlist_t)));
- else
- nvl->nvl_priv = 0;
-
- nv_mem_free(priv, priv, sizeof (nvpriv_t));
-}
-
-static int
-nvlist_contains_nvp(nvlist_t *nvl, nvpair_t *nvp)
-{
- nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
- i_nvp_t *curr;
-
- if (nvp == NULL)
- return (0);
-
- for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next)
- if (&curr->nvi_nvp == nvp)
- return (1);
-
- return (0);
-}
-
-/*
- * Make a copy of nvlist
- */
-/*ARGSUSED1*/
-int
-nvlist_dup(nvlist_t *nvl, nvlist_t **nvlp, int kmflag)
-{
-#if defined(_KERNEL) && !defined(_BOOT)
- return (nvlist_xdup(nvl, nvlp,
- (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep)));
-#else
- return (nvlist_xdup(nvl, nvlp, nv_alloc_nosleep));
-#endif
-}
-
-int
-nvlist_xdup(nvlist_t *nvl, nvlist_t **nvlp, nv_alloc_t *nva)
-{
- int err;
- nvlist_t *ret;
-
- if (nvl == NULL || nvlp == NULL)
- return (EINVAL);
-
- if ((err = nvlist_xalloc(&ret, nvl->nvl_nvflag, nva)) != 0)
- return (err);
-
- if ((err = nvlist_copy_pairs(nvl, ret)) != 0)
- nvlist_free(ret);
- else
- *nvlp = ret;
-
- return (err);
-}
-
-/*
- * Remove all with matching name
- */
-int
-nvlist_remove_all(nvlist_t *nvl, const char *name)
-{
- nvpriv_t *priv;
- i_nvp_t *curr;
- int error = ENOENT;
-
- if (nvl == NULL || name == NULL ||
- (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
- return (EINVAL);
-
- curr = priv->nvp_list;
- while (curr != NULL) {
- nvpair_t *nvp = &curr->nvi_nvp;
-
- curr = curr->nvi_next;
- if (strcmp(name, NVP_NAME(nvp)) != 0)
- continue;
-
- nvp_buf_unlink(nvl, nvp);
- nvpair_free(nvp);
- nvp_buf_free(nvl, nvp);
-
- error = 0;
- }
-
- return (error);
-}
-
-/*
- * Remove first one with matching name and type
- */
-int
-nvlist_remove(nvlist_t *nvl, const char *name, data_type_t type)
-{
- nvpriv_t *priv;
- i_nvp_t *curr;
-
- if (nvl == NULL || name == NULL ||
- (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
- return (EINVAL);
-
- curr = priv->nvp_list;
- while (curr != NULL) {
- nvpair_t *nvp = &curr->nvi_nvp;
-
- if (strcmp(name, NVP_NAME(nvp)) == 0 && NVP_TYPE(nvp) == type) {
- nvp_buf_unlink(nvl, nvp);
- nvpair_free(nvp);
- nvp_buf_free(nvl, nvp);
-
- return (0);
- }
- curr = curr->nvi_next;
- }
-
- return (ENOENT);
-}
-
-int
-nvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp)
-{
- if (nvl == NULL || nvp == NULL)
- return (EINVAL);
-
- nvp_buf_unlink(nvl, nvp);
- nvpair_free(nvp);
- nvp_buf_free(nvl, nvp);
- 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
-i_get_value_size(data_type_t type, const void *data, uint_t nelem)
-{
- uint64_t value_sz;
-
- if (i_validate_type_nelem(type, nelem) != 0)
- return (-1);
-
- /* Calculate required size for holding value */
- switch (type) {
- case DATA_TYPE_BOOLEAN:
- value_sz = 0;
- break;
- case DATA_TYPE_BOOLEAN_VALUE:
- value_sz = sizeof (boolean_t);
- break;
- case DATA_TYPE_BYTE:
- value_sz = sizeof (uchar_t);
- break;
- case DATA_TYPE_INT8:
- value_sz = sizeof (int8_t);
- break;
- case DATA_TYPE_UINT8:
- value_sz = sizeof (uint8_t);
- break;
- case DATA_TYPE_INT16:
- value_sz = sizeof (int16_t);
- break;
- case DATA_TYPE_UINT16:
- value_sz = sizeof (uint16_t);
- break;
- case DATA_TYPE_INT32:
- value_sz = sizeof (int32_t);
- break;
- case DATA_TYPE_UINT32:
- value_sz = sizeof (uint32_t);
- break;
- case DATA_TYPE_INT64:
- value_sz = sizeof (int64_t);
- break;
- case DATA_TYPE_UINT64:
- value_sz = sizeof (uint64_t);
- break;
-#if !defined(_KERNEL)
- case DATA_TYPE_DOUBLE:
- value_sz = sizeof (double);
- break;
-#endif
- case DATA_TYPE_STRING:
- if (data == NULL)
- value_sz = 0;
- else
- value_sz = strlen(data) + 1;
- break;
- case DATA_TYPE_BOOLEAN_ARRAY:
- value_sz = (uint64_t)nelem * sizeof (boolean_t);
- break;
- case DATA_TYPE_BYTE_ARRAY:
- value_sz = (uint64_t)nelem * sizeof (uchar_t);
- break;
- case DATA_TYPE_INT8_ARRAY:
- value_sz = (uint64_t)nelem * sizeof (int8_t);
- break;
- case DATA_TYPE_UINT8_ARRAY:
- value_sz = (uint64_t)nelem * sizeof (uint8_t);
- break;
- case DATA_TYPE_INT16_ARRAY:
- value_sz = (uint64_t)nelem * sizeof (int16_t);
- break;
- case DATA_TYPE_UINT16_ARRAY:
- value_sz = (uint64_t)nelem * sizeof (uint16_t);
- break;
- case DATA_TYPE_INT32_ARRAY:
- value_sz = (uint64_t)nelem * sizeof (int32_t);
- break;
- 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;
- uint_t i;
-
- /* no alignment requirement for strings */
- for (i = 0; i < nelem; i++) {
- if (strs[i] == NULL)
- return (-1);
- value_sz += strlen(strs[i]) + 1;
- }
- }
- break;
- case DATA_TYPE_HRTIME:
- value_sz = sizeof (hrtime_t);
- break;
- case DATA_TYPE_NVLIST:
- value_sz = NV_ALIGN(sizeof (nvlist_t));
- break;
- case DATA_TYPE_NVLIST_ARRAY:
- value_sz = (uint64_t)nelem * sizeof (uint64_t) +
- (uint64_t)nelem * NV_ALIGN(sizeof (nvlist_t));
- break;
- default:
- return (-1);
- }
-
- return (value_sz > INT32_MAX ? -1 : (int)value_sz);
-}
-
-static int
-nvlist_copy_embedded(nvlist_t *nvl, nvlist_t *onvl, nvlist_t *emb_nvl)
-{
- nvpriv_t *priv;
- int err;
-
- if ((priv = nv_priv_alloc_embedded((nvpriv_t *)(uintptr_t)
- nvl->nvl_priv)) == NULL)
- return (ENOMEM);
-
- nvlist_init(emb_nvl, onvl->nvl_nvflag, priv);
-
- if ((err = nvlist_copy_pairs(onvl, emb_nvl)) != 0) {
- nvlist_free(emb_nvl);
- emb_nvl->nvl_priv = 0;
- }
-
- return (err);
-}
-
-/*
- * nvlist_add_common - Add new <name,value> pair to nvlist
- */
-static int
-nvlist_add_common(nvlist_t *nvl, const char *name,
- data_type_t type, uint_t nelem, const void *data)
-{
- nvpair_t *nvp;
- uint_t i;
-
- int nvp_sz, name_sz, value_sz;
- int err = 0;
-
- if (name == NULL || nvl == NULL || nvl->nvl_priv == 0)
- return (EINVAL);
-
- if (nelem != 0 && data == NULL)
- 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.
- */
- if ((value_sz = i_get_value_size(type, data, nelem)) < 0)
- return (EINVAL);
-
- if (i_validate_nvpair_value(type, nelem, data) != 0)
- 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:
- if (data == nvl || data == NULL)
- return (EINVAL);
- break;
- case DATA_TYPE_NVLIST_ARRAY: {
- nvlist_t **onvlp = (nvlist_t **)data;
- for (i = 0; i < nelem; i++) {
- if (onvlp[i] == nvl || onvlp[i] == NULL)
- return (EINVAL);
- }
- break;
- }
- default:
- break;
- }
-
- /* calculate sizes of the nvpair elements and the nvpair itself */
- name_sz = strlen(name) + 1;
-
- nvp_sz = NVP_SIZE_CALC(name_sz, value_sz);
-
- if ((nvp = nvp_buf_alloc(nvl, nvp_sz)) == NULL)
- return (ENOMEM);
-
- ASSERT(nvp->nvp_size == nvp_sz);
- nvp->nvp_name_sz = name_sz;
- nvp->nvp_value_elem = nelem;
- nvp->nvp_type = type;
- bcopy(name, NVP_NAME(nvp), name_sz);
-
- switch (type) {
- case DATA_TYPE_BOOLEAN:
- break;
- case DATA_TYPE_STRING_ARRAY: {
- char *const *strs = data;
- char *buf = NVP_VALUE(nvp);
- char **cstrs = (void *)buf;
-
- /* skip pre-allocated space for pointer array */
- buf += nelem * sizeof (uint64_t);
- for (i = 0; i < nelem; i++) {
- int slen = strlen(strs[i]) + 1;
- bcopy(strs[i], buf, slen);
- cstrs[i] = buf;
- buf += slen;
- }
- break;
- }
- case DATA_TYPE_NVLIST: {
- nvlist_t *nnvl = EMBEDDED_NVL(nvp);
- nvlist_t *onvl = (nvlist_t *)data;
-
- if ((err = nvlist_copy_embedded(nvl, onvl, nnvl)) != 0) {
- nvp_buf_free(nvl, nvp);
- return (err);
- }
- break;
- }
- case DATA_TYPE_NVLIST_ARRAY: {
- nvlist_t **onvlp = (nvlist_t **)data;
- nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp);
- nvlist_t *embedded = (nvlist_t *)
- ((uintptr_t)nvlp + nelem * sizeof (uint64_t));
-
- for (i = 0; i < nelem; i++) {
- if ((err = nvlist_copy_embedded(nvl,
- onvlp[i], embedded)) != 0) {
- /*
- * Free any successfully created lists
- */
- nvpair_free(nvp);
- nvp_buf_free(nvl, nvp);
- return (err);
- }
-
- nvlp[i] = embedded++;
- }
- break;
- }
- default:
- bcopy(data, NVP_VALUE(nvp), value_sz);
- }
-
- /* if unique name, remove before add */
- if (nvl->nvl_nvflag & NV_UNIQUE_NAME)
- (void) nvlist_remove_all(nvl, name);
- else if (nvl->nvl_nvflag & NV_UNIQUE_NAME_TYPE)
- (void) nvlist_remove(nvl, name, type);
-
- nvp_buf_link(nvl, nvp);
-
- return (0);
-}
-
-int
-nvlist_add_boolean(nvlist_t *nvl, const char *name)
-{
- return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN, 0, NULL));
-}
-
-int
-nvlist_add_boolean_value(nvlist_t *nvl, const char *name, boolean_t val)
-{
- return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_VALUE, 1, &val));
-}
-
-int
-nvlist_add_byte(nvlist_t *nvl, const char *name, uchar_t val)
-{
- return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE, 1, &val));
-}
-
-int
-nvlist_add_int8(nvlist_t *nvl, const char *name, int8_t val)
-{
- return (nvlist_add_common(nvl, name, DATA_TYPE_INT8, 1, &val));
-}
-
-int
-nvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t val)
-{
- return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8, 1, &val));
-}
-
-int
-nvlist_add_int16(nvlist_t *nvl, const char *name, int16_t val)
-{
- return (nvlist_add_common(nvl, name, DATA_TYPE_INT16, 1, &val));
-}
-
-int
-nvlist_add_uint16(nvlist_t *nvl, const char *name, uint16_t val)
-{
- return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16, 1, &val));
-}
-
-int
-nvlist_add_int32(nvlist_t *nvl, const char *name, int32_t val)
-{
- return (nvlist_add_common(nvl, name, DATA_TYPE_INT32, 1, &val));
-}
-
-int
-nvlist_add_uint32(nvlist_t *nvl, const char *name, uint32_t val)
-{
- return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32, 1, &val));
-}
-
-int
-nvlist_add_int64(nvlist_t *nvl, const char *name, int64_t val)
-{
- return (nvlist_add_common(nvl, name, DATA_TYPE_INT64, 1, &val));
-}
-
-int
-nvlist_add_uint64(nvlist_t *nvl, const char *name, uint64_t val)
-{
- return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64, 1, &val));
-}
-
-#if !defined(_KERNEL)
-int
-nvlist_add_double(nvlist_t *nvl, const char *name, double val)
-{
- return (nvlist_add_common(nvl, name, DATA_TYPE_DOUBLE, 1, &val));
-}
-#endif
-
-int
-nvlist_add_string(nvlist_t *nvl, const char *name, const char *val)
-{
- return (nvlist_add_common(nvl, name, DATA_TYPE_STRING, 1, (void *)val));
-}
-
-int
-nvlist_add_boolean_array(nvlist_t *nvl, const char *name,
- boolean_t *a, uint_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, uchar_t *a, uint_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, uint_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, uint_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, uint_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, uint_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, uint_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, uint_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, uint_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, uint_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, uint_t n)
-{
- return (nvlist_add_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a));
-}
-
-int
-nvlist_add_hrtime(nvlist_t *nvl, const char *name, hrtime_t val)
-{
- return (nvlist_add_common(nvl, name, DATA_TYPE_HRTIME, 1, &val));
-}
-
-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, uint_t n)
-{
- return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a));
-}
-
-/* reading name-value pairs */
-nvpair_t *
-nvlist_next_nvpair(nvlist_t *nvl, nvpair_t *nvp)
-{
- nvpriv_t *priv;
- i_nvp_t *curr;
-
- if (nvl == NULL ||
- (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
- return (NULL);
-
- curr = NVPAIR2I_NVP(nvp);
-
- /*
- * 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.
- */
- if (nvp == NULL)
- curr = priv->nvp_list;
- else if (priv->nvp_curr == curr || nvlist_contains_nvp(nvl, nvp))
- curr = curr->nvi_next;
- else
- curr = NULL;
-
- priv->nvp_curr = curr;
-
- return (curr != NULL ? &curr->nvi_nvp : NULL);
-}
-
-nvpair_t *
-nvlist_prev_nvpair(nvlist_t *nvl, nvpair_t *nvp)
-{
- nvpriv_t *priv;
- i_nvp_t *curr;
-
- if (nvl == NULL ||
- (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
- return (NULL);
-
- curr = NVPAIR2I_NVP(nvp);
-
- if (nvp == NULL)
- curr = priv->nvp_last;
- else if (priv->nvp_curr == curr || nvlist_contains_nvp(nvl, nvp))
- curr = curr->nvi_prev;
- else
- curr = NULL;
-
- priv->nvp_curr = curr;
-
- return (curr != NULL ? &curr->nvi_nvp : NULL);
-}
-
-boolean_t
-nvlist_empty(nvlist_t *nvl)
-{
- nvpriv_t *priv;
-
- if (nvl == NULL ||
- (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
- return (B_TRUE);
-
- return (priv->nvp_list == NULL);
-}
-
-char *
-nvpair_name(nvpair_t *nvp)
-{
- return (NVP_NAME(nvp));
-}
-
-data_type_t
-nvpair_type(nvpair_t *nvp)
-{
- return (NVP_TYPE(nvp));
-}
-
-int
-nvpair_type_is_array(nvpair_t *nvp)
-{
- data_type_t type = NVP_TYPE(nvp);
-
- 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
-nvpair_value_common(nvpair_t *nvp, data_type_t type, uint_t *nelem, void *data)
-{
- if (nvp == NULL || nvpair_type(nvp) != type)
- 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:
- if (nelem != NULL)
- *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
- if (data == NULL)
- return (EINVAL);
- bcopy(NVP_VALUE(nvp), data,
- (size_t)i_get_value_size(type, NULL, 1));
- if (nelem != NULL)
- *nelem = 1;
- break;
-
- case DATA_TYPE_NVLIST:
- case DATA_TYPE_STRING:
- if (data == NULL)
- return (EINVAL);
- *(void **)data = (void *)NVP_VALUE(nvp);
- if (nelem != NULL)
- *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:
- if (nelem == NULL || data == NULL)
- return (EINVAL);
- if ((*nelem = NVP_NELEM(nvp)) != 0)
- *(void **)data = (void *)NVP_VALUE(nvp);
- else
- *(void **)data = NULL;
- break;
-
- default:
- return (ENOTSUP);
- }
-
- return (0);
-}
-
-static int
-nvlist_lookup_common(nvlist_t *nvl, const char *name, data_type_t type,
- uint_t *nelem, void *data)
-{
- nvpriv_t *priv;
- nvpair_t *nvp;
- i_nvp_t *curr;
-
- if (name == NULL || nvl == NULL ||
- (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
- return (EINVAL);
-
- if (!(nvl->nvl_nvflag & (NV_UNIQUE_NAME | NV_UNIQUE_NAME_TYPE)))
- return (ENOTSUP);
-
- for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
- nvp = &curr->nvi_nvp;
-
- if (strcmp(name, NVP_NAME(nvp)) == 0 && NVP_TYPE(nvp) == type)
- return (nvpair_value_common(nvp, type, nelem, data));
- }
-
- return (ENOENT);
-}
-
-int
-nvlist_lookup_boolean(nvlist_t *nvl, const char *name)
-{
- return (nvlist_lookup_common(nvl, name, DATA_TYPE_BOOLEAN, NULL, NULL));
-}
-
-int
-nvlist_lookup_boolean_value(nvlist_t *nvl, const char *name, boolean_t *val)
-{
- return (nvlist_lookup_common(nvl, name,
- DATA_TYPE_BOOLEAN_VALUE, NULL, val));
-}
-
-int
-nvlist_lookup_byte(nvlist_t *nvl, const char *name, uchar_t *val)
-{
- return (nvlist_lookup_common(nvl, name, DATA_TYPE_BYTE, NULL, val));
-}
-
-int
-nvlist_lookup_int8(nvlist_t *nvl, const char *name, int8_t *val)
-{
- return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT8, NULL, val));
-}
-
-int
-nvlist_lookup_uint8(nvlist_t *nvl, const char *name, uint8_t *val)
-{
- return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT8, NULL, val));
-}
-
-int
-nvlist_lookup_int16(nvlist_t *nvl, const char *name, int16_t *val)
-{
- return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT16, NULL, val));
-}
-
-int
-nvlist_lookup_uint16(nvlist_t *nvl, const char *name, uint16_t *val)
-{
- return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT16, NULL, val));
-}
-
-int
-nvlist_lookup_int32(nvlist_t *nvl, const char *name, int32_t *val)
-{
- return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT32, NULL, val));
-}
-
-int
-nvlist_lookup_uint32(nvlist_t *nvl, const char *name, uint32_t *val)
-{
- return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT32, NULL, val));
-}
-
-int
-nvlist_lookup_int64(nvlist_t *nvl, const char *name, int64_t *val)
-{
- return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT64, NULL, val));
-}
-
-int
-nvlist_lookup_uint64(nvlist_t *nvl, const char *name, uint64_t *val)
-{
- return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT64, NULL, val));
-}
-
-#if !defined(_KERNEL)
-int
-nvlist_lookup_double(nvlist_t *nvl, const char *name, double *val)
-{
- return (nvlist_lookup_common(nvl, name, DATA_TYPE_DOUBLE, NULL, val));
-}
-#endif
-
-int
-nvlist_lookup_string(nvlist_t *nvl, const char *name, char **val)
-{
- return (nvlist_lookup_common(nvl, name, DATA_TYPE_STRING, NULL, val));
-}
-
-int
-nvlist_lookup_nvlist(nvlist_t *nvl, const char *name, nvlist_t **val)
-{
- return (nvlist_lookup_common(nvl, name, DATA_TYPE_NVLIST, NULL, val));
-}
-
-int
-nvlist_lookup_boolean_array(nvlist_t *nvl, const char *name,
- boolean_t **a, uint_t *n)
-{
- return (nvlist_lookup_common(nvl, name,
- DATA_TYPE_BOOLEAN_ARRAY, n, a));
-}
-
-int
-nvlist_lookup_byte_array(nvlist_t *nvl, const char *name,
- uchar_t **a, uint_t *n)
-{
- return (nvlist_lookup_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a));
-}
-
-int
-nvlist_lookup_int8_array(nvlist_t *nvl, const char *name, int8_t **a, uint_t *n)
-{
- return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a));
-}
-
-int
-nvlist_lookup_uint8_array(nvlist_t *nvl, const char *name,
- uint8_t **a, uint_t *n)
-{
- return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a));
-}
-
-int
-nvlist_lookup_int16_array(nvlist_t *nvl, const char *name,
- int16_t **a, uint_t *n)
-{
- return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a));
-}
-
-int
-nvlist_lookup_uint16_array(nvlist_t *nvl, const char *name,
- uint16_t **a, uint_t *n)
-{
- return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a));
-}
-
-int
-nvlist_lookup_int32_array(nvlist_t *nvl, const char *name,
- int32_t **a, uint_t *n)
-{
- return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a));
-}
-
-int
-nvlist_lookup_uint32_array(nvlist_t *nvl, const char *name,
- uint32_t **a, uint_t *n)
-{
- return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a));
-}
-
-int
-nvlist_lookup_int64_array(nvlist_t *nvl, const char *name,
- int64_t **a, uint_t *n)
-{
- return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a));
-}
-
-int
-nvlist_lookup_uint64_array(nvlist_t *nvl, const char *name,
- uint64_t **a, uint_t *n)
-{
- return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a));
-}
-
-int
-nvlist_lookup_string_array(nvlist_t *nvl, const char *name,
- char ***a, uint_t *n)
-{
- return (nvlist_lookup_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a));
-}
-
-int
-nvlist_lookup_nvlist_array(nvlist_t *nvl, const char *name,
- nvlist_t ***a, uint_t *n)
-{
- return (nvlist_lookup_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a));
-}
-
-int
-nvlist_lookup_hrtime(nvlist_t *nvl, const char *name, hrtime_t *val)
-{
- return (nvlist_lookup_common(nvl, name, DATA_TYPE_HRTIME, NULL, val));
-}
-
-int
-nvlist_lookup_pairs(nvlist_t *nvl, int flag, ...)
-{
- va_list ap;
- char *name;
- int noentok = (flag & NV_FLAG_NOENTOK ? 1 : 0);
- int ret = 0;
-
- va_start(ap, flag);
- while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {
- data_type_t type;
- void *val;
- uint_t *nelem;
-
- switch (type = va_arg(ap, data_type_t)) {
- case DATA_TYPE_BOOLEAN:
- ret = nvlist_lookup_common(nvl, name, type, NULL, NULL);
- 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
- val = va_arg(ap, void *);
- ret = nvlist_lookup_common(nvl, name, type, NULL, val);
- 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:
- val = va_arg(ap, void *);
- nelem = va_arg(ap, uint_t *);
- ret = nvlist_lookup_common(nvl, name, type, nelem, val);
- break;
-
- default:
- ret = EINVAL;
- }
-
- if (ret == ENOENT && noentok)
- ret = 0;
- }
- va_end(ap);
-
- 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
-nvlist_lookup_nvpair_ei_sep(nvlist_t *nvl, const char *name, const char sep,
- nvpair_t **ret, int *ip, char **ep)
-{
- nvpair_t *nvp;
- const char *np;
- char *sepp;
- char *idxp, *idxep;
- nvlist_t **nva;
- long idx;
- int n;
-
- if (ip)
- *ip = -1; /* not indexed */
- if (ep)
- *ep = NULL;
-
- if ((nvl == NULL) || (name == NULL))
- return (EINVAL);
-
- /* step through components of name */
- for (np = name; np && *np; np = sepp) {
- /* ensure unique names */
- if (!(nvl->nvl_nvflag & NV_UNIQUE_NAME))
- return (ENOTSUP);
-
- /* skip white space */
- skip_whitespace(np);
- if (*np == 0)
- break;
-
- /* set 'sepp' to end of current component 'np' */
- if (sep)
- sepp = strchr(np, sep);
- else
- sepp = NULL;
-
- /* find start of next "[ index ]..." */
- idxp = strchr(np, '[');
-
- /* if sepp comes first, set idxp to NULL */
- if (sepp && idxp && (sepp < idxp))
- idxp = 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 */
- n = idxp++ - np;
-
- /* keep sepp up to date for *ep use as we advance */
- skip_whitespace(idxp);
- sepp = idxp;
-
- /* determine the index value */
-#if defined(_KERNEL) && !defined(_BOOT)
- if (ddi_strtol(idxp, &idxep, 0, &idx))
- goto fail;
-#else
- idx = strtol(idxp, &idxep, 0);
-#endif
- if (idxep == idxp)
- goto fail;
-
- /* keep sepp up to date for *ep use as we advance */
- sepp = idxep;
-
- /* skip white space index value and check for ']' */
- skip_whitespace(sepp);
- if (*sepp++ != ']')
- goto fail;
-
- /* for embedded arrays, support C syntax: "a[1].b" */
- skip_whitespace(sepp);
- if (sep && (*sepp == sep))
- sepp++;
- } else if (sepp) {
- n = sepp++ - np;
- } else {
- n = strlen(np);
- }
-
- /* trim trailing whitespace by reducing length of 'np' */
- if (n == 0)
- goto fail;
- for (n--; (np[n] == ' ') || (np[n] == '\t'); n--)
- ;
- n++;
-
- /* skip whitespace, and set sepp to NULL if complete */
- if (sepp) {
- skip_whitespace(sepp);
- if (*sepp == 0)
- sepp = NULL;
- }
-
- /*
- * 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.
- */
- for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
- nvp = nvlist_next_nvpair(nvl, nvp)) {
-
- /* continue if no match on name */
- if (strncmp(np, nvpair_name(nvp), n) ||
- (strlen(nvpair_name(nvp)) != n))
- continue;
-
- /* if indexed, verify type is array oriented */
- if (idxp && !nvpair_type_is_array(nvp))
- goto fail;
-
- /*
- * Full match found, return nvp and idx if this
- * was the last component.
- */
- if (sepp == NULL) {
- if (ret)
- *ret = nvp;
- if (ip && idxp)
- *ip = (int)idx; /* return index */
- return (0); /* found */
- }
-
- /*
- * More components: current match must be
- * of DATA_TYPE_NVLIST or DATA_TYPE_NVLIST_ARRAY
- * to support going deeper.
- */
- if (nvpair_type(nvp) == DATA_TYPE_NVLIST) {
- nvl = EMBEDDED_NVL(nvp);
- break;
- } else if (nvpair_type(nvp) == DATA_TYPE_NVLIST_ARRAY) {
- (void) nvpair_value_nvlist_array(nvp,
- &nva, (uint_t *)&n);
- if ((n < 0) || (idx >= n))
- goto fail;
- nvl = nva[idx];
- break;
- }
-
- /* type does not support more levels */
- goto fail;
- }
- if (nvp == NULL)
- goto fail; /* 'name' not found */
-
- /* search for match of next component in embedded 'nvl' list */
- }
-
-fail: if (ep && sepp)
- *ep = sepp;
- return (EINVAL);
-}
-
-/*
- * Return pointer to nvpair with specified 'name'.
- */
-int
-nvlist_lookup_nvpair(nvlist_t *nvl, const char *name, nvpair_t **ret)
-{
- return (nvlist_lookup_nvpair_ei_sep(nvl, name, 0, ret, NULL, NULL));
-}
-
-/*
- * 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.
- */
-int nvlist_lookup_nvpair_embedded_index(nvlist_t *nvl,
- const char *name, nvpair_t **ret, int *ip, char **ep)
-{
- return (nvlist_lookup_nvpair_ei_sep(nvl, name, '.', ret, ip, ep));
-}
-
-boolean_t
-nvlist_exists(nvlist_t *nvl, const char *name)
-{
- nvpriv_t *priv;
- nvpair_t *nvp;
- i_nvp_t *curr;
-
- if (name == NULL || nvl == NULL ||
- (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
- return (B_FALSE);
-
- for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
- nvp = &curr->nvi_nvp;
-
- if (strcmp(name, NVP_NAME(nvp)) == 0)
- return (B_TRUE);
- }
-
- return (B_FALSE);
-}
-
-int
-nvpair_value_boolean_value(nvpair_t *nvp, boolean_t *val)
-{
- return (nvpair_value_common(nvp, DATA_TYPE_BOOLEAN_VALUE, NULL, val));
-}
-
-int
-nvpair_value_byte(nvpair_t *nvp, uchar_t *val)
-{
- return (nvpair_value_common(nvp, DATA_TYPE_BYTE, NULL, val));
-}
-
-int
-nvpair_value_int8(nvpair_t *nvp, int8_t *val)
-{
- return (nvpair_value_common(nvp, DATA_TYPE_INT8, NULL, val));
-}
-
-int
-nvpair_value_uint8(nvpair_t *nvp, uint8_t *val)
-{
- return (nvpair_value_common(nvp, DATA_TYPE_UINT8, NULL, val));
-}
-
-int
-nvpair_value_int16(nvpair_t *nvp, int16_t *val)
-{
- return (nvpair_value_common(nvp, DATA_TYPE_INT16, NULL, val));
-}
-
-int
-nvpair_value_uint16(nvpair_t *nvp, uint16_t *val)
-{
- return (nvpair_value_common(nvp, DATA_TYPE_UINT16, NULL, val));
-}
-
-int
-nvpair_value_int32(nvpair_t *nvp, int32_t *val)
-{
- return (nvpair_value_common(nvp, DATA_TYPE_INT32, NULL, val));
-}
-
-int
-nvpair_value_uint32(nvpair_t *nvp, uint32_t *val)
-{
- return (nvpair_value_common(nvp, DATA_TYPE_UINT32, NULL, val));
-}
-
-int
-nvpair_value_int64(nvpair_t *nvp, int64_t *val)
-{
- return (nvpair_value_common(nvp, DATA_TYPE_INT64, NULL, val));
-}
-
-int
-nvpair_value_uint64(nvpair_t *nvp, uint64_t *val)
-{
- return (nvpair_value_common(nvp, DATA_TYPE_UINT64, NULL, val));
-}
-
-#if !defined(_KERNEL)
-int
-nvpair_value_double(nvpair_t *nvp, double *val)
-{
- return (nvpair_value_common(nvp, DATA_TYPE_DOUBLE, NULL, val));
-}
-#endif
-
-int
-nvpair_value_string(nvpair_t *nvp, char **val)
-{
- return (nvpair_value_common(nvp, DATA_TYPE_STRING, NULL, val));
-}
-
-int
-nvpair_value_nvlist(nvpair_t *nvp, nvlist_t **val)
-{
- return (nvpair_value_common(nvp, DATA_TYPE_NVLIST, NULL, val));
-}
-
-int
-nvpair_value_boolean_array(nvpair_t *nvp, boolean_t **val, uint_t *nelem)
-{
- return (nvpair_value_common(nvp, DATA_TYPE_BOOLEAN_ARRAY, nelem, val));
-}
-
-int
-nvpair_value_byte_array(nvpair_t *nvp, uchar_t **val, uint_t *nelem)
-{
- return (nvpair_value_common(nvp, DATA_TYPE_BYTE_ARRAY, nelem, val));
-}
-
-int
-nvpair_value_int8_array(nvpair_t *nvp, int8_t **val, uint_t *nelem)
-{
- return (nvpair_value_common(nvp, DATA_TYPE_INT8_ARRAY, nelem, val));
-}
-
-int
-nvpair_value_uint8_array(nvpair_t *nvp, uint8_t **val, uint_t *nelem)
-{
- return (nvpair_value_common(nvp, DATA_TYPE_UINT8_ARRAY, nelem, val));
-}
-
-int
-nvpair_value_int16_array(nvpair_t *nvp, int16_t **val, uint_t *nelem)
-{
- return (nvpair_value_common(nvp, DATA_TYPE_INT16_ARRAY, nelem, val));
-}
-
-int
-nvpair_value_uint16_array(nvpair_t *nvp, uint16_t **val, uint_t *nelem)
-{
- return (nvpair_value_common(nvp, DATA_TYPE_UINT16_ARRAY, nelem, val));
-}
-
-int
-nvpair_value_int32_array(nvpair_t *nvp, int32_t **val, uint_t *nelem)
-{
- return (nvpair_value_common(nvp, DATA_TYPE_INT32_ARRAY, nelem, val));
-}
-
-int
-nvpair_value_uint32_array(nvpair_t *nvp, uint32_t **val, uint_t *nelem)
-{
- return (nvpair_value_common(nvp, DATA_TYPE_UINT32_ARRAY, nelem, val));
-}
-
-int
-nvpair_value_int64_array(nvpair_t *nvp, int64_t **val, uint_t *nelem)
-{
- return (nvpair_value_common(nvp, DATA_TYPE_INT64_ARRAY, nelem, val));
-}
-
-int
-nvpair_value_uint64_array(nvpair_t *nvp, uint64_t **val, uint_t *nelem)
-{
- return (nvpair_value_common(nvp, DATA_TYPE_UINT64_ARRAY, nelem, val));
-}
-
-int
-nvpair_value_string_array(nvpair_t *nvp, char ***val, uint_t *nelem)
-{
- return (nvpair_value_common(nvp, DATA_TYPE_STRING_ARRAY, nelem, val));
-}
-
-int
-nvpair_value_nvlist_array(nvpair_t *nvp, nvlist_t ***val, uint_t *nelem)
-{
- return (nvpair_value_common(nvp, DATA_TYPE_NVLIST_ARRAY, nelem, val));
-}
-
-int
-nvpair_value_hrtime(nvpair_t *nvp, hrtime_t *val)
-{
- return (nvpair_value_common(nvp, DATA_TYPE_HRTIME, NULL, val));
-}
-
-/*
- * Add specified pair to the list.
- */
-int
-nvlist_add_nvpair(nvlist_t *nvl, nvpair_t *nvp)
-{
- if (nvl == NULL || nvp == NULL)
- return (EINVAL);
-
- return (nvlist_add_common(nvl, NVP_NAME(nvp), NVP_TYPE(nvp),
- NVP_NELEM(nvp), NVP_VALUE(nvp)));
-}
-
-/*
- * 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
-nvlist_merge(nvlist_t *dst, nvlist_t *nvl, int flag)
-{
- if (nvl == NULL || dst == NULL)
- return (EINVAL);
-
- if (dst != nvl)
- return (nvlist_copy_pairs(nvl, dst));
-
- return (0);
-}
-
-/*
- * Encoding related routines
- */
-#define NVS_OP_ENCODE 0
-#define NVS_OP_DECODE 1
-#define NVS_OP_GETSIZE 2
-
-typedef struct nvs_ops nvs_ops_t;
-
-typedef struct {
- int nvs_op;
- const nvs_ops_t *nvs_ops;
- void *nvs_private;
- nvpriv_t *nvs_priv;
-} 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 {
- int (*nvs_nvlist)(nvstream_t *, nvlist_t *, size_t *);
- int (*nvs_nvpair)(nvstream_t *, nvpair_t *, size_t *);
- int (*nvs_nvp_op)(nvstream_t *, nvpair_t *);
- int (*nvs_nvp_size)(nvstream_t *, nvpair_t *, size_t *);
- int (*nvs_nvl_fini)(nvstream_t *);
-};
-
-typedef struct {
- char nvh_encoding; /* nvs encoding method */
- char nvh_endian; /* nvs endian */
- char nvh_reserved1; /* reserved for future use */
- char nvh_reserved2; /* reserved for future use */
-} nvs_header_t;
-
-static int
-nvs_encode_pairs(nvstream_t *nvs, nvlist_t *nvl)
-{
- nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
- i_nvp_t *curr;
-
- /*
- * Walk nvpair in list and encode each nvpair
- */
- for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next)
- if (nvs->nvs_ops->nvs_nvpair(nvs, &curr->nvi_nvp, NULL) != 0)
- return (EFAULT);
-
- return (nvs->nvs_ops->nvs_nvl_fini(nvs));
-}
-
-static int
-nvs_decode_pairs(nvstream_t *nvs, nvlist_t *nvl)
-{
- nvpair_t *nvp;
- size_t nvsize;
- int err;
-
- /*
- * Get decoded size of next pair in stream, alloc
- * memory for nvpair_t, then decode the nvpair
- */
- while ((err = nvs->nvs_ops->nvs_nvpair(nvs, NULL, &nvsize)) == 0) {
- if (nvsize == 0) /* end of list */
- break;
-
- /* make sure len makes sense */
- if (nvsize < NVP_SIZE_CALC(1, 0))
- return (EFAULT);
-
- if ((nvp = nvp_buf_alloc(nvl, nvsize)) == NULL)
- return (ENOMEM);
-
- if ((err = nvs->nvs_ops->nvs_nvp_op(nvs, nvp)) != 0) {
- nvp_buf_free(nvl, nvp);
- return (err);
- }
-
- if (i_validate_nvpair(nvp) != 0) {
- nvpair_free(nvp);
- nvp_buf_free(nvl, nvp);
- return (EFAULT);
- }
-
- nvp_buf_link(nvl, nvp);
- }
- return (err);
-}
-
-static int
-nvs_getsize_pairs(nvstream_t *nvs, nvlist_t *nvl, size_t *buflen)
-{
- nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
- i_nvp_t *curr;
- uint64_t nvsize = *buflen;
- size_t size;
-
- /*
- * Get encoded size of nvpairs in nvlist
- */
- for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
- if (nvs->nvs_ops->nvs_nvp_size(nvs, &curr->nvi_nvp, &size) != 0)
- return (EINVAL);
-
- if ((nvsize += size) > INT32_MAX)
- return (EINVAL);
- }
-
- *buflen = nvsize;
- return (0);
-}
-
-static int
-nvs_operation(nvstream_t *nvs, nvlist_t *nvl, size_t *buflen)
-{
- int err;
-
- if (nvl->nvl_priv == 0)
- return (EFAULT);
-
- /*
- * Perform the operation, starting with header, then each nvpair
- */
- if ((err = nvs->nvs_ops->nvs_nvlist(nvs, nvl, buflen)) != 0)
- return (err);
-
- switch (nvs->nvs_op) {
- case NVS_OP_ENCODE:
- err = nvs_encode_pairs(nvs, nvl);
- break;
-
- case NVS_OP_DECODE:
- err = nvs_decode_pairs(nvs, nvl);
- break;
-
- case NVS_OP_GETSIZE:
- err = nvs_getsize_pairs(nvs, nvl, buflen);
- break;
-
- default:
- err = EINVAL;
- }
-
- return (err);
-}
-
-static int
-nvs_embedded(nvstream_t *nvs, nvlist_t *embedded)
-{
- switch (nvs->nvs_op) {
- case NVS_OP_ENCODE:
- return (nvs_operation(nvs, embedded, NULL));
-
- case NVS_OP_DECODE: {
- nvpriv_t *priv;
- int err;
-
- if (embedded->nvl_version != NV_VERSION)
- return (ENOTSUP);
-
- if ((priv = nv_priv_alloc_embedded(nvs->nvs_priv)) == NULL)
- return (ENOMEM);
-
- nvlist_init(embedded, embedded->nvl_nvflag, priv);
-
- if ((err = nvs_operation(nvs, embedded, NULL)) != 0)
- nvlist_free(embedded);
- return (err);
- }
- default:
- break;
- }
-
- return (EINVAL);
-}
-
-static int
-nvs_embedded_nvl_array(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
-{
- size_t nelem = NVP_NELEM(nvp);
- nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp);
- int i;
-
- switch (nvs->nvs_op) {
- case NVS_OP_ENCODE:
- for (i = 0; i < nelem; i++)
- if (nvs_embedded(nvs, nvlp[i]) != 0)
- return (EFAULT);
- break;
-
- case NVS_OP_DECODE: {
- size_t len = nelem * sizeof (uint64_t);
- nvlist_t *embedded = (nvlist_t *)((uintptr_t)nvlp + len);
-
- bzero(nvlp, len); /* don't trust packed data */
- for (i = 0; i < nelem; i++) {
- if (nvs_embedded(nvs, embedded) != 0) {
- nvpair_free(nvp);
- return (EFAULT);
- }
-
- nvlp[i] = embedded++;
- }
- break;
- }
- case NVS_OP_GETSIZE: {
- uint64_t nvsize = 0;
-
- for (i = 0; i < nelem; i++) {
- size_t nvp_sz = 0;
-
- if (nvs_operation(nvs, nvlp[i], &nvp_sz) != 0)
- return (EINVAL);
-
- if ((nvsize += nvp_sz) > INT32_MAX)
- return (EINVAL);
- }
-
- *size = nvsize;
- break;
- }
- default:
- return (EINVAL);
- }
-
- return (0);
-}
-
-static int nvs_native(nvstream_t *, nvlist_t *, char *, size_t *);
-static int nvs_xdr(nvstream_t *, nvlist_t *, char *, size_t *);
-
-/*
- * Common routine for nvlist operations:
- * encode, decode, getsize (encoded size).
- */
-static int
-nvlist_common(nvlist_t *nvl, char *buf, size_t *buflen, int encoding,
- int nvs_op)
-{
- int err = 0;
- nvstream_t nvs;
- int nvl_endian;
-#if BYTE_ORDER == _LITTLE_ENDIAN
- int host_endian = 1;
-#else
- int host_endian = 0;
-#endif /* _LITTLE_ENDIAN */
- nvs_header_t *nvh = (void *)buf;
-
- if (buflen == NULL || nvl == NULL ||
- (nvs.nvs_priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
- return (EINVAL);
-
- nvs.nvs_op = nvs_op;
-
- /*
- * 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:
- if (buf == NULL || *buflen < sizeof (nvs_header_t))
- return (EINVAL);
-
- nvh->nvh_encoding = encoding;
- nvh->nvh_endian = nvl_endian = host_endian;
- nvh->nvh_reserved1 = 0;
- nvh->nvh_reserved2 = 0;
- break;
-
- case NVS_OP_DECODE:
- if (buf == NULL || *buflen < sizeof (nvs_header_t))
- return (EINVAL);
-
- /* get method of encoding from first byte */
- encoding = nvh->nvh_encoding;
- nvl_endian = nvh->nvh_endian;
- break;
-
- case NVS_OP_GETSIZE:
- nvl_endian = host_endian;
-
- /*
- * 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);
- err = nvs_native(&nvs, nvl, buf, buflen);
- break;
- case NV_ENCODE_XDR:
- err = nvs_xdr(&nvs, nvl, buf, buflen);
- break;
- default:
- err = ENOTSUP;
- break;
- }
-
- return (err);
-}
-
-int
-nvlist_size(nvlist_t *nvl, size_t *size, int encoding)
-{
- return (nvlist_common(nvl, NULL, size, encoding, NVS_OP_GETSIZE));
-}
-
-/*
- * Pack nvlist into contiguous memory
- */
-/*ARGSUSED1*/
-int
-nvlist_pack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding,
- int kmflag)
-{
-#if defined(_KERNEL) && !defined(_BOOT)
- return (nvlist_xpack(nvl, bufp, buflen, encoding,
- (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep)));
-#else
- return (nvlist_xpack(nvl, bufp, buflen, encoding, nv_alloc_nosleep));
-#endif
-}
-
-int
-nvlist_xpack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding,
- nv_alloc_t *nva)
-{
- nvpriv_t nvpriv;
- size_t alloc_size;
- char *buf;
- int err;
-
- if (nva == NULL || nvl == NULL || bufp == NULL || buflen == NULL)
- return (EINVAL);
-
- if (*bufp != NULL)
- return (nvlist_common(nvl, *bufp, buflen, encoding,
- NVS_OP_ENCODE));
-
- /*
- * 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.
- */
- nv_priv_init(&nvpriv, nva, 0);
-
- if (err = nvlist_size(nvl, &alloc_size, encoding))
- return (err);
-
- if ((buf = nv_mem_zalloc(&nvpriv, alloc_size)) == NULL)
- return (ENOMEM);
-
- if ((err = nvlist_common(nvl, buf, &alloc_size, encoding,
- NVS_OP_ENCODE)) != 0) {
- nv_mem_free(&nvpriv, buf, alloc_size);
- } else {
- *buflen = alloc_size;
- *bufp = buf;
- }
-
- return (err);
-}
-
-/*
- * Unpack buf into an nvlist_t
- */
-/*ARGSUSED1*/
-int
-nvlist_unpack(char *buf, size_t buflen, nvlist_t **nvlp, int kmflag)
-{
-#if defined(_KERNEL) && !defined(_BOOT)
- return (nvlist_xunpack(buf, buflen, nvlp,
- (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep)));
-#else
- return (nvlist_xunpack(buf, buflen, nvlp, nv_alloc_nosleep));
-#endif
-}
-
-int
-nvlist_xunpack(char *buf, size_t buflen, nvlist_t **nvlp, nv_alloc_t *nva)
-{
- nvlist_t *nvl;
- int err;
-
- if (nvlp == NULL)
- return (EINVAL);
-
- if ((err = nvlist_xalloc(&nvl, 0, nva)) != 0)
- return (err);
-
- if ((err = nvlist_common(nvl, buf, &buflen, 0, NVS_OP_DECODE)) != 0)
- nvlist_free(nvl);
- else
- *nvlp = nvl;
-
- 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.
- */
- caddr_t n_base;
- caddr_t n_end;
- caddr_t n_curr;
- uint_t n_flag;
-} nvs_native_t;
-
-static int
-nvs_native_create(nvstream_t *nvs, nvs_native_t *native, char *buf,
- size_t buflen)
-{
- switch (nvs->nvs_op) {
- case NVS_OP_ENCODE:
- case NVS_OP_DECODE:
- nvs->nvs_private = native;
- native->n_curr = native->n_base = buf;
- native->n_end = buf + buflen;
- native->n_flag = 0;
- return (0);
-
- case NVS_OP_GETSIZE:
- nvs->nvs_private = native;
- native->n_curr = native->n_base = native->n_end = NULL;
- native->n_flag = 0;
- return (0);
- default:
- return (EINVAL);
- }
-}
-
-/*ARGSUSED*/
-static void
-nvs_native_destroy(nvstream_t *nvs)
-{
-}
-
-static int
-native_cp(nvstream_t *nvs, void *buf, size_t size)
-{
- nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
-
- if (native->n_curr + size > native->n_end)
- return (EFAULT);
-
- /*
- * The bcopy() below eliminates alignment requirement
- * on the buffer (stream) and is preferred over direct access.
- */
- switch (nvs->nvs_op) {
- case NVS_OP_ENCODE:
- bcopy(buf, native->n_curr, size);
- break;
- case NVS_OP_DECODE:
- bcopy(native->n_curr, buf, size);
- break;
- default:
- return (EINVAL);
- }
-
- native->n_curr += size;
- return (0);
-}
-
-/*
- * operate on nvlist_t header
- */
-static int
-nvs_native_nvlist(nvstream_t *nvs, nvlist_t *nvl, size_t *size)
-{
- nvs_native_t *native = nvs->nvs_private;
-
- switch (nvs->nvs_op) {
- case NVS_OP_ENCODE:
- case NVS_OP_DECODE:
- if (native->n_flag)
- return (0); /* packed embedded list */
-
- native->n_flag = 1;
-
- /* copy version and nvflag of the nvlist_t */
- if (native_cp(nvs, &nvl->nvl_version, sizeof (int32_t)) != 0 ||
- native_cp(nvs, &nvl->nvl_nvflag, sizeof (int32_t)) != 0)
- 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
- */
- if (native->n_flag) {
- *size += 4;
- } else {
- native->n_flag = 1;
- *size += 2 * sizeof (int32_t) + 4;
- }
-
- return (0);
-
- default:
- return (EINVAL);
- }
-}
-
-static int
-nvs_native_nvl_fini(nvstream_t *nvs)
-{
- if (nvs->nvs_op == NVS_OP_ENCODE) {
- nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
- /*
- * Add 4 zero bytes at end of nvlist. They are used
- * for end detection by the decode routine.
- */
- if (native->n_curr + sizeof (int) > native->n_end)
- return (EFAULT);
-
- bzero(native->n_curr, sizeof (int));
- native->n_curr += sizeof (int);
- }
-
- return (0);
-}
-
-static int
-nvpair_native_embedded(nvstream_t *nvs, nvpair_t *nvp)
-{
- if (nvs->nvs_op == NVS_OP_ENCODE) {
- nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
- char *packed = (void *)
- (native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp));
- /*
- * Null out the pointer that is meaningless in the packed
- * structure. The address may not be aligned, so we have
- * to use bzero.
- */
- bzero(packed + offsetof(nvlist_t, nvl_priv),
- sizeof(((nvlist_t *)NULL)->nvl_priv));
- }
-
- return (nvs_embedded(nvs, EMBEDDED_NVL(nvp)));
-}
-
-static int
-nvpair_native_embedded_array(nvstream_t *nvs, nvpair_t *nvp)
-{
- if (nvs->nvs_op == NVS_OP_ENCODE) {
- nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
- char *value = native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp);
- size_t len = NVP_NELEM(nvp) * sizeof (uint64_t);
- int i;
- /*
- * Null out pointers that are meaningless in the packed
- * structure. The addresses may not be aligned, so we have
- * to use bzero.
- */
- bzero(value, len);
-
- value += len;
- for (i = 0; i < NVP_NELEM(nvp); i++) {
- /*
- * Null out the pointer that is meaningless in the
- * packed structure. The address may not be aligned,
- * so we have to use bzero.
- */
- bzero(value + offsetof(nvlist_t, nvl_priv),
- sizeof(((nvlist_t *)NULL)->nvl_priv));
- value += sizeof(nvlist_t);
- }
- }
-
- return (nvs_embedded_nvl_array(nvs, nvp, NULL));
-}
-
-static void
-nvpair_native_string_array(nvstream_t *nvs, nvpair_t *nvp)
-{
- switch (nvs->nvs_op) {
- case NVS_OP_ENCODE: {
- nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
- uint64_t *strp = (void *)
- (native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp));
- /*
- * Null out pointers that are meaningless in the packed
- * structure. The addresses may not be aligned, so we have
- * to use bzero.
- */
- bzero(strp, NVP_NELEM(nvp) * sizeof (uint64_t));
- break;
- }
- case NVS_OP_DECODE: {
- char **strp = (void *)NVP_VALUE(nvp);
- char *buf = ((char *)strp + NVP_NELEM(nvp) * sizeof (uint64_t));
- int i;
-
- for (i = 0; i < NVP_NELEM(nvp); i++) {
- strp[i] = buf;
- buf += strlen(buf) + 1;
- }
- break;
- }
- }
-}
-
-static int
-nvs_native_nvp_op(nvstream_t *nvs, nvpair_t *nvp)
-{
- data_type_t type;
- 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.
- */
- switch (nvs->nvs_op) {
- case NVS_OP_ENCODE:
- case NVS_OP_DECODE:
- if (native_cp(nvs, nvp, nvp->nvp_size) != 0)
- return (EFAULT);
- break;
- default:
- return (EINVAL);
- }
-
- /* verify nvp_name_sz, check the name string length */
- if (i_validate_nvpair_name(nvp) != 0)
- return (EFAULT);
-
- type = NVP_TYPE(nvp);
-
- /*
- * 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.
- */
- if ((value_sz = i_get_value_size(type, NULL, NVP_NELEM(nvp))) < 0)
- return (EFAULT);
-
- if (NVP_SIZE_CALC(nvp->nvp_name_sz, value_sz) > nvp->nvp_size)
- return (EFAULT);
-
- switch (type) {
- case DATA_TYPE_NVLIST:
- ret = nvpair_native_embedded(nvs, nvp);
- break;
- case DATA_TYPE_NVLIST_ARRAY:
- ret = nvpair_native_embedded_array(nvs, nvp);
- break;
- case DATA_TYPE_STRING_ARRAY:
- nvpair_native_string_array(nvs, nvp);
- break;
- default:
- break;
- }
-
- return (ret);
-}
-
-static int
-nvs_native_nvp_size(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
-{
- uint64_t nvp_sz = nvp->nvp_size;
-
- switch (NVP_TYPE(nvp)) {
- case DATA_TYPE_NVLIST: {
- size_t nvsize = 0;
-
- if (nvs_operation(nvs, EMBEDDED_NVL(nvp), &nvsize) != 0)
- return (EINVAL);
-
- nvp_sz += nvsize;
- break;
- }
- case DATA_TYPE_NVLIST_ARRAY: {
- size_t nvsize;
-
- if (nvs_embedded_nvl_array(nvs, nvp, &nvsize) != 0)
- return (EINVAL);
-
- nvp_sz += nvsize;
- break;
- }
- default:
- break;
- }
-
- if (nvp_sz > INT32_MAX)
- return (EINVAL);
-
- *size = nvp_sz;
-
- return (0);
-}
-
-static int
-nvs_native_nvpair(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
-{
- switch (nvs->nvs_op) {
- case NVS_OP_ENCODE:
- return (nvs_native_nvp_op(nvs, nvp));
-
- case NVS_OP_DECODE: {
- nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
- int32_t decode_len;
-
- /* try to read the size value from the stream */
- if (native->n_curr + sizeof (int32_t) > native->n_end)
- return (EFAULT);
- bcopy(native->n_curr, &decode_len, sizeof (int32_t));
-
- /* sanity check the size value */
- if (decode_len < 0 ||
- decode_len > native->n_end - native->n_curr)
- 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)
- native->n_curr += sizeof (int32_t);
- break;
- }
-
- default:
- return (EINVAL);
- }
-
- return (0);
-}
-
-static const nvs_ops_t nvs_native_ops = {
- nvs_native_nvlist,
- nvs_native_nvpair,
- nvs_native_nvp_op,
- nvs_native_nvp_size,
- nvs_native_nvl_fini
-};
-
-static int
-nvs_native(nvstream_t *nvs, nvlist_t *nvl, char *buf, size_t *buflen)
-{
- nvs_native_t native;
- int err;
-
- nvs->nvs_ops = &nvs_native_ops;
-
- if ((err = nvs_native_create(nvs, &native, buf + sizeof (nvs_header_t),
- *buflen - sizeof (nvs_header_t))) != 0)
- return (err);
-
- err = nvs_operation(nvs, nvl, buflen);
-
- nvs_native_destroy(nvs);
-
- 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
-nvs_xdr_create(nvstream_t *nvs, XDR *xdr, char *buf, size_t buflen)
-{
- /* xdr data must be 4 byte aligned */
- if ((ulong_t)buf % 4 != 0)
- return (EFAULT);
-
- switch (nvs->nvs_op) {
- case NVS_OP_ENCODE:
- xdrmem_create(xdr, buf, (uint_t)buflen, XDR_ENCODE);
- nvs->nvs_private = xdr;
- return (0);
- case NVS_OP_DECODE:
- xdrmem_create(xdr, buf, (uint_t)buflen, XDR_DECODE);
- nvs->nvs_private = xdr;
- return (0);
- case NVS_OP_GETSIZE:
- nvs->nvs_private = NULL;
- return (0);
- default:
- return (EINVAL);
- }
-}
-
-static void
-nvs_xdr_destroy(nvstream_t *nvs)
-{
- switch (nvs->nvs_op) {
- case NVS_OP_ENCODE:
- case NVS_OP_DECODE:
- xdr_destroy((XDR *)nvs->nvs_private);
- break;
- default:
- break;
- }
-}
-
-static int
-nvs_xdr_nvlist(nvstream_t *nvs, nvlist_t *nvl, size_t *size)
-{
- switch (nvs->nvs_op) {
- case NVS_OP_ENCODE:
- case NVS_OP_DECODE: {
- XDR *xdr = nvs->nvs_private;
-
- if (!xdr_int(xdr, &nvl->nvl_version) ||
- !xdr_u_int(xdr, &nvl->nvl_nvflag))
- return (EFAULT);
- break;
- }
- case NVS_OP_GETSIZE: {
- /*
- * 2 * 4 for nvl_version + nvl_nvflag
- * and 8 for end of the entire list
- */
- *size += 2 * 4 + 8;
- break;
- }
- default:
- return (EINVAL);
- }
- return (0);
-}
-
-static int
-nvs_xdr_nvl_fini(nvstream_t *nvs)
-{
- if (nvs->nvs_op == NVS_OP_ENCODE) {
- XDR *xdr = nvs->nvs_private;
- int zero = 0;
-
- if (!xdr_int(xdr, &zero) || !xdr_int(xdr, &zero))
- return (EFAULT);
- }
-
- return (0);
-}
-
-/*
- * The format of xdr encoded nvpair is:
- * encode_size, decode_size, name string, data type, nelem, data
- */
-static int
-nvs_xdr_nvp_op(nvstream_t *nvs, nvpair_t *nvp)
-{
- data_type_t type;
- char *buf;
- char *buf_end = (char *)nvp + nvp->nvp_size;
- int value_sz;
- uint_t nelem, buflen;
- bool_t ret = FALSE;
- XDR *xdr = nvs->nvs_private;
-
- ASSERT(xdr != NULL && nvp != NULL);
-
- /* name string */
- if ((buf = NVP_NAME(nvp)) >= buf_end)
- return (EFAULT);
- buflen = buf_end - buf;
-
- if (!xdr_string(xdr, &buf, buflen - 1))
- return (EFAULT);
- nvp->nvp_name_sz = strlen(buf) + 1;
-
- /* type and nelem */
- if (!xdr_int(xdr, (int *)&nvp->nvp_type) ||
- !xdr_int(xdr, &nvp->nvp_value_elem))
- return (EFAULT);
-
- type = NVP_TYPE(nvp);
- nelem = nvp->nvp_value_elem;
-
- /*
- * 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.
- */
- if ((value_sz = i_get_value_size(type, NULL, nelem)) < 0)
- return (EFAULT);
-
- /* if there is no data to extract then return */
- if (nelem == 0)
- return (0);
-
- /* value */
- if ((buf = NVP_VALUE(nvp)) >= buf_end)
- return (EFAULT);
- buflen = buf_end - buf;
-
- if (buflen < value_sz)
- return (EFAULT);
-
- switch (type) {
- case DATA_TYPE_NVLIST:
- if (nvs_embedded(nvs, (void *)buf) == 0)
- return (0);
- break;
-
- case DATA_TYPE_NVLIST_ARRAY:
- if (nvs_embedded_nvl_array(nvs, nvp, NULL) == 0)
- return (0);
- break;
-
- case DATA_TYPE_BOOLEAN:
- ret = TRUE;
- break;
-
- case DATA_TYPE_BYTE:
- case DATA_TYPE_INT8:
- case DATA_TYPE_UINT8:
- ret = xdr_char(xdr, buf);
- break;
-
- case DATA_TYPE_INT16:
- ret = xdr_short(xdr, (void *)buf);
- break;
-
- case DATA_TYPE_UINT16:
- ret = xdr_u_short(xdr, (void *)buf);
- break;
-
- case DATA_TYPE_BOOLEAN_VALUE:
- case DATA_TYPE_INT32:
- ret = xdr_int(xdr, (void *)buf);
- break;
-
- case DATA_TYPE_UINT32:
- ret = xdr_u_int(xdr, (void *)buf);
- break;
-
- case DATA_TYPE_INT64:
- ret = xdr_longlong_t(xdr, (void *)buf);
- break;
-
- case DATA_TYPE_UINT64:
- ret = xdr_u_longlong_t(xdr, (void *)buf);
- break;
-
- case DATA_TYPE_HRTIME:
- /*
- * NOTE: must expose the definition of hrtime_t here
- */
- ret = xdr_longlong_t(xdr, (void *)buf);
- break;
-#if !defined(_KERNEL)
- case DATA_TYPE_DOUBLE:
- ret = xdr_double(xdr, (void *)buf);
- break;
-#endif
- case DATA_TYPE_STRING:
- ret = xdr_string(xdr, &buf, buflen - 1);
- break;
-
- case DATA_TYPE_BYTE_ARRAY:
- ret = xdr_opaque(xdr, buf, nelem);
- break;
-
- case DATA_TYPE_INT8_ARRAY:
- case DATA_TYPE_UINT8_ARRAY:
- ret = xdr_array(xdr, &buf, &nelem, buflen, sizeof (int8_t),
- (xdrproc_t)xdr_char);
- break;
-
- case DATA_TYPE_INT16_ARRAY:
- ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int16_t),
- sizeof (int16_t), (xdrproc_t)xdr_short);
- break;
-
- case DATA_TYPE_UINT16_ARRAY:
- ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint16_t),
- sizeof (uint16_t), (xdrproc_t)xdr_u_short);
- break;
-
- case DATA_TYPE_BOOLEAN_ARRAY:
- case DATA_TYPE_INT32_ARRAY:
- ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int32_t),
- sizeof (int32_t), (xdrproc_t)xdr_int);
- break;
-
- case DATA_TYPE_UINT32_ARRAY:
- ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint32_t),
- sizeof (uint32_t), (xdrproc_t)xdr_u_int);
- break;
-
- case DATA_TYPE_INT64_ARRAY:
- ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int64_t),
- sizeof (int64_t), (xdrproc_t)xdr_longlong_t);
- break;
-
- case DATA_TYPE_UINT64_ARRAY:
- ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint64_t),
- sizeof (uint64_t), (xdrproc_t)xdr_u_longlong_t);
- break;
-
- case DATA_TYPE_STRING_ARRAY: {
- size_t len = nelem * sizeof (uint64_t);
- char **strp = (void *)buf;
- int i;
-
- if (nvs->nvs_op == NVS_OP_DECODE)
- bzero(buf, len); /* don't trust packed data */
-
- for (i = 0; i < nelem; i++) {
- if (buflen <= len)
- return (EFAULT);
-
- buf += len;
- buflen -= len;
-
- if (xdr_string(xdr, &buf, buflen - 1) != TRUE)
- return (EFAULT);
-
- if (nvs->nvs_op == NVS_OP_DECODE)
- strp[i] = buf;
- len = strlen(buf) + 1;
- }
- ret = TRUE;
- break;
- }
- default:
- break;
- }
-
- return (ret == TRUE ? 0 : EFAULT);
-}
-
-static int
-nvs_xdr_nvp_size(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
-{
- data_type_t type = NVP_TYPE(nvp);
- /*
- * encode_size + decode_size + name string size + data type + nelem
- * where name string size = 4 + NV_ALIGN4(strlen(NVP_NAME(nvp)))
- */
- uint64_t nvp_sz = 4 + 4 + 4 + NV_ALIGN4(strlen(NVP_NAME(nvp))) + 4 + 4;
-
- 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:
- nvp_sz += 4; /* 4 is the minimum xdr unit */
- 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:
- nvp_sz += 4 + NV_ALIGN4(strlen((char *)NVP_VALUE(nvp)));
- break;
-
- case DATA_TYPE_BYTE_ARRAY:
- nvp_sz += NV_ALIGN4(NVP_NELEM(nvp));
- 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:
- nvp_sz += 4 + 4 * (uint64_t)NVP_NELEM(nvp);
- break;
-
- case DATA_TYPE_INT64_ARRAY:
- case DATA_TYPE_UINT64_ARRAY:
- nvp_sz += 4 + 8 * (uint64_t)NVP_NELEM(nvp);
- break;
-
- case DATA_TYPE_STRING_ARRAY: {
- int i;
- char **strs = (void *)NVP_VALUE(nvp);
-
- for (i = 0; i < NVP_NELEM(nvp); i++)
- nvp_sz += 4 + NV_ALIGN4(strlen(strs[i]));
-
- break;
- }
-
- case DATA_TYPE_NVLIST:
- case DATA_TYPE_NVLIST_ARRAY: {
- size_t nvsize = 0;
- int old_nvs_op = nvs->nvs_op;
- int err;
-
- nvs->nvs_op = NVS_OP_GETSIZE;
- if (type == DATA_TYPE_NVLIST)
- err = nvs_operation(nvs, EMBEDDED_NVL(nvp), &nvsize);
- else
- err = nvs_embedded_nvl_array(nvs, nvp, &nvsize);
- nvs->nvs_op = old_nvs_op;
-
- if (err != 0)
- return (EINVAL);
-
- nvp_sz += nvsize;
- break;
- }
-
- default:
- return (EINVAL);
- }
-
- if (nvp_sz > INT32_MAX)
- return (EINVAL);
-
- *size = nvp_sz;
-
- 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.
- */
-#define NVS_XDR_HDR_LEN ((size_t)(5 * 4))
-#define NVS_XDR_DATA_LEN(y) (((size_t)(y) <= NVS_XDR_HDR_LEN) ? \
- 0 : ((size_t)(y) - NVS_XDR_HDR_LEN))
-#define NVS_XDR_MAX_LEN(x) (NVP_SIZE_CALC(1, 0) + \
- (NVS_XDR_DATA_LEN(x) * 2) + \
- NV_ALIGN4((NVS_XDR_DATA_LEN(x) / 4)))
-
-static int
-nvs_xdr_nvpair(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
-{
- XDR *xdr = nvs->nvs_private;
- int32_t encode_len, decode_len;
-
- switch (nvs->nvs_op) {
- case NVS_OP_ENCODE: {
- size_t nvsize;
-
- if (nvs_xdr_nvp_size(nvs, nvp, &nvsize) != 0)
- return (EFAULT);
-
- decode_len = nvp->nvp_size;
- encode_len = nvsize;
- if (!xdr_int(xdr, &encode_len) || !xdr_int(xdr, &decode_len))
- return (EFAULT);
-
- return (nvs_xdr_nvp_op(nvs, nvp));
- }
- case NVS_OP_DECODE: {
- struct xdr_bytesrec bytesrec;
-
- /* get the encode and decode size */
- if (!xdr_int(xdr, &encode_len) || !xdr_int(xdr, &decode_len))
- return (EFAULT);
- *size = decode_len;
-
- /* are we at the end of the stream? */
- if (*size == 0)
- return (0);
-
- /* sanity check the size parameter */
- if (!xdr_control(xdr, XDR_GET_BYTES_AVAIL, &bytesrec))
- return (EFAULT);
-
- if (*size > NVS_XDR_MAX_LEN(bytesrec.xc_num_avail))
- return (EFAULT);
- break;
- }
-
- default:
- return (EINVAL);
- }
- return (0);
-}
-
-static const struct nvs_ops nvs_xdr_ops = {
- nvs_xdr_nvlist,
- nvs_xdr_nvpair,
- nvs_xdr_nvp_op,
- nvs_xdr_nvp_size,
- nvs_xdr_nvl_fini
-};
-
-static int
-nvs_xdr(nvstream_t *nvs, nvlist_t *nvl, char *buf, size_t *buflen)
-{
- XDR xdr;
- int err;
-
- nvs->nvs_ops = &nvs_xdr_ops;
-
- if ((err = nvs_xdr_create(nvs, &xdr, buf + sizeof (nvs_header_t),
- *buflen - sizeof (nvs_header_t))) != 0)
- return (err);
-
- err = nvs_operation(nvs, nvl, buflen);
-
- nvs_xdr_destroy(nvs);
-
- return (err);
-}
Index: sys/cddl/contrib/opensolaris/common/nvpair/nvpair_alloc_fixed.c
===================================================================
--- sys/cddl/contrib/opensolaris/common/nvpair/nvpair_alloc_fixed.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * 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
- * or http://www.opensolaris.org/os/licensing.
- * 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 2006 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#include <sys/nvpair.h>
-#include <sys/sysmacros.h>
-#if defined(_KERNEL) && !defined(_BOOT)
-#include <sys/varargs.h>
-#else
-#include <stdarg.h>
-#include <strings.h>
-#endif
-
-/*
- * This allocator is very simple.
- * - it uses a pre-allocated buffer for memory allocations.
- * - it does _not_ free memory in the pre-allocated buffer.
- *
- * The reason for the selected implemention is simplicity.
- * This allocator is designed for the usage in interrupt context when
- * the caller may not wait for free memory.
- */
-
-/* pre-allocated buffer for memory allocations */
-typedef struct nvbuf {
- uintptr_t nvb_buf; /* address of pre-allocated buffer */
- uintptr_t nvb_lim; /* limit address in the buffer */
- uintptr_t nvb_cur; /* current address in the buffer */
-} nvbuf_t;
-
-/*
- * Initialize the pre-allocated buffer allocator. The caller needs to supply
- *
- * buf address of pre-allocated buffer
- * bufsz size of pre-allocated buffer
- *
- * nv_fixed_init() calculates the remaining members of nvbuf_t.
- */
-static int
-nv_fixed_init(nv_alloc_t *nva, va_list valist)
-{
- uintptr_t base = va_arg(valist, uintptr_t);
- uintptr_t lim = base + va_arg(valist, size_t);
- nvbuf_t *nvb = (nvbuf_t *)P2ROUNDUP(base, sizeof (uintptr_t));
-
- if (base == 0 || (uintptr_t)&nvb[1] > lim)
- return (EINVAL);
-
- nvb->nvb_buf = (uintptr_t)&nvb[0];
- nvb->nvb_cur = (uintptr_t)&nvb[1];
- nvb->nvb_lim = lim;
- nva->nva_arg = nvb;
-
- return (0);
-}
-
-static void *
-nv_fixed_alloc(nv_alloc_t *nva, size_t size)
-{
- nvbuf_t *nvb = nva->nva_arg;
- uintptr_t new = nvb->nvb_cur;
-
- if (size == 0 || new + size > nvb->nvb_lim)
- return (NULL);
-
- nvb->nvb_cur = P2ROUNDUP(new + size, sizeof (uintptr_t));
-
- return ((void *)new);
-}
-
-/*ARGSUSED*/
-static void
-nv_fixed_free(nv_alloc_t *nva, void *buf, size_t size)
-{
- /* don't free memory in the pre-allocated buffer */
-}
-
-static void
-nv_fixed_reset(nv_alloc_t *nva)
-{
- nvbuf_t *nvb = nva->nva_arg;
-
- nvb->nvb_cur = (uintptr_t)&nvb[1];
-}
-
-const nv_alloc_ops_t nv_fixed_ops_def = {
- nv_fixed_init, /* nv_ao_init() */
- NULL, /* nv_ao_fini() */
- nv_fixed_alloc, /* nv_ao_alloc() */
- nv_fixed_free, /* nv_ao_free() */
- nv_fixed_reset /* nv_ao_reset() */
-};
-
-const nv_alloc_ops_t *nv_fixed_ops = &nv_fixed_ops_def;
Index: sys/cddl/contrib/opensolaris/common/nvpair/opensolaris_fnvpair.c
===================================================================
--- /dev/null
+++ sys/cddl/contrib/opensolaris/common/nvpair/opensolaris_fnvpair.c
@@ -0,0 +1,512 @@
+
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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) 2012 by Delphix. All rights reserved.
+ */
+
+#include <sys/nvpair.h>
+#ifndef _KERNEL
+#include <sys/zfs_context.h>
+#else
+#include <sys/debug.h>
+#include <sys/kmem.h>
+#include <sys/param.h>
+#include <sys/debug.h>
+#endif
+
+/*
+ * "Force" nvlist wrapper.
+ *
+ * These functions wrap the nvlist_* functions with assertions that assume
+ * the operation is successful. This allows the caller's code to be much
+ * more readable, especially for the fnvlist_lookup_* and fnvpair_value_*
+ * functions, which can return the requested value (rather than filling in
+ * a pointer).
+ *
+ * These functions use NV_UNIQUE_NAME, encoding NV_ENCODE_NATIVE, and allocate
+ * with KM_SLEEP.
+ *
+ * More wrappers should be added as needed -- for example
+ * nvlist_lookup_*_array and nvpair_value_*_array.
+ */
+
+nvlist_t *
+fnvlist_alloc(void)
+{
+ nvlist_t *nvl;
+ VERIFY0(nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP));
+ return (nvl);
+}
+
+void
+fnvlist_free(nvlist_t *nvl)
+{
+ nvlist_free(nvl);
+}
+
+size_t
+fnvlist_size(nvlist_t *nvl)
+{
+ size_t size;
+ VERIFY0(nvlist_size(nvl, &size, NV_ENCODE_NATIVE));
+ return (size);
+}
+
+/*
+ * Returns allocated buffer of size *sizep. Caller must free the buffer with
+ * fnvlist_pack_free().
+ */
+char *
+fnvlist_pack(nvlist_t *nvl, size_t *sizep)
+{
+ char *packed = 0;
+ VERIFY3U(nvlist_pack(nvl, &packed, sizep, NV_ENCODE_NATIVE,
+ KM_SLEEP), ==, 0);
+ return (packed);
+}
+
+/*ARGSUSED*/
+void
+fnvlist_pack_free(char *pack, size_t size)
+{
+#ifdef _KERNEL
+ kmem_free(pack, size);
+#else
+ free(pack);
+#endif
+}
+
+nvlist_t *
+fnvlist_unpack(char *buf, size_t buflen)
+{
+ nvlist_t *rv;
+ VERIFY0(nvlist_unpack(buf, buflen, &rv, KM_SLEEP));
+ return (rv);
+}
+
+nvlist_t *
+fnvlist_dup(nvlist_t *nvl)
+{
+ nvlist_t *rv;
+ VERIFY0(nvlist_dup(nvl, &rv, KM_SLEEP));
+ return (rv);
+}
+
+void
+fnvlist_merge(nvlist_t *dst, nvlist_t *src)
+{
+ VERIFY0(nvlist_merge(dst, src, KM_SLEEP));
+}
+
+size_t
+fnvlist_num_pairs(nvlist_t *nvl)
+{
+ size_t count = 0;
+ nvpair_t *pair;
+
+ for (pair = nvlist_next_nvpair(nvl, 0); pair != NULL;
+ pair = nvlist_next_nvpair(nvl, pair))
+ count++;
+ return (count);
+}
+
+void
+fnvlist_add_boolean(nvlist_t *nvl, const char *name)
+{
+ VERIFY0(nvlist_add_boolean(nvl, name));
+}
+
+void
+fnvlist_add_boolean_value(nvlist_t *nvl, const char *name, boolean_t val)
+{
+ VERIFY0(nvlist_add_boolean_value(nvl, name, val));
+}
+
+void
+fnvlist_add_byte(nvlist_t *nvl, const char *name, uchar_t val)
+{
+ VERIFY0(nvlist_add_byte(nvl, name, val));
+}
+
+void
+fnvlist_add_int8(nvlist_t *nvl, const char *name, int8_t val)
+{
+ VERIFY0(nvlist_add_int8(nvl, name, val));
+}
+
+void
+fnvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t val)
+{
+ VERIFY0(nvlist_add_uint8(nvl, name, val));
+}
+
+void
+fnvlist_add_int16(nvlist_t *nvl, const char *name, int16_t val)
+{
+ VERIFY0(nvlist_add_int16(nvl, name, val));
+}
+
+void
+fnvlist_add_uint16(nvlist_t *nvl, const char *name, uint16_t val)
+{
+ VERIFY0(nvlist_add_uint16(nvl, name, val));
+}
+
+void
+fnvlist_add_int32(nvlist_t *nvl, const char *name, int32_t val)
+{
+ VERIFY0(nvlist_add_int32(nvl, name, val));
+}
+
+void
+fnvlist_add_uint32(nvlist_t *nvl, const char *name, uint32_t val)
+{
+ VERIFY0(nvlist_add_uint32(nvl, name, val));
+}
+
+void
+fnvlist_add_int64(nvlist_t *nvl, const char *name, int64_t val)
+{
+ VERIFY0(nvlist_add_int64(nvl, name, val));
+}
+
+void
+fnvlist_add_uint64(nvlist_t *nvl, const char *name, uint64_t val)
+{
+ VERIFY0(nvlist_add_uint64(nvl, name, val));
+}
+
+void
+fnvlist_add_string(nvlist_t *nvl, const char *name, const char *val)
+{
+ VERIFY0(nvlist_add_string(nvl, name, val));
+}
+
+void
+fnvlist_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val)
+{
+ VERIFY0(nvlist_add_nvlist(nvl, name, val));
+}
+
+void
+fnvlist_add_nvpair(nvlist_t *nvl, nvpair_t *pair)
+{
+ VERIFY0(nvlist_add_nvpair(nvl, pair));
+}
+
+void
+fnvlist_add_boolean_array(nvlist_t *nvl, const char *name,
+ boolean_t *val, uint_t n)
+{
+ VERIFY0(nvlist_add_boolean_array(nvl, name, val, n));
+}
+
+void
+fnvlist_add_byte_array(nvlist_t *nvl, const char *name, uchar_t *val, uint_t n)
+{
+ VERIFY0(nvlist_add_byte_array(nvl, name, val, n));
+}
+
+void
+fnvlist_add_int8_array(nvlist_t *nvl, const char *name, int8_t *val, uint_t n)
+{
+ VERIFY0(nvlist_add_int8_array(nvl, name, val, n));
+}
+
+void
+fnvlist_add_uint8_array(nvlist_t *nvl, const char *name, uint8_t *val, uint_t n)
+{
+ VERIFY0(nvlist_add_uint8_array(nvl, name, val, n));
+}
+
+void
+fnvlist_add_int16_array(nvlist_t *nvl, const char *name, int16_t *val, uint_t n)
+{
+ VERIFY0(nvlist_add_int16_array(nvl, name, val, n));
+}
+
+void
+fnvlist_add_uint16_array(nvlist_t *nvl, const char *name,
+ uint16_t *val, uint_t n)
+{
+ VERIFY0(nvlist_add_uint16_array(nvl, name, val, n));
+}
+
+void
+fnvlist_add_int32_array(nvlist_t *nvl, const char *name, int32_t *val, uint_t n)
+{
+ VERIFY0(nvlist_add_int32_array(nvl, name, val, n));
+}
+
+void
+fnvlist_add_uint32_array(nvlist_t *nvl, const char *name,
+ uint32_t *val, uint_t n)
+{
+ VERIFY0(nvlist_add_uint32_array(nvl, name, val, n));
+}
+
+void
+fnvlist_add_int64_array(nvlist_t *nvl, const char *name, int64_t *val, uint_t n)
+{
+ VERIFY0(nvlist_add_int64_array(nvl, name, val, n));
+}
+
+void
+fnvlist_add_uint64_array(nvlist_t *nvl, const char *name,
+ uint64_t *val, uint_t n)
+{
+ VERIFY0(nvlist_add_uint64_array(nvl, name, val, n));
+}
+
+void
+fnvlist_add_string_array(nvlist_t *nvl, const char *name,
+ char * const *val, uint_t n)
+{
+ VERIFY0(nvlist_add_string_array(nvl, name, val, n));
+}
+
+void
+fnvlist_add_nvlist_array(nvlist_t *nvl, const char *name,
+ nvlist_t **val, uint_t n)
+{
+ VERIFY0(nvlist_add_nvlist_array(nvl, name, val, n));
+}
+
+void
+fnvlist_remove(nvlist_t *nvl, const char *name)
+{
+ VERIFY0(nvlist_remove_all(nvl, name));
+}
+
+void
+fnvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *pair)
+{
+ VERIFY0(nvlist_remove_nvpair(nvl, pair));
+}
+
+nvpair_t *
+fnvlist_lookup_nvpair(nvlist_t *nvl, const char *name)
+{
+ nvpair_t *rv;
+ VERIFY0(nvlist_lookup_nvpair(nvl, name, &rv));
+ return (rv);
+}
+
+/* returns B_TRUE if the entry exists */
+boolean_t
+fnvlist_lookup_boolean(nvlist_t *nvl, const char *name)
+{
+ return (nvlist_lookup_boolean(nvl, name) == 0);
+}
+
+boolean_t
+fnvlist_lookup_boolean_value(nvlist_t *nvl, const char *name)
+{
+ boolean_t rv;
+ VERIFY0(nvlist_lookup_boolean_value(nvl, name, &rv));
+ return (rv);
+}
+
+uchar_t
+fnvlist_lookup_byte(nvlist_t *nvl, const char *name)
+{
+ uchar_t rv;
+ VERIFY0(nvlist_lookup_byte(nvl, name, &rv));
+ return (rv);
+}
+
+int8_t
+fnvlist_lookup_int8(nvlist_t *nvl, const char *name)
+{
+ int8_t rv;
+ VERIFY0(nvlist_lookup_int8(nvl, name, &rv));
+ return (rv);
+}
+
+int16_t
+fnvlist_lookup_int16(nvlist_t *nvl, const char *name)
+{
+ int16_t rv;
+ VERIFY0(nvlist_lookup_int16(nvl, name, &rv));
+ return (rv);
+}
+
+int32_t
+fnvlist_lookup_int32(nvlist_t *nvl, const char *name)
+{
+ int32_t rv;
+ VERIFY0(nvlist_lookup_int32(nvl, name, &rv));
+ return (rv);
+}
+
+int64_t
+fnvlist_lookup_int64(nvlist_t *nvl, const char *name)
+{
+ int64_t rv;
+ VERIFY0(nvlist_lookup_int64(nvl, name, &rv));
+ return (rv);
+}
+
+uint8_t
+fnvlist_lookup_uint8_t(nvlist_t *nvl, const char *name)
+{
+ uint8_t rv;
+ VERIFY0(nvlist_lookup_uint8(nvl, name, &rv));
+ return (rv);
+}
+
+uint16_t
+fnvlist_lookup_uint16(nvlist_t *nvl, const char *name)
+{
+ uint16_t rv;
+ VERIFY0(nvlist_lookup_uint16(nvl, name, &rv));
+ return (rv);
+}
+
+uint32_t
+fnvlist_lookup_uint32(nvlist_t *nvl, const char *name)
+{
+ uint32_t rv;
+ VERIFY0(nvlist_lookup_uint32(nvl, name, &rv));
+ return (rv);
+}
+
+uint64_t
+fnvlist_lookup_uint64(nvlist_t *nvl, const char *name)
+{
+ uint64_t rv;
+ VERIFY0(nvlist_lookup_uint64(nvl, name, &rv));
+ return (rv);
+}
+
+char *
+fnvlist_lookup_string(nvlist_t *nvl, const char *name)
+{
+ char *rv;
+ VERIFY0(nvlist_lookup_string(nvl, name, &rv));
+ return (rv);
+}
+
+nvlist_t *
+fnvlist_lookup_nvlist(nvlist_t *nvl, const char *name)
+{
+ nvlist_t *rv;
+ VERIFY0(nvlist_lookup_nvlist(nvl, name, &rv));
+ return (rv);
+}
+
+boolean_t
+fnvpair_value_boolean_value(nvpair_t *nvp)
+{
+ boolean_t rv;
+ VERIFY0(nvpair_value_boolean_value(nvp, &rv));
+ return (rv);
+}
+
+uchar_t
+fnvpair_value_byte(nvpair_t *nvp)
+{
+ uchar_t rv;
+ VERIFY0(nvpair_value_byte(nvp, &rv));
+ return (rv);
+}
+
+int8_t
+fnvpair_value_int8(nvpair_t *nvp)
+{
+ int8_t rv;
+ VERIFY0(nvpair_value_int8(nvp, &rv));
+ return (rv);
+}
+
+int16_t
+fnvpair_value_int16(nvpair_t *nvp)
+{
+ int16_t rv;
+ VERIFY0(nvpair_value_int16(nvp, &rv));
+ return (rv);
+}
+
+int32_t
+fnvpair_value_int32(nvpair_t *nvp)
+{
+ int32_t rv;
+ VERIFY0(nvpair_value_int32(nvp, &rv));
+ return (rv);
+}
+
+int64_t
+fnvpair_value_int64(nvpair_t *nvp)
+{
+ int64_t rv;
+ VERIFY0(nvpair_value_int64(nvp, &rv));
+ return (rv);
+}
+
+uint8_t
+fnvpair_value_uint8_t(nvpair_t *nvp)
+{
+ uint8_t rv;
+ VERIFY0(nvpair_value_uint8(nvp, &rv));
+ return (rv);
+}
+
+uint16_t
+fnvpair_value_uint16(nvpair_t *nvp)
+{
+ uint16_t rv;
+ VERIFY0(nvpair_value_uint16(nvp, &rv));
+ return (rv);
+}
+
+uint32_t
+fnvpair_value_uint32(nvpair_t *nvp)
+{
+ uint32_t rv;
+ VERIFY0(nvpair_value_uint32(nvp, &rv));
+ return (rv);
+}
+
+uint64_t
+fnvpair_value_uint64(nvpair_t *nvp)
+{
+ uint64_t rv;
+ VERIFY0(nvpair_value_uint64(nvp, &rv));
+ return (rv);
+}
+
+char *
+fnvpair_value_string(nvpair_t *nvp)
+{
+ char *rv;
+ VERIFY0(nvpair_value_string(nvp, &rv));
+ return (rv);
+}
+
+nvlist_t *
+fnvpair_value_nvlist(nvpair_t *nvp)
+{
+ nvlist_t *rv;
+ VERIFY0(nvpair_value_nvlist(nvp, &rv));
+ return (rv);
+}
Index: sys/cddl/contrib/opensolaris/common/nvpair/opensolaris_nvpair.c
===================================================================
--- /dev/null
+++ sys/cddl/contrib/opensolaris/common/nvpair/opensolaris_nvpair.c
@@ -0,0 +1,3306 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <sys/debug.h>
+#include <sys/nvpair.h>
+#include <sys/nvpair_impl.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+
+#if defined(_KERNEL) && !defined(_BOOT)
+#include <sys/varargs.h>
+#include <sys/sunddi.h>
+#else
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#endif
+
+#ifndef offsetof
+#define offsetof(s, m) ((size_t)(&(((s *)0)->m)))
+#endif
+#define skip_whitespace(p) while ((*(p) == ' ') || (*(p) == '\t')) p++
+
+#if defined(__FreeBSD__) && !defined(_KERNEL)
+/*
+ * libnvpair is the lowest commen denominator for ZFS related libraries,
+ * defining aok here makes it usable by all ZFS related libraries
+ */
+int aok;
+#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
+ */
+#define NVP_SIZE_CALC(name_len, data_len) \
+ (NV_ALIGN((sizeof (nvpair_t)) + name_len) + NV_ALIGN(data_len))
+
+static int i_get_value_size(data_type_t type, const void *data, uint_t nelem);
+static int nvlist_add_common(nvlist_t *nvl, const char *name, data_type_t type,
+ uint_t nelem, const void *data);
+
+#define NV_STAT_EMBEDDED 0x1
+#define EMBEDDED_NVL(nvp) ((nvlist_t *)(void *)NVP_VALUE(nvp))
+#define EMBEDDED_NVL_ARRAY(nvp) ((nvlist_t **)(void *)NVP_VALUE(nvp))
+
+#define NVP_VALOFF(nvp) (NV_ALIGN(sizeof (nvpair_t) + (nvp)->nvp_name_sz))
+#define NVPAIR2I_NVP(nvp) \
+ ((i_nvp_t *)((size_t)(nvp) - offsetof(i_nvp_t, nvi_nvp)))
+
+
+int
+nv_alloc_init(nv_alloc_t *nva, const nv_alloc_ops_t *nvo, /* args */ ...)
+{
+ va_list valist;
+ int err = 0;
+
+ nva->nva_ops = nvo;
+ nva->nva_arg = NULL;
+
+ va_start(valist, nvo);
+ if (nva->nva_ops->nv_ao_init != NULL)
+ err = nva->nva_ops->nv_ao_init(nva, valist);
+ va_end(valist);
+
+ return (err);
+}
+
+void
+nv_alloc_reset(nv_alloc_t *nva)
+{
+ if (nva->nva_ops->nv_ao_reset != NULL)
+ nva->nva_ops->nv_ao_reset(nva);
+}
+
+void
+nv_alloc_fini(nv_alloc_t *nva)
+{
+ if (nva->nva_ops->nv_ao_fini != NULL)
+ nva->nva_ops->nv_ao_fini(nva);
+}
+
+nv_alloc_t *
+nvlist_lookup_nv_alloc(nvlist_t *nvl)
+{
+ nvpriv_t *priv;
+
+ if (nvl == NULL ||
+ (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
+ return (NULL);
+
+ return (priv->nvp_nva);
+}
+
+static void *
+nv_mem_zalloc(nvpriv_t *nvp, size_t size)
+{
+ nv_alloc_t *nva = nvp->nvp_nva;
+ void *buf;
+
+ if ((buf = nva->nva_ops->nv_ao_alloc(nva, size)) != NULL)
+ bzero(buf, size);
+
+ return (buf);
+}
+
+static void
+nv_mem_free(nvpriv_t *nvp, void *buf, size_t size)
+{
+ nv_alloc_t *nva = nvp->nvp_nva;
+
+ nva->nva_ops->nv_ao_free(nva, buf, size);
+}
+
+static void
+nv_priv_init(nvpriv_t *priv, nv_alloc_t *nva, uint32_t stat)
+{
+ bzero(priv, sizeof (nvpriv_t));
+
+ priv->nvp_nva = nva;
+ priv->nvp_stat = stat;
+}
+
+static nvpriv_t *
+nv_priv_alloc(nv_alloc_t *nva)
+{
+ nvpriv_t *priv;
+
+ /*
+ * nv_mem_alloc() cannot called here because it needs the priv
+ * argument.
+ */
+ if ((priv = nva->nva_ops->nv_ao_alloc(nva, sizeof (nvpriv_t))) == NULL)
+ return (NULL);
+
+ nv_priv_init(priv, nva, 0);
+
+ 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 *
+nv_priv_alloc_embedded(nvpriv_t *priv)
+{
+ nvpriv_t *emb_priv;
+
+ if ((emb_priv = nv_mem_zalloc(priv, sizeof (nvpriv_t))) == NULL)
+ return (NULL);
+
+ nv_priv_init(emb_priv, priv->nvp_nva, NV_STAT_EMBEDDED);
+
+ return (emb_priv);
+}
+
+static void
+nvlist_init(nvlist_t *nvl, uint32_t nvflag, nvpriv_t *priv)
+{
+ nvl->nvl_version = NV_VERSION;
+ nvl->nvl_nvflag = nvflag & (NV_UNIQUE_NAME|NV_UNIQUE_NAME_TYPE);
+ nvl->nvl_priv = (uint64_t)(uintptr_t)priv;
+ nvl->nvl_flag = 0;
+ nvl->nvl_pad = 0;
+}
+
+uint_t
+nvlist_nvflag(nvlist_t *nvl)
+{
+ return (nvl->nvl_nvflag);
+}
+
+/*
+ * nvlist_alloc - Allocate nvlist.
+ */
+/*ARGSUSED1*/
+int
+nvlist_alloc(nvlist_t **nvlp, uint_t nvflag, int kmflag)
+{
+#if defined(_KERNEL) && !defined(_BOOT)
+ return (nvlist_xalloc(nvlp, nvflag,
+ (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep)));
+#else
+ return (nvlist_xalloc(nvlp, nvflag, nv_alloc_nosleep));
+#endif
+}
+
+int
+nvlist_xalloc(nvlist_t **nvlp, uint_t nvflag, nv_alloc_t *nva)
+{
+ nvpriv_t *priv;
+
+ if (nvlp == NULL || nva == NULL)
+ return (EINVAL);
+
+ if ((priv = nv_priv_alloc(nva)) == NULL)
+ return (ENOMEM);
+
+ if ((*nvlp = nv_mem_zalloc(priv,
+ NV_ALIGN(sizeof (nvlist_t)))) == NULL) {
+ nv_mem_free(priv, priv, sizeof (nvpriv_t));
+ return (ENOMEM);
+ }
+
+ nvlist_init(*nvlp, nvflag, priv);
+
+ return (0);
+}
+
+/*
+ * nvp_buf_alloc - Allocate i_nvp_t for storing a new nv pair.
+ */
+static nvpair_t *
+nvp_buf_alloc(nvlist_t *nvl, size_t len)
+{
+ nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
+ i_nvp_t *buf;
+ nvpair_t *nvp;
+ size_t nvsize;
+
+ /*
+ * Allocate the buffer
+ */
+ nvsize = len + offsetof(i_nvp_t, nvi_nvp);
+
+ if ((buf = nv_mem_zalloc(priv, nvsize)) == NULL)
+ return (NULL);
+
+ nvp = &buf->nvi_nvp;
+ nvp->nvp_size = len;
+
+ return (nvp);
+}
+
+/*
+ * nvp_buf_free - de-Allocate an i_nvp_t.
+ */
+static void
+nvp_buf_free(nvlist_t *nvl, nvpair_t *nvp)
+{
+ nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
+ size_t nvsize = nvp->nvp_size + offsetof(i_nvp_t, nvi_nvp);
+
+ nv_mem_free(priv, NVPAIR2I_NVP(nvp), nvsize);
+}
+
+/*
+ * nvp_buf_link - link a new nv pair into the nvlist.
+ */
+static void
+nvp_buf_link(nvlist_t *nvl, nvpair_t *nvp)
+{
+ nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
+ i_nvp_t *curr = NVPAIR2I_NVP(nvp);
+
+ /* Put element at end of nvlist */
+ if (priv->nvp_list == NULL) {
+ priv->nvp_list = priv->nvp_last = curr;
+ } else {
+ curr->nvi_prev = priv->nvp_last;
+ priv->nvp_last->nvi_next = curr;
+ priv->nvp_last = curr;
+ }
+}
+
+/*
+ * nvp_buf_unlink - unlink an removed nvpair out of the nvlist.
+ */
+static void
+nvp_buf_unlink(nvlist_t *nvl, nvpair_t *nvp)
+{
+ nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
+ i_nvp_t *curr = NVPAIR2I_NVP(nvp);
+
+ /*
+ * protect nvlist_next_nvpair() against walking on freed memory.
+ */
+ if (priv->nvp_curr == curr)
+ priv->nvp_curr = curr->nvi_next;
+
+ if (curr == priv->nvp_list)
+ priv->nvp_list = curr->nvi_next;
+ else
+ curr->nvi_prev->nvi_next = curr->nvi_next;
+
+ if (curr == priv->nvp_last)
+ priv->nvp_last = curr->nvi_prev;
+ else
+ curr->nvi_next->nvi_prev = curr->nvi_prev;
+}
+
+/*
+ * take a nvpair type and number of elements and make sure the are valid
+ */
+static int
+i_validate_type_nelem(data_type_t type, uint_t nelem)
+{
+ 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
+i_validate_nvpair_name(nvpair_t *nvp)
+{
+ if ((nvp->nvp_name_sz <= 0) ||
+ (nvp->nvp_size < NVP_SIZE_CALC(nvp->nvp_name_sz, 0)))
+ return (EFAULT);
+
+ /* verify the name string, make sure its terminated */
+ if (NVP_NAME(nvp)[nvp->nvp_name_sz - 1] != '\0')
+ return (EFAULT);
+
+ return (strlen(NVP_NAME(nvp)) == nvp->nvp_name_sz - 1 ? 0 : EFAULT);
+}
+
+static int
+i_validate_nvpair_value(data_type_t type, uint_t nelem, const void *data)
+{
+ switch (type) {
+ case DATA_TYPE_BOOLEAN_VALUE:
+ if (*(boolean_t *)data != B_TRUE &&
+ *(boolean_t *)data != B_FALSE)
+ return (EINVAL);
+ break;
+ case DATA_TYPE_BOOLEAN_ARRAY: {
+ int i;
+
+ for (i = 0; i < nelem; i++)
+ if (((boolean_t *)data)[i] != B_TRUE &&
+ ((boolean_t *)data)[i] != B_FALSE)
+ 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
+i_validate_nvpair(nvpair_t *nvp)
+{
+ data_type_t type = NVP_TYPE(nvp);
+ int size1, size2;
+
+ /* verify nvp_name_sz, check the name string length */
+ if (i_validate_nvpair_name(nvp) != 0)
+ return (EFAULT);
+
+ if (i_validate_nvpair_value(type, NVP_NELEM(nvp), NVP_VALUE(nvp)) != 0)
+ return (EFAULT);
+
+ /*
+ * verify nvp_type, nvp_value_elem, and also possibly
+ * verify string values and get the value size.
+ */
+ size2 = i_get_value_size(type, NVP_VALUE(nvp), NVP_NELEM(nvp));
+ size1 = nvp->nvp_size - NVP_VALOFF(nvp);
+ if (size2 < 0 || size1 != NV_ALIGN(size2))
+ return (EFAULT);
+
+ return (0);
+}
+
+static int
+nvlist_copy_pairs(nvlist_t *snvl, nvlist_t *dnvl)
+{
+ nvpriv_t *priv;
+ i_nvp_t *curr;
+
+ if ((priv = (nvpriv_t *)(uintptr_t)snvl->nvl_priv) == NULL)
+ return (EINVAL);
+
+ for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
+ nvpair_t *nvp = &curr->nvi_nvp;
+ int err;
+
+ if ((err = nvlist_add_common(dnvl, NVP_NAME(nvp), NVP_TYPE(nvp),
+ NVP_NELEM(nvp), NVP_VALUE(nvp))) != 0)
+ return (err);
+ }
+
+ return (0);
+}
+
+/*
+ * Frees all memory allocated for an nvpair (like embedded lists) with
+ * the exception of the nvpair buffer itself.
+ */
+static void
+nvpair_free(nvpair_t *nvp)
+{
+ switch (NVP_TYPE(nvp)) {
+ case DATA_TYPE_NVLIST:
+ nvlist_free(EMBEDDED_NVL(nvp));
+ break;
+ case DATA_TYPE_NVLIST_ARRAY: {
+ nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp);
+ int i;
+
+ for (i = 0; i < NVP_NELEM(nvp); i++)
+ if (nvlp[i] != NULL)
+ nvlist_free(nvlp[i]);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+/*
+ * nvlist_free - free an unpacked nvlist
+ */
+void
+nvlist_free(nvlist_t *nvl)
+{
+ nvpriv_t *priv;
+ i_nvp_t *curr;
+
+ if (nvl == NULL ||
+ (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
+ return;
+
+ /*
+ * Unpacked nvlist are linked through i_nvp_t
+ */
+ curr = priv->nvp_list;
+ while (curr != NULL) {
+ nvpair_t *nvp = &curr->nvi_nvp;
+ curr = curr->nvi_next;
+
+ nvpair_free(nvp);
+ nvp_buf_free(nvl, nvp);
+ }
+
+ if (!(priv->nvp_stat & NV_STAT_EMBEDDED))
+ nv_mem_free(priv, nvl, NV_ALIGN(sizeof (nvlist_t)));
+ else
+ nvl->nvl_priv = 0;
+
+ nv_mem_free(priv, priv, sizeof (nvpriv_t));
+}
+
+static int
+nvlist_contains_nvp(nvlist_t *nvl, nvpair_t *nvp)
+{
+ nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
+ i_nvp_t *curr;
+
+ if (nvp == NULL)
+ return (0);
+
+ for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next)
+ if (&curr->nvi_nvp == nvp)
+ return (1);
+
+ return (0);
+}
+
+/*
+ * Make a copy of nvlist
+ */
+/*ARGSUSED1*/
+int
+nvlist_dup(nvlist_t *nvl, nvlist_t **nvlp, int kmflag)
+{
+#if defined(_KERNEL) && !defined(_BOOT)
+ return (nvlist_xdup(nvl, nvlp,
+ (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep)));
+#else
+ return (nvlist_xdup(nvl, nvlp, nv_alloc_nosleep));
+#endif
+}
+
+int
+nvlist_xdup(nvlist_t *nvl, nvlist_t **nvlp, nv_alloc_t *nva)
+{
+ int err;
+ nvlist_t *ret;
+
+ if (nvl == NULL || nvlp == NULL)
+ return (EINVAL);
+
+ if ((err = nvlist_xalloc(&ret, nvl->nvl_nvflag, nva)) != 0)
+ return (err);
+
+ if ((err = nvlist_copy_pairs(nvl, ret)) != 0)
+ nvlist_free(ret);
+ else
+ *nvlp = ret;
+
+ return (err);
+}
+
+/*
+ * Remove all with matching name
+ */
+int
+nvlist_remove_all(nvlist_t *nvl, const char *name)
+{
+ nvpriv_t *priv;
+ i_nvp_t *curr;
+ int error = ENOENT;
+
+ if (nvl == NULL || name == NULL ||
+ (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
+ return (EINVAL);
+
+ curr = priv->nvp_list;
+ while (curr != NULL) {
+ nvpair_t *nvp = &curr->nvi_nvp;
+
+ curr = curr->nvi_next;
+ if (strcmp(name, NVP_NAME(nvp)) != 0)
+ continue;
+
+ nvp_buf_unlink(nvl, nvp);
+ nvpair_free(nvp);
+ nvp_buf_free(nvl, nvp);
+
+ error = 0;
+ }
+
+ return (error);
+}
+
+/*
+ * Remove first one with matching name and type
+ */
+int
+nvlist_remove(nvlist_t *nvl, const char *name, data_type_t type)
+{
+ nvpriv_t *priv;
+ i_nvp_t *curr;
+
+ if (nvl == NULL || name == NULL ||
+ (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
+ return (EINVAL);
+
+ curr = priv->nvp_list;
+ while (curr != NULL) {
+ nvpair_t *nvp = &curr->nvi_nvp;
+
+ if (strcmp(name, NVP_NAME(nvp)) == 0 && NVP_TYPE(nvp) == type) {
+ nvp_buf_unlink(nvl, nvp);
+ nvpair_free(nvp);
+ nvp_buf_free(nvl, nvp);
+
+ return (0);
+ }
+ curr = curr->nvi_next;
+ }
+
+ return (ENOENT);
+}
+
+int
+nvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp)
+{
+ if (nvl == NULL || nvp == NULL)
+ return (EINVAL);
+
+ nvp_buf_unlink(nvl, nvp);
+ nvpair_free(nvp);
+ nvp_buf_free(nvl, nvp);
+ 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
+i_get_value_size(data_type_t type, const void *data, uint_t nelem)
+{
+ uint64_t value_sz;
+
+ if (i_validate_type_nelem(type, nelem) != 0)
+ return (-1);
+
+ /* Calculate required size for holding value */
+ switch (type) {
+ case DATA_TYPE_BOOLEAN:
+ value_sz = 0;
+ break;
+ case DATA_TYPE_BOOLEAN_VALUE:
+ value_sz = sizeof (boolean_t);
+ break;
+ case DATA_TYPE_BYTE:
+ value_sz = sizeof (uchar_t);
+ break;
+ case DATA_TYPE_INT8:
+ value_sz = sizeof (int8_t);
+ break;
+ case DATA_TYPE_UINT8:
+ value_sz = sizeof (uint8_t);
+ break;
+ case DATA_TYPE_INT16:
+ value_sz = sizeof (int16_t);
+ break;
+ case DATA_TYPE_UINT16:
+ value_sz = sizeof (uint16_t);
+ break;
+ case DATA_TYPE_INT32:
+ value_sz = sizeof (int32_t);
+ break;
+ case DATA_TYPE_UINT32:
+ value_sz = sizeof (uint32_t);
+ break;
+ case DATA_TYPE_INT64:
+ value_sz = sizeof (int64_t);
+ break;
+ case DATA_TYPE_UINT64:
+ value_sz = sizeof (uint64_t);
+ break;
+#if !defined(_KERNEL)
+ case DATA_TYPE_DOUBLE:
+ value_sz = sizeof (double);
+ break;
+#endif
+ case DATA_TYPE_STRING:
+ if (data == NULL)
+ value_sz = 0;
+ else
+ value_sz = strlen(data) + 1;
+ break;
+ case DATA_TYPE_BOOLEAN_ARRAY:
+ value_sz = (uint64_t)nelem * sizeof (boolean_t);
+ break;
+ case DATA_TYPE_BYTE_ARRAY:
+ value_sz = (uint64_t)nelem * sizeof (uchar_t);
+ break;
+ case DATA_TYPE_INT8_ARRAY:
+ value_sz = (uint64_t)nelem * sizeof (int8_t);
+ break;
+ case DATA_TYPE_UINT8_ARRAY:
+ value_sz = (uint64_t)nelem * sizeof (uint8_t);
+ break;
+ case DATA_TYPE_INT16_ARRAY:
+ value_sz = (uint64_t)nelem * sizeof (int16_t);
+ break;
+ case DATA_TYPE_UINT16_ARRAY:
+ value_sz = (uint64_t)nelem * sizeof (uint16_t);
+ break;
+ case DATA_TYPE_INT32_ARRAY:
+ value_sz = (uint64_t)nelem * sizeof (int32_t);
+ break;
+ 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;
+ uint_t i;
+
+ /* no alignment requirement for strings */
+ for (i = 0; i < nelem; i++) {
+ if (strs[i] == NULL)
+ return (-1);
+ value_sz += strlen(strs[i]) + 1;
+ }
+ }
+ break;
+ case DATA_TYPE_HRTIME:
+ value_sz = sizeof (hrtime_t);
+ break;
+ case DATA_TYPE_NVLIST:
+ value_sz = NV_ALIGN(sizeof (nvlist_t));
+ break;
+ case DATA_TYPE_NVLIST_ARRAY:
+ value_sz = (uint64_t)nelem * sizeof (uint64_t) +
+ (uint64_t)nelem * NV_ALIGN(sizeof (nvlist_t));
+ break;
+ default:
+ return (-1);
+ }
+
+ return (value_sz > INT32_MAX ? -1 : (int)value_sz);
+}
+
+static int
+nvlist_copy_embedded(nvlist_t *nvl, nvlist_t *onvl, nvlist_t *emb_nvl)
+{
+ nvpriv_t *priv;
+ int err;
+
+ if ((priv = nv_priv_alloc_embedded((nvpriv_t *)(uintptr_t)
+ nvl->nvl_priv)) == NULL)
+ return (ENOMEM);
+
+ nvlist_init(emb_nvl, onvl->nvl_nvflag, priv);
+
+ if ((err = nvlist_copy_pairs(onvl, emb_nvl)) != 0) {
+ nvlist_free(emb_nvl);
+ emb_nvl->nvl_priv = 0;
+ }
+
+ return (err);
+}
+
+/*
+ * nvlist_add_common - Add new <name,value> pair to nvlist
+ */
+static int
+nvlist_add_common(nvlist_t *nvl, const char *name,
+ data_type_t type, uint_t nelem, const void *data)
+{
+ nvpair_t *nvp;
+ uint_t i;
+
+ int nvp_sz, name_sz, value_sz;
+ int err = 0;
+
+ if (name == NULL || nvl == NULL || nvl->nvl_priv == 0)
+ return (EINVAL);
+
+ if (nelem != 0 && data == NULL)
+ 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.
+ */
+ if ((value_sz = i_get_value_size(type, data, nelem)) < 0)
+ return (EINVAL);
+
+ if (i_validate_nvpair_value(type, nelem, data) != 0)
+ 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:
+ if (data == nvl || data == NULL)
+ return (EINVAL);
+ break;
+ case DATA_TYPE_NVLIST_ARRAY: {
+ nvlist_t **onvlp = (nvlist_t **)data;
+ for (i = 0; i < nelem; i++) {
+ if (onvlp[i] == nvl || onvlp[i] == NULL)
+ return (EINVAL);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ /* calculate sizes of the nvpair elements and the nvpair itself */
+ name_sz = strlen(name) + 1;
+
+ nvp_sz = NVP_SIZE_CALC(name_sz, value_sz);
+
+ if ((nvp = nvp_buf_alloc(nvl, nvp_sz)) == NULL)
+ return (ENOMEM);
+
+ ASSERT(nvp->nvp_size == nvp_sz);
+ nvp->nvp_name_sz = name_sz;
+ nvp->nvp_value_elem = nelem;
+ nvp->nvp_type = type;
+ bcopy(name, NVP_NAME(nvp), name_sz);
+
+ switch (type) {
+ case DATA_TYPE_BOOLEAN:
+ break;
+ case DATA_TYPE_STRING_ARRAY: {
+ char *const *strs = data;
+ char *buf = NVP_VALUE(nvp);
+ char **cstrs = (void *)buf;
+
+ /* skip pre-allocated space for pointer array */
+ buf += nelem * sizeof (uint64_t);
+ for (i = 0; i < nelem; i++) {
+ int slen = strlen(strs[i]) + 1;
+ bcopy(strs[i], buf, slen);
+ cstrs[i] = buf;
+ buf += slen;
+ }
+ break;
+ }
+ case DATA_TYPE_NVLIST: {
+ nvlist_t *nnvl = EMBEDDED_NVL(nvp);
+ nvlist_t *onvl = (nvlist_t *)data;
+
+ if ((err = nvlist_copy_embedded(nvl, onvl, nnvl)) != 0) {
+ nvp_buf_free(nvl, nvp);
+ return (err);
+ }
+ break;
+ }
+ case DATA_TYPE_NVLIST_ARRAY: {
+ nvlist_t **onvlp = (nvlist_t **)data;
+ nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp);
+ nvlist_t *embedded = (nvlist_t *)
+ ((uintptr_t)nvlp + nelem * sizeof (uint64_t));
+
+ for (i = 0; i < nelem; i++) {
+ if ((err = nvlist_copy_embedded(nvl,
+ onvlp[i], embedded)) != 0) {
+ /*
+ * Free any successfully created lists
+ */
+ nvpair_free(nvp);
+ nvp_buf_free(nvl, nvp);
+ return (err);
+ }
+
+ nvlp[i] = embedded++;
+ }
+ break;
+ }
+ default:
+ bcopy(data, NVP_VALUE(nvp), value_sz);
+ }
+
+ /* if unique name, remove before add */
+ if (nvl->nvl_nvflag & NV_UNIQUE_NAME)
+ (void) nvlist_remove_all(nvl, name);
+ else if (nvl->nvl_nvflag & NV_UNIQUE_NAME_TYPE)
+ (void) nvlist_remove(nvl, name, type);
+
+ nvp_buf_link(nvl, nvp);
+
+ return (0);
+}
+
+int
+nvlist_add_boolean(nvlist_t *nvl, const char *name)
+{
+ return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN, 0, NULL));
+}
+
+int
+nvlist_add_boolean_value(nvlist_t *nvl, const char *name, boolean_t val)
+{
+ return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_VALUE, 1, &val));
+}
+
+int
+nvlist_add_byte(nvlist_t *nvl, const char *name, uchar_t val)
+{
+ return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE, 1, &val));
+}
+
+int
+nvlist_add_int8(nvlist_t *nvl, const char *name, int8_t val)
+{
+ return (nvlist_add_common(nvl, name, DATA_TYPE_INT8, 1, &val));
+}
+
+int
+nvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t val)
+{
+ return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8, 1, &val));
+}
+
+int
+nvlist_add_int16(nvlist_t *nvl, const char *name, int16_t val)
+{
+ return (nvlist_add_common(nvl, name, DATA_TYPE_INT16, 1, &val));
+}
+
+int
+nvlist_add_uint16(nvlist_t *nvl, const char *name, uint16_t val)
+{
+ return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16, 1, &val));
+}
+
+int
+nvlist_add_int32(nvlist_t *nvl, const char *name, int32_t val)
+{
+ return (nvlist_add_common(nvl, name, DATA_TYPE_INT32, 1, &val));
+}
+
+int
+nvlist_add_uint32(nvlist_t *nvl, const char *name, uint32_t val)
+{
+ return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32, 1, &val));
+}
+
+int
+nvlist_add_int64(nvlist_t *nvl, const char *name, int64_t val)
+{
+ return (nvlist_add_common(nvl, name, DATA_TYPE_INT64, 1, &val));
+}
+
+int
+nvlist_add_uint64(nvlist_t *nvl, const char *name, uint64_t val)
+{
+ return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64, 1, &val));
+}
+
+#if !defined(_KERNEL)
+int
+nvlist_add_double(nvlist_t *nvl, const char *name, double val)
+{
+ return (nvlist_add_common(nvl, name, DATA_TYPE_DOUBLE, 1, &val));
+}
+#endif
+
+int
+nvlist_add_string(nvlist_t *nvl, const char *name, const char *val)
+{
+ return (nvlist_add_common(nvl, name, DATA_TYPE_STRING, 1, (void *)val));
+}
+
+int
+nvlist_add_boolean_array(nvlist_t *nvl, const char *name,
+ boolean_t *a, uint_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, uchar_t *a, uint_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, uint_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, uint_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, uint_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, uint_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, uint_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, uint_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, uint_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, uint_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, uint_t n)
+{
+ return (nvlist_add_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a));
+}
+
+int
+nvlist_add_hrtime(nvlist_t *nvl, const char *name, hrtime_t val)
+{
+ return (nvlist_add_common(nvl, name, DATA_TYPE_HRTIME, 1, &val));
+}
+
+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, uint_t n)
+{
+ return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a));
+}
+
+/* reading name-value pairs */
+nvpair_t *
+nvlist_next_nvpair(nvlist_t *nvl, nvpair_t *nvp)
+{
+ nvpriv_t *priv;
+ i_nvp_t *curr;
+
+ if (nvl == NULL ||
+ (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
+ return (NULL);
+
+ curr = NVPAIR2I_NVP(nvp);
+
+ /*
+ * 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.
+ */
+ if (nvp == NULL)
+ curr = priv->nvp_list;
+ else if (priv->nvp_curr == curr || nvlist_contains_nvp(nvl, nvp))
+ curr = curr->nvi_next;
+ else
+ curr = NULL;
+
+ priv->nvp_curr = curr;
+
+ return (curr != NULL ? &curr->nvi_nvp : NULL);
+}
+
+nvpair_t *
+nvlist_prev_nvpair(nvlist_t *nvl, nvpair_t *nvp)
+{
+ nvpriv_t *priv;
+ i_nvp_t *curr;
+
+ if (nvl == NULL ||
+ (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
+ return (NULL);
+
+ curr = NVPAIR2I_NVP(nvp);
+
+ if (nvp == NULL)
+ curr = priv->nvp_last;
+ else if (priv->nvp_curr == curr || nvlist_contains_nvp(nvl, nvp))
+ curr = curr->nvi_prev;
+ else
+ curr = NULL;
+
+ priv->nvp_curr = curr;
+
+ return (curr != NULL ? &curr->nvi_nvp : NULL);
+}
+
+boolean_t
+nvlist_empty(nvlist_t *nvl)
+{
+ nvpriv_t *priv;
+
+ if (nvl == NULL ||
+ (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
+ return (B_TRUE);
+
+ return (priv->nvp_list == NULL);
+}
+
+char *
+nvpair_name(nvpair_t *nvp)
+{
+ return (NVP_NAME(nvp));
+}
+
+data_type_t
+nvpair_type(nvpair_t *nvp)
+{
+ return (NVP_TYPE(nvp));
+}
+
+int
+nvpair_type_is_array(nvpair_t *nvp)
+{
+ data_type_t type = NVP_TYPE(nvp);
+
+ 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
+nvpair_value_common(nvpair_t *nvp, data_type_t type, uint_t *nelem, void *data)
+{
+ if (nvp == NULL || nvpair_type(nvp) != type)
+ 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:
+ if (nelem != NULL)
+ *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
+ if (data == NULL)
+ return (EINVAL);
+ bcopy(NVP_VALUE(nvp), data,
+ (size_t)i_get_value_size(type, NULL, 1));
+ if (nelem != NULL)
+ *nelem = 1;
+ break;
+
+ case DATA_TYPE_NVLIST:
+ case DATA_TYPE_STRING:
+ if (data == NULL)
+ return (EINVAL);
+ *(void **)data = (void *)NVP_VALUE(nvp);
+ if (nelem != NULL)
+ *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:
+ if (nelem == NULL || data == NULL)
+ return (EINVAL);
+ if ((*nelem = NVP_NELEM(nvp)) != 0)
+ *(void **)data = (void *)NVP_VALUE(nvp);
+ else
+ *(void **)data = NULL;
+ break;
+
+ default:
+ return (ENOTSUP);
+ }
+
+ return (0);
+}
+
+static int
+nvlist_lookup_common(nvlist_t *nvl, const char *name, data_type_t type,
+ uint_t *nelem, void *data)
+{
+ nvpriv_t *priv;
+ nvpair_t *nvp;
+ i_nvp_t *curr;
+
+ if (name == NULL || nvl == NULL ||
+ (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
+ return (EINVAL);
+
+ if (!(nvl->nvl_nvflag & (NV_UNIQUE_NAME | NV_UNIQUE_NAME_TYPE)))
+ return (ENOTSUP);
+
+ for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
+ nvp = &curr->nvi_nvp;
+
+ if (strcmp(name, NVP_NAME(nvp)) == 0 && NVP_TYPE(nvp) == type)
+ return (nvpair_value_common(nvp, type, nelem, data));
+ }
+
+ return (ENOENT);
+}
+
+int
+nvlist_lookup_boolean(nvlist_t *nvl, const char *name)
+{
+ return (nvlist_lookup_common(nvl, name, DATA_TYPE_BOOLEAN, NULL, NULL));
+}
+
+int
+nvlist_lookup_boolean_value(nvlist_t *nvl, const char *name, boolean_t *val)
+{
+ return (nvlist_lookup_common(nvl, name,
+ DATA_TYPE_BOOLEAN_VALUE, NULL, val));
+}
+
+int
+nvlist_lookup_byte(nvlist_t *nvl, const char *name, uchar_t *val)
+{
+ return (nvlist_lookup_common(nvl, name, DATA_TYPE_BYTE, NULL, val));
+}
+
+int
+nvlist_lookup_int8(nvlist_t *nvl, const char *name, int8_t *val)
+{
+ return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT8, NULL, val));
+}
+
+int
+nvlist_lookup_uint8(nvlist_t *nvl, const char *name, uint8_t *val)
+{
+ return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT8, NULL, val));
+}
+
+int
+nvlist_lookup_int16(nvlist_t *nvl, const char *name, int16_t *val)
+{
+ return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT16, NULL, val));
+}
+
+int
+nvlist_lookup_uint16(nvlist_t *nvl, const char *name, uint16_t *val)
+{
+ return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT16, NULL, val));
+}
+
+int
+nvlist_lookup_int32(nvlist_t *nvl, const char *name, int32_t *val)
+{
+ return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT32, NULL, val));
+}
+
+int
+nvlist_lookup_uint32(nvlist_t *nvl, const char *name, uint32_t *val)
+{
+ return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT32, NULL, val));
+}
+
+int
+nvlist_lookup_int64(nvlist_t *nvl, const char *name, int64_t *val)
+{
+ return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT64, NULL, val));
+}
+
+int
+nvlist_lookup_uint64(nvlist_t *nvl, const char *name, uint64_t *val)
+{
+ return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT64, NULL, val));
+}
+
+#if !defined(_KERNEL)
+int
+nvlist_lookup_double(nvlist_t *nvl, const char *name, double *val)
+{
+ return (nvlist_lookup_common(nvl, name, DATA_TYPE_DOUBLE, NULL, val));
+}
+#endif
+
+int
+nvlist_lookup_string(nvlist_t *nvl, const char *name, char **val)
+{
+ return (nvlist_lookup_common(nvl, name, DATA_TYPE_STRING, NULL, val));
+}
+
+int
+nvlist_lookup_nvlist(nvlist_t *nvl, const char *name, nvlist_t **val)
+{
+ return (nvlist_lookup_common(nvl, name, DATA_TYPE_NVLIST, NULL, val));
+}
+
+int
+nvlist_lookup_boolean_array(nvlist_t *nvl, const char *name,
+ boolean_t **a, uint_t *n)
+{
+ return (nvlist_lookup_common(nvl, name,
+ DATA_TYPE_BOOLEAN_ARRAY, n, a));
+}
+
+int
+nvlist_lookup_byte_array(nvlist_t *nvl, const char *name,
+ uchar_t **a, uint_t *n)
+{
+ return (nvlist_lookup_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a));
+}
+
+int
+nvlist_lookup_int8_array(nvlist_t *nvl, const char *name, int8_t **a, uint_t *n)
+{
+ return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a));
+}
+
+int
+nvlist_lookup_uint8_array(nvlist_t *nvl, const char *name,
+ uint8_t **a, uint_t *n)
+{
+ return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a));
+}
+
+int
+nvlist_lookup_int16_array(nvlist_t *nvl, const char *name,
+ int16_t **a, uint_t *n)
+{
+ return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a));
+}
+
+int
+nvlist_lookup_uint16_array(nvlist_t *nvl, const char *name,
+ uint16_t **a, uint_t *n)
+{
+ return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a));
+}
+
+int
+nvlist_lookup_int32_array(nvlist_t *nvl, const char *name,
+ int32_t **a, uint_t *n)
+{
+ return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a));
+}
+
+int
+nvlist_lookup_uint32_array(nvlist_t *nvl, const char *name,
+ uint32_t **a, uint_t *n)
+{
+ return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a));
+}
+
+int
+nvlist_lookup_int64_array(nvlist_t *nvl, const char *name,
+ int64_t **a, uint_t *n)
+{
+ return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a));
+}
+
+int
+nvlist_lookup_uint64_array(nvlist_t *nvl, const char *name,
+ uint64_t **a, uint_t *n)
+{
+ return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a));
+}
+
+int
+nvlist_lookup_string_array(nvlist_t *nvl, const char *name,
+ char ***a, uint_t *n)
+{
+ return (nvlist_lookup_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a));
+}
+
+int
+nvlist_lookup_nvlist_array(nvlist_t *nvl, const char *name,
+ nvlist_t ***a, uint_t *n)
+{
+ return (nvlist_lookup_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a));
+}
+
+int
+nvlist_lookup_hrtime(nvlist_t *nvl, const char *name, hrtime_t *val)
+{
+ return (nvlist_lookup_common(nvl, name, DATA_TYPE_HRTIME, NULL, val));
+}
+
+int
+nvlist_lookup_pairs(nvlist_t *nvl, int flag, ...)
+{
+ va_list ap;
+ char *name;
+ int noentok = (flag & NV_FLAG_NOENTOK ? 1 : 0);
+ int ret = 0;
+
+ va_start(ap, flag);
+ while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {
+ data_type_t type;
+ void *val;
+ uint_t *nelem;
+
+ switch (type = va_arg(ap, data_type_t)) {
+ case DATA_TYPE_BOOLEAN:
+ ret = nvlist_lookup_common(nvl, name, type, NULL, NULL);
+ 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
+ val = va_arg(ap, void *);
+ ret = nvlist_lookup_common(nvl, name, type, NULL, val);
+ 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:
+ val = va_arg(ap, void *);
+ nelem = va_arg(ap, uint_t *);
+ ret = nvlist_lookup_common(nvl, name, type, nelem, val);
+ break;
+
+ default:
+ ret = EINVAL;
+ }
+
+ if (ret == ENOENT && noentok)
+ ret = 0;
+ }
+ va_end(ap);
+
+ 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
+nvlist_lookup_nvpair_ei_sep(nvlist_t *nvl, const char *name, const char sep,
+ nvpair_t **ret, int *ip, char **ep)
+{
+ nvpair_t *nvp;
+ const char *np;
+ char *sepp;
+ char *idxp, *idxep;
+ nvlist_t **nva;
+ long idx;
+ int n;
+
+ if (ip)
+ *ip = -1; /* not indexed */
+ if (ep)
+ *ep = NULL;
+
+ if ((nvl == NULL) || (name == NULL))
+ return (EINVAL);
+
+ /* step through components of name */
+ for (np = name; np && *np; np = sepp) {
+ /* ensure unique names */
+ if (!(nvl->nvl_nvflag & NV_UNIQUE_NAME))
+ return (ENOTSUP);
+
+ /* skip white space */
+ skip_whitespace(np);
+ if (*np == 0)
+ break;
+
+ /* set 'sepp' to end of current component 'np' */
+ if (sep)
+ sepp = strchr(np, sep);
+ else
+ sepp = NULL;
+
+ /* find start of next "[ index ]..." */
+ idxp = strchr(np, '[');
+
+ /* if sepp comes first, set idxp to NULL */
+ if (sepp && idxp && (sepp < idxp))
+ idxp = 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 */
+ n = idxp++ - np;
+
+ /* keep sepp up to date for *ep use as we advance */
+ skip_whitespace(idxp);
+ sepp = idxp;
+
+ /* determine the index value */
+#if defined(_KERNEL) && !defined(_BOOT)
+ if (ddi_strtol(idxp, &idxep, 0, &idx))
+ goto fail;
+#else
+ idx = strtol(idxp, &idxep, 0);
+#endif
+ if (idxep == idxp)
+ goto fail;
+
+ /* keep sepp up to date for *ep use as we advance */
+ sepp = idxep;
+
+ /* skip white space index value and check for ']' */
+ skip_whitespace(sepp);
+ if (*sepp++ != ']')
+ goto fail;
+
+ /* for embedded arrays, support C syntax: "a[1].b" */
+ skip_whitespace(sepp);
+ if (sep && (*sepp == sep))
+ sepp++;
+ } else if (sepp) {
+ n = sepp++ - np;
+ } else {
+ n = strlen(np);
+ }
+
+ /* trim trailing whitespace by reducing length of 'np' */
+ if (n == 0)
+ goto fail;
+ for (n--; (np[n] == ' ') || (np[n] == '\t'); n--)
+ ;
+ n++;
+
+ /* skip whitespace, and set sepp to NULL if complete */
+ if (sepp) {
+ skip_whitespace(sepp);
+ if (*sepp == 0)
+ sepp = NULL;
+ }
+
+ /*
+ * 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.
+ */
+ for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
+ nvp = nvlist_next_nvpair(nvl, nvp)) {
+
+ /* continue if no match on name */
+ if (strncmp(np, nvpair_name(nvp), n) ||
+ (strlen(nvpair_name(nvp)) != n))
+ continue;
+
+ /* if indexed, verify type is array oriented */
+ if (idxp && !nvpair_type_is_array(nvp))
+ goto fail;
+
+ /*
+ * Full match found, return nvp and idx if this
+ * was the last component.
+ */
+ if (sepp == NULL) {
+ if (ret)
+ *ret = nvp;
+ if (ip && idxp)
+ *ip = (int)idx; /* return index */
+ return (0); /* found */
+ }
+
+ /*
+ * More components: current match must be
+ * of DATA_TYPE_NVLIST or DATA_TYPE_NVLIST_ARRAY
+ * to support going deeper.
+ */
+ if (nvpair_type(nvp) == DATA_TYPE_NVLIST) {
+ nvl = EMBEDDED_NVL(nvp);
+ break;
+ } else if (nvpair_type(nvp) == DATA_TYPE_NVLIST_ARRAY) {
+ (void) nvpair_value_nvlist_array(nvp,
+ &nva, (uint_t *)&n);
+ if ((n < 0) || (idx >= n))
+ goto fail;
+ nvl = nva[idx];
+ break;
+ }
+
+ /* type does not support more levels */
+ goto fail;
+ }
+ if (nvp == NULL)
+ goto fail; /* 'name' not found */
+
+ /* search for match of next component in embedded 'nvl' list */
+ }
+
+fail: if (ep && sepp)
+ *ep = sepp;
+ return (EINVAL);
+}
+
+/*
+ * Return pointer to nvpair with specified 'name'.
+ */
+int
+nvlist_lookup_nvpair(nvlist_t *nvl, const char *name, nvpair_t **ret)
+{
+ return (nvlist_lookup_nvpair_ei_sep(nvl, name, 0, ret, NULL, NULL));
+}
+
+/*
+ * 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.
+ */
+int nvlist_lookup_nvpair_embedded_index(nvlist_t *nvl,
+ const char *name, nvpair_t **ret, int *ip, char **ep)
+{
+ return (nvlist_lookup_nvpair_ei_sep(nvl, name, '.', ret, ip, ep));
+}
+
+boolean_t
+nvlist_exists(nvlist_t *nvl, const char *name)
+{
+ nvpriv_t *priv;
+ nvpair_t *nvp;
+ i_nvp_t *curr;
+
+ if (name == NULL || nvl == NULL ||
+ (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
+ return (B_FALSE);
+
+ for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
+ nvp = &curr->nvi_nvp;
+
+ if (strcmp(name, NVP_NAME(nvp)) == 0)
+ return (B_TRUE);
+ }
+
+ return (B_FALSE);
+}
+
+int
+nvpair_value_boolean_value(nvpair_t *nvp, boolean_t *val)
+{
+ return (nvpair_value_common(nvp, DATA_TYPE_BOOLEAN_VALUE, NULL, val));
+}
+
+int
+nvpair_value_byte(nvpair_t *nvp, uchar_t *val)
+{
+ return (nvpair_value_common(nvp, DATA_TYPE_BYTE, NULL, val));
+}
+
+int
+nvpair_value_int8(nvpair_t *nvp, int8_t *val)
+{
+ return (nvpair_value_common(nvp, DATA_TYPE_INT8, NULL, val));
+}
+
+int
+nvpair_value_uint8(nvpair_t *nvp, uint8_t *val)
+{
+ return (nvpair_value_common(nvp, DATA_TYPE_UINT8, NULL, val));
+}
+
+int
+nvpair_value_int16(nvpair_t *nvp, int16_t *val)
+{
+ return (nvpair_value_common(nvp, DATA_TYPE_INT16, NULL, val));
+}
+
+int
+nvpair_value_uint16(nvpair_t *nvp, uint16_t *val)
+{
+ return (nvpair_value_common(nvp, DATA_TYPE_UINT16, NULL, val));
+}
+
+int
+nvpair_value_int32(nvpair_t *nvp, int32_t *val)
+{
+ return (nvpair_value_common(nvp, DATA_TYPE_INT32, NULL, val));
+}
+
+int
+nvpair_value_uint32(nvpair_t *nvp, uint32_t *val)
+{
+ return (nvpair_value_common(nvp, DATA_TYPE_UINT32, NULL, val));
+}
+
+int
+nvpair_value_int64(nvpair_t *nvp, int64_t *val)
+{
+ return (nvpair_value_common(nvp, DATA_TYPE_INT64, NULL, val));
+}
+
+int
+nvpair_value_uint64(nvpair_t *nvp, uint64_t *val)
+{
+ return (nvpair_value_common(nvp, DATA_TYPE_UINT64, NULL, val));
+}
+
+#if !defined(_KERNEL)
+int
+nvpair_value_double(nvpair_t *nvp, double *val)
+{
+ return (nvpair_value_common(nvp, DATA_TYPE_DOUBLE, NULL, val));
+}
+#endif
+
+int
+nvpair_value_string(nvpair_t *nvp, char **val)
+{
+ return (nvpair_value_common(nvp, DATA_TYPE_STRING, NULL, val));
+}
+
+int
+nvpair_value_nvlist(nvpair_t *nvp, nvlist_t **val)
+{
+ return (nvpair_value_common(nvp, DATA_TYPE_NVLIST, NULL, val));
+}
+
+int
+nvpair_value_boolean_array(nvpair_t *nvp, boolean_t **val, uint_t *nelem)
+{
+ return (nvpair_value_common(nvp, DATA_TYPE_BOOLEAN_ARRAY, nelem, val));
+}
+
+int
+nvpair_value_byte_array(nvpair_t *nvp, uchar_t **val, uint_t *nelem)
+{
+ return (nvpair_value_common(nvp, DATA_TYPE_BYTE_ARRAY, nelem, val));
+}
+
+int
+nvpair_value_int8_array(nvpair_t *nvp, int8_t **val, uint_t *nelem)
+{
+ return (nvpair_value_common(nvp, DATA_TYPE_INT8_ARRAY, nelem, val));
+}
+
+int
+nvpair_value_uint8_array(nvpair_t *nvp, uint8_t **val, uint_t *nelem)
+{
+ return (nvpair_value_common(nvp, DATA_TYPE_UINT8_ARRAY, nelem, val));
+}
+
+int
+nvpair_value_int16_array(nvpair_t *nvp, int16_t **val, uint_t *nelem)
+{
+ return (nvpair_value_common(nvp, DATA_TYPE_INT16_ARRAY, nelem, val));
+}
+
+int
+nvpair_value_uint16_array(nvpair_t *nvp, uint16_t **val, uint_t *nelem)
+{
+ return (nvpair_value_common(nvp, DATA_TYPE_UINT16_ARRAY, nelem, val));
+}
+
+int
+nvpair_value_int32_array(nvpair_t *nvp, int32_t **val, uint_t *nelem)
+{
+ return (nvpair_value_common(nvp, DATA_TYPE_INT32_ARRAY, nelem, val));
+}
+
+int
+nvpair_value_uint32_array(nvpair_t *nvp, uint32_t **val, uint_t *nelem)
+{
+ return (nvpair_value_common(nvp, DATA_TYPE_UINT32_ARRAY, nelem, val));
+}
+
+int
+nvpair_value_int64_array(nvpair_t *nvp, int64_t **val, uint_t *nelem)
+{
+ return (nvpair_value_common(nvp, DATA_TYPE_INT64_ARRAY, nelem, val));
+}
+
+int
+nvpair_value_uint64_array(nvpair_t *nvp, uint64_t **val, uint_t *nelem)
+{
+ return (nvpair_value_common(nvp, DATA_TYPE_UINT64_ARRAY, nelem, val));
+}
+
+int
+nvpair_value_string_array(nvpair_t *nvp, char ***val, uint_t *nelem)
+{
+ return (nvpair_value_common(nvp, DATA_TYPE_STRING_ARRAY, nelem, val));
+}
+
+int
+nvpair_value_nvlist_array(nvpair_t *nvp, nvlist_t ***val, uint_t *nelem)
+{
+ return (nvpair_value_common(nvp, DATA_TYPE_NVLIST_ARRAY, nelem, val));
+}
+
+int
+nvpair_value_hrtime(nvpair_t *nvp, hrtime_t *val)
+{
+ return (nvpair_value_common(nvp, DATA_TYPE_HRTIME, NULL, val));
+}
+
+/*
+ * Add specified pair to the list.
+ */
+int
+nvlist_add_nvpair(nvlist_t *nvl, nvpair_t *nvp)
+{
+ if (nvl == NULL || nvp == NULL)
+ return (EINVAL);
+
+ return (nvlist_add_common(nvl, NVP_NAME(nvp), NVP_TYPE(nvp),
+ NVP_NELEM(nvp), NVP_VALUE(nvp)));
+}
+
+/*
+ * 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
+nvlist_merge(nvlist_t *dst, nvlist_t *nvl, int flag)
+{
+ if (nvl == NULL || dst == NULL)
+ return (EINVAL);
+
+ if (dst != nvl)
+ return (nvlist_copy_pairs(nvl, dst));
+
+ return (0);
+}
+
+/*
+ * Encoding related routines
+ */
+#define NVS_OP_ENCODE 0
+#define NVS_OP_DECODE 1
+#define NVS_OP_GETSIZE 2
+
+typedef struct nvs_ops nvs_ops_t;
+
+typedef struct {
+ int nvs_op;
+ const nvs_ops_t *nvs_ops;
+ void *nvs_private;
+ nvpriv_t *nvs_priv;
+} 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 {
+ int (*nvs_nvlist)(nvstream_t *, nvlist_t *, size_t *);
+ int (*nvs_nvpair)(nvstream_t *, nvpair_t *, size_t *);
+ int (*nvs_nvp_op)(nvstream_t *, nvpair_t *);
+ int (*nvs_nvp_size)(nvstream_t *, nvpair_t *, size_t *);
+ int (*nvs_nvl_fini)(nvstream_t *);
+};
+
+typedef struct {
+ char nvh_encoding; /* nvs encoding method */
+ char nvh_endian; /* nvs endian */
+ char nvh_reserved1; /* reserved for future use */
+ char nvh_reserved2; /* reserved for future use */
+} nvs_header_t;
+
+static int
+nvs_encode_pairs(nvstream_t *nvs, nvlist_t *nvl)
+{
+ nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
+ i_nvp_t *curr;
+
+ /*
+ * Walk nvpair in list and encode each nvpair
+ */
+ for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next)
+ if (nvs->nvs_ops->nvs_nvpair(nvs, &curr->nvi_nvp, NULL) != 0)
+ return (EFAULT);
+
+ return (nvs->nvs_ops->nvs_nvl_fini(nvs));
+}
+
+static int
+nvs_decode_pairs(nvstream_t *nvs, nvlist_t *nvl)
+{
+ nvpair_t *nvp;
+ size_t nvsize;
+ int err;
+
+ /*
+ * Get decoded size of next pair in stream, alloc
+ * memory for nvpair_t, then decode the nvpair
+ */
+ while ((err = nvs->nvs_ops->nvs_nvpair(nvs, NULL, &nvsize)) == 0) {
+ if (nvsize == 0) /* end of list */
+ break;
+
+ /* make sure len makes sense */
+ if (nvsize < NVP_SIZE_CALC(1, 0))
+ return (EFAULT);
+
+ if ((nvp = nvp_buf_alloc(nvl, nvsize)) == NULL)
+ return (ENOMEM);
+
+ if ((err = nvs->nvs_ops->nvs_nvp_op(nvs, nvp)) != 0) {
+ nvp_buf_free(nvl, nvp);
+ return (err);
+ }
+
+ if (i_validate_nvpair(nvp) != 0) {
+ nvpair_free(nvp);
+ nvp_buf_free(nvl, nvp);
+ return (EFAULT);
+ }
+
+ nvp_buf_link(nvl, nvp);
+ }
+ return (err);
+}
+
+static int
+nvs_getsize_pairs(nvstream_t *nvs, nvlist_t *nvl, size_t *buflen)
+{
+ nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv;
+ i_nvp_t *curr;
+ uint64_t nvsize = *buflen;
+ size_t size;
+
+ /*
+ * Get encoded size of nvpairs in nvlist
+ */
+ for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) {
+ if (nvs->nvs_ops->nvs_nvp_size(nvs, &curr->nvi_nvp, &size) != 0)
+ return (EINVAL);
+
+ if ((nvsize += size) > INT32_MAX)
+ return (EINVAL);
+ }
+
+ *buflen = nvsize;
+ return (0);
+}
+
+static int
+nvs_operation(nvstream_t *nvs, nvlist_t *nvl, size_t *buflen)
+{
+ int err;
+
+ if (nvl->nvl_priv == 0)
+ return (EFAULT);
+
+ /*
+ * Perform the operation, starting with header, then each nvpair
+ */
+ if ((err = nvs->nvs_ops->nvs_nvlist(nvs, nvl, buflen)) != 0)
+ return (err);
+
+ switch (nvs->nvs_op) {
+ case NVS_OP_ENCODE:
+ err = nvs_encode_pairs(nvs, nvl);
+ break;
+
+ case NVS_OP_DECODE:
+ err = nvs_decode_pairs(nvs, nvl);
+ break;
+
+ case NVS_OP_GETSIZE:
+ err = nvs_getsize_pairs(nvs, nvl, buflen);
+ break;
+
+ default:
+ err = EINVAL;
+ }
+
+ return (err);
+}
+
+static int
+nvs_embedded(nvstream_t *nvs, nvlist_t *embedded)
+{
+ switch (nvs->nvs_op) {
+ case NVS_OP_ENCODE:
+ return (nvs_operation(nvs, embedded, NULL));
+
+ case NVS_OP_DECODE: {
+ nvpriv_t *priv;
+ int err;
+
+ if (embedded->nvl_version != NV_VERSION)
+ return (ENOTSUP);
+
+ if ((priv = nv_priv_alloc_embedded(nvs->nvs_priv)) == NULL)
+ return (ENOMEM);
+
+ nvlist_init(embedded, embedded->nvl_nvflag, priv);
+
+ if ((err = nvs_operation(nvs, embedded, NULL)) != 0)
+ nvlist_free(embedded);
+ return (err);
+ }
+ default:
+ break;
+ }
+
+ return (EINVAL);
+}
+
+static int
+nvs_embedded_nvl_array(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
+{
+ size_t nelem = NVP_NELEM(nvp);
+ nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp);
+ int i;
+
+ switch (nvs->nvs_op) {
+ case NVS_OP_ENCODE:
+ for (i = 0; i < nelem; i++)
+ if (nvs_embedded(nvs, nvlp[i]) != 0)
+ return (EFAULT);
+ break;
+
+ case NVS_OP_DECODE: {
+ size_t len = nelem * sizeof (uint64_t);
+ nvlist_t *embedded = (nvlist_t *)((uintptr_t)nvlp + len);
+
+ bzero(nvlp, len); /* don't trust packed data */
+ for (i = 0; i < nelem; i++) {
+ if (nvs_embedded(nvs, embedded) != 0) {
+ nvpair_free(nvp);
+ return (EFAULT);
+ }
+
+ nvlp[i] = embedded++;
+ }
+ break;
+ }
+ case NVS_OP_GETSIZE: {
+ uint64_t nvsize = 0;
+
+ for (i = 0; i < nelem; i++) {
+ size_t nvp_sz = 0;
+
+ if (nvs_operation(nvs, nvlp[i], &nvp_sz) != 0)
+ return (EINVAL);
+
+ if ((nvsize += nvp_sz) > INT32_MAX)
+ return (EINVAL);
+ }
+
+ *size = nvsize;
+ break;
+ }
+ default:
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+static int nvs_native(nvstream_t *, nvlist_t *, char *, size_t *);
+static int nvs_xdr(nvstream_t *, nvlist_t *, char *, size_t *);
+
+/*
+ * Common routine for nvlist operations:
+ * encode, decode, getsize (encoded size).
+ */
+static int
+nvlist_common(nvlist_t *nvl, char *buf, size_t *buflen, int encoding,
+ int nvs_op)
+{
+ int err = 0;
+ nvstream_t nvs;
+ int nvl_endian;
+#if BYTE_ORDER == _LITTLE_ENDIAN
+ int host_endian = 1;
+#else
+ int host_endian = 0;
+#endif /* _LITTLE_ENDIAN */
+ nvs_header_t *nvh = (void *)buf;
+
+ if (buflen == NULL || nvl == NULL ||
+ (nvs.nvs_priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL)
+ return (EINVAL);
+
+ nvs.nvs_op = nvs_op;
+
+ /*
+ * 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:
+ if (buf == NULL || *buflen < sizeof (nvs_header_t))
+ return (EINVAL);
+
+ nvh->nvh_encoding = encoding;
+ nvh->nvh_endian = nvl_endian = host_endian;
+ nvh->nvh_reserved1 = 0;
+ nvh->nvh_reserved2 = 0;
+ break;
+
+ case NVS_OP_DECODE:
+ if (buf == NULL || *buflen < sizeof (nvs_header_t))
+ return (EINVAL);
+
+ /* get method of encoding from first byte */
+ encoding = nvh->nvh_encoding;
+ nvl_endian = nvh->nvh_endian;
+ break;
+
+ case NVS_OP_GETSIZE:
+ nvl_endian = host_endian;
+
+ /*
+ * 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);
+ err = nvs_native(&nvs, nvl, buf, buflen);
+ break;
+ case NV_ENCODE_XDR:
+ err = nvs_xdr(&nvs, nvl, buf, buflen);
+ break;
+ default:
+ err = ENOTSUP;
+ break;
+ }
+
+ return (err);
+}
+
+int
+nvlist_size(nvlist_t *nvl, size_t *size, int encoding)
+{
+ return (nvlist_common(nvl, NULL, size, encoding, NVS_OP_GETSIZE));
+}
+
+/*
+ * Pack nvlist into contiguous memory
+ */
+/*ARGSUSED1*/
+int
+nvlist_pack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding,
+ int kmflag)
+{
+#if defined(_KERNEL) && !defined(_BOOT)
+ return (nvlist_xpack(nvl, bufp, buflen, encoding,
+ (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep)));
+#else
+ return (nvlist_xpack(nvl, bufp, buflen, encoding, nv_alloc_nosleep));
+#endif
+}
+
+int
+nvlist_xpack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding,
+ nv_alloc_t *nva)
+{
+ nvpriv_t nvpriv;
+ size_t alloc_size;
+ char *buf;
+ int err;
+
+ if (nva == NULL || nvl == NULL || bufp == NULL || buflen == NULL)
+ return (EINVAL);
+
+ if (*bufp != NULL)
+ return (nvlist_common(nvl, *bufp, buflen, encoding,
+ NVS_OP_ENCODE));
+
+ /*
+ * 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.
+ */
+ nv_priv_init(&nvpriv, nva, 0);
+
+ if (err = nvlist_size(nvl, &alloc_size, encoding))
+ return (err);
+
+ if ((buf = nv_mem_zalloc(&nvpriv, alloc_size)) == NULL)
+ return (ENOMEM);
+
+ if ((err = nvlist_common(nvl, buf, &alloc_size, encoding,
+ NVS_OP_ENCODE)) != 0) {
+ nv_mem_free(&nvpriv, buf, alloc_size);
+ } else {
+ *buflen = alloc_size;
+ *bufp = buf;
+ }
+
+ return (err);
+}
+
+/*
+ * Unpack buf into an nvlist_t
+ */
+/*ARGSUSED1*/
+int
+nvlist_unpack(char *buf, size_t buflen, nvlist_t **nvlp, int kmflag)
+{
+#if defined(_KERNEL) && !defined(_BOOT)
+ return (nvlist_xunpack(buf, buflen, nvlp,
+ (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep)));
+#else
+ return (nvlist_xunpack(buf, buflen, nvlp, nv_alloc_nosleep));
+#endif
+}
+
+int
+nvlist_xunpack(char *buf, size_t buflen, nvlist_t **nvlp, nv_alloc_t *nva)
+{
+ nvlist_t *nvl;
+ int err;
+
+ if (nvlp == NULL)
+ return (EINVAL);
+
+ if ((err = nvlist_xalloc(&nvl, 0, nva)) != 0)
+ return (err);
+
+ if ((err = nvlist_common(nvl, buf, &buflen, 0, NVS_OP_DECODE)) != 0)
+ nvlist_free(nvl);
+ else
+ *nvlp = nvl;
+
+ 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.
+ */
+ caddr_t n_base;
+ caddr_t n_end;
+ caddr_t n_curr;
+ uint_t n_flag;
+} nvs_native_t;
+
+static int
+nvs_native_create(nvstream_t *nvs, nvs_native_t *native, char *buf,
+ size_t buflen)
+{
+ switch (nvs->nvs_op) {
+ case NVS_OP_ENCODE:
+ case NVS_OP_DECODE:
+ nvs->nvs_private = native;
+ native->n_curr = native->n_base = buf;
+ native->n_end = buf + buflen;
+ native->n_flag = 0;
+ return (0);
+
+ case NVS_OP_GETSIZE:
+ nvs->nvs_private = native;
+ native->n_curr = native->n_base = native->n_end = NULL;
+ native->n_flag = 0;
+ return (0);
+ default:
+ return (EINVAL);
+ }
+}
+
+/*ARGSUSED*/
+static void
+nvs_native_destroy(nvstream_t *nvs)
+{
+}
+
+static int
+native_cp(nvstream_t *nvs, void *buf, size_t size)
+{
+ nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
+
+ if (native->n_curr + size > native->n_end)
+ return (EFAULT);
+
+ /*
+ * The bcopy() below eliminates alignment requirement
+ * on the buffer (stream) and is preferred over direct access.
+ */
+ switch (nvs->nvs_op) {
+ case NVS_OP_ENCODE:
+ bcopy(buf, native->n_curr, size);
+ break;
+ case NVS_OP_DECODE:
+ bcopy(native->n_curr, buf, size);
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ native->n_curr += size;
+ return (0);
+}
+
+/*
+ * operate on nvlist_t header
+ */
+static int
+nvs_native_nvlist(nvstream_t *nvs, nvlist_t *nvl, size_t *size)
+{
+ nvs_native_t *native = nvs->nvs_private;
+
+ switch (nvs->nvs_op) {
+ case NVS_OP_ENCODE:
+ case NVS_OP_DECODE:
+ if (native->n_flag)
+ return (0); /* packed embedded list */
+
+ native->n_flag = 1;
+
+ /* copy version and nvflag of the nvlist_t */
+ if (native_cp(nvs, &nvl->nvl_version, sizeof (int32_t)) != 0 ||
+ native_cp(nvs, &nvl->nvl_nvflag, sizeof (int32_t)) != 0)
+ 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
+ */
+ if (native->n_flag) {
+ *size += 4;
+ } else {
+ native->n_flag = 1;
+ *size += 2 * sizeof (int32_t) + 4;
+ }
+
+ return (0);
+
+ default:
+ return (EINVAL);
+ }
+}
+
+static int
+nvs_native_nvl_fini(nvstream_t *nvs)
+{
+ if (nvs->nvs_op == NVS_OP_ENCODE) {
+ nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
+ /*
+ * Add 4 zero bytes at end of nvlist. They are used
+ * for end detection by the decode routine.
+ */
+ if (native->n_curr + sizeof (int) > native->n_end)
+ return (EFAULT);
+
+ bzero(native->n_curr, sizeof (int));
+ native->n_curr += sizeof (int);
+ }
+
+ return (0);
+}
+
+static int
+nvpair_native_embedded(nvstream_t *nvs, nvpair_t *nvp)
+{
+ if (nvs->nvs_op == NVS_OP_ENCODE) {
+ nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
+ char *packed = (void *)
+ (native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp));
+ /*
+ * Null out the pointer that is meaningless in the packed
+ * structure. The address may not be aligned, so we have
+ * to use bzero.
+ */
+ bzero(packed + offsetof(nvlist_t, nvl_priv),
+ sizeof(((nvlist_t *)NULL)->nvl_priv));
+ }
+
+ return (nvs_embedded(nvs, EMBEDDED_NVL(nvp)));
+}
+
+static int
+nvpair_native_embedded_array(nvstream_t *nvs, nvpair_t *nvp)
+{
+ if (nvs->nvs_op == NVS_OP_ENCODE) {
+ nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
+ char *value = native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp);
+ size_t len = NVP_NELEM(nvp) * sizeof (uint64_t);
+ int i;
+ /*
+ * Null out pointers that are meaningless in the packed
+ * structure. The addresses may not be aligned, so we have
+ * to use bzero.
+ */
+ bzero(value, len);
+
+ value += len;
+ for (i = 0; i < NVP_NELEM(nvp); i++) {
+ /*
+ * Null out the pointer that is meaningless in the
+ * packed structure. The address may not be aligned,
+ * so we have to use bzero.
+ */
+ bzero(value + offsetof(nvlist_t, nvl_priv),
+ sizeof(((nvlist_t *)NULL)->nvl_priv));
+ value += sizeof(nvlist_t);
+ }
+ }
+
+ return (nvs_embedded_nvl_array(nvs, nvp, NULL));
+}
+
+static void
+nvpair_native_string_array(nvstream_t *nvs, nvpair_t *nvp)
+{
+ switch (nvs->nvs_op) {
+ case NVS_OP_ENCODE: {
+ nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
+ uint64_t *strp = (void *)
+ (native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp));
+ /*
+ * Null out pointers that are meaningless in the packed
+ * structure. The addresses may not be aligned, so we have
+ * to use bzero.
+ */
+ bzero(strp, NVP_NELEM(nvp) * sizeof (uint64_t));
+ break;
+ }
+ case NVS_OP_DECODE: {
+ char **strp = (void *)NVP_VALUE(nvp);
+ char *buf = ((char *)strp + NVP_NELEM(nvp) * sizeof (uint64_t));
+ int i;
+
+ for (i = 0; i < NVP_NELEM(nvp); i++) {
+ strp[i] = buf;
+ buf += strlen(buf) + 1;
+ }
+ break;
+ }
+ }
+}
+
+static int
+nvs_native_nvp_op(nvstream_t *nvs, nvpair_t *nvp)
+{
+ data_type_t type;
+ 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.
+ */
+ switch (nvs->nvs_op) {
+ case NVS_OP_ENCODE:
+ case NVS_OP_DECODE:
+ if (native_cp(nvs, nvp, nvp->nvp_size) != 0)
+ return (EFAULT);
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ /* verify nvp_name_sz, check the name string length */
+ if (i_validate_nvpair_name(nvp) != 0)
+ return (EFAULT);
+
+ type = NVP_TYPE(nvp);
+
+ /*
+ * 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.
+ */
+ if ((value_sz = i_get_value_size(type, NULL, NVP_NELEM(nvp))) < 0)
+ return (EFAULT);
+
+ if (NVP_SIZE_CALC(nvp->nvp_name_sz, value_sz) > nvp->nvp_size)
+ return (EFAULT);
+
+ switch (type) {
+ case DATA_TYPE_NVLIST:
+ ret = nvpair_native_embedded(nvs, nvp);
+ break;
+ case DATA_TYPE_NVLIST_ARRAY:
+ ret = nvpair_native_embedded_array(nvs, nvp);
+ break;
+ case DATA_TYPE_STRING_ARRAY:
+ nvpair_native_string_array(nvs, nvp);
+ break;
+ default:
+ break;
+ }
+
+ return (ret);
+}
+
+static int
+nvs_native_nvp_size(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
+{
+ uint64_t nvp_sz = nvp->nvp_size;
+
+ switch (NVP_TYPE(nvp)) {
+ case DATA_TYPE_NVLIST: {
+ size_t nvsize = 0;
+
+ if (nvs_operation(nvs, EMBEDDED_NVL(nvp), &nvsize) != 0)
+ return (EINVAL);
+
+ nvp_sz += nvsize;
+ break;
+ }
+ case DATA_TYPE_NVLIST_ARRAY: {
+ size_t nvsize;
+
+ if (nvs_embedded_nvl_array(nvs, nvp, &nvsize) != 0)
+ return (EINVAL);
+
+ nvp_sz += nvsize;
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (nvp_sz > INT32_MAX)
+ return (EINVAL);
+
+ *size = nvp_sz;
+
+ return (0);
+}
+
+static int
+nvs_native_nvpair(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
+{
+ switch (nvs->nvs_op) {
+ case NVS_OP_ENCODE:
+ return (nvs_native_nvp_op(nvs, nvp));
+
+ case NVS_OP_DECODE: {
+ nvs_native_t *native = (nvs_native_t *)nvs->nvs_private;
+ int32_t decode_len;
+
+ /* try to read the size value from the stream */
+ if (native->n_curr + sizeof (int32_t) > native->n_end)
+ return (EFAULT);
+ bcopy(native->n_curr, &decode_len, sizeof (int32_t));
+
+ /* sanity check the size value */
+ if (decode_len < 0 ||
+ decode_len > native->n_end - native->n_curr)
+ 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)
+ native->n_curr += sizeof (int32_t);
+ break;
+ }
+
+ default:
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+static const nvs_ops_t nvs_native_ops = {
+ nvs_native_nvlist,
+ nvs_native_nvpair,
+ nvs_native_nvp_op,
+ nvs_native_nvp_size,
+ nvs_native_nvl_fini
+};
+
+static int
+nvs_native(nvstream_t *nvs, nvlist_t *nvl, char *buf, size_t *buflen)
+{
+ nvs_native_t native;
+ int err;
+
+ nvs->nvs_ops = &nvs_native_ops;
+
+ if ((err = nvs_native_create(nvs, &native, buf + sizeof (nvs_header_t),
+ *buflen - sizeof (nvs_header_t))) != 0)
+ return (err);
+
+ err = nvs_operation(nvs, nvl, buflen);
+
+ nvs_native_destroy(nvs);
+
+ 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
+nvs_xdr_create(nvstream_t *nvs, XDR *xdr, char *buf, size_t buflen)
+{
+ /* xdr data must be 4 byte aligned */
+ if ((ulong_t)buf % 4 != 0)
+ return (EFAULT);
+
+ switch (nvs->nvs_op) {
+ case NVS_OP_ENCODE:
+ xdrmem_create(xdr, buf, (uint_t)buflen, XDR_ENCODE);
+ nvs->nvs_private = xdr;
+ return (0);
+ case NVS_OP_DECODE:
+ xdrmem_create(xdr, buf, (uint_t)buflen, XDR_DECODE);
+ nvs->nvs_private = xdr;
+ return (0);
+ case NVS_OP_GETSIZE:
+ nvs->nvs_private = NULL;
+ return (0);
+ default:
+ return (EINVAL);
+ }
+}
+
+static void
+nvs_xdr_destroy(nvstream_t *nvs)
+{
+ switch (nvs->nvs_op) {
+ case NVS_OP_ENCODE:
+ case NVS_OP_DECODE:
+ xdr_destroy((XDR *)nvs->nvs_private);
+ break;
+ default:
+ break;
+ }
+}
+
+static int
+nvs_xdr_nvlist(nvstream_t *nvs, nvlist_t *nvl, size_t *size)
+{
+ switch (nvs->nvs_op) {
+ case NVS_OP_ENCODE:
+ case NVS_OP_DECODE: {
+ XDR *xdr = nvs->nvs_private;
+
+ if (!xdr_int(xdr, &nvl->nvl_version) ||
+ !xdr_u_int(xdr, &nvl->nvl_nvflag))
+ return (EFAULT);
+ break;
+ }
+ case NVS_OP_GETSIZE: {
+ /*
+ * 2 * 4 for nvl_version + nvl_nvflag
+ * and 8 for end of the entire list
+ */
+ *size += 2 * 4 + 8;
+ break;
+ }
+ default:
+ return (EINVAL);
+ }
+ return (0);
+}
+
+static int
+nvs_xdr_nvl_fini(nvstream_t *nvs)
+{
+ if (nvs->nvs_op == NVS_OP_ENCODE) {
+ XDR *xdr = nvs->nvs_private;
+ int zero = 0;
+
+ if (!xdr_int(xdr, &zero) || !xdr_int(xdr, &zero))
+ return (EFAULT);
+ }
+
+ return (0);
+}
+
+/*
+ * The format of xdr encoded nvpair is:
+ * encode_size, decode_size, name string, data type, nelem, data
+ */
+static int
+nvs_xdr_nvp_op(nvstream_t *nvs, nvpair_t *nvp)
+{
+ data_type_t type;
+ char *buf;
+ char *buf_end = (char *)nvp + nvp->nvp_size;
+ int value_sz;
+ uint_t nelem, buflen;
+ bool_t ret = FALSE;
+ XDR *xdr = nvs->nvs_private;
+
+ ASSERT(xdr != NULL && nvp != NULL);
+
+ /* name string */
+ if ((buf = NVP_NAME(nvp)) >= buf_end)
+ return (EFAULT);
+ buflen = buf_end - buf;
+
+ if (!xdr_string(xdr, &buf, buflen - 1))
+ return (EFAULT);
+ nvp->nvp_name_sz = strlen(buf) + 1;
+
+ /* type and nelem */
+ if (!xdr_int(xdr, (int *)&nvp->nvp_type) ||
+ !xdr_int(xdr, &nvp->nvp_value_elem))
+ return (EFAULT);
+
+ type = NVP_TYPE(nvp);
+ nelem = nvp->nvp_value_elem;
+
+ /*
+ * 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.
+ */
+ if ((value_sz = i_get_value_size(type, NULL, nelem)) < 0)
+ return (EFAULT);
+
+ /* if there is no data to extract then return */
+ if (nelem == 0)
+ return (0);
+
+ /* value */
+ if ((buf = NVP_VALUE(nvp)) >= buf_end)
+ return (EFAULT);
+ buflen = buf_end - buf;
+
+ if (buflen < value_sz)
+ return (EFAULT);
+
+ switch (type) {
+ case DATA_TYPE_NVLIST:
+ if (nvs_embedded(nvs, (void *)buf) == 0)
+ return (0);
+ break;
+
+ case DATA_TYPE_NVLIST_ARRAY:
+ if (nvs_embedded_nvl_array(nvs, nvp, NULL) == 0)
+ return (0);
+ break;
+
+ case DATA_TYPE_BOOLEAN:
+ ret = TRUE;
+ break;
+
+ case DATA_TYPE_BYTE:
+ case DATA_TYPE_INT8:
+ case DATA_TYPE_UINT8:
+ ret = xdr_char(xdr, buf);
+ break;
+
+ case DATA_TYPE_INT16:
+ ret = xdr_short(xdr, (void *)buf);
+ break;
+
+ case DATA_TYPE_UINT16:
+ ret = xdr_u_short(xdr, (void *)buf);
+ break;
+
+ case DATA_TYPE_BOOLEAN_VALUE:
+ case DATA_TYPE_INT32:
+ ret = xdr_int(xdr, (void *)buf);
+ break;
+
+ case DATA_TYPE_UINT32:
+ ret = xdr_u_int(xdr, (void *)buf);
+ break;
+
+ case DATA_TYPE_INT64:
+ ret = xdr_longlong_t(xdr, (void *)buf);
+ break;
+
+ case DATA_TYPE_UINT64:
+ ret = xdr_u_longlong_t(xdr, (void *)buf);
+ break;
+
+ case DATA_TYPE_HRTIME:
+ /*
+ * NOTE: must expose the definition of hrtime_t here
+ */
+ ret = xdr_longlong_t(xdr, (void *)buf);
+ break;
+#if !defined(_KERNEL)
+ case DATA_TYPE_DOUBLE:
+ ret = xdr_double(xdr, (void *)buf);
+ break;
+#endif
+ case DATA_TYPE_STRING:
+ ret = xdr_string(xdr, &buf, buflen - 1);
+ break;
+
+ case DATA_TYPE_BYTE_ARRAY:
+ ret = xdr_opaque(xdr, buf, nelem);
+ break;
+
+ case DATA_TYPE_INT8_ARRAY:
+ case DATA_TYPE_UINT8_ARRAY:
+ ret = xdr_array(xdr, &buf, &nelem, buflen, sizeof (int8_t),
+ (xdrproc_t)xdr_char);
+ break;
+
+ case DATA_TYPE_INT16_ARRAY:
+ ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int16_t),
+ sizeof (int16_t), (xdrproc_t)xdr_short);
+ break;
+
+ case DATA_TYPE_UINT16_ARRAY:
+ ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint16_t),
+ sizeof (uint16_t), (xdrproc_t)xdr_u_short);
+ break;
+
+ case DATA_TYPE_BOOLEAN_ARRAY:
+ case DATA_TYPE_INT32_ARRAY:
+ ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int32_t),
+ sizeof (int32_t), (xdrproc_t)xdr_int);
+ break;
+
+ case DATA_TYPE_UINT32_ARRAY:
+ ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint32_t),
+ sizeof (uint32_t), (xdrproc_t)xdr_u_int);
+ break;
+
+ case DATA_TYPE_INT64_ARRAY:
+ ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int64_t),
+ sizeof (int64_t), (xdrproc_t)xdr_longlong_t);
+ break;
+
+ case DATA_TYPE_UINT64_ARRAY:
+ ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint64_t),
+ sizeof (uint64_t), (xdrproc_t)xdr_u_longlong_t);
+ break;
+
+ case DATA_TYPE_STRING_ARRAY: {
+ size_t len = nelem * sizeof (uint64_t);
+ char **strp = (void *)buf;
+ int i;
+
+ if (nvs->nvs_op == NVS_OP_DECODE)
+ bzero(buf, len); /* don't trust packed data */
+
+ for (i = 0; i < nelem; i++) {
+ if (buflen <= len)
+ return (EFAULT);
+
+ buf += len;
+ buflen -= len;
+
+ if (xdr_string(xdr, &buf, buflen - 1) != TRUE)
+ return (EFAULT);
+
+ if (nvs->nvs_op == NVS_OP_DECODE)
+ strp[i] = buf;
+ len = strlen(buf) + 1;
+ }
+ ret = TRUE;
+ break;
+ }
+ default:
+ break;
+ }
+
+ return (ret == TRUE ? 0 : EFAULT);
+}
+
+static int
+nvs_xdr_nvp_size(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
+{
+ data_type_t type = NVP_TYPE(nvp);
+ /*
+ * encode_size + decode_size + name string size + data type + nelem
+ * where name string size = 4 + NV_ALIGN4(strlen(NVP_NAME(nvp)))
+ */
+ uint64_t nvp_sz = 4 + 4 + 4 + NV_ALIGN4(strlen(NVP_NAME(nvp))) + 4 + 4;
+
+ 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:
+ nvp_sz += 4; /* 4 is the minimum xdr unit */
+ 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:
+ nvp_sz += 4 + NV_ALIGN4(strlen((char *)NVP_VALUE(nvp)));
+ break;
+
+ case DATA_TYPE_BYTE_ARRAY:
+ nvp_sz += NV_ALIGN4(NVP_NELEM(nvp));
+ 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:
+ nvp_sz += 4 + 4 * (uint64_t)NVP_NELEM(nvp);
+ break;
+
+ case DATA_TYPE_INT64_ARRAY:
+ case DATA_TYPE_UINT64_ARRAY:
+ nvp_sz += 4 + 8 * (uint64_t)NVP_NELEM(nvp);
+ break;
+
+ case DATA_TYPE_STRING_ARRAY: {
+ int i;
+ char **strs = (void *)NVP_VALUE(nvp);
+
+ for (i = 0; i < NVP_NELEM(nvp); i++)
+ nvp_sz += 4 + NV_ALIGN4(strlen(strs[i]));
+
+ break;
+ }
+
+ case DATA_TYPE_NVLIST:
+ case DATA_TYPE_NVLIST_ARRAY: {
+ size_t nvsize = 0;
+ int old_nvs_op = nvs->nvs_op;
+ int err;
+
+ nvs->nvs_op = NVS_OP_GETSIZE;
+ if (type == DATA_TYPE_NVLIST)
+ err = nvs_operation(nvs, EMBEDDED_NVL(nvp), &nvsize);
+ else
+ err = nvs_embedded_nvl_array(nvs, nvp, &nvsize);
+ nvs->nvs_op = old_nvs_op;
+
+ if (err != 0)
+ return (EINVAL);
+
+ nvp_sz += nvsize;
+ break;
+ }
+
+ default:
+ return (EINVAL);
+ }
+
+ if (nvp_sz > INT32_MAX)
+ return (EINVAL);
+
+ *size = nvp_sz;
+
+ 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.
+ */
+#define NVS_XDR_HDR_LEN ((size_t)(5 * 4))
+#define NVS_XDR_DATA_LEN(y) (((size_t)(y) <= NVS_XDR_HDR_LEN) ? \
+ 0 : ((size_t)(y) - NVS_XDR_HDR_LEN))
+#define NVS_XDR_MAX_LEN(x) (NVP_SIZE_CALC(1, 0) + \
+ (NVS_XDR_DATA_LEN(x) * 2) + \
+ NV_ALIGN4((NVS_XDR_DATA_LEN(x) / 4)))
+
+static int
+nvs_xdr_nvpair(nvstream_t *nvs, nvpair_t *nvp, size_t *size)
+{
+ XDR *xdr = nvs->nvs_private;
+ int32_t encode_len, decode_len;
+
+ switch (nvs->nvs_op) {
+ case NVS_OP_ENCODE: {
+ size_t nvsize;
+
+ if (nvs_xdr_nvp_size(nvs, nvp, &nvsize) != 0)
+ return (EFAULT);
+
+ decode_len = nvp->nvp_size;
+ encode_len = nvsize;
+ if (!xdr_int(xdr, &encode_len) || !xdr_int(xdr, &decode_len))
+ return (EFAULT);
+
+ return (nvs_xdr_nvp_op(nvs, nvp));
+ }
+ case NVS_OP_DECODE: {
+ struct xdr_bytesrec bytesrec;
+
+ /* get the encode and decode size */
+ if (!xdr_int(xdr, &encode_len) || !xdr_int(xdr, &decode_len))
+ return (EFAULT);
+ *size = decode_len;
+
+ /* are we at the end of the stream? */
+ if (*size == 0)
+ return (0);
+
+ /* sanity check the size parameter */
+ if (!xdr_control(xdr, XDR_GET_BYTES_AVAIL, &bytesrec))
+ return (EFAULT);
+
+ if (*size > NVS_XDR_MAX_LEN(bytesrec.xc_num_avail))
+ return (EFAULT);
+ break;
+ }
+
+ default:
+ return (EINVAL);
+ }
+ return (0);
+}
+
+static const struct nvs_ops nvs_xdr_ops = {
+ nvs_xdr_nvlist,
+ nvs_xdr_nvpair,
+ nvs_xdr_nvp_op,
+ nvs_xdr_nvp_size,
+ nvs_xdr_nvl_fini
+};
+
+static int
+nvs_xdr(nvstream_t *nvs, nvlist_t *nvl, char *buf, size_t *buflen)
+{
+ XDR xdr;
+ int err;
+
+ nvs->nvs_ops = &nvs_xdr_ops;
+
+ if ((err = nvs_xdr_create(nvs, &xdr, buf + sizeof (nvs_header_t),
+ *buflen - sizeof (nvs_header_t))) != 0)
+ return (err);
+
+ err = nvs_operation(nvs, nvl, buflen);
+
+ nvs_xdr_destroy(nvs);
+
+ return (err);
+}
Index: sys/cddl/contrib/opensolaris/common/nvpair/opensolaris_nvpair_alloc_fixed.c
===================================================================
--- /dev/null
+++ sys/cddl/contrib/opensolaris/common/nvpair/opensolaris_nvpair_alloc_fixed.c
@@ -0,0 +1,118 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/nvpair.h>
+#include <sys/sysmacros.h>
+#if defined(_KERNEL) && !defined(_BOOT)
+#include <sys/varargs.h>
+#else
+#include <stdarg.h>
+#include <strings.h>
+#endif
+
+/*
+ * This allocator is very simple.
+ * - it uses a pre-allocated buffer for memory allocations.
+ * - it does _not_ free memory in the pre-allocated buffer.
+ *
+ * The reason for the selected implemention is simplicity.
+ * This allocator is designed for the usage in interrupt context when
+ * the caller may not wait for free memory.
+ */
+
+/* pre-allocated buffer for memory allocations */
+typedef struct nvbuf {
+ uintptr_t nvb_buf; /* address of pre-allocated buffer */
+ uintptr_t nvb_lim; /* limit address in the buffer */
+ uintptr_t nvb_cur; /* current address in the buffer */
+} nvbuf_t;
+
+/*
+ * Initialize the pre-allocated buffer allocator. The caller needs to supply
+ *
+ * buf address of pre-allocated buffer
+ * bufsz size of pre-allocated buffer
+ *
+ * nv_fixed_init() calculates the remaining members of nvbuf_t.
+ */
+static int
+nv_fixed_init(nv_alloc_t *nva, va_list valist)
+{
+ uintptr_t base = va_arg(valist, uintptr_t);
+ uintptr_t lim = base + va_arg(valist, size_t);
+ nvbuf_t *nvb = (nvbuf_t *)P2ROUNDUP(base, sizeof (uintptr_t));
+
+ if (base == 0 || (uintptr_t)&nvb[1] > lim)
+ return (EINVAL);
+
+ nvb->nvb_buf = (uintptr_t)&nvb[0];
+ nvb->nvb_cur = (uintptr_t)&nvb[1];
+ nvb->nvb_lim = lim;
+ nva->nva_arg = nvb;
+
+ return (0);
+}
+
+static void *
+nv_fixed_alloc(nv_alloc_t *nva, size_t size)
+{
+ nvbuf_t *nvb = nva->nva_arg;
+ uintptr_t new = nvb->nvb_cur;
+
+ if (size == 0 || new + size > nvb->nvb_lim)
+ return (NULL);
+
+ nvb->nvb_cur = P2ROUNDUP(new + size, sizeof (uintptr_t));
+
+ return ((void *)new);
+}
+
+/*ARGSUSED*/
+static void
+nv_fixed_free(nv_alloc_t *nva, void *buf, size_t size)
+{
+ /* don't free memory in the pre-allocated buffer */
+}
+
+static void
+nv_fixed_reset(nv_alloc_t *nva)
+{
+ nvbuf_t *nvb = nva->nva_arg;
+
+ nvb->nvb_cur = (uintptr_t)&nvb[1];
+}
+
+const nv_alloc_ops_t nv_fixed_ops_def = {
+ nv_fixed_init, /* nv_ao_init() */
+ NULL, /* nv_ao_fini() */
+ nv_fixed_alloc, /* nv_ao_alloc() */
+ nv_fixed_free, /* nv_ao_free() */
+ nv_fixed_reset /* nv_ao_reset() */
+};
+
+const nv_alloc_ops_t *nv_fixed_ops = &nv_fixed_ops_def;
Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -126,9 +126,9 @@
cddl/compat/opensolaris/kern/opensolaris_zone.c optional zfs compile-with "${ZFS_C}"
cddl/contrib/opensolaris/common/acl/acl_common.c optional zfs compile-with "${ZFS_C}"
cddl/contrib/opensolaris/common/avl/avl.c optional zfs compile-with "${ZFS_C}"
-cddl/contrib/opensolaris/common/nvpair/fnvpair.c optional zfs compile-with "${ZFS_C}"
-cddl/contrib/opensolaris/common/nvpair/nvpair.c optional zfs compile-with "${ZFS_C}"
-cddl/contrib/opensolaris/common/nvpair/nvpair_alloc_fixed.c optional zfs compile-with "${ZFS_C}"
+cddl/contrib/opensolaris/common/nvpair/opensolaris_fnvpair.c optional zfs compile-with "${ZFS_C}"
+cddl/contrib/opensolaris/common/nvpair/opensolaris_nvpair.c optional zfs compile-with "${ZFS_C}"
+cddl/contrib/opensolaris/common/nvpair/opensolaris_nvpair_alloc_fixed.c optional zfs compile-with "${ZFS_C}"
cddl/contrib/opensolaris/common/unicode/u8_textprep.c optional zfs compile-with "${ZFS_C}"
cddl/contrib/opensolaris/common/zfs/zfeature_common.c optional zfs compile-with "${ZFS_C}"
cddl/contrib/opensolaris/common/zfs/zfs_comutil.c optional zfs compile-with "${ZFS_C}"
@@ -476,6 +476,9 @@
contrib/libfdt/fdt_strerror.c optional fdt
contrib/libfdt/fdt_sw.c optional fdt
contrib/libfdt/fdt_wip.c optional fdt
+contrib/libnv/dnvlist.c standard
+contrib/libnv/nvlist.c standard
+contrib/libnv/nvpair.c standard
contrib/ngatm/netnatm/api/cc_conn.c optional ngatm_ccatm \
compile-with "${NORMAL_C_NOWERROR} -I$S/contrib/ngatm"
contrib/ngatm/netnatm/api/cc_data.c optional ngatm_ccatm \
Index: sys/contrib/libnv/dnvlist.c
===================================================================
--- /dev/null
+++ sys/contrib/libnv/dnvlist.c
@@ -0,0 +1,128 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/contrib/libnv/dnvlist.c 285139 2015-07-04 16:33:37Z oshogbo $");
+
+#ifdef _KERNEL
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+
+#include <machine/stdarg.h>
+
+#else
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#endif
+
+#include <sys/dnv.h>
+#include <sys/nv.h>
+
+#include "nv_impl.h"
+
+#define DNVLIST_GET(ftype, type) \
+ftype \
+dnvlist_get_##type(const nvlist_t *nvl, const char *name, ftype defval) \
+{ \
+ \
+ if (nvlist_exists_##type(nvl, name)) \
+ return (nvlist_get_##type(nvl, name)); \
+ else \
+ return (defval); \
+}
+
+DNVLIST_GET(bool, bool)
+DNVLIST_GET(uint64_t, number)
+DNVLIST_GET(const char *, string)
+DNVLIST_GET(const nvlist_t *, nvlist)
+#ifndef _KERNEL
+DNVLIST_GET(int, descriptor)
+#endif
+
+#undef DNVLIST_GET
+
+const void *
+dnvlist_get_binary(const nvlist_t *nvl, const char *name, size_t *sizep,
+ const void *defval, size_t defsize)
+{
+ const void *value;
+
+ if (nvlist_exists_binary(nvl, name))
+ value = nvlist_get_binary(nvl, name, sizep);
+ else {
+ if (sizep != NULL)
+ *sizep = defsize;
+ value = defval;
+ }
+ return (value);
+}
+
+#define DNVLIST_TAKE(ftype, type) \
+ftype \
+dnvlist_take_##type(nvlist_t *nvl, const char *name, ftype defval) \
+{ \
+ \
+ if (nvlist_exists_##type(nvl, name)) \
+ return (nvlist_take_##type(nvl, name)); \
+ else \
+ return (defval); \
+}
+
+DNVLIST_TAKE(bool, bool)
+DNVLIST_TAKE(uint64_t, number)
+DNVLIST_TAKE(char *, string)
+DNVLIST_TAKE(nvlist_t *, nvlist)
+#ifndef _KERNEL
+DNVLIST_TAKE(int, descriptor)
+#endif
+
+#undef DNVLIST_TAKE
+
+void *
+dnvlist_take_binary(nvlist_t *nvl, const char *name, size_t *sizep,
+ void *defval, size_t defsize)
+{
+ void *value;
+
+ if (nvlist_exists_binary(nvl, name))
+ value = nvlist_take_binary(nvl, name, sizep);
+ else {
+ if (sizep != NULL)
+ *sizep = defsize;
+ value = defval;
+ }
+ return (value);
+}
+
Index: sys/contrib/libnv/nv_impl.h
===================================================================
--- /dev/null
+++ sys/contrib/libnv/nv_impl.h
@@ -0,0 +1,158 @@
+/*-
+ * 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
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: head/sys/contrib/libnv/nv_impl.h 286796 2015-08-15 06:34:49Z oshogbo $
+ */
+
+#ifndef _NV_IMPL_H_
+#define _NV_IMPL_H_
+
+#ifndef _NVPAIR_T_DECLARED
+#define _NVPAIR_T_DECLARED
+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_DESCRIPTOR_ARRAY
+
+#define NV_FLAG_BIG_ENDIAN 0x080
+#define NV_FLAG_IN_ARRAY 0x100
+
+#ifdef _KERNEL
+#define nv_malloc(size) malloc((size), M_NVLIST, M_WAITOK)
+#define nv_calloc(n, size) malloc((n) * (size), M_NVLIST, \
+ M_WAITOK | M_ZERO)
+#define nv_realloc(buf, size) realloc((buf), (size), M_NVLIST, \
+ M_WAITOK)
+#define nv_free(buf) free((buf), M_NVLIST)
+#define nv_strdup(buf) strdup((buf), M_NVLIST)
+#define nv_vasprintf(ptr, ...) vasprintf(ptr, M_NVLIST, __VA_ARGS__)
+
+#define ERRNO_SET(var) do { } while (0)
+#define ERRNO_SAVE() do { do { } while(0)
+#define ERRNO_RESTORE() } while (0)
+
+#define ERRNO_OR_DEFAULT(default) (default)
+
+#else
+
+#define nv_malloc(size) malloc((size))
+#define nv_calloc(n, size) calloc((n), (size))
+#define nv_realloc(buf, size) realloc((buf), (size))
+#define nv_free(buf) free((buf))
+#define nv_strdup(buf) strdup((buf))
+#define nv_vasprintf(ptr, ...) vasprintf(ptr, __VA_ARGS__)
+
+#define ERRNO_SET(var) do { errno = (var); } while (0)
+#define ERRNO_SAVE() do { \
+ int _serrno; \
+ \
+ _serrno = errno
+
+#define ERRNO_RESTORE() errno = _serrno; \
+ } while (0)
+
+#define ERRNO_OR_DEFAULT(default) (errno == 0 ? (default) : errno)
+
+#endif
+
+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);
+nvpair_t *nvlist_prev_nvpair(const nvlist_t *nvl, const nvpair_t *nvp);
+
+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);
+
+nvpair_t *nvlist_take_nvpair(nvlist_t *nvl, const char *name);
+
+/* Function removes the given nvpair from the nvlist. */
+void nvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp);
+
+void nvlist_free_nvpair(nvlist_t *nvl, nvpair_t *nvp);
+
+int nvpair_type(const nvpair_t *nvp);
+const char *nvpair_name(const nvpair_t *nvp);
+
+nvpair_t *nvpair_clone(const nvpair_t *nvp);
+
+nvpair_t *nvpair_create_null(const char *name);
+nvpair_t *nvpair_create_bool(const char *name, bool value);
+nvpair_t *nvpair_create_number(const char *name, uint64_t value);
+nvpair_t *nvpair_create_string(const char *name, const char *value);
+nvpair_t *nvpair_create_stringf(const char *name, const char *valuefmt, ...) __printflike(2, 3);
+nvpair_t *nvpair_create_stringv(const char *name, const char *valuefmt, va_list valueap) __printflike(2, 0);
+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);
+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);
+
+#endif /* !_NV_IMPL_H_ */
Index: sys/contrib/libnv/nvlist.c
===================================================================
--- /dev/null
+++ sys/contrib/libnv/nvlist.c
@@ -0,0 +1,2024 @@
+/*-
+ * 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
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/contrib/libnv/nvlist.c 286796 2015-08-15 06:34:49Z oshogbo $");
+
+#include <sys/param.h>
+#include <sys/endian.h>
+#include <sys/queue.h>
+
+#ifdef _KERNEL
+
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+
+#include <machine/stdarg.h>
+
+#else
+#include <sys/socket.h>
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#define _WITH_DPRINTF
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "msgio.h"
+#endif
+
+#ifdef HAVE_PJDLOG
+#include <pjdlog.h>
+#endif
+
+#include <sys/nv.h>
+
+#include "nv_impl.h"
+#include "nvlist_impl.h"
+#include "nvpair_impl.h"
+
+#ifndef HAVE_PJDLOG
+#ifdef _KERNEL
+#define PJDLOG_ASSERT(...) MPASS(__VA_ARGS__)
+#define PJDLOG_RASSERT(expr, ...) KASSERT(expr, (__VA_ARGS__))
+#define PJDLOG_ABORT(...) panic(__VA_ARGS__)
+#else
+#include <assert.h>
+#define PJDLOG_ASSERT(...) assert(__VA_ARGS__)
+#define PJDLOG_RASSERT(expr, ...) assert(expr)
+#define PJDLOG_ABORT(...) do { \
+ fprintf(stderr, "%s:%u: ", __FILE__, __LINE__); \
+ fprintf(stderr, __VA_ARGS__); \
+ fprintf(stderr, "\n"); \
+ abort(); \
+} while (0)
+#endif
+#endif
+
+#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)
+
+#define NVLIST_MAGIC 0x6e766c /* "nvl" */
+struct nvlist {
+ int nvl_magic;
+ int nvl_error;
+ int nvl_flags;
+ nvpair_t *nvl_parent;
+ nvpair_t *nvl_array_next;
+ struct nvl_head nvl_head;
+};
+
+#define NVLIST_ASSERT(nvl) do { \
+ PJDLOG_ASSERT((nvl) != NULL); \
+ PJDLOG_ASSERT((nvl)->nvl_magic == NVLIST_MAGIC); \
+} while (0)
+
+#ifdef _KERNEL
+MALLOC_DEFINE(M_NVLIST, "nvlist", "kernel nvlist");
+#endif
+
+#define NVPAIR_ASSERT(nvp) nvpair_assert(nvp)
+
+#define NVLIST_HEADER_MAGIC 0x6c
+#define NVLIST_HEADER_VERSION 0x00
+struct nvlist_header {
+ uint8_t nvlh_magic;
+ uint8_t nvlh_version;
+ uint8_t nvlh_flags;
+ uint64_t nvlh_descriptors;
+ uint64_t nvlh_size;
+} __packed;
+
+nvlist_t *
+nvlist_create(int flags)
+{
+ nvlist_t *nvl;
+
+ PJDLOG_ASSERT((flags & ~(NV_FLAG_PUBLIC_MASK)) == 0);
+
+ nvl = nv_malloc(sizeof(*nvl));
+ if (nvl == NULL)
+ return (NULL);
+ 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;
+
+ return (nvl);
+}
+
+void
+nvlist_destroy(nvlist_t *nvl)
+{
+ nvpair_t *nvp;
+
+ if (nvl == NULL)
+ return;
+
+ ERRNO_SAVE();
+
+ NVLIST_ASSERT(nvl);
+
+ while ((nvp = nvlist_first_nvpair(nvl)) != NULL) {
+ 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);
+
+ ERRNO_RESTORE();
+}
+
+void
+nvlist_set_error(nvlist_t *nvl, int error)
+{
+
+ PJDLOG_ASSERT(error != 0);
+
+ /*
+ * Check for error != 0 so that we don't do the wrong thing if somebody
+ * tries to abuse this API when asserts are disabled.
+ */
+ if (nvl != NULL && error != 0 && nvl->nvl_error == 0)
+ nvl->nvl_error = error;
+}
+
+int
+nvlist_error(const nvlist_t *nvl)
+{
+
+ if (nvl == NULL)
+ return (ENOMEM);
+
+ NVLIST_ASSERT(nvl);
+
+ return (nvl->nvl_error);
+}
+
+nvpair_t *
+nvlist_get_nvpair_parent(const nvlist_t *nvl)
+{
+
+ NVLIST_ASSERT(nvl);
+
+ return (nvl->nvl_parent);
+}
+
+const nvlist_t *
+nvlist_get_parent(const nvlist_t *nvl, void **cookiep)
+{
+ nvpair_t *nvp;
+
+ NVLIST_ASSERT(nvl);
+
+ nvp = nvl->nvl_parent;
+ if (cookiep != NULL)
+ *cookiep = nvp;
+ if (nvp == NULL)
+ return (NULL);
+
+ return (nvpair_nvlist(nvp));
+}
+
+void
+nvlist_set_parent(nvlist_t *nvl, nvpair_t *parent)
+{
+
+ NVLIST_ASSERT(nvl);
+
+ 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)
+{
+
+ NVLIST_ASSERT(nvl);
+ PJDLOG_ASSERT(nvl->nvl_error == 0);
+
+ return (nvlist_first_nvpair(nvl) == NULL);
+}
+
+int
+nvlist_flags(const nvlist_t *nvl)
+{
+
+ NVLIST_ASSERT(nvl);
+ PJDLOG_ASSERT(nvl->nvl_error == 0);
+
+ 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
+nvlist_report_missing(int type, const char *name)
+{
+
+ PJDLOG_ABORT("Element '%s' of type %s doesn't exist.",
+ name, nvpair_type_string(type));
+}
+
+static nvpair_t *
+nvlist_find(const nvlist_t *nvl, int type, const char *name)
+{
+ nvpair_t *nvp;
+
+ NVLIST_ASSERT(nvl);
+ PJDLOG_ASSERT(nvl->nvl_error == 0);
+ PJDLOG_ASSERT(type == NV_TYPE_NONE ||
+ (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
+
+ for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
+ nvp = nvlist_next_nvpair(nvl, nvp)) {
+ if (type != NV_TYPE_NONE && nvpair_type(nvp) != type)
+ continue;
+ if ((nvl->nvl_flags & NV_FLAG_IGNORE_CASE) != 0) {
+ if (strcasecmp(nvpair_name(nvp), name) != 0)
+ continue;
+ } else {
+ if (strcmp(nvpair_name(nvp), name) != 0)
+ continue;
+ }
+ break;
+ }
+
+ if (nvp == NULL)
+ ERRNO_SET(ENOENT);
+
+ return (nvp);
+}
+
+bool
+nvlist_exists_type(const nvlist_t *nvl, const char *name, int type)
+{
+
+ NVLIST_ASSERT(nvl);
+ PJDLOG_ASSERT(nvl->nvl_error == 0);
+ PJDLOG_ASSERT(type == NV_TYPE_NONE ||
+ (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
+
+ return (nvlist_find(nvl, type, name) != NULL);
+}
+
+void
+nvlist_free_type(nvlist_t *nvl, const char *name, int type)
+{
+ nvpair_t *nvp;
+
+ NVLIST_ASSERT(nvl);
+ PJDLOG_ASSERT(nvl->nvl_error == 0);
+ PJDLOG_ASSERT(type == NV_TYPE_NONE ||
+ (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
+
+ nvp = nvlist_find(nvl, type, name);
+ if (nvp != NULL)
+ nvlist_free_nvpair(nvl, nvp);
+ else
+ nvlist_report_missing(type, name);
+}
+
+nvlist_t *
+nvlist_clone(const nvlist_t *nvl)
+{
+ nvlist_t *newnvl;
+ nvpair_t *nvp, *newnvp;
+
+ NVLIST_ASSERT(nvl);
+
+ if (nvl->nvl_error != 0) {
+ ERRNO_SET(nvl->nvl_error);
+ return (NULL);
+ }
+
+ newnvl = nvlist_create(nvl->nvl_flags & NV_FLAG_PUBLIC_MASK);
+ for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
+ nvp = nvlist_next_nvpair(nvl, nvp)) {
+ newnvp = nvpair_clone(nvp);
+ if (newnvp == NULL)
+ break;
+ (void)nvlist_move_nvpair(newnvl, newnvp);
+ }
+ if (nvp != NULL) {
+ nvlist_destroy(newnvl);
+ return (NULL);
+ }
+ return (newnvl);
+}
+
+#ifndef _KERNEL
+static bool
+nvlist_dump_error_check(const nvlist_t *nvl, int fd, int level)
+{
+
+ if (nvlist_error(nvl) != 0) {
+ dprintf(fd, "%*serror: %d\n", level * 4, "",
+ nvlist_error(nvl));
+ return (true);
+ }
+
+ return (false);
+}
+
+/*
+ * Dump content of nvlist.
+ */
+void
+nvlist_dump(const nvlist_t *nvl, int fd)
+{
+ const nvlist_t *tmpnvl;
+ nvpair_t *nvp, *tmpnvp;
+ void *cookie;
+ int level;
+
+ level = 0;
+ if (nvlist_dump_error_check(nvl, fd, level))
+ return;
+
+ nvp = nvlist_first_nvpair(nvl);
+ while (nvp != NULL) {
+ dprintf(fd, "%*s%s (%s):", level * 4, "", nvpair_name(nvp),
+ nvpair_type_string(nvpair_type(nvp)));
+ switch (nvpair_type(nvp)) {
+ case NV_TYPE_NULL:
+ dprintf(fd, " null\n");
+ break;
+ case NV_TYPE_BOOL:
+ dprintf(fd, " %s\n", nvpair_get_bool(nvp) ?
+ "TRUE" : "FALSE");
+ break;
+ case NV_TYPE_NUMBER:
+ dprintf(fd, " %ju (%jd) (0x%jx)\n",
+ (uintmax_t)nvpair_get_number(nvp),
+ (intmax_t)nvpair_get_number(nvp),
+ (uintmax_t)nvpair_get_number(nvp));
+ break;
+ case NV_TYPE_STRING:
+ dprintf(fd, " [%s]\n", nvpair_get_string(nvp));
+ break;
+ case NV_TYPE_NVLIST:
+ dprintf(fd, "\n");
+ tmpnvl = nvpair_get_nvlist(nvp);
+ if (nvlist_dump_error_check(tmpnvl, fd, level + 1))
+ break;
+ tmpnvp = nvlist_first_nvpair(tmpnvl);
+ if (tmpnvp != NULL) {
+ nvl = tmpnvl;
+ nvp = tmpnvp;
+ level++;
+ continue;
+ }
+ break;
+ case NV_TYPE_DESCRIPTOR:
+ dprintf(fd, " %d\n", nvpair_get_descriptor(nvp));
+ break;
+ case NV_TYPE_BINARY:
+ {
+ const unsigned char *binary;
+ unsigned int ii;
+ size_t size;
+
+ binary = nvpair_get_binary(nvp, &size);
+ dprintf(fd, " %zu ", size);
+ for (ii = 0; ii < size; ii++)
+ dprintf(fd, "%02hhx", binary[ii]);
+ 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) {
+ 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;
+ }
+ }
+}
+
+void
+nvlist_fdump(const nvlist_t *nvl, FILE *fp)
+{
+
+ fflush(fp);
+ nvlist_dump(nvl, fileno(fp));
+}
+#endif
+
+/*
+ * The function obtains size of the nvlist after nvlist_pack().
+ */
+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, nitems;
+ unsigned int ii;
+
+ NVLIST_ASSERT(nvl);
+ PJDLOG_ASSERT(nvl->nvl_error == 0);
+
+ size = sizeof(struct nvlist_header);
+ nvp = nvlist_first_nvpair(nvl);
+ while (nvp != NULL) {
+ size += nvpair_header_size();
+ size += strlen(nvpair_name(nvp)) + 1;
+ if (nvpair_type(nvp) == NV_TYPE_NVLIST) {
+ size += sizeof(struct nvlist_header);
+ size += nvpair_header_size() + 1;
+ tmpnvl = nvpair_get_nvlist(nvp);
+ PJDLOG_ASSERT(tmpnvl->nvl_error == 0);
+ tmpnvp = nvlist_first_nvpair(tmpnvl);
+ if (tmpnvp != NULL) {
+ nvl = tmpnvl;
+ 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) {
+ 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;
+ }
+ }
+
+out:
+ return (size);
+}
+
+#ifndef _KERNEL
+static int *
+nvlist_xdescriptors(const nvlist_t *nvl, int *descs)
+{
+ nvpair_t *nvp;
+ const char *name;
+ int type;
+
+ NVLIST_ASSERT(nvl);
+ PJDLOG_ASSERT(nvl->nvl_error == 0);
+
+ nvp = NULL;
+ do {
+ while ((name = nvlist_next(nvl, &type, (void**)&nvp)) != NULL) {
+ switch (type) {
+ case NV_TYPE_DESCRIPTOR:
+ *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_pararr(nvl, (void**)&nvp)) != NULL);
+
+ return (descs);
+}
+#endif
+
+#ifndef _KERNEL
+int *
+nvlist_descriptors(const nvlist_t *nvl, size_t *nitemsp)
+{
+ size_t nitems;
+ int *fds;
+
+ nitems = nvlist_ndescriptors(nvl);
+ fds = nv_malloc(sizeof(fds[0]) * (nitems + 1));
+ if (fds == NULL)
+ return (NULL);
+ if (nitems > 0)
+ nvlist_xdescriptors(nvl, fds);
+ fds[nitems] = -1;
+ if (nitemsp != NULL)
+ *nitemsp = nitems;
+ return (fds);
+}
+#endif
+
+size_t
+nvlist_ndescriptors(const nvlist_t *nvl)
+{
+#ifndef _KERNEL
+ nvpair_t *nvp;
+ const char *name;
+ size_t ndescs;
+ int type;
+
+ NVLIST_ASSERT(nvl);
+ PJDLOG_ASSERT(nvl->nvl_error == 0);
+
+ ndescs = 0;
+ nvp = NULL;
+ do {
+ while ((name = nvlist_next(nvl, &type, (void**)&nvp)) != NULL) {
+ switch (type) {
+ case NV_TYPE_DESCRIPTOR:
+ ndescs++;
+ 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;
+ }
+ case NV_TYPE_DESCRIPTOR_ARRAY:
+ {
+ size_t nitems;
+
+ (void)nvpair_get_descriptor_array(nvp,
+ &nitems);
+ ndescs += nitems;
+ break;
+ }
+ }
+ }
+ } while ((nvl = nvlist_get_pararr(nvl, (void**)&nvp)) != NULL);
+
+ return (ndescs);
+#else
+ return (0);
+#endif
+}
+
+static unsigned char *
+nvlist_pack_header(const nvlist_t *nvl, unsigned char *ptr, size_t *leftp)
+{
+ struct nvlist_header nvlhdr;
+
+ NVLIST_ASSERT(nvl);
+
+ nvlhdr.nvlh_magic = NVLIST_HEADER_MAGIC;
+ nvlhdr.nvlh_version = NVLIST_HEADER_VERSION;
+ nvlhdr.nvlh_flags = nvl->nvl_flags;
+#if BYTE_ORDER == BIG_ENDIAN
+ nvlhdr.nvlh_flags |= NV_FLAG_BIG_ENDIAN;
+#endif
+ nvlhdr.nvlh_descriptors = nvlist_ndescriptors(nvl);
+ nvlhdr.nvlh_size = *leftp - sizeof(nvlhdr);
+ PJDLOG_ASSERT(*leftp >= sizeof(nvlhdr));
+ memcpy(ptr, &nvlhdr, sizeof(nvlhdr));
+ ptr += sizeof(nvlhdr);
+ *leftp -= sizeof(nvlhdr);
+
+ return (ptr);
+}
+
+static void *
+nvlist_xpack(const nvlist_t *nvl, int64_t *fdidxp, size_t *sizep)
+{
+ unsigned char *buf, *ptr;
+ size_t left, size;
+ const nvlist_t *tmpnvl;
+ nvpair_t *nvp, *tmpnvp;
+ void *cookie;
+
+ NVLIST_ASSERT(nvl);
+
+ if (nvl->nvl_error != 0) {
+ ERRNO_SET(nvl->nvl_error);
+ return (NULL);
+ }
+
+ size = nvlist_size(nvl);
+ buf = nv_malloc(size);
+ if (buf == NULL)
+ return (NULL);
+
+ ptr = buf;
+ left = size;
+
+ ptr = nvlist_pack_header(nvl, ptr, &left);
+
+ nvp = nvlist_first_nvpair(nvl);
+ while (nvp != NULL) {
+ NVPAIR_ASSERT(nvp);
+
+ nvpair_init_datasize(nvp);
+ ptr = nvpair_pack_header(nvp, ptr, &left);
+ if (ptr == NULL)
+ goto fail;
+ switch (nvpair_type(nvp)) {
+ case NV_TYPE_NULL:
+ ptr = nvpair_pack_null(nvp, ptr, &left);
+ break;
+ case NV_TYPE_BOOL:
+ ptr = nvpair_pack_bool(nvp, ptr, &left);
+ break;
+ case NV_TYPE_NUMBER:
+ ptr = nvpair_pack_number(nvp, ptr, &left);
+ break;
+ case NV_TYPE_STRING:
+ ptr = nvpair_pack_string(nvp, ptr, &left);
+ break;
+ case NV_TYPE_NVLIST:
+ tmpnvl = nvpair_get_nvlist(nvp);
+ ptr = nvlist_pack_header(tmpnvl, ptr, &left);
+ if (ptr == NULL)
+ goto fail;
+ tmpnvp = nvlist_first_nvpair(tmpnvl);
+ if (tmpnvp != NULL) {
+ nvl = tmpnvl;
+ nvp = tmpnvp;
+ continue;
+ }
+ ptr = nvpair_pack_nvlist_up(ptr, &left);
+ break;
+#ifndef _KERNEL
+ 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) {
+ 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;
+ }
+ }
+
+out:
+ if (sizep != NULL)
+ *sizep = size;
+ return (buf);
+fail:
+ nv_free(buf);
+ return (NULL);
+}
+
+void *
+nvlist_pack(const nvlist_t *nvl, size_t *sizep)
+{
+
+ NVLIST_ASSERT(nvl);
+
+ if (nvl->nvl_error != 0) {
+ ERRNO_SET(nvl->nvl_error);
+ return (NULL);
+ }
+
+ if (nvlist_ndescriptors(nvl) > 0) {
+ ERRNO_SET(EOPNOTSUPP);
+ return (NULL);
+ }
+
+ return (nvlist_xpack(nvl, NULL, sizep));
+}
+
+static bool
+nvlist_check_header(struct nvlist_header *nvlhdrp)
+{
+
+ if (nvlhdrp->nvlh_magic != NVLIST_HEADER_MAGIC) {
+ ERRNO_SET(EINVAL);
+ return (false);
+ }
+ if ((nvlhdrp->nvlh_flags & ~NV_FLAG_ALL_MASK) != 0) {
+ ERRNO_SET(EINVAL);
+ return (false);
+ }
+#if BYTE_ORDER == BIG_ENDIAN
+ if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) == 0) {
+ nvlhdrp->nvlh_size = le64toh(nvlhdrp->nvlh_size);
+ nvlhdrp->nvlh_descriptors = le64toh(nvlhdrp->nvlh_descriptors);
+ }
+#else
+ if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0) {
+ nvlhdrp->nvlh_size = be64toh(nvlhdrp->nvlh_size);
+ nvlhdrp->nvlh_descriptors = be64toh(nvlhdrp->nvlh_descriptors);
+ }
+#endif
+ return (true);
+}
+
+const unsigned char *
+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;
+
+ memcpy(&nvlhdr, ptr, sizeof(nvlhdr));
+
+ if (!nvlist_check_header(&nvlhdr))
+ goto failed;
+
+ if (nvlhdr.nvlh_size != *leftp - sizeof(nvlhdr))
+ goto failed;
+
+ /*
+ * nvlh_descriptors might be smaller than nfds in embedded nvlists.
+ */
+ if (nvlhdr.nvlh_descriptors > nfds)
+ goto failed;
+
+ if ((nvlhdr.nvlh_flags & ~NV_FLAG_ALL_MASK) != 0)
+ goto failed;
+
+ 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)
+ *isbep = (((int)nvlhdr.nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0);
+ *leftp -= sizeof(nvlhdr);
+
+ return (ptr);
+failed:
+ ERRNO_SET(EINVAL);
+ return (NULL);
+}
+
+static nvlist_t *
+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, *array;
+ nvpair_t *nvp;
+ size_t left;
+ bool isbe;
+
+ PJDLOG_ASSERT((flags & ~(NV_FLAG_PUBLIC_MASK)) == 0);
+
+ left = size;
+ ptr = buf;
+
+ tmpnvl = array = NULL;
+ nvl = retnvl = nvlist_create(0);
+ if (nvl == NULL)
+ goto failed;
+
+ ptr = nvlist_unpack_header(nvl, ptr, nfds, &isbe, &left);
+ if (ptr == NULL)
+ goto failed;
+ if (nvl->nvl_flags != flags) {
+ ERRNO_SET(EILSEQ);
+ goto failed;
+ }
+
+ while (left > 0) {
+ ptr = nvpair_unpack(isbe, ptr, &left, &nvp);
+ if (ptr == NULL)
+ goto failed;
+ switch (nvpair_type(nvp)) {
+ case NV_TYPE_NULL:
+ ptr = nvpair_unpack_null(isbe, nvp, ptr, &left);
+ break;
+ case NV_TYPE_BOOL:
+ ptr = nvpair_unpack_bool(isbe, nvp, ptr, &left);
+ break;
+ case NV_TYPE_NUMBER:
+ ptr = nvpair_unpack_number(isbe, nvp, ptr, &left);
+ break;
+ case NV_TYPE_STRING:
+ ptr = nvpair_unpack_string(isbe, nvp, ptr, &left);
+ break;
+ case NV_TYPE_NVLIST:
+ ptr = nvpair_unpack_nvlist(isbe, nvp, ptr, &left, nfds,
+ &tmpnvl);
+ if (tmpnvl == NULL || ptr == NULL)
+ goto failed;
+ nvlist_set_parent(tmpnvl, nvp);
+ break;
+#ifndef _KERNEL
+ case NV_TYPE_DESCRIPTOR:
+ 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);
+ break;
+ case NV_TYPE_NVLIST_UP:
+ if (nvl->nvl_parent == NULL)
+ goto failed;
+ 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));
+ }
+ if (ptr == NULL)
+ goto failed;
+ if (!nvlist_move_nvpair(nvl, nvp))
+ goto failed;
+ if (tmpnvl != NULL) {
+ nvl = tmpnvl;
+ tmpnvl = NULL;
+ }
+ }
+
+ return (retnvl);
+failed:
+ nvlist_destroy(retnvl);
+ return (NULL);
+}
+
+nvlist_t *
+nvlist_unpack(const void *buf, size_t size, int flags)
+{
+
+ return (nvlist_xunpack(buf, size, NULL, 0, flags));
+}
+
+#ifndef _KERNEL
+int
+nvlist_send(int sock, const nvlist_t *nvl)
+{
+ size_t datasize, nfds;
+ int *fds;
+ void *data;
+ int64_t fdidx;
+ int ret;
+
+ if (nvlist_error(nvl) != 0) {
+ ERRNO_SET(nvlist_error(nvl));
+ return (-1);
+ }
+
+ fds = nvlist_descriptors(nvl, &nfds);
+ if (fds == NULL)
+ return (-1);
+
+ ret = -1;
+ data = NULL;
+ fdidx = 0;
+
+ data = nvlist_xpack(nvl, &fdidx, &datasize);
+ if (data == NULL)
+ goto out;
+
+ if (buf_send(sock, data, datasize) == -1)
+ goto out;
+
+ if (nfds > 0) {
+ if (fd_send(sock, fds, nfds) == -1)
+ goto out;
+ }
+
+ ret = 0;
+out:
+ ERRNO_SAVE();
+ nv_free(fds);
+ nv_free(data);
+ ERRNO_RESTORE();
+ return (ret);
+}
+
+nvlist_t *
+nvlist_recv(int sock, int flags)
+{
+ struct nvlist_header nvlhdr;
+ nvlist_t *nvl, *ret;
+ unsigned char *buf;
+ size_t nfds, size, i;
+ int *fds;
+
+ if (buf_recv(sock, &nvlhdr, sizeof(nvlhdr)) == -1)
+ return (NULL);
+
+ if (!nvlist_check_header(&nvlhdr))
+ return (NULL);
+
+ nfds = (size_t)nvlhdr.nvlh_descriptors;
+ size = sizeof(nvlhdr) + (size_t)nvlhdr.nvlh_size;
+
+ buf = nv_malloc(size);
+ if (buf == NULL)
+ return (NULL);
+
+ memcpy(buf, &nvlhdr, sizeof(nvlhdr));
+
+ ret = NULL;
+ fds = NULL;
+
+ if (buf_recv(sock, buf + sizeof(nvlhdr), size - sizeof(nvlhdr)) == -1)
+ goto out;
+
+ if (nfds > 0) {
+ fds = nv_malloc(nfds * sizeof(fds[0]));
+ if (fds == NULL)
+ goto out;
+ if (fd_recv(sock, fds, nfds) == -1)
+ goto out;
+ }
+
+ nvl = nvlist_xunpack(buf, size, fds, nfds, flags);
+ if (nvl == NULL) {
+ ERRNO_SAVE();
+ for (i = 0; i < nfds; i++)
+ close(fds[i]);
+ ERRNO_RESTORE();
+ goto out;
+ }
+
+ ret = nvl;
+out:
+ ERRNO_SAVE();
+ nv_free(buf);
+ nv_free(fds);
+ ERRNO_RESTORE();
+
+ return (ret);
+}
+
+nvlist_t *
+nvlist_xfer(int sock, nvlist_t *nvl, int flags)
+{
+
+ if (nvlist_send(sock, nvl) < 0) {
+ nvlist_destroy(nvl);
+ return (NULL);
+ }
+ nvlist_destroy(nvl);
+ return (nvlist_recv(sock, flags));
+}
+#endif
+
+nvpair_t *
+nvlist_first_nvpair(const nvlist_t *nvl)
+{
+
+ NVLIST_ASSERT(nvl);
+
+ return (TAILQ_FIRST(&nvl->nvl_head));
+}
+
+nvpair_t *
+nvlist_next_nvpair(const nvlist_t *nvl, const nvpair_t *nvp)
+{
+ nvpair_t *retnvp;
+
+ NVLIST_ASSERT(nvl);
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
+
+ retnvp = nvpair_next(nvp);
+ PJDLOG_ASSERT(retnvp == NULL || nvpair_nvlist(retnvp) == nvl);
+
+ return (retnvp);
+
+}
+
+nvpair_t *
+nvlist_prev_nvpair(const nvlist_t *nvl, const nvpair_t *nvp)
+{
+ nvpair_t *retnvp;
+
+ NVLIST_ASSERT(nvl);
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
+
+ retnvp = nvpair_prev(nvp);
+ PJDLOG_ASSERT(nvpair_nvlist(retnvp) == nvl);
+
+ return (retnvp);
+}
+
+const char *
+nvlist_next(const nvlist_t *nvl, int *typep, void **cookiep)
+{
+ nvpair_t *nvp;
+
+ NVLIST_ASSERT(nvl);
+
+ if (cookiep == NULL || *cookiep == NULL)
+ nvp = nvlist_first_nvpair(nvl);
+ else
+ nvp = nvlist_next_nvpair(nvl, *cookiep);
+ if (nvp == NULL)
+ return (NULL);
+ if (typep != NULL)
+ *typep = nvpair_type(nvp);
+ if (cookiep != NULL)
+ *cookiep = nvp;
+ return (nvpair_name(nvp));
+}
+
+bool
+nvlist_exists(const nvlist_t *nvl, const char *name)
+{
+
+ return (nvlist_find(nvl, NV_TYPE_NONE, name) != NULL);
+}
+
+#define NVLIST_EXISTS(type, TYPE) \
+bool \
+nvlist_exists_##type(const nvlist_t *nvl, const char *name) \
+{ \
+ \
+ return (nvlist_find(nvl, NV_TYPE_##TYPE, name) != NULL); \
+}
+
+NVLIST_EXISTS(null, NULL)
+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
+
+#undef NVLIST_EXISTS
+
+void
+nvlist_add_nvpair(nvlist_t *nvl, const nvpair_t *nvp)
+{
+ nvpair_t *newnvp;
+
+ NVPAIR_ASSERT(nvp);
+
+ if (nvlist_error(nvl) != 0) {
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+ if ((nvl->nvl_flags & NV_FLAG_NO_UNIQUE) == 0) {
+ if (nvlist_exists(nvl, nvpair_name(nvp))) {
+ nvl->nvl_error = EEXIST;
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+ }
+
+ newnvp = nvpair_clone(nvp);
+ if (newnvp == NULL) {
+ nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+
+ nvpair_insert(&nvl->nvl_head, newnvp, nvl);
+}
+
+void
+nvlist_add_stringf(nvlist_t *nvl, const char *name, const char *valuefmt, ...)
+{
+ va_list valueap;
+
+ va_start(valueap, valuefmt);
+ nvlist_add_stringv(nvl, name, valuefmt, valueap);
+ va_end(valueap);
+}
+
+void
+nvlist_add_stringv(nvlist_t *nvl, const char *name, const char *valuefmt,
+ va_list valueap)
+{
+ nvpair_t *nvp;
+
+ if (nvlist_error(nvl) != 0) {
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+
+ nvp = nvpair_create_stringv(name, valuefmt, valueap);
+ if (nvp == NULL) {
+ nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
+ ERRNO_SET(nvl->nvl_error);
+ } else {
+ (void)nvlist_move_nvpair(nvl, nvp);
+ }
+}
+
+void
+nvlist_add_null(nvlist_t *nvl, const char *name)
+{
+ nvpair_t *nvp;
+
+ if (nvlist_error(nvl) != 0) {
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+
+ nvp = nvpair_create_null(name);
+ if (nvp == NULL) {
+ nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
+ ERRNO_SET(nvl->nvl_error);
+ } else {
+ (void)nvlist_move_nvpair(nvl, nvp);
+ }
+}
+
+void
+nvlist_add_binary(nvlist_t *nvl, const char *name, const void *value,
+ size_t size)
+{
+ nvpair_t *nvp;
+
+ if (nvlist_error(nvl) != 0) {
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+
+ nvp = nvpair_create_binary(name, value, size);
+ if (nvp == NULL) {
+ nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
+ ERRNO_SET(nvl->nvl_error);
+ } else {
+ (void)nvlist_move_nvpair(nvl, nvp);
+ }
+}
+
+
+#define NVLIST_ADD(vtype, type) \
+void \
+nvlist_add_##type(nvlist_t *nvl, const char *name, vtype value) \
+{ \
+ nvpair_t *nvp; \
+ \
+ if (nvlist_error(nvl) != 0) { \
+ ERRNO_SET(nvlist_error(nvl)); \
+ return; \
+ } \
+ \
+ nvp = nvpair_create_##type(name, value); \
+ if (nvp == NULL) { \
+ nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); \
+ ERRNO_SET(nvl->nvl_error); \
+ } else { \
+ (void)nvlist_move_nvpair(nvl, nvp); \
+ } \
+}
+
+NVLIST_ADD(bool, bool)
+NVLIST_ADD(uint64_t, number)
+NVLIST_ADD(const char *, string)
+NVLIST_ADD(const nvlist_t *, nvlist)
+#ifndef _KERNEL
+NVLIST_ADD(int, descriptor);
+#endif
+
+#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)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvpair_nvlist(nvp) == NULL);
+
+ if (nvlist_error(nvl) != 0) {
+ nvpair_free(nvp);
+ ERRNO_SET(nvlist_error(nvl));
+ return (false);
+ }
+ if ((nvl->nvl_flags & NV_FLAG_NO_UNIQUE) == 0) {
+ if (nvlist_exists(nvl, nvpair_name(nvp))) {
+ nvpair_free(nvp);
+ nvl->nvl_error = EEXIST;
+ ERRNO_SET(nvl->nvl_error);
+ return (false);
+ }
+ }
+
+ nvpair_insert(&nvl->nvl_head, nvp, nvl);
+ return (true);
+}
+
+void
+nvlist_move_string(nvlist_t *nvl, const char *name, char *value)
+{
+ nvpair_t *nvp;
+
+ if (nvlist_error(nvl) != 0) {
+ nv_free(value);
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+
+ nvp = nvpair_move_string(name, value);
+ 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(nvlist_t *nvl, const char *name, nvlist_t *value)
+{
+ nvpair_t *nvp;
+
+ if (nvlist_error(nvl) != 0) {
+ if (value != NULL && nvlist_get_nvpair_parent(value) != NULL)
+ nvlist_destroy(value);
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+
+ nvp = nvpair_move_nvlist(name, value);
+ 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(nvlist_t *nvl, const char *name, int value)
+{
+ nvpair_t *nvp;
+
+ if (nvlist_error(nvl) != 0) {
+ close(value);
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+
+ nvp = nvpair_move_descriptor(name, value);
+ if (nvp == NULL) {
+ nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
+ ERRNO_SET(nvl->nvl_error);
+ } else {
+ (void)nvlist_move_nvpair(nvl, nvp);
+ }
+}
+#endif
+
+void
+nvlist_move_binary(nvlist_t *nvl, const char *name, void *value, size_t size)
+{
+ nvpair_t *nvp;
+
+ if (nvlist_error(nvl) != 0) {
+ nv_free(value);
+ ERRNO_SET(nvlist_error(nvl));
+ return;
+ }
+
+ nvp = nvpair_move_binary(name, value, size);
+ 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_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)
+{
+
+ return (nvlist_find(nvl, NV_TYPE_NONE, name));
+}
+
+#define NVLIST_GET(ftype, type, TYPE) \
+ftype \
+nvlist_get_##type(const nvlist_t *nvl, const char *name) \
+{ \
+ const nvpair_t *nvp; \
+ \
+ nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name); \
+ if (nvp == NULL) \
+ nvlist_report_missing(NV_TYPE_##TYPE, name); \
+ return (nvpair_get_##type(nvp)); \
+}
+
+NVLIST_GET(bool, bool, BOOL)
+NVLIST_GET(uint64_t, number, NUMBER)
+NVLIST_GET(const char *, string, STRING)
+NVLIST_GET(const nvlist_t *, nvlist, NVLIST)
+#ifndef _KERNEL
+NVLIST_GET(int, descriptor, DESCRIPTOR)
+#endif
+
+#undef NVLIST_GET
+
+const void *
+nvlist_get_binary(const nvlist_t *nvl, const char *name, size_t *sizep)
+{
+ nvpair_t *nvp;
+
+ nvp = nvlist_find(nvl, NV_TYPE_BINARY, name);
+ if (nvp == NULL)
+ nvlist_report_missing(NV_TYPE_BINARY, name);
+
+ 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) \
+{ \
+ nvpair_t *nvp; \
+ ftype value; \
+ \
+ nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name); \
+ if (nvp == NULL) \
+ nvlist_report_missing(NV_TYPE_##TYPE, name); \
+ value = (ftype)(intptr_t)nvpair_get_##type(nvp); \
+ nvlist_remove_nvpair(nvl, nvp); \
+ nvpair_free_structure(nvp); \
+ return (value); \
+}
+
+NVLIST_TAKE(bool, bool, BOOL)
+NVLIST_TAKE(uint64_t, number, NUMBER)
+NVLIST_TAKE(char *, string, STRING)
+NVLIST_TAKE(nvlist_t *, nvlist, NVLIST)
+#ifndef _KERNEL
+NVLIST_TAKE(int, descriptor, DESCRIPTOR)
+#endif
+
+#undef NVLIST_TAKE
+
+void *
+nvlist_take_binary(nvlist_t *nvl, const char *name, size_t *sizep)
+{
+ nvpair_t *nvp;
+ void *value;
+
+ nvp = nvlist_find(nvl, NV_TYPE_BINARY, name);
+ if (nvp == NULL)
+ nvlist_report_missing(NV_TYPE_BINARY, name);
+
+ value = (void *)(intptr_t)nvpair_get_binary(nvp, sizep);
+ nvlist_remove_nvpair(nvl, nvp);
+ nvpair_free_structure(nvp);
+ 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)
+{
+
+ NVLIST_ASSERT(nvl);
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
+
+ nvpair_remove(&nvl->nvl_head, nvp, nvl);
+}
+
+void
+nvlist_free(nvlist_t *nvl, const char *name)
+{
+
+ nvlist_free_type(nvl, name, NV_TYPE_NONE);
+}
+
+#define NVLIST_FREE(type, TYPE) \
+void \
+nvlist_free_##type(nvlist_t *nvl, const char *name) \
+{ \
+ \
+ nvlist_free_type(nvl, name, NV_TYPE_##TYPE); \
+}
+
+NVLIST_FREE(null, NULL)
+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
+
+#undef NVLIST_FREE
+
+void
+nvlist_free_nvpair(nvlist_t *nvl, nvpair_t *nvp)
+{
+
+ NVLIST_ASSERT(nvl);
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
+
+ nvlist_remove_nvpair(nvl, nvp);
+ nvpair_free(nvp);
+}
+
Index: sys/contrib/libnv/nvlist_impl.h
===================================================================
--- /dev/null
+++ sys/contrib/libnv/nvlist_impl.h
@@ -0,0 +1,46 @@
+/*-
+ * 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
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: head/sys/contrib/libnv/nvlist_impl.h 286796 2015-08-15 06:34:49Z oshogbo $
+ */
+
+#ifndef _NVLIST_IMPL_H_
+#define _NVLIST_IMPL_H_
+
+#include <sys/nv.h>
+
+#ifndef _KERNEL
+#include <stdint.h>
+#endif
+
+nvpair_t *nvlist_get_nvpair_parent(const nvlist_t *nvl);
+const unsigned char *nvlist_unpack_header(nvlist_t *nvl,
+ const unsigned char *ptr, size_t nfds, bool *isbep, size_t *leftp);
+
+#endif /* !_NVLIST_IMPL_H_ */
Index: sys/contrib/libnv/nvpair.c
===================================================================
--- /dev/null
+++ sys/contrib/libnv/nvpair.c
@@ -0,0 +1,1997 @@
+/*-
+ * 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
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/contrib/libnv/nvpair.c 286796 2015-08-15 06:34:49Z oshogbo $");
+
+#include <sys/param.h>
+#include <sys/endian.h>
+#include <sys/queue.h>
+
+#ifdef _KERNEL
+
+#include <sys/errno.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+
+#include <machine/stdarg.h>
+
+#else
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "common_impl.h"
+#endif
+
+#ifdef HAVE_PJDLOG
+#include <pjdlog.h>
+#endif
+
+#include <sys/nv.h>
+
+#include "nv_impl.h"
+#include "nvlist_impl.h"
+#include "nvpair_impl.h"
+
+#ifndef HAVE_PJDLOG
+#ifdef _KERNEL
+#define PJDLOG_ASSERT(...) MPASS(__VA_ARGS__)
+#define PJDLOG_RASSERT(expr, ...) KASSERT(expr, (__VA_ARGS__))
+#define PJDLOG_ABORT(...) panic(__VA_ARGS__)
+#else
+#include <assert.h>
+#define PJDLOG_ASSERT(...) assert(__VA_ARGS__)
+#define PJDLOG_RASSERT(expr, ...) assert(expr)
+#define PJDLOG_ABORT(...) abort()
+#endif
+#endif
+
+#define NVPAIR_MAGIC 0x6e7670 /* "nvp" */
+struct nvpair {
+ int nvp_magic;
+ char *nvp_name;
+ 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;
+};
+
+#define NVPAIR_ASSERT(nvp) do { \
+ PJDLOG_ASSERT((nvp) != NULL); \
+ PJDLOG_ASSERT((nvp)->nvp_magic == NVPAIR_MAGIC); \
+} while (0)
+
+struct nvpair_header {
+ uint8_t nvph_type;
+ uint16_t nvph_namesize;
+ uint64_t nvph_datasize;
+ uint64_t nvph_nitems;
+} __packed;
+
+
+void
+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)
+{
+
+ NVPAIR_ASSERT(nvp);
+
+ return (nvp->nvp_list);
+}
+
+nvpair_t *
+nvpair_next(const nvpair_t *nvp)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_list != NULL);
+
+ return (TAILQ_NEXT(nvp, nvp_next));
+}
+
+nvpair_t *
+nvpair_prev(const nvpair_t *nvp)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_list != NULL);
+
+ return (TAILQ_PREV(nvp, nvl_head, nvp_next));
+}
+
+void
+nvpair_insert(struct nvl_head *head, nvpair_t *nvp, nvlist_t *nvl)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_list == NULL);
+ PJDLOG_ASSERT((nvlist_flags(nvl) & NV_FLAG_NO_UNIQUE) != 0 ||
+ !nvlist_exists(nvl, nvpair_name(nvp)));
+
+ TAILQ_INSERT_TAIL(head, nvp, nvp_next);
+ nvp->nvp_list = nvl;
+}
+
+static void
+nvpair_remove_nvlist(nvpair_t *nvp)
+{
+ nvlist_t *nvl;
+
+ /* XXX: DECONST is bad, mkay? */
+ nvl = __DECONST(nvlist_t *, nvpair_get_nvlist(nvp));
+ PJDLOG_ASSERT(nvl != NULL);
+ 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)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_list == 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;
+}
+
+nvpair_t *
+nvpair_clone(const nvpair_t *nvp)
+{
+ nvpair_t *newnvp;
+ const char *name;
+ const void *data;
+ size_t datasize;
+
+ NVPAIR_ASSERT(nvp);
+
+ name = nvpair_name(nvp);
+
+ switch (nvpair_type(nvp)) {
+ case NV_TYPE_NULL:
+ newnvp = nvpair_create_null(name);
+ break;
+ case NV_TYPE_BOOL:
+ newnvp = nvpair_create_bool(name, nvpair_get_bool(nvp));
+ break;
+ case NV_TYPE_NUMBER:
+ newnvp = nvpair_create_number(name, nvpair_get_number(nvp));
+ break;
+ case NV_TYPE_STRING:
+ newnvp = nvpair_create_string(name, nvpair_get_string(nvp));
+ break;
+ 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;
+ 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));
+ }
+
+ return (newnvp);
+}
+
+size_t
+nvpair_header_size(void)
+{
+
+ return (sizeof(struct nvpair_header));
+}
+
+size_t
+nvpair_size(const nvpair_t *nvp)
+{
+
+ NVPAIR_ASSERT(nvp);
+
+ return (nvp->nvp_datasize);
+}
+
+unsigned char *
+nvpair_pack_header(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
+{
+ struct nvpair_header nvphdr;
+ size_t namesize;
+
+ NVPAIR_ASSERT(nvp);
+
+ nvphdr.nvph_type = nvp->nvp_type;
+ namesize = strlen(nvp->nvp_name) + 1;
+ 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);
+ *leftp -= sizeof(nvphdr);
+
+ PJDLOG_ASSERT(*leftp >= namesize);
+ memcpy(ptr, nvp->nvp_name, namesize);
+ ptr += namesize;
+ *leftp -= namesize;
+
+ return (ptr);
+}
+
+unsigned char *
+nvpair_pack_null(const nvpair_t *nvp, unsigned char *ptr,
+ size_t *leftp __unused)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NULL);
+
+ return (ptr);
+}
+
+unsigned char *
+nvpair_pack_bool(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
+{
+ uint8_t value;
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL);
+
+ value = (uint8_t)nvp->nvp_data;
+
+ PJDLOG_ASSERT(*leftp >= sizeof(value));
+ memcpy(ptr, &value, sizeof(value));
+ ptr += sizeof(value);
+ *leftp -= sizeof(value);
+
+ return (ptr);
+}
+
+unsigned char *
+nvpair_pack_number(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
+{
+ uint64_t value;
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER);
+
+ value = (uint64_t)nvp->nvp_data;
+
+ PJDLOG_ASSERT(*leftp >= sizeof(value));
+ memcpy(ptr, &value, sizeof(value));
+ ptr += sizeof(value);
+ *leftp -= sizeof(value);
+
+ return (ptr);
+}
+
+unsigned char *
+nvpair_pack_string(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
+
+ 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_nvlist_up(unsigned char *ptr, size_t *leftp)
+{
+ struct nvpair_header nvphdr;
+ size_t namesize;
+ const char *name = "";
+
+ namesize = 1;
+ 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);
+ *leftp -= sizeof(nvphdr);
+
+ PJDLOG_ASSERT(*leftp >= namesize);
+ memcpy(ptr, name, namesize);
+ ptr += namesize;
+ *leftp -= namesize;
+
+ return (ptr);
+}
+
+#ifndef _KERNEL
+unsigned char *
+nvpair_pack_descriptor(const nvpair_t *nvp, unsigned char *ptr, int64_t *fdidxp,
+ size_t *leftp)
+{
+ int64_t value;
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
+
+ value = (int64_t)nvp->nvp_data;
+ 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)++;
+ }
+
+ PJDLOG_ASSERT(*leftp >= sizeof(value));
+ memcpy(ptr, &value, sizeof(value));
+ ptr += sizeof(value);
+ *leftp -= sizeof(value);
+
+ return (ptr);
+}
+#endif
+
+unsigned char *
+nvpair_pack_binary(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
+
+ 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_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)
+{
+
+ NVPAIR_ASSERT(nvp);
+
+ if (nvp->nvp_type == NV_TYPE_NVLIST) {
+ if (nvp->nvp_data == 0) {
+ nvp->nvp_datasize = 0;
+ } else {
+ nvp->nvp_datasize =
+ nvlist_size((const nvlist_t *)(intptr_t)nvp->nvp_data);
+ }
+ }
+}
+
+const unsigned char *
+nvpair_unpack_header(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
+ size_t *leftp)
+{
+ struct nvpair_header nvphdr;
+
+ if (*leftp < sizeof(nvphdr))
+ goto failed;
+
+ memcpy(&nvphdr, ptr, sizeof(nvphdr));
+ ptr += sizeof(nvphdr);
+ *leftp -= sizeof(nvphdr);
+
+#if NV_TYPE_FIRST > 0
+ if (nvphdr.nvph_type < NV_TYPE_FIRST)
+ goto failed;
+#endif
+ if (nvphdr.nvph_type > NV_TYPE_LAST &&
+ nvphdr.nvph_type != NV_TYPE_NVLIST_UP &&
+ nvphdr.nvph_type != NV_TYPE_NVLIST_ARRAY_NEXT) {
+ goto failed;
+ }
+
+#if BYTE_ORDER == BIG_ENDIAN
+ if (!isbe) {
+ nvphdr.nvph_namesize = le16toh(nvphdr.nvph_namesize);
+ nvphdr.nvph_datasize = le64toh(nvphdr.nvph_datasize);
+ }
+#else
+ if (isbe) {
+ nvphdr.nvph_namesize = be16toh(nvphdr.nvph_namesize);
+ nvphdr.nvph_datasize = be64toh(nvphdr.nvph_datasize);
+ }
+#endif
+
+ if (nvphdr.nvph_namesize > NV_NAME_MAX)
+ goto failed;
+ if (*leftp < nvphdr.nvph_namesize)
+ goto failed;
+ if (nvphdr.nvph_namesize < 1)
+ goto failed;
+ if (strnlen((const char *)ptr, nvphdr.nvph_namesize) !=
+ (size_t)(nvphdr.nvph_namesize - 1)) {
+ goto failed;
+ }
+
+ memcpy(nvp->nvp_name, ptr, nvphdr.nvph_namesize);
+ ptr += nvphdr.nvph_namesize;
+ *leftp -= nvphdr.nvph_namesize;
+
+ if (*leftp < nvphdr.nvph_datasize)
+ goto failed;
+
+ 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:
+ ERRNO_SET(EINVAL);
+ return (NULL);
+}
+
+const unsigned char *
+nvpair_unpack_null(bool isbe __unused, nvpair_t *nvp, const unsigned char *ptr,
+ size_t *leftp __unused)
+{
+
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NULL);
+
+ if (nvp->nvp_datasize != 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ return (ptr);
+}
+
+const unsigned char *
+nvpair_unpack_bool(bool isbe __unused, nvpair_t *nvp, const unsigned char *ptr,
+ size_t *leftp)
+{
+ uint8_t value;
+
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL);
+
+ if (nvp->nvp_datasize != sizeof(value)) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+ if (*leftp < sizeof(value)) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ memcpy(&value, ptr, sizeof(value));
+ ptr += sizeof(value);
+ *leftp -= sizeof(value);
+
+ if (value != 0 && value != 1) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ nvp->nvp_data = (uint64_t)value;
+
+ return (ptr);
+}
+
+const unsigned char *
+nvpair_unpack_number(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
+ size_t *leftp)
+{
+
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER);
+
+ if (nvp->nvp_datasize != sizeof(uint64_t)) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+ if (*leftp < sizeof(uint64_t)) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ if (isbe)
+ nvp->nvp_data = be64dec(ptr);
+ else
+ nvp->nvp_data = le64dec(ptr);
+
+ ptr += sizeof(uint64_t);
+ *leftp -= sizeof(uint64_t);
+
+ return (ptr);
+}
+
+const unsigned char *
+nvpair_unpack_string(bool isbe __unused, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp)
+{
+
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
+
+ if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ if (strnlen((const char *)ptr, nvp->nvp_datasize) !=
+ nvp->nvp_datasize - 1) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ nvp->nvp_data = (uint64_t)(uintptr_t)nv_strdup((const char *)ptr);
+ if (nvp->nvp_data == 0)
+ return (NULL);
+
+ ptr += nvp->nvp_datasize;
+ *leftp -= nvp->nvp_datasize;
+
+ return (ptr);
+}
+
+const unsigned char *
+nvpair_unpack_nvlist(bool isbe __unused, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp, size_t nfds, nvlist_t **child)
+{
+ nvlist_t *value;
+
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST);
+
+ if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ value = nvlist_create(0);
+ if (value == NULL)
+ return (NULL);
+
+ ptr = nvlist_unpack_header(value, ptr, nfds, NULL, leftp);
+ if (ptr == NULL)
+ return (NULL);
+
+ nvp->nvp_data = (uint64_t)(uintptr_t)value;
+ *child = value;
+
+ return (ptr);
+}
+
+#ifndef _KERNEL
+const unsigned char *
+nvpair_unpack_descriptor(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
+ size_t *leftp, const int *fds, size_t nfds)
+{
+ int64_t idx;
+
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
+
+ if (nvp->nvp_datasize != sizeof(idx)) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+ if (*leftp < sizeof(idx)) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ if (isbe)
+ idx = be64dec(ptr);
+ else
+ idx = le64dec(ptr);
+
+ if (idx < 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ if ((size_t)idx >= nfds) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ nvp->nvp_data = (uint64_t)fds[idx];
+
+ ptr += sizeof(idx);
+ *leftp -= sizeof(idx);
+
+ return (ptr);
+}
+#endif
+
+const unsigned char *
+nvpair_unpack_binary(bool isbe __unused, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp)
+{
+ void *value;
+
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
+
+ if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ value = nv_malloc(nvp->nvp_datasize);
+ if (value == NULL)
+ return (NULL);
+
+ memcpy(value, ptr, nvp->nvp_datasize);
+ ptr += nvp->nvp_datasize;
+ *leftp -= nvp->nvp_datasize;
+
+ nvp->nvp_data = (uint64_t)(uintptr_t)value;
+
+ return (ptr);
+}
+
+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)
+{
+ nvpair_t *nvp, *tmp;
+
+ nvp = nv_calloc(1, sizeof(*nvp) + NV_NAME_MAX);
+ if (nvp == NULL)
+ return (NULL);
+ nvp->nvp_name = (char *)(nvp + 1);
+
+ ptr = nvpair_unpack_header(isbe, nvp, ptr, leftp);
+ if (ptr == NULL)
+ goto failed;
+ tmp = nv_realloc(nvp, sizeof(*nvp) + strlen(nvp->nvp_name) + 1);
+ if (tmp == NULL)
+ goto failed;
+ nvp = tmp;
+
+ /* Update nvp_name after realloc(). */
+ nvp->nvp_name = (char *)(nvp + 1);
+ nvp->nvp_data = 0x00;
+ nvp->nvp_magic = NVPAIR_MAGIC;
+ *nvpp = nvp;
+ return (ptr);
+failed:
+ nv_free(nvp);
+ return (NULL);
+}
+
+int
+nvpair_type(const nvpair_t *nvp)
+{
+
+ NVPAIR_ASSERT(nvp);
+
+ return (nvp->nvp_type);
+}
+
+const char *
+nvpair_name(const nvpair_t *nvp)
+{
+
+ NVPAIR_ASSERT(nvp);
+
+ return (nvp->nvp_name);
+}
+
+nvpair_t *
+nvpair_create_stringf(const char *name, const char *valuefmt, ...)
+{
+ va_list valueap;
+ nvpair_t *nvp;
+
+ va_start(valueap, valuefmt);
+ nvp = nvpair_create_stringv(name, valuefmt, valueap);
+ va_end(valueap);
+
+ return (nvp);
+}
+
+nvpair_t *
+nvpair_create_stringv(const char *name, const char *valuefmt, va_list valueap)
+{
+ nvpair_t *nvp;
+ char *str;
+ int len;
+
+ len = nv_vasprintf(&str, valuefmt, valueap);
+ if (len < 0)
+ return (NULL);
+ nvp = nvpair_create_string(name, str);
+ if (nvp == NULL)
+ nv_free(str);
+ return (nvp);
+}
+
+nvpair_t *
+nvpair_create_null(const char *name)
+{
+
+ return (nvpair_allocv(name, NV_TYPE_NULL, 0, 0, 0));
+}
+
+nvpair_t *
+nvpair_create_bool(const char *name, bool value)
+{
+
+ return (nvpair_allocv(name, NV_TYPE_BOOL, value ? 1 : 0,
+ 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), 0));
+}
+
+nvpair_t *
+nvpair_create_string(const char *name, const char *value)
+{
+ nvpair_t *nvp;
+ size_t size;
+ char *data;
+
+ if (value == NULL) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ data = nv_strdup(value);
+ if (data == NULL)
+ return (NULL);
+ size = strlen(value) + 1;
+
+ nvp = nvpair_allocv(name, NV_TYPE_STRING, (uint64_t)(uintptr_t)data,
+ size, 0);
+ if (nvp == NULL)
+ nv_free(data);
+
+ return (nvp);
+}
+
+nvpair_t *
+nvpair_create_nvlist(const char *name, const nvlist_t *value)
+{
+ nvlist_t *nvl;
+ nvpair_t *nvp;
+
+ if (value == NULL) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ nvl = nvlist_clone(value);
+ if (nvl == NULL)
+ return (NULL);
+
+ nvp = nvpair_allocv(name, NV_TYPE_NVLIST, (uint64_t)(uintptr_t)nvl, 0,
+ 0);
+ if (nvp == NULL)
+ nvlist_destroy(nvl);
+ else
+ nvlist_set_parent(nvl, nvp);
+
+ return (nvp);
+}
+
+#ifndef _KERNEL
+nvpair_t *
+nvpair_create_descriptor(const char *name, int value)
+{
+ nvpair_t *nvp;
+
+ if (value < 0 || !fd_is_valid(value)) {
+ ERRNO_SET(EBADF);
+ return (NULL);
+ }
+
+ value = fcntl(value, F_DUPFD_CLOEXEC, 0);
+ if (value < 0)
+ return (NULL);
+
+ nvp = nvpair_allocv(name, NV_TYPE_DESCRIPTOR, (uint64_t)value,
+ sizeof(int64_t), 0);
+ if (nvp == NULL) {
+ ERRNO_SAVE();
+ close(value);
+ ERRNO_RESTORE();
+ }
+
+ return (nvp);
+}
+#endif
+
+nvpair_t *
+nvpair_create_binary(const char *name, const void *value, size_t size)
+{
+ nvpair_t *nvp;
+ void *data;
+
+ if (value == NULL || size == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ data = nv_malloc(size);
+ if (data == NULL)
+ return (NULL);
+ memcpy(data, value, size);
+
+ nvp = nvpair_allocv(name, NV_TYPE_BINARY, (uint64_t)(uintptr_t)data,
+ size, 0);
+ if (nvp == NULL)
+ nv_free(data);
+
+ return (nvp);
+}
+
+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;
+
+ if (value == NULL) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ nvp = nvpair_allocv(name, NV_TYPE_STRING, (uint64_t)(uintptr_t)value,
+ strlen(value) + 1, 0);
+ if (nvp == NULL) {
+ ERRNO_SAVE();
+ nv_free(value);
+ ERRNO_RESTORE();
+ }
+
+ return (nvp);
+}
+
+nvpair_t *
+nvpair_move_nvlist(const char *name, nvlist_t *value)
+{
+ nvpair_t *nvp;
+
+ if (value == NULL || nvlist_get_nvpair_parent(value) != NULL) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ if (nvlist_error(value) != 0) {
+ ERRNO_SET(nvlist_error(value));
+ nvlist_destroy(value);
+ return (NULL);
+ }
+
+ nvp = nvpair_allocv(name, NV_TYPE_NVLIST, (uint64_t)(uintptr_t)value,
+ 0, 0);
+ if (nvp == NULL)
+ nvlist_destroy(value);
+ else
+ nvlist_set_parent(value, nvp);
+
+ return (nvp);
+}
+
+#ifndef _KERNEL
+nvpair_t *
+nvpair_move_descriptor(const char *name, int value)
+{
+ nvpair_t *nvp;
+
+ if (value < 0 || !fd_is_valid(value)) {
+ ERRNO_SET(EBADF);
+ return (NULL);
+ }
+
+ nvp = nvpair_allocv(name, NV_TYPE_DESCRIPTOR, (uint64_t)value,
+ sizeof(int64_t), 0);
+ if (nvp == NULL) {
+ ERRNO_SAVE();
+ close(value);
+ ERRNO_RESTORE();
+ }
+
+ return (nvp);
+}
+#endif
+
+nvpair_t *
+nvpair_move_binary(const char *name, void *value, size_t size)
+{
+ nvpair_t *nvp;
+
+ if (value == NULL || size == 0) {
+ ERRNO_SET(EINVAL);
+ return (NULL);
+ }
+
+ nvp = nvpair_allocv(name, NV_TYPE_BINARY, (uint64_t)(uintptr_t)value,
+ 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);
+ ERRNO_RESTORE();
+ }
+
+ 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)
+{
+
+ NVPAIR_ASSERT(nvp);
+
+ return (nvp->nvp_data == 1);
+}
+
+uint64_t
+nvpair_get_number(const nvpair_t *nvp)
+{
+
+ NVPAIR_ASSERT(nvp);
+
+ return (nvp->nvp_data);
+}
+
+const char *
+nvpair_get_string(const nvpair_t *nvp)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
+
+ return ((const char *)(intptr_t)nvp->nvp_data);
+}
+
+const nvlist_t *
+nvpair_get_nvlist(const nvpair_t *nvp)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST);
+
+ return ((const nvlist_t *)(intptr_t)nvp->nvp_data);
+}
+
+#ifndef _KERNEL
+int
+nvpair_get_descriptor(const nvpair_t *nvp)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
+
+ return ((int)nvp->nvp_data);
+}
+#endif
+
+const void *
+nvpair_get_binary(const nvpair_t *nvp, size_t *sizep)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
+
+ 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);
+
+ nvp->nvp_magic = 0;
+ switch (nvp->nvp_type) {
+#ifndef _KERNEL
+ 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);
+ break;
+ case NV_TYPE_STRING:
+ nv_free((char *)(intptr_t)nvp->nvp_data);
+ break;
+ 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);
+}
+
+void
+nvpair_free_structure(nvpair_t *nvp)
+{
+
+ NVPAIR_ASSERT(nvp);
+ PJDLOG_ASSERT(nvp->nvp_list == NULL);
+
+ nvp->nvp_magic = 0;
+ nv_free(nvp);
+}
+
+const char *
+nvpair_type_string(int type)
+{
+
+ switch (type) {
+ case NV_TYPE_NULL:
+ return ("NULL");
+ case NV_TYPE_BOOL:
+ return ("BOOL");
+ case NV_TYPE_NUMBER:
+ return ("NUMBER");
+ case NV_TYPE_STRING:
+ return ("STRING");
+ case NV_TYPE_NVLIST:
+ return ("NVLIST");
+ case NV_TYPE_DESCRIPTOR:
+ 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>");
+ }
+}
+
Index: sys/contrib/libnv/nvpair_impl.h
===================================================================
--- /dev/null
+++ sys/contrib/libnv/nvpair_impl.h
@@ -0,0 +1,113 @@
+/*-
+ * 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
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: head/sys/contrib/libnv/nvpair_impl.h 286796 2015-08-15 06:34:49Z oshogbo $
+ */
+
+#ifndef _NVPAIR_IMPL_H_
+#define _NVPAIR_IMPL_H_
+
+#include <sys/nv.h>
+#include <sys/queue.h>
+
+#ifndef _KERNEL
+#include <stdint.h>
+#endif
+
+TAILQ_HEAD(nvl_head, nvpair);
+
+void nvpair_assert(const nvpair_t *nvp);
+nvlist_t *nvpair_nvlist(const nvpair_t *nvp);
+nvpair_t *nvpair_next(const nvpair_t *nvp);
+nvpair_t *nvpair_prev(const nvpair_t *nvp);
+void nvpair_insert(struct nvl_head *head, nvpair_t *nvp, nvlist_t *nvl);
+void nvpair_remove(struct nvl_head *head, nvpair_t *nvp, const nvlist_t *nvl);
+size_t nvpair_header_size(void);
+size_t nvpair_size(const nvpair_t *nvp);
+const unsigned char *nvpair_unpack(bool isbe, const unsigned char *ptr,
+ size_t *leftp, nvpair_t **nvpp);
+void nvpair_free_structure(nvpair_t *nvp);
+void nvpair_init_datasize(nvpair_t *nvp);
+const char *nvpair_type_string(int type);
+
+/* Pack functions. */
+unsigned char *nvpair_pack_header(const nvpair_t *nvp, unsigned char *ptr,
+ size_t *leftp);
+unsigned char *nvpair_pack_null(const nvpair_t *nvp, unsigned char *ptr,
+ size_t *leftp);
+unsigned char *nvpair_pack_bool(const nvpair_t *nvp, unsigned char *ptr,
+ size_t *leftp);
+unsigned char *nvpair_pack_number(const nvpair_t *nvp, unsigned char *ptr,
+ size_t *leftp);
+unsigned char *nvpair_pack_string(const nvpair_t *nvp, unsigned char *ptr,
+ size_t *leftp);
+unsigned char *nvpair_pack_descriptor(const nvpair_t *nvp, unsigned char *ptr,
+ int64_t *fdidxp, size_t *leftp);
+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,
+ const unsigned char *ptr, size_t *leftp);
+const unsigned char *nvpair_unpack_null(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp);
+const unsigned char *nvpair_unpack_bool(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp);
+const unsigned char *nvpair_unpack_number(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp);
+const unsigned char *nvpair_unpack_string(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp);
+const unsigned char *nvpair_unpack_nvlist(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp, size_t nfds, nvlist_t **child);
+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_ */
Index: sys/modules/zfs/Makefile
===================================================================
--- sys/modules/zfs/Makefile
+++ sys/modules/zfs/Makefile
@@ -17,9 +17,9 @@
.PATH: ${SUNW}/common/avl
SRCS+= avl.c
.PATH: ${SUNW}/common/nvpair
-SRCS+= nvpair.c
-SRCS+= nvpair_alloc_fixed.c
-SRCS+= fnvpair.c
+SRCS+= opensolaris_nvpair.c
+SRCS+= opensolaris_nvpair_alloc_fixed.c
+SRCS+= opensolaris_fnvpair.c
.PATH: ${.CURDIR}/../../cddl/contrib/opensolaris/common/unicode
SRCS+= u8_textprep.c
Index: sys/sys/dnv.h
===================================================================
--- /dev/null
+++ sys/sys/dnv.h
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: head/sys/sys/dnv.h 285130 2015-07-04 10:33:33Z oshogbo $
+ */
+
+#ifndef _DNV_H_
+#define _DNV_H_
+
+#include <sys/cdefs.h>
+
+#ifndef _KERNEL
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#endif
+
+#ifndef _NVLIST_T_DECLARED
+#define _NVLIST_T_DECLARED
+struct nvlist;
+
+typedef struct nvlist nvlist_t;
+#endif
+
+__BEGIN_DECLS
+
+/*
+ * The dnvlist_get functions returns value associated with the given name.
+ * If it returns a pointer, the pointer represents internal buffer and should
+ * not be freed by the caller.
+ * If no element of the given name and type exists, the function will return
+ * provided default value.
+ */
+
+bool dnvlist_get_bool(const nvlist_t *nvl, const char *name, bool defval);
+uint64_t dnvlist_get_number(const nvlist_t *nvl, const char *name, uint64_t defval);
+const char *dnvlist_get_string(const nvlist_t *nvl, const char *name, const char *defval);
+const nvlist_t *dnvlist_get_nvlist(const nvlist_t *nvl, const char *name, const nvlist_t *defval);
+int dnvlist_get_descriptor(const nvlist_t *nvl, const char *name, int defval);
+const void *dnvlist_get_binary(const nvlist_t *nvl, const char *name, size_t *sizep, const void *defval, size_t defsize);
+
+/*
+ * The dnvlist_take functions returns value associated with the given name and
+ * remove corresponding nvpair.
+ * If it returns a pointer, the caller has to free it.
+ * If no element of the given name and type exists, the function will return
+ * provided default value.
+ */
+
+bool dnvlist_take_bool(nvlist_t *nvl, const char *name, bool defval);
+uint64_t dnvlist_take_number(nvlist_t *nvl, const char *name, uint64_t defval);
+char *dnvlist_take_string(nvlist_t *nvl, const char *name, char *defval);
+nvlist_t *dnvlist_take_nvlist(nvlist_t *nvl, const char *name, nvlist_t *defval);
+int dnvlist_take_descriptor(nvlist_t *nvl, const char *name, int defval);
+void *dnvlist_take_binary(nvlist_t *nvl, const char *name, size_t *sizep, void *defval, size_t defsize);
+
+__END_DECLS
+
+#endif /* !_DNV_H_ */
Index: sys/sys/nv.h
===================================================================
--- /dev/null
+++ sys/sys/nv.h
@@ -0,0 +1,246 @@
+/*-
+ * 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
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: head/sys/sys/nv.h 286796 2015-08-15 06:34:49Z oshogbo $
+ */
+
+#ifndef _NV_H_
+#define _NV_H_
+
+#include <sys/cdefs.h>
+
+#ifndef _KERNEL
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#endif
+
+#ifndef _NVLIST_T_DECLARED
+#define _NVLIST_T_DECLARED
+struct nvlist;
+
+typedef struct nvlist nvlist_t;
+#endif
+
+#define NV_NAME_MAX 2048
+
+#define NV_TYPE_NONE 0
+
+#define NV_TYPE_NULL 1
+#define NV_TYPE_BOOL 2
+#define NV_TYPE_NUMBER 3
+#define NV_TYPE_STRING 4
+#define NV_TYPE_NVLIST 5
+#define NV_TYPE_DESCRIPTOR 6
+#define NV_TYPE_BINARY 7
+#define NV_TYPE_BOOL_ARRAY 8
+#define NV_TYPE_NUMBER_ARRAY 9
+#define NV_TYPE_STRING_ARRAY 10
+#define NV_TYPE_NVLIST_ARRAY 11
+#define NV_TYPE_DESCRIPTOR_ARRAY 12
+
+/*
+ * Perform case-insensitive lookups of provided names.
+ */
+#define NV_FLAG_IGNORE_CASE 0x01
+/*
+ * Names don't have to be unique.
+ */
+#define NV_FLAG_NO_UNIQUE 0x02
+
+#if defined(_KERNEL) && defined(MALLOC_DECLARE)
+MALLOC_DECLARE(M_NVLIST);
+#endif
+
+__BEGIN_DECLS
+
+nvlist_t *nvlist_create(int flags);
+void nvlist_destroy(nvlist_t *nvl);
+int nvlist_error(const nvlist_t *nvl);
+bool nvlist_empty(const nvlist_t *nvl);
+int nvlist_flags(const nvlist_t *nvl);
+void nvlist_set_error(nvlist_t *nvl, int error);
+
+nvlist_t *nvlist_clone(const nvlist_t *nvl);
+
+#ifndef _KERNEL
+void nvlist_dump(const nvlist_t *nvl, int fd);
+void nvlist_fdump(const nvlist_t *nvl, FILE *fp);
+#endif
+
+size_t nvlist_size(const nvlist_t *nvl);
+void *nvlist_pack(const nvlist_t *nvl, size_t *sizep);
+nvlist_t *nvlist_unpack(const void *buf, size_t size, int flags);
+
+int nvlist_send(int sock, const nvlist_t *nvl);
+nvlist_t *nvlist_recv(int sock, int flags);
+nvlist_t *nvlist_xfer(int sock, nvlist_t *nvl, int flags);
+
+const char *nvlist_next(const nvlist_t *nvl, int *typep, void **cookiep);
+
+const nvlist_t *nvlist_get_parent(const nvlist_t *nvl, void **cookiep);
+
+const nvlist_t *nvlist_get_array_next(const nvlist_t *nvl);
+bool nvlist_in_array(const nvlist_t *nvl);
+
+const nvlist_t *nvlist_get_pararr(const nvlist_t *nvl, void **cookiep);
+
+/*
+ * The nvlist_exists functions check if the given name (optionally of the given
+ * type) exists on nvlist.
+ */
+
+bool nvlist_exists(const nvlist_t *nvl, const char *name);
+bool nvlist_exists_type(const nvlist_t *nvl, const char *name, int type);
+
+bool nvlist_exists_null(const nvlist_t *nvl, const char *name);
+bool nvlist_exists_bool(const nvlist_t *nvl, const char *name);
+bool nvlist_exists_number(const nvlist_t *nvl, const char *name);
+bool nvlist_exists_string(const nvlist_t *nvl, const char *name);
+bool nvlist_exists_nvlist(const nvlist_t *nvl, const char *name);
+bool nvlist_exists_binary(const nvlist_t *nvl, const char *name);
+bool nvlist_exists_bool_array(const nvlist_t *nvl, const char *name);
+bool nvlist_exists_number_array(const nvlist_t *nvl, const char *name);
+bool nvlist_exists_string_array(const nvlist_t *nvl, const char *name);
+bool nvlist_exists_nvlist_array(const nvlist_t *nvl, const char *name);
+#ifndef _KERNEL
+bool nvlist_exists_descriptor(const nvlist_t *nvl, const char *name);
+bool nvlist_exists_descriptor_array(const nvlist_t *nvl, const char *name);
+#endif
+
+/*
+ * The nvlist_add functions add the given name/value pair.
+ * If a pointer is provided, nvlist_add will internally allocate memory for the
+ * given data (in other words it won't consume provided buffer).
+ */
+
+void nvlist_add_null(nvlist_t *nvl, const char *name);
+void nvlist_add_bool(nvlist_t *nvl, const char *name, bool value);
+void nvlist_add_number(nvlist_t *nvl, const char *name, uint64_t value);
+void nvlist_add_string(nvlist_t *nvl, const char *name, const char *value);
+void nvlist_add_stringf(nvlist_t *nvl, const char *name, const char *valuefmt, ...) __printflike(3, 4);
+#ifdef _VA_LIST_DECLARED
+void nvlist_add_stringv(nvlist_t *nvl, const char *name, const char *valuefmt, va_list valueap) __printflike(3, 0);
+#endif
+void nvlist_add_nvlist(nvlist_t *nvl, const char *name, const nvlist_t *value);
+void nvlist_add_binary(nvlist_t *nvl, const char *name, const void *value, size_t size);
+void nvlist_add_bool_array(nvlist_t *nvl, const char *name, const bool *value, size_t nitems);
+void nvlist_add_number_array(nvlist_t *nvl, const char *name, const uint64_t *value, size_t nitems);
+void nvlist_add_string_array(nvlist_t *nvl, const char *name, const char * const *value, size_t nitems);
+void nvlist_add_nvlist_array(nvlist_t *nvl, const char *name, const nvlist_t * const *value, size_t nitems);
+#ifndef _KERNEL
+void nvlist_add_descriptor(nvlist_t *nvl, const char *name, int value);
+void nvlist_add_descriptor_array(nvlist_t *nvl, const char *name, const int *value, size_t nitems);
+#endif
+
+/*
+ * The nvlist_move functions add the given name/value pair.
+ * The functions consumes provided buffer.
+ */
+
+void nvlist_move_string(nvlist_t *nvl, const char *name, char *value);
+void nvlist_move_nvlist(nvlist_t *nvl, const char *name, nvlist_t *value);
+void 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);
+void nvlist_move_string_array(nvlist_t *nvl, const char *name, char **value, size_t nitems);
+void nvlist_move_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **value, size_t nitems);
+void nvlist_move_number_array(nvlist_t *nvl, const char *name, uint64_t *value, size_t nitems);
+#ifndef _KERNEL
+void nvlist_move_descriptor(nvlist_t *nvl, const char *name, int value);
+void nvlist_move_descriptor_array(nvlist_t *nvl, const char *name, int *value, size_t nitems);
+#endif
+
+/*
+ * The nvlist_get functions returns value associated with the given name.
+ * If it returns a pointer, the pointer represents internal buffer and should
+ * not be freed by the caller.
+ */
+
+bool nvlist_get_bool(const nvlist_t *nvl, const char *name);
+uint64_t nvlist_get_number(const nvlist_t *nvl, const char *name);
+const char *nvlist_get_string(const nvlist_t *nvl, const char *name);
+const nvlist_t *nvlist_get_nvlist(const nvlist_t *nvl, const char *name);
+const void *nvlist_get_binary(const nvlist_t *nvl, const char *name, size_t *sizep);
+const bool *nvlist_get_bool_array(const nvlist_t *nvl, const char *name, size_t *nitemsp);
+const uint64_t *nvlist_get_number_array(const nvlist_t *nvl, const char *name, size_t *nitemsp);
+const char * const *nvlist_get_string_array(const nvlist_t *nvl, const char *name, size_t *nitemsp);
+const nvlist_t * const *nvlist_get_nvlist_array(const nvlist_t *nvl, const char *name, size_t *nitemsp);
+#ifndef _KERNEL
+int nvlist_get_descriptor(const nvlist_t *nvl, const char *name);
+const int *nvlist_get_descriptor_array(const nvlist_t *nvl, const char *name, size_t *nitemsp);
+#endif
+
+/*
+ * The nvlist_take functions returns value associated with the given name and
+ * remove the given entry from the nvlist.
+ * The caller is responsible for freeing received data.
+ */
+
+bool nvlist_take_bool(nvlist_t *nvl, const char *name);
+uint64_t nvlist_take_number(nvlist_t *nvl, const char *name);
+char *nvlist_take_string(nvlist_t *nvl, const char *name);
+nvlist_t *nvlist_take_nvlist(nvlist_t *nvl, const char *name);
+void *nvlist_take_binary(nvlist_t *nvl, const char *name, size_t *sizep);
+bool *nvlist_take_bool_array(nvlist_t *nvl, const char *name, size_t *nitemsp);
+uint64_t *nvlist_take_number_array(nvlist_t *nvl, const char *name, size_t *nitemsp);
+char **nvlist_take_string_array(nvlist_t *nvl, const char *name, size_t *nitemsp);
+nvlist_t **nvlist_take_nvlist_array(nvlist_t *nvl, const char *name, size_t *nitemsp);
+#ifndef _KERNEL
+int nvlist_take_descriptor(nvlist_t *nvl, const char *name);
+int *nvlist_take_descriptor_array(nvlist_t *nvl, const char *name, size_t *nitemsp);
+#endif
+
+/*
+ * The nvlist_free functions removes the given name/value pair from the nvlist
+ * and frees memory associated with it.
+ */
+
+void nvlist_free(nvlist_t *nvl, const char *name);
+void nvlist_free_type(nvlist_t *nvl, const char *name, int type);
+
+void nvlist_free_null(nvlist_t *nvl, const char *name);
+void nvlist_free_bool(nvlist_t *nvl, const char *name);
+void nvlist_free_number(nvlist_t *nvl, const char *name);
+void nvlist_free_string(nvlist_t *nvl, const char *name);
+void nvlist_free_nvlist(nvlist_t *nvl, const char *name);
+void nvlist_free_binary(nvlist_t *nvl, const char *name);
+void nvlist_free_bool_array(nvlist_t *nvl, const char *name);
+void nvlist_free_number_array(nvlist_t *nvl, const char *name);
+void nvlist_free_string_array(nvlist_t *nvl, const char *name);
+void nvlist_free_nvlist_array(nvlist_t *nvl, const char *name);
+void nvlist_free_binary_array(nvlist_t *nvl, const char *name);
+#ifndef _KERNEL
+void nvlist_free_descriptor(nvlist_t *nvl, const char *name);
+void nvlist_free_descriptor_array(nvlist_t *nvl, const char *name);
+#endif
+
+__END_DECLS
+
+#endif /* !_NV_H_ */

File Metadata

Mime Type
text/plain
Expires
Sun, Oct 26, 4:57 PM (3 h, 10 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24240406
Default Alt Text
D4249.id10445.diff (504 KB)

Event Timeline