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