2 * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include "json_script.h"
23 struct json_script_ctx *ctx;
24 struct blob_attr *vars;
30 int (*cb)(struct json_call *call, struct blob_attr *cur);
33 static int json_process_expr(struct json_call *call, struct blob_attr *cur);
34 static int json_process_cmd(struct json_call *call, struct blob_attr *cur);
35 static int eval_string(struct json_call *call, struct blob_buf *buf, const char *name, const char *pattern);
37 struct json_script_file *
38 json_script_file_from_blobmsg(const char *name, void *data, int len)
40 struct json_script_file *f;
45 name_len = strlen(name) + 1;
47 f = calloc_a(sizeof(*f) + len, &new_name, name_len);
51 memcpy(f->data, data, len);
53 f->avl.key = strcpy(new_name, name);
58 static struct json_script_file *
59 json_script_get_file(struct json_script_ctx *ctx, const char *filename)
61 struct json_script_file *f;
63 f = avl_find_element(&ctx->files, filename, f, avl);
67 f = ctx->handle_file(ctx, filename);
71 avl_insert(&ctx->files, &f->avl);
75 static void __json_script_run(struct json_call *call, struct json_script_file *file,
76 struct blob_attr *context)
78 struct json_script_ctx *ctx = call->ctx;
80 if (file->seq == call->seq) {
82 ctx->handle_error(ctx, "Recursive include", context);
87 file->seq = call->seq;
89 json_process_cmd(call, file->data);
94 const char *json_script_find_var(struct json_script_ctx *ctx, struct blob_attr *vars,
97 struct blob_attr *cur;
100 blobmsg_for_each_attr(cur, vars, rem) {
101 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
104 if (strcmp(blobmsg_name(cur), name) != 0)
107 return blobmsg_data(cur);
110 return ctx->handle_var(ctx, name, vars);
114 msg_find_var(struct json_call *call, const char *name)
116 return json_script_find_var(call->ctx, call->vars, name);
120 json_get_tuple(struct blob_attr *cur, struct blob_attr **tb, int t1, int t2)
122 static struct blobmsg_policy expr_tuple[3] = {
123 { .type = BLOBMSG_TYPE_STRING },
128 expr_tuple[1].type = t1;
129 expr_tuple[2].type = t2;
130 blobmsg_parse_array(expr_tuple, 3, tb, blobmsg_data(cur), blobmsg_data_len(cur));
133 static int handle_if(struct json_call *call, struct blob_attr *expr)
135 struct blob_attr *tb[4];
138 static const struct blobmsg_policy if_tuple[4] = {
139 { .type = BLOBMSG_TYPE_STRING },
140 { .type = BLOBMSG_TYPE_ARRAY },
141 { .type = BLOBMSG_TYPE_ARRAY },
142 { .type = BLOBMSG_TYPE_ARRAY },
145 blobmsg_parse_array(if_tuple, 4, tb, blobmsg_data(expr), blobmsg_data_len(expr));
147 if (!tb[1] || !tb[2])
150 ret = json_process_expr(call, tb[1]);
155 return json_process_cmd(call, tb[2]);
160 return json_process_cmd(call, tb[3]);
163 static int handle_case(struct json_call *call, struct blob_attr *expr)
165 struct blob_attr *tb[3], *cur;
169 json_get_tuple(expr, tb, BLOBMSG_TYPE_STRING, BLOBMSG_TYPE_TABLE);
170 if (!tb[1] || !tb[2])
173 var = msg_find_var(call, blobmsg_data(tb[1]));
177 blobmsg_for_each_attr(cur, tb[2], rem) {
178 if (!strcmp(var, blobmsg_name(cur)))
179 return json_process_cmd(call, cur);
185 static int handle_return(struct json_call *call, struct blob_attr *expr)
190 static int handle_include(struct json_call *call, struct blob_attr *expr)
192 struct blob_attr *tb[3];
193 struct json_script_file *f;
195 json_get_tuple(expr, tb, BLOBMSG_TYPE_STRING, 0);
199 f = json_script_get_file(call->ctx, blobmsg_data(tb[1]));
203 __json_script_run(call, f, expr);
207 static const struct json_handler cmd[] = {
209 { "case", handle_case },
210 { "return", handle_return },
211 { "include", handle_include },
214 static int eq_regex_cmp(const char *str, const char *pattern, bool regex)
220 return !strcmp(str, pattern);
222 if (regcomp(®, pattern, REG_EXTENDED | REG_NOSUB))
225 ret = !regexec(®, str, 0, NULL, 0);
231 static int expr_eq_regex(struct json_call *call, struct blob_attr *expr, bool regex)
233 struct json_script_ctx *ctx = call->ctx;
234 struct blob_attr *tb[3], *cur;
238 json_get_tuple(expr, tb, BLOBMSG_TYPE_STRING, 0);
239 if (!tb[1] || !tb[2])
242 var = msg_find_var(call, blobmsg_data(tb[1]));
246 switch(blobmsg_type(tb[2])) {
247 case BLOBMSG_TYPE_STRING:
248 return eq_regex_cmp(var, blobmsg_data(tb[2]), regex);
249 case BLOBMSG_TYPE_ARRAY:
250 blobmsg_for_each_attr(cur, tb[2], rem) {
251 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) {
252 ctx->handle_error(ctx, "Unexpected element type", cur);
256 if (eq_regex_cmp(var, blobmsg_data(cur), regex))
261 ctx->handle_error(ctx, "Unexpected element type", tb[2]);
266 static int handle_expr_eq(struct json_call *call, struct blob_attr *expr)
268 return expr_eq_regex(call, expr, false);
271 static int handle_expr_regex(struct json_call *call, struct blob_attr *expr)
273 return expr_eq_regex(call, expr, true);
276 static int handle_expr_has(struct json_call *call, struct blob_attr *expr)
278 struct json_script_ctx *ctx = call->ctx;
279 struct blob_attr *tb[3], *cur;
282 json_get_tuple(expr, tb, 0, 0);
286 switch(blobmsg_type(tb[1])) {
287 case BLOBMSG_TYPE_STRING:
288 return !!msg_find_var(call, blobmsg_data(tb[1]));
289 case BLOBMSG_TYPE_ARRAY:
290 blobmsg_for_each_attr(cur, tb[1], rem) {
291 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) {
292 ctx->handle_error(ctx, "Unexpected element type", cur);
296 if (msg_find_var(call, blobmsg_data(cur)))
301 ctx->handle_error(ctx, "Unexpected element type", tb[1]);
306 static int expr_and_or(struct json_call *call, struct blob_attr *expr, bool and)
308 struct blob_attr *cur;
312 blobmsg_for_each_attr(cur, expr, rem) {
316 ret = json_process_expr(call, cur);
327 static int handle_expr_and(struct json_call *call, struct blob_attr *expr)
329 return expr_and_or(call, expr, 1);
332 static int handle_expr_or(struct json_call *call, struct blob_attr *expr)
334 return expr_and_or(call, expr, 0);
337 static int handle_expr_not(struct json_call *call, struct blob_attr *expr)
339 struct blob_attr *tb[3];
342 json_get_tuple(expr, tb, BLOBMSG_TYPE_ARRAY, 0);
346 ret = json_process_expr(call, tb[1]);
352 static int handle_expr_isdir(struct json_call *call, struct blob_attr *expr)
354 static struct blob_buf b;
355 struct blob_attr *tb[3];
356 const char *pattern, *path;
360 json_get_tuple(expr, tb, BLOBMSG_TYPE_STRING, 0);
361 if (!tb[1] || blobmsg_type(tb[1]) != BLOBMSG_TYPE_STRING)
363 pattern = blobmsg_data(tb[1]);
365 blob_buf_init(&b, 0);
366 ret = eval_string(call, &b, NULL, pattern);
369 path = blobmsg_data(blob_data(b.head));
370 ret = stat(path, &s);
373 return S_ISDIR(s.st_mode);
376 static const struct json_handler expr[] = {
377 { "eq", handle_expr_eq },
378 { "regex", handle_expr_regex },
379 { "has", handle_expr_has },
380 { "and", handle_expr_and },
381 { "or", handle_expr_or },
382 { "not", handle_expr_not },
383 { "isdir", handle_expr_isdir },
387 __json_process_type(struct json_call *call, struct blob_attr *cur,
388 const struct json_handler *h, int n, bool *found)
390 const char *name = blobmsg_data(blobmsg_data(cur));
393 for (i = 0; i < n; i++) {
394 if (strcmp(name, h[i].name) != 0)
398 return h[i].cb(call, cur);
405 static int json_process_expr(struct json_call *call, struct blob_attr *cur)
407 struct json_script_ctx *ctx = call->ctx;
411 if (blobmsg_type(cur) != BLOBMSG_TYPE_ARRAY ||
412 blobmsg_type(blobmsg_data(cur)) != BLOBMSG_TYPE_STRING) {
413 ctx->handle_error(ctx, "Unexpected element type", cur);
417 ret = __json_process_type(call, cur, expr, ARRAY_SIZE(expr), &found);
419 const char *name = blobmsg_data(blobmsg_data(cur));
420 ctx->handle_expr(ctx, name, cur, call->vars);
426 static int eval_string(struct json_call *call, struct blob_buf *buf, const char *name, const char *pattern)
428 char *dest, *next, *str;
433 dest = blobmsg_alloc_string_buffer(buf, name, 1);
437 next = alloca(strlen(pattern) + 1);
438 strcpy(next, pattern);
440 for (str = next; str; str = next) {
446 end = strchr(str, '%');
452 end = str + strlen(str);
458 cur = msg_find_var(call, str);
462 cur_len = strlen(cur);
475 new_buf = blobmsg_realloc_string_buffer(buf, len + cur_len + 1);
477 /* Make eval_string return -1 */
483 memcpy(dest + len, cur, cur_len);
488 blobmsg_add_string_buffer(buf);
496 static int cmd_add_string(struct json_call *call, const char *pattern)
498 return eval_string(call, &call->ctx->buf, NULL, pattern);
501 int json_script_eval_string(struct json_script_ctx *ctx, struct blob_attr *vars,
502 struct blob_buf *buf, const char *name,
505 struct json_call call = {
510 return eval_string(&call, buf, name, pattern);
513 static int cmd_process_strings(struct json_call *call, struct blob_attr *attr)
515 struct json_script_ctx *ctx = call->ctx;
516 struct blob_attr *cur;
521 blob_buf_init(&ctx->buf, 0);
522 c = blobmsg_open_array(&ctx->buf, NULL);
523 blobmsg_for_each_attr(cur, attr, rem) {
527 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) {
528 blobmsg_add_blob(&ctx->buf, cur);
532 ret = cmd_add_string(call, blobmsg_data(cur));
534 ctx->handle_error(ctx, "Unterminated variable reference in string", attr);
539 blobmsg_close_array(&ctx->buf, c);
544 static int __json_process_cmd(struct json_call *call, struct blob_attr *cur)
546 struct json_script_ctx *ctx = call->ctx;
551 if (blobmsg_type(cur) != BLOBMSG_TYPE_ARRAY ||
552 blobmsg_type(blobmsg_data(cur)) != BLOBMSG_TYPE_STRING) {
553 ctx->handle_error(ctx, "Unexpected element type", cur);
557 ret = __json_process_type(call, cur, cmd, ARRAY_SIZE(cmd), &found);
561 name = blobmsg_data(blobmsg_data(cur));
562 ret = cmd_process_strings(call, cur);
566 ctx->handle_command(ctx, name, blob_data(ctx->buf.head), call->vars);
571 static int json_process_cmd(struct json_call *call, struct blob_attr *block)
573 struct json_script_ctx *ctx = call->ctx;
574 struct blob_attr *cur;
579 if (blobmsg_type(block) != BLOBMSG_TYPE_ARRAY) {
580 ctx->handle_error(ctx, "Unexpected element type", block);
584 blobmsg_for_each_attr(cur, block, rem) {
588 switch(blobmsg_type(cur)) {
589 case BLOBMSG_TYPE_STRING:
591 return __json_process_cmd(call, block);
593 ret = json_process_cmd(call, cur);
604 void json_script_run_file(struct json_script_ctx *ctx, struct json_script_file *file,
605 struct blob_attr *vars)
607 static unsigned int _seq = 0;
608 struct json_call call = {
620 __json_script_run(&call, file, NULL);
623 void json_script_run(struct json_script_ctx *ctx, const char *name,
624 struct blob_attr *vars)
626 struct json_script_file *file;
628 file = json_script_get_file(ctx, name);
632 json_script_run_file(ctx, file, vars);
635 static void __json_script_file_free(struct json_script_file *f)
637 struct json_script_file *next;
645 __json_script_file_free(next);
649 json_script_free(struct json_script_ctx *ctx)
651 struct json_script_file *f, *next;
653 avl_remove_all_elements(&ctx->files, f, avl, next)
654 __json_script_file_free(f);
656 blob_buf_free(&ctx->buf);
660 __default_handle_error(struct json_script_ctx *ctx, const char *msg,
661 struct blob_attr *context)
666 __default_handle_var(struct json_script_ctx *ctx, const char *name,
667 struct blob_attr *vars)
673 __default_handle_expr(struct json_script_ctx *ctx, const char *name,
674 struct blob_attr *expr, struct blob_attr *vars)
676 ctx->handle_error(ctx, "Unknown expression type", expr);
680 static struct json_script_file *
681 __default_handle_file(struct json_script_ctx *ctx, const char *name)
686 void json_script_init(struct json_script_ctx *ctx)
688 avl_init(&ctx->files, avl_strcmp, false, NULL);
690 if (!ctx->handle_error)
691 ctx->handle_error = __default_handle_error;
693 if (!ctx->handle_var)
694 ctx->handle_var = __default_handle_var;
696 if (!ctx->handle_expr)
697 ctx->handle_expr = __default_handle_expr;
699 if (!ctx->handle_file)
700 ctx->handle_file = __default_handle_file;