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
;
313 blobmsg_for_each_attr(cur
, expr
, rem
) {
317 ret
= json_process_expr(call
, cur
);
328 static int handle_expr_and(struct json_call
*call
, struct blob_attr
*expr
)
330 return expr_and_or(call
, expr
, 1);
333 static int handle_expr_or(struct json_call
*call
, struct blob_attr
*expr
)
335 return expr_and_or(call
, expr
, 0);
338 static int handle_expr_not(struct json_call
*call
, struct blob_attr
*expr
)
340 struct blob_attr
*tb
[3];
343 json_get_tuple(expr
, tb
, BLOBMSG_TYPE_ARRAY
, 0);
347 ret
= json_process_expr(call
, tb
[1]);
353 static int handle_expr_isdir(struct json_call
*call
, struct blob_attr
*expr
)
355 static struct blob_buf b
;
356 struct blob_attr
*tb
[3];
357 const char *pattern
, *path
;
361 json_get_tuple(expr
, tb
, BLOBMSG_TYPE_STRING
, 0);
362 if (!tb
[1] || blobmsg_type(tb
[1]) != BLOBMSG_TYPE_STRING
)
364 pattern
= blobmsg_data(tb
[1]);
366 blob_buf_init(&b
, 0);
367 ret
= eval_string(call
, &b
, NULL
, pattern
);
370 path
= blobmsg_data(blob_data(b
.head
));
371 ret
= stat(path
, &s
);
374 return S_ISDIR(s
.st_mode
);
377 static const struct json_handler expr
[] = {
378 { "eq", handle_expr_eq
},
379 { "regex", handle_expr_regex
},
380 { "has", handle_expr_has
},
381 { "and", handle_expr_and
},
382 { "or", handle_expr_or
},
383 { "not", handle_expr_not
},
384 { "isdir", handle_expr_isdir
},
388 __json_process_type(struct json_call
*call
, struct blob_attr
*cur
,
389 const struct json_handler
*h
, int n
, bool *found
)
391 const char *name
= blobmsg_data(blobmsg_data(cur
));
394 for (i
= 0; i
< n
; i
++) {
395 if (strcmp(name
, h
[i
].name
) != 0)
399 return h
[i
].cb(call
, cur
);
406 static int json_process_expr(struct json_call
*call
, struct blob_attr
*cur
)
408 struct json_script_ctx
*ctx
= call
->ctx
;
412 if (blobmsg_type(cur
) != BLOBMSG_TYPE_ARRAY
||
413 blobmsg_type(blobmsg_data(cur
)) != BLOBMSG_TYPE_STRING
) {
414 ctx
->handle_error(ctx
, "Unexpected element type", cur
);
418 ret
= __json_process_type(call
, cur
, expr
, ARRAY_SIZE(expr
), &found
);
420 const char *name
= blobmsg_data(blobmsg_data(cur
));
421 ctx
->handle_expr(ctx
, name
, cur
, call
->vars
);
427 static int eval_string(struct json_call
*call
, struct blob_buf
*buf
, const char *name
, const char *pattern
)
429 char *dest
, *next
, *str
;
434 dest
= blobmsg_alloc_string_buffer(buf
, name
, 1);
438 next
= alloca(strlen(pattern
) + 1);
439 strcpy(next
, pattern
);
441 for (str
= next
; str
; str
= next
) {
447 end
= strchr(str
, '%');
453 end
= str
+ strlen(str
);
459 cur
= msg_find_var(call
, str
);
463 cur_len
= strlen(cur
);
476 new_buf
= blobmsg_realloc_string_buffer(buf
, len
+ cur_len
+ 1);
478 /* Make eval_string return -1 */
484 memcpy(dest
+ len
, cur
, cur_len
);
489 blobmsg_add_string_buffer(buf
);
497 static int cmd_add_string(struct json_call
*call
, const char *pattern
)
499 return eval_string(call
, &call
->ctx
->buf
, NULL
, pattern
);
502 int json_script_eval_string(struct json_script_ctx
*ctx
, struct blob_attr
*vars
,
503 struct blob_buf
*buf
, const char *name
,
506 struct json_call call
= {
511 return eval_string(&call
, buf
, name
, pattern
);
514 static int cmd_process_strings(struct json_call
*call
, struct blob_attr
*attr
)
516 struct json_script_ctx
*ctx
= call
->ctx
;
517 struct blob_attr
*cur
;
523 blob_buf_init(&ctx
->buf
, 0);
524 c
= blobmsg_open_array(&ctx
->buf
, NULL
);
525 blobmsg_for_each_attr(cur
, attr
, rem
) {
529 if (blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
) {
530 blobmsg_add_blob(&ctx
->buf
, cur
);
534 ret
= cmd_add_string(call
, blobmsg_data(cur
));
536 ctx
->handle_error(ctx
, "Unterminated variable reference in string", attr
);
541 blobmsg_close_array(&ctx
->buf
, c
);
546 static int __json_process_cmd(struct json_call
*call
, struct blob_attr
*cur
)
548 struct json_script_ctx
*ctx
= call
->ctx
;
553 if (blobmsg_type(cur
) != BLOBMSG_TYPE_ARRAY
||
554 blobmsg_type(blobmsg_data(cur
)) != BLOBMSG_TYPE_STRING
) {
555 ctx
->handle_error(ctx
, "Unexpected element type", cur
);
559 ret
= __json_process_type(call
, cur
, cmd
, ARRAY_SIZE(cmd
), &found
);
563 name
= blobmsg_data(blobmsg_data(cur
));
564 ret
= cmd_process_strings(call
, cur
);
568 ctx
->handle_command(ctx
, name
, blob_data(ctx
->buf
.head
), call
->vars
);
573 static int json_process_cmd(struct json_call
*call
, struct blob_attr
*block
)
575 struct json_script_ctx
*ctx
= call
->ctx
;
576 struct blob_attr
*cur
;
581 if (blobmsg_type(block
) != BLOBMSG_TYPE_ARRAY
) {
582 ctx
->handle_error(ctx
, "Unexpected element type", block
);
586 blobmsg_for_each_attr(cur
, block
, rem
) {
590 switch(blobmsg_type(cur
)) {
591 case BLOBMSG_TYPE_STRING
:
593 return __json_process_cmd(call
, block
);
596 ret
= json_process_cmd(call
, cur
);
607 void json_script_run_file(struct json_script_ctx
*ctx
, struct json_script_file
*file
,
608 struct blob_attr
*vars
)
610 static unsigned int _seq
= 0;
611 struct json_call call
= {
623 __json_script_run(&call
, file
, NULL
);
626 void json_script_run(struct json_script_ctx
*ctx
, const char *name
,
627 struct blob_attr
*vars
)
629 struct json_script_file
*file
;
631 file
= json_script_get_file(ctx
, name
);
635 json_script_run_file(ctx
, file
, vars
);
638 static void __json_script_file_free(struct json_script_file
*f
)
640 struct json_script_file
*next
;
648 __json_script_file_free(next
);
652 json_script_free(struct json_script_ctx
*ctx
)
654 struct json_script_file
*f
, *next
;
656 avl_remove_all_elements(&ctx
->files
, f
, avl
, next
)
657 __json_script_file_free(f
);
659 blob_buf_free(&ctx
->buf
);
663 __default_handle_error(struct json_script_ctx
*ctx
, const char *msg
,
664 struct blob_attr
*context
)
669 __default_handle_var(struct json_script_ctx
*ctx
, const char *name
,
670 struct blob_attr
*vars
)
676 __default_handle_expr(struct json_script_ctx
*ctx
, const char *name
,
677 struct blob_attr
*expr
, struct blob_attr
*vars
)
679 ctx
->handle_error(ctx
, "Unknown expression type", expr
);
683 static struct json_script_file
*
684 __default_handle_file(struct json_script_ctx
*ctx
, const char *name
)
689 void json_script_init(struct json_script_ctx
*ctx
)
691 avl_init(&ctx
->files
, avl_strcmp
, false, NULL
);
693 if (!ctx
->handle_error
)
694 ctx
->handle_error
= __default_handle_error
;
696 if (!ctx
->handle_var
)
697 ctx
->handle_var
= __default_handle_var
;
699 if (!ctx
->handle_expr
)
700 ctx
->handle_expr
= __default_handle_expr
;
702 if (!ctx
->handle_file
)
703 ctx
->handle_file
= __default_handle_file
;