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 19 #include "avl-cmp.h" 20 #include "json_script.h" 21 22 struct json_call { 23 struct json_script_ctx *ctx; 24 struct blob_attr *vars; 25 unsigned int seq; 26 }; 27 28 struct json_handler { 29 const char *name; 30 int (*cb)(struct json_call *call, struct blob_attr *cur); 31 }; 32 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); 36 37 struct json_script_file * 38 json_script_file_from_blobmsg(const char *name, void *data, int len) 39 { 40 struct json_script_file *f; 41 char *new_name; 42 int name_len = 0; 43 44 if (name) 45 name_len = strlen(name) + 1; 46 47 f = calloc_a(sizeof(*f) + len, &new_name, name_len); 48 if (!f) 49 return NULL; 50 51 memcpy(f->data, data, len); 52 if (name) 53 f->avl.key = strcpy(new_name, name); 54 55 return f; 56 } 57 58 static struct json_script_file * 59 json_script_get_file(struct json_script_ctx *ctx, const char *filename) 60 { 61 struct json_script_file *f; 62 63 f = avl_find_element(&ctx->files, filename, f, avl); 64 if (f) 65 return f; 66 67 f = ctx->handle_file(ctx, filename); 68 if (!f) 69 return NULL; 70 71 avl_insert(&ctx->files, &f->avl); 72 return f; 73 } 74 75 static void __json_script_run(struct json_call *call, struct json_script_file *file, 76 struct blob_attr *context) 77 { 78 struct json_script_ctx *ctx = call->ctx; 79 80 if (file->seq == call->seq) { 81 if (context) 82 ctx->handle_error(ctx, "Recursive include", context); 83 84 return; 85 } 86 87 file->seq = call->seq; 88 while (file) { 89 json_process_cmd(call, file->data); 90 file = file->next; 91 } 92 } 93 94 const char *json_script_find_var(struct json_script_ctx *ctx, struct blob_attr *vars, 95 const char *name) 96 { 97 struct blob_attr *cur; 98 size_t rem; 99 100 blobmsg_for_each_attr(cur, vars, rem) { 101 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) 102 continue; 103 104 if (strcmp(blobmsg_name(cur), name) != 0) 105 continue; 106 107 return blobmsg_data(cur); 108 } 109 110 return ctx->handle_var(ctx, name, vars); 111 } 112 113 static const char * 114 msg_find_var(struct json_call *call, const char *name) 115 { 116 return json_script_find_var(call->ctx, call->vars, name); 117 } 118 119 static void 120 json_get_tuple(struct blob_attr *cur, struct blob_attr **tb, int t1, int t2) 121 { 122 static struct blobmsg_policy expr_tuple[3] = { 123 { .type = BLOBMSG_TYPE_STRING }, 124 {}, 125 {}, 126 }; 127 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)); 131 } 132 133 static int handle_if(struct json_call *call, struct blob_attr *expr) 134 { 135 struct blob_attr *tb[4]; 136 int ret; 137 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 }, 143 }; 144 145 blobmsg_parse_array(if_tuple, 4, tb, blobmsg_data(expr), blobmsg_data_len(expr)); 146 147 if (!tb[1] || !tb[2]) 148 return 0; 149 150 ret = json_process_expr(call, tb[1]); 151 if (ret < 0) 152 return 0; 153 154 if (ret) 155 return json_process_cmd(call, tb[2]); 156 157 if (!tb[3]) 158 return 0; 159 160 return json_process_cmd(call, tb[3]); 161 } 162 163 static int handle_case(struct json_call *call, struct blob_attr *expr) 164 { 165 struct blob_attr *tb[3], *cur; 166 const char *var; 167 size_t rem; 168 169 json_get_tuple(expr, tb, BLOBMSG_TYPE_STRING, BLOBMSG_TYPE_TABLE); 170 if (!tb[1] || !tb[2]) 171 return 0; 172 173 var = msg_find_var(call, blobmsg_data(tb[1])); 174 if (!var) 175 return 0; 176 177 blobmsg_for_each_attr(cur, tb[2], rem) { 178 if (!strcmp(var, blobmsg_name(cur))) 179 return json_process_cmd(call, cur); 180 } 181 182 return 0; 183 } 184 185 static int handle_return(struct json_call *call, struct blob_attr *expr) 186 { 187 return -2; 188 } 189 190 static int handle_include(struct json_call *call, struct blob_attr *expr) 191 { 192 struct blob_attr *tb[3]; 193 struct json_script_file *f; 194 195 json_get_tuple(expr, tb, BLOBMSG_TYPE_STRING, 0); 196 if (!tb[1]) 197 return 0; 198 199 f = json_script_get_file(call->ctx, blobmsg_data(tb[1])); 200 if (!f) 201 return 0; 202 203 __json_script_run(call, f, expr); 204 return 0; 205 } 206 207 static const struct json_handler cmd[] = { 208 { "if", handle_if }, 209 { "case", handle_case }, 210 { "return", handle_return }, 211 { "include", handle_include }, 212 }; 213 214 static int eq_regex_cmp(const char *str, const char *pattern, bool regex) 215 { 216 regex_t reg; 217 int ret; 218 219 if (!regex) 220 return !strcmp(str, pattern); 221 222 if (regcomp(®, pattern, REG_EXTENDED | REG_NOSUB)) 223 return 0; 224 225 ret = !regexec(®, str, 0, NULL, 0); 226 regfree(®); 227 228 return ret; 229 } 230 231 static int expr_eq_regex(struct json_call *call, struct blob_attr *expr, bool regex) 232 { 233 struct json_script_ctx *ctx = call->ctx; 234 struct blob_attr *tb[3], *cur; 235 const char *var; 236 size_t rem; 237 238 json_get_tuple(expr, tb, BLOBMSG_TYPE_STRING, 0); 239 if (!tb[1] || !tb[2]) 240 return -1; 241 242 var = msg_find_var(call, blobmsg_data(tb[1])); 243 if (!var) 244 return 0; 245 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); 253 return -1; 254 } 255 256 if (eq_regex_cmp(var, blobmsg_data(cur), regex)) 257 return 1; 258 } 259 return 0; 260 default: 261 ctx->handle_error(ctx, "Unexpected element type", tb[2]); 262 return -1; 263 } 264 } 265 266 static int handle_expr_eq(struct json_call *call, struct blob_attr *expr) 267 { 268 return expr_eq_regex(call, expr, false); 269 } 270 271 static int handle_expr_regex(struct json_call *call, struct blob_attr *expr) 272 { 273 return expr_eq_regex(call, expr, true); 274 } 275 276 static int handle_expr_has(struct json_call *call, struct blob_attr *expr) 277 { 278 struct json_script_ctx *ctx = call->ctx; 279 struct blob_attr *tb[3], *cur; 280 size_t rem; 281 282 json_get_tuple(expr, tb, 0, 0); 283 if (!tb[1]) 284 return -1; 285 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); 293 return -1; 294 } 295 296 if (msg_find_var(call, blobmsg_data(cur))) 297 return 1; 298 } 299 return 0; 300 default: 301 ctx->handle_error(ctx, "Unexpected element type", tb[1]); 302 return -1; 303 } 304 } 305 306 static int expr_and_or(struct json_call *call, struct blob_attr *expr, bool and) 307 { 308 struct blob_attr *cur; 309 int ret; 310 size_t rem; 311 int i = 0; 312 313 blobmsg_for_each_attr(cur, expr, rem) { 314 if (i++ < 1) 315 continue; 316 317 ret = json_process_expr(call, cur); 318 if (ret < 0) 319 return ret; 320 321 if (ret != and) 322 return ret; 323 } 324 325 return and; 326 } 327 328 static int handle_expr_and(struct json_call *call, struct blob_attr *expr) 329 { 330 return expr_and_or(call, expr, 1); 331 } 332 333 static int handle_expr_or(struct json_call *call, struct blob_attr *expr) 334 { 335 return expr_and_or(call, expr, 0); 336 } 337 338 static int handle_expr_not(struct json_call *call, struct blob_attr *expr) 339 { 340 struct blob_attr *tb[3]; 341 int ret; 342 343 json_get_tuple(expr, tb, BLOBMSG_TYPE_ARRAY, 0); 344 if (!tb[1]) 345 return -1; 346 347 ret = json_process_expr(call, tb[1]); 348 if (ret < 0) 349 return ret; 350 return !ret; 351 } 352 353 static int handle_expr_isdir(struct json_call *call, struct blob_attr *expr) 354 { 355 static struct blob_buf b; 356 struct blob_attr *tb[3]; 357 const char *pattern, *path; 358 struct stat s; 359 int ret; 360 361 json_get_tuple(expr, tb, BLOBMSG_TYPE_STRING, 0); 362 if (!tb[1] || blobmsg_type(tb[1]) != BLOBMSG_TYPE_STRING) 363 return -1; 364 pattern = blobmsg_data(tb[1]); 365 366 blob_buf_init(&b, 0); 367 ret = eval_string(call, &b, NULL, pattern); 368 if (ret < 0) 369 return ret; 370 path = blobmsg_data(blob_data(b.head)); 371 ret = stat(path, &s); 372 if (ret < 0) 373 return 0; 374 return S_ISDIR(s.st_mode); 375 } 376 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 }, 385 }; 386 387 static int 388 __json_process_type(struct json_call *call, struct blob_attr *cur, 389 const struct json_handler *h, int n, bool *found) 390 { 391 const char *name = blobmsg_data(blobmsg_data(cur)); 392 int i; 393 394 for (i = 0; i < n; i++) { 395 if (strcmp(name, h[i].name) != 0) 396 continue; 397 398 *found = true; 399 return h[i].cb(call, cur); 400 } 401 402 *found = false; 403 return -1; 404 } 405 406 static int json_process_expr(struct json_call *call, struct blob_attr *cur) 407 { 408 struct json_script_ctx *ctx = call->ctx; 409 bool found; 410 int ret; 411 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); 415 return -1; 416 } 417 418 ret = __json_process_type(call, cur, expr, ARRAY_SIZE(expr), &found); 419 if (!found) { 420 const char *name = blobmsg_data(blobmsg_data(cur)); 421 ctx->handle_expr(ctx, name, cur, call->vars); 422 } 423 424 return ret; 425 } 426 427 static int eval_string(struct json_call *call, struct blob_buf *buf, const char *name, const char *pattern) 428 { 429 char *dest, *next, *str; 430 int len = 0; 431 bool var = false; 432 char c = '%'; 433 434 dest = blobmsg_alloc_string_buffer(buf, name, 0); 435 if (!dest) 436 return -1; 437 438 next = alloca(strlen(pattern) + 1); 439 strcpy(next, pattern); 440 441 for (str = next; str; str = next) { 442 const char *cur; 443 char *end, *new_buf; 444 int cur_len = 0; 445 bool cur_var = var; 446 447 end = strchr(str, '%'); 448 if (end) { 449 *end = 0; 450 next = end + 1; 451 var = !var; 452 } else { 453 end = str + strlen(str); 454 next = NULL; 455 } 456 457 if (cur_var) { 458 if (end > str) { 459 cur = msg_find_var(call, str); 460 if (!cur) 461 continue; 462 463 cur_len = strlen(cur); 464 } else { 465 cur = &c; 466 cur_len = 1; 467 } 468 } else { 469 if (str == end) 470 continue; 471 472 cur = str; 473 cur_len = end - str; 474 } 475 476 new_buf = blobmsg_realloc_string_buffer(buf, len + cur_len); 477 if (!new_buf) { 478 /* Make eval_string return -1 */ 479 var = true; 480 break; 481 } 482 483 dest = new_buf; 484 memcpy(dest + len, cur, cur_len); 485 len += cur_len; 486 } 487 488 dest[len] = 0; 489 blobmsg_add_string_buffer(buf); 490 491 if (var) 492 return -1; 493 494 return 0; 495 } 496 497 static int cmd_add_string(struct json_call *call, const char *pattern) 498 { 499 return eval_string(call, &call->ctx->buf, NULL, pattern); 500 } 501 502 int json_script_eval_string(struct json_script_ctx *ctx, struct blob_attr *vars, 503 struct blob_buf *buf, const char *name, 504 const char *pattern) 505 { 506 struct json_call call = { 507 .ctx = ctx, 508 .vars = vars, 509 }; 510 511 return eval_string(&call, buf, name, pattern); 512 } 513 514 static int cmd_process_strings(struct json_call *call, struct blob_attr *attr) 515 { 516 struct json_script_ctx *ctx = call->ctx; 517 struct blob_attr *cur; 518 int args = -1; 519 int ret; 520 size_t rem; 521 void *c; 522 523 blob_buf_init(&ctx->buf, 0); 524 c = blobmsg_open_array(&ctx->buf, NULL); 525 blobmsg_for_each_attr(cur, attr, rem) { 526 if (args++ < 0) 527 continue; 528 529 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) { 530 blobmsg_add_blob(&ctx->buf, cur); 531 continue; 532 } 533 534 ret = cmd_add_string(call, blobmsg_data(cur)); 535 if (ret) { 536 ctx->handle_error(ctx, "Unterminated variable reference in string", attr); 537 return ret; 538 } 539 } 540 541 blobmsg_close_array(&ctx->buf, c); 542 543 return 0; 544 } 545 546 static int __json_process_cmd(struct json_call *call, struct blob_attr *cur) 547 { 548 struct json_script_ctx *ctx = call->ctx; 549 const char *name; 550 bool found; 551 int ret; 552 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); 556 return -1; 557 } 558 559 ret = __json_process_type(call, cur, cmd, ARRAY_SIZE(cmd), &found); 560 if (found) 561 return ret; 562 563 name = blobmsg_data(blobmsg_data(cur)); 564 ret = cmd_process_strings(call, cur); 565 if (ret) 566 return ret; 567 568 ctx->handle_command(ctx, name, blob_data(ctx->buf.head), call->vars); 569 570 return 0; 571 } 572 573 static int json_process_cmd(struct json_call *call, struct blob_attr *block) 574 { 575 struct json_script_ctx *ctx = call->ctx; 576 struct blob_attr *cur; 577 size_t rem; 578 int ret; 579 int i = 0; 580 581 if (blobmsg_type(block) != BLOBMSG_TYPE_ARRAY) { 582 ctx->handle_error(ctx, "Unexpected element type", block); 583 return -1; 584 } 585 586 blobmsg_for_each_attr(cur, block, rem) { 587 if (ctx->abort) 588 break; 589 590 switch(blobmsg_type(cur)) { 591 case BLOBMSG_TYPE_STRING: 592 if (!i) 593 return __json_process_cmd(call, block); 594 fallthrough; 595 default: 596 ret = json_process_cmd(call, cur); 597 if (ret < -1) 598 return ret; 599 break; 600 } 601 i++; 602 } 603 604 return 0; 605 } 606 607 void json_script_run_file(struct json_script_ctx *ctx, struct json_script_file *file, 608 struct blob_attr *vars) 609 { 610 static unsigned int _seq = 0; 611 struct json_call call = { 612 .ctx = ctx, 613 .vars = vars, 614 .seq = ++_seq, 615 }; 616 617 /* overflow */ 618 if (!call.seq) 619 call.seq = ++_seq; 620 621 ctx->abort = false; 622 623 __json_script_run(&call, file, NULL); 624 } 625 626 void json_script_run(struct json_script_ctx *ctx, const char *name, 627 struct blob_attr *vars) 628 { 629 struct json_script_file *file; 630 631 file = json_script_get_file(ctx, name); 632 if (!file) 633 return; 634 635 json_script_run_file(ctx, file, vars); 636 } 637 638 static void __json_script_file_free(struct json_script_file *f) 639 { 640 struct json_script_file *next; 641 642 if (!f) 643 return; 644 645 next = f->next; 646 free(f); 647 648 __json_script_file_free(next); 649 } 650 651 void 652 json_script_free(struct json_script_ctx *ctx) 653 { 654 struct json_script_file *f, *next; 655 656 avl_remove_all_elements(&ctx->files, f, avl, next) 657 __json_script_file_free(f); 658 659 blob_buf_free(&ctx->buf); 660 } 661 662 static void 663 __default_handle_error(struct json_script_ctx *ctx, const char *msg, 664 struct blob_attr *context) 665 { 666 } 667 668 static const char * 669 __default_handle_var(struct json_script_ctx *ctx, const char *name, 670 struct blob_attr *vars) 671 { 672 return NULL; 673 } 674 675 static int 676 __default_handle_expr(struct json_script_ctx *ctx, const char *name, 677 struct blob_attr *expr, struct blob_attr *vars) 678 { 679 ctx->handle_error(ctx, "Unknown expression type", expr); 680 return -1; 681 } 682 683 static struct json_script_file * 684 __default_handle_file(struct json_script_ctx *ctx, const char *name) 685 { 686 return NULL; 687 } 688 689 void json_script_init(struct json_script_ctx *ctx) 690 { 691 avl_init(&ctx->files, avl_strcmp, false, NULL); 692 693 if (!ctx->handle_error) 694 ctx->handle_error = __default_handle_error; 695 696 if (!ctx->handle_var) 697 ctx->handle_var = __default_handle_var; 698 699 if (!ctx->handle_expr) 700 ctx->handle_expr = __default_handle_expr; 701 702 if (!ctx->handle_file) 703 ctx->handle_file = __default_handle_file; 704 } 705
This page was automatically generated by LXR 0.3.1. • OpenWrt