]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/subr_nvlist.c
Mark local function as static as a result of removing recursion.
[FreeBSD/FreeBSD.git] / sys / kern / subr_nvlist.c
1 /*-
2  * Copyright (c) 2009-2013 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * This software was developed by Pawel Jakub Dawidek under sponsorship from
6  * the FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/param.h>
34 #include <sys/endian.h>
35 #include <sys/queue.h>
36
37 #ifdef _KERNEL
38
39 #include <sys/errno.h>
40 #include <sys/kernel.h>
41 #include <sys/lock.h>
42 #include <sys/malloc.h>
43 #include <sys/systm.h>
44
45 #include <machine/stdarg.h>
46
47 #else
48 #include <sys/socket.h>
49
50 #include <errno.h>
51 #include <stdarg.h>
52 #include <stdbool.h>
53 #include <stdint.h>
54 #define _WITH_DPRINTF
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <unistd.h>
59
60 #include "msgio.h"
61 #endif
62
63 #ifdef HAVE_PJDLOG
64 #include <pjdlog.h>
65 #endif
66
67 #include <sys/nv.h>
68 #include <sys/nv_impl.h>
69 #include <sys/nvlist_impl.h>
70 #include <sys/nvpair_impl.h>
71
72 #ifndef HAVE_PJDLOG
73 #ifdef _KERNEL
74 #define PJDLOG_ASSERT(...)              MPASS(__VA_ARGS__)
75 #define PJDLOG_RASSERT(expr, ...)       KASSERT(expr, (__VA_ARGS__))
76 #define PJDLOG_ABORT(...)               panic(__VA_ARGS__)
77 #else
78 #include <assert.h>
79 #define PJDLOG_ASSERT(...)              assert(__VA_ARGS__)
80 #define PJDLOG_RASSERT(expr, ...)       assert(expr)
81 #define PJDLOG_ABORT(...)               do {                            \
82         fprintf(stderr, "%s:%u: ", __FILE__, __LINE__);                 \
83         fprintf(stderr, __VA_ARGS__);                                   \
84         fprintf(stderr, "\n");                                          \
85         abort();                                                        \
86 } while (0)
87 #endif
88 #endif
89
90 #define NV_FLAG_PRIVATE_MASK    (NV_FLAG_BIG_ENDIAN)
91 #define NV_FLAG_PUBLIC_MASK     (NV_FLAG_IGNORE_CASE)
92 #define NV_FLAG_ALL_MASK        (NV_FLAG_PRIVATE_MASK | NV_FLAG_PUBLIC_MASK)
93
94 #define NVLIST_MAGIC    0x6e766c        /* "nvl" */
95 struct nvlist {
96         int              nvl_magic;
97         int              nvl_error;
98         int              nvl_flags;
99         nvpair_t        *nvl_parent;
100         struct nvl_head  nvl_head;
101 };
102
103 #define NVLIST_ASSERT(nvl)      do {                                    \
104         PJDLOG_ASSERT((nvl) != NULL);                                   \
105         PJDLOG_ASSERT((nvl)->nvl_magic == NVLIST_MAGIC);                \
106 } while (0)
107
108 #ifdef _KERNEL
109 MALLOC_DEFINE(M_NVLIST, "nvlist", "kernel nvlist");
110 #endif
111
112 #define NVPAIR_ASSERT(nvp)      nvpair_assert(nvp)
113
114 #define NVLIST_HEADER_MAGIC     0x6c
115 #define NVLIST_HEADER_VERSION   0x00
116 struct nvlist_header {
117         uint8_t         nvlh_magic;
118         uint8_t         nvlh_version;
119         uint8_t         nvlh_flags;
120         uint64_t        nvlh_descriptors;
121         uint64_t        nvlh_size;
122 } __packed;
123
124 nvlist_t *
125 nvlist_create(int flags)
126 {
127         nvlist_t *nvl;
128
129         PJDLOG_ASSERT((flags & ~(NV_FLAG_PUBLIC_MASK)) == 0);
130
131         nvl = nv_malloc(sizeof(*nvl));
132         nvl->nvl_error = 0;
133         nvl->nvl_flags = flags;
134         nvl->nvl_parent = NULL;
135         TAILQ_INIT(&nvl->nvl_head);
136         nvl->nvl_magic = NVLIST_MAGIC;
137
138         return (nvl);
139 }
140
141 void
142 nvlist_destroy(nvlist_t *nvl)
143 {
144         nvpair_t *nvp;
145
146         if (nvl == NULL)
147                 return;
148
149         ERRNO_SAVE();
150
151         NVLIST_ASSERT(nvl);
152
153         while ((nvp = nvlist_first_nvpair(nvl)) != NULL) {
154                 nvlist_remove_nvpair(nvl, nvp);
155                 nvpair_free(nvp);
156         }
157         nvl->nvl_magic = 0;
158         nv_free(nvl);
159
160         ERRNO_RESTORE();
161 }
162
163 void
164 nvlist_set_error(nvlist_t *nvl, int error)
165 {
166
167         PJDLOG_ASSERT(error != 0);
168
169         /*
170          * Check for error != 0 so that we don't do the wrong thing if somebody
171          * tries to abuse this API when asserts are disabled.
172          */
173         if (nvl != NULL && error != 0 && nvl->nvl_error == 0)
174                 nvl->nvl_error = error;
175 }
176
177 int
178 nvlist_error(const nvlist_t *nvl)
179 {
180
181         if (nvl == NULL)
182                 return (ENOMEM);
183
184         NVLIST_ASSERT(nvl);
185
186         return (nvl->nvl_error);
187 }
188
189 nvpair_t *
190 nvlist_get_nvpair_parent(const nvlist_t *nvl)
191 {
192
193         NVLIST_ASSERT(nvl);
194
195         return (nvl->nvl_parent);
196 }
197
198 const nvlist_t *
199 nvlist_get_parent(const nvlist_t *nvl, void **cookiep)
200 {
201         nvpair_t *nvp;
202
203         NVLIST_ASSERT(nvl);
204
205         nvp = nvl->nvl_parent;
206         if (cookiep != NULL)
207                 *cookiep = nvp;
208         if (nvp == NULL)
209                 return (NULL);
210
211         return (nvpair_nvlist(nvp));
212 }
213
214 void
215 nvlist_set_parent(nvlist_t *nvl, nvpair_t *parent)
216 {
217
218         NVLIST_ASSERT(nvl);
219
220         nvl->nvl_parent = parent;
221 }
222
223 bool
224 nvlist_empty(const nvlist_t *nvl)
225 {
226
227         NVLIST_ASSERT(nvl);
228         PJDLOG_ASSERT(nvl->nvl_error == 0);
229
230         return (nvlist_first_nvpair(nvl) == NULL);
231 }
232
233 static void
234 nvlist_report_missing(int type, const char *name)
235 {
236
237         PJDLOG_ABORT("Element '%s' of type %s doesn't exist.",
238             name, nvpair_type_string(type));
239 }
240
241 static nvpair_t *
242 nvlist_find(const nvlist_t *nvl, int type, const char *name)
243 {
244         nvpair_t *nvp;
245
246         NVLIST_ASSERT(nvl);
247         PJDLOG_ASSERT(nvl->nvl_error == 0);
248         PJDLOG_ASSERT(type == NV_TYPE_NONE ||
249             (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
250
251         for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
252             nvp = nvlist_next_nvpair(nvl, nvp)) {
253                 if (type != NV_TYPE_NONE && nvpair_type(nvp) != type)
254                         continue;
255                 if ((nvl->nvl_flags & NV_FLAG_IGNORE_CASE) != 0) {
256                         if (strcasecmp(nvpair_name(nvp), name) != 0)
257                                 continue;
258                 } else {
259                         if (strcmp(nvpair_name(nvp), name) != 0)
260                                 continue;
261                 }
262                 break;
263         }
264
265         if (nvp == NULL)
266                 ERRNO_SET(ENOENT);
267
268         return (nvp);
269 }
270
271 bool
272 nvlist_exists_type(const nvlist_t *nvl, const char *name, int type)
273 {
274
275         NVLIST_ASSERT(nvl);
276         PJDLOG_ASSERT(nvl->nvl_error == 0);
277         PJDLOG_ASSERT(type == NV_TYPE_NONE ||
278             (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
279
280         return (nvlist_find(nvl, type, name) != NULL);
281 }
282
283 void
284 nvlist_free_type(nvlist_t *nvl, const char *name, int type)
285 {
286         nvpair_t *nvp;
287
288         NVLIST_ASSERT(nvl);
289         PJDLOG_ASSERT(nvl->nvl_error == 0);
290         PJDLOG_ASSERT(type == NV_TYPE_NONE ||
291             (type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST));
292
293         nvp = nvlist_find(nvl, type, name);
294         if (nvp != NULL)
295                 nvlist_free_nvpair(nvl, nvp);
296         else
297                 nvlist_report_missing(type, name);
298 }
299
300 nvlist_t *
301 nvlist_clone(const nvlist_t *nvl)
302 {
303         nvlist_t *newnvl;
304         nvpair_t *nvp, *newnvp;
305
306         NVLIST_ASSERT(nvl);
307
308         if (nvl->nvl_error != 0) {
309                 ERRNO_SET(nvl->nvl_error);
310                 return (NULL);
311         }
312
313         newnvl = nvlist_create(nvl->nvl_flags & NV_FLAG_PUBLIC_MASK);
314         for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
315             nvp = nvlist_next_nvpair(nvl, nvp)) {
316                 newnvp = nvpair_clone(nvp);
317                 if (newnvp == NULL)
318                         break;
319                 nvlist_move_nvpair(newnvl, newnvp);
320         }
321         if (nvp != NULL) {
322                 nvlist_destroy(newnvl);
323                 return (NULL);
324         }
325         return (newnvl);
326 }
327
328 #ifndef _KERNEL
329 static bool
330 nvlist_dump_error_check(const nvlist_t *nvl, int fd, int level)
331 {
332
333         if (nvlist_error(nvl) != 0) {
334                 dprintf(fd, "%*serror: %d\n", level * 4, "",
335                     nvlist_error(nvl));
336                 return (true);
337         }
338
339         return (false);
340 }
341
342 /*
343  * Dump content of nvlist.
344  */
345 void
346 nvlist_dump(const nvlist_t *nvl, int fd)
347 {
348         const nvlist_t *tmpnvl;
349         nvpair_t *nvp, *tmpnvp;
350         void *cookie;
351         int level;
352
353         level = 0;
354         if (nvlist_dump_error_check(nvl, fd, level))
355                 return;
356
357         nvp = nvlist_first_nvpair(nvl);
358         while (nvp != NULL) {
359                 dprintf(fd, "%*s%s (%s):", level * 4, "", nvpair_name(nvp),
360                     nvpair_type_string(nvpair_type(nvp)));
361                 switch (nvpair_type(nvp)) {
362                 case NV_TYPE_NULL:
363                         dprintf(fd, " null\n");
364                         break;
365                 case NV_TYPE_BOOL:
366                         dprintf(fd, " %s\n", nvpair_get_bool(nvp) ?
367                             "TRUE" : "FALSE");
368                         break;
369                 case NV_TYPE_NUMBER:
370                         dprintf(fd, " %ju (%jd) (0x%jx)\n",
371                             (uintmax_t)nvpair_get_number(nvp),
372                             (intmax_t)nvpair_get_number(nvp),
373                             (uintmax_t)nvpair_get_number(nvp));
374                         break;
375                 case NV_TYPE_STRING:
376                         dprintf(fd, " [%s]\n", nvpair_get_string(nvp));
377                         break;
378                 case NV_TYPE_NVLIST:
379                         dprintf(fd, "\n");
380                         tmpnvl = nvpair_get_nvlist(nvp);
381                         if (nvlist_dump_error_check(tmpnvl, fd, level + 1))
382                                 break;
383                         tmpnvp = nvlist_first_nvpair(tmpnvl);
384                         if (tmpnvp != NULL) {
385                                 nvl = tmpnvl;
386                                 nvp = tmpnvp;
387                                 level++;
388                                 continue;
389                         }
390                         break;
391                 case NV_TYPE_DESCRIPTOR:
392                         dprintf(fd, " %d\n", nvpair_get_descriptor(nvp));
393                         break;
394                 case NV_TYPE_BINARY:
395                     {
396                         const unsigned char *binary;
397                         unsigned int ii;
398                         size_t size;
399
400                         binary = nvpair_get_binary(nvp, &size);
401                         dprintf(fd, " %zu ", size);
402                         for (ii = 0; ii < size; ii++)
403                                 dprintf(fd, "%02hhx", binary[ii]);
404                         dprintf(fd, "\n");
405                         break;
406                     }
407                 default:
408                         PJDLOG_ABORT("Unknown type: %d.", nvpair_type(nvp));
409                 }
410
411                 while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
412                         cookie = NULL;
413                         nvl = nvlist_get_parent(nvl, &cookie);
414                         if (nvl == NULL)
415                                 return;
416                         nvp = cookie;
417                         level--;
418                 }
419         }
420 }
421
422 void
423 nvlist_fdump(const nvlist_t *nvl, FILE *fp)
424 {
425
426         fflush(fp);
427         nvlist_dump(nvl, fileno(fp));
428 }
429 #endif
430
431 /*
432  * The function obtains size of the nvlist after nvlist_pack().
433  */
434 size_t
435 nvlist_size(const nvlist_t *nvl)
436 {
437         const nvlist_t *tmpnvl;
438         const nvpair_t *nvp, *tmpnvp;
439         void *cookie;
440         size_t size;
441
442         NVLIST_ASSERT(nvl);
443         PJDLOG_ASSERT(nvl->nvl_error == 0);
444
445         size = sizeof(struct nvlist_header);
446         nvp = nvlist_first_nvpair(nvl);
447         while (nvp != NULL) {
448                 size += nvpair_header_size();
449                 size += strlen(nvpair_name(nvp)) + 1;
450                 if (nvpair_type(nvp) == NV_TYPE_NVLIST) {
451                         size += sizeof(struct nvlist_header);
452                         size += nvpair_header_size() + 1;
453                         tmpnvl = nvpair_get_nvlist(nvp);
454                         PJDLOG_ASSERT(tmpnvl->nvl_error == 0);
455                         tmpnvp = nvlist_first_nvpair(tmpnvl);
456                         if (tmpnvp != NULL) {
457                                 nvl = tmpnvl;
458                                 nvp = tmpnvp;
459                                 continue;
460                         }
461                 } else {
462                         size += nvpair_size(nvp);
463                 }
464
465                 while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
466                         cookie = NULL;
467                         nvl = nvlist_get_parent(nvl, &cookie);
468                         if (nvl == NULL)
469                                 goto out;
470                         nvp = cookie;
471                 }
472         }
473
474 out:
475         return (size);
476 }
477
478 #ifndef _KERNEL
479 static int *
480 nvlist_xdescriptors(const nvlist_t *nvl, int *descs)
481 {
482         nvpair_t *nvp;
483         const char *name;
484         int type;
485
486         NVLIST_ASSERT(nvl);
487         PJDLOG_ASSERT(nvl->nvl_error == 0);
488
489         nvp = NULL;
490         do {
491                 while ((name = nvlist_next(nvl, &type, (void**)&nvp)) != NULL) {
492                         switch (type) {
493                         case NV_TYPE_DESCRIPTOR:
494                                 *descs = nvpair_get_descriptor(nvp);
495                                 descs++;
496                                 break;
497                         case NV_TYPE_NVLIST:
498                                 nvl = nvpair_get_nvlist(nvp);
499                                 nvp = NULL;
500                                 break;
501                         }
502                 }
503         } while ((nvl = nvlist_get_parent(nvl, (void**)&nvp)) != NULL);
504
505         return (descs);
506 }
507 #endif
508
509 #ifndef _KERNEL
510 int *
511 nvlist_descriptors(const nvlist_t *nvl, size_t *nitemsp)
512 {
513         size_t nitems;
514         int *fds;
515
516         nitems = nvlist_ndescriptors(nvl);
517         fds = nv_malloc(sizeof(fds[0]) * (nitems + 1));
518         if (fds == NULL)
519                 return (NULL);
520         if (nitems > 0)
521                 nvlist_xdescriptors(nvl, fds);
522         fds[nitems] = -1;
523         if (nitemsp != NULL)
524                 *nitemsp = nitems;
525         return (fds);
526 }
527 #endif
528
529 size_t
530 nvlist_ndescriptors(const nvlist_t *nvl)
531 {
532 #ifndef _KERNEL
533         nvpair_t *nvp;
534         const char *name;
535         size_t ndescs;
536         int type;
537
538         NVLIST_ASSERT(nvl);
539         PJDLOG_ASSERT(nvl->nvl_error == 0);
540
541         ndescs = 0;
542         nvp = NULL;
543         do {
544                 while ((name = nvlist_next(nvl, &type, (void**)&nvp)) != NULL) {
545                         switch (type) {
546                         case NV_TYPE_DESCRIPTOR:
547                                 ndescs++;
548                                 break;
549                         case NV_TYPE_NVLIST:
550                                 nvl = nvpair_get_nvlist(nvp);
551                                 nvp = NULL;
552                                 break;
553                         }
554                 }
555         } while ((nvl = nvlist_get_parent(nvl, (void**)&nvp)) != NULL);
556
557         return (ndescs);
558 #else
559         return (0);
560 #endif
561 }
562
563 static unsigned char *
564 nvlist_pack_header(const nvlist_t *nvl, unsigned char *ptr, size_t *leftp)
565 {
566         struct nvlist_header nvlhdr;
567
568         NVLIST_ASSERT(nvl);
569
570         nvlhdr.nvlh_magic = NVLIST_HEADER_MAGIC;
571         nvlhdr.nvlh_version = NVLIST_HEADER_VERSION;
572         nvlhdr.nvlh_flags = nvl->nvl_flags;
573 #if BYTE_ORDER == BIG_ENDIAN
574         nvlhdr.nvlh_flags |= NV_FLAG_BIG_ENDIAN;
575 #endif
576         nvlhdr.nvlh_descriptors = nvlist_ndescriptors(nvl);
577         nvlhdr.nvlh_size = *leftp - sizeof(nvlhdr);
578         PJDLOG_ASSERT(*leftp >= sizeof(nvlhdr));
579         memcpy(ptr, &nvlhdr, sizeof(nvlhdr));
580         ptr += sizeof(nvlhdr);
581         *leftp -= sizeof(nvlhdr);
582
583         return (ptr);
584 }
585
586 static void *
587 nvlist_xpack(const nvlist_t *nvl, int64_t *fdidxp, size_t *sizep)
588 {
589         unsigned char *buf, *ptr;
590         size_t left, size;
591         const nvlist_t *tmpnvl;
592         nvpair_t *nvp, *tmpnvp;
593         void *cookie;
594
595         NVLIST_ASSERT(nvl);
596
597         if (nvl->nvl_error != 0) {
598                 ERRNO_SET(nvl->nvl_error);
599                 return (NULL);
600         }
601
602         size = nvlist_size(nvl);
603         buf = nv_malloc(size);
604         if (buf == NULL)
605                 return (NULL);
606
607         ptr = buf;
608         left = size;
609
610         ptr = nvlist_pack_header(nvl, ptr, &left);
611
612         nvp = nvlist_first_nvpair(nvl);
613         while (nvp != NULL) {
614                 NVPAIR_ASSERT(nvp);
615
616                 nvpair_init_datasize(nvp);
617                 ptr = nvpair_pack_header(nvp, ptr, &left);
618                 if (ptr == NULL) {
619                         nv_free(buf);
620                         return (NULL);
621                 }
622                 switch (nvpair_type(nvp)) {
623                 case NV_TYPE_NULL:
624                         ptr = nvpair_pack_null(nvp, ptr, &left);
625                         break;
626                 case NV_TYPE_BOOL:
627                         ptr = nvpair_pack_bool(nvp, ptr, &left);
628                         break;
629                 case NV_TYPE_NUMBER:
630                         ptr = nvpair_pack_number(nvp, ptr, &left);
631                         break;
632                 case NV_TYPE_STRING:
633                         ptr = nvpair_pack_string(nvp, ptr, &left);
634                         break;
635                 case NV_TYPE_NVLIST:
636                         tmpnvl = nvpair_get_nvlist(nvp);
637                         ptr = nvlist_pack_header(tmpnvl, ptr, &left);
638                         if (ptr == NULL)
639                                 goto out;
640                         tmpnvp = nvlist_first_nvpair(tmpnvl);
641                         if (tmpnvp != NULL) {
642                                 nvl = tmpnvl;
643                                 nvp = tmpnvp;
644                                 continue;
645                         }
646                         ptr = nvpair_pack_nvlist_up(ptr, &left);
647                         break;
648 #ifndef _KERNEL
649                 case NV_TYPE_DESCRIPTOR:
650                         ptr = nvpair_pack_descriptor(nvp, ptr, fdidxp, &left);
651                         break;
652 #endif
653                 case NV_TYPE_BINARY:
654                         ptr = nvpair_pack_binary(nvp, ptr, &left);
655                         break;
656                 default:
657                         PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp));
658                 }
659                 if (ptr == NULL) {
660                         nv_free(buf);
661                         return (NULL);
662                 }
663                 while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
664                         cookie = NULL;
665                         nvl = nvlist_get_parent(nvl, &cookie);
666                         if (nvl == NULL)
667                                 goto out;
668                         nvp = cookie;
669                         ptr = nvpair_pack_nvlist_up(ptr, &left);
670                         if (ptr == NULL)
671                                 goto out;
672                 }
673         }
674
675 out:
676         if (sizep != NULL)
677                 *sizep = size;
678         return (buf);
679 }
680
681 void *
682 nvlist_pack(const nvlist_t *nvl, size_t *sizep)
683 {
684
685         NVLIST_ASSERT(nvl);
686
687         if (nvl->nvl_error != 0) {
688                 ERRNO_SET(nvl->nvl_error);
689                 return (NULL);
690         }
691
692         if (nvlist_ndescriptors(nvl) > 0) {
693                 ERRNO_SET(EOPNOTSUPP);
694                 return (NULL);
695         }
696
697         return (nvlist_xpack(nvl, NULL, sizep));
698 }
699
700 static bool
701 nvlist_check_header(struct nvlist_header *nvlhdrp)
702 {
703
704         if (nvlhdrp->nvlh_magic != NVLIST_HEADER_MAGIC) {
705                 ERRNO_SET(EINVAL);
706                 return (false);
707         }
708         if ((nvlhdrp->nvlh_flags & ~NV_FLAG_ALL_MASK) != 0) {
709                 ERRNO_SET(EINVAL);
710                 return (false);
711         }
712 #if BYTE_ORDER == BIG_ENDIAN
713         if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) == 0) {
714                 nvlhdrp->nvlh_size = le64toh(nvlhdrp->nvlh_size);
715                 nvlhdrp->nvlh_descriptors = le64toh(nvlhdrp->nvlh_descriptors);
716         }
717 #else
718         if ((nvlhdrp->nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0) {
719                 nvlhdrp->nvlh_size = be64toh(nvlhdrp->nvlh_size);
720                 nvlhdrp->nvlh_descriptors = be64toh(nvlhdrp->nvlh_descriptors);
721         }
722 #endif
723         return (true);
724 }
725
726 const unsigned char *
727 nvlist_unpack_header(nvlist_t *nvl, const unsigned char *ptr, size_t nfds,
728     bool *isbep, size_t *leftp)
729 {
730         struct nvlist_header nvlhdr;
731
732         if (*leftp < sizeof(nvlhdr))
733                 goto failed;
734
735         memcpy(&nvlhdr, ptr, sizeof(nvlhdr));
736
737         if (!nvlist_check_header(&nvlhdr))
738                 goto failed;
739
740         if (nvlhdr.nvlh_size != *leftp - sizeof(nvlhdr))
741                 goto failed;
742
743         /*
744          * nvlh_descriptors might be smaller than nfds in embedded nvlists.
745          */
746         if (nvlhdr.nvlh_descriptors > nfds)
747                 goto failed;
748
749         if ((nvlhdr.nvlh_flags & ~NV_FLAG_ALL_MASK) != 0)
750                 goto failed;
751
752         nvl->nvl_flags = (nvlhdr.nvlh_flags & NV_FLAG_PUBLIC_MASK);
753
754         ptr += sizeof(nvlhdr);
755         if (isbep != NULL)
756                 *isbep = (((int)nvlhdr.nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0);
757         *leftp -= sizeof(nvlhdr);
758
759         return (ptr);
760 failed:
761         ERRNO_SET(EINVAL);
762         return (NULL);
763 }
764
765 static nvlist_t *
766 nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds)
767 {
768         const unsigned char *ptr;
769         nvlist_t *nvl, *retnvl, *tmpnvl;
770         nvpair_t *nvp;
771         size_t left;
772         bool isbe;
773
774         left = size;
775         ptr = buf;
776
777         tmpnvl = NULL;
778         nvl = retnvl = nvlist_create(0);
779         if (nvl == NULL)
780                 goto failed;
781
782         ptr = nvlist_unpack_header(nvl, ptr, nfds, &isbe, &left);
783         if (ptr == NULL)
784                 goto failed;
785
786         while (left > 0) {
787                 ptr = nvpair_unpack(isbe, ptr, &left, &nvp);
788                 if (ptr == NULL)
789                         goto failed;
790                 switch (nvpair_type(nvp)) {
791                 case NV_TYPE_NULL:
792                         ptr = nvpair_unpack_null(isbe, nvp, ptr, &left);
793                         break;
794                 case NV_TYPE_BOOL:
795                         ptr = nvpair_unpack_bool(isbe, nvp, ptr, &left);
796                         break;
797                 case NV_TYPE_NUMBER:
798                         ptr = nvpair_unpack_number(isbe, nvp, ptr, &left);
799                         break;
800                 case NV_TYPE_STRING:
801                         ptr = nvpair_unpack_string(isbe, nvp, ptr, &left);
802                         break;
803                 case NV_TYPE_NVLIST:
804                         ptr = nvpair_unpack_nvlist(isbe, nvp, ptr, &left, nfds,
805                             &tmpnvl);
806                         nvlist_set_parent(tmpnvl, nvp);
807                         break;
808 #ifndef _KERNEL
809                 case NV_TYPE_DESCRIPTOR:
810                         ptr = nvpair_unpack_descriptor(isbe, nvp, ptr, &left,
811                             fds, nfds);
812                         break;
813 #endif
814                 case NV_TYPE_BINARY:
815                         ptr = nvpair_unpack_binary(isbe, nvp, ptr, &left);
816                         break;
817                 case NV_TYPE_NVLIST_UP:
818                         if (nvl->nvl_parent == NULL)
819                                 goto failed;
820                         nvl = nvpair_nvlist(nvl->nvl_parent);
821                         continue;
822                 default:
823                         PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp));
824                 }
825                 if (ptr == NULL)
826                         goto failed;
827                 nvlist_move_nvpair(nvl, nvp);
828                 if (tmpnvl != NULL) {
829                         nvl = tmpnvl;
830                         tmpnvl = NULL;
831                 }
832         }
833
834         return (retnvl);
835 failed:
836         nvlist_destroy(retnvl);
837         return (NULL);
838 }
839
840 nvlist_t *
841 nvlist_unpack(const void *buf, size_t size)
842 {
843
844         return (nvlist_xunpack(buf, size, NULL, 0));
845 }
846
847 #ifndef _KERNEL
848 int
849 nvlist_send(int sock, const nvlist_t *nvl)
850 {
851         size_t datasize, nfds;
852         int *fds;
853         void *data;
854         int64_t fdidx;
855         int ret;
856
857         if (nvlist_error(nvl) != 0) {
858                 ERRNO_SET(nvlist_error(nvl));
859                 return (-1);
860         }
861
862         fds = nvlist_descriptors(nvl, &nfds);
863         if (fds == NULL)
864                 return (-1);
865
866         ret = -1;
867         data = NULL;
868         fdidx = 0;
869
870         data = nvlist_xpack(nvl, &fdidx, &datasize);
871         if (data == NULL)
872                 goto out;
873
874         if (buf_send(sock, data, datasize) == -1)
875                 goto out;
876
877         if (nfds > 0) {
878                 if (fd_send(sock, fds, nfds) == -1)
879                         goto out;
880         }
881
882         ret = 0;
883 out:
884         ERRNO_SAVE();
885         free(fds);
886         free(data);
887         ERRNO_RESTORE();
888         return (ret);
889 }
890
891 nvlist_t *
892 nvlist_recv(int sock)
893 {
894         struct nvlist_header nvlhdr;
895         nvlist_t *nvl, *ret;
896         unsigned char *buf;
897         size_t nfds, size, i;
898         int *fds;
899
900         if (buf_recv(sock, &nvlhdr, sizeof(nvlhdr)) == -1)
901                 return (NULL);
902
903         if (!nvlist_check_header(&nvlhdr))
904                 return (NULL);
905
906         nfds = (size_t)nvlhdr.nvlh_descriptors;
907         size = sizeof(nvlhdr) + (size_t)nvlhdr.nvlh_size;
908
909         buf = nv_malloc(size);
910         if (buf == NULL)
911                 return (NULL);
912
913         memcpy(buf, &nvlhdr, sizeof(nvlhdr));
914
915         ret = NULL;
916         fds = NULL;
917
918         if (buf_recv(sock, buf + sizeof(nvlhdr), size - sizeof(nvlhdr)) == -1)
919                 goto out;
920
921         if (nfds > 0) {
922                 fds = nv_malloc(nfds * sizeof(fds[0]));
923                 if (fds == NULL)
924                         goto out;
925                 if (fd_recv(sock, fds, nfds) == -1)
926                         goto out;
927         }
928
929         nvl = nvlist_xunpack(buf, size, fds, nfds);
930         if (nvl == NULL) {
931                 ERRNO_SAVE();
932                 for (i = 0; i < nfds; i++)
933                         close(fds[i]);
934                 ERRNO_RESTORE();
935                 goto out;
936         }
937
938         ret = nvl;
939 out:
940         ERRNO_SAVE();
941         free(buf);
942         free(fds);
943         ERRNO_RESTORE();
944
945         return (ret);
946 }
947
948 nvlist_t *
949 nvlist_xfer(int sock, nvlist_t *nvl)
950 {
951
952         if (nvlist_send(sock, nvl) < 0) {
953                 nvlist_destroy(nvl);
954                 return (NULL);
955         }
956         nvlist_destroy(nvl);
957         return (nvlist_recv(sock));
958 }
959 #endif
960
961 nvpair_t *
962 nvlist_first_nvpair(const nvlist_t *nvl)
963 {
964
965         NVLIST_ASSERT(nvl);
966
967         return (TAILQ_FIRST(&nvl->nvl_head));
968 }
969
970 nvpair_t *
971 nvlist_next_nvpair(const nvlist_t *nvl, const nvpair_t *nvp)
972 {
973         nvpair_t *retnvp;
974
975         NVLIST_ASSERT(nvl);
976         NVPAIR_ASSERT(nvp);
977         PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
978
979         retnvp = nvpair_next(nvp);
980         PJDLOG_ASSERT(retnvp == NULL || nvpair_nvlist(retnvp) == nvl);
981
982         return (retnvp);
983
984 }
985
986 nvpair_t *
987 nvlist_prev_nvpair(const nvlist_t *nvl, const nvpair_t *nvp)
988 {
989         nvpair_t *retnvp;
990
991         NVLIST_ASSERT(nvl);
992         NVPAIR_ASSERT(nvp);
993         PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
994
995         retnvp = nvpair_prev(nvp);
996         PJDLOG_ASSERT(nvpair_nvlist(retnvp) == nvl);
997
998         return (retnvp);
999 }
1000
1001 const char *
1002 nvlist_next(const nvlist_t *nvl, int *typep, void **cookiep)
1003 {
1004         nvpair_t *nvp;
1005
1006         NVLIST_ASSERT(nvl);
1007         PJDLOG_ASSERT(cookiep != NULL);
1008
1009         if (*cookiep == NULL)
1010                 nvp = nvlist_first_nvpair(nvl);
1011         else
1012                 nvp = nvlist_next_nvpair(nvl, *cookiep);
1013         if (nvp == NULL)
1014                 return (NULL);
1015         if (typep != NULL)
1016                 *typep = nvpair_type(nvp);
1017         *cookiep = nvp;
1018         return (nvpair_name(nvp));
1019 }
1020
1021 bool
1022 nvlist_exists(const nvlist_t *nvl, const char *name)
1023 {
1024
1025         return (nvlist_find(nvl, NV_TYPE_NONE, name) != NULL);
1026 }
1027
1028 #define NVLIST_EXISTS(type, TYPE)                                       \
1029 bool                                                                    \
1030 nvlist_exists_##type(const nvlist_t *nvl, const char *name)             \
1031 {                                                                       \
1032                                                                         \
1033         return (nvlist_find(nvl, NV_TYPE_##TYPE, name) != NULL);        \
1034 }
1035
1036 NVLIST_EXISTS(null, NULL)
1037 NVLIST_EXISTS(bool, BOOL)
1038 NVLIST_EXISTS(number, NUMBER)
1039 NVLIST_EXISTS(string, STRING)
1040 NVLIST_EXISTS(nvlist, NVLIST)
1041 #ifndef _KERNEL
1042 NVLIST_EXISTS(descriptor, DESCRIPTOR)
1043 #endif
1044 NVLIST_EXISTS(binary, BINARY)
1045
1046 #undef  NVLIST_EXISTS
1047
1048 void
1049 nvlist_add_nvpair(nvlist_t *nvl, const nvpair_t *nvp)
1050 {
1051         nvpair_t *newnvp;
1052
1053         NVPAIR_ASSERT(nvp);
1054
1055         if (nvlist_error(nvl) != 0) {
1056                 ERRNO_SET(nvlist_error(nvl));
1057                 return;
1058         }
1059         if (nvlist_exists(nvl, nvpair_name(nvp))) {
1060                 nvl->nvl_error = EEXIST;
1061                 ERRNO_SET(nvlist_error(nvl));
1062                 return;
1063         }
1064
1065         newnvp = nvpair_clone(nvp);
1066         if (newnvp == NULL) {
1067                 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1068                 ERRNO_SET(nvlist_error(nvl));
1069                 return;
1070         }
1071
1072         nvpair_insert(&nvl->nvl_head, newnvp, nvl);
1073 }
1074
1075 void
1076 nvlist_add_stringf(nvlist_t *nvl, const char *name, const char *valuefmt, ...)
1077 {
1078         va_list valueap;
1079
1080         va_start(valueap, valuefmt);
1081         nvlist_add_stringv(nvl, name, valuefmt, valueap);
1082         va_end(valueap);
1083 }
1084
1085 void
1086 nvlist_add_stringv(nvlist_t *nvl, const char *name, const char *valuefmt,
1087     va_list valueap)
1088 {
1089         nvpair_t *nvp;
1090
1091         if (nvlist_error(nvl) != 0) {
1092                 ERRNO_SET(nvlist_error(nvl));
1093                 return;
1094         }
1095
1096         nvp = nvpair_create_stringv(name, valuefmt, valueap);
1097         if (nvp == NULL) {
1098                 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1099                 ERRNO_SET(nvl->nvl_error);
1100         } else {
1101                 nvlist_move_nvpair(nvl, nvp);
1102         }
1103 }
1104
1105 void
1106 nvlist_add_null(nvlist_t *nvl, const char *name)
1107 {
1108         nvpair_t *nvp;
1109
1110         if (nvlist_error(nvl) != 0) {
1111                 ERRNO_SET(nvlist_error(nvl));
1112                 return;
1113         }
1114
1115         nvp = nvpair_create_null(name);
1116         if (nvp == NULL) {
1117                 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1118                 ERRNO_SET(nvl->nvl_error);
1119         } else {
1120                 nvlist_move_nvpair(nvl, nvp);
1121         }
1122 }
1123
1124 void
1125 nvlist_add_bool(nvlist_t *nvl, const char *name, bool value)
1126 {
1127         nvpair_t *nvp;
1128
1129         if (nvlist_error(nvl) != 0) {
1130                 ERRNO_SET(nvlist_error(nvl));
1131                 return;
1132         }
1133
1134         nvp = nvpair_create_bool(name, value);
1135         if (nvp == NULL) {
1136                 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1137                 ERRNO_SET(nvl->nvl_error);
1138         } else {
1139                 nvlist_move_nvpair(nvl, nvp);
1140         }
1141 }
1142
1143 void
1144 nvlist_add_number(nvlist_t *nvl, const char *name, uint64_t value)
1145 {
1146         nvpair_t *nvp;
1147
1148         if (nvlist_error(nvl) != 0) {
1149                 ERRNO_SET(nvlist_error(nvl));
1150                 return;
1151         }
1152
1153         nvp = nvpair_create_number(name, value);
1154         if (nvp == NULL) {
1155                 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1156                 ERRNO_SET(nvl->nvl_error);
1157         } else {
1158                 nvlist_move_nvpair(nvl, nvp);
1159         }
1160 }
1161
1162 void
1163 nvlist_add_string(nvlist_t *nvl, const char *name, const char *value)
1164 {
1165         nvpair_t *nvp;
1166
1167         if (nvlist_error(nvl) != 0) {
1168                 ERRNO_SET(nvlist_error(nvl));
1169                 return;
1170         }
1171
1172         nvp = nvpair_create_string(name, value);
1173         if (nvp == NULL) {
1174                 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1175                 ERRNO_SET(nvl->nvl_error);
1176         } else {
1177                 nvlist_move_nvpair(nvl, nvp);
1178         }
1179 }
1180
1181 void
1182 nvlist_add_nvlist(nvlist_t *nvl, const char *name, const nvlist_t *value)
1183 {
1184         nvpair_t *nvp;
1185
1186         if (nvlist_error(nvl) != 0) {
1187                 ERRNO_SET(nvlist_error(nvl));
1188                 return;
1189         }
1190
1191         nvp = nvpair_create_nvlist(name, value);
1192         if (nvp == NULL) {
1193                 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1194                 ERRNO_SET(nvl->nvl_error);
1195         } else {
1196                 nvlist_move_nvpair(nvl, nvp);
1197         }
1198 }
1199
1200 #ifndef _KERNEL
1201 void
1202 nvlist_add_descriptor(nvlist_t *nvl, const char *name, int value)
1203 {
1204         nvpair_t *nvp;
1205
1206         if (nvlist_error(nvl) != 0) {
1207                 errno = nvlist_error(nvl);
1208                 return;
1209         }
1210
1211         nvp = nvpair_create_descriptor(name, value);
1212         if (nvp == NULL)
1213                 nvl->nvl_error = errno = (errno != 0 ? errno : ENOMEM);
1214         else
1215                 nvlist_move_nvpair(nvl, nvp);
1216 }
1217 #endif
1218
1219 void
1220 nvlist_add_binary(nvlist_t *nvl, const char *name, const void *value,
1221     size_t size)
1222 {
1223         nvpair_t *nvp;
1224
1225         if (nvlist_error(nvl) != 0) {
1226                 ERRNO_SET(nvlist_error(nvl));
1227                 return;
1228         }
1229
1230         nvp = nvpair_create_binary(name, value, size);
1231         if (nvp == NULL) {
1232                 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1233                 ERRNO_SET(nvl->nvl_error);
1234         } else {
1235                 nvlist_move_nvpair(nvl, nvp);
1236         }
1237 }
1238
1239 void
1240 nvlist_move_nvpair(nvlist_t *nvl, nvpair_t *nvp)
1241 {
1242
1243         NVPAIR_ASSERT(nvp);
1244         PJDLOG_ASSERT(nvpair_nvlist(nvp) == NULL);
1245
1246         if (nvlist_error(nvl) != 0) {
1247                 nvpair_free(nvp);
1248                 ERRNO_SET(nvlist_error(nvl));
1249                 return;
1250         }
1251         if (nvlist_exists(nvl, nvpair_name(nvp))) {
1252                 nvpair_free(nvp);
1253                 nvl->nvl_error = EEXIST;
1254                 ERRNO_SET(nvl->nvl_error);
1255                 return;
1256         }
1257
1258         nvpair_insert(&nvl->nvl_head, nvp, nvl);
1259 }
1260
1261 void
1262 nvlist_move_string(nvlist_t *nvl, const char *name, char *value)
1263 {
1264         nvpair_t *nvp;
1265
1266         if (nvlist_error(nvl) != 0) {
1267                 nv_free(value);
1268                 ERRNO_SET(nvlist_error(nvl));
1269                 return;
1270         }
1271
1272         nvp = nvpair_move_string(name, value);
1273         if (nvp == NULL) {
1274                 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1275                 ERRNO_SET(nvl->nvl_error);
1276         } else {
1277                 nvlist_move_nvpair(nvl, nvp);
1278         }
1279 }
1280
1281 void
1282 nvlist_move_nvlist(nvlist_t *nvl, const char *name, nvlist_t *value)
1283 {
1284         nvpair_t *nvp;
1285
1286         if (nvlist_error(nvl) != 0) {
1287                 if (value != NULL && nvlist_get_nvpair_parent(value) != NULL)
1288                         nvlist_destroy(value);
1289                 ERRNO_SET(nvlist_error(nvl));
1290                 return;
1291         }
1292
1293         nvp = nvpair_move_nvlist(name, value);
1294         if (nvp == NULL) {
1295                 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1296                 ERRNO_SET(nvl->nvl_error);
1297         } else {
1298                 nvlist_move_nvpair(nvl, nvp);
1299         }
1300 }
1301
1302 #ifndef _KERNEL
1303 void
1304 nvlist_move_descriptor(nvlist_t *nvl, const char *name, int value)
1305 {
1306         nvpair_t *nvp;
1307
1308         if (nvlist_error(nvl) != 0) {
1309                 close(value);
1310                 ERRNO_SET(nvlist_error(nvl));
1311                 return;
1312         }
1313
1314         nvp = nvpair_move_descriptor(name, value);
1315         if (nvp == NULL) {
1316                 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1317                 ERRNO_SET(nvl->nvl_error);
1318         } else {
1319                 nvlist_move_nvpair(nvl, nvp);
1320         }
1321 }
1322 #endif
1323
1324 void
1325 nvlist_move_binary(nvlist_t *nvl, const char *name, void *value, size_t size)
1326 {
1327         nvpair_t *nvp;
1328
1329         if (nvlist_error(nvl) != 0) {
1330                 nv_free(value);
1331                 ERRNO_SET(nvlist_error(nvl));
1332                 return;
1333         }
1334
1335         nvp = nvpair_move_binary(name, value, size);
1336         if (nvp == NULL) {
1337                 nvl->nvl_error = ERRNO_OR_DEFAULT(ENOMEM);
1338                 ERRNO_SET(nvl->nvl_error);
1339         } else {
1340                 nvlist_move_nvpair(nvl, nvp);
1341         }
1342 }
1343
1344 const nvpair_t *
1345 nvlist_get_nvpair(const nvlist_t *nvl, const char *name)
1346 {
1347
1348         return (nvlist_find(nvl, NV_TYPE_NONE, name));
1349 }
1350
1351 #define NVLIST_GET(ftype, type, TYPE)                                   \
1352 ftype                                                                   \
1353 nvlist_get_##type(const nvlist_t *nvl, const char *name)                \
1354 {                                                                       \
1355         const nvpair_t *nvp;                                            \
1356                                                                         \
1357         nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name);                   \
1358         if (nvp == NULL)                                                \
1359                 nvlist_report_missing(NV_TYPE_##TYPE, name);            \
1360         return (nvpair_get_##type(nvp));                                \
1361 }
1362
1363 NVLIST_GET(bool, bool, BOOL)
1364 NVLIST_GET(uint64_t, number, NUMBER)
1365 NVLIST_GET(const char *, string, STRING)
1366 NVLIST_GET(const nvlist_t *, nvlist, NVLIST)
1367 #ifndef _KERNEL
1368 NVLIST_GET(int, descriptor, DESCRIPTOR)
1369 #endif
1370
1371 #undef  NVLIST_GET
1372
1373 const void *
1374 nvlist_get_binary(const nvlist_t *nvl, const char *name, size_t *sizep)
1375 {
1376         nvpair_t *nvp;
1377
1378         nvp = nvlist_find(nvl, NV_TYPE_BINARY, name);
1379         if (nvp == NULL)
1380                 nvlist_report_missing(NV_TYPE_BINARY, name);
1381
1382         return (nvpair_get_binary(nvp, sizep));
1383 }
1384
1385 #define NVLIST_TAKE(ftype, type, TYPE)                                  \
1386 ftype                                                                   \
1387 nvlist_take_##type(nvlist_t *nvl, const char *name)                     \
1388 {                                                                       \
1389         nvpair_t *nvp;                                                  \
1390         ftype value;                                                    \
1391                                                                         \
1392         nvp = nvlist_find(nvl, NV_TYPE_##TYPE, name);                   \
1393         if (nvp == NULL)                                                \
1394                 nvlist_report_missing(NV_TYPE_##TYPE, name);            \
1395         value = (ftype)(intptr_t)nvpair_get_##type(nvp);                \
1396         nvlist_remove_nvpair(nvl, nvp);                                 \
1397         nvpair_free_structure(nvp);                                     \
1398         return (value);                                                 \
1399 }
1400
1401 NVLIST_TAKE(bool, bool, BOOL)
1402 NVLIST_TAKE(uint64_t, number, NUMBER)
1403 NVLIST_TAKE(char *, string, STRING)
1404 NVLIST_TAKE(nvlist_t *, nvlist, NVLIST)
1405 #ifndef _KERNEL
1406 NVLIST_TAKE(int, descriptor, DESCRIPTOR)
1407 #endif
1408
1409 #undef  NVLIST_TAKE
1410
1411 void *
1412 nvlist_take_binary(nvlist_t *nvl, const char *name, size_t *sizep)
1413 {
1414         nvpair_t *nvp;
1415         void *value;
1416
1417         nvp = nvlist_find(nvl, NV_TYPE_BINARY, name);
1418         if (nvp == NULL)
1419                 nvlist_report_missing(NV_TYPE_BINARY, name);
1420
1421         value = (void *)(intptr_t)nvpair_get_binary(nvp, sizep);
1422         nvlist_remove_nvpair(nvl, nvp);
1423         nvpair_free_structure(nvp);
1424         return (value);
1425 }
1426
1427 void
1428 nvlist_remove_nvpair(nvlist_t *nvl, nvpair_t *nvp)
1429 {
1430
1431         NVLIST_ASSERT(nvl);
1432         NVPAIR_ASSERT(nvp);
1433         PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
1434
1435         nvpair_remove(&nvl->nvl_head, nvp, nvl);
1436 }
1437
1438 void
1439 nvlist_free(nvlist_t *nvl, const char *name)
1440 {
1441
1442         nvlist_free_type(nvl, name, NV_TYPE_NONE);
1443 }
1444
1445 #define NVLIST_FREE(type, TYPE)                                         \
1446 void                                                                    \
1447 nvlist_free_##type(nvlist_t *nvl, const char *name)                     \
1448 {                                                                       \
1449                                                                         \
1450         nvlist_free_type(nvl, name, NV_TYPE_##TYPE);                    \
1451 }
1452
1453 NVLIST_FREE(null, NULL)
1454 NVLIST_FREE(bool, BOOL)
1455 NVLIST_FREE(number, NUMBER)
1456 NVLIST_FREE(string, STRING)
1457 NVLIST_FREE(nvlist, NVLIST)
1458 #ifndef _KERNEL
1459 NVLIST_FREE(descriptor, DESCRIPTOR)
1460 #endif
1461 NVLIST_FREE(binary, BINARY)
1462
1463 #undef  NVLIST_FREE
1464
1465 void
1466 nvlist_free_nvpair(nvlist_t *nvl, nvpair_t *nvp)
1467 {
1468
1469         NVLIST_ASSERT(nvl);
1470         NVPAIR_ASSERT(nvp);
1471         PJDLOG_ASSERT(nvpair_nvlist(nvp) == nvl);
1472
1473         nvlist_remove_nvpair(nvl, nvp);
1474         nvpair_free(nvp);
1475 }
1476