Initialize Tizen 2.3
[adaptation/xorg/driver/xserver-xorg-module-xdbg.git] / common / ds / bool_exp_rule_checker.c
1 /**************************************************************************
2
3 xserver-xorg-video-exynos
4
5 Copyright 2010 - 2011 Samsung Electronics co., Ltd. All Rights Reserved.
6
7 Contact: Boram Park <boram1288.park@samsung.com>
8
9 Permission is hereby granted, free of charge, to any person obtaining a
10 copy of this software and associated documentation files (the
11 "Software"), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sub license, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
16
17 The above copyright notice and this permission notice (including the
18 next paragraph) shall be included in all copies or substantial portions
19 of the Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
24 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
25 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
29 **************************************************************************/
30
31 #include <stdio.h>
32 #include <string.h>
33 #include <strings.h>
34 #include <stdlib.h>
35
36 #include "bool_exp_parser.h"
37 #include "bool_exp_rule_checker.h"
38
39 #define MAX_RULE        64
40
41 #ifndef REPLY
42 #define REPLY(fmt, ARG...)  \
43     do { \
44         if (reply && len && *len > 0) \
45         { \
46             int s = snprintf (reply, *len, fmt, ##ARG); \
47             reply += s; \
48             *len -= s; \
49         } \
50     } while (0)
51 #endif
52
53 #ifndef MIN
54 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
55 #endif
56
57 typedef struct
58 {
59     POLICY_TYPE policy;
60
61     BINARY_TREE tree;
62 } RULE;
63
64 struct _RULE_CHECKER
65 {
66     RULE rules[MAX_RULE];
67
68     int count;
69 };
70
71 typedef struct
72 {
73     int type;
74     int reqID;
75     const char * name;
76     int pid;
77     char * cmd;
78 } VAL_ARGUMENTS;
79
80 typedef struct
81 {
82     char **reply;
83     int  *len;
84 } REPLY_BUFFER;
85
86 static int print_func (BINARY_TREE tree, BINARY_TREE_NODE node, BINARY_TREE_NODE parent, void * arg)
87 {
88     REPLY_BUFFER *buffer = (REPLY_BUFFER*)arg;
89     char *reply = *buffer->reply;
90     int *len = buffer->len;
91     char * operators[] = { "==", "<", ">", "<=", ">=", "!=" };
92
93     PARSE_DATA data = bintree_get_node_data (node);
94
95     if (data->node_type == ALL)
96         REPLY ("ALL");
97     else if (data->node_type == AND)
98         REPLY (" and ");
99     else if (data->node_type == OR)
100         REPLY (" or ");
101     else // data->node_type == DATA
102     {
103         if (node == bintree_get_left_child (parent))
104             REPLY ("(");
105
106         REPLY ("%s %s ", data->variable_name, operators[data->compare]);
107
108         if (data->value_type == INTEGER)
109             REPLY ("%d", data->value.integer);
110         else
111             REPLY ("%s", data->value.string);
112
113         if (node == bintree_get_right_child (parent))
114             REPLY (")");
115     }
116
117     *buffer->reply = reply;
118
119     return 0;
120 }
121
122 static int compare_string (COMPARER compare, char * str2, char * str1)
123 {
124     int result = strcasecmp (str2, str1);
125     switch (compare)
126     {
127     case EQUAL:
128         return result == 0;
129     case LESS:
130         return result < 0;
131     case GREATER:
132         return result > 0;
133     case LESS_EQ:
134         return result <= 0;
135     case GREATER_EQ:
136         return result >= 0;
137     case NOT_EQ:
138         return result != 0;
139     }
140
141     return 0;
142 }
143
144 static int compare_int (COMPARER compare, int int2, int int1)
145 {
146     switch (compare)
147     {
148     case EQUAL:
149         return int1 == int2;
150     case LESS:
151         return int1 < int2;
152     case GREATER:
153         return int1 > int2;
154     case LESS_EQ:
155         return int1 <= int2;
156     case GREATER_EQ:
157         return int1 >= int2;
158     case NOT_EQ:
159         return int1 != int2;
160     }
161
162     return 0;
163 }
164
165 static int validate_func (BINARY_TREE tree, BINARY_TREE_NODE node, BINARY_TREE_NODE parent, void * arg)
166 {
167     VAL_ARGUMENTS * args = (VAL_ARGUMENTS*)arg;
168     BINARY_TREE_NODE left, right;
169
170     PARSE_DATA left_data = NULL, right_data = NULL;
171     PARSE_DATA data = bintree_get_node_data (node);
172
173     data->result = BEP_UNKNOWN;
174
175     if (data->node_type == AND || data->node_type == OR)
176     {
177         left = bintree_get_left_child (node);
178         right = bintree_get_right_child (node);
179         if (left == NULL || right == NULL)
180         {
181             printf ("Node error\n");
182             return -1;
183         }
184
185         left_data = bintree_get_node_data (left);
186         right_data = bintree_get_node_data (right);
187     }
188
189     if (data->node_type == ALL)
190     {
191         data->result = BEP_TRUE;
192     }
193     else if (data->node_type == DATA)
194     {
195         char major[64];
196         char * minor = NULL;
197
198         if (args->name)
199             minor = index (args->name, ':');
200         if (minor)
201         {
202             int min = MIN (sizeof(major)-1, minor-args->name);
203             strncpy (major, args->name, min);
204             major[min] = '\0';
205             minor++;
206         }
207         if (!strcasecmp (data->variable_name, "TYPE"))
208         {
209             char * type_string;
210             if (args->type == 0) // EVENT
211                 type_string = "EVENT";
212             else if (args->type == 1)
213                 type_string = "REQUEST";
214             else if (args->type == 2)
215                 type_string = "REPLY";
216             else if (args->type == 3)
217                 type_string = "FLUSH";
218             else if (args->type == 4)
219                 type_string = "ERROR";
220             else
221             {
222                 fprintf (stderr, "Invalid type %d\n", args->type);
223                 return -1;
224             }
225
226             if (compare_string (data->compare, data->value.string, type_string))
227                 data->result = BEP_TRUE;
228             else
229                 data->result = BEP_FALSE;
230         }
231         else if (!strcasecmp (data->variable_name, "MAJOR"))
232         {
233             if (minor && compare_string (data->compare, data->value.string, major))
234                 data->result = BEP_TRUE;
235             else
236                 data->result = BEP_FALSE;
237         }
238         else if (!strcasecmp (data->variable_name, "MINOR"))
239         {
240             if (minor && compare_string (data->compare, data->value.string, minor))
241                 data->result = BEP_TRUE;
242             else
243                 data->result = BEP_FALSE;
244         }
245         else if (!strcasecmp (data->variable_name, "PID"))
246         {
247             if (compare_int (data->compare, data->value.integer, args->pid))
248                 data->result = BEP_TRUE;
249             else
250                 data->result = BEP_FALSE;
251         }
252         else if (!strcasecmp (data->variable_name, "CMD") || !strcasecmp (data->variable_name, "COMMAND"))
253         {
254             if (args->cmd && compare_string (data->compare, data->value.string, args->cmd))
255                 data->result = BEP_TRUE;
256             else
257                 data->result = BEP_FALSE;
258         }
259     }
260     else if (data->node_type == AND)
261     {
262         if (left_data->result == BEP_TRUE && right_data->result == BEP_TRUE)
263             data->result = BEP_TRUE;
264         else
265             data->result = BEP_FALSE;
266     }
267     else if (data->node_type == OR)
268     {
269         if (left_data->result == BEP_TRUE || right_data->result == BEP_TRUE)
270             data->result = BEP_TRUE;
271         else
272             data->result = BEP_FALSE;
273     }
274     else
275         return -1;
276
277     return 0;
278 }
279
280
281 RULE_CHECKER rulechecker_init()
282 {
283     RULE_CHECKER rc = calloc (sizeof (struct _RULE_CHECKER), 1);
284     if (rc == NULL)
285         return NULL;
286
287     rc->count = 0;
288
289     return rc;
290 }
291
292 void rulechecker_destroy (RULE_CHECKER rc)
293 {
294     int i;
295     for (i=rc->count - 1; i>=0; i--)
296         rulechecker_remove_rule (rc, i);
297
298     free (rc);
299 }
300
301 RC_RESULT_TYPE rulechecker_add_rule (RULE_CHECKER rc, POLICY_TYPE policy, const char * rule_string)
302 {
303     if (rc->count == MAX_RULE)
304         return RC_ERR_TOO_MANY_RULES;
305
306     rc->rules[rc->count].tree = bool_exp_parse (rule_string);
307     if (rc->rules[rc->count].tree == NULL)
308         return RC_ERR_PARSE_ERROR;
309     rc->rules[rc->count].policy = policy;
310
311     rc->count++;
312
313     return RC_OK;
314 }
315
316 RC_RESULT_TYPE rulechecker_remove_rule (RULE_CHECKER rc, int index)
317 {
318     if (index < 0 || index >= rc->count)
319         return RC_ERR_NO_RULE;
320
321     bintree_destroy_tree (rc->rules[index].tree);
322
323     rc->count--;
324     if (index != rc->count)
325         memmove (&rc->rules[index], &rc->rules[index + 1], sizeof (RULE) * (rc->count - index));
326
327     return RC_OK;
328 }
329
330 void rulechecker_print_rule (RULE_CHECKER rc, char *reply, int *len)
331 {
332     REPLY_BUFFER buffer = {&reply, len};
333     int i;
334
335     REPLY (" ---------------- Evlog Rules ----------------\n");
336
337     for (i=0; i<rc->count; i++)
338     {
339         REPLY (" [Rule %d] [%s] \"", i, rc->rules[i].policy == ALLOW ? "ALLOW" : "DENY");
340
341         bintree_inorder_traverse (rc->rules[i].tree, print_func, (void*)&buffer);
342         REPLY ("\"\n");
343     }
344 }
345
346 const char * rulechecker_print_usage()
347 {
348     return
349         "######################################################################\n"
350         "###     RuleChecker 1.0 for XDBG EvLog filtering.                  ###\n"
351         "###                 Designed and developed by                      ###\n"
352         "###                 YoungHoon Jung <yhoon.jung@samsung.com>        ###\n"
353         "######################################################################\n"
354         "\n"
355         "-----------------------------------------------------------------\n"
356         "How to read evlog messages :\n"
357         "      Client(pid: [PID]|       [CMD])   <======     [TYPE]( [MAJOR]:  [MINOR])   =====     XServer\n"
358         "\n"
359         "   ie)\n"
360         "        Client(pid:00345|        xdbg)   <======    Event (       X11:SendEvent)   =====     XServer\n"
361         "             ==> type = event && pid = 345 && cmd = xdbg && major = X11 && minor = SendEvent\n"
362         "        Client(pid:00111|        xeyes)     =====   Request(       SHM:ShmAttach)   ======>   XServer\n"
363         "             ==> type = request && pid = 111 && cmd = xeyes && major = SHM && minor = ShmAttach\n"
364         "\n"
365         "-----------------------------------------------------------------\n"
366         "Usage : xdbg evlog_rule add [POLICY] [RULE]\n"
367         "        xdbg evlog_rule remove [INDEX]\n"
368         "        xdbg evlog_rule file [RULE_FILE]\n"
369         "        xdbg evlog_rule help / print\n"
370         "      [POLICY] : allow / deny \n"
371         "      [RULE] : C Language-style boolean expression syntax. [VARIABLE] [COMPAROTOR] [VALUE]\n"
372         "      [VARIABLE] : type / major / minor / command / cmd / pid\n"
373         "      [COMPARATOR] : & / && / and / | / || / or / = / == / != / > / >= / < / <=\n"
374         "      [VALUE] : string / number  \n"
375         "\n"
376         "   ie)\n"
377         "        xdbg evlog_rule add allow \"(type=request) && (major == X11 and (minor = SendEvent or minor = ReceiveEvent))\"\n"
378         "        xdbg evlog_rule add deny cmd!=ls\n"
379         "        xdbg evlog_rule remove 1\n"
380         "\n";
381 }
382
383 int rulechecker_validate_rule (RULE_CHECKER rc, int type, int reqID, const char * name, int pid, char * cmd)
384 {
385     VAL_ARGUMENTS args = { type, reqID, name, pid, cmd };
386     BINARY_TREE_NODE node;
387     PARSE_DATA data;
388
389     // set default value here
390     POLICY_TYPE default_policy = DENY;
391     int i;
392     for (i=rc->count - 1; i >= 0; i--)
393     {
394         bintree_postorder_traverse (rc->rules[i].tree, validate_func, &args);
395         node = bintree_get_head (rc->rules[i].tree);
396         data = bintree_get_node_data (node);
397
398         if (data->result == BEP_TRUE)
399         {
400             return rc->rules[i].policy == ALLOW;
401         }
402     }
403
404     return default_policy == ALLOW;
405 }