Path: blob/main/sys/contrib/openzfs/lib/libnvpair/libnvpair.c
48375 views
// SPDX-License-Identifier: CDDL-1.01/*2* CDDL HEADER START3*4* The contents of this file are subject to the terms of the5* 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.LICENSE9* or https://opensource.org/licenses/CDDL-1.0.10* See the License for the specific language governing permissions11* and limitations under the License.12*13* When distributing Covered Code, include this CDDL HEADER in each14* file and include the License file at usr/src/OPENSOLARIS.LICENSE.15* If applicable, add the following below this CDDL HEADER, with the16* fields enclosed by brackets "[]" replaced with your own identifying17* information: Portions Copyright [yyyy] [name of copyright owner]18*19* CDDL HEADER END20*/21/*22* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.23* Copyright (c) 2012 by Delphix. All rights reserved.24*/2526#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 "libnvpair.h"3334/*35* libnvpair - A tools library for manipulating <name, value> pairs.36*37* This library provides routines packing an unpacking nv pairs38* for transporting data across process boundaries, transporting39* between kernel and userland, and possibly saving onto disk files.40*/4142/*43* Print control structure.44*/4546#define DEFINEOP(opname, vtype) \47struct { \48int (*op)(struct nvlist_prtctl *, void *, nvlist_t *, \49const char *, vtype); \50void *arg; \51} opname5253#define DEFINEARROP(opname, vtype) \54struct { \55int (*op)(struct nvlist_prtctl *, void *, nvlist_t *, \56const char *, vtype, uint_t); \57void *arg; \58} opname5960struct nvlist_printops {61DEFINEOP(print_boolean, int);62DEFINEOP(print_boolean_value, boolean_t);63DEFINEOP(print_byte, uchar_t);64DEFINEOP(print_int8, int8_t);65DEFINEOP(print_uint8, uint8_t);66DEFINEOP(print_int16, int16_t);67DEFINEOP(print_uint16, uint16_t);68DEFINEOP(print_int32, int32_t);69DEFINEOP(print_uint32, uint32_t);70DEFINEOP(print_int64, int64_t);71DEFINEOP(print_uint64, uint64_t);72DEFINEOP(print_double, double);73DEFINEOP(print_string, const char *);74DEFINEOP(print_hrtime, hrtime_t);75DEFINEOP(print_nvlist, nvlist_t *);76DEFINEARROP(print_boolean_array, boolean_t *);77DEFINEARROP(print_byte_array, uchar_t *);78DEFINEARROP(print_int8_array, int8_t *);79DEFINEARROP(print_uint8_array, uint8_t *);80DEFINEARROP(print_int16_array, int16_t *);81DEFINEARROP(print_uint16_array, uint16_t *);82DEFINEARROP(print_int32_array, int32_t *);83DEFINEARROP(print_uint32_array, uint32_t *);84DEFINEARROP(print_int64_array, int64_t *);85DEFINEARROP(print_uint64_array, uint64_t *);86DEFINEARROP(print_string_array, const char **);87DEFINEARROP(print_nvlist_array, nvlist_t **);88};8990struct nvlist_prtctl {91FILE *nvprt_fp; /* output destination */92enum nvlist_indent_mode nvprt_indent_mode; /* see above */93int nvprt_indent; /* absolute indent, or tab depth */94int nvprt_indentinc; /* indent or tab increment */95const char *nvprt_nmfmt; /* member name format, max one %s */96const char *nvprt_eomfmt; /* after member format, e.g. "\n" */97const char *nvprt_btwnarrfmt; /* between array members */98int nvprt_btwnarrfmt_nl; /* nvprt_eoamfmt includes newline? */99struct nvlist_printops *nvprt_dfltops;100struct nvlist_printops *nvprt_custops;101};102103#define DFLTPRTOP(pctl, type) \104((pctl)->nvprt_dfltops->print_##type.op)105106#define DFLTPRTOPARG(pctl, type) \107((pctl)->nvprt_dfltops->print_##type.arg)108109#define CUSTPRTOP(pctl, type) \110((pctl)->nvprt_custops->print_##type.op)111112#define CUSTPRTOPARG(pctl, type) \113((pctl)->nvprt_custops->print_##type.arg)114115#define RENDER(pctl, type, nvl, name, val) \116{ \117int done = 0; \118if ((pctl)->nvprt_custops && CUSTPRTOP(pctl, type)) { \119done = CUSTPRTOP(pctl, type)(pctl, \120CUSTPRTOPARG(pctl, type), nvl, name, val); \121} \122if (!done) { \123(void) DFLTPRTOP(pctl, type)(pctl, \124DFLTPRTOPARG(pctl, type), nvl, name, val); \125} \126(void) fprintf(pctl->nvprt_fp, "%s", pctl->nvprt_eomfmt); \127}128129#define ARENDER(pctl, type, nvl, name, arrp, count) \130{ \131int done = 0; \132if ((pctl)->nvprt_custops && CUSTPRTOP(pctl, type)) { \133done = CUSTPRTOP(pctl, type)(pctl, \134CUSTPRTOPARG(pctl, type), nvl, name, arrp, count); \135} \136if (!done) { \137(void) DFLTPRTOP(pctl, type)(pctl, \138DFLTPRTOPARG(pctl, type), nvl, name, arrp, count); \139} \140(void) fprintf(pctl->nvprt_fp, "%s", pctl->nvprt_eomfmt); \141}142143static void nvlist_print_with_indent(nvlist_t *, nvlist_prtctl_t);144145/*146* ======================================================================147* | |148* | Indentation |149* | |150* ======================================================================151*/152153static void154indent(nvlist_prtctl_t pctl, int onemore)155{156int depth;157158switch (pctl->nvprt_indent_mode) {159case NVLIST_INDENT_ABS:160(void) fprintf(pctl->nvprt_fp, "%*s",161pctl->nvprt_indent + onemore * pctl->nvprt_indentinc, "");162break;163164case NVLIST_INDENT_TABBED:165depth = pctl->nvprt_indent + onemore;166while (depth-- > 0)167(void) fprintf(pctl->nvprt_fp, "\t");168}169}170171/*172* ======================================================================173* | |174* | Default nvlist member rendering functions. |175* | |176* ======================================================================177*/178179/*180* Generate functions to print single-valued nvlist members.181*182* type_and_variant - suffix to form function name183* vtype - C type for the member value184* ptype - C type to cast value to for printing185* vfmt - format string for pair value, e.g "%d" or "0x%llx"186*/187188#define NVLIST_PRTFUNC(type_and_variant, vtype, ptype, vfmt) \189static int \190nvprint_##type_and_variant(nvlist_prtctl_t pctl, void *private, \191nvlist_t *nvl, const char *name, vtype value) \192{ \193(void) private; \194(void) nvl; \195FILE *fp = pctl->nvprt_fp; \196indent(pctl, 1); \197(void) fprintf(fp, pctl->nvprt_nmfmt, name); \198(void) fprintf(fp, vfmt, (ptype)value); \199return (1); \200}201202/*203* Workaround for GCC 12+ with UBSan enabled deficencies.204*205* GCC 12+ invoked with -fsanitize=undefined incorrectly reports the code206* below as violating -Wformat-overflow.207*/208#if defined(__GNUC__) && !defined(__clang__) && \209defined(ZFS_UBSAN_ENABLED) && defined(HAVE_FORMAT_OVERFLOW)210#pragma GCC diagnostic push211#pragma GCC diagnostic ignored "-Wformat-overflow"212#endif213NVLIST_PRTFUNC(boolean, int, int, "%d")214NVLIST_PRTFUNC(boolean_value, boolean_t, int, "%d")215NVLIST_PRTFUNC(byte, uchar_t, uchar_t, "0x%2.2x")216NVLIST_PRTFUNC(int8, int8_t, int, "%d")217NVLIST_PRTFUNC(uint8, uint8_t, uint8_t, "0x%x")218NVLIST_PRTFUNC(int16, int16_t, int16_t, "%d")219NVLIST_PRTFUNC(uint16, uint16_t, uint16_t, "0x%x")220NVLIST_PRTFUNC(int32, int32_t, int32_t, "%d")221NVLIST_PRTFUNC(uint32, uint32_t, uint32_t, "0x%x")222NVLIST_PRTFUNC(int64, int64_t, longlong_t, "%lld")223NVLIST_PRTFUNC(uint64, uint64_t, u_longlong_t, "0x%llx")224NVLIST_PRTFUNC(double, double, double, "0x%f")225NVLIST_PRTFUNC(string, const char *, const char *, "%s")226NVLIST_PRTFUNC(hrtime, hrtime_t, hrtime_t, "0x%llx")227#if defined(__GNUC__) && !defined(__clang__) && \228defined(ZFS_UBSAN_ENABLED) && defined(HAVE_FORMAT_OVERFLOW)229#pragma GCC diagnostic pop230#endif231232/*233* Generate functions to print array-valued nvlist members.234*/235236#define NVLIST_ARRPRTFUNC(type_and_variant, vtype, ptype, vfmt) \237static int \238nvaprint_##type_and_variant(nvlist_prtctl_t pctl, void *private, \239nvlist_t *nvl, const char *name, vtype *valuep, uint_t count) \240{ \241(void) private; \242(void) nvl; \243FILE *fp = pctl->nvprt_fp; \244uint_t i; \245for (i = 0; i < count; i++) { \246if (i == 0 || pctl->nvprt_btwnarrfmt_nl) { \247indent(pctl, 1); \248(void) fprintf(fp, pctl->nvprt_nmfmt, name); \249if (pctl->nvprt_btwnarrfmt_nl) \250(void) fprintf(fp, "[%d]: ", i); \251} \252if (i != 0) \253(void) fprintf(fp, "%s", pctl->nvprt_btwnarrfmt); \254(void) fprintf(fp, vfmt, (ptype)valuep[i]); \255} \256return (1); \257}258259NVLIST_ARRPRTFUNC(boolean_array, boolean_t, boolean_t, "%d")260NVLIST_ARRPRTFUNC(byte_array, uchar_t, uchar_t, "0x%2.2x")261NVLIST_ARRPRTFUNC(int8_array, int8_t, int8_t, "%d")262NVLIST_ARRPRTFUNC(uint8_array, uint8_t, uint8_t, "0x%x")263NVLIST_ARRPRTFUNC(int16_array, int16_t, int16_t, "%d")264NVLIST_ARRPRTFUNC(uint16_array, uint16_t, uint16_t, "0x%x")265NVLIST_ARRPRTFUNC(int32_array, int32_t, int32_t, "%d")266NVLIST_ARRPRTFUNC(uint32_array, uint32_t, uint32_t, "0x%x")267NVLIST_ARRPRTFUNC(int64_array, int64_t, longlong_t, "%lld")268NVLIST_ARRPRTFUNC(uint64_array, uint64_t, u_longlong_t, "0x%llx")269NVLIST_ARRPRTFUNC(string_array, const char *, const char *, "%s")270271static int272nvprint_nvlist(nvlist_prtctl_t pctl, void *private,273nvlist_t *nvl, const char *name, nvlist_t *value)274{275(void) private, (void) nvl;276FILE *fp = pctl->nvprt_fp;277278indent(pctl, 1);279(void) fprintf(fp, "%s = (embedded nvlist)\n", name);280281pctl->nvprt_indent += pctl->nvprt_indentinc;282nvlist_print_with_indent(value, pctl);283pctl->nvprt_indent -= pctl->nvprt_indentinc;284285indent(pctl, 1);286(void) fprintf(fp, "(end %s)\n", name);287288return (1);289}290291static int292nvaprint_nvlist_array(nvlist_prtctl_t pctl, void *private,293nvlist_t *nvl, const char *name, nvlist_t **valuep, uint_t count)294{295(void) private, (void) nvl;296FILE *fp = pctl->nvprt_fp;297uint_t i;298299indent(pctl, 1);300(void) fprintf(fp, "%s = (array of embedded nvlists)\n", name);301302for (i = 0; i < count; i++) {303indent(pctl, 1);304(void) fprintf(fp, "(start %s[%d])\n", name, i);305306pctl->nvprt_indent += pctl->nvprt_indentinc;307nvlist_print_with_indent(valuep[i], pctl);308pctl->nvprt_indent -= pctl->nvprt_indentinc;309310indent(pctl, 1);311(void) fprintf(fp, "(end %s[%d])\n", name, i);312}313314return (1);315}316317/*318* ======================================================================319* | |320* | Interfaces that allow control over formatting. |321* | |322* ======================================================================323*/324325void326nvlist_prtctl_setdest(nvlist_prtctl_t pctl, FILE *fp)327{328pctl->nvprt_fp = fp;329}330331FILE *332nvlist_prtctl_getdest(nvlist_prtctl_t pctl)333{334return (pctl->nvprt_fp);335}336337338void339nvlist_prtctl_setindent(nvlist_prtctl_t pctl, enum nvlist_indent_mode mode,340int start, int inc)341{342if (mode < NVLIST_INDENT_ABS || mode > NVLIST_INDENT_TABBED)343mode = NVLIST_INDENT_TABBED;344345if (start < 0)346start = 0;347348if (inc < 0)349inc = 1;350351pctl->nvprt_indent_mode = mode;352pctl->nvprt_indent = start;353pctl->nvprt_indentinc = inc;354}355356void357nvlist_prtctl_doindent(nvlist_prtctl_t pctl, int onemore)358{359indent(pctl, onemore);360}361362363void364nvlist_prtctl_setfmt(nvlist_prtctl_t pctl, enum nvlist_prtctl_fmt which,365const char *fmt)366{367switch (which) {368case NVLIST_FMT_MEMBER_NAME:369if (fmt == NULL)370fmt = "%s = ";371pctl->nvprt_nmfmt = fmt;372break;373374case NVLIST_FMT_MEMBER_POSTAMBLE:375if (fmt == NULL)376fmt = "\n";377pctl->nvprt_eomfmt = fmt;378break;379380case NVLIST_FMT_BTWN_ARRAY:381if (fmt == NULL) {382pctl->nvprt_btwnarrfmt = " ";383pctl->nvprt_btwnarrfmt_nl = 0;384} else {385pctl->nvprt_btwnarrfmt = fmt;386pctl->nvprt_btwnarrfmt_nl = (strchr(fmt, '\n') != NULL);387}388break;389390default:391break;392}393}394395396void397nvlist_prtctl_dofmt(nvlist_prtctl_t pctl, enum nvlist_prtctl_fmt which, ...)398{399FILE *fp = pctl->nvprt_fp;400va_list ap;401const char *name;402403va_start(ap, which);404405switch (which) {406case NVLIST_FMT_MEMBER_NAME:407name = va_arg(ap, const char *);408(void) fprintf(fp, pctl->nvprt_nmfmt, name);409break;410411case NVLIST_FMT_MEMBER_POSTAMBLE:412(void) fprintf(fp, "%s", pctl->nvprt_eomfmt);413break;414415case NVLIST_FMT_BTWN_ARRAY:416(void) fprintf(fp, "%s", pctl->nvprt_btwnarrfmt);417break;418419default:420break;421}422423va_end(ap);424}425426/*427* ======================================================================428* | |429* | Interfaces to allow appointment of replacement rendering functions.|430* | |431* ======================================================================432*/433434#define NVLIST_PRINTCTL_REPLACE(type, vtype) \435void \436nvlist_prtctlop_##type(nvlist_prtctl_t pctl, \437int (*func)(nvlist_prtctl_t, void *, nvlist_t *, const char *, vtype), \438void *private) \439{ \440CUSTPRTOP(pctl, type) = func; \441CUSTPRTOPARG(pctl, type) = private; \442}443444NVLIST_PRINTCTL_REPLACE(boolean, int)445NVLIST_PRINTCTL_REPLACE(boolean_value, boolean_t)446NVLIST_PRINTCTL_REPLACE(byte, uchar_t)447NVLIST_PRINTCTL_REPLACE(int8, int8_t)448NVLIST_PRINTCTL_REPLACE(uint8, uint8_t)449NVLIST_PRINTCTL_REPLACE(int16, int16_t)450NVLIST_PRINTCTL_REPLACE(uint16, uint16_t)451NVLIST_PRINTCTL_REPLACE(int32, int32_t)452NVLIST_PRINTCTL_REPLACE(uint32, uint32_t)453NVLIST_PRINTCTL_REPLACE(int64, int64_t)454NVLIST_PRINTCTL_REPLACE(uint64, uint64_t)455NVLIST_PRINTCTL_REPLACE(double, double)456NVLIST_PRINTCTL_REPLACE(string, const char *)457NVLIST_PRINTCTL_REPLACE(hrtime, hrtime_t)458NVLIST_PRINTCTL_REPLACE(nvlist, nvlist_t *)459460#define NVLIST_PRINTCTL_AREPLACE(type, vtype) \461void \462nvlist_prtctlop_##type(nvlist_prtctl_t pctl, \463int (*func)(nvlist_prtctl_t, void *, nvlist_t *, const char *, vtype, \464uint_t), void *private) \465{ \466CUSTPRTOP(pctl, type) = func; \467CUSTPRTOPARG(pctl, type) = private; \468}469470NVLIST_PRINTCTL_AREPLACE(boolean_array, boolean_t *)471NVLIST_PRINTCTL_AREPLACE(byte_array, uchar_t *)472NVLIST_PRINTCTL_AREPLACE(int8_array, int8_t *)473NVLIST_PRINTCTL_AREPLACE(uint8_array, uint8_t *)474NVLIST_PRINTCTL_AREPLACE(int16_array, int16_t *)475NVLIST_PRINTCTL_AREPLACE(uint16_array, uint16_t *)476NVLIST_PRINTCTL_AREPLACE(int32_array, int32_t *)477NVLIST_PRINTCTL_AREPLACE(uint32_array, uint32_t *)478NVLIST_PRINTCTL_AREPLACE(int64_array, int64_t *)479NVLIST_PRINTCTL_AREPLACE(uint64_array, uint64_t *)480NVLIST_PRINTCTL_AREPLACE(string_array, const char **)481NVLIST_PRINTCTL_AREPLACE(nvlist_array, nvlist_t **)482483/*484* ======================================================================485* | |486* | Interfaces to manage nvlist_prtctl_t cookies. |487* | |488* ======================================================================489*/490491492static const struct nvlist_printops defprtops =493{494{ nvprint_boolean, NULL },495{ nvprint_boolean_value, NULL },496{ nvprint_byte, NULL },497{ nvprint_int8, NULL },498{ nvprint_uint8, NULL },499{ nvprint_int16, NULL },500{ nvprint_uint16, NULL },501{ nvprint_int32, NULL },502{ nvprint_uint32, NULL },503{ nvprint_int64, NULL },504{ nvprint_uint64, NULL },505{ nvprint_double, NULL },506{ nvprint_string, NULL },507{ nvprint_hrtime, NULL },508{ nvprint_nvlist, NULL },509{ nvaprint_boolean_array, NULL },510{ nvaprint_byte_array, NULL },511{ nvaprint_int8_array, NULL },512{ nvaprint_uint8_array, NULL },513{ nvaprint_int16_array, NULL },514{ nvaprint_uint16_array, NULL },515{ nvaprint_int32_array, NULL },516{ nvaprint_uint32_array, NULL },517{ nvaprint_int64_array, NULL },518{ nvaprint_uint64_array, NULL },519{ nvaprint_string_array, NULL },520{ nvaprint_nvlist_array, NULL },521};522523static void524prtctl_defaults(FILE *fp, struct nvlist_prtctl *pctl,525struct nvlist_printops *ops)526{527pctl->nvprt_fp = fp;528pctl->nvprt_indent_mode = NVLIST_INDENT_TABBED;529pctl->nvprt_indent = 0;530pctl->nvprt_indentinc = 1;531pctl->nvprt_nmfmt = "%s = ";532pctl->nvprt_eomfmt = "\n";533pctl->nvprt_btwnarrfmt = " ";534pctl->nvprt_btwnarrfmt_nl = 0;535536pctl->nvprt_dfltops = (struct nvlist_printops *)&defprtops;537pctl->nvprt_custops = ops;538}539540nvlist_prtctl_t541nvlist_prtctl_alloc(void)542{543struct nvlist_prtctl *pctl;544struct nvlist_printops *ops;545546if ((pctl = malloc(sizeof (*pctl))) == NULL)547return (NULL);548549if ((ops = calloc(1, sizeof (*ops))) == NULL) {550free(pctl);551return (NULL);552}553554prtctl_defaults(stdout, pctl, ops);555556return (pctl);557}558559void560nvlist_prtctl_free(nvlist_prtctl_t pctl)561{562if (pctl != NULL) {563free(pctl->nvprt_custops);564free(pctl);565}566}567568/*569* ======================================================================570* | |571* | Top-level print request interfaces. |572* | |573* ======================================================================574*/575576/*577* nvlist_print - Prints elements in an event buffer578*/579static void580nvlist_print_with_indent(nvlist_t *nvl, nvlist_prtctl_t pctl)581{582FILE *fp = pctl->nvprt_fp;583const char *name;584uint_t nelem;585nvpair_t *nvp;586587if (nvl == NULL)588return;589590indent(pctl, 0);591(void) fprintf(fp, "nvlist version: %d\n", NVL_VERSION(nvl));592593nvp = nvlist_next_nvpair(nvl, NULL);594595while (nvp) {596data_type_t type = nvpair_type(nvp);597598name = nvpair_name(nvp);599nelem = 0;600601switch (type) {602case DATA_TYPE_BOOLEAN: {603RENDER(pctl, boolean, nvl, name, 1);604break;605}606case DATA_TYPE_BOOLEAN_VALUE: {607boolean_t val;608(void) nvpair_value_boolean_value(nvp, &val);609RENDER(pctl, boolean_value, nvl, name, val);610break;611}612case DATA_TYPE_BYTE: {613uchar_t val;614(void) nvpair_value_byte(nvp, &val);615RENDER(pctl, byte, nvl, name, val);616break;617}618case DATA_TYPE_INT8: {619int8_t val;620(void) nvpair_value_int8(nvp, &val);621RENDER(pctl, int8, nvl, name, val);622break;623}624case DATA_TYPE_UINT8: {625uint8_t val;626(void) nvpair_value_uint8(nvp, &val);627RENDER(pctl, uint8, nvl, name, val);628break;629}630case DATA_TYPE_INT16: {631int16_t val;632(void) nvpair_value_int16(nvp, &val);633RENDER(pctl, int16, nvl, name, val);634break;635}636case DATA_TYPE_UINT16: {637uint16_t val;638(void) nvpair_value_uint16(nvp, &val);639RENDER(pctl, uint16, nvl, name, val);640break;641}642case DATA_TYPE_INT32: {643int32_t val;644(void) nvpair_value_int32(nvp, &val);645RENDER(pctl, int32, nvl, name, val);646break;647}648case DATA_TYPE_UINT32: {649uint32_t val;650(void) nvpair_value_uint32(nvp, &val);651RENDER(pctl, uint32, nvl, name, val);652break;653}654case DATA_TYPE_INT64: {655int64_t val;656(void) nvpair_value_int64(nvp, &val);657RENDER(pctl, int64, nvl, name, val);658break;659}660case DATA_TYPE_UINT64: {661uint64_t val;662(void) nvpair_value_uint64(nvp, &val);663RENDER(pctl, uint64, nvl, name, val);664break;665}666case DATA_TYPE_DOUBLE: {667double val;668(void) nvpair_value_double(nvp, &val);669RENDER(pctl, double, nvl, name, val);670break;671}672case DATA_TYPE_STRING: {673const char *val;674(void) nvpair_value_string(nvp, &val);675RENDER(pctl, string, nvl, name, val);676break;677}678case DATA_TYPE_BOOLEAN_ARRAY: {679boolean_t *val;680(void) nvpair_value_boolean_array(nvp, &val, &nelem);681ARENDER(pctl, boolean_array, nvl, name, val, nelem);682break;683}684case DATA_TYPE_BYTE_ARRAY: {685uchar_t *val;686(void) nvpair_value_byte_array(nvp, &val, &nelem);687ARENDER(pctl, byte_array, nvl, name, val, nelem);688break;689}690case DATA_TYPE_INT8_ARRAY: {691int8_t *val;692(void) nvpair_value_int8_array(nvp, &val, &nelem);693ARENDER(pctl, int8_array, nvl, name, val, nelem);694break;695}696case DATA_TYPE_UINT8_ARRAY: {697uint8_t *val;698(void) nvpair_value_uint8_array(nvp, &val, &nelem);699ARENDER(pctl, uint8_array, nvl, name, val, nelem);700break;701}702case DATA_TYPE_INT16_ARRAY: {703int16_t *val;704(void) nvpair_value_int16_array(nvp, &val, &nelem);705ARENDER(pctl, int16_array, nvl, name, val, nelem);706break;707}708case DATA_TYPE_UINT16_ARRAY: {709uint16_t *val;710(void) nvpair_value_uint16_array(nvp, &val, &nelem);711ARENDER(pctl, uint16_array, nvl, name, val, nelem);712break;713}714case DATA_TYPE_INT32_ARRAY: {715int32_t *val;716(void) nvpair_value_int32_array(nvp, &val, &nelem);717ARENDER(pctl, int32_array, nvl, name, val, nelem);718break;719}720case DATA_TYPE_UINT32_ARRAY: {721uint32_t *val;722(void) nvpair_value_uint32_array(nvp, &val, &nelem);723ARENDER(pctl, uint32_array, nvl, name, val, nelem);724break;725}726case DATA_TYPE_INT64_ARRAY: {727int64_t *val;728(void) nvpair_value_int64_array(nvp, &val, &nelem);729ARENDER(pctl, int64_array, nvl, name, val, nelem);730break;731}732case DATA_TYPE_UINT64_ARRAY: {733uint64_t *val;734(void) nvpair_value_uint64_array(nvp, &val, &nelem);735ARENDER(pctl, uint64_array, nvl, name, val, nelem);736break;737}738case DATA_TYPE_STRING_ARRAY: {739const char **val;740(void) nvpair_value_string_array(nvp, &val, &nelem);741ARENDER(pctl, string_array, nvl, name, val, nelem);742break;743}744case DATA_TYPE_HRTIME: {745hrtime_t val;746(void) nvpair_value_hrtime(nvp, &val);747RENDER(pctl, hrtime, nvl, name, val);748break;749}750case DATA_TYPE_NVLIST: {751nvlist_t *val;752(void) nvpair_value_nvlist(nvp, &val);753RENDER(pctl, nvlist, nvl, name, val);754break;755}756case DATA_TYPE_NVLIST_ARRAY: {757nvlist_t **val;758(void) nvpair_value_nvlist_array(nvp, &val, &nelem);759ARENDER(pctl, nvlist_array, nvl, name, val, nelem);760break;761}762default:763(void) fprintf(fp, " unknown data type (%d)", type);764break;765}766nvp = nvlist_next_nvpair(nvl, nvp);767}768}769770void771nvlist_print(FILE *fp, nvlist_t *nvl)772{773struct nvlist_prtctl pc;774775prtctl_defaults(fp, &pc, NULL);776nvlist_print_with_indent(nvl, &pc);777}778779void780nvlist_prt(nvlist_t *nvl, nvlist_prtctl_t pctl)781{782nvlist_print_with_indent(nvl, pctl);783}784785/*786* ======================================================================787* | |788* | Misc private interface. |789* | |790* ======================================================================791*/792793/*794* Determine if string 'value' matches 'nvp' value. The 'value' string is795* converted, depending on the type of 'nvp', prior to match. For numeric796* types, a radix independent sscanf conversion of 'value' is used. If 'nvp'797* is an array type, 'ai' is the index into the array against which we are798* checking for match. If nvp is of DATA_TYPE_STRING*, the caller can pass799* in a regex_t compilation of value in 'value_regex' to trigger regular800* expression string match instead of simple strcmp().801*802* Return 1 on match, 0 on no-match, and -1 on error. If the error is803* related to value syntax error and 'ep' is non-NULL, *ep will point into804* the 'value' string at the location where the error exists.805*806* NOTE: It may be possible to move the non-regex_t version of this into807* common code used by library/kernel/boot.808*/809int810nvpair_value_match_regex(nvpair_t *nvp, int ai,811const char *value, regex_t *value_regex, const char **ep)812{813const char *evalue;814uint_t a_len;815int sr;816817if (ep)818*ep = NULL;819820if ((nvp == NULL) || (value == NULL))821return (-1); /* error fail match - invalid args */822823/* make sure array and index combination make sense */824if ((nvpair_type_is_array(nvp) && (ai < 0)) ||825(!nvpair_type_is_array(nvp) && (ai >= 0)))826return (-1); /* error fail match - bad index */827828/* non-string values should be single 'chunk' */829if ((nvpair_type(nvp) != DATA_TYPE_STRING) &&830(nvpair_type(nvp) != DATA_TYPE_STRING_ARRAY)) {831value += strspn(value, " \t");832evalue = value + strcspn(value, " \t");833if (*evalue) {834if (ep)835*ep = evalue;836return (-1); /* error fail match - syntax */837}838}839840sr = EOF;841switch (nvpair_type(nvp)) {842case DATA_TYPE_STRING: {843const char *val;844845/* check string value for match */846if (nvpair_value_string(nvp, &val) == 0) {847if (value_regex) {848if (regexec(value_regex, val,849(size_t)0, NULL, 0) == 0)850return (1); /* match */851} else {852if (strcmp(value, val) == 0)853return (1); /* match */854}855}856break;857}858case DATA_TYPE_STRING_ARRAY: {859const char **val_array;860861/* check indexed string value of array for match */862if ((nvpair_value_string_array(nvp, &val_array, &a_len) == 0) &&863(ai < a_len)) {864if (value_regex) {865if (regexec(value_regex, val_array[ai],866(size_t)0, NULL, 0) == 0)867return (1);868} else {869if (strcmp(value, val_array[ai]) == 0)870return (1);871}872}873break;874}875case DATA_TYPE_BYTE: {876uchar_t val, val_arg;877878/* scanf uchar_t from value and check for match */879sr = sscanf(value, "%c", &val_arg);880if ((sr == 1) && (nvpair_value_byte(nvp, &val) == 0) &&881(val == val_arg))882return (1);883break;884}885case DATA_TYPE_BYTE_ARRAY: {886uchar_t *val_array, val_arg;887888889/* check indexed value of array for match */890sr = sscanf(value, "%c", &val_arg);891if ((sr == 1) &&892(nvpair_value_byte_array(nvp, &val_array, &a_len) == 0) &&893(ai < a_len) &&894(val_array[ai] == val_arg))895return (1);896break;897}898case DATA_TYPE_INT8: {899int8_t val, val_arg;900901/* scanf int8_t from value and check for match */902sr = sscanf(value, "%"SCNi8, &val_arg);903if ((sr == 1) &&904(nvpair_value_int8(nvp, &val) == 0) &&905(val == val_arg))906return (1);907break;908}909case DATA_TYPE_INT8_ARRAY: {910int8_t *val_array, val_arg;911912/* check indexed value of array for match */913sr = sscanf(value, "%"SCNi8, &val_arg);914if ((sr == 1) &&915(nvpair_value_int8_array(nvp, &val_array, &a_len) == 0) &&916(ai < a_len) &&917(val_array[ai] == val_arg))918return (1);919break;920}921case DATA_TYPE_UINT8: {922uint8_t val, val_arg;923924/* scanf uint8_t from value and check for match */925sr = sscanf(value, "%"SCNi8, (int8_t *)&val_arg);926if ((sr == 1) &&927(nvpair_value_uint8(nvp, &val) == 0) &&928(val == val_arg))929return (1);930break;931}932case DATA_TYPE_UINT8_ARRAY: {933uint8_t *val_array, val_arg;934935/* check indexed value of array for match */936sr = sscanf(value, "%"SCNi8, (int8_t *)&val_arg);937if ((sr == 1) &&938(nvpair_value_uint8_array(nvp, &val_array, &a_len) == 0) &&939(ai < a_len) &&940(val_array[ai] == val_arg))941return (1);942break;943}944case DATA_TYPE_INT16: {945int16_t val, val_arg;946947/* scanf int16_t from value and check for match */948sr = sscanf(value, "%"SCNi16, &val_arg);949if ((sr == 1) &&950(nvpair_value_int16(nvp, &val) == 0) &&951(val == val_arg))952return (1);953break;954}955case DATA_TYPE_INT16_ARRAY: {956int16_t *val_array, val_arg;957958/* check indexed value of array for match */959sr = sscanf(value, "%"SCNi16, &val_arg);960if ((sr == 1) &&961(nvpair_value_int16_array(nvp, &val_array, &a_len) == 0) &&962(ai < a_len) &&963(val_array[ai] == val_arg))964return (1);965break;966}967case DATA_TYPE_UINT16: {968uint16_t val, val_arg;969970/* scanf uint16_t from value and check for match */971sr = sscanf(value, "%"SCNi16, (int16_t *)&val_arg);972if ((sr == 1) &&973(nvpair_value_uint16(nvp, &val) == 0) &&974(val == val_arg))975return (1);976break;977}978case DATA_TYPE_UINT16_ARRAY: {979uint16_t *val_array, val_arg;980981/* check indexed value of array for match */982sr = sscanf(value, "%"SCNi16, (int16_t *)&val_arg);983if ((sr == 1) &&984(nvpair_value_uint16_array(nvp, &val_array, &a_len) == 0) &&985(ai < a_len) &&986(val_array[ai] == val_arg))987return (1);988break;989}990case DATA_TYPE_INT32: {991int32_t val, val_arg;992993/* scanf int32_t from value and check for match */994sr = sscanf(value, "%"SCNi32, &val_arg);995if ((sr == 1) &&996(nvpair_value_int32(nvp, &val) == 0) &&997(val == val_arg))998return (1);999break;1000}1001case DATA_TYPE_INT32_ARRAY: {1002int32_t *val_array, val_arg;10031004/* check indexed value of array for match */1005sr = sscanf(value, "%"SCNi32, &val_arg);1006if ((sr == 1) &&1007(nvpair_value_int32_array(nvp, &val_array, &a_len) == 0) &&1008(ai < a_len) &&1009(val_array[ai] == val_arg))1010return (1);1011break;1012}1013case DATA_TYPE_UINT32: {1014uint32_t val, val_arg;10151016/* scanf uint32_t from value and check for match */1017sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg);1018if ((sr == 1) &&1019(nvpair_value_uint32(nvp, &val) == 0) &&1020(val == val_arg))1021return (1);1022break;1023}1024case DATA_TYPE_UINT32_ARRAY: {1025uint32_t *val_array, val_arg;10261027/* check indexed value of array for match */1028sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg);1029if ((sr == 1) &&1030(nvpair_value_uint32_array(nvp, &val_array, &a_len) == 0) &&1031(ai < a_len) &&1032(val_array[ai] == val_arg))1033return (1);1034break;1035}1036case DATA_TYPE_INT64: {1037int64_t val, val_arg;10381039/* scanf int64_t from value and check for match */1040sr = sscanf(value, "%"SCNi64, &val_arg);1041if ((sr == 1) &&1042(nvpair_value_int64(nvp, &val) == 0) &&1043(val == val_arg))1044return (1);1045break;1046}1047case DATA_TYPE_INT64_ARRAY: {1048int64_t *val_array, val_arg;10491050/* check indexed value of array for match */1051sr = sscanf(value, "%"SCNi64, &val_arg);1052if ((sr == 1) &&1053(nvpair_value_int64_array(nvp, &val_array, &a_len) == 0) &&1054(ai < a_len) &&1055(val_array[ai] == val_arg))1056return (1);1057break;1058}1059case DATA_TYPE_UINT64: {1060uint64_t val_arg, val;10611062/* scanf uint64_t from value and check for match */1063sr = sscanf(value, "%"SCNi64, (int64_t *)&val_arg);1064if ((sr == 1) &&1065(nvpair_value_uint64(nvp, &val) == 0) &&1066(val == val_arg))1067return (1);1068break;1069}1070case DATA_TYPE_UINT64_ARRAY: {1071uint64_t *val_array, val_arg;10721073/* check indexed value of array for match */1074sr = sscanf(value, "%"SCNi64, (int64_t *)&val_arg);1075if ((sr == 1) &&1076(nvpair_value_uint64_array(nvp, &val_array, &a_len) == 0) &&1077(ai < a_len) &&1078(val_array[ai] == val_arg))1079return (1);1080break;1081}1082case DATA_TYPE_BOOLEAN_VALUE: {1083int32_t val_arg;1084boolean_t val;10851086/* scanf boolean_t from value and check for match */1087sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg);1088if ((sr == 1) &&1089(nvpair_value_boolean_value(nvp, &val) == 0) &&1090(val == val_arg))1091return (1);1092break;1093}1094case DATA_TYPE_BOOLEAN_ARRAY: {1095boolean_t *val_array;1096int32_t val_arg;10971098/* check indexed value of array for match */1099sr = sscanf(value, "%"SCNi32, (int32_t *)&val_arg);1100if ((sr == 1) &&1101(nvpair_value_boolean_array(nvp,1102&val_array, &a_len) == 0) &&1103(ai < a_len) &&1104(val_array[ai] == val_arg))1105return (1);1106break;1107}1108case DATA_TYPE_HRTIME:1109case DATA_TYPE_NVLIST:1110case DATA_TYPE_NVLIST_ARRAY:1111case DATA_TYPE_BOOLEAN:1112case DATA_TYPE_DOUBLE:1113case DATA_TYPE_UNKNOWN:1114default:1115/*1116* unknown/unsupported data type1117*/1118return (-1); /* error fail match */1119}11201121/*1122* check to see if sscanf failed conversion, return approximate1123* pointer to problem1124*/1125if (sr != 1) {1126if (ep)1127*ep = value;1128return (-1); /* error fail match - syntax */1129}11301131return (0); /* fail match */1132}11331134int1135nvpair_value_match(nvpair_t *nvp, int ai, const char *value, const char **ep)1136{1137return (nvpair_value_match_regex(nvp, ai, value, NULL, ep));1138}11391140/*1141* Similar to nvlist_print() but handles arrays slightly differently.1142*/1143void1144dump_nvlist(nvlist_t *list, int indent)1145{1146int len;1147char *buf;11481149len = nvlist_snprintf(NULL, 0, list, indent);1150len++; /* Add null terminator */11511152buf = malloc(len);1153if (buf == NULL)1154return;11551156(void) nvlist_snprintf(buf, len, list, indent);11571158/*1159* fputs does not have limitations on the size of the buffer being1160* printed (unlike printf).1161*/1162fputs(buf, stdout);11631164free(buf);1165}116611671168