diff options
Diffstat (limited to 'usr/src/lib/libnvpair')
-rw-r--r-- | usr/src/lib/libnvpair/libnvpair.h | 2 | ||||
-rw-r--r-- | usr/src/lib/libnvpair/mapfile-vers | 2 | ||||
-rw-r--r-- | usr/src/lib/libnvpair/nvpair_json.c | 284 |
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); +} |