Home | History | Annotate | Line # | Download | only in libnvpair
      1 /*
      2  * This file and its contents are supplied under the terms of the
      3  * Common Development and Distribution License ("CDDL"), version 1.0.
      4  * You may only use this file in accordance with the terms of version
      5  * 1.0 of the CDDL.
      6  *
      7  * A full copy of the text of the CDDL should have accompanied this
      8  * source.  A copy of the CDDL is also available via the Internet at
      9  * http://www.illumos.org/license/CDDL.
     10  */
     11 /*
     12  * Copyright (c) 2014, Joyent, Inc.
     13  */
     14 
     15 #include <stdio.h>
     16 #include <stdlib.h>
     17 #include <strings.h>
     18 #include <wchar.h>
     19 #include <sys/debug.h>
     20 
     21 #include "libnvpair.h"
     22 
     23 #define	FPRINTF(fp, ...)				\
     24 	do {						\
     25 		if (fprintf(fp, __VA_ARGS__) < 0)	\
     26 			return (-1);			\
     27 	} while (0)
     28 
     29 /*
     30  * When formatting a string for JSON output we must escape certain characters,
     31  * as described in RFC4627.  This applies to both member names and
     32  * DATA_TYPE_STRING values.
     33  *
     34  * This function will only operate correctly if the following conditions are
     35  * met:
     36  *
     37  *       1. The input String is encoded in the current locale.
     38  *
     39  *       2. The current locale includes the Basic Multilingual Plane (plane 0)
     40  *          as defined in the Unicode standard.
     41  *
     42  * The output will be entirely 7-bit ASCII (as a subset of UTF-8) with all
     43  * representable Unicode characters included in their escaped numeric form.
     44  */
     45 static int
     46 nvlist_print_json_string(FILE *fp, const char *input)
     47 {
     48 	mbstate_t mbr;
     49 	wchar_t c;
     50 	size_t sz;
     51 
     52 	bzero(&mbr, sizeof (mbr));
     53 
     54 	FPRINTF(fp, "\"");
     55 	while ((sz = mbrtowc(&c, input, MB_CUR_MAX, &mbr)) > 0) {
     56 		switch (c) {
     57 		case '"':
     58 			FPRINTF(fp, "\\\"");
     59 			break;
     60 		case '\n':
     61 			FPRINTF(fp, "\\n");
     62 			break;
     63 		case '\r':
     64 			FPRINTF(fp, "\\r");
     65 			break;
     66 		case '\\':
     67 			FPRINTF(fp, "\\\\");
     68 			break;
     69 		case '\f':
     70 			FPRINTF(fp, "\\f");
     71 			break;
     72 		case '\t':
     73 			FPRINTF(fp, "\\t");
     74 			break;
     75 		case '\b':
     76 			FPRINTF(fp, "\\b");
     77 			break;
     78 		default:
     79 			if ((c >= 0x00 && c <= 0x1f) ||
     80 			    (c > 0x7f && c <= 0xffff)) {
     81 				/*
     82 				 * Render both Control Characters and Unicode
     83 				 * characters in the Basic Multilingual Plane
     84 				 * as JSON-escaped multibyte characters.
     85 				 */
     86 				FPRINTF(fp, "\\u%04x", (int)(0xffff & c));
     87 			} else if (c >= 0x20 && c <= 0x7f) {
     88 				/*
     89 				 * Render other 7-bit ASCII characters directly
     90 				 * and drop other, unrepresentable characters.
     91 				 */
     92 				FPRINTF(fp, "%c", (int)(0xff & c));
     93 			}
     94 			break;
     95 		}
     96 		input += sz;
     97 	}
     98 
     99 	if (sz == (size_t)-1 || sz == (size_t)-2) {
    100 		/*
    101 		 * We last read an invalid multibyte character sequence,
    102 		 * so return an error.
    103 		 */
    104 		return (-1);
    105 	}
    106 
    107 	FPRINTF(fp, "\"");
    108 	return (0);
    109 }
    110 
    111 /*
    112  * Dump a JSON-formatted representation of an nvlist to the provided FILE *.
    113  * This routine does not output any new-lines or additional whitespace other
    114  * than that contained in strings, nor does it call fflush(3C).
    115  */
    116 int
    117 nvlist_print_json(FILE *fp, nvlist_t *nvl)
    118 {
    119 	nvpair_t *curr;
    120 	boolean_t first = B_TRUE;
    121 
    122 	FPRINTF(fp, "{");
    123 
    124 	for (curr = nvlist_next_nvpair(nvl, NULL); curr;
    125 	    curr = nvlist_next_nvpair(nvl, curr)) {
    126 		data_type_t type = nvpair_type(curr);
    127 
    128 		if (!first)
    129 			FPRINTF(fp, ",");
    130 		else
    131 			first = B_FALSE;
    132 
    133 		if (nvlist_print_json_string(fp, nvpair_name(curr)) == -1)
    134 			return (-1);
    135 		FPRINTF(fp, ":");
    136 
    137 		switch (type) {
    138 		case DATA_TYPE_STRING: {
    139 			char *string = fnvpair_value_string(curr);
    140 			if (nvlist_print_json_string(fp, string) == -1)
    141 				return (-1);
    142 			break;
    143 		}
    144 
    145 		case DATA_TYPE_BOOLEAN: {
    146 			FPRINTF(fp, "true");
    147 			break;
    148 		}
    149 
    150 		case DATA_TYPE_BOOLEAN_VALUE: {
    151 			FPRINTF(fp, "%s", fnvpair_value_boolean_value(curr) ==
    152 			    B_TRUE ? "true" : "false");
    153 			break;
    154 		}
    155 
    156 		case DATA_TYPE_BYTE: {
    157 			FPRINTF(fp, "%hhu", fnvpair_value_byte(curr));
    158 			break;
    159 		}
    160 
    161 		case DATA_TYPE_INT8: {
    162 			FPRINTF(fp, "%hhd", fnvpair_value_int8(curr));
    163 			break;
    164 		}
    165 
    166 		case DATA_TYPE_UINT8: {
    167 			FPRINTF(fp, "%hhu", fnvpair_value_uint8_t(curr));
    168 			break;
    169 		}
    170 
    171 		case DATA_TYPE_INT16: {
    172 			FPRINTF(fp, "%hd", fnvpair_value_int16(curr));
    173 			break;
    174 		}
    175 
    176 		case DATA_TYPE_UINT16: {
    177 			FPRINTF(fp, "%hu", fnvpair_value_uint16(curr));
    178 			break;
    179 		}
    180 
    181 		case DATA_TYPE_INT32: {
    182 			FPRINTF(fp, "%d", fnvpair_value_int32(curr));
    183 			break;
    184 		}
    185 
    186 		case DATA_TYPE_UINT32: {
    187 			FPRINTF(fp, "%u", fnvpair_value_uint32(curr));
    188 			break;
    189 		}
    190 
    191 		case DATA_TYPE_INT64: {
    192 			FPRINTF(fp, "%lld",
    193 			    (long long)fnvpair_value_int64(curr));
    194 			break;
    195 		}
    196 
    197 		case DATA_TYPE_UINT64: {
    198 			FPRINTF(fp, "%llu",
    199 			    (unsigned long long)fnvpair_value_uint64(curr));
    200 			break;
    201 		}
    202 
    203 		case DATA_TYPE_HRTIME: {
    204 			hrtime_t val;
    205 			VERIFY0(nvpair_value_hrtime(curr, &val));
    206 			FPRINTF(fp, "%llu", (unsigned long long)val);
    207 			break;
    208 		}
    209 
    210 		case DATA_TYPE_DOUBLE: {
    211 			double val;
    212 			VERIFY0(nvpair_value_double(curr, &val));
    213 			FPRINTF(fp, "%f", val);
    214 			break;
    215 		}
    216 
    217 		case DATA_TYPE_NVLIST: {
    218 			if (nvlist_print_json(fp,
    219 			    fnvpair_value_nvlist(curr)) == -1)
    220 				return (-1);
    221 			break;
    222 		}
    223 
    224 		case DATA_TYPE_STRING_ARRAY: {
    225 			char **val;
    226 			uint_t valsz, i;
    227 			VERIFY0(nvpair_value_string_array(curr, &val, &valsz));
    228 			FPRINTF(fp, "[");
    229 			for (i = 0; i < valsz; i++) {
    230 				if (i > 0)
    231 					FPRINTF(fp, ",");
    232 				if (nvlist_print_json_string(fp, val[i]) == -1)
    233 					return (-1);
    234 			}
    235 			FPRINTF(fp, "]");
    236 			break;
    237 		}
    238 
    239 		case DATA_TYPE_NVLIST_ARRAY: {
    240 			nvlist_t **val;
    241 			uint_t valsz, i;
    242 			VERIFY0(nvpair_value_nvlist_array(curr, &val, &valsz));
    243 			FPRINTF(fp, "[");
    244 			for (i = 0; i < valsz; i++) {
    245 				if (i > 0)
    246 					FPRINTF(fp, ",");
    247 				if (nvlist_print_json(fp, val[i]) == -1)
    248 					return (-1);
    249 			}
    250 			FPRINTF(fp, "]");
    251 			break;
    252 		}
    253 
    254 		case DATA_TYPE_BOOLEAN_ARRAY: {
    255 			boolean_t *val;
    256 			uint_t valsz, i;
    257 			VERIFY0(nvpair_value_boolean_array(curr, &val, &valsz));
    258 			FPRINTF(fp, "[");
    259 			for (i = 0; i < valsz; i++) {
    260 				if (i > 0)
    261 					FPRINTF(fp, ",");
    262 				FPRINTF(fp, val[i] == B_TRUE ?
    263 				    "true" : "false");
    264 			}
    265 			FPRINTF(fp, "]");
    266 			break;
    267 		}
    268 
    269 		case DATA_TYPE_BYTE_ARRAY: {
    270 			uchar_t *val;
    271 			uint_t valsz, i;
    272 			VERIFY0(nvpair_value_byte_array(curr, &val, &valsz));
    273 			FPRINTF(fp, "[");
    274 			for (i = 0; i < valsz; i++) {
    275 				if (i > 0)
    276 					FPRINTF(fp, ",");
    277 				FPRINTF(fp, "%hhu", val[i]);
    278 			}
    279 			FPRINTF(fp, "]");
    280 			break;
    281 		}
    282 
    283 		case DATA_TYPE_UINT8_ARRAY: {
    284 			uint8_t *val;
    285 			uint_t valsz, i;
    286 			VERIFY0(nvpair_value_uint8_array(curr, &val, &valsz));
    287 			FPRINTF(fp, "[");
    288 			for (i = 0; i < valsz; i++) {
    289 				if (i > 0)
    290 					FPRINTF(fp, ",");
    291 				FPRINTF(fp, "%hhu", val[i]);
    292 			}
    293 			FPRINTF(fp, "]");
    294 			break;
    295 		}
    296 
    297 		case DATA_TYPE_INT8_ARRAY: {
    298 			int8_t *val;
    299 			uint_t valsz, i;
    300 			VERIFY0(nvpair_value_int8_array(curr, &val, &valsz));
    301 			FPRINTF(fp, "[");
    302 			for (i = 0; i < valsz; i++) {
    303 				if (i > 0)
    304 					FPRINTF(fp, ",");
    305 				FPRINTF(fp, "%hhd", val[i]);
    306 			}
    307 			FPRINTF(fp, "]");
    308 			break;
    309 		}
    310 
    311 		case DATA_TYPE_UINT16_ARRAY: {
    312 			uint16_t *val;
    313 			uint_t valsz, i;
    314 			VERIFY0(nvpair_value_uint16_array(curr, &val, &valsz));
    315 			FPRINTF(fp, "[");
    316 			for (i = 0; i < valsz; i++) {
    317 				if (i > 0)
    318 					FPRINTF(fp, ",");
    319 				FPRINTF(fp, "%hu", val[i]);
    320 			}
    321 			FPRINTF(fp, "]");
    322 			break;
    323 		}
    324 
    325 		case DATA_TYPE_INT16_ARRAY: {
    326 			int16_t *val;
    327 			uint_t valsz, i;
    328 			VERIFY0(nvpair_value_int16_array(curr, &val, &valsz));
    329 			FPRINTF(fp, "[");
    330 			for (i = 0; i < valsz; i++) {
    331 				if (i > 0)
    332 					FPRINTF(fp, ",");
    333 				FPRINTF(fp, "%hd", val[i]);
    334 			}
    335 			FPRINTF(fp, "]");
    336 			break;
    337 		}
    338 
    339 		case DATA_TYPE_UINT32_ARRAY: {
    340 			uint32_t *val;
    341 			uint_t valsz, i;
    342 			VERIFY0(nvpair_value_uint32_array(curr, &val, &valsz));
    343 			FPRINTF(fp, "[");
    344 			for (i = 0; i < valsz; i++) {
    345 				if (i > 0)
    346 					FPRINTF(fp, ",");
    347 				FPRINTF(fp, "%u", val[i]);
    348 			}
    349 			FPRINTF(fp, "]");
    350 			break;
    351 		}
    352 
    353 		case DATA_TYPE_INT32_ARRAY: {
    354 			int32_t *val;
    355 			uint_t valsz, i;
    356 			VERIFY0(nvpair_value_int32_array(curr, &val, &valsz));
    357 			FPRINTF(fp, "[");
    358 			for (i = 0; i < valsz; i++) {
    359 				if (i > 0)
    360 					FPRINTF(fp, ",");
    361 				FPRINTF(fp, "%d", val[i]);
    362 			}
    363 			FPRINTF(fp, "]");
    364 			break;
    365 		}
    366 
    367 		case DATA_TYPE_UINT64_ARRAY: {
    368 			uint64_t *val;
    369 			uint_t valsz, i;
    370 			VERIFY0(nvpair_value_uint64_array(curr, &val, &valsz));
    371 			FPRINTF(fp, "[");
    372 			for (i = 0; i < valsz; i++) {
    373 				if (i > 0)
    374 					FPRINTF(fp, ",");
    375 				FPRINTF(fp, "%llu",
    376 				    (unsigned long long)val[i]);
    377 			}
    378 			FPRINTF(fp, "]");
    379 			break;
    380 		}
    381 
    382 		case DATA_TYPE_INT64_ARRAY: {
    383 			int64_t *val;
    384 			uint_t valsz, i;
    385 			VERIFY0(nvpair_value_int64_array(curr, &val, &valsz));
    386 			FPRINTF(fp, "[");
    387 			for (i = 0; i < valsz; i++) {
    388 				if (i > 0)
    389 					FPRINTF(fp, ",");
    390 				FPRINTF(fp, "%lld", (long long)val[i]);
    391 			}
    392 			FPRINTF(fp, "]");
    393 			break;
    394 		}
    395 
    396 		case DATA_TYPE_UNKNOWN:
    397 			return (-1);
    398 		}
    399 	}
    400 
    401 	FPRINTF(fp, "}");
    402 	return (0);
    403 }
    404