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;
128 for (i = 0; i < list->ljil_item_count; i++) {
130 llapi_err_noerrno(LLAPI_MSG_ERROR,
131 "%d json items but %d is NULL!",
132 list->ljil_item_count, i);
133 /* Don't bomb out here so that we still emit
138 fprintf(fp, "\"%s\": ", item->lji_key);
139 switch (item->lji_type) {
140 case LLAPI_JSON_INTEGER:
141 fprintf(fp, "%d", item->lji_integer);
143 case LLAPI_JSON_BIGNUM:
144 fprintf(fp, LPU64, item->lji_u64);
146 case LLAPI_JSON_REAL:
147 fprintf(fp, "%f", item->lji_real);
149 case LLAPI_JSON_STRING:
150 if (llapi_json_escape_string(&escaped_string,
151 item->lji_string) < 0) {
152 if (escaped_string != NULL)
153 free(escaped_string);
157 fprintf(fp, "\"%s\"", escaped_string);
159 if (escaped_string != NULL)
160 free(escaped_string);
163 llapi_err_noerrno(LLAPI_MSG_ERROR,
164 "Invalid item type: %d", item->lji_type);
165 /* Ensure valid JSON */
170 if (i < list->ljil_item_count - 1)
173 item = item->lji_next;
180 /** Create a list to hold JSON items.
181 * \param[out] json_items Item list handle, allocated here
183 * \retval 0 on success.
184 * \retval -errno on error.
186 int llapi_json_init_list(struct llapi_json_item_list **json_items)
188 struct llapi_json_item_list *new_list;
190 new_list = calloc(1, sizeof(*new_list));
191 if (new_list == NULL)
194 new_list->ljil_item_count = 0;
196 *json_items = new_list;
201 /** Deallocate a list of JSON items.
202 * \param json_items Item list handle, deallocated here
204 * \retval 0 on success.
205 * \retval -errno on error.
207 int llapi_json_destroy_list(struct llapi_json_item_list **json_items)
210 struct llapi_json_item_list *list;
211 struct llapi_json_item *cur_item;
212 struct llapi_json_item *last_item;
214 if (json_items == NULL || *json_items == NULL)
218 cur_item = list->ljil_items;
220 for (i = 0; i < list->ljil_item_count; i++) {
221 if (cur_item == NULL) {
222 llapi_err_noerrno(LLAPI_MSG_ERROR,
223 "%d json items but %d is NULL!",
224 list->ljil_item_count, i);
228 if (cur_item->lji_key != NULL)
229 free(cur_item->lji_key);
231 if (cur_item->lji_type == LLAPI_JSON_STRING
232 && cur_item->lji_string != NULL)
233 free(cur_item->lji_string);
235 last_item = cur_item;
236 cur_item = last_item->lji_next;
246 /** Add an item to a list of JSON items.
247 * \param json_items Item list handle
248 * \param key Item key name
249 * \param type Item key type
250 * \param val Item key value
252 * \retval 0 on success.
253 * \retval -errno on error.
255 int llapi_json_add_item(struct llapi_json_item_list **json_items,
256 char *key, __u32 type, void *val)
258 struct llapi_json_item_list *list;
259 struct llapi_json_item *new_item;
261 if (json_items == NULL || *json_items == NULL)
269 new_item = calloc(1, sizeof(*new_item));
270 if (new_item == NULL)
273 new_item->lji_key = calloc(1, strlen(key) + 1);
274 if (new_item->lji_key == NULL)
277 strncpy(new_item->lji_key, key, strlen(key));
278 new_item->lji_type = type;
279 new_item->lji_next = NULL;
281 switch (new_item->lji_type) {
282 case LLAPI_JSON_INTEGER:
283 new_item->lji_integer = *(int *)val;
285 case LLAPI_JSON_BIGNUM:
286 new_item->lji_u64 = *(__u64 *)val;
288 case LLAPI_JSON_REAL:
289 new_item->lji_real = *(double *)val;
291 case LLAPI_JSON_STRING:
292 new_item->lji_string = calloc(1, strlen((char *)val) + 1);
293 if (new_item->lji_string == NULL)
295 strncpy(new_item->lji_string,
296 (char *)val, strlen((char *)val));
299 llapi_err_noerrno(LLAPI_MSG_ERROR, "Unknown JSON type: %d",
304 if (list->ljil_item_count == 0) {
305 list->ljil_items = new_item;
307 new_item->lji_next = list->ljil_items;
308 list->ljil_items = new_item;
310 list->ljil_item_count++;