4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * (C) Copyright 2014 Intel Corporation.
8 * All rights reserved. This program and the accompanying materials
9 * are made available under the terms of the GNU Lesser General Public License
10 * (LGPL) version 2.1 or (at your discretion) any later version.
11 * (LGPL) version 2.1 accompanies this distribution, and is available at
12 * http://www.gnu.org/licenses/lgpl-2.1.html
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
22 * lustre/utils/liblustreapi_json.c
24 * lustreapi library for json calls
26 * Author: Michael MacDonald <michael.macdonald@intel.com>
27 * Author: Bruno Faccini <bruno.faccini@intel.com>
37 #include <sys/types.h>
38 #ifdef HAVE_LINUX_UNISTD_H
39 #include <linux/unistd.h>
44 #include <liblustre.h>
45 #include <lustre/lustreapi.h>
47 /** Quick-n'-dirty JSON string escape routine.
48 * \param[out] out_string JSON-escaped string, allocated here
49 * \param[in] in_string Unescaped string
51 * \retval 0 on success.
52 * \retval -errno on error.
55 * http://www.ietf.org/rfc/rfc4627.txt (section 2.5)
57 int llapi_json_escape_string(char **out_string, char *in_string)
60 char escape_chars[] = {'\b', '\f', '\n', '\r', '\t', '"', '\\',
62 char *escaped_chars[] = {"\\\\b", "\\\\f", "\\\\n", "\\\\r",
63 "\\\\t", "\\\\\"", "\\\\\\\\"};
64 char *src = in_string;
65 char *idx, *dst, *tmp;
67 size_t tmp_len, escaped_length = strlen(in_string);
69 /* add up the extra space needed for the escapes */
71 idx = strchr(escape_chars, *src);
73 tmp = escaped_chars[idx - escape_chars];
74 escaped_length += strlen(tmp);
79 escaped_string = calloc(1, escaped_length + 1);
80 if (escaped_string == NULL)
85 for (i = 0; *src && i <= escaped_length; i++) {
86 idx = strchr(escape_chars, *src);
88 tmp = escaped_chars[idx - escape_chars];
89 tmp_len = strlen(tmp);
90 memcpy(dst, tmp, tmp_len);
102 *out_string = escaped_string;
107 /** Write a list of JSON items to a filehandle.
108 * \param json_items list of JSON items to be written
109 * \param fp open filehandle to use for write
111 * \retval 0 on success.
112 * \retval -errno on error.
114 int llapi_json_write_list(struct llapi_json_item_list **json_items, FILE *fp)
117 char *escaped_string = NULL;
118 struct llapi_json_item_list *list;
119 struct llapi_json_item *item;
121 if (json_items == NULL || *json_items == NULL)
125 item = list->ljil_items;
127 if (fprintf(fp, "{") < 0)
129 for (i = 0; i < list->ljil_item_count; i++) {
131 llapi_err_noerrno(LLAPI_MSG_ERROR,
132 "%d json items but %d is NULL!",
133 list->ljil_item_count, i);
134 /* Don't bomb out here so that we still emit
139 if (fprintf(fp, "\"%s\": ", item->lji_key) < 0)
141 switch (item->lji_type) {
142 case LLAPI_JSON_INTEGER:
143 if (fprintf(fp, "%d", item->lji_integer) < 0)
146 case LLAPI_JSON_BIGNUM:
147 if (fprintf(fp, LPU64, item->lji_u64) < 0)
150 case LLAPI_JSON_REAL:
151 if (fprintf(fp, "%f", item->lji_real) < 0)
154 case LLAPI_JSON_STRING:
155 if (llapi_json_escape_string(&escaped_string,
156 item->lji_string) < 0) {
157 if (escaped_string != NULL)
158 free(escaped_string);
162 if (fprintf(fp, "\"%s\"", escaped_string) < 0) {
163 if (escaped_string != NULL)
164 free(escaped_string);
168 if (escaped_string != NULL)
169 free(escaped_string);
172 llapi_err_noerrno(LLAPI_MSG_ERROR,
173 "Invalid item type: %d", item->lji_type);
174 /* Ensure valid JSON */
175 if (fprintf(fp, "\"\"") < 0)
180 if (i < list->ljil_item_count - 1)
181 if (fprintf(fp, ", ") < 0)
184 item = item->lji_next;
186 if (fprintf(fp, "}\n") < 0)
192 /** Create a list to hold JSON items.
193 * \param[out] json_items Item list handle, allocated here
195 * \retval 0 on success.
196 * \retval -errno on error.
198 int llapi_json_init_list(struct llapi_json_item_list **json_items)
200 struct llapi_json_item_list *new_list;
202 new_list = calloc(1, sizeof(*new_list));
203 if (new_list == NULL)
206 new_list->ljil_item_count = 0;
208 *json_items = new_list;
213 /** Deallocate a list of JSON items.
214 * \param json_items Item list handle, deallocated here
216 * \retval 0 on success.
217 * \retval -errno on error.
219 int llapi_json_destroy_list(struct llapi_json_item_list **json_items)
222 struct llapi_json_item_list *list;
223 struct llapi_json_item *cur_item;
224 struct llapi_json_item *last_item;
226 if (json_items == NULL || *json_items == NULL)
230 cur_item = list->ljil_items;
232 for (i = 0; i < list->ljil_item_count; i++) {
233 if (cur_item == NULL) {
234 llapi_err_noerrno(LLAPI_MSG_ERROR,
235 "%d json items but %d is NULL!",
236 list->ljil_item_count, i);
240 if (cur_item->lji_key != NULL)
241 free(cur_item->lji_key);
243 if (cur_item->lji_type == LLAPI_JSON_STRING
244 && cur_item->lji_string != NULL)
245 free(cur_item->lji_string);
247 last_item = cur_item;
248 cur_item = last_item->lji_next;
258 /** Add an item to a list of JSON items.
259 * \param json_items Item list handle
260 * \param key Item key name
261 * \param type Item key type
262 * \param val Item key value
264 * \retval 0 on success.
265 * \retval -errno on error.
267 int llapi_json_add_item(struct llapi_json_item_list **json_items,
268 char *key, __u32 type, void *val)
270 struct llapi_json_item_list *list;
271 struct llapi_json_item *new_item;
273 if (json_items == NULL || *json_items == NULL)
281 new_item = calloc(1, sizeof(*new_item));
282 if (new_item == NULL)
285 new_item->lji_key = calloc(1, strlen(key) + 1);
286 if (new_item->lji_key == NULL)
289 strncpy(new_item->lji_key, key, strlen(key));
290 new_item->lji_type = type;
291 new_item->lji_next = NULL;
293 switch (new_item->lji_type) {
294 case LLAPI_JSON_INTEGER:
295 new_item->lji_integer = *(int *)val;
297 case LLAPI_JSON_BIGNUM:
298 new_item->lji_u64 = *(__u64 *)val;
300 case LLAPI_JSON_REAL:
301 new_item->lji_real = *(double *)val;
303 case LLAPI_JSON_STRING:
304 new_item->lji_string = calloc(1, strlen((char *)val) + 1);
305 if (new_item->lji_string == NULL)
307 strncpy(new_item->lji_string,
308 (char *)val, strlen((char *)val));
311 llapi_err_noerrno(LLAPI_MSG_ERROR, "Unknown JSON type: %d",
316 if (list->ljil_item_count == 0) {
317 list->ljil_items = new_item;
319 new_item->lji_next = list->ljil_items;
320 list->ljil_items = new_item;
322 list->ljil_item_count++;