• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/libubox/json_script.c

  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(&reg, pattern, REG_EXTENDED | REG_NOSUB))
223                 return 0;
224 
225         ret = !regexec(&reg, str, 0, NULL, 0);
226         regfree(&reg);
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