json_script.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  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. size_t 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. size_t 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. size_t 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. size_t 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;
  249. size_t rem;
  250. int i = 0;
  251. blobmsg_for_each_attr(cur, expr, rem) {
  252. if (i++ < 1)
  253. continue;
  254. ret = json_process_expr(call, cur);
  255. if (ret < 0)
  256. return ret;
  257. if (ret != and)
  258. return ret;
  259. }
  260. return and;
  261. }
  262. static int handle_expr_and(struct json_call *call, struct blob_attr *expr)
  263. {
  264. return expr_and_or(call, expr, 1);
  265. }
  266. static int handle_expr_or(struct json_call *call, struct blob_attr *expr)
  267. {
  268. return expr_and_or(call, expr, 0);
  269. }
  270. static int handle_expr_not(struct json_call *call, struct blob_attr *expr)
  271. {
  272. struct blob_attr *tb[3];
  273. int ret;
  274. json_get_tuple(expr, tb, BLOBMSG_TYPE_ARRAY, 0);
  275. if (!tb[1])
  276. return -1;
  277. ret = json_process_expr(call, tb[1]);
  278. if (ret < 0)
  279. return ret;
  280. return !ret;
  281. }
  282. static int handle_expr_isdir(struct json_call *call, struct blob_attr *expr)
  283. {
  284. static struct blob_buf b;
  285. struct blob_attr *tb[3];
  286. const char *pattern, *path;
  287. struct stat s;
  288. int ret;
  289. json_get_tuple(expr, tb, BLOBMSG_TYPE_STRING, 0);
  290. if (!tb[1] || blobmsg_type(tb[1]) != BLOBMSG_TYPE_STRING)
  291. return -1;
  292. pattern = blobmsg_data(tb[1]);
  293. blob_buf_init(&b, 0);
  294. ret = eval_string(call, &b, NULL, pattern);
  295. if (ret < 0)
  296. return ret;
  297. path = blobmsg_data(blob_data(b.head));
  298. ret = stat(path, &s);
  299. if (ret < 0)
  300. return 0;
  301. return S_ISDIR(s.st_mode);
  302. }
  303. static const struct json_handler expr[] = {
  304. { "eq", handle_expr_eq },
  305. { "regex", handle_expr_regex },
  306. { "has", handle_expr_has },
  307. { "and", handle_expr_and },
  308. { "or", handle_expr_or },
  309. { "not", handle_expr_not },
  310. { "isdir", handle_expr_isdir },
  311. };
  312. static int
  313. __json_process_type(struct json_call *call, struct blob_attr *cur,
  314. const struct json_handler *h, int n, bool *found)
  315. {
  316. const char *name = blobmsg_data(blobmsg_data(cur));
  317. int i;
  318. for (i = 0; i < n; i++) {
  319. if (strcmp(name, h[i].name) != 0)
  320. continue;
  321. *found = true;
  322. return h[i].cb(call, cur);
  323. }
  324. *found = false;
  325. return -1;
  326. }
  327. static int json_process_expr(struct json_call *call, struct blob_attr *cur)
  328. {
  329. struct json_script_ctx *ctx = call->ctx;
  330. bool found;
  331. int ret;
  332. if (blobmsg_type(cur) != BLOBMSG_TYPE_ARRAY ||
  333. blobmsg_type(blobmsg_data(cur)) != BLOBMSG_TYPE_STRING) {
  334. ctx->handle_error(ctx, "Unexpected element type", cur);
  335. return -1;
  336. }
  337. ret = __json_process_type(call, cur, expr, ARRAY_SIZE(expr), &found);
  338. if (!found) {
  339. const char *name = blobmsg_data(blobmsg_data(cur));
  340. ctx->handle_expr(ctx, name, cur, call->vars);
  341. }
  342. return ret;
  343. }
  344. static int eval_string(struct json_call *call, struct blob_buf *buf, const char *name, const char *pattern)
  345. {
  346. char *dest, *next, *str;
  347. int len = 0;
  348. bool var = false;
  349. char c = '%';
  350. dest = blobmsg_alloc_string_buffer(buf, name, 0);
  351. if (!dest)
  352. return -1;
  353. next = alloca(strlen(pattern) + 1);
  354. strcpy(next, pattern);
  355. for (str = next; str; str = next) {
  356. const char *cur;
  357. char *end, *new_buf;
  358. int cur_len = 0;
  359. bool cur_var = var;
  360. end = strchr(str, '%');
  361. if (end) {
  362. *end = 0;
  363. next = end + 1;
  364. var = !var;
  365. } else {
  366. end = str + strlen(str);
  367. next = NULL;
  368. }
  369. if (cur_var) {
  370. if (end > str) {
  371. cur = msg_find_var(call, str);
  372. if (!cur)
  373. continue;
  374. cur_len = strlen(cur);
  375. } else {
  376. cur = &c;
  377. cur_len = 1;
  378. }
  379. } else {
  380. if (str == end)
  381. continue;
  382. cur = str;
  383. cur_len = end - str;
  384. }
  385. new_buf = blobmsg_realloc_string_buffer(buf, len + cur_len);
  386. if (!new_buf) {
  387. /* Make eval_string return -1 */
  388. var = true;
  389. break;
  390. }
  391. dest = new_buf;
  392. memcpy(dest + len, cur, cur_len);
  393. len += cur_len;
  394. }
  395. dest[len] = 0;
  396. blobmsg_add_string_buffer(buf);
  397. if (var)
  398. return -1;
  399. return 0;
  400. }
  401. static int cmd_add_string(struct json_call *call, const char *pattern)
  402. {
  403. return eval_string(call, &call->ctx->buf, NULL, pattern);
  404. }
  405. int json_script_eval_string(struct json_script_ctx *ctx, struct blob_attr *vars,
  406. struct blob_buf *buf, const char *name,
  407. const char *pattern)
  408. {
  409. struct json_call call = {
  410. .ctx = ctx,
  411. .vars = vars,
  412. };
  413. return eval_string(&call, buf, name, pattern);
  414. }
  415. static int cmd_process_strings(struct json_call *call, struct blob_attr *attr)
  416. {
  417. struct json_script_ctx *ctx = call->ctx;
  418. struct blob_attr *cur;
  419. int args = -1;
  420. int ret;
  421. size_t rem;
  422. void *c;
  423. blob_buf_init(&ctx->buf, 0);
  424. c = blobmsg_open_array(&ctx->buf, NULL);
  425. blobmsg_for_each_attr(cur, attr, rem) {
  426. if (args++ < 0)
  427. continue;
  428. if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) {
  429. blobmsg_add_blob(&ctx->buf, cur);
  430. continue;
  431. }
  432. ret = cmd_add_string(call, blobmsg_data(cur));
  433. if (ret) {
  434. ctx->handle_error(ctx, "Unterminated variable reference in string", attr);
  435. return ret;
  436. }
  437. }
  438. blobmsg_close_array(&ctx->buf, c);
  439. return 0;
  440. }
  441. static int __json_process_cmd(struct json_call *call, struct blob_attr *cur)
  442. {
  443. struct json_script_ctx *ctx = call->ctx;
  444. const char *name;
  445. bool found;
  446. int ret;
  447. if (blobmsg_type(cur) != BLOBMSG_TYPE_ARRAY ||
  448. blobmsg_type(blobmsg_data(cur)) != BLOBMSG_TYPE_STRING) {
  449. ctx->handle_error(ctx, "Unexpected element type", cur);
  450. return -1;
  451. }
  452. ret = __json_process_type(call, cur, cmd, ARRAY_SIZE(cmd), &found);
  453. if (found)
  454. return ret;
  455. name = blobmsg_data(blobmsg_data(cur));
  456. ret = cmd_process_strings(call, cur);
  457. if (ret)
  458. return ret;
  459. ctx->handle_command(ctx, name, blob_data(ctx->buf.head), call->vars);
  460. return 0;
  461. }
  462. static int json_process_cmd(struct json_call *call, struct blob_attr *block)
  463. {
  464. struct json_script_ctx *ctx = call->ctx;
  465. struct blob_attr *cur;
  466. size_t rem;
  467. int ret;
  468. int i = 0;
  469. if (blobmsg_type(block) != BLOBMSG_TYPE_ARRAY) {
  470. ctx->handle_error(ctx, "Unexpected element type", block);
  471. return -1;
  472. }
  473. blobmsg_for_each_attr(cur, block, rem) {
  474. if (ctx->abort)
  475. break;
  476. switch(blobmsg_type(cur)) {
  477. case BLOBMSG_TYPE_STRING:
  478. if (!i)
  479. return __json_process_cmd(call, block);
  480. fallthrough;
  481. default:
  482. ret = json_process_cmd(call, cur);
  483. if (ret < -1)
  484. return ret;
  485. break;
  486. }
  487. i++;
  488. }
  489. return 0;
  490. }
  491. void json_script_run_file(struct json_script_ctx *ctx, struct json_script_file *file,
  492. struct blob_attr *vars)
  493. {
  494. static unsigned int _seq = 0;
  495. struct json_call call = {
  496. .ctx = ctx,
  497. .vars = vars,
  498. .seq = ++_seq,
  499. };
  500. /* overflow */
  501. if (!call.seq)
  502. call.seq = ++_seq;
  503. ctx->abort = false;
  504. __json_script_run(&call, file, NULL);
  505. }
  506. void json_script_run(struct json_script_ctx *ctx, const char *name,
  507. struct blob_attr *vars)
  508. {
  509. struct json_script_file *file;
  510. file = json_script_get_file(ctx, name);
  511. if (!file)
  512. return;
  513. json_script_run_file(ctx, file, vars);
  514. }
  515. static void __json_script_file_free(struct json_script_file *f)
  516. {
  517. struct json_script_file *next;
  518. if (!f)
  519. return;
  520. next = f->next;
  521. free(f);
  522. __json_script_file_free(next);
  523. }
  524. void
  525. json_script_free(struct json_script_ctx *ctx)
  526. {
  527. struct json_script_file *f, *next;
  528. avl_remove_all_elements(&ctx->files, f, avl, next)
  529. __json_script_file_free(f);
  530. blob_buf_free(&ctx->buf);
  531. }
  532. static void
  533. __default_handle_error(struct json_script_ctx *ctx, const char *msg,
  534. struct blob_attr *context)
  535. {
  536. }
  537. static const char *
  538. __default_handle_var(struct json_script_ctx *ctx, const char *name,
  539. struct blob_attr *vars)
  540. {
  541. return NULL;
  542. }
  543. static int
  544. __default_handle_expr(struct json_script_ctx *ctx, const char *name,
  545. struct blob_attr *expr, struct blob_attr *vars)
  546. {
  547. ctx->handle_error(ctx, "Unknown expression type", expr);
  548. return -1;
  549. }
  550. static struct json_script_file *
  551. __default_handle_file(struct json_script_ctx *ctx, const char *name)
  552. {
  553. return NULL;
  554. }
  555. void json_script_init(struct json_script_ctx *ctx)
  556. {
  557. avl_init(&ctx->files, avl_strcmp, false, NULL);
  558. if (!ctx->handle_error)
  559. ctx->handle_error = __default_handle_error;
  560. if (!ctx->handle_var)
  561. ctx->handle_var = __default_handle_var;
  562. if (!ctx->handle_expr)
  563. ctx->handle_expr = __default_handle_expr;
  564. if (!ctx->handle_file)
  565. ctx->handle_file = __default_handle_file;
  566. }