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