1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 2474 eschrock * Common Development and Distribution License (the "License"). 6 2474 eschrock * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 1193 mws 22 0 stevel /* 23 11022 Tom * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 0 stevel * Use is subject to license terms. 25 0 stevel */ 26 0 stevel 27 0 stevel #include <sys/stropts.h> 28 0 stevel #include <sys/debug.h> 29 0 stevel #include <sys/isa_defs.h> 30 0 stevel #include <sys/int_limits.h> 31 0 stevel #include <sys/nvpair.h> 32 0 stevel #include <sys/nvpair_impl.h> 33 0 stevel #include <rpc/types.h> 34 0 stevel #include <rpc/xdr.h> 35 0 stevel 36 0 stevel #if defined(_KERNEL) && !defined(_BOOT) 37 0 stevel #include <sys/varargs.h> 38 6640 cth #include <sys/ddi.h> 39 6640 cth #include <sys/sunddi.h> 40 0 stevel #else 41 0 stevel #include <stdarg.h> 42 6640 cth #include <stdlib.h> 43 6640 cth #include <string.h> 44 0 stevel #include <strings.h> 45 0 stevel #endif 46 0 stevel 47 0 stevel #ifndef offsetof 48 6640 cth #define offsetof(s, m) ((size_t)(&(((s *)0)->m))) 49 0 stevel #endif 50 6640 cth #define skip_whitespace(p) while ((*(p) == ' ') || (*(p) == '\t')) p++ 51 0 stevel 52 0 stevel /* 53 0 stevel * nvpair.c - Provides kernel & userland interfaces for manipulating 54 0 stevel * name-value pairs. 55 0 stevel * 56 0 stevel * Overview Diagram 57 0 stevel * 58 0 stevel * +--------------+ 59 0 stevel * | nvlist_t | 60 0 stevel * |--------------| 61 0 stevel * | nvl_version | 62 0 stevel * | nvl_nvflag | 63 0 stevel * | nvl_priv -+-+ 64 0 stevel * | nvl_flag | | 65 0 stevel * | nvl_pad | | 66 0 stevel * +--------------+ | 67 0 stevel * V 68 0 stevel * +--------------+ last i_nvp in list 69 0 stevel * | nvpriv_t | +---------------------> 70 0 stevel * |--------------| | 71 0 stevel * +--+- nvp_list | | +------------+ 72 0 stevel * | | nvp_last -+--+ + nv_alloc_t | 73 0 stevel * | | nvp_curr | |------------| 74 0 stevel * | | nvp_nva -+----> | nva_ops | 75 0 stevel * | | nvp_stat | | nva_arg | 76 0 stevel * | +--------------+ +------------+ 77 0 stevel * | 78 0 stevel * +-------+ 79 0 stevel * V 80 0 stevel * +---------------------+ +-------------------+ 81 0 stevel * | i_nvp_t | +-->| i_nvp_t | +--> 82 0 stevel * |---------------------| | |-------------------| | 83 0 stevel * | nvi_next -+--+ | nvi_next -+--+ 84 0 stevel * | nvi_prev (NULL) | <----+ nvi_prev | 85 0 stevel * | . . . . . . . . . . | | . . . . . . . . . | 86 0 stevel * | nvp (nvpair_t) | | nvp (nvpair_t) | 87 0 stevel * | - nvp_size | | - nvp_size | 88 0 stevel * | - nvp_name_sz | | - nvp_name_sz | 89 0 stevel * | - nvp_value_elem | | - nvp_value_elem | 90 0 stevel * | - nvp_type | | - nvp_type | 91 0 stevel * | - data ... | | - data ... | 92 0 stevel * +---------------------+ +-------------------+ 93 0 stevel * 94 0 stevel * 95 0 stevel * 96 0 stevel * +---------------------+ +---------------------+ 97 0 stevel * | i_nvp_t | +--> +-->| i_nvp_t (last) | 98 0 stevel * |---------------------| | | |---------------------| 99 0 stevel * | nvi_next -+--+ ... --+ | nvi_next (NULL) | 100 0 stevel * <-+- nvi_prev |<-- ... <----+ nvi_prev | 101 0 stevel * | . . . . . . . . . | | . . . . . . . . . | 102 0 stevel * | nvp (nvpair_t) | | nvp (nvpair_t) | 103 0 stevel * | - nvp_size | | - nvp_size | 104 0 stevel * | - nvp_name_sz | | - nvp_name_sz | 105 0 stevel * | - nvp_value_elem | | - nvp_value_elem | 106 0 stevel * | - DATA_TYPE_NVLIST | | - nvp_type | 107 0 stevel * | - data (embedded) | | - data ... | 108 0 stevel * | nvlist name | +---------------------+ 109 0 stevel * | +--------------+ | 110 0 stevel * | | nvlist_t | | 111 0 stevel * | |--------------| | 112 0 stevel * | | nvl_version | | 113 0 stevel * | | nvl_nvflag | | 114 0 stevel * | | nvl_priv --+---+----> 115 0 stevel * | | nvl_flag | | 116 0 stevel * | | nvl_pad | | 117 0 stevel * | +--------------+ | 118 0 stevel * +---------------------+ 119 0 stevel * 120 0 stevel * 121 0 stevel * N.B. nvpair_t may be aligned on 4 byte boundary, so +4 will 122 0 stevel * allow value to be aligned on 8 byte boundary 123 0 stevel * 124 0 stevel * name_len is the length of the name string including the null terminator 125 0 stevel * so it must be >= 1 126 0 stevel */ 127 0 stevel #define NVP_SIZE_CALC(name_len, data_len) \ 128 0 stevel (NV_ALIGN((sizeof (nvpair_t)) + name_len) + NV_ALIGN(data_len)) 129 0 stevel 130 0 stevel static int i_get_value_size(data_type_t type, const void *data, uint_t nelem); 131 0 stevel static int nvlist_add_common(nvlist_t *nvl, const char *name, data_type_t type, 132 0 stevel uint_t nelem, const void *data); 133 0 stevel 134 0 stevel #define NV_STAT_EMBEDDED 0x1 135 0 stevel #define EMBEDDED_NVL(nvp) ((nvlist_t *)(void *)NVP_VALUE(nvp)) 136 0 stevel #define EMBEDDED_NVL_ARRAY(nvp) ((nvlist_t **)(void *)NVP_VALUE(nvp)) 137 0 stevel 138 0 stevel #define NVP_VALOFF(nvp) (NV_ALIGN(sizeof (nvpair_t) + (nvp)->nvp_name_sz)) 139 0 stevel #define NVPAIR2I_NVP(nvp) \ 140 0 stevel ((i_nvp_t *)((size_t)(nvp) - offsetof(i_nvp_t, nvi_nvp))) 141 0 stevel 142 0 stevel 143 0 stevel int 144 0 stevel nv_alloc_init(nv_alloc_t *nva, const nv_alloc_ops_t *nvo, /* args */ ...) 145 0 stevel { 146 0 stevel va_list valist; 147 0 stevel int err = 0; 148 0 stevel 149 0 stevel nva->nva_ops = nvo; 150 0 stevel nva->nva_arg = NULL; 151 0 stevel 152 0 stevel va_start(valist, nvo); 153 0 stevel if (nva->nva_ops->nv_ao_init != NULL) 154 0 stevel err = nva->nva_ops->nv_ao_init(nva, valist); 155 0 stevel va_end(valist); 156 0 stevel 157 0 stevel return (err); 158 0 stevel } 159 0 stevel 160 0 stevel void 161 0 stevel nv_alloc_reset(nv_alloc_t *nva) 162 0 stevel { 163 0 stevel if (nva->nva_ops->nv_ao_reset != NULL) 164 0 stevel nva->nva_ops->nv_ao_reset(nva); 165 0 stevel } 166 0 stevel 167 0 stevel void 168 0 stevel nv_alloc_fini(nv_alloc_t *nva) 169 0 stevel { 170 0 stevel if (nva->nva_ops->nv_ao_fini != NULL) 171 0 stevel nva->nva_ops->nv_ao_fini(nva); 172 0 stevel } 173 0 stevel 174 0 stevel nv_alloc_t * 175 0 stevel nvlist_lookup_nv_alloc(nvlist_t *nvl) 176 0 stevel { 177 0 stevel nvpriv_t *priv; 178 0 stevel 179 0 stevel if (nvl == NULL || 180 0 stevel (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 181 0 stevel return (NULL); 182 0 stevel 183 0 stevel return (priv->nvp_nva); 184 0 stevel } 185 0 stevel 186 0 stevel static void * 187 0 stevel nv_mem_zalloc(nvpriv_t *nvp, size_t size) 188 0 stevel { 189 0 stevel nv_alloc_t *nva = nvp->nvp_nva; 190 0 stevel void *buf; 191 0 stevel 192 0 stevel if ((buf = nva->nva_ops->nv_ao_alloc(nva, size)) != NULL) 193 0 stevel bzero(buf, size); 194 0 stevel 195 0 stevel return (buf); 196 0 stevel } 197 0 stevel 198 0 stevel static void 199 0 stevel nv_mem_free(nvpriv_t *nvp, void *buf, size_t size) 200 0 stevel { 201 0 stevel nv_alloc_t *nva = nvp->nvp_nva; 202 0 stevel 203 0 stevel nva->nva_ops->nv_ao_free(nva, buf, size); 204 0 stevel } 205 0 stevel 206 0 stevel static void 207 0 stevel nv_priv_init(nvpriv_t *priv, nv_alloc_t *nva, uint32_t stat) 208 0 stevel { 209 6643 eschrock bzero(priv, sizeof (nvpriv_t)); 210 0 stevel 211 0 stevel priv->nvp_nva = nva; 212 0 stevel priv->nvp_stat = stat; 213 0 stevel } 214 0 stevel 215 0 stevel static nvpriv_t * 216 0 stevel nv_priv_alloc(nv_alloc_t *nva) 217 0 stevel { 218 0 stevel nvpriv_t *priv; 219 0 stevel 220 0 stevel /* 221 0 stevel * nv_mem_alloc() cannot called here because it needs the priv 222 0 stevel * argument. 223 0 stevel */ 224 0 stevel if ((priv = nva->nva_ops->nv_ao_alloc(nva, sizeof (nvpriv_t))) == NULL) 225 0 stevel return (NULL); 226 0 stevel 227 0 stevel nv_priv_init(priv, nva, 0); 228 0 stevel 229 0 stevel return (priv); 230 0 stevel } 231 0 stevel 232 0 stevel /* 233 0 stevel * Embedded lists need their own nvpriv_t's. We create a new 234 0 stevel * nvpriv_t using the parameters and allocator from the parent 235 0 stevel * list's nvpriv_t. 236 0 stevel */ 237 0 stevel static nvpriv_t * 238 0 stevel nv_priv_alloc_embedded(nvpriv_t *priv) 239 0 stevel { 240 0 stevel nvpriv_t *emb_priv; 241 0 stevel 242 0 stevel if ((emb_priv = nv_mem_zalloc(priv, sizeof (nvpriv_t))) == NULL) 243 0 stevel return (NULL); 244 0 stevel 245 0 stevel nv_priv_init(emb_priv, priv->nvp_nva, NV_STAT_EMBEDDED); 246 0 stevel 247 0 stevel return (emb_priv); 248 0 stevel } 249 0 stevel 250 0 stevel static void 251 0 stevel nvlist_init(nvlist_t *nvl, uint32_t nvflag, nvpriv_t *priv) 252 0 stevel { 253 0 stevel nvl->nvl_version = NV_VERSION; 254 0 stevel nvl->nvl_nvflag = nvflag & (NV_UNIQUE_NAME|NV_UNIQUE_NAME_TYPE); 255 0 stevel nvl->nvl_priv = (uint64_t)(uintptr_t)priv; 256 0 stevel nvl->nvl_flag = 0; 257 0 stevel nvl->nvl_pad = 0; 258 0 stevel } 259 0 stevel 260 0 stevel /* 261 0 stevel * nvlist_alloc - Allocate nvlist. 262 0 stevel */ 263 0 stevel /*ARGSUSED1*/ 264 0 stevel int 265 0 stevel nvlist_alloc(nvlist_t **nvlp, uint_t nvflag, int kmflag) 266 0 stevel { 267 0 stevel #if defined(_KERNEL) && !defined(_BOOT) 268 0 stevel return (nvlist_xalloc(nvlp, nvflag, 269 0 stevel (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep))); 270 0 stevel #else 271 0 stevel return (nvlist_xalloc(nvlp, nvflag, nv_alloc_nosleep)); 272 0 stevel #endif 273 0 stevel } 274 0 stevel 275 0 stevel int 276 0 stevel nvlist_xalloc(nvlist_t **nvlp, uint_t nvflag, nv_alloc_t *nva) 277 0 stevel { 278 0 stevel nvpriv_t *priv; 279 0 stevel 280 0 stevel if (nvlp == NULL || nva == NULL) 281 0 stevel return (EINVAL); 282 0 stevel 283 0 stevel if ((priv = nv_priv_alloc(nva)) == NULL) 284 0 stevel return (ENOMEM); 285 0 stevel 286 0 stevel if ((*nvlp = nv_mem_zalloc(priv, 287 0 stevel NV_ALIGN(sizeof (nvlist_t)))) == NULL) { 288 0 stevel nv_mem_free(priv, priv, sizeof (nvpriv_t)); 289 0 stevel return (ENOMEM); 290 0 stevel } 291 0 stevel 292 0 stevel nvlist_init(*nvlp, nvflag, priv); 293 0 stevel 294 0 stevel return (0); 295 0 stevel } 296 0 stevel 297 0 stevel /* 298 0 stevel * nvp_buf_alloc - Allocate i_nvp_t for storing a new nv pair. 299 0 stevel */ 300 0 stevel static nvpair_t * 301 0 stevel nvp_buf_alloc(nvlist_t *nvl, size_t len) 302 0 stevel { 303 0 stevel nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 304 0 stevel i_nvp_t *buf; 305 0 stevel nvpair_t *nvp; 306 0 stevel size_t nvsize; 307 0 stevel 308 0 stevel /* 309 0 stevel * Allocate the buffer 310 0 stevel */ 311 0 stevel nvsize = len + offsetof(i_nvp_t, nvi_nvp); 312 0 stevel 313 0 stevel if ((buf = nv_mem_zalloc(priv, nvsize)) == NULL) 314 0 stevel return (NULL); 315 0 stevel 316 0 stevel nvp = &buf->nvi_nvp; 317 0 stevel nvp->nvp_size = len; 318 0 stevel 319 0 stevel return (nvp); 320 0 stevel } 321 0 stevel 322 0 stevel /* 323 0 stevel * nvp_buf_free - de-Allocate an i_nvp_t. 324 0 stevel */ 325 0 stevel static void 326 0 stevel nvp_buf_free(nvlist_t *nvl, nvpair_t *nvp) 327 0 stevel { 328 0 stevel nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 329 0 stevel size_t nvsize = nvp->nvp_size + offsetof(i_nvp_t, nvi_nvp); 330 0 stevel 331 0 stevel nv_mem_free(priv, NVPAIR2I_NVP(nvp), nvsize); 332 0 stevel } 333 0 stevel 334 0 stevel /* 335 0 stevel * nvp_buf_link - link a new nv pair into the nvlist. 336 0 stevel */ 337 0 stevel static void 338 0 stevel nvp_buf_link(nvlist_t *nvl, nvpair_t *nvp) 339 0 stevel { 340 0 stevel nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 341 0 stevel i_nvp_t *curr = NVPAIR2I_NVP(nvp); 342 0 stevel 343 0 stevel /* Put element at end of nvlist */ 344 0 stevel if (priv->nvp_list == NULL) { 345 0 stevel priv->nvp_list = priv->nvp_last = curr; 346 0 stevel } else { 347 0 stevel curr->nvi_prev = priv->nvp_last; 348 0 stevel priv->nvp_last->nvi_next = curr; 349 0 stevel priv->nvp_last = curr; 350 0 stevel } 351 0 stevel } 352 0 stevel 353 0 stevel /* 354 0 stevel * nvp_buf_unlink - unlink an removed nvpair out of the nvlist. 355 0 stevel */ 356 0 stevel static void 357 0 stevel nvp_buf_unlink(nvlist_t *nvl, nvpair_t *nvp) 358 0 stevel { 359 0 stevel nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 360 0 stevel i_nvp_t *curr = NVPAIR2I_NVP(nvp); 361 0 stevel 362 0 stevel /* 363 0 stevel * protect nvlist_next_nvpair() against walking on freed memory. 364 0 stevel */ 365 0 stevel if (priv->nvp_curr == curr) 366 0 stevel priv->nvp_curr = curr->nvi_next; 367 0 stevel 368 0 stevel if (curr == priv->nvp_list) 369 0 stevel priv->nvp_list = curr->nvi_next; 370 0 stevel else 371 0 stevel curr->nvi_prev->nvi_next = curr->nvi_next; 372 0 stevel 373 0 stevel if (curr == priv->nvp_last) 374 0 stevel priv->nvp_last = curr->nvi_prev; 375 0 stevel else 376 0 stevel curr->nvi_next->nvi_prev = curr->nvi_prev; 377 0 stevel } 378 0 stevel 379 0 stevel /* 380 0 stevel * take a nvpair type and number of elements and make sure the are valid 381 0 stevel */ 382 0 stevel static int 383 0 stevel i_validate_type_nelem(data_type_t type, uint_t nelem) 384 0 stevel { 385 0 stevel switch (type) { 386 0 stevel case DATA_TYPE_BOOLEAN: 387 0 stevel if (nelem != 0) 388 0 stevel return (EINVAL); 389 0 stevel break; 390 0 stevel case DATA_TYPE_BOOLEAN_VALUE: 391 0 stevel case DATA_TYPE_BYTE: 392 0 stevel case DATA_TYPE_INT8: 393 0 stevel case DATA_TYPE_UINT8: 394 0 stevel case DATA_TYPE_INT16: 395 0 stevel case DATA_TYPE_UINT16: 396 0 stevel case DATA_TYPE_INT32: 397 0 stevel case DATA_TYPE_UINT32: 398 0 stevel case DATA_TYPE_INT64: 399 0 stevel case DATA_TYPE_UINT64: 400 0 stevel case DATA_TYPE_STRING: 401 0 stevel case DATA_TYPE_HRTIME: 402 0 stevel case DATA_TYPE_NVLIST: 403 7243 robj #if !defined(_KERNEL) 404 7243 robj case DATA_TYPE_DOUBLE: 405 7243 robj #endif 406 0 stevel if (nelem != 1) 407 0 stevel return (EINVAL); 408 0 stevel break; 409 0 stevel case DATA_TYPE_BOOLEAN_ARRAY: 410 0 stevel case DATA_TYPE_BYTE_ARRAY: 411 0 stevel case DATA_TYPE_INT8_ARRAY: 412 0 stevel case DATA_TYPE_UINT8_ARRAY: 413 0 stevel case DATA_TYPE_INT16_ARRAY: 414 0 stevel case DATA_TYPE_UINT16_ARRAY: 415 0 stevel case DATA_TYPE_INT32_ARRAY: 416 0 stevel case DATA_TYPE_UINT32_ARRAY: 417 0 stevel case DATA_TYPE_INT64_ARRAY: 418 0 stevel case DATA_TYPE_UINT64_ARRAY: 419 0 stevel case DATA_TYPE_STRING_ARRAY: 420 0 stevel case DATA_TYPE_NVLIST_ARRAY: 421 0 stevel /* we allow arrays with 0 elements */ 422 0 stevel break; 423 0 stevel default: 424 0 stevel return (EINVAL); 425 0 stevel } 426 0 stevel return (0); 427 0 stevel } 428 0 stevel 429 0 stevel /* 430 0 stevel * Verify nvp_name_sz and check the name string length. 431 0 stevel */ 432 0 stevel static int 433 0 stevel i_validate_nvpair_name(nvpair_t *nvp) 434 0 stevel { 435 0 stevel if ((nvp->nvp_name_sz <= 0) || 436 0 stevel (nvp->nvp_size < NVP_SIZE_CALC(nvp->nvp_name_sz, 0))) 437 0 stevel return (EFAULT); 438 0 stevel 439 0 stevel /* verify the name string, make sure its terminated */ 440 0 stevel if (NVP_NAME(nvp)[nvp->nvp_name_sz - 1] != '\0') 441 0 stevel return (EFAULT); 442 0 stevel 443 0 stevel return (strlen(NVP_NAME(nvp)) == nvp->nvp_name_sz - 1 ? 0 : EFAULT); 444 0 stevel } 445 0 stevel 446 0 stevel static int 447 0 stevel i_validate_nvpair_value(data_type_t type, uint_t nelem, const void *data) 448 0 stevel { 449 0 stevel switch (type) { 450 0 stevel case DATA_TYPE_BOOLEAN_VALUE: 451 0 stevel if (*(boolean_t *)data != B_TRUE && 452 0 stevel *(boolean_t *)data != B_FALSE) 453 0 stevel return (EINVAL); 454 0 stevel break; 455 0 stevel case DATA_TYPE_BOOLEAN_ARRAY: { 456 0 stevel int i; 457 0 stevel 458 0 stevel for (i = 0; i < nelem; i++) 459 0 stevel if (((boolean_t *)data)[i] != B_TRUE && 460 0 stevel ((boolean_t *)data)[i] != B_FALSE) 461 0 stevel return (EINVAL); 462 0 stevel break; 463 0 stevel } 464 0 stevel default: 465 0 stevel break; 466 0 stevel } 467 0 stevel 468 0 stevel return (0); 469 0 stevel } 470 0 stevel 471 0 stevel /* 472 0 stevel * This function takes a pointer to what should be a nvpair and it's size 473 0 stevel * and then verifies that all the nvpair fields make sense and can be 474 0 stevel * trusted. This function is used when decoding packed nvpairs. 475 0 stevel */ 476 0 stevel static int 477 0 stevel i_validate_nvpair(nvpair_t *nvp) 478 0 stevel { 479 0 stevel data_type_t type = NVP_TYPE(nvp); 480 0 stevel int size1, size2; 481 0 stevel 482 0 stevel /* verify nvp_name_sz, check the name string length */ 483 0 stevel if (i_validate_nvpair_name(nvp) != 0) 484 0 stevel return (EFAULT); 485 0 stevel 486 0 stevel if (i_validate_nvpair_value(type, NVP_NELEM(nvp), NVP_VALUE(nvp)) != 0) 487 0 stevel return (EFAULT); 488 0 stevel 489 0 stevel /* 490 0 stevel * verify nvp_type, nvp_value_elem, and also possibly 491 0 stevel * verify string values and get the value size. 492 0 stevel */ 493 0 stevel size2 = i_get_value_size(type, NVP_VALUE(nvp), NVP_NELEM(nvp)); 494 0 stevel size1 = nvp->nvp_size - NVP_VALOFF(nvp); 495 0 stevel if (size2 < 0 || size1 != NV_ALIGN(size2)) 496 0 stevel return (EFAULT); 497 0 stevel 498 0 stevel return (0); 499 0 stevel } 500 0 stevel 501 0 stevel static int 502 0 stevel nvlist_copy_pairs(nvlist_t *snvl, nvlist_t *dnvl) 503 0 stevel { 504 0 stevel nvpriv_t *priv; 505 0 stevel i_nvp_t *curr; 506 0 stevel 507 0 stevel if ((priv = (nvpriv_t *)(uintptr_t)snvl->nvl_priv) == NULL) 508 0 stevel return (EINVAL); 509 0 stevel 510 0 stevel for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) { 511 0 stevel nvpair_t *nvp = &curr->nvi_nvp; 512 0 stevel int err; 513 0 stevel 514 0 stevel if ((err = nvlist_add_common(dnvl, NVP_NAME(nvp), NVP_TYPE(nvp), 515 0 stevel NVP_NELEM(nvp), NVP_VALUE(nvp))) != 0) 516 0 stevel return (err); 517 0 stevel } 518 0 stevel 519 0 stevel return (0); 520 0 stevel } 521 0 stevel 522 0 stevel /* 523 0 stevel * Frees all memory allocated for an nvpair (like embedded lists) with 524 0 stevel * the exception of the nvpair buffer itself. 525 0 stevel */ 526 0 stevel static void 527 0 stevel nvpair_free(nvpair_t *nvp) 528 0 stevel { 529 0 stevel switch (NVP_TYPE(nvp)) { 530 0 stevel case DATA_TYPE_NVLIST: 531 0 stevel nvlist_free(EMBEDDED_NVL(nvp)); 532 0 stevel break; 533 0 stevel case DATA_TYPE_NVLIST_ARRAY: { 534 0 stevel nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp); 535 0 stevel int i; 536 0 stevel 537 0 stevel for (i = 0; i < NVP_NELEM(nvp); i++) 538 0 stevel if (nvlp[i] != NULL) 539 0 stevel nvlist_free(nvlp[i]); 540 0 stevel break; 541 0 stevel } 542 0 stevel default: 543 0 stevel break; 544 0 stevel } 545 0 stevel } 546 0 stevel 547 0 stevel /* 548 0 stevel * nvlist_free - free an unpacked nvlist 549 0 stevel */ 550 0 stevel void 551 0 stevel nvlist_free(nvlist_t *nvl) 552 0 stevel { 553 0 stevel nvpriv_t *priv; 554 0 stevel i_nvp_t *curr; 555 0 stevel 556 0 stevel if (nvl == NULL || 557 0 stevel (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 558 0 stevel return; 559 0 stevel 560 0 stevel /* 561 0 stevel * Unpacked nvlist are linked through i_nvp_t 562 0 stevel */ 563 0 stevel curr = priv->nvp_list; 564 0 stevel while (curr != NULL) { 565 0 stevel nvpair_t *nvp = &curr->nvi_nvp; 566 0 stevel curr = curr->nvi_next; 567 0 stevel 568 0 stevel nvpair_free(nvp); 569 0 stevel nvp_buf_free(nvl, nvp); 570 0 stevel } 571 0 stevel 572 0 stevel if (!(priv->nvp_stat & NV_STAT_EMBEDDED)) 573 0 stevel nv_mem_free(priv, nvl, NV_ALIGN(sizeof (nvlist_t))); 574 0 stevel else 575 2856 nd150628 nvl->nvl_priv = 0; 576 0 stevel 577 0 stevel nv_mem_free(priv, priv, sizeof (nvpriv_t)); 578 0 stevel } 579 0 stevel 580 0 stevel static int 581 0 stevel nvlist_contains_nvp(nvlist_t *nvl, nvpair_t *nvp) 582 0 stevel { 583 0 stevel nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 584 0 stevel i_nvp_t *curr; 585 0 stevel 586 0 stevel if (nvp == NULL) 587 0 stevel return (0); 588 0 stevel 589 0 stevel for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) 590 0 stevel if (&curr->nvi_nvp == nvp) 591 0 stevel return (1); 592 0 stevel 593 0 stevel return (0); 594 0 stevel } 595 0 stevel 596 0 stevel /* 597 0 stevel * Make a copy of nvlist 598 0 stevel */ 599 0 stevel /*ARGSUSED1*/ 600 0 stevel int 601 0 stevel nvlist_dup(nvlist_t *nvl, nvlist_t **nvlp, int kmflag) 602 0 stevel { 603 0 stevel #if defined(_KERNEL) && !defined(_BOOT) 604 0 stevel return (nvlist_xdup(nvl, nvlp, 605 0 stevel (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep))); 606 0 stevel #else 607 0 stevel return (nvlist_xdup(nvl, nvlp, nv_alloc_nosleep)); 608 0 stevel #endif 609 0 stevel } 610 0 stevel 611 0 stevel int 612 0 stevel nvlist_xdup(nvlist_t *nvl, nvlist_t **nvlp, nv_alloc_t *nva) 613 0 stevel { 614 0 stevel int err; 615 2474 eschrock nvlist_t *ret; 616 0 stevel 617 0 stevel if (nvl == NULL || nvlp == NULL) 618 0 stevel return (EINVAL); 619 0 stevel 620 2474 eschrock if ((err = nvlist_xalloc(&ret, nvl->nvl_nvflag, nva)) != 0) 621 0 stevel return (err); 622 0 stevel 623 2474 eschrock if ((err = nvlist_copy_pairs(nvl, ret)) != 0) 624 2474 eschrock nvlist_free(ret); 625 2474 eschrock else 626 2474 eschrock *nvlp = ret; 627 0 stevel 628 0 stevel return (err); 629 0 stevel } 630 0 stevel 631 0 stevel /* 632 0 stevel * Remove all with matching name 633 0 stevel */ 634 0 stevel int 635 0 stevel nvlist_remove_all(nvlist_t *nvl, const char *name) 636 0 stevel { 637 0 stevel nvpriv_t *priv; 638 0 stevel i_nvp_t *curr; 639 0 stevel int error = ENOENT; 640 0 stevel 641 0 stevel if (nvl == NULL || name == NULL || 642 0 stevel (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 643 0 stevel return (EINVAL); 644 0 stevel 645 0 stevel curr = priv->nvp_list; 646 0 stevel while (curr != NULL) { 647 0 stevel nvpair_t *nvp = &curr->nvi_nvp; 648 0 stevel 649 0 stevel curr = curr->nvi_next; 650 0 stevel if (strcmp(name, NVP_NAME(nvp)) != 0) 651 0 stevel continue; 652 0 stevel 653 0 stevel nvp_buf_unlink(nvl, nvp); 654 0 stevel nvpair_free(nvp); 655 0 stevel nvp_buf_free(nvl, nvp); 656 0 stevel 657 0 stevel error = 0; 658 0 stevel } 659 0 stevel 660 0 stevel return (error); 661 0 stevel } 662 0 stevel 663 0 stevel /* 664 0 stevel * Remove first one with matching name and type 665 0 stevel */ 666 0 stevel int 667 0 stevel nvlist_remove(nvlist_t *nvl, const char *name, data_type_t type) 668 0 stevel { 669 0 stevel nvpriv_t *priv; 670 0 stevel i_nvp_t *curr; 671 0 stevel 672 0 stevel if (nvl == NULL || name == NULL || 673 0 stevel (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 674 0 stevel return (EINVAL); 675 0 stevel 676 0 stevel curr = priv->nvp_list; 677 0 stevel while (curr != NULL) { 678 0 stevel nvpair_t *nvp = &curr->nvi_nvp; 679 0 stevel 680 0 stevel if (strcmp(name, NVP_NAME(nvp)) == 0 && NVP_TYPE(nvp) == type) { 681 0 stevel nvp_buf_unlink(nvl, nvp); 682 0 stevel nvpair_free(nvp); 683 0 stevel nvp_buf_free(nvl, nvp); 684 0 stevel 685 0 stevel return (0); 686 0 stevel } 687 0 stevel curr = curr->nvi_next; 688 0 stevel } 689 0 stevel 690 0 stevel return (ENOENT); 691 0 stevel } 692 0 stevel 693 11022 Tom int 694 11022 Tom nvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp) 695 11022 Tom { 696 11022 Tom if (nvl == NULL || nvp == NULL) 697 11022 Tom return (EINVAL); 698 11022 Tom 699 11022 Tom nvp_buf_unlink(nvl, nvp); 700 11022 Tom nvpair_free(nvp); 701 11022 Tom nvp_buf_free(nvl, nvp); 702 11022 Tom return (0); 703 11022 Tom } 704 11022 Tom 705 0 stevel /* 706 0 stevel * This function calculates the size of an nvpair value. 707 0 stevel * 708 0 stevel * The data argument controls the behavior in case of the data types 709 0 stevel * DATA_TYPE_STRING and 710 0 stevel * DATA_TYPE_STRING_ARRAY 711 0 stevel * Is data == NULL then the size of the string(s) is excluded. 712 0 stevel */ 713 0 stevel static int 714 0 stevel i_get_value_size(data_type_t type, const void *data, uint_t nelem) 715 0 stevel { 716 0 stevel uint64_t value_sz; 717 0 stevel 718 0 stevel if (i_validate_type_nelem(type, nelem) != 0) 719 0 stevel return (-1); 720 0 stevel 721 0 stevel /* Calculate required size for holding value */ 722 0 stevel switch (type) { 723 0 stevel case DATA_TYPE_BOOLEAN: 724 0 stevel value_sz = 0; 725 0 stevel break; 726 0 stevel case DATA_TYPE_BOOLEAN_VALUE: 727 0 stevel value_sz = sizeof (boolean_t); 728 0 stevel break; 729 0 stevel case DATA_TYPE_BYTE: 730 0 stevel value_sz = sizeof (uchar_t); 731 0 stevel break; 732 0 stevel case DATA_TYPE_INT8: 733 0 stevel value_sz = sizeof (int8_t); 734 0 stevel break; 735 0 stevel case DATA_TYPE_UINT8: 736 0 stevel value_sz = sizeof (uint8_t); 737 0 stevel break; 738 0 stevel case DATA_TYPE_INT16: 739 0 stevel value_sz = sizeof (int16_t); 740 0 stevel break; 741 0 stevel case DATA_TYPE_UINT16: 742 0 stevel value_sz = sizeof (uint16_t); 743 0 stevel break; 744 0 stevel case DATA_TYPE_INT32: 745 0 stevel value_sz = sizeof (int32_t); 746 0 stevel break; 747 0 stevel case DATA_TYPE_UINT32: 748 0 stevel value_sz = sizeof (uint32_t); 749 0 stevel break; 750 0 stevel case DATA_TYPE_INT64: 751 0 stevel value_sz = sizeof (int64_t); 752 0 stevel break; 753 0 stevel case DATA_TYPE_UINT64: 754 0 stevel value_sz = sizeof (uint64_t); 755 0 stevel break; 756 7243 robj #if !defined(_KERNEL) 757 7243 robj case DATA_TYPE_DOUBLE: 758 7243 robj value_sz = sizeof (double); 759 7243 robj break; 760 7243 robj #endif 761 0 stevel case DATA_TYPE_STRING: 762 0 stevel if (data == NULL) 763 0 stevel value_sz = 0; 764 0 stevel else 765 0 stevel value_sz = strlen(data) + 1; 766 0 stevel break; 767 0 stevel case DATA_TYPE_BOOLEAN_ARRAY: 768 0 stevel value_sz = (uint64_t)nelem * sizeof (boolean_t); 769 0 stevel break; 770 0 stevel case DATA_TYPE_BYTE_ARRAY: 771 0 stevel value_sz = (uint64_t)nelem * sizeof (uchar_t); 772 0 stevel break; 773 0 stevel case DATA_TYPE_INT8_ARRAY: 774 0 stevel value_sz = (uint64_t)nelem * sizeof (int8_t); 775 0 stevel break; 776 0 stevel case DATA_TYPE_UINT8_ARRAY: 777 0 stevel value_sz = (uint64_t)nelem * sizeof (uint8_t); 778 0 stevel break; 779 0 stevel case DATA_TYPE_INT16_ARRAY: 780 0 stevel value_sz = (uint64_t)nelem * sizeof (int16_t); 781 0 stevel break; 782 0 stevel case DATA_TYPE_UINT16_ARRAY: 783 0 stevel value_sz = (uint64_t)nelem * sizeof (uint16_t); 784 0 stevel break; 785 0 stevel case DATA_TYPE_INT32_ARRAY: 786 0 stevel value_sz = (uint64_t)nelem * sizeof (int32_t); 787 0 stevel break; 788 0 stevel case DATA_TYPE_UINT32_ARRAY: 789 0 stevel value_sz = (uint64_t)nelem * sizeof (uint32_t); 790 0 stevel break; 791 0 stevel case DATA_TYPE_INT64_ARRAY: 792 0 stevel value_sz = (uint64_t)nelem * sizeof (int64_t); 793 0 stevel break; 794 0 stevel case DATA_TYPE_UINT64_ARRAY: 795 0 stevel value_sz = (uint64_t)nelem * sizeof (uint64_t); 796 0 stevel break; 797 0 stevel case DATA_TYPE_STRING_ARRAY: 798 0 stevel value_sz = (uint64_t)nelem * sizeof (uint64_t); 799 0 stevel 800 0 stevel if (data != NULL) { 801 0 stevel char *const *strs = data; 802 0 stevel uint_t i; 803 0 stevel 804 0 stevel /* no alignment requirement for strings */ 805 0 stevel for (i = 0; i < nelem; i++) { 806 0 stevel if (strs[i] == NULL) 807 0 stevel return (-1); 808 0 stevel value_sz += strlen(strs[i]) + 1; 809 0 stevel } 810 0 stevel } 811 0 stevel break; 812 0 stevel case DATA_TYPE_HRTIME: 813 0 stevel value_sz = sizeof (hrtime_t); 814 0 stevel break; 815 0 stevel case DATA_TYPE_NVLIST: 816 0 stevel value_sz = NV_ALIGN(sizeof (nvlist_t)); 817 0 stevel break; 818 0 stevel case DATA_TYPE_NVLIST_ARRAY: 819 0 stevel value_sz = (uint64_t)nelem * sizeof (uint64_t) + 820 0 stevel (uint64_t)nelem * NV_ALIGN(sizeof (nvlist_t)); 821 0 stevel break; 822 0 stevel default: 823 0 stevel return (-1); 824 0 stevel } 825 0 stevel 826 0 stevel return (value_sz > INT32_MAX ? -1 : (int)value_sz); 827 0 stevel } 828 0 stevel 829 0 stevel static int 830 0 stevel nvlist_copy_embedded(nvlist_t *nvl, nvlist_t *onvl, nvlist_t *emb_nvl) 831 0 stevel { 832 0 stevel nvpriv_t *priv; 833 0 stevel int err; 834 0 stevel 835 0 stevel if ((priv = nv_priv_alloc_embedded((nvpriv_t *)(uintptr_t) 836 0 stevel nvl->nvl_priv)) == NULL) 837 0 stevel return (ENOMEM); 838 0 stevel 839 0 stevel nvlist_init(emb_nvl, onvl->nvl_nvflag, priv); 840 0 stevel 841 0 stevel if ((err = nvlist_copy_pairs(onvl, emb_nvl)) != 0) { 842 0 stevel nvlist_free(emb_nvl); 843 0 stevel emb_nvl->nvl_priv = 0; 844 0 stevel } 845 0 stevel 846 0 stevel return (err); 847 0 stevel } 848 0 stevel 849 0 stevel /* 850 0 stevel * nvlist_add_common - Add new <name,value> pair to nvlist 851 0 stevel */ 852 0 stevel static int 853 0 stevel nvlist_add_common(nvlist_t *nvl, const char *name, 854 0 stevel data_type_t type, uint_t nelem, const void *data) 855 0 stevel { 856 0 stevel nvpair_t *nvp; 857 1193 mws uint_t i; 858 1193 mws 859 0 stevel int nvp_sz, name_sz, value_sz; 860 0 stevel int err = 0; 861 0 stevel 862 0 stevel if (name == NULL || nvl == NULL || nvl->nvl_priv == 0) 863 0 stevel return (EINVAL); 864 0 stevel 865 0 stevel if (nelem != 0 && data == NULL) 866 0 stevel return (EINVAL); 867 0 stevel 868 0 stevel /* 869 0 stevel * Verify type and nelem and get the value size. 870 0 stevel * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY 871 0 stevel * is the size of the string(s) included. 872 0 stevel */ 873 0 stevel if ((value_sz = i_get_value_size(type, data, nelem)) < 0) 874 0 stevel return (EINVAL); 875 0 stevel 876 0 stevel if (i_validate_nvpair_value(type, nelem, data) != 0) 877 0 stevel return (EINVAL); 878 0 stevel 879 1193 mws /* 880 1193 mws * If we're adding an nvlist or nvlist array, ensure that we are not 881 1193 mws * adding the input nvlist to itself, which would cause recursion, 882 1193 mws * and ensure that no NULL nvlist pointers are present. 883 1193 mws */ 884 0 stevel switch (type) { 885 0 stevel case DATA_TYPE_NVLIST: 886 1193 mws if (data == nvl || data == NULL) 887 0 stevel return (EINVAL); 888 0 stevel break; 889 0 stevel case DATA_TYPE_NVLIST_ARRAY: { 890 1193 mws nvlist_t **onvlp = (nvlist_t **)data; 891 1193 mws for (i = 0; i < nelem; i++) { 892 1193 mws if (onvlp[i] == nvl || onvlp[i] == NULL) 893 0 stevel return (EINVAL); 894 0 stevel } 895 0 stevel break; 896 1193 mws } 897 2856 nd150628 default: 898 2856 nd150628 break; 899 0 stevel } 900 0 stevel 901 0 stevel /* calculate sizes of the nvpair elements and the nvpair itself */ 902 0 stevel name_sz = strlen(name) + 1; 903 0 stevel 904 0 stevel nvp_sz = NVP_SIZE_CALC(name_sz, value_sz); 905 0 stevel 906 0 stevel if ((nvp = nvp_buf_alloc(nvl, nvp_sz)) == NULL) 907 0 stevel return (ENOMEM); 908 0 stevel 909 0 stevel ASSERT(nvp->nvp_size == nvp_sz); 910 0 stevel nvp->nvp_name_sz = name_sz; 911 0 stevel nvp->nvp_value_elem = nelem; 912 0 stevel nvp->nvp_type = type; 913 0 stevel bcopy(name, NVP_NAME(nvp), name_sz); 914 0 stevel 915 0 stevel switch (type) { 916 0 stevel case DATA_TYPE_BOOLEAN: 917 0 stevel break; 918 0 stevel case DATA_TYPE_STRING_ARRAY: { 919 0 stevel char *const *strs = data; 920 0 stevel char *buf = NVP_VALUE(nvp); 921 0 stevel char **cstrs = (void *)buf; 922 0 stevel 923 0 stevel /* skip pre-allocated space for pointer array */ 924 0 stevel buf += nelem * sizeof (uint64_t); 925 0 stevel for (i = 0; i < nelem; i++) { 926 0 stevel int slen = strlen(strs[i]) + 1; 927 0 stevel bcopy(strs[i], buf, slen); 928 0 stevel cstrs[i] = buf; 929 0 stevel buf += slen; 930 0 stevel } 931 0 stevel break; 932 0 stevel } 933 0 stevel case DATA_TYPE_NVLIST: { 934 0 stevel nvlist_t *nnvl = EMBEDDED_NVL(nvp); 935 0 stevel nvlist_t *onvl = (nvlist_t *)data; 936 0 stevel 937 0 stevel if ((err = nvlist_copy_embedded(nvl, onvl, nnvl)) != 0) { 938 0 stevel nvp_buf_free(nvl, nvp); 939 0 stevel return (err); 940 0 stevel } 941 0 stevel break; 942 0 stevel } 943 0 stevel case DATA_TYPE_NVLIST_ARRAY: { 944 0 stevel nvlist_t **onvlp = (nvlist_t **)data; 945 0 stevel nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp); 946 0 stevel nvlist_t *embedded = (nvlist_t *) 947 0 stevel ((uintptr_t)nvlp + nelem * sizeof (uint64_t)); 948 0 stevel 949 0 stevel for (i = 0; i < nelem; i++) { 950 0 stevel if ((err = nvlist_copy_embedded(nvl, 951 0 stevel onvlp[i], embedded)) != 0) { 952 0 stevel /* 953 0 stevel * Free any successfully created lists 954 0 stevel */ 955 0 stevel nvpair_free(nvp); 956 0 stevel nvp_buf_free(nvl, nvp); 957 0 stevel return (err); 958 0 stevel } 959 0 stevel 960 0 stevel nvlp[i] = embedded++; 961 0 stevel } 962 0 stevel break; 963 0 stevel } 964 0 stevel default: 965 0 stevel bcopy(data, NVP_VALUE(nvp), value_sz); 966 0 stevel } 967 0 stevel 968 0 stevel /* if unique name, remove before add */ 969 0 stevel if (nvl->nvl_nvflag & NV_UNIQUE_NAME) 970 0 stevel (void) nvlist_remove_all(nvl, name); 971 0 stevel else if (nvl->nvl_nvflag & NV_UNIQUE_NAME_TYPE) 972 0 stevel (void) nvlist_remove(nvl, name, type); 973 0 stevel 974 0 stevel nvp_buf_link(nvl, nvp); 975 0 stevel 976 0 stevel return (0); 977 0 stevel } 978 0 stevel 979 0 stevel int 980 0 stevel nvlist_add_boolean(nvlist_t *nvl, const char *name) 981 0 stevel { 982 0 stevel return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN, 0, NULL)); 983 0 stevel } 984 0 stevel 985 0 stevel int 986 0 stevel nvlist_add_boolean_value(nvlist_t *nvl, const char *name, boolean_t val) 987 0 stevel { 988 0 stevel return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_VALUE, 1, &val)); 989 0 stevel } 990 0 stevel 991 0 stevel int 992 0 stevel nvlist_add_byte(nvlist_t *nvl, const char *name, uchar_t val) 993 0 stevel { 994 0 stevel return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE, 1, &val)); 995 0 stevel } 996 0 stevel 997 0 stevel int 998 0 stevel nvlist_add_int8(nvlist_t *nvl, const char *name, int8_t val) 999 0 stevel { 1000 0 stevel return (nvlist_add_common(nvl, name, DATA_TYPE_INT8, 1, &val)); 1001 0 stevel } 1002 0 stevel 1003 0 stevel int 1004 0 stevel nvlist_add_uint8(nvlist_t *nvl, const char *name, uint8_t val) 1005 0 stevel { 1006 0 stevel return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8, 1, &val)); 1007 0 stevel } 1008 0 stevel 1009 0 stevel int 1010 0 stevel nvlist_add_int16(nvlist_t *nvl, const char *name, int16_t val) 1011 0 stevel { 1012 0 stevel return (nvlist_add_common(nvl, name, DATA_TYPE_INT16, 1, &val)); 1013 0 stevel } 1014 0 stevel 1015 0 stevel int 1016 0 stevel nvlist_add_uint16(nvlist_t *nvl, const char *name, uint16_t val) 1017 0 stevel { 1018 0 stevel return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16, 1, &val)); 1019 0 stevel } 1020 0 stevel 1021 0 stevel int 1022 0 stevel nvlist_add_int32(nvlist_t *nvl, const char *name, int32_t val) 1023 0 stevel { 1024 0 stevel return (nvlist_add_common(nvl, name, DATA_TYPE_INT32, 1, &val)); 1025 0 stevel } 1026 0 stevel 1027 0 stevel int 1028 0 stevel nvlist_add_uint32(nvlist_t *nvl, const char *name, uint32_t val) 1029 0 stevel { 1030 0 stevel return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32, 1, &val)); 1031 0 stevel } 1032 0 stevel 1033 0 stevel int 1034 0 stevel nvlist_add_int64(nvlist_t *nvl, const char *name, int64_t val) 1035 0 stevel { 1036 0 stevel return (nvlist_add_common(nvl, name, DATA_TYPE_INT64, 1, &val)); 1037 0 stevel } 1038 0 stevel 1039 0 stevel int 1040 0 stevel nvlist_add_uint64(nvlist_t *nvl, const char *name, uint64_t val) 1041 0 stevel { 1042 0 stevel return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64, 1, &val)); 1043 0 stevel } 1044 0 stevel 1045 7243 robj #if !defined(_KERNEL) 1046 7243 robj int 1047 7243 robj nvlist_add_double(nvlist_t *nvl, const char *name, double val) 1048 7243 robj { 1049 7243 robj return (nvlist_add_common(nvl, name, DATA_TYPE_DOUBLE, 1, &val)); 1050 7243 robj } 1051 7243 robj #endif 1052 7243 robj 1053 0 stevel int 1054 0 stevel nvlist_add_string(nvlist_t *nvl, const char *name, const char *val) 1055 0 stevel { 1056 0 stevel return (nvlist_add_common(nvl, name, DATA_TYPE_STRING, 1, (void *)val)); 1057 0 stevel } 1058 0 stevel 1059 0 stevel int 1060 0 stevel nvlist_add_boolean_array(nvlist_t *nvl, const char *name, 1061 0 stevel boolean_t *a, uint_t n) 1062 0 stevel { 1063 0 stevel return (nvlist_add_common(nvl, name, DATA_TYPE_BOOLEAN_ARRAY, n, a)); 1064 0 stevel } 1065 0 stevel 1066 0 stevel int 1067 0 stevel nvlist_add_byte_array(nvlist_t *nvl, const char *name, uchar_t *a, uint_t n) 1068 0 stevel { 1069 0 stevel return (nvlist_add_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a)); 1070 0 stevel } 1071 0 stevel 1072 0 stevel int 1073 0 stevel nvlist_add_int8_array(nvlist_t *nvl, const char *name, int8_t *a, uint_t n) 1074 0 stevel { 1075 0 stevel return (nvlist_add_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a)); 1076 0 stevel } 1077 0 stevel 1078 0 stevel int 1079 0 stevel nvlist_add_uint8_array(nvlist_t *nvl, const char *name, uint8_t *a, uint_t n) 1080 0 stevel { 1081 0 stevel return (nvlist_add_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a)); 1082 0 stevel } 1083 0 stevel 1084 0 stevel int 1085 0 stevel nvlist_add_int16_array(nvlist_t *nvl, const char *name, int16_t *a, uint_t n) 1086 0 stevel { 1087 0 stevel return (nvlist_add_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a)); 1088 0 stevel } 1089 0 stevel 1090 0 stevel int 1091 0 stevel nvlist_add_uint16_array(nvlist_t *nvl, const char *name, uint16_t *a, uint_t n) 1092 0 stevel { 1093 0 stevel return (nvlist_add_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a)); 1094 0 stevel } 1095 0 stevel 1096 0 stevel int 1097 0 stevel nvlist_add_int32_array(nvlist_t *nvl, const char *name, int32_t *a, uint_t n) 1098 0 stevel { 1099 0 stevel return (nvlist_add_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a)); 1100 0 stevel } 1101 0 stevel 1102 0 stevel int 1103 0 stevel nvlist_add_uint32_array(nvlist_t *nvl, const char *name, uint32_t *a, uint_t n) 1104 0 stevel { 1105 0 stevel return (nvlist_add_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a)); 1106 0 stevel } 1107 0 stevel 1108 0 stevel int 1109 0 stevel nvlist_add_int64_array(nvlist_t *nvl, const char *name, int64_t *a, uint_t n) 1110 0 stevel { 1111 0 stevel return (nvlist_add_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a)); 1112 0 stevel } 1113 0 stevel 1114 0 stevel int 1115 0 stevel nvlist_add_uint64_array(nvlist_t *nvl, const char *name, uint64_t *a, uint_t n) 1116 0 stevel { 1117 0 stevel return (nvlist_add_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a)); 1118 0 stevel } 1119 0 stevel 1120 0 stevel int 1121 0 stevel nvlist_add_string_array(nvlist_t *nvl, const char *name, 1122 0 stevel char *const *a, uint_t n) 1123 0 stevel { 1124 0 stevel return (nvlist_add_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a)); 1125 0 stevel } 1126 0 stevel 1127 0 stevel int 1128 0 stevel nvlist_add_hrtime(nvlist_t *nvl, const char *name, hrtime_t val) 1129 0 stevel { 1130 0 stevel return (nvlist_add_common(nvl, name, DATA_TYPE_HRTIME, 1, &val)); 1131 0 stevel } 1132 0 stevel 1133 0 stevel int 1134 0 stevel nvlist_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val) 1135 0 stevel { 1136 0 stevel return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST, 1, val)); 1137 0 stevel } 1138 0 stevel 1139 0 stevel int 1140 0 stevel nvlist_add_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **a, uint_t n) 1141 0 stevel { 1142 0 stevel return (nvlist_add_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a)); 1143 0 stevel } 1144 0 stevel 1145 0 stevel /* reading name-value pairs */ 1146 0 stevel nvpair_t * 1147 0 stevel nvlist_next_nvpair(nvlist_t *nvl, nvpair_t *nvp) 1148 0 stevel { 1149 0 stevel nvpriv_t *priv; 1150 0 stevel i_nvp_t *curr; 1151 0 stevel 1152 0 stevel if (nvl == NULL || 1153 0 stevel (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 1154 0 stevel return (NULL); 1155 0 stevel 1156 0 stevel curr = NVPAIR2I_NVP(nvp); 1157 0 stevel 1158 0 stevel /* 1159 5367 ahrens * Ensure that nvp is a valid nvpair on this nvlist. 1160 5367 ahrens * NB: nvp_curr is used only as a hint so that we don't always 1161 5367 ahrens * have to walk the list to determine if nvp is still on the list. 1162 0 stevel */ 1163 0 stevel if (nvp == NULL) 1164 0 stevel curr = priv->nvp_list; 1165 5367 ahrens else if (priv->nvp_curr == curr || nvlist_contains_nvp(nvl, nvp)) 1166 0 stevel curr = curr->nvi_next; 1167 5367 ahrens else 1168 0 stevel curr = NULL; 1169 0 stevel 1170 0 stevel priv->nvp_curr = curr; 1171 0 stevel 1172 0 stevel return (curr != NULL ? &curr->nvi_nvp : NULL); 1173 11022 Tom } 1174 11022 Tom 1175 11022 Tom nvpair_t * 1176 11022 Tom nvlist_prev_nvpair(nvlist_t *nvl, nvpair_t *nvp) 1177 11022 Tom { 1178 11022 Tom nvpriv_t *priv; 1179 11022 Tom i_nvp_t *curr; 1180 11022 Tom 1181 11022 Tom if (nvl == NULL || 1182 11022 Tom (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 1183 11022 Tom return (NULL); 1184 11022 Tom 1185 11022 Tom curr = NVPAIR2I_NVP(nvp); 1186 11022 Tom 1187 11022 Tom if (nvp == NULL) 1188 11022 Tom curr = priv->nvp_last; 1189 11022 Tom else if (priv->nvp_curr == curr || nvlist_contains_nvp(nvl, nvp)) 1190 11022 Tom curr = curr->nvi_prev; 1191 11022 Tom else 1192 11022 Tom curr = NULL; 1193 11022 Tom 1194 11022 Tom priv->nvp_curr = curr; 1195 11022 Tom 1196 11022 Tom return (curr != NULL ? &curr->nvi_nvp : NULL); 1197 11022 Tom } 1198 11022 Tom 1199 11022 Tom boolean_t 1200 11022 Tom nvlist_empty(nvlist_t *nvl) 1201 11022 Tom { 1202 11022 Tom nvpriv_t *priv; 1203 11022 Tom 1204 11022 Tom if (nvl == NULL || 1205 11022 Tom (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 1206 11022 Tom return (B_TRUE); 1207 11022 Tom 1208 11022 Tom return (priv->nvp_list == NULL); 1209 0 stevel } 1210 0 stevel 1211 0 stevel char * 1212 0 stevel nvpair_name(nvpair_t *nvp) 1213 0 stevel { 1214 0 stevel return (NVP_NAME(nvp)); 1215 0 stevel } 1216 0 stevel 1217 0 stevel data_type_t 1218 0 stevel nvpair_type(nvpair_t *nvp) 1219 0 stevel { 1220 0 stevel return (NVP_TYPE(nvp)); 1221 0 stevel } 1222 0 stevel 1223 6640 cth int 1224 6640 cth nvpair_type_is_array(nvpair_t *nvp) 1225 6640 cth { 1226 6640 cth data_type_t type = NVP_TYPE(nvp); 1227 6640 cth 1228 6640 cth if ((type == DATA_TYPE_BYTE_ARRAY) || 1229 6640 cth (type == DATA_TYPE_UINT8_ARRAY) || 1230 6640 cth (type == DATA_TYPE_INT16_ARRAY) || 1231 6640 cth (type == DATA_TYPE_UINT16_ARRAY) || 1232 6640 cth (type == DATA_TYPE_INT32_ARRAY) || 1233 6640 cth (type == DATA_TYPE_UINT32_ARRAY) || 1234 6640 cth (type == DATA_TYPE_INT64_ARRAY) || 1235 6640 cth (type == DATA_TYPE_UINT64_ARRAY) || 1236 6640 cth (type == DATA_TYPE_BOOLEAN_ARRAY) || 1237 6640 cth (type == DATA_TYPE_STRING_ARRAY) || 1238 6640 cth (type == DATA_TYPE_NVLIST_ARRAY)) 1239 6640 cth return (1); 1240 6640 cth return (0); 1241 6640 cth 1242 6640 cth } 1243 6640 cth 1244 0 stevel static int 1245 0 stevel nvpair_value_common(nvpair_t *nvp, data_type_t type, uint_t *nelem, void *data) 1246 0 stevel { 1247 0 stevel if (nvp == NULL || nvpair_type(nvp) != type) 1248 0 stevel return (EINVAL); 1249 0 stevel 1250 0 stevel /* 1251 0 stevel * For non-array types, we copy the data. 1252 0 stevel * For array types (including string), we set a pointer. 1253 0 stevel */ 1254 0 stevel switch (type) { 1255 0 stevel case DATA_TYPE_BOOLEAN: 1256 0 stevel if (nelem != NULL) 1257 0 stevel *nelem = 0; 1258 0 stevel break; 1259 0 stevel 1260 0 stevel case DATA_TYPE_BOOLEAN_VALUE: 1261 0 stevel case DATA_TYPE_BYTE: 1262 0 stevel case DATA_TYPE_INT8: 1263 0 stevel case DATA_TYPE_UINT8: 1264 0 stevel case DATA_TYPE_INT16: 1265 0 stevel case DATA_TYPE_UINT16: 1266 0 stevel case DATA_TYPE_INT32: 1267 0 stevel case DATA_TYPE_UINT32: 1268 0 stevel case DATA_TYPE_INT64: 1269 0 stevel case DATA_TYPE_UINT64: 1270 0 stevel case DATA_TYPE_HRTIME: 1271 7243 robj #if !defined(_KERNEL) 1272 7243 robj case DATA_TYPE_DOUBLE: 1273 7243 robj #endif 1274 0 stevel if (data == NULL) 1275 0 stevel return (EINVAL); 1276 0 stevel bcopy(NVP_VALUE(nvp), data, 1277 0 stevel (size_t)i_get_value_size(type, NULL, 1)); 1278 0 stevel if (nelem != NULL) 1279 0 stevel *nelem = 1; 1280 0 stevel break; 1281 0 stevel 1282 0 stevel case DATA_TYPE_NVLIST: 1283 0 stevel case DATA_TYPE_STRING: 1284 0 stevel if (data == NULL) 1285 0 stevel return (EINVAL); 1286 0 stevel *(void **)data = (void *)NVP_VALUE(nvp); 1287 0 stevel if (nelem != NULL) 1288 0 stevel *nelem = 1; 1289 0 stevel break; 1290 0 stevel 1291 0 stevel case DATA_TYPE_BOOLEAN_ARRAY: 1292 0 stevel case DATA_TYPE_BYTE_ARRAY: 1293 0 stevel case DATA_TYPE_INT8_ARRAY: 1294 0 stevel case DATA_TYPE_UINT8_ARRAY: 1295 0 stevel case DATA_TYPE_INT16_ARRAY: 1296 0 stevel case DATA_TYPE_UINT16_ARRAY: 1297 0 stevel case DATA_TYPE_INT32_ARRAY: 1298 0 stevel case DATA_TYPE_UINT32_ARRAY: 1299 0 stevel case DATA_TYPE_INT64_ARRAY: 1300 0 stevel case DATA_TYPE_UINT64_ARRAY: 1301 0 stevel case DATA_TYPE_STRING_ARRAY: 1302 0 stevel case DATA_TYPE_NVLIST_ARRAY: 1303 0 stevel if (nelem == NULL || data == NULL) 1304 0 stevel return (EINVAL); 1305 0 stevel if ((*nelem = NVP_NELEM(nvp)) != 0) 1306 0 stevel *(void **)data = (void *)NVP_VALUE(nvp); 1307 0 stevel else 1308 0 stevel *(void **)data = NULL; 1309 0 stevel break; 1310 0 stevel 1311 0 stevel default: 1312 0 stevel return (ENOTSUP); 1313 0 stevel } 1314 0 stevel 1315 0 stevel return (0); 1316 0 stevel } 1317 0 stevel 1318 0 stevel static int 1319 0 stevel nvlist_lookup_common(nvlist_t *nvl, const char *name, data_type_t type, 1320 0 stevel uint_t *nelem, void *data) 1321 0 stevel { 1322 0 stevel nvpriv_t *priv; 1323 0 stevel nvpair_t *nvp; 1324 0 stevel i_nvp_t *curr; 1325 0 stevel 1326 0 stevel if (name == NULL || nvl == NULL || 1327 0 stevel (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 1328 0 stevel return (EINVAL); 1329 0 stevel 1330 0 stevel if (!(nvl->nvl_nvflag & (NV_UNIQUE_NAME | NV_UNIQUE_NAME_TYPE))) 1331 0 stevel return (ENOTSUP); 1332 0 stevel 1333 0 stevel for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) { 1334 0 stevel nvp = &curr->nvi_nvp; 1335 0 stevel 1336 0 stevel if (strcmp(name, NVP_NAME(nvp)) == 0 && NVP_TYPE(nvp) == type) 1337 0 stevel return (nvpair_value_common(nvp, type, nelem, data)); 1338 0 stevel } 1339 0 stevel 1340 0 stevel return (ENOENT); 1341 0 stevel } 1342 0 stevel 1343 0 stevel int 1344 0 stevel nvlist_lookup_boolean(nvlist_t *nvl, const char *name) 1345 0 stevel { 1346 0 stevel return (nvlist_lookup_common(nvl, name, DATA_TYPE_BOOLEAN, NULL, NULL)); 1347 0 stevel } 1348 0 stevel 1349 0 stevel int 1350 0 stevel nvlist_lookup_boolean_value(nvlist_t *nvl, const char *name, boolean_t *val) 1351 0 stevel { 1352 0 stevel return (nvlist_lookup_common(nvl, name, 1353 0 stevel DATA_TYPE_BOOLEAN_VALUE, NULL, val)); 1354 0 stevel } 1355 0 stevel 1356 0 stevel int 1357 0 stevel nvlist_lookup_byte(nvlist_t *nvl, const char *name, uchar_t *val) 1358 0 stevel { 1359 0 stevel return (nvlist_lookup_common(nvl, name, DATA_TYPE_BYTE, NULL, val)); 1360 0 stevel } 1361 0 stevel 1362 0 stevel int 1363 0 stevel nvlist_lookup_int8(nvlist_t *nvl, const char *name, int8_t *val) 1364 0 stevel { 1365 0 stevel return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT8, NULL, val)); 1366 0 stevel } 1367 0 stevel 1368 0 stevel int 1369 0 stevel nvlist_lookup_uint8(nvlist_t *nvl, const char *name, uint8_t *val) 1370 0 stevel { 1371 0 stevel return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT8, NULL, val)); 1372 0 stevel } 1373 0 stevel 1374 0 stevel int 1375 0 stevel nvlist_lookup_int16(nvlist_t *nvl, const char *name, int16_t *val) 1376 0 stevel { 1377 0 stevel return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT16, NULL, val)); 1378 0 stevel } 1379 0 stevel 1380 0 stevel int 1381 0 stevel nvlist_lookup_uint16(nvlist_t *nvl, const char *name, uint16_t *val) 1382 0 stevel { 1383 0 stevel return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT16, NULL, val)); 1384 0 stevel } 1385 0 stevel 1386 0 stevel int 1387 0 stevel nvlist_lookup_int32(nvlist_t *nvl, const char *name, int32_t *val) 1388 0 stevel { 1389 0 stevel return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT32, NULL, val)); 1390 0 stevel } 1391 0 stevel 1392 0 stevel int 1393 0 stevel nvlist_lookup_uint32(nvlist_t *nvl, const char *name, uint32_t *val) 1394 0 stevel { 1395 0 stevel return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT32, NULL, val)); 1396 0 stevel } 1397 0 stevel 1398 0 stevel int 1399 0 stevel nvlist_lookup_int64(nvlist_t *nvl, const char *name, int64_t *val) 1400 0 stevel { 1401 0 stevel return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT64, NULL, val)); 1402 0 stevel } 1403 0 stevel 1404 0 stevel int 1405 0 stevel nvlist_lookup_uint64(nvlist_t *nvl, const char *name, uint64_t *val) 1406 0 stevel { 1407 0 stevel return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT64, NULL, val)); 1408 0 stevel } 1409 0 stevel 1410 7243 robj #if !defined(_KERNEL) 1411 7243 robj int 1412 7243 robj nvlist_lookup_double(nvlist_t *nvl, const char *name, double *val) 1413 7243 robj { 1414 7243 robj return (nvlist_lookup_common(nvl, name, DATA_TYPE_DOUBLE, NULL, val)); 1415 7243 robj } 1416 7243 robj #endif 1417 7243 robj 1418 0 stevel int 1419 0 stevel nvlist_lookup_string(nvlist_t *nvl, const char *name, char **val) 1420 0 stevel { 1421 0 stevel return (nvlist_lookup_common(nvl, name, DATA_TYPE_STRING, NULL, val)); 1422 0 stevel } 1423 0 stevel 1424 0 stevel int 1425 0 stevel nvlist_lookup_nvlist(nvlist_t *nvl, const char *name, nvlist_t **val) 1426 0 stevel { 1427 0 stevel return (nvlist_lookup_common(nvl, name, DATA_TYPE_NVLIST, NULL, val)); 1428 0 stevel } 1429 0 stevel 1430 0 stevel int 1431 0 stevel nvlist_lookup_boolean_array(nvlist_t *nvl, const char *name, 1432 0 stevel boolean_t **a, uint_t *n) 1433 0 stevel { 1434 0 stevel return (nvlist_lookup_common(nvl, name, 1435 0 stevel DATA_TYPE_BOOLEAN_ARRAY, n, a)); 1436 0 stevel } 1437 0 stevel 1438 0 stevel int 1439 0 stevel nvlist_lookup_byte_array(nvlist_t *nvl, const char *name, 1440 0 stevel uchar_t **a, uint_t *n) 1441 0 stevel { 1442 0 stevel return (nvlist_lookup_common(nvl, name, DATA_TYPE_BYTE_ARRAY, n, a)); 1443 0 stevel } 1444 0 stevel 1445 0 stevel int 1446 0 stevel nvlist_lookup_int8_array(nvlist_t *nvl, const char *name, int8_t **a, uint_t *n) 1447 0 stevel { 1448 0 stevel return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT8_ARRAY, n, a)); 1449 0 stevel } 1450 0 stevel 1451 0 stevel int 1452 0 stevel nvlist_lookup_uint8_array(nvlist_t *nvl, const char *name, 1453 0 stevel uint8_t **a, uint_t *n) 1454 0 stevel { 1455 0 stevel return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT8_ARRAY, n, a)); 1456 0 stevel } 1457 0 stevel 1458 0 stevel int 1459 0 stevel nvlist_lookup_int16_array(nvlist_t *nvl, const char *name, 1460 0 stevel int16_t **a, uint_t *n) 1461 0 stevel { 1462 0 stevel return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT16_ARRAY, n, a)); 1463 0 stevel } 1464 0 stevel 1465 0 stevel int 1466 0 stevel nvlist_lookup_uint16_array(nvlist_t *nvl, const char *name, 1467 0 stevel uint16_t **a, uint_t *n) 1468 0 stevel { 1469 0 stevel return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT16_ARRAY, n, a)); 1470 0 stevel } 1471 0 stevel 1472 0 stevel int 1473 0 stevel nvlist_lookup_int32_array(nvlist_t *nvl, const char *name, 1474 0 stevel int32_t **a, uint_t *n) 1475 0 stevel { 1476 0 stevel return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT32_ARRAY, n, a)); 1477 0 stevel } 1478 0 stevel 1479 0 stevel int 1480 0 stevel nvlist_lookup_uint32_array(nvlist_t *nvl, const char *name, 1481 0 stevel uint32_t **a, uint_t *n) 1482 0 stevel { 1483 0 stevel return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT32_ARRAY, n, a)); 1484 0 stevel } 1485 0 stevel 1486 0 stevel int 1487 0 stevel nvlist_lookup_int64_array(nvlist_t *nvl, const char *name, 1488 0 stevel int64_t **a, uint_t *n) 1489 0 stevel { 1490 0 stevel return (nvlist_lookup_common(nvl, name, DATA_TYPE_INT64_ARRAY, n, a)); 1491 0 stevel } 1492 0 stevel 1493 0 stevel int 1494 0 stevel nvlist_lookup_uint64_array(nvlist_t *nvl, const char *name, 1495 0 stevel uint64_t **a, uint_t *n) 1496 0 stevel { 1497 0 stevel return (nvlist_lookup_common(nvl, name, DATA_TYPE_UINT64_ARRAY, n, a)); 1498 0 stevel } 1499 0 stevel 1500 0 stevel int 1501 0 stevel nvlist_lookup_string_array(nvlist_t *nvl, const char *name, 1502 0 stevel char ***a, uint_t *n) 1503 0 stevel { 1504 0 stevel return (nvlist_lookup_common(nvl, name, DATA_TYPE_STRING_ARRAY, n, a)); 1505 0 stevel } 1506 0 stevel 1507 0 stevel int 1508 0 stevel nvlist_lookup_nvlist_array(nvlist_t *nvl, const char *name, 1509 0 stevel nvlist_t ***a, uint_t *n) 1510 0 stevel { 1511 0 stevel return (nvlist_lookup_common(nvl, name, DATA_TYPE_NVLIST_ARRAY, n, a)); 1512 0 stevel } 1513 0 stevel 1514 0 stevel int 1515 0 stevel nvlist_lookup_hrtime(nvlist_t *nvl, const char *name, hrtime_t *val) 1516 0 stevel { 1517 0 stevel return (nvlist_lookup_common(nvl, name, DATA_TYPE_HRTIME, NULL, val)); 1518 0 stevel } 1519 0 stevel 1520 0 stevel int 1521 0 stevel nvlist_lookup_pairs(nvlist_t *nvl, int flag, ...) 1522 0 stevel { 1523 0 stevel va_list ap; 1524 0 stevel char *name; 1525 0 stevel int noentok = (flag & NV_FLAG_NOENTOK ? 1 : 0); 1526 0 stevel int ret = 0; 1527 0 stevel 1528 0 stevel va_start(ap, flag); 1529 0 stevel while (ret == 0 && (name = va_arg(ap, char *)) != NULL) { 1530 0 stevel data_type_t type; 1531 0 stevel void *val; 1532 0 stevel uint_t *nelem; 1533 0 stevel 1534 0 stevel switch (type = va_arg(ap, data_type_t)) { 1535 0 stevel case DATA_TYPE_BOOLEAN: 1536 0 stevel ret = nvlist_lookup_common(nvl, name, type, NULL, NULL); 1537 0 stevel break; 1538 0 stevel 1539 0 stevel case DATA_TYPE_BOOLEAN_VALUE: 1540 0 stevel case DATA_TYPE_BYTE: 1541 0 stevel case DATA_TYPE_INT8: 1542 0 stevel case DATA_TYPE_UINT8: 1543 0 stevel case DATA_TYPE_INT16: 1544 0 stevel case DATA_TYPE_UINT16: 1545 0 stevel case DATA_TYPE_INT32: 1546 0 stevel case DATA_TYPE_UINT32: 1547 0 stevel case DATA_TYPE_INT64: 1548 0 stevel case DATA_TYPE_UINT64: 1549 0 stevel case DATA_TYPE_HRTIME: 1550 0 stevel case DATA_TYPE_STRING: 1551 0 stevel case DATA_TYPE_NVLIST: 1552 7243 robj #if !defined(_KERNEL) 1553 7243 robj case DATA_TYPE_DOUBLE: 1554 7243 robj #endif 1555 0 stevel val = va_arg(ap, void *); 1556 0 stevel ret = nvlist_lookup_common(nvl, name, type, NULL, val); 1557 0 stevel break; 1558 0 stevel 1559 0 stevel case DATA_TYPE_BYTE_ARRAY: 1560 0 stevel case DATA_TYPE_BOOLEAN_ARRAY: 1561 0 stevel case DATA_TYPE_INT8_ARRAY: 1562 0 stevel case DATA_TYPE_UINT8_ARRAY: 1563 0 stevel case DATA_TYPE_INT16_ARRAY: 1564 0 stevel case DATA_TYPE_UINT16_ARRAY: 1565 0 stevel case DATA_TYPE_INT32_ARRAY: 1566 0 stevel case DATA_TYPE_UINT32_ARRAY: 1567 0 stevel case DATA_TYPE_INT64_ARRAY: 1568 0 stevel case DATA_TYPE_UINT64_ARRAY: 1569 0 stevel case DATA_TYPE_STRING_ARRAY: 1570 0 stevel case DATA_TYPE_NVLIST_ARRAY: 1571 0 stevel val = va_arg(ap, void *); 1572 0 stevel nelem = va_arg(ap, uint_t *); 1573 0 stevel ret = nvlist_lookup_common(nvl, name, type, nelem, val); 1574 0 stevel break; 1575 0 stevel 1576 0 stevel default: 1577 0 stevel ret = EINVAL; 1578 0 stevel } 1579 0 stevel 1580 0 stevel if (ret == ENOENT && noentok) 1581 0 stevel ret = 0; 1582 0 stevel } 1583 0 stevel va_end(ap); 1584 0 stevel 1585 0 stevel return (ret); 1586 0 stevel } 1587 0 stevel 1588 6640 cth /* 1589 6640 cth * Find the 'name'ed nvpair in the nvlist 'nvl'. If 'name' found, the function 1590 6640 cth * returns zero and a pointer to the matching nvpair is returned in '*ret' 1591 6640 cth * (given 'ret' is non-NULL). If 'sep' is specified then 'name' will penitrate 1592 6640 cth * multiple levels of embedded nvlists, with 'sep' as the separator. As an 1593 6640 cth * example, if sep is '.', name might look like: "a" or "a.b" or "a.c[3]" or 1594 6640 cth * "a.d[3].e[1]". This matches the C syntax for array embed (for convience, 1595 6640 cth * code also supports "a.d[3]e[1]" syntax). 1596 6640 cth * 1597 6640 cth * If 'ip' is non-NULL and the last name component is an array, return the 1598 6640 cth * value of the "...[index]" array index in *ip. For an array reference that 1599 6640 cth * is not indexed, *ip will be returned as -1. If there is a syntax error in 1600 6640 cth * 'name', and 'ep' is non-NULL then *ep will be set to point to the location 1601 6640 cth * inside the 'name' string where the syntax error was detected. 1602 6640 cth */ 1603 6640 cth static int 1604 6640 cth nvlist_lookup_nvpair_ei_sep(nvlist_t *nvl, const char *name, const char sep, 1605 6640 cth nvpair_t **ret, int *ip, char **ep) 1606 6640 cth { 1607 6640 cth nvpair_t *nvp; 1608 6640 cth const char *np; 1609 6640 cth char *sepp; 1610 6640 cth char *idxp, *idxep; 1611 6640 cth nvlist_t **nva; 1612 6640 cth long idx; 1613 6640 cth int n; 1614 6640 cth 1615 6640 cth if (ip) 1616 6640 cth *ip = -1; /* not indexed */ 1617 6640 cth if (ep) 1618 6640 cth *ep = NULL; 1619 6640 cth 1620 6640 cth if ((nvl == NULL) || (name == NULL)) 1621 6640 cth return (EINVAL); 1622 6640 cth 1623 6640 cth /* step through components of name */ 1624 6640 cth for (np = name; np && *np; np = sepp) { 1625 6640 cth /* ensure unique names */ 1626 6640 cth if (!(nvl->nvl_nvflag & NV_UNIQUE_NAME)) 1627 6640 cth return (ENOTSUP); 1628 6640 cth 1629 6640 cth /* skip white space */ 1630 6640 cth skip_whitespace(np); 1631 6640 cth if (*np == 0) 1632 6640 cth break; 1633 6640 cth 1634 6640 cth /* set 'sepp' to end of current component 'np' */ 1635 6640 cth if (sep) 1636 6640 cth sepp = strchr(np, sep); 1637 6640 cth else 1638 6640 cth sepp = NULL; 1639 6640 cth 1640 6640 cth /* find start of next "[ index ]..." */ 1641 6640 cth idxp = strchr(np, '['); 1642 6640 cth 1643 6640 cth /* if sepp comes first, set idxp to NULL */ 1644 6640 cth if (sepp && idxp && (sepp < idxp)) 1645 6640 cth idxp = NULL; 1646 6640 cth 1647 6640 cth /* 1648 6640 cth * At this point 'idxp' is set if there is an index 1649 6640 cth * expected for the current component. 1650 6640 cth */ 1651 6640 cth if (idxp) { 1652 6640 cth /* set 'n' to length of current 'np' name component */ 1653 6640 cth n = idxp++ - np; 1654 6640 cth 1655 6640 cth /* keep sepp up to date for *ep use as we advance */ 1656 6640 cth skip_whitespace(idxp); 1657 6640 cth sepp = idxp; 1658 6640 cth 1659 6640 cth /* determine the index value */ 1660 6640 cth #if defined(_KERNEL) && !defined(_BOOT) 1661 6640 cth if (ddi_strtol(idxp, &idxep, 0, &idx)) 1662 6640 cth goto fail; 1663 6640 cth #else 1664 6640 cth idx = strtol(idxp, &idxep, 0); 1665 6640 cth #endif 1666 6640 cth if (idxep == idxp) 1667 6640 cth goto fail; 1668 6640 cth 1669 6640 cth /* keep sepp up to date for *ep use as we advance */ 1670 6640 cth sepp = idxep; 1671 6640 cth 1672 6640 cth /* skip white space index value and check for ']' */ 1673 6640 cth skip_whitespace(sepp); 1674 6640 cth if (*sepp++ != ']') 1675 6640 cth goto fail; 1676 6640 cth 1677 6640 cth /* for embedded arrays, support C syntax: "a[1].b" */ 1678 6640 cth skip_whitespace(sepp); 1679 6640 cth if (sep && (*sepp == sep)) 1680 6640 cth sepp++; 1681 6640 cth } else if (sepp) { 1682 6640 cth n = sepp++ - np; 1683 6640 cth } else { 1684 6640 cth n = strlen(np); 1685 6640 cth } 1686 6640 cth 1687 6640 cth /* trim trailing whitespace by reducing length of 'np' */ 1688 6640 cth if (n == 0) 1689 6640 cth goto fail; 1690 6640 cth for (n--; (np[n] == ' ') || (np[n] == '\t'); n--) 1691 6640 cth ; 1692 6640 cth n++; 1693 6640 cth 1694 6640 cth /* skip whitespace, and set sepp to NULL if complete */ 1695 6640 cth if (sepp) { 1696 6640 cth skip_whitespace(sepp); 1697 6640 cth if (*sepp == 0) 1698 6640 cth sepp = NULL; 1699 6640 cth } 1700 6640 cth 1701 6640 cth /* 1702 6640 cth * At this point: 1703 6640 cth * o 'n' is the length of current 'np' component. 1704 6640 cth * o 'idxp' is set if there was an index, and value 'idx'. 1705 6640 cth * o 'sepp' is set to the beginning of the next component, 1706 6640 cth * and set to NULL if we have no more components. 1707 6640 cth * 1708 6640 cth * Search for nvpair with matching component name. 1709 6640 cth */ 1710 6640 cth for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 1711 6640 cth nvp = nvlist_next_nvpair(nvl, nvp)) { 1712 6640 cth 1713 6640 cth /* continue if no match on name */ 1714 6640 cth if (strncmp(np, nvpair_name(nvp), n) || 1715 6640 cth (strlen(nvpair_name(nvp)) != n)) 1716 6640 cth continue; 1717 6640 cth 1718 6640 cth /* if indexed, verify type is array oriented */ 1719 6640 cth if (idxp && !nvpair_type_is_array(nvp)) 1720 6640 cth goto fail; 1721 6640 cth 1722 6640 cth /* 1723 6640 cth * Full match found, return nvp and idx if this 1724 6640 cth * was the last component. 1725 6640 cth */ 1726 6640 cth if (sepp == NULL) { 1727 6640 cth if (ret) 1728 6640 cth *ret = nvp; 1729 6640 cth if (ip && idxp) 1730 6640 cth *ip = (int)idx; /* return index */ 1731 6640 cth return (0); /* found */ 1732 6640 cth } 1733 6640 cth 1734 6640 cth /* 1735 6640 cth * More components: current match must be 1736 6640 cth * of DATA_TYPE_NVLIST or DATA_TYPE_NVLIST_ARRAY 1737 6640 cth * to support going deeper. 1738 6640 cth */ 1739 6640 cth if (nvpair_type(nvp) == DATA_TYPE_NVLIST) { 1740 6640 cth nvl = EMBEDDED_NVL(nvp); 1741 6640 cth break; 1742 6640 cth } else if (nvpair_type(nvp) == DATA_TYPE_NVLIST_ARRAY) { 1743 6640 cth (void) nvpair_value_nvlist_array(nvp, 1744 6640 cth &nva, (uint_t *)&n); 1745 6640 cth if ((n < 0) || (idx >= n)) 1746 6640 cth goto fail; 1747 6640 cth nvl = nva[idx]; 1748 6640 cth break; 1749 6640 cth } 1750 6640 cth 1751 6640 cth /* type does not support more levels */ 1752 6640 cth goto fail; 1753 6640 cth } 1754 6640 cth if (nvp == NULL) 1755 6640 cth goto fail; /* 'name' not found */ 1756 6640 cth 1757 6640 cth /* search for match of next component in embedded 'nvl' list */ 1758 6640 cth } 1759 6640 cth 1760 6640 cth fail: if (ep && sepp) 1761 6640 cth *ep = sepp; 1762 6640 cth return (EINVAL); 1763 6640 cth } 1764 6640 cth 1765 6640 cth /* 1766 6640 cth * Return pointer to nvpair with specified 'name'. 1767 6640 cth */ 1768 0 stevel int 1769 5345 eschrock nvlist_lookup_nvpair(nvlist_t *nvl, const char *name, nvpair_t **ret) 1770 5345 eschrock { 1771 6640 cth return (nvlist_lookup_nvpair_ei_sep(nvl, name, 0, ret, NULL, NULL)); 1772 6640 cth } 1773 5345 eschrock 1774 6640 cth /* 1775 6640 cth * Determine if named nvpair exists in nvlist (use embedded separator of '.' 1776 6640 cth * and return array index). See nvlist_lookup_nvpair_ei_sep for more detailed 1777 6640 cth * description. 1778 6640 cth */ 1779 6640 cth int nvlist_lookup_nvpair_embedded_index(nvlist_t *nvl, 1780 6640 cth const char *name, nvpair_t **ret, int *ip, char **ep) 1781 6640 cth { 1782 6640 cth return (nvlist_lookup_nvpair_ei_sep(nvl, name, '.', ret, ip, ep)); 1783 5345 eschrock } 1784 5345 eschrock 1785 5345 eschrock boolean_t 1786 5345 eschrock nvlist_exists(nvlist_t *nvl, const char *name) 1787 5345 eschrock { 1788 5345 eschrock nvpriv_t *priv; 1789 5345 eschrock nvpair_t *nvp; 1790 5345 eschrock i_nvp_t *curr; 1791 5345 eschrock 1792 5345 eschrock if (name == NULL || nvl == NULL || 1793 5345 eschrock (priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 1794 5345 eschrock return (B_FALSE); 1795 5345 eschrock 1796 5345 eschrock for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) { 1797 5345 eschrock nvp = &curr->nvi_nvp; 1798 5345 eschrock 1799 5345 eschrock if (strcmp(name, NVP_NAME(nvp)) == 0) 1800 5345 eschrock return (B_TRUE); 1801 5345 eschrock } 1802 5345 eschrock 1803 5345 eschrock return (B_FALSE); 1804 5345 eschrock } 1805 5345 eschrock 1806 5345 eschrock int 1807 0 stevel nvpair_value_boolean_value(nvpair_t *nvp, boolean_t *val) 1808 0 stevel { 1809 0 stevel return (nvpair_value_common(nvp, DATA_TYPE_BOOLEAN_VALUE, NULL, val)); 1810 0 stevel } 1811 0 stevel 1812 0 stevel int 1813 0 stevel nvpair_value_byte(nvpair_t *nvp, uchar_t *val) 1814 0 stevel { 1815 0 stevel return (nvpair_value_common(nvp, DATA_TYPE_BYTE, NULL, val)); 1816 0 stevel } 1817 0 stevel 1818 0 stevel int 1819 0 stevel nvpair_value_int8(nvpair_t *nvp, int8_t *val) 1820 0 stevel { 1821 0 stevel return (nvpair_value_common(nvp, DATA_TYPE_INT8, NULL, val)); 1822 0 stevel } 1823 0 stevel 1824 0 stevel int 1825 0 stevel nvpair_value_uint8(nvpair_t *nvp, uint8_t *val) 1826 0 stevel { 1827 0 stevel return (nvpair_value_common(nvp, DATA_TYPE_UINT8, NULL, val)); 1828 0 stevel } 1829 0 stevel 1830 0 stevel int 1831 0 stevel nvpair_value_int16(nvpair_t *nvp, int16_t *val) 1832 0 stevel { 1833 0 stevel return (nvpair_value_common(nvp, DATA_TYPE_INT16, NULL, val)); 1834 0 stevel } 1835 0 stevel 1836 0 stevel int 1837 0 stevel nvpair_value_uint16(nvpair_t *nvp, uint16_t *val) 1838 0 stevel { 1839 0 stevel return (nvpair_value_common(nvp, DATA_TYPE_UINT16, NULL, val)); 1840 0 stevel } 1841 0 stevel 1842 0 stevel int 1843 0 stevel nvpair_value_int32(nvpair_t *nvp, int32_t *val) 1844 0 stevel { 1845 0 stevel return (nvpair_value_common(nvp, DATA_TYPE_INT32, NULL, val)); 1846 0 stevel } 1847 0 stevel 1848 0 stevel int 1849 0 stevel nvpair_value_uint32(nvpair_t *nvp, uint32_t *val) 1850 0 stevel { 1851 0 stevel return (nvpair_value_common(nvp, DATA_TYPE_UINT32, NULL, val)); 1852 0 stevel } 1853 0 stevel 1854 0 stevel int 1855 0 stevel nvpair_value_int64(nvpair_t *nvp, int64_t *val) 1856 0 stevel { 1857 0 stevel return (nvpair_value_common(nvp, DATA_TYPE_INT64, NULL, val)); 1858 0 stevel } 1859 0 stevel 1860 0 stevel int 1861 0 stevel nvpair_value_uint64(nvpair_t *nvp, uint64_t *val) 1862 0 stevel { 1863 0 stevel return (nvpair_value_common(nvp, DATA_TYPE_UINT64, NULL, val)); 1864 0 stevel } 1865 7243 robj 1866 7243 robj #if !defined(_KERNEL) 1867 7243 robj int 1868 7243 robj nvpair_value_double(nvpair_t *nvp, double *val) 1869 7243 robj { 1870 7243 robj return (nvpair_value_common(nvp, DATA_TYPE_DOUBLE, NULL, val)); 1871 7243 robj } 1872 7243 robj #endif 1873 0 stevel 1874 0 stevel int 1875 0 stevel nvpair_value_string(nvpair_t *nvp, char **val) 1876 0 stevel { 1877 0 stevel return (nvpair_value_common(nvp, DATA_TYPE_STRING, NULL, val)); 1878 0 stevel } 1879 0 stevel 1880 0 stevel int 1881 0 stevel nvpair_value_nvlist(nvpair_t *nvp, nvlist_t **val) 1882 0 stevel { 1883 0 stevel return (nvpair_value_common(nvp, DATA_TYPE_NVLIST, NULL, val)); 1884 0 stevel } 1885 0 stevel 1886 0 stevel int 1887 0 stevel nvpair_value_boolean_array(nvpair_t *nvp, boolean_t **val, uint_t *nelem) 1888 0 stevel { 1889 0 stevel return (nvpair_value_common(nvp, DATA_TYPE_BOOLEAN_ARRAY, nelem, val)); 1890 0 stevel } 1891 0 stevel 1892 0 stevel int 1893 0 stevel nvpair_value_byte_array(nvpair_t *nvp, uchar_t **val, uint_t *nelem) 1894 0 stevel { 1895 0 stevel return (nvpair_value_common(nvp, DATA_TYPE_BYTE_ARRAY, nelem, val)); 1896 0 stevel } 1897 0 stevel 1898 0 stevel int 1899 0 stevel nvpair_value_int8_array(nvpair_t *nvp, int8_t **val, uint_t *nelem) 1900 0 stevel { 1901 0 stevel return (nvpair_value_common(nvp, DATA_TYPE_INT8_ARRAY, nelem, val)); 1902 0 stevel } 1903 0 stevel 1904 0 stevel int 1905 0 stevel nvpair_value_uint8_array(nvpair_t *nvp, uint8_t **val, uint_t *nelem) 1906 0 stevel { 1907 0 stevel return (nvpair_value_common(nvp, DATA_TYPE_UINT8_ARRAY, nelem, val)); 1908 0 stevel } 1909 0 stevel 1910 0 stevel int 1911 0 stevel nvpair_value_int16_array(nvpair_t *nvp, int16_t **val, uint_t *nelem) 1912 0 stevel { 1913 0 stevel return (nvpair_value_common(nvp, DATA_TYPE_INT16_ARRAY, nelem, val)); 1914 0 stevel } 1915 0 stevel 1916 0 stevel int 1917 0 stevel nvpair_value_uint16_array(nvpair_t *nvp, uint16_t **val, uint_t *nelem) 1918 0 stevel { 1919 0 stevel return (nvpair_value_common(nvp, DATA_TYPE_UINT16_ARRAY, nelem, val)); 1920 0 stevel } 1921 0 stevel 1922 0 stevel int 1923 0 stevel nvpair_value_int32_array(nvpair_t *nvp, int32_t **val, uint_t *nelem) 1924 0 stevel { 1925 0 stevel return (nvpair_value_common(nvp, DATA_TYPE_INT32_ARRAY, nelem, val)); 1926 0 stevel } 1927 0 stevel 1928 0 stevel int 1929 0 stevel nvpair_value_uint32_array(nvpair_t *nvp, uint32_t **val, uint_t *nelem) 1930 0 stevel { 1931 0 stevel return (nvpair_value_common(nvp, DATA_TYPE_UINT32_ARRAY, nelem, val)); 1932 0 stevel } 1933 0 stevel 1934 0 stevel int 1935 0 stevel nvpair_value_int64_array(nvpair_t *nvp, int64_t **val, uint_t *nelem) 1936 0 stevel { 1937 0 stevel return (nvpair_value_common(nvp, DATA_TYPE_INT64_ARRAY, nelem, val)); 1938 0 stevel } 1939 0 stevel 1940 0 stevel int 1941 0 stevel nvpair_value_uint64_array(nvpair_t *nvp, uint64_t **val, uint_t *nelem) 1942 0 stevel { 1943 0 stevel return (nvpair_value_common(nvp, DATA_TYPE_UINT64_ARRAY, nelem, val)); 1944 0 stevel } 1945 0 stevel 1946 0 stevel int 1947 0 stevel nvpair_value_string_array(nvpair_t *nvp, char ***val, uint_t *nelem) 1948 0 stevel { 1949 0 stevel return (nvpair_value_common(nvp, DATA_TYPE_STRING_ARRAY, nelem, val)); 1950 0 stevel } 1951 0 stevel 1952 0 stevel int 1953 0 stevel nvpair_value_nvlist_array(nvpair_t *nvp, nvlist_t ***val, uint_t *nelem) 1954 0 stevel { 1955 0 stevel return (nvpair_value_common(nvp, DATA_TYPE_NVLIST_ARRAY, nelem, val)); 1956 0 stevel } 1957 0 stevel 1958 0 stevel int 1959 0 stevel nvpair_value_hrtime(nvpair_t *nvp, hrtime_t *val) 1960 0 stevel { 1961 0 stevel return (nvpair_value_common(nvp, DATA_TYPE_HRTIME, NULL, val)); 1962 0 stevel } 1963 0 stevel 1964 0 stevel /* 1965 0 stevel * Add specified pair to the list. 1966 0 stevel */ 1967 0 stevel int 1968 0 stevel nvlist_add_nvpair(nvlist_t *nvl, nvpair_t *nvp) 1969 0 stevel { 1970 0 stevel if (nvl == NULL || nvp == NULL) 1971 0 stevel return (EINVAL); 1972 0 stevel 1973 0 stevel return (nvlist_add_common(nvl, NVP_NAME(nvp), NVP_TYPE(nvp), 1974 0 stevel NVP_NELEM(nvp), NVP_VALUE(nvp))); 1975 0 stevel } 1976 0 stevel 1977 0 stevel /* 1978 0 stevel * Merge the supplied nvlists and put the result in dst. 1979 0 stevel * The merged list will contain all names specified in both lists, 1980 0 stevel * the values are taken from nvl in the case of duplicates. 1981 0 stevel * Return 0 on success. 1982 0 stevel */ 1983 0 stevel /*ARGSUSED*/ 1984 0 stevel int 1985 0 stevel nvlist_merge(nvlist_t *dst, nvlist_t *nvl, int flag) 1986 0 stevel { 1987 0 stevel if (nvl == NULL || dst == NULL) 1988 0 stevel return (EINVAL); 1989 0 stevel 1990 0 stevel if (dst != nvl) 1991 0 stevel return (nvlist_copy_pairs(nvl, dst)); 1992 0 stevel 1993 0 stevel return (0); 1994 0 stevel } 1995 0 stevel 1996 0 stevel /* 1997 0 stevel * Encoding related routines 1998 0 stevel */ 1999 0 stevel #define NVS_OP_ENCODE 0 2000 0 stevel #define NVS_OP_DECODE 1 2001 0 stevel #define NVS_OP_GETSIZE 2 2002 0 stevel 2003 0 stevel typedef struct nvs_ops nvs_ops_t; 2004 0 stevel 2005 0 stevel typedef struct { 2006 0 stevel int nvs_op; 2007 0 stevel const nvs_ops_t *nvs_ops; 2008 0 stevel void *nvs_private; 2009 0 stevel nvpriv_t *nvs_priv; 2010 0 stevel } nvstream_t; 2011 0 stevel 2012 0 stevel /* 2013 0 stevel * nvs operations are: 2014 0 stevel * - nvs_nvlist 2015 0 stevel * encoding / decoding of a nvlist header (nvlist_t) 2016 0 stevel * calculates the size used for header and end detection 2017 0 stevel * 2018 0 stevel * - nvs_nvpair 2019 0 stevel * responsible for the first part of encoding / decoding of an nvpair 2020 0 stevel * calculates the decoded size of an nvpair 2021 0 stevel * 2022 0 stevel * - nvs_nvp_op 2023 0 stevel * second part of encoding / decoding of an nvpair 2024 0 stevel * 2025 0 stevel * - nvs_nvp_size 2026 0 stevel * calculates the encoding size of an nvpair 2027 0 stevel * 2028 0 stevel * - nvs_nvl_fini 2029 0 stevel * encodes the end detection mark (zeros). 2030 0 stevel */ 2031 0 stevel struct nvs_ops { 2032 0 stevel int (*nvs_nvlist)(nvstream_t *, nvlist_t *, size_t *); 2033 0 stevel int (*nvs_nvpair)(nvstream_t *, nvpair_t *, size_t *); 2034 0 stevel int (*nvs_nvp_op)(nvstream_t *, nvpair_t *); 2035 0 stevel int (*nvs_nvp_size)(nvstream_t *, nvpair_t *, size_t *); 2036 0 stevel int (*nvs_nvl_fini)(nvstream_t *); 2037 0 stevel }; 2038 0 stevel 2039 0 stevel typedef struct { 2040 0 stevel char nvh_encoding; /* nvs encoding method */ 2041 0 stevel char nvh_endian; /* nvs endian */ 2042 0 stevel char nvh_reserved1; /* reserved for future use */ 2043 0 stevel char nvh_reserved2; /* reserved for future use */ 2044 0 stevel } nvs_header_t; 2045 0 stevel 2046 0 stevel static int 2047 0 stevel nvs_encode_pairs(nvstream_t *nvs, nvlist_t *nvl) 2048 0 stevel { 2049 0 stevel nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 2050 0 stevel i_nvp_t *curr; 2051 0 stevel 2052 0 stevel /* 2053 0 stevel * Walk nvpair in list and encode each nvpair 2054 0 stevel */ 2055 0 stevel for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) 2056 0 stevel if (nvs->nvs_ops->nvs_nvpair(nvs, &curr->nvi_nvp, NULL) != 0) 2057 0 stevel return (EFAULT); 2058 0 stevel 2059 0 stevel return (nvs->nvs_ops->nvs_nvl_fini(nvs)); 2060 0 stevel } 2061 0 stevel 2062 0 stevel static int 2063 0 stevel nvs_decode_pairs(nvstream_t *nvs, nvlist_t *nvl) 2064 0 stevel { 2065 0 stevel nvpair_t *nvp; 2066 0 stevel size_t nvsize; 2067 0 stevel int err; 2068 0 stevel 2069 0 stevel /* 2070 0 stevel * Get decoded size of next pair in stream, alloc 2071 0 stevel * memory for nvpair_t, then decode the nvpair 2072 0 stevel */ 2073 0 stevel while ((err = nvs->nvs_ops->nvs_nvpair(nvs, NULL, &nvsize)) == 0) { 2074 0 stevel if (nvsize == 0) /* end of list */ 2075 0 stevel break; 2076 0 stevel 2077 0 stevel /* make sure len makes sense */ 2078 0 stevel if (nvsize < NVP_SIZE_CALC(1, 0)) 2079 0 stevel return (EFAULT); 2080 0 stevel 2081 0 stevel if ((nvp = nvp_buf_alloc(nvl, nvsize)) == NULL) 2082 0 stevel return (ENOMEM); 2083 0 stevel 2084 0 stevel if ((err = nvs->nvs_ops->nvs_nvp_op(nvs, nvp)) != 0) { 2085 0 stevel nvp_buf_free(nvl, nvp); 2086 0 stevel return (err); 2087 0 stevel } 2088 0 stevel 2089 0 stevel if (i_validate_nvpair(nvp) != 0) { 2090 0 stevel nvpair_free(nvp); 2091 0 stevel nvp_buf_free(nvl, nvp); 2092 0 stevel return (EFAULT); 2093 0 stevel } 2094 0 stevel 2095 0 stevel nvp_buf_link(nvl, nvp); 2096 0 stevel } 2097 0 stevel return (err); 2098 0 stevel } 2099 0 stevel 2100 0 stevel static int 2101 0 stevel nvs_getsize_pairs(nvstream_t *nvs, nvlist_t *nvl, size_t *buflen) 2102 0 stevel { 2103 0 stevel nvpriv_t *priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv; 2104 0 stevel i_nvp_t *curr; 2105 0 stevel uint64_t nvsize = *buflen; 2106 0 stevel size_t size; 2107 0 stevel 2108 0 stevel /* 2109 0 stevel * Get encoded size of nvpairs in nvlist 2110 0 stevel */ 2111 0 stevel for (curr = priv->nvp_list; curr != NULL; curr = curr->nvi_next) { 2112 0 stevel if (nvs->nvs_ops->nvs_nvp_size(nvs, &curr->nvi_nvp, &size) != 0) 2113 0 stevel return (EINVAL); 2114 0 stevel 2115 0 stevel if ((nvsize += size) > INT32_MAX) 2116 0 stevel return (EINVAL); 2117 0 stevel } 2118 0 stevel 2119 0 stevel *buflen = nvsize; 2120 0 stevel return (0); 2121 0 stevel } 2122 0 stevel 2123 0 stevel static int 2124 0 stevel nvs_operation(nvstream_t *nvs, nvlist_t *nvl, size_t *buflen) 2125 0 stevel { 2126 0 stevel int err; 2127 0 stevel 2128 2856 nd150628 if (nvl->nvl_priv == 0) 2129 0 stevel return (EFAULT); 2130 0 stevel 2131 0 stevel /* 2132 0 stevel * Perform the operation, starting with header, then each nvpair 2133 0 stevel */ 2134 0 stevel if ((err = nvs->nvs_ops->nvs_nvlist(nvs, nvl, buflen)) != 0) 2135 0 stevel return (err); 2136 0 stevel 2137 0 stevel switch (nvs->nvs_op) { 2138 0 stevel case NVS_OP_ENCODE: 2139 0 stevel err = nvs_encode_pairs(nvs, nvl); 2140 0 stevel break; 2141 0 stevel 2142 0 stevel case NVS_OP_DECODE: 2143 0 stevel err = nvs_decode_pairs(nvs, nvl); 2144 0 stevel break; 2145 0 stevel 2146 0 stevel case NVS_OP_GETSIZE: 2147 0 stevel err = nvs_getsize_pairs(nvs, nvl, buflen); 2148 0 stevel break; 2149 0 stevel 2150 0 stevel default: 2151 0 stevel err = EINVAL; 2152 0 stevel } 2153 0 stevel 2154 0 stevel return (err); 2155 0 stevel } 2156 0 stevel 2157 0 stevel static int 2158 0 stevel nvs_embedded(nvstream_t *nvs, nvlist_t *embedded) 2159 0 stevel { 2160 0 stevel switch (nvs->nvs_op) { 2161 0 stevel case NVS_OP_ENCODE: 2162 0 stevel return (nvs_operation(nvs, embedded, NULL)); 2163 0 stevel 2164 0 stevel case NVS_OP_DECODE: { 2165 0 stevel nvpriv_t *priv; 2166 0 stevel int err; 2167 0 stevel 2168 0 stevel if (embedded->nvl_version != NV_VERSION) 2169 0 stevel return (ENOTSUP); 2170 0 stevel 2171 0 stevel if ((priv = nv_priv_alloc_embedded(nvs->nvs_priv)) == NULL) 2172 0 stevel return (ENOMEM); 2173 0 stevel 2174 0 stevel nvlist_init(embedded, embedded->nvl_nvflag, priv); 2175 0 stevel 2176 0 stevel if ((err = nvs_operation(nvs, embedded, NULL)) != 0) 2177 0 stevel nvlist_free(embedded); 2178 0 stevel return (err); 2179 0 stevel } 2180 0 stevel default: 2181 0 stevel break; 2182 0 stevel } 2183 0 stevel 2184 0 stevel return (EINVAL); 2185 0 stevel } 2186 0 stevel 2187 0 stevel static int 2188 0 stevel nvs_embedded_nvl_array(nvstream_t *nvs, nvpair_t *nvp, size_t *size) 2189 0 stevel { 2190 0 stevel size_t nelem = NVP_NELEM(nvp); 2191 0 stevel nvlist_t **nvlp = EMBEDDED_NVL_ARRAY(nvp); 2192 0 stevel int i; 2193 0 stevel 2194 0 stevel switch (nvs->nvs_op) { 2195 0 stevel case NVS_OP_ENCODE: 2196 0 stevel for (i = 0; i < nelem; i++) 2197 0 stevel if (nvs_embedded(nvs, nvlp[i]) != 0) 2198 0 stevel return (EFAULT); 2199 0 stevel break; 2200 0 stevel 2201 0 stevel case NVS_OP_DECODE: { 2202 0 stevel size_t len = nelem * sizeof (uint64_t); 2203 0 stevel nvlist_t *embedded = (nvlist_t *)((uintptr_t)nvlp + len); 2204 0 stevel 2205 0 stevel bzero(nvlp, len); /* don't trust packed data */ 2206 0 stevel for (i = 0; i < nelem; i++) { 2207 0 stevel if (nvs_embedded(nvs, embedded) != 0) { 2208 0 stevel nvpair_free(nvp); 2209 0 stevel return (EFAULT); 2210 0 stevel } 2211 0 stevel 2212 0 stevel nvlp[i] = embedded++; 2213 0 stevel } 2214 0 stevel break; 2215 0 stevel } 2216 0 stevel case NVS_OP_GETSIZE: { 2217 0 stevel uint64_t nvsize = 0; 2218 0 stevel 2219 0 stevel for (i = 0; i < nelem; i++) { 2220 0 stevel size_t nvp_sz = 0; 2221 0 stevel 2222 0 stevel if (nvs_operation(nvs, nvlp[i], &nvp_sz) != 0) 2223 0 stevel return (EINVAL); 2224 0 stevel 2225 0 stevel if ((nvsize += nvp_sz) > INT32_MAX) 2226 0 stevel return (EINVAL); 2227 0 stevel } 2228 0 stevel 2229 0 stevel *size = nvsize; 2230 0 stevel break; 2231 0 stevel } 2232 0 stevel default: 2233 0 stevel return (EINVAL); 2234 0 stevel } 2235 0 stevel 2236 0 stevel return (0); 2237 0 stevel } 2238 0 stevel 2239 0 stevel static int nvs_native(nvstream_t *, nvlist_t *, char *, size_t *); 2240 0 stevel static int nvs_xdr(nvstream_t *, nvlist_t *, char *, size_t *); 2241 0 stevel 2242 0 stevel /* 2243 0 stevel * Common routine for nvlist operations: 2244 0 stevel * encode, decode, getsize (encoded size). 2245 0 stevel */ 2246 0 stevel static int 2247 0 stevel nvlist_common(nvlist_t *nvl, char *buf, size_t *buflen, int encoding, 2248 0 stevel int nvs_op) 2249 0 stevel { 2250 0 stevel int err = 0; 2251 0 stevel nvstream_t nvs; 2252 0 stevel int nvl_endian; 2253 0 stevel #ifdef _LITTLE_ENDIAN 2254 0 stevel int host_endian = 1; 2255 0 stevel #else 2256 0 stevel int host_endian = 0; 2257 0 stevel #endif /* _LITTLE_ENDIAN */ 2258 0 stevel nvs_header_t *nvh = (void *)buf; 2259 0 stevel 2260 0 stevel if (buflen == NULL || nvl == NULL || 2261 0 stevel (nvs.nvs_priv = (nvpriv_t *)(uintptr_t)nvl->nvl_priv) == NULL) 2262 0 stevel return (EINVAL); 2263 0 stevel 2264 0 stevel nvs.nvs_op = nvs_op; 2265 0 stevel 2266 0 stevel /* 2267 0 stevel * For NVS_OP_ENCODE and NVS_OP_DECODE make sure an nvlist and 2268 0 stevel * a buffer is allocated. The first 4 bytes in the buffer are 2269 0 stevel * used for encoding method and host endian. 2270 0 stevel */ 2271 0 stevel switch (nvs_op) { 2272 0 stevel case NVS_OP_ENCODE: 2273 0 stevel if (buf == NULL || *buflen < sizeof (nvs_header_t)) 2274 0 stevel return (EINVAL); 2275 0 stevel 2276 0 stevel nvh->nvh_encoding = encoding; 2277 0 stevel nvh->nvh_endian = nvl_endian = host_endian; 2278 0 stevel nvh->nvh_reserved1 = 0; 2279 0 stevel nvh->nvh_reserved2 = 0; 2280 0 stevel break; 2281 0 stevel 2282 0 stevel case NVS_OP_DECODE: 2283 0 stevel if (buf == NULL || *buflen < sizeof (nvs_header_t)) 2284 0 stevel return (EINVAL); 2285 0 stevel 2286 0 stevel /* get method of encoding from first byte */ 2287 0 stevel encoding = nvh->nvh_encoding; 2288 0 stevel nvl_endian = nvh->nvh_endian; 2289 0 stevel break; 2290 0 stevel 2291 0 stevel case NVS_OP_GETSIZE: 2292 0 stevel nvl_endian = host_endian; 2293 0 stevel 2294 0 stevel /* 2295 0 stevel * add the size for encoding 2296 0 stevel */ 2297 0 stevel *buflen = sizeof (nvs_header_t); 2298 0 stevel break; 2299 0 stevel 2300 0 stevel default: 2301 0 stevel return (ENOTSUP); 2302 0 stevel } 2303 0 stevel 2304 0 stevel /* 2305 0 stevel * Create an nvstream with proper encoding method 2306 0 stevel */ 2307 0 stevel switch (encoding) { 2308 0 stevel case NV_ENCODE_NATIVE: 2309 0 stevel /* 2310 0 stevel * check endianness, in case we are unpacking 2311 0 stevel * from a file 2312 0 stevel */ 2313 0 stevel if (nvl_endian != host_endian) 2314 0 stevel return (ENOTSUP); 2315 0 stevel err = nvs_native(&nvs, nvl, buf, buflen); 2316 0 stevel break; 2317 0 stevel case NV_ENCODE_XDR: 2318 0 stevel err = nvs_xdr(&nvs, nvl, buf, buflen); 2319 0 stevel break; 2320 0 stevel default: 2321 0 stevel err = ENOTSUP; 2322 0 stevel break; 2323 0 stevel } 2324 0 stevel 2325 0 stevel return (err); 2326 0 stevel } 2327 0 stevel 2328 0 stevel int 2329 0 stevel nvlist_size(nvlist_t *nvl, size_t *size, int encoding) 2330 0 stevel { 2331 0 stevel return (nvlist_common(nvl, NULL, size, encoding, NVS_OP_GETSIZE)); 2332 0 stevel } 2333 0 stevel 2334 0 stevel /* 2335 0 stevel * Pack nvlist into contiguous memory 2336 0 stevel */ 2337 0 stevel /*ARGSUSED1*/ 2338 0 stevel int 2339 0 stevel nvlist_pack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding, 2340 0 stevel int kmflag) 2341 0 stevel { 2342 0 stevel #if defined(_KERNEL) && !defined(_BOOT) 2343 0 stevel return (nvlist_xpack(nvl, bufp, buflen, encoding, 2344 0 stevel (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep))); 2345 0 stevel #else 2346 0 stevel return (nvlist_xpack(nvl, bufp, buflen, encoding, nv_alloc_nosleep)); 2347 0 stevel #endif 2348 0 stevel } 2349 0 stevel 2350 0 stevel int 2351 0 stevel nvlist_xpack(nvlist_t *nvl, char **bufp, size_t *buflen, int encoding, 2352 0 stevel nv_alloc_t *nva) 2353 0 stevel { 2354 0 stevel nvpriv_t nvpriv; 2355 0 stevel size_t alloc_size; 2356 0 stevel char *buf; 2357 0 stevel int err; 2358 0 stevel 2359 0 stevel if (nva == NULL || nvl == NULL || bufp == NULL || buflen == NULL) 2360 0 stevel return (EINVAL); 2361 0 stevel 2362 0 stevel if (*bufp != NULL) 2363 0 stevel return (nvlist_common(nvl, *bufp, buflen, encoding, 2364 0 stevel NVS_OP_ENCODE)); 2365 0 stevel 2366 0 stevel /* 2367 0 stevel * Here is a difficult situation: 2368 0 stevel * 1. The nvlist has fixed allocator properties. 2369 0 stevel * All other nvlist routines (like nvlist_add_*, ...) use 2370 0 stevel * these properties. 2371 0 stevel * 2. When using nvlist_pack() the user can specify his own 2372 0 stevel * allocator properties (e.g. by using KM_NOSLEEP). 2373 0 stevel * 2374 0 stevel * We use the user specified properties (2). A clearer solution 2375 0 stevel * will be to remove the kmflag from nvlist_pack(), but we will 2376 0 stevel * not change the interface. 2377 0 stevel */ 2378 0 stevel nv_priv_init(&nvpriv, nva, 0); 2379 0 stevel 2380 0 stevel if (err = nvlist_size(nvl, &alloc_size, encoding)) 2381 0 stevel return (err); 2382 0 stevel 2383 0 stevel if ((buf = nv_mem_zalloc(&nvpriv, alloc_size)) == NULL) 2384 0 stevel return (ENOMEM); 2385 0 stevel 2386 0 stevel if ((err = nvlist_common(nvl, buf, &alloc_size, encoding, 2387 0 stevel NVS_OP_ENCODE)) != 0) { 2388 0 stevel nv_mem_free(&nvpriv, buf, alloc_size); 2389 0 stevel } else { 2390 0 stevel *buflen = alloc_size; 2391 0 stevel *bufp = buf; 2392 0 stevel } 2393 0 stevel 2394 0 stevel return (err); 2395 0 stevel } 2396 0 stevel 2397 0 stevel /* 2398 0 stevel * Unpack buf into an nvlist_t 2399 0 stevel */ 2400 0 stevel /*ARGSUSED1*/ 2401 0 stevel int 2402 0 stevel nvlist_unpack(char *buf, size_t buflen, nvlist_t **nvlp, int kmflag) 2403 0 stevel { 2404 0 stevel #if defined(_KERNEL) && !defined(_BOOT) 2405 0 stevel return (nvlist_xunpack(buf, buflen, nvlp, 2406 0 stevel (kmflag == KM_SLEEP ? nv_alloc_sleep : nv_alloc_nosleep))); 2407 0 stevel #else 2408 0 stevel return (nvlist_xunpack(buf, buflen, nvlp, nv_alloc_nosleep)); 2409 0 stevel #endif 2410 0 stevel } 2411 0 stevel 2412 0 stevel int 2413 0 stevel nvlist_xunpack(char *buf, size_t buflen, nvlist_t **nvlp, nv_alloc_t *nva) 2414 0 stevel { 2415 0 stevel nvlist_t *nvl; 2416 0 stevel int err; 2417 0 stevel 2418 0 stevel if (nvlp == NULL) 2419 0 stevel return (EINVAL); 2420 0 stevel 2421 0 stevel if ((err = nvlist_xalloc(&nvl, 0, nva)) != 0) 2422 0 stevel return (err); 2423 0 stevel 2424 0 stevel if ((err = nvlist_common(nvl, buf, &buflen, 0, NVS_OP_DECODE)) != 0) 2425 0 stevel nvlist_free(nvl); 2426 0 stevel else 2427 0 stevel *nvlp = nvl; 2428 0 stevel 2429 0 stevel return (err); 2430 0 stevel } 2431 0 stevel 2432 0 stevel /* 2433 0 stevel * Native encoding functions 2434 0 stevel */ 2435 0 stevel typedef struct { 2436 0 stevel /* 2437 0 stevel * This structure is used when decoding a packed nvpair in 2438 0 stevel * the native format. n_base points to a buffer containing the 2439 0 stevel * packed nvpair. n_end is a pointer to the end of the buffer. 2440 0 stevel * (n_end actually points to the first byte past the end of the 2441 0 stevel * buffer.) n_curr is a pointer that lies between n_base and n_end. 2442 0 stevel * It points to the current data that we are decoding. 2443 0 stevel * The amount of data left in the buffer is equal to n_end - n_curr. 2444 0 stevel * n_flag is used to recognize a packed embedded list. 2445 0 stevel */ 2446 0 stevel caddr_t n_base; 2447 0 stevel caddr_t n_end; 2448 0 stevel caddr_t n_curr; 2449 0 stevel uint_t n_flag; 2450 0 stevel } nvs_native_t; 2451 0 stevel 2452 0 stevel static int 2453 0 stevel nvs_native_create(nvstream_t *nvs, nvs_native_t *native, char *buf, 2454 0 stevel size_t buflen) 2455 0 stevel { 2456 0 stevel switch (nvs->nvs_op) { 2457 0 stevel case NVS_OP_ENCODE: 2458 0 stevel case NVS_OP_DECODE: 2459 0 stevel nvs->nvs_private = native; 2460 0 stevel native->n_curr = native->n_base = buf; 2461 0 stevel native->n_end = buf + buflen; 2462 0 stevel native->n_flag = 0; 2463 0 stevel return (0); 2464 0 stevel 2465 0 stevel case NVS_OP_GETSIZE: 2466 0 stevel nvs->nvs_private = native; 2467 0 stevel native->n_curr = native->n_base = native->n_end = NULL; 2468 0 stevel native->n_flag = 0; 2469 0 stevel return (0); 2470 0 stevel default: 2471 0 stevel return (EINVAL); 2472 0 stevel } 2473 0 stevel } 2474 0 stevel 2475 0 stevel /*ARGSUSED*/ 2476 0 stevel static void 2477 0 stevel nvs_native_destroy(nvstream_t *nvs) 2478 0 stevel { 2479 0 stevel } 2480 0 stevel 2481 0 stevel static int 2482 0 stevel native_cp(nvstream_t *nvs, void *buf, size_t size) 2483 0 stevel { 2484 0 stevel nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 2485 0 stevel 2486 0 stevel if (native->n_curr + size > native->n_end) 2487 0 stevel return (EFAULT); 2488 0 stevel 2489 0 stevel /* 2490 0 stevel * The bcopy() below eliminates alignment requirement 2491 0 stevel * on the buffer (stream) and is preferred over direct access. 2492 0 stevel */ 2493 0 stevel switch (nvs->nvs_op) { 2494 0 stevel case NVS_OP_ENCODE: 2495 0 stevel bcopy(buf, native->n_curr, size); 2496 0 stevel break; 2497 0 stevel case NVS_OP_DECODE: 2498 0 stevel bcopy(native->n_curr, buf, size); 2499 0 stevel break; 2500 0 stevel default: 2501 0 stevel return (EINVAL); 2502 0 stevel } 2503 0 stevel 2504 0 stevel native->n_curr += size; 2505 0 stevel return (0); 2506 0 stevel } 2507 0 stevel 2508 0 stevel /* 2509 0 stevel * operate on nvlist_t header 2510 0 stevel */ 2511 0 stevel static int 2512 0 stevel nvs_native_nvlist(nvstream_t *nvs, nvlist_t *nvl, size_t *size) 2513 0 stevel { 2514 0 stevel nvs_native_t *native = nvs->nvs_private; 2515 0 stevel 2516 0 stevel switch (nvs->nvs_op) { 2517 0 stevel case NVS_OP_ENCODE: 2518 0 stevel case NVS_OP_DECODE: 2519 0 stevel if (native->n_flag) 2520 0 stevel return (0); /* packed embedded list */ 2521 0 stevel 2522 0 stevel native->n_flag = 1; 2523 0 stevel 2524 0 stevel /* copy version and nvflag of the nvlist_t */ 2525 0 stevel if (native_cp(nvs, &nvl->nvl_version, sizeof (int32_t)) != 0 || 2526 0 stevel native_cp(nvs, &nvl->nvl_nvflag, sizeof (int32_t)) != 0) 2527 0 stevel return (EFAULT); 2528 0 stevel 2529 0 stevel return (0); 2530 0 stevel 2531 0 stevel case NVS_OP_GETSIZE: 2532 0 stevel /* 2533 0 stevel * if calculate for packed embedded list 2534 0 stevel * 4 for end of the embedded list 2535 0 stevel * else 2536 0 stevel * 2 * sizeof (int32_t) for nvl_version and nvl_nvflag 2537 0 stevel * and 4 for end of the entire list 2538 0 stevel */ 2539 0 stevel if (native->n_flag) { 2540 0 stevel *size += 4; 2541 0 stevel } else { 2542 0 stevel native->n_flag = 1; 2543 0 stevel *size += 2 * sizeof (int32_t) + 4; 2544 0 stevel } 2545 0 stevel 2546 0 stevel return (0); 2547 0 stevel 2548 0 stevel default: 2549 0 stevel return (EINVAL); 2550 0 stevel } 2551 0 stevel } 2552 0 stevel 2553 0 stevel static int 2554 0 stevel nvs_native_nvl_fini(nvstream_t *nvs) 2555 0 stevel { 2556 0 stevel if (nvs->nvs_op == NVS_OP_ENCODE) { 2557 0 stevel nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 2558 0 stevel /* 2559 0 stevel * Add 4 zero bytes at end of nvlist. They are used 2560 0 stevel * for end detection by the decode routine. 2561 0 stevel */ 2562 0 stevel if (native->n_curr + sizeof (int) > native->n_end) 2563 0 stevel return (EFAULT); 2564 0 stevel 2565 0 stevel bzero(native->n_curr, sizeof (int)); 2566 0 stevel native->n_curr += sizeof (int); 2567 0 stevel } 2568 0 stevel 2569 0 stevel return (0); 2570 0 stevel } 2571 0 stevel 2572 0 stevel static int 2573 0 stevel nvpair_native_embedded(nvstream_t *nvs, nvpair_t *nvp) 2574 0 stevel { 2575 0 stevel if (nvs->nvs_op == NVS_OP_ENCODE) { 2576 0 stevel nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 2577 0 stevel nvlist_t *packed = (void *) 2578 0 stevel (native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp)); 2579 0 stevel /* 2580 0 stevel * Null out the pointer that is meaningless in the packed 2581 0 stevel * structure. The address may not be aligned, so we have 2582 0 stevel * to use bzero. 2583 0 stevel */ 2584 0 stevel bzero(&packed->nvl_priv, sizeof (packed->nvl_priv)); 2585 0 stevel } 2586 0 stevel 2587 0 stevel return (nvs_embedded(nvs, EMBEDDED_NVL(nvp))); 2588 0 stevel } 2589 0 stevel 2590 0 stevel static int 2591 0 stevel nvpair_native_embedded_array(nvstream_t *nvs, nvpair_t *nvp) 2592 0 stevel { 2593 0 stevel if (nvs->nvs_op == NVS_OP_ENCODE) { 2594 0 stevel nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 2595 0 stevel char *value = native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp); 2596 0 stevel size_t len = NVP_NELEM(nvp) * sizeof (uint64_t); 2597 0 stevel nvlist_t *packed = (nvlist_t *)((uintptr_t)value + len); 2598 0 stevel int i; 2599 0 stevel /* 2600 0 stevel * Null out pointers that are meaningless in the packed 2601 0 stevel * structure. The addresses may not be aligned, so we have 2602 0 stevel * to use bzero. 2603 0 stevel */ 2604 0 stevel bzero(value, len); 2605 0 stevel 2606 0 stevel for (i = 0; i < NVP_NELEM(nvp); i++, packed++) 2607 0 stevel /* 2608 0 stevel * Null out the pointer that is meaningless in the 2609 0 stevel * packed structure. The address may not be aligned, 2610 0 stevel * so we have to use bzero. 2611 0 stevel */ 2612 0 stevel bzero(&packed->nvl_priv, sizeof (packed->nvl_priv)); 2613 0 stevel } 2614 0 stevel 2615 0 stevel return (nvs_embedded_nvl_array(nvs, nvp, NULL)); 2616 0 stevel } 2617 0 stevel 2618 0 stevel static void 2619 0 stevel nvpair_native_string_array(nvstream_t *nvs, nvpair_t *nvp) 2620 0 stevel { 2621 0 stevel switch (nvs->nvs_op) { 2622 0 stevel case NVS_OP_ENCODE: { 2623 0 stevel nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 2624 0 stevel uint64_t *strp = (void *) 2625 0 stevel (native->n_curr - nvp->nvp_size + NVP_VALOFF(nvp)); 2626 0 stevel /* 2627 0 stevel * Null out pointers that are meaningless in the packed 2628 0 stevel * structure. The addresses may not be aligned, so we have 2629 0 stevel * to use bzero. 2630 0 stevel */ 2631 0 stevel bzero(strp, NVP_NELEM(nvp) * sizeof (uint64_t)); 2632 0 stevel break; 2633 0 stevel } 2634 0 stevel case NVS_OP_DECODE: { 2635 0 stevel char **strp = (void *)NVP_VALUE(nvp); 2636 0 stevel char *buf = ((char *)strp + NVP_NELEM(nvp) * sizeof (uint64_t)); 2637 0 stevel int i; 2638 0 stevel 2639 0 stevel for (i = 0; i < NVP_NELEM(nvp); i++) { 2640 0 stevel strp[i] = buf; 2641 0 stevel buf += strlen(buf) + 1; 2642 0 stevel } 2643 0 stevel break; 2644 0 stevel } 2645 0 stevel } 2646 0 stevel } 2647 0 stevel 2648 0 stevel static int 2649 0 stevel nvs_native_nvp_op(nvstream_t *nvs, nvpair_t *nvp) 2650 0 stevel { 2651 0 stevel data_type_t type; 2652 0 stevel int value_sz; 2653 0 stevel int ret = 0; 2654 0 stevel 2655 0 stevel /* 2656 0 stevel * We do the initial bcopy of the data before we look at 2657 0 stevel * the nvpair type, because when we're decoding, we won't 2658 0 stevel * have the correct values for the pair until we do the bcopy. 2659 0 stevel */ 2660 0 stevel switch (nvs->nvs_op) { 2661 0 stevel case NVS_OP_ENCODE: 2662 0 stevel case NVS_OP_DECODE: 2663 0 stevel if (native_cp(nvs, nvp, nvp->nvp_size) != 0) 2664 0 stevel return (EFAULT); 2665 0 stevel break; 2666 0 stevel default: 2667 0 stevel return (EINVAL); 2668 0 stevel } 2669 0 stevel 2670 0 stevel /* verify nvp_name_sz, check the name string length */ 2671 0 stevel if (i_validate_nvpair_name(nvp) != 0) 2672 0 stevel return (EFAULT); 2673 0 stevel 2674 0 stevel type = NVP_TYPE(nvp); 2675 0 stevel 2676 0 stevel /* 2677 0 stevel * Verify type and nelem and get the value size. 2678 0 stevel * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY 2679 0 stevel * is the size of the string(s) excluded. 2680 0 stevel */ 2681 0 stevel if ((value_sz = i_get_value_size(type, NULL, NVP_NELEM(nvp))) < 0) 2682 0 stevel return (EFAULT); 2683 0 stevel 2684 0 stevel if (NVP_SIZE_CALC(nvp->nvp_name_sz, value_sz) > nvp->nvp_size) 2685 0 stevel return (EFAULT); 2686 0 stevel 2687 0 stevel switch (type) { 2688 0 stevel case DATA_TYPE_NVLIST: 2689 0 stevel ret = nvpair_native_embedded(nvs, nvp); 2690 0 stevel break; 2691 0 stevel case DATA_TYPE_NVLIST_ARRAY: 2692 0 stevel ret = nvpair_native_embedded_array(nvs, nvp); 2693 0 stevel break; 2694 0 stevel case DATA_TYPE_STRING_ARRAY: 2695 0 stevel nvpair_native_string_array(nvs, nvp); 2696 0 stevel break; 2697 0 stevel default: 2698 0 stevel break; 2699 0 stevel } 2700 0 stevel 2701 0 stevel return (ret); 2702 0 stevel } 2703 0 stevel 2704 0 stevel static int 2705 0 stevel nvs_native_nvp_size(nvstream_t *nvs, nvpair_t *nvp, size_t *size) 2706 0 stevel { 2707 0 stevel uint64_t nvp_sz = nvp->nvp_size; 2708 0 stevel 2709 0 stevel switch (NVP_TYPE(nvp)) { 2710 0 stevel case DATA_TYPE_NVLIST: { 2711 0 stevel size_t nvsize = 0; 2712 0 stevel 2713 0 stevel if (nvs_operation(nvs, EMBEDDED_NVL(nvp), &nvsize) != 0) 2714 0 stevel return (EINVAL); 2715 0 stevel 2716 0 stevel nvp_sz += nvsize; 2717 0 stevel break; 2718 0 stevel } 2719 0 stevel case DATA_TYPE_NVLIST_ARRAY: { 2720 0 stevel size_t nvsize; 2721 0 stevel 2722 0 stevel if (nvs_embedded_nvl_array(nvs, nvp, &nvsize) != 0) 2723 0 stevel return (EINVAL); 2724 0 stevel 2725 0 stevel nvp_sz += nvsize; 2726 0 stevel break; 2727 0 stevel } 2728 0 stevel default: 2729 0 stevel break; 2730 0 stevel } 2731 0 stevel 2732 0 stevel if (nvp_sz > INT32_MAX) 2733 0 stevel return (EINVAL); 2734 0 stevel 2735 0 stevel *size = nvp_sz; 2736 0 stevel 2737 0 stevel return (0); 2738 0 stevel } 2739 0 stevel 2740 0 stevel static int 2741 0 stevel nvs_native_nvpair(nvstream_t *nvs, nvpair_t *nvp, size_t *size) 2742 0 stevel { 2743 0 stevel switch (nvs->nvs_op) { 2744 0 stevel case NVS_OP_ENCODE: 2745 0 stevel return (nvs_native_nvp_op(nvs, nvp)); 2746 0 stevel 2747 0 stevel case NVS_OP_DECODE: { 2748 0 stevel nvs_native_t *native = (nvs_native_t *)nvs->nvs_private; 2749 0 stevel int32_t decode_len; 2750 0 stevel 2751 0 stevel /* try to read the size value from the stream */ 2752 0 stevel if (native->n_curr + sizeof (int32_t) > native->n_end) 2753 0 stevel return (EFAULT); 2754 0 stevel bcopy(native->n_curr, &decode_len, sizeof (int32_t)); 2755 0 stevel 2756 0 stevel /* sanity check the size value */ 2757 0 stevel if (decode_len < 0 || 2758 0 stevel decode_len > native->n_end - native->n_curr) 2759 0 stevel return (EFAULT); 2760 0 stevel 2761 0 stevel *size = decode_len; 2762 0 stevel 2763 0 stevel /* 2764 0 stevel * If at the end of the stream then move the cursor 2765 0 stevel * forward, otherwise nvpair_native_op() will read 2766 0 stevel * the entire nvpair at the same cursor position. 2767 0 stevel */ 2768 0 stevel if (*size == 0) 2769 0 stevel native->n_curr += sizeof (int32_t); 2770 0 stevel break; 2771 0 stevel } 2772 0 stevel 2773 0 stevel default: 2774 0 stevel return (EINVAL); 2775 0 stevel } 2776 0 stevel 2777 0 stevel return (0); 2778 0 stevel } 2779 0 stevel 2780 0 stevel static const nvs_ops_t nvs_native_ops = { 2781 0 stevel nvs_native_nvlist, 2782 0 stevel nvs_native_nvpair, 2783 0 stevel nvs_native_nvp_op, 2784 0 stevel nvs_native_nvp_size, 2785 0 stevel nvs_native_nvl_fini 2786 0 stevel }; 2787 0 stevel 2788 0 stevel static int 2789 0 stevel nvs_native(nvstream_t *nvs, nvlist_t *nvl, char *buf, size_t *buflen) 2790 0 stevel { 2791 0 stevel nvs_native_t native; 2792 0 stevel int err; 2793 0 stevel 2794 0 stevel nvs->nvs_ops = &nvs_native_ops; 2795 0 stevel 2796 0 stevel if ((err = nvs_native_create(nvs, &native, buf + sizeof (nvs_header_t), 2797 0 stevel *buflen - sizeof (nvs_header_t))) != 0) 2798 0 stevel return (err); 2799 0 stevel 2800 0 stevel err = nvs_operation(nvs, nvl, buflen); 2801 0 stevel 2802 0 stevel nvs_native_destroy(nvs); 2803 0 stevel 2804 0 stevel return (err); 2805 0 stevel } 2806 0 stevel 2807 0 stevel /* 2808 0 stevel * XDR encoding functions 2809 0 stevel * 2810 0 stevel * An xdr packed nvlist is encoded as: 2811 0 stevel * 2812 0 stevel * - encoding methode and host endian (4 bytes) 2813 0 stevel * - nvl_version (4 bytes) 2814 0 stevel * - nvl_nvflag (4 bytes) 2815 0 stevel * 2816 0 stevel * - encoded nvpairs, the format of one xdr encoded nvpair is: 2817 0 stevel * - encoded size of the nvpair (4 bytes) 2818 0 stevel * - decoded size of the nvpair (4 bytes) 2819 0 stevel * - name string, (4 + sizeof(NV_ALIGN4(string)) 2820 0 stevel * a string is coded as size (4 bytes) and data 2821 0 stevel * - data type (4 bytes) 2822 0 stevel * - number of elements in the nvpair (4 bytes) 2823 0 stevel * - data 2824 0 stevel * 2825 0 stevel * - 2 zero's for end of the entire list (8 bytes) 2826 0 stevel */ 2827 0 stevel static int 2828 0 stevel nvs_xdr_create(nvstream_t *nvs, XDR *xdr, char *buf, size_t buflen) 2829 0 stevel { 2830 0 stevel /* xdr data must be 4 byte aligned */ 2831 0 stevel if ((ulong_t)buf % 4 != 0) 2832 0 stevel return (EFAULT); 2833 0 stevel 2834 0 stevel switch (nvs->nvs_op) { 2835 0 stevel case NVS_OP_ENCODE: 2836 0 stevel xdrmem_create(xdr, buf, (uint_t)buflen, XDR_ENCODE); 2837 0 stevel nvs->nvs_private = xdr; 2838 0 stevel return (0); 2839 0 stevel case NVS_OP_DECODE: 2840 0 stevel xdrmem_create(xdr, buf, (uint_t)buflen, XDR_DECODE); 2841 0 stevel nvs->nvs_private = xdr; 2842 0 stevel return (0); 2843 0 stevel case NVS_OP_GETSIZE: 2844 0 stevel nvs->nvs_private = NULL; 2845 0 stevel return (0); 2846 0 stevel default: 2847 0 stevel return (EINVAL); 2848 0 stevel } 2849 0 stevel } 2850 0 stevel 2851 0 stevel static void 2852 0 stevel nvs_xdr_destroy(nvstream_t *nvs) 2853 0 stevel { 2854 0 stevel switch (nvs->nvs_op) { 2855 0 stevel case NVS_OP_ENCODE: 2856 0 stevel case NVS_OP_DECODE: 2857 0 stevel xdr_destroy((XDR *)nvs->nvs_private); 2858 0 stevel break; 2859 0 stevel default: 2860 0 stevel break; 2861 0 stevel } 2862 0 stevel } 2863 0 stevel 2864 0 stevel static int 2865 0 stevel nvs_xdr_nvlist(nvstream_t *nvs, nvlist_t *nvl, size_t *size) 2866 0 stevel { 2867 0 stevel switch (nvs->nvs_op) { 2868 0 stevel case NVS_OP_ENCODE: 2869 0 stevel case NVS_OP_DECODE: { 2870 0 stevel XDR *xdr = nvs->nvs_private; 2871 0 stevel 2872 0 stevel if (!xdr_int(xdr, &nvl->nvl_version) || 2873 0 stevel !xdr_u_int(xdr, &nvl->nvl_nvflag)) 2874 0 stevel return (EFAULT); 2875 0 stevel break; 2876 0 stevel } 2877 0 stevel case NVS_OP_GETSIZE: { 2878 0 stevel /* 2879 0 stevel * 2 * 4 for nvl_version + nvl_nvflag 2880 0 stevel * and 8 for end of the entire list 2881 0 stevel */ 2882 0 stevel *size += 2 * 4 + 8; 2883 0 stevel break; 2884 0 stevel } 2885 0 stevel default: 2886 0 stevel return (EINVAL); 2887 0 stevel } 2888 0 stevel return (0); 2889 0 stevel } 2890 0 stevel 2891 0 stevel static int 2892 0 stevel nvs_xdr_nvl_fini(nvstream_t *nvs) 2893 0 stevel { 2894 0 stevel if (nvs->nvs_op == NVS_OP_ENCODE) { 2895 0 stevel XDR *xdr = nvs->nvs_private; 2896 0 stevel int zero = 0; 2897 0 stevel 2898 0 stevel if (!xdr_int(xdr, &zero) || !xdr_int(xdr, &zero)) 2899 0 stevel return (EFAULT); 2900 0 stevel } 2901 0 stevel 2902 0 stevel return (0); 2903 0 stevel } 2904 0 stevel 2905 0 stevel /* 2906 0 stevel * The format of xdr encoded nvpair is: 2907 0 stevel * encode_size, decode_size, name string, data type, nelem, data 2908 0 stevel */ 2909 0 stevel static int 2910 0 stevel nvs_xdr_nvp_op(nvstream_t *nvs, nvpair_t *nvp) 2911 0 stevel { 2912 0 stevel data_type_t type; 2913 0 stevel char *buf; 2914 0 stevel char *buf_end = (char *)nvp + nvp->nvp_size; 2915 0 stevel int value_sz; 2916 0 stevel uint_t nelem, buflen; 2917 0 stevel bool_t ret = FALSE; 2918 0 stevel XDR *xdr = nvs->nvs_private; 2919 0 stevel 2920 0 stevel ASSERT(xdr != NULL && nvp != NULL); 2921 0 stevel 2922 0 stevel /* name string */ 2923 0 stevel if ((buf = NVP_NAME(nvp)) >= buf_end) 2924 0 stevel return (EFAULT); 2925 0 stevel buflen = buf_end - buf; 2926 0 stevel 2927 0 stevel if (!xdr_string(xdr, &buf, buflen - 1)) 2928 0 stevel return (EFAULT); 2929 0 stevel nvp->nvp_name_sz = strlen(buf) + 1; 2930 0 stevel 2931 0 stevel /* type and nelem */ 2932 0 stevel if (!xdr_int(xdr, (int *)&nvp->nvp_type) || 2933 0 stevel !xdr_int(xdr, &nvp->nvp_value_elem)) 2934 0 stevel return (EFAULT); 2935 0 stevel 2936 0 stevel type = NVP_TYPE(nvp); 2937 0 stevel nelem = nvp->nvp_value_elem; 2938 0 stevel 2939 0 stevel /* 2940 0 stevel * Verify type and nelem and get the value size. 2941 0 stevel * In case of data types DATA_TYPE_STRING and DATA_TYPE_STRING_ARRAY 2942 0 stevel * is the size of the string(s) excluded. 2943 0 stevel */ 2944 0 stevel if ((value_sz = i_get_value_size(type, NULL, nelem)) < 0) 2945 0 stevel return (EFAULT); 2946 0 stevel 2947 0 stevel /* if there is no data to extract then return */ 2948 0 stevel if (nelem == 0) 2949 0 stevel return (0); 2950 0 stevel 2951 0 stevel /* value */ 2952 0 stevel if ((buf = NVP_VALUE(nvp)) >= buf_end) 2953 0 stevel return (EFAULT); 2954 0 stevel buflen = buf_end - buf; 2955 0 stevel 2956 0 stevel if (buflen < value_sz) 2957 0 stevel return (EFAULT); 2958 0 stevel 2959 0 stevel switch (type) { 2960 0 stevel case DATA_TYPE_NVLIST: 2961 0 stevel if (nvs_embedded(nvs, (void *)buf) == 0) 2962 0 stevel return (0); 2963 0 stevel break; 2964 0 stevel 2965 0 stevel case DATA_TYPE_NVLIST_ARRAY: 2966 0 stevel if (nvs_embedded_nvl_array(nvs, nvp, NULL) == 0) 2967 0 stevel return (0); 2968 0 stevel break; 2969 0 stevel 2970 0 stevel case DATA_TYPE_BOOLEAN: 2971 0 stevel ret = TRUE; 2972 0 stevel break; 2973 0 stevel 2974 0 stevel case DATA_TYPE_BYTE: 2975 0 stevel case DATA_TYPE_INT8: 2976 0 stevel case DATA_TYPE_UINT8: 2977 0 stevel ret = xdr_char(xdr, buf); 2978 0 stevel break; 2979 0 stevel 2980 0 stevel case DATA_TYPE_INT16: 2981 0 stevel ret = xdr_short(xdr, (void *)buf); 2982 0 stevel break; 2983 0 stevel 2984 0 stevel case DATA_TYPE_UINT16: 2985 0 stevel ret = xdr_u_short(xdr, (void *)buf); 2986 0 stevel break; 2987 0 stevel 2988 0 stevel case DATA_TYPE_BOOLEAN_VALUE: 2989 0 stevel case DATA_TYPE_INT32: 2990 0 stevel ret = xdr_int(xdr, (void *)buf); 2991 0 stevel break; 2992 0 stevel 2993 0 stevel case DATA_TYPE_UINT32: 2994 0 stevel ret = xdr_u_int(xdr, (void *)buf); 2995 0 stevel break; 2996 0 stevel 2997 0 stevel case DATA_TYPE_INT64: 2998 0 stevel ret = xdr_longlong_t(xdr, (void *)buf); 2999 0 stevel break; 3000 0 stevel 3001 0 stevel case DATA_TYPE_UINT64: 3002 0 stevel ret = xdr_u_longlong_t(xdr, (void *)buf); 3003 0 stevel break; 3004 0 stevel 3005 0 stevel case DATA_TYPE_HRTIME: 3006 0 stevel /* 3007 0 stevel * NOTE: must expose the definition of hrtime_t here 3008 0 stevel */ 3009 0 stevel ret = xdr_longlong_t(xdr, (void *)buf); 3010 0 stevel break; 3011 7243 robj #if !defined(_KERNEL) 3012 7243 robj case DATA_TYPE_DOUBLE: 3013 7243 robj ret = xdr_double(xdr, (void *)buf); 3014 7243 robj break; 3015 7243 robj #endif 3016 0 stevel case DATA_TYPE_STRING: 3017 0 stevel ret = xdr_string(xdr, &buf, buflen - 1); 3018 0 stevel break; 3019 0 stevel 3020 0 stevel case DATA_TYPE_BYTE_ARRAY: 3021 0 stevel ret = xdr_opaque(xdr, buf, nelem); 3022 0 stevel break; 3023 0 stevel 3024 0 stevel case DATA_TYPE_INT8_ARRAY: 3025 0 stevel case DATA_TYPE_UINT8_ARRAY: 3026 0 stevel ret = xdr_array(xdr, &buf, &nelem, buflen, sizeof (int8_t), 3027 0 stevel (xdrproc_t)xdr_char); 3028 0 stevel break; 3029 0 stevel 3030 0 stevel case DATA_TYPE_INT16_ARRAY: 3031 0 stevel ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int16_t), 3032 0 stevel sizeof (int16_t), (xdrproc_t)xdr_short); 3033 0 stevel break; 3034 0 stevel 3035 0 stevel case DATA_TYPE_UINT16_ARRAY: 3036 0 stevel ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint16_t), 3037 0 stevel sizeof (uint16_t), (xdrproc_t)xdr_u_short); 3038 0 stevel break; 3039 0 stevel 3040 0 stevel case DATA_TYPE_BOOLEAN_ARRAY: 3041 0 stevel case DATA_TYPE_INT32_ARRAY: 3042 0 stevel ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int32_t), 3043 0 stevel sizeof (int32_t), (xdrproc_t)xdr_int); 3044 0 stevel break; 3045 0 stevel 3046 0 stevel case DATA_TYPE_UINT32_ARRAY: 3047 0 stevel ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint32_t), 3048 0 stevel sizeof (uint32_t), (xdrproc_t)xdr_u_int); 3049 0 stevel break; 3050 0 stevel 3051 0 stevel case DATA_TYPE_INT64_ARRAY: 3052 0 stevel ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (int64_t), 3053 0 stevel sizeof (int64_t), (xdrproc_t)xdr_longlong_t); 3054 0 stevel break; 3055 0 stevel 3056 0 stevel case DATA_TYPE_UINT64_ARRAY: 3057 0 stevel ret = xdr_array(xdr, &buf, &nelem, buflen / sizeof (uint64_t), 3058 0 stevel sizeof (uint64_t), (xdrproc_t)xdr_u_longlong_t); 3059 0 stevel break; 3060 0 stevel 3061 0 stevel case DATA_TYPE_STRING_ARRAY: { 3062 0 stevel size_t len = nelem * sizeof (uint64_t); 3063 0 stevel char **strp = (void *)buf; 3064 0 stevel int i; 3065 0 stevel 3066 0 stevel if (nvs->nvs_op == NVS_OP_DECODE) 3067 0 stevel bzero(buf, len); /* don't trust packed data */ 3068 0 stevel 3069 0 stevel for (i = 0; i < nelem; i++) { 3070 0 stevel if (buflen <= len) 3071 0 stevel return (EFAULT); 3072 0 stevel 3073 0 stevel buf += len; 3074 0 stevel buflen -= len; 3075 0 stevel 3076 0 stevel if (xdr_string(xdr, &buf, buflen - 1) != TRUE) 3077 0 stevel return (EFAULT); 3078 0 stevel 3079 0 stevel if (nvs->nvs_op == NVS_OP_DECODE) 3080 0 stevel strp[i] = buf; 3081 0 stevel len = strlen(buf) + 1; 3082 0 stevel } 3083 0 stevel ret = TRUE; 3084 0 stevel break; 3085 0 stevel } 3086 0 stevel default: 3087 0 stevel break; 3088 0 stevel } 3089 0 stevel 3090 0 stevel return (ret == TRUE ? 0 : EFAULT); 3091 0 stevel } 3092 0 stevel 3093 0 stevel static int 3094 0 stevel nvs_xdr_nvp_size(nvstream_t *nvs, nvpair_t *nvp, size_t *size) 3095 0 stevel { 3096 0 stevel data_type_t type = NVP_TYPE(nvp); 3097 0 stevel /* 3098 0 stevel * encode_size + decode_size + name string size + data type + nelem 3099 0 stevel * where name string size = 4 + NV_ALIGN4(strlen(NVP_NAME(nvp))) 3100 0 stevel */ 3101 0 stevel uint64_t nvp_sz = 4 + 4 + 4 + NV_ALIGN4(strlen(NVP_NAME(nvp))) + 4 + 4; 3102 0 stevel 3103 0 stevel switch (type) { 3104 0 stevel case DATA_TYPE_BOOLEAN: 3105 0 stevel break; 3106 0 stevel 3107 0 stevel case DATA_TYPE_BOOLEAN_VALUE: 3108 0 stevel case DATA_TYPE_BYTE: 3109 0 stevel case DATA_TYPE_INT8: 3110 0 stevel case DATA_TYPE_UINT8: 3111 0 stevel case DATA_TYPE_INT16: 3112 0 stevel case DATA_TYPE_UINT16: 3113 0 stevel case DATA_TYPE_INT32: 3114 0 stevel case DATA_TYPE_UINT32: 3115 0 stevel nvp_sz += 4; /* 4 is the minimum xdr unit */ 3116 0 stevel break; 3117 0 stevel 3118 0 stevel case DATA_TYPE_INT64: 3119 0 stevel case DATA_TYPE_UINT64: 3120 0 stevel case DATA_TYPE_HRTIME: 3121 7243 robj #if !defined(_KERNEL) 3122 7243 robj case DATA_TYPE_DOUBLE: 3123 7243 robj #endif 3124 0 stevel nvp_sz += 8; 3125 0 stevel break; 3126 0 stevel 3127 0 stevel case DATA_TYPE_STRING: 3128 0 stevel nvp_sz += 4 + NV_ALIGN4(strlen((char *)NVP_VALUE(nvp))); 3129 0 stevel break; 3130 0 stevel 3131 0 stevel case DATA_TYPE_BYTE_ARRAY: 3132 0 stevel nvp_sz += NV_ALIGN4(NVP_NELEM(nvp)); 3133 0 stevel break; 3134 0 stevel 3135 0 stevel case DATA_TYPE_BOOLEAN_ARRAY: 3136 0 stevel case DATA_TYPE_INT8_ARRAY: 3137 0 stevel case DATA_TYPE_UINT8_ARRAY: 3138 0 stevel case DATA_TYPE_INT16_ARRAY: 3139 0 stevel case DATA_TYPE_UINT16_ARRAY: 3140 0 stevel case DATA_TYPE_INT32_ARRAY: 3141 0 stevel case DATA_TYPE_UINT32_ARRAY: 3142 0 stevel nvp_sz += 4 + 4 * (uint64_t)NVP_NELEM(nvp); 3143 0 stevel break; 3144 0 stevel 3145 0 stevel case DATA_TYPE_INT64_ARRAY: 3146 0 stevel case DATA_TYPE_UINT64_ARRAY: 3147 0 stevel nvp_sz += 4 + 8 * (uint64_t)NVP_NELEM(nvp); 3148 0