--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <libds/log.h>
+#include "protocol-trace.h"
+
+#define PATH_MAX 512
+#define MAX_RULE 64
+#define STRING_MAX 64
+
+#define BUF_SNPRINTF(fmt, ARG...) do { \
+ str_l = snprintf(str_buff, str_r, fmt, ##ARG); \
+ str_buff += str_l; \
+ str_r -= str_l; \
+} while (0)
+
+#ifndef REPLY
+ #define REPLY(fmt, ARG...) \
+ do { \
+ if (reply && len && *len > 0) { \
+ int s = snprintf(reply, *len, fmt, ##ARG); \
+ reply += s; \
+ *len -= s; \
+ } \
+ } while (0)
+#endif
+
+#define MIN(a,b) ((a)<(b)?(a):(b))
+
+struct protocol_trace_tree_node
+{
+ struct protocol_trace_tree_node *left;
+ struct protocol_trace_tree_node *right;
+};
+
+struct protocol_trace_tree
+{
+ int size;
+ struct protocol_trace_tree_node *head;
+};
+
+//enums for protocol_trace_policy_type
+enum protocol_trace_policy_type
+{
+ PROTOCOL_POLICY_TYPE_UNDEFINED,
+ PROTOCOL_POLICY_TYPE_ALLOW,
+ PROTOCOL_POLICY_TYPE_DENY
+};
+
+struct protocol_trace_rule
+{
+ enum protocol_trace_policy_type policy;
+ struct protocol_trace_tree *tree;
+};
+
+struct protocol_trace_rule_checker
+{
+ struct protocol_trace_rule rules[MAX_RULE];
+ int count;
+};
+
+//enums for protocol_trace_protocol_log
+enum protocol_trace_protocol_type {
+ PROTOCOL_TYPE_REQUEST,
+ PROTOCOL_TYPE_EVENT
+};
+
+struct protocol_trace_protocol_log
+{
+ enum protocol_trace_protocol_type type;
+ int client_pid;
+ int target_id;
+ char name[PATH_MAX + 1];
+ char cmd[PATH_MAX + 1];
+};
+
+//enums for protocol_trace_rule_node
+enum protocol_trace_result_type
+{
+ PROTOCOL_TRACE_RESULT_UNKNOWN,
+ PROTOCOL_TRACE_RESULT_TRUE,
+ PROTOCOL_TRACE_RESULT_FALSE
+};
+
+enum protocol_trace_node_type
+{
+ PROTOCOL_TRACE_NODE_TYPE_NONE,
+ PROTOCOL_TRACE_NODE_TYPE_AND,
+ PROTOCOL_TRACE_NODE_TYPE_OR,
+ PROTOCOL_TRACE_NODE_TYPE_DATA,
+ PROTOCOL_TRACE_NODE_TYPE_ALL
+};
+
+enum protocol_trace_comparer
+{
+ PROTOCOL_TRACE_COMPARER_EQUAL,
+ PROTOCOL_TRACE_COMPARER_LESS,
+ PROTOCOL_TRACE_COMPARER_GREATER,
+ PROTOCOL_TRACE_COMPARER_LESS_EQ,
+ PROTOCOL_TRACE_COMPARER_GREATE_EQ,
+ PROTOCOL_TRACE_COMPARER_NOT_EQ
+};
+
+enum protocol_trace_data_type
+{
+ PROTOCOL_TRACE_DATA_TYPE_INTEGER,
+ PROTOCOL_TRACE_DATA_TYPE_STRING
+};
+
+struct protocol_trace_rule_node
+{
+ enum protocol_trace_node_type node_type;
+ enum protocol_trace_comparer comparer;
+ enum protocol_trace_data_type value_type;
+ enum protocol_trace_result_type result;
+ char variable_name[STRING_MAX];
+
+ union
+ {
+ char string[STRING_MAX];
+ int integer;
+ }value;
+};
+
+//enums for protocol_trace_token_data
+enum protocol_trace_token
+{
+ PROTOCOL_TRACE_TOKEN_UNKNOWN,
+ PROTOCOL_TRACE_TOKEN_L_BR,
+ PROTOCOL_TRACE_TOKEN_R_BR,
+ PROTOCOL_TRACE_TOKEN_NOT_EQ,
+ PROTOCOL_TRACE_TOKEN_EQUAL,
+ PROTOCOL_TRACE_TOKEN_LSS_THAN,
+ PROTOCOL_TRACE_TOKEN_LSS_EQ,
+ PROTOCOL_TRACE_TOKEN_GRT_THAN,
+ PROTOCOL_TRACE_TOKEN_GRT_EQ,
+ PROTOCOL_TRACE_TOKEN_AND,
+ PROTOCOL_TRACE_TOKEN_OR,
+ PROTOCOL_TRACE_TOKEN_SPACE,
+ PROTOCOL_TRACE_TOKEN_SYMBOL,
+ PROTOCOL_TRACE_TOKEN_NUMBER,
+ PROTOCOL_TRACE_TOKEN_EOS,
+};
+
+struct protocol_trace_token_data
+{
+ const char **string;
+ enum protocol_trace_token last_token;
+ const char *last_symbol;
+ int symbol_len;
+};
+
+struct protocol_trace_validate_args
+{
+ int type;
+ int target_id;
+ const char *name;
+ int pid;
+ const char *cmd;
+};
+
+struct argument_details {
+ char type;
+ int nullable;
+};
+
+struct protocol_trace_reply_buffer
+{
+ char **reply;
+ int *len;
+};
+
+enum protocol_trace_rule_set_result
+{
+ PROTOCOL_TRACE_RULE_SET_OK,
+ PROTOCOL_TRACE_RULE_SET_ERR_TOO_MANY_RULES,
+ PROTOCOL_TRACE_RULE_SET_ERR_PARSE,
+ PROTOCOL_TRACE_RULE_SET_ERR_NO_RULE
+};
+
+typedef int (*tree_traverse_cb) (struct protocol_trace_tree *tree,
+ struct protocol_trace_tree_node *node,
+ struct protocol_trace_tree_node *parent,
+ void *arg);
+static struct protocol_trace_tree_node *parser_parse_token(
+ struct protocol_trace_tree *tree,
+ struct protocol_trace_token_data *token);
+static bool rule_set(const int argc, const char **argv, char *reply, int *len);
+
+char trace_env_path[PATH_MAX + 1];
+static FILE *log_fp_ptrace = NULL;
+static struct wl_protocol_logger *ds_wl_protocol_logger;
+static struct protocol_trace_rule_checker *rc = NULL;
+static struct wl_display *display;
+
+static struct
+{
+ const char *token_char;
+ const int token_length;
+ enum protocol_trace_token token_name;
+} token_table[] =
+{
+ {"\0", 1, PROTOCOL_TRACE_TOKEN_EOS},
+ {"\t", 1, PROTOCOL_TRACE_TOKEN_SPACE},
+ {" ", 1, PROTOCOL_TRACE_TOKEN_SPACE},
+ {"!=", 2, PROTOCOL_TRACE_TOKEN_NOT_EQ},
+ {"&", 1, PROTOCOL_TRACE_TOKEN_AND},
+ {"&&", 2, PROTOCOL_TRACE_TOKEN_AND},
+ {"(", 1, PROTOCOL_TRACE_TOKEN_L_BR},
+ {")", 1, PROTOCOL_TRACE_TOKEN_R_BR},
+ {"<", 1, PROTOCOL_TRACE_TOKEN_LSS_THAN},
+ {"<=", 2, PROTOCOL_TRACE_TOKEN_LSS_EQ},
+ {"<>", 2, PROTOCOL_TRACE_TOKEN_NOT_EQ},
+ {"=", 1, PROTOCOL_TRACE_TOKEN_EQUAL},
+ {"==", 2, PROTOCOL_TRACE_TOKEN_EQUAL},
+ {">", 1, PROTOCOL_TRACE_TOKEN_GRT_THAN},
+ {">=", 2, PROTOCOL_TRACE_TOKEN_GRT_EQ},
+ {"and", 3, PROTOCOL_TRACE_TOKEN_AND},
+ {"or", 2, PROTOCOL_TRACE_TOKEN_OR},
+ {"|", 1, PROTOCOL_TRACE_TOKEN_OR},
+ {"||", 2, PROTOCOL_TRACE_TOKEN_OR},
+};
+
+static struct protocol_trace_tree_node *
+bintree_get_head(struct protocol_trace_tree *tree)
+{
+ return tree->head;
+}
+
+static void
+bintree_set_head(struct protocol_trace_tree *tree,
+ struct protocol_trace_tree_node *head)
+{
+ tree->head = head;
+}
+
+static struct protocol_trace_tree_node *
+bintree_get_left_child(struct protocol_trace_tree_node *node)
+{
+ return node->left;
+}
+
+static void
+bintree_set_left_child(struct protocol_trace_tree_node *node,
+ struct protocol_trace_tree_node *child)
+{
+ node->left = child;
+}
+
+static struct protocol_trace_tree_node *
+bintree_get_right_child(struct protocol_trace_tree_node *node)
+{
+ return node->right;
+}
+
+static void
+bintree_set_right_child(struct protocol_trace_tree_node *node,
+ struct protocol_trace_tree_node *child)
+{
+ node->right = child;
+}
+
+static void *
+bintree_get_node_data(struct protocol_trace_tree_node *node)
+{
+ return (void*)(node+1);
+}
+
+static int
+bintree_inorder_traverse_recursive(struct protocol_trace_tree *tree,
+ struct protocol_trace_tree_node *node,
+ struct protocol_trace_tree_node *parent,
+ tree_traverse_cb func, void *arg)
+{
+ if (node->left) {
+ if (bintree_inorder_traverse_recursive(tree, node->left, node,
+ func, arg) != 0)
+ return 1;
+ }
+
+ if (func(tree, node, parent, arg))
+ return 1;
+
+ if (node->right) {
+ if (bintree_inorder_traverse_recursive(tree, node->right, node,
+ func, arg) != 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+static void
+bintree_inorder_traverse(struct protocol_trace_tree *tree,
+ tree_traverse_cb func, void *arg)
+{
+ if (tree->head)
+ bintree_inorder_traverse_recursive(tree, tree->head, tree->head,
+ func, arg);
+}
+
+static int
+bintree_postorder_traverse_recursive(struct protocol_trace_tree *tree,
+ struct protocol_trace_tree_node *node,
+ struct protocol_trace_tree_node *parent,
+ tree_traverse_cb func, void *arg)
+{
+ if (node->left) {
+ if (bintree_postorder_traverse_recursive(tree, node->left, node,
+ func, arg) != 0)
+ return 1;
+ }
+ if (node->right) {
+ if (bintree_postorder_traverse_recursive(tree, node->right, node,
+ func, arg) != 0)
+ return 1;
+ }
+
+ return func(tree, node,parent, arg);
+}
+
+static void
+bintree_postorder_traverse(struct protocol_trace_tree *tree,
+ tree_traverse_cb func, void *arg)
+{
+ if (tree->head)
+ bintree_postorder_traverse_recursive(tree, tree->head, tree->head,
+ func, arg);
+}
+
+static struct protocol_trace_tree *
+bintree_create_tree(int size)
+{
+ struct protocol_trace_tree *tree;
+
+ tree = calloc(1, sizeof(struct protocol_trace_tree) + size);
+ if (!tree)
+ return NULL;
+
+ tree->size = size;
+ tree->head = NULL;
+
+ return tree;
+}
+static struct protocol_trace_tree_node *
+bintree_create_node(struct protocol_trace_tree *tree)
+{
+ struct protocol_trace_tree_node *node;
+
+ node = calloc(1, sizeof(struct protocol_trace_tree_node) + tree->size);
+ if (!node)
+ return NULL;
+
+ node->left = NULL;
+ node->right = NULL;
+
+ return node;
+}
+
+static void
+bintree_remove_node(struct protocol_trace_tree_node *node)
+{
+ free(node);
+}
+
+static void
+bintree_remove_node_recursive(struct protocol_trace_tree_node *node)
+{
+ if (node->left)
+ bintree_remove_node_recursive(node->left);
+ if (node->right)
+ bintree_remove_node_recursive(node->right);
+
+ bintree_remove_node(node);
+}
+
+static void
+bintree_destroy_tree(struct protocol_trace_tree *tree)
+{
+ if (tree->head)
+ bintree_remove_node_recursive(tree->head);
+ free(tree);
+}
+
+static int
+rulechecker_string_compare(enum protocol_trace_comparer comparer,
+ char *str2, const char *str1)
+{
+ int result;
+
+ result = strcasecmp(str2, str1);
+
+ switch (comparer) {
+ case PROTOCOL_TRACE_COMPARER_EQUAL:
+ return result == 0;
+ case PROTOCOL_TRACE_COMPARER_LESS:
+ return result < 0;
+ case PROTOCOL_TRACE_COMPARER_GREATER:
+ return result > 0;
+ case PROTOCOL_TRACE_COMPARER_LESS_EQ:
+ return result <= 0;
+ case PROTOCOL_TRACE_COMPARER_GREATE_EQ:
+ return result >= 0;
+ case PROTOCOL_TRACE_COMPARER_NOT_EQ:
+ return result != 0;
+ }
+
+ return 0;
+}
+
+static int
+rulechecker_int_compare(enum protocol_trace_comparer comparer,
+ int int2, int int1)
+{
+ switch (comparer) {
+ case PROTOCOL_TRACE_COMPARER_EQUAL:
+ return int1 == int2;
+ case PROTOCOL_TRACE_COMPARER_LESS:
+ return int1 < int2;
+ case PROTOCOL_TRACE_COMPARER_GREATER:
+ return int1 > int2;
+ case PROTOCOL_TRACE_COMPARER_LESS_EQ:
+ return int1 <= int2;
+ case PROTOCOL_TRACE_COMPARER_GREATE_EQ:
+ return int1 >= int2;
+ case PROTOCOL_TRACE_COMPARER_NOT_EQ:
+ return int1 != int2;
+ }
+
+ return 0;
+}
+
+static int
+rulechecker_validate_rule_func(struct protocol_trace_tree *tree,
+ struct protocol_trace_tree_node *node,
+ struct protocol_trace_tree_node *parent,
+ void *arg)
+{
+ struct protocol_trace_validate_args *args;
+ struct protocol_trace_tree_node *left, *right;
+ struct protocol_trace_rule_node *data, *left_data, *right_data;
+
+ args = (struct protocol_trace_validate_args *)arg;
+ data = (struct protocol_trace_rule_node *)bintree_get_node_data(node);
+ data->result = PROTOCOL_TRACE_RESULT_UNKNOWN;
+
+ if (data->node_type == PROTOCOL_TRACE_NODE_TYPE_AND ||
+ data->node_type == PROTOCOL_TRACE_NODE_TYPE_OR) {
+ left = bintree_get_left_child(node);
+ right = bintree_get_right_child(node);
+ if (!left || !right) {
+ ds_err("Node error");
+ return -1;
+ }
+
+ left_data = (struct protocol_trace_rule_node *)bintree_get_node_data(left);
+ right_data = (struct protocol_trace_rule_node *)bintree_get_node_data(right);
+ }
+
+ if (data->node_type == PROTOCOL_TRACE_NODE_TYPE_ALL) {
+ data->result = PROTOCOL_TRACE_RESULT_TRUE;
+ } else if (data->node_type == PROTOCOL_TRACE_NODE_TYPE_DATA) {
+ char iface[64] = {0,};
+ char *msg = NULL;
+
+ if (args->name) {
+ msg = (char *) strchr(args->name, ':');
+ }
+ if (msg) {
+ int size_iface = sizeof(iface) -1;
+ int min = MIN(size_iface, msg-args->name);
+ strncpy(iface, args->name, min);
+ iface[min] = '\0';
+ msg++;
+ }
+ if (!strcasecmp(data->variable_name, "TYPE")) {
+ const char *type_string;
+ if (args->type == 0)
+ type_string = "REQUEST";
+ else if (args->type == 1)
+ type_string = "EVENT";
+ else {
+ ds_err("Invalid type %d", args->type);
+ return -1;
+ }
+
+ if (rulechecker_string_compare(data->comparer,
+ data->value.string, type_string))
+ data->result = PROTOCOL_TRACE_RESULT_TRUE;
+ else
+ data->result = PROTOCOL_TRACE_RESULT_FALSE;
+ } else if (!strcasecmp(data->variable_name, "IFACE")) {
+ if (msg && iface[0] &&
+ rulechecker_string_compare(data->comparer,
+ data->value.string, (const char *)iface))
+ data->result = PROTOCOL_TRACE_RESULT_TRUE;
+ else
+ data->result = PROTOCOL_TRACE_RESULT_FALSE;
+ } else if (!strcasecmp(data->variable_name, "MSG")) {
+ if (msg &&
+ rulechecker_string_compare(data->comparer,
+ data->value.string, msg))
+ data->result = PROTOCOL_TRACE_RESULT_TRUE;
+ else
+ data->result = PROTOCOL_TRACE_RESULT_FALSE;
+ } else if (!strcasecmp(data->variable_name, "PID")) {
+ if (rulechecker_int_compare(data->comparer,
+ data->value.integer, args->pid))
+ data->result = PROTOCOL_TRACE_RESULT_TRUE;
+ else
+ data->result = PROTOCOL_TRACE_RESULT_FALSE;
+ } else if (!strcasecmp(data->variable_name, "CMD") ||
+ !strcasecmp(data->variable_name, "COMMAND")) {
+ if (msg &&
+ rulechecker_string_compare(data->comparer,
+ data->value.string, args->cmd))
+ data->result = PROTOCOL_TRACE_RESULT_TRUE;
+ else
+ data->result = PROTOCOL_TRACE_RESULT_FALSE;
+ }
+ } else if (data->node_type == PROTOCOL_TRACE_NODE_TYPE_AND) {
+ if (left_data->result == PROTOCOL_TRACE_RESULT_TRUE &&
+ right_data->result == PROTOCOL_TRACE_RESULT_TRUE)
+ data->result = PROTOCOL_TRACE_RESULT_TRUE;
+ else
+ data->result = PROTOCOL_TRACE_RESULT_FALSE;
+ } else if (data->node_type == PROTOCOL_TRACE_NODE_TYPE_OR) {
+ if (left_data->result == PROTOCOL_TRACE_RESULT_TRUE ||
+ right_data->result == PROTOCOL_TRACE_RESULT_TRUE)
+ data->result = PROTOCOL_TRACE_RESULT_TRUE;
+ else
+ data->result = PROTOCOL_TRACE_RESULT_FALSE;
+ } else {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+rulechecker_validate_rules(struct protocol_trace_rule_checker *rc,
+ int type, int target_id, const char *name, int pid, const char *cmd)
+{
+ struct protocol_trace_validate_args args = {type, target_id, name, pid, cmd};
+ struct protocol_trace_tree_node *node;
+ struct protocol_trace_rule_node *data;
+ enum protocol_trace_policy_type default_policy;
+
+ default_policy = PROTOCOL_POLICY_TYPE_DENY;
+
+ for (int i = rc->count - 1; i >= 0 ; i--) {
+ bintree_postorder_traverse(rc->rules[i].tree, rulechecker_validate_rule_func, &args);
+ node = (struct protocol_trace_tree_node *)bintree_get_head(rc->rules[i].tree);
+ data = (struct protocol_trace_rule_node *)bintree_get_node_data(node);
+
+ if (data->result == PROTOCOL_TRACE_RESULT_TRUE) {
+ return rc->rules[i].policy == PROTOCOL_POLICY_TYPE_ALLOW;
+ }
+ }
+
+ return default_policy == PROTOCOL_POLICY_TYPE_ALLOW;
+}
+
+static char *
+logger_cmd_get(char *path)
+{
+ char *p;
+
+ if (!path) return NULL;
+
+ p = strrchr(path, '/');
+
+ return (p) ? p+1 : path;
+}
+
+static bool
+logger_validate_rule(struct protocol_trace_protocol_log *log)
+{
+ const char *cmd = "";
+ int ret;
+
+ if (!rc)
+ return false;
+
+ cmd = logger_cmd_get(log->cmd);
+
+ ret = rulechecker_validate_rules(rc, log->type, log->target_id, log->name,
+ log->client_pid, cmd);
+
+ return ret;
+}
+
+static void
+logger_get_proc_name(pid_t pid, char *name, int size)
+{
+ FILE *h;
+ char proc[PATH_MAX], pname[PATH_MAX];
+ size_t len;
+
+ if (!name) return;
+
+ snprintf(proc, PATH_MAX, "/proc/%d/cmdline", pid);
+
+ h = fopen(proc, "r");
+ if (!h) return;
+
+ len = fread(pname, sizeof(char), PATH_MAX, h);
+ if (len > 0)
+ pname[len - 1]='\0';
+ else
+ strncpy(pname, "NO NAME", sizeof(pname));
+
+ fclose(h);
+
+ strncpy(name, pname, size);
+}
+
+static const char *
+logger_get_next_argument(const char *signature, struct argument_details *details)
+{
+ details->nullable = 0;
+
+ for (; *signature; ++signature) {
+ switch (*signature) {
+ case 'i':
+ case 'u':
+ case 'f':
+ case 's':
+ case 'o':
+ case 'n':
+ case 'a':
+ case 'h':
+ details->type = *signature;
+ return signature + 1;
+ case '?':
+ details->nullable = 1;
+ }
+ }
+ details->type = '\0';
+
+ return signature;
+}
+
+static void
+logger_handle_client_destroy(struct wl_listener *listener, void *data)
+{
+ struct wl_client *wc = (struct wl_client *)data;
+ struct timespec tp;
+ unsigned int time;
+ pid_t client_pid =-1;
+
+ char strbuf[PATH_MAX], *str_buff = strbuf;
+ int str_r, str_l;
+
+ str_buff[0] = '\0';
+ str_r = sizeof(strbuf);
+
+ wl_client_get_credentials(wc, &client_pid, NULL, NULL);
+
+ clock_gettime(CLOCK_MONOTONIC, &tp);
+ time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
+
+ BUF_SNPRINTF("[%10.3f] Server [PID:%d] client destroying", time / 1000.0,
+ client_pid);
+
+ if (log_fp_ptrace)
+ fprintf(log_fp_ptrace, "%s\n", strbuf);
+ else
+ ds_dbg("%s", strbuf);
+
+ wl_list_remove(&listener->link);
+ free(listener);
+ listener = NULL;
+}
+
+static void
+logger_add_client_destroy_listener(struct wl_client *client)
+{
+ struct wl_listener *destroy_listener;
+
+ destroy_listener = wl_client_get_destroy_listener(client,
+ logger_handle_client_destroy);
+ if (destroy_listener)
+ return;
+
+ destroy_listener = calloc(1, sizeof *destroy_listener);
+ if (!destroy_listener)
+ return;
+
+ destroy_listener->notify = logger_handle_client_destroy;
+ wl_client_add_destroy_listener(client, destroy_listener);
+}
+
+void
+logger_func(void *user_data, enum wl_protocol_logger_type direction,
+ const struct wl_protocol_logger_message *message)
+{
+ struct argument_details arg;
+ struct wl_client *wc;
+ const char *signature;;
+ pid_t client_pid = -1;
+ struct timespec tp;
+ unsigned int time;
+
+ char strbuf[PATH_MAX], *str_buff;
+ int str_r, str_l;
+
+ wc = wl_resource_get_client(message->resource);
+ if (wc) {
+ logger_add_client_destroy_listener(wc);
+ wl_client_get_credentials(wc, &client_pid, NULL, NULL);
+ }
+
+ clock_gettime(CLOCK_MONOTONIC, &tp);
+ time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
+
+ struct protocol_trace_protocol_log elog = {PROTOCOL_TYPE_REQUEST,};
+ if (direction == WL_PROTOCOL_LOGGER_EVENT)
+ elog.type = PROTOCOL_TYPE_EVENT;
+ else
+ elog.type = PROTOCOL_TYPE_REQUEST;
+ elog.client_pid = client_pid;
+ elog.target_id = wl_resource_get_id(message->resource);
+ snprintf(elog.name, PATH_MAX,"%s:%s",
+ wl_resource_get_class(message->resource), message->message->name);
+
+ char name[PATH_MAX];
+ logger_get_proc_name(client_pid, name, PATH_MAX);
+ snprintf(elog.cmd, PATH_MAX, "%s", name);
+
+ if (!logger_validate_rule(&elog)) return;
+
+ str_buff = strbuf;
+ str_buff[0] = '\0';
+ str_r = sizeof(strbuf);
+
+ BUF_SNPRINTF("[%10.3f] %s%d%s%s@%u.%s(",
+ time / 1000.0,
+ elog.type ? "Server->Client [PID:" : "Server<-Client [PID:",
+ client_pid, "]",
+ wl_resource_get_class(message->resource),
+ wl_resource_get_id(message->resource),
+ message->message->name);
+
+ signature = message->message->signature;
+
+ for (int i = 0; i < message->arguments_count; i++) {
+ signature = logger_get_next_argument(signature, &arg);
+
+ if (i > 0) BUF_SNPRINTF(", ");
+
+ switch (arg.type) {
+ case 'u':
+ BUF_SNPRINTF("%u", message->arguments[i].u);
+ break;
+ case 'i':
+ BUF_SNPRINTF("%i", message->arguments[i].i);
+ break;
+ case 'f':
+ BUF_SNPRINTF("%f", wl_fixed_to_double(message->arguments[i].f));
+ break;
+ case 's':
+ BUF_SNPRINTF("\"%s\"", message->arguments[i].s);
+ break;
+ case 'o':
+ if (message->arguments[i].o) {
+ struct wl_resource *resource;
+ resource = (struct wl_resource *)message->arguments[i].o;
+ BUF_SNPRINTF("%s@%u",
+ wl_resource_get_class(resource),
+ wl_resource_get_id(resource));
+ } else
+ BUF_SNPRINTF("nil");
+ break;
+ case 'n':
+ BUF_SNPRINTF("new id %s@", (message->message->types[i]) ?
+ message->message->types[i]->name : "[unknown]");
+ if (message->arguments[i].n != 0)
+ BUF_SNPRINTF("%u", message->arguments[i].n);
+ else
+ BUF_SNPRINTF("nil");
+ break;
+ case 'a':
+ BUF_SNPRINTF("array");
+ break;
+ case 'h':
+ BUF_SNPRINTF("fd %d", message->arguments[i].h);
+ break;
+ }
+ }
+
+ BUF_SNPRINTF("), cmd: %s", elog.cmd ? elog.cmd : "cmd is NULL");
+
+ if (log_fp_ptrace)
+ fprintf(log_fp_ptrace, "%s\n", strbuf);
+ else
+ ds_dbg("%s", strbuf);
+}
+
+static void
+logger_set(void)
+{
+ ds_dbg("IN >> logger_set");
+
+ log_fp_ptrace = fopen(trace_env_path, "a");
+ if (!log_fp_ptrace) {
+ ds_err("failed open file(%s)", trace_env_path);
+ return;
+ }
+ setvbuf(log_fp_ptrace, NULL, _IOLBF, 512);
+ ds_dbg("has log_fp_ptrace");
+
+ if (ds_wl_protocol_logger) {
+ ds_dbg("if has ds_wl_protocol_logger -> destroy");
+ wl_protocol_logger_destroy(ds_wl_protocol_logger);
+ ds_wl_protocol_logger = NULL;
+ }
+ ds_wl_protocol_logger =
+ wl_display_add_protocol_logger(display, logger_func, NULL);
+
+ ds_dbg("OUT << logger_set");
+}
+
+static void
+logger_unset(void)
+{
+ ds_dbg("IN >> logger_unset");
+
+ if (ds_wl_protocol_logger) {
+ wl_protocol_logger_destroy(ds_wl_protocol_logger);
+ ds_wl_protocol_logger = NULL;
+ }
+
+ ds_dbg("OUT << logger_unset");
+}
+
+static enum protocol_trace_token
+parser_get_next_token(const char **string)
+{
+ static int token_cnt;
+ int i, compare_res, found = 0, first, last;
+
+ first = 0;
+ last = token_cnt -1;
+ token_cnt = sizeof(token_table) / sizeof(token_table[0]);
+
+ i = (first + last) / 2;
+ while (1) {
+ compare_res = strncmp(*string, token_table[i].token_char,
+ token_table[i].token_length);
+ while (compare_res == 0) {
+ found = 1;
+ i++;
+ if (i == token_cnt)
+ break;
+ compare_res = strncmp(*string, token_table[i].token_char,
+ token_table[i].token_length);
+ }
+
+ if (found) {
+ i--;
+ *string += token_table[i].token_length;
+ return token_table[i].token_name;
+ }
+
+ if (first >= last)
+ break;
+
+ if (compare_res > 0)
+ first = i + 1;
+ else
+ last = i - 1;
+
+ i = (first + last) / 2;
+ }
+
+ if (isalpha(**string)) {
+ (*string)++;
+ while (isalpha(**string) || isdigit(**string) ||
+ **string == '_' || **string == '-') {
+ (*string)++;
+ }
+
+ return PROTOCOL_TRACE_TOKEN_SYMBOL;
+ }
+
+ if (isdigit(**string)) {
+ (*string)++;
+ while (isdigit(**string))
+ (*string)++;
+
+ return PROTOCOL_TRACE_TOKEN_NUMBER;
+ }
+
+ return PROTOCOL_TRACE_TOKEN_UNKNOWN;
+}
+
+static void
+parser_process_token(struct protocol_trace_token_data *token)
+{
+ do {
+ token->last_symbol = *(token->string);
+ token->last_token = parser_get_next_token(token->string);
+ token->symbol_len = *(token->string) - token->last_symbol;
+ } while (token->last_token == PROTOCOL_TRACE_TOKEN_SPACE);
+}
+
+static struct protocol_trace_tree_node *
+parser_parse_statement(struct protocol_trace_tree *tree,
+ struct protocol_trace_token_data *token)
+{
+ struct protocol_trace_tree_node *node = NULL;
+ struct protocol_trace_rule_node *data;
+
+ if (token->last_token == PROTOCOL_TRACE_TOKEN_L_BR) {
+ parser_process_token(token);
+
+ node = parser_parse_token(tree, token);
+ if (!node)
+ return NULL;
+
+ if (token->last_token != PROTOCOL_TRACE_TOKEN_R_BR)
+ goto fail;
+
+ parser_process_token(token);
+
+ return node;
+ }
+
+ if (token->last_token != PROTOCOL_TRACE_TOKEN_SYMBOL)
+ goto fail;
+
+ node = bintree_create_node(tree);
+ if (!node)
+ goto fail;
+
+ data = (struct protocol_trace_rule_node *) bintree_get_node_data(node);
+
+ strncpy(data->variable_name, token->last_symbol, token->symbol_len);
+ data->variable_name[token->symbol_len] = '\0';
+
+ if (!strcasecmp(data->variable_name, "all")) {
+ ds_dbg("data = all");
+ data->node_type = PROTOCOL_TRACE_NODE_TYPE_ALL;
+ parser_process_token(token);
+
+ return node;
+ }
+
+ data->node_type = PROTOCOL_TRACE_NODE_TYPE_DATA;
+
+ parser_process_token(token);
+
+ switch (token->last_token) {
+ case PROTOCOL_TRACE_TOKEN_NOT_EQ:
+ data->comparer = PROTOCOL_TRACE_COMPARER_NOT_EQ;
+ break;
+ case PROTOCOL_TRACE_TOKEN_EQUAL:
+ data->comparer = PROTOCOL_TRACE_COMPARER_EQUAL;
+ break;
+ case PROTOCOL_TRACE_TOKEN_LSS_THAN:
+ data->comparer = PROTOCOL_TRACE_COMPARER_LESS_EQ;
+ break;
+ case PROTOCOL_TRACE_TOKEN_GRT_THAN:
+ data->comparer = PROTOCOL_TRACE_COMPARER_GREATER;
+ break;
+ case PROTOCOL_TRACE_TOKEN_GRT_EQ:
+ data->comparer = PROTOCOL_TRACE_COMPARER_GREATE_EQ;
+ break;
+ default:
+ goto fail;
+ }
+
+ parser_process_token(token);
+
+ if (token->last_token == PROTOCOL_TRACE_TOKEN_NUMBER) {
+ data->value_type = PROTOCOL_TRACE_DATA_TYPE_INTEGER;
+ data->value.integer = atoi(token->last_symbol);
+ } else if (token->last_token == PROTOCOL_TRACE_TOKEN_SYMBOL) {
+ data->value_type = PROTOCOL_TRACE_DATA_TYPE_STRING;
+ strncpy(data->value.string, token->last_symbol, token->symbol_len);
+ data->value.string[token->symbol_len] = '\0';
+ } else {
+ goto fail;
+ }
+
+ parser_process_token(token);
+
+ return node;
+
+fail:
+ if (node)
+ bintree_remove_node_recursive(node);
+
+ return NULL;
+}
+
+static struct protocol_trace_tree_node *
+parser_parse_token(struct protocol_trace_tree *tree,
+ struct protocol_trace_token_data *token)
+{
+ struct protocol_trace_tree_node *node, *left = NULL, *right = NULL;
+ struct protocol_trace_rule_node *data;
+
+ node = parser_parse_statement(tree,token);
+ if (!node) {
+ ds_err("PARSE statement error\n");
+ goto fail;
+ }
+
+ while (token->last_token == PROTOCOL_TRACE_TOKEN_AND) {
+ left = node;
+ node = NULL;
+
+ parser_process_token(token);
+
+ right = parser_parse_statement(tree, token);
+ if (!right)
+ goto fail;
+
+ node = bintree_create_node(tree);
+ if (!node)
+ goto fail;
+
+ data = (struct protocol_trace_rule_node *) bintree_get_node_data(node);
+ data->node_type = PROTOCOL_TRACE_NODE_TYPE_AND;
+ bintree_set_left_child(node, left);
+ bintree_set_right_child(node, right);
+ }
+
+ if (token->last_token == PROTOCOL_TRACE_TOKEN_OR) {
+ left = node;
+ node = NULL;
+
+ parser_process_token(token);
+
+ right = parser_parse_token(tree, token);
+ if (!right)
+ goto fail;
+
+ node = bintree_create_node(tree);
+ if (!node)
+ goto fail;
+
+ data = (struct protocol_trace_rule_node *) bintree_get_node_data(node);
+ data->node_type = PROTOCOL_TRACE_NODE_TYPE_OR;
+ bintree_set_left_child(node, left);
+ bintree_set_right_child(node, right);
+ }
+
+ return node;
+
+fail:
+ ds_dbg("[fail] recursive remove node");
+ if (left)
+ bintree_remove_node_recursive(left);
+
+ return NULL;
+}
+
+static struct protocol_trace_tree *
+parser_parse_rule_string(const char *string)
+{
+ struct protocol_trace_tree *tree;
+ struct protocol_trace_tree_node *node;
+ struct protocol_trace_token_data token;
+
+ token.string = &string;
+ parser_process_token(&token);
+
+ tree = bintree_create_tree(sizeof(struct protocol_trace_rule_node));
+ if (!tree)
+ return NULL;
+
+ node = parser_parse_token(tree, &token);
+ if (!node) {
+ bintree_destroy_tree(tree);
+ ds_dbg("finish destroy tree & return null");
+ return NULL;
+ }
+
+ bintree_set_head(tree, node);
+
+ return tree;
+}
+
+static enum protocol_trace_rule_set_result
+rulechecker_rule_add(struct protocol_trace_rule_checker *rc,
+ enum protocol_trace_policy_type policy, const char *rule_string)
+{
+ if (rc->count == MAX_RULE)
+ return PROTOCOL_TRACE_RULE_SET_ERR_TOO_MANY_RULES;
+
+ rc->rules[rc->count].tree = parser_parse_rule_string(rule_string);
+ if (!rc->rules[rc->count].tree) {
+ ds_dbg("parse error");
+ return PROTOCOL_TRACE_RULE_SET_ERR_PARSE;
+ }
+
+ rc->rules[rc->count].policy = policy;
+ rc->count++;
+
+ return PROTOCOL_TRACE_RULE_SET_OK;
+}
+
+static const char *
+rulechecker_usage_print()
+{
+ return
+ "##########################################################\n"
+ "### Enlightenment Protocol Log filtering. ###\n"
+ "##########################################################\n"
+ "\n"
+ "-----------------------------------------------------------------\n"
+ "How to read enlightenment_info protocol messages :\n"
+ "[timestamp] Server --> Client [PID: [pid]] interface@id.message(arguments..) cmd: CMD\n"
+ " ex)\n"
+ "[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"
+ " ==> type = event && pid = 103 && cmd = launchpad-loader && iface = wl_touch && msg = up\n"
+ "[4234234.123] Server <-- Client [PID: 123] wl_seat@32.get_touch(new id wl_touch@22) cmd: /usr/bin/launchpad-loader\n"
+ " ==> type = request && pid = 123 && cmd = launchpad-loader && iface = wl_seat && msg = get_touch\n"
+ "-----------------------------------------------------------------\n"
+ "Usage : enlightenment_info -protocol_rule add [POLICY] [RULE]\n"
+ " enlightenment_info -protocol_rule remove [INDEX]\n"
+ " enlightenment_info -protocol_rule file [RULE_FILE]\n"
+ " enlightenment_info -protocol_rule print\n"
+ " enlightenment_info -protocol_rule help\n"
+ " [POLICY] : allow / deny \n"
+ " [RULE] : C Language-style boolean expression syntax. [VARIABLE] [COMPAROTOR] [VALUE]\n"
+ " [VARIABLE] : type / iface / msg / cmd(command) / pid\n"
+ " [COMPARATOR] : & / && / and / | / || / or / = / == / != / > / >= / < / <=\n"
+ " [VALUE] : string / number \n"
+ " ex)\n"
+ " enlightenment_info -protocol_rule add allow \"(type=request) && (iface == wl_pointer and (msg = down or msg = up))\"\n"
+ " enlightenment_info -protocol_rule add deny cmd!= launch-loader\n"
+ " enlightenment_info -protocol_rule remove all\n"
+ " enlightenment_info -protocol_rule remove 3\n"
+ "\n";
+}
+
+static int
+rulechecker_print_func(struct protocol_trace_tree *tree,
+ struct protocol_trace_tree_node *node,
+ struct protocol_trace_tree_node *parent, void *arg)
+{
+ struct protocol_trace_reply_buffer *buffer = (struct protocol_trace_reply_buffer *)arg;
+ char *reply = *buffer->reply;
+ int *len = buffer->len;
+ const char *operators[] = {"==", "<", ">", "<=", ">=", "!=" };
+ struct protocol_trace_rule_node *data;
+
+ data = (struct protocol_trace_rule_node *)bintree_get_node_data(node);
+
+ if (data->node_type == PROTOCOL_TRACE_NODE_TYPE_ALL)
+ REPLY(" ALL");
+ else if (data->node_type == PROTOCOL_TRACE_NODE_TYPE_AND)
+ REPLY(" AND");
+ else if (data->node_type == PROTOCOL_TRACE_NODE_TYPE_OR)
+ REPLY(" OR");
+ else { // data->node_type == PROTOCOL_TRACE_NODE_TYPE_DATA
+ if (node == bintree_get_left_child(parent))
+ REPLY(" (");
+ REPLY(" %s %s ",
+ data->variable_name, operators[data->comparer]);
+
+ if (data->value_type == PROTOCOL_TRACE_DATA_TYPE_INTEGER)
+ REPLY(" %d",
+ data->value.integer);
+ else
+ REPLY(" %s",
+ data->value.string);
+
+ if (node == bintree_get_right_child(parent))
+ REPLY(" )");
+ }
+
+ *buffer->reply = reply;
+
+ return 0;
+}
+
+static void
+rulechecker_print_rules(struct protocol_trace_rule_checker *rc,
+ char *reply, int *len)
+{
+ struct protocol_trace_reply_buffer buffer = {&reply, len};
+ int i;
+
+ REPLY("\n --------------------[ Protocol Filter Rules ]--------------------\n");
+ REPLY(" No Policy Rule\n");
+ REPLY(" -----------------------------------------------------------------\n");
+
+ for (i =0; i < rc->count; i++) {
+ REPLY(" %3d %10s \"", i,
+ rc->rules[i].policy == PROTOCOL_POLICY_TYPE_ALLOW ?
+ "ALLOW" : "DENY");
+ bintree_inorder_traverse(rc->rules[i].tree, rulechecker_print_func,
+ (void*) & buffer);
+ REPLY("\"\n");
+ }
+}
+
+static enum protocol_trace_rule_set_result
+rulechecker_rule_remove(struct protocol_trace_rule_checker *rc, int index)
+{
+ if (index < 0 || index >= rc->count)
+ return PROTOCOL_TRACE_RULE_SET_ERR_NO_RULE;
+
+ bintree_destroy_tree(rc->rules[index].tree);
+ rc->count--;
+ if (index != rc->count) {
+ memmove(&rc->rules[index], &rc->rules[index + 1],
+ sizeof(struct protocol_trace_rule)*(rc->count - index));
+ }
+
+ return PROTOCOL_TRACE_RULE_SET_OK;
+}
+
+static struct protocol_trace_rule_checker *
+rulechecker_init()
+{
+ struct protocol_trace_rule_checker *rc;
+
+ rc = calloc(1, sizeof *rc);
+ if (!rc)
+ return NULL;
+
+ rc->count = 0;
+
+ return rc;
+}
+
+static void rulechecker_destroy(struct protocol_trace_rule_checker *rc)
+{
+ for (int i = rc->count - 1; i >= 0; i--)
+ rulechecker_rule_remove(rc, i);
+
+ free(rc);
+}
+
+static bool
+rule_file_set(const char *filename, char *reply, int *len)
+{
+ int fd = -1, rule_len;
+ char fs[8096], *pfs;
+
+ ds_dbg("IN >> rule_file_set");
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ ds_err("failed: open '%s'", filename);
+ return false;
+ }
+
+ rule_len = read(fd, fs, sizeof(fs));
+ pfs = fs;
+
+ while (pfs -fs < rule_len) {
+ int i, new_argc =3;
+ const char *new_argv[3] = {"add", };
+ char policy[64] = {0,};
+ char rule[1024] = {0,};
+
+ if (pfs[0] == ' ' || pfs[0] == '\n') {
+ pfs++;
+ continue;
+ }
+ for (i = 0; pfs[i] != ' '; i++)
+ policy[i] = pfs[i];
+
+ new_argv[1] = policy;
+ pfs += (strlen(new_argv[1]) + 1);
+
+ memset(rule, 0, sizeof(rule));
+ for (i = 0; pfs[i] != '\n'; i++)
+ rule[i] = pfs[i];
+
+ new_argv[2] = rule;
+
+ pfs += (strlen(new_argv[2]) +1);
+
+ if (!rule_set((const int)new_argc, (const char**)new_argv,
+ reply, len)) {
+ close(fd);
+ return false;
+ }
+ }
+ close(fd);
+
+ ds_dbg("OUT << rule_file_set");
+
+ return true;
+}
+
+static int
+rule_check_remove_rule(const char *str)
+{
+ char *endptr;
+ int index;
+
+ index = strtol(str, &endptr, 10);
+
+ if (errno == ERANGE) {
+ ds_err("Rule remove fail : overflow");
+ return -1;
+ }
+
+ if (errno != 0) {
+ ds_err("Rule remove fail : other error");
+ return -1;
+ }
+
+ if (endptr == 0) {
+ ds_err("Rule remove fail : non-numeric");
+ return -1;
+ }
+
+ if (*endptr != '\0') {
+ ds_err("Rule remove fail : non-numeric at end");
+ return -1;
+ }
+
+ if (isspace(*str)) {
+ ds_err("Rule remove fail : space at beginning");
+ return -1;
+ }
+
+ return index;
+}
+
+static void
+rule_arguments_merge(char *target, int target_size,
+ int argc, const char **argv)
+{
+ int i, len;
+
+ for (i = 0; i < argc; i++) {
+ len = snprintf(target, target_size, "%s", argv[i]);
+ target += len;
+ target_size -= len;
+
+ if (i != argc - 1) {
+ *(target++) = ' ';
+ target_size--;
+ }
+ }
+}
+
+static bool
+rule_set(const int argc, const char **argv, char *reply, int *len)
+{
+ const char * command;
+
+ ds_dbg("IN >> rule_set");
+ ds_dbg("(parameter) argc = %d, argv[0] = %s", argc, argv[0]);
+
+ if (argc == 0) {
+ rulechecker_print_rules(rc, reply, len);
+ return true;
+ }
+
+ command = argv[0];
+
+ if (!strcasecmp(command, "add")) {
+ ds_dbg("ADD");
+ enum protocol_trace_policy_type policy_type;
+ enum protocol_trace_rule_set_result result;
+ const char * policy = argv[1]; //allow, deny
+ char merge[8192] = {0,}, rule[8192] = {0,};
+ int i, index=0, size_rule, apply = 0, size_merge;
+
+ if (argc <3) {
+ ds_err("Error: Too few argumens.");
+ return false;
+ }
+
+ if (!strcasecmp(policy, "ALLOW"))
+ policy_type = PROTOCOL_POLICY_TYPE_ALLOW;
+ else if (!strcasecmp(policy, "DENY"))
+ policy_type = PROTOCOL_POLICY_TYPE_DENY;
+ else {
+ ds_err("Error : Unknown : [%s].\n should be ALLOW/DENY.", policy);
+ return false;
+ }
+
+ rule_arguments_merge(merge, sizeof(merge), argc -2, &(argv[2]));
+
+ size_rule = sizeof(rule) -1;
+ size_merge = strlen(merge);
+
+ for (i = 0; i < size_merge; i++) {
+ if (merge[i] == '\"' || merge[i] == '\'') {
+ rule[index++] = ' ';
+ if (index > size_rule)
+ return false;
+ continue;
+ }
+ if (merge[i] == '+') {
+ rule[index++] = ' ';
+ if (index > size_rule)
+ return false;
+ if (apply == 0) {
+ const char * plus = "|| type=reply || type=error";
+ int size_plus = strlen(plus);
+ int len = MIN(size_rule - index, size_plus);
+ snprintf(rule, sizeof(rule), "%s", plus);
+ index += len;
+ if (index >size_rule)
+ return false;
+ apply =1;
+ }
+ continue;
+ }
+ rule[index++] = merge[i];
+ if (index > size_rule)
+ return false;
+ }
+ ds_dbg("ADD :: rule = %s", rule);
+
+ result = rulechecker_rule_add(rc, policy_type, rule);
+
+ if (result == PROTOCOL_TRACE_RULE_SET_ERR_TOO_MANY_RULES) {
+ ds_err("Error: Too many rules were added.");
+ return false;
+ } else if (result == PROTOCOL_TRACE_RULE_SET_ERR_PARSE) {
+ ds_err("Error: parsing the rule [%s]", rule);
+ return false;
+ }
+ ds_dbg( "The rule was successfully added");
+
+ } else if (!strcasecmp(command, "remove")) {
+ const char * remove_idx;
+ int i;
+
+ ds_dbg("REMOVE");
+
+ if (argc < 2) {
+ ds_err("Error: Too few arguments");
+ return false;
+ }
+
+ for (i = 0; i < argc - 1; i++) {
+ remove_idx = argv[i + 1];
+ if (!strcasecmp(remove_idx, "all")) {
+ ds_dbg("REMOVE :: all");
+ rulechecker_destroy(rc);
+ rc = rulechecker_init();
+ if (!rc) {
+ ds_err("Error: rules not removed");
+ return false;
+ }
+ } else {
+ int index = rule_check_remove_rule(remove_idx);
+ if (index == -1) {
+ ds_err("Rule remove fail : overflow");
+ } else {
+ ds_dbg("REMOVE :: remove idx = %d", index);
+
+ if (isdigit(*remove_idx) &&
+ rulechecker_rule_remove(rc, index) == 0)
+ ds_dbg("Rule remove success : rule [%d]", index);
+ else
+ ds_err("Rule remove fail : No rule [%s]", remove_idx);
+ }
+ }
+ }
+ } else if (!strcasecmp(command, "file")) {
+ ds_dbg("FILE");
+ if (argc <2) {
+ ds_err("Error: Too few argumens.");
+ return false;
+ }
+
+ if (!rule_file_set(argv[1], reply, len))
+ return false;
+
+ rulechecker_print_rules(rc, reply, len);
+ } else if (!strcasecmp(command, "print")) {
+ rulechecker_print_rules(rc, reply, len);
+ } else if (!strcasecmp(command, "help")) {
+ ds_dbg( "%s", rulechecker_usage_print());
+ } else {
+ ds_err("%s\nUnknown command : [%s] ", rulechecker_usage_print(), command);
+ }
+
+ ds_dbg("OUT << rule_set");
+
+ return true;
+}
+
+static bool
+rule_init(char *rule_path)
+{
+ bool ret = false;
+ const char *argv[2];
+ int argc = 2;
+
+ char tmpReply[4096];
+ int tmpLen = sizeof(tmpReply);
+ char *reply = tmpReply;
+ int *len = &tmpLen;
+
+ if (!rule_path || strlen(rule_path) <= 0) {
+ rule_path = alloca(10);
+ snprintf(rule_path, 10, "%s", "/tmp/rule");
+ ds_inf("rule path is default = %s", rule_path);
+ }
+
+ argv[0] = "file";
+ argv[1] = rule_path;
+
+ ds_dbg("rule_path = %s", rule_path);
+
+ ret = rule_set(argc, (const char**)&(argv[0]), reply, len);
+ ds_inf("%s", &tmpReply);
+
+ return ret;
+}
+
+static bool
+logger_init(char *trace_path)
+{
+ ds_dbg("IN >> logger_init");
+ if (!trace_path || strlen(trace_path) <= 0) {
+ snprintf(trace_env_path, sizeof(trace_env_path), "%s", "/tmp/trace");
+ ds_inf("trace path is default = %s", trace_env_path);
+ } else {
+ snprintf(trace_env_path, sizeof(trace_env_path), "%s", trace_path);
+ }
+
+ ds_dbg("saved trace path = %s", trace_env_path);
+
+ logger_unset();
+ ds_dbg("OUT << logger_init");
+
+ return true;
+}
+
+int
+protocol_trace_enable(bool state)
+{
+ if (log_fp_ptrace != NULL) {
+ fclose(log_fp_ptrace);
+ log_fp_ptrace = NULL;
+ }
+
+ if (state) {
+ //TODO: can change trace file path by cmd
+ ds_inf("state: protocol_trace enabled");
+ logger_set();
+ return 1;
+ } else {
+ ds_inf("state: protocol_trace disabled");
+ logger_unset();
+ return 0;
+ }
+
+ return -1;
+}
+
+bool
+protocol_trace_init(struct wl_display *d)
+{
+ bool ret = false;
+ char *env_path = NULL;
+
+ display = d;
+ rc = rulechecker_init();
+
+ env_path = getenv("DS_PROTOCOL_RULE_FILE");
+ ret = rule_init(env_path);
+
+ if (env_path) {
+ char *tmp = strdup(env_path);
+ if (!tmp) return false;
+ free(tmp);
+ env_path = NULL;
+ }
+ if (!ret)
+ return ret;
+
+ env_path = getenv("DS_PROTOCOL_TRACE_FILE");
+ ret = logger_init(env_path);
+
+ if (env_path) {
+ char *tmp = strdup(env_path);
+ if (!tmp) return false;
+ free(tmp);
+ env_path = NULL;
+ }
+
+ return ret;
+}
+
+void
+protocol_trace_fini()
+{
+ rulechecker_destroy(rc);
+}
\ No newline at end of file