1258065Spjd/*- 2258065Spjd * Copyright (c) 2009-2013 The FreeBSD Foundation 3258065Spjd * All rights reserved. 4258065Spjd * 5258065Spjd * This software was developed by Pawel Jakub Dawidek under sponsorship from 6258065Spjd * the FreeBSD Foundation. 7258065Spjd * 8258065Spjd * Redistribution and use in source and binary forms, with or without 9258065Spjd * modification, are permitted provided that the following conditions 10258065Spjd * are met: 11258065Spjd * 1. Redistributions of source code must retain the above copyright 12258065Spjd * notice, this list of conditions and the following disclaimer. 13258065Spjd * 2. Redistributions in binary form must reproduce the above copyright 14258065Spjd * notice, this list of conditions and the following disclaimer in the 15258065Spjd * documentation and/or other materials provided with the distribution. 16258065Spjd * 17258065Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 18258065Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19258065Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20258065Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 21258065Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22258065Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23258065Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24258065Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25258065Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26258065Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27258065Spjd * SUCH DAMAGE. 28258065Spjd */ 29258065Spjd 30258065Spjd#include <sys/cdefs.h> 31258065Spjd__FBSDID("$FreeBSD$"); 32258065Spjd 33258065Spjd#include <sys/param.h> 34258065Spjd#include <sys/endian.h> 35258065Spjd#include <sys/queue.h> 36279438Srstone 37279438Srstone#ifdef _KERNEL 38279438Srstone 39279438Srstone#include <sys/errno.h> 40279438Srstone#include <sys/kernel.h> 41279438Srstone#include <sys/lock.h> 42279438Srstone#include <sys/malloc.h> 43279438Srstone#include <sys/systm.h> 44279438Srstone 45279438Srstone#include <machine/stdarg.h> 46279438Srstone 47279438Srstone#else 48258065Spjd#include <sys/socket.h> 49258065Spjd 50258065Spjd#include <errno.h> 51258065Spjd#include <stdarg.h> 52258065Spjd#include <stdbool.h> 53258065Spjd#include <stdint.h> 54258065Spjd#define _WITH_DPRINTF 55258065Spjd#include <stdio.h> 56258065Spjd#include <stdlib.h> 57258065Spjd#include <string.h> 58258065Spjd#include <unistd.h> 59279439Srstone 60279439Srstone#include "msgio.h" 61279438Srstone#endif 62258065Spjd 63258065Spjd#ifdef HAVE_PJDLOG 64258065Spjd#include <pjdlog.h> 65258065Spjd#endif 66258065Spjd 67279439Srstone#include <sys/nv.h> 68279439Srstone#include <sys/nv_impl.h> 69279439Srstone#include <sys/nvlist_impl.h> 70279439Srstone#include <sys/nvpair_impl.h> 71258065Spjd 72258065Spjd#ifndef HAVE_PJDLOG 73279438Srstone#ifdef _KERNEL 74279438Srstone#define PJDLOG_ASSERT(...) MPASS(__VA_ARGS__) 75279438Srstone#define PJDLOG_RASSERT(expr, ...) KASSERT(expr, (__VA_ARGS__)) 76279438Srstone#define PJDLOG_ABORT(...) panic(__VA_ARGS__) 77279438Srstone#else 78258065Spjd#include <assert.h> 79258065Spjd#define PJDLOG_ASSERT(...) assert(__VA_ARGS__) 80258065Spjd#define PJDLOG_RASSERT(expr, ...) assert(expr) 81258065Spjd#define PJDLOG_ABORT(...) do { \ 82258065Spjd fprintf(stderr, "%s:%u: ", __FILE__, __LINE__); \ 83258065Spjd fprintf(stderr, __VA_ARGS__); \ 84258065Spjd fprintf(stderr, "\n"); \ 85258065Spjd abort(); \ 86258065Spjd} while (0) 87258065Spjd#endif 88279438Srstone#endif 89258065Spjd 90258065Spjd#define NV_FLAG_PRIVATE_MASK (NV_FLAG_BIG_ENDIAN) 91258065Spjd#define NV_FLAG_PUBLIC_MASK (NV_FLAG_IGNORE_CASE) 92258065Spjd#define NV_FLAG_ALL_MASK (NV_FLAG_PRIVATE_MASK | NV_FLAG_PUBLIC_MASK) 93258065Spjd 94258065Spjd#define NVLIST_MAGIC 0x6e766c /* "nvl" */ 95258065Spjdstruct nvlist { 96271579Spjd int nvl_magic; 97271579Spjd int nvl_error; 98271579Spjd int nvl_flags; 99271579Spjd nvpair_t *nvl_parent; 100271579Spjd struct nvl_head nvl_head; 101258065Spjd}; 102258065Spjd 103258065Spjd#define NVLIST_ASSERT(nvl) do { \ 104258065Spjd PJDLOG_ASSERT((nvl) != NULL); \ 105258065Spjd PJDLOG_ASSERT((nvl)->nvl_magic == NVLIST_MAGIC); \ 106258065Spjd} while (0) 107258065Spjd 108279438Srstone#ifdef _KERNEL 109279438SrstoneMALLOC_DEFINE(M_NVLIST, "nvlist", "kernel nvlist"); 110279438Srstone#endif 111279438Srstone 112258065Spjd#define NVPAIR_ASSERT(nvp) nvpair_assert(nvp) 113258065Spjd 114258065Spjd#define NVLIST_HEADER_MAGIC 0x6c 115258065Spjd#define NVLIST_HEADER_VERSION 0x00 116258065Spjdstruct nvlist_header { 117258065Spjd uint8_t nvlh_magic; 118258065Spjd uint8_t nvlh_version; 119258065Spjd uint8_t nvlh_flags; 120258065Spjd uint64_t nvlh_descriptors; 121258065Spjd uint64_t nvlh_size; 122258065Spjd} __packed; 123258065Spjd 124258065Spjdnvlist_t * 125258065Spjdnvlist_create(int flags) 126258065Spjd{ 127258065Spjd nvlist_t *nvl; 128258065Spjd 129258065Spjd PJDLOG_ASSERT((flags & ~(NV_FLAG_PUBLIC_MASK)) == 0); 130258065Spjd 131279438Srstone nvl = nv_malloc(sizeof(*nvl)); 132258065Spjd nvl->nvl_error = 0; 133258065Spjd nvl->nvl_flags = flags; 134271579Spjd nvl->nvl_parent = NULL; 135258065Spjd TAILQ_INIT(&nvl->nvl_head); 136258065Spjd nvl->nvl_magic = NVLIST_MAGIC; 137258065Spjd 138258065Spjd return (nvl); 139258065Spjd} 140258065Spjd 141258065Spjdvoid 142258065Spjdnvlist_destroy(nvlist_t *nvl) 143258065Spjd{ 144258065Spjd nvpair_t *nvp; 145258065Spjd int serrno; 146258065Spjd 147258065Spjd if (nvl == NULL) 148258065Spjd return; 149258065Spjd 150279438Srstone SAVE_ERRNO(serrno); 151258065Spjd 152258065Spjd NVLIST_ASSERT(nvl); 153258065Spjd 154260222Spjd while ((nvp = nvlist_first_nvpair(nvl)) != NULL) { 155258065Spjd nvlist_remove_nvpair(nvl, nvp); 156260222Spjd nvpair_free(nvp); 157260222Spjd } 158258065Spjd nvl->nvl_magic = 0; 159279438Srstone nv_free(nvl); 160258065Spjd 161279438Srstone RESTORE_ERRNO(serrno); 162258065Spjd} 163258065Spjd 164279434Srstonevoid 165279434Srstonenvlist_set_error(nvlist_t *nvl, int error) 166279434Srstone{ 167279434Srstone 168279434Srstone PJDLOG_ASSERT(error != 0); 169279434Srstone 170279434Srstone /* 171279434Srstone * Check for error != 0 so that we don't do the wrong thing if somebody 172279434Srstone * tries to abuse this API when asserts are disabled. 173279434Srstone */ 174279434Srstone if (nvl != NULL && error != 0 && nvl->nvl_error == 0) 175279434Srstone nvl->nvl_error = error; 176279434Srstone} 177279434Srstone 178258065Spjdint 179258065Spjdnvlist_error(const nvlist_t *nvl) 180258065Spjd{ 181258065Spjd 182258065Spjd if (nvl == NULL) 183258065Spjd return (ENOMEM); 184258065Spjd 185258065Spjd NVLIST_ASSERT(nvl); 186258065Spjd 187258065Spjd return (nvl->nvl_error); 188258065Spjd} 189258065Spjd 190271579Spjdnvpair_t * 191271579Spjdnvlist_get_nvpair_parent(const nvlist_t *nvl) 192271579Spjd{ 193271579Spjd 194271579Spjd NVLIST_ASSERT(nvl); 195271579Spjd 196271579Spjd return (nvl->nvl_parent); 197271579Spjd} 198271579Spjd 199271579Spjdconst nvlist_t * 200277921Spjdnvlist_get_parent(const nvlist_t *nvl, void **cookiep) 201271579Spjd{ 202277921Spjd nvpair_t *nvp; 203271579Spjd 204271579Spjd NVLIST_ASSERT(nvl); 205271579Spjd 206277921Spjd nvp = nvl->nvl_parent; 207277921Spjd if (cookiep != NULL) 208277921Spjd *cookiep = nvp; 209277921Spjd if (nvp == NULL) 210271579Spjd return (NULL); 211271579Spjd 212277921Spjd return (nvpair_nvlist(nvp)); 213271579Spjd} 214271579Spjd 215271579Spjdvoid 216271579Spjdnvlist_set_parent(nvlist_t *nvl, nvpair_t *parent) 217271579Spjd{ 218271579Spjd 219271579Spjd NVLIST_ASSERT(nvl); 220271579Spjd 221271579Spjd nvl->nvl_parent = parent; 222271579Spjd} 223271579Spjd 224258065Spjdbool 225258065Spjdnvlist_empty(const nvlist_t *nvl) 226258065Spjd{ 227258065Spjd 228258065Spjd NVLIST_ASSERT(nvl); 229258065Spjd PJDLOG_ASSERT(nvl->nvl_error == 0); 230258065Spjd 231258065Spjd return (nvlist_first_nvpair(nvl) == NULL); 232258065Spjd} 233258065Spjd 234292637Sngieint 235292637Sngienvlist_flags(const nvlist_t *nvl) 236292637Sngie{ 237292637Sngie 238292637Sngie NVLIST_ASSERT(nvl); 239292637Sngie PJDLOG_ASSERT(nvl->nvl_error == 0); 240292637Sngie PJDLOG_ASSERT((nvl->nvl_flags & ~(NV_FLAG_PUBLIC_MASK)) == 0); 241292637Sngie 242292637Sngie return (nvl->nvl_flags); 243292637Sngie} 244292637Sngie 245258065Spjdstatic void 246279435Srstonenvlist_report_missing(int type, const char *name) 247258065Spjd{ 248258065Spjd 249258065Spjd PJDLOG_ABORT("Element '%s' of type %s doesn't exist.", 250279435Srstone name, nvpair_type_string(type)); 251258065Spjd} 252258065Spjd 253258065Spjdstatic nvpair_t * 254279435Srstonenvlist_find(const nvlist_t *nvl, int type, const char *name) 255258065Spjd{ 256258065Spjd nvpair_t *nvp; 257258065Spjd 258258065Spjd NVLIST_ASSERT(nvl); 259258065Spjd PJDLOG_ASSERT(nvl->nvl_error == 0); 260258065Spjd PJDLOG_ASSERT(type == NV_TYPE_NONE || 261258065Spjd (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST)); 262258065Spjd 263258065Spjd for (nvp = nvlist_first_nvpair(nvl); nvp != NULL; 264258065Spjd nvp = nvlist_next_nvpair(nvl, nvp)) { 265258065Spjd if (type != NV_TYPE_NONE && nvpair_type(nvp) != type) 266258065Spjd continue; 267258065Spjd if ((nvl->nvl_flags & NV_FLAG_IGNORE_CASE) != 0) { 268258065Spjd if (strcasecmp(nvpair_name(nvp), name) != 0) 269258065Spjd continue; 270258065Spjd } else { 271258065Spjd if (strcmp(nvpair_name(nvp), name) != 0) 272258065Spjd continue; 273258065Spjd } 274258065Spjd break; 275258065Spjd } 276258065Spjd 277258065Spjd if (nvp == NULL) 278279438Srstone RESTORE_ERRNO(ENOENT); 279258065Spjd 280258065Spjd return (nvp); 281258065Spjd} 282258065Spjd 283258065Spjdbool 284258065Spjdnvlist_exists_type(const nvlist_t *nvl, const char *name, int type) 285258065Spjd{ 286258065Spjd 287279435Srstone NVLIST_ASSERT(nvl); 288279435Srstone PJDLOG_ASSERT(nvl->nvl_error == 0); 289279435Srstone PJDLOG_ASSERT(type == NV_TYPE_NONE || 290279435Srstone (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST)); 291279435Srstone 292279435Srstone return (nvlist_find(nvl, type, name) != NULL); 293258065Spjd} 294258065Spjd 295258065Spjdvoid 296258065Spjdnvlist_free_type(nvlist_t *nvl, const char *name, int type) 297258065Spjd{ 298279435Srstone nvpair_t *nvp; 299258065Spjd 300279435Srstone NVLIST_ASSERT(nvl); 301279435Srstone PJDLOG_ASSERT(nvl->nvl_error == 0); 302279435Srstone PJDLOG_ASSERT(type == NV_TYPE_NONE || 303279435Srstone (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST)); 304279435Srstone 305279435Srstone nvp = nvlist_find(nvl, type, name); 306279435Srstone if (nvp != NULL) 307279435Srstone nvlist_free_nvpair(nvl, nvp); 308279435Srstone else 309279435Srstone nvlist_report_missing(type, name); 310258065Spjd} 311258065Spjd 312258065Spjdnvlist_t * 313258065Spjdnvlist_clone(const nvlist_t *nvl) 314258065Spjd{ 315258065Spjd nvlist_t *newnvl; 316258065Spjd nvpair_t *nvp, *newnvp; 317258065Spjd 318258065Spjd NVLIST_ASSERT(nvl); 319258065Spjd 320258065Spjd if (nvl->nvl_error != 0) { 321279438Srstone RESTORE_ERRNO(nvl->nvl_error); 322258065Spjd return (NULL); 323258065Spjd } 324258065Spjd 325258065Spjd newnvl = nvlist_create(nvl->nvl_flags & NV_FLAG_PUBLIC_MASK); 326258065Spjd for (nvp = nvlist_first_nvpair(nvl); nvp != NULL; 327258065Spjd nvp = nvlist_next_nvpair(nvl, nvp)) { 328258065Spjd newnvp = nvpair_clone(nvp); 329258065Spjd if (newnvp == NULL) 330258065Spjd break; 331258065Spjd nvlist_move_nvpair(newnvl, newnvp); 332258065Spjd } 333258065Spjd if (nvp != NULL) { 334258065Spjd nvlist_destroy(newnvl); 335258065Spjd return (NULL); 336258065Spjd } 337258065Spjd return (newnvl); 338258065Spjd} 339258065Spjd 340279438Srstone#ifndef _KERNEL 341271579Spjdstatic bool 342271579Spjdnvlist_dump_error_check(const nvlist_t *nvl, int fd, int level) 343271579Spjd{ 344271579Spjd 345271579Spjd if (nvlist_error(nvl) != 0) { 346271579Spjd dprintf(fd, "%*serror: %d\n", level * 4, "", 347271579Spjd nvlist_error(nvl)); 348271579Spjd return (true); 349271579Spjd } 350271579Spjd 351271579Spjd return (false); 352271579Spjd} 353271579Spjd 354258065Spjd/* 355258065Spjd * Dump content of nvlist. 356258065Spjd */ 357271579Spjdvoid 358271579Spjdnvlist_dump(const nvlist_t *nvl, int fd) 359258065Spjd{ 360277925Spjd const nvlist_t *tmpnvl; 361277925Spjd nvpair_t *nvp, *tmpnvp; 362277927Spjd void *cookie; 363271579Spjd int level; 364258065Spjd 365271579Spjd level = 0; 366271579Spjd if (nvlist_dump_error_check(nvl, fd, level)) 367258065Spjd return; 368258065Spjd 369271579Spjd nvp = nvlist_first_nvpair(nvl); 370271579Spjd while (nvp != NULL) { 371258065Spjd dprintf(fd, "%*s%s (%s):", level * 4, "", nvpair_name(nvp), 372258065Spjd nvpair_type_string(nvpair_type(nvp))); 373258065Spjd switch (nvpair_type(nvp)) { 374258065Spjd case NV_TYPE_NULL: 375258065Spjd dprintf(fd, " null\n"); 376258065Spjd break; 377258065Spjd case NV_TYPE_BOOL: 378258065Spjd dprintf(fd, " %s\n", nvpair_get_bool(nvp) ? 379258065Spjd "TRUE" : "FALSE"); 380258065Spjd break; 381258065Spjd case NV_TYPE_NUMBER: 382258065Spjd dprintf(fd, " %ju (%jd) (0x%jx)\n", 383258065Spjd (uintmax_t)nvpair_get_number(nvp), 384258065Spjd (intmax_t)nvpair_get_number(nvp), 385258065Spjd (uintmax_t)nvpair_get_number(nvp)); 386258065Spjd break; 387258065Spjd case NV_TYPE_STRING: 388258065Spjd dprintf(fd, " [%s]\n", nvpair_get_string(nvp)); 389258065Spjd break; 390258065Spjd case NV_TYPE_NVLIST: 391258065Spjd dprintf(fd, "\n"); 392277925Spjd tmpnvl = nvpair_get_nvlist(nvp); 393277925Spjd if (nvlist_dump_error_check(tmpnvl, fd, level + 1)) 394271579Spjd break; 395277925Spjd tmpnvp = nvlist_first_nvpair(tmpnvl); 396277925Spjd if (tmpnvp != NULL) { 397277925Spjd nvl = tmpnvl; 398277925Spjd nvp = tmpnvp; 399277925Spjd level++; 400277925Spjd continue; 401271579Spjd } 402277925Spjd break; 403258065Spjd case NV_TYPE_DESCRIPTOR: 404258065Spjd dprintf(fd, " %d\n", nvpair_get_descriptor(nvp)); 405258065Spjd break; 406258065Spjd case NV_TYPE_BINARY: 407258065Spjd { 408258065Spjd const unsigned char *binary; 409258065Spjd unsigned int ii; 410258065Spjd size_t size; 411258065Spjd 412258065Spjd binary = nvpair_get_binary(nvp, &size); 413258065Spjd dprintf(fd, " %zu ", size); 414258065Spjd for (ii = 0; ii < size; ii++) 415258065Spjd dprintf(fd, "%02hhx", binary[ii]); 416258065Spjd dprintf(fd, "\n"); 417258065Spjd break; 418258065Spjd } 419258065Spjd default: 420258065Spjd PJDLOG_ABORT("Unknown type: %d.", nvpair_type(nvp)); 421258065Spjd } 422271579Spjd 423271579Spjd while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) { 424277927Spjd cookie = NULL; 425277927Spjd nvl = nvlist_get_parent(nvl, &cookie); 426277921Spjd if (nvl == NULL) 427271579Spjd return; 428277927Spjd nvp = cookie; 429277921Spjd level--; 430271579Spjd } 431258065Spjd } 432258065Spjd} 433258065Spjd 434258065Spjdvoid 435258065Spjdnvlist_fdump(const nvlist_t *nvl, FILE *fp) 436258065Spjd{ 437258065Spjd 438258065Spjd fflush(fp); 439258065Spjd nvlist_dump(nvl, fileno(fp)); 440258065Spjd} 441279438Srstone#endif 442258065Spjd 443258065Spjd/* 444258065Spjd * The function obtains size of the nvlist after nvlist_pack(). 445258065Spjd */ 446271579Spjdsize_t 447271579Spjdnvlist_size(const nvlist_t *nvl) 448258065Spjd{ 449277925Spjd const nvlist_t *tmpnvl; 450277925Spjd const nvpair_t *nvp, *tmpnvp; 451277927Spjd void *cookie; 452258065Spjd size_t size; 453258065Spjd 454258065Spjd NVLIST_ASSERT(nvl); 455258065Spjd PJDLOG_ASSERT(nvl->nvl_error == 0); 456258065Spjd 457258065Spjd size = sizeof(struct nvlist_header); 458271579Spjd nvp = nvlist_first_nvpair(nvl); 459271579Spjd while (nvp != NULL) { 460258065Spjd size += nvpair_header_size(); 461258065Spjd size += strlen(nvpair_name(nvp)) + 1; 462271579Spjd if (nvpair_type(nvp) == NV_TYPE_NVLIST) { 463271579Spjd size += sizeof(struct nvlist_header); 464271579Spjd size += nvpair_header_size() + 1; 465277925Spjd tmpnvl = nvpair_get_nvlist(nvp); 466277925Spjd PJDLOG_ASSERT(tmpnvl->nvl_error == 0); 467277925Spjd tmpnvp = nvlist_first_nvpair(tmpnvl); 468277925Spjd if (tmpnvp != NULL) { 469277925Spjd nvl = tmpnvl; 470277925Spjd nvp = tmpnvp; 471277925Spjd continue; 472277925Spjd } 473271579Spjd } else { 474258065Spjd size += nvpair_size(nvp); 475271579Spjd } 476271579Spjd 477271579Spjd while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) { 478277927Spjd cookie = NULL; 479277927Spjd nvl = nvlist_get_parent(nvl, &cookie); 480277921Spjd if (nvl == NULL) 481271579Spjd goto out; 482277927Spjd nvp = cookie; 483271579Spjd } 484258065Spjd } 485258065Spjd 486271579Spjdout: 487258065Spjd return (size); 488258065Spjd} 489258065Spjd 490279438Srstone#ifndef _KERNEL 491258065Spjdstatic int * 492258065Spjdnvlist_xdescriptors(const nvlist_t *nvl, int *descs, int level) 493258065Spjd{ 494258065Spjd const nvpair_t *nvp; 495258065Spjd 496258065Spjd NVLIST_ASSERT(nvl); 497258065Spjd PJDLOG_ASSERT(nvl->nvl_error == 0); 498258065Spjd PJDLOG_ASSERT(level < 3); 499258065Spjd 500258065Spjd for (nvp = nvlist_first_nvpair(nvl); nvp != NULL; 501258065Spjd nvp = nvlist_next_nvpair(nvl, nvp)) { 502258065Spjd switch (nvpair_type(nvp)) { 503258065Spjd case NV_TYPE_DESCRIPTOR: 504258065Spjd *descs = nvpair_get_descriptor(nvp); 505258065Spjd descs++; 506258065Spjd break; 507258065Spjd case NV_TYPE_NVLIST: 508258065Spjd descs = nvlist_xdescriptors(nvpair_get_nvlist(nvp), 509258065Spjd descs, level + 1); 510258065Spjd break; 511258065Spjd } 512258065Spjd } 513258065Spjd 514258065Spjd return (descs); 515258065Spjd} 516279438Srstone#endif 517258065Spjd 518279438Srstone#ifndef _KERNEL 519258065Spjdint * 520258065Spjdnvlist_descriptors(const nvlist_t *nvl, size_t *nitemsp) 521258065Spjd{ 522258065Spjd size_t nitems; 523258065Spjd int *fds; 524258065Spjd 525258065Spjd nitems = nvlist_ndescriptors(nvl); 526279438Srstone fds = nv_malloc(sizeof(fds[0]) * (nitems + 1)); 527258065Spjd if (fds == NULL) 528258065Spjd return (NULL); 529258065Spjd if (nitems > 0) 530258065Spjd nvlist_xdescriptors(nvl, fds, 0); 531258065Spjd fds[nitems] = -1; 532258065Spjd if (nitemsp != NULL) 533258065Spjd *nitemsp = nitems; 534258065Spjd return (fds); 535258065Spjd} 536279438Srstone#endif 537258065Spjd 538258065Spjdstatic size_t 539258065Spjdnvlist_xndescriptors(const nvlist_t *nvl, int level) 540258065Spjd{ 541279438Srstone#ifndef _KERNEL 542258065Spjd const nvpair_t *nvp; 543258065Spjd size_t ndescs; 544258065Spjd 545258065Spjd NVLIST_ASSERT(nvl); 546258065Spjd PJDLOG_ASSERT(nvl->nvl_error == 0); 547258065Spjd PJDLOG_ASSERT(level < 3); 548258065Spjd 549258065Spjd ndescs = 0; 550258065Spjd for (nvp = nvlist_first_nvpair(nvl); nvp != NULL; 551258065Spjd nvp = nvlist_next_nvpair(nvl, nvp)) { 552258065Spjd switch (nvpair_type(nvp)) { 553258065Spjd case NV_TYPE_DESCRIPTOR: 554258065Spjd ndescs++; 555258065Spjd break; 556258065Spjd case NV_TYPE_NVLIST: 557258065Spjd ndescs += nvlist_xndescriptors(nvpair_get_nvlist(nvp), 558258065Spjd level + 1); 559258065Spjd break; 560258065Spjd } 561258065Spjd } 562258065Spjd 563258065Spjd return (ndescs); 564279438Srstone#else 565279438Srstone return (0); 566279438Srstone#endif 567258065Spjd} 568258065Spjd 569258065Spjdsize_t 570258065Spjdnvlist_ndescriptors(const nvlist_t *nvl) 571258065Spjd{ 572258065Spjd 573258065Spjd return (nvlist_xndescriptors(nvl, 0)); 574258065Spjd} 575258065Spjd 576258065Spjdstatic unsigned char * 577258065Spjdnvlist_pack_header(const nvlist_t *nvl, unsigned char *ptr, size_t *leftp) 578258065Spjd{ 579258065Spjd struct nvlist_header nvlhdr; 580258065Spjd 581258065Spjd NVLIST_ASSERT(nvl); 582258065Spjd 583258065Spjd nvlhdr.nvlh_magic = NVLIST_HEADER_MAGIC; 584258065Spjd nvlhdr.nvlh_version = NVLIST_HEADER_VERSION; 585258065Spjd nvlhdr.nvlh_flags = nvl->nvl_flags; 586258065Spjd#if BYTE_ORDER == BIG_ENDIAN 587258065Spjd nvlhdr.nvlh_flags |= NV_FLAG_BIG_ENDIAN; 588258065Spjd#endif 589258065Spjd nvlhdr.nvlh_descriptors = nvlist_ndescriptors(nvl); 590258065Spjd nvlhdr.nvlh_size = *leftp - sizeof(nvlhdr); 591258065Spjd PJDLOG_ASSERT(*leftp >= sizeof(nvlhdr)); 592258065Spjd memcpy(ptr, &nvlhdr, sizeof(nvlhdr)); 593258065Spjd ptr += sizeof(nvlhdr); 594258065Spjd *leftp -= sizeof(nvlhdr); 595258065Spjd 596258065Spjd return (ptr); 597258065Spjd} 598258065Spjd 599258065Spjdvoid * 600258065Spjdnvlist_xpack(const nvlist_t *nvl, int64_t *fdidxp, size_t *sizep) 601258065Spjd{ 602258065Spjd unsigned char *buf, *ptr; 603258065Spjd size_t left, size; 604277925Spjd const nvlist_t *tmpnvl; 605277925Spjd nvpair_t *nvp, *tmpnvp; 606277927Spjd void *cookie; 607258065Spjd 608258065Spjd NVLIST_ASSERT(nvl); 609258065Spjd 610258065Spjd if (nvl->nvl_error != 0) { 611279438Srstone RESTORE_ERRNO(nvl->nvl_error); 612258065Spjd return (NULL); 613258065Spjd } 614258065Spjd 615258065Spjd size = nvlist_size(nvl); 616279438Srstone buf = nv_malloc(size); 617258065Spjd if (buf == NULL) 618258065Spjd return (NULL); 619258065Spjd 620258065Spjd ptr = buf; 621258065Spjd left = size; 622258065Spjd 623258065Spjd ptr = nvlist_pack_header(nvl, ptr, &left); 624258065Spjd 625271579Spjd nvp = nvlist_first_nvpair(nvl); 626271579Spjd while (nvp != NULL) { 627271579Spjd NVPAIR_ASSERT(nvp); 628271579Spjd 629271579Spjd nvpair_init_datasize(nvp); 630271579Spjd ptr = nvpair_pack_header(nvp, ptr, &left); 631258065Spjd if (ptr == NULL) { 632279438Srstone nv_free(buf); 633258065Spjd return (NULL); 634258065Spjd } 635271579Spjd switch (nvpair_type(nvp)) { 636271579Spjd case NV_TYPE_NULL: 637271579Spjd ptr = nvpair_pack_null(nvp, ptr, &left); 638271579Spjd break; 639271579Spjd case NV_TYPE_BOOL: 640271579Spjd ptr = nvpair_pack_bool(nvp, ptr, &left); 641271579Spjd break; 642271579Spjd case NV_TYPE_NUMBER: 643271579Spjd ptr = nvpair_pack_number(nvp, ptr, &left); 644271579Spjd break; 645271579Spjd case NV_TYPE_STRING: 646271579Spjd ptr = nvpair_pack_string(nvp, ptr, &left); 647271579Spjd break; 648271579Spjd case NV_TYPE_NVLIST: 649277925Spjd tmpnvl = nvpair_get_nvlist(nvp); 650277925Spjd ptr = nvlist_pack_header(tmpnvl, ptr, &left); 651277925Spjd if (ptr == NULL) 652277925Spjd goto out; 653277925Spjd tmpnvp = nvlist_first_nvpair(tmpnvl); 654277925Spjd if (tmpnvp != NULL) { 655277925Spjd nvl = tmpnvl; 656277925Spjd nvp = tmpnvp; 657277925Spjd continue; 658277925Spjd } 659277925Spjd ptr = nvpair_pack_nvlist_up(ptr, &left); 660277925Spjd break; 661279438Srstone#ifndef _KERNEL 662271579Spjd case NV_TYPE_DESCRIPTOR: 663271579Spjd ptr = nvpair_pack_descriptor(nvp, ptr, fdidxp, &left); 664271579Spjd break; 665279438Srstone#endif 666271579Spjd case NV_TYPE_BINARY: 667271579Spjd ptr = nvpair_pack_binary(nvp, ptr, &left); 668271579Spjd break; 669271579Spjd default: 670271579Spjd PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp)); 671271579Spjd } 672271579Spjd if (ptr == NULL) { 673279438Srstone nv_free(buf); 674271579Spjd return (NULL); 675271579Spjd } 676271579Spjd while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) { 677277927Spjd cookie = NULL; 678277927Spjd nvl = nvlist_get_parent(nvl, &cookie); 679277921Spjd if (nvl == NULL) 680271579Spjd goto out; 681277927Spjd nvp = cookie; 682271579Spjd ptr = nvpair_pack_nvlist_up(ptr, &left); 683271579Spjd if (ptr == NULL) 684271579Spjd goto out; 685271579Spjd } 686258065Spjd } 687258065Spjd 688271579Spjdout: 689258065Spjd if (sizep != NULL) 690258065Spjd *sizep = size; 691258065Spjd return (buf); 692258065Spjd} 693258065Spjd 694258065Spjdvoid * 695258065Spjdnvlist_pack(const nvlist_t *nvl, size_t *sizep) 696258065Spjd{ 697258065Spjd 698258065Spjd NVLIST_ASSERT(nvl); 699258065Spjd 700258065Spjd if (nvl->nvl_error != 0) { 701279438Srstone RESTORE_ERRNO(nvl->nvl_error); 702258065Spjd return (NULL); 703258065Spjd } 704258065Spjd 705258065Spjd if (nvlist_ndescriptors(nvl) > 0) { 706279438Srstone RESTORE_ERRNO(EOPNOTSUPP); 707258065Spjd return (NULL); 708258065Spjd } 709258065Spjd 710258065Spjd return (nvlist_xpack(nvl, NULL, sizep)); 711258065Spjd} 712258065Spjd 713258065Spjdstatic bool 714258065Spjdnvlist_check_header(struct nvlist_header *nvlhdrp) 715258065Spjd{ 716258065Spjd 717258065Spjd if (nvlhdrp->nvlh_magic != NVLIST_HEADER_MAGIC) { 718279438Srstone RESTORE_ERRNO(EINVAL); 719258065Spjd return (false); 720258065Spjd } 721264021Sjilles if ((nvlhdrp->nvlh_flags & ~NV_FLAG_ALL_MASK) != 0) { 722279438Srstone RESTORE_ERRNO(EINVAL); 723258065Spjd return (false); 724258065Spjd } 725258065Spjd#if BYTE_ORDER == BIG_ENDIAN 726258065Spjd if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) == 0) { 727258065Spjd nvlhdrp->nvlh_size = le64toh(nvlhdrp->nvlh_size); 728258065Spjd nvlhdrp->nvlh_descriptors = le64toh(nvlhdrp->nvlh_descriptors); 729258065Spjd } 730258065Spjd#else 731258065Spjd if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0) { 732258065Spjd nvlhdrp->nvlh_size = be64toh(nvlhdrp->nvlh_size); 733258065Spjd nvlhdrp->nvlh_descriptors = be64toh(nvlhdrp->nvlh_descriptors); 734258065Spjd } 735258065Spjd#endif 736258065Spjd return (true); 737258065Spjd} 738258065Spjd 739271579Spjdconst unsigned char * 740258065Spjdnvlist_unpack_header(nvlist_t *nvl, const unsigned char *ptr, size_t nfds, 741272843Spjd bool *isbep, size_t *leftp) 742258065Spjd{ 743258065Spjd struct nvlist_header nvlhdr; 744258065Spjd 745258065Spjd if (*leftp < sizeof(nvlhdr)) 746258065Spjd goto failed; 747258065Spjd 748258065Spjd memcpy(&nvlhdr, ptr, sizeof(nvlhdr)); 749258065Spjd 750258065Spjd if (!nvlist_check_header(&nvlhdr)) 751258065Spjd goto failed; 752258065Spjd 753258065Spjd if (nvlhdr.nvlh_size != *leftp - sizeof(nvlhdr)) 754258065Spjd goto failed; 755258065Spjd 756258065Spjd /* 757258065Spjd * nvlh_descriptors might be smaller than nfds in embedded nvlists. 758258065Spjd */ 759258065Spjd if (nvlhdr.nvlh_descriptors > nfds) 760258065Spjd goto failed; 761258065Spjd 762258065Spjd if ((nvlhdr.nvlh_flags & ~NV_FLAG_ALL_MASK) != 0) 763258065Spjd goto failed; 764258065Spjd 765258065Spjd nvl->nvl_flags = (nvlhdr.nvlh_flags & NV_FLAG_PUBLIC_MASK); 766258065Spjd 767258065Spjd ptr += sizeof(nvlhdr); 768272843Spjd if (isbep != NULL) 769272843Spjd *isbep = (((int)nvlhdr.nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0); 770258065Spjd *leftp -= sizeof(nvlhdr); 771258065Spjd 772258065Spjd return (ptr); 773258065Spjdfailed: 774279438Srstone RESTORE_ERRNO(EINVAL); 775258065Spjd return (NULL); 776258065Spjd} 777258065Spjd 778258065Spjdnvlist_t * 779258065Spjdnvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds) 780258065Spjd{ 781258065Spjd const unsigned char *ptr; 782271579Spjd nvlist_t *nvl, *retnvl, *tmpnvl; 783258065Spjd nvpair_t *nvp; 784258065Spjd size_t left; 785272843Spjd bool isbe; 786258065Spjd 787258065Spjd left = size; 788258065Spjd ptr = buf; 789258065Spjd 790271579Spjd tmpnvl = NULL; 791271579Spjd nvl = retnvl = nvlist_create(0); 792258065Spjd if (nvl == NULL) 793258065Spjd goto failed; 794258065Spjd 795272843Spjd ptr = nvlist_unpack_header(nvl, ptr, nfds, &isbe, &left); 796258065Spjd if (ptr == NULL) 797258065Spjd goto failed; 798258065Spjd 799258065Spjd while (left > 0) { 800272843Spjd ptr = nvpair_unpack(isbe, ptr, &left, &nvp); 801258065Spjd if (ptr == NULL) 802258065Spjd goto failed; 803271579Spjd switch (nvpair_type(nvp)) { 804271579Spjd case NV_TYPE_NULL: 805272843Spjd ptr = nvpair_unpack_null(isbe, nvp, ptr, &left); 806271579Spjd break; 807271579Spjd case NV_TYPE_BOOL: 808272843Spjd ptr = nvpair_unpack_bool(isbe, nvp, ptr, &left); 809271579Spjd break; 810271579Spjd case NV_TYPE_NUMBER: 811272843Spjd ptr = nvpair_unpack_number(isbe, nvp, ptr, &left); 812271579Spjd break; 813271579Spjd case NV_TYPE_STRING: 814272843Spjd ptr = nvpair_unpack_string(isbe, nvp, ptr, &left); 815271579Spjd break; 816271579Spjd case NV_TYPE_NVLIST: 817272843Spjd ptr = nvpair_unpack_nvlist(isbe, nvp, ptr, &left, nfds, 818272843Spjd &tmpnvl); 819271579Spjd nvlist_set_parent(tmpnvl, nvp); 820271579Spjd break; 821279438Srstone#ifndef _KERNEL 822271579Spjd case NV_TYPE_DESCRIPTOR: 823272843Spjd ptr = nvpair_unpack_descriptor(isbe, nvp, ptr, &left, 824271579Spjd fds, nfds); 825271579Spjd break; 826279438Srstone#endif 827271579Spjd case NV_TYPE_BINARY: 828272843Spjd ptr = nvpair_unpack_binary(isbe, nvp, ptr, &left); 829271579Spjd break; 830271579Spjd case NV_TYPE_NVLIST_UP: 831271579Spjd if (nvl->nvl_parent == NULL) 832271579Spjd goto failed; 833271579Spjd nvl = nvpair_nvlist(nvl->nvl_parent); 834271579Spjd continue; 835271579Spjd default: 836271579Spjd PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp)); 837271579Spjd } 838271579Spjd if (ptr == NULL) 839271579Spjd goto failed; 840258065Spjd nvlist_move_nvpair(nvl, nvp); 841271579Spjd if (tmpnvl != NULL) { 842271579Spjd nvl = tmpnvl; 843271579Spjd tmpnvl = NULL; 844271579Spjd } 845258065Spjd } 846258065Spjd 847271579Spjd return (retnvl); 848258065Spjdfailed: 849271579Spjd nvlist_destroy(retnvl); 850258065Spjd return (NULL); 851258065Spjd} 852258065Spjd 853258065Spjdnvlist_t * 854258065Spjdnvlist_unpack(const void *buf, size_t size) 855258065Spjd{ 856258065Spjd 857258065Spjd return (nvlist_xunpack(buf, size, NULL, 0)); 858258065Spjd} 859258065Spjd 860279438Srstone#ifndef _KERNEL 861258065Spjdint 862258065Spjdnvlist_send(int sock, const nvlist_t *nvl) 863258065Spjd{ 864258065Spjd size_t datasize, nfds; 865258065Spjd int *fds; 866258065Spjd void *data; 867258065Spjd int64_t fdidx; 868258065Spjd int serrno, ret; 869258065Spjd 870258065Spjd if (nvlist_error(nvl) != 0) { 871258065Spjd errno = nvlist_error(nvl); 872258065Spjd return (-1); 873258065Spjd } 874258065Spjd 875258065Spjd fds = nvlist_descriptors(nvl, &nfds); 876258065Spjd if (fds == NULL) 877258065Spjd return (-1); 878258065Spjd 879258065Spjd ret = -1; 880258065Spjd data = NULL; 881258065Spjd fdidx = 0; 882258065Spjd 883258065Spjd data = nvlist_xpack(nvl, &fdidx, &datasize); 884258065Spjd if (data == NULL) 885258065Spjd goto out; 886258065Spjd 887258065Spjd if (buf_send(sock, data, datasize) == -1) 888258065Spjd goto out; 889258065Spjd 890258065Spjd if (nfds > 0) { 891258065Spjd if (fd_send(sock, fds, nfds) == -1) 892258065Spjd goto out; 893258065Spjd } 894258065Spjd 895258065Spjd ret = 0; 896258065Spjdout: 897258065Spjd serrno = errno; 898258065Spjd free(fds); 899258065Spjd free(data); 900258065Spjd errno = serrno; 901258065Spjd return (ret); 902258065Spjd} 903258065Spjd 904258065Spjdnvlist_t * 905258065Spjdnvlist_recv(int sock) 906258065Spjd{ 907258065Spjd struct nvlist_header nvlhdr; 908258065Spjd nvlist_t *nvl, *ret; 909259430Spjd unsigned char *buf; 910271028Spjd size_t nfds, size, i; 911271028Spjd int serrno, *fds; 912258065Spjd 913259430Spjd if (buf_recv(sock, &nvlhdr, sizeof(nvlhdr)) == -1) 914258065Spjd return (NULL); 915258065Spjd 916258065Spjd if (!nvlist_check_header(&nvlhdr)) 917258065Spjd return (NULL); 918258065Spjd 919258065Spjd nfds = (size_t)nvlhdr.nvlh_descriptors; 920258065Spjd size = sizeof(nvlhdr) + (size_t)nvlhdr.nvlh_size; 921258065Spjd 922258065Spjd buf = malloc(size); 923258065Spjd if (buf == NULL) 924258065Spjd return (NULL); 925258065Spjd 926259430Spjd memcpy(buf, &nvlhdr, sizeof(nvlhdr)); 927259430Spjd 928258065Spjd ret = NULL; 929258065Spjd fds = NULL; 930258065Spjd 931259430Spjd if (buf_recv(sock, buf + sizeof(nvlhdr), size - sizeof(nvlhdr)) == -1) 932258065Spjd goto out; 933258065Spjd 934258065Spjd if (nfds > 0) { 935258065Spjd fds = malloc(nfds * sizeof(fds[0])); 936258065Spjd if (fds == NULL) 937258065Spjd goto out; 938258065Spjd if (fd_recv(sock, fds, nfds) == -1) 939258065Spjd goto out; 940258065Spjd } 941258065Spjd 942258065Spjd nvl = nvlist_xunpack(buf, size, fds, nfds); 943271026Spjd if (nvl == NULL) { 944271026Spjd for (i = 0; i < nfds; i++) 945271026Spjd close(fds[i]); 946258065Spjd goto out; 947271026Spjd } 948258065Spjd 949258065Spjd ret = nvl; 950258065Spjdout: 951258065Spjd serrno = errno; 952258065Spjd free(buf); 953258065Spjd free(fds); 954258065Spjd errno = serrno; 955258065Spjd 956258065Spjd return (ret); 957258065Spjd} 958258065Spjd 959258065Spjdnvlist_t * 960258065Spjdnvlist_xfer(int sock, nvlist_t *nvl) 961258065Spjd{ 962258065Spjd 963258065Spjd if (nvlist_send(sock, nvl) < 0) { 964258065Spjd nvlist_destroy(nvl); 965258065Spjd return (NULL); 966258065Spjd } 967258065Spjd nvlist_destroy(nvl); 968258065Spjd return (nvlist_recv(sock)); 969258065Spjd} 970279438Srstone#endif 971258065Spjd 972258065Spjdnvpair_t * 973258065Spjdnvlist_first_nvpair(const nvlist_t *nvl) 974258065Spjd{ 975258065Spjd 976258065Spjd NVLIST_ASSERT(nvl); 977258065Spjd 978258065Spjd return (TAILQ_FIRST(&nvl->nvl_head)); 979258065Spjd} 980258065Spjd 981258065Spjdnvpair_t * 982258065Spjdnvlist_next_nvpair(const nvlist_t *nvl, const nvpair_t *nvp) 983258065Spjd{ 984258065Spjd nvpair_t *retnvp; 985258065Spjd 986258065Spjd NVLIST_ASSERT(nvl); 987258065Spjd NVPAIR_ASSERT(nvp); 988258065Spjd PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl); 989258065Spjd 990258065Spjd retnvp = nvpair_next(nvp); 991258065Spjd PJDLOG_ASSERT(retnvp == NULL || nvpair_nvlist(retnvp) == nvl); 992258065Spjd 993258065Spjd return (retnvp); 994258065Spjd 995258065Spjd} 996258065Spjd 997258065Spjdnvpair_t * 998258065Spjdnvlist_prev_nvpair(const nvlist_t *nvl, const nvpair_t *nvp) 999258065Spjd{ 1000258065Spjd nvpair_t *retnvp; 1001258065Spjd 1002258065Spjd NVLIST_ASSERT(nvl); 1003258065Spjd NVPAIR_ASSERT(nvp); 1004258065Spjd PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl); 1005258065Spjd 1006258065Spjd retnvp = nvpair_prev(nvp); 1007258065Spjd PJDLOG_ASSERT(nvpair_nvlist(retnvp) == nvl); 1008258065Spjd 1009258065Spjd return (retnvp); 1010258065Spjd} 1011258065Spjd 1012258065Spjdconst char * 1013258065Spjdnvlist_next(const nvlist_t *nvl, int *typep, void **cookiep) 1014258065Spjd{ 1015258065Spjd nvpair_t *nvp; 1016258065Spjd 1017258065Spjd NVLIST_ASSERT(nvl); 1018258065Spjd PJDLOG_ASSERT(cookiep != NULL); 1019258065Spjd 1020258065Spjd if (*cookiep == NULL) 1021258065Spjd nvp = nvlist_first_nvpair(nvl); 1022258065Spjd else 1023258065Spjd nvp = nvlist_next_nvpair(nvl, *cookiep); 1024258065Spjd if (nvp == NULL) 1025258065Spjd return (NULL); 1026258065Spjd if (typep != NULL) 1027258065Spjd *typep = nvpair_type(nvp); 1028258065Spjd *cookiep = nvp; 1029258065Spjd return (nvpair_name(nvp)); 1030258065Spjd} 1031258065Spjd 1032258065Spjdbool 1033258065Spjdnvlist_exists(const nvlist_t *nvl, const char *name) 1034258065Spjd{ 1035258065Spjd 1036279435Srstone return (nvlist_find(nvl, NV_TYPE_NONE, name) != NULL); 1037258065Spjd} 1038258065Spjd 1039279435Srstone#define NVLIST_EXISTS(type, TYPE) \ 1040258065Spjdbool \ 1041258065Spjdnvlist_exists_##type(const nvlist_t *nvl, const char *name) \ 1042258065Spjd{ \ 1043258065Spjd \ 1044279435Srstone return (nvlist_find(nvl, NV_TYPE_##TYPE, name) != NULL); \ 1045258065Spjd} 1046258065Spjd 1047279435SrstoneNVLIST_EXISTS(null, NULL) 1048279435SrstoneNVLIST_EXISTS(bool, BOOL) 1049279435SrstoneNVLIST_EXISTS(number, NUMBER) 1050279435SrstoneNVLIST_EXISTS(string, STRING) 1051279435SrstoneNVLIST_EXISTS(nvlist, NVLIST) 1052279438Srstone#ifndef _KERNEL 1053279435SrstoneNVLIST_EXISTS(descriptor, DESCRIPTOR) 1054279438Srstone#endif 1055279435SrstoneNVLIST_EXISTS(binary, BINARY) 1056258065Spjd 1057258065Spjd#undef NVLIST_EXISTS 1058258065Spjd 1059258065Spjdvoid 1060258065Spjdnvlist_add_nvpair(nvlist_t *nvl, const nvpair_t *nvp) 1061258065Spjd{ 1062258065Spjd nvpair_t *newnvp; 1063258065Spjd 1064258065Spjd NVPAIR_ASSERT(nvp); 1065258065Spjd 1066258065Spjd if (nvlist_error(nvl) != 0) { 1067279438Srstone RESTORE_ERRNO(nvlist_error(nvl)); 1068258065Spjd return; 1069258065Spjd } 1070258065Spjd if (nvlist_exists(nvl, nvpair_name(nvp))) { 1071279438Srstone nvl->nvl_error = EEXIST; 1072279438Srstone RESTORE_ERRNO(nvlist_error(nvl)); 1073258065Spjd return; 1074258065Spjd } 1075258065Spjd 1076258065Spjd newnvp = nvpair_clone(nvp); 1077258065Spjd if (newnvp == NULL) { 1078279438Srstone nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1079279438Srstone RESTORE_ERRNO(nvlist_error(nvl)); 1080258065Spjd return; 1081258065Spjd } 1082258065Spjd 1083258065Spjd nvpair_insert(&nvl->nvl_head, newnvp, nvl); 1084258065Spjd} 1085258065Spjd 1086258065Spjdvoid 1087258065Spjdnvlist_add_stringf(nvlist_t *nvl, const char *name, const char *valuefmt, ...) 1088258065Spjd{ 1089258065Spjd va_list valueap; 1090258065Spjd 1091258065Spjd va_start(valueap, valuefmt); 1092258065Spjd nvlist_add_stringv(nvl, name, valuefmt, valueap); 1093258065Spjd va_end(valueap); 1094258065Spjd} 1095258065Spjd 1096258065Spjdvoid 1097258065Spjdnvlist_add_stringv(nvlist_t *nvl, const char *name, const char *valuefmt, 1098258065Spjd va_list valueap) 1099258065Spjd{ 1100258065Spjd nvpair_t *nvp; 1101258065Spjd 1102258065Spjd if (nvlist_error(nvl) != 0) { 1103279438Srstone RESTORE_ERRNO(nvlist_error(nvl)); 1104258065Spjd return; 1105258065Spjd } 1106258065Spjd 1107258065Spjd nvp = nvpair_create_stringv(name, valuefmt, valueap); 1108279438Srstone if (nvp == NULL) { 1109279438Srstone nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1110279438Srstone RESTORE_ERRNO(nvl->nvl_error); 1111279438Srstone } else 1112258065Spjd nvlist_move_nvpair(nvl, nvp); 1113258065Spjd} 1114258065Spjd 1115258065Spjdvoid 1116292637Sngienvlist_add_null(nvlist_t *nvl, const char *name) 1117258065Spjd{ 1118258065Spjd nvpair_t *nvp; 1119258065Spjd 1120258065Spjd if (nvlist_error(nvl) != 0) { 1121279438Srstone RESTORE_ERRNO(nvlist_error(nvl)); 1122258065Spjd return; 1123258065Spjd } 1124258065Spjd 1125292637Sngie nvp = nvpair_create_null(name); 1126279438Srstone if (nvp == NULL) { 1127279438Srstone nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1128279438Srstone RESTORE_ERRNO(nvl->nvl_error); 1129279438Srstone } else 1130258065Spjd nvlist_move_nvpair(nvl, nvp); 1131258065Spjd} 1132258065Spjd 1133258065Spjdvoid 1134292637Sngienvlist_add_bool(nvlist_t *nvl, const char *name, bool value) 1135258065Spjd{ 1136258065Spjd nvpair_t *nvp; 1137258065Spjd 1138258065Spjd if (nvlist_error(nvl) != 0) { 1139279438Srstone RESTORE_ERRNO(nvlist_error(nvl)); 1140258065Spjd return; 1141258065Spjd } 1142258065Spjd 1143292637Sngie nvp = nvpair_create_bool(name, value); 1144279438Srstone if (nvp == NULL) { 1145279438Srstone nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1146279438Srstone RESTORE_ERRNO(nvl->nvl_error); 1147279438Srstone } else 1148258065Spjd nvlist_move_nvpair(nvl, nvp); 1149258065Spjd} 1150258065Spjd 1151258065Spjdvoid 1152292637Sngienvlist_add_number(nvlist_t *nvl, const char *name, uint64_t value) 1153258065Spjd{ 1154258065Spjd nvpair_t *nvp; 1155258065Spjd 1156258065Spjd if (nvlist_error(nvl) != 0) { 1157279438Srstone RESTORE_ERRNO(nvlist_error(nvl)); 1158258065Spjd return; 1159258065Spjd } 1160258065Spjd 1161292637Sngie nvp = nvpair_create_number(name, value); 1162279438Srstone if (nvp == NULL) { 1163279438Srstone nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1164279438Srstone RESTORE_ERRNO(nvl->nvl_error); 1165279438Srstone } else 1166258065Spjd nvlist_move_nvpair(nvl, nvp); 1167258065Spjd} 1168258065Spjd 1169258065Spjdvoid 1170292637Sngienvlist_add_string(nvlist_t *nvl, const char *name, const char *value) 1171258065Spjd{ 1172258065Spjd nvpair_t *nvp; 1173258065Spjd 1174258065Spjd if (nvlist_error(nvl) != 0) { 1175279438Srstone RESTORE_ERRNO(nvlist_error(nvl)); 1176258065Spjd return; 1177258065Spjd } 1178258065Spjd 1179292637Sngie nvp = nvpair_create_string(name, value); 1180279438Srstone if (nvp == NULL) { 1181279438Srstone nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1182279438Srstone RESTORE_ERRNO(nvl->nvl_error); 1183279438Srstone } else 1184258065Spjd nvlist_move_nvpair(nvl, nvp); 1185258065Spjd} 1186258065Spjd 1187258065Spjdvoid 1188292637Sngienvlist_add_nvlist(nvlist_t *nvl, const char *name, const nvlist_t *value) 1189258065Spjd{ 1190258065Spjd nvpair_t *nvp; 1191258065Spjd 1192258065Spjd if (nvlist_error(nvl) != 0) { 1193279438Srstone RESTORE_ERRNO(nvlist_error(nvl)); 1194258065Spjd return; 1195258065Spjd } 1196258065Spjd 1197292637Sngie nvp = nvpair_create_nvlist(name, value); 1198279438Srstone if (nvp == NULL) { 1199279438Srstone nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1200279438Srstone RESTORE_ERRNO(nvl->nvl_error); 1201279438Srstone } else 1202258065Spjd nvlist_move_nvpair(nvl, nvp); 1203258065Spjd} 1204258065Spjd 1205279438Srstone#ifndef _KERNEL 1206258065Spjdvoid 1207292637Sngienvlist_add_descriptor(nvlist_t *nvl, const char *name, int value) 1208258065Spjd{ 1209258065Spjd nvpair_t *nvp; 1210258065Spjd 1211258065Spjd if (nvlist_error(nvl) != 0) { 1212258065Spjd errno = nvlist_error(nvl); 1213258065Spjd return; 1214258065Spjd } 1215258065Spjd 1216292637Sngie nvp = nvpair_create_descriptor(name, value); 1217258065Spjd if (nvp == NULL) 1218258065Spjd nvl->nvl_error = errno = (errno != 0 ? errno : ENOMEM); 1219258065Spjd else 1220258065Spjd nvlist_move_nvpair(nvl, nvp); 1221258065Spjd} 1222279438Srstone#endif 1223258065Spjd 1224258065Spjdvoid 1225292637Sngienvlist_add_binary(nvlist_t *nvl, const char *name, const void *value, 1226292637Sngie size_t size) 1227258065Spjd{ 1228258065Spjd nvpair_t *nvp; 1229258065Spjd 1230258065Spjd if (nvlist_error(nvl) != 0) { 1231279438Srstone RESTORE_ERRNO(nvlist_error(nvl)); 1232258065Spjd return; 1233258065Spjd } 1234258065Spjd 1235292637Sngie nvp = nvpair_create_binary(name, value, size); 1236279438Srstone if (nvp == NULL) { 1237279438Srstone nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1238279438Srstone RESTORE_ERRNO(nvl->nvl_error); 1239279438Srstone } else 1240258065Spjd nvlist_move_nvpair(nvl, nvp); 1241258065Spjd} 1242258065Spjd 1243258065Spjdvoid 1244258065Spjdnvlist_move_nvpair(nvlist_t *nvl, nvpair_t *nvp) 1245258065Spjd{ 1246258065Spjd 1247258065Spjd NVPAIR_ASSERT(nvp); 1248258065Spjd PJDLOG_ASSERT(nvpair_nvlist(nvp) == NULL); 1249258065Spjd 1250258065Spjd if (nvlist_error(nvl) != 0) { 1251258065Spjd nvpair_free(nvp); 1252279438Srstone RESTORE_ERRNO(nvlist_error(nvl)); 1253258065Spjd return; 1254258065Spjd } 1255258065Spjd if (nvlist_exists(nvl, nvpair_name(nvp))) { 1256258065Spjd nvpair_free(nvp); 1257279438Srstone nvl->nvl_error = EEXIST; 1258279438Srstone RESTORE_ERRNO(nvl->nvl_error); 1259258065Spjd return; 1260258065Spjd } 1261258065Spjd 1262258065Spjd nvpair_insert(&nvl->nvl_head, nvp, nvl); 1263258065Spjd} 1264258065Spjd 1265258065Spjdvoid 1266292637Sngienvlist_move_string(nvlist_t *nvl, const char *name, char *value) 1267258065Spjd{ 1268258065Spjd nvpair_t *nvp; 1269258065Spjd 1270258065Spjd if (nvlist_error(nvl) != 0) { 1271279438Srstone nv_free(value); 1272279438Srstone RESTORE_ERRNO(nvlist_error(nvl)); 1273258065Spjd return; 1274258065Spjd } 1275258065Spjd 1276292637Sngie nvp = nvpair_move_string(name, value); 1277279438Srstone if (nvp == NULL) { 1278279438Srstone nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1279279438Srstone RESTORE_ERRNO(nvl->nvl_error); 1280279438Srstone } else 1281258065Spjd nvlist_move_nvpair(nvl, nvp); 1282258065Spjd} 1283258065Spjd 1284258065Spjdvoid 1285292637Sngienvlist_move_nvlist(nvlist_t *nvl, const char *name, nvlist_t *value) 1286258065Spjd{ 1287258065Spjd nvpair_t *nvp; 1288258065Spjd 1289258065Spjd if (nvlist_error(nvl) != 0) { 1290271579Spjd if (value != NULL && nvlist_get_nvpair_parent(value) != NULL) 1291271579Spjd nvlist_destroy(value); 1292279438Srstone RESTORE_ERRNO(nvlist_error(nvl)); 1293258065Spjd return; 1294258065Spjd } 1295258065Spjd 1296292637Sngie nvp = nvpair_move_nvlist(name, value); 1297279438Srstone if (nvp == NULL) { 1298279438Srstone nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1299279438Srstone RESTORE_ERRNO(nvl->nvl_error); 1300279438Srstone } else 1301258065Spjd nvlist_move_nvpair(nvl, nvp); 1302258065Spjd} 1303258065Spjd 1304279438Srstone#ifndef _KERNEL 1305258065Spjdvoid 1306292637Sngienvlist_move_descriptor(nvlist_t *nvl, const char *name, int value) 1307258065Spjd{ 1308258065Spjd nvpair_t *nvp; 1309258065Spjd 1310258065Spjd if (nvlist_error(nvl) != 0) { 1311258065Spjd close(value); 1312258065Spjd errno = nvlist_error(nvl); 1313258065Spjd return; 1314258065Spjd } 1315258065Spjd 1316292637Sngie nvp = nvpair_move_descriptor(name, value); 1317258065Spjd if (nvp == NULL) 1318258065Spjd nvl->nvl_error = errno = (errno != 0 ? errno : ENOMEM); 1319258065Spjd else 1320258065Spjd nvlist_move_nvpair(nvl, nvp); 1321258065Spjd} 1322279438Srstone#endif 1323258065Spjd 1324258065Spjdvoid 1325292637Sngienvlist_move_binary(nvlist_t *nvl, const char *name, void *value, size_t size) 1326258065Spjd{ 1327258065Spjd nvpair_t *nvp; 1328258065Spjd 1329258065Spjd if (nvlist_error(nvl) != 0) { 1330279438Srstone nv_free(value); 1331279438Srstone RESTORE_ERRNO(nvlist_error(nvl)); 1332258065Spjd return; 1333258065Spjd } 1334258065Spjd 1335292637Sngie nvp = nvpair_move_binary(name, value, size); 1336279438Srstone if (nvp == NULL) { 1337279438Srstone nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); 1338279438Srstone RESTORE_ERRNO(nvl->nvl_error); 1339279438Srstone } else 1340258065Spjd nvlist_move_nvpair(nvl, nvp); 1341258065Spjd} 1342258065Spjd 1343279435Srstoneconst nvpair_t * 1344279435Srstonenvlist_get_nvpair(const nvlist_t *nvl, const char *name) 1345279435Srstone{ 1346279435Srstone 1347279435Srstone return (nvlist_find(nvl, NV_TYPE_NONE, name)); 1348279435Srstone} 1349279435Srstone 1350279435Srstone#define NVLIST_GET(ftype, type, TYPE) \ 1351258065Spjdftype \ 1352258065Spjdnvlist_get_##type(const nvlist_t *nvl, const char *name) \ 1353258065Spjd{ \ 1354279435Srstone const nvpair_t *nvp; \ 1355258065Spjd \ 1356279435Srstone nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name); \ 1357279435Srstone if (nvp == NULL) \ 1358279435Srstone nvlist_report_missing(NV_TYPE_##TYPE, name); \ 1359279435Srstone return (nvpair_get_##type(nvp)); \ 1360258065Spjd} 1361258065Spjd 1362279435SrstoneNVLIST_GET(bool, bool, BOOL) 1363279435SrstoneNVLIST_GET(uint64_t, number, NUMBER) 1364279435SrstoneNVLIST_GET(const char *, string, STRING) 1365279435SrstoneNVLIST_GET(const nvlist_t *, nvlist, NVLIST) 1366279438Srstone#ifndef _KERNEL 1367279435SrstoneNVLIST_GET(int, descriptor, DESCRIPTOR) 1368279438Srstone#endif 1369258065Spjd 1370258065Spjd#undef NVLIST_GET 1371258065Spjd 1372258065Spjdconst void * 1373258065Spjdnvlist_get_binary(const nvlist_t *nvl, const char *name, size_t *sizep) 1374258065Spjd{ 1375279435Srstone nvpair_t *nvp; 1376258065Spjd 1377279435Srstone nvp = nvlist_find(nvl, NV_TYPE_BINARY, name); 1378279435Srstone if (nvp == NULL) 1379279435Srstone nvlist_report_missing(NV_TYPE_BINARY, name); 1380279435Srstone 1381279435Srstone return (nvpair_get_binary(nvp, sizep)); 1382258065Spjd} 1383258065Spjd 1384279435Srstone#define NVLIST_TAKE(ftype, type, TYPE) \ 1385258065Spjdftype \ 1386258065Spjdnvlist_take_##type(nvlist_t *nvl, const char *name) \ 1387258065Spjd{ \ 1388279435Srstone nvpair_t *nvp; \ 1389279435Srstone ftype value; \ 1390258065Spjd \ 1391279435Srstone nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name); \ 1392279435Srstone if (nvp == NULL) \ 1393279435Srstone nvlist_report_missing(NV_TYPE_##TYPE, name); \ 1394279435Srstone value = (ftype)(intptr_t)nvpair_get_##type(nvp); \ 1395279435Srstone nvlist_remove_nvpair(nvl, nvp); \ 1396279435Srstone nvpair_free_structure(nvp); \ 1397279435Srstone return (value); \ 1398258065Spjd} 1399258065Spjd 1400279435SrstoneNVLIST_TAKE(bool, bool, BOOL) 1401279435SrstoneNVLIST_TAKE(uint64_t, number, NUMBER) 1402279435SrstoneNVLIST_TAKE(char *, string, STRING) 1403279435SrstoneNVLIST_TAKE(nvlist_t *, nvlist, NVLIST) 1404279438Srstone#ifndef _KERNEL 1405279435SrstoneNVLIST_TAKE(int, descriptor, DESCRIPTOR) 1406279438Srstone#endif 1407258065Spjd 1408258065Spjd#undef NVLIST_TAKE 1409258065Spjd 1410258065Spjdvoid * 1411258065Spjdnvlist_take_binary(nvlist_t *nvl, const char *name, size_t *sizep) 1412258065Spjd{ 1413279435Srstone nvpair_t *nvp; 1414279435Srstone void *value; 1415258065Spjd 1416279435Srstone nvp = nvlist_find(nvl, NV_TYPE_BINARY, name); 1417279435Srstone if (nvp == NULL) 1418279435Srstone nvlist_report_missing(NV_TYPE_BINARY, name); 1419279435Srstone 1420279435Srstone value = (void *)(intptr_t)nvpair_get_binary(nvp, sizep); 1421279435Srstone nvlist_remove_nvpair(nvl, nvp); 1422279435Srstone nvpair_free_structure(nvp); 1423279435Srstone return (value); 1424258065Spjd} 1425258065Spjd 1426258065Spjdvoid 1427258065Spjdnvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp) 1428258065Spjd{ 1429258065Spjd 1430258065Spjd NVLIST_ASSERT(nvl); 1431258065Spjd NVPAIR_ASSERT(nvp); 1432258065Spjd PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl); 1433258065Spjd 1434258065Spjd nvpair_remove(&nvl->nvl_head, nvp, nvl); 1435258065Spjd} 1436258065Spjd 1437258065Spjdvoid 1438258065Spjdnvlist_free(nvlist_t *nvl, const char *name) 1439258065Spjd{ 1440258065Spjd 1441279435Srstone nvlist_free_type(nvl, name, NV_TYPE_NONE); 1442258065Spjd} 1443258065Spjd 1444279435Srstone#define NVLIST_FREE(type, TYPE) \ 1445258065Spjdvoid \ 1446258065Spjdnvlist_free_##type(nvlist_t *nvl, const char *name) \ 1447258065Spjd{ \ 1448258065Spjd \ 1449279435Srstone nvlist_free_type(nvl, name, NV_TYPE_##TYPE); \ 1450258065Spjd} 1451258065Spjd 1452279435SrstoneNVLIST_FREE(null, NULL) 1453279435SrstoneNVLIST_FREE(bool, BOOL) 1454279435SrstoneNVLIST_FREE(number, NUMBER) 1455279435SrstoneNVLIST_FREE(string, STRING) 1456279435SrstoneNVLIST_FREE(nvlist, NVLIST) 1457279438Srstone#ifndef _KERNEL 1458279435SrstoneNVLIST_FREE(descriptor, DESCRIPTOR) 1459279438Srstone#endif 1460279435SrstoneNVLIST_FREE(binary, BINARY) 1461258065Spjd 1462258065Spjd#undef NVLIST_FREE 1463258065Spjd 1464258065Spjdvoid 1465258065Spjdnvlist_free_nvpair(nvlist_t *nvl, nvpair_t *nvp) 1466258065Spjd{ 1467258065Spjd 1468258065Spjd NVLIST_ASSERT(nvl); 1469258065Spjd NVPAIR_ASSERT(nvp); 1470258065Spjd PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl); 1471258065Spjd 1472258065Spjd nvlist_remove_nvpair(nvl, nvp); 1473258065Spjd nvpair_free(nvp); 1474258065Spjd} 1475292637Sngie 1476