fe707ca6b5
- Add nvlist_{add,get,take,move,exists,free}_{number,bool,string,nvlist, descriptor} functions. - Add support for (un)packing arrays. - Add the nvl_array_next field to the nvlist structure. If an array is added by the nvlist_{move,add}_nvlist_array function this field will contains next element in the array. - Add the nitems field to the nvpair and nvpair_header structure. This field contains number of elements in the array. - Add special flag (NV_FLAG_IN_ARRAY) which is set if nvlist is a part of an array. - Add special type (NV_TYPE_NVLIST_ARRAY_NEXT).This type is used only on packing/unpacking. - Add new API for traversing arrays (nvlist_get_array_next). - Add the nvlist_get_pararr function which combines the nvlist_get_array_next and nvlist_get_parent functions. If nvlist is in the array it will return next element from array. If nvlist is last element in array or it isn't in array it will return his container (parent). This function should simplify traveling over nvlist. - Add tests for new features. - Add documentation for new functions. - Add my copyright. - Regenerate the sys/cddl/compat/opensolaris/sys/nvpair.h file. PR: 191083 Reviewed by: allanjude (doc) Approved by: pjd (mentor)
2025 lines
42 KiB
C
2025 lines
42 KiB
C
/*-
|
|
* 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$");
|
|
|
|
#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);
|
|
}
|
|
|