summaryrefslogtreecommitdiff
path: root/usr/src/lib/libnvpair
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libnvpair')
-rw-r--r--usr/src/lib/libnvpair/libnvpair.h2
-rw-r--r--usr/src/lib/libnvpair/mapfile-vers2
-rw-r--r--usr/src/lib/libnvpair/nvpair_json.c284
3 files changed, 197 insertions, 91 deletions
diff --git a/usr/src/lib/libnvpair/libnvpair.h b/usr/src/lib/libnvpair/libnvpair.h
index b05669e506..197ec37f46 100644
--- a/usr/src/lib/libnvpair/libnvpair.h
+++ b/usr/src/lib/libnvpair/libnvpair.h
@@ -49,6 +49,8 @@ extern int nvpair_value_match_regex(nvpair_t *, int, char *, regex_t *,
extern void nvlist_print(FILE *, nvlist_t *);
extern int nvlist_print_json(FILE *, nvlist_t *);
extern void dump_nvlist(nvlist_t *, int);
+extern int nvlist_dump_json(nvlist_t *, char **);
+extern void nvlist_dump_json_free(nvlist_t *, char *);
/*
* Private nvlist printing interface that allows the caller some control
diff --git a/usr/src/lib/libnvpair/mapfile-vers b/usr/src/lib/libnvpair/mapfile-vers
index 0403964e05..9b1f048f75 100644
--- a/usr/src/lib/libnvpair/mapfile-vers
+++ b/usr/src/lib/libnvpair/mapfile-vers
@@ -244,6 +244,8 @@ SYMBOL_VERSION SUNWprivate_1.1 {
dump_nvlist;
nvlist_add_hrtime;
nvlist_lookup_hrtime;
+ nvlist_dump_json;
+ nvlist_dump_json_free;
nvlist_print;
nvlist_print_json;
nvlist_prt;
diff --git a/usr/src/lib/libnvpair/nvpair_json.c b/usr/src/lib/libnvpair/nvpair_json.c
index 6aa3e9c01c..3205d229ab 100644
--- a/usr/src/lib/libnvpair/nvpair_json.c
+++ b/usr/src/lib/libnvpair/nvpair_json.c
@@ -18,16 +18,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.
@@ -44,7 +99,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;
@@ -52,29 +108,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) ||
@@ -84,13 +140,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;
}
@@ -105,98 +163,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;
}
@@ -204,20 +267,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;
}
@@ -226,14 +290,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;
}
@@ -241,14 +306,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;
}
@@ -256,14 +322,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;
}
@@ -271,13 +337,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;
}
@@ -285,13 +351,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;
}
@@ -299,13 +365,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;
}
@@ -313,13 +379,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;
}
@@ -327,13 +393,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;
}
@@ -341,13 +407,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;
}
@@ -355,13 +421,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;
}
@@ -369,14 +435,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;
}
@@ -384,13 +450,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;
}
@@ -401,6 +468,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);
+}