1260710Savg/* 2260710Savg * This file and its contents are supplied under the terms of the 3260710Savg * Common Development and Distribution License ("CDDL"), version 1.0. 4260710Savg * You may only use this file in accordance with the terms of version 5260710Savg * 1.0 of the CDDL. 6260710Savg * 7260710Savg * A full copy of the text of the CDDL should have accompanied this 8260710Savg * source. A copy of the CDDL is also available via the Internet at 9260710Savg * http://www.illumos.org/license/CDDL. 10260710Savg */ 11260710Savg/* 12275552Sdelphij * Copyright (c) 2014, Joyent, Inc. 13260710Savg */ 14260710Savg 15260710Savg#include <stdio.h> 16260710Savg#include <stdlib.h> 17260710Savg#include <strings.h> 18260710Savg#include <wchar.h> 19260710Savg#include <sys/debug.h> 20260710Savg 21260710Savg#include "libnvpair.h" 22260710Savg 23275552Sdelphij#define FPRINTF(fp, ...) \ 24275552Sdelphij do { \ 25275552Sdelphij if (fprintf(fp, __VA_ARGS__) < 0) \ 26275552Sdelphij return (-1); \ 27275552Sdelphij } while (0) 28260710Savg 29260710Savg/* 30260710Savg * When formatting a string for JSON output we must escape certain characters, 31260710Savg * as described in RFC4627. This applies to both member names and 32260710Savg * DATA_TYPE_STRING values. 33260710Savg * 34260710Savg * This function will only operate correctly if the following conditions are 35260710Savg * met: 36260710Savg * 37260710Savg * 1. The input String is encoded in the current locale. 38260710Savg * 39260710Savg * 2. The current locale includes the Basic Multilingual Plane (plane 0) 40260710Savg * as defined in the Unicode standard. 41260710Savg * 42260710Savg * The output will be entirely 7-bit ASCII (as a subset of UTF-8) with all 43260710Savg * representable Unicode characters included in their escaped numeric form. 44260710Savg */ 45260710Savgstatic int 46260710Savgnvlist_print_json_string(FILE *fp, const char *input) 47260710Savg{ 48260710Savg mbstate_t mbr; 49260710Savg wchar_t c; 50260710Savg size_t sz; 51260710Savg 52260710Savg bzero(&mbr, sizeof (mbr)); 53260710Savg 54260710Savg FPRINTF(fp, "\""); 55260710Savg while ((sz = mbrtowc(&c, input, MB_CUR_MAX, &mbr)) > 0) { 56260710Savg switch (c) { 57260710Savg case '"': 58260710Savg FPRINTF(fp, "\\\""); 59260710Savg break; 60260710Savg case '\n': 61260710Savg FPRINTF(fp, "\\n"); 62260710Savg break; 63260710Savg case '\r': 64260710Savg FPRINTF(fp, "\\r"); 65260710Savg break; 66260710Savg case '\\': 67260710Savg FPRINTF(fp, "\\\\"); 68260710Savg break; 69260710Savg case '\f': 70260710Savg FPRINTF(fp, "\\f"); 71260710Savg break; 72260710Savg case '\t': 73260710Savg FPRINTF(fp, "\\t"); 74260710Savg break; 75260710Savg case '\b': 76260710Savg FPRINTF(fp, "\\b"); 77260710Savg break; 78260710Savg default: 79260710Savg if ((c >= 0x00 && c <= 0x1f) || 80260710Savg (c > 0x7f && c <= 0xffff)) { 81260710Savg /* 82260710Savg * Render both Control Characters and Unicode 83260710Savg * characters in the Basic Multilingual Plane 84260710Savg * as JSON-escaped multibyte characters. 85260710Savg */ 86260710Savg FPRINTF(fp, "\\u%04x", (int)(0xffff & c)); 87260710Savg } else if (c >= 0x20 && c <= 0x7f) { 88260710Savg /* 89260710Savg * Render other 7-bit ASCII characters directly 90260710Savg * and drop other, unrepresentable characters. 91260710Savg */ 92260710Savg FPRINTF(fp, "%c", (int)(0xff & c)); 93260710Savg } 94260710Savg break; 95260710Savg } 96260710Savg input += sz; 97260710Savg } 98260710Savg 99260710Savg if (sz == (size_t)-1 || sz == (size_t)-2) { 100260710Savg /* 101260710Savg * We last read an invalid multibyte character sequence, 102260710Savg * so return an error. 103260710Savg */ 104260710Savg return (-1); 105260710Savg } 106260710Savg 107260710Savg FPRINTF(fp, "\""); 108260710Savg return (0); 109260710Savg} 110260710Savg 111260710Savg/* 112260710Savg * Dump a JSON-formatted representation of an nvlist to the provided FILE *. 113260710Savg * This routine does not output any new-lines or additional whitespace other 114260710Savg * than that contained in strings, nor does it call fflush(3C). 115260710Savg */ 116260710Savgint 117260710Savgnvlist_print_json(FILE *fp, nvlist_t *nvl) 118260710Savg{ 119260710Savg nvpair_t *curr; 120260710Savg boolean_t first = B_TRUE; 121260710Savg 122260710Savg FPRINTF(fp, "{"); 123260710Savg 124260710Savg for (curr = nvlist_next_nvpair(nvl, NULL); curr; 125260710Savg curr = nvlist_next_nvpair(nvl, curr)) { 126260710Savg data_type_t type = nvpair_type(curr); 127260710Savg 128260710Savg if (!first) 129260710Savg FPRINTF(fp, ","); 130260710Savg else 131260710Savg first = B_FALSE; 132260710Savg 133260710Savg if (nvlist_print_json_string(fp, nvpair_name(curr)) == -1) 134260710Savg return (-1); 135260710Savg FPRINTF(fp, ":"); 136260710Savg 137260710Savg switch (type) { 138260710Savg case DATA_TYPE_STRING: { 139260710Savg char *string = fnvpair_value_string(curr); 140260710Savg if (nvlist_print_json_string(fp, string) == -1) 141260710Savg return (-1); 142260710Savg break; 143260710Savg } 144260710Savg 145260710Savg case DATA_TYPE_BOOLEAN: { 146260710Savg FPRINTF(fp, "true"); 147260710Savg break; 148260710Savg } 149260710Savg 150260710Savg case DATA_TYPE_BOOLEAN_VALUE: { 151260710Savg FPRINTF(fp, "%s", fnvpair_value_boolean_value(curr) == 152260710Savg B_TRUE ? "true" : "false"); 153260710Savg break; 154260710Savg } 155260710Savg 156260710Savg case DATA_TYPE_BYTE: { 157260710Savg FPRINTF(fp, "%hhu", fnvpair_value_byte(curr)); 158260710Savg break; 159260710Savg } 160260710Savg 161260710Savg case DATA_TYPE_INT8: { 162260710Savg FPRINTF(fp, "%hhd", fnvpair_value_int8(curr)); 163260710Savg break; 164260710Savg } 165260710Savg 166260710Savg case DATA_TYPE_UINT8: { 167260710Savg FPRINTF(fp, "%hhu", fnvpair_value_uint8_t(curr)); 168260710Savg break; 169260710Savg } 170260710Savg 171260710Savg case DATA_TYPE_INT16: { 172260710Savg FPRINTF(fp, "%hd", fnvpair_value_int16(curr)); 173260710Savg break; 174260710Savg } 175260710Savg 176260710Savg case DATA_TYPE_UINT16: { 177260710Savg FPRINTF(fp, "%hu", fnvpair_value_uint16(curr)); 178260710Savg break; 179260710Savg } 180260710Savg 181260710Savg case DATA_TYPE_INT32: { 182260710Savg FPRINTF(fp, "%d", fnvpair_value_int32(curr)); 183260710Savg break; 184260710Savg } 185260710Savg 186260710Savg case DATA_TYPE_UINT32: { 187260710Savg FPRINTF(fp, "%u", fnvpair_value_uint32(curr)); 188260710Savg break; 189260710Savg } 190260710Savg 191260710Savg case DATA_TYPE_INT64: { 192260710Savg FPRINTF(fp, "%lld", 193260710Savg (long long)fnvpair_value_int64(curr)); 194260710Savg break; 195260710Savg } 196260710Savg 197260710Savg case DATA_TYPE_UINT64: { 198260710Savg FPRINTF(fp, "%llu", 199260710Savg (unsigned long long)fnvpair_value_uint64(curr)); 200260710Savg break; 201260710Savg } 202260710Savg 203260710Savg case DATA_TYPE_HRTIME: { 204260710Savg hrtime_t val; 205260710Savg VERIFY0(nvpair_value_hrtime(curr, &val)); 206260710Savg FPRINTF(fp, "%llu", (unsigned long long)val); 207260710Savg break; 208260710Savg } 209260710Savg 210260710Savg case DATA_TYPE_DOUBLE: { 211260710Savg double val; 212260710Savg VERIFY0(nvpair_value_double(curr, &val)); 213260710Savg FPRINTF(fp, "%f", val); 214260710Savg break; 215260710Savg } 216260710Savg 217260710Savg case DATA_TYPE_NVLIST: { 218260710Savg if (nvlist_print_json(fp, 219260710Savg fnvpair_value_nvlist(curr)) == -1) 220260710Savg return (-1); 221260710Savg break; 222260710Savg } 223260710Savg 224260710Savg case DATA_TYPE_STRING_ARRAY: { 225260710Savg char **val; 226260710Savg uint_t valsz, i; 227260710Savg VERIFY0(nvpair_value_string_array(curr, &val, &valsz)); 228260710Savg FPRINTF(fp, "["); 229260710Savg for (i = 0; i < valsz; i++) { 230260710Savg if (i > 0) 231260710Savg FPRINTF(fp, ","); 232260710Savg if (nvlist_print_json_string(fp, val[i]) == -1) 233260710Savg return (-1); 234260710Savg } 235260710Savg FPRINTF(fp, "]"); 236260710Savg break; 237260710Savg } 238260710Savg 239260710Savg case DATA_TYPE_NVLIST_ARRAY: { 240260710Savg nvlist_t **val; 241260710Savg uint_t valsz, i; 242260710Savg VERIFY0(nvpair_value_nvlist_array(curr, &val, &valsz)); 243260710Savg FPRINTF(fp, "["); 244260710Savg for (i = 0; i < valsz; i++) { 245260710Savg if (i > 0) 246260710Savg FPRINTF(fp, ","); 247260710Savg if (nvlist_print_json(fp, val[i]) == -1) 248260710Savg return (-1); 249260710Savg } 250260710Savg FPRINTF(fp, "]"); 251260710Savg break; 252260710Savg } 253260710Savg 254260710Savg case DATA_TYPE_BOOLEAN_ARRAY: { 255260710Savg boolean_t *val; 256260710Savg uint_t valsz, i; 257260710Savg VERIFY0(nvpair_value_boolean_array(curr, &val, &valsz)); 258260710Savg FPRINTF(fp, "["); 259260710Savg for (i = 0; i < valsz; i++) { 260260710Savg if (i > 0) 261260710Savg FPRINTF(fp, ","); 262260710Savg FPRINTF(fp, val[i] == B_TRUE ? 263260710Savg "true" : "false"); 264260710Savg } 265260710Savg FPRINTF(fp, "]"); 266260710Savg break; 267260710Savg } 268260710Savg 269260710Savg case DATA_TYPE_BYTE_ARRAY: { 270260710Savg uchar_t *val; 271260710Savg uint_t valsz, i; 272260710Savg VERIFY0(nvpair_value_byte_array(curr, &val, &valsz)); 273260710Savg FPRINTF(fp, "["); 274260710Savg for (i = 0; i < valsz; i++) { 275260710Savg if (i > 0) 276260710Savg FPRINTF(fp, ","); 277260710Savg FPRINTF(fp, "%hhu", val[i]); 278260710Savg } 279260710Savg FPRINTF(fp, "]"); 280260710Savg break; 281260710Savg } 282260710Savg 283260710Savg case DATA_TYPE_UINT8_ARRAY: { 284260710Savg uint8_t *val; 285260710Savg uint_t valsz, i; 286260710Savg VERIFY0(nvpair_value_uint8_array(curr, &val, &valsz)); 287260710Savg FPRINTF(fp, "["); 288260710Savg for (i = 0; i < valsz; i++) { 289260710Savg if (i > 0) 290260710Savg FPRINTF(fp, ","); 291260710Savg FPRINTF(fp, "%hhu", val[i]); 292260710Savg } 293260710Savg FPRINTF(fp, "]"); 294260710Savg break; 295260710Savg } 296260710Savg 297260710Savg case DATA_TYPE_INT8_ARRAY: { 298260710Savg int8_t *val; 299260710Savg uint_t valsz, i; 300260710Savg VERIFY0(nvpair_value_int8_array(curr, &val, &valsz)); 301260710Savg FPRINTF(fp, "["); 302260710Savg for (i = 0; i < valsz; i++) { 303260710Savg if (i > 0) 304260710Savg FPRINTF(fp, ","); 305275552Sdelphij FPRINTF(fp, "%hhd", val[i]); 306260710Savg } 307260710Savg FPRINTF(fp, "]"); 308260710Savg break; 309260710Savg } 310260710Savg 311260710Savg case DATA_TYPE_UINT16_ARRAY: { 312260710Savg uint16_t *val; 313260710Savg uint_t valsz, i; 314260710Savg VERIFY0(nvpair_value_uint16_array(curr, &val, &valsz)); 315260710Savg FPRINTF(fp, "["); 316260710Savg for (i = 0; i < valsz; i++) { 317260710Savg if (i > 0) 318260710Savg FPRINTF(fp, ","); 319260710Savg FPRINTF(fp, "%hu", val[i]); 320260710Savg } 321260710Savg FPRINTF(fp, "]"); 322260710Savg break; 323260710Savg } 324260710Savg 325260710Savg case DATA_TYPE_INT16_ARRAY: { 326260710Savg int16_t *val; 327260710Savg uint_t valsz, i; 328260710Savg VERIFY0(nvpair_value_int16_array(curr, &val, &valsz)); 329260710Savg FPRINTF(fp, "["); 330260710Savg for (i = 0; i < valsz; i++) { 331260710Savg if (i > 0) 332260710Savg FPRINTF(fp, ","); 333275552Sdelphij FPRINTF(fp, "%hd", val[i]); 334260710Savg } 335260710Savg FPRINTF(fp, "]"); 336260710Savg break; 337260710Savg } 338260710Savg 339260710Savg case DATA_TYPE_UINT32_ARRAY: { 340260710Savg uint32_t *val; 341260710Savg uint_t valsz, i; 342260710Savg VERIFY0(nvpair_value_uint32_array(curr, &val, &valsz)); 343260710Savg FPRINTF(fp, "["); 344260710Savg for (i = 0; i < valsz; i++) { 345260710Savg if (i > 0) 346260710Savg FPRINTF(fp, ","); 347260710Savg FPRINTF(fp, "%u", val[i]); 348260710Savg } 349260710Savg FPRINTF(fp, "]"); 350260710Savg break; 351260710Savg } 352260710Savg 353260710Savg case DATA_TYPE_INT32_ARRAY: { 354260710Savg int32_t *val; 355260710Savg uint_t valsz, i; 356260710Savg VERIFY0(nvpair_value_int32_array(curr, &val, &valsz)); 357260710Savg FPRINTF(fp, "["); 358260710Savg for (i = 0; i < valsz; i++) { 359260710Savg if (i > 0) 360260710Savg FPRINTF(fp, ","); 361260710Savg FPRINTF(fp, "%d", val[i]); 362260710Savg } 363260710Savg FPRINTF(fp, "]"); 364260710Savg break; 365260710Savg } 366260710Savg 367260710Savg case DATA_TYPE_UINT64_ARRAY: { 368260710Savg uint64_t *val; 369260710Savg uint_t valsz, i; 370260710Savg VERIFY0(nvpair_value_uint64_array(curr, &val, &valsz)); 371260710Savg FPRINTF(fp, "["); 372260710Savg for (i = 0; i < valsz; i++) { 373260710Savg if (i > 0) 374260710Savg FPRINTF(fp, ","); 375260710Savg FPRINTF(fp, "%llu", 376260710Savg (unsigned long long)val[i]); 377260710Savg } 378260710Savg FPRINTF(fp, "]"); 379260710Savg break; 380260710Savg } 381260710Savg 382260710Savg case DATA_TYPE_INT64_ARRAY: { 383260710Savg int64_t *val; 384260710Savg uint_t valsz, i; 385260710Savg VERIFY0(nvpair_value_int64_array(curr, &val, &valsz)); 386260710Savg FPRINTF(fp, "["); 387260710Savg for (i = 0; i < valsz; i++) { 388260710Savg if (i > 0) 389260710Savg FPRINTF(fp, ","); 390260710Savg FPRINTF(fp, "%lld", (long long)val[i]); 391260710Savg } 392260710Savg FPRINTF(fp, "]"); 393260710Savg break; 394260710Savg } 395260710Savg 396260710Savg case DATA_TYPE_UNKNOWN: 397260710Savg return (-1); 398260710Savg } 399260710Savg } 400260710Savg 401260710Savg FPRINTF(fp, "}"); 402260710Savg return (0); 403260710Savg} 404