]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/subr_nvpair.c
Must have one of either M_WAITOK or M_NOWAIT, read the man page bruno.
[FreeBSD/FreeBSD.git] / sys / kern / subr_nvpair.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/lock.h>
41 #include <sys/malloc.h>
42 #include <sys/systm.h>
43
44 #include <machine/stdarg.h>
45
46 #else
47 #include <errno.h>
48 #include <fcntl.h>
49 #include <stdarg.h>
50 #include <stdbool.h>
51 #include <stdint.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <unistd.h>
55
56 #include "common_impl.h"
57 #endif
58
59 #ifdef HAVE_PJDLOG
60 #include <pjdlog.h>
61 #endif
62
63 #include <sys/nv.h>
64 #include <sys/nv_impl.h>
65 #include <sys/nvlist_impl.h>
66 #include <sys/nvpair_impl.h>
67
68 #ifndef HAVE_PJDLOG
69 #ifdef _KERNEL
70 #define PJDLOG_ASSERT(...)              MPASS(__VA_ARGS__)
71 #define PJDLOG_RASSERT(expr, ...)       KASSERT(expr, (__VA_ARGS__))
72 #define PJDLOG_ABORT(...)               panic(__VA_ARGS__)
73 #else
74 #include <assert.h>
75 #define PJDLOG_ASSERT(...)              assert(__VA_ARGS__)
76 #define PJDLOG_RASSERT(expr, ...)       assert(expr)
77 #define PJDLOG_ABORT(...)               abort()
78 #endif
79 #endif
80
81 #define NVPAIR_MAGIC    0x6e7670        /* "nvp" */
82 struct nvpair {
83         int              nvp_magic;
84         char            *nvp_name;
85         int              nvp_type;
86         uint64_t         nvp_data;
87         size_t           nvp_datasize;
88         nvlist_t        *nvp_list;
89         TAILQ_ENTRY(nvpair) nvp_next;
90 };
91
92 #define NVPAIR_ASSERT(nvp)      do {                                    \
93         PJDLOG_ASSERT((nvp) != NULL);                                   \
94         PJDLOG_ASSERT((nvp)->nvp_magic == NVPAIR_MAGIC);                \
95 } while (0)
96
97 struct nvpair_header {
98         uint8_t         nvph_type;
99         uint16_t        nvph_namesize;
100         uint64_t        nvph_datasize;
101 } __packed;
102
103
104 void
105 nvpair_assert(const nvpair_t *nvp)
106 {
107
108         NVPAIR_ASSERT(nvp);
109 }
110
111 nvlist_t *
112 nvpair_nvlist(const nvpair_t *nvp)
113 {
114
115         NVPAIR_ASSERT(nvp);
116
117         return (nvp->nvp_list);
118 }
119
120 nvpair_t *
121 nvpair_next(const nvpair_t *nvp)
122 {
123
124         NVPAIR_ASSERT(nvp);
125         PJDLOG_ASSERT(nvp->nvp_list != NULL);
126
127         return (TAILQ_NEXT(nvp, nvp_next));
128 }
129
130 nvpair_t *
131 nvpair_prev(const nvpair_t *nvp)
132 {
133
134         NVPAIR_ASSERT(nvp);
135         PJDLOG_ASSERT(nvp->nvp_list != NULL);
136
137         return (TAILQ_PREV(nvp, nvl_head, nvp_next));
138 }
139
140 void
141 nvpair_insert(struct nvl_head *head, nvpair_t *nvp, nvlist_t *nvl)
142 {
143
144         NVPAIR_ASSERT(nvp);
145         PJDLOG_ASSERT(nvp->nvp_list == NULL);
146         PJDLOG_ASSERT((nvlist_flags(nvl) & NV_FLAG_NO_UNIQUE) != 0 ||
147             !nvlist_exists(nvl, nvpair_name(nvp)));
148
149         TAILQ_INSERT_TAIL(head, nvp, nvp_next);
150         nvp->nvp_list = nvl;
151 }
152
153 static void
154 nvpair_remove_nvlist(nvpair_t *nvp)
155 {
156         nvlist_t *nvl;
157
158         /* XXX: DECONST is bad, mkay? */
159         nvl = __DECONST(nvlist_t *, nvpair_get_nvlist(nvp));
160         PJDLOG_ASSERT(nvl != NULL);
161         nvlist_set_parent(nvl, NULL);
162 }
163
164 void
165 nvpair_remove(struct nvl_head *head, nvpair_t *nvp, const nvlist_t *nvl)
166 {
167
168         NVPAIR_ASSERT(nvp);
169         PJDLOG_ASSERT(nvp->nvp_list == nvl);
170
171         if (nvpair_type(nvp) == NV_TYPE_NVLIST)
172                 nvpair_remove_nvlist(nvp);
173
174         TAILQ_REMOVE(head, nvp, nvp_next);
175         nvp->nvp_list = NULL;
176 }
177
178 nvpair_t *
179 nvpair_clone(const nvpair_t *nvp)
180 {
181         nvpair_t *newnvp;
182         const char *name;
183         const void *data;
184         size_t datasize;
185
186         NVPAIR_ASSERT(nvp);
187
188         name = nvpair_name(nvp);
189
190         switch (nvpair_type(nvp)) {
191         case NV_TYPE_NULL:
192                 newnvp = nvpair_create_null(name);
193                 break;
194         case NV_TYPE_BOOL:
195                 newnvp = nvpair_create_bool(name, nvpair_get_bool(nvp));
196                 break;
197         case NV_TYPE_NUMBER:
198                 newnvp = nvpair_create_number(name, nvpair_get_number(nvp));
199                 break;
200         case NV_TYPE_STRING:
201                 newnvp = nvpair_create_string(name, nvpair_get_string(nvp));
202                 break;
203         case NV_TYPE_NVLIST:
204                 newnvp = nvpair_create_nvlist(name, nvpair_get_nvlist(nvp));
205                 break;
206 #ifndef _KERNEL
207         case NV_TYPE_DESCRIPTOR:
208                 newnvp = nvpair_create_descriptor(name,
209                     nvpair_get_descriptor(nvp));
210                 break;
211 #endif
212         case NV_TYPE_BINARY:
213                 data = nvpair_get_binary(nvp, &datasize);
214                 newnvp = nvpair_create_binary(name, data, datasize);
215                 break;
216         default:
217                 PJDLOG_ABORT("Unknown type: %d.", nvpair_type(nvp));
218         }
219
220         return (newnvp);
221 }
222
223 size_t
224 nvpair_header_size(void)
225 {
226
227         return (sizeof(struct nvpair_header));
228 }
229
230 size_t
231 nvpair_size(const nvpair_t *nvp)
232 {
233
234         NVPAIR_ASSERT(nvp);
235
236         return (nvp->nvp_datasize);
237 }
238
239 unsigned char *
240 nvpair_pack_header(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
241 {
242         struct nvpair_header nvphdr;
243         size_t namesize;
244
245         NVPAIR_ASSERT(nvp);
246
247         nvphdr.nvph_type = nvp->nvp_type;
248         namesize = strlen(nvp->nvp_name) + 1;
249         PJDLOG_ASSERT(namesize > 0 && namesize <= UINT16_MAX);
250         nvphdr.nvph_namesize = namesize;
251         nvphdr.nvph_datasize = nvp->nvp_datasize;
252         PJDLOG_ASSERT(*leftp >= sizeof(nvphdr));
253         memcpy(ptr, &nvphdr, sizeof(nvphdr));
254         ptr += sizeof(nvphdr);
255         *leftp -= sizeof(nvphdr);
256
257         PJDLOG_ASSERT(*leftp >= namesize);
258         memcpy(ptr, nvp->nvp_name, namesize);
259         ptr += namesize;
260         *leftp -= namesize;
261
262         return (ptr);
263 }
264
265 unsigned char *
266 nvpair_pack_null(const nvpair_t *nvp, unsigned char *ptr,
267     size_t *leftp __unused)
268 {
269
270         NVPAIR_ASSERT(nvp);
271         PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NULL);
272
273         return (ptr);
274 }
275
276 unsigned char *
277 nvpair_pack_bool(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
278 {
279         uint8_t value;
280
281         NVPAIR_ASSERT(nvp);
282         PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL);
283
284         value = (uint8_t)nvp->nvp_data;
285
286         PJDLOG_ASSERT(*leftp >= sizeof(value));
287         memcpy(ptr, &value, sizeof(value));
288         ptr += sizeof(value);
289         *leftp -= sizeof(value);
290
291         return (ptr);
292 }
293
294 unsigned char *
295 nvpair_pack_number(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
296 {
297         uint64_t value;
298
299         NVPAIR_ASSERT(nvp);
300         PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER);
301
302         value = (uint64_t)nvp->nvp_data;
303
304         PJDLOG_ASSERT(*leftp >= sizeof(value));
305         memcpy(ptr, &value, sizeof(value));
306         ptr += sizeof(value);
307         *leftp -= sizeof(value);
308
309         return (ptr);
310 }
311
312 unsigned char *
313 nvpair_pack_string(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
314 {
315
316         NVPAIR_ASSERT(nvp);
317         PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
318
319         PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
320         memcpy(ptr, (const void *)(intptr_t)nvp->nvp_data, nvp->nvp_datasize);
321         ptr += nvp->nvp_datasize;
322         *leftp -= nvp->nvp_datasize;
323
324         return (ptr);
325 }
326
327 unsigned char *
328 nvpair_pack_nvlist_up(unsigned char *ptr, size_t *leftp)
329 {
330         struct nvpair_header nvphdr;
331         size_t namesize;
332         const char *name = "";
333
334         namesize = 1;
335         nvphdr.nvph_type = NV_TYPE_NVLIST_UP;
336         nvphdr.nvph_namesize = namesize;
337         nvphdr.nvph_datasize = 0;
338         PJDLOG_ASSERT(*leftp >= sizeof(nvphdr));
339         memcpy(ptr, &nvphdr, sizeof(nvphdr));
340         ptr += sizeof(nvphdr);
341         *leftp -= sizeof(nvphdr);
342
343         PJDLOG_ASSERT(*leftp >= namesize);
344         memcpy(ptr, name, namesize);
345         ptr += namesize;
346         *leftp -= namesize;
347
348         return (ptr);
349 }
350
351 #ifndef _KERNEL
352 unsigned char *
353 nvpair_pack_descriptor(const nvpair_t *nvp, unsigned char *ptr, int64_t *fdidxp,
354     size_t *leftp)
355 {
356         int64_t value;
357
358         NVPAIR_ASSERT(nvp);
359         PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
360
361         value = (int64_t)nvp->nvp_data;
362         if (value != -1) {
363                 /*
364                  * If there is a real descriptor here, we change its number
365                  * to position in the array of descriptors send via control
366                  * message.
367                  */
368                 PJDLOG_ASSERT(fdidxp != NULL);
369
370                 value = *fdidxp;
371                 (*fdidxp)++;
372         }
373
374         PJDLOG_ASSERT(*leftp >= sizeof(value));
375         memcpy(ptr, &value, sizeof(value));
376         ptr += sizeof(value);
377         *leftp -= sizeof(value);
378
379         return (ptr);
380 }
381 #endif
382
383 unsigned char *
384 nvpair_pack_binary(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
385 {
386
387         NVPAIR_ASSERT(nvp);
388         PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
389
390         PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
391         memcpy(ptr, (const void *)(intptr_t)nvp->nvp_data, nvp->nvp_datasize);
392         ptr += nvp->nvp_datasize;
393         *leftp -= nvp->nvp_datasize;
394
395         return (ptr);
396 }
397
398 void
399 nvpair_init_datasize(nvpair_t *nvp)
400 {
401
402         NVPAIR_ASSERT(nvp);
403
404         if (nvp->nvp_type == NV_TYPE_NVLIST) {
405                 if (nvp->nvp_data == 0) {
406                         nvp->nvp_datasize = 0;
407                 } else {
408                         nvp->nvp_datasize =
409                             nvlist_size((const nvlist_t *)(intptr_t)nvp->nvp_data);
410                 }
411         }
412 }
413
414 const unsigned char *
415 nvpair_unpack_header(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
416     size_t *leftp)
417 {
418         struct nvpair_header nvphdr;
419
420         if (*leftp < sizeof(nvphdr))
421                 goto failed;
422
423         memcpy(&nvphdr, ptr, sizeof(nvphdr));
424         ptr += sizeof(nvphdr);
425         *leftp -= sizeof(nvphdr);
426
427 #if NV_TYPE_FIRST > 0
428         if (nvphdr.nvph_type < NV_TYPE_FIRST)
429                 goto failed;
430 #endif
431         if (nvphdr.nvph_type > NV_TYPE_LAST &&
432             nvphdr.nvph_type != NV_TYPE_NVLIST_UP) {
433                 goto failed;
434         }
435
436 #if BYTE_ORDER == BIG_ENDIAN
437         if (!isbe) {
438                 nvphdr.nvph_namesize = le16toh(nvphdr.nvph_namesize);
439                 nvphdr.nvph_datasize = le64toh(nvphdr.nvph_datasize);
440         }
441 #else
442         if (isbe) {
443                 nvphdr.nvph_namesize = be16toh(nvphdr.nvph_namesize);
444                 nvphdr.nvph_datasize = be64toh(nvphdr.nvph_datasize);
445         }
446 #endif
447
448         if (nvphdr.nvph_namesize > NV_NAME_MAX)
449                 goto failed;
450         if (*leftp < nvphdr.nvph_namesize)
451                 goto failed;
452         if (nvphdr.nvph_namesize < 1)
453                 goto failed;
454         if (strnlen((const char *)ptr, nvphdr.nvph_namesize) !=
455             (size_t)(nvphdr.nvph_namesize - 1)) {
456                 goto failed;
457         }
458
459         memcpy(nvp->nvp_name, ptr, nvphdr.nvph_namesize);
460         ptr += nvphdr.nvph_namesize;
461         *leftp -= nvphdr.nvph_namesize;
462
463         if (*leftp < nvphdr.nvph_datasize)
464                 goto failed;
465
466         nvp->nvp_type = nvphdr.nvph_type;
467         nvp->nvp_data = 0;
468         nvp->nvp_datasize = nvphdr.nvph_datasize;
469
470         return (ptr);
471 failed:
472         ERRNO_SET(EINVAL);
473         return (NULL);
474 }
475
476 const unsigned char *
477 nvpair_unpack_null(bool isbe __unused, nvpair_t *nvp, const unsigned char *ptr,
478     size_t *leftp __unused)
479 {
480
481         PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NULL);
482
483         if (nvp->nvp_datasize != 0) {
484                 ERRNO_SET(EINVAL);
485                 return (NULL);
486         }
487
488         return (ptr);
489 }
490
491 const unsigned char *
492 nvpair_unpack_bool(bool isbe __unused, nvpair_t *nvp, const unsigned char *ptr,
493     size_t *leftp)
494 {
495         uint8_t value;
496
497         PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL);
498
499         if (nvp->nvp_datasize != sizeof(value)) {
500                 ERRNO_SET(EINVAL);
501                 return (NULL);
502         }
503         if (*leftp < sizeof(value)) {
504                 ERRNO_SET(EINVAL);
505                 return (NULL);
506         }
507
508         memcpy(&value, ptr, sizeof(value));
509         ptr += sizeof(value);
510         *leftp -= sizeof(value);
511
512         if (value != 0 && value != 1) {
513                 ERRNO_SET(EINVAL);
514                 return (NULL);
515         }
516
517         nvp->nvp_data = (uint64_t)value;
518
519         return (ptr);
520 }
521
522 const unsigned char *
523 nvpair_unpack_number(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
524      size_t *leftp)
525 {
526
527         PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER);
528
529         if (nvp->nvp_datasize != sizeof(uint64_t)) {
530                 ERRNO_SET(EINVAL);
531                 return (NULL);
532         }
533         if (*leftp < sizeof(uint64_t)) {
534                 ERRNO_SET(EINVAL);
535                 return (NULL);
536         }
537
538         if (isbe)
539                 nvp->nvp_data = be64dec(ptr);
540         else
541                 nvp->nvp_data = le64dec(ptr);
542         ptr += sizeof(uint64_t);
543         *leftp -= sizeof(uint64_t);
544
545         return (ptr);
546 }
547
548 const unsigned char *
549 nvpair_unpack_string(bool isbe __unused, nvpair_t *nvp,
550     const unsigned char *ptr, size_t *leftp)
551 {
552
553         PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
554
555         if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
556                 ERRNO_SET(EINVAL);
557                 return (NULL);
558         }
559
560         if (strnlen((const char *)ptr, nvp->nvp_datasize) !=
561             nvp->nvp_datasize - 1) {
562                 ERRNO_SET(EINVAL);
563                 return (NULL);
564         }
565
566         nvp->nvp_data = (uint64_t)(uintptr_t)nv_strdup((const char *)ptr);
567         if (nvp->nvp_data == 0)
568                 return (NULL);
569
570         ptr += nvp->nvp_datasize;
571         *leftp -= nvp->nvp_datasize;
572
573         return (ptr);
574 }
575
576 const unsigned char *
577 nvpair_unpack_nvlist(bool isbe __unused, nvpair_t *nvp,
578     const unsigned char *ptr, size_t *leftp, size_t nfds, nvlist_t **child)
579 {
580         nvlist_t *value;
581
582         PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST);
583
584         if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
585                 ERRNO_SET(EINVAL);
586                 return (NULL);
587         }
588
589         value = nvlist_create(0);
590         if (value == NULL)
591                 return (NULL);
592
593         ptr = nvlist_unpack_header(value, ptr, nfds, NULL, leftp);
594         if (ptr == NULL)
595                 return (NULL);
596
597         nvp->nvp_data = (uint64_t)(uintptr_t)value;
598         *child = value;
599
600         return (ptr);
601 }
602
603 #ifndef _KERNEL
604 const unsigned char *
605 nvpair_unpack_descriptor(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
606     size_t *leftp, const int *fds, size_t nfds)
607 {
608         int64_t idx;
609
610         PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
611
612         if (nvp->nvp_datasize != sizeof(idx)) {
613                 ERRNO_SET(EINVAL);
614                 return (NULL);
615         }
616         if (*leftp < sizeof(idx)) {
617                 ERRNO_SET(EINVAL);
618                 return (NULL);
619         }
620
621         if (isbe)
622                 idx = be64dec(ptr);
623         else
624                 idx = le64dec(ptr);
625
626         if (idx < 0) {
627                 ERRNO_SET(EINVAL);
628                 return (NULL);
629         }
630
631         if ((size_t)idx >= nfds) {
632                 ERRNO_SET(EINVAL);
633                 return (NULL);
634         }
635
636         nvp->nvp_data = (uint64_t)fds[idx];
637
638         ptr += sizeof(idx);
639         *leftp -= sizeof(idx);
640
641         return (ptr);
642 }
643 #endif
644
645 const unsigned char *
646 nvpair_unpack_binary(bool isbe __unused, nvpair_t *nvp,
647     const unsigned char *ptr, size_t *leftp)
648 {
649         void *value;
650
651         PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
652
653         if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
654                 ERRNO_SET(EINVAL);
655                 return (NULL);
656         }
657
658         value = nv_malloc(nvp->nvp_datasize);
659         if (value == NULL)
660                 return (NULL);
661
662         memcpy(value, ptr, nvp->nvp_datasize);
663         ptr += nvp->nvp_datasize;
664         *leftp -= nvp->nvp_datasize;
665
666         nvp->nvp_data = (uint64_t)(uintptr_t)value;
667
668         return (ptr);
669 }
670
671 const unsigned char *
672 nvpair_unpack(bool isbe, const unsigned char *ptr, size_t *leftp,
673     nvpair_t **nvpp)
674 {
675         nvpair_t *nvp, *tmp;
676
677         nvp = nv_calloc(1, sizeof(*nvp) + NV_NAME_MAX);
678         if (nvp == NULL)
679                 return (NULL);
680         nvp->nvp_name = (char *)(nvp + 1);
681
682         ptr = nvpair_unpack_header(isbe, nvp, ptr, leftp);
683         if (ptr == NULL)
684                 goto failed;
685         tmp = nv_realloc(nvp, sizeof(*nvp) + strlen(nvp->nvp_name) + 1);
686         if (tmp == NULL)
687                 goto failed;
688         nvp = tmp;
689
690         /* Update nvp_name after realloc(). */
691         nvp->nvp_name = (char *)(nvp + 1);
692         nvp->nvp_data = 0x00;
693         nvp->nvp_magic = NVPAIR_MAGIC;
694         *nvpp = nvp;
695         return (ptr);
696 failed:
697         nv_free(nvp);
698         return (NULL);
699 }
700
701 int
702 nvpair_type(const nvpair_t *nvp)
703 {
704
705         NVPAIR_ASSERT(nvp);
706
707         return (nvp->nvp_type);
708 }
709
710 const char *
711 nvpair_name(const nvpair_t *nvp)
712 {
713
714         NVPAIR_ASSERT(nvp);
715
716         return (nvp->nvp_name);
717 }
718
719 static nvpair_t *
720 nvpair_allocv(const char *name, int type, uint64_t data, size_t datasize)
721 {
722         nvpair_t *nvp;
723         size_t namelen;
724
725         PJDLOG_ASSERT(type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST);
726
727         namelen = strlen(name);
728         if (namelen >= NV_NAME_MAX) {
729                 ERRNO_SET(ENAMETOOLONG);
730                 return (NULL);
731         }
732
733         nvp = nv_calloc(1, sizeof(*nvp) + namelen + 1);
734         if (nvp != NULL) {
735                 nvp->nvp_name = (char *)(nvp + 1);
736                 memcpy(nvp->nvp_name, name, namelen);
737                 nvp->nvp_name[namelen] = '\0';
738                 nvp->nvp_type = type;
739                 nvp->nvp_data = data;
740                 nvp->nvp_datasize = datasize;
741                 nvp->nvp_magic = NVPAIR_MAGIC;
742         }
743
744         return (nvp);
745 }
746
747 nvpair_t *
748 nvpair_create_stringf(const char *name, const char *valuefmt, ...)
749 {
750         va_list valueap;
751         nvpair_t *nvp;
752
753         va_start(valueap, valuefmt);
754         nvp = nvpair_create_stringv(name, valuefmt, valueap);
755         va_end(valueap);
756
757         return (nvp);
758 }
759
760 nvpair_t *
761 nvpair_create_stringv(const char *name, const char *valuefmt, va_list valueap)
762 {
763         nvpair_t *nvp;
764         char *str;
765         int len;
766
767         len = nv_vasprintf(&str, valuefmt, valueap);
768         if (len < 0)
769                 return (NULL);
770         nvp = nvpair_create_string(name, str);
771         if (nvp == NULL)
772                 nv_free(str);
773         return (nvp);
774 }
775
776 nvpair_t *
777 nvpair_create_null(const char *name)
778 {
779
780         return (nvpair_allocv(name, NV_TYPE_NULL, 0, 0));
781 }
782
783 nvpair_t *
784 nvpair_create_bool(const char *name, bool value)
785 {
786
787         return (nvpair_allocv(name, NV_TYPE_BOOL, value ? 1 : 0,
788             sizeof(uint8_t)));
789 }
790
791 nvpair_t *
792 nvpair_create_number(const char *name, uint64_t value)
793 {
794
795         return (nvpair_allocv(name, NV_TYPE_NUMBER, value, sizeof(value)));
796 }
797
798 nvpair_t *
799 nvpair_create_string(const char *name, const char *value)
800 {
801         nvpair_t *nvp;
802         size_t size;
803         char *data;
804
805         if (value == NULL) {
806                 ERRNO_SET(EINVAL);
807                 return (NULL);
808         }
809
810         data = nv_strdup(value);
811         if (data == NULL)
812                 return (NULL);
813         size = strlen(value) + 1;
814
815         nvp = nvpair_allocv(name, NV_TYPE_STRING, (uint64_t)(uintptr_t)data,
816             size);
817         if (nvp == NULL)
818                 nv_free(data);
819
820         return (nvp);
821 }
822
823 nvpair_t *
824 nvpair_create_nvlist(const char *name, const nvlist_t *value)
825 {
826         nvlist_t *nvl;
827         nvpair_t *nvp;
828
829         if (value == NULL) {
830                 ERRNO_SET(EINVAL);
831                 return (NULL);
832         }
833
834         nvl = nvlist_clone(value);
835         if (nvl == NULL)
836                 return (NULL);
837
838         nvp = nvpair_allocv(name, NV_TYPE_NVLIST, (uint64_t)(uintptr_t)nvl, 0);
839         if (nvp == NULL)
840                 nvlist_destroy(nvl);
841         else
842                 nvlist_set_parent(nvl, nvp);
843
844         return (nvp);
845 }
846
847 #ifndef _KERNEL
848 nvpair_t *
849 nvpair_create_descriptor(const char *name, int value)
850 {
851         nvpair_t *nvp;
852
853         if (value < 0 || !fd_is_valid(value)) {
854                 ERRNO_SET(EBADF);
855                 return (NULL);
856         }
857
858         value = fcntl(value, F_DUPFD_CLOEXEC, 0);
859         if (value < 0)
860                 return (NULL);
861
862         nvp = nvpair_allocv(name, NV_TYPE_DESCRIPTOR, (uint64_t)value,
863             sizeof(int64_t));
864         if (nvp == NULL) {
865                 ERRNO_SAVE();
866                 close(value);
867                 ERRNO_RESTORE();
868         }
869
870         return (nvp);
871 }
872 #endif
873
874 nvpair_t *
875 nvpair_create_binary(const char *name, const void *value, size_t size)
876 {
877         nvpair_t *nvp;
878         void *data;
879
880         if (value == NULL || size == 0) {
881                 ERRNO_SET(EINVAL);
882                 return (NULL);
883         }
884
885         data = nv_malloc(size);
886         if (data == NULL)
887                 return (NULL);
888         memcpy(data, value, size);
889
890         nvp = nvpair_allocv(name, NV_TYPE_BINARY, (uint64_t)(uintptr_t)data,
891             size);
892         if (nvp == NULL)
893                 nv_free(data);
894
895         return (nvp);
896 }
897
898 nvpair_t *
899 nvpair_move_string(const char *name, char *value)
900 {
901         nvpair_t *nvp;
902
903         if (value == NULL) {
904                 ERRNO_SET(EINVAL);
905                 return (NULL);
906         }
907
908         nvp = nvpair_allocv(name, NV_TYPE_STRING, (uint64_t)(uintptr_t)value,
909             strlen(value) + 1);
910         if (nvp == NULL) {
911                 ERRNO_SAVE();
912                 nv_free(value);
913                 ERRNO_RESTORE();
914         }
915
916         return (nvp);
917 }
918
919 nvpair_t *
920 nvpair_move_nvlist(const char *name, nvlist_t *value)
921 {
922         nvpair_t *nvp;
923
924         if (value == NULL || nvlist_get_nvpair_parent(value) != NULL) {
925                 ERRNO_SET(EINVAL);
926                 return (NULL);
927         }
928
929         if (nvlist_error(value) != 0) {
930                 ERRNO_SET(nvlist_error(value));
931                 nvlist_destroy(value);
932                 return (NULL);
933         }
934
935         nvp = nvpair_allocv(name, NV_TYPE_NVLIST, (uint64_t)(uintptr_t)value,
936             0);
937         if (nvp == NULL)
938                 nvlist_destroy(value);
939         else
940                 nvlist_set_parent(value, nvp);
941
942         return (nvp);
943 }
944
945 #ifndef _KERNEL
946 nvpair_t *
947 nvpair_move_descriptor(const char *name, int value)
948 {
949         nvpair_t *nvp;
950
951         if (value < 0 || !fd_is_valid(value)) {
952                 ERRNO_SET(EBADF);
953                 return (NULL);
954         }
955
956         nvp = nvpair_allocv(name, NV_TYPE_DESCRIPTOR, (uint64_t)value,
957             sizeof(int64_t));
958         if (nvp == NULL) {
959                 ERRNO_SAVE();
960                 close(value);
961                 ERRNO_RESTORE();
962         }
963
964         return (nvp);
965 }
966 #endif
967
968 nvpair_t *
969 nvpair_move_binary(const char *name, void *value, size_t size)
970 {
971         nvpair_t *nvp;
972
973         if (value == NULL || size == 0) {
974                 ERRNO_SET(EINVAL);
975                 return (NULL);
976         }
977
978         nvp = nvpair_allocv(name, NV_TYPE_BINARY, (uint64_t)(uintptr_t)value,
979             size);
980         if (nvp == NULL) {
981                 ERRNO_SAVE();
982                 nv_free(value);
983                 ERRNO_RESTORE();
984         }
985
986         return (nvp);
987 }
988
989 bool
990 nvpair_get_bool(const nvpair_t *nvp)
991 {
992
993         NVPAIR_ASSERT(nvp);
994
995         return (nvp->nvp_data == 1);
996 }
997
998 uint64_t
999 nvpair_get_number(const nvpair_t *nvp)
1000 {
1001
1002         NVPAIR_ASSERT(nvp);
1003
1004         return (nvp->nvp_data);
1005 }
1006
1007 const char *
1008 nvpair_get_string(const nvpair_t *nvp)
1009 {
1010
1011         NVPAIR_ASSERT(nvp);
1012         PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
1013
1014         return ((const char *)(intptr_t)nvp->nvp_data);
1015 }
1016
1017 const nvlist_t *
1018 nvpair_get_nvlist(const nvpair_t *nvp)
1019 {
1020
1021         NVPAIR_ASSERT(nvp);
1022         PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST);
1023
1024         return ((const nvlist_t *)(intptr_t)nvp->nvp_data);
1025 }
1026
1027 #ifndef _KERNEL
1028 int
1029 nvpair_get_descriptor(const nvpair_t *nvp)
1030 {
1031
1032         NVPAIR_ASSERT(nvp);
1033         PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
1034
1035         return ((int)nvp->nvp_data);
1036 }
1037 #endif
1038
1039 const void *
1040 nvpair_get_binary(const nvpair_t *nvp, size_t *sizep)
1041 {
1042
1043         NVPAIR_ASSERT(nvp);
1044         PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
1045
1046         if (sizep != NULL)
1047                 *sizep = nvp->nvp_datasize;
1048         return ((const void *)(intptr_t)nvp->nvp_data);
1049 }
1050
1051 void
1052 nvpair_free(nvpair_t *nvp)
1053 {
1054
1055         NVPAIR_ASSERT(nvp);
1056         PJDLOG_ASSERT(nvp->nvp_list == NULL);
1057
1058         nvp->nvp_magic = 0;
1059         switch (nvp->nvp_type) {
1060 #ifndef _KERNEL
1061         case NV_TYPE_DESCRIPTOR:
1062                 close((int)nvp->nvp_data);
1063                 break;
1064 #endif
1065         case NV_TYPE_NVLIST:
1066                 nvlist_destroy((nvlist_t *)(intptr_t)nvp->nvp_data);
1067                 break;
1068         case NV_TYPE_STRING:
1069                 nv_free((char *)(intptr_t)nvp->nvp_data);
1070                 break;
1071         case NV_TYPE_BINARY:
1072                 nv_free((void *)(intptr_t)nvp->nvp_data);
1073                 break;
1074         }
1075         nv_free(nvp);
1076 }
1077
1078 void
1079 nvpair_free_structure(nvpair_t *nvp)
1080 {
1081
1082         NVPAIR_ASSERT(nvp);
1083         PJDLOG_ASSERT(nvp->nvp_list == NULL);
1084
1085         nvp->nvp_magic = 0;
1086         nv_free(nvp);
1087 }
1088
1089 const char *
1090 nvpair_type_string(int type)
1091 {
1092
1093         switch (type) {
1094         case NV_TYPE_NULL:
1095                 return ("NULL");
1096         case NV_TYPE_BOOL:
1097                 return ("BOOL");
1098         case NV_TYPE_NUMBER:
1099                 return ("NUMBER");
1100         case NV_TYPE_STRING:
1101                 return ("STRING");
1102         case NV_TYPE_NVLIST:
1103                 return ("NVLIST");
1104         case NV_TYPE_DESCRIPTOR:
1105                 return ("DESCRIPTOR");
1106         case NV_TYPE_BINARY:
1107                 return ("BINARY");
1108         default:
1109                 return ("<UNKNOWN>");
1110         }
1111 }
1112