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