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