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 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
);
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
)