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