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