summaryrefslogtreecommitdiff
path: root/usr/src/lib/libnvpair/nvpair_json.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libnvpair/nvpair_json.c')
-rw-r--r--usr/src/lib/libnvpair/nvpair_json.c366
1 files changed, 238 insertions, 128 deletions
diff --git a/usr/src/lib/libnvpair/nvpair_json.c b/usr/src/lib/libnvpair/nvpair_json.c
index 7ebd1be7a0..559010bd51 100644
--- a/usr/src/lib/libnvpair/nvpair_json.c
+++ b/usr/src/lib/libnvpair/nvpair_json.c
@@ -9,7 +9,7 @@
* http://www.illumos.org/license/CDDL.
*/
/*
- * Copyright (c) 2014, Joyent, Inc.
+ * Copyright (c) 2017, Joyent, Inc.
*/
#include <stdio.h>
@@ -29,6 +29,35 @@
return (-1); \
} while (0)
+#define FPRINTF_JSON_ARRAY(val, valsz, func, level, indent, bufp, \
+ blen, offp) \
+ do { \
+ int i, j; \
+ FPRINTF(bufp, blen, offp, "["); \
+ for (i = 0; i < valsz; i++) { \
+ if (i > 0) { \
+ FPRINTF(bufp, blen, offp, ","); \
+ } \
+ if (indent != NULL) { \
+ FPRINTF(bufp, blen, offp, "\n"); \
+ for (j = 0; j <= level + 1; j++) \
+ FPRINTF(bufp, blen, offp, \
+ "%s", indent); \
+ } \
+ if (func(val[i], bufp, blen, offp) == -1) { \
+ return (-1); \
+ } \
+ } \
+ if (indent != NULL) { \
+ FPRINTF(bufp, blen, offp, "\n"); \
+ for (j = 0; j <= level; j++) { \
+ FPRINTF(bufp, blen, offp, "%s", \
+ indent); \
+ } \
+ } \
+ FPRINTF(bufp, blen, offp, "]"); \
+ } while (0)
+
/*
* A realloc-aware snprintf/asprintf like function.
*/
@@ -167,7 +196,93 @@ nvlist_print_json_string(const char *input, char **bufp, size_t *blen,
}
static int
-nvlist_do_json(nvlist_t *nvl, char **bufp, size_t *blen, off_t *offp)
+nvlist_print_json_boolean_value(boolean_t b, char **bufp, size_t *blen,
+ off_t *offp)
+{
+ FPRINTF(bufp, blen, offp, "%s", b == B_TRUE ? "true" : "false");
+ return (0);
+}
+
+static int
+nvlist_print_json_byte(char byte, char **bufp, size_t *blen, off_t *offp)
+{
+ FPRINTF(bufp, blen, offp, "%hhu", byte);
+ return (0);
+}
+
+static int
+nvlist_print_json_int8(int8_t num, char **bufp, size_t *blen, off_t *offp)
+{
+ FPRINTF(bufp, blen, offp, "%hhd", num);
+ return (0);
+}
+
+static int
+nvlist_print_json_uint8(uint8_t num, char **bufp, size_t *blen, off_t *offp)
+{
+ FPRINTF(bufp, blen, offp, "%hhu", num);
+ return (0);
+}
+
+static int
+nvlist_print_json_int16(int16_t num, char **bufp, size_t *blen, off_t *offp)
+{
+ FPRINTF(bufp, blen, offp, "%hd", num);
+ return (0);
+}
+
+static int
+nvlist_print_json_uint16(uint16_t num, char **bufp, size_t *blen, off_t *offp)
+{
+ FPRINTF(bufp, blen, offp, "%hu", num);
+ return (0);
+}
+
+static int
+nvlist_print_json_int32(int32_t num, char **bufp, size_t *blen, off_t *offp)
+{
+ FPRINTF(bufp, blen, offp, "%d", num);
+ return (0);
+}
+
+static int
+nvlist_print_json_uint32(uint32_t num, char **bufp, size_t *blen, off_t *offp)
+{
+ FPRINTF(bufp, blen, offp, "%u", num);
+ return (0);
+}
+
+static int
+nvlist_print_json_int64(int64_t num, char **bufp, size_t *blen, off_t *offp)
+{
+ FPRINTF(bufp, blen, offp, "%lld", (long long)num);
+ return (0);
+}
+
+static int
+nvlist_print_json_uint64(uint64_t num, char **bufp, size_t *blen, off_t *offp)
+{
+ FPRINTF(bufp, blen, offp, "%llu", (unsigned long long)num);
+ return (0);
+}
+
+static int
+nvlist_print_json_hrtime(hrtime_t val, char **bufp, size_t *blen, off_t *offp)
+{
+ FPRINTF(bufp, blen, offp, "%llu", (unsigned long long)val);
+ return (0);
+}
+
+static int
+nvlist_print_json_double(double num, char **bufp, size_t *blen, off_t *offp)
+{
+ FPRINTF(bufp, blen, offp, "%f", num);
+ return (0);
+}
+
+static int
+nvlist_do_json(nvlist_t *nvl, char **bufp, size_t *blen, off_t *offp,
+ char *indent, int level)
{
nvpair_t *curr;
boolean_t first = B_TRUE;
@@ -176,6 +291,7 @@ nvlist_do_json(nvlist_t *nvl, char **bufp, size_t *blen, off_t *offp)
for (curr = nvlist_next_nvpair(nvl, NULL); curr;
curr = nvlist_next_nvpair(nvl, curr)) {
+ int i;
data_type_t type = nvpair_type(curr);
if (!first)
@@ -183,121 +299,138 @@ nvlist_do_json(nvlist_t *nvl, char **bufp, size_t *blen, off_t *offp)
else
first = B_FALSE;
+ if (indent != NULL) {
+ FPRINTF(bufp, blen, offp, "\n");
+ for (i = 0; i <= level; i++) {
+ FPRINTF(bufp, blen, offp, "%s", indent);
+ }
+ }
+
if (nvlist_print_json_string(nvpair_name(curr), bufp, blen,
offp) == -1)
return (-1);
- FPRINTF(bufp, blen, offp, ":");
+ FPRINTF(bufp, blen, offp, indent == NULL ? ":" : ": ");
switch (type) {
case DATA_TYPE_STRING: {
- char *string = fnvpair_value_string(curr);
- if (nvlist_print_json_string(string, bufp, blen,
- offp) == -1)
+ if (nvlist_print_json_string(
+ fnvpair_value_string(curr), bufp, blen, offp) != 0)
return (-1);
break;
}
case DATA_TYPE_BOOLEAN: {
- FPRINTF(bufp, blen, offp, "true");
+ if (nvlist_print_json_boolean_value(B_TRUE, bufp, blen,
+ offp) != 0)
+ return (-1);
break;
}
case DATA_TYPE_BOOLEAN_VALUE: {
- FPRINTF(bufp, blen, offp, "%s",
- fnvpair_value_boolean_value(curr) == B_TRUE ?
- "true" : "false");
+ if (nvlist_print_json_boolean_value(
+ fnvpair_value_boolean_value(curr), bufp, blen,
+ offp) != 0)
+ return (-1);
break;
}
case DATA_TYPE_BYTE: {
- FPRINTF(bufp, blen, offp, "%hhu",
- fnvpair_value_byte(curr));
+ if (nvlist_print_json_byte(
+ fnvpair_value_byte(curr), bufp, blen, offp) != 0)
+ return (-1);
break;
}
case DATA_TYPE_INT8: {
- FPRINTF(bufp, blen, offp, "%hhd",
- fnvpair_value_int8(curr));
+ if (nvlist_print_json_int8(
+ fnvpair_value_int8(curr), bufp, blen, offp) != 0)
+ return (-1);
break;
}
case DATA_TYPE_UINT8: {
- FPRINTF(bufp, blen, offp, "%hhu",
- fnvpair_value_uint8_t(curr));
+ if (nvlist_print_json_uint8(
+ fnvpair_value_uint8_t(curr), bufp, blen,
+ offp) != 0)
+ return (-1);
break;
}
case DATA_TYPE_INT16: {
- FPRINTF(bufp, blen, offp, "%hd",
- fnvpair_value_int16(curr));
+ if (nvlist_print_json_int16(
+ fnvpair_value_int16(curr), bufp, blen, offp) != 0)
+ return (-1);
break;
}
case DATA_TYPE_UINT16: {
- FPRINTF(bufp, blen, offp, "%hu",
- fnvpair_value_uint16(curr));
+ if (nvlist_print_json_uint16(
+ fnvpair_value_uint16(curr), bufp, blen, offp) != 0)
+ return (-1);
break;
}
case DATA_TYPE_INT32: {
- FPRINTF(bufp, blen, offp, "%d",
- fnvpair_value_int32(curr));
+ if (nvlist_print_json_int32(
+ fnvpair_value_int32(curr), bufp, blen, offp) != 0)
+ return (-1);
break;
}
case DATA_TYPE_UINT32: {
- FPRINTF(bufp, blen, offp, "%u",
- fnvpair_value_uint32(curr));
+ if (nvlist_print_json_uint32(
+ fnvpair_value_uint32(curr), bufp, blen, offp) != 0)
+ return (-1);
break;
}
case DATA_TYPE_INT64: {
- FPRINTF(bufp, blen, offp, "%lld",
- (long long)fnvpair_value_int64(curr));
+ if (nvlist_print_json_int64(
+ fnvpair_value_int64(curr), bufp, blen, offp) != 0)
+ return (-1);
break;
}
case DATA_TYPE_UINT64: {
- FPRINTF(bufp, blen, offp, "%llu",
- (unsigned long long)fnvpair_value_uint64(curr));
+ if (nvlist_print_json_uint64(
+ fnvpair_value_uint64(curr), bufp, blen, offp) != 0)
+ return (-1);
break;
}
case DATA_TYPE_HRTIME: {
hrtime_t val;
VERIFY0(nvpair_value_hrtime(curr, &val));
- FPRINTF(bufp, blen, offp, "%llu",
- (unsigned long long)val);
+
+ if (nvlist_print_json_hrtime(val, bufp, blen,
+ offp) != 0)
+ return (-1);
break;
}
case DATA_TYPE_DOUBLE: {
double val;
VERIFY0(nvpair_value_double(curr, &val));
- FPRINTF(bufp, blen, offp, "%f", val);
+
+ if (nvlist_print_json_double(
+ val, bufp, blen, offp) != 0)
+ return (-1);
break;
}
case DATA_TYPE_NVLIST: {
if (nvlist_do_json(fnvpair_value_nvlist(curr), bufp,
- blen, offp) == -1)
+ blen, offp, indent, level + 1) == -1)
return (-1);
break;
}
case DATA_TYPE_STRING_ARRAY: {
char **val;
- uint_t valsz, i;
+ uint_t valsz;
VERIFY0(nvpair_value_string_array(curr, &val, &valsz));
- FPRINTF(bufp, blen, offp, "[");
- for (i = 0; i < valsz; i++) {
- if (i > 0)
- FPRINTF(bufp, blen, offp, ",");
- if (nvlist_print_json_string(val[i], bufp,
- blen, offp) == -1)
- return (-1);
- }
- FPRINTF(bufp, blen, offp, "]");
+ FPRINTF_JSON_ARRAY(val, valsz, nvlist_print_json_string,
+ level, indent, bufp, blen, offp);
break;
}
@@ -310,7 +443,7 @@ nvlist_do_json(nvlist_t *nvl, char **bufp, size_t *blen, off_t *offp)
if (i > 0)
FPRINTF(bufp, blen, offp, ",");
if (nvlist_do_json(val[i], bufp, blen,
- offp) == -1)
+ offp, indent, level + 1) == -1)
return (-1);
}
FPRINTF(bufp, blen, offp, "]");
@@ -319,144 +452,92 @@ nvlist_do_json(nvlist_t *nvl, char **bufp, size_t *blen, off_t *offp)
case DATA_TYPE_BOOLEAN_ARRAY: {
boolean_t *val;
- uint_t valsz, i;
+ uint_t valsz;
VERIFY0(nvpair_value_boolean_array(curr, &val, &valsz));
- FPRINTF(bufp, blen, offp, "[");
- for (i = 0; i < valsz; i++) {
- if (i > 0)
- FPRINTF(bufp, blen, offp, ",");
- FPRINTF(bufp, blen, offp, val[i] == B_TRUE ?
- "true" : "false");
- }
- FPRINTF(bufp, blen, offp, "]");
+ FPRINTF_JSON_ARRAY(val, valsz,
+ nvlist_print_json_boolean_value, level, indent,
+ bufp, blen, offp);
break;
}
case DATA_TYPE_BYTE_ARRAY: {
uchar_t *val;
- uint_t valsz, i;
+ uint_t valsz;
VERIFY0(nvpair_value_byte_array(curr, &val, &valsz));
- FPRINTF(bufp, blen, offp, "[");
- for (i = 0; i < valsz; i++) {
- if (i > 0)
- FPRINTF(bufp, blen, offp, ",");
- FPRINTF(bufp, blen, offp, "%hhu", val[i]);
- }
- FPRINTF(bufp, blen, offp, "]");
+ FPRINTF_JSON_ARRAY(val, valsz, nvlist_print_json_byte,
+ level, indent, bufp, blen, offp);
break;
}
case DATA_TYPE_UINT8_ARRAY: {
uint8_t *val;
- uint_t valsz, i;
+ uint_t valsz;
VERIFY0(nvpair_value_uint8_array(curr, &val, &valsz));
- FPRINTF(bufp, blen, offp, "[");
- for (i = 0; i < valsz; i++) {
- if (i > 0)
- FPRINTF(bufp, blen, offp, ",");
- FPRINTF(bufp, blen, offp, "%hhu", val[i]);
- }
- FPRINTF(bufp, blen, offp, "]");
+ FPRINTF_JSON_ARRAY(val, valsz, nvlist_print_json_uint8,
+ level, indent, bufp, blen, offp);
break;
}
case DATA_TYPE_INT8_ARRAY: {
int8_t *val;
- uint_t valsz, i;
+ uint_t valsz;
VERIFY0(nvpair_value_int8_array(curr, &val, &valsz));
- FPRINTF(bufp, blen, offp, "[");
- for (i = 0; i < valsz; i++) {
- if (i > 0)
- FPRINTF(bufp, blen, offp, ",");
- FPRINTF(bufp, blen, offp, "%hd", val[i]);
- }
- FPRINTF(bufp, blen, offp, "]");
+ FPRINTF_JSON_ARRAY(val, valsz, nvlist_print_json_int8,
+ level, indent, bufp, blen, offp);
break;
}
case DATA_TYPE_UINT16_ARRAY: {
uint16_t *val;
- uint_t valsz, i;
+ uint_t valsz;
VERIFY0(nvpair_value_uint16_array(curr, &val, &valsz));
- FPRINTF(bufp, blen, offp, "[");
- for (i = 0; i < valsz; i++) {
- if (i > 0)
- FPRINTF(bufp, blen, offp, ",");
- FPRINTF(bufp, blen, offp, "%hu", val[i]);
- }
- FPRINTF(bufp, blen, offp, "]");
+ FPRINTF_JSON_ARRAY(val, valsz, nvlist_print_json_uint16,
+ level, indent, bufp, blen, offp);
break;
}
case DATA_TYPE_INT16_ARRAY: {
int16_t *val;
- uint_t valsz, i;
+ uint_t valsz;
VERIFY0(nvpair_value_int16_array(curr, &val, &valsz));
- FPRINTF(bufp, blen, offp, "[");
- for (i = 0; i < valsz; i++) {
- if (i > 0)
- FPRINTF(bufp, blen, offp, ",");
- FPRINTF(bufp, blen, offp, "%hd", val[i]);
- }
- FPRINTF(bufp, blen, offp, "]");
+ FPRINTF_JSON_ARRAY(val, valsz, nvlist_print_json_int16,
+ level, indent, bufp, blen, offp);
break;
}
case DATA_TYPE_UINT32_ARRAY: {
uint32_t *val;
- uint_t valsz, i;
+ uint_t valsz;
VERIFY0(nvpair_value_uint32_array(curr, &val, &valsz));
- FPRINTF(bufp, blen, offp, "[");
- for (i = 0; i < valsz; i++) {
- if (i > 0)
- FPRINTF(bufp, blen, offp, ",");
- FPRINTF(bufp, blen, offp, "%u", val[i]);
- }
- FPRINTF(bufp, blen, offp, "]");
+ FPRINTF_JSON_ARRAY(val, valsz, nvlist_print_json_uint32,
+ level, indent, bufp, blen, offp);
break;
}
case DATA_TYPE_INT32_ARRAY: {
int32_t *val;
- uint_t valsz, i;
+ uint_t valsz;
VERIFY0(nvpair_value_int32_array(curr, &val, &valsz));
- FPRINTF(bufp, blen, offp, "[");
- for (i = 0; i < valsz; i++) {
- if (i > 0)
- FPRINTF(bufp, blen, offp, ",");
- FPRINTF(bufp, blen, offp, "%d", val[i]);
- }
- FPRINTF(bufp, blen, offp, "]");
+ FPRINTF_JSON_ARRAY(val, valsz, nvlist_print_json_int32,
+ level, indent, bufp, blen, offp);
break;
}
case DATA_TYPE_UINT64_ARRAY: {
uint64_t *val;
- uint_t valsz, i;
+ uint_t valsz;
VERIFY0(nvpair_value_uint64_array(curr, &val, &valsz));
- FPRINTF(bufp, blen, offp, "[");
- for (i = 0; i < valsz; i++) {
- if (i > 0)
- FPRINTF(bufp, blen, offp, ",");
- FPRINTF(bufp, blen, offp, "%llu",
- (unsigned long long)val[i]);
- }
- FPRINTF(bufp, blen, offp, "]");
+ FPRINTF_JSON_ARRAY(val, valsz, nvlist_print_json_uint64,
+ level, indent, bufp, blen, offp);
break;
}
case DATA_TYPE_INT64_ARRAY: {
int64_t *val;
- uint_t valsz, i;
+ uint_t valsz;
VERIFY0(nvpair_value_int64_array(curr, &val, &valsz));
- FPRINTF(bufp, blen, offp, "[");
- for (i = 0; i < valsz; i++) {
- if (i > 0)
- FPRINTF(bufp, blen, offp, ",");
- FPRINTF(bufp, blen, offp, "%lld",
- (long long)val[i]);
- }
- FPRINTF(bufp, blen, offp, "]");
+ FPRINTF_JSON_ARRAY(val, valsz, nvlist_print_json_int64,
+ level, indent, bufp, blen, offp);
break;
}
@@ -465,18 +546,33 @@ nvlist_do_json(nvlist_t *nvl, char **bufp, size_t *blen, off_t *offp)
}
}
+ if (indent != NULL) {
+ FPRINTF(bufp, blen, offp, "\n");
+ }
+
FPRINTF(bufp, blen, offp, "}");
+
+ if (indent != NULL) {
+ FPRINTF(bufp, blen, offp, "\n");
+ }
+
return (0);
}
int
nvlist_dump_json(nvlist_t *nvl, char **bufp)
{
+ return (nvlist_dump_json_pretty(nvl, bufp, NULL));
+}
+
+int
+nvlist_dump_json_pretty(nvlist_t *nvl, char **bufp, char *indent)
+{
off_t off = 0;
size_t l = 0;
*bufp = NULL;
- return (nvlist_do_json(nvl, bufp, &l, &off));
+ return (nvlist_do_json(nvl, bufp, &l, &off, indent, 0));
}
/* ARGSUSED */
@@ -494,10 +590,24 @@ nvlist_dump_json_free(nvlist_t *nvl, char *buf)
int
nvlist_print_json(FILE *fp, nvlist_t *nvl)
{
+ return (nvlist_print_json_pretty(fp, nvl, NULL));
+}
+
+/*
+ * Dump a JSON-formatted representation of an nvlist to the provided FILE *.
+ * This routine outputs newlines and extra whitespace to make the output
+ * "pretty". The string given in `indent` will be used to indent the
+ * output. For example, give " " for 2 space indentation, " " for 4
+ * space indentation, "\t" for tabbed indentation, etc. An indent of NULL
+ * will disable pretty-printing.
+ */
+int
+nvlist_print_json_pretty(FILE *fp, nvlist_t *nvl, char *indent)
+{
int ret;
char *buf;
- if ((ret = nvlist_dump_json(nvl, &buf)) < 0)
+ if ((ret = nvlist_dump_json_pretty(nvl, &buf, indent)) < 0)
return (ret);
ret = fprintf(fp, "%s", buf);
nvlist_dump_json_free(nvl, buf);