diff options
Diffstat (limited to 'src/tools/lib/traceevent/parse-filter.c')
-rw-r--r-- | src/tools/lib/traceevent/parse-filter.c | 2303 |
1 files changed, 0 insertions, 2303 deletions
diff --git a/src/tools/lib/traceevent/parse-filter.c b/src/tools/lib/traceevent/parse-filter.c deleted file mode 100644 index 2500e75..0000000 --- a/src/tools/lib/traceevent/parse-filter.c +++ /dev/null @@ -1,2303 +0,0 @@ -/* - * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License (not later!) - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, see <http://www.gnu.org/licenses> - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> -#include <errno.h> -#include <sys/types.h> - -#include "event-parse.h" -#include "event-utils.h" - -#define COMM "COMM" - -static struct format_field comm = { - .name = "COMM", -}; - -struct event_list { - struct event_list *next; - struct event_format *event; -}; - -#define MAX_ERR_STR_SIZE 256 - -static void show_error(char **error_str, const char *fmt, ...) -{ - unsigned long long index; - const char *input; - char *error; - va_list ap; - int len; - int i; - - if (!error_str) - return; - - input = pevent_get_input_buf(); - index = pevent_get_input_buf_ptr(); - len = input ? strlen(input) : 0; - - error = malloc_or_die(MAX_ERR_STR_SIZE + (len*2) + 3); - - if (len) { - strcpy(error, input); - error[len] = '\n'; - for (i = 1; i < len && i < index; i++) - error[len+i] = ' '; - error[len + i] = '^'; - error[len + i + 1] = '\n'; - len += i+2; - } - - va_start(ap, fmt); - vsnprintf(error + len, MAX_ERR_STR_SIZE, fmt, ap); - va_end(ap); - - *error_str = error; -} - -static void free_token(char *token) -{ - pevent_free_token(token); -} - -static enum event_type read_token(char **tok) -{ - enum event_type type; - char *token = NULL; - - do { - free_token(token); - type = pevent_read_token(&token); - } while (type == EVENT_NEWLINE || type == EVENT_SPACE); - - /* If token is = or ! check to see if the next char is ~ */ - if (token && - (strcmp(token, "=") == 0 || strcmp(token, "!") == 0) && - pevent_peek_char() == '~') { - /* append it */ - *tok = malloc_or_die(3); - sprintf(*tok, "%c%c", *token, '~'); - free_token(token); - /* Now remove the '~' from the buffer */ - pevent_read_token(&token); - free_token(token); - } else - *tok = token; - - return type; -} - -static int filter_cmp(const void *a, const void *b) -{ - const struct filter_type *ea = a; - const struct filter_type *eb = b; - - if (ea->event_id < eb->event_id) - return -1; - - if (ea->event_id > eb->event_id) - return 1; - - return 0; -} - -static struct filter_type * -find_filter_type(struct event_filter *filter, int id) -{ - struct filter_type *filter_type; - struct filter_type key; - - key.event_id = id; - - filter_type = bsearch(&key, filter->event_filters, - filter->filters, - sizeof(*filter->event_filters), - filter_cmp); - - return filter_type; -} - -static struct filter_type * -add_filter_type(struct event_filter *filter, int id) -{ - struct filter_type *filter_type; - int i; - - filter_type = find_filter_type(filter, id); - if (filter_type) - return filter_type; - - filter->event_filters = realloc(filter->event_filters, - sizeof(*filter->event_filters) * - (filter->filters + 1)); - if (!filter->event_filters) - die("Could not allocate filter"); - - for (i = 0; i < filter->filters; i++) { - if (filter->event_filters[i].event_id > id) - break; - } - - if (i < filter->filters) - memmove(&filter->event_filters[i+1], - &filter->event_filters[i], - sizeof(*filter->event_filters) * - (filter->filters - i)); - - filter_type = &filter->event_filters[i]; - filter_type->event_id = id; - filter_type->event = pevent_find_event(filter->pevent, id); - filter_type->filter = NULL; - - filter->filters++; - - return filter_type; -} - -/** - * pevent_filter_alloc - create a new event filter - * @pevent: The pevent that this filter is associated with - */ -struct event_filter *pevent_filter_alloc(struct pevent *pevent) -{ - struct event_filter *filter; - - filter = malloc_or_die(sizeof(*filter)); - memset(filter, 0, sizeof(*filter)); - filter->pevent = pevent; - pevent_ref(pevent); - - return filter; -} - -static struct filter_arg *allocate_arg(void) -{ - struct filter_arg *arg; - - arg = malloc_or_die(sizeof(*arg)); - memset(arg, 0, sizeof(*arg)); - - return arg; -} - -static void free_arg(struct filter_arg *arg) -{ - if (!arg) - return; - - switch (arg->type) { - case FILTER_ARG_NONE: - case FILTER_ARG_BOOLEAN: - break; - - case FILTER_ARG_NUM: - free_arg(arg->num.left); - free_arg(arg->num.right); - break; - - case FILTER_ARG_EXP: - free_arg(arg->exp.left); - free_arg(arg->exp.right); - break; - - case FILTER_ARG_STR: - free(arg->str.val); - regfree(&arg->str.reg); - free(arg->str.buffer); - break; - - case FILTER_ARG_VALUE: - if (arg->value.type == FILTER_STRING || - arg->value.type == FILTER_CHAR) - free(arg->value.str); - break; - - case FILTER_ARG_OP: - free_arg(arg->op.left); - free_arg(arg->op.right); - default: - break; - } - - free(arg); -} - -static void add_event(struct event_list **events, - struct event_format *event) -{ - struct event_list *list; - - list = malloc_or_die(sizeof(*list)); - list->next = *events; - *events = list; - list->event = event; -} - -static int event_match(struct event_format *event, - regex_t *sreg, regex_t *ereg) -{ - if (sreg) { - return !regexec(sreg, event->system, 0, NULL, 0) && - !regexec(ereg, event->name, 0, NULL, 0); - } - - return !regexec(ereg, event->system, 0, NULL, 0) || - !regexec(ereg, event->name, 0, NULL, 0); -} - -static int -find_event(struct pevent *pevent, struct event_list **events, - char *sys_name, char *event_name) -{ - struct event_format *event; - regex_t ereg; - regex_t sreg; - int match = 0; - char *reg; - int ret; - int i; - - if (!event_name) { - /* if no name is given, then swap sys and name */ - event_name = sys_name; - sys_name = NULL; - } - - reg = malloc_or_die(strlen(event_name) + 3); - sprintf(reg, "^%s$", event_name); - - ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB); - free(reg); - - if (ret) - return -1; - - if (sys_name) { - reg = malloc_or_die(strlen(sys_name) + 3); - sprintf(reg, "^%s$", sys_name); - ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB); - free(reg); - if (ret) { - regfree(&ereg); - return -1; - } - } - - for (i = 0; i < pevent->nr_events; i++) { - event = pevent->events[i]; - if (event_match(event, sys_name ? &sreg : NULL, &ereg)) { - match = 1; - add_event(events, event); - } - } - - regfree(&ereg); - if (sys_name) - regfree(&sreg); - - if (!match) - return -1; - - return 0; -} - -static void free_events(struct event_list *events) -{ - struct event_list *event; - - while (events) { - event = events; - events = events->next; - free(event); - } -} - -static struct filter_arg * -create_arg_item(struct event_format *event, const char *token, - enum event_type type, char **error_str) -{ - struct format_field *field; - struct filter_arg *arg; - - arg = allocate_arg(); - - switch (type) { - - case EVENT_SQUOTE: - case EVENT_DQUOTE: - arg->type = FILTER_ARG_VALUE; - arg->value.type = - type == EVENT_DQUOTE ? FILTER_STRING : FILTER_CHAR; - arg->value.str = strdup(token); - if (!arg->value.str) - die("malloc string"); - break; - case EVENT_ITEM: - /* if it is a number, then convert it */ - if (isdigit(token[0])) { - arg->type = FILTER_ARG_VALUE; - arg->value.type = FILTER_NUMBER; - arg->value.val = strtoull(token, NULL, 0); - break; - } - /* Consider this a field */ - field = pevent_find_any_field(event, token); - if (!field) { - if (strcmp(token, COMM) != 0) { - /* not a field, Make it false */ - arg->type = FILTER_ARG_BOOLEAN; - arg->boolean.value = FILTER_FALSE; - break; - } - /* If token is 'COMM' then it is special */ - field = &comm; - } - arg->type = FILTER_ARG_FIELD; - arg->field.field = field; - break; - default: - free_arg(arg); - show_error(error_str, "expected a value but found %s", - token); - return NULL; - } - return arg; -} - -static struct filter_arg * -create_arg_op(enum filter_op_type btype) -{ - struct filter_arg *arg; - - arg = allocate_arg(); - arg->type = FILTER_ARG_OP; - arg->op.type = btype; - - return arg; -} - -static struct filter_arg * -create_arg_exp(enum filter_exp_type etype) -{ - struct filter_arg *arg; - - arg = allocate_arg(); - arg->type = FILTER_ARG_EXP; - arg->op.type = etype; - - return arg; -} - -static struct filter_arg * -create_arg_cmp(enum filter_exp_type etype) -{ - struct filter_arg *arg; - - arg = allocate_arg(); - /* Use NUM and change if necessary */ - arg->type = FILTER_ARG_NUM; - arg->op.type = etype; - - return arg; -} - -static int add_right(struct filter_arg *op, struct filter_arg *arg, - char **error_str) -{ - struct filter_arg *left; - char *str; - int op_type; - int ret; - - switch (op->type) { - case FILTER_ARG_EXP: - if (op->exp.right) - goto out_fail; - op->exp.right = arg; - break; - - case FILTER_ARG_OP: - if (op->op.right) - goto out_fail; - op->op.right = arg; - break; - - case FILTER_ARG_NUM: - if (op->op.right) - goto out_fail; - /* - * The arg must be num, str, or field - */ - switch (arg->type) { - case FILTER_ARG_VALUE: - case FILTER_ARG_FIELD: - break; - default: - show_error(error_str, - "Illegal rvalue"); - return -1; - } - - /* - * Depending on the type, we may need to - * convert this to a string or regex. - */ - switch (arg->value.type) { - case FILTER_CHAR: - /* - * A char should be converted to number if - * the string is 1 byte, and the compare - * is not a REGEX. - */ - if (strlen(arg->value.str) == 1 && - op->num.type != FILTER_CMP_REGEX && - op->num.type != FILTER_CMP_NOT_REGEX) { - arg->value.type = FILTER_NUMBER; - goto do_int; - } - /* fall through */ - case FILTER_STRING: - - /* convert op to a string arg */ - op_type = op->num.type; - left = op->num.left; - str = arg->value.str; - - /* reset the op for the new field */ - memset(op, 0, sizeof(*op)); - - /* - * If left arg was a field not found then - * NULL the entire op. - */ - if (left->type == FILTER_ARG_BOOLEAN) { - free_arg(left); - free_arg(arg); - op->type = FILTER_ARG_BOOLEAN; - op->boolean.value = FILTER_FALSE; - break; - } - - /* Left arg must be a field */ - if (left->type != FILTER_ARG_FIELD) { - show_error(error_str, - "Illegal lvalue for string comparison"); - return -1; - } - - /* Make sure this is a valid string compare */ - switch (op_type) { - case FILTER_CMP_EQ: - op_type = FILTER_CMP_MATCH; - break; - case FILTER_CMP_NE: - op_type = FILTER_CMP_NOT_MATCH; - break; - - case FILTER_CMP_REGEX: - case FILTER_CMP_NOT_REGEX: - ret = regcomp(&op->str.reg, str, REG_ICASE|REG_NOSUB); - if (ret) { - show_error(error_str, - "RegEx '%s' did not compute", - str); - return -1; - } - break; - default: - show_error(error_str, - "Illegal comparison for string"); - return -1; - } - - op->type = FILTER_ARG_STR; - op->str.type = op_type; - op->str.field = left->field.field; - op->str.val = strdup(str); - if (!op->str.val) - die("malloc string"); - /* - * Need a buffer to copy data for tests - */ - op->str.buffer = malloc_or_die(op->str.field->size + 1); - /* Null terminate this buffer */ - op->str.buffer[op->str.field->size] = 0; - - /* We no longer have left or right args */ - free_arg(arg); - free_arg(left); - - break; - - case FILTER_NUMBER: - - do_int: - switch (op->num.type) { - case FILTER_CMP_REGEX: - case FILTER_CMP_NOT_REGEX: - show_error(error_str, - "Op not allowed with integers"); - return -1; - - default: - break; - } - - /* numeric compare */ - op->num.right = arg; - break; - default: - goto out_fail; - } - break; - default: - goto out_fail; - } - - return 0; - - out_fail: - show_error(error_str, - "Syntax error"); - return -1; -} - -static struct filter_arg * -rotate_op_right(struct filter_arg *a, struct filter_arg *b) -{ - struct filter_arg *arg; - - arg = a->op.right; - a->op.right = b; - return arg; -} - -static int add_left(struct filter_arg *op, struct filter_arg *arg) -{ - switch (op->type) { - case FILTER_ARG_EXP: - if (arg->type == FILTER_ARG_OP) - arg = rotate_op_right(arg, op); - op->exp.left = arg; - break; - - case FILTER_ARG_OP: - op->op.left = arg; - break; - case FILTER_ARG_NUM: - if (arg->type == FILTER_ARG_OP) - arg = rotate_op_right(arg, op); - - /* left arg of compares must be a field */ - if (arg->type != FILTER_ARG_FIELD && - arg->type != FILTER_ARG_BOOLEAN) - return -1; - op->num.left = arg; - break; - default: - return -1; - } - return 0; -} - -enum op_type { - OP_NONE, - OP_BOOL, - OP_NOT, - OP_EXP, - OP_CMP, -}; - -static enum op_type process_op(const char *token, - enum filter_op_type *btype, - enum filter_cmp_type *ctype, - enum filter_exp_type *etype) -{ - *btype = FILTER_OP_NOT; - *etype = FILTER_EXP_NONE; - *ctype = FILTER_CMP_NONE; - - if (strcmp(token, "&&") == 0) - *btype = FILTER_OP_AND; - else if (strcmp(token, "||") == 0) - *btype = FILTER_OP_OR; - else if (strcmp(token, "!") == 0) - return OP_NOT; - - if (*btype != FILTER_OP_NOT) - return OP_BOOL; - - /* Check for value expressions */ - if (strcmp(token, "+") == 0) { - *etype = FILTER_EXP_ADD; - } else if (strcmp(token, "-") == 0) { - *etype = FILTER_EXP_SUB; - } else if (strcmp(token, "*") == 0) { - *etype = FILTER_EXP_MUL; - } else if (strcmp(token, "/") == 0) { - *etype = FILTER_EXP_DIV; - } else if (strcmp(token, "%") == 0) { - *etype = FILTER_EXP_MOD; - } else if (strcmp(token, ">>") == 0) { - *etype = FILTER_EXP_RSHIFT; - } else if (strcmp(token, "<<") == 0) { - *etype = FILTER_EXP_LSHIFT; - } else if (strcmp(token, "&") == 0) { - *etype = FILTER_EXP_AND; - } else if (strcmp(token, "|") == 0) { - *etype = FILTER_EXP_OR; - } else if (strcmp(token, "^") == 0) { - *etype = FILTER_EXP_XOR; - } else if (strcmp(token, "~") == 0) - *etype = FILTER_EXP_NOT; - - if (*etype != FILTER_EXP_NONE) - return OP_EXP; - - /* Check for compares */ - if (strcmp(token, "==") == 0) - *ctype = FILTER_CMP_EQ; - else if (strcmp(token, "!=") == 0) - *ctype = FILTER_CMP_NE; - else if (strcmp(token, "<") == 0) - *ctype = FILTER_CMP_LT; - else if (strcmp(token, ">") == 0) - *ctype = FILTER_CMP_GT; - else if (strcmp(token, "<=") == 0) - *ctype = FILTER_CMP_LE; - else if (strcmp(token, ">=") == 0) - *ctype = FILTER_CMP_GE; - else if (strcmp(token, "=~") == 0) - *ctype = FILTER_CMP_REGEX; - else if (strcmp(token, "!~") == 0) - *ctype = FILTER_CMP_NOT_REGEX; - else - return OP_NONE; - - return OP_CMP; -} - -static int check_op_done(struct filter_arg *arg) -{ - switch (arg->type) { - case FILTER_ARG_EXP: - return arg->exp.right != NULL; - - case FILTER_ARG_OP: - return arg->op.right != NULL; - - case FILTER_ARG_NUM: - return arg->num.right != NULL; - - case FILTER_ARG_STR: - /* A string conversion is always done */ - return 1; - - case FILTER_ARG_BOOLEAN: - /* field not found, is ok */ - return 1; - - default: - return 0; - } -} - -enum filter_vals { - FILTER_VAL_NORM, - FILTER_VAL_FALSE, - FILTER_VAL_TRUE, -}; - -void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child, - struct filter_arg *arg) -{ - struct filter_arg *other_child; - struct filter_arg **ptr; - - if (parent->type != FILTER_ARG_OP && - arg->type != FILTER_ARG_OP) - die("can not reparent other than OP"); - - /* Get the sibling */ - if (old_child->op.right == arg) { - ptr = &old_child->op.right; - other_child = old_child->op.left; - } else if (old_child->op.left == arg) { - ptr = &old_child->op.left; - other_child = old_child->op.right; - } else - die("Error in reparent op, find other child"); - - /* Detach arg from old_child */ - *ptr = NULL; - - /* Check for root */ - if (parent == old_child) { - free_arg(other_child); - *parent = *arg; - /* Free arg without recussion */ - free(arg); - return; - } - - if (parent->op.right == old_child) - ptr = &parent->op.right; - else if (parent->op.left == old_child) - ptr = &parent->op.left; - else - die("Error in reparent op"); - *ptr = arg; - - free_arg(old_child); -} - -enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg) -{ - enum filter_vals lval, rval; - - switch (arg->type) { - - /* bad case */ - case FILTER_ARG_BOOLEAN: - return FILTER_VAL_FALSE + arg->boolean.value; - - /* good cases: */ - case FILTER_ARG_STR: - case FILTER_ARG_VALUE: - case FILTER_ARG_FIELD: - return FILTER_VAL_NORM; - - case FILTER_ARG_EXP: - lval = test_arg(arg, arg->exp.left); - if (lval != FILTER_VAL_NORM) - return lval; - rval = test_arg(arg, arg->exp.right); - if (rval != FILTER_VAL_NORM) - return rval; - return FILTER_VAL_NORM; - - case FILTER_ARG_NUM: - lval = test_arg(arg, arg->num.left); - if (lval != FILTER_VAL_NORM) - return lval; - rval = test_arg(arg, arg->num.right); - if (rval != FILTER_VAL_NORM) - return rval; - return FILTER_VAL_NORM; - - case FILTER_ARG_OP: - if (arg->op.type != FILTER_OP_NOT) { - lval = test_arg(arg, arg->op.left); - switch (lval) { - case FILTER_VAL_NORM: - break; - case FILTER_VAL_TRUE: - if (arg->op.type == FILTER_OP_OR) - return FILTER_VAL_TRUE; - rval = test_arg(arg, arg->op.right); - if (rval != FILTER_VAL_NORM) - return rval; - - reparent_op_arg(parent, arg, arg->op.right); - return FILTER_VAL_NORM; - - case FILTER_VAL_FALSE: - if (arg->op.type == FILTER_OP_AND) - return FILTER_VAL_FALSE; - rval = test_arg(arg, arg->op.right); - if (rval != FILTER_VAL_NORM) - return rval; - - reparent_op_arg(parent, arg, arg->op.right); - return FILTER_VAL_NORM; - } - } - - rval = test_arg(arg, arg->op.right); - switch (rval) { - case FILTER_VAL_NORM: - break; - case FILTER_VAL_TRUE: - if (arg->op.type == FILTER_OP_OR) - return FILTER_VAL_TRUE; - if (arg->op.type == FILTER_OP_NOT) - return FILTER_VAL_FALSE; - - reparent_op_arg(parent, arg, arg->op.left); - return FILTER_VAL_NORM; - - case FILTER_VAL_FALSE: - if (arg->op.type == FILTER_OP_AND) - return FILTER_VAL_FALSE; - if (arg->op.type == FILTER_OP_NOT) - return FILTER_VAL_TRUE; - - reparent_op_arg(parent, arg, arg->op.left); - return FILTER_VAL_NORM; - } - - return FILTER_VAL_NORM; - default: - die("bad arg in filter tree"); - } - return FILTER_VAL_NORM; -} - -/* Remove any unknown event fields */ -static struct filter_arg *collapse_tree(struct filter_arg *arg) -{ - enum filter_vals ret; - - ret = test_arg(arg, arg); - switch (ret) { - case FILTER_VAL_NORM: - return arg; - - case FILTER_VAL_TRUE: - case FILTER_VAL_FALSE: - free_arg(arg); - arg = allocate_arg(); - arg->type = FILTER_ARG_BOOLEAN; - arg->boolean.value = ret == FILTER_VAL_TRUE; - } - - return arg; -} - -static int -process_filter(struct event_format *event, struct filter_arg **parg, - char **error_str, int not) -{ - enum event_type type; - char *token = NULL; - struct filter_arg *current_op = NULL; - struct filter_arg *current_exp = NULL; - struct filter_arg *left_item = NULL; - struct filter_arg *arg = NULL; - enum op_type op_type; - enum filter_op_type btype; - enum filter_exp_type etype; - enum filter_cmp_type ctype; - int ret; - - *parg = NULL; - - do { - free(token); - type = read_token(&token); - switch (type) { - case EVENT_SQUOTE: - case EVENT_DQUOTE: - case EVENT_ITEM: - arg = create_arg_item(event, token, type, error_str); - if (!arg) - goto fail; - if (!left_item) - left_item = arg; - else if (current_exp) { - ret = add_right(current_exp, arg, error_str); - if (ret < 0) - goto fail; - left_item = NULL; - /* Not's only one one expression */ - if (not) { - arg = NULL; - if (current_op) - goto fail_print; - free(token); - *parg = current_exp; - return 0; - } - } else - goto fail_print; - arg = NULL; - break; - - case EVENT_DELIM: - if (*token == ',') { - show_error(error_str, - "Illegal token ','"); - goto fail; - } - - if (*token == '(') { - if (left_item) { - show_error(error_str, - "Open paren can not come after item"); - goto fail; - } - if (current_exp) { - show_error(error_str, - "Open paren can not come after expression"); - goto fail; - } - - ret = process_filter(event, &arg, error_str, 0); - if (ret != 1) { - if (ret == 0) - show_error(error_str, - "Unbalanced number of '('"); - goto fail; - } - ret = 0; - - /* A not wants just one expression */ - if (not) { - if (current_op) - goto fail_print; - *parg = arg; - return 0; - } - - if (current_op) - ret = add_right(current_op, arg, error_str); - else - current_exp = arg; - - if (ret < 0) - goto fail; - - } else { /* ')' */ - if (!current_op && !current_exp) - goto fail_print; - - /* Make sure everything is finished at this level */ - if (current_exp && !check_op_done(current_exp)) - goto fail_print; - if (current_op && !check_op_done(current_op)) - goto fail_print; - - if (current_op) - *parg = current_op; - else - *parg = current_exp; - return 1; - } - break; - - case EVENT_OP: - op_type = process_op(token, &btype, &ctype, &etype); - - /* All expect a left arg except for NOT */ - switch (op_type) { - case OP_BOOL: - /* Logic ops need a left expression */ - if (!current_exp && !current_op) - goto fail_print; - /* fall through */ - case OP_NOT: - /* logic only processes ops and exp */ - if (left_item) - goto fail_print; - break; - case OP_EXP: - case OP_CMP: - if (!left_item) - goto fail_print; - break; - case OP_NONE: - show_error(error_str, - "Unknown op token %s", token); - goto fail; - } - - ret = 0; - switch (op_type) { - case OP_BOOL: - arg = create_arg_op(btype); - if (current_op) - ret = add_left(arg, current_op); - else - ret = add_left(arg, current_exp); - current_op = arg; - current_exp = NULL; - break; - - case OP_NOT: - arg = create_arg_op(btype); - if (current_op) - ret = add_right(current_op, arg, error_str); - if (ret < 0) - goto fail; - current_exp = arg; - ret = process_filter(event, &arg, error_str, 1); - if (ret < 0) - goto fail; - ret = add_right(current_exp, arg, error_str); - if (ret < 0) - goto fail; - break; - - case OP_EXP: - case OP_CMP: - if (op_type == OP_EXP) - arg = create_arg_exp(etype); - else - arg = create_arg_cmp(ctype); - - if (current_op) - ret = add_right(current_op, arg, error_str); - if (ret < 0) - goto fail; - ret = add_left(arg, left_item); - if (ret < 0) { - arg = NULL; - goto fail_print; - } - current_exp = arg; - break; - default: - break; - } - arg = NULL; - if (ret < 0) - goto fail_print; - break; - case EVENT_NONE: - break; - default: - goto fail_print; - } - } while (type != EVENT_NONE); - - if (!current_op && !current_exp) - goto fail_print; - - if (!current_op) - current_op = current_exp; - - current_op = collapse_tree(current_op); - - *parg = current_op; - - return 0; - - fail_print: - show_error(error_str, "Syntax error"); - fail: - free_arg(current_op); - free_arg(current_exp); - free_arg(arg); - free(token); - return -1; -} - -static int -process_event(struct event_format *event, const char *filter_str, - struct filter_arg **parg, char **error_str) -{ - int ret; - - pevent_buffer_init(filter_str, strlen(filter_str)); - - ret = process_filter(event, parg, error_str, 0); - if (ret == 1) { - show_error(error_str, - "Unbalanced number of ')'"); - return -1; - } - if (ret < 0) - return ret; - - /* If parg is NULL, then make it into FALSE */ - if (!*parg) { - *parg = allocate_arg(); - (*parg)->type = FILTER_ARG_BOOLEAN; - (*parg)->boolean.value = FILTER_FALSE; - } - - return 0; -} - -static int filter_event(struct event_filter *filter, - struct event_format *event, - const char *filter_str, char **error_str) -{ - struct filter_type *filter_type; - struct filter_arg *arg; - int ret; - - if (filter_str) { - ret = process_event(event, filter_str, &arg, error_str); - if (ret < 0) - return ret; - - } else { - /* just add a TRUE arg */ - arg = allocate_arg(); - arg->type = FILTER_ARG_BOOLEAN; - arg->boolean.value = FILTER_TRUE; - } - - filter_type = add_filter_type(filter, event->id); - if (filter_type->filter) - free_arg(filter_type->filter); - filter_type->filter = arg; - - return 0; -} - -/** - * pevent_filter_add_filter_str - add a new filter - * @filter: the event filter to add to - * @filter_str: the filter string that contains the filter - * @error_str: string containing reason for failed filter - * - * Returns 0 if the filter was successfully added - * -1 if there was an error. - * - * On error, if @error_str points to a string pointer, - * it is set to the reason that the filter failed. - * This string must be freed with "free". - */ -int pevent_filter_add_filter_str(struct event_filter *filter, - const char *filter_str, - char **error_str) -{ - struct pevent *pevent = filter->pevent; - struct event_list *event; - struct event_list *events = NULL; - const char *filter_start; - const char *next_event; - char *this_event; - char *event_name = NULL; - char *sys_name = NULL; - char *sp; - int rtn = 0; - int len; - int ret; - - /* clear buffer to reset show error */ - pevent_buffer_init("", 0); - - if (error_str) - *error_str = NULL; - - filter_start = strchr(filter_str, ':'); - if (filter_start) - len = filter_start - filter_str; - else - len = strlen(filter_str); - - - do { - next_event = strchr(filter_str, ','); - if (next_event && - (!filter_start || next_event < filter_start)) - len = next_event - filter_str; - else if (filter_start) - len = filter_start - filter_str; - else - len = strlen(filter_str); - - this_event = malloc_or_die(len + 1); - memcpy(this_event, filter_str, len); - this_event[len] = 0; - - if (next_event) - next_event++; - - filter_str = next_event; - - sys_name = strtok_r(this_event, "/", &sp); - event_name = strtok_r(NULL, "/", &sp); - - if (!sys_name) { - show_error(error_str, "No filter found"); - /* This can only happen when events is NULL, but still */ - free_events(events); - free(this_event); - return -1; - } - - /* Find this event */ - ret = find_event(pevent, &events, strim(sys_name), strim(event_name)); - if (ret < 0) { - if (event_name) - show_error(error_str, - "No event found under '%s.%s'", - sys_name, event_name); - else - show_error(error_str, - "No event found under '%s'", - sys_name); - free_events(events); - free(this_event); - return -1; - } - free(this_event); - } while (filter_str); - - /* Skip the ':' */ - if (filter_start) - filter_start++; - - /* filter starts here */ - for (event = events; event; event = event->next) { - ret = filter_event(filter, event->event, filter_start, - error_str); - /* Failures are returned if a parse error happened */ - if (ret < 0) - rtn = ret; - - if (ret >= 0 && pevent->test_filters) { - char *test; - test = pevent_filter_make_string(filter, event->event->id); - printf(" '%s: %s'\n", event->event->name, test); - free(test); - } - } - - free_events(events); - - if (rtn >= 0 && pevent->test_filters) - exit(0); - - return rtn; -} - -static void free_filter_type(struct filter_type *filter_type) -{ - free_arg(filter_type->filter); -} - -/** - * pevent_filter_remove_event - remove a filter for an event - * @filter: the event filter to remove from - * @event_id: the event to remove a filter for - * - * Removes the filter saved for an event defined by @event_id - * from the @filter. - * - * Returns 1: if an event was removed - * 0: if the event was not found - */ -int pevent_filter_remove_event(struct event_filter *filter, - int event_id) -{ - struct filter_type *filter_type; - unsigned long len; - - if (!filter->filters) - return 0; - - filter_type = find_filter_type(filter, event_id); - - if (!filter_type) - return 0; - - free_filter_type(filter_type); - - /* The filter_type points into the event_filters array */ - len = (unsigned long)(filter->event_filters + filter->filters) - - (unsigned long)(filter_type + 1); - - memmove(filter_type, filter_type + 1, len); - filter->filters--; - - memset(&filter->event_filters[filter->filters], 0, - sizeof(*filter_type)); - - return 1; -} - -/** - * pevent_filter_reset - clear all filters in a filter - * @filter: the event filter to reset - * - * Removes all filters from a filter and resets it. - */ -void pevent_filter_reset(struct event_filter *filter) -{ - int i; - - for (i = 0; i < filter->filters; i++) - free_filter_type(&filter->event_filters[i]); - - free(filter->event_filters); - filter->filters = 0; - filter->event_filters = NULL; -} - -void pevent_filter_free(struct event_filter *filter) -{ - pevent_unref(filter->pevent); - - pevent_filter_reset(filter); - - free(filter); -} - -static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg); - -static int copy_filter_type(struct event_filter *filter, - struct event_filter *source, - struct filter_type *filter_type) -{ - struct filter_arg *arg; - struct event_format *event; - const char *sys; - const char *name; - char *str; - - /* Can't assume that the pevent's are the same */ - sys = filter_type->event->system; - name = filter_type->event->name; - event = pevent_find_event_by_name(filter->pevent, sys, name); - if (!event) - return -1; - - str = arg_to_str(source, filter_type->filter); - if (!str) - return -1; - - if (strcmp(str, "TRUE") == 0 || strcmp(str, "FALSE") == 0) { - /* Add trivial event */ - arg = allocate_arg(); - arg->type = FILTER_ARG_BOOLEAN; - if (strcmp(str, "TRUE") == 0) - arg->boolean.value = 1; - else - arg->boolean.value = 0; - - filter_type = add_filter_type(filter, event->id); - filter_type->filter = arg; - - free(str); - return 0; - } - - filter_event(filter, event, str, NULL); - free(str); - - return 0; -} - -/** - * pevent_filter_copy - copy a filter using another filter - * @dest - the filter to copy to - * @source - the filter to copy from - * - * Returns 0 on success and -1 if not all filters were copied - */ -int pevent_filter_copy(struct event_filter *dest, struct event_filter *source) -{ - int ret = 0; - int i; - - pevent_filter_reset(dest); - - for (i = 0; i < source->filters; i++) { - if (copy_filter_type(dest, source, &source->event_filters[i])) - ret = -1; - } - return ret; -} - - -/** - * pevent_update_trivial - update the trivial filters with the given filter - * @dest - the filter to update - * @source - the filter as the source of the update - * @type - the type of trivial filter to update. - * - * Scan dest for trivial events matching @type to replace with the source. - * - * Returns 0 on success and -1 if there was a problem updating, but - * events may have still been updated on error. - */ -int pevent_update_trivial(struct event_filter *dest, struct event_filter *source, - enum filter_trivial_type type) -{ - struct pevent *src_pevent; - struct pevent *dest_pevent; - struct event_format *event; - struct filter_type *filter_type; - struct filter_arg *arg; - char *str; - int i; - - src_pevent = source->pevent; - dest_pevent = dest->pevent; - - /* Do nothing if either of the filters has nothing to filter */ - if (!dest->filters || !source->filters) - return 0; - - for (i = 0; i < dest->filters; i++) { - filter_type = &dest->event_filters[i]; - arg = filter_type->filter; - if (arg->type != FILTER_ARG_BOOLEAN) - continue; - if ((arg->boolean.value && type == FILTER_TRIVIAL_FALSE) || - (!arg->boolean.value && type == FILTER_TRIVIAL_TRUE)) - continue; - - event = filter_type->event; - - if (src_pevent != dest_pevent) { - /* do a look up */ - event = pevent_find_event_by_name(src_pevent, - event->system, - event->name); - if (!event) - return -1; - } - - str = pevent_filter_make_string(source, event->id); - if (!str) - continue; - - /* Don't bother if the filter is trivial too */ - if (strcmp(str, "TRUE") != 0 && strcmp(str, "FALSE") != 0) - filter_event(dest, event, str, NULL); - free(str); - } - return 0; -} - -/** - * pevent_filter_clear_trivial - clear TRUE and FALSE filters - * @filter: the filter to remove trivial filters from - * @type: remove only true, false, or both - * - * Removes filters that only contain a TRUE or FALES boolean arg. - */ -void pevent_filter_clear_trivial(struct event_filter *filter, - enum filter_trivial_type type) -{ - struct filter_type *filter_type; - int count = 0; - int *ids = NULL; - int i; - - if (!filter->filters) - return; - - /* - * Two steps, first get all ids with trivial filters. - * then remove those ids. - */ - for (i = 0; i < filter->filters; i++) { - filter_type = &filter->event_filters[i]; - if (filter_type->filter->type != FILTER_ARG_BOOLEAN) - continue; - switch (type) { - case FILTER_TRIVIAL_FALSE: - if (filter_type->filter->boolean.value) - continue; - case FILTER_TRIVIAL_TRUE: - if (!filter_type->filter->boolean.value) - continue; - default: - break; - } - - ids = realloc(ids, sizeof(*ids) * (count + 1)); - if (!ids) - die("Can't allocate ids"); - ids[count++] = filter_type->event_id; - } - - if (!count) - return; - - for (i = 0; i < count; i++) - pevent_filter_remove_event(filter, ids[i]); - - free(ids); -} - -/** - * pevent_filter_event_has_trivial - return true event contains trivial filter - * @filter: the filter with the information - * @event_id: the id of the event to test - * @type: trivial type to test for (TRUE, FALSE, EITHER) - * - * Returns 1 if the event contains a matching trivial type - * otherwise 0. - */ -int pevent_filter_event_has_trivial(struct event_filter *filter, - int event_id, - enum filter_trivial_type type) -{ - struct filter_type *filter_type; - - if (!filter->filters) - return 0; - - filter_type = find_filter_type(filter, event_id); - - if (!filter_type) - return 0; - - if (filter_type->filter->type != FILTER_ARG_BOOLEAN) - return 0; - - switch (type) { - case FILTER_TRIVIAL_FALSE: - return !filter_type->filter->boolean.value; - - case FILTER_TRIVIAL_TRUE: - return filter_type->filter->boolean.value; - default: - return 1; - } -} - -static int test_filter(struct event_format *event, - struct filter_arg *arg, struct pevent_record *record); - -static const char * -get_comm(struct event_format *event, struct pevent_record *record) -{ - const char *comm; - int pid; - - pid = pevent_data_pid(event->pevent, record); - comm = pevent_data_comm_from_pid(event->pevent, pid); - return comm; -} - -static unsigned long long -get_value(struct event_format *event, - struct format_field *field, struct pevent_record *record) -{ - unsigned long long val; - - /* Handle our dummy "comm" field */ - if (field == &comm) { - const char *name; - - name = get_comm(event, record); - return (unsigned long)name; - } - - pevent_read_number_field(field, record->data, &val); - - if (!(field->flags & FIELD_IS_SIGNED)) - return val; - - switch (field->size) { - case 1: - return (char)val; - case 2: - return (short)val; - case 4: - return (int)val; - case 8: - return (long long)val; - } - return val; -} - -static unsigned long long -get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record); - -static unsigned long long -get_exp_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record) -{ - unsigned long long lval, rval; - - lval = get_arg_value(event, arg->exp.left, record); - rval = get_arg_value(event, arg->exp.right, record); - - switch (arg->exp.type) { - case FILTER_EXP_ADD: - return lval + rval; - - case FILTER_EXP_SUB: - return lval - rval; - - case FILTER_EXP_MUL: - return lval * rval; - - case FILTER_EXP_DIV: - return lval / rval; - - case FILTER_EXP_MOD: - return lval % rval; - - case FILTER_EXP_RSHIFT: - return lval >> rval; - - case FILTER_EXP_LSHIFT: - return lval << rval; - - case FILTER_EXP_AND: - return lval & rval; - - case FILTER_EXP_OR: - return lval | rval; - - case FILTER_EXP_XOR: - return lval ^ rval; - - case FILTER_EXP_NOT: - default: - die("error in exp"); - } - return 0; -} - -static unsigned long long -get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record) -{ - switch (arg->type) { - case FILTER_ARG_FIELD: - return get_value(event, arg->field.field, record); - - case FILTER_ARG_VALUE: - if (arg->value.type != FILTER_NUMBER) - die("must have number field!"); - return arg->value.val; - - case FILTER_ARG_EXP: - return get_exp_value(event, arg, record); - - default: - die("oops in filter"); - } - return 0; -} - -static int test_num(struct event_format *event, - struct filter_arg *arg, struct pevent_record *record) -{ - unsigned long long lval, rval; - - lval = get_arg_value(event, arg->num.left, record); - rval = get_arg_value(event, arg->num.right, record); - - switch (arg->num.type) { - case FILTER_CMP_EQ: - return lval == rval; - - case FILTER_CMP_NE: - return lval != rval; - - case FILTER_CMP_GT: - return lval > rval; - - case FILTER_CMP_LT: - return lval < rval; - - case FILTER_CMP_GE: - return lval >= rval; - - case FILTER_CMP_LE: - return lval <= rval; - - default: - /* ?? */ - return 0; - } -} - -static const char *get_field_str(struct filter_arg *arg, struct pevent_record *record) -{ - struct event_format *event; - struct pevent *pevent; - unsigned long long addr; - const char *val = NULL; - char hex[64]; - - /* If the field is not a string convert it */ - if (arg->str.field->flags & FIELD_IS_STRING) { - val = record->data + arg->str.field->offset; - - /* - * We need to copy the data since we can't be sure the field - * is null terminated. - */ - if (*(val + arg->str.field->size - 1)) { - /* copy it */ - memcpy(arg->str.buffer, val, arg->str.field->size); - /* the buffer is already NULL terminated */ - val = arg->str.buffer; - } - - } else { - event = arg->str.field->event; - pevent = event->pevent; - addr = get_value(event, arg->str.field, record); - - if (arg->str.field->flags & (FIELD_IS_POINTER | FIELD_IS_LONG)) - /* convert to a kernel symbol */ - val = pevent_find_function(pevent, addr); - - if (val == NULL) { - /* just use the hex of the string name */ - snprintf(hex, 64, "0x%llx", addr); - val = hex; - } - } - - return val; -} - -static int test_str(struct event_format *event, - struct filter_arg *arg, struct pevent_record *record) -{ - const char *val; - - if (arg->str.field == &comm) - val = get_comm(event, record); - else - val = get_field_str(arg, record); - - switch (arg->str.type) { - case FILTER_CMP_MATCH: - return strcmp(val, arg->str.val) == 0; - - case FILTER_CMP_NOT_MATCH: - return strcmp(val, arg->str.val) != 0; - - case FILTER_CMP_REGEX: - /* Returns zero on match */ - return !regexec(&arg->str.reg, val, 0, NULL, 0); - - case FILTER_CMP_NOT_REGEX: - return regexec(&arg->str.reg, val, 0, NULL, 0); - - default: - /* ?? */ - return 0; - } -} - -static int test_op(struct event_format *event, - struct filter_arg *arg, struct pevent_record *record) -{ - switch (arg->op.type) { - case FILTER_OP_AND: - return test_filter(event, arg->op.left, record) && - test_filter(event, arg->op.right, record); - - case FILTER_OP_OR: - return test_filter(event, arg->op.left, record) || - test_filter(event, arg->op.right, record); - - case FILTER_OP_NOT: - return !test_filter(event, arg->op.right, record); - - default: - /* ?? */ - return 0; - } -} - -static int test_filter(struct event_format *event, - struct filter_arg *arg, struct pevent_record *record) -{ - switch (arg->type) { - case FILTER_ARG_BOOLEAN: - /* easy case */ - return arg->boolean.value; - - case FILTER_ARG_OP: - return test_op(event, arg, record); - - case FILTER_ARG_NUM: - return test_num(event, arg, record); - - case FILTER_ARG_STR: - return test_str(event, arg, record); - - case FILTER_ARG_EXP: - case FILTER_ARG_VALUE: - case FILTER_ARG_FIELD: - /* - * Expressions, fields and values evaluate - * to true if they return non zero - */ - return !!get_arg_value(event, arg, record); - - default: - die("oops!"); - /* ?? */ - return 0; - } -} - -/** - * pevent_event_filtered - return true if event has filter - * @filter: filter struct with filter information - * @event_id: event id to test if filter exists - * - * Returns 1 if filter found for @event_id - * otherwise 0; - */ -int pevent_event_filtered(struct event_filter *filter, - int event_id) -{ - struct filter_type *filter_type; - - if (!filter->filters) - return 0; - - filter_type = find_filter_type(filter, event_id); - - return filter_type ? 1 : 0; -} - -/** - * pevent_filter_match - test if a record matches a filter - * @filter: filter struct with filter information - * @record: the record to test against the filter - * - * Returns: - * 1 - filter found for event and @record matches - * 0 - filter found for event and @record does not match - * -1 - no filter found for @record's event - * -2 - if no filters exist - */ -int pevent_filter_match(struct event_filter *filter, - struct pevent_record *record) -{ - struct pevent *pevent = filter->pevent; - struct filter_type *filter_type; - int event_id; - - if (!filter->filters) - return FILTER_NONE; - - event_id = pevent_data_type(pevent, record); - - filter_type = find_filter_type(filter, event_id); - - if (!filter_type) - return FILTER_NOEXIST; - - return test_filter(filter_type->event, filter_type->filter, record) ? - FILTER_MATCH : FILTER_MISS; -} - -static char *op_to_str(struct event_filter *filter, struct filter_arg *arg) -{ - char *str = NULL; - char *left = NULL; - char *right = NULL; - char *op = NULL; - int left_val = -1; - int right_val = -1; - int val; - int len; - - switch (arg->op.type) { - case FILTER_OP_AND: - op = "&&"; - /* fall through */ - case FILTER_OP_OR: - if (!op) - op = "||"; - - left = arg_to_str(filter, arg->op.left); - right = arg_to_str(filter, arg->op.right); - if (!left || !right) - break; - - /* Try to consolidate boolean values */ - if (strcmp(left, "TRUE") == 0) - left_val = 1; - else if (strcmp(left, "FALSE") == 0) - left_val = 0; - - if (strcmp(right, "TRUE") == 0) - right_val = 1; - else if (strcmp(right, "FALSE") == 0) - right_val = 0; - - if (left_val >= 0) { - if ((arg->op.type == FILTER_OP_AND && !left_val) || - (arg->op.type == FILTER_OP_OR && left_val)) { - /* Just return left value */ - str = left; - left = NULL; - break; - } - if (right_val >= 0) { - /* just evaluate this. */ - val = 0; - switch (arg->op.type) { - case FILTER_OP_AND: - val = left_val && right_val; - break; - case FILTER_OP_OR: - val = left_val || right_val; - break; - default: - break; - } - str = malloc_or_die(6); - if (val) - strcpy(str, "TRUE"); - else - strcpy(str, "FALSE"); - break; - } - } - if (right_val >= 0) { - if ((arg->op.type == FILTER_OP_AND && !right_val) || - (arg->op.type == FILTER_OP_OR && right_val)) { - /* Just return right value */ - str = right; - right = NULL; - break; - } - /* The right value is meaningless */ - str = left; - left = NULL; - break; - } - - len = strlen(left) + strlen(right) + strlen(op) + 10; - str = malloc_or_die(len); - snprintf(str, len, "(%s) %s (%s)", - left, op, right); - break; - - case FILTER_OP_NOT: - op = "!"; - right = arg_to_str(filter, arg->op.right); - if (!right) - break; - - /* See if we can consolidate */ - if (strcmp(right, "TRUE") == 0) - right_val = 1; - else if (strcmp(right, "FALSE") == 0) - right_val = 0; - if (right_val >= 0) { - /* just return the opposite */ - str = malloc_or_die(6); - if (right_val) - strcpy(str, "FALSE"); - else - strcpy(str, "TRUE"); - break; - } - len = strlen(right) + strlen(op) + 3; - str = malloc_or_die(len); - snprintf(str, len, "%s(%s)", op, right); - break; - - default: - /* ?? */ - break; - } - free(left); - free(right); - return str; -} - -static char *val_to_str(struct event_filter *filter, struct filter_arg *arg) -{ - char *str; - - str = malloc_or_die(30); - - snprintf(str, 30, "%lld", arg->value.val); - - return str; -} - -static char *field_to_str(struct event_filter *filter, struct filter_arg *arg) -{ - return strdup(arg->field.field->name); -} - -static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg) -{ - char *lstr; - char *rstr; - char *op; - char *str = NULL; - int len; - - lstr = arg_to_str(filter, arg->exp.left); - rstr = arg_to_str(filter, arg->exp.right); - if (!lstr || !rstr) - goto out; - - switch (arg->exp.type) { - case FILTER_EXP_ADD: - op = "+"; - break; - case FILTER_EXP_SUB: - op = "-"; - break; - case FILTER_EXP_MUL: - op = "*"; - break; - case FILTER_EXP_DIV: - op = "/"; - break; - case FILTER_EXP_MOD: - op = "%"; - break; - case FILTER_EXP_RSHIFT: - op = ">>"; - break; - case FILTER_EXP_LSHIFT: - op = "<<"; - break; - case FILTER_EXP_AND: - op = "&"; - break; - case FILTER_EXP_OR: - op = "|"; - break; - case FILTER_EXP_XOR: - op = "^"; - break; - default: - die("oops in exp"); - } - - len = strlen(op) + strlen(lstr) + strlen(rstr) + 4; - str = malloc_or_die(len); - snprintf(str, len, "%s %s %s", lstr, op, rstr); -out: - free(lstr); - free(rstr); - - return str; -} - -static char *num_to_str(struct event_filter *filter, struct filter_arg *arg) -{ - char *lstr; - char *rstr; - char *str = NULL; - char *op = NULL; - int len; - - lstr = arg_to_str(filter, arg->num.left); - rstr = arg_to_str(filter, arg->num.right); - if (!lstr || !rstr) - goto out; - - switch (arg->num.type) { - case FILTER_CMP_EQ: - op = "=="; - /* fall through */ - case FILTER_CMP_NE: - if (!op) - op = "!="; - /* fall through */ - case FILTER_CMP_GT: - if (!op) - op = ">"; - /* fall through */ - case FILTER_CMP_LT: - if (!op) - op = "<"; - /* fall through */ - case FILTER_CMP_GE: - if (!op) - op = ">="; - /* fall through */ - case FILTER_CMP_LE: - if (!op) - op = "<="; - - len = strlen(lstr) + strlen(op) + strlen(rstr) + 4; - str = malloc_or_die(len); - sprintf(str, "%s %s %s", lstr, op, rstr); - - break; - - default: - /* ?? */ - break; - } - -out: - free(lstr); - free(rstr); - return str; -} - -static char *str_to_str(struct event_filter *filter, struct filter_arg *arg) -{ - char *str = NULL; - char *op = NULL; - int len; - - switch (arg->str.type) { - case FILTER_CMP_MATCH: - op = "=="; - /* fall through */ - case FILTER_CMP_NOT_MATCH: - if (!op) - op = "!="; - /* fall through */ - case FILTER_CMP_REGEX: - if (!op) - op = "=~"; - /* fall through */ - case FILTER_CMP_NOT_REGEX: - if (!op) - op = "!~"; - - len = strlen(arg->str.field->name) + strlen(op) + - strlen(arg->str.val) + 6; - str = malloc_or_die(len); - snprintf(str, len, "%s %s \"%s\"", - arg->str.field->name, - op, arg->str.val); - break; - - default: - /* ?? */ - break; - } - return str; -} - -static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg) -{ - char *str; - - switch (arg->type) { - case FILTER_ARG_BOOLEAN: - str = malloc_or_die(6); - if (arg->boolean.value) - strcpy(str, "TRUE"); - else - strcpy(str, "FALSE"); - return str; - - case FILTER_ARG_OP: - return op_to_str(filter, arg); - - case FILTER_ARG_NUM: - return num_to_str(filter, arg); - - case FILTER_ARG_STR: - return str_to_str(filter, arg); - - case FILTER_ARG_VALUE: - return val_to_str(filter, arg); - - case FILTER_ARG_FIELD: - return field_to_str(filter, arg); - - case FILTER_ARG_EXP: - return exp_to_str(filter, arg); - - default: - /* ?? */ - return NULL; - } - -} - -/** - * pevent_filter_make_string - return a string showing the filter - * @filter: filter struct with filter information - * @event_id: the event id to return the filter string with - * - * Returns a string that displays the filter contents. - * This string must be freed with free(str). - * NULL is returned if no filter is found. - */ -char * -pevent_filter_make_string(struct event_filter *filter, int event_id) -{ - struct filter_type *filter_type; - - if (!filter->filters) - return NULL; - - filter_type = find_filter_type(filter, event_id); - - if (!filter_type) - return NULL; - - return arg_to_str(filter, filter_type->filter); -} - -/** - * pevent_filter_compare - compare two filters and return if they are the same - * @filter1: Filter to compare with @filter2 - * @filter2: Filter to compare with @filter1 - * - * Returns: - * 1 if the two filters hold the same content. - * 0 if they do not. - */ -int pevent_filter_compare(struct event_filter *filter1, struct event_filter *filter2) -{ - struct filter_type *filter_type1; - struct filter_type *filter_type2; - char *str1, *str2; - int result; - int i; - - /* Do the easy checks first */ - if (filter1->filters != filter2->filters) - return 0; - if (!filter1->filters && !filter2->filters) - return 1; - - /* - * Now take a look at each of the events to see if they have the same - * filters to them. - */ - for (i = 0; i < filter1->filters; i++) { - filter_type1 = &filter1->event_filters[i]; - filter_type2 = find_filter_type(filter2, filter_type1->event_id); - if (!filter_type2) - break; - if (filter_type1->filter->type != filter_type2->filter->type) - break; - switch (filter_type1->filter->type) { - case FILTER_TRIVIAL_FALSE: - case FILTER_TRIVIAL_TRUE: - /* trivial types just need the type compared */ - continue; - default: - break; - } - /* The best way to compare complex filters is with strings */ - str1 = arg_to_str(filter1, filter_type1->filter); - str2 = arg_to_str(filter2, filter_type2->filter); - if (str1 && str2) - result = strcmp(str1, str2) != 0; - else - /* bail out if allocation fails */ - result = 1; - - free(str1); - free(str2); - if (result) - break; - } - - if (i < filter1->filters) - return 0; - return 1; -} - |