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