1 /*-
2 * Copyright (c) 2009-2013 The FreeBSD Foundation
3 * Copyright (c) 2013-2015 Mariusz Zaborski <oshogbo@FreeBSD.org>
4 * All rights reserved.
5 *
6 * This software was developed by Pawel Jakub Dawidek under sponsorship from
7 * the FreeBSD Foundation.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <sys/param.h>
35 #include <sys/endian.h>
36 #include <sys/queue.h>
37
38 #ifdef _KERNEL
39
40 #include <sys/errno.h>
41 #include <sys/lock.h>
42 #include <sys/malloc.h>
43 #include <sys/systm.h>
44
45 #include <machine/stdarg.h>
46
47 #else
48 #include <errno.h>
49 #include <fcntl.h>
50 #include <stdarg.h>
51 #include <stdbool.h>
52 #include <stdint.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56
57 #include "common_impl.h"
58 #endif
59
60 #ifdef HAVE_PJDLOG
61 #include <pjdlog.h>
62 #endif
63
64 #include <sys/nv.h>
65
66 #include "nv_impl.h"
67 #include "nvlist_impl.h"
68 #include "nvpair_impl.h"
69
70 #ifndef HAVE_PJDLOG
71 #ifdef _KERNEL
72 #define PJDLOG_ASSERT(...) MPASS(__VA_ARGS__)
73 #define PJDLOG_RASSERT(expr, ...) KASSERT(expr, (__VA_ARGS__))
74 #define PJDLOG_ABORT(...) panic(__VA_ARGS__)
75 #else
76 #include <assert.h>
77 #define PJDLOG_ASSERT(...) assert(__VA_ARGS__)
78 #define PJDLOG_RASSERT(expr, ...) assert(expr)
79 #define PJDLOG_ABORT(...) abort()
80 #endif
81 #endif
82
83 #define NVPAIR_MAGIC 0x6e7670 /* "nvp" */
84 struct nvpair {
85 int nvp_magic;
86 char *nvp_name;
87 int nvp_type;
88 uint64_t nvp_data;
89 size_t nvp_datasize;
90 size_t nvp_nitems; /* Used only for array types. */
91 nvlist_t *nvp_list;
92 TAILQ_ENTRY(nvpair) nvp_next;
93 };
94
95 #define NVPAIR_ASSERT(nvp) do { \
96 PJDLOG_ASSERT((nvp) != NULL); \
97 PJDLOG_ASSERT((nvp)->nvp_magic == NVPAIR_MAGIC); \
98 } while (0)
99
100 struct nvpair_header {
101 uint8_t nvph_type;
102 uint16_t nvph_namesize;
103 uint64_t nvph_datasize;
104 uint64_t nvph_nitems;
105 } __packed;
106
107
108 void
nvpair_assert(const nvpair_t * nvp)109 nvpair_assert(const nvpair_t *nvp)
110 {
111
112 NVPAIR_ASSERT(nvp);
113 }
114
115 static nvpair_t *
nvpair_allocv(const char * name,int type,uint64_t data,size_t datasize,size_t nitems)116 nvpair_allocv(const char *name, int type, uint64_t data, size_t datasize,
117 size_t nitems)
118 {
119 nvpair_t *nvp;
120 size_t namelen;
121
122 PJDLOG_ASSERT(type >= NV_TYPE_FIRST && type <= NV_TYPE_LAST);
123
124 namelen = strlen(name);
125 if (namelen >= NV_NAME_MAX) {
126 ERRNO_SET(ENAMETOOLONG);
127 return (NULL);
128 }
129
130 nvp = nv_calloc(1, sizeof(*nvp) + namelen + 1);
131 if (nvp != NULL) {
132 nvp->nvp_name = (char *)(nvp + 1);
133 memcpy(nvp->nvp_name, name, namelen);
134 nvp->nvp_name[namelen] = '\0';
135 nvp->nvp_type = type;
136 nvp->nvp_data = data;
137 nvp->nvp_datasize = datasize;
138 nvp->nvp_nitems = nitems;
139 nvp->nvp_magic = NVPAIR_MAGIC;
140 }
141
142 return (nvp);
143 }
144
145 nvlist_t *
nvpair_nvlist(const nvpair_t * nvp)146 nvpair_nvlist(const nvpair_t *nvp)
147 {
148
149 NVPAIR_ASSERT(nvp);
150
151 return (nvp->nvp_list);
152 }
153
154 nvpair_t *
nvpair_next(const nvpair_t * nvp)155 nvpair_next(const nvpair_t *nvp)
156 {
157
158 NVPAIR_ASSERT(nvp);
159 PJDLOG_ASSERT(nvp->nvp_list != NULL);
160
161 return (TAILQ_NEXT(nvp, nvp_next));
162 }
163
164 nvpair_t *
nvpair_prev(const nvpair_t * nvp)165 nvpair_prev(const nvpair_t *nvp)
166 {
167
168 NVPAIR_ASSERT(nvp);
169 PJDLOG_ASSERT(nvp->nvp_list != NULL);
170
171 return (TAILQ_PREV(nvp, nvl_head, nvp_next));
172 }
173
174 void
nvpair_insert(struct nvl_head * head,nvpair_t * nvp,nvlist_t * nvl)175 nvpair_insert(struct nvl_head *head, nvpair_t *nvp, nvlist_t *nvl)
176 {
177
178 NVPAIR_ASSERT(nvp);
179 PJDLOG_ASSERT(nvp->nvp_list == NULL);
180 PJDLOG_ASSERT((nvlist_flags(nvl) & NV_FLAG_NO_UNIQUE) != 0 ||
181 !nvlist_exists(nvl, nvpair_name(nvp)));
182
183 TAILQ_INSERT_TAIL(head, nvp, nvp_next);
184 nvp->nvp_list = nvl;
185 }
186
187 static void
nvpair_remove_nvlist(nvpair_t * nvp)188 nvpair_remove_nvlist(nvpair_t *nvp)
189 {
190 nvlist_t *nvl;
191
192 /* XXX: DECONST is bad, mkay? */
193 nvl = __DECONST(nvlist_t *, nvpair_get_nvlist(nvp));
194 PJDLOG_ASSERT(nvl != NULL);
195 nvlist_set_parent(nvl, NULL);
196 }
197
198 static void
nvpair_remove_nvlist_array(nvpair_t * nvp)199 nvpair_remove_nvlist_array(nvpair_t *nvp)
200 {
201 nvlist_t **nvlarray;
202 size_t count, i;
203
204 /* XXX: DECONST is bad, mkay? */
205 nvlarray = __DECONST(nvlist_t **,
206 nvpair_get_nvlist_array(nvp, &count));
207 for (i = 0; i < count; i++)
208 nvlist_set_array_next(nvlarray[i], NULL);
209 }
210
211 void
nvpair_remove(struct nvl_head * head,nvpair_t * nvp,const nvlist_t * nvl)212 nvpair_remove(struct nvl_head *head, nvpair_t *nvp, const nvlist_t *nvl)
213 {
214
215 NVPAIR_ASSERT(nvp);
216 PJDLOG_ASSERT(nvp->nvp_list == nvl);
217
218 if (nvpair_type(nvp) == NV_TYPE_NVLIST)
219 nvpair_remove_nvlist(nvp);
220 else if (nvpair_type(nvp) == NV_TYPE_NVLIST_ARRAY)
221 nvpair_remove_nvlist_array(nvp);
222
223 TAILQ_REMOVE(head, nvp, nvp_next);
224 nvp->nvp_list = NULL;
225 }
226
227 nvpair_t *
nvpair_clone(const nvpair_t * nvp)228 nvpair_clone(const nvpair_t *nvp)
229 {
230 nvpair_t *newnvp;
231 const char *name;
232 const void *data;
233 size_t datasize;
234
235 NVPAIR_ASSERT(nvp);
236
237 name = nvpair_name(nvp);
238
239 switch (nvpair_type(nvp)) {
240 case NV_TYPE_NULL:
241 newnvp = nvpair_create_null(name);
242 break;
243 case NV_TYPE_BOOL:
244 newnvp = nvpair_create_bool(name, nvpair_get_bool(nvp));
245 break;
246 case NV_TYPE_NUMBER:
247 newnvp = nvpair_create_number(name, nvpair_get_number(nvp));
248 break;
249 case NV_TYPE_STRING:
250 newnvp = nvpair_create_string(name, nvpair_get_string(nvp));
251 break;
252 case NV_TYPE_NVLIST:
253 newnvp = nvpair_create_nvlist(name, nvpair_get_nvlist(nvp));
254 break;
255 case NV_TYPE_BINARY:
256 data = nvpair_get_binary(nvp, &datasize);
257 newnvp = nvpair_create_binary(name, data, datasize);
258 break;
259 case NV_TYPE_BOOL_ARRAY:
260 data = nvpair_get_bool_array(nvp, &datasize);
261 newnvp = nvpair_create_bool_array(name, data, datasize);
262 break;
263 case NV_TYPE_NUMBER_ARRAY:
264 data = nvpair_get_number_array(nvp, &datasize);
265 newnvp = nvpair_create_number_array(name, data, datasize);
266 break;
267 case NV_TYPE_STRING_ARRAY:
268 data = nvpair_get_string_array(nvp, &datasize);
269 newnvp = nvpair_create_string_array(name, data, datasize);
270 break;
271 case NV_TYPE_NVLIST_ARRAY:
272 data = nvpair_get_nvlist_array(nvp, &datasize);
273 newnvp = nvpair_create_nvlist_array(name, data, datasize);
274 break;
275 #ifndef _KERNEL
276 case NV_TYPE_DESCRIPTOR:
277 newnvp = nvpair_create_descriptor(name,
278 nvpair_get_descriptor(nvp));
279 break;
280 case NV_TYPE_DESCRIPTOR_ARRAY:
281 data = nvpair_get_descriptor_array(nvp, &datasize);
282 newnvp = nvpair_create_descriptor_array(name, data, datasize);
283 break;
284 #endif
285 default:
286 PJDLOG_ABORT("Unknown type: %d.", nvpair_type(nvp));
287 }
288
289 return (newnvp);
290 }
291
292 size_t
nvpair_header_size(void)293 nvpair_header_size(void)
294 {
295
296 return (sizeof(struct nvpair_header));
297 }
298
299 size_t
nvpair_size(const nvpair_t * nvp)300 nvpair_size(const nvpair_t *nvp)
301 {
302
303 NVPAIR_ASSERT(nvp);
304
305 return (nvp->nvp_datasize);
306 }
307
308 unsigned char *
nvpair_pack_header(const nvpair_t * nvp,unsigned char * ptr,size_t * leftp)309 nvpair_pack_header(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
310 {
311 struct nvpair_header nvphdr;
312 size_t namesize;
313
314 NVPAIR_ASSERT(nvp);
315
316 nvphdr.nvph_type = nvp->nvp_type;
317 namesize = strlen(nvp->nvp_name) + 1;
318 PJDLOG_ASSERT(namesize > 0 && namesize <= UINT16_MAX);
319 nvphdr.nvph_namesize = namesize;
320 nvphdr.nvph_datasize = nvp->nvp_datasize;
321 nvphdr.nvph_nitems = nvp->nvp_nitems;
322 PJDLOG_ASSERT(*leftp >= sizeof(nvphdr));
323 memcpy(ptr, &nvphdr, sizeof(nvphdr));
324 ptr += sizeof(nvphdr);
325 *leftp -= sizeof(nvphdr);
326
327 PJDLOG_ASSERT(*leftp >= namesize);
328 memcpy(ptr, nvp->nvp_name, namesize);
329 ptr += namesize;
330 *leftp -= namesize;
331
332 return (ptr);
333 }
334
335 unsigned char *
nvpair_pack_null(const nvpair_t * nvp,unsigned char * ptr,size_t * leftp __unused)336 nvpair_pack_null(const nvpair_t *nvp, unsigned char *ptr,
337 size_t *leftp __unused)
338 {
339
340 NVPAIR_ASSERT(nvp);
341 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NULL);
342
343 return (ptr);
344 }
345
346 unsigned char *
nvpair_pack_bool(const nvpair_t * nvp,unsigned char * ptr,size_t * leftp)347 nvpair_pack_bool(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
348 {
349 uint8_t value;
350
351 NVPAIR_ASSERT(nvp);
352 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL);
353
354 value = (uint8_t)nvp->nvp_data;
355
356 PJDLOG_ASSERT(*leftp >= sizeof(value));
357 memcpy(ptr, &value, sizeof(value));
358 ptr += sizeof(value);
359 *leftp -= sizeof(value);
360
361 return (ptr);
362 }
363
364 unsigned char *
nvpair_pack_number(const nvpair_t * nvp,unsigned char * ptr,size_t * leftp)365 nvpair_pack_number(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
366 {
367 uint64_t value;
368
369 NVPAIR_ASSERT(nvp);
370 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER);
371
372 value = (uint64_t)nvp->nvp_data;
373
374 PJDLOG_ASSERT(*leftp >= sizeof(value));
375 memcpy(ptr, &value, sizeof(value));
376 ptr += sizeof(value);
377 *leftp -= sizeof(value);
378
379 return (ptr);
380 }
381
382 unsigned char *
nvpair_pack_string(const nvpair_t * nvp,unsigned char * ptr,size_t * leftp)383 nvpair_pack_string(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
384 {
385
386 NVPAIR_ASSERT(nvp);
387 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
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 unsigned char *
nvpair_pack_nvlist_up(unsigned char * ptr,size_t * leftp)398 nvpair_pack_nvlist_up(unsigned char *ptr, size_t *leftp)
399 {
400 struct nvpair_header nvphdr;
401 size_t namesize;
402 const char *name = "";
403
404 namesize = 1;
405 nvphdr.nvph_type = NV_TYPE_NVLIST_UP;
406 nvphdr.nvph_namesize = namesize;
407 nvphdr.nvph_datasize = 0;
408 nvphdr.nvph_nitems = 0;
409 PJDLOG_ASSERT(*leftp >= sizeof(nvphdr));
410 memcpy(ptr, &nvphdr, sizeof(nvphdr));
411 ptr += sizeof(nvphdr);
412 *leftp -= sizeof(nvphdr);
413
414 PJDLOG_ASSERT(*leftp >= namesize);
415 memcpy(ptr, name, namesize);
416 ptr += namesize;
417 *leftp -= namesize;
418
419 return (ptr);
420 }
421
422 unsigned char *
nvpair_pack_nvlist_array_next(unsigned char * ptr,size_t * leftp)423 nvpair_pack_nvlist_array_next(unsigned char *ptr, size_t *leftp)
424 {
425 struct nvpair_header nvphdr;
426 size_t namesize;
427 const char *name = "";
428
429 namesize = 1;
430 nvphdr.nvph_type = NV_TYPE_NVLIST_ARRAY_NEXT;
431 nvphdr.nvph_namesize = namesize;
432 nvphdr.nvph_datasize = 0;
433 nvphdr.nvph_nitems = 0;
434 PJDLOG_ASSERT(*leftp >= sizeof(nvphdr));
435 memcpy(ptr, &nvphdr, sizeof(nvphdr));
436 ptr += sizeof(nvphdr);
437 *leftp -= sizeof(nvphdr);
438
439 PJDLOG_ASSERT(*leftp >= namesize);
440 memcpy(ptr, name, namesize);
441 ptr += namesize;
442 *leftp -= namesize;
443
444 return (ptr);
445 }
446
447 #ifndef _KERNEL
448 unsigned char *
nvpair_pack_descriptor(const nvpair_t * nvp,unsigned char * ptr,int64_t * fdidxp,size_t * leftp)449 nvpair_pack_descriptor(const nvpair_t *nvp, unsigned char *ptr, int64_t *fdidxp,
450 size_t *leftp)
451 {
452 int64_t value;
453
454 NVPAIR_ASSERT(nvp);
455 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
456
457 value = (int64_t)nvp->nvp_data;
458 if (value != -1) {
459 /*
460 * If there is a real descriptor here, we change its number
461 * to position in the array of descriptors send via control
462 * message.
463 */
464 PJDLOG_ASSERT(fdidxp != NULL);
465
466 value = *fdidxp;
467 (*fdidxp)++;
468 }
469
470 PJDLOG_ASSERT(*leftp >= sizeof(value));
471 memcpy(ptr, &value, sizeof(value));
472 ptr += sizeof(value);
473 *leftp -= sizeof(value);
474
475 return (ptr);
476 }
477 #endif
478
479 unsigned char *
nvpair_pack_binary(const nvpair_t * nvp,unsigned char * ptr,size_t * leftp)480 nvpair_pack_binary(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
481 {
482
483 NVPAIR_ASSERT(nvp);
484 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
485
486 PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
487 memcpy(ptr, (const void *)(intptr_t)nvp->nvp_data, nvp->nvp_datasize);
488 ptr += nvp->nvp_datasize;
489 *leftp -= nvp->nvp_datasize;
490
491 return (ptr);
492 }
493
494 unsigned char *
nvpair_pack_bool_array(const nvpair_t * nvp,unsigned char * ptr,size_t * leftp)495 nvpair_pack_bool_array(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
496 {
497
498 NVPAIR_ASSERT(nvp);
499 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL_ARRAY);
500 PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
501
502 memcpy(ptr, (const void *)(intptr_t)nvp->nvp_data, nvp->nvp_datasize);
503 ptr += nvp->nvp_datasize;
504 *leftp -= nvp->nvp_datasize;
505
506 return (ptr);
507 }
508
509 unsigned char *
nvpair_pack_number_array(const nvpair_t * nvp,unsigned char * ptr,size_t * leftp)510 nvpair_pack_number_array(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
511 {
512
513 NVPAIR_ASSERT(nvp);
514 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER_ARRAY);
515 PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
516
517 memcpy(ptr, (const void *)(intptr_t)nvp->nvp_data, nvp->nvp_datasize);
518 ptr += nvp->nvp_datasize;
519 *leftp -= nvp->nvp_datasize;
520
521 return (ptr);
522 }
523
524 unsigned char *
nvpair_pack_string_array(const nvpair_t * nvp,unsigned char * ptr,size_t * leftp)525 nvpair_pack_string_array(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
526 {
527 unsigned int ii;
528 size_t size, len;
529 const char * const *array;
530
531 NVPAIR_ASSERT(nvp);
532 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING_ARRAY);
533 PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
534
535 size = 0;
536 array = nvpair_get_string_array(nvp, NULL);
537 PJDLOG_ASSERT(array != NULL);
538
539 for (ii = 0; ii < nvp->nvp_nitems; ii++) {
540 len = strlen(array[ii]) + 1;
541 PJDLOG_ASSERT(*leftp >= len);
542
543 memcpy(ptr, (const void *)array[ii], len);
544 size += len;
545 ptr += len;
546 *leftp -= len;
547 }
548
549 PJDLOG_ASSERT(size == nvp->nvp_datasize);
550
551 return (ptr);
552 }
553
554 #ifndef _KERNEL
555 unsigned char *
nvpair_pack_descriptor_array(const nvpair_t * nvp,unsigned char * ptr,int64_t * fdidxp,size_t * leftp)556 nvpair_pack_descriptor_array(const nvpair_t *nvp, unsigned char *ptr,
557 int64_t *fdidxp, size_t *leftp)
558 {
559 int64_t value;
560 const int *array;
561 unsigned int ii;
562
563 NVPAIR_ASSERT(nvp);
564 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR_ARRAY);
565 PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
566
567 array = nvpair_get_descriptor_array(nvp, NULL);
568 PJDLOG_ASSERT(array != NULL);
569
570 for (ii = 0; ii < nvp->nvp_nitems; ii++) {
571 PJDLOG_ASSERT(*leftp >= sizeof(value));
572
573 value = array[ii];
574 if (value != -1) {
575 /*
576 * If there is a real descriptor here, we change its
577 * number to position in the array of descriptors send
578 * via control message.
579 */
580 PJDLOG_ASSERT(fdidxp != NULL);
581
582 value = *fdidxp;
583 (*fdidxp)++;
584 }
585 memcpy(ptr, &value, sizeof(value));
586 ptr += sizeof(value);
587 *leftp -= sizeof(value);
588 }
589
590 return (ptr);
591 }
592 #endif
593
594 void
nvpair_init_datasize(nvpair_t * nvp)595 nvpair_init_datasize(nvpair_t *nvp)
596 {
597
598 NVPAIR_ASSERT(nvp);
599
600 if (nvp->nvp_type == NV_TYPE_NVLIST) {
601 if (nvp->nvp_data == 0) {
602 nvp->nvp_datasize = 0;
603 } else {
604 nvp->nvp_datasize =
605 nvlist_size((const nvlist_t *)(intptr_t)nvp->nvp_data);
606 }
607 }
608 }
609
610 const unsigned char *
nvpair_unpack_header(bool isbe,nvpair_t * nvp,const unsigned char * ptr,size_t * leftp)611 nvpair_unpack_header(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
612 size_t *leftp)
613 {
614 struct nvpair_header nvphdr;
615
616 if (*leftp < sizeof(nvphdr))
617 goto failed;
618
619 memcpy(&nvphdr, ptr, sizeof(nvphdr));
620 ptr += sizeof(nvphdr);
621 *leftp -= sizeof(nvphdr);
622
623 #if NV_TYPE_FIRST > 0
624 if (nvphdr.nvph_type < NV_TYPE_FIRST)
625 goto failed;
626 #endif
627 if (nvphdr.nvph_type > NV_TYPE_LAST &&
628 nvphdr.nvph_type != NV_TYPE_NVLIST_UP &&
629 nvphdr.nvph_type != NV_TYPE_NVLIST_ARRAY_NEXT) {
630 goto failed;
631 }
632
633 #if BYTE_ORDER == BIG_ENDIAN
634 if (!isbe) {
635 nvphdr.nvph_namesize = le16toh(nvphdr.nvph_namesize);
636 nvphdr.nvph_datasize = le64toh(nvphdr.nvph_datasize);
637 }
638 #else
639 if (isbe) {
640 nvphdr.nvph_namesize = be16toh(nvphdr.nvph_namesize);
641 nvphdr.nvph_datasize = be64toh(nvphdr.nvph_datasize);
642 }
643 #endif
644
645 if (nvphdr.nvph_namesize > NV_NAME_MAX)
646 goto failed;
647 if (*leftp < nvphdr.nvph_namesize)
648 goto failed;
649 if (nvphdr.nvph_namesize < 1)
650 goto failed;
651 if (strnlen((const char *)ptr, nvphdr.nvph_namesize) !=
652 (size_t)(nvphdr.nvph_namesize - 1)) {
653 goto failed;
654 }
655
656 memcpy(nvp->nvp_name, ptr, nvphdr.nvph_namesize);
657 ptr += nvphdr.nvph_namesize;
658 *leftp -= nvphdr.nvph_namesize;
659
660 if (*leftp < nvphdr.nvph_datasize)
661 goto failed;
662
663 nvp->nvp_type = nvphdr.nvph_type;
664 nvp->nvp_data = 0;
665 nvp->nvp_datasize = nvphdr.nvph_datasize;
666 nvp->nvp_nitems = nvphdr.nvph_nitems;
667
668 return (ptr);
669 failed:
670 ERRNO_SET(EINVAL);
671 return (NULL);
672 }
673
674 const unsigned char *
nvpair_unpack_null(bool isbe __unused,nvpair_t * nvp,const unsigned char * ptr,size_t * leftp __unused)675 nvpair_unpack_null(bool isbe __unused, nvpair_t *nvp, const unsigned char *ptr,
676 size_t *leftp __unused)
677 {
678
679 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NULL);
680
681 if (nvp->nvp_datasize != 0) {
682 ERRNO_SET(EINVAL);
683 return (NULL);
684 }
685
686 return (ptr);
687 }
688
689 const unsigned char *
nvpair_unpack_bool(bool isbe __unused,nvpair_t * nvp,const unsigned char * ptr,size_t * leftp)690 nvpair_unpack_bool(bool isbe __unused, nvpair_t *nvp, const unsigned char *ptr,
691 size_t *leftp)
692 {
693 uint8_t value;
694
695 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL);
696
697 if (nvp->nvp_datasize != sizeof(value)) {
698 ERRNO_SET(EINVAL);
699 return (NULL);
700 }
701 if (*leftp < sizeof(value)) {
702 ERRNO_SET(EINVAL);
703 return (NULL);
704 }
705
706 memcpy(&value, ptr, sizeof(value));
707 ptr += sizeof(value);
708 *leftp -= sizeof(value);
709
710 if (value != 0 && value != 1) {
711 ERRNO_SET(EINVAL);
712 return (NULL);
713 }
714
715 nvp->nvp_data = (uint64_t)value;
716
717 return (ptr);
718 }
719
720 const unsigned char *
nvpair_unpack_number(bool isbe,nvpair_t * nvp,const unsigned char * ptr,size_t * leftp)721 nvpair_unpack_number(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
722 size_t *leftp)
723 {
724
725 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER);
726
727 if (nvp->nvp_datasize != sizeof(uint64_t)) {
728 ERRNO_SET(EINVAL);
729 return (NULL);
730 }
731 if (*leftp < sizeof(uint64_t)) {
732 ERRNO_SET(EINVAL);
733 return (NULL);
734 }
735
736 if (isbe)
737 nvp->nvp_data = be64dec(ptr);
738 else
739 nvp->nvp_data = le64dec(ptr);
740
741 ptr += sizeof(uint64_t);
742 *leftp -= sizeof(uint64_t);
743
744 return (ptr);
745 }
746
747 const unsigned char *
nvpair_unpack_string(bool isbe __unused,nvpair_t * nvp,const unsigned char * ptr,size_t * leftp)748 nvpair_unpack_string(bool isbe __unused, nvpair_t *nvp,
749 const unsigned char *ptr, size_t *leftp)
750 {
751
752 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
753
754 if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
755 ERRNO_SET(EINVAL);
756 return (NULL);
757 }
758
759 if (strnlen((const char *)ptr, nvp->nvp_datasize) !=
760 nvp->nvp_datasize - 1) {
761 ERRNO_SET(EINVAL);
762 return (NULL);
763 }
764
765 nvp->nvp_data = (uint64_t)(uintptr_t)nv_strdup((const char *)ptr);
766 if (nvp->nvp_data == 0)
767 return (NULL);
768
769 ptr += nvp->nvp_datasize;
770 *leftp -= nvp->nvp_datasize;
771
772 return (ptr);
773 }
774
775 const unsigned char *
nvpair_unpack_nvlist(bool isbe __unused,nvpair_t * nvp,const unsigned char * ptr,size_t * leftp,size_t nfds,nvlist_t ** child)776 nvpair_unpack_nvlist(bool isbe __unused, nvpair_t *nvp,
777 const unsigned char *ptr, size_t *leftp, size_t nfds, nvlist_t **child)
778 {
779 nvlist_t *value;
780
781 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST);
782
783 if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
784 ERRNO_SET(EINVAL);
785 return (NULL);
786 }
787
788 value = nvlist_create(0);
789 if (value == NULL)
790 return (NULL);
791
792 ptr = nvlist_unpack_header(value, ptr, nfds, NULL, leftp);
793 if (ptr == NULL)
794 return (NULL);
795
796 nvp->nvp_data = (uint64_t)(uintptr_t)value;
797 *child = value;
798
799 return (ptr);
800 }
801
802 #ifndef _KERNEL
803 const unsigned char *
nvpair_unpack_descriptor(bool isbe,nvpair_t * nvp,const unsigned char * ptr,size_t * leftp,const int * fds,size_t nfds)804 nvpair_unpack_descriptor(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
805 size_t *leftp, const int *fds, size_t nfds)
806 {
807 int64_t idx;
808
809 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
810
811 if (nvp->nvp_datasize != sizeof(idx)) {
812 ERRNO_SET(EINVAL);
813 return (NULL);
814 }
815 if (*leftp < sizeof(idx)) {
816 ERRNO_SET(EINVAL);
817 return (NULL);
818 }
819
820 if (isbe)
821 idx = be64dec(ptr);
822 else
823 idx = le64dec(ptr);
824
825 if (idx < 0) {
826 ERRNO_SET(EINVAL);
827 return (NULL);
828 }
829
830 if ((size_t)idx >= nfds) {
831 ERRNO_SET(EINVAL);
832 return (NULL);
833 }
834
835 nvp->nvp_data = (uint64_t)fds[idx];
836
837 ptr += sizeof(idx);
838 *leftp -= sizeof(idx);
839
840 return (ptr);
841 }
842 #endif
843
844 const unsigned char *
nvpair_unpack_binary(bool isbe __unused,nvpair_t * nvp,const unsigned char * ptr,size_t * leftp)845 nvpair_unpack_binary(bool isbe __unused, nvpair_t *nvp,
846 const unsigned char *ptr, size_t *leftp)
847 {
848 void *value;
849
850 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
851
852 if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0) {
853 ERRNO_SET(EINVAL);
854 return (NULL);
855 }
856
857 value = nv_malloc(nvp->nvp_datasize);
858 if (value == NULL)
859 return (NULL);
860
861 memcpy(value, ptr, nvp->nvp_datasize);
862 ptr += nvp->nvp_datasize;
863 *leftp -= nvp->nvp_datasize;
864
865 nvp->nvp_data = (uint64_t)(uintptr_t)value;
866
867 return (ptr);
868 }
869
870 const unsigned char *
nvpair_unpack_bool_array(bool isbe __unused,nvpair_t * nvp,const unsigned char * ptr,size_t * leftp)871 nvpair_unpack_bool_array(bool isbe __unused, nvpair_t *nvp,
872 const unsigned char *ptr, size_t *leftp)
873 {
874 uint8_t *value;
875 size_t size;
876 unsigned int i;
877
878 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL_ARRAY);
879
880 size = sizeof(*value) * nvp->nvp_nitems;
881 if (nvp->nvp_datasize != size || *leftp < size ||
882 nvp->nvp_nitems == 0 || size < nvp->nvp_nitems) {
883 ERRNO_SET(EINVAL);
884 return (NULL);
885 }
886
887 value = nv_malloc(size);
888 if (value == NULL)
889 return (NULL);
890
891 for (i = 0; i < nvp->nvp_nitems; i++) {
892 value[i] = *(const uint8_t *)ptr;
893
894 ptr += sizeof(*value);
895 *leftp -= sizeof(*value);
896 }
897
898 nvp->nvp_data = (uint64_t)(uintptr_t)value;
899
900 return (ptr);
901 }
902
903 const unsigned char *
nvpair_unpack_number_array(bool isbe,nvpair_t * nvp,const unsigned char * ptr,size_t * leftp)904 nvpair_unpack_number_array(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
905 size_t *leftp)
906 {
907 uint64_t *value;
908 size_t size;
909 unsigned int i;
910
911 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER_ARRAY);
912
913 size = sizeof(*value) * nvp->nvp_nitems;
914 if (nvp->nvp_datasize != size || *leftp < size ||
915 nvp->nvp_nitems == 0 || size < nvp->nvp_nitems) {
916 ERRNO_SET(EINVAL);
917 return (NULL);
918 }
919
920 value = nv_malloc(size);
921 if (value == NULL)
922 return (NULL);
923
924 for (i = 0; i < nvp->nvp_nitems; i++) {
925 if (isbe)
926 value[i] = be64dec(ptr);
927 else
928 value[i] = le64dec(ptr);
929
930 ptr += sizeof(*value);
931 *leftp -= sizeof(*value);
932 }
933
934 nvp->nvp_data = (uint64_t)(uintptr_t)value;
935
936 return (ptr);
937 }
938
939 const unsigned char *
nvpair_unpack_string_array(bool isbe __unused,nvpair_t * nvp,const unsigned char * ptr,size_t * leftp)940 nvpair_unpack_string_array(bool isbe __unused, nvpair_t *nvp,
941 const unsigned char *ptr, size_t *leftp)
942 {
943 ssize_t size;
944 size_t len;
945 const char *tmp;
946 char **value;
947 unsigned int ii, j;
948
949 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING_ARRAY);
950
951 if (*leftp < nvp->nvp_datasize || nvp->nvp_datasize == 0 ||
952 nvp->nvp_nitems == 0) {
953 ERRNO_SET(EINVAL);
954 return (NULL);
955 }
956
957 size = nvp->nvp_datasize;
958 tmp = (const char *)ptr;
959 for (ii = 0; ii < nvp->nvp_nitems; ii++) {
960 len = strnlen(tmp, size - 1) + 1;
961 size -= len;
962 if (size < 0) {
963 ERRNO_SET(EINVAL);
964 return (NULL);
965 }
966 tmp += len;
967 }
968 if (size != 0) {
969 ERRNO_SET(EINVAL);
970 return (NULL);
971 }
972
973 value = nv_malloc(sizeof(*value) * nvp->nvp_nitems);
974 if (value == NULL)
975 return (NULL);
976
977 for (ii = 0; ii < nvp->nvp_nitems; ii++) {
978 value[ii] = nv_strdup((const char *)ptr);
979 if (value[ii] == NULL)
980 goto out;
981 len = strlen(value[ii]) + 1;
982 ptr += len;
983 *leftp -= len;
984 }
985 nvp->nvp_data = (uint64_t)(uintptr_t)value;
986
987 return (ptr);
988 out:
989 for (j = 0; j < ii; j++)
990 nv_free(value[j]);
991 nv_free(value);
992 return (NULL);
993 }
994
995 #ifndef _KERNEL
996 const unsigned char *
nvpair_unpack_descriptor_array(bool isbe,nvpair_t * nvp,const unsigned char * ptr,size_t * leftp,const int * fds,size_t nfds)997 nvpair_unpack_descriptor_array(bool isbe, nvpair_t *nvp,
998 const unsigned char *ptr, size_t *leftp, const int *fds, size_t nfds)
999 {
1000 int64_t idx;
1001 size_t size;
1002 unsigned int ii;
1003 int *array;
1004
1005 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR_ARRAY);
1006
1007 size = sizeof(idx) * nvp->nvp_nitems;
1008 if (nvp->nvp_datasize != size || *leftp < size ||
1009 nvp->nvp_nitems == 0 || size < nvp->nvp_nitems) {
1010 ERRNO_SET(EINVAL);
1011 return (NULL);
1012 }
1013
1014 array = (int *)nv_malloc(size);
1015 if (array == NULL)
1016 return (NULL);
1017
1018 for (ii = 0; ii < nvp->nvp_nitems; ii++) {
1019 if (isbe)
1020 idx = be64dec(ptr);
1021 else
1022 idx = le64dec(ptr);
1023
1024 if (idx < 0) {
1025 ERRNO_SET(EINVAL);
1026 nv_free(array);
1027 return (NULL);
1028 }
1029
1030 if ((size_t)idx >= nfds) {
1031 ERRNO_SET(EINVAL);
1032 nv_free(array);
1033 return (NULL);
1034 }
1035
1036 array[ii] = (uint64_t)fds[idx];
1037
1038 ptr += sizeof(idx);
1039 *leftp -= sizeof(idx);
1040 }
1041
1042 nvp->nvp_data = (uint64_t)(uintptr_t)array;
1043
1044 return (ptr);
1045 }
1046 #endif
1047
1048 const unsigned char *
nvpair_unpack_nvlist_array(bool isbe __unused,nvpair_t * nvp,const unsigned char * ptr,size_t * leftp,nvlist_t ** firstel)1049 nvpair_unpack_nvlist_array(bool isbe __unused, nvpair_t *nvp,
1050 const unsigned char *ptr, size_t *leftp, nvlist_t **firstel)
1051 {
1052 nvlist_t **value;
1053 nvpair_t *tmpnvp;
1054 unsigned int ii, j;
1055 size_t sizeup;
1056
1057 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST_ARRAY);
1058
1059 sizeup = sizeof(struct nvpair_header) * nvp->nvp_nitems;
1060 if (nvp->nvp_nitems == 0 || sizeup < nvp->nvp_nitems ||
1061 sizeup > *leftp) {
1062 ERRNO_SET(EINVAL);
1063 return (NULL);
1064 }
1065
1066 value = nv_malloc(nvp->nvp_nitems * sizeof(*value));
1067 if (value == NULL)
1068 return (NULL);
1069
1070 for (ii = 0; ii < nvp->nvp_nitems; ii++) {
1071 value[ii] = nvlist_create(0);
1072 if (value[ii] == NULL)
1073 goto fail;
1074 if (ii > 0) {
1075 tmpnvp = nvpair_allocv(" ", NV_TYPE_NVLIST,
1076 (uint64_t)(uintptr_t)value[ii], 0, 0);
1077 if (tmpnvp == NULL)
1078 goto fail;
1079 nvlist_set_array_next(value[ii - 1], tmpnvp);
1080 }
1081 }
1082 nvlist_set_flags(value[nvp->nvp_nitems - 1], NV_FLAG_IN_ARRAY);
1083
1084 nvp->nvp_data = (uint64_t)(uintptr_t)value;
1085 *firstel = value[0];
1086
1087 return (ptr);
1088 fail:
1089 ERRNO_SAVE();
1090 for (j = 0; j < ii; j++)
1091 nvlist_destroy(value[j]);
1092 nv_free(value);
1093 ERRNO_RESTORE();
1094
1095 return (NULL);
1096 }
1097
1098 const unsigned char *
nvpair_unpack(bool isbe,const unsigned char * ptr,size_t * leftp,nvpair_t ** nvpp)1099 nvpair_unpack(bool isbe, const unsigned char *ptr, size_t *leftp,
1100 nvpair_t **nvpp)
1101 {
1102 nvpair_t *nvp, *tmp;
1103
1104 nvp = nv_calloc(1, sizeof(*nvp) + NV_NAME_MAX);
1105 if (nvp == NULL)
1106 return (NULL);
1107 nvp->nvp_name = (char *)(nvp + 1);
1108
1109 ptr = nvpair_unpack_header(isbe, nvp, ptr, leftp);
1110 if (ptr == NULL)
1111 goto failed;
1112 tmp = nv_realloc(nvp, sizeof(*nvp) + strlen(nvp->nvp_name) + 1);
1113 if (tmp == NULL)
1114 goto failed;
1115 nvp = tmp;
1116
1117 /* Update nvp_name after realloc(). */
1118 nvp->nvp_name = (char *)(nvp + 1);
1119 nvp->nvp_data = 0x00;
1120 nvp->nvp_magic = NVPAIR_MAGIC;
1121 *nvpp = nvp;
1122 return (ptr);
1123 failed:
1124 nv_free(nvp);
1125 return (NULL);
1126 }
1127
1128 int
nvpair_type(const nvpair_t * nvp)1129 nvpair_type(const nvpair_t *nvp)
1130 {
1131
1132 NVPAIR_ASSERT(nvp);
1133
1134 return (nvp->nvp_type);
1135 }
1136
1137 const char *
nvpair_name(const nvpair_t * nvp)1138 nvpair_name(const nvpair_t *nvp)
1139 {
1140
1141 NVPAIR_ASSERT(nvp);
1142
1143 return (nvp->nvp_name);
1144 }
1145
1146 nvpair_t *
nvpair_create_stringf(const char * name,const char * valuefmt,...)1147 nvpair_create_stringf(const char *name, const char *valuefmt, ...)
1148 {
1149 va_list valueap;
1150 nvpair_t *nvp;
1151
1152 va_start(valueap, valuefmt);
1153 nvp = nvpair_create_stringv(name, valuefmt, valueap);
1154 va_end(valueap);
1155
1156 return (nvp);
1157 }
1158
1159 nvpair_t *
nvpair_create_stringv(const char * name,const char * valuefmt,va_list valueap)1160 nvpair_create_stringv(const char *name, const char *valuefmt, va_list valueap)
1161 {
1162 nvpair_t *nvp;
1163 char *str;
1164 int len;
1165
1166 len = nv_vasprintf(&str, valuefmt, valueap);
1167 if (len < 0)
1168 return (NULL);
1169 nvp = nvpair_create_string(name, str);
1170 if (nvp == NULL)
1171 nv_free(str);
1172 return (nvp);
1173 }
1174
1175 nvpair_t *
nvpair_create_null(const char * name)1176 nvpair_create_null(const char *name)
1177 {
1178
1179 return (nvpair_allocv(name, NV_TYPE_NULL, 0, 0, 0));
1180 }
1181
1182 nvpair_t *
nvpair_create_bool(const char * name,bool value)1183 nvpair_create_bool(const char *name, bool value)
1184 {
1185
1186 return (nvpair_allocv(name, NV_TYPE_BOOL, value ? 1 : 0,
1187 sizeof(uint8_t), 0));
1188 }
1189
1190 nvpair_t *
nvpair_create_number(const char * name,uint64_t value)1191 nvpair_create_number(const char *name, uint64_t value)
1192 {
1193
1194 return (nvpair_allocv(name, NV_TYPE_NUMBER, value, sizeof(value), 0));
1195 }
1196
1197 nvpair_t *
nvpair_create_string(const char * name,const char * value)1198 nvpair_create_string(const char *name, const char *value)
1199 {
1200 nvpair_t *nvp;
1201 size_t size;
1202 char *data;
1203
1204 if (value == NULL) {
1205 ERRNO_SET(EINVAL);
1206 return (NULL);
1207 }
1208
1209 data = nv_strdup(value);
1210 if (data == NULL)
1211 return (NULL);
1212 size = strlen(value) + 1;
1213
1214 nvp = nvpair_allocv(name, NV_TYPE_STRING, (uint64_t)(uintptr_t)data,
1215 size, 0);
1216 if (nvp == NULL)
1217 nv_free(data);
1218
1219 return (nvp);
1220 }
1221
1222 nvpair_t *
nvpair_create_nvlist(const char * name,const nvlist_t * value)1223 nvpair_create_nvlist(const char *name, const nvlist_t *value)
1224 {
1225 nvlist_t *nvl;
1226 nvpair_t *nvp;
1227
1228 if (value == NULL) {
1229 ERRNO_SET(EINVAL);
1230 return (NULL);
1231 }
1232
1233 nvl = nvlist_clone(value);
1234 if (nvl == NULL)
1235 return (NULL);
1236
1237 nvp = nvpair_allocv(name, NV_TYPE_NVLIST, (uint64_t)(uintptr_t)nvl, 0,
1238 0);
1239 if (nvp == NULL)
1240 nvlist_destroy(nvl);
1241 else
1242 nvlist_set_parent(nvl, nvp);
1243
1244 return (nvp);
1245 }
1246
1247 #ifndef _KERNEL
1248 nvpair_t *
nvpair_create_descriptor(const char * name,int value)1249 nvpair_create_descriptor(const char *name, int value)
1250 {
1251 nvpair_t *nvp;
1252
1253 if (value < 0 || !fd_is_valid(value)) {
1254 ERRNO_SET(EBADF);
1255 return (NULL);
1256 }
1257
1258 value = fcntl(value, F_DUPFD_CLOEXEC, 0);
1259 if (value < 0)
1260 return (NULL);
1261
1262 nvp = nvpair_allocv(name, NV_TYPE_DESCRIPTOR, (uint64_t)value,
1263 sizeof(int64_t), 0);
1264 if (nvp == NULL) {
1265 ERRNO_SAVE();
1266 close(value);
1267 ERRNO_RESTORE();
1268 }
1269
1270 return (nvp);
1271 }
1272 #endif
1273
1274 nvpair_t *
nvpair_create_binary(const char * name,const void * value,size_t size)1275 nvpair_create_binary(const char *name, const void *value, size_t size)
1276 {
1277 nvpair_t *nvp;
1278 void *data;
1279
1280 if (value == NULL || size == 0) {
1281 ERRNO_SET(EINVAL);
1282 return (NULL);
1283 }
1284
1285 data = nv_malloc(size);
1286 if (data == NULL)
1287 return (NULL);
1288 memcpy(data, value, size);
1289
1290 nvp = nvpair_allocv(name, NV_TYPE_BINARY, (uint64_t)(uintptr_t)data,
1291 size, 0);
1292 if (nvp == NULL)
1293 nv_free(data);
1294
1295 return (nvp);
1296 }
1297
1298 nvpair_t *
nvpair_create_bool_array(const char * name,const bool * value,size_t nitems)1299 nvpair_create_bool_array(const char *name, const bool *value, size_t nitems)
1300 {
1301 nvpair_t *nvp;
1302 size_t size;
1303 void *data;
1304
1305 if (value == NULL || nitems == 0) {
1306 ERRNO_SET(EINVAL);
1307 return (NULL);
1308 }
1309
1310 size = sizeof(value[0]) * nitems;
1311 data = nv_malloc(size);
1312 if (data == NULL)
1313 return (NULL);
1314
1315 memcpy(data, value, size);
1316 nvp = nvpair_allocv(name, NV_TYPE_BOOL_ARRAY, (uint64_t)(uintptr_t)data,
1317 size, nitems);
1318 if (nvp == NULL) {
1319 ERRNO_SAVE();
1320 nv_free(data);
1321 ERRNO_RESTORE();
1322 }
1323
1324 return (nvp);
1325 }
1326
1327 nvpair_t *
nvpair_create_number_array(const char * name,const uint64_t * value,size_t nitems)1328 nvpair_create_number_array(const char *name, const uint64_t *value,
1329 size_t nitems)
1330 {
1331 nvpair_t *nvp;
1332 size_t size;
1333 void *data;
1334
1335 if (value == NULL || nitems == 0) {
1336 ERRNO_SET(EINVAL);
1337 return (NULL);
1338 }
1339
1340 size = sizeof(value[0]) * nitems;
1341 data = nv_malloc(size);
1342 if (data == NULL)
1343 return (NULL);
1344
1345 memcpy(data, value, size);
1346 nvp = nvpair_allocv(name, NV_TYPE_NUMBER_ARRAY,
1347 (uint64_t)(uintptr_t)data, size, nitems);
1348 if (nvp == NULL) {
1349 ERRNO_SAVE();
1350 nv_free(data);
1351 ERRNO_RESTORE();
1352 }
1353
1354 return (nvp);
1355 }
1356
1357 nvpair_t *
nvpair_create_string_array(const char * name,const char * const * value,size_t nitems)1358 nvpair_create_string_array(const char *name, const char * const *value,
1359 size_t nitems)
1360 {
1361 nvpair_t *nvp;
1362 unsigned int ii;
1363 size_t datasize, size;
1364 char **data;
1365
1366 if (value == NULL || nitems == 0) {
1367 ERRNO_SET(EINVAL);
1368 return (NULL);
1369 }
1370
1371 nvp = NULL;
1372 datasize = 0;
1373 data = nv_malloc(sizeof(value[0]) * nitems);
1374 if (data == NULL)
1375 return (NULL);
1376
1377 for (ii = 0; ii < nitems; ii++) {
1378 if (value[ii] == NULL) {
1379 ERRNO_SET(EINVAL);
1380 goto fail;
1381 }
1382
1383 size = strlen(value[ii]) + 1;
1384 datasize += size;
1385 data[ii] = nv_strdup(value[ii]);
1386 if (data[ii] == NULL)
1387 goto fail;
1388 }
1389 nvp = nvpair_allocv(name, NV_TYPE_STRING_ARRAY,
1390 (uint64_t)(uintptr_t)data, datasize, nitems);
1391
1392 fail:
1393 if (nvp == NULL) {
1394 ERRNO_SAVE();
1395 for (; ii > 0; ii--)
1396 nv_free(data[ii - 1]);
1397 nv_free(data);
1398 ERRNO_RESTORE();
1399 }
1400
1401 return (nvp);
1402 }
1403
1404 nvpair_t *
nvpair_create_nvlist_array(const char * name,const nvlist_t * const * value,size_t nitems)1405 nvpair_create_nvlist_array(const char *name, const nvlist_t * const *value,
1406 size_t nitems)
1407 {
1408 unsigned int ii;
1409 nvlist_t **nvls;
1410 nvpair_t *nvp;
1411 int flags;
1412
1413 nvp = NULL;
1414 nvls = NULL;
1415 ii = 0;
1416
1417 if (value == NULL || nitems == 0) {
1418 ERRNO_SET(EINVAL);
1419 return (NULL);
1420 }
1421
1422 nvls = nv_malloc(sizeof(value[0]) * nitems);
1423 if (nvls == NULL)
1424 return (NULL);
1425
1426 for (ii = 0; ii < nitems; ii++) {
1427 if (value[ii] == NULL) {
1428 ERRNO_SET(EINVAL);
1429 goto fail;
1430 }
1431
1432 nvls[ii] = nvlist_clone(value[ii]);
1433 if (nvls[ii] == NULL)
1434 goto fail;
1435
1436 if (ii > 0) {
1437 nvp = nvpair_allocv(" ", NV_TYPE_NVLIST,
1438 (uint64_t)(uintptr_t)nvls[ii], 0, 0);
1439 if (nvp == NULL)
1440 goto fail;
1441 nvlist_set_array_next(nvls[ii - 1], nvp);
1442 }
1443 }
1444 flags = nvlist_flags(nvls[nitems - 1]) | NV_FLAG_IN_ARRAY;
1445 nvlist_set_flags(nvls[nitems - 1], flags);
1446
1447 nvp = nvpair_allocv(name, NV_TYPE_NVLIST_ARRAY,
1448 (uint64_t)(uintptr_t)nvls, 0, nitems);
1449
1450 fail:
1451 if (nvp == NULL) {
1452 ERRNO_SAVE();
1453 for (; ii > 0; ii--)
1454 nvlist_destroy(nvls[ii - 1]);
1455
1456 nv_free(nvls);
1457 ERRNO_RESTORE();
1458 } else {
1459 for (ii = 0; ii < nitems; ii++)
1460 nvlist_set_parent(nvls[ii], nvp);
1461 }
1462
1463 return (nvp);
1464 }
1465
1466 #ifndef _KERNEL
1467 nvpair_t *
nvpair_create_descriptor_array(const char * name,const int * value,size_t nitems)1468 nvpair_create_descriptor_array(const char *name, const int *value,
1469 size_t nitems)
1470 {
1471 unsigned int ii;
1472 nvpair_t *nvp;
1473 int *fds;
1474
1475 if (value == NULL) {
1476 ERRNO_SET(EINVAL);
1477 return (NULL);
1478 }
1479
1480 nvp = NULL;
1481
1482 fds = nv_malloc(sizeof(value[0]) * nitems);
1483 if (fds == NULL)
1484 return (NULL);
1485 for (ii = 0; ii < nitems; ii++) {
1486 if (value[ii] == -1) {
1487 fds[ii] = -1;
1488 } else {
1489 if (!fd_is_valid(value[ii])) {
1490 ERRNO_SET(EBADF);
1491 goto fail;
1492 }
1493
1494 fds[ii] = fcntl(value[ii], F_DUPFD_CLOEXEC, 0);
1495 if (fds[ii] == -1)
1496 goto fail;
1497 }
1498 }
1499
1500 nvp = nvpair_allocv(name, NV_TYPE_DESCRIPTOR_ARRAY,
1501 (uint64_t)(uintptr_t)fds, sizeof(int64_t) * nitems, nitems);
1502
1503 fail:
1504 if (nvp == NULL) {
1505 ERRNO_SAVE();
1506 for (; ii > 0; ii--) {
1507 if (fds[ii - 1] != -1)
1508 close(fds[ii - 1]);
1509 }
1510 nv_free(fds);
1511 ERRNO_RESTORE();
1512 }
1513
1514 return (nvp);
1515 }
1516 #endif
1517
1518 nvpair_t *
nvpair_move_string(const char * name,char * value)1519 nvpair_move_string(const char *name, char *value)
1520 {
1521 nvpair_t *nvp;
1522
1523 if (value == NULL) {
1524 ERRNO_SET(EINVAL);
1525 return (NULL);
1526 }
1527
1528 nvp = nvpair_allocv(name, NV_TYPE_STRING, (uint64_t)(uintptr_t)value,
1529 strlen(value) + 1, 0);
1530 if (nvp == NULL) {
1531 ERRNO_SAVE();
1532 nv_free(value);
1533 ERRNO_RESTORE();
1534 }
1535
1536 return (nvp);
1537 }
1538
1539 nvpair_t *
nvpair_move_nvlist(const char * name,nvlist_t * value)1540 nvpair_move_nvlist(const char *name, nvlist_t *value)
1541 {
1542 nvpair_t *nvp;
1543
1544 if (value == NULL || nvlist_get_nvpair_parent(value) != NULL) {
1545 ERRNO_SET(EINVAL);
1546 return (NULL);
1547 }
1548
1549 if (nvlist_error(value) != 0) {
1550 ERRNO_SET(nvlist_error(value));
1551 nvlist_destroy(value);
1552 return (NULL);
1553 }
1554
1555 nvp = nvpair_allocv(name, NV_TYPE_NVLIST, (uint64_t)(uintptr_t)value,
1556 0, 0);
1557 if (nvp == NULL)
1558 nvlist_destroy(value);
1559 else
1560 nvlist_set_parent(value, nvp);
1561
1562 return (nvp);
1563 }
1564
1565 #ifndef _KERNEL
1566 nvpair_t *
nvpair_move_descriptor(const char * name,int value)1567 nvpair_move_descriptor(const char *name, int value)
1568 {
1569 nvpair_t *nvp;
1570
1571 if (value < 0 || !fd_is_valid(value)) {
1572 ERRNO_SET(EBADF);
1573 return (NULL);
1574 }
1575
1576 nvp = nvpair_allocv(name, NV_TYPE_DESCRIPTOR, (uint64_t)value,
1577 sizeof(int64_t), 0);
1578 if (nvp == NULL) {
1579 ERRNO_SAVE();
1580 close(value);
1581 ERRNO_RESTORE();
1582 }
1583
1584 return (nvp);
1585 }
1586 #endif
1587
1588 nvpair_t *
nvpair_move_binary(const char * name,void * value,size_t size)1589 nvpair_move_binary(const char *name, void *value, size_t size)
1590 {
1591 nvpair_t *nvp;
1592
1593 if (value == NULL || size == 0) {
1594 ERRNO_SET(EINVAL);
1595 return (NULL);
1596 }
1597
1598 nvp = nvpair_allocv(name, NV_TYPE_BINARY, (uint64_t)(uintptr_t)value,
1599 size, 0);
1600 if (nvp == NULL) {
1601 ERRNO_SAVE();
1602 nv_free(value);
1603 ERRNO_RESTORE();
1604 }
1605
1606 return (nvp);
1607 }
1608
1609 nvpair_t *
nvpair_move_bool_array(const char * name,bool * value,size_t nitems)1610 nvpair_move_bool_array(const char *name, bool *value, size_t nitems)
1611 {
1612 nvpair_t *nvp;
1613
1614 if (value == NULL || nitems == 0) {
1615 ERRNO_SET(EINVAL);
1616 return (NULL);
1617 }
1618
1619 nvp = nvpair_allocv(name, NV_TYPE_BOOL_ARRAY,
1620 (uint64_t)(uintptr_t)value, sizeof(value[0]) * nitems, nitems);
1621 if (nvp == NULL) {
1622 ERRNO_SAVE();
1623 nv_free(value);
1624 ERRNO_RESTORE();
1625 }
1626
1627 return (nvp);
1628 }
1629
1630 nvpair_t *
nvpair_move_string_array(const char * name,char ** value,size_t nitems)1631 nvpair_move_string_array(const char *name, char **value, size_t nitems)
1632 {
1633 nvpair_t *nvp;
1634 size_t i, size;
1635
1636 if (value == NULL || nitems == 0) {
1637 ERRNO_SET(EINVAL);
1638 return (NULL);
1639 }
1640
1641 size = 0;
1642 for (i = 0; i < nitems; i++) {
1643 if (value[i] == NULL) {
1644 ERRNO_SET(EINVAL);
1645 return (NULL);
1646 }
1647
1648 size += strlen(value[i]) + 1;
1649 }
1650
1651 nvp = nvpair_allocv(name, NV_TYPE_STRING_ARRAY,
1652 (uint64_t)(uintptr_t)value, size, nitems);
1653 if (nvp == NULL) {
1654 ERRNO_SAVE();
1655 for (i = 0; i < nitems; i++)
1656 nv_free(value[i]);
1657 nv_free(value);
1658 ERRNO_RESTORE();
1659 }
1660
1661 return (nvp);
1662 }
1663
1664 nvpair_t *
nvpair_move_number_array(const char * name,uint64_t * value,size_t nitems)1665 nvpair_move_number_array(const char *name, uint64_t *value, size_t nitems)
1666 {
1667 nvpair_t *nvp;
1668
1669 if (value == NULL || nitems == 0) {
1670 ERRNO_SET(EINVAL);
1671 return (NULL);
1672 }
1673
1674 nvp = nvpair_allocv(name, NV_TYPE_NUMBER_ARRAY,
1675 (uint64_t)(uintptr_t)value, sizeof(value[0]) * nitems, nitems);
1676 if (nvp == NULL) {
1677 ERRNO_SAVE();
1678 nv_free(value);
1679 ERRNO_RESTORE();
1680 }
1681
1682 return (nvp);
1683 }
1684
1685 nvpair_t *
nvpair_move_nvlist_array(const char * name,nvlist_t ** value,size_t nitems)1686 nvpair_move_nvlist_array(const char *name, nvlist_t **value, size_t nitems)
1687 {
1688 unsigned int ii;
1689 nvpair_t *nvp;
1690 int flags;
1691
1692 nvp = NULL;
1693 if (value == NULL || nitems == 0) {
1694 ERRNO_SET(EINVAL);
1695 return (NULL);
1696 }
1697
1698 for (ii = 0; ii < nitems; ii++) {
1699 if (value == NULL || nvlist_error(value[ii]) != 0 ||
1700 nvlist_get_pararr(value[ii], NULL) != NULL) {
1701 ERRNO_SET(EINVAL);
1702 goto fail;
1703 }
1704 if (ii > 0) {
1705 nvp = nvpair_allocv(" ", NV_TYPE_NVLIST,
1706 (uint64_t)(uintptr_t)value[ii], 0, 0);
1707 if (nvp == NULL)
1708 goto fail;
1709 nvlist_set_array_next(value[ii - 1], nvp);
1710 }
1711 }
1712 flags = nvlist_flags(value[nitems - 1]) | NV_FLAG_IN_ARRAY;
1713 nvlist_set_flags(value[nitems - 1], flags);
1714
1715 nvp = nvpair_allocv(name, NV_TYPE_NVLIST_ARRAY,
1716 (uint64_t)(uintptr_t)value, 0, nitems);
1717 fail:
1718 if (nvp == NULL) {
1719 ERRNO_SAVE();
1720 for (ii = 0; ii < nitems; ii++) {
1721 if (value[ii] != NULL &&
1722 nvlist_get_pararr(value[ii], NULL) != NULL) {
1723 nvlist_destroy(value[ii]);
1724 }
1725 nv_free(value);
1726 }
1727 ERRNO_RESTORE();
1728 } else {
1729 for (ii = 0; ii < nitems; ii++)
1730 nvlist_set_parent(value[ii], nvp);
1731 }
1732
1733 return (nvp);
1734 }
1735
1736 #ifndef _KERNEL
1737 nvpair_t *
nvpair_move_descriptor_array(const char * name,int * value,size_t nitems)1738 nvpair_move_descriptor_array(const char *name, int *value, size_t nitems)
1739 {
1740 nvpair_t *nvp;
1741 size_t i;
1742
1743 nvp = NULL;
1744 if (value == NULL || nitems == 0) {
1745 ERRNO_SET(EINVAL);
1746 return (NULL);
1747 }
1748
1749 for (i = 0; i < nitems; i++) {
1750 if (value[i] != -1 && !fd_is_valid(value[i])) {
1751 ERRNO_SET(EBADF);
1752 goto fail;
1753 }
1754 }
1755
1756 nvp = nvpair_allocv(name, NV_TYPE_DESCRIPTOR_ARRAY,
1757 (uint64_t)(uintptr_t)value, sizeof(value[0]) * nitems, nitems);
1758
1759 fail:
1760 if (nvp == NULL) {
1761 ERRNO_SAVE();
1762 for (i = 0; i < nitems; i++) {
1763 if (fd_is_valid(value[i]))
1764 close(value[i]);
1765 }
1766 nv_free(value);
1767 ERRNO_RESTORE();
1768 }
1769
1770 return (nvp);
1771 }
1772 #endif
1773
1774 bool
nvpair_get_bool(const nvpair_t * nvp)1775 nvpair_get_bool(const nvpair_t *nvp)
1776 {
1777
1778 NVPAIR_ASSERT(nvp);
1779
1780 return (nvp->nvp_data == 1);
1781 }
1782
1783 uint64_t
nvpair_get_number(const nvpair_t * nvp)1784 nvpair_get_number(const nvpair_t *nvp)
1785 {
1786
1787 NVPAIR_ASSERT(nvp);
1788
1789 return (nvp->nvp_data);
1790 }
1791
1792 const char *
nvpair_get_string(const nvpair_t * nvp)1793 nvpair_get_string(const nvpair_t *nvp)
1794 {
1795
1796 NVPAIR_ASSERT(nvp);
1797 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING);
1798
1799 return ((const char *)(intptr_t)nvp->nvp_data);
1800 }
1801
1802 const nvlist_t *
nvpair_get_nvlist(const nvpair_t * nvp)1803 nvpair_get_nvlist(const nvpair_t *nvp)
1804 {
1805
1806 NVPAIR_ASSERT(nvp);
1807 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST);
1808
1809 return ((const nvlist_t *)(intptr_t)nvp->nvp_data);
1810 }
1811
1812 #ifndef _KERNEL
1813 int
nvpair_get_descriptor(const nvpair_t * nvp)1814 nvpair_get_descriptor(const nvpair_t *nvp)
1815 {
1816
1817 NVPAIR_ASSERT(nvp);
1818 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR);
1819
1820 return ((int)nvp->nvp_data);
1821 }
1822 #endif
1823
1824 const void *
nvpair_get_binary(const nvpair_t * nvp,size_t * sizep)1825 nvpair_get_binary(const nvpair_t *nvp, size_t *sizep)
1826 {
1827
1828 NVPAIR_ASSERT(nvp);
1829 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BINARY);
1830
1831 if (sizep != NULL)
1832 *sizep = nvp->nvp_datasize;
1833
1834 return ((const void *)(intptr_t)nvp->nvp_data);
1835 }
1836
1837 const bool *
nvpair_get_bool_array(const nvpair_t * nvp,size_t * nitems)1838 nvpair_get_bool_array(const nvpair_t *nvp, size_t *nitems)
1839 {
1840
1841 NVPAIR_ASSERT(nvp);
1842 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_BOOL_ARRAY);
1843
1844 if (nitems != NULL)
1845 *nitems = nvp->nvp_nitems;
1846
1847 return ((const bool *)(intptr_t)nvp->nvp_data);
1848 }
1849
1850 const uint64_t *
nvpair_get_number_array(const nvpair_t * nvp,size_t * nitems)1851 nvpair_get_number_array(const nvpair_t *nvp, size_t *nitems)
1852 {
1853
1854 NVPAIR_ASSERT(nvp);
1855 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER_ARRAY);
1856
1857 if (nitems != NULL)
1858 *nitems = nvp->nvp_nitems;
1859
1860 return ((const uint64_t *)(intptr_t)nvp->nvp_data);
1861 }
1862
1863 const char * const *
nvpair_get_string_array(const nvpair_t * nvp,size_t * nitems)1864 nvpair_get_string_array(const nvpair_t *nvp, size_t *nitems)
1865 {
1866
1867 NVPAIR_ASSERT(nvp);
1868 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_STRING_ARRAY);
1869
1870 if (nitems != NULL)
1871 *nitems = nvp->nvp_nitems;
1872
1873 return ((const char * const *)(intptr_t)nvp->nvp_data);
1874 }
1875
1876 const nvlist_t * const *
nvpair_get_nvlist_array(const nvpair_t * nvp,size_t * nitems)1877 nvpair_get_nvlist_array(const nvpair_t *nvp, size_t *nitems)
1878 {
1879
1880 NVPAIR_ASSERT(nvp);
1881 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST_ARRAY);
1882
1883 if (nitems != NULL)
1884 *nitems = nvp->nvp_nitems;
1885
1886 return ((const nvlist_t * const *)((intptr_t)nvp->nvp_data));
1887 }
1888
1889 #ifndef _KERNEL
1890 const int *
nvpair_get_descriptor_array(const nvpair_t * nvp,size_t * nitems)1891 nvpair_get_descriptor_array(const nvpair_t *nvp, size_t *nitems)
1892 {
1893
1894 NVPAIR_ASSERT(nvp);
1895 PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_DESCRIPTOR_ARRAY);
1896
1897 if (nitems != NULL)
1898 *nitems = nvp->nvp_nitems;
1899
1900 return ((const int *)(intptr_t)nvp->nvp_data);
1901 }
1902 #endif
1903
1904 void
nvpair_free(nvpair_t * nvp)1905 nvpair_free(nvpair_t *nvp)
1906 {
1907 size_t i;
1908
1909 NVPAIR_ASSERT(nvp);
1910 PJDLOG_ASSERT(nvp->nvp_list == NULL);
1911
1912 nvp->nvp_magic = 0;
1913 switch (nvp->nvp_type) {
1914 #ifndef _KERNEL
1915 case NV_TYPE_DESCRIPTOR:
1916 close((int)nvp->nvp_data);
1917 break;
1918 case NV_TYPE_DESCRIPTOR_ARRAY:
1919 for (i = 0; i < nvp->nvp_nitems; i++)
1920 close(((int *)(intptr_t)nvp->nvp_data)[i]);
1921 break;
1922 #endif
1923 case NV_TYPE_NVLIST:
1924 nvlist_destroy((nvlist_t *)(intptr_t)nvp->nvp_data);
1925 break;
1926 case NV_TYPE_STRING:
1927 nv_free((char *)(intptr_t)nvp->nvp_data);
1928 break;
1929 case NV_TYPE_BINARY:
1930 nv_free((void *)(intptr_t)nvp->nvp_data);
1931 break;
1932 case NV_TYPE_NVLIST_ARRAY:
1933 for (i = 0; i < nvp->nvp_nitems; i++) {
1934 nvlist_destroy(
1935 ((nvlist_t **)(intptr_t)nvp->nvp_data)[i]);
1936 }
1937 nv_free(((nvlist_t **)(intptr_t)nvp->nvp_data));
1938 break;
1939 case NV_TYPE_NUMBER_ARRAY:
1940 nv_free((uint64_t *)(intptr_t)nvp->nvp_data);
1941 break;
1942 case NV_TYPE_BOOL_ARRAY:
1943 nv_free((bool *)(intptr_t)nvp->nvp_data);
1944 break;
1945 case NV_TYPE_STRING_ARRAY:
1946 for (i = 0; i < nvp->nvp_nitems; i++)
1947 nv_free(((char **)(intptr_t)nvp->nvp_data)[i]);
1948 break;
1949 }
1950 nv_free(nvp);
1951 }
1952
1953 void
nvpair_free_structure(nvpair_t * nvp)1954 nvpair_free_structure(nvpair_t *nvp)
1955 {
1956
1957 NVPAIR_ASSERT(nvp);
1958 PJDLOG_ASSERT(nvp->nvp_list == NULL);
1959
1960 nvp->nvp_magic = 0;
1961 nv_free(nvp);
1962 }
1963
1964 const char *
nvpair_type_string(int type)1965 nvpair_type_string(int type)
1966 {
1967
1968 switch (type) {
1969 case NV_TYPE_NULL:
1970 return ("NULL");
1971 case NV_TYPE_BOOL:
1972 return ("BOOL");
1973 case NV_TYPE_NUMBER:
1974 return ("NUMBER");
1975 case NV_TYPE_STRING:
1976 return ("STRING");
1977 case NV_TYPE_NVLIST:
1978 return ("NVLIST");
1979 case NV_TYPE_DESCRIPTOR:
1980 return ("DESCRIPTOR");
1981 case NV_TYPE_BINARY:
1982 return ("BINARY");
1983 case NV_TYPE_BOOL_ARRAY:
1984 return ("BOOL ARRAY");
1985 case NV_TYPE_NUMBER_ARRAY:
1986 return ("NUMBER ARRAY");
1987 case NV_TYPE_STRING_ARRAY:
1988 return ("STRING ARRAY");
1989 case NV_TYPE_NVLIST_ARRAY:
1990 return ("NVLIST ARRAY");
1991 case NV_TYPE_DESCRIPTOR_ARRAY:
1992 return ("DESCRIPTOR ARRAY");
1993 default:
1994 return ("<UNKNOWN>");
1995 }
1996 }
1997
1998