]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/subr_nvpair.c
Fix locking for oshmctl() and shmsys().
[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_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(int type, uint64_t data, size_t datasize, const char *namefmt,
720     va_list nameap)
721 {
722         nvpair_t *nvp;
723         char *name;
724         int namelen;
725
726         PJDLOG_ASSERT(type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST);
727
728         namelen = nv_vasprintf(&name, namefmt, nameap);
729         if (namelen < 0)
730                 return (NULL);
731
732         PJDLOG_ASSERT(namelen > 0);
733         if (namelen >= NV_NAME_MAX) {
734                 nv_free(name);
735                 RESTORE_ERRNO(ENAMETOOLONG);
736                 return (NULL);
737         }
738
739         nvp = nv_calloc(1, sizeof(*nvp) + namelen + 1);
740         if (nvp != NULL) {
741                 nvp->nvp_name = (char *)(nvp + 1);
742                 memcpy(nvp->nvp_name, name, namelen + 1);
743                 nvp->nvp_type = type;
744                 nvp->nvp_data = data;
745                 nvp->nvp_datasize = datasize;
746                 nvp->nvp_magic = NVPAIR_MAGIC;
747         }
748         nv_free(name);
749
750         return (nvp);
751 };
752
753 nvpair_t *
754 nvpair_create_null(const char *name)
755 {
756
757         return (nvpair_createf_null("%s", name));
758 }
759
760 nvpair_t *
761 nvpair_create_bool(const char *name, bool value)
762 {
763
764         return (nvpair_createf_bool(value, "%s", name));
765 }
766
767 nvpair_t *
768 nvpair_create_number(const char *name, uint64_t value)
769 {
770
771         return (nvpair_createf_number(value, "%s", name));
772 }
773
774 nvpair_t *
775 nvpair_create_string(const char *name, const char *value)
776 {
777
778         return (nvpair_createf_string(value, "%s", name));
779 }
780
781 nvpair_t *
782 nvpair_create_stringf(const char *name, const char *valuefmt, ...)
783 {
784         va_list valueap;
785         nvpair_t *nvp;
786
787         va_start(valueap, valuefmt);
788         nvp = nvpair_create_stringv(name, valuefmt, valueap);
789         va_end(valueap);
790
791         return (nvp);
792 }
793
794 nvpair_t *
795 nvpair_create_stringv(const char *name, const char *valuefmt, va_list valueap)
796 {
797         nvpair_t *nvp;
798         char *str;
799         int len;
800
801         len = nv_vasprintf(&str, valuefmt, valueap);
802         if (len < 0)
803                 return (NULL);
804         nvp = nvpair_create_string(name, str);
805         if (nvp == NULL)
806                 nv_free(str);
807         return (nvp);
808 }
809
810 nvpair_t *
811 nvpair_create_nvlist(const char *name, const nvlist_t *value)
812 {
813
814         return (nvpair_createf_nvlist(value, "%s", name));
815 }
816
817 #ifndef _KERNEL
818 nvpair_t *
819 nvpair_create_descriptor(const char *name, int value)
820 {
821
822         return (nvpair_createf_descriptor(value, "%s", name));
823 }
824 #endif
825
826 nvpair_t *
827 nvpair_create_binary(const char *name, const void *value, size_t size)
828 {
829
830         return (nvpair_createf_binary(value, size, "%s", name));
831 }
832
833 nvpair_t *
834 nvpair_createf_null(const char *namefmt, ...)
835 {
836         va_list nameap;
837         nvpair_t *nvp;
838
839         va_start(nameap, namefmt);
840         nvp = nvpair_createv_null(namefmt, nameap);
841         va_end(nameap);
842
843         return (nvp);
844 }
845
846 nvpair_t *
847 nvpair_createf_bool(bool value, const char *namefmt, ...)
848 {
849         va_list nameap;
850         nvpair_t *nvp;
851
852         va_start(nameap, namefmt);
853         nvp = nvpair_createv_bool(value, namefmt, nameap);
854         va_end(nameap);
855
856         return (nvp);
857 }
858
859 nvpair_t *
860 nvpair_createf_number(uint64_t value, const char *namefmt, ...)
861 {
862         va_list nameap;
863         nvpair_t *nvp;
864
865         va_start(nameap, namefmt);
866         nvp = nvpair_createv_number(value, namefmt, nameap);
867         va_end(nameap);
868
869         return (nvp);
870 }
871
872 nvpair_t *
873 nvpair_createf_string(const char *value, const char *namefmt, ...)
874 {
875         va_list nameap;
876         nvpair_t *nvp;
877
878         va_start(nameap, namefmt);
879         nvp = nvpair_createv_string(value, namefmt, nameap);
880         va_end(nameap);
881
882         return (nvp);
883 }
884
885 nvpair_t *
886 nvpair_createf_nvlist(const nvlist_t *value, const char *namefmt, ...)
887 {
888         va_list nameap;
889         nvpair_t *nvp;
890
891         va_start(nameap, namefmt);
892         nvp = nvpair_createv_nvlist(value, namefmt, nameap);
893         va_end(nameap);
894
895         return (nvp);
896 }
897
898 #ifndef _KERNEL
899 nvpair_t *
900 nvpair_createf_descriptor(int value, const char *namefmt, ...)
901 {
902         va_list nameap;
903         nvpair_t *nvp;
904
905         va_start(nameap, namefmt);
906         nvp = nvpair_createv_descriptor(value, namefmt, nameap);
907         va_end(nameap);
908
909         return (nvp);
910 }
911 #endif
912
913 nvpair_t *
914 nvpair_createf_binary(const void *value, size_t size, const char *namefmt, ...)
915 {
916         va_list nameap;
917         nvpair_t *nvp;
918
919         va_start(nameap, namefmt);
920         nvp = nvpair_createv_binary(value, size, namefmt, nameap);
921         va_end(nameap);
922
923         return (nvp);
924 }
925
926 nvpair_t *
927 nvpair_createv_null(const char *namefmt, va_list nameap)
928 {
929
930         return (nvpair_allocv(NV_TYPE_NULL, 0, 0, namefmt, nameap));
931 }
932
933 nvpair_t *
934 nvpair_createv_bool(bool value, const char *namefmt, va_list nameap)
935 {
936
937         return (nvpair_allocv(NV_TYPE_BOOL, value ? 1 : 0, sizeof(uint8_t),
938             namefmt, nameap));
939 }
940
941 nvpair_t *
942 nvpair_createv_number(uint64_t value, const char *namefmt, va_list nameap)
943 {
944
945         return (nvpair_allocv(NV_TYPE_NUMBER, value, sizeof(value), namefmt,
946             nameap));
947 }
948
949 nvpair_t *
950 nvpair_createv_string(const char *value, const char *namefmt, va_list nameap)
951 {
952         nvpair_t *nvp;
953         size_t size;
954         char *data;
955
956         if (value == NULL) {
957                 RESTORE_ERRNO(EINVAL);
958                 return (NULL);
959         }
960
961         data = nv_strdup(value);
962         if (data == NULL)
963                 return (NULL);
964         size = strlen(value) + 1;
965
966         nvp = nvpair_allocv(NV_TYPE_STRING, (uint64_t)(uintptr_t)data, size,
967             namefmt, nameap);
968         if (nvp == NULL)
969                 nv_free(data);
970
971         return (nvp);
972 }
973
974 nvpair_t *
975 nvpair_createv_nvlist(const nvlist_t *value, const char *namefmt,
976     va_list nameap)
977 {
978         nvlist_t *nvl;
979         nvpair_t *nvp;
980
981         if (value == NULL) {
982                 RESTORE_ERRNO(EINVAL);
983                 return (NULL);
984         }
985
986         nvl = nvlist_clone(value);
987         if (nvl == NULL)
988                 return (NULL);
989
990         nvp = nvpair_allocv(NV_TYPE_NVLIST, (uint64_t)(uintptr_t)nvl, 0,
991             namefmt, nameap);
992         if (nvp == NULL)
993                 nvlist_destroy(nvl);
994         else
995                 nvlist_set_parent(nvl, nvp);
996
997         return (nvp);
998 }
999
1000 #ifndef _KERNEL
1001 nvpair_t *
1002 nvpair_createv_descriptor(int value, const char *namefmt, va_list nameap)
1003 {
1004         nvpair_t *nvp;
1005
1006         if (value < 0 || !fd_is_valid(value)) {
1007                 errno = EBADF;
1008                 return (NULL);
1009         }
1010
1011         value = fcntl(value, F_DUPFD_CLOEXEC, 0);
1012         if (value < 0)
1013                 return (NULL);
1014
1015         nvp = nvpair_allocv(NV_TYPE_DESCRIPTOR, (uint64_t)value,
1016             sizeof(int64_t), namefmt, nameap);
1017         if (nvp == NULL)
1018                 close(value);
1019
1020         return (nvp);
1021 }
1022 #endif
1023
1024 nvpair_t *
1025 nvpair_createv_binary(const void *value, size_t size, const char *namefmt,
1026     va_list nameap)
1027 {
1028         nvpair_t *nvp;
1029         void *data;
1030
1031         if (value == NULL || size == 0) {
1032                 RESTORE_ERRNO(EINVAL);
1033                 return (NULL);
1034         }
1035
1036         data = nv_malloc(size);
1037         if (data == NULL)
1038                 return (NULL);
1039         memcpy(data, value, size);
1040
1041         nvp = nvpair_allocv(NV_TYPE_BINARY, (uint64_t)(uintptr_t)data, size,
1042             namefmt, nameap);
1043         if (nvp == NULL)
1044                 nv_free(data);
1045
1046         return (nvp);
1047 }
1048
1049 nvpair_t *
1050 nvpair_move_string(const char *name, char *value)
1051 {
1052
1053         return (nvpair_movef_string(value, "%s", name));
1054 }
1055
1056 nvpair_t *
1057 nvpair_move_nvlist(const char *name, nvlist_t *value)
1058 {
1059
1060         return (nvpair_movef_nvlist(value, "%s", name));
1061 }
1062
1063 #ifndef _KERNEL
1064 nvpair_t *
1065 nvpair_move_descriptor(const char *name, int value)
1066 {
1067
1068         return (nvpair_movef_descriptor(value, "%s", name));
1069 }
1070 #endif
1071
1072 nvpair_t *
1073 nvpair_move_binary(const char *name, void *value, size_t size)
1074 {
1075
1076         return (nvpair_movef_binary(value, size, "%s", name));
1077 }
1078
1079 nvpair_t *
1080 nvpair_movef_string(char *value, const char *namefmt, ...)
1081 {
1082         va_list nameap;
1083         nvpair_t *nvp;
1084
1085         va_start(nameap, namefmt);
1086         nvp = nvpair_movev_string(value, namefmt, nameap);
1087         va_end(nameap);
1088
1089         return (nvp);
1090 }
1091
1092 nvpair_t *
1093 nvpair_movef_nvlist(nvlist_t *value, const char *namefmt, ...)
1094 {
1095         va_list nameap;
1096         nvpair_t *nvp;
1097
1098         va_start(nameap, namefmt);
1099         nvp = nvpair_movev_nvlist(value, namefmt, nameap);
1100         va_end(nameap);
1101
1102         return (nvp);
1103 }
1104
1105 #ifndef _KERNEL
1106 nvpair_t *
1107 nvpair_movef_descriptor(int value, const char *namefmt, ...)
1108 {
1109         va_list nameap;
1110         nvpair_t *nvp;
1111
1112         va_start(nameap, namefmt);
1113         nvp = nvpair_movev_descriptor(value, namefmt, nameap);
1114         va_end(nameap);
1115
1116         return (nvp);
1117 }
1118 #endif
1119
1120 nvpair_t *
1121 nvpair_movef_binary(void *value, size_t size, const char *namefmt, ...)
1122 {
1123         va_list nameap;
1124         nvpair_t *nvp;
1125
1126         va_start(nameap, namefmt);
1127         nvp = nvpair_movev_binary(value, size, namefmt, nameap);
1128         va_end(nameap);
1129
1130         return (nvp);
1131 }
1132
1133 nvpair_t *
1134 nvpair_movev_string(char *value, const char *namefmt, va_list nameap)
1135 {
1136         nvpair_t *nvp;
1137         int serrno;
1138
1139         if (value == NULL) {
1140                 RESTORE_ERRNO(EINVAL);
1141                 return (NULL);
1142         }
1143
1144         nvp = nvpair_allocv(NV_TYPE_STRING, (uint64_t)(uintptr_t)value,
1145             strlen(value) + 1, namefmt, nameap);
1146         if (nvp == NULL) {
1147                 SAVE_ERRNO(serrno);
1148                 nv_free(value);
1149                 RESTORE_ERRNO(serrno);
1150         }
1151
1152         return (nvp);
1153 }
1154
1155 nvpair_t *
1156 nvpair_movev_nvlist(nvlist_t *value, const char *namefmt, va_list nameap)
1157 {
1158         nvpair_t *nvp;
1159
1160         if (value == NULL || nvlist_get_nvpair_parent(value) != NULL) {
1161                 RESTORE_ERRNO(EINVAL);
1162                 return (NULL);
1163         }
1164
1165         if (nvlist_error(value) != 0) {
1166                 RESTORE_ERRNO(nvlist_error(value));
1167                 nvlist_destroy(value);
1168                 return (NULL);
1169         }
1170
1171         nvp = nvpair_allocv(NV_TYPE_NVLIST, (uint64_t)(uintptr_t)value, 0,
1172             namefmt, nameap);
1173         if (nvp == NULL)
1174                 nvlist_destroy(value);
1175         else
1176                 nvlist_set_parent(value, nvp);
1177
1178         return (nvp);
1179 }
1180
1181 #ifndef _KERNEL
1182 nvpair_t *
1183 nvpair_movev_descriptor(int value, const char *namefmt, va_list nameap)
1184 {
1185         nvpair_t *nvp;
1186         int serrno;
1187
1188         if (value < 0 || !fd_is_valid(value)) {
1189                 errno = EBADF;
1190                 return (NULL);
1191         }
1192
1193         nvp = nvpair_allocv(NV_TYPE_DESCRIPTOR, (uint64_t)value,
1194             sizeof(int64_t), namefmt, nameap);
1195         if (nvp == NULL) {
1196                 serrno = errno;
1197                 close(value);
1198                 errno = serrno;
1199         }
1200
1201         return (nvp);
1202 }
1203 #endif
1204
1205 nvpair_t *
1206 nvpair_movev_binary(void *value, size_t size, const char *namefmt,
1207     va_list nameap)
1208 {
1209         nvpair_t *nvp;
1210         int serrno;
1211
1212         if (value == NULL || size == 0) {
1213                 RESTORE_ERRNO(EINVAL);
1214                 return (NULL);
1215         }
1216
1217         nvp = nvpair_allocv(NV_TYPE_BINARY, (uint64_t)(uintptr_t)value, size,
1218             namefmt, nameap);
1219         if (nvp == NULL) {
1220                 SAVE_ERRNO(serrno);
1221                 nv_free(value);
1222                 RESTORE_ERRNO(serrno);
1223         }
1224
1225         return (nvp);
1226 }
1227
1228 bool
1229 nvpair_get_bool(const nvpair_t *nvp)
1230 {
1231
1232         NVPAIR_ASSERT(nvp);
1233
1234         return (nvp->nvp_data == 1);
1235 }
1236
1237 uint64_t
1238 nvpair_get_number(const nvpair_t *nvp)
1239 {
1240
1241         NVPAIR_ASSERT(nvp);
1242
1243         return (nvp->nvp_data);
1244 }
1245
1246 const char *
1247 nvpair_get_string(const nvpair_t *nvp)
1248 {
1249
1250         NVPAIR_ASSERT(nvp);
1251         PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
1252
1253         return ((const char *)(intptr_t)nvp->nvp_data);
1254 }
1255
1256 const nvlist_t *
1257 nvpair_get_nvlist(const nvpair_t *nvp)
1258 {
1259
1260         NVPAIR_ASSERT(nvp);
1261         PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST);
1262
1263         return ((const nvlist_t *)(intptr_t)nvp->nvp_data);
1264 }
1265
1266 #ifndef _KERNEL
1267 int
1268 nvpair_get_descriptor(const nvpair_t *nvp)
1269 {
1270
1271         NVPAIR_ASSERT(nvp);
1272         PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
1273
1274         return ((int)nvp->nvp_data);
1275 }
1276 #endif
1277
1278 const void *
1279 nvpair_get_binary(const nvpair_t *nvp, size_t *sizep)
1280 {
1281
1282         NVPAIR_ASSERT(nvp);
1283         PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
1284
1285         if (sizep != NULL)
1286                 *sizep = nvp->nvp_datasize;
1287         return ((const void *)(intptr_t)nvp->nvp_data);
1288 }
1289
1290 void
1291 nvpair_free(nvpair_t *nvp)
1292 {
1293
1294         NVPAIR_ASSERT(nvp);
1295         PJDLOG_ASSERT(nvp->nvp_list == NULL);
1296
1297         nvp->nvp_magic = 0;
1298         switch (nvp->nvp_type) {
1299 #ifndef _KERNEL
1300         case NV_TYPE_DESCRIPTOR:
1301                 close((int)nvp->nvp_data);
1302                 break;
1303 #endif
1304         case NV_TYPE_NVLIST:
1305                 nvlist_destroy((nvlist_t *)(intptr_t)nvp->nvp_data);
1306                 break;
1307         case NV_TYPE_STRING:
1308                 nv_free((char *)(intptr_t)nvp->nvp_data);
1309                 break;
1310         case NV_TYPE_BINARY:
1311                 nv_free((void *)(intptr_t)nvp->nvp_data);
1312                 break;
1313         }
1314         nv_free(nvp);
1315 }
1316
1317 void
1318 nvpair_free_structure(nvpair_t *nvp)
1319 {
1320
1321         NVPAIR_ASSERT(nvp);
1322         PJDLOG_ASSERT(nvp->nvp_list == NULL);
1323
1324         nvp->nvp_magic = 0;
1325         nv_free(nvp);
1326 }
1327
1328 const char *
1329 nvpair_type_string(int type)
1330 {
1331
1332         switch (type) {
1333         case NV_TYPE_NULL:
1334                 return ("NULL");
1335         case NV_TYPE_BOOL:
1336                 return ("BOOL");
1337         case NV_TYPE_NUMBER:
1338                 return ("NUMBER");
1339         case NV_TYPE_STRING:
1340                 return ("STRING");
1341         case NV_TYPE_NVLIST:
1342                 return ("NVLIST");
1343         case NV_TYPE_DESCRIPTOR:
1344                 return ("DESCRIPTOR");
1345         case NV_TYPE_BINARY:
1346                 return ("BINARY");
1347         default:
1348                 return ("<UNKNOWN>");
1349         }
1350 }