2 * Copyright (c) 2009-2013 The FreeBSD Foundation
5 * This software was developed by Pawel Jakub Dawidek under sponsorship from
6 * the FreeBSD Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/param.h>
34 #include <sys/endian.h>
35 #include <sys/queue.h>
39 #include <sys/errno.h>
41 #include <sys/malloc.h>
42 #include <sys/systm.h>
44 #include <machine/stdarg.h>
56 #include "common_impl.h"
66 #include "nvlist_impl.h"
67 #include "nvpair_impl.h"
71 #define PJDLOG_ASSERT(...) MPASS(__VA_ARGS__)
72 #define PJDLOG_RASSERT(expr, ...) KASSERT(expr, (__VA_ARGS__))
73 #define PJDLOG_ABORT(...) panic(__VA_ARGS__)
76 #define PJDLOG_ASSERT(...) assert(__VA_ARGS__)
77 #define PJDLOG_RASSERT(expr, ...) assert(expr)
78 #define PJDLOG_ABORT(...) abort()
82 #define NVPAIR_MAGIC 0x6e7670 /* "nvp" */
90 TAILQ_ENTRY(nvpair) nvp_next;
93 #define NVPAIR_ASSERT(nvp) do { \
94 PJDLOG_ASSERT((nvp) != NULL); \
95 PJDLOG_ASSERT((nvp)->nvp_magic == NVPAIR_MAGIC); \
98 struct nvpair_header {
100 uint16_t nvph_namesize;
101 uint64_t nvph_datasize;
106 nvpair_assert(const nvpair_t *nvp)
113 nvpair_nvlist(const nvpair_t *nvp)
118 return (nvp->nvp_list);
122 nvpair_next(const nvpair_t *nvp)
126 PJDLOG_ASSERT(nvp->nvp_list != NULL);
128 return (TAILQ_NEXT(nvp, nvp_next));
132 nvpair_prev(const nvpair_t *nvp)
136 PJDLOG_ASSERT(nvp->nvp_list != NULL);
138 return (TAILQ_PREV(nvp, nvl_head, nvp_next));
142 nvpair_insert(struct nvl_head *head, nvpair_t *nvp, nvlist_t *nvl)
146 PJDLOG_ASSERT(nvp->nvp_list == NULL);
147 PJDLOG_ASSERT((nvlist_flags(nvl) & NV_FLAG_NO_UNIQUE) != 0 ||
148 !nvlist_exists(nvl, nvpair_name(nvp)));
150 TAILQ_INSERT_TAIL(head, nvp, nvp_next);
155 nvpair_remove_nvlist(nvpair_t *nvp)
159 /* XXX: DECONST is bad, mkay? */
160 nvl = __DECONST(nvlist_t *, nvpair_get_nvlist(nvp));
161 PJDLOG_ASSERT(nvl != NULL);
162 nvlist_set_parent(nvl, NULL);
166 nvpair_remove(struct nvl_head *head, nvpair_t *nvp, const nvlist_t *nvl)
170 PJDLOG_ASSERT(nvp->nvp_list == nvl);
172 if (nvpair_type(nvp) == NV_TYPE_NVLIST)
173 nvpair_remove_nvlist(nvp);
175 TAILQ_REMOVE(head, nvp, nvp_next);
176 nvp->nvp_list = NULL;
180 nvpair_clone(const nvpair_t *nvp)
189 name = nvpair_name(nvp);
191 switch (nvpair_type(nvp)) {
193 newnvp = nvpair_create_null(name);
196 newnvp = nvpair_create_bool(name, nvpair_get_bool(nvp));
199 newnvp = nvpair_create_number(name, nvpair_get_number(nvp));
202 newnvp = nvpair_create_string(name, nvpair_get_string(nvp));
205 newnvp = nvpair_create_nvlist(name, nvpair_get_nvlist(nvp));
208 case NV_TYPE_DESCRIPTOR:
209 newnvp = nvpair_create_descriptor(name,
210 nvpair_get_descriptor(nvp));
214 data = nvpair_get_binary(nvp, &datasize);
215 newnvp = nvpair_create_binary(name, data, datasize);
218 PJDLOG_ABORT("Unknown type: %d.", nvpair_type(nvp));
225 nvpair_header_size(void)
228 return (sizeof(struct nvpair_header));
232 nvpair_size(const nvpair_t *nvp)
237 return (nvp->nvp_datasize);
241 nvpair_pack_header(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
243 struct nvpair_header nvphdr;
248 nvphdr.nvph_type = nvp->nvp_type;
249 namesize = strlen(nvp->nvp_name) + 1;
250 PJDLOG_ASSERT(namesize > 0 && namesize <= UINT16_MAX);
251 nvphdr.nvph_namesize = namesize;
252 nvphdr.nvph_datasize = nvp->nvp_datasize;
253 PJDLOG_ASSERT(*leftp >= sizeof(nvphdr));
254 memcpy(ptr, &nvphdr, sizeof(nvphdr));
255 ptr += sizeof(nvphdr);
256 *leftp -= sizeof(nvphdr);
258 PJDLOG_ASSERT(*leftp >= namesize);
259 memcpy(ptr, nvp->nvp_name, namesize);
267 nvpair_pack_null(const nvpair_t *nvp, unsigned char *ptr,
268 size_t *leftp __unused)
272 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NULL);
278 nvpair_pack_bool(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
283 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL);
285 value = (uint8_t)nvp->nvp_data;
287 PJDLOG_ASSERT(*leftp >= sizeof(value));
288 memcpy(ptr, &value, sizeof(value));
289 ptr += sizeof(value);
290 *leftp -= sizeof(value);
296 nvpair_pack_number(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
301 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER);
303 value = (uint64_t)nvp->nvp_data;
305 PJDLOG_ASSERT(*leftp >= sizeof(value));
306 memcpy(ptr, &value, sizeof(value));
307 ptr += sizeof(value);
308 *leftp -= sizeof(value);
314 nvpair_pack_string(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
318 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
320 PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
321 memcpy(ptr, (const void *)(intptr_t)nvp->nvp_data, nvp->nvp_datasize);
322 ptr += nvp->nvp_datasize;
323 *leftp -= nvp->nvp_datasize;
329 nvpair_pack_nvlist_up(unsigned char *ptr, size_t *leftp)
331 struct nvpair_header nvphdr;
333 const char *name = "";
336 nvphdr.nvph_type = NV_TYPE_NVLIST_UP;
337 nvphdr.nvph_namesize = namesize;
338 nvphdr.nvph_datasize = 0;
339 PJDLOG_ASSERT(*leftp >= sizeof(nvphdr));
340 memcpy(ptr, &nvphdr, sizeof(nvphdr));
341 ptr += sizeof(nvphdr);
342 *leftp -= sizeof(nvphdr);
344 PJDLOG_ASSERT(*leftp >= namesize);
345 memcpy(ptr, name, namesize);
354 nvpair_pack_descriptor(const nvpair_t *nvp, unsigned char *ptr, int64_t *fdidxp,
360 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
362 value = (int64_t)nvp->nvp_data;
365 * If there is a real descriptor here, we change its number
366 * to position in the array of descriptors send via control
369 PJDLOG_ASSERT(fdidxp != NULL);
375 PJDLOG_ASSERT(*leftp >= sizeof(value));
376 memcpy(ptr, &value, sizeof(value));
377 ptr += sizeof(value);
378 *leftp -= sizeof(value);
385 nvpair_pack_binary(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
389 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
391 PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
392 memcpy(ptr, (const void *)(intptr_t)nvp->nvp_data, nvp->nvp_datasize);
393 ptr += nvp->nvp_datasize;
394 *leftp -= nvp->nvp_datasize;
400 nvpair_init_datasize(nvpair_t *nvp)
405 if (nvp->nvp_type == NV_TYPE_NVLIST) {
406 if (nvp->nvp_data == 0) {
407 nvp->nvp_datasize = 0;
410 nvlist_size((const nvlist_t *)(intptr_t)nvp->nvp_data);
415 const unsigned char *
416 nvpair_unpack_header(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
419 struct nvpair_header nvphdr;
421 if (*leftp < sizeof(nvphdr))
424 memcpy(&nvphdr, ptr, sizeof(nvphdr));
425 ptr += sizeof(nvphdr);
426 *leftp -= sizeof(nvphdr);
428 #if NV_TYPE_FIRST > 0
429 if (nvphdr.nvph_type < NV_TYPE_FIRST)
432 if (nvphdr.nvph_type > NV_TYPE_LAST &&
433 nvphdr.nvph_type != NV_TYPE_NVLIST_UP) {
437 #if BYTE_ORDER == BIG_ENDIAN
439 nvphdr.nvph_namesize = le16toh(nvphdr.nvph_namesize);
440 nvphdr.nvph_datasize = le64toh(nvphdr.nvph_datasize);
444 nvphdr.nvph_namesize = be16toh(nvphdr.nvph_namesize);
445 nvphdr.nvph_datasize = be64toh(nvphdr.nvph_datasize);
449 if (nvphdr.nvph_namesize > NV_NAME_MAX)
451 if (*leftp < nvphdr.nvph_namesize)
453 if (nvphdr.nvph_namesize < 1)
455 if (strnlen((const char *)ptr, nvphdr.nvph_namesize) !=
456 (size_t)(nvphdr.nvph_namesize - 1)) {
460 memcpy(nvp->nvp_name, ptr, nvphdr.nvph_namesize);
461 ptr += nvphdr.nvph_namesize;
462 *leftp -= nvphdr.nvph_namesize;
464 if (*leftp < nvphdr.nvph_datasize)
467 nvp->nvp_type = nvphdr.nvph_type;
469 nvp->nvp_datasize = nvphdr.nvph_datasize;
477 const unsigned char *
478 nvpair_unpack_null(bool isbe __unused, nvpair_t *nvp, const unsigned char *ptr,
479 size_t *leftp __unused)
482 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NULL);
484 if (nvp->nvp_datasize != 0) {
492 const unsigned char *
493 nvpair_unpack_bool(bool isbe __unused, nvpair_t *nvp, const unsigned char *ptr,
498 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL);
500 if (nvp->nvp_datasize != sizeof(value)) {
504 if (*leftp < sizeof(value)) {
509 memcpy(&value, ptr, sizeof(value));
510 ptr += sizeof(value);
511 *leftp -= sizeof(value);
513 if (value != 0 && value != 1) {
518 nvp->nvp_data = (uint64_t)value;
523 const unsigned char *
524 nvpair_unpack_number(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
528 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER);
530 if (nvp->nvp_datasize != sizeof(uint64_t)) {
534 if (*leftp < sizeof(uint64_t)) {
540 nvp->nvp_data = be64dec(ptr);
542 nvp->nvp_data = le64dec(ptr);
543 ptr += sizeof(uint64_t);
544 *leftp -= sizeof(uint64_t);
549 const unsigned char *
550 nvpair_unpack_string(bool isbe __unused, nvpair_t *nvp,
551 const unsigned char *ptr, size_t *leftp)
554 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
556 if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
561 if (strnlen((const char *)ptr, nvp->nvp_datasize) !=
562 nvp->nvp_datasize - 1) {
567 nvp->nvp_data = (uint64_t)(uintptr_t)nv_strdup((const char *)ptr);
568 if (nvp->nvp_data == 0)
571 ptr += nvp->nvp_datasize;
572 *leftp -= nvp->nvp_datasize;
577 const unsigned char *
578 nvpair_unpack_nvlist(bool isbe __unused, nvpair_t *nvp,
579 const unsigned char *ptr, size_t *leftp, size_t nfds, nvlist_t **child)
583 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST);
585 if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
590 value = nvlist_create(0);
594 ptr = nvlist_unpack_header(value, ptr, nfds, NULL, leftp);
598 nvp->nvp_data = (uint64_t)(uintptr_t)value;
605 const unsigned char *
606 nvpair_unpack_descriptor(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
607 size_t *leftp, const int *fds, size_t nfds)
611 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
613 if (nvp->nvp_datasize != sizeof(idx)) {
617 if (*leftp < sizeof(idx)) {
632 if ((size_t)idx >= nfds) {
637 nvp->nvp_data = (uint64_t)fds[idx];
640 *leftp -= sizeof(idx);
646 const unsigned char *
647 nvpair_unpack_binary(bool isbe __unused, nvpair_t *nvp,
648 const unsigned char *ptr, size_t *leftp)
652 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
654 if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
659 value = nv_malloc(nvp->nvp_datasize);
663 memcpy(value, ptr, nvp->nvp_datasize);
664 ptr += nvp->nvp_datasize;
665 *leftp -= nvp->nvp_datasize;
667 nvp->nvp_data = (uint64_t)(uintptr_t)value;
672 const unsigned char *
673 nvpair_unpack(bool isbe, const unsigned char *ptr, size_t *leftp,
678 nvp = nv_calloc(1, sizeof(*nvp) + NV_NAME_MAX);
681 nvp->nvp_name = (char *)(nvp + 1);
683 ptr = nvpair_unpack_header(isbe, nvp, ptr, leftp);
686 tmp = nv_realloc(nvp, sizeof(*nvp) + strlen(nvp->nvp_name) + 1);
691 /* Update nvp_name after realloc(). */
692 nvp->nvp_name = (char *)(nvp + 1);
693 nvp->nvp_data = 0x00;
694 nvp->nvp_magic = NVPAIR_MAGIC;
703 nvpair_type(const nvpair_t *nvp)
708 return (nvp->nvp_type);
712 nvpair_name(const nvpair_t *nvp)
717 return (nvp->nvp_name);
721 nvpair_allocv(const char *name, int type, uint64_t data, size_t datasize)
726 PJDLOG_ASSERT(type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST);
728 namelen = strlen(name);
729 if (namelen >= NV_NAME_MAX) {
730 ERRNO_SET(ENAMETOOLONG);
734 nvp = nv_calloc(1, sizeof(*nvp) + namelen + 1);
736 nvp->nvp_name = (char *)(nvp + 1);
737 memcpy(nvp->nvp_name, name, namelen);
738 nvp->nvp_name[namelen] = '\0';
739 nvp->nvp_type = type;
740 nvp->nvp_data = data;
741 nvp->nvp_datasize = datasize;
742 nvp->nvp_magic = NVPAIR_MAGIC;
749 nvpair_create_stringf(const char *name, const char *valuefmt, ...)
754 va_start(valueap, valuefmt);
755 nvp = nvpair_create_stringv(name, valuefmt, valueap);
762 nvpair_create_stringv(const char *name, const char *valuefmt, va_list valueap)
768 len = nv_vasprintf(&str, valuefmt, valueap);
771 nvp = nvpair_create_string(name, str);
778 nvpair_create_null(const char *name)
781 return (nvpair_allocv(name, NV_TYPE_NULL, 0, 0));
785 nvpair_create_bool(const char *name, bool value)
788 return (nvpair_allocv(name, NV_TYPE_BOOL, value ? 1 : 0,
793 nvpair_create_number(const char *name, uint64_t value)
796 return (nvpair_allocv(name, NV_TYPE_NUMBER, value, sizeof(value)));
800 nvpair_create_string(const char *name, const char *value)
811 data = nv_strdup(value);
814 size = strlen(value) + 1;
816 nvp = nvpair_allocv(name, NV_TYPE_STRING, (uint64_t)(uintptr_t)data,
825 nvpair_create_nvlist(const char *name, const nvlist_t *value)
835 nvl = nvlist_clone(value);
839 nvp = nvpair_allocv(name, NV_TYPE_NVLIST, (uint64_t)(uintptr_t)nvl, 0);
843 nvlist_set_parent(nvl, nvp);
850 nvpair_create_descriptor(const char *name, int value)
854 if (value < 0 || !fd_is_valid(value)) {
859 value = fcntl(value, F_DUPFD_CLOEXEC, 0);
863 nvp = nvpair_allocv(name, NV_TYPE_DESCRIPTOR, (uint64_t)value,
876 nvpair_create_binary(const char *name, const void *value, size_t size)
881 if (value == NULL || size == 0) {
886 data = nv_malloc(size);
889 memcpy(data, value, size);
891 nvp = nvpair_allocv(name, NV_TYPE_BINARY, (uint64_t)(uintptr_t)data,
900 nvpair_move_string(const char *name, char *value)
909 nvp = nvpair_allocv(name, NV_TYPE_STRING, (uint64_t)(uintptr_t)value,
921 nvpair_move_nvlist(const char *name, nvlist_t *value)
925 if (value == NULL || nvlist_get_nvpair_parent(value) != NULL) {
930 if (nvlist_error(value) != 0) {
931 ERRNO_SET(nvlist_error(value));
932 nvlist_destroy(value);
936 nvp = nvpair_allocv(name, NV_TYPE_NVLIST, (uint64_t)(uintptr_t)value,
939 nvlist_destroy(value);
941 nvlist_set_parent(value, nvp);
948 nvpair_move_descriptor(const char *name, int value)
952 if (value < 0 || !fd_is_valid(value)) {
957 nvp = nvpair_allocv(name, NV_TYPE_DESCRIPTOR, (uint64_t)value,
970 nvpair_move_binary(const char *name, void *value, size_t size)
974 if (value == NULL || size == 0) {
979 nvp = nvpair_allocv(name, NV_TYPE_BINARY, (uint64_t)(uintptr_t)value,
991 nvpair_get_bool(const nvpair_t *nvp)
996 return (nvp->nvp_data == 1);
1000 nvpair_get_number(const nvpair_t *nvp)
1005 return (nvp->nvp_data);
1009 nvpair_get_string(const nvpair_t *nvp)
1013 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
1015 return ((const char *)(intptr_t)nvp->nvp_data);
1019 nvpair_get_nvlist(const nvpair_t *nvp)
1023 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST);
1025 return ((const nvlist_t *)(intptr_t)nvp->nvp_data);
1030 nvpair_get_descriptor(const nvpair_t *nvp)
1034 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
1036 return ((int)nvp->nvp_data);
1041 nvpair_get_binary(const nvpair_t *nvp, size_t *sizep)
1045 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
1048 *sizep = nvp->nvp_datasize;
1049 return ((const void *)(intptr_t)nvp->nvp_data);
1053 nvpair_free(nvpair_t *nvp)
1057 PJDLOG_ASSERT(nvp->nvp_list == NULL);
1060 switch (nvp->nvp_type) {
1062 case NV_TYPE_DESCRIPTOR:
1063 close((int)nvp->nvp_data);
1066 case NV_TYPE_NVLIST:
1067 nvlist_destroy((nvlist_t *)(intptr_t)nvp->nvp_data);
1069 case NV_TYPE_STRING:
1070 nv_free((char *)(intptr_t)nvp->nvp_data);
1072 case NV_TYPE_BINARY:
1073 nv_free((void *)(intptr_t)nvp->nvp_data);
1080 nvpair_free_structure(nvpair_t *nvp)
1084 PJDLOG_ASSERT(nvp->nvp_list == NULL);
1091 nvpair_type_string(int type)
1099 case NV_TYPE_NUMBER:
1101 case NV_TYPE_STRING:
1103 case NV_TYPE_NVLIST:
1105 case NV_TYPE_DESCRIPTOR:
1106 return ("DESCRIPTOR");
1107 case NV_TYPE_BINARY:
1110 return ("<UNKNOWN>");