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