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