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 <libcfs/util/string.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;
262 if (json_items == NULL || *json_items == NULL)
270 new_item = calloc(1, sizeof(*new_item));
271 if (new_item == NULL)
274 len = strlen(key) + 1;
275 new_item->lji_key = calloc(len, sizeof(char));
276 if (new_item->lji_key == NULL)
279 strlcpy(new_item->lji_key, key, len);
280 new_item->lji_type = type;
281 new_item->lji_next = NULL;
283 switch (new_item->lji_type) {
284 case LLAPI_JSON_INTEGER:
285 new_item->lji_integer = *(int *)val;
287 case LLAPI_JSON_BIGNUM:
288 new_item->lji_u64 = *(__u64 *)val;
290 case LLAPI_JSON_REAL:
291 new_item->lji_real = *(double *)val;
293 case LLAPI_JSON_STRING:
294 len = strlen((char *)val) + 1;
295 new_item->lji_string = calloc(len, sizeof(char));
296 if (new_item->lji_string == NULL)
298 strlcpy(new_item->lji_string, (char *)val, len);
301 llapi_err_noerrno(LLAPI_MSG_ERROR, "Unknown JSON type: %d",
306 if (list->ljil_item_count == 0) {
307 list->ljil_items = new_item;
309 new_item->lji_next = list->ljil_items;
310 list->ljil_items = new_item;
312 list->ljil_item_count++;