45a31202fc8c7e62a26a77977759accba67b2d5c
[platform/core/uifw/libds-tizen.git] / examples / protocol-trace.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <time.h>
4 #include <ctype.h>
5 #include <fcntl.h>
6 #include <unistd.h>
7 #include <errno.h>
8 #include <libds/log.h>
9 #include "protocol-trace.h"
10
11 #define PATH_MAX 512
12 #define MAX_RULE 64
13 #define STRING_MAX 64
14
15 #define BUF_SNPRINTF(fmt, ARG...) do { \
16     str_l = snprintf(str_buff, str_r, fmt, ##ARG); \
17     str_buff += str_l; \
18     str_r -= str_l; \
19 } while (0)
20
21 #ifndef REPLY
22     #define REPLY(fmt, ARG...)  \
23         do { \
24             if (reply && len && *len > 0) { \
25                 int s = snprintf(reply, *len, fmt, ##ARG); \
26                 reply += s; \
27                 *len -= s; \
28             } \
29         } while (0)
30 #endif
31
32 #define MIN(a,b) ((a)<(b)?(a):(b))
33
34 struct protocol_trace_tree_node
35 {
36     struct protocol_trace_tree_node *left;
37     struct protocol_trace_tree_node *right;
38 };
39
40 struct protocol_trace_tree
41 {
42     int size;
43     struct protocol_trace_tree_node *head;
44 };
45
46 //enums for protocol_trace_policy_type
47 enum protocol_trace_policy_type
48 {
49     PROTOCOL_POLICY_TYPE_UNDEFINED,
50     PROTOCOL_POLICY_TYPE_ALLOW,
51     PROTOCOL_POLICY_TYPE_DENY
52 };
53
54 struct protocol_trace_rule
55 {
56     enum protocol_trace_policy_type policy;
57     struct protocol_trace_tree *tree;
58 };
59
60 struct protocol_trace_rule_checker
61 {
62     struct protocol_trace_rule rules[MAX_RULE];
63     int count;
64 };
65
66 //enums for protocol_trace_protocol_log
67 enum protocol_trace_protocol_type {
68     PROTOCOL_TYPE_REQUEST,
69     PROTOCOL_TYPE_EVENT
70 };
71
72 struct protocol_trace_protocol_log
73 {
74     enum protocol_trace_protocol_type type;
75     int client_pid;
76     int target_id;
77     char name[PATH_MAX + 1];
78     char cmd[PATH_MAX + 1];
79 };
80
81 //enums for protocol_trace_rule_node
82 enum protocol_trace_result_type
83 {
84     PROTOCOL_TRACE_RESULT_UNKNOWN,
85     PROTOCOL_TRACE_RESULT_TRUE,
86     PROTOCOL_TRACE_RESULT_FALSE
87 };
88
89 enum protocol_trace_node_type
90 {
91     PROTOCOL_TRACE_NODE_TYPE_NONE,
92     PROTOCOL_TRACE_NODE_TYPE_AND,
93     PROTOCOL_TRACE_NODE_TYPE_OR,
94     PROTOCOL_TRACE_NODE_TYPE_DATA,
95     PROTOCOL_TRACE_NODE_TYPE_ALL
96 };
97
98 enum protocol_trace_comparer
99 {
100     PROTOCOL_TRACE_COMPARER_EQUAL,
101     PROTOCOL_TRACE_COMPARER_LESS,
102     PROTOCOL_TRACE_COMPARER_GREATER,
103     PROTOCOL_TRACE_COMPARER_LESS_EQ,
104     PROTOCOL_TRACE_COMPARER_GREATE_EQ,
105     PROTOCOL_TRACE_COMPARER_NOT_EQ
106 };
107
108 enum protocol_trace_data_type
109 {
110     PROTOCOL_TRACE_DATA_TYPE_INTEGER,
111     PROTOCOL_TRACE_DATA_TYPE_STRING
112 };
113
114 struct protocol_trace_rule_node
115 {
116     enum protocol_trace_node_type node_type;
117     enum protocol_trace_comparer comparer;
118     enum protocol_trace_data_type value_type;
119     enum protocol_trace_result_type result;
120     char variable_name[STRING_MAX];
121
122     union
123     {
124         char string[STRING_MAX];
125         int integer;
126     }value;
127 };
128
129 //enums for protocol_trace_token_data
130 enum protocol_trace_token
131 {
132     PROTOCOL_TRACE_TOKEN_UNKNOWN,
133     PROTOCOL_TRACE_TOKEN_L_BR,
134     PROTOCOL_TRACE_TOKEN_R_BR,
135     PROTOCOL_TRACE_TOKEN_NOT_EQ,
136     PROTOCOL_TRACE_TOKEN_EQUAL,
137     PROTOCOL_TRACE_TOKEN_LSS_THAN,
138     PROTOCOL_TRACE_TOKEN_LSS_EQ,
139     PROTOCOL_TRACE_TOKEN_GRT_THAN,
140     PROTOCOL_TRACE_TOKEN_GRT_EQ,
141     PROTOCOL_TRACE_TOKEN_AND,
142     PROTOCOL_TRACE_TOKEN_OR,
143     PROTOCOL_TRACE_TOKEN_SPACE,
144     PROTOCOL_TRACE_TOKEN_SYMBOL,
145     PROTOCOL_TRACE_TOKEN_NUMBER,
146     PROTOCOL_TRACE_TOKEN_EOS,
147 };
148
149 struct protocol_trace_token_data
150 {
151     const char **string;
152     enum protocol_trace_token last_token;
153     const char *last_symbol;
154     int symbol_len;
155 };
156
157 struct protocol_trace_validate_args
158 {
159     int type;
160     int target_id;
161     const char *name;
162     int pid;
163     const char *cmd;
164 };
165
166 struct argument_details {
167     char type;
168     int nullable;
169 };
170
171 struct protocol_trace_reply_buffer
172 {
173     char **reply;
174     int *len;
175 };
176
177 enum protocol_trace_rule_set_result
178 {
179     PROTOCOL_TRACE_RULE_SET_OK,
180     PROTOCOL_TRACE_RULE_SET_ERR_TOO_MANY_RULES,
181     PROTOCOL_TRACE_RULE_SET_ERR_PARSE,
182     PROTOCOL_TRACE_RULE_SET_ERR_NO_RULE
183 };
184
185 typedef int (*tree_traverse_cb) (struct protocol_trace_tree *tree,
186         struct protocol_trace_tree_node *node,
187         struct protocol_trace_tree_node *parent,
188         void *arg);
189 static struct protocol_trace_tree_node *parser_parse_token(
190         struct protocol_trace_tree *tree,
191         struct protocol_trace_token_data *token);
192 static bool rule_set(const int argc, const char **argv, char *reply, int *len);
193
194 char trace_env_path[PATH_MAX + 1];
195 static FILE *log_fp_ptrace = NULL;
196 static struct wl_protocol_logger *ds_wl_protocol_logger;
197 static struct protocol_trace_rule_checker *global_rc = NULL;
198 static struct wl_display *display;
199
200 static struct
201 {
202     const char *token_char;
203     const int token_length;
204     enum protocol_trace_token token_name;
205 } token_table[] =
206 {
207     {"\0",  1, PROTOCOL_TRACE_TOKEN_EOS},
208     {"\t",  1, PROTOCOL_TRACE_TOKEN_SPACE},
209     {" ",   1, PROTOCOL_TRACE_TOKEN_SPACE},
210     {"!=",  2, PROTOCOL_TRACE_TOKEN_NOT_EQ},
211     {"&",   1, PROTOCOL_TRACE_TOKEN_AND},
212     {"&&",  2, PROTOCOL_TRACE_TOKEN_AND},
213     {"(",   1, PROTOCOL_TRACE_TOKEN_L_BR},
214     {")",   1, PROTOCOL_TRACE_TOKEN_R_BR},
215     {"<",   1, PROTOCOL_TRACE_TOKEN_LSS_THAN},
216     {"<=",  2, PROTOCOL_TRACE_TOKEN_LSS_EQ},
217     {"<>",  2, PROTOCOL_TRACE_TOKEN_NOT_EQ},
218     {"=",   1, PROTOCOL_TRACE_TOKEN_EQUAL},
219     {"==",  2, PROTOCOL_TRACE_TOKEN_EQUAL},
220     {">",   1, PROTOCOL_TRACE_TOKEN_GRT_THAN},
221     {">=",  2, PROTOCOL_TRACE_TOKEN_GRT_EQ},
222     {"and", 3, PROTOCOL_TRACE_TOKEN_AND},
223     {"or",  2, PROTOCOL_TRACE_TOKEN_OR},
224     {"|",   1, PROTOCOL_TRACE_TOKEN_OR},
225     {"||",  2, PROTOCOL_TRACE_TOKEN_OR},
226 };
227
228 static struct protocol_trace_tree_node *
229 bintree_get_head(struct protocol_trace_tree *tree)
230 {
231     return tree->head;
232 }
233
234 static void
235 bintree_set_head(struct protocol_trace_tree *tree,
236         struct protocol_trace_tree_node *head)
237 {
238     tree->head = head;
239 }
240
241 static struct protocol_trace_tree_node *
242 bintree_get_left_child(struct protocol_trace_tree_node *node)
243 {
244     return node->left;
245 }
246
247 static void
248 bintree_set_left_child(struct protocol_trace_tree_node *node,
249         struct protocol_trace_tree_node *child)
250 {
251     node->left = child;
252 }
253
254 static struct protocol_trace_tree_node *
255 bintree_get_right_child(struct protocol_trace_tree_node *node)
256 {
257     return node->right;
258 }
259
260 static void
261 bintree_set_right_child(struct protocol_trace_tree_node *node,
262         struct protocol_trace_tree_node *child)
263 {
264     node->right = child;
265 }
266
267 static void *
268 bintree_get_node_data(struct protocol_trace_tree_node *node)
269 {
270     return (void*)(node+1);
271 }
272
273 static int
274 bintree_inorder_traverse_recursive(struct protocol_trace_tree *tree,
275         struct protocol_trace_tree_node *node,
276         struct protocol_trace_tree_node *parent,
277         tree_traverse_cb func, void *arg)
278 {
279     if (node->left) {
280         if (bintree_inorder_traverse_recursive(tree, node->left, node,
281                  func, arg) != 0)
282             return 1;
283     }
284
285     if (func(tree, node, parent, arg))
286         return 1;
287
288     if (node->right) {
289         if (bintree_inorder_traverse_recursive(tree, node->right, node,
290                 func, arg) != 0)
291             return 1;
292     }
293
294     return 0;
295 }
296
297 static void
298 bintree_inorder_traverse(struct protocol_trace_tree *tree,
299         tree_traverse_cb func, void *arg)
300 {
301     if (tree->head)
302         bintree_inorder_traverse_recursive(tree, tree->head, tree->head,
303                 func, arg);
304 }
305
306 static int
307 bintree_postorder_traverse_recursive(struct protocol_trace_tree *tree,
308         struct protocol_trace_tree_node *node,
309         struct protocol_trace_tree_node *parent,
310         tree_traverse_cb func, void *arg)
311 {
312     if (node->left) {
313         if (bintree_postorder_traverse_recursive(tree, node->left, node,
314                 func, arg) != 0)
315             return 1;
316     }
317     if (node->right) {
318         if (bintree_postorder_traverse_recursive(tree, node->right, node,
319                 func, arg) != 0)
320             return 1;
321     }
322
323     return func(tree, node,parent, arg);
324 }
325
326 static void
327 bintree_postorder_traverse(struct protocol_trace_tree *tree,
328         tree_traverse_cb func, void *arg)
329 {
330     if (tree->head)
331         bintree_postorder_traverse_recursive(tree, tree->head, tree->head,
332                 func, arg);
333 }
334
335 static struct protocol_trace_tree *
336 bintree_create_tree(int size)
337 {
338     struct protocol_trace_tree *tree;
339
340     tree = calloc(1, sizeof(struct protocol_trace_tree) + size);
341     if (!tree)
342         return NULL;
343
344     tree->size = size;
345     tree->head = NULL;
346
347     return tree;
348 }
349 static struct protocol_trace_tree_node *
350 bintree_create_node(struct protocol_trace_tree *tree)
351 {
352     struct protocol_trace_tree_node *node;
353
354     node = calloc(1, sizeof(struct protocol_trace_tree_node) + tree->size);
355     if (!node)
356         return NULL;
357
358     node->left = NULL;
359     node->right = NULL;
360
361     return node;
362 }
363
364 static void
365 bintree_remove_node(struct protocol_trace_tree_node *node)
366 {
367     free(node);
368 }
369
370 static void
371 bintree_remove_node_recursive(struct protocol_trace_tree_node *node)
372 {
373     if (node->left)
374         bintree_remove_node_recursive(node->left);
375     if (node->right)
376         bintree_remove_node_recursive(node->right);
377
378     bintree_remove_node(node);
379 }
380
381 static void
382 bintree_destroy_tree(struct protocol_trace_tree *tree)
383 {
384     if (tree->head)
385         bintree_remove_node_recursive(tree->head);
386     free(tree);
387 }
388
389 static int
390 rulechecker_string_compare(enum protocol_trace_comparer comparer,
391         char *str2, const char *str1)
392 {
393     int result;
394
395     result = strcasecmp(str2, str1);
396
397     switch (comparer) {
398         case PROTOCOL_TRACE_COMPARER_EQUAL:
399             return result == 0;
400         case PROTOCOL_TRACE_COMPARER_LESS:
401             return result < 0;
402         case PROTOCOL_TRACE_COMPARER_GREATER:
403             return result > 0;
404         case PROTOCOL_TRACE_COMPARER_LESS_EQ:
405             return result <= 0;
406         case PROTOCOL_TRACE_COMPARER_GREATE_EQ:
407             return result >= 0;
408         case PROTOCOL_TRACE_COMPARER_NOT_EQ:
409             return result != 0;
410     }
411
412     return 0;
413 }
414
415 static int
416 rulechecker_int_compare(enum protocol_trace_comparer comparer,
417         int int2, int int1)
418 {
419     switch (comparer) {
420         case PROTOCOL_TRACE_COMPARER_EQUAL:
421             return int1 == int2;
422         case PROTOCOL_TRACE_COMPARER_LESS:
423             return int1 < int2;
424         case PROTOCOL_TRACE_COMPARER_GREATER:
425             return int1 > int2;
426         case PROTOCOL_TRACE_COMPARER_LESS_EQ:
427             return int1 <= int2;
428         case PROTOCOL_TRACE_COMPARER_GREATE_EQ:
429             return int1 >= int2;
430         case PROTOCOL_TRACE_COMPARER_NOT_EQ:
431             return int1 != int2;
432     }
433
434     return 0;
435 }
436
437 static int
438 rulechecker_validate_rule_func(struct protocol_trace_tree *tree,
439         struct protocol_trace_tree_node *node,
440         struct protocol_trace_tree_node *parent,
441         void *arg)
442 {
443     struct protocol_trace_validate_args *args;
444     struct protocol_trace_tree_node *left, *right;
445     struct protocol_trace_rule_node *data, *left_data, *right_data;
446
447     args = (struct protocol_trace_validate_args *)arg;
448     data = (struct protocol_trace_rule_node *)bintree_get_node_data(node);
449     data->result = PROTOCOL_TRACE_RESULT_UNKNOWN;
450
451     if (data->node_type == PROTOCOL_TRACE_NODE_TYPE_AND ||
452         data->node_type == PROTOCOL_TRACE_NODE_TYPE_OR) {
453         left = bintree_get_left_child(node);
454         right = bintree_get_right_child(node);
455         if (!left || !right) {
456             ds_err("Node error");
457             return -1;
458         }
459
460         left_data = (struct protocol_trace_rule_node *)bintree_get_node_data(left);
461         right_data = (struct protocol_trace_rule_node *)bintree_get_node_data(right);
462     }
463
464     if (data->node_type == PROTOCOL_TRACE_NODE_TYPE_ALL) {
465         data->result = PROTOCOL_TRACE_RESULT_TRUE;
466     } else if (data->node_type == PROTOCOL_TRACE_NODE_TYPE_DATA) {
467         char iface[64] = {0,};
468         char *msg = NULL;
469
470         if (args->name) {
471             msg = (char *) strchr(args->name, ':');
472         }
473         if (msg) {
474             int size_iface = sizeof(iface) -1;
475             int min = MIN(size_iface, msg-args->name);
476             strncpy(iface, args->name, min);
477             iface[min] = '\0';
478             msg++;
479         }
480         if (!strcasecmp(data->variable_name, "TYPE")) {
481             const char *type_string;
482             if (args->type == 0)
483                 type_string = "REQUEST";
484             else if (args->type == 1)
485                 type_string = "EVENT";
486             else {
487                 ds_err("Invalid type %d", args->type);
488                 return -1;
489             }
490
491             if (rulechecker_string_compare(data->comparer,
492                     data->value.string, type_string))
493                 data->result = PROTOCOL_TRACE_RESULT_TRUE;
494             else
495                 data->result = PROTOCOL_TRACE_RESULT_FALSE;
496         } else if (!strcasecmp(data->variable_name, "IFACE")) {
497             if (msg && iface[0] &&
498                 rulechecker_string_compare(data->comparer,
499                         data->value.string, (const char *)iface))
500                 data->result = PROTOCOL_TRACE_RESULT_TRUE;
501             else
502                 data->result = PROTOCOL_TRACE_RESULT_FALSE;
503         } else if (!strcasecmp(data->variable_name, "MSG")) {
504             if (msg &&
505                 rulechecker_string_compare(data->comparer,
506                         data->value.string, msg))
507                 data->result = PROTOCOL_TRACE_RESULT_TRUE;
508             else
509                 data->result = PROTOCOL_TRACE_RESULT_FALSE;
510         } else if (!strcasecmp(data->variable_name, "PID")) {
511             if (rulechecker_int_compare(data->comparer,
512                     data->value.integer, args->pid))
513                 data->result = PROTOCOL_TRACE_RESULT_TRUE;
514             else
515                 data->result = PROTOCOL_TRACE_RESULT_FALSE;
516         } else if (!strcasecmp(data->variable_name, "CMD") ||
517             !strcasecmp(data->variable_name, "COMMAND")) {
518             if (msg &&
519                 rulechecker_string_compare(data->comparer,
520                         data->value.string, args->cmd))
521                 data->result = PROTOCOL_TRACE_RESULT_TRUE;
522             else
523                 data->result = PROTOCOL_TRACE_RESULT_FALSE;
524         }
525     } else if (data->node_type == PROTOCOL_TRACE_NODE_TYPE_AND) {
526         if (left_data->result == PROTOCOL_TRACE_RESULT_TRUE &&
527             right_data->result == PROTOCOL_TRACE_RESULT_TRUE)
528             data->result = PROTOCOL_TRACE_RESULT_TRUE;
529         else
530             data->result = PROTOCOL_TRACE_RESULT_FALSE;
531     } else if (data->node_type == PROTOCOL_TRACE_NODE_TYPE_OR) {
532         if (left_data->result == PROTOCOL_TRACE_RESULT_TRUE ||
533             right_data->result == PROTOCOL_TRACE_RESULT_TRUE)
534             data->result = PROTOCOL_TRACE_RESULT_TRUE;
535         else
536             data->result = PROTOCOL_TRACE_RESULT_FALSE;
537     } else {
538         return -1;
539     }
540
541     return 0;
542 }
543
544 static int
545 rulechecker_validate_rules(struct protocol_trace_rule_checker *rc,
546         int type, int target_id, const char *name, int pid, const char *cmd)
547 {
548     struct protocol_trace_validate_args args = {type, target_id, name, pid, cmd};
549     struct protocol_trace_tree_node *node;
550     struct protocol_trace_rule_node *data;
551     enum protocol_trace_policy_type default_policy;
552
553     default_policy = PROTOCOL_POLICY_TYPE_DENY;
554
555     for (int i = rc->count - 1; i >= 0 ; i--) {
556         bintree_postorder_traverse(rc->rules[i].tree, rulechecker_validate_rule_func, &args);
557         node = (struct protocol_trace_tree_node *)bintree_get_head(rc->rules[i].tree);
558         data = (struct protocol_trace_rule_node *)bintree_get_node_data(node);
559
560         if (data->result == PROTOCOL_TRACE_RESULT_TRUE) {
561             return rc->rules[i].policy == PROTOCOL_POLICY_TYPE_ALLOW;
562         }
563     }
564
565     return default_policy == PROTOCOL_POLICY_TYPE_ALLOW;
566 }
567
568 static char *
569 logger_cmd_get(char *path)
570 {
571     char *p;
572
573     if (!path) return NULL;
574
575     p = strrchr(path, '/');
576
577     return (p) ? p+1 : path;
578 }
579
580 static bool
581 logger_validate_rule(struct protocol_trace_protocol_log *log)
582 {
583     const char *cmd = "";
584     int ret;
585
586     if (!global_rc)
587         return false;
588
589     cmd = logger_cmd_get(log->cmd);
590
591     ret = rulechecker_validate_rules(global_rc, log->type, log->target_id, log->name,
592             log->client_pid, cmd);
593
594     return ret;
595 }
596
597 static void
598 logger_get_proc_name(pid_t pid, char *name, int size)
599 {
600     FILE *h;
601     char proc[PATH_MAX], pname[PATH_MAX];
602     size_t len;
603
604     if (!name) return;
605
606     snprintf(proc, PATH_MAX, "/proc/%d/cmdline", pid);
607
608     h = fopen(proc, "r");
609     if (!h) return;
610
611     len = fread(pname, sizeof(char), PATH_MAX, h);
612     if (len > 0)
613         pname[len - 1]='\0';
614     else
615         strncpy(pname, "NO NAME", sizeof(pname));
616
617     fclose(h);
618
619     strncpy(name, pname, size);
620 }
621
622 static const char *
623 logger_get_next_argument(const char *signature, struct argument_details *details)
624 {
625     details->nullable = 0;
626
627     for (; *signature; ++signature) {
628         switch (*signature) {
629             case 'i':
630             case 'u':
631             case 'f':
632             case 's':
633             case 'o':
634             case 'n':
635             case 'a':
636             case 'h':
637                 details->type = *signature;
638                 return signature + 1;
639             case '?':
640                 details->nullable = 1;
641         }
642     }
643     details->type = '\0';
644
645     return signature;
646 }
647
648 static void
649 logger_handle_client_destroy(struct wl_listener *listener, void *data)
650 {
651     struct wl_client *wc = (struct wl_client *)data;
652     struct timespec tp;
653     unsigned int time;
654     pid_t client_pid =-1;
655
656     char strbuf[PATH_MAX], *str_buff = strbuf;
657     int str_r, str_l;
658
659     str_buff[0] = '\0';
660     str_r = sizeof(strbuf);
661
662     wl_client_get_credentials(wc, &client_pid, NULL, NULL);
663
664     clock_gettime(CLOCK_MONOTONIC, &tp);
665     time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
666
667     BUF_SNPRINTF("[%10.3f] Server   [PID:%d] client destroying", time / 1000.0,
668             client_pid);
669
670     if (log_fp_ptrace)
671         fprintf(log_fp_ptrace, "%s\n", strbuf);
672     else
673         ds_dbg("%s", strbuf);
674
675     wl_list_remove(&listener->link);
676     free(listener);
677     listener = NULL;
678 }
679
680 static void
681 logger_add_client_destroy_listener(struct wl_client *client)
682 {
683     struct wl_listener *destroy_listener;
684
685     destroy_listener = wl_client_get_destroy_listener(client,
686             logger_handle_client_destroy);
687     if (destroy_listener)
688         return;
689
690     destroy_listener = calloc(1, sizeof *destroy_listener);
691     if (!destroy_listener)
692         return;
693
694     destroy_listener->notify = logger_handle_client_destroy;
695     wl_client_add_destroy_listener(client, destroy_listener);
696 }
697
698 void
699 logger_func(void *user_data, enum wl_protocol_logger_type direction,
700         const struct wl_protocol_logger_message *message)
701 {
702     struct argument_details arg;
703     struct wl_client *wc;
704     const char *signature;;
705     pid_t client_pid = -1;
706     struct timespec tp;
707     unsigned int time;
708
709     char strbuf[PATH_MAX], *str_buff;
710     int str_r, str_l;
711
712     wc = wl_resource_get_client(message->resource);
713     if (wc) {
714         logger_add_client_destroy_listener(wc);
715         wl_client_get_credentials(wc, &client_pid, NULL, NULL);
716     }
717
718     clock_gettime(CLOCK_MONOTONIC, &tp);
719     time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
720
721     struct protocol_trace_protocol_log elog = {PROTOCOL_TYPE_REQUEST,};
722     if (direction == WL_PROTOCOL_LOGGER_EVENT)
723         elog.type = PROTOCOL_TYPE_EVENT;
724     else
725         elog.type = PROTOCOL_TYPE_REQUEST;
726     elog.client_pid = client_pid;
727     elog.target_id = wl_resource_get_id(message->resource);
728     snprintf(elog.name, PATH_MAX,"%s:%s",
729             wl_resource_get_class(message->resource), message->message->name);
730
731     char name[PATH_MAX];
732     logger_get_proc_name(client_pid, name, PATH_MAX);
733     snprintf(elog.cmd, PATH_MAX, "%s", name);
734
735     if (!logger_validate_rule(&elog)) return;
736
737     str_buff = strbuf;
738     str_buff[0] = '\0';
739     str_r = sizeof(strbuf);
740
741     BUF_SNPRINTF("[%10.3f] %s%d%s%s@%u.%s(",
742             time / 1000.0,
743             elog.type ? "Server->Client [PID:" : "Server<-Client [PID:",
744             client_pid, "]",
745             wl_resource_get_class(message->resource),
746             wl_resource_get_id(message->resource),
747             message->message->name);
748
749     signature = message->message->signature;
750
751     for (int i = 0; i < message->arguments_count; i++) {
752         signature = logger_get_next_argument(signature, &arg);
753
754         if (i > 0) BUF_SNPRINTF(", ");
755
756         switch (arg.type) {
757             case 'u':
758                 BUF_SNPRINTF("%u", message->arguments[i].u);
759                 break;
760             case 'i':
761                 BUF_SNPRINTF("%i", message->arguments[i].i);
762                 break;
763             case 'f':
764                 BUF_SNPRINTF("%f", wl_fixed_to_double(message->arguments[i].f));
765                 break;
766             case 's':
767                 BUF_SNPRINTF("\"%s\"", message->arguments[i].s);
768                 break;
769             case 'o':
770                 if (message->arguments[i].o) {
771                     struct wl_resource *resource;
772                     resource = (struct wl_resource *)message->arguments[i].o;
773                     BUF_SNPRINTF("%s@%u",
774                             wl_resource_get_class(resource),
775                             wl_resource_get_id(resource));
776                 } else
777                     BUF_SNPRINTF("nil");
778                 break;
779             case 'n':
780                 BUF_SNPRINTF("new id %s@", (message->message->types[i]) ?
781                         message->message->types[i]->name : "[unknown]");
782                 if (message->arguments[i].n != 0)
783                     BUF_SNPRINTF("%u", message->arguments[i].n);
784                 else
785                     BUF_SNPRINTF("nil");
786                 break;
787             case 'a':
788                 BUF_SNPRINTF("array");
789                 break;
790             case 'h':
791                 BUF_SNPRINTF("fd %d", message->arguments[i].h);
792                 break;
793         }
794     }
795
796     BUF_SNPRINTF("), cmd: %s", elog.cmd ? elog.cmd : "cmd is NULL");
797
798     if (log_fp_ptrace)
799         fprintf(log_fp_ptrace, "%s\n", strbuf);
800     else
801         ds_dbg("%s", strbuf);
802 }
803
804 static void
805 logger_set(void)
806 {
807     ds_dbg("IN >> logger_set");
808
809     log_fp_ptrace = fopen(trace_env_path, "a");
810     if (!log_fp_ptrace) {
811         ds_err("failed open file(%s)", trace_env_path);
812         return;
813     }
814     setvbuf(log_fp_ptrace, NULL, _IOLBF, 512);
815     ds_dbg("has log_fp_ptrace");
816
817     if (ds_wl_protocol_logger) {
818         ds_dbg("if has ds_wl_protocol_logger -> destroy");
819         wl_protocol_logger_destroy(ds_wl_protocol_logger);
820         ds_wl_protocol_logger = NULL;
821     }
822     ds_wl_protocol_logger =
823             wl_display_add_protocol_logger(display, logger_func, NULL);
824
825     ds_dbg("OUT << logger_set");
826 }
827
828 static void
829 logger_unset(void)
830 {
831     ds_dbg("IN >> logger_unset");
832
833     if (ds_wl_protocol_logger) {
834         wl_protocol_logger_destroy(ds_wl_protocol_logger);
835         ds_wl_protocol_logger = NULL;
836     }
837
838     ds_dbg("OUT << logger_unset");
839 }
840
841 static enum protocol_trace_token
842 parser_get_next_token(const char **string)
843 {
844     static int token_cnt;
845     int i, compare_res, found = 0, first, last;
846
847     first = 0;
848     last = token_cnt -1;
849     token_cnt = sizeof(token_table) / sizeof(token_table[0]);
850
851     i = (first + last) / 2;
852     while (1) {
853         compare_res = strncmp(*string, token_table[i].token_char,
854                 token_table[i].token_length);
855         while (compare_res == 0) {
856             found = 1;
857             i++;
858             if (i == token_cnt)
859                 break;
860             compare_res = strncmp(*string, token_table[i].token_char,
861                     token_table[i].token_length);
862         }
863
864         if (found) {
865             i--;
866             *string += token_table[i].token_length;
867             return token_table[i].token_name;
868         }
869
870         if (first >= last)
871             break;
872
873         if (compare_res > 0)
874             first = i + 1;
875         else
876             last = i - 1;
877
878         i = (first + last) / 2;
879     }
880
881     if (isalpha(**string)) {
882         (*string)++;
883         while (isalpha(**string) || isdigit(**string) ||
884                 **string == '_' || **string == '-') {
885             (*string)++;
886         }
887
888         return PROTOCOL_TRACE_TOKEN_SYMBOL;
889     }
890
891     if (isdigit(**string)) {
892         (*string)++;
893         while (isdigit(**string))
894             (*string)++;
895
896         return PROTOCOL_TRACE_TOKEN_NUMBER;
897     }
898
899     return PROTOCOL_TRACE_TOKEN_UNKNOWN;
900 }
901
902 static void
903 parser_process_token(struct protocol_trace_token_data *token)
904 {
905     do {
906         token->last_symbol = *(token->string);
907         token->last_token = parser_get_next_token(token->string);
908         token->symbol_len = *(token->string) - token->last_symbol;
909     } while (token->last_token == PROTOCOL_TRACE_TOKEN_SPACE);
910 }
911
912 static struct protocol_trace_tree_node *
913 parser_parse_statement(struct protocol_trace_tree *tree,
914         struct protocol_trace_token_data *token)
915 {
916     struct protocol_trace_tree_node *node = NULL;
917     struct protocol_trace_rule_node *data;
918
919     if (token->last_token == PROTOCOL_TRACE_TOKEN_L_BR) {
920         parser_process_token(token);
921
922         node = parser_parse_token(tree, token);
923         if (!node)
924             return NULL;
925
926         if (token->last_token != PROTOCOL_TRACE_TOKEN_R_BR)
927             goto fail;
928
929         parser_process_token(token);
930
931         return node;
932     }
933
934     if (token->last_token != PROTOCOL_TRACE_TOKEN_SYMBOL)
935         goto fail;
936
937     node = bintree_create_node(tree);
938     if (!node)
939         goto fail;
940
941     data = (struct protocol_trace_rule_node *) bintree_get_node_data(node);
942
943     strncpy(data->variable_name, token->last_symbol, token->symbol_len);
944     data->variable_name[token->symbol_len] = '\0';
945
946     if (!strcasecmp(data->variable_name, "all")) {
947         ds_dbg("data = all");
948         data->node_type = PROTOCOL_TRACE_NODE_TYPE_ALL;
949         parser_process_token(token);
950
951         return node;
952     }
953
954     data->node_type = PROTOCOL_TRACE_NODE_TYPE_DATA;
955
956     parser_process_token(token);
957
958     switch (token->last_token) {
959         case PROTOCOL_TRACE_TOKEN_NOT_EQ:
960             data->comparer = PROTOCOL_TRACE_COMPARER_NOT_EQ;
961             break;
962         case PROTOCOL_TRACE_TOKEN_EQUAL:
963             data->comparer = PROTOCOL_TRACE_COMPARER_EQUAL;
964             break;
965         case PROTOCOL_TRACE_TOKEN_LSS_THAN:
966             data->comparer = PROTOCOL_TRACE_COMPARER_LESS_EQ;
967             break;
968         case PROTOCOL_TRACE_TOKEN_GRT_THAN:
969             data->comparer = PROTOCOL_TRACE_COMPARER_GREATER;
970             break;
971         case PROTOCOL_TRACE_TOKEN_GRT_EQ:
972             data->comparer = PROTOCOL_TRACE_COMPARER_GREATE_EQ;
973             break;
974         default:
975             goto fail;
976     }
977
978     parser_process_token(token);
979
980     if (token->last_token == PROTOCOL_TRACE_TOKEN_NUMBER) {
981         data->value_type = PROTOCOL_TRACE_DATA_TYPE_INTEGER;
982         data->value.integer = atoi(token->last_symbol);
983     } else if (token->last_token == PROTOCOL_TRACE_TOKEN_SYMBOL) {
984         data->value_type = PROTOCOL_TRACE_DATA_TYPE_STRING;
985         strncpy(data->value.string, token->last_symbol, token->symbol_len);
986         data->value.string[token->symbol_len] = '\0';
987     } else {
988         goto fail;
989     }
990
991     parser_process_token(token);
992
993     return node;
994
995 fail:
996     if (node)
997         bintree_remove_node_recursive(node);
998
999     return NULL;
1000 }
1001
1002 static struct protocol_trace_tree_node *
1003 parser_parse_token(struct protocol_trace_tree *tree,
1004         struct protocol_trace_token_data *token)
1005 {
1006     struct protocol_trace_tree_node *node, *left = NULL, *right = NULL;
1007     struct protocol_trace_rule_node *data;
1008
1009     node = parser_parse_statement(tree,token);
1010     if (!node) {
1011         ds_err("PARSE statement error\n");
1012         goto fail;
1013     }
1014
1015     while (token->last_token == PROTOCOL_TRACE_TOKEN_AND) {
1016         left = node;
1017         node = NULL;
1018
1019         parser_process_token(token);
1020
1021         right = parser_parse_statement(tree, token);
1022         if (!right)
1023             goto fail;
1024
1025         node = bintree_create_node(tree);
1026         if (!node)
1027             goto fail;
1028
1029         data = (struct protocol_trace_rule_node *) bintree_get_node_data(node);
1030         data->node_type = PROTOCOL_TRACE_NODE_TYPE_AND;
1031         bintree_set_left_child(node, left);
1032         bintree_set_right_child(node, right);
1033     }
1034
1035     if (token->last_token == PROTOCOL_TRACE_TOKEN_OR) {
1036         left = node;
1037         node = NULL;
1038
1039         parser_process_token(token);
1040
1041         right = parser_parse_token(tree, token);
1042         if (!right)
1043             goto fail;
1044
1045         node = bintree_create_node(tree);
1046         if (!node)
1047             goto fail;
1048
1049         data = (struct protocol_trace_rule_node *) bintree_get_node_data(node);
1050         data->node_type = PROTOCOL_TRACE_NODE_TYPE_OR;
1051         bintree_set_left_child(node, left);
1052         bintree_set_right_child(node, right);
1053     }
1054
1055     return node;
1056
1057 fail:
1058     ds_dbg("[fail] recursive remove node");
1059     if (left)
1060         bintree_remove_node_recursive(left);
1061
1062     return NULL;
1063 }
1064
1065 static struct protocol_trace_tree *
1066 parser_parse_rule_string(const char *string)
1067 {
1068     struct protocol_trace_tree *tree;
1069     struct protocol_trace_tree_node *node;
1070     struct protocol_trace_token_data token;
1071
1072     token.string = &string;
1073     parser_process_token(&token);
1074
1075     tree = bintree_create_tree(sizeof(struct protocol_trace_rule_node));
1076     if (!tree)
1077         return NULL;
1078
1079     node = parser_parse_token(tree, &token);
1080     if (!node) {
1081         bintree_destroy_tree(tree);
1082         ds_dbg("finish destroy tree & return null");
1083         return NULL;
1084     }
1085
1086     bintree_set_head(tree, node);
1087
1088     return tree;
1089 }
1090
1091 static enum protocol_trace_rule_set_result
1092 rulechecker_rule_add(struct protocol_trace_rule_checker *rc,
1093         enum protocol_trace_policy_type policy, const char *rule_string)
1094 {
1095     if (rc->count == MAX_RULE)
1096         return PROTOCOL_TRACE_RULE_SET_ERR_TOO_MANY_RULES;
1097
1098     rc->rules[rc->count].tree = parser_parse_rule_string(rule_string);
1099     if (!rc->rules[rc->count].tree) {
1100         ds_dbg("parse error");
1101         return PROTOCOL_TRACE_RULE_SET_ERR_PARSE;
1102     }
1103
1104     rc->rules[rc->count].policy = policy;
1105     rc->count++;
1106
1107     return PROTOCOL_TRACE_RULE_SET_OK;
1108 }
1109
1110 static const char *
1111 rulechecker_usage_print()
1112 {
1113     return
1114           "##########################################################\n"
1115           "###     Enlightenment Protocol Log filtering.          ###\n"
1116           "##########################################################\n"
1117           "\n"
1118           "-----------------------------------------------------------------\n"
1119           "How to read enlightenment_info protocol messages :\n"
1120           "[timestamp]   Server --> Client [PID: [pid]] interface@id.message(arguments..) cmd: CMD\n"
1121           "  ex)\n"
1122           "[1476930.145] Server --> Client [PID: 103] wl_touch@10.down(758, 6769315, wl_surface@23, 0, 408.000, 831.000) cmd: /usr/bin/launchpad-loader\n"
1123           "             ==> type = event && pid = 103 && cmd = launchpad-loader && iface = wl_touch && msg = up\n"
1124           "[4234234.123] Server <-- Client [PID: 123] wl_seat@32.get_touch(new id wl_touch@22) cmd: /usr/bin/launchpad-loader\n"
1125           "             ==> type = request && pid = 123 && cmd = launchpad-loader && iface = wl_seat && msg = get_touch\n"
1126           "-----------------------------------------------------------------\n"
1127           "Usage : enlightenment_info -protocol_rule add [POLICY] [RULE]\n"
1128           "        enlightenment_info -protocol_rule remove [INDEX]\n"
1129           "        enlightenment_info -protocol_rule file [RULE_FILE]\n"
1130           "        enlightenment_info -protocol_rule print\n"
1131           "        enlightenment_info -protocol_rule help\n"
1132           "        [POLICY] : allow / deny \n"
1133           "        [RULE] : C Language-style boolean expression syntax. [VARIABLE] [COMPAROTOR] [VALUE]\n"
1134           "        [VARIABLE] : type / iface / msg / cmd(command) / pid\n"
1135           "        [COMPARATOR] : & / && / and / | / || / or / = / == / != / > / >= / < / <=\n"
1136           "        [VALUE] : string / number  \n"
1137           "  ex)\n"
1138           "        enlightenment_info -protocol_rule add allow \"(type=request) && (iface == wl_pointer and (msg = down or msg = up))\"\n"
1139           "        enlightenment_info -protocol_rule add deny cmd!= launch-loader\n"
1140           "        enlightenment_info -protocol_rule remove all\n"
1141           "        enlightenment_info -protocol_rule remove 3\n"
1142         "\n";
1143 }
1144
1145 static int
1146 rulechecker_print_func(struct protocol_trace_tree *tree,
1147         struct protocol_trace_tree_node *node,
1148         struct protocol_trace_tree_node *parent, void *arg)
1149 {
1150     struct protocol_trace_reply_buffer *buffer = (struct protocol_trace_reply_buffer *)arg;
1151     char *reply = *buffer->reply;
1152     int *len = buffer->len;
1153     const char *operators[] = {"==", "<", ">", "<=", ">=", "!=" };
1154     struct protocol_trace_rule_node *data;
1155
1156     data = (struct protocol_trace_rule_node *)bintree_get_node_data(node);
1157
1158     if (data->node_type == PROTOCOL_TRACE_NODE_TYPE_ALL)
1159         REPLY(" ALL");
1160     else if (data->node_type == PROTOCOL_TRACE_NODE_TYPE_AND)
1161         REPLY(" AND");
1162     else if (data->node_type == PROTOCOL_TRACE_NODE_TYPE_OR)
1163         REPLY(" OR");
1164     else { // data->node_type == PROTOCOL_TRACE_NODE_TYPE_DATA
1165         if (node == bintree_get_left_child(parent))
1166             REPLY(" (");
1167         REPLY(" %s %s ",
1168                 data->variable_name, operators[data->comparer]);
1169
1170         if (data->value_type == PROTOCOL_TRACE_DATA_TYPE_INTEGER)
1171             REPLY(" %d",
1172                     data->value.integer);
1173         else
1174             REPLY(" %s",
1175                     data->value.string);
1176
1177         if (node == bintree_get_right_child(parent))
1178             REPLY(" )");
1179     }
1180
1181     *buffer->reply = reply;
1182
1183     return 0;
1184 }
1185
1186 static void
1187 rulechecker_print_rules(struct protocol_trace_rule_checker *rc,
1188         char *reply, int *len)
1189 {
1190     struct protocol_trace_reply_buffer buffer = {&reply, len};
1191     int i;
1192
1193     REPLY("\n --------------------[ Protocol Filter Rules ]--------------------\n");
1194     REPLY("  No      Policy              Rule\n");
1195     REPLY(" -----------------------------------------------------------------\n");
1196
1197     for (i =0; i < rc->count; i++) {
1198         REPLY("  %3d %10s \"", i,
1199                 rc->rules[i].policy == PROTOCOL_POLICY_TYPE_ALLOW ?
1200                 "ALLOW" : "DENY");
1201         bintree_inorder_traverse(rc->rules[i].tree, rulechecker_print_func,
1202                 (void*) & buffer);
1203         REPLY("\"\n");
1204     }
1205 }
1206
1207 static enum protocol_trace_rule_set_result
1208 rulechecker_rule_remove(struct protocol_trace_rule_checker *rc, int index)
1209 {
1210     if (index < 0 || index >= rc->count)
1211         return PROTOCOL_TRACE_RULE_SET_ERR_NO_RULE;
1212
1213     bintree_destroy_tree(rc->rules[index].tree);
1214     rc->count--;
1215     if (index != rc->count) {
1216         memmove(&rc->rules[index], &rc->rules[index + 1],
1217                 sizeof(struct protocol_trace_rule)*(rc->count - index));
1218     }
1219
1220     return PROTOCOL_TRACE_RULE_SET_OK;
1221 }
1222
1223 static struct protocol_trace_rule_checker *
1224 rulechecker_init()
1225 {
1226     struct protocol_trace_rule_checker *rc;
1227
1228     rc = calloc(1, sizeof *rc);
1229     if (!rc)
1230         return NULL;
1231
1232     rc->count = 0;
1233
1234     return rc;
1235 }
1236
1237 static void rulechecker_destroy(struct protocol_trace_rule_checker *rc)
1238 {
1239     for (int i = rc->count - 1; i >= 0; i--)
1240         rulechecker_rule_remove(rc, i);
1241
1242     free(rc);
1243 }
1244
1245 static bool
1246 rule_file_set(const char *filename, char *reply, int *len)
1247 {
1248     int fd = -1, rule_len;
1249     char fs[8096], *pfs;
1250
1251     ds_dbg("IN >> rule_file_set");
1252
1253     fd = open(filename, O_RDONLY);
1254     if (fd < 0) {
1255         ds_err("failed: open '%s'", filename);
1256         return false;
1257     }
1258
1259     rule_len = read(fd, fs, sizeof(fs));
1260     pfs = fs;
1261
1262     while (pfs -fs < rule_len) {
1263         int i, new_argc =3;
1264         const char *new_argv[3] = {"add", };
1265         char policy[64] = {0,};
1266         char rule[1024] = {0,};
1267
1268         if (pfs[0] == ' ' || pfs[0] == '\n') {
1269             pfs++;
1270             continue;
1271         }
1272         for (i = 0; pfs[i] != ' '; i++)
1273             policy[i] = pfs[i];
1274
1275         new_argv[1] = policy;
1276         pfs += (strlen(new_argv[1]) + 1);
1277
1278         memset(rule, 0, sizeof(rule));
1279         for (i = 0; pfs[i] != '\n'; i++)
1280             rule[i] = pfs[i];
1281
1282         new_argv[2] = rule;
1283
1284         pfs += (strlen(new_argv[2]) +1);
1285
1286         if (!rule_set((const int)new_argc, (const char**)new_argv,
1287                 reply, len)) {
1288             close(fd);
1289             return false;
1290         }
1291     }
1292     close(fd);
1293
1294     ds_dbg("OUT << rule_file_set");
1295
1296     return true;
1297 }
1298
1299 static int
1300 rule_check_remove_rule(const char *str)
1301 {
1302     char *endptr;
1303     int index;
1304
1305     index = strtol(str, &endptr, 10);
1306
1307     if (errno == ERANGE) {
1308         ds_err("Rule remove fail : overflow");
1309         return -1;
1310     }
1311
1312     if (errno != 0) {
1313         ds_err("Rule remove fail : other error");
1314         return -1;
1315     }
1316
1317     if (endptr == 0) {
1318         ds_err("Rule remove fail : non-numeric");
1319         return -1;
1320     }
1321
1322     if (*endptr != '\0') {
1323         ds_err("Rule remove fail : non-numeric at end");
1324         return -1;
1325     }
1326
1327     if (isspace(*str)) {
1328         ds_err("Rule remove fail : space at beginning");
1329         return -1;
1330     }
1331
1332     return index;
1333 }
1334
1335 static void
1336 rule_arguments_merge(char *target, int target_size,
1337         int argc, const char **argv)
1338 {
1339     int i, len;
1340
1341     for (i = 0; i < argc; i++) {
1342         len = snprintf(target, target_size, "%s", argv[i]);
1343         target += len;
1344         target_size -= len;
1345
1346         if (i != argc - 1) {
1347             *(target++) = ' ';
1348             target_size--;
1349         }
1350     }
1351 }
1352
1353 static bool
1354 rule_set(const int argc, const char **argv, char *reply, int *len)
1355 {
1356     const char * command;
1357
1358     ds_dbg("IN >> rule_set");
1359     ds_dbg("(parameter) argc = %d, argv[0] = %s", argc, argv[0]);
1360
1361     if (argc == 0) {
1362         rulechecker_print_rules(global_rc, reply, len);
1363         return true;
1364     }
1365
1366     command = argv[0];
1367
1368     if (!strcasecmp(command, "add")) {
1369         ds_dbg("ADD");
1370         enum protocol_trace_policy_type policy_type;
1371         enum protocol_trace_rule_set_result result;
1372         const char * policy = argv[1]; //allow, deny
1373         char merge[8192] = {0,}, rule[8192] = {0,};
1374         int i, index=0, size_rule, apply = 0, size_merge;
1375
1376         if (argc <3) {
1377             ds_err("Error: Too few argumens.");
1378             return false;
1379         }
1380
1381         if (!strcasecmp(policy, "ALLOW"))
1382             policy_type = PROTOCOL_POLICY_TYPE_ALLOW;
1383         else if (!strcasecmp(policy, "DENY"))
1384             policy_type = PROTOCOL_POLICY_TYPE_DENY;
1385         else {
1386             ds_err("Error : Unknown : [%s].\n should be ALLOW/DENY.", policy);
1387             return false;
1388         }
1389
1390         rule_arguments_merge(merge, sizeof(merge), argc -2, &(argv[2]));
1391
1392         size_rule = sizeof(rule) -1;
1393         size_merge = strlen(merge);
1394
1395         for (i = 0; i < size_merge; i++) {
1396             if (merge[i] == '\"' || merge[i] == '\'') {
1397                 rule[index++] = ' ';
1398                 if (index > size_rule)
1399                     return false;
1400                 continue;
1401             }
1402             if (merge[i] == '+') {
1403                 rule[index++] = ' ';
1404                 if (index > size_rule)
1405                     return false;
1406                 if (apply == 0) {
1407                     const char * plus = "|| type=reply || type=error";
1408                     int size_plus = strlen(plus);
1409                     int l = MIN(size_rule - index, size_plus);
1410                     snprintf(rule, sizeof(rule), "%s", plus);
1411                     index += l;
1412                     if (index >size_rule)
1413                         return false;
1414                     apply =1;
1415                 }
1416                 continue;
1417             }
1418             rule[index++] = merge[i];
1419             if (index > size_rule)
1420                 return false;
1421         }
1422         ds_dbg("ADD :: rule = %s", rule);
1423
1424         result = rulechecker_rule_add(global_rc, policy_type, rule);
1425
1426         if (result == PROTOCOL_TRACE_RULE_SET_ERR_TOO_MANY_RULES) {
1427             ds_err("Error: Too many rules were added.");
1428             return false;
1429         } else if (result == PROTOCOL_TRACE_RULE_SET_ERR_PARSE) {
1430             ds_err("Error: parsing the rule [%s]", rule);
1431             return false;
1432         }
1433         ds_dbg( "The rule was successfully added");
1434
1435     } else if (!strcasecmp(command, "remove")) {
1436         const char * remove_idx;
1437         int i;
1438
1439         ds_dbg("REMOVE");
1440
1441         if (argc < 2) {
1442             ds_err("Error: Too few arguments");
1443             return false;
1444         }
1445
1446         for (i = 0; i < argc - 1; i++) {
1447             remove_idx = argv[i + 1];
1448             if (!strcasecmp(remove_idx, "all")) {
1449                 ds_dbg("REMOVE :: all");
1450                 rulechecker_destroy(global_rc);
1451                 global_rc = rulechecker_init();
1452                 if (!global_rc) {
1453                     ds_err("Error: rules not removed");
1454                     return false;
1455                 }
1456             } else {
1457                 int index = rule_check_remove_rule(remove_idx);
1458                 if (index == -1) {
1459                     ds_err("Rule remove fail : overflow");
1460                 } else {
1461                     ds_dbg("REMOVE :: remove idx = %d", index);
1462
1463                     if (isdigit(*remove_idx) &&
1464                         rulechecker_rule_remove(global_rc, index) == 0)
1465                         ds_dbg("Rule remove success : rule [%d]", index);
1466                     else
1467                         ds_err("Rule remove fail : No rule [%s]", remove_idx);
1468                 }
1469             }
1470         }
1471     } else if (!strcasecmp(command, "file")) {
1472         ds_dbg("FILE");
1473         if (argc <2) {
1474             ds_err("Error: Too few argumens.");
1475             return false;
1476         }
1477
1478         if (!rule_file_set(argv[1], reply, len))
1479             return false;
1480
1481         rulechecker_print_rules(global_rc, reply, len);
1482     } else if (!strcasecmp(command, "print")) {
1483         rulechecker_print_rules(global_rc, reply, len);
1484     } else if (!strcasecmp(command, "help")) {
1485         ds_dbg( "%s", rulechecker_usage_print());
1486     } else {
1487         ds_err("%s\nUnknown command : [%s] ", rulechecker_usage_print(), command);
1488     }
1489
1490     ds_dbg("OUT << rule_set");
1491
1492     return true;
1493 }
1494
1495 static bool
1496 rule_init(char *rule_path)
1497 {
1498     bool ret = false;
1499     const char *argv[2];
1500     int argc = 2;
1501
1502     char tmpReply[4096];
1503     int tmpLen = sizeof(tmpReply);
1504     char *reply = tmpReply;
1505     int *len = &tmpLen;
1506
1507     if (!rule_path || strlen(rule_path) <= 0) {
1508         rule_path = alloca(10);
1509         snprintf(rule_path, 10, "%s", "/tmp/rule");
1510         ds_inf("rule path is default = %s", rule_path);
1511     }
1512
1513     argv[0] = "file";
1514     argv[1] = rule_path;
1515
1516     ds_dbg("rule_path = %s", rule_path);
1517
1518     ret = rule_set(argc, (const char**)&(argv[0]), reply, len);
1519     if (!ret) return ret;
1520
1521     ds_inf("%s", &tmpReply);
1522
1523     return ret;
1524 }
1525
1526 static bool
1527 logger_init(char *trace_path)
1528 {
1529     ds_dbg("IN >> logger_init");
1530     if (!trace_path || strlen(trace_path) <= 0) {
1531         snprintf(trace_env_path, sizeof(trace_env_path), "%s", "/tmp/trace");
1532         ds_inf("trace path is default = %s", trace_env_path);
1533     } else {
1534         snprintf(trace_env_path, sizeof(trace_env_path), "%s", trace_path);
1535     }
1536
1537     ds_dbg("saved trace path = %s", trace_env_path);
1538
1539     logger_unset();
1540     ds_dbg("OUT << logger_init");
1541
1542     return true;
1543 }
1544
1545 int
1546 protocol_trace_enable(bool state)
1547 {
1548     if (log_fp_ptrace != NULL) {
1549         fclose(log_fp_ptrace);
1550         log_fp_ptrace = NULL;
1551     }
1552
1553     if (state) {
1554         //TODO: can change trace file path by cmd
1555         ds_inf("state: protocol_trace enabled");
1556         logger_set();
1557         return 1;
1558     } else {
1559         ds_inf("state: protocol_trace disabled");
1560         logger_unset();
1561         return 0;
1562     }
1563
1564     return -1;
1565 }
1566
1567 bool
1568 protocol_trace_init(struct wl_display *d)
1569 {
1570     bool ret = false;
1571     char *env_path = NULL;
1572
1573     display = d;
1574     global_rc = rulechecker_init();
1575
1576     env_path = getenv("DS_PROTOCOL_RULE_FILE");
1577     ret = rule_init(env_path);
1578
1579     if (env_path) {
1580         char *tmp = strdup(env_path);
1581         if (!tmp) return false;
1582         free(tmp);
1583         env_path = NULL;
1584     }
1585     if (!ret)
1586         return ret;
1587
1588     env_path = getenv("DS_PROTOCOL_TRACE_FILE");
1589     ret = logger_init(env_path);
1590
1591     if (env_path)  {
1592         char *tmp = strdup(env_path);
1593         if (!tmp) return false;
1594         free(tmp);
1595         env_path = NULL;
1596     }
1597
1598     return ret;
1599 }
1600
1601 void
1602 protocol_trace_fini()
1603 {
1604     rulechecker_destroy(global_rc);
1605 }