|
|
@@ -38,41 +38,31 @@ struct event_list {
|
|
|
struct event_format *event;
|
|
|
};
|
|
|
|
|
|
-#define MAX_ERR_STR_SIZE 256
|
|
|
-
|
|
|
-static void show_error(char **error_str, const char *fmt, ...)
|
|
|
+static void show_error(char *error_buf, 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';
|
|
|
+ strcpy(error_buf, input);
|
|
|
+ error_buf[len] = '\n';
|
|
|
for (i = 1; i < len && i < index; i++)
|
|
|
- error[len+i] = ' ';
|
|
|
- error[len + i] = '^';
|
|
|
- error[len + i + 1] = '\n';
|
|
|
+ error_buf[len+i] = ' ';
|
|
|
+ error_buf[len + i] = '^';
|
|
|
+ error_buf[len + i + 1] = '\n';
|
|
|
len += i+2;
|
|
|
}
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
- vsnprintf(error + len, MAX_ERR_STR_SIZE, fmt, ap);
|
|
|
+ vsnprintf(error_buf + len, PEVENT_FILTER_ERROR_BUFSZ - len, fmt, ap);
|
|
|
va_end(ap);
|
|
|
-
|
|
|
- *error_str = error;
|
|
|
}
|
|
|
|
|
|
static void free_token(char *token)
|
|
|
@@ -95,7 +85,11 @@ static enum event_type read_token(char **tok)
|
|
|
(strcmp(token, "=") == 0 || strcmp(token, "!") == 0) &&
|
|
|
pevent_peek_char() == '~') {
|
|
|
/* append it */
|
|
|
- *tok = malloc_or_die(3);
|
|
|
+ *tok = malloc(3);
|
|
|
+ if (*tok == NULL) {
|
|
|
+ free_token(token);
|
|
|
+ return EVENT_ERROR;
|
|
|
+ }
|
|
|
sprintf(*tok, "%c%c", *token, '~');
|
|
|
free_token(token);
|
|
|
/* Now remove the '~' from the buffer */
|
|
|
@@ -147,11 +141,13 @@ add_filter_type(struct event_filter *filter, int 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");
|
|
|
+ filter_type = realloc(filter->event_filters,
|
|
|
+ sizeof(*filter->event_filters) *
|
|
|
+ (filter->filters + 1));
|
|
|
+ if (!filter_type)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ filter->event_filters = filter_type;
|
|
|
|
|
|
for (i = 0; i < filter->filters; i++) {
|
|
|
if (filter->event_filters[i].event_id > id)
|
|
|
@@ -182,7 +178,10 @@ struct event_filter *pevent_filter_alloc(struct pevent *pevent)
|
|
|
{
|
|
|
struct event_filter *filter;
|
|
|
|
|
|
- filter = malloc_or_die(sizeof(*filter));
|
|
|
+ filter = malloc(sizeof(*filter));
|
|
|
+ if (filter == NULL)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
memset(filter, 0, sizeof(*filter));
|
|
|
filter->pevent = pevent;
|
|
|
pevent_ref(pevent);
|
|
|
@@ -192,12 +191,7 @@ struct event_filter *pevent_filter_alloc(struct pevent *pevent)
|
|
|
|
|
|
static struct filter_arg *allocate_arg(void)
|
|
|
{
|
|
|
- struct filter_arg *arg;
|
|
|
-
|
|
|
- arg = malloc_or_die(sizeof(*arg));
|
|
|
- memset(arg, 0, sizeof(*arg));
|
|
|
-
|
|
|
- return arg;
|
|
|
+ return calloc(1, sizeof(struct filter_arg));
|
|
|
}
|
|
|
|
|
|
static void free_arg(struct filter_arg *arg)
|
|
|
@@ -242,15 +236,19 @@ static void free_arg(struct filter_arg *arg)
|
|
|
free(arg);
|
|
|
}
|
|
|
|
|
|
-static void add_event(struct event_list **events,
|
|
|
+static int add_event(struct event_list **events,
|
|
|
struct event_format *event)
|
|
|
{
|
|
|
struct event_list *list;
|
|
|
|
|
|
- list = malloc_or_die(sizeof(*list));
|
|
|
+ list = malloc(sizeof(*list));
|
|
|
+ if (list == NULL)
|
|
|
+ return -1;
|
|
|
+
|
|
|
list->next = *events;
|
|
|
*events = list;
|
|
|
list->event = event;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
static int event_match(struct event_format *event,
|
|
|
@@ -265,7 +263,7 @@ static int event_match(struct event_format *event,
|
|
|
!regexec(ereg, event->name, 0, NULL, 0);
|
|
|
}
|
|
|
|
|
|
-static int
|
|
|
+static enum pevent_errno
|
|
|
find_event(struct pevent *pevent, struct event_list **events,
|
|
|
char *sys_name, char *event_name)
|
|
|
{
|
|
|
@@ -273,6 +271,7 @@ find_event(struct pevent *pevent, struct event_list **events,
|
|
|
regex_t ereg;
|
|
|
regex_t sreg;
|
|
|
int match = 0;
|
|
|
+ int fail = 0;
|
|
|
char *reg;
|
|
|
int ret;
|
|
|
int i;
|
|
|
@@ -283,23 +282,31 @@ find_event(struct pevent *pevent, struct event_list **events,
|
|
|
sys_name = NULL;
|
|
|
}
|
|
|
|
|
|
- reg = malloc_or_die(strlen(event_name) + 3);
|
|
|
+ reg = malloc(strlen(event_name) + 3);
|
|
|
+ if (reg == NULL)
|
|
|
+ return PEVENT_ERRNO__MEM_ALLOC_FAILED;
|
|
|
+
|
|
|
sprintf(reg, "^%s$", event_name);
|
|
|
|
|
|
ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB);
|
|
|
free(reg);
|
|
|
|
|
|
if (ret)
|
|
|
- return -1;
|
|
|
+ return PEVENT_ERRNO__INVALID_EVENT_NAME;
|
|
|
|
|
|
if (sys_name) {
|
|
|
- reg = malloc_or_die(strlen(sys_name) + 3);
|
|
|
+ reg = malloc(strlen(sys_name) + 3);
|
|
|
+ if (reg == NULL) {
|
|
|
+ regfree(&ereg);
|
|
|
+ return PEVENT_ERRNO__MEM_ALLOC_FAILED;
|
|
|
+ }
|
|
|
+
|
|
|
sprintf(reg, "^%s$", sys_name);
|
|
|
ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB);
|
|
|
free(reg);
|
|
|
if (ret) {
|
|
|
regfree(&ereg);
|
|
|
- return -1;
|
|
|
+ return PEVENT_ERRNO__INVALID_EVENT_NAME;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -307,7 +314,10 @@ find_event(struct pevent *pevent, struct event_list **events,
|
|
|
event = pevent->events[i];
|
|
|
if (event_match(event, sys_name ? &sreg : NULL, &ereg)) {
|
|
|
match = 1;
|
|
|
- add_event(events, event);
|
|
|
+ if (add_event(events, event) < 0) {
|
|
|
+ fail = 1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -316,7 +326,9 @@ find_event(struct pevent *pevent, struct event_list **events,
|
|
|
regfree(&sreg);
|
|
|
|
|
|
if (!match)
|
|
|
- return -1;
|
|
|
+ return PEVENT_ERRNO__EVENT_NOT_FOUND;
|
|
|
+ if (fail)
|
|
|
+ return PEVENT_ERRNO__MEM_ALLOC_FAILED;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
@@ -332,14 +344,18 @@ static void free_events(struct event_list *events)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static struct filter_arg *
|
|
|
+static enum pevent_errno
|
|
|
create_arg_item(struct event_format *event, const char *token,
|
|
|
- enum event_type type, char **error_str)
|
|
|
+ enum event_type type, struct filter_arg **parg, char *error_str)
|
|
|
{
|
|
|
struct format_field *field;
|
|
|
struct filter_arg *arg;
|
|
|
|
|
|
arg = allocate_arg();
|
|
|
+ if (arg == NULL) {
|
|
|
+ show_error(error_str, "failed to allocate filter arg");
|
|
|
+ return PEVENT_ERRNO__MEM_ALLOC_FAILED;
|
|
|
+ }
|
|
|
|
|
|
switch (type) {
|
|
|
|
|
|
@@ -349,8 +365,11 @@ create_arg_item(struct event_format *event, const char *token,
|
|
|
arg->value.type =
|
|
|
type == EVENT_DQUOTE ? FILTER_STRING : FILTER_CHAR;
|
|
|
arg->value.str = strdup(token);
|
|
|
- if (!arg->value.str)
|
|
|
- die("malloc string");
|
|
|
+ if (!arg->value.str) {
|
|
|
+ free_arg(arg);
|
|
|
+ show_error(error_str, "failed to allocate string filter arg");
|
|
|
+ return PEVENT_ERRNO__MEM_ALLOC_FAILED;
|
|
|
+ }
|
|
|
break;
|
|
|
case EVENT_ITEM:
|
|
|
/* if it is a number, then convert it */
|
|
|
@@ -377,11 +396,11 @@ create_arg_item(struct event_format *event, const char *token,
|
|
|
break;
|
|
|
default:
|
|
|
free_arg(arg);
|
|
|
- show_error(error_str, "expected a value but found %s",
|
|
|
- token);
|
|
|
- return NULL;
|
|
|
+ show_error(error_str, "expected a value but found %s", token);
|
|
|
+ return PEVENT_ERRNO__UNEXPECTED_TYPE;
|
|
|
}
|
|
|
- return arg;
|
|
|
+ *parg = arg;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
static struct filter_arg *
|
|
|
@@ -390,6 +409,9 @@ create_arg_op(enum filter_op_type btype)
|
|
|
struct filter_arg *arg;
|
|
|
|
|
|
arg = allocate_arg();
|
|
|
+ if (!arg)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
arg->type = FILTER_ARG_OP;
|
|
|
arg->op.type = btype;
|
|
|
|
|
|
@@ -402,6 +424,9 @@ create_arg_exp(enum filter_exp_type etype)
|
|
|
struct filter_arg *arg;
|
|
|
|
|
|
arg = allocate_arg();
|
|
|
+ if (!arg)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
arg->type = FILTER_ARG_EXP;
|
|
|
arg->op.type = etype;
|
|
|
|
|
|
@@ -414,6 +439,9 @@ create_arg_cmp(enum filter_exp_type etype)
|
|
|
struct filter_arg *arg;
|
|
|
|
|
|
arg = allocate_arg();
|
|
|
+ if (!arg)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
/* Use NUM and change if necessary */
|
|
|
arg->type = FILTER_ARG_NUM;
|
|
|
arg->op.type = etype;
|
|
|
@@ -421,8 +449,8 @@ create_arg_cmp(enum filter_exp_type etype)
|
|
|
return arg;
|
|
|
}
|
|
|
|
|
|
-static int add_right(struct filter_arg *op, struct filter_arg *arg,
|
|
|
- char **error_str)
|
|
|
+static enum pevent_errno
|
|
|
+add_right(struct filter_arg *op, struct filter_arg *arg, char *error_str)
|
|
|
{
|
|
|
struct filter_arg *left;
|
|
|
char *str;
|
|
|
@@ -453,9 +481,8 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg,
|
|
|
case FILTER_ARG_FIELD:
|
|
|
break;
|
|
|
default:
|
|
|
- show_error(error_str,
|
|
|
- "Illegal rvalue");
|
|
|
- return -1;
|
|
|
+ show_error(error_str, "Illegal rvalue");
|
|
|
+ return PEVENT_ERRNO__ILLEGAL_RVALUE;
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
@@ -502,7 +529,7 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg,
|
|
|
if (left->type != FILTER_ARG_FIELD) {
|
|
|
show_error(error_str,
|
|
|
"Illegal lvalue for string comparison");
|
|
|
- return -1;
|
|
|
+ return PEVENT_ERRNO__ILLEGAL_LVALUE;
|
|
|
}
|
|
|
|
|
|
/* Make sure this is a valid string compare */
|
|
|
@@ -521,25 +548,31 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg,
|
|
|
show_error(error_str,
|
|
|
"RegEx '%s' did not compute",
|
|
|
str);
|
|
|
- return -1;
|
|
|
+ return PEVENT_ERRNO__INVALID_REGEX;
|
|
|
}
|
|
|
break;
|
|
|
default:
|
|
|
show_error(error_str,
|
|
|
"Illegal comparison for string");
|
|
|
- return -1;
|
|
|
+ return PEVENT_ERRNO__ILLEGAL_STRING_CMP;
|
|
|
}
|
|
|
|
|
|
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");
|
|
|
+ if (!op->str.val) {
|
|
|
+ show_error(error_str, "Failed to allocate string filter");
|
|
|
+ return PEVENT_ERRNO__MEM_ALLOC_FAILED;
|
|
|
+ }
|
|
|
/*
|
|
|
* Need a buffer to copy data for tests
|
|
|
*/
|
|
|
- op->str.buffer = malloc_or_die(op->str.field->size + 1);
|
|
|
+ op->str.buffer = malloc(op->str.field->size + 1);
|
|
|
+ if (!op->str.buffer) {
|
|
|
+ show_error(error_str, "Failed to allocate string filter");
|
|
|
+ return PEVENT_ERRNO__MEM_ALLOC_FAILED;
|
|
|
+ }
|
|
|
/* Null terminate this buffer */
|
|
|
op->str.buffer[op->str.field->size] = 0;
|
|
|
|
|
|
@@ -557,7 +590,7 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg,
|
|
|
case FILTER_CMP_NOT_REGEX:
|
|
|
show_error(error_str,
|
|
|
"Op not allowed with integers");
|
|
|
- return -1;
|
|
|
+ return PEVENT_ERRNO__ILLEGAL_INTEGER_CMP;
|
|
|
|
|
|
default:
|
|
|
break;
|
|
|
@@ -577,9 +610,8 @@ static int add_right(struct filter_arg *op, struct filter_arg *arg,
|
|
|
return 0;
|
|
|
|
|
|
out_fail:
|
|
|
- show_error(error_str,
|
|
|
- "Syntax error");
|
|
|
- return -1;
|
|
|
+ show_error(error_str, "Syntax error");
|
|
|
+ return PEVENT_ERRNO__SYNTAX_ERROR;
|
|
|
}
|
|
|
|
|
|
static struct filter_arg *
|
|
|
@@ -592,7 +624,7 @@ rotate_op_right(struct filter_arg *a, struct filter_arg *b)
|
|
|
return arg;
|
|
|
}
|
|
|
|
|
|
-static int add_left(struct filter_arg *op, struct filter_arg *arg)
|
|
|
+static enum pevent_errno add_left(struct filter_arg *op, struct filter_arg *arg)
|
|
|
{
|
|
|
switch (op->type) {
|
|
|
case FILTER_ARG_EXP:
|
|
|
@@ -611,11 +643,11 @@ static int add_left(struct filter_arg *op, struct filter_arg *arg)
|
|
|
/* left arg of compares must be a field */
|
|
|
if (arg->type != FILTER_ARG_FIELD &&
|
|
|
arg->type != FILTER_ARG_BOOLEAN)
|
|
|
- return -1;
|
|
|
+ return PEVENT_ERRNO__INVALID_ARG_TYPE;
|
|
|
op->num.left = arg;
|
|
|
break;
|
|
|
default:
|
|
|
- return -1;
|
|
|
+ return PEVENT_ERRNO__INVALID_ARG_TYPE;
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
@@ -728,15 +760,18 @@ enum filter_vals {
|
|
|
FILTER_VAL_TRUE,
|
|
|
};
|
|
|
|
|
|
-void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child,
|
|
|
- struct filter_arg *arg)
|
|
|
+static enum pevent_errno
|
|
|
+reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child,
|
|
|
+ struct filter_arg *arg, char *error_str)
|
|
|
{
|
|
|
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");
|
|
|
+ arg->type != FILTER_ARG_OP) {
|
|
|
+ show_error(error_str, "can not reparent other than OP");
|
|
|
+ return PEVENT_ERRNO__REPARENT_NOT_OP;
|
|
|
+ }
|
|
|
|
|
|
/* Get the sibling */
|
|
|
if (old_child->op.right == arg) {
|
|
|
@@ -745,8 +780,10 @@ void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child,
|
|
|
} 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");
|
|
|
+ } else {
|
|
|
+ show_error(error_str, "Error in reparent op, find other child");
|
|
|
+ return PEVENT_ERRNO__REPARENT_FAILED;
|
|
|
+ }
|
|
|
|
|
|
/* Detach arg from old_child */
|
|
|
*ptr = NULL;
|
|
|
@@ -757,23 +794,29 @@ void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child,
|
|
|
*parent = *arg;
|
|
|
/* Free arg without recussion */
|
|
|
free(arg);
|
|
|
- return;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
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");
|
|
|
+ else {
|
|
|
+ show_error(error_str, "Error in reparent op");
|
|
|
+ return PEVENT_ERRNO__REPARENT_FAILED;
|
|
|
+ }
|
|
|
+
|
|
|
*ptr = arg;
|
|
|
|
|
|
free_arg(old_child);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg)
|
|
|
+/* Returns either filter_vals (success) or pevent_errno (failfure) */
|
|
|
+static int test_arg(struct filter_arg *parent, struct filter_arg *arg,
|
|
|
+ char *error_str)
|
|
|
{
|
|
|
- enum filter_vals lval, rval;
|
|
|
+ int lval, rval;
|
|
|
|
|
|
switch (arg->type) {
|
|
|
|
|
|
@@ -788,63 +831,68 @@ enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg)
|
|
|
return FILTER_VAL_NORM;
|
|
|
|
|
|
case FILTER_ARG_EXP:
|
|
|
- lval = test_arg(arg, arg->exp.left);
|
|
|
+ lval = test_arg(arg, arg->exp.left, error_str);
|
|
|
if (lval != FILTER_VAL_NORM)
|
|
|
return lval;
|
|
|
- rval = test_arg(arg, arg->exp.right);
|
|
|
+ rval = test_arg(arg, arg->exp.right, error_str);
|
|
|
if (rval != FILTER_VAL_NORM)
|
|
|
return rval;
|
|
|
return FILTER_VAL_NORM;
|
|
|
|
|
|
case FILTER_ARG_NUM:
|
|
|
- lval = test_arg(arg, arg->num.left);
|
|
|
+ lval = test_arg(arg, arg->num.left, error_str);
|
|
|
if (lval != FILTER_VAL_NORM)
|
|
|
return lval;
|
|
|
- rval = test_arg(arg, arg->num.right);
|
|
|
+ rval = test_arg(arg, arg->num.right, error_str);
|
|
|
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);
|
|
|
+ lval = test_arg(arg, arg->op.left, error_str);
|
|
|
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);
|
|
|
+ rval = test_arg(arg, arg->op.right, error_str);
|
|
|
if (rval != FILTER_VAL_NORM)
|
|
|
return rval;
|
|
|
|
|
|
- reparent_op_arg(parent, arg, arg->op.right);
|
|
|
- return FILTER_VAL_NORM;
|
|
|
+ return reparent_op_arg(parent, arg, arg->op.right,
|
|
|
+ error_str);
|
|
|
|
|
|
case FILTER_VAL_FALSE:
|
|
|
if (arg->op.type == FILTER_OP_AND)
|
|
|
return FILTER_VAL_FALSE;
|
|
|
- rval = test_arg(arg, arg->op.right);
|
|
|
+ rval = test_arg(arg, arg->op.right, error_str);
|
|
|
if (rval != FILTER_VAL_NORM)
|
|
|
return rval;
|
|
|
|
|
|
- reparent_op_arg(parent, arg, arg->op.right);
|
|
|
- return FILTER_VAL_NORM;
|
|
|
+ return reparent_op_arg(parent, arg, arg->op.right,
|
|
|
+ error_str);
|
|
|
+
|
|
|
+ default:
|
|
|
+ return lval;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- rval = test_arg(arg, arg->op.right);
|
|
|
+ rval = test_arg(arg, arg->op.right, error_str);
|
|
|
switch (rval) {
|
|
|
case FILTER_VAL_NORM:
|
|
|
+ default:
|
|
|
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;
|
|
|
+ return reparent_op_arg(parent, arg, arg->op.left,
|
|
|
+ error_str);
|
|
|
|
|
|
case FILTER_VAL_FALSE:
|
|
|
if (arg->op.type == FILTER_OP_AND)
|
|
|
@@ -852,41 +900,56 @@ enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg)
|
|
|
if (arg->op.type == FILTER_OP_NOT)
|
|
|
return FILTER_VAL_TRUE;
|
|
|
|
|
|
- reparent_op_arg(parent, arg, arg->op.left);
|
|
|
- return FILTER_VAL_NORM;
|
|
|
+ return reparent_op_arg(parent, arg, arg->op.left,
|
|
|
+ error_str);
|
|
|
}
|
|
|
|
|
|
- return FILTER_VAL_NORM;
|
|
|
+ return rval;
|
|
|
default:
|
|
|
- die("bad arg in filter tree");
|
|
|
+ show_error(error_str, "bad arg in filter tree");
|
|
|
+ return PEVENT_ERRNO__BAD_FILTER_ARG;
|
|
|
}
|
|
|
return FILTER_VAL_NORM;
|
|
|
}
|
|
|
|
|
|
/* Remove any unknown event fields */
|
|
|
-static struct filter_arg *collapse_tree(struct filter_arg *arg)
|
|
|
+static int collapse_tree(struct filter_arg *arg,
|
|
|
+ struct filter_arg **arg_collapsed, char *error_str)
|
|
|
{
|
|
|
- enum filter_vals ret;
|
|
|
+ int ret;
|
|
|
|
|
|
- ret = test_arg(arg, arg);
|
|
|
+ ret = test_arg(arg, arg, error_str);
|
|
|
switch (ret) {
|
|
|
case FILTER_VAL_NORM:
|
|
|
- return arg;
|
|
|
+ break;
|
|
|
|
|
|
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;
|
|
|
+ if (arg) {
|
|
|
+ arg->type = FILTER_ARG_BOOLEAN;
|
|
|
+ arg->boolean.value = ret == FILTER_VAL_TRUE;
|
|
|
+ } else {
|
|
|
+ show_error(error_str, "Failed to allocate filter arg");
|
|
|
+ ret = PEVENT_ERRNO__MEM_ALLOC_FAILED;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ /* test_arg() already set the error_str */
|
|
|
+ free_arg(arg);
|
|
|
+ arg = NULL;
|
|
|
+ break;
|
|
|
}
|
|
|
|
|
|
- return arg;
|
|
|
+ *arg_collapsed = arg;
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
-static int
|
|
|
+static enum pevent_errno
|
|
|
process_filter(struct event_format *event, struct filter_arg **parg,
|
|
|
- char **error_str, int not)
|
|
|
+ char *error_str, int not)
|
|
|
{
|
|
|
enum event_type type;
|
|
|
char *token = NULL;
|
|
|
@@ -898,7 +961,7 @@ process_filter(struct event_format *event, struct filter_arg **parg,
|
|
|
enum filter_op_type btype;
|
|
|
enum filter_exp_type etype;
|
|
|
enum filter_cmp_type ctype;
|
|
|
- int ret;
|
|
|
+ enum pevent_errno ret;
|
|
|
|
|
|
*parg = NULL;
|
|
|
|
|
|
@@ -909,8 +972,8 @@ process_filter(struct event_format *event, struct filter_arg **parg,
|
|
|
case EVENT_SQUOTE:
|
|
|
case EVENT_DQUOTE:
|
|
|
case EVENT_ITEM:
|
|
|
- arg = create_arg_item(event, token, type, error_str);
|
|
|
- if (!arg)
|
|
|
+ ret = create_arg_item(event, token, type, &arg, error_str);
|
|
|
+ if (ret < 0)
|
|
|
goto fail;
|
|
|
if (!left_item)
|
|
|
left_item = arg;
|
|
|
@@ -923,20 +986,20 @@ process_filter(struct event_format *event, struct filter_arg **parg,
|
|
|
if (not) {
|
|
|
arg = NULL;
|
|
|
if (current_op)
|
|
|
- goto fail_print;
|
|
|
+ goto fail_syntax;
|
|
|
free(token);
|
|
|
*parg = current_exp;
|
|
|
return 0;
|
|
|
}
|
|
|
} else
|
|
|
- goto fail_print;
|
|
|
+ goto fail_syntax;
|
|
|
arg = NULL;
|
|
|
break;
|
|
|
|
|
|
case EVENT_DELIM:
|
|
|
if (*token == ',') {
|
|
|
- show_error(error_str,
|
|
|
- "Illegal token ','");
|
|
|
+ show_error(error_str, "Illegal token ','");
|
|
|
+ ret = PEVENT_ERRNO__ILLEGAL_TOKEN;
|
|
|
goto fail;
|
|
|
}
|
|
|
|
|
|
@@ -944,19 +1007,23 @@ process_filter(struct event_format *event, struct filter_arg **parg,
|
|
|
if (left_item) {
|
|
|
show_error(error_str,
|
|
|
"Open paren can not come after item");
|
|
|
+ ret = PEVENT_ERRNO__INVALID_PAREN;
|
|
|
goto fail;
|
|
|
}
|
|
|
if (current_exp) {
|
|
|
show_error(error_str,
|
|
|
"Open paren can not come after expression");
|
|
|
+ ret = PEVENT_ERRNO__INVALID_PAREN;
|
|
|
goto fail;
|
|
|
}
|
|
|
|
|
|
ret = process_filter(event, &arg, error_str, 0);
|
|
|
- if (ret != 1) {
|
|
|
- if (ret == 0)
|
|
|
+ if (ret != PEVENT_ERRNO__UNBALANCED_PAREN) {
|
|
|
+ if (ret == 0) {
|
|
|
show_error(error_str,
|
|
|
"Unbalanced number of '('");
|
|
|
+ ret = PEVENT_ERRNO__UNBALANCED_PAREN;
|
|
|
+ }
|
|
|
goto fail;
|
|
|
}
|
|
|
ret = 0;
|
|
|
@@ -964,7 +1031,7 @@ process_filter(struct event_format *event, struct filter_arg **parg,
|
|
|
/* A not wants just one expression */
|
|
|
if (not) {
|
|
|
if (current_op)
|
|
|
- goto fail_print;
|
|
|
+ goto fail_syntax;
|
|
|
*parg = arg;
|
|
|
return 0;
|
|
|
}
|
|
|
@@ -979,19 +1046,19 @@ process_filter(struct event_format *event, struct filter_arg **parg,
|
|
|
|
|
|
} else { /* ')' */
|
|
|
if (!current_op && !current_exp)
|
|
|
- goto fail_print;
|
|
|
+ goto fail_syntax;
|
|
|
|
|
|
/* Make sure everything is finished at this level */
|
|
|
if (current_exp && !check_op_done(current_exp))
|
|
|
- goto fail_print;
|
|
|
+ goto fail_syntax;
|
|
|
if (current_op && !check_op_done(current_op))
|
|
|
- goto fail_print;
|
|
|
+ goto fail_syntax;
|
|
|
|
|
|
if (current_op)
|
|
|
*parg = current_op;
|
|
|
else
|
|
|
*parg = current_exp;
|
|
|
- return 1;
|
|
|
+ return PEVENT_ERRNO__UNBALANCED_PAREN;
|
|
|
}
|
|
|
break;
|
|
|
|
|
|
@@ -1003,21 +1070,22 @@ process_filter(struct event_format *event, struct filter_arg **parg,
|
|
|
case OP_BOOL:
|
|
|
/* Logic ops need a left expression */
|
|
|
if (!current_exp && !current_op)
|
|
|
- goto fail_print;
|
|
|
+ goto fail_syntax;
|
|
|
/* fall through */
|
|
|
case OP_NOT:
|
|
|
/* logic only processes ops and exp */
|
|
|
if (left_item)
|
|
|
- goto fail_print;
|
|
|
+ goto fail_syntax;
|
|
|
break;
|
|
|
case OP_EXP:
|
|
|
case OP_CMP:
|
|
|
if (!left_item)
|
|
|
- goto fail_print;
|
|
|
+ goto fail_syntax;
|
|
|
break;
|
|
|
case OP_NONE:
|
|
|
show_error(error_str,
|
|
|
"Unknown op token %s", token);
|
|
|
+ ret = PEVENT_ERRNO__UNKNOWN_TOKEN;
|
|
|
goto fail;
|
|
|
}
|
|
|
|
|
|
@@ -1025,6 +1093,8 @@ process_filter(struct event_format *event, struct filter_arg **parg,
|
|
|
switch (op_type) {
|
|
|
case OP_BOOL:
|
|
|
arg = create_arg_op(btype);
|
|
|
+ if (arg == NULL)
|
|
|
+ goto fail_alloc;
|
|
|
if (current_op)
|
|
|
ret = add_left(arg, current_op);
|
|
|
else
|
|
|
@@ -1035,6 +1105,8 @@ process_filter(struct event_format *event, struct filter_arg **parg,
|
|
|
|
|
|
case OP_NOT:
|
|
|
arg = create_arg_op(btype);
|
|
|
+ if (arg == NULL)
|
|
|
+ goto fail_alloc;
|
|
|
if (current_op)
|
|
|
ret = add_right(current_op, arg, error_str);
|
|
|
if (ret < 0)
|
|
|
@@ -1054,6 +1126,8 @@ process_filter(struct event_format *event, struct filter_arg **parg,
|
|
|
arg = create_arg_exp(etype);
|
|
|
else
|
|
|
arg = create_arg_cmp(ctype);
|
|
|
+ if (arg == NULL)
|
|
|
+ goto fail_alloc;
|
|
|
|
|
|
if (current_op)
|
|
|
ret = add_right(current_op, arg, error_str);
|
|
|
@@ -1062,7 +1136,7 @@ process_filter(struct event_format *event, struct filter_arg **parg,
|
|
|
ret = add_left(arg, left_item);
|
|
|
if (ret < 0) {
|
|
|
arg = NULL;
|
|
|
- goto fail_print;
|
|
|
+ goto fail_syntax;
|
|
|
}
|
|
|
current_exp = arg;
|
|
|
break;
|
|
|
@@ -1071,57 +1145,64 @@ process_filter(struct event_format *event, struct filter_arg **parg,
|
|
|
}
|
|
|
arg = NULL;
|
|
|
if (ret < 0)
|
|
|
- goto fail_print;
|
|
|
+ goto fail_syntax;
|
|
|
break;
|
|
|
case EVENT_NONE:
|
|
|
break;
|
|
|
+ case EVENT_ERROR:
|
|
|
+ goto fail_alloc;
|
|
|
default:
|
|
|
- goto fail_print;
|
|
|
+ goto fail_syntax;
|
|
|
}
|
|
|
} while (type != EVENT_NONE);
|
|
|
|
|
|
if (!current_op && !current_exp)
|
|
|
- goto fail_print;
|
|
|
+ goto fail_syntax;
|
|
|
|
|
|
if (!current_op)
|
|
|
current_op = current_exp;
|
|
|
|
|
|
- current_op = collapse_tree(current_op);
|
|
|
+ ret = collapse_tree(current_op, parg, error_str);
|
|
|
+ if (ret < 0)
|
|
|
+ goto fail;
|
|
|
|
|
|
*parg = current_op;
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
- fail_print:
|
|
|
+ fail_alloc:
|
|
|
+ show_error(error_str, "failed to allocate filter arg");
|
|
|
+ ret = PEVENT_ERRNO__MEM_ALLOC_FAILED;
|
|
|
+ goto fail;
|
|
|
+ fail_syntax:
|
|
|
show_error(error_str, "Syntax error");
|
|
|
+ ret = PEVENT_ERRNO__SYNTAX_ERROR;
|
|
|
fail:
|
|
|
free_arg(current_op);
|
|
|
free_arg(current_exp);
|
|
|
free_arg(arg);
|
|
|
free(token);
|
|
|
- return -1;
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
-static int
|
|
|
+static enum pevent_errno
|
|
|
process_event(struct event_format *event, const char *filter_str,
|
|
|
- struct filter_arg **parg, char **error_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();
|
|
|
+ if (*parg == NULL)
|
|
|
+ return PEVENT_ERRNO__MEM_ALLOC_FAILED;
|
|
|
+
|
|
|
(*parg)->type = FILTER_ARG_BOOLEAN;
|
|
|
(*parg)->boolean.value = FILTER_FALSE;
|
|
|
}
|
|
|
@@ -1129,13 +1210,13 @@ process_event(struct event_format *event, const char *filter_str,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int filter_event(struct event_filter *filter,
|
|
|
- struct event_format *event,
|
|
|
- const char *filter_str, char **error_str)
|
|
|
+static enum pevent_errno
|
|
|
+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;
|
|
|
+ enum pevent_errno ret;
|
|
|
|
|
|
if (filter_str) {
|
|
|
ret = process_event(event, filter_str, &arg, error_str);
|
|
|
@@ -1145,11 +1226,17 @@ static int filter_event(struct event_filter *filter,
|
|
|
} else {
|
|
|
/* just add a TRUE arg */
|
|
|
arg = allocate_arg();
|
|
|
+ if (arg == NULL)
|
|
|
+ return PEVENT_ERRNO__MEM_ALLOC_FAILED;
|
|
|
+
|
|
|
arg->type = FILTER_ARG_BOOLEAN;
|
|
|
arg->boolean.value = FILTER_TRUE;
|
|
|
}
|
|
|
|
|
|
filter_type = add_filter_type(filter, event->id);
|
|
|
+ if (filter_type == NULL)
|
|
|
+ return PEVENT_ERRNO__MEM_ALLOC_FAILED;
|
|
|
+
|
|
|
if (filter_type->filter)
|
|
|
free_arg(filter_type->filter);
|
|
|
filter_type->filter = arg;
|
|
|
@@ -1157,22 +1244,24 @@ static int filter_event(struct event_filter *filter,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static void filter_init_error_buf(struct event_filter *filter)
|
|
|
+{
|
|
|
+ /* clear buffer to reset show error */
|
|
|
+ pevent_buffer_init("", 0);
|
|
|
+ filter->error_buffer[0] = '\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".
|
|
|
+ * Returns 0 if the filter was successfully added or a
|
|
|
+ * negative error code. Use pevent_filter_strerror() to see
|
|
|
+ * actual error message in case of error.
|
|
|
*/
|
|
|
-int pevent_filter_add_filter_str(struct event_filter *filter,
|
|
|
- const char *filter_str,
|
|
|
- char **error_str)
|
|
|
+enum pevent_errno pevent_filter_add_filter_str(struct event_filter *filter,
|
|
|
+ const char *filter_str)
|
|
|
{
|
|
|
struct pevent *pevent = filter->pevent;
|
|
|
struct event_list *event;
|
|
|
@@ -1183,15 +1272,11 @@ int pevent_filter_add_filter_str(struct event_filter *filter,
|
|
|
char *event_name = NULL;
|
|
|
char *sys_name = NULL;
|
|
|
char *sp;
|
|
|
- int rtn = 0;
|
|
|
+ enum pevent_errno rtn = 0; /* PEVENT_ERRNO__SUCCESS */
|
|
|
int len;
|
|
|
int ret;
|
|
|
|
|
|
- /* clear buffer to reset show error */
|
|
|
- pevent_buffer_init("", 0);
|
|
|
-
|
|
|
- if (error_str)
|
|
|
- *error_str = NULL;
|
|
|
+ filter_init_error_buf(filter);
|
|
|
|
|
|
filter_start = strchr(filter_str, ':');
|
|
|
if (filter_start)
|
|
|
@@ -1199,7 +1284,6 @@ int pevent_filter_add_filter_str(struct event_filter *filter,
|
|
|
else
|
|
|
len = strlen(filter_str);
|
|
|
|
|
|
-
|
|
|
do {
|
|
|
next_event = strchr(filter_str, ',');
|
|
|
if (next_event &&
|
|
|
@@ -1210,7 +1294,12 @@ int pevent_filter_add_filter_str(struct event_filter *filter,
|
|
|
else
|
|
|
len = strlen(filter_str);
|
|
|
|
|
|
- this_event = malloc_or_die(len + 1);
|
|
|
+ this_event = malloc(len + 1);
|
|
|
+ if (this_event == NULL) {
|
|
|
+ /* This can only happen when events is NULL, but still */
|
|
|
+ free_events(events);
|
|
|
+ return PEVENT_ERRNO__MEM_ALLOC_FAILED;
|
|
|
+ }
|
|
|
memcpy(this_event, filter_str, len);
|
|
|
this_event[len] = 0;
|
|
|
|
|
|
@@ -1223,27 +1312,18 @@ int pevent_filter_add_filter_str(struct event_filter *filter,
|
|
|
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;
|
|
|
+ return PEVENT_ERRNO__FILTER_NOT_FOUND;
|
|
|
}
|
|
|
|
|
|
/* 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;
|
|
|
+ return ret;
|
|
|
}
|
|
|
free(this_event);
|
|
|
} while (filter_str);
|
|
|
@@ -1255,7 +1335,7 @@ int pevent_filter_add_filter_str(struct event_filter *filter,
|
|
|
/* filter starts here */
|
|
|
for (event = events; event; event = event->next) {
|
|
|
ret = filter_event(filter, event->event, filter_start,
|
|
|
- error_str);
|
|
|
+ filter->error_buffer);
|
|
|
/* Failures are returned if a parse error happened */
|
|
|
if (ret < 0)
|
|
|
rtn = ret;
|
|
|
@@ -1263,8 +1343,10 @@ int pevent_filter_add_filter_str(struct event_filter *filter,
|
|
|
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);
|
|
|
+ if (test) {
|
|
|
+ printf(" '%s: %s'\n", event->event->name, test);
|
|
|
+ free(test);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -1281,6 +1363,32 @@ static void free_filter_type(struct filter_type *filter_type)
|
|
|
free_arg(filter_type->filter);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * pevent_filter_strerror - fill error message in a buffer
|
|
|
+ * @filter: the event filter contains error
|
|
|
+ * @err: the error code
|
|
|
+ * @buf: the buffer to be filled in
|
|
|
+ * @buflen: the size of the buffer
|
|
|
+ *
|
|
|
+ * Returns 0 if message was filled successfully, -1 if error
|
|
|
+ */
|
|
|
+int pevent_filter_strerror(struct event_filter *filter, enum pevent_errno err,
|
|
|
+ char *buf, size_t buflen)
|
|
|
+{
|
|
|
+ if (err <= __PEVENT_ERRNO__START || err >= __PEVENT_ERRNO__END)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ if (strlen(filter->error_buffer) > 0) {
|
|
|
+ size_t len = snprintf(buf, buflen, "%s", filter->error_buffer);
|
|
|
+
|
|
|
+ if (len > buflen)
|
|
|
+ return -1;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ return pevent_strerror(filter->pevent, err, buf, buflen);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* pevent_filter_remove_event - remove a filter for an event
|
|
|
* @filter: the event filter to remove from
|
|
|
@@ -1374,6 +1482,9 @@ static int copy_filter_type(struct event_filter *filter,
|
|
|
if (strcmp(str, "TRUE") == 0 || strcmp(str, "FALSE") == 0) {
|
|
|
/* Add trivial event */
|
|
|
arg = allocate_arg();
|
|
|
+ if (arg == NULL)
|
|
|
+ return -1;
|
|
|
+
|
|
|
arg->type = FILTER_ARG_BOOLEAN;
|
|
|
if (strcmp(str, "TRUE") == 0)
|
|
|
arg->boolean.value = 1;
|
|
|
@@ -1381,6 +1492,9 @@ static int copy_filter_type(struct event_filter *filter,
|
|
|
arg->boolean.value = 0;
|
|
|
|
|
|
filter_type = add_filter_type(filter, event->id);
|
|
|
+ if (filter_type == NULL)
|
|
|
+ return -1;
|
|
|
+
|
|
|
filter_type->filter = arg;
|
|
|
|
|
|
free(str);
|
|
|
@@ -1482,8 +1596,10 @@ int pevent_update_trivial(struct event_filter *dest, struct event_filter *source
|
|
|
* @type: remove only true, false, or both
|
|
|
*
|
|
|
* Removes filters that only contain a TRUE or FALES boolean arg.
|
|
|
+ *
|
|
|
+ * Returns 0 on success and -1 if there was a problem.
|
|
|
*/
|
|
|
-void pevent_filter_clear_trivial(struct event_filter *filter,
|
|
|
+int pevent_filter_clear_trivial(struct event_filter *filter,
|
|
|
enum filter_trivial_type type)
|
|
|
{
|
|
|
struct filter_type *filter_type;
|
|
|
@@ -1492,13 +1608,15 @@ void pevent_filter_clear_trivial(struct event_filter *filter,
|
|
|
int i;
|
|
|
|
|
|
if (!filter->filters)
|
|
|
- return;
|
|
|
+ return 0;
|
|
|
|
|
|
/*
|
|
|
* Two steps, first get all ids with trivial filters.
|
|
|
* then remove those ids.
|
|
|
*/
|
|
|
for (i = 0; i < filter->filters; i++) {
|
|
|
+ int *new_ids;
|
|
|
+
|
|
|
filter_type = &filter->event_filters[i];
|
|
|
if (filter_type->filter->type != FILTER_ARG_BOOLEAN)
|
|
|
continue;
|
|
|
@@ -1513,19 +1631,24 @@ void pevent_filter_clear_trivial(struct event_filter *filter,
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- ids = realloc(ids, sizeof(*ids) * (count + 1));
|
|
|
- if (!ids)
|
|
|
- die("Can't allocate ids");
|
|
|
+ new_ids = realloc(ids, sizeof(*ids) * (count + 1));
|
|
|
+ if (!new_ids) {
|
|
|
+ free(ids);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ ids = new_ids;
|
|
|
ids[count++] = filter_type->event_id;
|
|
|
}
|
|
|
|
|
|
if (!count)
|
|
|
- return;
|
|
|
+ return 0;
|
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
pevent_filter_remove_event(filter, ids[i]);
|
|
|
|
|
|
free(ids);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -1565,8 +1688,8 @@ int pevent_filter_event_has_trivial(struct event_filter *filter,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static int test_filter(struct event_format *event,
|
|
|
- struct filter_arg *arg, struct pevent_record *record);
|
|
|
+static int test_filter(struct event_format *event, struct filter_arg *arg,
|
|
|
+ struct pevent_record *record, enum pevent_errno *err);
|
|
|
|
|
|
static const char *
|
|
|
get_comm(struct event_format *event, struct pevent_record *record)
|
|
|
@@ -1612,15 +1735,24 @@ get_value(struct event_format *event,
|
|
|
}
|
|
|
|
|
|
static unsigned long long
|
|
|
-get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record);
|
|
|
+get_arg_value(struct event_format *event, struct filter_arg *arg,
|
|
|
+ struct pevent_record *record, enum pevent_errno *err);
|
|
|
|
|
|
static unsigned long long
|
|
|
-get_exp_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record)
|
|
|
+get_exp_value(struct event_format *event, struct filter_arg *arg,
|
|
|
+ struct pevent_record *record, enum pevent_errno *err)
|
|
|
{
|
|
|
unsigned long long lval, rval;
|
|
|
|
|
|
- lval = get_arg_value(event, arg->exp.left, record);
|
|
|
- rval = get_arg_value(event, arg->exp.right, record);
|
|
|
+ lval = get_arg_value(event, arg->exp.left, record, err);
|
|
|
+ rval = get_arg_value(event, arg->exp.right, record, err);
|
|
|
+
|
|
|
+ if (*err) {
|
|
|
+ /*
|
|
|
+ * There was an error, no need to process anymore.
|
|
|
+ */
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
|
|
|
switch (arg->exp.type) {
|
|
|
case FILTER_EXP_ADD:
|
|
|
@@ -1655,39 +1787,51 @@ get_exp_value(struct event_format *event, struct filter_arg *arg, struct pevent_
|
|
|
|
|
|
case FILTER_EXP_NOT:
|
|
|
default:
|
|
|
- die("error in exp");
|
|
|
+ if (!*err)
|
|
|
+ *err = PEVENT_ERRNO__INVALID_EXP_TYPE;
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
static unsigned long long
|
|
|
-get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record)
|
|
|
+get_arg_value(struct event_format *event, struct filter_arg *arg,
|
|
|
+ struct pevent_record *record, enum pevent_errno *err)
|
|
|
{
|
|
|
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!");
|
|
|
+ if (arg->value.type != FILTER_NUMBER) {
|
|
|
+ if (!*err)
|
|
|
+ *err = PEVENT_ERRNO__NOT_A_NUMBER;
|
|
|
+ }
|
|
|
return arg->value.val;
|
|
|
|
|
|
case FILTER_ARG_EXP:
|
|
|
- return get_exp_value(event, arg, record);
|
|
|
+ return get_exp_value(event, arg, record, err);
|
|
|
|
|
|
default:
|
|
|
- die("oops in filter");
|
|
|
+ if (!*err)
|
|
|
+ *err = PEVENT_ERRNO__INVALID_ARG_TYPE;
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int test_num(struct event_format *event,
|
|
|
- struct filter_arg *arg, struct pevent_record *record)
|
|
|
+static int test_num(struct event_format *event, struct filter_arg *arg,
|
|
|
+ struct pevent_record *record, enum pevent_errno *err)
|
|
|
{
|
|
|
unsigned long long lval, rval;
|
|
|
|
|
|
- lval = get_arg_value(event, arg->num.left, record);
|
|
|
- rval = get_arg_value(event, arg->num.right, record);
|
|
|
+ lval = get_arg_value(event, arg->num.left, record, err);
|
|
|
+ rval = get_arg_value(event, arg->num.right, record, err);
|
|
|
+
|
|
|
+ if (*err) {
|
|
|
+ /*
|
|
|
+ * There was an error, no need to process anymore.
|
|
|
+ */
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
|
|
|
switch (arg->num.type) {
|
|
|
case FILTER_CMP_EQ:
|
|
|
@@ -1709,7 +1853,8 @@ static int test_num(struct event_format *event,
|
|
|
return lval <= rval;
|
|
|
|
|
|
default:
|
|
|
- /* ?? */
|
|
|
+ if (!*err)
|
|
|
+ *err = PEVENT_ERRNO__ILLEGAL_INTEGER_CMP;
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
|
@@ -1756,8 +1901,8 @@ static const char *get_field_str(struct filter_arg *arg, struct pevent_record *r
|
|
|
return val;
|
|
|
}
|
|
|
|
|
|
-static int test_str(struct event_format *event,
|
|
|
- struct filter_arg *arg, struct pevent_record *record)
|
|
|
+static int test_str(struct event_format *event, struct filter_arg *arg,
|
|
|
+ struct pevent_record *record, enum pevent_errno *err)
|
|
|
{
|
|
|
const char *val;
|
|
|
|
|
|
@@ -1781,48 +1926,57 @@ static int test_str(struct event_format *event,
|
|
|
return regexec(&arg->str.reg, val, 0, NULL, 0);
|
|
|
|
|
|
default:
|
|
|
- /* ?? */
|
|
|
+ if (!*err)
|
|
|
+ *err = PEVENT_ERRNO__ILLEGAL_STRING_CMP;
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static int test_op(struct event_format *event,
|
|
|
- struct filter_arg *arg, struct pevent_record *record)
|
|
|
+static int test_op(struct event_format *event, struct filter_arg *arg,
|
|
|
+ struct pevent_record *record, enum pevent_errno *err)
|
|
|
{
|
|
|
switch (arg->op.type) {
|
|
|
case FILTER_OP_AND:
|
|
|
- return test_filter(event, arg->op.left, record) &&
|
|
|
- test_filter(event, arg->op.right, record);
|
|
|
+ return test_filter(event, arg->op.left, record, err) &&
|
|
|
+ test_filter(event, arg->op.right, record, err);
|
|
|
|
|
|
case FILTER_OP_OR:
|
|
|
- return test_filter(event, arg->op.left, record) ||
|
|
|
- test_filter(event, arg->op.right, record);
|
|
|
+ return test_filter(event, arg->op.left, record, err) ||
|
|
|
+ test_filter(event, arg->op.right, record, err);
|
|
|
|
|
|
case FILTER_OP_NOT:
|
|
|
- return !test_filter(event, arg->op.right, record);
|
|
|
+ return !test_filter(event, arg->op.right, record, err);
|
|
|
|
|
|
default:
|
|
|
- /* ?? */
|
|
|
+ if (!*err)
|
|
|
+ *err = PEVENT_ERRNO__INVALID_OP_TYPE;
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static int test_filter(struct event_format *event,
|
|
|
- struct filter_arg *arg, struct pevent_record *record)
|
|
|
+static int test_filter(struct event_format *event, struct filter_arg *arg,
|
|
|
+ struct pevent_record *record, enum pevent_errno *err)
|
|
|
{
|
|
|
+ if (*err) {
|
|
|
+ /*
|
|
|
+ * There was an error, no need to process anymore.
|
|
|
+ */
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
switch (arg->type) {
|
|
|
case FILTER_ARG_BOOLEAN:
|
|
|
/* easy case */
|
|
|
return arg->boolean.value;
|
|
|
|
|
|
case FILTER_ARG_OP:
|
|
|
- return test_op(event, arg, record);
|
|
|
+ return test_op(event, arg, record, err);
|
|
|
|
|
|
case FILTER_ARG_NUM:
|
|
|
- return test_num(event, arg, record);
|
|
|
+ return test_num(event, arg, record, err);
|
|
|
|
|
|
case FILTER_ARG_STR:
|
|
|
- return test_str(event, arg, record);
|
|
|
+ return test_str(event, arg, record, err);
|
|
|
|
|
|
case FILTER_ARG_EXP:
|
|
|
case FILTER_ARG_VALUE:
|
|
|
@@ -1831,11 +1985,11 @@ static int test_filter(struct event_format *event,
|
|
|
* Expressions, fields and values evaluate
|
|
|
* to true if they return non zero
|
|
|
*/
|
|
|
- return !!get_arg_value(event, arg, record);
|
|
|
+ return !!get_arg_value(event, arg, record, err);
|
|
|
|
|
|
default:
|
|
|
- die("oops!");
|
|
|
- /* ?? */
|
|
|
+ if (!*err)
|
|
|
+ *err = PEVENT_ERRNO__INVALID_ARG_TYPE;
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
|
@@ -1848,8 +2002,7 @@ static int test_filter(struct event_format *event,
|
|
|
* Returns 1 if filter found for @event_id
|
|
|
* otherwise 0;
|
|
|
*/
|
|
|
-int pevent_event_filtered(struct event_filter *filter,
|
|
|
- int event_id)
|
|
|
+int pevent_event_filtered(struct event_filter *filter, int event_id)
|
|
|
{
|
|
|
struct filter_type *filter_type;
|
|
|
|
|
|
@@ -1866,31 +2019,38 @@ int pevent_event_filtered(struct event_filter *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
|
|
|
+ * Returns: match result or error code (prefixed with PEVENT_ERRNO__)
|
|
|
+ * FILTER_MATCH - filter found for event and @record matches
|
|
|
+ * FILTER_MISS - filter found for event and @record does not match
|
|
|
+ * FILTER_NOT_FOUND - no filter found for @record's event
|
|
|
+ * NO_FILTER - if no filters exist
|
|
|
+ * otherwise - error occurred during test
|
|
|
*/
|
|
|
-int pevent_filter_match(struct event_filter *filter,
|
|
|
- struct pevent_record *record)
|
|
|
+enum pevent_errno pevent_filter_match(struct event_filter *filter,
|
|
|
+ struct pevent_record *record)
|
|
|
{
|
|
|
struct pevent *pevent = filter->pevent;
|
|
|
struct filter_type *filter_type;
|
|
|
int event_id;
|
|
|
+ int ret;
|
|
|
+ enum pevent_errno err = 0;
|
|
|
+
|
|
|
+ filter_init_error_buf(filter);
|
|
|
|
|
|
if (!filter->filters)
|
|
|
- return FILTER_NONE;
|
|
|
+ return PEVENT_ERRNO__NO_FILTER;
|
|
|
|
|
|
event_id = pevent_data_type(pevent, record);
|
|
|
|
|
|
filter_type = find_filter_type(filter, event_id);
|
|
|
-
|
|
|
if (!filter_type)
|
|
|
- return FILTER_NOEXIST;
|
|
|
+ return PEVENT_ERRNO__FILTER_NOT_FOUND;
|
|
|
+
|
|
|
+ ret = test_filter(filter_type->event, filter_type->filter, record, &err);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
|
|
|
- return test_filter(filter_type->event, filter_type->filter, record) ?
|
|
|
- FILTER_MATCH : FILTER_MISS;
|
|
|
+ return ret ? PEVENT_ERRNO__FILTER_MATCH : PEVENT_ERRNO__FILTER_MISS;
|
|
|
}
|
|
|
|
|
|
static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
|
|
|
@@ -1902,7 +2062,6 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
|
|
|
int left_val = -1;
|
|
|
int right_val = -1;
|
|
|
int val;
|
|
|
- int len;
|
|
|
|
|
|
switch (arg->op.type) {
|
|
|
case FILTER_OP_AND:
|
|
|
@@ -1949,11 +2108,7 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
- str = malloc_or_die(6);
|
|
|
- if (val)
|
|
|
- strcpy(str, "TRUE");
|
|
|
- else
|
|
|
- strcpy(str, "FALSE");
|
|
|
+ asprintf(&str, val ? "TRUE" : "FALSE");
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
@@ -1971,10 +2126,7 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- len = strlen(left) + strlen(right) + strlen(op) + 10;
|
|
|
- str = malloc_or_die(len);
|
|
|
- snprintf(str, len, "(%s) %s (%s)",
|
|
|
- left, op, right);
|
|
|
+ asprintf(&str, "(%s) %s (%s)", left, op, right);
|
|
|
break;
|
|
|
|
|
|
case FILTER_OP_NOT:
|
|
|
@@ -1990,16 +2142,10 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
|
|
|
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");
|
|
|
+ asprintf(&str, right_val ? "FALSE" : "TRUE");
|
|
|
break;
|
|
|
}
|
|
|
- len = strlen(right) + strlen(op) + 3;
|
|
|
- str = malloc_or_die(len);
|
|
|
- snprintf(str, len, "%s(%s)", op, right);
|
|
|
+ asprintf(&str, "%s(%s)", op, right);
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
@@ -2013,11 +2159,9 @@ static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
|
|
|
|
|
|
static char *val_to_str(struct event_filter *filter, struct filter_arg *arg)
|
|
|
{
|
|
|
- char *str;
|
|
|
-
|
|
|
- str = malloc_or_die(30);
|
|
|
+ char *str = NULL;
|
|
|
|
|
|
- snprintf(str, 30, "%lld", arg->value.val);
|
|
|
+ asprintf(&str, "%lld", arg->value.val);
|
|
|
|
|
|
return str;
|
|
|
}
|
|
|
@@ -2033,7 +2177,6 @@ static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg)
|
|
|
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);
|
|
|
@@ -2072,12 +2215,11 @@ static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg)
|
|
|
op = "^";
|
|
|
break;
|
|
|
default:
|
|
|
- die("oops in exp");
|
|
|
+ op = "[ERROR IN EXPRESSION TYPE]";
|
|
|
+ break;
|
|
|
}
|
|
|
|
|
|
- len = strlen(op) + strlen(lstr) + strlen(rstr) + 4;
|
|
|
- str = malloc_or_die(len);
|
|
|
- snprintf(str, len, "%s %s %s", lstr, op, rstr);
|
|
|
+ asprintf(&str, "%s %s %s", lstr, op, rstr);
|
|
|
out:
|
|
|
free(lstr);
|
|
|
free(rstr);
|
|
|
@@ -2091,7 +2233,6 @@ static char *num_to_str(struct event_filter *filter, struct filter_arg *arg)
|
|
|
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);
|
|
|
@@ -2122,10 +2263,7 @@ static char *num_to_str(struct event_filter *filter, struct filter_arg *arg)
|
|
|
if (!op)
|
|
|
op = "<=";
|
|
|
|
|
|
- len = strlen(lstr) + strlen(op) + strlen(rstr) + 4;
|
|
|
- str = malloc_or_die(len);
|
|
|
- sprintf(str, "%s %s %s", lstr, op, rstr);
|
|
|
-
|
|
|
+ asprintf(&str, "%s %s %s", lstr, op, rstr);
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
@@ -2143,7 +2281,6 @@ 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:
|
|
|
@@ -2161,12 +2298,8 @@ static char *str_to_str(struct event_filter *filter, struct filter_arg *arg)
|
|
|
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);
|
|
|
+ asprintf(&str, "%s %s \"%s\"",
|
|
|
+ arg->str.field->name, op, arg->str.val);
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
@@ -2178,15 +2311,11 @@ static char *str_to_str(struct event_filter *filter, struct filter_arg *arg)
|
|
|
|
|
|
static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg)
|
|
|
{
|
|
|
- char *str;
|
|
|
+ char *str = NULL;
|
|
|
|
|
|
switch (arg->type) {
|
|
|
case FILTER_ARG_BOOLEAN:
|
|
|
- str = malloc_or_die(6);
|
|
|
- if (arg->boolean.value)
|
|
|
- strcpy(str, "TRUE");
|
|
|
- else
|
|
|
- strcpy(str, "FALSE");
|
|
|
+ asprintf(&str, arg->boolean.value ? "TRUE" : "FALSE");
|
|
|
return str;
|
|
|
|
|
|
case FILTER_ARG_OP:
|
|
|
@@ -2221,7 +2350,7 @@ static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg)
|
|
|
*
|
|
|
* Returns a string that displays the filter contents.
|
|
|
* This string must be freed with free(str).
|
|
|
- * NULL is returned if no filter is found.
|
|
|
+ * NULL is returned if no filter is found or allocation failed.
|
|
|
*/
|
|
|
char *
|
|
|
pevent_filter_make_string(struct event_filter *filter, int event_id)
|