2303 lines · 47.6 KB · C
RawDownload
/* * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License (not later!) * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not,  see <http://www.gnu.org/licenses> * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdarg.h>#include <errno.h>#include <sys/types.h> #include "event-parse.h"#include "event-utils.h" #define COMM "COMM" static struct format_field comm = {	.name = "COMM",}; struct event_list {	struct event_list	*next;	struct event_format	*event;}; #define MAX_ERR_STR_SIZE 256 static void show_error(char **error_str, const char *fmt, ...){	unsigned long long index;	const char *input;	char *error;	va_list ap;	int len;	int i; 	if (!error_str)		return; 	input = pevent_get_input_buf();	index = pevent_get_input_buf_ptr();	len = input ? strlen(input) : 0; 	error = malloc_or_die(MAX_ERR_STR_SIZE + (len*2) + 3); 	if (len) {		strcpy(error, input);		error[len] = '\n';		for (i = 1; i < len && i < index; i++)			error[len+i] = ' ';		error[len + i] = '^';		error[len + i + 1] = '\n';		len += i+2;	} 	va_start(ap, fmt);	vsnprintf(error + len, MAX_ERR_STR_SIZE, fmt, ap);	va_end(ap); 	*error_str = error;} static void free_token(char *token){	pevent_free_token(token);} static enum event_type read_token(char **tok){	enum event_type type;	char *token = NULL; 	do {		free_token(token);		type = pevent_read_token(&token);	} while (type == EVENT_NEWLINE || type == EVENT_SPACE); 	/* If token is = or ! check to see if the next char is ~ */	if (token &&	    (strcmp(token, "=") == 0 || strcmp(token, "!") == 0) &&	    pevent_peek_char() == '~') {		/* append it */		*tok = malloc_or_die(3);		sprintf(*tok, "%c%c", *token, '~');		free_token(token);		/* Now remove the '~' from the buffer */		pevent_read_token(&token);		free_token(token);	} else		*tok = token; 	return type;} static int filter_cmp(const void *a, const void *b){	const struct filter_type *ea = a;	const struct filter_type *eb = b; 	if (ea->event_id < eb->event_id)		return -1; 	if (ea->event_id > eb->event_id)		return 1; 	return 0;} static struct filter_type *find_filter_type(struct event_filter *filter, int id){	struct filter_type *filter_type;	struct filter_type key; 	key.event_id = id; 	filter_type = bsearch(&key, filter->event_filters,			      filter->filters,			      sizeof(*filter->event_filters),			      filter_cmp); 	return filter_type;} static struct filter_type *add_filter_type(struct event_filter *filter, int id){	struct filter_type *filter_type;	int i; 	filter_type = find_filter_type(filter, id);	if (filter_type)		return filter_type; 	filter->event_filters =	realloc(filter->event_filters,					sizeof(*filter->event_filters) *					(filter->filters + 1));	if (!filter->event_filters)		die("Could not allocate filter"); 	for (i = 0; i < filter->filters; i++) {		if (filter->event_filters[i].event_id > id)			break;	} 	if (i < filter->filters)		memmove(&filter->event_filters[i+1],			&filter->event_filters[i],			sizeof(*filter->event_filters) *			(filter->filters - i)); 	filter_type = &filter->event_filters[i];	filter_type->event_id = id;	filter_type->event = pevent_find_event(filter->pevent, id);	filter_type->filter = NULL; 	filter->filters++; 	return filter_type;} /** * pevent_filter_alloc - create a new event filter * @pevent: The pevent that this filter is associated with */struct event_filter *pevent_filter_alloc(struct pevent *pevent){	struct event_filter *filter; 	filter = malloc_or_die(sizeof(*filter));	memset(filter, 0, sizeof(*filter));	filter->pevent = pevent;	pevent_ref(pevent); 	return filter;} static struct filter_arg *allocate_arg(void){	struct filter_arg *arg; 	arg = malloc_or_die(sizeof(*arg));	memset(arg, 0, sizeof(*arg)); 	return arg;} static void free_arg(struct filter_arg *arg){	if (!arg)		return; 	switch (arg->type) {	case FILTER_ARG_NONE:	case FILTER_ARG_BOOLEAN:		break; 	case FILTER_ARG_NUM:		free_arg(arg->num.left);		free_arg(arg->num.right);		break; 	case FILTER_ARG_EXP:		free_arg(arg->exp.left);		free_arg(arg->exp.right);		break; 	case FILTER_ARG_STR:		free(arg->str.val);		regfree(&arg->str.reg);		free(arg->str.buffer);		break; 	case FILTER_ARG_VALUE:		if (arg->value.type == FILTER_STRING ||		    arg->value.type == FILTER_CHAR)			free(arg->value.str);		break; 	case FILTER_ARG_OP:		free_arg(arg->op.left);		free_arg(arg->op.right);	default:		break;	} 	free(arg);} static void add_event(struct event_list **events,		      struct event_format *event){	struct event_list *list; 	list = malloc_or_die(sizeof(*list));	list->next = *events;	*events = list;	list->event = event;} static int event_match(struct event_format *event,		       regex_t *sreg, regex_t *ereg){	if (sreg) {		return !regexec(sreg, event->system, 0, NULL, 0) &&			!regexec(ereg, event->name, 0, NULL, 0);	} 	return !regexec(ereg, event->system, 0, NULL, 0) ||		!regexec(ereg, event->name, 0, NULL, 0);} static intfind_event(struct pevent *pevent, struct event_list **events,	   char *sys_name, char *event_name){	struct event_format *event;	regex_t ereg;	regex_t sreg;	int match = 0;	char *reg;	int ret;	int i; 	if (!event_name) {		/* if no name is given, then swap sys and name */		event_name = sys_name;		sys_name = NULL;	} 	reg = malloc_or_die(strlen(event_name) + 3);	sprintf(reg, "^%s$", event_name); 	ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB);	free(reg); 	if (ret)		return -1; 	if (sys_name) {		reg = malloc_or_die(strlen(sys_name) + 3);		sprintf(reg, "^%s$", sys_name);		ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB);		free(reg);		if (ret) {			regfree(&ereg);			return -1;		}	} 	for (i = 0; i < pevent->nr_events; i++) {		event = pevent->events[i];		if (event_match(event, sys_name ? &sreg : NULL, &ereg)) {			match = 1;			add_event(events, event);		}	} 	regfree(&ereg);	if (sys_name)		regfree(&sreg); 	if (!match)		return -1; 	return 0;} static void free_events(struct event_list *events){	struct event_list *event; 	while (events) {		event = events;		events = events->next;		free(event);	}} static struct filter_arg *create_arg_item(struct event_format *event, const char *token,		enum event_type type, char **error_str){	struct format_field *field;	struct filter_arg *arg; 	arg = allocate_arg(); 	switch (type) { 	case EVENT_SQUOTE:	case EVENT_DQUOTE:		arg->type = FILTER_ARG_VALUE;		arg->value.type =			type == EVENT_DQUOTE ? FILTER_STRING : FILTER_CHAR;		arg->value.str = strdup(token);		if (!arg->value.str)			die("malloc string");		break;	case EVENT_ITEM:		/* if it is a number, then convert it */		if (isdigit(token[0])) {			arg->type = FILTER_ARG_VALUE;			arg->value.type = FILTER_NUMBER;			arg->value.val = strtoull(token, NULL, 0);			break;		}		/* Consider this a field */		field = pevent_find_any_field(event, token);		if (!field) {			if (strcmp(token, COMM) != 0) {				/* not a field, Make it false */				arg->type = FILTER_ARG_BOOLEAN;				arg->boolean.value = FILTER_FALSE;				break;			}			/* If token is 'COMM' then it is special */			field = &comm;		}		arg->type = FILTER_ARG_FIELD;		arg->field.field = field;		break;	default:		free_arg(arg);		show_error(error_str, "expected a value but found %s",			   token);		return NULL;	}	return arg;} static struct filter_arg *create_arg_op(enum filter_op_type btype){	struct filter_arg *arg; 	arg = allocate_arg();	arg->type = FILTER_ARG_OP;	arg->op.type = btype; 	return arg;} static struct filter_arg *create_arg_exp(enum filter_exp_type etype){	struct filter_arg *arg; 	arg = allocate_arg();	arg->type = FILTER_ARG_EXP;	arg->op.type = etype; 	return arg;} static struct filter_arg *create_arg_cmp(enum filter_exp_type etype){	struct filter_arg *arg; 	arg = allocate_arg();	/* Use NUM and change if necessary */	arg->type = FILTER_ARG_NUM;	arg->op.type = etype; 	return arg;} static int add_right(struct filter_arg *op, struct filter_arg *arg,		     char **error_str){	struct filter_arg *left;	char *str;	int op_type;	int ret; 	switch (op->type) {	case FILTER_ARG_EXP:		if (op->exp.right)			goto out_fail;		op->exp.right = arg;		break; 	case FILTER_ARG_OP:		if (op->op.right)			goto out_fail;		op->op.right = arg;		break; 	case FILTER_ARG_NUM:		if (op->op.right)			goto out_fail;		/*		 * The arg must be num, str, or field		 */		switch (arg->type) {		case FILTER_ARG_VALUE:		case FILTER_ARG_FIELD:			break;		default:			show_error(error_str,				   "Illegal rvalue");			return -1;		} 		/*		 * Depending on the type, we may need to		 * convert this to a string or regex.		 */		switch (arg->value.type) {		case FILTER_CHAR:			/*			 * A char should be converted to number if			 * the string is 1 byte, and the compare			 * is not a REGEX.			 */			if (strlen(arg->value.str) == 1 &&			    op->num.type != FILTER_CMP_REGEX &&			    op->num.type != FILTER_CMP_NOT_REGEX) {				arg->value.type = FILTER_NUMBER;				goto do_int;			}			/* fall through */		case FILTER_STRING: 			/* convert op to a string arg */			op_type = op->num.type;			left = op->num.left;			str = arg->value.str; 			/* reset the op for the new field */			memset(op, 0, sizeof(*op)); 			/*			 * If left arg was a field not found then			 * NULL the entire op.			 */			if (left->type == FILTER_ARG_BOOLEAN) {				free_arg(left);				free_arg(arg);				op->type = FILTER_ARG_BOOLEAN;				op->boolean.value = FILTER_FALSE;				break;			} 

Lines 1–500 of 2303.