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 rule_error(cur, "Unexpected element type");
314 ret = __rule_process_type(cur, msg, expr, ARRAY_SIZE(expr), &found);
316 rule_error(cur, "Unknown expression type");
321 static void cmd_add_string(const char *pattern, struct blob_attr *msg)
323 char *dest, *next, *str;
327 blobmsg_alloc_string_buffer(&b, NULL, 1);
328 str = alloca(strlen(pattern) + 1);
329 strcpy(str, pattern);
336 next = strchr(str, '%');
338 next = str + strlen(str);
343 cur = msg_find_var(msg, str);
345 cur_len = strlen(cur);
352 cur_len = next - str;
356 dest = blobmsg_realloc_string_buffer(&b, cur_len);
357 memcpy(dest + len, cur, cur_len);
366 blobmsg_add_string_buffer(&b);
369 static int cmd_process_strings(struct blob_attr *attr, struct blob_attr *msg)
371 struct blob_attr *cur;
376 blob_buf_init(&b, 0);
377 c = blobmsg_open_array(&b, NULL);
378 blobmsg_for_each_attr(cur, attr, rem) {
382 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) {
383 rule_error(attr, "Invalid argument in command");
387 cmd_add_string(blobmsg_data(cur), msg);
390 blobmsg_close_array(&b, c);
395 static int __rule_process_cmd(struct blob_attr *cur, struct blob_attr *msg)
401 ret = __rule_process_type(cur, msg, cmd, ARRAY_SIZE(cmd), &found);
405 name = blobmsg_data(blobmsg_data(cur));
406 ret = cmd_process_strings(cur, msg);
410 rule_handle_command(name, blob_data(b.head));
415 static int rule_process_cmd(struct blob_attr *block, struct blob_attr *msg)
417 struct blob_attr *cur;
422 if (blobmsg_type(block) != BLOBMSG_TYPE_ARRAY) {
423 rule_error(block, "Unexpected element type");
427 blobmsg_for_each_attr(cur, block, rem) {
428 switch(blobmsg_type(cur)) {
429 case BLOBMSG_TYPE_STRING:
431 return __rule_process_cmd(block, msg);
433 ret = rule_process_cmd(cur, msg);
444 void rule_process_msg(struct rule_file *f, struct blob_attr *msg)
446 rule_process_cmd(f->data, msg);
449 static struct rule_file *
450 rule_file_load(const char *filename)
455 json_object *obj = NULL;
457 blob_buf_init(&b, 0);
459 if (stat(filename, &st))
462 obj = json_object_from_file((char *) filename);
466 if (!json_object_is_type(obj, json_type_array)) {
467 json_object_put(obj);
471 blobmsg_add_json_element(&b, filename, obj);
472 json_object_put(obj);
474 r = calloc(1, sizeof(*r) + blob_len(b.head));
475 memcpy(r->data, blob_data(b.head), blob_len(b.head));
476 r->avl.key = blobmsg_name(r->data);
481 static struct avl_tree rule_files;
484 rule_file_get(const char *filename)
488 if (!rule_files.comp)
489 avl_init(&rule_files, avl_strcmp, false, NULL);
491 r = avl_find_element(&rule_files, filename, r, avl);
495 r = rule_file_load(filename);
499 avl_insert(&rule_files, &r->avl);
504 rule_file_free_all(void)
506 struct rule_file *r, *next;
508 avl_remove_all_elements(&rule_files, r, avl, next)