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 <strings.h>
  17 
  18 #include "libnvpair.h"
  19 
  20 /*
  21  * When formatting a string for JSON output we must escape certain characters,
  22  * as described in RFC4627.  This applies to both member names and
  23  * DATA_TYPE_STRING values.
  24  */
  25 static void
  26 nvlist_print_json_string(FILE *fp, const char *input)
  27 {
  28         char c;
  29 
  30         fprintf(fp, "\"");
  31         while ((c = *input++) != '\0') {
  32                 switch (c) {
  33                 case '"':
  34                         fprintf(fp, "\\\"");
  35                         break;
  36                 case '\n':
  37                         fprintf(fp, "\\n");
  38                         break;
  39                 case '\r':
  40                         fprintf(fp, "\\r");
  41                         break;
  42                 case '\\':
  43                         fprintf(fp, "\\\\");
  44                         break;
  45                 case '\f':
  46                         fprintf(fp, "\\f");
  47                         break;
  48                 case '\t':
  49                         fprintf(fp, "\\t");
  50                         break;
  51                 case '\b':
  52                         fprintf(fp, "\\b");
  53                         break;
  54                 default:
  55                         if (c >= 0x00 && c <= 0x1f) {
  56                                 fprintf(fp, "\\u00%02hhu", c);
  57                         } else {
  58                                 fprintf(fp, "%c", c);
  59                         }
  60                         break;
  61                 }
  62         }
  63         fprintf(fp, "\"");
  64 }
  65 
  66 void
  67 nvlist_print_json(FILE *fp, nvlist_t *nvl)
  68 {
  69         nvpair_t *curr;
  70         boolean_t first = B_TRUE;
  71 
  72         fprintf(fp, "{");
  73 
  74         for (curr = nvlist_next_nvpair(nvl, NULL); curr;
  75             curr = nvlist_next_nvpair(nvl, curr)) {
  76                 data_type_t type = nvpair_type(curr);
  77 
  78                 if (!first)
  79                         fprintf(fp, ",");
  80                 else
  81                         first = B_FALSE;
  82 
  83                 nvlist_print_json_string(fp, nvpair_name(curr));
  84                 fprintf(fp, ":");
  85 
  86                 switch (type) {
  87                 case DATA_TYPE_STRING: {
  88                         char *string;
  89                         nvpair_value_string(curr, &string);
  90                         nvlist_print_json_string(fp, string);
  91                         break;
  92                 }
  93 
  94                 case DATA_TYPE_BOOLEAN: {
  95                         fprintf(fp, "true");
  96                         break;
  97                 }
  98 
  99                 case DATA_TYPE_BOOLEAN_VALUE: {
 100                         boolean_t boolean;
 101                         nvpair_value_boolean_value(curr, &boolean);
 102                         fprintf(fp, "%s", boolean == B_TRUE ? "true" :
 103                             "false");
 104                         break;
 105                 }
 106 
 107                 case DATA_TYPE_BYTE: {
 108                         uchar_t val;
 109                         nvpair_value_byte(curr, &val);
 110                         fprintf(fp, "%hhu", val);
 111                         break;
 112                 }
 113 
 114                 case DATA_TYPE_INT8: {
 115                         int8_t val;
 116                         nvpair_value_int8(curr, &val);
 117                         fprintf(fp, "%hhd", val);
 118                         break;
 119                 }
 120 
 121                 case DATA_TYPE_UINT8: {
 122                         uint8_t val;
 123                         nvpair_value_uint8(curr, &val);
 124                         fprintf(fp, "%hhu", val);
 125                         break;
 126                 }
 127 
 128                 case DATA_TYPE_INT16: {
 129                         int16_t val;
 130                         nvpair_value_int16(curr, &val);
 131                         fprintf(fp, "%hd", val);
 132                         break;
 133                 }
 134 
 135                 case DATA_TYPE_UINT16: {
 136                         uint16_t val;
 137                         nvpair_value_uint16(curr, &val);
 138                         fprintf(fp, "%hu", val);
 139                         break;
 140                 }
 141 
 142                 case DATA_TYPE_INT32: {
 143                         int32_t val;
 144                         nvpair_value_int32(curr, &val);
 145                         fprintf(fp, "%d", val);
 146                         break;
 147                 }
 148 
 149                 case DATA_TYPE_UINT32: {
 150                         uint32_t val;
 151                         nvpair_value_uint32(curr, &val);
 152                         fprintf(fp, "%u", val);
 153                         break;
 154                 }
 155 
 156                 case DATA_TYPE_INT64: {
 157                         int64_t val;
 158                         nvpair_value_int64(curr, &val);
 159                         fprintf(fp, "%lld", val);
 160                         break;
 161                 }
 162 
 163                 case DATA_TYPE_UINT64: {
 164                         uint64_t val;
 165                         nvpair_value_uint64(curr, &val);
 166                         fprintf(fp, "%llu", val);
 167                         break;
 168                 }
 169 
 170                 case DATA_TYPE_HRTIME: {
 171                         hrtime_t val;
 172                         nvpair_value_hrtime(curr, &val);
 173                         fprintf(fp, "%llu", val);
 174                         break;
 175                 }
 176 
 177                 case DATA_TYPE_DOUBLE: {
 178                         double val;
 179                         nvpair_value_double(curr, &val);
 180                         fprintf(fp, "%f", val);
 181                         break;
 182                 }
 183 
 184                 case DATA_TYPE_NVLIST: {
 185                         nvlist_t *val;
 186                         nvpair_value_nvlist(curr, &val);
 187                         nvlist_print_json(fp, val);
 188                         break;
 189                 }
 190 
 191                 case DATA_TYPE_STRING_ARRAY: {
 192                         char **val;
 193                         uint_t valsz, pos;
 194                         nvpair_value_string_array(curr, &val, &valsz);
 195                         fprintf(fp, "[");
 196                         for (pos = 0; pos < valsz; pos++) {
 197                                 if (pos > 0)
 198                                         fprintf(fp, ",");
 199                                 nvlist_print_json_string(fp, val[pos]);
 200                         }
 201                         fprintf(fp, "]");
 202                         break;
 203                 }
 204 
 205                 case DATA_TYPE_NVLIST_ARRAY: {
 206                         nvlist_t **val;
 207                         uint_t valsz, pos;
 208                         nvpair_value_nvlist_array(curr, &val, &valsz);
 209                         fprintf(fp, "[");
 210                         for (pos = 0; pos < valsz; pos++) {
 211                                 if (pos > 0)
 212                                         fprintf(fp, ",");
 213                                 nvlist_print_json(fp, val[pos]);
 214                         }
 215                         fprintf(fp, "]");
 216                         break;
 217                 }
 218 
 219                 case DATA_TYPE_BOOLEAN_ARRAY: {
 220                         boolean_t *val;
 221                         uint_t valsz, pos;
 222                         nvpair_value_boolean_array(curr, &val, &valsz);
 223                         fprintf(fp, "[");
 224                         for (pos = 0; pos < valsz; pos++) {
 225                                 if (pos > 0)
 226                                         fprintf(fp, ",");
 227                                 fprintf(fp, val[pos] == B_TRUE ?
 228                                     "true" : "false");
 229                         }
 230                         fprintf(fp, "]");
 231                         break;
 232                 }
 233 
 234                 case DATA_TYPE_BYTE_ARRAY: {
 235                         uchar_t *val;
 236                         uint_t valsz, pos;
 237                         nvpair_value_byte_array(curr, &val, &valsz);
 238                         fprintf(fp, "[");
 239                         for (pos = 0; pos < valsz; pos++) {
 240                                 if (pos > 0)
 241                                         fprintf(fp, ",");
 242                                 fprintf(fp, "%hhu", val[pos]);
 243                         }
 244                         fprintf(fp, "]");
 245                         break;
 246                 }
 247 
 248                 case DATA_TYPE_UINT8_ARRAY: {
 249                         uint8_t *val;
 250                         uint_t valsz, pos;
 251                         nvpair_value_uint8_array(curr, &val, &valsz);
 252                         fprintf(fp, "[");
 253                         for (pos = 0; pos < valsz; pos++) {
 254                                 if (pos > 0)
 255                                         fprintf(fp, ",");
 256                                 fprintf(fp, "%hhu", val[pos]);
 257                         }
 258                         fprintf(fp, "]");
 259                         break;
 260                 }
 261 
 262                 case DATA_TYPE_INT8_ARRAY: {
 263                         int8_t *val;
 264                         uint_t valsz, pos;
 265                         nvpair_value_int8_array(curr, &val, &valsz);
 266                         fprintf(fp, "[");
 267                         for (pos = 0; pos < valsz; pos++) {
 268                                 if (pos > 0)
 269                                         fprintf(fp, ",");
 270                                 fprintf(fp, "%hd", val[pos]);
 271                         }
 272                         fprintf(fp, "]");
 273                         break;
 274                 }
 275 
 276                 case DATA_TYPE_UINT16_ARRAY: {
 277                         uint16_t *val;
 278                         uint_t valsz, pos;
 279                         nvpair_value_uint16_array(curr, &val, &valsz);
 280                         fprintf(fp, "[");
 281                         for (pos = 0; pos < valsz; pos++) {
 282                                 if (pos > 0)
 283                                         fprintf(fp, ",");
 284                                 fprintf(fp, "%hu", val[pos]);
 285                         }
 286                         fprintf(fp, "]");
 287                         break;
 288                 }
 289 
 290                 case DATA_TYPE_INT16_ARRAY: {
 291                         int16_t *val;
 292                         uint_t valsz, pos;
 293                         nvpair_value_int16_array(curr, &val, &valsz);
 294                         fprintf(fp, "[");
 295                         for (pos = 0; pos < valsz; pos++) {
 296                                 if (pos > 0)
 297                                         fprintf(fp, ",");
 298                                 fprintf(fp, "%hhd", val[pos]);
 299                         }
 300                         fprintf(fp, "]");
 301                         break;
 302                 }
 303 
 304                 case DATA_TYPE_UINT32_ARRAY: {
 305                         uint32_t *val;
 306                         uint_t valsz, pos;
 307                         nvpair_value_uint32_array(curr, &val, &valsz);
 308                         fprintf(fp, "[");
 309                         for (pos = 0; pos < valsz; pos++) {
 310                                 if (pos > 0)
 311                                         fprintf(fp, ",");
 312                                 fprintf(fp, "%u", val[pos]);
 313                         }
 314                         fprintf(fp, "]");
 315                         break;
 316                 }
 317 
 318                 case DATA_TYPE_INT32_ARRAY: {
 319                         int32_t *val;
 320                         uint_t valsz, pos;
 321                         nvpair_value_int32_array(curr, &val, &valsz);
 322                         fprintf(fp, "[");
 323                         for (pos = 0; pos < valsz; pos++) {
 324                                 if (pos > 0)
 325                                         fprintf(fp, ",");
 326                                 fprintf(fp, "%d", val[pos]);
 327                         }
 328                         fprintf(fp, "]");
 329                         break;
 330                 }
 331 
 332                 case DATA_TYPE_UINT64_ARRAY: {
 333                         uint64_t *val;
 334                         uint_t valsz, pos;
 335                         nvpair_value_uint64_array(curr, &val, &valsz);
 336                         fprintf(fp, "[");
 337                         for (pos = 0; pos < valsz; pos++) {
 338                                 if (pos > 0)
 339                                         fprintf(fp, ",");
 340                                 fprintf(fp, "%llu", val[pos]);
 341                         }
 342                         fprintf(fp, "]");
 343                         break;
 344                 }
 345 
 346                 case DATA_TYPE_INT64_ARRAY: {
 347                         int64_t *val;
 348                         uint_t valsz, pos;
 349                         nvpair_value_int64_array(curr, &val, &valsz);
 350                         fprintf(fp, "[");
 351                         for (pos = 0; pos < valsz; pos++) {
 352                                 if (pos > 0)
 353                                         fprintf(fp, ",");
 354                                 fprintf(fp, "%lld", val[pos]);
 355                         }
 356                         fprintf(fp, "]");
 357                         break;
 358                 }
 359 
 360                 case DATA_TYPE_UNKNOWN:
 361                         fprintf(fp, "null");
 362                         break;
 363                 }
 364         }
 365 
 366         fprintf(fp, "}");
 367 }