diff options
Diffstat (limited to 'usr/src/lib/libnvpair/nvpair_json.c')
| -rw-r--r-- | usr/src/lib/libnvpair/nvpair_json.c | 284 | 
1 files changed, 193 insertions, 91 deletions
| diff --git a/usr/src/lib/libnvpair/nvpair_json.c b/usr/src/lib/libnvpair/nvpair_json.c index 5a317f5f94..7ebd1be7a0 100644 --- a/usr/src/lib/libnvpair/nvpair_json.c +++ b/usr/src/lib/libnvpair/nvpair_json.c @@ -17,16 +17,71 @@  #include <strings.h>  #include <wchar.h>  #include <sys/debug.h> +#include <stdarg.h> +#include <assert.h>  #include "libnvpair.h" -#define	FPRINTF(fp, ...)				\ +#define	FPRINTF(bufp, blen, offp, ...)			\  	do {						\ -		if (fprintf(fp, __VA_ARGS__) < 0)	\ +		if (nvlist_rasnprintf(bufp, blen, offp,	\ +		    __VA_ARGS__) < 0)			\  			return (-1);			\  	} while (0)  /* + * A realloc-aware snprintf/asprintf like function. + */ +/*PRINTFLIKE4*/ +static int +nvlist_rasnprintf(char **bufp, size_t *blen, off_t *boff, char *input, ...) +{ +	int ret; +	va_list ap; +	size_t size; +	char *b; + +	if (*bufp == NULL) { +		assert(*blen == 0); +		assert(*boff == 0); +		/* Pick a reasonable starting point, let's say 1k */ +		*blen = 1024; +		*bufp = malloc(*blen); +		if (*bufp == NULL) +			return (-1); +	} + +	size = *blen - *boff; +	va_start(ap, input); +	/* E_SEC_PRINTF_VAR_FMT */ +	ret = vsnprintf(*bufp + *boff, size, input, ap); +	va_end(ap); +	if (ret < 0) +		return (-1); + +	if (ret >= size) { +		size_t asize = *blen; +		while (ret + *boff >= asize) +			asize += 1024; +		if ((b = realloc(*bufp, asize)) == NULL) +			return (-1); +		*bufp = b; +		*blen = asize; +		size = *blen - *boff; +		va_start(ap, input); +		/* E_SEC_PRINTF_VAR_FMT */ +		ret = vsnprintf(*bufp + *boff, size, input, ap); +		va_end(ap); +		if (ret < 0) +			return (-1); +		assert(ret < size); +	} +	*boff += ret; + +	return (0); +} + +/*   * When formatting a string for JSON output we must escape certain characters,   * as described in RFC4627.  This applies to both member names and   * DATA_TYPE_STRING values. @@ -43,7 +98,8 @@   * representable Unicode characters included in their escaped numeric form.   */  static int -nvlist_print_json_string(FILE *fp, const char *input) +nvlist_print_json_string(const char *input, char **bufp, size_t *blen, +    off_t *offp)  {  	mbstate_t mbr;  	wchar_t c; @@ -51,29 +107,29 @@ nvlist_print_json_string(FILE *fp, const char *input)  	bzero(&mbr, sizeof (mbr)); -	FPRINTF(fp, "\""); +	FPRINTF(bufp, blen, offp, "\"");  	while ((sz = mbrtowc(&c, input, MB_CUR_MAX, &mbr)) > 0) {  		switch (c) {  		case '"': -			FPRINTF(fp, "\\\""); +			FPRINTF(bufp, blen, offp, "\\\"");  			break;  		case '\n': -			FPRINTF(fp, "\\n"); +			FPRINTF(bufp, blen, offp, "\\n");  			break;  		case '\r': -			FPRINTF(fp, "\\r"); +			FPRINTF(bufp, blen, offp, "\\r");  			break;  		case '\\': -			FPRINTF(fp, "\\\\"); +			FPRINTF(bufp, blen, offp, "\\\\");  			break;  		case '\f': -			FPRINTF(fp, "\\f"); +			FPRINTF(bufp, blen, offp, "\\f");  			break;  		case '\t': -			FPRINTF(fp, "\\t"); +			FPRINTF(bufp, blen, offp, "\\t");  			break;  		case '\b': -			FPRINTF(fp, "\\b"); +			FPRINTF(bufp, blen, offp, "\\b");  			break;  		default:  			if ((c >= 0x00 && c <= 0x1f) || @@ -83,13 +139,15 @@ nvlist_print_json_string(FILE *fp, const char *input)  				 * characters in the Basic Multilingual Plane  				 * as JSON-escaped multibyte characters.  				 */ -				FPRINTF(fp, "\\u%04x", (int)(0xffff & c)); +				FPRINTF(bufp, blen, offp, "\\u%04x", +				    (int)(0xffff & c));  			} else if (c >= 0x20 && c <= 0x7f) {  				/*  				 * Render other 7-bit ASCII characters directly  				 * and drop other, unrepresentable characters.  				 */ -				FPRINTF(fp, "%c", (int)(0xff & c)); +				FPRINTF(bufp, blen, offp, "%c", +				    (int)(0xff & c));  			}  			break;  		} @@ -104,98 +162,103 @@ nvlist_print_json_string(FILE *fp, const char *input)  		return (-1);  	} -	FPRINTF(fp, "\""); +	FPRINTF(bufp, blen, offp, "\"");  	return (0);  } -/* - * Dump a JSON-formatted representation of an nvlist to the provided FILE *. - * This routine does not output any new-lines or additional whitespace other - * than that contained in strings, nor does it call fflush(3C). - */ -int -nvlist_print_json(FILE *fp, nvlist_t *nvl) +static int +nvlist_do_json(nvlist_t *nvl, char **bufp, size_t *blen, off_t *offp)  {  	nvpair_t *curr;  	boolean_t first = B_TRUE; -	FPRINTF(fp, "{"); +	FPRINTF(bufp, blen, offp, "{");  	for (curr = nvlist_next_nvpair(nvl, NULL); curr;  	    curr = nvlist_next_nvpair(nvl, curr)) {  		data_type_t type = nvpair_type(curr);  		if (!first) -			FPRINTF(fp, ","); +			FPRINTF(bufp, blen, offp, ",");  		else  			first = B_FALSE; -		if (nvlist_print_json_string(fp, nvpair_name(curr)) == -1) +		if (nvlist_print_json_string(nvpair_name(curr), bufp, blen, +		    offp) == -1)  			return (-1); -		FPRINTF(fp, ":"); +		FPRINTF(bufp, blen, offp, ":");  		switch (type) {  		case DATA_TYPE_STRING: {  			char *string = fnvpair_value_string(curr); -			if (nvlist_print_json_string(fp, string) == -1) +			if (nvlist_print_json_string(string, bufp, blen, +			    offp) == -1)  				return (-1);  			break;  		}  		case DATA_TYPE_BOOLEAN: { -			FPRINTF(fp, "true"); +			FPRINTF(bufp, blen, offp, "true");  			break;  		}  		case DATA_TYPE_BOOLEAN_VALUE: { -			FPRINTF(fp, "%s", fnvpair_value_boolean_value(curr) == -			    B_TRUE ? "true" : "false"); +			FPRINTF(bufp, blen, offp, "%s", +			    fnvpair_value_boolean_value(curr) == B_TRUE ? +			    "true" : "false");  			break;  		}  		case DATA_TYPE_BYTE: { -			FPRINTF(fp, "%hhu", fnvpair_value_byte(curr)); +			FPRINTF(bufp, blen, offp, "%hhu", +			    fnvpair_value_byte(curr));  			break;  		}  		case DATA_TYPE_INT8: { -			FPRINTF(fp, "%hhd", fnvpair_value_int8(curr)); +			FPRINTF(bufp, blen, offp, "%hhd", +			    fnvpair_value_int8(curr));  			break;  		}  		case DATA_TYPE_UINT8: { -			FPRINTF(fp, "%hhu", fnvpair_value_uint8_t(curr)); +			FPRINTF(bufp, blen, offp, "%hhu", +			    fnvpair_value_uint8_t(curr));  			break;  		}  		case DATA_TYPE_INT16: { -			FPRINTF(fp, "%hd", fnvpair_value_int16(curr)); +			FPRINTF(bufp, blen, offp, "%hd", +			    fnvpair_value_int16(curr));  			break;  		}  		case DATA_TYPE_UINT16: { -			FPRINTF(fp, "%hu", fnvpair_value_uint16(curr)); +			FPRINTF(bufp, blen, offp, "%hu", +			    fnvpair_value_uint16(curr));  			break;  		}  		case DATA_TYPE_INT32: { -			FPRINTF(fp, "%d", fnvpair_value_int32(curr)); +			FPRINTF(bufp, blen, offp, "%d", +			    fnvpair_value_int32(curr));  			break;  		}  		case DATA_TYPE_UINT32: { -			FPRINTF(fp, "%u", fnvpair_value_uint32(curr)); +			FPRINTF(bufp, blen, offp, "%u", +			    fnvpair_value_uint32(curr));  			break;  		}  		case DATA_TYPE_INT64: { -			FPRINTF(fp, "%lld", +			FPRINTF(bufp, blen, offp, "%lld",  			    (long long)fnvpair_value_int64(curr));  			break;  		}  		case DATA_TYPE_UINT64: { -			FPRINTF(fp, "%llu", +			FPRINTF(bufp, blen, offp, "%llu",  			    (unsigned long long)fnvpair_value_uint64(curr));  			break;  		} @@ -203,20 +266,21 @@ nvlist_print_json(FILE *fp, nvlist_t *nvl)  		case DATA_TYPE_HRTIME: {  			hrtime_t val;  			VERIFY0(nvpair_value_hrtime(curr, &val)); -			FPRINTF(fp, "%llu", (unsigned long long)val); +			FPRINTF(bufp, blen, offp, "%llu", +			    (unsigned long long)val);  			break;  		}  		case DATA_TYPE_DOUBLE: {  			double val;  			VERIFY0(nvpair_value_double(curr, &val)); -			FPRINTF(fp, "%f", val); +			FPRINTF(bufp, blen, offp, "%f", val);  			break;  		}  		case DATA_TYPE_NVLIST: { -			if (nvlist_print_json(fp, -			    fnvpair_value_nvlist(curr)) == -1) +			if (nvlist_do_json(fnvpair_value_nvlist(curr), bufp, +			    blen, offp) == -1)  				return (-1);  			break;  		} @@ -225,14 +289,15 @@ nvlist_print_json(FILE *fp, nvlist_t *nvl)  			char **val;  			uint_t valsz, i;  			VERIFY0(nvpair_value_string_array(curr, &val, &valsz)); -			FPRINTF(fp, "["); +			FPRINTF(bufp, blen, offp, "[");  			for (i = 0; i < valsz; i++) {  				if (i > 0) -					FPRINTF(fp, ","); -				if (nvlist_print_json_string(fp, val[i]) == -1) +					FPRINTF(bufp, blen, offp, ","); +				if (nvlist_print_json_string(val[i], bufp, +				    blen, offp) == -1)  					return (-1);  			} -			FPRINTF(fp, "]"); +			FPRINTF(bufp, blen, offp, "]");  			break;  		} @@ -240,14 +305,15 @@ nvlist_print_json(FILE *fp, nvlist_t *nvl)  			nvlist_t **val;  			uint_t valsz, i;  			VERIFY0(nvpair_value_nvlist_array(curr, &val, &valsz)); -			FPRINTF(fp, "["); +			FPRINTF(bufp, blen, offp, "[");  			for (i = 0; i < valsz; i++) {  				if (i > 0) -					FPRINTF(fp, ","); -				if (nvlist_print_json(fp, val[i]) == -1) +					FPRINTF(bufp, blen, offp, ","); +				if (nvlist_do_json(val[i], bufp, blen, +				    offp) == -1)  					return (-1);  			} -			FPRINTF(fp, "]"); +			FPRINTF(bufp, blen, offp, "]");  			break;  		} @@ -255,14 +321,14 @@ nvlist_print_json(FILE *fp, nvlist_t *nvl)  			boolean_t *val;  			uint_t valsz, i;  			VERIFY0(nvpair_value_boolean_array(curr, &val, &valsz)); -			FPRINTF(fp, "["); +			FPRINTF(bufp, blen, offp, "[");  			for (i = 0; i < valsz; i++) {  				if (i > 0) -					FPRINTF(fp, ","); -				FPRINTF(fp, val[i] == B_TRUE ? +					FPRINTF(bufp, blen, offp, ","); +				FPRINTF(bufp, blen, offp, val[i] == B_TRUE ?  				    "true" : "false");  			} -			FPRINTF(fp, "]"); +			FPRINTF(bufp, blen, offp, "]");  			break;  		} @@ -270,13 +336,13 @@ nvlist_print_json(FILE *fp, nvlist_t *nvl)  			uchar_t *val;  			uint_t valsz, i;  			VERIFY0(nvpair_value_byte_array(curr, &val, &valsz)); -			FPRINTF(fp, "["); +			FPRINTF(bufp, blen, offp, "[");  			for (i = 0; i < valsz; i++) {  				if (i > 0) -					FPRINTF(fp, ","); -				FPRINTF(fp, "%hhu", val[i]); +					FPRINTF(bufp, blen, offp, ","); +				FPRINTF(bufp, blen, offp, "%hhu", val[i]);  			} -			FPRINTF(fp, "]"); +			FPRINTF(bufp, blen, offp, "]");  			break;  		} @@ -284,13 +350,13 @@ nvlist_print_json(FILE *fp, nvlist_t *nvl)  			uint8_t *val;  			uint_t valsz, i;  			VERIFY0(nvpair_value_uint8_array(curr, &val, &valsz)); -			FPRINTF(fp, "["); +			FPRINTF(bufp, blen, offp, "[");  			for (i = 0; i < valsz; i++) {  				if (i > 0) -					FPRINTF(fp, ","); -				FPRINTF(fp, "%hhu", val[i]); +					FPRINTF(bufp, blen, offp, ","); +				FPRINTF(bufp, blen, offp, "%hhu", val[i]);  			} -			FPRINTF(fp, "]"); +			FPRINTF(bufp, blen, offp, "]");  			break;  		} @@ -298,13 +364,13 @@ nvlist_print_json(FILE *fp, nvlist_t *nvl)  			int8_t *val;  			uint_t valsz, i;  			VERIFY0(nvpair_value_int8_array(curr, &val, &valsz)); -			FPRINTF(fp, "["); +			FPRINTF(bufp, blen, offp, "[");  			for (i = 0; i < valsz; i++) {  				if (i > 0) -					FPRINTF(fp, ","); -				FPRINTF(fp, "%hd", val[i]); +					FPRINTF(bufp, blen, offp, ","); +				FPRINTF(bufp, blen, offp, "%hd", val[i]);  			} -			FPRINTF(fp, "]"); +			FPRINTF(bufp, blen, offp, "]");  			break;  		} @@ -312,13 +378,13 @@ nvlist_print_json(FILE *fp, nvlist_t *nvl)  			uint16_t *val;  			uint_t valsz, i;  			VERIFY0(nvpair_value_uint16_array(curr, &val, &valsz)); -			FPRINTF(fp, "["); +			FPRINTF(bufp, blen, offp, "[");  			for (i = 0; i < valsz; i++) {  				if (i > 0) -					FPRINTF(fp, ","); -				FPRINTF(fp, "%hu", val[i]); +					FPRINTF(bufp, blen, offp, ","); +				FPRINTF(bufp, blen, offp, "%hu", val[i]);  			} -			FPRINTF(fp, "]"); +			FPRINTF(bufp, blen, offp, "]");  			break;  		} @@ -326,13 +392,13 @@ nvlist_print_json(FILE *fp, nvlist_t *nvl)  			int16_t *val;  			uint_t valsz, i;  			VERIFY0(nvpair_value_int16_array(curr, &val, &valsz)); -			FPRINTF(fp, "["); +			FPRINTF(bufp, blen, offp, "[");  			for (i = 0; i < valsz; i++) {  				if (i > 0) -					FPRINTF(fp, ","); -				FPRINTF(fp, "%hd", val[i]); +					FPRINTF(bufp, blen, offp, ","); +				FPRINTF(bufp, blen, offp, "%hd", val[i]);  			} -			FPRINTF(fp, "]"); +			FPRINTF(bufp, blen, offp, "]");  			break;  		} @@ -340,13 +406,13 @@ nvlist_print_json(FILE *fp, nvlist_t *nvl)  			uint32_t *val;  			uint_t valsz, i;  			VERIFY0(nvpair_value_uint32_array(curr, &val, &valsz)); -			FPRINTF(fp, "["); +			FPRINTF(bufp, blen, offp, "[");  			for (i = 0; i < valsz; i++) {  				if (i > 0) -					FPRINTF(fp, ","); -				FPRINTF(fp, "%u", val[i]); +					FPRINTF(bufp, blen, offp, ","); +				FPRINTF(bufp, blen, offp, "%u", val[i]);  			} -			FPRINTF(fp, "]"); +			FPRINTF(bufp, blen, offp, "]");  			break;  		} @@ -354,13 +420,13 @@ nvlist_print_json(FILE *fp, nvlist_t *nvl)  			int32_t *val;  			uint_t valsz, i;  			VERIFY0(nvpair_value_int32_array(curr, &val, &valsz)); -			FPRINTF(fp, "["); +			FPRINTF(bufp, blen, offp, "[");  			for (i = 0; i < valsz; i++) {  				if (i > 0) -					FPRINTF(fp, ","); -				FPRINTF(fp, "%d", val[i]); +					FPRINTF(bufp, blen, offp, ","); +				FPRINTF(bufp, blen, offp, "%d", val[i]);  			} -			FPRINTF(fp, "]"); +			FPRINTF(bufp, blen, offp, "]");  			break;  		} @@ -368,14 +434,14 @@ nvlist_print_json(FILE *fp, nvlist_t *nvl)  			uint64_t *val;  			uint_t valsz, i;  			VERIFY0(nvpair_value_uint64_array(curr, &val, &valsz)); -			FPRINTF(fp, "["); +			FPRINTF(bufp, blen, offp, "[");  			for (i = 0; i < valsz; i++) {  				if (i > 0) -					FPRINTF(fp, ","); -				FPRINTF(fp, "%llu", +					FPRINTF(bufp, blen, offp, ","); +				FPRINTF(bufp, blen, offp, "%llu",  				    (unsigned long long)val[i]);  			} -			FPRINTF(fp, "]"); +			FPRINTF(bufp, blen, offp, "]");  			break;  		} @@ -383,13 +449,14 @@ nvlist_print_json(FILE *fp, nvlist_t *nvl)  			int64_t *val;  			uint_t valsz, i;  			VERIFY0(nvpair_value_int64_array(curr, &val, &valsz)); -			FPRINTF(fp, "["); +			FPRINTF(bufp, blen, offp, "[");  			for (i = 0; i < valsz; i++) {  				if (i > 0) -					FPRINTF(fp, ","); -				FPRINTF(fp, "%lld", (long long)val[i]); +					FPRINTF(bufp, blen, offp, ","); +				FPRINTF(bufp, blen, offp, "%lld", +				    (long long)val[i]);  			} -			FPRINTF(fp, "]"); +			FPRINTF(bufp, blen, offp, "]");  			break;  		} @@ -398,6 +465,41 @@ nvlist_print_json(FILE *fp, nvlist_t *nvl)  		}  	} -	FPRINTF(fp, "}"); +	FPRINTF(bufp, blen, offp, "}");  	return (0);  } + +int +nvlist_dump_json(nvlist_t *nvl, char **bufp) +{ +	off_t off = 0; +	size_t l = 0; + +	*bufp = NULL; +	return (nvlist_do_json(nvl, bufp, &l, &off)); +} + +/* ARGSUSED */ +void +nvlist_dump_json_free(nvlist_t *nvl, char *buf) +{ +	free(buf); +} + +/* + * Dump a JSON-formatted representation of an nvlist to the provided FILE *. + * This routine does not output any new-lines or additional whitespace other + * than that contained in strings, nor does it call fflush(3C). + */ +int +nvlist_print_json(FILE *fp, nvlist_t *nvl) +{ +	int ret; +	char *buf; + +	if ((ret = nvlist_dump_json(nvl, &buf)) < 0) +		return (ret); +	ret = fprintf(fp, "%s", buf); +	nvlist_dump_json_free(nvl, buf); +	return (ret); +} | 
