diff options
Diffstat (limited to 'tools/lib/traceevent/parse-filter.c')
| -rw-r--r-- | tools/lib/traceevent/parse-filter.c | 673 | 
1 files changed, 401 insertions, 272 deletions
diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c index 2500e75583f..b50234402fc 100644 --- a/tools/lib/traceevent/parse-filter.c +++ b/tools/lib/traceevent/parse-filter.c @@ -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); +			}  		}  	} @@ -1282,6 +1364,32 @@ static void free_filter_type(struct filter_type *filter_type)  }  /** + * 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   * @event_id: the event to remove a filter for @@ -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)  | 
