7 #include <libubox/avl-cmp.h>
8 #include <libubox/blobmsg_json.h>
12 static struct blob_buf b;
14 static int rule_process_expr(struct blob_attr *cur, struct blob_attr *msg);
15 static int rule_process_cmd(struct blob_attr *cur, struct blob_attr *msg);
17 static char *__msg_find_var(struct blob_attr *msg, const char *name)
19 struct blob_attr *cur;
22 blob_for_each_attr(cur, msg, rem) {
23 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
26 if (strcmp(blobmsg_name(cur), name) != 0)
29 return blobmsg_data(cur);
35 static char *msg_find_var(struct blob_attr *msg, const char *name)
39 if (!strcmp(name, "DEVICENAME") || !strcmp(name, "DEVNAME")) {
40 str = __msg_find_var(msg, "DEVPATH");
47 return __msg_find_var(msg, name);
51 rule_get_tuple(struct blob_attr *cur, struct blob_attr **tb, int t1, int t2)
53 static struct blobmsg_policy expr_tuple[3] = {
54 { .type = BLOBMSG_TYPE_STRING },
59 expr_tuple[1].type = t1;
60 expr_tuple[2].type = t2;
61 blobmsg_parse_array(expr_tuple, 3, tb, blobmsg_data(cur), blobmsg_data_len(cur));
64 static int handle_if(struct blob_attr *expr, struct blob_attr *msg)
66 struct blob_attr *tb[4];
69 static const struct blobmsg_policy if_tuple[4] = {
70 { .type = BLOBMSG_TYPE_STRING },
71 { .type = BLOBMSG_TYPE_ARRAY },
72 { .type = BLOBMSG_TYPE_ARRAY },
73 { .type = BLOBMSG_TYPE_ARRAY },
76 blobmsg_parse_array(if_tuple, 4, tb, blobmsg_data(expr), blobmsg_data_len(expr));
81 ret = rule_process_expr(tb[1], msg);
86 return rule_process_cmd(tb[2], msg);
91 return rule_process_cmd(tb[3], msg);
94 static int handle_case(struct blob_attr *expr, struct blob_attr *msg)
96 struct blob_attr *tb[3], *cur;
100 rule_get_tuple(expr, tb, BLOBMSG_TYPE_STRING, BLOBMSG_TYPE_TABLE);
101 if (!tb[1] || !tb[2])
104 var = msg_find_var(msg, blobmsg_data(tb[1]));
108 blobmsg_for_each_attr(cur, tb[2], rem) {
109 if (!strcmp(var, blobmsg_name(cur)))
110 return rule_process_cmd(cur, msg);
116 static int handle_return(struct blob_attr *expr, struct blob_attr *msg)
121 static int handle_include(struct blob_attr *expr, struct blob_attr *msg)
123 struct blob_attr *tb[3];
126 rule_get_tuple(expr, tb, BLOBMSG_TYPE_STRING, 0);
130 r = rule_file_get(blobmsg_data(tb[1]));
134 return rule_process_cmd(r->data, msg);
137 static const struct rule_handler cmd[] = {
139 { "case", handle_case },
140 { "return", handle_return },
141 { "include", handle_include },
144 static int eq_regex_cmp(const char *str, const char *pattern, bool regex)
150 return !strcmp(str, pattern);
152 if (regcomp(®, pattern, REG_EXTENDED | REG_NOSUB))
155 ret = !regexec(®, str, 0, NULL, 0);
161 static int expr_eq_regex(struct blob_attr *expr, struct blob_attr *msg, bool regex)
163 struct blob_attr *tb[3], *cur;
167 rule_get_tuple(expr, tb, BLOBMSG_TYPE_STRING, 0);
168 if (!tb[1] || !tb[2])
171 var = msg_find_var(msg, blobmsg_data(tb[1]));
175 switch(blobmsg_type(tb[2])) {
176 case BLOBMSG_TYPE_STRING:
177 return eq_regex_cmp(var, blobmsg_data(tb[2]), regex);
178 case BLOBMSG_TYPE_ARRAY:
179 blobmsg_for_each_attr(cur, tb[2], rem) {
180 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) {
181 rule_error(cur, "Unexpected element type");
185 if (eq_regex_cmp(var, blobmsg_data(cur), regex))
190 rule_error(tb[2], "Unexpected element type");
195 static int handle_expr_eq(struct blob_attr *expr, struct blob_attr *msg)
197 return expr_eq_regex(expr, msg, false);
200 static int handle_expr_regex(struct blob_attr *expr, struct blob_attr *msg)
202 return expr_eq_regex(expr, msg, true);
205 static int handle_expr_has(struct blob_attr *expr, struct blob_attr *msg)
207 struct blob_attr *tb[3], *cur;
210 rule_get_tuple(expr, tb, 0, 0);
214 switch(blobmsg_type(tb[1])) {
215 case BLOBMSG_TYPE_STRING:
216 return !!msg_find_var(msg, blobmsg_data(tb[1]));
217 case BLOBMSG_TYPE_ARRAY:
218 blobmsg_for_each_attr(cur, tb[1], rem) {
219 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) {
220 rule_error(cur, "Unexpected element type");
224 if (msg_find_var(msg, blobmsg_data(cur)))
229 rule_error(tb[1], "Unexpected element type");
234 static int expr_and_or(struct blob_attr *expr, struct blob_attr *msg, bool and)
236 struct blob_attr *cur;
240 blobmsg_for_each_attr(cur, expr, rem) {
244 ret = rule_process_expr(cur, msg);
255 static int handle_expr_and(struct blob_attr *expr, struct blob_attr *msg)
257 return expr_and_or(expr, msg, 1);
260 static int handle_expr_or(struct blob_attr *expr, struct blob_attr *msg)
262 return expr_and_or(expr, msg, 0);
265 static int handle_expr_not(struct blob_attr *expr, struct blob_attr *msg)
267 struct blob_attr *tb[3];
269 rule_get_tuple(expr, tb, BLOBMSG_TYPE_ARRAY, 0);
273 return rule_process_expr(tb[1], msg);
276 static const struct rule_handler expr[] = {
277 { "eq", handle_expr_eq },
278 { "regex", handle_expr_regex },
279 { "has", handle_expr_has },
280 { "and", handle_expr_and },
281 { "or", handle_expr_or },
282 { "not", handle_expr_not },
286 __rule_process_type(struct blob_attr *cur, struct blob_attr *msg,
287 const struct rule_handler *h, int n, bool *found)
289 const char *name = blobmsg_data(blobmsg_data(cur));
292 for (i = 0; i < n; i++) {
293 if (strcmp(name, h[i].name) != 0)
297 return h[i].handler(cur, msg);
304 static int rule_process_expr(struct blob_attr *cur, struct blob_attr *msg)
309 if (blobmsg_type(cur) != BLOBMSG_TYPE_ARRAY ||
310 blobmsg_type(blobmsg_data(cur)) != BLOBMSG_TYPE_STRING) {
311 rule_error(cur, "Unexpected element type");
315 ret = __rule_process_type(cur, msg, expr, ARRAY_SIZE(expr), &found);
317 rule_error(cur, "Unknown expression type");
322 static void cmd_add_string(const char *pattern, struct blob_attr *msg)
324 char *dest, *next, *str;
328 dest = blobmsg_alloc_string_buffer(&b, NULL, 1);
329 str = alloca(strlen(pattern) + 1);
330 strcpy(str, pattern);
337 next = strchr(str, '%');
339 next = str + strlen(str);
344 cur = msg_find_var(msg, str);
346 cur_len = strlen(cur);
353 cur_len = next - str;
357 dest = blobmsg_realloc_string_buffer(&b, cur_len + 1);
358 memcpy(dest + len, cur, cur_len);
367 blobmsg_add_string_buffer(&b);
370 static int cmd_process_strings(struct blob_attr *attr, struct blob_attr *msg)
372 struct blob_attr *cur;
377 blob_buf_init(&b, 0);
378 c = blobmsg_open_array(&b, NULL);
379 blobmsg_for_each_attr(cur, attr, rem) {
383 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) {
384 rule_error(attr, "Invalid argument in command");
388 cmd_add_string(blobmsg_data(cur), msg);
391 blobmsg_close_array(&b, c);
396 static int __rule_process_cmd(struct blob_attr *cur, struct blob_attr *msg)
402 if (blobmsg_type(cur) != BLOBMSG_TYPE_ARRAY ||
403 blobmsg_type(blobmsg_data(cur)) != BLOBMSG_TYPE_STRING) {
404 rule_error(cur, "Unexpected element type");
408 ret = __rule_process_type(cur, msg, cmd, ARRAY_SIZE(cmd), &found);
412 name = blobmsg_data(blobmsg_data(cur));
413 ret = cmd_process_strings(cur, msg);
417 rule_handle_command(name, blob_data(b.head));
422 static int rule_process_cmd(struct blob_attr *block, struct blob_attr *msg)
424 struct blob_attr *cur;
429 if (blobmsg_type(block) != BLOBMSG_TYPE_ARRAY) {
430 rule_error(block, "Unexpected element type");
434 blobmsg_for_each_attr(cur, block, rem) {
435 switch(blobmsg_type(cur)) {
436 case BLOBMSG_TYPE_STRING:
438 return __rule_process_cmd(block, msg);
440 ret = rule_process_cmd(cur, msg);
451 void rule_process_msg(struct rule_file *f, struct blob_attr *msg)
453 rule_process_cmd(f->data, msg);
456 static struct rule_file *
457 rule_file_load(const char *filename)
462 json_object *obj = NULL;
464 blob_buf_init(&b, 0);
466 if (stat(filename, &st))
469 obj = json_object_from_file((char *) filename);
473 if (!json_object_is_type(obj, json_type_array)) {
474 json_object_put(obj);
478 blobmsg_add_json_element(&b, filename, obj);
479 json_object_put(obj);
481 r = calloc(1, sizeof(*r) + blob_len(b.head));
482 memcpy(r->data, blob_data(b.head), blob_len(b.head));
483 r->avl.key = blobmsg_name(r->data);
488 static struct avl_tree rule_files;
491 rule_file_get(const char *filename)
495 if (!rule_files.comp)
496 avl_init(&rule_files, avl_strcmp, false, NULL);
498 r = avl_find_element(&rule_files, filename, r, avl);
502 r = rule_file_load(filename);
506 avl_insert(&rule_files, &r->avl);
511 rule_file_free_all(void)
513 struct rule_file *r, *next;
515 avl_remove_all_elements(&rule_files, r, avl, next)