1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2009-2013 The FreeBSD Foundation
5 * Copyright (c) 2013-2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
6 * All rights reserved.
7 *
8 * This software was developed by Pawel Jakub Dawidek under sponsorship from
9 * the FreeBSD Foundation.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include <sys/param.h>
37 #include <sys/endian.h>
38 #include <sys/queue.h>
39
40 #ifdef _KERNEL
41
42 #include <sys/errno.h>
43 #include <sys/kernel.h>
44 #include <sys/lock.h>
45 #include <sys/malloc.h>
46 #include <sys/systm.h>
47
48 #include <machine/stdarg.h>
49
50 #else
51 #include <sys/socket.h>
52
53 #include <errno.h>
54 #include <stdarg.h>
55 #include <stdbool.h>
56 #include <stdint.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <unistd.h>
61
62 #include "msgio.h"
63 #endif
64
65 #ifdef HAVE_PJDLOG
66 #include <pjdlog.h>
67 #endif
68
69 #include <sys/nv.h>
70
71 #include "nv_impl.h"
72 #include "nvlist_impl.h"
73 #include "nvpair_impl.h"
74
75 #ifndef HAVE_PJDLOG
76 #ifdef _KERNEL
77 #define PJDLOG_ASSERT(...) MPASS(__VA_ARGS__)
78 #define PJDLOG_RASSERT(expr, ...) KASSERT(expr, (__VA_ARGS__))
79 #define PJDLOG_ABORT(...) panic(__VA_ARGS__)
80 #else
81 #include <assert.h>
82 #define PJDLOG_ASSERT(...) assert(__VA_ARGS__)
83 #define PJDLOG_RASSERT(expr, ...) assert(expr)
84 #define PJDLOG_ABORT(...) do { \
85 fprintf(stderr, "%s:%u: ", __FILE__, __LINE__); \
86 fprintf(stderr, __VA_ARGS__); \
87 fprintf(stderr, "\n"); \
88 abort(); \
89 } while (0)
90 #endif
91 #endif
92
93 #define NV_FLAG_PRIVATE_MASK (NV_FLAG_BIG_ENDIAN | NV_FLAG_IN_ARRAY)
94 #define NV_FLAG_PUBLIC_MASK (NV_FLAG_IGNORE_CASE | NV_FLAG_NO_UNIQUE)
95 #define NV_FLAG_ALL_MASK (NV_FLAG_PRIVATE_MASK | NV_FLAG_PUBLIC_MASK)
96
97 #define NVLIST_MAGIC 0x6e766c /* "nvl" */
98 struct nvlist {
99 int nvl_magic;
100 int nvl_error;
101 int nvl_flags;
102 size_t nvl_datasize;
103 nvpair_t *nvl_parent;
104 nvpair_t *nvl_array_next;
105 struct nvl_head nvl_head;
106 };
107
108 #define NVLIST_ASSERT(nvl) do { \
109 PJDLOG_ASSERT((nvl) != NULL); \
110 PJDLOG_ASSERT((nvl)->nvl_magic == NVLIST_MAGIC); \
111 } while (0)
112
113 #ifdef _KERNEL
114 MALLOC_DEFINE(M_NVLIST, "nvlist", "kernel nvlist");
115 #endif
116
117 #define NVPAIR_ASSERT(nvp) nvpair_assert(nvp)
118
119 #define NVLIST_HEADER_MAGIC 0x6c
120 #define NVLIST_HEADER_VERSION 0x00
121
122 nvlist_t *
nvlist_create(int flags)123 nvlist_create(int flags)
124 {
125 nvlist_t *nvl;
126
127 PJDLOG_ASSERT((flags & ~(NV_FLAG_PUBLIC_MASK)) == 0);
128
129 nvl = nv_malloc(sizeof(*nvl));
130 if (nvl == NULL)
131 return (NULL);
132 nvl->nvl_error = 0;
133 nvl->nvl_flags = flags;
134 nvl->nvl_parent = NULL;
135 nvl->nvl_array_next = NULL;
136 nvl->nvl_datasize = sizeof(struct nvlist_header);
137 TAILQ_INIT(&nvl->nvl_head);
138 nvl->nvl_magic = NVLIST_MAGIC;
139
140 return (nvl);
141 }
142
143 void
nvlist_destroy(nvlist_t * nvl)144 nvlist_destroy(nvlist_t *nvl)
145 {
146 nvpair_t *nvp;
147
148 if (nvl == NULL)
149 return;
150
151 ERRNO_SAVE();
152
153 NVLIST_ASSERT(nvl);
154
155 while ((nvp = nvlist_first_nvpair(nvl)) != NULL) {
156 nvlist_remove_nvpair(nvl, nvp);
157 nvpair_free(nvp);
158 }
159 if (nvl->nvl_array_next != NULL)
160 nvpair_free_structure(nvl->nvl_array_next);
161 nvl->nvl_array_next = NULL;
162 nvl->nvl_parent = NULL;
163 nvl->nvl_magic = 0;
164 nv_free(nvl);
165
166 ERRNO_RESTORE();
167 }
168
169 void
nvlist_set_error(nvlist_t * nvl,int error)170 nvlist_set_error(nvlist_t *nvl, int error)
171 {
172
173 PJDLOG_ASSERT(error != 0);
174
175 /*
176 * Check for error != 0 so that we don't do the wrong thing if somebody
177 * tries to abuse this API when asserts are disabled.
178 */
179 if (nvl != NULL && error != 0 && nvl->nvl_error == 0)
180 nvl->nvl_error = error;
181 }
182
183 int
nvlist_error(const nvlist_t * nvl)184 nvlist_error(const nvlist_t *nvl)
185 {
186
187 if (nvl == NULL)
188 return (ENOMEM);
189
190 NVLIST_ASSERT(nvl);
191
192 return (nvl->nvl_error);
193 }
194
195 nvpair_t *
nvlist_get_nvpair_parent(const nvlist_t * nvl)196 nvlist_get_nvpair_parent(const nvlist_t *nvl)
197 {
198
199 NVLIST_ASSERT(nvl);
200
201 return (nvl->nvl_parent);
202 }
203
204 const nvlist_t *
nvlist_get_parent(const nvlist_t * nvl,void ** cookiep)205 nvlist_get_parent(const nvlist_t *nvl, void **cookiep)
206 {
207 nvpair_t *nvp;
208
209 NVLIST_ASSERT(nvl);
210
211 nvp = nvl->nvl_parent;
212 if (cookiep != NULL)
213 *cookiep = nvp;
214 if (nvp == NULL)
215 return (NULL);
216
217 return (nvpair_nvlist(nvp));
218 }
219
220 void
nvlist_set_parent(nvlist_t * nvl,nvpair_t * parent)221 nvlist_set_parent(nvlist_t *nvl, nvpair_t *parent)
222 {
223
224 NVLIST_ASSERT(nvl);
225
226 nvl->nvl_parent = parent;
227 }
228
229 void
nvlist_set_array_next(nvlist_t * nvl,nvpair_t * ele)230 nvlist_set_array_next(nvlist_t *nvl, nvpair_t *ele)
231 {
232
233 NVLIST_ASSERT(nvl);
234
235 if (ele != NULL) {
236 nvl->nvl_flags |= NV_FLAG_IN_ARRAY;
237 } else {
238 nvl->nvl_flags &= ~NV_FLAG_IN_ARRAY;
239 nv_free(nvl->nvl_array_next);
240 }
241
242 nvl->nvl_array_next = ele;
243 }
244
245 static void
nvlist_update_size(nvlist_t * nvl,nvpair_t * new,ssize_t mul)246 nvlist_update_size(nvlist_t *nvl, nvpair_t *new, ssize_t mul)
247 {
248 ssize_t size;
249 size_t nitems;
250 const nvlist_t *nvlistnew;
251 const nvlist_t * const *nvlarray;
252 nvlist_t *parent;
253 unsigned int ii;
254
255 NVLIST_ASSERT(nvl);
256 NVPAIR_ASSERT(new);
257 PJDLOG_ASSERT(mul == 1 || mul == -1);
258
259 size = nvpair_header_size();
260 size += strlen(nvpair_name(new)) + 1;
261
262 if (nvpair_type(new) == NV_TYPE_NVLIST) {
263 nvlistnew = nvpair_get_nvlist(new);
264 size += nvlistnew->nvl_datasize;
265 size += nvpair_header_size() + 1;
266 } else if (nvpair_type(new) == NV_TYPE_NVLIST_ARRAY) {
267 nvlarray = nvpair_get_nvlist_array(new, &nitems);
268 PJDLOG_ASSERT(nitems > 0);
269
270 size += (nvpair_header_size() + 1) * nitems;
271 for (ii = 0; ii < nitems; ii++) {
272 PJDLOG_ASSERT(nvlarray[ii]->nvl_error == 0);
273 size += nvlarray[ii]->nvl_datasize;
274 }
275 } else {
276 size += nvpair_size(new);
277 }
278
279 size *= mul;
280
281 nvl->nvl_datasize += size;
282
283 parent = nvl;
284 while ((parent = __DECONST(nvlist_t *,
285 nvlist_get_parent(parent, NULL))) != NULL) {
286 parent->nvl_datasize += size;
287 }
288 }
289
290 nvpair_t *
nvlist_get_array_next_nvpair(nvlist_t * nvl)291 nvlist_get_array_next_nvpair(nvlist_t *nvl)
292 {
293
294 NVLIST_ASSERT(nvl);
295
296 return (nvl->nvl_array_next);
297 }
298
299 bool
nvlist_in_array(const nvlist_t * nvl)300 nvlist_in_array(const nvlist_t *nvl)
301 {
302
303 NVLIST_ASSERT(nvl);
304
305 return ((nvl->nvl_flags & NV_FLAG_IN_ARRAY) != 0);
306 }
307
308 const nvlist_t *
nvlist_get_array_next(const nvlist_t * nvl)309 nvlist_get_array_next(const nvlist_t *nvl)
310 {
311 nvpair_t *nvp;
312
313 NVLIST_ASSERT(nvl);
314
315 nvp = nvl->nvl_array_next;
316 if (nvp == NULL)
317 return (NULL);
318
319 return (nvpair_get_nvlist(nvp));
320 }
321
322 const nvlist_t *
nvlist_get_pararr(const nvlist_t * nvl,void ** cookiep)323 nvlist_get_pararr(const nvlist_t *nvl, void **cookiep)
324 {
325 const nvlist_t *ret;
326
327 ret = nvlist_get_array_next(nvl);
328 if (ret != NULL) {
329 if (cookiep != NULL)
330 *cookiep = NULL;
331 return (ret);
332 }
333
334 return (nvlist_get_parent(nvl, cookiep));
335 }
336
337 bool
nvlist_empty(const nvlist_t * nvl)338 nvlist_empty(const nvlist_t *nvl)
339 {
340
341 NVLIST_ASSERT(nvl);
342 PJDLOG_ASSERT(nvl->nvl_error == 0);
343
344 return (nvlist_first_nvpair(nvl) == NULL);
345 }
346
347 int
nvlist_flags(const nvlist_t * nvl)348 nvlist_flags(const nvlist_t *nvl)
349 {
350
351 NVLIST_ASSERT(nvl);
352 PJDLOG_ASSERT(nvl->nvl_error == 0);
353
354 return (nvl->nvl_flags & NV_FLAG_PUBLIC_MASK);
355 }
356
357 void
nvlist_set_flags(nvlist_t * nvl,int flags)358 nvlist_set_flags(nvlist_t *nvl, int flags)
359 {
360
361 NVLIST_ASSERT(nvl);
362 PJDLOG_ASSERT(nvl->nvl_error == 0);
363
364 nvl->nvl_flags = flags;
365 }
366
367 void
nvlist_report_missing(int type,const char * name)368 nvlist_report_missing(int type, const char *name)
369 {
370
371 PJDLOG_ABORT("Element '%s' of type %s doesn't exist.",
372 name, nvpair_type_string(type));
373 }
374
375 static nvpair_t *
nvlist_find(const nvlist_t * nvl,int type,const char * name)376 nvlist_find(const nvlist_t *nvl, int type, const char *name)
377 {
378 nvpair_t *nvp;
379
380 NVLIST_ASSERT(nvl);
381 PJDLOG_ASSERT(nvl->nvl_error == 0);
382 PJDLOG_ASSERT(type == NV_TYPE_NONE ||
383 (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
384
385 for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
386 nvp = nvlist_next_nvpair(nvl, nvp)) {
387 if (type != NV_TYPE_NONE && nvpair_type(nvp) != type)
388 continue;
389 if ((nvl->nvl_flags & NV_FLAG_IGNORE_CASE) != 0) {
390 if (strcasecmp(nvpair_name(nvp), name) != 0)
391 continue;
392 } else {
393 if (strcmp(nvpair_name(nvp), name) != 0)
394 continue;
395 }
396 break;
397 }
398
399 if (nvp == NULL)
400 ERRNO_SET(ENOENT);
401
402 return (nvp);
403 }
404
405 bool
nvlist_exists_type(const nvlist_t * nvl,const char * name,int type)406 nvlist_exists_type(const nvlist_t *nvl, const char *name, int type)
407 {
408
409 NVLIST_ASSERT(nvl);
410 PJDLOG_ASSERT(nvl->nvl_error == 0);
411 PJDLOG_ASSERT(type == NV_TYPE_NONE ||
412 (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
413
414 return (nvlist_find(nvl, type, name) != NULL);
415 }
416
417 void
nvlist_free_type(nvlist_t * nvl,const char * name,int type)418 nvlist_free_type(nvlist_t *nvl, const char *name, int type)
419 {
420 nvpair_t *nvp;
421
422 NVLIST_ASSERT(nvl);
423 PJDLOG_ASSERT(nvl->nvl_error == 0);
424 PJDLOG_ASSERT(type == NV_TYPE_NONE ||
425 (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
426
427 nvp = nvlist_find(nvl, type, name);
428 if (nvp != NULL)
429 nvlist_free_nvpair(nvl, nvp);
430 else
431 nvlist_report_missing(type, name);
432 }
433
434 nvlist_t *
nvlist_clone(const nvlist_t * nvl)435 nvlist_clone(const nvlist_t *nvl)
436 {
437 nvlist_t *newnvl;
438 nvpair_t *nvp, *newnvp;
439
440 NVLIST_ASSERT(nvl);
441
442 if (nvl->nvl_error != 0) {
443 ERRNO_SET(nvl->nvl_error);
444 return (NULL);
445 }
446
447 newnvl = nvlist_create(nvl->nvl_flags & NV_FLAG_PUBLIC_MASK);
448 for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
449 nvp = nvlist_next_nvpair(nvl, nvp)) {
450 newnvp = nvpair_clone(nvp);
451 if (newnvp == NULL)
452 break;
453 (void)nvlist_move_nvpair(newnvl, newnvp);
454 }
455 if (nvp != NULL) {
456 nvlist_destroy(newnvl);
457 return (NULL);
458 }
459 return (newnvl);
460 }
461
462 #ifndef _KERNEL
463 static bool
nvlist_dump_error_check(const nvlist_t * nvl,int fd,int level)464 nvlist_dump_error_check(const nvlist_t *nvl, int fd, int level)
465 {
466
467 if (nvlist_error(nvl) != 0) {
468 dprintf(fd, "%*serror: %d\n", level * 4, "",
469 nvlist_error(nvl));
470 return (true);
471 }
472
473 return (false);
474 }
475
476 /*
477 * Dump content of nvlist.
478 */
479 void
nvlist_dump(const nvlist_t * nvl,int fd)480 nvlist_dump(const nvlist_t *nvl, int fd)
481 {
482 const nvlist_t *tmpnvl;
483 nvpair_t *nvp, *tmpnvp;
484 void *cookie;
485 int level;
486
487 level = 0;
488 if (nvlist_dump_error_check(nvl, fd, level))
489 return;
490
491 nvp = nvlist_first_nvpair(nvl);
492 while (nvp != NULL) {
493 dprintf(fd, "%*s%s (%s):", level * 4, "", nvpair_name(nvp),
494 nvpair_type_string(nvpair_type(nvp)));
495 switch (nvpair_type(nvp)) {
496 case NV_TYPE_NULL:
497 dprintf(fd, " null\n");
498 break;
499 case NV_TYPE_BOOL:
500 dprintf(fd, " %s\n", nvpair_get_bool(nvp) ?
501 "TRUE" : "FALSE");
502 break;
503 case NV_TYPE_NUMBER:
504 dprintf(fd, " %ju (%jd) (0x%jx)\n",
505 (uintmax_t)nvpair_get_number(nvp),
506 (intmax_t)nvpair_get_number(nvp),
507 (uintmax_t)nvpair_get_number(nvp));
508 break;
509 case NV_TYPE_STRING:
510 dprintf(fd, " [%s]\n", nvpair_get_string(nvp));
511 break;
512 case NV_TYPE_NVLIST:
513 dprintf(fd, "\n");
514 tmpnvl = nvpair_get_nvlist(nvp);
515 if (nvlist_dump_error_check(tmpnvl, fd, level + 1))
516 break;
517 tmpnvp = nvlist_first_nvpair(tmpnvl);
518 if (tmpnvp != NULL) {
519 nvl = tmpnvl;
520 nvp = tmpnvp;
521 level++;
522 continue;
523 }
524 break;
525 case NV_TYPE_DESCRIPTOR:
526 dprintf(fd, " %d\n", nvpair_get_descriptor(nvp));
527 break;
528 case NV_TYPE_BINARY:
529 {
530 const unsigned char *binary;
531 unsigned int ii;
532 size_t size;
533
534 binary = nvpair_get_binary(nvp, &size);
535 dprintf(fd, " %zu ", size);
536 for (ii = 0; ii < size; ii++)
537 dprintf(fd, "%02hhx", binary[ii]);
538 dprintf(fd, "\n");
539 break;
540 }
541 case NV_TYPE_BOOL_ARRAY:
542 {
543 const bool *value;
544 unsigned int ii;
545 size_t nitems;
546
547 value = nvpair_get_bool_array(nvp, &nitems);
548 dprintf(fd, " [ ");
549 for (ii = 0; ii < nitems; ii++) {
550 dprintf(fd, "%s", value[ii] ? "TRUE" : "FALSE");
551 if (ii != nitems - 1)
552 dprintf(fd, ", ");
553 }
554 dprintf(fd, " ]\n");
555 break;
556 }
557 case NV_TYPE_STRING_ARRAY:
558 {
559 const char * const *value;
560 unsigned int ii;
561 size_t nitems;
562
563 value = nvpair_get_string_array(nvp, &nitems);
564 dprintf(fd, " [ ");
565 for (ii = 0; ii < nitems; ii++) {
566 if (value[ii] == NULL)
567 dprintf(fd, "NULL");
568 else
569 dprintf(fd, "\"%s\"", value[ii]);
570 if (ii != nitems - 1)
571 dprintf(fd, ", ");
572 }
573 dprintf(fd, " ]\n");
574 break;
575 }
576 case NV_TYPE_NUMBER_ARRAY:
577 {
578 const uint64_t *value;
579 unsigned int ii;
580 size_t nitems;
581
582 value = nvpair_get_number_array(nvp, &nitems);
583 dprintf(fd, " [ ");
584 for (ii = 0; ii < nitems; ii++) {
585 dprintf(fd, "%ju (%jd) (0x%jx)",
586 value[ii], value[ii], value[ii]);
587 if (ii != nitems - 1)
588 dprintf(fd, ", ");
589 }
590 dprintf(fd, " ]\n");
591 break;
592 }
593 case NV_TYPE_DESCRIPTOR_ARRAY:
594 {
595 const int *value;
596 unsigned int ii;
597 size_t nitems;
598
599 value = nvpair_get_descriptor_array(nvp, &nitems);
600 dprintf(fd, " [ ");
601 for (ii = 0; ii < nitems; ii++) {
602 dprintf(fd, "%d", value[ii]);
603 if (ii != nitems - 1)
604 dprintf(fd, ", ");
605 }
606 dprintf(fd, " ]\n");
607 break;
608 }
609 case NV_TYPE_NVLIST_ARRAY:
610 {
611 const nvlist_t * const *value;
612 unsigned int ii;
613 size_t nitems;
614
615 value = nvpair_get_nvlist_array(nvp, &nitems);
616 dprintf(fd, " %zu\n", nitems);
617 tmpnvl = NULL;
618 tmpnvp = NULL;
619 for (ii = 0; ii < nitems; ii++) {
620 if (nvlist_dump_error_check(value[ii], fd,
621 level + 1)) {
622 break;
623 }
624
625 if (tmpnvl == NULL) {
626 tmpnvp = nvlist_first_nvpair(value[ii]);
627 if (tmpnvp != NULL) {
628 tmpnvl = value[ii];
629 } else {
630 dprintf(fd, "%*s,\n",
631 (level + 1) * 4, "");
632 }
633 }
634 }
635 if (tmpnvp != NULL) {
636 nvl = tmpnvl;
637 nvp = tmpnvp;
638 level++;
639 continue;
640 }
641 break;
642 }
643 default:
644 PJDLOG_ABORT("Unknown type: %d.", nvpair_type(nvp));
645 }
646
647 while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
648 do {
649 cookie = NULL;
650 if (nvlist_in_array(nvl))
651 dprintf(fd, "%*s,\n", level * 4, "");
652 nvl = nvlist_get_pararr(nvl, &cookie);
653 if (nvl == NULL)
654 return;
655 if (nvlist_in_array(nvl) && cookie == NULL) {
656 nvp = nvlist_first_nvpair(nvl);
657 } else {
658 nvp = cookie;
659 level--;
660 }
661 } while (nvp == NULL);
662 if (nvlist_in_array(nvl) && cookie == NULL)
663 break;
664 }
665 }
666 }
667
668 void
nvlist_fdump(const nvlist_t * nvl,FILE * fp)669 nvlist_fdump(const nvlist_t *nvl, FILE *fp)
670 {
671
672 fflush(fp);
673 nvlist_dump(nvl, fileno(fp));
674 }
675 #endif
676
677 /*
678 * The function obtains size of the nvlist after nvlist_pack().
679 */
680 size_t
nvlist_size(const nvlist_t * nvl)681 nvlist_size(const nvlist_t *nvl)
682 {
683
684 return (nvl->nvl_datasize);
685 }
686
687 #ifndef _KERNEL
688 static int *
nvlist_xdescriptors(const nvlist_t * nvl,int * descs)689 nvlist_xdescriptors(const nvlist_t *nvl, int *descs)
690 {
691 void *cookie;
692 nvpair_t *nvp;
693 int type;
694
695 NVLIST_ASSERT(nvl);
696 PJDLOG_ASSERT(nvl->nvl_error == 0);
697
698 cookie = NULL;
699 do {
700 while (nvlist_next(nvl, &type, &cookie) != NULL) {
701 nvp = cookie;
702 switch (type) {
703 case NV_TYPE_DESCRIPTOR:
704 *descs = nvpair_get_descriptor(nvp);
705 descs++;
706 break;
707 case NV_TYPE_DESCRIPTOR_ARRAY:
708 {
709 const int *value;
710 size_t nitems;
711 unsigned int ii;
712
713 value = nvpair_get_descriptor_array(nvp,
714 &nitems);
715 for (ii = 0; ii < nitems; ii++) {
716 *descs = value[ii];
717 descs++;
718 }
719 break;
720 }
721 case NV_TYPE_NVLIST:
722 nvl = nvpair_get_nvlist(nvp);
723 cookie = NULL;
724 break;
725 case NV_TYPE_NVLIST_ARRAY:
726 {
727 const nvlist_t * const *value;
728 size_t nitems;
729
730 value = nvpair_get_nvlist_array(nvp, &nitems);
731 PJDLOG_ASSERT(value != NULL);
732 PJDLOG_ASSERT(nitems > 0);
733
734 nvl = value[0];
735 cookie = NULL;
736 break;
737 }
738 }
739 }
740 } while ((nvl = nvlist_get_pararr(nvl, &cookie)) != NULL);
741
742 return (descs);
743 }
744 #endif
745
746 #ifndef _KERNEL
747 int *
nvlist_descriptors(const nvlist_t * nvl,size_t * nitemsp)748 nvlist_descriptors(const nvlist_t *nvl, size_t *nitemsp)
749 {
750 size_t nitems;
751 int *fds;
752
753 nitems = nvlist_ndescriptors(nvl);
754 fds = nv_calloc(nitems + 1, sizeof(fds[0]));
755 if (fds == NULL)
756 return (NULL);
757 if (nitems > 0)
758 nvlist_xdescriptors(nvl, fds);
759 fds[nitems] = -1;
760 if (nitemsp != NULL)
761 *nitemsp = nitems;
762 return (fds);
763 }
764 #endif
765
766 size_t
nvlist_ndescriptors(const nvlist_t * nvl)767 nvlist_ndescriptors(const nvlist_t *nvl)
768 {
769 #ifndef _KERNEL
770 void *cookie;
771 nvpair_t *nvp;
772 size_t ndescs;
773 int type;
774
775 NVLIST_ASSERT(nvl);
776 PJDLOG_ASSERT(nvl->nvl_error == 0);
777
778 ndescs = 0;
779 cookie = NULL;
780 do {
781 while (nvlist_next(nvl, &type, &cookie) != NULL) {
782 nvp = cookie;
783 switch (type) {
784 case NV_TYPE_DESCRIPTOR:
785 ndescs++;
786 break;
787 case NV_TYPE_NVLIST:
788 nvl = nvpair_get_nvlist(nvp);
789 cookie = NULL;
790 break;
791 case NV_TYPE_NVLIST_ARRAY:
792 {
793 const nvlist_t * const *value;
794 size_t nitems;
795
796 value = nvpair_get_nvlist_array(nvp, &nitems);
797 PJDLOG_ASSERT(value != NULL);
798 PJDLOG_ASSERT(nitems > 0);
799
800 nvl = value[0];
801 cookie = NULL;
802 break;
803 }
804 case NV_TYPE_DESCRIPTOR_ARRAY:
805 {
806 size_t nitems;
807
808 (void)nvpair_get_descriptor_array(nvp,
809 &nitems);
810 ndescs += nitems;
811 break;
812 }
813 }
814 }
815 } while ((nvl = nvlist_get_pararr(nvl, &cookie)) != NULL);
816
817 return (ndescs);
818 #else
819 return (0);
820 #endif
821 }
822
823 static unsigned char *
nvlist_pack_header(const nvlist_t * nvl,unsigned char * ptr,size_t * leftp)824 nvlist_pack_header(const nvlist_t *nvl, unsigned char *ptr, size_t *leftp)
825 {
826 struct nvlist_header nvlhdr;
827
828 NVLIST_ASSERT(nvl);
829
830 nvlhdr.nvlh_magic = NVLIST_HEADER_MAGIC;
831 nvlhdr.nvlh_version = NVLIST_HEADER_VERSION;
832 nvlhdr.nvlh_flags = nvl->nvl_flags;
833 #if BYTE_ORDER == BIG_ENDIAN
834 nvlhdr.nvlh_flags |= NV_FLAG_BIG_ENDIAN;
835 #endif
836 nvlhdr.nvlh_descriptors = nvlist_ndescriptors(nvl);
837 nvlhdr.nvlh_size = *leftp - sizeof(nvlhdr);
838 PJDLOG_ASSERT(*leftp >= sizeof(nvlhdr));
839 memcpy(ptr, &nvlhdr, sizeof(nvlhdr));
840 ptr += sizeof(nvlhdr);
841 *leftp -= sizeof(nvlhdr);
842
843 return (ptr);
844 }
845
846 static void *
nvlist_xpack(const nvlist_t * nvl,int64_t * fdidxp,size_t * sizep)847 nvlist_xpack(const nvlist_t *nvl, int64_t *fdidxp, size_t *sizep)
848 {
849 unsigned char *buf, *ptr;
850 size_t left, size;
851 const nvlist_t *tmpnvl;
852 nvpair_t *nvp, *tmpnvp;
853 void *cookie;
854
855 NVLIST_ASSERT(nvl);
856
857 if (nvl->nvl_error != 0) {
858 ERRNO_SET(nvl->nvl_error);
859 return (NULL);
860 }
861
862 size = nvlist_size(nvl);
863 buf = nv_malloc(size);
864 if (buf == NULL)
865 return (NULL);
866
867 ptr = buf;
868 left = size;
869
870 ptr = nvlist_pack_header(nvl, ptr, &left);
871
872 nvp = nvlist_first_nvpair(nvl);
873 while (nvp != NULL) {
874 NVPAIR_ASSERT(nvp);
875
876 nvpair_init_datasize(nvp);
877 ptr = nvpair_pack_header(nvp, ptr, &left);
878 if (ptr == NULL)
879 goto fail;
880 switch (nvpair_type(nvp)) {
881 case NV_TYPE_NULL:
882 ptr = nvpair_pack_null(nvp, ptr, &left);
883 break;
884 case NV_TYPE_BOOL:
885 ptr = nvpair_pack_bool(nvp, ptr, &left);
886 break;
887 case NV_TYPE_NUMBER:
888 ptr = nvpair_pack_number(nvp, ptr, &left);
889 break;
890 case NV_TYPE_STRING:
891 ptr = nvpair_pack_string(nvp, ptr, &left);
892 break;
893 case NV_TYPE_NVLIST:
894 tmpnvl = nvpair_get_nvlist(nvp);
895 ptr = nvlist_pack_header(tmpnvl, ptr, &left);
896 if (ptr == NULL)
897 goto fail;
898 tmpnvp = nvlist_first_nvpair(tmpnvl);
899 if (tmpnvp != NULL) {
900 nvl = tmpnvl;
901 nvp = tmpnvp;
902 continue;
903 }
904 ptr = nvpair_pack_nvlist_up(ptr, &left);
905 break;
906 #ifndef _KERNEL
907 case NV_TYPE_DESCRIPTOR:
908 ptr = nvpair_pack_descriptor(nvp, ptr, fdidxp, &left);
909 break;
910 case NV_TYPE_DESCRIPTOR_ARRAY:
911 ptr = nvpair_pack_descriptor_array(nvp, ptr, fdidxp,
912 &left);
913 break;
914 #endif
915 case NV_TYPE_BINARY:
916 ptr = nvpair_pack_binary(nvp, ptr, &left);
917 break;
918 case NV_TYPE_BOOL_ARRAY:
919 ptr = nvpair_pack_bool_array(nvp, ptr, &left);
920 break;
921 case NV_TYPE_NUMBER_ARRAY:
922 ptr = nvpair_pack_number_array(nvp, ptr, &left);
923 break;
924 case NV_TYPE_STRING_ARRAY:
925 ptr = nvpair_pack_string_array(nvp, ptr, &left);
926 break;
927 case NV_TYPE_NVLIST_ARRAY:
928 {
929 const nvlist_t * const * value;
930 size_t nitems;
931 unsigned int ii;
932
933 tmpnvl = NULL;
934 value = nvpair_get_nvlist_array(nvp, &nitems);
935 for (ii = 0; ii < nitems; ii++) {
936 ptr = nvlist_pack_header(value[ii], ptr, &left);
937 if (ptr == NULL)
938 goto out;
939 tmpnvp = nvlist_first_nvpair(value[ii]);
940 if (tmpnvp != NULL) {
941 tmpnvl = value[ii];
942 break;
943 }
944 ptr = nvpair_pack_nvlist_array_next(ptr, &left);
945 if (ptr == NULL)
946 goto out;
947 }
948 if (tmpnvl != NULL) {
949 nvl = tmpnvl;
950 nvp = tmpnvp;
951 continue;
952 }
953 break;
954 }
955 default:
956 PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp));
957 }
958 if (ptr == NULL)
959 goto fail;
960 while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
961 do {
962 cookie = NULL;
963 if (nvlist_in_array(nvl)) {
964 ptr = nvpair_pack_nvlist_array_next(ptr,
965 &left);
966 if (ptr == NULL)
967 goto fail;
968 }
969 nvl = nvlist_get_pararr(nvl, &cookie);
970 if (nvl == NULL)
971 goto out;
972 if (nvlist_in_array(nvl) && cookie == NULL) {
973 nvp = nvlist_first_nvpair(nvl);
974 ptr = nvlist_pack_header(nvl, ptr,
975 &left);
976 if (ptr == NULL)
977 goto fail;
978 } else if (nvpair_type((nvpair_t *)cookie) !=
979 NV_TYPE_NVLIST_ARRAY) {
980 ptr = nvpair_pack_nvlist_up(ptr, &left);
981 if (ptr == NULL)
982 goto fail;
983 nvp = cookie;
984 } else {
985 nvp = cookie;
986 }
987 } while (nvp == NULL);
988 if (nvlist_in_array(nvl) && cookie == NULL)
989 break;
990 }
991 }
992
993 out:
994 if (sizep != NULL)
995 *sizep = size;
996 return (buf);
997 fail:
998 nv_free(buf);
999 return (NULL);
1000 }
1001
1002 void *
nvlist_pack(const nvlist_t * nvl,size_t * sizep)1003 nvlist_pack(const nvlist_t *nvl, size_t *sizep)
1004 {
1005
1006 NVLIST_ASSERT(nvl);
1007
1008 if (nvl->nvl_error != 0) {
1009 ERRNO_SET(nvl->nvl_error);
1010 return (NULL);
1011 }
1012
1013 if (nvlist_ndescriptors(nvl) > 0) {
1014 ERRNO_SET(EOPNOTSUPP);
1015 return (NULL);
1016 }
1017
1018 return (nvlist_xpack(nvl, NULL, sizep));
1019 }
1020
1021 static bool
nvlist_check_header(struct nvlist_header * nvlhdrp)1022 nvlist_check_header(struct nvlist_header *nvlhdrp)
1023 {
1024
1025 if (nvlhdrp->nvlh_size > SIZE_MAX - sizeof(*nvlhdrp)) {
1026 ERRNO_SET(EINVAL);
1027 return (false);
1028 }
1029 if (nvlhdrp->nvlh_magic != NVLIST_HEADER_MAGIC) {
1030 ERRNO_SET(EINVAL);
1031 return (false);
1032 }
1033 if ((nvlhdrp->nvlh_flags & ~NV_FLAG_ALL_MASK) != 0) {
1034 ERRNO_SET(EINVAL);
1035 return (false);
1036 }
1037 #if BYTE_ORDER == BIG_ENDIAN
1038 if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) == 0) {
1039 nvlhdrp->nvlh_size = le64toh(nvlhdrp->nvlh_size);
1040 nvlhdrp->nvlh_descriptors = le64toh(nvlhdrp->nvlh_descriptors);
1041 }
1042 #else
1043 if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0) {
1044 nvlhdrp->nvlh_size = be64toh(nvlhdrp->nvlh_size);
1045 nvlhdrp->nvlh_descriptors = be64toh(nvlhdrp->nvlh_descriptors);
1046 }
1047 #endif
1048 return (true);
1049 }
1050
1051 const unsigned char *
nvlist_unpack_header(nvlist_t * nvl,const unsigned char * ptr,size_t nfds,bool * isbep,size_t * leftp)1052 nvlist_unpack_header(nvlist_t *nvl, const unsigned char *ptr, size_t nfds,
1053 bool *isbep, size_t *leftp)
1054 {
1055 struct nvlist_header nvlhdr;
1056 int inarrayf;
1057
1058 if (*leftp < sizeof(nvlhdr))
1059 goto fail;
1060
1061 memcpy(&nvlhdr, ptr, sizeof(nvlhdr));
1062
1063 if (!nvlist_check_header(&nvlhdr))
1064 goto fail;
1065
1066 if (nvlhdr.nvlh_size != *leftp - sizeof(nvlhdr))
1067 goto fail;
1068
1069 /*
1070 * nvlh_descriptors might be smaller than nfds in embedded nvlists.
1071 */
1072 if (nvlhdr.nvlh_descriptors > nfds)
1073 goto fail;
1074
1075 if ((nvlhdr.nvlh_flags & ~NV_FLAG_ALL_MASK) != 0)
1076 goto fail;
1077
1078 inarrayf = (nvl->nvl_flags & NV_FLAG_IN_ARRAY);
1079 nvl->nvl_flags = (nvlhdr.nvlh_flags & NV_FLAG_PUBLIC_MASK) | inarrayf;
1080
1081 ptr += sizeof(nvlhdr);
1082 if (isbep != NULL)
1083 *isbep = (((int)nvlhdr.nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0);
1084 *leftp -= sizeof(nvlhdr);
1085
1086 return (ptr);
1087 fail:
1088 ERRNO_SET(EINVAL);
1089 return (NULL);
1090 }
1091
1092 static nvlist_t *
nvlist_xunpack(const void * buf,size_t size,const int * fds,size_t nfds,int flags)1093 nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds,
1094 int flags)
1095 {
1096 const unsigned char *ptr;
1097 nvlist_t *nvl, *retnvl, *tmpnvl, *array;
1098 nvpair_t *nvp;
1099 size_t left;
1100 bool isbe;
1101
1102 PJDLOG_ASSERT((flags & ~(NV_FLAG_PUBLIC_MASK)) == 0);
1103
1104 left = size;
1105 ptr = buf;
1106
1107 tmpnvl = array = NULL;
1108 nvl = retnvl = nvlist_create(0);
1109 if (nvl == NULL)
1110 goto fail;
1111
1112 ptr = nvlist_unpack_header(nvl, ptr, nfds, &isbe, &left);
1113 if (ptr == NULL)
1114 goto fail;
1115 if (nvl->nvl_flags != flags) {
1116 ERRNO_SET(EILSEQ);
1117 goto fail;
1118 }
1119
1120 while (left > 0) {
1121 ptr = nvpair_unpack(isbe, ptr, &left, &nvp);
1122 if (ptr == NULL)
1123 goto fail;
1124 switch (nvpair_type(nvp)) {
1125 case NV_TYPE_NULL:
1126 ptr = nvpair_unpack_null(isbe, nvp, ptr, &left);
1127 break;
1128 case NV_TYPE_BOOL:
1129 ptr = nvpair_unpack_bool(isbe, nvp, ptr, &left);
1130 break;
1131 case NV_TYPE_NUMBER:
1132 ptr = nvpair_unpack_number(isbe, nvp, ptr, &left);
1133 break;
1134 case NV_TYPE_STRING:
1135 ptr = nvpair_unpack_string(isbe, nvp, ptr, &left);
1136 break;
1137 case NV_TYPE_NVLIST:
1138 ptr = nvpair_unpack_nvlist(isbe, nvp, ptr, &left, nfds,
1139 &tmpnvl);
1140 if (tmpnvl == NULL || ptr == NULL)
1141 goto fail;
1142 nvlist_set_parent(tmpnvl, nvp);
1143 break;
1144 #ifndef _KERNEL
1145 case NV_TYPE_DESCRIPTOR:
1146 ptr = nvpair_unpack_descriptor(isbe, nvp, ptr, &left,
1147 fds, nfds);
1148 break;
1149 case NV_TYPE_DESCRIPTOR_ARRAY:
1150 ptr = nvpair_unpack_descriptor_array(isbe, nvp, ptr,
1151 &left, fds, nfds);
1152 break;
1153 #endif
1154 case NV_TYPE_BINARY:
1155 ptr = nvpair_unpack_binary(isbe, nvp, ptr, &left);
1156 break;
1157 case NV_TYPE_NVLIST_UP:
1158 if (nvl->nvl_parent == NULL)
1159 goto fail;
1160 nvl = nvpair_nvlist(nvl->nvl_parent);
1161 nvpair_free_structure(nvp);
1162 continue;
1163 case NV_TYPE_NVLIST_ARRAY_NEXT:
1164 if (nvl->nvl_array_next == NULL) {
1165 if (nvl->nvl_parent == NULL)
1166 goto fail;
1167 nvl = nvpair_nvlist(nvl->nvl_parent);
1168 } else {
1169 nvl = __DECONST(nvlist_t *,
1170 nvlist_get_array_next(nvl));
1171 ptr = nvlist_unpack_header(nvl, ptr, nfds,
1172 &isbe, &left);
1173 if (ptr == NULL)
1174 goto fail;
1175 }
1176 nvpair_free_structure(nvp);
1177 continue;
1178 case NV_TYPE_BOOL_ARRAY:
1179 ptr = nvpair_unpack_bool_array(isbe, nvp, ptr, &left);
1180 break;
1181 case NV_TYPE_NUMBER_ARRAY:
1182 ptr = nvpair_unpack_number_array(isbe, nvp, ptr, &left);
1183 break;
1184 case NV_TYPE_STRING_ARRAY:
1185 ptr = nvpair_unpack_string_array(isbe, nvp, ptr, &left);
1186 break;
1187 case NV_TYPE_NVLIST_ARRAY:
1188 ptr = nvpair_unpack_nvlist_array(isbe, nvp, ptr, &left,
1189 &array);
1190 if (ptr == NULL)
1191 goto fail;
1192 PJDLOG_ASSERT(array != NULL);
1193 tmpnvl = array;
1194 do {
1195 nvlist_set_parent(array, nvp);
1196 array = __DECONST(nvlist_t *,
1197 nvlist_get_array_next(array));
1198 } while (array != NULL);
1199 ptr = nvlist_unpack_header(tmpnvl, ptr, nfds, &isbe,
1200 &left);
1201 break;
1202 default:
1203 PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp));
1204 }
1205 if (ptr == NULL)
1206 goto fail;
1207 if (!nvlist_move_nvpair(nvl, nvp))
1208 goto fail;
1209 if (tmpnvl != NULL) {
1210 nvl = tmpnvl;
1211 tmpnvl = NULL;
1212 }
1213 }
1214
1215 return (retnvl);
1216 fail:
1217 nvlist_destroy(retnvl);
1218 return (NULL);
1219 }
1220
1221 nvlist_t *
nvlist_unpack(const void * buf,size_t size,int flags)1222 nvlist_unpack(const void *buf, size_t size, int flags)
1223 {
1224
1225 return (nvlist_xunpack(buf, size, NULL, 0, flags));
1226 }
1227
1228 #ifndef _KERNEL
1229 int
nvlist_send(int sock,const nvlist_t * nvl)1230 nvlist_send(int sock, const nvlist_t *nvl)
1231 {
1232 size_t datasize, nfds;
1233 int *fds;
1234 void *data;
1235 int64_t fdidx;
1236 int ret;
1237
1238 if (nvlist_error(nvl) != 0) {
1239 ERRNO_SET(nvlist_error(nvl));
1240 return (-1);
1241 }
1242
1243 fds = nvlist_descriptors(nvl, &nfds);
1244 if (fds == NULL)
1245 return (-1);
1246
1247 ret = -1;
1248 fdidx = 0;
1249
1250 data = nvlist_xpack(nvl, &fdidx, &datasize);
1251 if (data == NULL)
1252 goto out;
1253
1254 if (buf_send(sock, data, datasize) == -1)
1255 goto out;
1256
1257 if (nfds > 0) {
1258 if (fd_send(sock, fds, nfds) == -1)
1259 goto out;
1260 }
1261
1262 ret = 0;
1263 out:
1264 ERRNO_SAVE();
1265 nv_free(fds);
1266 nv_free(data);
1267 ERRNO_RESTORE();
1268 return (ret);
1269 }
1270
1271 nvlist_t *
nvlist_recv(int sock,int flags)1272 nvlist_recv(int sock, int flags)
1273 {
1274 struct nvlist_header nvlhdr;
1275 nvlist_t *nvl, *ret;
1276 unsigned char *buf;
1277 size_t nfds, size, i, offset;
1278 int *fds, soflags, sotype;
1279 socklen_t solen;
1280
1281 solen = sizeof(sotype);
1282 if (getsockopt(sock, SOL_SOCKET, SO_TYPE, &sotype, &solen) != 0)
1283 return (NULL);
1284
1285 soflags = sotype == SOCK_DGRAM ? MSG_PEEK : 0;
1286 if (buf_recv(sock, &nvlhdr, sizeof(nvlhdr), soflags) == -1)
1287 return (NULL);
1288
1289 if (!nvlist_check_header(&nvlhdr))
1290 return (NULL);
1291
1292 nfds = (size_t)nvlhdr.nvlh_descriptors;
1293 size = sizeof(nvlhdr) + (size_t)nvlhdr.nvlh_size;
1294
1295 buf = nv_malloc(size);
1296 if (buf == NULL)
1297 return (NULL);
1298
1299 ret = NULL;
1300 fds = NULL;
1301
1302 if (sotype == SOCK_DGRAM)
1303 offset = 0;
1304 else {
1305 memcpy(buf, &nvlhdr, sizeof(nvlhdr));
1306 offset = sizeof(nvlhdr);
1307 }
1308
1309 if (buf_recv(sock, buf + offset, size - offset, 0) == -1)
1310 goto out;
1311
1312 if (nfds > 0) {
1313 fds = nv_calloc(nfds, sizeof(fds[0]));
1314 if (fds == NULL)
1315 goto out;
1316 if (fd_recv(sock, fds, nfds) == -1)
1317 goto out;
1318 }
1319
1320 nvl = nvlist_xunpack(buf, size, fds, nfds, flags);
1321 if (nvl == NULL) {
1322 ERRNO_SAVE();
1323 for (i = 0; i < nfds; i++)
1324 close(fds[i]);
1325 ERRNO_RESTORE();
1326 goto out;
1327 }
1328
1329 ret = nvl;
1330 out:
1331 ERRNO_SAVE();
1332 nv_free(buf);
1333 nv_free(fds);
1334 ERRNO_RESTORE();
1335
1336 return (ret);
1337 }
1338
1339 nvlist_t *
nvlist_xfer(int sock,nvlist_t * nvl,int flags)1340 nvlist_xfer(int sock, nvlist_t *nvl, int flags)
1341 {
1342
1343 if (nvlist_send(sock, nvl) < 0) {
1344 nvlist_destroy(nvl);
1345 return (NULL);
1346 }
1347 nvlist_destroy(nvl);
1348 return (nvlist_recv(sock, flags));
1349 }
1350 #endif
1351
1352 nvpair_t *
nvlist_first_nvpair(const nvlist_t * nvl)1353 nvlist_first_nvpair(const nvlist_t *nvl)
1354 {
1355
1356 NVLIST_ASSERT(nvl);
1357
1358 return (TAILQ_FIRST(&nvl->nvl_head));
1359 }
1360
1361 nvpair_t *
nvlist_next_nvpair(const nvlist_t * nvl __unused,const nvpair_t * nvp)1362 nvlist_next_nvpair(const nvlist_t *nvl __unused, const nvpair_t *nvp)
1363 {
1364 nvpair_t *retnvp;
1365
1366 NVLIST_ASSERT(nvl);
1367 NVPAIR_ASSERT(nvp);
1368 PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
1369
1370 retnvp = nvpair_next(nvp);
1371 PJDLOG_ASSERT(retnvp == NULL || nvpair_nvlist(retnvp) == nvl);
1372
1373 return (retnvp);
1374
1375 }
1376
1377 nvpair_t *
nvlist_prev_nvpair(const nvlist_t * nvl __unused,const nvpair_t * nvp)1378 nvlist_prev_nvpair(const nvlist_t *nvl __unused, const nvpair_t *nvp)
1379 {
1380 nvpair_t *retnvp;
1381
1382 NVLIST_ASSERT(nvl);
1383 NVPAIR_ASSERT(nvp);
1384 PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
1385
1386 retnvp = nvpair_prev(nvp);
1387 PJDLOG_ASSERT(nvpair_nvlist(retnvp) == nvl);
1388
1389 return (retnvp);
1390 }
1391
1392 const char *
nvlist_next(const nvlist_t * nvl,int * typep,void ** cookiep)1393 nvlist_next(const nvlist_t *nvl, int *typep, void **cookiep)
1394 {
1395 nvpair_t *nvp;
1396
1397 NVLIST_ASSERT(nvl);
1398
1399 if (cookiep == NULL || *cookiep == NULL)
1400 nvp = nvlist_first_nvpair(nvl);
1401 else
1402 nvp = nvlist_next_nvpair(nvl, *cookiep);
1403 if (nvp == NULL)
1404 return (NULL);
1405 if (typep != NULL)
1406 *typep = nvpair_type(nvp);
1407 if (cookiep != NULL)
1408 *cookiep = nvp;
1409 return (nvpair_name(nvp));
1410 }
1411
1412 bool
nvlist_exists(const nvlist_t * nvl,const char * name)1413 nvlist_exists(const nvlist_t *nvl, const char *name)
1414 {
1415
1416 return (nvlist_find(nvl, NV_TYPE_NONE, name) != NULL);
1417 }
1418
1419 #define NVLIST_EXISTS(type, TYPE) \
1420 bool \
1421 nvlist_exists_##type(const nvlist_t *nvl, const char *name) \
1422 { \
1423 \
1424 return (nvlist_find(nvl, NV_TYPE_##TYPE, name) != NULL); \
1425 }
1426
NVLIST_EXISTS(null,NULL)1427 NVLIST_EXISTS(null, NULL)
1428 NVLIST_EXISTS(bool, BOOL)
1429 NVLIST_EXISTS(number, NUMBER)
1430 NVLIST_EXISTS(string, STRING)
1431 NVLIST_EXISTS(nvlist, NVLIST)
1432 NVLIST_EXISTS(binary, BINARY)
1433 NVLIST_EXISTS(bool_array, BOOL_ARRAY)
1434 NVLIST_EXISTS(number_array, NUMBER_ARRAY)
1435 NVLIST_EXISTS(string_array, STRING_ARRAY)
1436 NVLIST_EXISTS(nvlist_array, NVLIST_ARRAY)
1437 #ifndef _KERNEL
1438 NVLIST_EXISTS(descriptor, DESCRIPTOR)
1439 NVLIST_EXISTS(descriptor_array, DESCRIPTOR_ARRAY)
1440 #endif
1441
1442 #undef NVLIST_EXISTS
1443
1444 void
1445 nvlist_add_nvpair(nvlist_t *nvl, const nvpair_t *nvp)
1446 {
1447 nvpair_t *newnvp;
1448
1449 NVPAIR_ASSERT(nvp);
1450
1451 if (nvlist_error(nvl) != 0) {
1452 ERRNO_SET(nvlist_error(nvl));
1453 return;
1454 }
1455 if ((nvl->nvl_flags & NV_FLAG_NO_UNIQUE) == 0) {
1456 if (nvlist_exists(nvl, nvpair_name(nvp))) {
1457 nvl->nvl_error = EEXIST;
1458 ERRNO_SET(nvlist_error(nvl));
1459 return;
1460 }
1461 }
1462
1463 newnvp = nvpair_clone(nvp);
1464 if (newnvp == NULL) {
1465 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1466 ERRNO_SET(nvlist_error(nvl));
1467 return;
1468 }
1469
1470 nvpair_insert(&nvl->nvl_head, newnvp, nvl);
1471 nvlist_update_size(nvl, newnvp, 1);
1472 }
1473
1474 void
nvlist_add_stringf(nvlist_t * nvl,const char * name,const char * valuefmt,...)1475 nvlist_add_stringf(nvlist_t *nvl, const char *name, const char *valuefmt, ...)
1476 {
1477 va_list valueap;
1478
1479 va_start(valueap, valuefmt);
1480 nvlist_add_stringv(nvl, name, valuefmt, valueap);
1481 va_end(valueap);
1482 }
1483
1484 void
nvlist_add_stringv(nvlist_t * nvl,const char * name,const char * valuefmt,va_list valueap)1485 nvlist_add_stringv(nvlist_t *nvl, const char *name, const char *valuefmt,
1486 va_list valueap)
1487 {
1488 nvpair_t *nvp;
1489
1490 if (nvlist_error(nvl) != 0) {
1491 ERRNO_SET(nvlist_error(nvl));
1492 return;
1493 }
1494
1495 nvp = nvpair_create_stringv(name, valuefmt, valueap);
1496 if (nvp == NULL) {
1497 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1498 ERRNO_SET(nvl->nvl_error);
1499 } else {
1500 (void)nvlist_move_nvpair(nvl, nvp);
1501 }
1502 }
1503
1504 void
nvlist_add_null(nvlist_t * nvl,const char * name)1505 nvlist_add_null(nvlist_t *nvl, const char *name)
1506 {
1507 nvpair_t *nvp;
1508
1509 if (nvlist_error(nvl) != 0) {
1510 ERRNO_SET(nvlist_error(nvl));
1511 return;
1512 }
1513
1514 nvp = nvpair_create_null(name);
1515 if (nvp == NULL) {
1516 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1517 ERRNO_SET(nvl->nvl_error);
1518 } else {
1519 (void)nvlist_move_nvpair(nvl, nvp);
1520 }
1521 }
1522
1523 void
nvlist_add_binary(nvlist_t * nvl,const char * name,const void * value,size_t size)1524 nvlist_add_binary(nvlist_t *nvl, const char *name, const void *value,
1525 size_t size)
1526 {
1527 nvpair_t *nvp;
1528
1529 if (nvlist_error(nvl) != 0) {
1530 ERRNO_SET(nvlist_error(nvl));
1531 return;
1532 }
1533
1534 nvp = nvpair_create_binary(name, value, size);
1535 if (nvp == NULL) {
1536 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1537 ERRNO_SET(nvl->nvl_error);
1538 } else {
1539 (void)nvlist_move_nvpair(nvl, nvp);
1540 }
1541 }
1542
1543
1544 #define NVLIST_ADD(vtype, type) \
1545 void \
1546 nvlist_add_##type(nvlist_t *nvl, const char *name, vtype value) \
1547 { \
1548 nvpair_t *nvp; \
1549 \
1550 if (nvlist_error(nvl) != 0) { \
1551 ERRNO_SET(nvlist_error(nvl)); \
1552 return; \
1553 } \
1554 \
1555 nvp = nvpair_create_##type(name, value); \
1556 if (nvp == NULL) { \
1557 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); \
1558 ERRNO_SET(nvl->nvl_error); \
1559 } else { \
1560 (void)nvlist_move_nvpair(nvl, nvp); \
1561 } \
1562 }
1563
1564 NVLIST_ADD(bool, bool)
1565 NVLIST_ADD(uint64_t, number)
1566 NVLIST_ADD(const char *, string)
1567 NVLIST_ADD(const nvlist_t *, nvlist)
1568 #ifndef _KERNEL
1569 NVLIST_ADD(int, descriptor);
1570 #endif
1571
1572 #undef NVLIST_ADD
1573
1574 #define NVLIST_ADD_ARRAY(vtype, type) \
1575 void \
1576 nvlist_add_##type##_array(nvlist_t *nvl, const char *name, vtype value, \
1577 size_t nitems) \
1578 { \
1579 nvpair_t *nvp; \
1580 \
1581 if (nvlist_error(nvl) != 0) { \
1582 ERRNO_SET(nvlist_error(nvl)); \
1583 return; \
1584 } \
1585 \
1586 nvp = nvpair_create_##type##_array(name, value, nitems); \
1587 if (nvp == NULL) { \
1588 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); \
1589 ERRNO_SET(nvl->nvl_error); \
1590 } else { \
1591 (void)nvlist_move_nvpair(nvl, nvp); \
1592 } \
1593 }
1594
NVLIST_ADD_ARRAY(const bool *,bool)1595 NVLIST_ADD_ARRAY(const bool *, bool)
1596 NVLIST_ADD_ARRAY(const uint64_t *, number)
1597 NVLIST_ADD_ARRAY(const char * const *, string)
1598 NVLIST_ADD_ARRAY(const nvlist_t * const *, nvlist)
1599 #ifndef _KERNEL
1600 NVLIST_ADD_ARRAY(const int *, descriptor)
1601 #endif
1602
1603 #undef NVLIST_ADD_ARRAY
1604
1605 #define NVLIST_APPEND_ARRAY(vtype, type, TYPE) \
1606 void \
1607 nvlist_append_##type##_array(nvlist_t *nvl, const char *name, vtype value)\
1608 { \
1609 nvpair_t *nvp; \
1610 \
1611 if (nvlist_error(nvl) != 0) { \
1612 ERRNO_SET(nvlist_error(nvl)); \
1613 return; \
1614 } \
1615 nvp = nvlist_find(nvl, NV_TYPE_##TYPE##_ARRAY, name); \
1616 if (nvp == NULL) { \
1617 nvlist_add_##type##_array(nvl, name, &value, 1); \
1618 return; \
1619 } \
1620 nvlist_update_size(nvl, nvp, -1); \
1621 if (nvpair_append_##type##_array(nvp, value) == -1) { \
1622 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM); \
1623 ERRNO_SET(nvl->nvl_error); \
1624 } \
1625 nvlist_update_size(nvl, nvp, 1); \
1626 }
1627
1628 NVLIST_APPEND_ARRAY(const bool, bool, BOOL)
1629 NVLIST_APPEND_ARRAY(const uint64_t, number, NUMBER)
1630 NVLIST_APPEND_ARRAY(const char *, string, STRING)
1631 NVLIST_APPEND_ARRAY(const nvlist_t *, nvlist, NVLIST)
1632 #ifndef _KERNEL
1633 NVLIST_APPEND_ARRAY(const int, descriptor, DESCRIPTOR)
1634 #endif
1635
1636 #undef NVLIST_APPEND_ARRAY
1637
1638 bool
1639 nvlist_move_nvpair(nvlist_t *nvl, nvpair_t *nvp)
1640 {
1641
1642 NVPAIR_ASSERT(nvp);
1643 PJDLOG_ASSERT(nvpair_nvlist(nvp) == NULL);
1644
1645 if (nvlist_error(nvl) != 0) {
1646 nvpair_free(nvp);
1647 ERRNO_SET(nvlist_error(nvl));
1648 return (false);
1649 }
1650 if ((nvl->nvl_flags & NV_FLAG_NO_UNIQUE) == 0) {
1651 if (nvlist_exists(nvl, nvpair_name(nvp))) {
1652 nvpair_free(nvp);
1653 nvl->nvl_error = EEXIST;
1654 ERRNO_SET(nvl->nvl_error);
1655 return (false);
1656 }
1657 }
1658
1659 nvpair_insert(&nvl->nvl_head, nvp, nvl);
1660 nvlist_update_size(nvl, nvp, 1);
1661 return (true);
1662 }
1663
1664 void
nvlist_move_string(nvlist_t * nvl,const char * name,char * value)1665 nvlist_move_string(nvlist_t *nvl, const char *name, char *value)
1666 {
1667 nvpair_t *nvp;
1668
1669 if (nvlist_error(nvl) != 0) {
1670 nv_free(value);
1671 ERRNO_SET(nvlist_error(nvl));
1672 return;
1673 }
1674
1675 nvp = nvpair_move_string(name, value);
1676 if (nvp == NULL) {
1677 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1678 ERRNO_SET(nvl->nvl_error);
1679 } else {
1680 (void)nvlist_move_nvpair(nvl, nvp);
1681 }
1682 }
1683
1684 void
nvlist_move_nvlist(nvlist_t * nvl,const char * name,nvlist_t * value)1685 nvlist_move_nvlist(nvlist_t *nvl, const char *name, nvlist_t *value)
1686 {
1687 nvpair_t *nvp;
1688
1689 if (nvlist_error(nvl) != 0) {
1690 if (value != NULL && nvlist_get_nvpair_parent(value) != NULL)
1691 nvlist_destroy(value);
1692 ERRNO_SET(nvlist_error(nvl));
1693 return;
1694 }
1695
1696 nvp = nvpair_move_nvlist(name, value);
1697 if (nvp == NULL) {
1698 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1699 ERRNO_SET(nvl->nvl_error);
1700 } else {
1701 (void)nvlist_move_nvpair(nvl, nvp);
1702 }
1703 }
1704
1705 #ifndef _KERNEL
1706 void
nvlist_move_descriptor(nvlist_t * nvl,const char * name,int value)1707 nvlist_move_descriptor(nvlist_t *nvl, const char *name, int value)
1708 {
1709 nvpair_t *nvp;
1710
1711 if (nvlist_error(nvl) != 0) {
1712 close(value);
1713 ERRNO_SET(nvlist_error(nvl));
1714 return;
1715 }
1716
1717 nvp = nvpair_move_descriptor(name, value);
1718 if (nvp == NULL) {
1719 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1720 ERRNO_SET(nvl->nvl_error);
1721 } else {
1722 (void)nvlist_move_nvpair(nvl, nvp);
1723 }
1724 }
1725 #endif
1726
1727 void
nvlist_move_binary(nvlist_t * nvl,const char * name,void * value,size_t size)1728 nvlist_move_binary(nvlist_t *nvl, const char *name, void *value, size_t size)
1729 {
1730 nvpair_t *nvp;
1731
1732 if (nvlist_error(nvl) != 0) {
1733 nv_free(value);
1734 ERRNO_SET(nvlist_error(nvl));
1735 return;
1736 }
1737
1738 nvp = nvpair_move_binary(name, value, size);
1739 if (nvp == NULL) {
1740 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1741 ERRNO_SET(nvl->nvl_error);
1742 } else {
1743 (void)nvlist_move_nvpair(nvl, nvp);
1744 }
1745 }
1746
1747 void
nvlist_move_bool_array(nvlist_t * nvl,const char * name,bool * value,size_t nitems)1748 nvlist_move_bool_array(nvlist_t *nvl, const char *name, bool *value,
1749 size_t nitems)
1750 {
1751 nvpair_t *nvp;
1752
1753 if (nvlist_error(nvl) != 0) {
1754 nv_free(value);
1755 ERRNO_SET(nvlist_error(nvl));
1756 return;
1757 }
1758
1759 nvp = nvpair_move_bool_array(name, value, nitems);
1760 if (nvp == NULL) {
1761 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1762 ERRNO_SET(nvl->nvl_error);
1763 } else {
1764 (void)nvlist_move_nvpair(nvl, nvp);
1765 }
1766 }
1767
1768 void
nvlist_move_string_array(nvlist_t * nvl,const char * name,char ** value,size_t nitems)1769 nvlist_move_string_array(nvlist_t *nvl, const char *name, char **value,
1770 size_t nitems)
1771 {
1772 nvpair_t *nvp;
1773 size_t i;
1774
1775 if (nvlist_error(nvl) != 0) {
1776 if (value != NULL) {
1777 for (i = 0; i < nitems; i++)
1778 nv_free(value[i]);
1779 nv_free(value);
1780 }
1781 ERRNO_SET(nvlist_error(nvl));
1782 return;
1783 }
1784
1785 nvp = nvpair_move_string_array(name, value, nitems);
1786 if (nvp == NULL) {
1787 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1788 ERRNO_SET(nvl->nvl_error);
1789 } else {
1790 (void)nvlist_move_nvpair(nvl, nvp);
1791 }
1792 }
1793
1794 void
nvlist_move_nvlist_array(nvlist_t * nvl,const char * name,nvlist_t ** value,size_t nitems)1795 nvlist_move_nvlist_array(nvlist_t *nvl, const char *name, nvlist_t **value,
1796 size_t nitems)
1797 {
1798 nvpair_t *nvp;
1799 size_t i;
1800
1801 if (nvlist_error(nvl) != 0) {
1802 if (value != NULL) {
1803 for (i = 0; i < nitems; i++) {
1804 if (nvlist_get_pararr(value[i], NULL) == NULL)
1805 nvlist_destroy(value[i]);
1806 }
1807 }
1808 nv_free(value);
1809 ERRNO_SET(nvlist_error(nvl));
1810 return;
1811 }
1812
1813 nvp = nvpair_move_nvlist_array(name, value, nitems);
1814 if (nvp == NULL) {
1815 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1816 ERRNO_SET(nvl->nvl_error);
1817 } else {
1818 (void)nvlist_move_nvpair(nvl, nvp);
1819 }
1820 }
1821
1822 void
nvlist_move_number_array(nvlist_t * nvl,const char * name,uint64_t * value,size_t nitems)1823 nvlist_move_number_array(nvlist_t *nvl, const char *name, uint64_t *value,
1824 size_t nitems)
1825 {
1826 nvpair_t *nvp;
1827
1828 if (nvlist_error(nvl) != 0) {
1829 nv_free(value);
1830 ERRNO_SET(nvlist_error(nvl));
1831 return;
1832 }
1833
1834 nvp = nvpair_move_number_array(name, value, nitems);
1835 if (nvp == NULL) {
1836 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1837 ERRNO_SET(nvl->nvl_error);
1838 } else {
1839 (void)nvlist_move_nvpair(nvl, nvp);
1840 }
1841 }
1842
1843 #ifndef _KERNEL
1844 void
nvlist_move_descriptor_array(nvlist_t * nvl,const char * name,int * value,size_t nitems)1845 nvlist_move_descriptor_array(nvlist_t *nvl, const char *name, int *value,
1846 size_t nitems)
1847 {
1848 nvpair_t *nvp;
1849 size_t i;
1850
1851 if (nvlist_error(nvl) != 0) {
1852 if (value != 0) {
1853 for (i = 0; i < nitems; i++)
1854 close(value[i]);
1855 nv_free(value);
1856 }
1857
1858 ERRNO_SET(nvlist_error(nvl));
1859 return;
1860 }
1861
1862 nvp = nvpair_move_descriptor_array(name, value, nitems);
1863 if (nvp == NULL) {
1864 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1865 ERRNO_SET(nvl->nvl_error);
1866 } else {
1867 (void)nvlist_move_nvpair(nvl, nvp);
1868 }
1869 }
1870 #endif
1871
1872 const nvpair_t *
nvlist_get_nvpair(const nvlist_t * nvl,const char * name)1873 nvlist_get_nvpair(const nvlist_t *nvl, const char *name)
1874 {
1875
1876 return (nvlist_find(nvl, NV_TYPE_NONE, name));
1877 }
1878
1879 #define NVLIST_GET(ftype, type, TYPE) \
1880 ftype \
1881 nvlist_get_##type(const nvlist_t *nvl, const char *name) \
1882 { \
1883 const nvpair_t *nvp; \
1884 \
1885 nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name); \
1886 if (nvp == NULL) \
1887 nvlist_report_missing(NV_TYPE_##TYPE, name); \
1888 return (nvpair_get_##type(nvp)); \
1889 }
1890
NVLIST_GET(bool,bool,BOOL)1891 NVLIST_GET(bool, bool, BOOL)
1892 NVLIST_GET(uint64_t, number, NUMBER)
1893 NVLIST_GET(const char *, string, STRING)
1894 NVLIST_GET(const nvlist_t *, nvlist, NVLIST)
1895 #ifndef _KERNEL
1896 NVLIST_GET(int, descriptor, DESCRIPTOR)
1897 #endif
1898
1899 #undef NVLIST_GET
1900
1901 const void *
1902 nvlist_get_binary(const nvlist_t *nvl, const char *name, size_t *sizep)
1903 {
1904 nvpair_t *nvp;
1905
1906 nvp = nvlist_find(nvl, NV_TYPE_BINARY, name);
1907 if (nvp == NULL)
1908 nvlist_report_missing(NV_TYPE_BINARY, name);
1909
1910 return (nvpair_get_binary(nvp, sizep));
1911 }
1912
1913 #define NVLIST_GET_ARRAY(ftype, type, TYPE) \
1914 ftype \
1915 nvlist_get_##type##_array(const nvlist_t *nvl, const char *name, \
1916 size_t *nitems) \
1917 { \
1918 const nvpair_t *nvp; \
1919 \
1920 nvp = nvlist_find(nvl, NV_TYPE_##TYPE##_ARRAY, name); \
1921 if (nvp == NULL) \
1922 nvlist_report_missing(NV_TYPE_##TYPE##_ARRAY, name); \
1923 return (nvpair_get_##type##_array(nvp, nitems)); \
1924 }
1925
NVLIST_GET_ARRAY(const bool *,bool,BOOL)1926 NVLIST_GET_ARRAY(const bool *, bool, BOOL)
1927 NVLIST_GET_ARRAY(const uint64_t *, number, NUMBER)
1928 NVLIST_GET_ARRAY(const char * const *, string, STRING)
1929 NVLIST_GET_ARRAY(const nvlist_t * const *, nvlist, NVLIST)
1930 #ifndef _KERNEL
1931 NVLIST_GET_ARRAY(const int *, descriptor, DESCRIPTOR)
1932 #endif
1933
1934 #undef NVLIST_GET_ARRAY
1935
1936 #define NVLIST_TAKE(ftype, type, TYPE) \
1937 ftype \
1938 nvlist_take_##type(nvlist_t *nvl, const char *name) \
1939 { \
1940 nvpair_t *nvp; \
1941 ftype value; \
1942 \
1943 nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name); \
1944 if (nvp == NULL) \
1945 nvlist_report_missing(NV_TYPE_##TYPE, name); \
1946 value = (ftype)(intptr_t)nvpair_get_##type(nvp); \
1947 nvlist_remove_nvpair(nvl, nvp); \
1948 nvpair_free_structure(nvp); \
1949 return (value); \
1950 }
1951
1952 NVLIST_TAKE(bool, bool, BOOL)
1953 NVLIST_TAKE(uint64_t, number, NUMBER)
1954 NVLIST_TAKE(char *, string, STRING)
1955 NVLIST_TAKE(nvlist_t *, nvlist, NVLIST)
1956 #ifndef _KERNEL
1957 NVLIST_TAKE(int, descriptor, DESCRIPTOR)
1958 #endif
1959
1960 #undef NVLIST_TAKE
1961
1962 void *
1963 nvlist_take_binary(nvlist_t *nvl, const char *name, size_t *sizep)
1964 {
1965 nvpair_t *nvp;
1966 void *value;
1967
1968 nvp = nvlist_find(nvl, NV_TYPE_BINARY, name);
1969 if (nvp == NULL)
1970 nvlist_report_missing(NV_TYPE_BINARY, name);
1971
1972 value = (void *)(intptr_t)nvpair_get_binary(nvp, sizep);
1973 nvlist_remove_nvpair(nvl, nvp);
1974 nvpair_free_structure(nvp);
1975 return (value);
1976 }
1977
1978 #define NVLIST_TAKE_ARRAY(ftype, type, TYPE) \
1979 ftype \
1980 nvlist_take_##type##_array(nvlist_t *nvl, const char *name, \
1981 size_t *nitems) \
1982 { \
1983 nvpair_t *nvp; \
1984 ftype value; \
1985 \
1986 nvp = nvlist_find(nvl, NV_TYPE_##TYPE##_ARRAY, name); \
1987 if (nvp == NULL) \
1988 nvlist_report_missing(NV_TYPE_##TYPE##_ARRAY, name); \
1989 value = (ftype)(intptr_t)nvpair_get_##type##_array(nvp, nitems);\
1990 nvlist_remove_nvpair(nvl, nvp); \
1991 nvpair_free_structure(nvp); \
1992 return (value); \
1993 }
1994
NVLIST_TAKE_ARRAY(bool *,bool,BOOL)1995 NVLIST_TAKE_ARRAY(bool *, bool, BOOL)
1996 NVLIST_TAKE_ARRAY(uint64_t *, number, NUMBER)
1997 NVLIST_TAKE_ARRAY(char **, string, STRING)
1998 NVLIST_TAKE_ARRAY(nvlist_t **, nvlist, NVLIST)
1999 #ifndef _KERNEL
2000 NVLIST_TAKE_ARRAY(int *, descriptor, DESCRIPTOR)
2001 #endif
2002
2003 void
2004 nvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp)
2005 {
2006
2007 NVLIST_ASSERT(nvl);
2008 NVPAIR_ASSERT(nvp);
2009 PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
2010
2011 nvpair_remove(&nvl->nvl_head, nvp, nvl);
2012 nvlist_update_size(nvl, nvp, -1);
2013 }
2014
2015 void
nvlist_free(nvlist_t * nvl,const char * name)2016 nvlist_free(nvlist_t *nvl, const char *name)
2017 {
2018
2019 nvlist_free_type(nvl, name, NV_TYPE_NONE);
2020 }
2021
2022 #define NVLIST_FREE(type, TYPE) \
2023 void \
2024 nvlist_free_##type(nvlist_t *nvl, const char *name) \
2025 { \
2026 \
2027 nvlist_free_type(nvl, name, NV_TYPE_##TYPE); \
2028 }
2029
NVLIST_FREE(null,NULL)2030 NVLIST_FREE(null, NULL)
2031 NVLIST_FREE(bool, BOOL)
2032 NVLIST_FREE(number, NUMBER)
2033 NVLIST_FREE(string, STRING)
2034 NVLIST_FREE(nvlist, NVLIST)
2035 NVLIST_FREE(binary, BINARY)
2036 NVLIST_FREE(bool_array, BOOL_ARRAY)
2037 NVLIST_FREE(number_array, NUMBER_ARRAY)
2038 NVLIST_FREE(string_array, STRING_ARRAY)
2039 NVLIST_FREE(nvlist_array, NVLIST_ARRAY)
2040 #ifndef _KERNEL
2041 NVLIST_FREE(descriptor, DESCRIPTOR)
2042 NVLIST_FREE(descriptor_array, DESCRIPTOR_ARRAY)
2043 #endif
2044
2045 #undef NVLIST_FREE
2046
2047 void
2048 nvlist_free_nvpair(nvlist_t *nvl, nvpair_t *nvp)
2049 {
2050
2051 NVLIST_ASSERT(nvl);
2052 NVPAIR_ASSERT(nvp);
2053 PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
2054
2055 nvlist_remove_nvpair(nvl, nvp);
2056 nvpair_free(nvp);
2057 }
2058
2059