json_script.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698
  1. /*
  2. * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
  3. *
  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.
  7. *
  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.
  15. */
  16. #include <sys/stat.h>
  17. #include <regex.h>
  18. #include "avl-cmp.h"
  19. #include "json_script.h"
  20. struct json_call {
  21. struct json_script_ctx *ctx;
  22. struct blob_attr *vars;
  23. unsigned int seq;
  24. };
  25. struct json_handler {
  26. const char *name;
  27. int (*cb)(struct json_call *call, struct blob_attr *cur);
  28. };
  29. static int json_process_expr(struct json_call *call, struct blob_attr *cur);
  30. static int json_process_cmd(struct json_call *call, struct blob_attr *cur);
  31. static int eval_string(struct json_call *call, struct blob_buf *buf, const char *name, const char *pattern);
  32. struct json_script_file *
  33. json_script_file_from_blobmsg(const char *name, void *data, int len)
  34. {
  35. struct json_script_file *f;
  36. char *new_name;
  37. int name_len = 0;
  38. if (name)
  39. name_len = strlen(name) + 1;
  40. f = calloc_a(sizeof(*f) + len, &new_name, name_len);
  41. if (!f)
  42. return NULL;
  43. memcpy(f->data, data, len);
  44. if (name)
  45. f->avl.key = strcpy(new_name, name);
  46. return f;
  47. }
  48. static struct json_script_file *
  49. json_script_get_file(struct json_script_ctx *ctx, const char *filename)
  50. {
  51. struct json_script_file *f;
  52. f = avl_find_element(&ctx->files, filename, f, avl);
  53. if (f)
  54. return f;
  55. f = ctx->handle_file(ctx, filename);
  56. if (!f)
  57. return NULL;
  58. avl_insert(&ctx->files, &f->avl);
  59. return f;
  60. }
  61. static void __json_script_run(struct json_call *call, struct json_script_file *file,
  62. struct blob_attr *context)
  63. {
  64. struct json_script_ctx *ctx = call->ctx;
  65. if (file->seq == call->seq) {
  66. if (context)
  67. ctx->handle_error(ctx, "Recursive include", context);
  68. return;
  69. }
  70. file->seq = call->seq;
  71. while (file) {
  72. json_process_cmd(call, file->data);
  73. file = file->next;
  74. }
  75. }
  76. const char *json_script_find_var(struct json_script_ctx *ctx, struct blob_attr *vars,
  77. const char *name)
  78. {
  79. struct blob_attr *cur;
  80. int rem;
  81. blobmsg_for_each_attr(cur, vars, rem) {
  82. if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
  83. continue;
  84. if (strcmp(blobmsg_name(cur), name) != 0)
  85. continue;
  86. return blobmsg_data(cur);
  87. }
  88. return ctx->handle_var(ctx, name, vars);
  89. }
  90. static const char *
  91. msg_find_var(struct json_call *call, const char *name)
  92. {
  93. return json_script_find_var(call->ctx, call->vars, name);
  94. }
  95. static void
  96. json_get_tuple(struct blob_attr *cur, struct blob_attr **tb, int t1, int t2)
  97. {
  98. static struct blobmsg_policy expr_tuple[3] = {
  99. { .type = BLOBMSG_TYPE_STRING },
  100. {},
  101. {},
  102. };
  103. expr_tuple[1].type = t1;
  104. expr_tuple[2].type = t2;
  105. blobmsg_parse_array(expr_tuple, 3, tb, blobmsg_data(cur), blobmsg_data_len(cur));
  106. }
  107. static int handle_if(struct json_call *call, struct blob_attr *expr)
  108. {
  109. struct blob_attr *tb[4];
  110. int ret;
  111. static const struct blobmsg_policy if_tuple[4] = {
  112. { .type = BLOBMSG_TYPE_STRING },
  113. { .type = BLOBMSG_TYPE_ARRAY },
  114. { .type = BLOBMSG_TYPE_ARRAY },
  115. { .type = BLOBMSG_TYPE_ARRAY },
  116. };
  117. blobmsg_parse_array(if_tuple, 4, tb, blobmsg_data(expr), blobmsg_data_len(expr));
  118. if (!tb[1] || !tb[2])
  119. return 0;
  120. ret = json_process_expr(call, tb[1]);
  121. if (ret < 0)
  122. return 0;
  123. if (ret)
  124. return json_process_cmd(call, tb[2]);
  125. if (!tb[3])
  126. return 0;
  127. return json_process_cmd(call, tb[3]);
  128. }
  129. static int handle_case(struct json_call *call, struct blob_attr *expr)
  130. {
  131. struct blob_attr *tb[3], *cur;
  132. const char *var;
  133. int rem;
  134. json_get_tuple(expr, tb, BLOBMSG_TYPE_STRING, BLOBMSG_TYPE_TABLE);
  135. if (!tb[1] || !tb[2])
  136. return 0;
  137. var = msg_find_var(call, blobmsg_data(tb[1]));
  138. if (!var)
  139. return 0;
  140. blobmsg_for_each_attr(cur, tb[2], rem) {
  141. if (!strcmp(var, blobmsg_name(cur)))
  142. return json_process_cmd(call, cur);
  143. }
  144. return 0;
  145. }
  146. static int handle_return(struct json_call *call, struct blob_attr *expr)
  147. {
  148. return -2;
  149. }
  150. static int handle_include(struct json_call *call, struct blob_attr *expr)
  151. {
  152. struct blob_attr *tb[3];
  153. struct json_script_file *f;
  154. json_get_tuple(expr, tb, BLOBMSG_TYPE_STRING, 0);
  155. if (!tb[1])
  156. return 0;
  157. f = json_script_get_file(call->ctx, blobmsg_data(tb[1]));
  158. if (!f)
  159. return 0;
  160. __json_script_run(call, f, expr);
  161. return 0;
  162. }
  163. static const struct json_handler cmd[] = {
  164. { "if", handle_if },
  165. { "case", handle_case },
  166. { "return", handle_return },
  167. { "include", handle_include },
  168. };
  169. static int eq_regex_cmp(const char *str, const char *pattern, bool regex)
  170. {
  171. regex_t reg;
  172. int ret;
  173. if (!regex)
  174. return !strcmp(str, pattern);
  175. if (regcomp(&reg, pattern, REG_EXTENDED | REG_NOSUB))
  176. return 0;
  177. ret = !regexec(&reg, str, 0, NULL, 0);
  178. regfree(&reg);
  179. return ret;
  180. }
  181. static int expr_eq_regex(struct json_call *call, struct blob_attr *expr, bool regex)
  182. {
  183. struct json_script_ctx *ctx = call->ctx;
  184. struct blob_attr *tb[3], *cur;
  185. const char *var;
  186. int rem;
  187. json_get_tuple(expr, tb, BLOBMSG_TYPE_STRING, 0);
  188. if (!tb[1] || !tb[2])
  189. return -1;
  190. var = msg_find_var(call, blobmsg_data(tb[1]));
  191. if (!var)
  192. return 0;
  193. switch(blobmsg_type(tb[2])) {
  194. case BLOBMSG_TYPE_STRING:
  195. return eq_regex_cmp(var, blobmsg_data(tb[2]), regex);
  196. case BLOBMSG_TYPE_ARRAY:
  197. blobmsg_for_each_attr(cur, tb[2], rem) {
  198. if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) {
  199. ctx->handle_error(ctx, "Unexpected element type", cur);
  200. return -1;
  201. }
  202. if (eq_regex_cmp(var, blobmsg_data(cur), regex))
  203. return 1;
  204. }
  205. return 0;
  206. default:
  207. ctx->handle_error(ctx, "Unexpected element type", tb[2]);
  208. return -1;
  209. }
  210. }
  211. static int handle_expr_eq(struct json_call *call, struct blob_attr *expr)
  212. {
  213. return expr_eq_regex(call, expr, false);
  214. }
  215. static int handle_expr_regex(struct json_call *call, struct blob_attr *expr)
  216. {
  217. return expr_eq_regex(call, expr, true);
  218. }
  219. static int handle_expr_has(struct json_call *call, struct blob_attr *expr)
  220. {
  221. struct json_script_ctx *ctx = call->ctx;
  222. struct blob_attr *tb[3], *cur;
  223. int rem;
  224. json_get_tuple(expr, tb, 0, 0);
  225. if (!tb[1])
  226. return -1;
  227. switch(blobmsg_type(tb[1])) {
  228. case BLOBMSG_TYPE_STRING:
  229. return !!msg_find_var(call, blobmsg_data(tb[1]));
  230. case BLOBMSG_TYPE_ARRAY:
  231. blobmsg_for_each_attr(cur, tb[1], rem) {
  232. if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) {
  233. ctx->handle_error(ctx, "Unexpected element type", cur);
  234. return -1;
  235. }
  236. if (msg_find_var(call, blobmsg_data(cur)))
  237. return 1;
  238. }
  239. return 0;
  240. default:
  241. ctx->handle_error(ctx, "Unexpected element type", tb[1]);
  242. return -1;
  243. }
  244. }
  245. static int expr_and_or(struct json_call *call, struct blob_attr *expr, bool and)
  246. {
  247. struct blob_attr *cur;
  248. int ret, rem;
  249. int i = 0;
  250. blobmsg_for_each_attr(cur, expr, rem) {
  251. if (i++ < 1)
  252. continue;
  253. ret = json_process_expr(call, cur);
  254. if (ret < 0)
  255. return ret;
  256. if (ret != and)
  257. return ret;
  258. }
  259. return and;
  260. }
  261. static int handle_expr_and(struct json_call *call, struct blob_attr *expr)
  262. {
  263. return expr_and_or(call, expr, 1);
  264. }
  265. static int handle_expr_or(struct json_call *call, struct blob_attr *expr)
  266. {
  267. return expr_and_or(call, expr, 0);
  268. }
  269. static int handle_expr_not(struct json_call *call, struct blob_attr *expr)
  270. {
  271. struct blob_attr *tb[3];
  272. int ret;
  273. json_get_tuple(expr, tb, BLOBMSG_TYPE_ARRAY, 0);
  274. if (!tb[1])
  275. return -1;
  276. ret = json_process_expr(call, tb[1]);
  277. if (ret < 0)
  278. return ret;
  279. return !ret;
  280. }
  281. static int handle_expr_isdir(struct json_call *call, struct blob_attr *expr)
  282. {
  283. static struct blob_buf b;
  284. struct blob_attr *tb[3];
  285. const char *pattern, *path;
  286. struct stat s;
  287. int ret;
  288. json_get_tuple(expr, tb, BLOBMSG_TYPE_STRING, 0);
  289. if (!tb[1] || blobmsg_type(tb[1]) != BLOBMSG_TYPE_STRING)
  290. return -1;
  291. pattern = blobmsg_data(tb[1]);
  292. blob_buf_init(&b, 0);
  293. ret = eval_string(call, &b, NULL, pattern);
  294. if (ret < 0)
  295. return ret;
  296. path = blobmsg_data(blob_data(b.head));
  297. ret = stat(path, &s);
  298. if (ret < 0)
  299. return 0;
  300. return S_ISDIR(s.st_mode);
  301. }
  302. static const struct json_handler expr[] = {
  303. { "eq", handle_expr_eq },
  304. { "regex", handle_expr_regex },
  305. { "has", handle_expr_has },
  306. { "and", handle_expr_and },
  307. { "or", handle_expr_or },
  308. { "not", handle_expr_not },
  309. { "isdir", handle_expr_isdir },
  310. };
  311. static int
  312. __json_process_type(struct json_call *call, struct blob_attr *cur,
  313. const struct json_handler *h, int n, bool *found)
  314. {
  315. const char *name = blobmsg_data(blobmsg_data(cur));
  316. int i;
  317. for (i = 0; i < n; i++) {
  318. if (strcmp(name, h[i].name) != 0)
  319. continue;
  320. *found = true;
  321. return h[i].cb(call, cur);
  322. }
  323. *found = false;
  324. return -1;
  325. }
  326. static int json_process_expr(struct json_call *call, struct blob_attr *cur)
  327. {
  328. struct json_script_ctx *ctx = call->ctx;
  329. bool found;
  330. int ret;
  331. if (blobmsg_type(cur) != BLOBMSG_TYPE_ARRAY ||
  332. blobmsg_type(blobmsg_data(cur)) != BLOBMSG_TYPE_STRING) {
  333. ctx->handle_error(ctx, "Unexpected element type", cur);
  334. return -1;
  335. }
  336. ret = __json_process_type(call, cur, expr, ARRAY_SIZE(expr), &found);
  337. if (!found)
  338. ctx->handle_error(ctx, "Unknown expression type", cur);
  339. return ret;
  340. }
  341. static int eval_string(struct json_call *call, struct blob_buf *buf, const char *name, const char *pattern)
  342. {
  343. char *dest, *next, *str;
  344. int len = 0;
  345. bool var = false;
  346. char c = '%';
  347. dest = blobmsg_alloc_string_buffer(buf, name, 1);
  348. if (!dest)
  349. return -1;
  350. next = alloca(strlen(pattern) + 1);
  351. strcpy(next, pattern);
  352. for (str = next; str; str = next) {
  353. const char *cur;
  354. char *end, *new_buf;
  355. int cur_len = 0;
  356. bool cur_var = var;
  357. end = strchr(str, '%');
  358. if (end) {
  359. *end = 0;
  360. next = end + 1;
  361. var = !var;
  362. } else {
  363. end = str + strlen(str);
  364. next = NULL;
  365. }
  366. if (cur_var) {
  367. if (end > str) {
  368. cur = msg_find_var(call, str);
  369. if (!cur)
  370. continue;
  371. cur_len = strlen(cur);
  372. } else {
  373. cur = &c;
  374. cur_len = 1;
  375. }
  376. } else {
  377. if (str == end)
  378. continue;
  379. cur = str;
  380. cur_len = end - str;
  381. }
  382. new_buf = blobmsg_realloc_string_buffer(buf, len + cur_len + 1);
  383. if (!new_buf) {
  384. /* Make eval_string return -1 */
  385. var = true;
  386. break;
  387. }
  388. dest = new_buf;
  389. memcpy(dest + len, cur, cur_len);
  390. len += cur_len;
  391. }
  392. dest[len] = 0;
  393. blobmsg_add_string_buffer(buf);
  394. if (var)
  395. return -1;
  396. return 0;
  397. }
  398. static int cmd_add_string(struct json_call *call, const char *pattern)
  399. {
  400. return eval_string(call, &call->ctx->buf, NULL, pattern);
  401. }
  402. int json_script_eval_string(struct json_script_ctx *ctx, struct blob_attr *vars,
  403. struct blob_buf *buf, const char *name,
  404. const char *pattern)
  405. {
  406. struct json_call call = {
  407. .ctx = ctx,
  408. .vars = vars,
  409. };
  410. return eval_string(&call, buf, name, pattern);
  411. }
  412. static int cmd_process_strings(struct json_call *call, struct blob_attr *attr)
  413. {
  414. struct json_script_ctx *ctx = call->ctx;
  415. struct blob_attr *cur;
  416. int args = -1;
  417. int rem, ret;
  418. void *c;
  419. blob_buf_init(&ctx->buf, 0);
  420. c = blobmsg_open_array(&ctx->buf, NULL);
  421. blobmsg_for_each_attr(cur, attr, rem) {
  422. if (args++ < 0)
  423. continue;
  424. if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) {
  425. blobmsg_add_blob(&ctx->buf, cur);
  426. continue;
  427. }
  428. ret = cmd_add_string(call, blobmsg_data(cur));
  429. if (ret) {
  430. ctx->handle_error(ctx, "Unterminated variable reference in string", attr);
  431. return ret;
  432. }
  433. }
  434. blobmsg_close_array(&ctx->buf, c);
  435. return 0;
  436. }
  437. static int __json_process_cmd(struct json_call *call, struct blob_attr *cur)
  438. {
  439. struct json_script_ctx *ctx = call->ctx;
  440. const char *name;
  441. bool found;
  442. int ret;
  443. if (blobmsg_type(cur) != BLOBMSG_TYPE_ARRAY ||
  444. blobmsg_type(blobmsg_data(cur)) != BLOBMSG_TYPE_STRING) {
  445. ctx->handle_error(ctx, "Unexpected element type", cur);
  446. return -1;
  447. }
  448. ret = __json_process_type(call, cur, cmd, ARRAY_SIZE(cmd), &found);
  449. if (found)
  450. return ret;
  451. name = blobmsg_data(blobmsg_data(cur));
  452. ret = cmd_process_strings(call, cur);
  453. if (ret)
  454. return ret;
  455. ctx->handle_command(ctx, name, blob_data(ctx->buf.head), call->vars);
  456. return 0;
  457. }
  458. static int json_process_cmd(struct json_call *call, struct blob_attr *block)
  459. {
  460. struct json_script_ctx *ctx = call->ctx;
  461. struct blob_attr *cur;
  462. int rem;
  463. int ret;
  464. int i = 0;
  465. if (blobmsg_type(block) != BLOBMSG_TYPE_ARRAY) {
  466. ctx->handle_error(ctx, "Unexpected element type", block);
  467. return -1;
  468. }
  469. blobmsg_for_each_attr(cur, block, rem) {
  470. if (ctx->abort)
  471. break;
  472. switch(blobmsg_type(cur)) {
  473. case BLOBMSG_TYPE_STRING:
  474. if (!i)
  475. return __json_process_cmd(call, block);
  476. default:
  477. ret = json_process_cmd(call, cur);
  478. if (ret < -1)
  479. return ret;
  480. break;
  481. }
  482. i++;
  483. }
  484. return 0;
  485. }
  486. void json_script_run_file(struct json_script_ctx *ctx, struct json_script_file *file,
  487. struct blob_attr *vars)
  488. {
  489. static unsigned int _seq = 0;
  490. struct json_call call = {
  491. .ctx = ctx,
  492. .vars = vars,
  493. .seq = ++_seq,
  494. };
  495. /* overflow */
  496. if (!call.seq)
  497. call.seq = ++_seq;
  498. ctx->abort = false;
  499. __json_script_run(&call, file, NULL);
  500. }
  501. void json_script_run(struct json_script_ctx *ctx, const char *name,
  502. struct blob_attr *vars)
  503. {
  504. struct json_script_file *file;
  505. file = json_script_get_file(ctx, name);
  506. if (!file)
  507. return;
  508. json_script_run_file(ctx, file, vars);
  509. }
  510. static void __json_script_file_free(struct json_script_file *f)
  511. {
  512. struct json_script_file *next;
  513. if (!f)
  514. return;
  515. next = f->next;
  516. free(f);
  517. __json_script_file_free(next);
  518. }
  519. void
  520. json_script_free(struct json_script_ctx *ctx)
  521. {
  522. struct json_script_file *f, *next;
  523. avl_remove_all_elements(&ctx->files, f, avl, next)
  524. __json_script_file_free(f);
  525. blob_buf_free(&ctx->buf);
  526. }
  527. static void
  528. __default_handle_error(struct json_script_ctx *ctx, const char *msg,
  529. struct blob_attr *context)
  530. {
  531. }
  532. static const char *
  533. __default_handle_var(struct json_script_ctx *ctx, const char *name,
  534. struct blob_attr *vars)
  535. {
  536. return NULL;
  537. }
  538. static int
  539. __default_handle_expr(struct json_script_ctx *ctx, const char *name,
  540. struct blob_attr *expr, struct blob_attr *vars)
  541. {
  542. return -1;
  543. }
  544. static struct json_script_file *
  545. __default_handle_file(struct json_script_ctx *ctx, const char *name)
  546. {
  547. return NULL;
  548. }
  549. void json_script_init(struct json_script_ctx *ctx)
  550. {
  551. avl_init(&ctx->files, avl_strcmp, false, NULL);
  552. if (!ctx->handle_error)
  553. ctx->handle_error = __default_handle_error;
  554. if (!ctx->handle_var)
  555. ctx->handle_var = __default_handle_var;
  556. if (!ctx->handle_expr)
  557. ctx->handle_expr = __default_handle_expr;
  558. if (!ctx->handle_file)
  559. ctx->handle_file = __default_handle_file;
  560. }