Path: blob/main/sys/contrib/openzfs/lib/libnvpair/libnvpair_json.c
48378 views
// SPDX-License-Identifier: CDDL-1.01/*2* This file and its contents are supplied under the terms of the3* Common Development and Distribution License ("CDDL"), version 1.0.4* You may only use this file in accordance with the terms of version5* 1.0 of the CDDL.6*7* A full copy of the text of the CDDL should have accompanied this8* source. A copy of the CDDL is also available via the Internet at9* http://www.illumos.org/license/CDDL.10*/11/*12* Copyright (c) 2014, Joyent, Inc.13* Copyright (c) 2017 by Delphix. All rights reserved.14*/1516#include <stdio.h>17#include <stdlib.h>18#include <string.h>19#include <wchar.h>20#include <sys/debug.h>2122#include "libnvpair.h"2324#define FPRINTF(fp, ...) \25do { \26if (fprintf(fp, __VA_ARGS__) < 0) \27return (-1); \28} while (0)2930/*31* When formatting a string for JSON output we must escape certain characters,32* as described in RFC4627. This applies to both member names and33* DATA_TYPE_STRING values.34*35* This function will only operate correctly if the following conditions are36* met:37*38* 1. The input String is encoded in the current locale.39*40* 2. The current locale includes the Basic Multilingual Plane (plane 0)41* as defined in the Unicode standard.42*43* The output will be entirely 7-bit ASCII (as a subset of UTF-8) with all44* representable Unicode characters included in their escaped numeric form.45*/46static int47nvlist_print_json_string(FILE *fp, const char *input)48{49mbstate_t mbr = {0};50wchar_t c;51size_t sz;5253FPRINTF(fp, "\"");54while ((sz = mbrtowc(&c, input, MB_CUR_MAX, &mbr)) > 0) {55if (sz == (size_t)-1 || sz == (size_t)-2) {56/*57* We last read an invalid multibyte character sequence,58* so return an error.59*/60return (-1);61}62switch (c) {63case '"':64FPRINTF(fp, "\\\"");65break;66case '\n':67FPRINTF(fp, "\\n");68break;69case '\r':70FPRINTF(fp, "\\r");71break;72case '\\':73FPRINTF(fp, "\\\\");74break;75case '\f':76FPRINTF(fp, "\\f");77break;78case '\t':79FPRINTF(fp, "\\t");80break;81case '\b':82FPRINTF(fp, "\\b");83break;84default:85if ((c >= 0x00 && c <= 0x1f) ||86(c > 0x7f && c <= 0xffff)) {87/*88* Render both Control Characters and Unicode89* characters in the Basic Multilingual Plane90* as JSON-escaped multibyte characters.91*/92FPRINTF(fp, "\\u%04x", (int)(0xffff & c));93} else if (c >= 0x20 && c <= 0x7f) {94/*95* Render other 7-bit ASCII characters directly96* and drop other, unrepresentable characters.97*/98FPRINTF(fp, "%c", (int)(0xff & c));99}100break;101}102input += sz;103}104105FPRINTF(fp, "\"");106return (0);107}108109/*110* Dump a JSON-formatted representation of an nvlist to the provided FILE *.111* This routine does not output any new-lines or additional whitespace other112* than that contained in strings, nor does it call fflush(3C).113*/114int115nvlist_print_json(FILE *fp, nvlist_t *nvl)116{117nvpair_t *curr;118boolean_t first = B_TRUE;119120FPRINTF(fp, "{");121122for (curr = nvlist_next_nvpair(nvl, NULL); curr;123curr = nvlist_next_nvpair(nvl, curr)) {124data_type_t type = nvpair_type(curr);125126if (!first)127FPRINTF(fp, ",");128else129first = B_FALSE;130131if (nvlist_print_json_string(fp, nvpair_name(curr)) == -1)132return (-1);133FPRINTF(fp, ":");134135switch (type) {136case DATA_TYPE_STRING: {137const char *string = fnvpair_value_string(curr);138if (nvlist_print_json_string(fp, string) == -1)139return (-1);140break;141}142143case DATA_TYPE_BOOLEAN: {144FPRINTF(fp, "true");145break;146}147148case DATA_TYPE_BOOLEAN_VALUE: {149FPRINTF(fp, "%s", fnvpair_value_boolean_value(curr) ==150B_TRUE ? "true" : "false");151break;152}153154case DATA_TYPE_BYTE: {155FPRINTF(fp, "%hhu", fnvpair_value_byte(curr));156break;157}158159case DATA_TYPE_INT8: {160FPRINTF(fp, "%hhd", fnvpair_value_int8(curr));161break;162}163164case DATA_TYPE_UINT8: {165FPRINTF(fp, "%hhu", fnvpair_value_uint8(curr));166break;167}168169case DATA_TYPE_INT16: {170FPRINTF(fp, "%hd", fnvpair_value_int16(curr));171break;172}173174case DATA_TYPE_UINT16: {175FPRINTF(fp, "%hu", fnvpair_value_uint16(curr));176break;177}178179case DATA_TYPE_INT32: {180FPRINTF(fp, "%d", fnvpair_value_int32(curr));181break;182}183184case DATA_TYPE_UINT32: {185FPRINTF(fp, "%u", fnvpair_value_uint32(curr));186break;187}188189case DATA_TYPE_INT64: {190FPRINTF(fp, "%lld",191(long long)fnvpair_value_int64(curr));192break;193}194195case DATA_TYPE_UINT64: {196FPRINTF(fp, "%llu",197(unsigned long long)fnvpair_value_uint64(curr));198break;199}200201case DATA_TYPE_HRTIME: {202hrtime_t val;203VERIFY0(nvpair_value_hrtime(curr, &val));204FPRINTF(fp, "%llu", (unsigned long long)val);205break;206}207208case DATA_TYPE_DOUBLE: {209double val;210VERIFY0(nvpair_value_double(curr, &val));211FPRINTF(fp, "%f", val);212break;213}214215case DATA_TYPE_NVLIST: {216if (nvlist_print_json(fp,217fnvpair_value_nvlist(curr)) == -1)218return (-1);219break;220}221222case DATA_TYPE_STRING_ARRAY: {223const char **val;224uint_t valsz, i;225VERIFY0(nvpair_value_string_array(curr, &val, &valsz));226FPRINTF(fp, "[");227for (i = 0; i < valsz; i++) {228if (i > 0)229FPRINTF(fp, ",");230if (nvlist_print_json_string(fp, val[i]) == -1)231return (-1);232}233FPRINTF(fp, "]");234break;235}236237case DATA_TYPE_NVLIST_ARRAY: {238nvlist_t **val;239uint_t valsz, i;240VERIFY0(nvpair_value_nvlist_array(curr, &val, &valsz));241FPRINTF(fp, "[");242for (i = 0; i < valsz; i++) {243if (i > 0)244FPRINTF(fp, ",");245if (nvlist_print_json(fp, val[i]) == -1)246return (-1);247}248FPRINTF(fp, "]");249break;250}251252case DATA_TYPE_BOOLEAN_ARRAY: {253boolean_t *val;254uint_t valsz, i;255VERIFY0(nvpair_value_boolean_array(curr, &val, &valsz));256FPRINTF(fp, "[");257for (i = 0; i < valsz; i++) {258if (i > 0)259FPRINTF(fp, ",");260FPRINTF(fp, val[i] == B_TRUE ?261"true" : "false");262}263FPRINTF(fp, "]");264break;265}266267case DATA_TYPE_BYTE_ARRAY: {268uchar_t *val;269uint_t valsz, i;270VERIFY0(nvpair_value_byte_array(curr, &val, &valsz));271FPRINTF(fp, "[");272for (i = 0; i < valsz; i++) {273if (i > 0)274FPRINTF(fp, ",");275FPRINTF(fp, "%hhu", val[i]);276}277FPRINTF(fp, "]");278break;279}280281case DATA_TYPE_UINT8_ARRAY: {282uint8_t *val;283uint_t valsz, i;284VERIFY0(nvpair_value_uint8_array(curr, &val, &valsz));285FPRINTF(fp, "[");286for (i = 0; i < valsz; i++) {287if (i > 0)288FPRINTF(fp, ",");289FPRINTF(fp, "%hhu", val[i]);290}291FPRINTF(fp, "]");292break;293}294295case DATA_TYPE_INT8_ARRAY: {296int8_t *val;297uint_t valsz, i;298VERIFY0(nvpair_value_int8_array(curr, &val, &valsz));299FPRINTF(fp, "[");300for (i = 0; i < valsz; i++) {301if (i > 0)302FPRINTF(fp, ",");303FPRINTF(fp, "%hhd", val[i]);304}305FPRINTF(fp, "]");306break;307}308309case DATA_TYPE_UINT16_ARRAY: {310uint16_t *val;311uint_t valsz, i;312VERIFY0(nvpair_value_uint16_array(curr, &val, &valsz));313FPRINTF(fp, "[");314for (i = 0; i < valsz; i++) {315if (i > 0)316FPRINTF(fp, ",");317FPRINTF(fp, "%hu", val[i]);318}319FPRINTF(fp, "]");320break;321}322323case DATA_TYPE_INT16_ARRAY: {324int16_t *val;325uint_t valsz, i;326VERIFY0(nvpair_value_int16_array(curr, &val, &valsz));327FPRINTF(fp, "[");328for (i = 0; i < valsz; i++) {329if (i > 0)330FPRINTF(fp, ",");331FPRINTF(fp, "%hd", val[i]);332}333FPRINTF(fp, "]");334break;335}336337case DATA_TYPE_UINT32_ARRAY: {338uint32_t *val;339uint_t valsz, i;340VERIFY0(nvpair_value_uint32_array(curr, &val, &valsz));341FPRINTF(fp, "[");342for (i = 0; i < valsz; i++) {343if (i > 0)344FPRINTF(fp, ",");345FPRINTF(fp, "%u", val[i]);346}347FPRINTF(fp, "]");348break;349}350351case DATA_TYPE_INT32_ARRAY: {352int32_t *val;353uint_t valsz, i;354VERIFY0(nvpair_value_int32_array(curr, &val, &valsz));355FPRINTF(fp, "[");356for (i = 0; i < valsz; i++) {357if (i > 0)358FPRINTF(fp, ",");359FPRINTF(fp, "%d", val[i]);360}361FPRINTF(fp, "]");362break;363}364365case DATA_TYPE_UINT64_ARRAY: {366uint64_t *val;367uint_t valsz, i;368VERIFY0(nvpair_value_uint64_array(curr, &val, &valsz));369FPRINTF(fp, "[");370for (i = 0; i < valsz; i++) {371if (i > 0)372FPRINTF(fp, ",");373FPRINTF(fp, "%llu",374(unsigned long long)val[i]);375}376FPRINTF(fp, "]");377break;378}379380case DATA_TYPE_INT64_ARRAY: {381int64_t *val;382uint_t valsz, i;383VERIFY0(nvpair_value_int64_array(curr, &val, &valsz));384FPRINTF(fp, "[");385for (i = 0; i < valsz; i++) {386if (i > 0)387FPRINTF(fp, ",");388FPRINTF(fp, "%lld", (long long)val[i]);389}390FPRINTF(fp, "]");391break;392}393394case DATA_TYPE_UNKNOWN:395case DATA_TYPE_DONTCARE:396return (-1);397}398399}400401FPRINTF(fp, "}");402return (0);403}404405406