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