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) 2013, Joyent, Inc. All rights reserved. 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", 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", 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(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", fnvpair_value_int64(curr)); 193 break; 194 } 195 196 case DATA_TYPE_UINT64: { 197 FPRINTF(fp, "%llu", fnvpair_value_uint64(curr)); 198 break; 199 } 200 201 case DATA_TYPE_HRTIME: { 202 FPRINTF(fp, "%llu", fnvpair_value_hrtime(curr)); 203 break; 204 } 205 206 case DATA_TYPE_DOUBLE: { 207 FPRINTF(fp, "%f", fnvpair_value_double(curr)); 208 break; 209 } 210 211 case DATA_TYPE_NVLIST: { 212 if (nvlist_print_json(fp, 213 fnvpair_value_nvlist(curr)) == -1) 214 return (-1); 215 break; 216 } 217 218 case DATA_TYPE_STRING_ARRAY: { 219 char **val; 220 uint_t valsz, i; 221 VERIFY0(nvpair_value_string_array(curr, &val, &valsz)); 222 FPRINTF(fp, "["); 223 for (i = 0; i < valsz; i++) { 224 if (i > 0) 225 FPRINTF(fp, ","); 226 if (nvlist_print_json_string(fp, val[i]) == -1) 227 return (-1); 228 } 229 FPRINTF(fp, "]"); 230 break; 231 } 232 233 case DATA_TYPE_NVLIST_ARRAY: { 234 nvlist_t **val; 235 uint_t valsz, i; 236 VERIFY0(nvpair_value_nvlist_array(curr, &val, &valsz)); 237 FPRINTF(fp, "["); 238 for (i = 0; i < valsz; i++) { 239 if (i > 0) 240 FPRINTF(fp, ","); 241 if (nvlist_print_json(fp, val[i]) == -1) 242 return (-1); 243 } 244 FPRINTF(fp, "]"); 245 break; 246 } 247 248 case DATA_TYPE_BOOLEAN_ARRAY: { 249 boolean_t *val; 250 uint_t valsz, i; 251 VERIFY0(nvpair_value_boolean_array(curr, &val, &valsz)); 252 FPRINTF(fp, "["); 253 for (i = 0; i < valsz; i++) { 254 if (i > 0) 255 FPRINTF(fp, ","); 256 FPRINTF(fp, val[i] == B_TRUE ? 257 "true" : "false"); 258 } 259 FPRINTF(fp, "]"); 260 break; 261 } 262 263 case DATA_TYPE_BYTE_ARRAY: { 264 uchar_t *val; 265 uint_t valsz, i; 266 VERIFY0(nvpair_value_byte_array(curr, &val, &valsz)); 267 FPRINTF(fp, "["); 268 for (i = 0; i < valsz; i++) { 269 if (i > 0) 270 FPRINTF(fp, ","); 271 FPRINTF(fp, "%hhu", val[i]); 272 } 273 FPRINTF(fp, "]"); 274 break; 275 } 276 277 case DATA_TYPE_UINT8_ARRAY: { 278 uint8_t *val; 279 uint_t valsz, i; 280 VERIFY0(nvpair_value_uint8_array(curr, &val, &valsz)); 281 FPRINTF(fp, "["); 282 for (i = 0; i < valsz; i++) { 283 if (i > 0) 284 FPRINTF(fp, ","); 285 FPRINTF(fp, "%hhu", val[i]); 286 } 287 FPRINTF(fp, "]"); 288 break; 289 } 290 291 case DATA_TYPE_INT8_ARRAY: { 292 int8_t *val; 293 uint_t valsz, i; 294 VERIFY0(nvpair_value_int8_array(curr, &val, &valsz)); 295 FPRINTF(fp, "["); 296 for (i = 0; i < valsz; i++) { 297 if (i > 0) 298 FPRINTF(fp, ","); 299 FPRINTF(fp, "%hd", val[i]); 300 } 301 FPRINTF(fp, "]"); 302 break; 303 } 304 305 case DATA_TYPE_UINT16_ARRAY: { 306 uint16_t *val; 307 uint_t valsz, i; 308 VERIFY0(nvpair_value_uint16_array(curr, &val, &valsz)); 309 FPRINTF(fp, "["); 310 for (i = 0; i < valsz; i++) { 311 if (i > 0) 312 FPRINTF(fp, ","); 313 FPRINTF(fp, "%hu", val[i]); 314 } 315 FPRINTF(fp, "]"); 316 break; 317 } 318 319 case DATA_TYPE_INT16_ARRAY: { 320 int16_t *val; 321 uint_t valsz, i; 322 VERIFY0(nvpair_value_int16_array(curr, &val, &valsz)); 323 FPRINTF(fp, "["); 324 for (i = 0; i < valsz; i++) { 325 if (i > 0) 326 FPRINTF(fp, ","); 327 FPRINTF(fp, "%hhd", val[i]); 328 } 329 FPRINTF(fp, "]"); 330 break; 331 } 332 333 case DATA_TYPE_UINT32_ARRAY: { 334 uint32_t *val; 335 uint_t valsz, i; 336 VERIFY0(nvpair_value_uint32_array(curr, &val, &valsz)); 337 FPRINTF(fp, "["); 338 for (i = 0; i < valsz; i++) { 339 if (i > 0) 340 FPRINTF(fp, ","); 341 FPRINTF(fp, "%u", val[i]); 342 } 343 FPRINTF(fp, "]"); 344 break; 345 } 346 347 case DATA_TYPE_INT32_ARRAY: { 348 int32_t *val; 349 uint_t valsz, i; 350 VERIFY0(nvpair_value_int32_array(curr, &val, &valsz)); 351 FPRINTF(fp, "["); 352 for (i = 0; i < valsz; i++) { 353 if (i > 0) 354 FPRINTF(fp, ","); 355 FPRINTF(fp, "%d", val[i]); 356 } 357 FPRINTF(fp, "]"); 358 break; 359 } 360 361 case DATA_TYPE_UINT64_ARRAY: { 362 uint64_t *val; 363 uint_t valsz, i; 364 VERIFY0(nvpair_value_uint64_array(curr, &val, &valsz)); 365 FPRINTF(fp, "["); 366 for (i = 0; i < valsz; i++) { 367 if (i > 0) 368 FPRINTF(fp, ","); 369 FPRINTF(fp, "%llu", val[i]); 370 } 371 FPRINTF(fp, "]"); 372 break; 373 } 374 375 case DATA_TYPE_INT64_ARRAY: { 376 int64_t *val; 377 uint_t valsz, i; 378 VERIFY0(nvpair_value_int64_array(curr, &val, &valsz)); 379 FPRINTF(fp, "["); 380 for (i = 0; i < valsz; i++) { 381 if (i > 0) 382 FPRINTF(fp, ","); 383 FPRINTF(fp, "%lld", val[i]); 384 } 385 FPRINTF(fp, "]"); 386 break; 387 } 388 389 case DATA_TYPE_UNKNOWN: 390 return (-1); 391 } 392 } 393 394 FPRINTF(fp, "}"); 395 return (0); 396 }