1168404Spjd/*
2168404Spjd * CDDL HEADER START
3168404Spjd *
4168404Spjd * The contents of this file are subject to the terms of the
5185029Spjd * Common Development and Distribution License (the "License").
6185029Spjd * You may not use this file except in compliance with the License.
7168404Spjd *
8168404Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9168404Spjd * or http://www.opensolaris.org/os/licensing.
10168404Spjd * See the License for the specific language governing permissions
11168404Spjd * and limitations under the License.
12168404Spjd *
13168404Spjd * When distributing Covered Code, include this CDDL HEADER in each
14168404Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15168404Spjd * If applicable, add the following below this CDDL HEADER, with the
16168404Spjd * fields enclosed by brackets "[]" replaced with your own identifying
17168404Spjd * information: Portions Copyright [yyyy] [name of copyright owner]
18168404Spjd *
19168404Spjd * CDDL HEADER END
20168404Spjd */
21168404Spjd/*
22219089Spjd * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
23236884Smm * Copyright (c) 2012 by Delphix. All rights reserved.
24168404Spjd */
25168404Spjd
26219089Spjd#include <solaris.h>
27185029Spjd#include <inttypes.h>
28168404Spjd#include <unistd.h>
29307124Smav#include <string.h>
30219089Spjd#include <libintl.h>
31219089Spjd#include <stdarg.h>
32168404Spjd#include "libnvpair.h"
33168404Spjd
34168404Spjd/*
35168404Spjd * libnvpair - A tools library for manipulating <name, value> pairs.
36168404Spjd *
37168404Spjd *	This library provides routines packing an unpacking nv pairs
38168404Spjd *	for transporting data across process boundaries, transporting
39168404Spjd *	between kernel and userland, and possibly saving onto disk files.
40168404Spjd */
41168404Spjd
42219089Spjd/*
43219089Spjd * Print control structure.
44219089Spjd */
45219089Spjd
46219089Spjd#define	DEFINEOP(opname, vtype) \
47219089Spjd	struct { \
48219089Spjd		int (*op)(struct nvlist_prtctl *, void *, nvlist_t *, \
49219089Spjd		    const char *, vtype); \
50219089Spjd		void *arg; \
51219089Spjd	} opname
52219089Spjd
53219089Spjd#define	DEFINEARROP(opname, vtype) \
54219089Spjd	struct { \
55219089Spjd		int (*op)(struct nvlist_prtctl *, void *, nvlist_t *, \
56219089Spjd		    const char *, vtype, uint_t); \
57219089Spjd		void *arg; \
58219089Spjd	} opname
59219089Spjd
60219089Spjdstruct nvlist_printops {
61219089Spjd	DEFINEOP(print_boolean, int);
62219089Spjd	DEFINEOP(print_boolean_value, boolean_t);
63219089Spjd	DEFINEOP(print_byte, uchar_t);
64219089Spjd	DEFINEOP(print_int8, int8_t);
65219089Spjd	DEFINEOP(print_uint8, uint8_t);
66219089Spjd	DEFINEOP(print_int16, int16_t);
67219089Spjd	DEFINEOP(print_uint16, uint16_t);
68219089Spjd	DEFINEOP(print_int32, int32_t);
69219089Spjd	DEFINEOP(print_uint32, uint32_t);
70219089Spjd	DEFINEOP(print_int64, int64_t);
71219089Spjd	DEFINEOP(print_uint64, uint64_t);
72219089Spjd	DEFINEOP(print_double, double);
73219089Spjd	DEFINEOP(print_string, char *);
74219089Spjd	DEFINEOP(print_hrtime, hrtime_t);
75219089Spjd	DEFINEOP(print_nvlist, nvlist_t *);
76219089Spjd	DEFINEARROP(print_boolean_array, boolean_t *);
77219089Spjd	DEFINEARROP(print_byte_array, uchar_t *);
78219089Spjd	DEFINEARROP(print_int8_array, int8_t *);
79219089Spjd	DEFINEARROP(print_uint8_array, uint8_t *);
80219089Spjd	DEFINEARROP(print_int16_array, int16_t *);
81219089Spjd	DEFINEARROP(print_uint16_array, uint16_t *);
82219089Spjd	DEFINEARROP(print_int32_array, int32_t *);
83219089Spjd	DEFINEARROP(print_uint32_array, uint32_t *);
84219089Spjd	DEFINEARROP(print_int64_array, int64_t *);
85219089Spjd	DEFINEARROP(print_uint64_array, uint64_t *);
86219089Spjd	DEFINEARROP(print_string_array, char **);
87219089Spjd	DEFINEARROP(print_nvlist_array, nvlist_t **);
88219089Spjd};
89219089Spjd
90219089Spjdstruct nvlist_prtctl {
91219089Spjd	FILE *nvprt_fp;			/* output destination */
92219089Spjd	enum nvlist_indent_mode nvprt_indent_mode; /* see above */
93219089Spjd	int nvprt_indent;		/* absolute indent, or tab depth */
94219089Spjd	int nvprt_indentinc;		/* indent or tab increment */
95219089Spjd	const char *nvprt_nmfmt;	/* member name format, max one %s */
96219089Spjd	const char *nvprt_eomfmt;	/* after member format, e.g. "\n" */
97219089Spjd	const char *nvprt_btwnarrfmt;	/* between array members */
98219089Spjd	int nvprt_btwnarrfmt_nl;	/* nvprt_eoamfmt includes newline? */
99219089Spjd	struct nvlist_printops *nvprt_dfltops;
100219089Spjd	struct nvlist_printops *nvprt_custops;
101219089Spjd};
102219089Spjd
103219089Spjd#define	DFLTPRTOP(pctl, type) \
104219089Spjd	((pctl)->nvprt_dfltops->print_##type.op)
105219089Spjd
106219089Spjd#define	DFLTPRTOPARG(pctl, type) \
107219089Spjd	((pctl)->nvprt_dfltops->print_##type.arg)
108219089Spjd
109219089Spjd#define	CUSTPRTOP(pctl, type) \
110219089Spjd	((pctl)->nvprt_custops->print_##type.op)
111219089Spjd
112219089Spjd#define	CUSTPRTOPARG(pctl, type) \
113219089Spjd	((pctl)->nvprt_custops->print_##type.arg)
114219089Spjd
115219089Spjd#define	RENDER(pctl, type, nvl, name, val) \
116219089Spjd	{ \
117219089Spjd		int done = 0; \
118219089Spjd		if ((pctl)->nvprt_custops && CUSTPRTOP(pctl, type)) { \
119219089Spjd			done = CUSTPRTOP(pctl, type)(pctl, \
120219089Spjd			    CUSTPRTOPARG(pctl, type), nvl, name, val); \
121219089Spjd		} \
122219089Spjd		if (!done) { \
123219089Spjd			(void) DFLTPRTOP(pctl, type)(pctl, \
124219089Spjd			    DFLTPRTOPARG(pctl, type), nvl, name, val); \
125219089Spjd		} \
126219089Spjd		(void) fprintf(pctl->nvprt_fp, pctl->nvprt_eomfmt); \
127219089Spjd	}
128219089Spjd
129219089Spjd#define	ARENDER(pctl, type, nvl, name, arrp, count) \
130219089Spjd	{ \
131219089Spjd		int done = 0; \
132219089Spjd		if ((pctl)->nvprt_custops && CUSTPRTOP(pctl, type)) { \
133219089Spjd			done = CUSTPRTOP(pctl, type)(pctl, \
134219089Spjd			    CUSTPRTOPARG(pctl, type), nvl, name, arrp, count); \
135219089Spjd		} \
136219089Spjd		if (!done) { \
137219089Spjd			(void) DFLTPRTOP(pctl, type)(pctl, \
138219089Spjd			    DFLTPRTOPARG(pctl, type), nvl, name, arrp, count); \
139219089Spjd		} \
140219089Spjd		(void) fprintf(pctl->nvprt_fp, pctl->nvprt_eomfmt); \
141219089Spjd	}
142219089Spjd
143219089Spjdstatic void nvlist_print_with_indent(nvlist_t *, nvlist_prtctl_t);
144219089Spjd
145219089Spjd/*
146219089Spjd * ======================================================================
147219089Spjd * |									|
148219089Spjd * | Indentation							|
149219089Spjd * |									|
150219089Spjd * ======================================================================
151219089Spjd */
152219089Spjd
153168404Spjdstatic void
154219089Spjdindent(nvlist_prtctl_t pctl, int onemore)
155168404Spjd{
156219089Spjd	int depth;
157219089Spjd
158219089Spjd	switch (pctl->nvprt_indent_mode) {
159219089Spjd	case NVLIST_INDENT_ABS:
160219089Spjd		(void) fprintf(pctl->nvprt_fp, "%*s",
161219089Spjd		    pctl->nvprt_indent + onemore * pctl->nvprt_indentinc, "");
162219089Spjd		break;
163219089Spjd
164219089Spjd	case NVLIST_INDENT_TABBED:
165219089Spjd		depth = pctl->nvprt_indent + onemore;
166219089Spjd		while (depth-- > 0)
167219089Spjd			(void) fprintf(pctl->nvprt_fp, "\t");
168219089Spjd	}
169168404Spjd}
170168404Spjd
171168404Spjd/*
172219089Spjd * ======================================================================
173219089Spjd * |									|
174219089Spjd * | Default nvlist member rendering functions.				|
175219089Spjd * |									|
176219089Spjd * ======================================================================
177168404Spjd */
178219089Spjd
179219089Spjd/*
180219089Spjd * Generate functions to print single-valued nvlist members.
181219089Spjd *
182219089Spjd * type_and_variant - suffix to form function name
183219089Spjd * vtype - C type for the member value
184219089Spjd * ptype - C type to cast value to for printing
185219089Spjd * vfmt - format string for pair value, e.g "%d" or "0x%llx"
186219089Spjd */
187219089Spjd
188219089Spjd#define	NVLIST_PRTFUNC(type_and_variant, vtype, ptype, vfmt) \
189219089Spjdstatic int \
190219089Spjdnvprint_##type_and_variant(nvlist_prtctl_t pctl, void *private, \
191219089Spjd    nvlist_t *nvl, const char *name, vtype value) \
192219089Spjd{ \
193219089Spjd	FILE *fp = pctl->nvprt_fp; \
194219089Spjd	NOTE(ARGUNUSED(private)) \
195219089Spjd	NOTE(ARGUNUSED(nvl)) \
196219089Spjd	indent(pctl, 1); \
197219089Spjd	(void) fprintf(fp, pctl->nvprt_nmfmt, name); \
198219089Spjd	(void) fprintf(fp, vfmt, (ptype)value); \
199219089Spjd	return (1); \
200219089Spjd}
201219089Spjd
202219089SpjdNVLIST_PRTFUNC(boolean, int, int, "%d")
203219089SpjdNVLIST_PRTFUNC(boolean_value, boolean_t, int, "%d")
204219089SpjdNVLIST_PRTFUNC(byte, uchar_t, uchar_t, "0x%2.2x")
205219089SpjdNVLIST_PRTFUNC(int8, int8_t, int, "%d")
206219089SpjdNVLIST_PRTFUNC(uint8, uint8_t, uint8_t, "0x%x")
207219089SpjdNVLIST_PRTFUNC(int16, int16_t, int16_t, "%d")
208219089SpjdNVLIST_PRTFUNC(uint16, uint16_t, uint16_t, "0x%x")
209219089SpjdNVLIST_PRTFUNC(int32, int32_t, int32_t, "%d")
210219089SpjdNVLIST_PRTFUNC(uint32, uint32_t, uint32_t, "0x%x")
211219089SpjdNVLIST_PRTFUNC(int64, int64_t, longlong_t, "%lld")
212219089SpjdNVLIST_PRTFUNC(uint64, uint64_t, u_longlong_t, "0x%llx")
213302846SasomersNVLIST_PRTFUNC(double, double, double, "0x%f")
214219089SpjdNVLIST_PRTFUNC(string, char *, char *, "%s")
215219089SpjdNVLIST_PRTFUNC(hrtime, hrtime_t, hrtime_t, "0x%llx")
216219089Spjd
217219089Spjd/*
218219089Spjd * Generate functions to print array-valued nvlist members.
219219089Spjd */
220219089Spjd
221219089Spjd#define	NVLIST_ARRPRTFUNC(type_and_variant, vtype, ptype, vfmt) \
222219089Spjdstatic int \
223219089Spjdnvaprint_##type_and_variant(nvlist_prtctl_t pctl, void *private, \
224219089Spjd    nvlist_t *nvl, const char *name, vtype *valuep, uint_t count) \
225219089Spjd{ \
226219089Spjd	FILE *fp = pctl->nvprt_fp; \
227219089Spjd	uint_t i; \
228219089Spjd	NOTE(ARGUNUSED(private)) \
229219089Spjd	NOTE(ARGUNUSED(nvl)) \
230219089Spjd	for (i = 0; i < count; i++) { \
231219089Spjd		if (i == 0 || pctl->nvprt_btwnarrfmt_nl) { \
232219089Spjd			indent(pctl, 1); \
233219089Spjd			(void) fprintf(fp, pctl->nvprt_nmfmt, name); \
234219089Spjd			if (pctl->nvprt_btwnarrfmt_nl) \
235219089Spjd				(void) fprintf(fp, "[%d]: ", i); \
236219089Spjd		} \
237219089Spjd		if (i != 0) \
238219089Spjd			(void) fprintf(fp, pctl->nvprt_btwnarrfmt); \
239219089Spjd		(void) fprintf(fp, vfmt, (ptype)valuep[i]); \
240219089Spjd	} \
241219089Spjd	return (1); \
242219089Spjd}
243219089Spjd
244219089SpjdNVLIST_ARRPRTFUNC(boolean_array, boolean_t, boolean_t, "%d")
245219089SpjdNVLIST_ARRPRTFUNC(byte_array, uchar_t, uchar_t, "0x%2.2x")
246219089SpjdNVLIST_ARRPRTFUNC(int8_array, int8_t, int8_t, "%d")
247219089SpjdNVLIST_ARRPRTFUNC(uint8_array, uint8_t, uint8_t, "0x%x")
248219089SpjdNVLIST_ARRPRTFUNC(int16_array, int16_t, int16_t, "%d")
249219089SpjdNVLIST_ARRPRTFUNC(uint16_array, uint16_t, uint16_t, "0x%x")
250219089SpjdNVLIST_ARRPRTFUNC(int32_array, int32_t, int32_t, "%d")
251219089SpjdNVLIST_ARRPRTFUNC(uint32_array, uint32_t, uint32_t, "0x%x")
252219089SpjdNVLIST_ARRPRTFUNC(int64_array, int64_t, longlong_t, "%lld")
253219089SpjdNVLIST_ARRPRTFUNC(uint64_array, uint64_t, u_longlong_t, "0x%llx")
254219089SpjdNVLIST_ARRPRTFUNC(string_array, char *, char *, "%s")
255219089Spjd
256219089Spjd/*ARGSUSED*/
257219089Spjdstatic int
258219089Spjdnvprint_nvlist(nvlist_prtctl_t pctl, void *private,
259219089Spjd    nvlist_t *nvl, const char *name, nvlist_t *value)
260219089Spjd{
261219089Spjd	FILE *fp = pctl->nvprt_fp;
262219089Spjd
263219089Spjd	indent(pctl, 1);
264219089Spjd	(void) fprintf(fp, "%s = (embedded nvlist)\n", name);
265219089Spjd
266219089Spjd	pctl->nvprt_indent += pctl->nvprt_indentinc;
267219089Spjd	nvlist_print_with_indent(value, pctl);
268219089Spjd	pctl->nvprt_indent -= pctl->nvprt_indentinc;
269219089Spjd
270219089Spjd	indent(pctl, 1);
271219089Spjd	(void) fprintf(fp, "(end %s)\n", name);
272219089Spjd
273219089Spjd	return (1);
274219089Spjd}
275219089Spjd
276219089Spjd/*ARGSUSED*/
277219089Spjdstatic int
278219089Spjdnvaprint_nvlist_array(nvlist_prtctl_t pctl, void *private,
279219089Spjd    nvlist_t *nvl, const char *name, nvlist_t **valuep, uint_t count)
280219089Spjd{
281219089Spjd	FILE *fp = pctl->nvprt_fp;
282219089Spjd	uint_t i;
283219089Spjd
284219089Spjd	indent(pctl, 1);
285219089Spjd	(void) fprintf(fp, "%s = (array of embedded nvlists)\n", name);
286219089Spjd
287219089Spjd	for (i = 0; i < count; i++) {
288219089Spjd		indent(pctl, 1);
289219089Spjd		(void) fprintf(fp, "(start %s[%d])\n", name, i);
290219089Spjd
291219089Spjd		pctl->nvprt_indent += pctl->nvprt_indentinc;
292219089Spjd		nvlist_print_with_indent(valuep[i], pctl);
293219089Spjd		pctl->nvprt_indent -= pctl->nvprt_indentinc;
294219089Spjd
295219089Spjd		indent(pctl, 1);
296219089Spjd		(void) fprintf(fp, "(end %s[%d])\n", name, i);
297219089Spjd	}
298219089Spjd
299219089Spjd	return (1);
300219089Spjd}
301219089Spjd
302219089Spjd/*
303219089Spjd * ======================================================================
304219089Spjd * |									|
305219089Spjd * | Interfaces that allow control over formatting.			|
306219089Spjd * |									|
307219089Spjd * ======================================================================
308219089Spjd */
309219089Spjd
310168404Spjdvoid
311219089Spjdnvlist_prtctl_setdest(nvlist_prtctl_t pctl, FILE *fp)
312168404Spjd{
313219089Spjd	pctl->nvprt_fp = fp;
314219089Spjd}
315219089Spjd
316219089SpjdFILE *
317219089Spjdnvlist_prtctl_getdest(nvlist_prtctl_t pctl)
318219089Spjd{
319219089Spjd	return (pctl->nvprt_fp);
320219089Spjd}
321219089Spjd
322219089Spjd
323219089Spjdvoid
324219089Spjdnvlist_prtctl_setindent(nvlist_prtctl_t pctl, enum nvlist_indent_mode mode,
325219089Spjd    int start, int inc)
326219089Spjd{
327219089Spjd	if (mode < NVLIST_INDENT_ABS || mode > NVLIST_INDENT_TABBED)
328219089Spjd		mode = NVLIST_INDENT_TABBED;
329219089Spjd
330219089Spjd	if (start < 0)
331219089Spjd		start = 0;
332219089Spjd
333219089Spjd	if (inc < 0)
334219089Spjd		inc = 1;
335219089Spjd
336219089Spjd	pctl->nvprt_indent_mode = mode;
337219089Spjd	pctl->nvprt_indent = start;
338219089Spjd	pctl->nvprt_indentinc = inc;
339219089Spjd}
340219089Spjd
341219089Spjdvoid
342219089Spjdnvlist_prtctl_doindent(nvlist_prtctl_t pctl, int onemore)
343219089Spjd{
344219089Spjd	indent(pctl, onemore);
345219089Spjd}
346219089Spjd
347219089Spjd
348219089Spjdvoid
349219089Spjdnvlist_prtctl_setfmt(nvlist_prtctl_t pctl, enum nvlist_prtctl_fmt which,
350219089Spjd    const char *fmt)
351219089Spjd{
352219089Spjd	switch (which) {
353219089Spjd	case NVLIST_FMT_MEMBER_NAME:
354219089Spjd		if (fmt == NULL)
355219089Spjd			fmt = "%s = ";
356219089Spjd		pctl->nvprt_nmfmt = fmt;
357219089Spjd		break;
358219089Spjd
359219089Spjd	case NVLIST_FMT_MEMBER_POSTAMBLE:
360219089Spjd		if (fmt == NULL)
361219089Spjd			fmt = "\n";
362219089Spjd		pctl->nvprt_eomfmt = fmt;
363219089Spjd		break;
364219089Spjd
365219089Spjd	case NVLIST_FMT_BTWN_ARRAY:
366219089Spjd		if (fmt == NULL) {
367219089Spjd			pctl->nvprt_btwnarrfmt = " ";
368219089Spjd			pctl->nvprt_btwnarrfmt_nl = 0;
369219089Spjd		} else {
370219089Spjd			pctl->nvprt_btwnarrfmt = fmt;
371219089Spjd			pctl->nvprt_btwnarrfmt_nl = (strstr(fmt, "\n") != NULL);
372219089Spjd		}
373219089Spjd		break;
374219089Spjd
375219089Spjd	default:
376219089Spjd		break;
377219089Spjd	}
378219089Spjd}
379219089Spjd
380219089Spjd
381219089Spjdvoid
382219089Spjdnvlist_prtctl_dofmt(nvlist_prtctl_t pctl, enum nvlist_prtctl_fmt which, ...)
383219089Spjd{
384219089Spjd	FILE *fp = pctl->nvprt_fp;
385219089Spjd	va_list ap;
386168404Spjd	char *name;
387219089Spjd
388219089Spjd	va_start(ap, which);
389219089Spjd
390219089Spjd	switch (which) {
391219089Spjd	case NVLIST_FMT_MEMBER_NAME:
392219089Spjd		name = va_arg(ap, char *);
393219089Spjd		(void) fprintf(fp, pctl->nvprt_nmfmt, name);
394219089Spjd		break;
395219089Spjd
396219089Spjd	case NVLIST_FMT_MEMBER_POSTAMBLE:
397219089Spjd		(void) fprintf(fp, pctl->nvprt_eomfmt);
398219089Spjd		break;
399219089Spjd
400219089Spjd	case NVLIST_FMT_BTWN_ARRAY:
401219089Spjd		(void) fprintf(fp, pctl->nvprt_btwnarrfmt); \
402219089Spjd		break;
403219089Spjd
404219089Spjd	default:
405219089Spjd		break;
406219089Spjd	}
407219089Spjd
408219089Spjd	va_end(ap);
409219089Spjd}
410219089Spjd
411219089Spjd/*
412219089Spjd * ======================================================================
413219089Spjd * |									|
414219089Spjd * | Interfaces to allow appointment of replacement rendering functions.|
415219089Spjd * |									|
416219089Spjd * ======================================================================
417219089Spjd */
418219089Spjd
419219089Spjd#define	NVLIST_PRINTCTL_REPLACE(type, vtype) \
420219089Spjdvoid \
421219089Spjdnvlist_prtctlop_##type(nvlist_prtctl_t pctl, \
422219089Spjd    int (*func)(nvlist_prtctl_t, void *, nvlist_t *, const char *, vtype), \
423219089Spjd    void *private) \
424219089Spjd{ \
425219089Spjd	CUSTPRTOP(pctl, type) = func; \
426219089Spjd	CUSTPRTOPARG(pctl, type) = private; \
427219089Spjd}
428219089Spjd
429219089SpjdNVLIST_PRINTCTL_REPLACE(boolean, int)
430219089SpjdNVLIST_PRINTCTL_REPLACE(boolean_value, boolean_t)
431219089SpjdNVLIST_PRINTCTL_REPLACE(byte, uchar_t)
432219089SpjdNVLIST_PRINTCTL_REPLACE(int8, int8_t)
433219089SpjdNVLIST_PRINTCTL_REPLACE(uint8, uint8_t)
434219089SpjdNVLIST_PRINTCTL_REPLACE(int16, int16_t)
435219089SpjdNVLIST_PRINTCTL_REPLACE(uint16, uint16_t)
436219089SpjdNVLIST_PRINTCTL_REPLACE(int32, int32_t)
437219089SpjdNVLIST_PRINTCTL_REPLACE(uint32, uint32_t)
438219089SpjdNVLIST_PRINTCTL_REPLACE(int64, int64_t)
439219089SpjdNVLIST_PRINTCTL_REPLACE(uint64, uint64_t)
440219089SpjdNVLIST_PRINTCTL_REPLACE(double, double)
441219089SpjdNVLIST_PRINTCTL_REPLACE(string, char *)
442219089SpjdNVLIST_PRINTCTL_REPLACE(hrtime, hrtime_t)
443219089SpjdNVLIST_PRINTCTL_REPLACE(nvlist, nvlist_t *)
444219089Spjd
445219089Spjd#define	NVLIST_PRINTCTL_AREPLACE(type, vtype) \
446219089Spjdvoid \
447219089Spjdnvlist_prtctlop_##type(nvlist_prtctl_t pctl, \
448219089Spjd    int (*func)(nvlist_prtctl_t, void *, nvlist_t *, const char *, vtype, \
449219089Spjd    uint_t), void *private) \
450219089Spjd{ \
451219089Spjd	CUSTPRTOP(pctl, type) = func; \
452219089Spjd	CUSTPRTOPARG(pctl, type) = private; \
453219089Spjd}
454219089Spjd
455219089SpjdNVLIST_PRINTCTL_AREPLACE(boolean_array, boolean_t *)
456219089SpjdNVLIST_PRINTCTL_AREPLACE(byte_array, uchar_t *)
457219089SpjdNVLIST_PRINTCTL_AREPLACE(int8_array, int8_t *)
458219089SpjdNVLIST_PRINTCTL_AREPLACE(uint8_array, uint8_t *)
459219089SpjdNVLIST_PRINTCTL_AREPLACE(int16_array, int16_t *)
460219089SpjdNVLIST_PRINTCTL_AREPLACE(uint16_array, uint16_t *)
461219089SpjdNVLIST_PRINTCTL_AREPLACE(int32_array, int32_t *)
462219089SpjdNVLIST_PRINTCTL_AREPLACE(uint32_array, uint32_t *)
463219089SpjdNVLIST_PRINTCTL_AREPLACE(int64_array, int64_t *)
464219089SpjdNVLIST_PRINTCTL_AREPLACE(uint64_array, uint64_t *)
465219089SpjdNVLIST_PRINTCTL_AREPLACE(string_array, char **)
466219089SpjdNVLIST_PRINTCTL_AREPLACE(nvlist_array, nvlist_t **)
467219089Spjd
468219089Spjd/*
469219089Spjd * ======================================================================
470219089Spjd * |									|
471219089Spjd * | Interfaces to manage nvlist_prtctl_t cookies.			|
472219089Spjd * |									|
473219089Spjd * ======================================================================
474219089Spjd */
475219089Spjd
476219089Spjd
477219089Spjdstatic const struct nvlist_printops defprtops = {
478219089Spjd	{ nvprint_boolean, NULL },
479219089Spjd	{ nvprint_boolean_value, NULL },
480219089Spjd	{ nvprint_byte, NULL },
481219089Spjd	{ nvprint_int8, NULL },
482219089Spjd	{ nvprint_uint8, NULL },
483219089Spjd	{ nvprint_int16, NULL },
484219089Spjd	{ nvprint_uint16, NULL },
485219089Spjd	{ nvprint_int32, NULL },
486219089Spjd	{ nvprint_uint32, NULL },
487219089Spjd	{ nvprint_int64, NULL },
488219089Spjd	{ nvprint_uint64, NULL },
489219089Spjd	{ nvprint_double, NULL },
490219089Spjd	{ nvprint_string, NULL },
491219089Spjd	{ nvprint_hrtime, NULL },
492219089Spjd	{ nvprint_nvlist, NULL },
493219089Spjd	{ nvaprint_boolean_array, NULL },
494219089Spjd	{ nvaprint_byte_array, NULL },
495219089Spjd	{ nvaprint_int8_array, NULL },
496219089Spjd	{ nvaprint_uint8_array, NULL },
497219089Spjd	{ nvaprint_int16_array, NULL },
498219089Spjd	{ nvaprint_uint16_array, NULL },
499219089Spjd	{ nvaprint_int32_array, NULL },
500219089Spjd	{ nvaprint_uint32_array, NULL },
501219089Spjd	{ nvaprint_int64_array, NULL },
502219089Spjd	{ nvaprint_uint64_array, NULL },
503219089Spjd	{ nvaprint_string_array, NULL },
504219089Spjd	{ nvaprint_nvlist_array, NULL },
505219089Spjd};
506219089Spjd
507219089Spjdstatic void
508219089Spjdprtctl_defaults(FILE *fp, struct nvlist_prtctl *pctl,
509219089Spjd    struct nvlist_printops *ops)
510219089Spjd{
511219089Spjd	pctl->nvprt_fp = fp;
512219089Spjd	pctl->nvprt_indent_mode = NVLIST_INDENT_TABBED;
513219089Spjd	pctl->nvprt_indent = 0;
514219089Spjd	pctl->nvprt_indentinc = 1;
515219089Spjd	pctl->nvprt_nmfmt = "%s = ";
516219089Spjd	pctl->nvprt_eomfmt = "\n";
517219089Spjd	pctl->nvprt_btwnarrfmt = " ";
518219089Spjd	pctl->nvprt_btwnarrfmt_nl = 0;
519219089Spjd
520219089Spjd	pctl->nvprt_dfltops = (struct nvlist_printops *)&defprtops;
521219089Spjd	pctl->nvprt_custops = ops;
522219089Spjd}
523219089Spjd
524219089Spjdnvlist_prtctl_t
525219089Spjdnvlist_prtctl_alloc(void)
526219089Spjd{
527219089Spjd	struct nvlist_prtctl *pctl;
528219089Spjd	struct nvlist_printops *ops;
529219089Spjd
530219089Spjd	if ((pctl = malloc(sizeof (*pctl))) == NULL)
531219089Spjd		return (NULL);
532219089Spjd
533219089Spjd	if ((ops = calloc(1, sizeof (*ops))) == NULL) {
534219089Spjd		free(pctl);
535219089Spjd		return (NULL);
536219089Spjd	}
537219089Spjd
538219089Spjd	prtctl_defaults(stdout, pctl, ops);
539219089Spjd
540219089Spjd	return (pctl);
541219089Spjd}
542219089Spjd
543219089Spjdvoid
544219089Spjdnvlist_prtctl_free(nvlist_prtctl_t pctl)
545219089Spjd{
546219089Spjd	if (pctl != NULL) {
547219089Spjd		free(pctl->nvprt_custops);
548219089Spjd		free(pctl);
549219089Spjd	}
550219089Spjd}
551219089Spjd
552219089Spjd/*
553219089Spjd * ======================================================================
554219089Spjd * |									|
555219089Spjd * | Top-level print request interfaces.				|
556219089Spjd * |									|
557219089Spjd * ======================================================================
558219089Spjd */
559219089Spjd
560219089Spjd/*
561219089Spjd * nvlist_print - Prints elements in an event buffer
562219089Spjd */
563219089Spjdstatic void
564219089Spjdnvlist_print_with_indent(nvlist_t *nvl, nvlist_prtctl_t pctl)
565219089Spjd{
566219089Spjd	FILE *fp = pctl->nvprt_fp;
567219089Spjd	char *name;
568168404Spjd	uint_t nelem;
569168404Spjd	nvpair_t *nvp;
570168404Spjd
571168404Spjd	if (nvl == NULL)
572168404Spjd		return;
573168404Spjd
574219089Spjd	indent(pctl, 0);
575168404Spjd	(void) fprintf(fp, "nvlist version: %d\n", NVL_VERSION(nvl));
576168404Spjd
577168404Spjd	nvp = nvlist_next_nvpair(nvl, NULL);
578168404Spjd
579168404Spjd	while (nvp) {
580168404Spjd		data_type_t type = nvpair_type(nvp);
581168404Spjd
582168404Spjd		name = nvpair_name(nvp);
583168404Spjd		nelem = 0;
584219089Spjd
585168404Spjd		switch (type) {
586168404Spjd		case DATA_TYPE_BOOLEAN: {
587219089Spjd			RENDER(pctl, boolean, nvl, name, 1);
588168404Spjd			break;
589168404Spjd		}
590168404Spjd		case DATA_TYPE_BOOLEAN_VALUE: {
591168404Spjd			boolean_t val;
592168404Spjd			(void) nvpair_value_boolean_value(nvp, &val);
593219089Spjd			RENDER(pctl, boolean_value, nvl, name, val);
594168404Spjd			break;
595168404Spjd		}
596168404Spjd		case DATA_TYPE_BYTE: {
597168404Spjd			uchar_t val;
598168404Spjd			(void) nvpair_value_byte(nvp, &val);
599219089Spjd			RENDER(pctl, byte, nvl, name, val);
600168404Spjd			break;
601168404Spjd		}
602168404Spjd		case DATA_TYPE_INT8: {
603168404Spjd			int8_t val;
604168404Spjd			(void) nvpair_value_int8(nvp, &val);
605219089Spjd			RENDER(pctl, int8, nvl, name, val);
606168404Spjd			break;
607168404Spjd		}
608168404Spjd		case DATA_TYPE_UINT8: {
609168404Spjd			uint8_t val;
610168404Spjd			(void) nvpair_value_uint8(nvp, &val);
611219089Spjd			RENDER(pctl, uint8, nvl, name, val);
612168404Spjd			break;
613168404Spjd		}
614168404Spjd		case DATA_TYPE_INT16: {
615168404Spjd			int16_t val;
616168404Spjd			(void) nvpair_value_int16(nvp, &val);
617219089Spjd			RENDER(pctl, int16, nvl, name, val);
618168404Spjd			break;
619168404Spjd		}
620168404Spjd		case DATA_TYPE_UINT16: {
621168404Spjd			uint16_t val;
622168404Spjd			(void) nvpair_value_uint16(nvp, &val);
623219089Spjd			RENDER(pctl, uint16, nvl, name, val);
624168404Spjd			break;
625168404Spjd		}
626168404Spjd		case DATA_TYPE_INT32: {
627168404Spjd			int32_t val;
628168404Spjd			(void) nvpair_value_int32(nvp, &val);
629219089Spjd			RENDER(pctl, int32, nvl, name, val);
630168404Spjd			break;
631168404Spjd		}
632168404Spjd		case DATA_TYPE_UINT32: {
633168404Spjd			uint32_t val;
634168404Spjd			(void) nvpair_value_uint32(nvp, &val);
635219089Spjd			RENDER(pctl, uint32, nvl, name, val);
636168404Spjd			break;
637168404Spjd		}
638168404Spjd		case DATA_TYPE_INT64: {
639168404Spjd			int64_t val;
640168404Spjd			(void) nvpair_value_int64(nvp, &val);
641219089Spjd			RENDER(pctl, int64, nvl, name, val);
642168404Spjd			break;
643168404Spjd		}
644168404Spjd		case DATA_TYPE_UINT64: {
645168404Spjd			uint64_t val;
646168404Spjd			(void) nvpair_value_uint64(nvp, &val);
647219089Spjd			RENDER(pctl, uint64, nvl, name, val);
648168404Spjd			break;
649168404Spjd		}
650185029Spjd		case DATA_TYPE_DOUBLE: {
651185029Spjd			double val;
652185029Spjd			(void) nvpair_value_double(nvp, &val);
653219089Spjd			RENDER(pctl, double, nvl, name, val);
654185029Spjd			break;
655185029Spjd		}
656168404Spjd		case DATA_TYPE_STRING: {
657168404Spjd			char *val;
658168404Spjd			(void) nvpair_value_string(nvp, &val);
659219089Spjd			RENDER(pctl, string, nvl, name, val);
660168404Spjd			break;
661168404Spjd		}
662168404Spjd		case DATA_TYPE_BOOLEAN_ARRAY: {
663168404Spjd			boolean_t *val;
664168404Spjd			(void) nvpair_value_boolean_array(nvp, &val, &nelem);
665219089Spjd			ARENDER(pctl, boolean_array, nvl, name, val, nelem);
666168404Spjd			break;
667168404Spjd		}
668168404Spjd		case DATA_TYPE_BYTE_ARRAY: {
669168404Spjd			uchar_t *val;
670168404Spjd			(void) nvpair_value_byte_array(nvp, &val, &nelem);
671219089Spjd			ARENDER(pctl, byte_array, nvl, name, val, nelem);
672168404Spjd			break;
673168404Spjd		}
674168404Spjd		case DATA_TYPE_INT8_ARRAY: {
675168404Spjd			int8_t *val;
676168404Spjd			(void) nvpair_value_int8_array(nvp, &val, &nelem);
677219089Spjd			ARENDER(pctl, int8_array, nvl, name, val, nelem);
678168404Spjd			break;
679168404Spjd		}
680168404Spjd		case DATA_TYPE_UINT8_ARRAY: {
681168404Spjd			uint8_t *val;
682168404Spjd			(void) nvpair_value_uint8_array(nvp, &val, &nelem);
683219089Spjd			ARENDER(pctl, uint8_array, nvl, name, val, nelem);
684168404Spjd			break;
685168404Spjd		}
686168404Spjd		case DATA_TYPE_INT16_ARRAY: {
687168404Spjd			int16_t *val;
688168404Spjd			(void) nvpair_value_int16_array(nvp, &val, &nelem);
689219089Spjd			ARENDER(pctl, int16_array, nvl, name, val, nelem);
690168404Spjd			break;
691168404Spjd		}
692168404Spjd		case DATA_TYPE_UINT16_ARRAY: {
693168404Spjd			uint16_t *val;
694168404Spjd			(void) nvpair_value_uint16_array(nvp, &val, &nelem);
695219089Spjd			ARENDER(pctl, uint16_array, nvl, name, val, nelem);
696168404Spjd			break;
697168404Spjd		}
698168404Spjd		case DATA_TYPE_INT32_ARRAY: {
699168404Spjd			int32_t *val;
700168404Spjd			(void) nvpair_value_int32_array(nvp, &val, &nelem);
701219089Spjd			ARENDER(pctl, int32_array, nvl, name, val, nelem);
702168404Spjd			break;
703168404Spjd		}
704168404Spjd		case DATA_TYPE_UINT32_ARRAY: {
705168404Spjd			uint32_t *val;
706168404Spjd			(void) nvpair_value_uint32_array(nvp, &val, &nelem);
707219089Spjd			ARENDER(pctl, uint32_array, nvl, name, val, nelem);
708168404Spjd			break;
709168404Spjd		}
710168404Spjd		case DATA_TYPE_INT64_ARRAY: {
711168404Spjd			int64_t *val;
712168404Spjd			(void) nvpair_value_int64_array(nvp, &val, &nelem);
713219089Spjd			ARENDER(pctl, int64_array, nvl, name, val, nelem);
714168404Spjd			break;
715168404Spjd		}
716168404Spjd		case DATA_TYPE_UINT64_ARRAY: {
717168404Spjd			uint64_t *val;
718168404Spjd			(void) nvpair_value_uint64_array(nvp, &val, &nelem);
719219089Spjd			ARENDER(pctl, uint64_array, nvl, name, val, nelem);
720168404Spjd			break;
721168404Spjd		}
722168404Spjd		case DATA_TYPE_STRING_ARRAY: {
723168404Spjd			char **val;
724168404Spjd			(void) nvpair_value_string_array(nvp, &val, &nelem);
725219089Spjd			ARENDER(pctl, string_array, nvl, name, val, nelem);
726168404Spjd			break;
727168404Spjd		}
728168404Spjd		case DATA_TYPE_HRTIME: {
729168404Spjd			hrtime_t val;
730168404Spjd			(void) nvpair_value_hrtime(nvp, &val);
731219089Spjd			RENDER(pctl, hrtime, nvl, name, val);
732168404Spjd			break;
733168404Spjd		}
734168404Spjd		case DATA_TYPE_NVLIST: {
735168404Spjd			nvlist_t *val;
736168404Spjd			(void) nvpair_value_nvlist(nvp, &val);
737219089Spjd			RENDER(pctl, nvlist, nvl, name, val);
738168404Spjd			break;
739168404Spjd		}
740168404Spjd		case DATA_TYPE_NVLIST_ARRAY: {
741168404Spjd			nvlist_t **val;
742168404Spjd			(void) nvpair_value_nvlist_array(nvp, &val, &nelem);
743219089Spjd			ARENDER(pctl, nvlist_array, nvl, name, val, nelem);
744168404Spjd			break;
745168404Spjd		}
746168404Spjd		default:
747168404Spjd			(void) fprintf(fp, " unknown data type (%d)", type);
748168404Spjd			break;
749168404Spjd		}
750168404Spjd		nvp = nvlist_next_nvpair(nvl, nvp);
751168404Spjd	}
752168404Spjd}
753168404Spjd
754168404Spjdvoid
755168404Spjdnvlist_print(FILE *fp, nvlist_t *nvl)
756168404Spjd{
757219089Spjd	struct nvlist_prtctl pc;
758219089Spjd
759219089Spjd	prtctl_defaults(fp, &pc, NULL);
760219089Spjd	nvlist_print_with_indent(nvl, &pc);
761168404Spjd}
762185029Spjd
763219089Spjdvoid
764219089Spjdnvlist_prt(nvlist_t *nvl, nvlist_prtctl_t pctl)
765219089Spjd{
766219089Spjd	nvlist_print_with_indent(nvl, pctl);
767219089Spjd}
768219089Spjd
769219089Spjd#define	NVP(elem, type, vtype, ptype, format) { \
770219089Spjd	vtype	value; \
771219089Spjd\
772219089Spjd	(void) nvpair_value_##type(elem, &value); \
773219089Spjd	(void) printf("%*s%s: " format "\n", indent, "", \
774219089Spjd	    nvpair_name(elem), (ptype)value); \
775219089Spjd}
776219089Spjd
777219089Spjd#define	NVPA(elem, type, vtype, ptype, format) { \
778219089Spjd	uint_t	i, count; \
779219089Spjd	vtype	*value;  \
780219089Spjd\
781219089Spjd	(void) nvpair_value_##type(elem, &value, &count); \
782219089Spjd	for (i = 0; i < count; i++) { \
783219089Spjd		(void) printf("%*s%s[%d]: " format "\n", indent, "", \
784219089Spjd		    nvpair_name(elem), i, (ptype)value[i]); \
785219089Spjd	} \
786219089Spjd}
787219089Spjd
788185029Spjd/*
789219089Spjd * Similar to nvlist_print() but handles arrays slightly differently.
790219089Spjd */
791219089Spjdvoid
792219089Spjddump_nvlist(nvlist_t *list, int indent)
793219089Spjd{
794219089Spjd	nvpair_t	*elem = NULL;
795219089Spjd	boolean_t	bool_value;
796282751Savg	boolean_t	*bool_array_value;
797219089Spjd	nvlist_t	*nvlist_value;
798219089Spjd	nvlist_t	**nvlist_array_value;
799219089Spjd	uint_t		i, count;
800219089Spjd
801219089Spjd	if (list == NULL) {
802219089Spjd		return;
803219089Spjd	}
804219089Spjd
805219089Spjd	while ((elem = nvlist_next_nvpair(list, elem)) != NULL) {
806219089Spjd		switch (nvpair_type(elem)) {
807236884Smm		case DATA_TYPE_BOOLEAN:
808236884Smm			(void) printf("%*s%s\n", indent, "", nvpair_name(elem));
809236884Smm			break;
810236884Smm
811219089Spjd		case DATA_TYPE_BOOLEAN_VALUE:
812219089Spjd			(void) nvpair_value_boolean_value(elem, &bool_value);
813219089Spjd			(void) printf("%*s%s: %s\n", indent, "",
814219089Spjd			    nvpair_name(elem), bool_value ? "true" : "false");
815219089Spjd			break;
816219089Spjd
817219089Spjd		case DATA_TYPE_BYTE:
818219089Spjd			NVP(elem, byte, uchar_t, int, "%u");
819219089Spjd			break;
820219089Spjd
821219089Spjd		case DATA_TYPE_INT8:
822219089Spjd			NVP(elem, int8, int8_t, int, "%d");
823219089Spjd			break;
824219089Spjd
825219089Spjd		case DATA_TYPE_UINT8:
826219089Spjd			NVP(elem, uint8, uint8_t, int, "%u");
827219089Spjd			break;
828219089Spjd
829219089Spjd		case DATA_TYPE_INT16:
830219089Spjd			NVP(elem, int16, int16_t, int, "%d");
831219089Spjd			break;
832219089Spjd
833219089Spjd		case DATA_TYPE_UINT16:
834219089Spjd			NVP(elem, uint16, uint16_t, int, "%u");
835219089Spjd			break;
836219089Spjd
837219089Spjd		case DATA_TYPE_INT32:
838219089Spjd			NVP(elem, int32, int32_t, long, "%ld");
839219089Spjd			break;
840219089Spjd
841219089Spjd		case DATA_TYPE_UINT32:
842219089Spjd			NVP(elem, uint32, uint32_t, ulong_t, "%lu");
843219089Spjd			break;
844219089Spjd
845219089Spjd		case DATA_TYPE_INT64:
846219089Spjd			NVP(elem, int64, int64_t, longlong_t, "%lld");
847219089Spjd			break;
848219089Spjd
849219089Spjd		case DATA_TYPE_UINT64:
850219089Spjd			NVP(elem, uint64, uint64_t, u_longlong_t, "%llu");
851219089Spjd			break;
852219089Spjd
853219089Spjd		case DATA_TYPE_STRING:
854219089Spjd			NVP(elem, string, char *, char *, "'%s'");
855219089Spjd			break;
856219089Spjd
857282751Savg		case DATA_TYPE_BOOLEAN_ARRAY:
858282751Savg			(void) nvpair_value_boolean_array(elem,
859282751Savg			    &bool_array_value, &count);
860282751Savg			for (i = 0; i < count; i++) {
861282751Savg				(void) printf("%*s%s[%d]: %s\n", indent, "",
862282751Savg				    nvpair_name(elem), i,
863282751Savg				    bool_array_value[i] ? "true" : "false");
864282751Savg			}
865282751Savg			break;
866282751Savg
867219089Spjd		case DATA_TYPE_BYTE_ARRAY:
868219089Spjd			NVPA(elem, byte_array, uchar_t, int, "%u");
869219089Spjd			break;
870219089Spjd
871219089Spjd		case DATA_TYPE_INT8_ARRAY:
872219089Spjd			NVPA(elem, int8_array, int8_t, int, "%d");
873219089Spjd			break;
874219089Spjd
875219089Spjd		case DATA_TYPE_UINT8_ARRAY:
876219089Spjd			NVPA(elem, uint8_array, uint8_t, int, "%u");
877219089Spjd			break;
878219089Spjd
879219089Spjd		case DATA_TYPE_INT16_ARRAY:
880219089Spjd			NVPA(elem, int16_array, int16_t, int, "%d");
881219089Spjd			break;
882219089Spjd
883219089Spjd		case DATA_TYPE_UINT16_ARRAY:
884219089Spjd			NVPA(elem, uint16_array, uint16_t, int, "%u");
885219089Spjd			break;
886219089Spjd
887219089Spjd		case DATA_TYPE_INT32_ARRAY:
888219089Spjd			NVPA(elem, int32_array, int32_t, long, "%ld");
889219089Spjd			break;
890219089Spjd
891219089Spjd		case DATA_TYPE_UINT32_ARRAY:
892219089Spjd			NVPA(elem, uint32_array, uint32_t, ulong_t, "%lu");
893219089Spjd			break;
894219089Spjd
895219089Spjd		case DATA_TYPE_INT64_ARRAY:
896219089Spjd			NVPA(elem, int64_array, int64_t, longlong_t, "%lld");
897219089Spjd			break;
898219089Spjd
899219089Spjd		case DATA_TYPE_UINT64_ARRAY:
900219089Spjd			NVPA(elem, uint64_array, uint64_t, u_longlong_t,
901219089Spjd			    "%llu");
902219089Spjd			break;
903219089Spjd
904219089Spjd		case DATA_TYPE_STRING_ARRAY:
905219089Spjd			NVPA(elem, string_array, char *, char *, "'%s'");
906219089Spjd			break;
907219089Spjd
908219089Spjd		case DATA_TYPE_NVLIST:
909219089Spjd			(void) nvpair_value_nvlist(elem, &nvlist_value);
910219089Spjd			(void) printf("%*s%s:\n", indent, "",
911219089Spjd			    nvpair_name(elem));
912219089Spjd			dump_nvlist(nvlist_value, indent + 4);
913219089Spjd			break;
914219089Spjd
915219089Spjd		case DATA_TYPE_NVLIST_ARRAY:
916219089Spjd			(void) nvpair_value_nvlist_array(elem,
917219089Spjd			    &nvlist_array_value, &count);
918219089Spjd			for (i = 0; i < count; i++) {
919219089Spjd				(void) printf("%*s%s[%u]:\n", indent, "",
920219089Spjd				    nvpair_name(elem), i);
921219089Spjd				dump_nvlist(nvlist_array_value[i], indent + 4);
922219089Spjd			}
923219089Spjd			break;
924219089Spjd
925219089Spjd		default:
926219089Spjd			(void) printf(dgettext(TEXT_DOMAIN, "bad config type "
927219089Spjd			    "%d for %s\n"), nvpair_type(elem),
928219089Spjd			    nvpair_name(elem));
929219089Spjd		}
930219089Spjd	}
931219089Spjd}
932219089Spjd
933219089Spjd/*
934219089Spjd * ======================================================================
935219089Spjd * |									|
936219089Spjd * | Misc private interface.						|
937219089Spjd * |									|
938219089Spjd * ======================================================================
939219089Spjd */
940219089Spjd
941219089Spjd/*
942185029Spjd * Determine if string 'value' matches 'nvp' value.  The 'value' string is
943185029Spjd * converted, depending on the type of 'nvp', prior to match.  For numeric
944185029Spjd * types, a radix independent sscanf conversion of 'value' is used. If 'nvp'
945185029Spjd * is an array type, 'ai' is the index into the array against which we are
946185029Spjd * checking for match. If nvp is of DATA_TYPE_STRING*, the caller can pass
947185029Spjd * in a regex_t compilation of value in 'value_regex' to trigger regular
948185029Spjd * expression string match instead of simple strcmp().
949185029Spjd *
950185029Spjd * Return 1 on match, 0 on no-match, and -1 on error.  If the error is
951185029Spjd * related to value syntax error and 'ep' is non-NULL, *ep will point into
952185029Spjd * the 'value' string at the location where the error exists.
953185029Spjd *
954185029Spjd * NOTE: It may be possible to move the non-regex_t version of this into
955185029Spjd * common code used by library/kernel/boot.
956185029Spjd */
957185029Spjdint
958185029Spjdnvpair_value_match_regex(nvpair_t *nvp, int ai,
959185029Spjd    char *value, regex_t *value_regex, char **ep)
960185029Spjd{
961185029Spjd	char	*evalue;
962185029Spjd	uint_t	a_len;
963185029Spjd	int	sr;
964185029Spjd
965185029Spjd	if (ep)
966185029Spjd		*ep = NULL;
967185029Spjd
968185029Spjd	if ((nvp == NULL) || (value == NULL))
969185029Spjd		return (-1);		/* error fail match - invalid args */
970185029Spjd
971185029Spjd	/* make sure array and index combination make sense */
972185029Spjd	if ((nvpair_type_is_array(nvp) && (ai < 0)) ||
973185029Spjd	    (!nvpair_type_is_array(nvp) && (ai >= 0)))
974185029Spjd		return (-1);		/* error fail match - bad index */
975185029Spjd
976185029Spjd	/* non-string values should be single 'chunk' */
977185029Spjd	if ((nvpair_type(nvp) != DATA_TYPE_STRING) &&
978185029Spjd	    (nvpair_type(nvp) != DATA_TYPE_STRING_ARRAY)) {
979185029Spjd		value += strspn(value, " \t");
980185029Spjd		evalue = value + strcspn(value, " \t");
981185029Spjd		if (*evalue) {
982185029Spjd			if (ep)
983185029Spjd				*ep = evalue;
984185029Spjd			return (-1);	/* error fail match - syntax */
985185029Spjd		}
986185029Spjd	}
987185029Spjd
988185029Spjd	sr = EOF;
989185029Spjd	switch (nvpair_type(nvp)) {
990185029Spjd	case DATA_TYPE_STRING: {
991185029Spjd		char	*val;
992185029Spjd
993185029Spjd		/* check string value for match */
994185029Spjd		if (nvpair_value_string(nvp, &val) == 0) {
995185029Spjd			if (value_regex) {
996185029Spjd				if (regexec(value_regex, val,
997185029Spjd				    (size_t)0, NULL, 0) == 0)
998185029Spjd					return (1);	/* match */
999185029Spjd			} else {
1000185029Spjd				if (strcmp(value, val) == 0)
1001185029Spjd					return (1);	/* match */
1002185029Spjd			}
1003185029Spjd		}
1004185029Spjd		break;
1005185029Spjd	}
1006185029Spjd	case DATA_TYPE_STRING_ARRAY: {
1007185029Spjd		char **val_array;
1008185029Spjd
1009185029Spjd		/* check indexed string value of array for match */
1010185029Spjd		if ((nvpair_value_string_array(nvp, &val_array, &a_len) == 0) &&
1011185029Spjd		    (ai < a_len)) {
1012185029Spjd			if (value_regex) {
1013185029Spjd				if (regexec(value_regex, val_array[ai],
1014185029Spjd				    (size_t)0, NULL, 0) == 0)
1015185029Spjd					return (1);
1016185029Spjd			} else {
1017185029Spjd				if (strcmp(value, val_array[ai]) == 0)
1018185029Spjd					return (1);
1019185029Spjd			}
1020185029Spjd		}
1021185029Spjd		break;
1022185029Spjd	}
1023185029Spjd	case DATA_TYPE_BYTE: {
1024185029Spjd		uchar_t val, val_arg;
1025185029Spjd
1026185029Spjd		/* scanf uchar_t from value and check for match */
1027185029Spjd		sr = sscanf(value, "%c", &val_arg);
1028185029Spjd		if ((sr == 1) && (nvpair_value_byte(nvp, &val) == 0) &&
1029185029Spjd		    (val == val_arg))
1030185029Spjd			return (1);
1031185029Spjd		break;
1032185029Spjd	}
1033185029Spjd	case DATA_TYPE_BYTE_ARRAY: {
1034185029Spjd		uchar_t *val_array, val_arg;
1035185029Spjd
1036185029Spjd
1037185029Spjd		/* check indexed value of array for match */
1038185029Spjd		sr = sscanf(value, "%c", &val_arg);
1039185029Spjd		if ((sr == 1) &&
1040185029Spjd		    (nvpair_value_byte_array(nvp, &val_array, &a_len) == 0) &&
1041185029Spjd		    (ai < a_len) &&
1042185029Spjd		    (val_array[ai] == val_arg))
1043185029Spjd			return (1);
1044185029Spjd		break;
1045185029Spjd	}
1046185029Spjd	case DATA_TYPE_INT8: {
1047185029Spjd		int8_t val, val_arg;
1048185029Spjd
1049185029Spjd		/* scanf int8_t from value and check for match */
1050185029Spjd		sr = sscanf(value, "%"SCNi8, &val_arg);
1051185029Spjd		if ((sr == 1) &&
1052185029Spjd		    (nvpair_value_int8(nvp, &val) == 0) &&
1053185029Spjd		    (val == val_arg))
1054185029Spjd			return (1);
1055185029Spjd		break;
1056185029Spjd	}
1057185029Spjd	case DATA_TYPE_INT8_ARRAY: {
1058185029Spjd		int8_t *val_array, val_arg;
1059185029Spjd
1060185029Spjd		/* check indexed value of array for match */
1061185029Spjd		sr = sscanf(value, "%"SCNi8, &val_arg);
1062185029Spjd		if ((sr == 1) &&
1063185029Spjd		    (nvpair_value_int8_array(nvp, &val_array, &a_len) == 0) &&
1064185029Spjd		    (ai < a_len) &&
1065185029Spjd		    (val_array[ai] == val_arg))
1066185029Spjd			return (1);
1067185029Spjd		break;
1068185029Spjd	}
1069185029Spjd	case DATA_TYPE_UINT8: {
1070185029Spjd		uint8_t val, val_arg;
1071185029Spjd
1072185029Spjd		/* scanf uint8_t from value and check for match */
1073185029Spjd		sr = sscanf(value, "%"SCNi8, (int8_t *)&val_arg);
1074185029Spjd		if ((sr == 1) &&
1075185029Spjd		    (nvpair_value_uint8(nvp, &val) == 0) &&
1076185029Spjd		    (val == val_arg))
1077185029Spjd			return (1);
1078185029Spjd		break;
1079185029Spjd	}
1080185029Spjd	case DATA_TYPE_UINT8_ARRAY: {
1081185029Spjd		uint8_t *val_array, val_arg;
1082185029Spjd
1083185029Spjd		/* check indexed value of array for match */
1084185029Spjd		sr = sscanf(value, "%"SCNi8, (int8_t *)&val_arg);
1085185029Spjd		if ((sr == 1) &&
1086185029Spjd		    (nvpair_value_uint8_array(nvp, &val_array, &a_len) == 0) &&
1087185029Spjd		    (ai < a_len) &&
1088185029Spjd		    (val_array[ai] == val_arg))
1089185029Spjd			return (1);
1090185029Spjd		break;
1091185029Spjd	}
1092185029Spjd	case DATA_TYPE_INT16: {
1093185029Spjd		int16_t val, val_arg;
1094185029Spjd
1095185029Spjd		/* scanf int16_t from value and check for match */
1096185029Spjd		sr = sscanf(value, "%"SCNi16, &val_arg);
1097185029Spjd		if ((sr == 1) &&
1098185029Spjd		    (nvpair_value_int16(nvp, &val) == 0) &&
1099185029Spjd		    (val == val_arg))
1100185029Spjd			return (1);
1101185029Spjd		break;
1102185029Spjd	}
1103185029Spjd	case DATA_TYPE_INT16_ARRAY: {
1104185029Spjd		int16_t *val_array, val_arg;
1105185029Spjd
1106185029Spjd		/* check indexed value of array for match */
1107185029Spjd		sr = sscanf(value, "%"SCNi16, &val_arg);
1108185029Spjd		if ((sr == 1) &&
1109185029Spjd		    (nvpair_value_int16_array(nvp, &val_array, &a_len) == 0) &&
1110185029Spjd		    (ai < a_len) &&
1111185029Spjd		    (val_array[ai] == val_arg))
1112185029Spjd			return (1);
1113185029Spjd		break;
1114185029Spjd	}
1115185029Spjd	case DATA_TYPE_UINT16: {
1116185029Spjd		uint16_t val, val_arg;
1117185029Spjd
1118185029Spjd		/* scanf uint16_t from value and check for match */
1119185029Spjd		sr = sscanf(value, "%"SCNi16, (int16_t *)&val_arg);
1120185029Spjd		if ((sr == 1) &&
1121185029Spjd		    (nvpair_value_uint16(nvp, &val) == 0) &&
1122185029Spjd		    (val == val_arg))
1123185029Spjd			return (1);
1124185029Spjd		break;
1125185029Spjd	}
1126185029Spjd	case DATA_TYPE_UINT16_ARRAY: {
1127185029Spjd		uint16_t *val_array, val_arg;
1128185029Spjd
1129185029Spjd		/* check indexed value of array for match */
1130185029Spjd		sr = sscanf(value, "%"SCNi16, (int16_t *)&val_arg);
1131185029Spjd		if ((sr == 1) &&
1132185029Spjd		    (nvpair_value_uint16_array(nvp, &val_array, &a_len) == 0) &&
1133185029Spjd		    (ai < a_len) &&
1134185029Spjd		    (val_array[ai] == val_arg))
1135185029Spjd			return (1);
1136185029Spjd		break;
1137185029Spjd	}
1138185029Spjd	case DATA_TYPE_INT32: {
1139185029Spjd		int32_t val, val_arg;
1140185029Spjd
1141185029Spjd		/* scanf int32_t from value and check for match */
1142185029Spjd		sr = sscanf(value, "%"SCNi32, &val_arg);
1143185029Spjd		if ((sr == 1) &&
1144185029Spjd		    (nvpair_value_int32(nvp, &val) == 0) &&
1145185029Spjd		    (val == val_arg))
1146185029Spjd			return (1);
1147185029Spjd		break;
1148185029Spjd	}
1149185029Spjd	case DATA_TYPE_INT32_ARRAY: {
1150185029Spjd		int32_t *val_array, val_arg;
1151185029Spjd
1152185029Spjd		/* check indexed value of array for match */
1153185029Spjd		sr = sscanf(value, "%"SCNi32, &val_arg);
1154185029Spjd		if ((sr == 1) &&
1155185029Spjd		    (nvpair_value_int32_array(nvp, &val_array, &a_len) == 0) &&
1156185029Spjd		    (ai < a_len) &&
1157185029Spjd		    (val_array[ai] == val_arg))
1158185029Spjd			return (1);
1159185029Spjd		break;
1160185029Spjd	}
1161185029Spjd	case DATA_TYPE_UINT32: {
1162185029Spjd		uint32_t val, val_arg;
1163185029Spjd
1164185029Spjd		/* scanf uint32_t from value and check for match */
1165185029Spjd		sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg);
1166185029Spjd		if ((sr == 1) &&
1167185029Spjd		    (nvpair_value_uint32(nvp, &val) == 0) &&
1168185029Spjd		    (val == val_arg))
1169185029Spjd			return (1);
1170185029Spjd		break;
1171185029Spjd	}
1172185029Spjd	case DATA_TYPE_UINT32_ARRAY: {
1173185029Spjd		uint32_t *val_array, val_arg;
1174185029Spjd
1175185029Spjd		/* check indexed value of array for match */
1176185029Spjd		sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg);
1177185029Spjd		if ((sr == 1) &&
1178185029Spjd		    (nvpair_value_uint32_array(nvp, &val_array, &a_len) == 0) &&
1179185029Spjd		    (ai < a_len) &&
1180185029Spjd		    (val_array[ai] == val_arg))
1181185029Spjd			return (1);
1182185029Spjd		break;
1183185029Spjd	}
1184185029Spjd	case DATA_TYPE_INT64: {
1185185029Spjd		int64_t val, val_arg;
1186185029Spjd
1187185029Spjd		/* scanf int64_t from value and check for match */
1188185029Spjd		sr = sscanf(value, "%"SCNi64, &val_arg);
1189185029Spjd		if ((sr == 1) &&
1190185029Spjd		    (nvpair_value_int64(nvp, &val) == 0) &&
1191185029Spjd		    (val == val_arg))
1192185029Spjd			return (1);
1193185029Spjd		break;
1194185029Spjd	}
1195185029Spjd	case DATA_TYPE_INT64_ARRAY: {
1196185029Spjd		int64_t *val_array, val_arg;
1197185029Spjd
1198185029Spjd		/* check indexed value of array for match */
1199185029Spjd		sr = sscanf(value, "%"SCNi64, &val_arg);
1200185029Spjd		if ((sr == 1) &&
1201185029Spjd		    (nvpair_value_int64_array(nvp, &val_array, &a_len) == 0) &&
1202185029Spjd		    (ai < a_len) &&
1203185029Spjd		    (val_array[ai] == val_arg))
1204185029Spjd				return (1);
1205185029Spjd		break;
1206185029Spjd	}
1207185029Spjd	case DATA_TYPE_UINT64: {
1208185029Spjd		uint64_t val_arg, val;
1209185029Spjd
1210185029Spjd		/* scanf uint64_t from value and check for match */
1211185029Spjd		sr = sscanf(value, "%"SCNi64, (int64_t *)&val_arg);
1212185029Spjd		if ((sr == 1) &&
1213185029Spjd		    (nvpair_value_uint64(nvp, &val) == 0) &&
1214185029Spjd		    (val == val_arg))
1215185029Spjd			return (1);
1216185029Spjd		break;
1217185029Spjd	}
1218185029Spjd	case DATA_TYPE_UINT64_ARRAY: {
1219185029Spjd		uint64_t *val_array, val_arg;
1220185029Spjd
1221185029Spjd		/* check indexed value of array for match */
1222185029Spjd		sr = sscanf(value, "%"SCNi64, (int64_t *)&val_arg);
1223185029Spjd		if ((sr == 1) &&
1224185029Spjd		    (nvpair_value_uint64_array(nvp, &val_array, &a_len) == 0) &&
1225185029Spjd		    (ai < a_len) &&
1226185029Spjd		    (val_array[ai] == val_arg))
1227185029Spjd			return (1);
1228185029Spjd		break;
1229185029Spjd	}
1230185029Spjd	case DATA_TYPE_BOOLEAN_VALUE: {
1231307124Smav		int32_t val_arg;
1232307124Smav		boolean_t val;
1233185029Spjd
1234185029Spjd		/* scanf boolean_t from value and check for match */
1235185029Spjd		sr = sscanf(value, "%"SCNi32, &val_arg);
1236185029Spjd		if ((sr == 1) &&
1237185029Spjd		    (nvpair_value_boolean_value(nvp, &val) == 0) &&
1238185029Spjd		    (val == val_arg))
1239185029Spjd			return (1);
1240185029Spjd		break;
1241185029Spjd	}
1242185029Spjd	case DATA_TYPE_BOOLEAN_ARRAY: {
1243307124Smav		boolean_t *val_array;
1244307124Smav		int32_t val_arg;
1245185029Spjd
1246185029Spjd		/* check indexed value of array for match */
1247185029Spjd		sr = sscanf(value, "%"SCNi32, &val_arg);
1248185029Spjd		if ((sr == 1) &&
1249185029Spjd		    (nvpair_value_boolean_array(nvp,
1250185029Spjd		    &val_array, &a_len) == 0) &&
1251185029Spjd		    (ai < a_len) &&
1252185029Spjd		    (val_array[ai] == val_arg))
1253185029Spjd			return (1);
1254185029Spjd		break;
1255185029Spjd	}
1256185029Spjd	case DATA_TYPE_HRTIME:
1257185029Spjd	case DATA_TYPE_NVLIST:
1258185029Spjd	case DATA_TYPE_NVLIST_ARRAY:
1259185029Spjd	case DATA_TYPE_BOOLEAN:
1260185029Spjd	case DATA_TYPE_DOUBLE:
1261185029Spjd	case DATA_TYPE_UNKNOWN:
1262185029Spjd	default:
1263185029Spjd		/*
1264185029Spjd		 * unknown/unsupported data type
1265185029Spjd		 */
1266185029Spjd		return (-1);		/* error fail match */
1267185029Spjd	}
1268185029Spjd
1269185029Spjd	/*
1270185029Spjd	 * check to see if sscanf failed conversion, return approximate
1271185029Spjd	 * pointer to problem
1272185029Spjd	 */
1273185029Spjd	if (sr != 1) {
1274185029Spjd		if (ep)
1275185029Spjd			*ep = value;
1276185029Spjd		return (-1);		/* error fail match  - syntax */
1277185029Spjd	}
1278185029Spjd
1279185029Spjd	return (0);			/* fail match */
1280185029Spjd}
1281185029Spjd
1282185029Spjdint
1283185029Spjdnvpair_value_match(nvpair_t *nvp, int ai, char *value, char **ep)
1284185029Spjd{
1285185029Spjd	return (nvpair_value_match_regex(nvp, ai, value, NULL, ep));
1286185029Spjd}
1287