1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 2012 by Delphix. All rights reserved.
24 */
25
26#include <unistd.h>
27#include <string.h>
28#include <libintl.h>
29#include <sys/types.h>
30#include <sys/inttypes.h>
31#include <stdarg.h>
32#include <note.h>
33#include "libnvpair.h"
34
35/*
36 * libnvpair - A tools library for manipulating <name, value> pairs.
37 *
38 *	This library provides routines packing an unpacking nv pairs
39 *	for transporting data across process boundaries, transporting
40 *	between kernel and userland, and possibly saving onto disk files.
41 */
42
43/*
44 * Print control structure.
45 */
46
47#define	DEFINEOP(opname, vtype) \
48	struct { \
49		int (*op)(struct nvlist_prtctl *, void *, nvlist_t *, \
50		    const char *, vtype); \
51		void *arg; \
52	} opname
53
54#define	DEFINEARROP(opname, vtype) \
55	struct { \
56		int (*op)(struct nvlist_prtctl *, void *, nvlist_t *, \
57		    const char *, vtype, uint_t); \
58		void *arg; \
59	} opname
60
61struct nvlist_printops {
62	DEFINEOP(print_boolean, int);
63	DEFINEOP(print_boolean_value, boolean_t);
64	DEFINEOP(print_byte, uchar_t);
65	DEFINEOP(print_int8, int8_t);
66	DEFINEOP(print_uint8, uint8_t);
67	DEFINEOP(print_int16, int16_t);
68	DEFINEOP(print_uint16, uint16_t);
69	DEFINEOP(print_int32, int32_t);
70	DEFINEOP(print_uint32, uint32_t);
71	DEFINEOP(print_int64, int64_t);
72	DEFINEOP(print_uint64, uint64_t);
73	DEFINEOP(print_double, double);
74	DEFINEOP(print_string, char *);
75	DEFINEOP(print_hrtime, hrtime_t);
76	DEFINEOP(print_nvlist, nvlist_t *);
77	DEFINEARROP(print_boolean_array, boolean_t *);
78	DEFINEARROP(print_byte_array, uchar_t *);
79	DEFINEARROP(print_int8_array, int8_t *);
80	DEFINEARROP(print_uint8_array, uint8_t *);
81	DEFINEARROP(print_int16_array, int16_t *);
82	DEFINEARROP(print_uint16_array, uint16_t *);
83	DEFINEARROP(print_int32_array, int32_t *);
84	DEFINEARROP(print_uint32_array, uint32_t *);
85	DEFINEARROP(print_int64_array, int64_t *);
86	DEFINEARROP(print_uint64_array, uint64_t *);
87	DEFINEARROP(print_string_array, char **);
88	DEFINEARROP(print_nvlist_array, nvlist_t **);
89};
90
91struct nvlist_prtctl {
92	FILE *nvprt_fp;			/* output destination */
93	enum nvlist_indent_mode nvprt_indent_mode; /* see above */
94	int nvprt_indent;		/* absolute indent, or tab depth */
95	int nvprt_indentinc;		/* indent or tab increment */
96	const char *nvprt_nmfmt;	/* member name format, max one %s */
97	const char *nvprt_eomfmt;	/* after member format, e.g. "\n" */
98	const char *nvprt_btwnarrfmt;	/* between array members */
99	int nvprt_btwnarrfmt_nl;	/* nvprt_eoamfmt includes newline? */
100	struct nvlist_printops *nvprt_dfltops;
101	struct nvlist_printops *nvprt_custops;
102};
103
104#define	DFLTPRTOP(pctl, type) \
105	((pctl)->nvprt_dfltops->print_##type.op)
106
107#define	DFLTPRTOPARG(pctl, type) \
108	((pctl)->nvprt_dfltops->print_##type.arg)
109
110#define	CUSTPRTOP(pctl, type) \
111	((pctl)->nvprt_custops->print_##type.op)
112
113#define	CUSTPRTOPARG(pctl, type) \
114	((pctl)->nvprt_custops->print_##type.arg)
115
116#define	RENDER(pctl, type, nvl, name, val) \
117	{ \
118		int done = 0; \
119		if ((pctl)->nvprt_custops && CUSTPRTOP(pctl, type)) { \
120			done = CUSTPRTOP(pctl, type)(pctl, \
121			    CUSTPRTOPARG(pctl, type), nvl, name, val); \
122		} \
123		if (!done) { \
124			(void) DFLTPRTOP(pctl, type)(pctl, \
125			    DFLTPRTOPARG(pctl, type), nvl, name, val); \
126		} \
127		(void) fprintf(pctl->nvprt_fp, pctl->nvprt_eomfmt); \
128	}
129
130#define	ARENDER(pctl, type, nvl, name, arrp, count) \
131	{ \
132		int done = 0; \
133		if ((pctl)->nvprt_custops && CUSTPRTOP(pctl, type)) { \
134			done = CUSTPRTOP(pctl, type)(pctl, \
135			    CUSTPRTOPARG(pctl, type), nvl, name, arrp, count); \
136		} \
137		if (!done) { \
138			(void) DFLTPRTOP(pctl, type)(pctl, \
139			    DFLTPRTOPARG(pctl, type), nvl, name, arrp, count); \
140		} \
141		(void) fprintf(pctl->nvprt_fp, pctl->nvprt_eomfmt); \
142	}
143
144static void nvlist_print_with_indent(nvlist_t *, nvlist_prtctl_t);
145
146/*
147 * ======================================================================
148 * |									|
149 * | Indentation							|
150 * |									|
151 * ======================================================================
152 */
153
154static void
155indent(nvlist_prtctl_t pctl, int onemore)
156{
157	int depth;
158
159	switch (pctl->nvprt_indent_mode) {
160	case NVLIST_INDENT_ABS:
161		(void) fprintf(pctl->nvprt_fp, "%*s",
162		    pctl->nvprt_indent + onemore * pctl->nvprt_indentinc, "");
163		break;
164
165	case NVLIST_INDENT_TABBED:
166		depth = pctl->nvprt_indent + onemore;
167		while (depth-- > 0)
168			(void) fprintf(pctl->nvprt_fp, "\t");
169	}
170}
171
172/*
173 * ======================================================================
174 * |									|
175 * | Default nvlist member rendering functions.				|
176 * |									|
177 * ======================================================================
178 */
179
180/*
181 * Generate functions to print single-valued nvlist members.
182 *
183 * type_and_variant - suffix to form function name
184 * vtype - C type for the member value
185 * ptype - C type to cast value to for printing
186 * vfmt - format string for pair value, e.g "%d" or "0x%llx"
187 */
188
189#define	NVLIST_PRTFUNC(type_and_variant, vtype, ptype, vfmt) \
190static int \
191nvprint_##type_and_variant(nvlist_prtctl_t pctl, void *private, \
192    nvlist_t *nvl, const char *name, vtype value) \
193{ \
194	FILE *fp = pctl->nvprt_fp; \
195	NOTE(ARGUNUSED(private)) \
196	NOTE(ARGUNUSED(nvl)) \
197	indent(pctl, 1); \
198	(void) fprintf(fp, pctl->nvprt_nmfmt, name); \
199	(void) fprintf(fp, vfmt, (ptype)value); \
200	return (1); \
201}
202
203NVLIST_PRTFUNC(boolean, int, int, "%d")
204NVLIST_PRTFUNC(boolean_value, boolean_t, int, "%d")
205NVLIST_PRTFUNC(byte, uchar_t, uchar_t, "0x%2.2x")
206NVLIST_PRTFUNC(int8, int8_t, int, "%d")
207NVLIST_PRTFUNC(uint8, uint8_t, uint8_t, "0x%x")
208NVLIST_PRTFUNC(int16, int16_t, int16_t, "%d")
209NVLIST_PRTFUNC(uint16, uint16_t, uint16_t, "0x%x")
210NVLIST_PRTFUNC(int32, int32_t, int32_t, "%d")
211NVLIST_PRTFUNC(uint32, uint32_t, uint32_t, "0x%x")
212NVLIST_PRTFUNC(int64, int64_t, longlong_t, "%lld")
213NVLIST_PRTFUNC(uint64, uint64_t, u_longlong_t, "0x%llx")
214NVLIST_PRTFUNC(double, double, double, "0x%f")
215NVLIST_PRTFUNC(string, char *, char *, "%s")
216NVLIST_PRTFUNC(hrtime, hrtime_t, hrtime_t, "0x%llx")
217
218/*
219 * Generate functions to print array-valued nvlist members.
220 */
221
222#define	NVLIST_ARRPRTFUNC(type_and_variant, vtype, ptype, vfmt) \
223static int \
224nvaprint_##type_and_variant(nvlist_prtctl_t pctl, void *private, \
225    nvlist_t *nvl, const char *name, vtype *valuep, uint_t count) \
226{ \
227	FILE *fp = pctl->nvprt_fp; \
228	uint_t i; \
229	NOTE(ARGUNUSED(private)) \
230	NOTE(ARGUNUSED(nvl)) \
231	for (i = 0; i < count; i++) { \
232		if (i == 0 || pctl->nvprt_btwnarrfmt_nl) { \
233			indent(pctl, 1); \
234			(void) fprintf(fp, pctl->nvprt_nmfmt, name); \
235			if (pctl->nvprt_btwnarrfmt_nl) \
236				(void) fprintf(fp, "[%d]: ", i); \
237		} \
238		if (i != 0) \
239			(void) fprintf(fp, pctl->nvprt_btwnarrfmt); \
240		(void) fprintf(fp, vfmt, (ptype)valuep[i]); \
241	} \
242	return (1); \
243}
244
245NVLIST_ARRPRTFUNC(boolean_array, boolean_t, boolean_t, "%d")
246NVLIST_ARRPRTFUNC(byte_array, uchar_t, uchar_t, "0x%2.2x")
247NVLIST_ARRPRTFUNC(int8_array, int8_t, int8_t, "%d")
248NVLIST_ARRPRTFUNC(uint8_array, uint8_t, uint8_t, "0x%x")
249NVLIST_ARRPRTFUNC(int16_array, int16_t, int16_t, "%d")
250NVLIST_ARRPRTFUNC(uint16_array, uint16_t, uint16_t, "0x%x")
251NVLIST_ARRPRTFUNC(int32_array, int32_t, int32_t, "%d")
252NVLIST_ARRPRTFUNC(uint32_array, uint32_t, uint32_t, "0x%x")
253NVLIST_ARRPRTFUNC(int64_array, int64_t, longlong_t, "%lld")
254NVLIST_ARRPRTFUNC(uint64_array, uint64_t, u_longlong_t, "0x%llx")
255NVLIST_ARRPRTFUNC(string_array, char *, char *, "%s")
256
257/*ARGSUSED*/
258static int
259nvprint_nvlist(nvlist_prtctl_t pctl, void *private,
260    nvlist_t *nvl, const char *name, nvlist_t *value)
261{
262	FILE *fp = pctl->nvprt_fp;
263
264	indent(pctl, 1);
265	(void) fprintf(fp, "%s = (embedded nvlist)\n", name);
266
267	pctl->nvprt_indent += pctl->nvprt_indentinc;
268	nvlist_print_with_indent(value, pctl);
269	pctl->nvprt_indent -= pctl->nvprt_indentinc;
270
271	indent(pctl, 1);
272	(void) fprintf(fp, "(end %s)\n", name);
273
274	return (1);
275}
276
277/*ARGSUSED*/
278static int
279nvaprint_nvlist_array(nvlist_prtctl_t pctl, void *private,
280    nvlist_t *nvl, const char *name, nvlist_t **valuep, uint_t count)
281{
282	FILE *fp = pctl->nvprt_fp;
283	uint_t i;
284
285	indent(pctl, 1);
286	(void) fprintf(fp, "%s = (array of embedded nvlists)\n", name);
287
288	for (i = 0; i < count; i++) {
289		indent(pctl, 1);
290		(void) fprintf(fp, "(start %s[%d])\n", name, i);
291
292		pctl->nvprt_indent += pctl->nvprt_indentinc;
293		nvlist_print_with_indent(valuep[i], pctl);
294		pctl->nvprt_indent -= pctl->nvprt_indentinc;
295
296		indent(pctl, 1);
297		(void) fprintf(fp, "(end %s[%d])\n", name, i);
298	}
299
300	return (1);
301}
302
303/*
304 * ======================================================================
305 * |									|
306 * | Interfaces that allow control over formatting.			|
307 * |									|
308 * ======================================================================
309 */
310
311void
312nvlist_prtctl_setdest(nvlist_prtctl_t pctl, FILE *fp)
313{
314	pctl->nvprt_fp = fp;
315}
316
317FILE *
318nvlist_prtctl_getdest(nvlist_prtctl_t pctl)
319{
320	return (pctl->nvprt_fp);
321}
322
323
324void
325nvlist_prtctl_setindent(nvlist_prtctl_t pctl, enum nvlist_indent_mode mode,
326    int start, int inc)
327{
328	if (mode < NVLIST_INDENT_ABS || mode > NVLIST_INDENT_TABBED)
329		mode = NVLIST_INDENT_TABBED;
330
331	if (start < 0)
332		start = 0;
333
334	if (inc < 0)
335		inc = 1;
336
337	pctl->nvprt_indent_mode = mode;
338	pctl->nvprt_indent = start;
339	pctl->nvprt_indentinc = inc;
340}
341
342void
343nvlist_prtctl_doindent(nvlist_prtctl_t pctl, int onemore)
344{
345	indent(pctl, onemore);
346}
347
348
349void
350nvlist_prtctl_setfmt(nvlist_prtctl_t pctl, enum nvlist_prtctl_fmt which,
351    const char *fmt)
352{
353	switch (which) {
354	case NVLIST_FMT_MEMBER_NAME:
355		if (fmt == NULL)
356			fmt = "%s = ";
357		pctl->nvprt_nmfmt = fmt;
358		break;
359
360	case NVLIST_FMT_MEMBER_POSTAMBLE:
361		if (fmt == NULL)
362			fmt = "\n";
363		pctl->nvprt_eomfmt = fmt;
364		break;
365
366	case NVLIST_FMT_BTWN_ARRAY:
367		if (fmt == NULL) {
368			pctl->nvprt_btwnarrfmt = " ";
369			pctl->nvprt_btwnarrfmt_nl = 0;
370		} else {
371			pctl->nvprt_btwnarrfmt = fmt;
372			pctl->nvprt_btwnarrfmt_nl = (strstr(fmt, "\n") != NULL);
373		}
374		break;
375
376	default:
377		break;
378	}
379}
380
381
382void
383nvlist_prtctl_dofmt(nvlist_prtctl_t pctl, enum nvlist_prtctl_fmt which, ...)
384{
385	FILE *fp = pctl->nvprt_fp;
386	va_list ap;
387	char *name;
388
389	va_start(ap, which);
390
391	switch (which) {
392	case NVLIST_FMT_MEMBER_NAME:
393		name = va_arg(ap, char *);
394		(void) fprintf(fp, pctl->nvprt_nmfmt, name);
395		break;
396
397	case NVLIST_FMT_MEMBER_POSTAMBLE:
398		(void) fprintf(fp, pctl->nvprt_eomfmt);
399		break;
400
401	case NVLIST_FMT_BTWN_ARRAY:
402		(void) fprintf(fp, pctl->nvprt_btwnarrfmt); \
403		break;
404
405	default:
406		break;
407	}
408
409	va_end(ap);
410}
411
412/*
413 * ======================================================================
414 * |									|
415 * | Interfaces to allow appointment of replacement rendering functions.|
416 * |									|
417 * ======================================================================
418 */
419
420#define	NVLIST_PRINTCTL_REPLACE(type, vtype) \
421void \
422nvlist_prtctlop_##type(nvlist_prtctl_t pctl, \
423    int (*func)(nvlist_prtctl_t, void *, nvlist_t *, const char *, vtype), \
424    void *private) \
425{ \
426	CUSTPRTOP(pctl, type) = func; \
427	CUSTPRTOPARG(pctl, type) = private; \
428}
429
430NVLIST_PRINTCTL_REPLACE(boolean, int)
431NVLIST_PRINTCTL_REPLACE(boolean_value, boolean_t)
432NVLIST_PRINTCTL_REPLACE(byte, uchar_t)
433NVLIST_PRINTCTL_REPLACE(int8, int8_t)
434NVLIST_PRINTCTL_REPLACE(uint8, uint8_t)
435NVLIST_PRINTCTL_REPLACE(int16, int16_t)
436NVLIST_PRINTCTL_REPLACE(uint16, uint16_t)
437NVLIST_PRINTCTL_REPLACE(int32, int32_t)
438NVLIST_PRINTCTL_REPLACE(uint32, uint32_t)
439NVLIST_PRINTCTL_REPLACE(int64, int64_t)
440NVLIST_PRINTCTL_REPLACE(uint64, uint64_t)
441NVLIST_PRINTCTL_REPLACE(double, double)
442NVLIST_PRINTCTL_REPLACE(string, char *)
443NVLIST_PRINTCTL_REPLACE(hrtime, hrtime_t)
444NVLIST_PRINTCTL_REPLACE(nvlist, nvlist_t *)
445
446#define	NVLIST_PRINTCTL_AREPLACE(type, vtype) \
447void \
448nvlist_prtctlop_##type(nvlist_prtctl_t pctl, \
449    int (*func)(nvlist_prtctl_t, void *, nvlist_t *, const char *, vtype, \
450    uint_t), void *private) \
451{ \
452	CUSTPRTOP(pctl, type) = func; \
453	CUSTPRTOPARG(pctl, type) = private; \
454}
455
456NVLIST_PRINTCTL_AREPLACE(boolean_array, boolean_t *)
457NVLIST_PRINTCTL_AREPLACE(byte_array, uchar_t *)
458NVLIST_PRINTCTL_AREPLACE(int8_array, int8_t *)
459NVLIST_PRINTCTL_AREPLACE(uint8_array, uint8_t *)
460NVLIST_PRINTCTL_AREPLACE(int16_array, int16_t *)
461NVLIST_PRINTCTL_AREPLACE(uint16_array, uint16_t *)
462NVLIST_PRINTCTL_AREPLACE(int32_array, int32_t *)
463NVLIST_PRINTCTL_AREPLACE(uint32_array, uint32_t *)
464NVLIST_PRINTCTL_AREPLACE(int64_array, int64_t *)
465NVLIST_PRINTCTL_AREPLACE(uint64_array, uint64_t *)
466NVLIST_PRINTCTL_AREPLACE(string_array, char **)
467NVLIST_PRINTCTL_AREPLACE(nvlist_array, nvlist_t **)
468
469/*
470 * ======================================================================
471 * |									|
472 * | Interfaces to manage nvlist_prtctl_t cookies.			|
473 * |									|
474 * ======================================================================
475 */
476
477
478static const struct nvlist_printops defprtops = {
479	{ nvprint_boolean, NULL },
480	{ nvprint_boolean_value, NULL },
481	{ nvprint_byte, NULL },
482	{ nvprint_int8, NULL },
483	{ nvprint_uint8, NULL },
484	{ nvprint_int16, NULL },
485	{ nvprint_uint16, NULL },
486	{ nvprint_int32, NULL },
487	{ nvprint_uint32, NULL },
488	{ nvprint_int64, NULL },
489	{ nvprint_uint64, NULL },
490	{ nvprint_double, NULL },
491	{ nvprint_string, NULL },
492	{ nvprint_hrtime, NULL },
493	{ nvprint_nvlist, NULL },
494	{ nvaprint_boolean_array, NULL },
495	{ nvaprint_byte_array, NULL },
496	{ nvaprint_int8_array, NULL },
497	{ nvaprint_uint8_array, NULL },
498	{ nvaprint_int16_array, NULL },
499	{ nvaprint_uint16_array, NULL },
500	{ nvaprint_int32_array, NULL },
501	{ nvaprint_uint32_array, NULL },
502	{ nvaprint_int64_array, NULL },
503	{ nvaprint_uint64_array, NULL },
504	{ nvaprint_string_array, NULL },
505	{ nvaprint_nvlist_array, NULL },
506};
507
508static void
509prtctl_defaults(FILE *fp, struct nvlist_prtctl *pctl,
510    struct nvlist_printops *ops)
511{
512	pctl->nvprt_fp = fp;
513	pctl->nvprt_indent_mode = NVLIST_INDENT_TABBED;
514	pctl->nvprt_indent = 0;
515	pctl->nvprt_indentinc = 1;
516	pctl->nvprt_nmfmt = "%s = ";
517	pctl->nvprt_eomfmt = "\n";
518	pctl->nvprt_btwnarrfmt = " ";
519	pctl->nvprt_btwnarrfmt_nl = 0;
520
521	pctl->nvprt_dfltops = (struct nvlist_printops *)&defprtops;
522	pctl->nvprt_custops = ops;
523}
524
525nvlist_prtctl_t
526nvlist_prtctl_alloc(void)
527{
528	struct nvlist_prtctl *pctl;
529	struct nvlist_printops *ops;
530
531	if ((pctl = malloc(sizeof (*pctl))) == NULL)
532		return (NULL);
533
534	if ((ops = calloc(1, sizeof (*ops))) == NULL) {
535		free(pctl);
536		return (NULL);
537	}
538
539	prtctl_defaults(stdout, pctl, ops);
540
541	return (pctl);
542}
543
544void
545nvlist_prtctl_free(nvlist_prtctl_t pctl)
546{
547	if (pctl != NULL) {
548		free(pctl->nvprt_custops);
549		free(pctl);
550	}
551}
552
553/*
554 * ======================================================================
555 * |									|
556 * | Top-level print request interfaces.				|
557 * |									|
558 * ======================================================================
559 */
560
561/*
562 * nvlist_print - Prints elements in an event buffer
563 */
564static void
565nvlist_print_with_indent(nvlist_t *nvl, nvlist_prtctl_t pctl)
566{
567	FILE *fp = pctl->nvprt_fp;
568	char *name;
569	uint_t nelem;
570	nvpair_t *nvp;
571
572	if (nvl == NULL)
573		return;
574
575	indent(pctl, 0);
576	(void) fprintf(fp, "nvlist version: %d\n", NVL_VERSION(nvl));
577
578	nvp = nvlist_next_nvpair(nvl, NULL);
579
580	while (nvp) {
581		data_type_t type = nvpair_type(nvp);
582
583		name = nvpair_name(nvp);
584		nelem = 0;
585
586		switch (type) {
587		case DATA_TYPE_BOOLEAN: {
588			RENDER(pctl, boolean, nvl, name, 1);
589			break;
590		}
591		case DATA_TYPE_BOOLEAN_VALUE: {
592			boolean_t val;
593			(void) nvpair_value_boolean_value(nvp, &val);
594			RENDER(pctl, boolean_value, nvl, name, val);
595			break;
596		}
597		case DATA_TYPE_BYTE: {
598			uchar_t val;
599			(void) nvpair_value_byte(nvp, &val);
600			RENDER(pctl, byte, nvl, name, val);
601			break;
602		}
603		case DATA_TYPE_INT8: {
604			int8_t val;
605			(void) nvpair_value_int8(nvp, &val);
606			RENDER(pctl, int8, nvl, name, val);
607			break;
608		}
609		case DATA_TYPE_UINT8: {
610			uint8_t val;
611			(void) nvpair_value_uint8(nvp, &val);
612			RENDER(pctl, uint8, nvl, name, val);
613			break;
614		}
615		case DATA_TYPE_INT16: {
616			int16_t val;
617			(void) nvpair_value_int16(nvp, &val);
618			RENDER(pctl, int16, nvl, name, val);
619			break;
620		}
621		case DATA_TYPE_UINT16: {
622			uint16_t val;
623			(void) nvpair_value_uint16(nvp, &val);
624			RENDER(pctl, uint16, nvl, name, val);
625			break;
626		}
627		case DATA_TYPE_INT32: {
628			int32_t val;
629			(void) nvpair_value_int32(nvp, &val);
630			RENDER(pctl, int32, nvl, name, val);
631			break;
632		}
633		case DATA_TYPE_UINT32: {
634			uint32_t val;
635			(void) nvpair_value_uint32(nvp, &val);
636			RENDER(pctl, uint32, nvl, name, val);
637			break;
638		}
639		case DATA_TYPE_INT64: {
640			int64_t val;
641			(void) nvpair_value_int64(nvp, &val);
642			RENDER(pctl, int64, nvl, name, val);
643			break;
644		}
645		case DATA_TYPE_UINT64: {
646			uint64_t val;
647			(void) nvpair_value_uint64(nvp, &val);
648			RENDER(pctl, uint64, nvl, name, val);
649			break;
650		}
651		case DATA_TYPE_DOUBLE: {
652			double val;
653			(void) nvpair_value_double(nvp, &val);
654			RENDER(pctl, double, nvl, name, val);
655			break;
656		}
657		case DATA_TYPE_STRING: {
658			char *val;
659			(void) nvpair_value_string(nvp, &val);
660			RENDER(pctl, string, nvl, name, val);
661			break;
662		}
663		case DATA_TYPE_BOOLEAN_ARRAY: {
664			boolean_t *val;
665			(void) nvpair_value_boolean_array(nvp, &val, &nelem);
666			ARENDER(pctl, boolean_array, nvl, name, val, nelem);
667			break;
668		}
669		case DATA_TYPE_BYTE_ARRAY: {
670			uchar_t *val;
671			(void) nvpair_value_byte_array(nvp, &val, &nelem);
672			ARENDER(pctl, byte_array, nvl, name, val, nelem);
673			break;
674		}
675		case DATA_TYPE_INT8_ARRAY: {
676			int8_t *val;
677			(void) nvpair_value_int8_array(nvp, &val, &nelem);
678			ARENDER(pctl, int8_array, nvl, name, val, nelem);
679			break;
680		}
681		case DATA_TYPE_UINT8_ARRAY: {
682			uint8_t *val;
683			(void) nvpair_value_uint8_array(nvp, &val, &nelem);
684			ARENDER(pctl, uint8_array, nvl, name, val, nelem);
685			break;
686		}
687		case DATA_TYPE_INT16_ARRAY: {
688			int16_t *val;
689			(void) nvpair_value_int16_array(nvp, &val, &nelem);
690			ARENDER(pctl, int16_array, nvl, name, val, nelem);
691			break;
692		}
693		case DATA_TYPE_UINT16_ARRAY: {
694			uint16_t *val;
695			(void) nvpair_value_uint16_array(nvp, &val, &nelem);
696			ARENDER(pctl, uint16_array, nvl, name, val, nelem);
697			break;
698		}
699		case DATA_TYPE_INT32_ARRAY: {
700			int32_t *val;
701			(void) nvpair_value_int32_array(nvp, &val, &nelem);
702			ARENDER(pctl, int32_array, nvl, name, val, nelem);
703			break;
704		}
705		case DATA_TYPE_UINT32_ARRAY: {
706			uint32_t *val;
707			(void) nvpair_value_uint32_array(nvp, &val, &nelem);
708			ARENDER(pctl, uint32_array, nvl, name, val, nelem);
709			break;
710		}
711		case DATA_TYPE_INT64_ARRAY: {
712			int64_t *val;
713			(void) nvpair_value_int64_array(nvp, &val, &nelem);
714			ARENDER(pctl, int64_array, nvl, name, val, nelem);
715			break;
716		}
717		case DATA_TYPE_UINT64_ARRAY: {
718			uint64_t *val;
719			(void) nvpair_value_uint64_array(nvp, &val, &nelem);
720			ARENDER(pctl, uint64_array, nvl, name, val, nelem);
721			break;
722		}
723		case DATA_TYPE_STRING_ARRAY: {
724			char **val;
725			(void) nvpair_value_string_array(nvp, &val, &nelem);
726			ARENDER(pctl, string_array, nvl, name, val, nelem);
727			break;
728		}
729		case DATA_TYPE_HRTIME: {
730			hrtime_t val;
731			(void) nvpair_value_hrtime(nvp, &val);
732			RENDER(pctl, hrtime, nvl, name, val);
733			break;
734		}
735		case DATA_TYPE_NVLIST: {
736			nvlist_t *val;
737			(void) nvpair_value_nvlist(nvp, &val);
738			RENDER(pctl, nvlist, nvl, name, val);
739			break;
740		}
741		case DATA_TYPE_NVLIST_ARRAY: {
742			nvlist_t **val;
743			(void) nvpair_value_nvlist_array(nvp, &val, &nelem);
744			ARENDER(pctl, nvlist_array, nvl, name, val, nelem);
745			break;
746		}
747		default:
748			(void) fprintf(fp, " unknown data type (%d)", type);
749			break;
750		}
751		nvp = nvlist_next_nvpair(nvl, nvp);
752	}
753}
754
755void
756nvlist_print(FILE *fp, nvlist_t *nvl)
757{
758	struct nvlist_prtctl pc;
759
760	prtctl_defaults(fp, &pc, NULL);
761	nvlist_print_with_indent(nvl, &pc);
762}
763
764void
765nvlist_prt(nvlist_t *nvl, nvlist_prtctl_t pctl)
766{
767	nvlist_print_with_indent(nvl, pctl);
768}
769
770#define	NVP(elem, type, vtype, ptype, format) { \
771	vtype	value; \
772\
773	(void) nvpair_value_##type(elem, &value); \
774	(void) printf("%*s%s: " format "\n", indent, "", \
775	    nvpair_name(elem), (ptype)value); \
776}
777
778#define	NVPA(elem, type, vtype, ptype, format) { \
779	uint_t	i, count; \
780	vtype	*value;  \
781\
782	(void) nvpair_value_##type(elem, &value, &count); \
783	for (i = 0; i < count; i++) { \
784		(void) printf("%*s%s[%d]: " format "\n", indent, "", \
785		    nvpair_name(elem), i, (ptype)value[i]); \
786	} \
787}
788
789/*
790 * Similar to nvlist_print() but handles arrays slightly differently.
791 */
792void
793dump_nvlist(nvlist_t *list, int indent)
794{
795	nvpair_t	*elem = NULL;
796	boolean_t	bool_value;
797	boolean_t	*bool_array_value;
798	nvlist_t	*nvlist_value;
799	nvlist_t	**nvlist_array_value;
800	uint_t		i, count;
801
802	if (list == NULL) {
803		return;
804	}
805
806	while ((elem = nvlist_next_nvpair(list, elem)) != NULL) {
807		switch (nvpair_type(elem)) {
808		case DATA_TYPE_BOOLEAN:
809			(void) printf("%*s%s\n", indent, "", nvpair_name(elem));
810			break;
811
812		case DATA_TYPE_BOOLEAN_VALUE:
813			(void) nvpair_value_boolean_value(elem, &bool_value);
814			(void) printf("%*s%s: %s\n", indent, "",
815			    nvpair_name(elem), bool_value ? "true" : "false");
816			break;
817
818		case DATA_TYPE_BYTE:
819			NVP(elem, byte, uchar_t, int, "%u");
820			break;
821
822		case DATA_TYPE_INT8:
823			NVP(elem, int8, int8_t, int, "%d");
824			break;
825
826		case DATA_TYPE_UINT8:
827			NVP(elem, uint8, uint8_t, int, "%u");
828			break;
829
830		case DATA_TYPE_INT16:
831			NVP(elem, int16, int16_t, int, "%d");
832			break;
833
834		case DATA_TYPE_UINT16:
835			NVP(elem, uint16, uint16_t, int, "%u");
836			break;
837
838		case DATA_TYPE_INT32:
839			NVP(elem, int32, int32_t, long, "%ld");
840			break;
841
842		case DATA_TYPE_UINT32:
843			NVP(elem, uint32, uint32_t, ulong_t, "%lu");
844			break;
845
846		case DATA_TYPE_INT64:
847			NVP(elem, int64, int64_t, longlong_t, "%lld");
848			break;
849
850		case DATA_TYPE_UINT64:
851			NVP(elem, uint64, uint64_t, u_longlong_t, "%llu");
852			break;
853
854		case DATA_TYPE_STRING:
855			NVP(elem, string, char *, char *, "'%s'");
856			break;
857
858		case DATA_TYPE_BOOLEAN_ARRAY:
859			(void) nvpair_value_boolean_array(elem,
860			    &bool_array_value, &count);
861			for (i = 0; i < count; i++) {
862				(void) printf("%*s%s[%d]: %s\n", indent, "",
863				    nvpair_name(elem), i,
864				    bool_array_value[i] ? "true" : "false");
865			}
866			break;
867
868		case DATA_TYPE_BYTE_ARRAY:
869			NVPA(elem, byte_array, uchar_t, int, "%u");
870			break;
871
872		case DATA_TYPE_INT8_ARRAY:
873			NVPA(elem, int8_array, int8_t, int, "%d");
874			break;
875
876		case DATA_TYPE_UINT8_ARRAY:
877			NVPA(elem, uint8_array, uint8_t, int, "%u");
878			break;
879
880		case DATA_TYPE_INT16_ARRAY:
881			NVPA(elem, int16_array, int16_t, int, "%d");
882			break;
883
884		case DATA_TYPE_UINT16_ARRAY:
885			NVPA(elem, uint16_array, uint16_t, int, "%u");
886			break;
887
888		case DATA_TYPE_INT32_ARRAY:
889			NVPA(elem, int32_array, int32_t, long, "%ld");
890			break;
891
892		case DATA_TYPE_UINT32_ARRAY:
893			NVPA(elem, uint32_array, uint32_t, ulong_t, "%lu");
894			break;
895
896		case DATA_TYPE_INT64_ARRAY:
897			NVPA(elem, int64_array, int64_t, longlong_t, "%lld");
898			break;
899
900		case DATA_TYPE_UINT64_ARRAY:
901			NVPA(elem, uint64_array, uint64_t, u_longlong_t,
902			    "%llu");
903			break;
904
905		case DATA_TYPE_STRING_ARRAY:
906			NVPA(elem, string_array, char *, char *, "'%s'");
907			break;
908
909		case DATA_TYPE_NVLIST:
910			(void) nvpair_value_nvlist(elem, &nvlist_value);
911			(void) printf("%*s%s:\n", indent, "",
912			    nvpair_name(elem));
913			dump_nvlist(nvlist_value, indent + 4);
914			break;
915
916		case DATA_TYPE_NVLIST_ARRAY:
917			(void) nvpair_value_nvlist_array(elem,
918			    &nvlist_array_value, &count);
919			for (i = 0; i < count; i++) {
920				(void) printf("%*s%s[%u]:\n", indent, "",
921				    nvpair_name(elem), i);
922				dump_nvlist(nvlist_array_value[i], indent + 4);
923			}
924			break;
925
926		default:
927			(void) printf(dgettext(TEXT_DOMAIN, "bad config type "
928			    "%d for %s\n"), nvpair_type(elem),
929			    nvpair_name(elem));
930		}
931	}
932}
933
934/*
935 * ======================================================================
936 * |									|
937 * | Misc private interface.						|
938 * |									|
939 * ======================================================================
940 */
941
942/*
943 * Determine if string 'value' matches 'nvp' value.  The 'value' string is
944 * converted, depending on the type of 'nvp', prior to match.  For numeric
945 * types, a radix independent sscanf conversion of 'value' is used. If 'nvp'
946 * is an array type, 'ai' is the index into the array against which we are
947 * checking for match. If nvp is of DATA_TYPE_STRING*, the caller can pass
948 * in a regex_t compilation of value in 'value_regex' to trigger regular
949 * expression string match instead of simple strcmp().
950 *
951 * Return 1 on match, 0 on no-match, and -1 on error.  If the error is
952 * related to value syntax error and 'ep' is non-NULL, *ep will point into
953 * the 'value' string at the location where the error exists.
954 *
955 * NOTE: It may be possible to move the non-regex_t version of this into
956 * common code used by library/kernel/boot.
957 */
958int
959nvpair_value_match_regex(nvpair_t *nvp, int ai,
960    char *value, regex_t *value_regex, char **ep)
961{
962	char	*evalue;
963	uint_t	a_len;
964	int	sr;
965
966	if (ep)
967		*ep = NULL;
968
969	if ((nvp == NULL) || (value == NULL))
970		return (-1);		/* error fail match - invalid args */
971
972	/* make sure array and index combination make sense */
973	if ((nvpair_type_is_array(nvp) && (ai < 0)) ||
974	    (!nvpair_type_is_array(nvp) && (ai >= 0)))
975		return (-1);		/* error fail match - bad index */
976
977	/* non-string values should be single 'chunk' */
978	if ((nvpair_type(nvp) != DATA_TYPE_STRING) &&
979	    (nvpair_type(nvp) != DATA_TYPE_STRING_ARRAY)) {
980		value += strspn(value, " \t");
981		evalue = value + strcspn(value, " \t");
982		if (*evalue) {
983			if (ep)
984				*ep = evalue;
985			return (-1);	/* error fail match - syntax */
986		}
987	}
988
989	sr = EOF;
990	switch (nvpair_type(nvp)) {
991	case DATA_TYPE_STRING: {
992		char	*val;
993
994		/* check string value for match */
995		if (nvpair_value_string(nvp, &val) == 0) {
996			if (value_regex) {
997				if (regexec(value_regex, val,
998				    (size_t)0, NULL, 0) == 0)
999					return (1);	/* match */
1000			} else {
1001				if (strcmp(value, val) == 0)
1002					return (1);	/* match */
1003			}
1004		}
1005		break;
1006	}
1007	case DATA_TYPE_STRING_ARRAY: {
1008		char **val_array;
1009
1010		/* check indexed string value of array for match */
1011		if ((nvpair_value_string_array(nvp, &val_array, &a_len) == 0) &&
1012		    (ai < a_len)) {
1013			if (value_regex) {
1014				if (regexec(value_regex, val_array[ai],
1015				    (size_t)0, NULL, 0) == 0)
1016					return (1);
1017			} else {
1018				if (strcmp(value, val_array[ai]) == 0)
1019					return (1);
1020			}
1021		}
1022		break;
1023	}
1024	case DATA_TYPE_BYTE: {
1025		uchar_t val, val_arg;
1026
1027		/* scanf uchar_t from value and check for match */
1028		sr = sscanf(value, "%c", &val_arg);
1029		if ((sr == 1) && (nvpair_value_byte(nvp, &val) == 0) &&
1030		    (val == val_arg))
1031			return (1);
1032		break;
1033	}
1034	case DATA_TYPE_BYTE_ARRAY: {
1035		uchar_t *val_array, val_arg;
1036
1037
1038		/* check indexed value of array for match */
1039		sr = sscanf(value, "%c", &val_arg);
1040		if ((sr == 1) &&
1041		    (nvpair_value_byte_array(nvp, &val_array, &a_len) == 0) &&
1042		    (ai < a_len) &&
1043		    (val_array[ai] == val_arg))
1044			return (1);
1045		break;
1046	}
1047	case DATA_TYPE_INT8: {
1048		int8_t val, val_arg;
1049
1050		/* scanf int8_t from value and check for match */
1051		sr = sscanf(value, "%"SCNi8, &val_arg);
1052		if ((sr == 1) &&
1053		    (nvpair_value_int8(nvp, &val) == 0) &&
1054		    (val == val_arg))
1055			return (1);
1056		break;
1057	}
1058	case DATA_TYPE_INT8_ARRAY: {
1059		int8_t *val_array, val_arg;
1060
1061		/* check indexed value of array for match */
1062		sr = sscanf(value, "%"SCNi8, &val_arg);
1063		if ((sr == 1) &&
1064		    (nvpair_value_int8_array(nvp, &val_array, &a_len) == 0) &&
1065		    (ai < a_len) &&
1066		    (val_array[ai] == val_arg))
1067			return (1);
1068		break;
1069	}
1070	case DATA_TYPE_UINT8: {
1071		uint8_t val, val_arg;
1072
1073		/* scanf uint8_t from value and check for match */
1074		sr = sscanf(value, "%"SCNi8, (int8_t *)&val_arg);
1075		if ((sr == 1) &&
1076		    (nvpair_value_uint8(nvp, &val) == 0) &&
1077		    (val == val_arg))
1078			return (1);
1079		break;
1080	}
1081	case DATA_TYPE_UINT8_ARRAY: {
1082		uint8_t *val_array, val_arg;
1083
1084		/* check indexed value of array for match */
1085		sr = sscanf(value, "%"SCNi8, (int8_t *)&val_arg);
1086		if ((sr == 1) &&
1087		    (nvpair_value_uint8_array(nvp, &val_array, &a_len) == 0) &&
1088		    (ai < a_len) &&
1089		    (val_array[ai] == val_arg))
1090			return (1);
1091		break;
1092	}
1093	case DATA_TYPE_INT16: {
1094		int16_t val, val_arg;
1095
1096		/* scanf int16_t from value and check for match */
1097		sr = sscanf(value, "%"SCNi16, &val_arg);
1098		if ((sr == 1) &&
1099		    (nvpair_value_int16(nvp, &val) == 0) &&
1100		    (val == val_arg))
1101			return (1);
1102		break;
1103	}
1104	case DATA_TYPE_INT16_ARRAY: {
1105		int16_t *val_array, val_arg;
1106
1107		/* check indexed value of array for match */
1108		sr = sscanf(value, "%"SCNi16, &val_arg);
1109		if ((sr == 1) &&
1110		    (nvpair_value_int16_array(nvp, &val_array, &a_len) == 0) &&
1111		    (ai < a_len) &&
1112		    (val_array[ai] == val_arg))
1113			return (1);
1114		break;
1115	}
1116	case DATA_TYPE_UINT16: {
1117		uint16_t val, val_arg;
1118
1119		/* scanf uint16_t from value and check for match */
1120		sr = sscanf(value, "%"SCNi16, (int16_t *)&val_arg);
1121		if ((sr == 1) &&
1122		    (nvpair_value_uint16(nvp, &val) == 0) &&
1123		    (val == val_arg))
1124			return (1);
1125		break;
1126	}
1127	case DATA_TYPE_UINT16_ARRAY: {
1128		uint16_t *val_array, val_arg;
1129
1130		/* check indexed value of array for match */
1131		sr = sscanf(value, "%"SCNi16, (int16_t *)&val_arg);
1132		if ((sr == 1) &&
1133		    (nvpair_value_uint16_array(nvp, &val_array, &a_len) == 0) &&
1134		    (ai < a_len) &&
1135		    (val_array[ai] == val_arg))
1136			return (1);
1137		break;
1138	}
1139	case DATA_TYPE_INT32: {
1140		int32_t val, val_arg;
1141
1142		/* scanf int32_t from value and check for match */
1143		sr = sscanf(value, "%"SCNi32, &val_arg);
1144		if ((sr == 1) &&
1145		    (nvpair_value_int32(nvp, &val) == 0) &&
1146		    (val == val_arg))
1147			return (1);
1148		break;
1149	}
1150	case DATA_TYPE_INT32_ARRAY: {
1151		int32_t *val_array, val_arg;
1152
1153		/* check indexed value of array for match */
1154		sr = sscanf(value, "%"SCNi32, &val_arg);
1155		if ((sr == 1) &&
1156		    (nvpair_value_int32_array(nvp, &val_array, &a_len) == 0) &&
1157		    (ai < a_len) &&
1158		    (val_array[ai] == val_arg))
1159			return (1);
1160		break;
1161	}
1162	case DATA_TYPE_UINT32: {
1163		uint32_t val, val_arg;
1164
1165		/* scanf uint32_t from value and check for match */
1166		sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg);
1167		if ((sr == 1) &&
1168		    (nvpair_value_uint32(nvp, &val) == 0) &&
1169		    (val == val_arg))
1170			return (1);
1171		break;
1172	}
1173	case DATA_TYPE_UINT32_ARRAY: {
1174		uint32_t *val_array, val_arg;
1175
1176		/* check indexed value of array for match */
1177		sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg);
1178		if ((sr == 1) &&
1179		    (nvpair_value_uint32_array(nvp, &val_array, &a_len) == 0) &&
1180		    (ai < a_len) &&
1181		    (val_array[ai] == val_arg))
1182			return (1);
1183		break;
1184	}
1185	case DATA_TYPE_INT64: {
1186		int64_t val, val_arg;
1187
1188		/* scanf int64_t from value and check for match */
1189		sr = sscanf(value, "%"SCNi64, &val_arg);
1190		if ((sr == 1) &&
1191		    (nvpair_value_int64(nvp, &val) == 0) &&
1192		    (val == val_arg))
1193			return (1);
1194		break;
1195	}
1196	case DATA_TYPE_INT64_ARRAY: {
1197		int64_t *val_array, val_arg;
1198
1199		/* check indexed value of array for match */
1200		sr = sscanf(value, "%"SCNi64, &val_arg);
1201		if ((sr == 1) &&
1202		    (nvpair_value_int64_array(nvp, &val_array, &a_len) == 0) &&
1203		    (ai < a_len) &&
1204		    (val_array[ai] == val_arg))
1205				return (1);
1206		break;
1207	}
1208	case DATA_TYPE_UINT64: {
1209		uint64_t val_arg, val;
1210
1211		/* scanf uint64_t from value and check for match */
1212		sr = sscanf(value, "%"SCNi64, (int64_t *)&val_arg);
1213		if ((sr == 1) &&
1214		    (nvpair_value_uint64(nvp, &val) == 0) &&
1215		    (val == val_arg))
1216			return (1);
1217		break;
1218	}
1219	case DATA_TYPE_UINT64_ARRAY: {
1220		uint64_t *val_array, val_arg;
1221
1222		/* check indexed value of array for match */
1223		sr = sscanf(value, "%"SCNi64, (int64_t *)&val_arg);
1224		if ((sr == 1) &&
1225		    (nvpair_value_uint64_array(nvp, &val_array, &a_len) == 0) &&
1226		    (ai < a_len) &&
1227		    (val_array[ai] == val_arg))
1228			return (1);
1229		break;
1230	}
1231	case DATA_TYPE_BOOLEAN_VALUE: {
1232		int32_t val_arg;
1233		boolean_t val;
1234
1235		/* scanf boolean_t from value and check for match */
1236		sr = sscanf(value, "%"SCNi32, &val_arg);
1237		if ((sr == 1) &&
1238		    (nvpair_value_boolean_value(nvp, &val) == 0) &&
1239		    (val == val_arg))
1240			return (1);
1241		break;
1242	}
1243	case DATA_TYPE_BOOLEAN_ARRAY: {
1244		boolean_t *val_array;
1245		int32_t val_arg;
1246
1247		/* check indexed value of array for match */
1248		sr = sscanf(value, "%"SCNi32, &val_arg);
1249		if ((sr == 1) &&
1250		    (nvpair_value_boolean_array(nvp,
1251		    &val_array, &a_len) == 0) &&
1252		    (ai < a_len) &&
1253		    (val_array[ai] == val_arg))
1254			return (1);
1255		break;
1256	}
1257	case DATA_TYPE_HRTIME:
1258	case DATA_TYPE_NVLIST:
1259	case DATA_TYPE_NVLIST_ARRAY:
1260	case DATA_TYPE_BOOLEAN:
1261	case DATA_TYPE_DOUBLE:
1262	case DATA_TYPE_UNKNOWN:
1263	default:
1264		/*
1265		 * unknown/unsupported data type
1266		 */
1267		return (-1);		/* error fail match */
1268	}
1269
1270	/*
1271	 * check to see if sscanf failed conversion, return approximate
1272	 * pointer to problem
1273	 */
1274	if (sr != 1) {
1275		if (ep)
1276			*ep = value;
1277		return (-1);		/* error fail match  - syntax */
1278	}
1279
1280	return (0);			/* fail match */
1281}
1282
1283int
1284nvpair_value_match(nvpair_t *nvp, int ai, char *value, char **ep)
1285{
1286	return (nvpair_value_match_regex(nvp, ai, value, NULL, ep));
1287}
1288