9 #include "protocol-trace.h"
15 #define BUF_SNPRINTF(fmt, ARG...) do { \
16 str_l = snprintf(str_buff, str_r, fmt, ##ARG); \
22 #define REPLY(fmt, ARG...) \
24 if (reply && len && *len > 0) { \
25 int s = snprintf(reply, *len, fmt, ##ARG); \
32 #define MIN(a,b) ((a)<(b)?(a):(b))
34 struct protocol_trace_tree_node
36 struct protocol_trace_tree_node *left;
37 struct protocol_trace_tree_node *right;
40 struct protocol_trace_tree
43 struct protocol_trace_tree_node *head;
46 //enums for protocol_trace_policy_type
47 enum protocol_trace_policy_type
49 PROTOCOL_POLICY_TYPE_UNDEFINED,
50 PROTOCOL_POLICY_TYPE_ALLOW,
51 PROTOCOL_POLICY_TYPE_DENY
54 struct protocol_trace_rule
56 enum protocol_trace_policy_type policy;
57 struct protocol_trace_tree *tree;
60 struct protocol_trace_rule_checker
62 struct protocol_trace_rule rules[MAX_RULE];
66 //enums for protocol_trace_protocol_log
67 enum protocol_trace_protocol_type {
68 PROTOCOL_TYPE_REQUEST,
72 struct protocol_trace_protocol_log
74 enum protocol_trace_protocol_type type;
77 char name[PATH_MAX + 1];
78 char cmd[PATH_MAX + 1];
81 //enums for protocol_trace_rule_node
82 enum protocol_trace_result_type
84 PROTOCOL_TRACE_RESULT_UNKNOWN,
85 PROTOCOL_TRACE_RESULT_TRUE,
86 PROTOCOL_TRACE_RESULT_FALSE
89 enum protocol_trace_node_type
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
98 enum protocol_trace_comparer
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
108 enum protocol_trace_data_type
110 PROTOCOL_TRACE_DATA_TYPE_INTEGER,
111 PROTOCOL_TRACE_DATA_TYPE_STRING
114 struct protocol_trace_rule_node
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];
124 char string[STRING_MAX];
129 //enums for protocol_trace_token_data
130 enum protocol_trace_token
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,
149 struct protocol_trace_token_data
152 enum protocol_trace_token last_token;
153 const char *last_symbol;
157 struct protocol_trace_validate_args
166 struct argument_details {
171 struct protocol_trace_reply_buffer
177 enum protocol_trace_rule_set_result
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
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,
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);
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 *rc = NULL;
198 static struct wl_display *display;
202 const char *token_char;
203 const int token_length;
204 enum protocol_trace_token token_name;
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},
228 static struct protocol_trace_tree_node *
229 bintree_get_head(struct protocol_trace_tree *tree)
235 bintree_set_head(struct protocol_trace_tree *tree,
236 struct protocol_trace_tree_node *head)
241 static struct protocol_trace_tree_node *
242 bintree_get_left_child(struct protocol_trace_tree_node *node)
248 bintree_set_left_child(struct protocol_trace_tree_node *node,
249 struct protocol_trace_tree_node *child)
254 static struct protocol_trace_tree_node *
255 bintree_get_right_child(struct protocol_trace_tree_node *node)
261 bintree_set_right_child(struct protocol_trace_tree_node *node,
262 struct protocol_trace_tree_node *child)
268 bintree_get_node_data(struct protocol_trace_tree_node *node)
270 return (void*)(node+1);
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)
280 if (bintree_inorder_traverse_recursive(tree, node->left, node,
285 if (func(tree, node, parent, arg))
289 if (bintree_inorder_traverse_recursive(tree, node->right, node,
298 bintree_inorder_traverse(struct protocol_trace_tree *tree,
299 tree_traverse_cb func, void *arg)
302 bintree_inorder_traverse_recursive(tree, tree->head, tree->head,
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)
313 if (bintree_postorder_traverse_recursive(tree, node->left, node,
318 if (bintree_postorder_traverse_recursive(tree, node->right, node,
323 return func(tree, node,parent, arg);
327 bintree_postorder_traverse(struct protocol_trace_tree *tree,
328 tree_traverse_cb func, void *arg)
331 bintree_postorder_traverse_recursive(tree, tree->head, tree->head,
335 static struct protocol_trace_tree *
336 bintree_create_tree(int size)
338 struct protocol_trace_tree *tree;
340 tree = calloc(1, sizeof(struct protocol_trace_tree) + size);
349 static struct protocol_trace_tree_node *
350 bintree_create_node(struct protocol_trace_tree *tree)
352 struct protocol_trace_tree_node *node;
354 node = calloc(1, sizeof(struct protocol_trace_tree_node) + tree->size);
365 bintree_remove_node(struct protocol_trace_tree_node *node)
371 bintree_remove_node_recursive(struct protocol_trace_tree_node *node)
374 bintree_remove_node_recursive(node->left);
376 bintree_remove_node_recursive(node->right);
378 bintree_remove_node(node);
382 bintree_destroy_tree(struct protocol_trace_tree *tree)
385 bintree_remove_node_recursive(tree->head);
390 rulechecker_string_compare(enum protocol_trace_comparer comparer,
391 char *str2, const char *str1)
395 result = strcasecmp(str2, str1);
398 case PROTOCOL_TRACE_COMPARER_EQUAL:
400 case PROTOCOL_TRACE_COMPARER_LESS:
402 case PROTOCOL_TRACE_COMPARER_GREATER:
404 case PROTOCOL_TRACE_COMPARER_LESS_EQ:
406 case PROTOCOL_TRACE_COMPARER_GREATE_EQ:
408 case PROTOCOL_TRACE_COMPARER_NOT_EQ:
416 rulechecker_int_compare(enum protocol_trace_comparer comparer,
420 case PROTOCOL_TRACE_COMPARER_EQUAL:
422 case PROTOCOL_TRACE_COMPARER_LESS:
424 case PROTOCOL_TRACE_COMPARER_GREATER:
426 case PROTOCOL_TRACE_COMPARER_LESS_EQ:
428 case PROTOCOL_TRACE_COMPARER_GREATE_EQ:
430 case PROTOCOL_TRACE_COMPARER_NOT_EQ:
438 rulechecker_validate_rule_func(struct protocol_trace_tree *tree,
439 struct protocol_trace_tree_node *node,
440 struct protocol_trace_tree_node *parent,
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;
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;
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");
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);
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,};
471 msg = (char *) strchr(args->name, ':');
474 int size_iface = sizeof(iface) -1;
475 int min = MIN(size_iface, msg-args->name);
476 strncpy(iface, args->name, min);
480 if (!strcasecmp(data->variable_name, "TYPE")) {
481 const char *type_string;
483 type_string = "REQUEST";
484 else if (args->type == 1)
485 type_string = "EVENT";
487 ds_err("Invalid type %d", args->type);
491 if (rulechecker_string_compare(data->comparer,
492 data->value.string, type_string))
493 data->result = PROTOCOL_TRACE_RESULT_TRUE;
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;
502 data->result = PROTOCOL_TRACE_RESULT_FALSE;
503 } else if (!strcasecmp(data->variable_name, "MSG")) {
505 rulechecker_string_compare(data->comparer,
506 data->value.string, msg))
507 data->result = PROTOCOL_TRACE_RESULT_TRUE;
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;
515 data->result = PROTOCOL_TRACE_RESULT_FALSE;
516 } else if (!strcasecmp(data->variable_name, "CMD") ||
517 !strcasecmp(data->variable_name, "COMMAND")) {
519 rulechecker_string_compare(data->comparer,
520 data->value.string, args->cmd))
521 data->result = PROTOCOL_TRACE_RESULT_TRUE;
523 data->result = PROTOCOL_TRACE_RESULT_FALSE;
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;
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;
536 data->result = PROTOCOL_TRACE_RESULT_FALSE;
545 rulechecker_validate_rules(struct protocol_trace_rule_checker *rc,
546 int type, int target_id, const char *name, int pid, const char *cmd)
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;
553 default_policy = PROTOCOL_POLICY_TYPE_DENY;
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);
560 if (data->result == PROTOCOL_TRACE_RESULT_TRUE) {
561 return rc->rules[i].policy == PROTOCOL_POLICY_TYPE_ALLOW;
565 return default_policy == PROTOCOL_POLICY_TYPE_ALLOW;
569 logger_cmd_get(char *path)
573 if (!path) return NULL;
575 p = strrchr(path, '/');
577 return (p) ? p+1 : path;
581 logger_validate_rule(struct protocol_trace_protocol_log *log)
583 const char *cmd = "";
589 cmd = logger_cmd_get(log->cmd);
591 ret = rulechecker_validate_rules(rc, log->type, log->target_id, log->name,
592 log->client_pid, cmd);
598 logger_get_proc_name(pid_t pid, char *name, int size)
601 char proc[PATH_MAX], pname[PATH_MAX];
606 snprintf(proc, PATH_MAX, "/proc/%d/cmdline", pid);
608 h = fopen(proc, "r");
611 len = fread(pname, sizeof(char), PATH_MAX, h);
615 strncpy(pname, "NO NAME", sizeof(pname));
619 strncpy(name, pname, size);
623 logger_get_next_argument(const char *signature, struct argument_details *details)
625 details->nullable = 0;
627 for (; *signature; ++signature) {
628 switch (*signature) {
637 details->type = *signature;
638 return signature + 1;
640 details->nullable = 1;
643 details->type = '\0';
649 logger_handle_client_destroy(struct wl_listener *listener, void *data)
651 struct wl_client *wc = (struct wl_client *)data;
654 pid_t client_pid =-1;
656 char strbuf[PATH_MAX], *str_buff = strbuf;
660 str_r = sizeof(strbuf);
662 wl_client_get_credentials(wc, &client_pid, NULL, NULL);
664 clock_gettime(CLOCK_MONOTONIC, &tp);
665 time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
667 BUF_SNPRINTF("[%10.3f] Server [PID:%d] client destroying", time / 1000.0,
671 fprintf(log_fp_ptrace, "%s\n", strbuf);
673 ds_dbg("%s", strbuf);
675 wl_list_remove(&listener->link);
681 logger_add_client_destroy_listener(struct wl_client *client)
683 struct wl_listener *destroy_listener;
685 destroy_listener = wl_client_get_destroy_listener(client,
686 logger_handle_client_destroy);
687 if (destroy_listener)
690 destroy_listener = calloc(1, sizeof *destroy_listener);
691 if (!destroy_listener)
694 destroy_listener->notify = logger_handle_client_destroy;
695 wl_client_add_destroy_listener(client, destroy_listener);
699 logger_func(void *user_data, enum wl_protocol_logger_type direction,
700 const struct wl_protocol_logger_message *message)
702 struct argument_details arg;
703 struct wl_client *wc;
704 const char *signature;;
705 pid_t client_pid = -1;
709 char strbuf[PATH_MAX], *str_buff;
712 wc = wl_resource_get_client(message->resource);
714 logger_add_client_destroy_listener(wc);
715 wl_client_get_credentials(wc, &client_pid, NULL, NULL);
718 clock_gettime(CLOCK_MONOTONIC, &tp);
719 time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
721 struct protocol_trace_protocol_log elog = {PROTOCOL_TYPE_REQUEST,};
722 if (direction == WL_PROTOCOL_LOGGER_EVENT)
723 elog.type = PROTOCOL_TYPE_EVENT;
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);
732 logger_get_proc_name(client_pid, name, PATH_MAX);
733 snprintf(elog.cmd, PATH_MAX, "%s", name);
735 if (!logger_validate_rule(&elog)) return;
739 str_r = sizeof(strbuf);
741 BUF_SNPRINTF("[%10.3f] %s%d%s%s@%u.%s(",
743 elog.type ? "Server->Client [PID:" : "Server<-Client [PID:",
745 wl_resource_get_class(message->resource),
746 wl_resource_get_id(message->resource),
747 message->message->name);
749 signature = message->message->signature;
751 for (int i = 0; i < message->arguments_count; i++) {
752 signature = logger_get_next_argument(signature, &arg);
754 if (i > 0) BUF_SNPRINTF(", ");
758 BUF_SNPRINTF("%u", message->arguments[i].u);
761 BUF_SNPRINTF("%i", message->arguments[i].i);
764 BUF_SNPRINTF("%f", wl_fixed_to_double(message->arguments[i].f));
767 BUF_SNPRINTF("\"%s\"", message->arguments[i].s);
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));
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);
788 BUF_SNPRINTF("array");
791 BUF_SNPRINTF("fd %d", message->arguments[i].h);
796 BUF_SNPRINTF("), cmd: %s", elog.cmd ? elog.cmd : "cmd is NULL");
799 fprintf(log_fp_ptrace, "%s\n", strbuf);
801 ds_dbg("%s", strbuf);
807 ds_dbg("IN >> logger_set");
809 log_fp_ptrace = fopen(trace_env_path, "a");
810 if (!log_fp_ptrace) {
811 ds_err("failed open file(%s)", trace_env_path);
814 setvbuf(log_fp_ptrace, NULL, _IOLBF, 512);
815 ds_dbg("has log_fp_ptrace");
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;
822 ds_wl_protocol_logger =
823 wl_display_add_protocol_logger(display, logger_func, NULL);
825 ds_dbg("OUT << logger_set");
831 ds_dbg("IN >> logger_unset");
833 if (ds_wl_protocol_logger) {
834 wl_protocol_logger_destroy(ds_wl_protocol_logger);
835 ds_wl_protocol_logger = NULL;
838 ds_dbg("OUT << logger_unset");
841 static enum protocol_trace_token
842 parser_get_next_token(const char **string)
844 static int token_cnt;
845 int i, compare_res, found = 0, first, last;
849 token_cnt = sizeof(token_table) / sizeof(token_table[0]);
851 i = (first + last) / 2;
853 compare_res = strncmp(*string, token_table[i].token_char,
854 token_table[i].token_length);
855 while (compare_res == 0) {
860 compare_res = strncmp(*string, token_table[i].token_char,
861 token_table[i].token_length);
866 *string += token_table[i].token_length;
867 return token_table[i].token_name;
878 i = (first + last) / 2;
881 if (isalpha(**string)) {
883 while (isalpha(**string) || isdigit(**string) ||
884 **string == '_' || **string == '-') {
888 return PROTOCOL_TRACE_TOKEN_SYMBOL;
891 if (isdigit(**string)) {
893 while (isdigit(**string))
896 return PROTOCOL_TRACE_TOKEN_NUMBER;
899 return PROTOCOL_TRACE_TOKEN_UNKNOWN;
903 parser_process_token(struct protocol_trace_token_data *token)
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);
912 static struct protocol_trace_tree_node *
913 parser_parse_statement(struct protocol_trace_tree *tree,
914 struct protocol_trace_token_data *token)
916 struct protocol_trace_tree_node *node = NULL;
917 struct protocol_trace_rule_node *data;
919 if (token->last_token == PROTOCOL_TRACE_TOKEN_L_BR) {
920 parser_process_token(token);
922 node = parser_parse_token(tree, token);
926 if (token->last_token != PROTOCOL_TRACE_TOKEN_R_BR)
929 parser_process_token(token);
934 if (token->last_token != PROTOCOL_TRACE_TOKEN_SYMBOL)
937 node = bintree_create_node(tree);
941 data = (struct protocol_trace_rule_node *) bintree_get_node_data(node);
943 strncpy(data->variable_name, token->last_symbol, token->symbol_len);
944 data->variable_name[token->symbol_len] = '\0';
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);
954 data->node_type = PROTOCOL_TRACE_NODE_TYPE_DATA;
956 parser_process_token(token);
958 switch (token->last_token) {
959 case PROTOCOL_TRACE_TOKEN_NOT_EQ:
960 data->comparer = PROTOCOL_TRACE_COMPARER_NOT_EQ;
962 case PROTOCOL_TRACE_TOKEN_EQUAL:
963 data->comparer = PROTOCOL_TRACE_COMPARER_EQUAL;
965 case PROTOCOL_TRACE_TOKEN_LSS_THAN:
966 data->comparer = PROTOCOL_TRACE_COMPARER_LESS_EQ;
968 case PROTOCOL_TRACE_TOKEN_GRT_THAN:
969 data->comparer = PROTOCOL_TRACE_COMPARER_GREATER;
971 case PROTOCOL_TRACE_TOKEN_GRT_EQ:
972 data->comparer = PROTOCOL_TRACE_COMPARER_GREATE_EQ;
978 parser_process_token(token);
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';
991 parser_process_token(token);
997 bintree_remove_node_recursive(node);
1002 static struct protocol_trace_tree_node *
1003 parser_parse_token(struct protocol_trace_tree *tree,
1004 struct protocol_trace_token_data *token)
1006 struct protocol_trace_tree_node *node, *left = NULL, *right = NULL;
1007 struct protocol_trace_rule_node *data;
1009 node = parser_parse_statement(tree,token);
1011 ds_err("PARSE statement error\n");
1015 while (token->last_token == PROTOCOL_TRACE_TOKEN_AND) {
1019 parser_process_token(token);
1021 right = parser_parse_statement(tree, token);
1025 node = bintree_create_node(tree);
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);
1035 if (token->last_token == PROTOCOL_TRACE_TOKEN_OR) {
1039 parser_process_token(token);
1041 right = parser_parse_token(tree, token);
1045 node = bintree_create_node(tree);
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);
1058 ds_dbg("[fail] recursive remove node");
1060 bintree_remove_node_recursive(left);
1065 static struct protocol_trace_tree *
1066 parser_parse_rule_string(const char *string)
1068 struct protocol_trace_tree *tree;
1069 struct protocol_trace_tree_node *node;
1070 struct protocol_trace_token_data token;
1072 token.string = &string;
1073 parser_process_token(&token);
1075 tree = bintree_create_tree(sizeof(struct protocol_trace_rule_node));
1079 node = parser_parse_token(tree, &token);
1081 bintree_destroy_tree(tree);
1082 ds_dbg("finish destroy tree & return null");
1086 bintree_set_head(tree, node);
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)
1095 if (rc->count == MAX_RULE)
1096 return PROTOCOL_TRACE_RULE_SET_ERR_TOO_MANY_RULES;
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;
1104 rc->rules[rc->count].policy = policy;
1107 return PROTOCOL_TRACE_RULE_SET_OK;
1111 rulechecker_usage_print()
1114 "##########################################################\n"
1115 "### Enlightenment Protocol Log filtering. ###\n"
1116 "##########################################################\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"
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"
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"
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)
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;
1156 data = (struct protocol_trace_rule_node *)bintree_get_node_data(node);
1158 if (data->node_type == PROTOCOL_TRACE_NODE_TYPE_ALL)
1160 else if (data->node_type == PROTOCOL_TRACE_NODE_TYPE_AND)
1162 else if (data->node_type == PROTOCOL_TRACE_NODE_TYPE_OR)
1164 else { // data->node_type == PROTOCOL_TRACE_NODE_TYPE_DATA
1165 if (node == bintree_get_left_child(parent))
1168 data->variable_name, operators[data->comparer]);
1170 if (data->value_type == PROTOCOL_TRACE_DATA_TYPE_INTEGER)
1172 data->value.integer);
1175 data->value.string);
1177 if (node == bintree_get_right_child(parent))
1181 *buffer->reply = reply;
1187 rulechecker_print_rules(struct protocol_trace_rule_checker *rc,
1188 char *reply, int *len)
1190 struct protocol_trace_reply_buffer buffer = {&reply, len};
1193 REPLY("\n --------------------[ Protocol Filter Rules ]--------------------\n");
1194 REPLY(" No Policy Rule\n");
1195 REPLY(" -----------------------------------------------------------------\n");
1197 for (i =0; i < rc->count; i++) {
1198 REPLY(" %3d %10s \"", i,
1199 rc->rules[i].policy == PROTOCOL_POLICY_TYPE_ALLOW ?
1201 bintree_inorder_traverse(rc->rules[i].tree, rulechecker_print_func,
1207 static enum protocol_trace_rule_set_result
1208 rulechecker_rule_remove(struct protocol_trace_rule_checker *rc, int index)
1210 if (index < 0 || index >= rc->count)
1211 return PROTOCOL_TRACE_RULE_SET_ERR_NO_RULE;
1213 bintree_destroy_tree(rc->rules[index].tree);
1215 if (index != rc->count) {
1216 memmove(&rc->rules[index], &rc->rules[index + 1],
1217 sizeof(struct protocol_trace_rule)*(rc->count - index));
1220 return PROTOCOL_TRACE_RULE_SET_OK;
1223 static struct protocol_trace_rule_checker *
1226 struct protocol_trace_rule_checker *rc;
1228 rc = calloc(1, sizeof *rc);
1237 static void rulechecker_destroy(struct protocol_trace_rule_checker *rc)
1239 for (int i = rc->count - 1; i >= 0; i--)
1240 rulechecker_rule_remove(rc, i);
1246 rule_file_set(const char *filename, char *reply, int *len)
1248 int fd = -1, rule_len;
1249 char fs[8096], *pfs;
1251 ds_dbg("IN >> rule_file_set");
1253 fd = open(filename, O_RDONLY);
1255 ds_err("failed: open '%s'", filename);
1259 rule_len = read(fd, fs, sizeof(fs));
1262 while (pfs -fs < rule_len) {
1264 const char *new_argv[3] = {"add", };
1265 char policy[64] = {0,};
1266 char rule[1024] = {0,};
1268 if (pfs[0] == ' ' || pfs[0] == '\n') {
1272 for (i = 0; pfs[i] != ' '; i++)
1275 new_argv[1] = policy;
1276 pfs += (strlen(new_argv[1]) + 1);
1278 memset(rule, 0, sizeof(rule));
1279 for (i = 0; pfs[i] != '\n'; i++)
1284 pfs += (strlen(new_argv[2]) +1);
1286 if (!rule_set((const int)new_argc, (const char**)new_argv,
1294 ds_dbg("OUT << rule_file_set");
1300 rule_check_remove_rule(const char *str)
1305 index = strtol(str, &endptr, 10);
1307 if (errno == ERANGE) {
1308 ds_err("Rule remove fail : overflow");
1313 ds_err("Rule remove fail : other error");
1318 ds_err("Rule remove fail : non-numeric");
1322 if (*endptr != '\0') {
1323 ds_err("Rule remove fail : non-numeric at end");
1327 if (isspace(*str)) {
1328 ds_err("Rule remove fail : space at beginning");
1336 rule_arguments_merge(char *target, int target_size,
1337 int argc, const char **argv)
1341 for (i = 0; i < argc; i++) {
1342 len = snprintf(target, target_size, "%s", argv[i]);
1346 if (i != argc - 1) {
1354 rule_set(const int argc, const char **argv, char *reply, int *len)
1356 const char * command;
1358 ds_dbg("IN >> rule_set");
1359 ds_dbg("(parameter) argc = %d, argv[0] = %s", argc, argv[0]);
1362 rulechecker_print_rules(rc, reply, len);
1368 if (!strcasecmp(command, "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;
1377 ds_err("Error: Too few argumens.");
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;
1386 ds_err("Error : Unknown : [%s].\n should be ALLOW/DENY.", policy);
1390 rule_arguments_merge(merge, sizeof(merge), argc -2, &(argv[2]));
1392 size_rule = sizeof(rule) -1;
1393 size_merge = strlen(merge);
1395 for (i = 0; i < size_merge; i++) {
1396 if (merge[i] == '\"' || merge[i] == '\'') {
1397 rule[index++] = ' ';
1398 if (index > size_rule)
1402 if (merge[i] == '+') {
1403 rule[index++] = ' ';
1404 if (index > size_rule)
1407 const char * plus = "|| type=reply || type=error";
1408 int size_plus = strlen(plus);
1409 int len = MIN(size_rule - index, size_plus);
1410 snprintf(rule, sizeof(rule), "%s", plus);
1412 if (index >size_rule)
1418 rule[index++] = merge[i];
1419 if (index > size_rule)
1422 ds_dbg("ADD :: rule = %s", rule);
1424 result = rulechecker_rule_add(rc, policy_type, rule);
1426 if (result == PROTOCOL_TRACE_RULE_SET_ERR_TOO_MANY_RULES) {
1427 ds_err("Error: Too many rules were added.");
1429 } else if (result == PROTOCOL_TRACE_RULE_SET_ERR_PARSE) {
1430 ds_err("Error: parsing the rule [%s]", rule);
1433 ds_dbg( "The rule was successfully added");
1435 } else if (!strcasecmp(command, "remove")) {
1436 const char * remove_idx;
1442 ds_err("Error: Too few arguments");
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(rc);
1451 rc = rulechecker_init();
1453 ds_err("Error: rules not removed");
1457 int index = rule_check_remove_rule(remove_idx);
1459 ds_err("Rule remove fail : overflow");
1461 ds_dbg("REMOVE :: remove idx = %d", index);
1463 if (isdigit(*remove_idx) &&
1464 rulechecker_rule_remove(rc, index) == 0)
1465 ds_dbg("Rule remove success : rule [%d]", index);
1467 ds_err("Rule remove fail : No rule [%s]", remove_idx);
1471 } else if (!strcasecmp(command, "file")) {
1474 ds_err("Error: Too few argumens.");
1478 if (!rule_file_set(argv[1], reply, len))
1481 rulechecker_print_rules(rc, reply, len);
1482 } else if (!strcasecmp(command, "print")) {
1483 rulechecker_print_rules(rc, reply, len);
1484 } else if (!strcasecmp(command, "help")) {
1485 ds_dbg( "%s", rulechecker_usage_print());
1487 ds_err("%s\nUnknown command : [%s] ", rulechecker_usage_print(), command);
1490 ds_dbg("OUT << rule_set");
1496 rule_init(char *rule_path)
1499 const char *argv[2];
1502 char tmpReply[4096];
1503 int tmpLen = sizeof(tmpReply);
1504 char *reply = tmpReply;
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);
1514 argv[1] = rule_path;
1516 ds_dbg("rule_path = %s", rule_path);
1518 ret = rule_set(argc, (const char**)&(argv[0]), reply, len);
1519 ds_inf("%s", &tmpReply);
1525 logger_init(char *trace_path)
1527 ds_dbg("IN >> logger_init");
1528 if (!trace_path || strlen(trace_path) <= 0) {
1529 snprintf(trace_env_path, sizeof(trace_env_path), "%s", "/tmp/trace");
1530 ds_inf("trace path is default = %s", trace_env_path);
1532 snprintf(trace_env_path, sizeof(trace_env_path), "%s", trace_path);
1535 ds_dbg("saved trace path = %s", trace_env_path);
1538 ds_dbg("OUT << logger_init");
1544 protocol_trace_enable(bool state)
1546 if (log_fp_ptrace != NULL) {
1547 fclose(log_fp_ptrace);
1548 log_fp_ptrace = NULL;
1552 //TODO: can change trace file path by cmd
1553 ds_inf("state: protocol_trace enabled");
1557 ds_inf("state: protocol_trace disabled");
1566 protocol_trace_init(struct wl_display *d)
1569 char *env_path = NULL;
1572 rc = rulechecker_init();
1574 env_path = getenv("DS_PROTOCOL_RULE_FILE");
1575 ret = rule_init(env_path);
1578 char *tmp = strdup(env_path);
1579 if (!tmp) return false;
1586 env_path = getenv("DS_PROTOCOL_TRACE_FILE");
1587 ret = logger_init(env_path);
1590 char *tmp = strdup(env_path);
1591 if (!tmp) return false;
1600 protocol_trace_fini()
1602 rulechecker_destroy(rc);