aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2011-01-21 11:44:32 -0500
committerSteven Rostedt <rostedt@goodmis.org>2011-01-21 11:44:32 -0500
commitd41d342e3bc4f3c15dd56a483053471378222de8 (patch)
tree6ac4720cd32ec80bf549fe67282e48ed65451c11
parentb8b14ccd92219d98b6336069de79d5605b4e3f45 (diff)
parse-events: Rewrite filter algorithm to simplify it
New rewrite of the parse event filter to greatly simplify the logic. Should be much easier to modify it now. Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--parse-events.h3
-rw-r--r--parse-filter.c1196
2 files changed, 652 insertions, 547 deletions
diff --git a/parse-events.h b/parse-events.h
index 3ffe56f..43213d4 100644
--- a/parse-events.h
+++ b/parse-events.h
@@ -620,7 +620,8 @@ enum filter_arg_type {
620 620
621enum filter_value_type { 621enum filter_value_type {
622 FILTER_NUMBER, 622 FILTER_NUMBER,
623 FILTER_STRING 623 FILTER_STRING,
624 FILTER_CHAR
624}; 625};
625 626
626struct fliter_arg; 627struct fliter_arg;
diff --git a/parse-filter.c b/parse-filter.c
index e5ff909..bd52033 100644
--- a/parse-filter.c
+++ b/parse-filter.c
@@ -324,226 +324,13 @@ static void free_events(struct event_list *events)
324 } 324 }
325} 325}
326 326
327static enum event_type 327static struct filter_arg *
328process_paren(struct event_format *event, struct filter_arg **parg, 328create_arg_item(struct event_format *event,
329 char **tok, char **error_str); 329 const char *token, enum filter_arg_type type,
330 330 char **error_str)
331static enum event_type
332process_not(struct event_format *event, struct filter_arg **parg,
333 char **tok, char **error_str);
334
335static enum event_type
336process_value_token(struct event_format *event, struct filter_arg **parg,
337 enum event_type type, char **tok, char **error_str);
338
339static enum event_type
340process_op_token(struct event_format *event, struct filter_arg *larg,
341 struct filter_arg **parg, enum event_type type, char **tok,
342 char **error_str);
343
344/*
345 * process_token
346 * Called when a new expression is found. Processes an op, or
347 * ends early if a ')' is found.
348 *
349 * Output: tok, parg
350 */
351static enum event_type
352process_token(struct event_format *event, struct filter_arg **parg,
353 char **tok, char **error_str)
354{
355 struct filter_arg *arg = NULL;
356 enum event_type type;
357 char *token;
358
359 *tok = NULL;
360 *parg = NULL;
361
362 type = read_token(&token);
363
364 /*
365 * This is a start of a new expresion. We expect to find
366 * a item or a parenthesis.
367 */
368 switch (type) {
369 case EVENT_SQUOTE:
370 case EVENT_DQUOTE:
371 case EVENT_ITEM:
372 type = process_value_token(event, &arg, type, &token, error_str);
373 if (type == EVENT_ERROR) {
374 free_token(token);
375 return type;
376 }
377 type = read_token(&token);
378 break;
379 case EVENT_DELIM:
380 if (strcmp(token, "(") != 0)
381 break;
382
383 free_token(token);
384 type = process_paren(event, &arg, &token, error_str);
385 if (type == EVENT_NONE) {
386 *tok = token;
387 *parg = arg;
388 return type;
389 }
390 if (arg) {
391 /*
392 * If the parenthesis was a full expression,
393 * then just return it. Otherwise, we may still
394 * need to find an op.
395 */
396 switch (arg->type) {
397 case FILTER_ARG_OP:
398 case FILTER_ARG_NUM:
399 case FILTER_ARG_STR:
400 *tok = token;
401 *parg = arg;
402 return type;
403 default:
404 break;
405 }
406 }
407 break;
408
409 case EVENT_OP:
410 if (strcmp(token, "!") != 0)
411 break;
412
413 /*
414 * A not is its own filter, it just negates,
415 * process it by itself.
416 */
417 *tok = token;
418 type = process_not(event, parg, tok, error_str);
419 return type;
420
421 default:
422 break;
423 }
424
425 for (;;) {
426 if (type == EVENT_NONE) {
427 show_error(error_str, "unexpected end of filter");
428 type = EVENT_ERROR;
429
430 } else if (type == EVENT_DELIM && strcmp(token, ")") == 0) {
431 /* Parenthesis call this and may return at anytime. */
432 *tok = token;
433 *parg = arg;
434 return type;
435
436 } else if (type != EVENT_OP) {
437 show_error(error_str, "Expected an OP but found %s", token);
438 type = EVENT_ERROR;
439 }
440
441 if (type == EVENT_ERROR) {
442 free_token(token);
443 return type;
444 }
445
446 *tok = token;
447 *parg = NULL;
448 type = process_op_token(event, arg, parg, type, tok, error_str);
449
450 if (type == EVENT_ERROR) {
451 free_arg(*parg);
452 *parg = NULL;
453 return EVENT_ERROR;
454 }
455
456 if (!(*parg) || (*parg)->type != FILTER_ARG_EXP)
457 break;
458
459 /*
460 * This op was an expression (value return)
461 * It's not fine by itself, there had better be an OP
462 * after it.
463 */
464 token = *tok;
465 *tok = NULL;
466 arg = *parg;
467 }
468
469 return type;
470}
471
472/*
473 * Input: tok
474 * Output: parg, tok
475 */
476static enum event_type
477process_bool(struct event_format *event, struct filter_arg *larg,
478 struct filter_arg **parg, char **tok, char **error_str)
479{
480 struct filter_arg *rarg;
481 struct filter_arg *arg;
482 enum event_type type;
483 enum filter_op_type btype;
484
485 /* Can only be called with '&&' or '||' */
486 btype = strcmp(*tok, "&&") == 0 ?
487 FILTER_OP_AND : FILTER_OP_OR;
488
489 type = process_token(event, &rarg, tok, error_str);
490 if (type == EVENT_ERROR) {
491 free_arg(larg);
492 *parg = NULL;
493 return type;
494 }
495
496 /*
497 * If larg or rarg is null then if this is AND, the whole expression
498 * becomes NULL, else if this is an OR, then we use the non NULL
499 * condition.
500 */
501 if (!larg || !rarg) {
502 if (btype == FILTER_OP_AND ||
503 (!larg && !rarg)) {
504 free_arg(larg);
505 free_arg(rarg);
506 *parg = NULL;
507 return type;
508 }
509 *parg = larg ? larg : rarg;
510 return type;
511 }
512
513 arg = allocate_arg();
514 arg->type = FILTER_ARG_OP;
515 arg->op.type = btype;
516 arg->op.left = larg;
517 arg->op.right = rarg;
518
519
520 /*
521 * If the next token is also a boolean expression, then
522 * make the next boolean the parent..
523 */
524 if (type != EVENT_OP ||
525 (strcmp(*tok, "&&") != 0 && strcmp(*tok, "||") != 0)) {
526 *parg = arg;
527 return type;
528 }
529
530 return process_bool(event, arg, parg, tok, error_str);
531}
532
533/*
534 * Input: tok
535 * Output: parg
536 */
537static enum event_type
538process_value_token(struct event_format *event, struct filter_arg **parg,
539 enum event_type type, char **tok, char **error_str)
540{ 331{
541 struct format_field *field; 332 struct format_field *field;
542 struct filter_arg *arg; 333 struct filter_arg *arg;
543 char *token;
544
545 token = *tok;
546 *tok = NULL;
547 334
548 arg = allocate_arg(); 335 arg = allocate_arg();
549 336
@@ -552,8 +339,11 @@ process_value_token(struct event_format *event, struct filter_arg **parg,
552 case EVENT_SQUOTE: 339 case EVENT_SQUOTE:
553 case EVENT_DQUOTE: 340 case EVENT_DQUOTE:
554 arg->type = FILTER_ARG_VALUE; 341 arg->type = FILTER_ARG_VALUE;
555 arg->value.type = FILTER_STRING; 342 arg->value.type =
556 arg->value.str = token; 343 type == EVENT_DQUOTE ? FILTER_STRING : FILTER_CHAR;
344 arg->value.str = strdup(token);
345 if (!arg->value.str)
346 die("malloc string");
557 break; 347 break;
558 case EVENT_ITEM: 348 case EVENT_ITEM:
559 /* if it is a number, then convert it */ 349 /* if it is a number, then convert it */
@@ -561,24 +351,20 @@ process_value_token(struct event_format *event, struct filter_arg **parg,
561 arg->type = FILTER_ARG_VALUE; 351 arg->type = FILTER_ARG_VALUE;
562 arg->value.type = FILTER_NUMBER; 352 arg->value.type = FILTER_NUMBER;
563 arg->value.val = strtoll(token, NULL, 0); 353 arg->value.val = strtoll(token, NULL, 0);
564 free_token(token);
565 break; 354 break;
566 } 355 }
567 /* Consider this a field */ 356 /* Consider this a field */
568 field = pevent_find_any_field(event, token); 357 field = pevent_find_any_field(event, token);
569 if (!field) { 358 if (!field) {
570 if (strcmp(token, COMM) != 0) { 359 if (strcmp(token, COMM) != 0) {
571 /* not a field, so NULL it up */ 360 /* not a field, Make it false */
572 free_token(token); 361 arg->type = FILTER_ARG_BOOLEAN;
573 free_arg(arg); 362 arg->bool.value = FILTER_FALSE;
574 arg = NULL;
575 break; 363 break;
576 } 364 }
577 /* If token is 'COMM' then it is special */ 365 /* If token is 'COMM' then it is special */
578 field = &comm; 366 field = &comm;
579 } 367 }
580 free_token(token);
581
582 arg->type = FILTER_ARG_FIELD; 368 arg->type = FILTER_ARG_FIELD;
583 arg->field.field = field; 369 arg->field.field = field;
584 break; 370 break;
@@ -586,428 +372,745 @@ process_value_token(struct event_format *event, struct filter_arg **parg,
586 free_arg(arg); 372 free_arg(arg);
587 show_error(error_str, "expected a value but found %s", 373 show_error(error_str, "expected a value but found %s",
588 token); 374 token);
589 free_token(token); 375 return NULL;
590 return EVENT_ERROR;
591 } 376 }
377 return arg;
378}
592 379
593 *parg = arg; 380static struct filter_arg *
594 return type; 381create_arg_op(enum filter_op_type btype)
382{
383 struct filter_arg *arg;
384
385 arg = allocate_arg();
386 arg->type = FILTER_ARG_OP;
387 arg->op.type = btype;
388
389 return arg;
595} 390}
596 391
597/* 392static struct filter_arg *
598 * Output: parg, tok 393create_arg_exp(enum filter_exp_type etype)
599 */
600static enum event_type
601process_value(struct event_format *event, struct filter_arg **parg,
602 enum event_type *orig_type, char **tok, char **error_str)
603{ 394{
604 enum event_type type; 395 struct filter_arg *arg;
605 char *token; 396
606 397 arg = allocate_arg();
607 *tok = NULL; 398 arg->type = FILTER_ARG_EXP;
608 type = read_token(&token); 399 arg->op.type = etype;
609 *orig_type = type; 400
610 if (type == EVENT_DELIM && strcmp(token, "(") == 0) { 401 return arg;
611 type = process_paren(event, parg, &token, error_str); 402}
612 /* Must be a expression or value */ 403
613 if (type == EVENT_ERROR || !(*parg)) { 404static struct filter_arg *
614 free_token(token); 405create_arg_cmp(enum filter_exp_type etype)
615 return type; 406{
616 } 407 struct filter_arg *arg;
617 switch ((*parg)->type) { 408
618 case FILTER_ARG_BOOLEAN: 409 arg = allocate_arg();
410 /* Use NUM and change if necessary */
411 arg->type = FILTER_ARG_NUM;
412 arg->op.type = etype;
413
414 return arg;
415}
416
417static int add_right(struct filter_arg *op, struct filter_arg *arg,
418 char **error_str)
419{
420 struct filter_arg *left;
421 char *str;
422 int op_type;
423 int ret;
424
425 switch (op->type) {
426 case FILTER_ARG_EXP:
427 if (op->exp.right)
428 goto out_fail;
429 op->exp.right = arg;
430 break;
431
432 case FILTER_ARG_OP:
433 if (op->op.right)
434 goto out_fail;
435 op->op.right = arg;
436 break;
437
438 case FILTER_ARG_NUM:
439 if (op->op.right)
440 goto out_fail;
441 /*
442 * The arg must be num, str, or field
443 */
444 switch (arg->type) {
619 case FILTER_ARG_VALUE: 445 case FILTER_ARG_VALUE:
620 case FILTER_ARG_FIELD: 446 case FILTER_ARG_FIELD:
621 case FILTER_ARG_EXP:
622 break; 447 break;
623 default: 448 default:
624 show_error(error_str, "expected a value"); 449 show_error(error_str,
625 free_token(token); 450 "Illegal rvalue");
626 return EVENT_ERROR; 451 return -1;
627 } 452 }
628 } else {
629 type = process_value_token(event, parg, type, &token, error_str);
630 free_token(token);
631 if (type == EVENT_ERROR)
632 return type;
633 type = read_token(&token);
634 }
635 453
636 *tok = token; 454 /*
637 return type; 455 * Depending on the type, we may need to
638} 456 * convert this to a string or regex.
457 */
458 switch (arg->value.type) {
459 case FILTER_CHAR:
460 /*
461 * A char should be converted to number if
462 * the string is 1 byte, and the compare
463 * is not a REGEX.
464 */
465 if (strlen(arg->value.str) == 1 &&
466 op->num.type != FILTER_CMP_REGEX &&
467 op->num.type != FILTER_CMP_NOT_REGEX) {
468 arg->value.type = FILTER_NUMBER;
469 goto do_int;
470 }
471 /* fall through */
472 case FILTER_STRING:
639 473
640/* 474 /* convert op to a string arg */
641 * Input: larg 475 op_type = op->num.type;
642 * Output: parg, tok 476 left = op->num.left;
643 */ 477 str = arg->value.str;
644static enum event_type
645process_cmp(struct event_format *event, enum filter_cmp_type op_type,
646 struct filter_arg *larg, struct filter_arg **parg,
647 char **tok, char **error_str)
648{
649 struct filter_arg *arg;
650 struct filter_arg *rarg = NULL;
651 enum event_type orig_type;
652 enum event_type type;
653 int ret;
654 478
655 *parg = NULL; 479 /* reset the op for the new field */
480 memset(op, 0, sizeof(*op));
656 481
657 type = process_value(event, &rarg, &orig_type, tok, error_str); 482 /*
658 if (type == EVENT_ERROR) { 483 * If left arg was a field not found then
659 free_arg(rarg); 484 * NULL the entire op.
660 return type; 485 */
661 } 486 if (left->type == FILTER_ARG_BOOLEAN) {
487 free_arg(left);
488 free_arg(arg);
489 op->type = FILTER_ARG_BOOLEAN;
490 op->bool.value = FILTER_FALSE;
491 break;
492 }
662 493
663 arg = allocate_arg(); 494 /* Left arg must be a field */
664 /* 495 if (left->type != FILTER_ARG_FIELD) {
665 * If either arg is NULL or right was field not found. 496 show_error(error_str,
666 * Then make the entire expression NULL. (will turn to FALSE) 497 "Illegal lvalue for string comparison");
667 */ 498 return -1;
668 if (!larg || !rarg) { 499 }
669 free_arg(larg);
670 free_arg(rarg);
671 free_arg(arg);
672 arg = NULL;
673 goto cont;
674 }
675 500
676 switch (orig_type) { 501 /* Make sure this is a valid string compare */
677 case EVENT_SQUOTE:
678 /* treat this as a character if string is of length 1? */
679 if (strlen(rarg->str.val) == 1) {
680 switch (op_type) { 502 switch (op_type) {
503 case FILTER_CMP_EQ:
504 op_type = FILTER_CMP_MATCH;
505 break;
506 case FILTER_CMP_NE:
507 op_type = FILTER_CMP_NOT_MATCH;
508 break;
509
681 case FILTER_CMP_REGEX: 510 case FILTER_CMP_REGEX:
682 case FILTER_CMP_NOT_REGEX: 511 case FILTER_CMP_NOT_REGEX:
683 /* regex can't be used with ints */ 512 ret = regcomp(&op->str.reg, str, REG_ICASE|REG_NOSUB);
513 if (ret) {
514 show_error(error_str,
515 "RegEx '%s' did not compute",
516 str);
517 return -1;
518 }
684 break; 519 break;
685 default: 520 default:
686 goto as_int; 521 show_error(error_str,
522 "Illegal comparison for string");
523 return -1;
687 } 524 }
688 }
689 /* fall through */
690 case EVENT_DQUOTE:
691 arg->type = FILTER_ARG_STR;
692
693 if (larg->type != FILTER_ARG_FIELD) {
694 free(larg);
695 free(rarg);
696 show_error(error_str,
697 "Illegal lval for string comparison");
698 free_arg(arg);
699 return EVENT_ERROR;
700 }
701 525
702 arg->str.field = larg->field.field; 526 op->type = FILTER_ARG_STR;
703 free_arg(larg); 527 op->str.type = op_type;
528 op->str.field = left->field.field;
529 op->str.val = strdup(str);
530 if (!op->str.val)
531 die("malloc string");
532 /*
533 * Need a buffer to copy data for tests
534 */
535 op->str.buffer = malloc_or_die(op->str.field->size + 1);
536 /* Null terminate this buffer */
537 op->str.buffer[op->str.field->size] = 0;
704 538
705 /* free the rarg, and use its token */ 539 /* We no longer have left or right args */
706 arg->str.val = rarg->value.str; 540 free_arg(arg);
707 rarg->value.str = NULL; 541 free_arg(left);
708 free_arg(rarg);
709 542
710 /* Make sure this is a valid string compare */
711 switch (op_type) {
712 case FILTER_CMP_EQ:
713 op_type = FILTER_CMP_MATCH;
714 break;
715 case FILTER_CMP_NE:
716 op_type = FILTER_CMP_NOT_MATCH;
717 break; 543 break;
718 544
719 case FILTER_CMP_REGEX: 545 case FILTER_NUMBER:
720 case FILTER_CMP_NOT_REGEX: 546
721 ret = regcomp(&arg->str.reg, arg->str.val, REG_ICASE|REG_NOSUB); 547 do_int:
722 if (ret) { 548 switch (op->num.type) {
549 case FILTER_CMP_REGEX:
550 case FILTER_CMP_NOT_REGEX:
723 show_error(error_str, 551 show_error(error_str,
724 "RegEx '%s' did not compute", 552 "Op not allowed with integers");
725 arg->str.val); 553 return -1;
726 free_arg(arg); 554
727 return EVENT_ERROR; 555 default:
556 break;
728 } 557 }
558
559 /* numeric compare */
560 op->num.right = arg;
729 break; 561 break;
730 default: 562 default:
731 show_error(error_str, 563 goto out_fail;
732 "Illegal comparison for string");
733 free_arg(arg);
734 return EVENT_ERROR;
735 } 564 }
736
737 arg->str.type = op_type;
738
739 /*
740 * Need a buffer to copy data int for tests */
741 arg->str.buffer = malloc_or_die(arg->str.field->size + 1);
742 /* Null terminate this buffer */
743 arg->str.buffer[arg->str.field->size] = 0;
744
745 break; 565 break;
746 default: 566 default:
747 as_int: 567 goto out_fail;
748 switch (op_type) {
749 case FILTER_CMP_REGEX:
750 case FILTER_CMP_NOT_REGEX:
751 show_error(error_str,
752 "Op not allowed with integers");
753 free_arg(arg);
754 return EVENT_ERROR;
755 default:
756 break;
757 }
758 /* numeric compare */
759 arg->type = FILTER_ARG_NUM;
760 arg->num.type = op_type;
761 arg->num.left = larg;
762 arg->num.right = rarg;
763 break;
764 } 568 }
765 cont: 569
766 *parg = arg; 570 return 0;
767 return type; 571
572 out_fail:
573 show_error(error_str,
574 "Syntax error");
575 return -1;
768} 576}
769 577
770/* 578static struct filter_arg *
771 * Input: larg 579rotate_op_right(struct filter_arg *a, struct filter_arg *b)
772 * Output: parg, tok
773 */
774static enum event_type
775process_exp(struct event_format *event, enum filter_exp_type etype,
776 struct filter_arg *larg, struct filter_arg **parg,
777 char **tok, char **error_str)
778{ 580{
779 struct filter_arg *rarg = NULL;
780 struct filter_arg *arg; 581 struct filter_arg *arg;
781 enum event_type orig_type;
782 enum event_type type;
783 582
784 type = process_value(event, &rarg, &orig_type, tok, error_str); 583 arg = a->op.right;
785 if (type == EVENT_ERROR) { 584 a->op.right = b;
786 free_arg(rarg); 585 return arg;
787 return type; 586}
788 }
789 587
790 /* larg can be NULL if a field did not match */ 588static int add_left(struct filter_arg *op, struct filter_arg *arg)
791 if (!larg) { 589{
792 /* syntax is correct, just return NULL */ 590 switch (op->type) {
793 arg = NULL; 591 case FILTER_ARG_EXP:
794 free_arg(rarg); 592 if (arg->type == FILTER_ARG_OP)
795 goto cont; 593 arg = rotate_op_right(arg, op);
796 } 594 op->exp.left = arg;
595 break;
797 596
798 arg = allocate_arg(); 597 case FILTER_ARG_OP:
799 arg->type = FILTER_ARG_EXP; 598 op->op.left = arg;
800 arg->exp.type = etype; 599 break;
801 arg->exp.left = larg; 600 case FILTER_ARG_NUM:
802 arg->exp.right = rarg; 601 if (arg->type == FILTER_ARG_OP)
602 arg = rotate_op_right(arg, op);
803 603
804 cont: 604 /* left arg of compares must be a field */
805 /* still need a cmp */ 605 if (arg->type != FILTER_ARG_FIELD &&
806 type = process_op_token(event, arg, parg, type, tok, error_str); 606 arg->type != FILTER_ARG_BOOLEAN)
807 return type; 607 return -1;
608 op->num.left = arg;
609 break;
610 default:
611 return -1;
612 }
613 return 0;
808} 614}
809 615
810/* 616enum op_type {
811 * Input: tok 617 OP_NONE,
812 * Output: parg, tok 618 OP_BOOL,
813 */ 619 OP_NOT,
814static enum event_type 620 OP_EXP,
815process_op_token(struct event_format *event, struct filter_arg *larg, 621 OP_CMP,
816 struct filter_arg **parg, enum event_type type, char **tok, 622};
817 char **error_str) 623
624static enum op_type process_op(const char *token,
625 enum filter_op_type *btype,
626 enum filter_cmp_type *ctype,
627 enum filter_exp_type *etype)
818{ 628{
819 enum filter_cmp_type ctype; 629 *btype = FILTER_OP_NOT;
820 enum filter_exp_type etype = FILTER_EXP_NONE; 630 *etype = FILTER_EXP_NONE;
821 char *token; 631 *ctype = FILTER_CMP_NONE;
822 632
823 token = *tok; 633 if (strcmp(token, "&&") == 0)
824 *parg = NULL; 634 *btype = FILTER_OP_AND;
635 else if (strcmp(token, "||") == 0)
636 *btype = FILTER_OP_OR;
637 else if (strcmp(token, "!") == 0)
638 return OP_NOT;
825 639
826 if (type != EVENT_OP) { 640 if (*btype != FILTER_OP_NOT)
827 *parg = larg; 641 return OP_BOOL;
828 return type;
829 }
830
831 if (strcmp(token, "&&") == 0 || strcmp(token, "||") == 0) {
832 /* handle boolean cases */
833 return process_bool(event, larg, parg, tok, error_str);
834 }
835 642
836 /* Check for value expressions */ 643 /* Check for value expressions */
837 if (strcmp(token, "+") == 0) { 644 if (strcmp(token, "+") == 0) {
838 etype = FILTER_EXP_ADD; 645 *etype = FILTER_EXP_ADD;
839 } else if (strcmp(token, "-") == 0) { 646 } else if (strcmp(token, "-") == 0) {
840 etype = FILTER_EXP_SUB; 647 *etype = FILTER_EXP_SUB;
841 } else if (strcmp(token, "*") == 0) { 648 } else if (strcmp(token, "*") == 0) {
842 etype = FILTER_EXP_MUL; 649 *etype = FILTER_EXP_MUL;
843 } else if (strcmp(token, "/") == 0) { 650 } else if (strcmp(token, "/") == 0) {
844 etype = FILTER_EXP_DIV; 651 *etype = FILTER_EXP_DIV;
845 } else if (strcmp(token, "%") == 0) { 652 } else if (strcmp(token, "%") == 0) {
846 etype = FILTER_EXP_MOD; 653 *etype = FILTER_EXP_MOD;
847 } else if (strcmp(token, ">>") == 0) { 654 } else if (strcmp(token, ">>") == 0) {
848 etype = FILTER_EXP_RSHIFT; 655 *etype = FILTER_EXP_RSHIFT;
849 } else if (strcmp(token, "<<") == 0) { 656 } else if (strcmp(token, "<<") == 0) {
850 etype = FILTER_EXP_LSHIFT; 657 *etype = FILTER_EXP_LSHIFT;
851 } else if (strcmp(token, "&") == 0) { 658 } else if (strcmp(token, "&") == 0) {
852 etype = FILTER_EXP_AND; 659 *etype = FILTER_EXP_AND;
853 } else if (strcmp(token, "|") == 0) { 660 } else if (strcmp(token, "|") == 0) {
854 etype = FILTER_EXP_OR; 661 *etype = FILTER_EXP_OR;
855 } else if (strcmp(token, "^") == 0) { 662 } else if (strcmp(token, "^") == 0) {
856 etype = FILTER_EXP_XOR; 663 *etype = FILTER_EXP_XOR;
857 } else if (strcmp(token, "~") == 0) 664 } else if (strcmp(token, "~") == 0)
858 etype = FILTER_EXP_NOT; 665 *etype = FILTER_EXP_NOT;
666
667 if (*etype != FILTER_EXP_NONE)
668 return OP_EXP;
669
670 /* Check for compares */
671 if (strcmp(token, "==") == 0)
672 *ctype = FILTER_CMP_EQ;
673 else if (strcmp(token, "!=") == 0)
674 *ctype = FILTER_CMP_NE;
675 else if (strcmp(token, "<") == 0)
676 *ctype = FILTER_CMP_LT;
677 else if (strcmp(token, ">") == 0)
678 *ctype = FILTER_CMP_GT;
679 else if (strcmp(token, "<=") == 0)
680 *ctype = FILTER_CMP_LE;
681 else if (strcmp(token, ">=") == 0)
682 *ctype = FILTER_CMP_GE;
683 else if (strcmp(token, "=~") == 0)
684 *ctype = FILTER_CMP_REGEX;
685 else if (strcmp(token, "!~") == 0)
686 *ctype = FILTER_CMP_NOT_REGEX;
687 else
688 return OP_NONE;
859 689
860 if (etype != FILTER_EXP_NONE) { 690 return OP_CMP;
861 free_token(token); 691}
862 return process_exp(event, etype, larg, parg, tok, error_str);
863 }
864 692
865 if (strcmp(token, "==") == 0) { 693static int check_op_done(struct filter_arg *arg)
866 ctype = FILTER_CMP_EQ; 694{
867 } else if (strcmp(token, "!=") == 0) { 695 switch (arg->type) {
868 ctype = FILTER_CMP_NE; 696 case FILTER_ARG_EXP:
869 } else if (strcmp(token, "<") == 0) { 697 return arg->exp.right != NULL;
870 ctype = FILTER_CMP_LT;
871 } else if (strcmp(token, ">") == 0) {
872 ctype = FILTER_CMP_GT;
873 } else if (strcmp(token, "<=") == 0) {
874 ctype = FILTER_CMP_LE;
875 } else if (strcmp(token, ">=") == 0) {
876 ctype = FILTER_CMP_GE;
877 } else if (strcmp(token, "=~") == 0) {
878 ctype = FILTER_CMP_REGEX;
879 } else if (strcmp(token, "!~") == 0) {
880 ctype = FILTER_CMP_NOT_REGEX;
881 } else {
882 show_error(error_str,
883 "Unknown op '%s'", token);
884 free_token(token);
885 return EVENT_ERROR;
886 }
887 698
888 free_token(token); 699 case FILTER_ARG_OP:
889 *tok = NULL; 700 return arg->op.right != NULL;
890 return process_cmp(event, ctype, larg, parg, tok, error_str); 701
702 case FILTER_ARG_NUM:
703 return arg->num.right != NULL;
704
705 case FILTER_ARG_STR:
706 /* A string conversion is always done */
707 return 1;
708
709 case FILTER_ARG_BOOLEAN:
710 /* field not found, is ok */
711 return 1;
712
713 default:
714 return 0;
715 }
891} 716}
892 717
893static enum event_type 718enum filter_vals {
894process_filter(struct event_format *event, struct filter_arg **parg, 719 FILTER_VAL_NORM,
895 char **tok, char **error_str) 720 FILTER_VAL_FALSE,
896{ 721 FILTER_VAL_TRUE,
897 struct filter_arg *larg = NULL; 722};
898 enum event_type type;
899 723
900 *parg = NULL; 724void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child,
901 *tok = NULL; 725 struct filter_arg *arg)
726{
727 struct filter_arg *other_child;
728 struct filter_arg **ptr;
729
730 if (parent->type != FILTER_ARG_OP &&
731 arg->type != FILTER_ARG_OP)
732 die("can not reparent other than OP");
733
734 /* Get the sibling */
735 if (old_child->op.right == arg) {
736 ptr = &old_child->op.right;
737 other_child = old_child->op.left;
738 } else if (old_child->op.left == arg) {
739 ptr = &old_child->op.left;
740 other_child = old_child->op.right;
741 } else
742 die("Error in reparent op, find other child");
902 743
903 type = process_token(event, parg, tok, error_str); 744 /* Detach arg from old_child */
745 *ptr = NULL;
904 746
905 if (type == EVENT_OP && 747 /* Check for root */
906 (strcmp(*tok, "&&") == 0 || strcmp(*tok, "||") == 0)) { 748 if (parent == old_child) {
907 larg = *parg; 749 free_arg(other_child);
908 *parg = NULL; 750 *parent = *arg;
909 type = process_bool(event, larg, parg, tok, error_str); 751 /* Free arg without recussion */
752 free(arg);
753 return;
910 } 754 }
911 755
912 return type; 756 if (parent->op.right == old_child)
757 ptr = &parent->op.right;
758 else if (parent->op.left == old_child)
759 ptr = &parent->op.left;
760 else
761 die("Error in reparent op");
762 *ptr = arg;
763
764 free_arg(old_child);
913} 765}
914 766
915static enum event_type 767enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg)
916process_paren(struct event_format *event, struct filter_arg **parg,
917 char **tok, char **error_str)
918{ 768{
919 struct filter_arg *arg; 769 enum filter_vals lval, rval;
920 enum event_type type;
921 770
922 *parg = NULL; 771 switch (arg->type) {
923 772
924 type = process_token(event, &arg, tok, error_str); 773 /* bad case */
925 if (type == EVENT_ERROR) { 774 case FILTER_ARG_BOOLEAN:
926 free_arg(arg); 775 return FILTER_VAL_FALSE + arg->bool.value;
927 return type;
928 }
929 776
930 if (type == EVENT_OP && 777 /* good cases: */
931 (strcmp(*tok, "&&") == 0 || strcmp(*tok, "||") == 0)) { 778 case FILTER_ARG_STR:
932 type = process_bool(event, arg, parg, tok, error_str); 779 case FILTER_ARG_VALUE:
933 } 780 case FILTER_ARG_FIELD:
781 return FILTER_VAL_NORM;
934 782
935 if (type != EVENT_DELIM || strcmp(*tok, ")") != 0) { 783 case FILTER_ARG_EXP:
936 if (*tok) 784 lval = test_arg(arg, arg->exp.left);
937 show_error(error_str, 785 if (lval != FILTER_VAL_NORM)
938 "Expected ')' but found %s", *tok); 786 return lval;
939 else 787 rval = test_arg(arg, arg->exp.right);
940 show_error(error_str, 788 if (rval != FILTER_VAL_NORM)
941 "Unexpected end of filter; Expected ')'"); 789 return rval;
942 free_token(*tok); 790 return FILTER_VAL_NORM;
943 *tok = NULL;
944 free_arg(arg);
945 return EVENT_ERROR;
946 }
947 free_token(*tok);
948 *tok = NULL;
949 791
950 *parg = arg; 792 case FILTER_ARG_NUM:
793 lval = test_arg(arg, arg->num.left);
794 if (lval != FILTER_VAL_NORM)
795 return lval;
796 rval = test_arg(arg, arg->num.right);
797 if (rval != FILTER_VAL_NORM)
798 return rval;
799 return FILTER_VAL_NORM;
800
801 case FILTER_ARG_OP:
802 if (arg->op.type != FILTER_OP_NOT) {
803 lval = test_arg(arg, arg->op.left);
804 switch (lval) {
805 case FILTER_VAL_NORM:
806 break;
807 case FILTER_VAL_TRUE:
808 if (arg->op.type == FILTER_OP_OR)
809 return FILTER_VAL_TRUE;
810 rval = test_arg(arg, arg->op.right);
811 if (rval != FILTER_VAL_NORM)
812 return rval;
813
814 reparent_op_arg(parent, arg, arg->op.right);
815 return FILTER_VAL_NORM;
816
817 case FILTER_VAL_FALSE:
818 if (arg->op.type == FILTER_OP_AND)
819 return FILTER_VAL_FALSE;
820 rval = test_arg(arg, arg->op.right);
821 if (rval != FILTER_VAL_NORM)
822 return rval;
823
824 reparent_op_arg(parent, arg, arg->op.right);
825 return FILTER_VAL_NORM;
826 }
827 }
828
829 rval = test_arg(arg, arg->op.right);
830 switch (rval) {
831 case FILTER_VAL_NORM:
832 break;
833 case FILTER_VAL_TRUE:
834 if (arg->op.type == FILTER_OP_OR)
835 return FILTER_VAL_TRUE;
836 if (arg->op.type == FILTER_OP_NOT)
837 return FILTER_VAL_FALSE;
838
839 reparent_op_arg(parent, arg, arg->op.left);
840 return FILTER_VAL_NORM;
841
842 case FILTER_VAL_FALSE:
843 if (arg->op.type == FILTER_OP_AND)
844 return FILTER_VAL_FALSE;
845 if (arg->op.type == FILTER_OP_NOT)
846 return FILTER_VAL_TRUE;
847
848 reparent_op_arg(parent, arg, arg->op.left);
849 return FILTER_VAL_NORM;
850 }
951 851
952 return read_token(tok); 852 return FILTER_VAL_NORM;
853 default:
854 die("bad arg in filter tree");
855 }
856 return FILTER_VAL_NORM;
953} 857}
954 858
955static enum event_type 859/* Remove any unknown event fields */
956process_not(struct event_format *event, struct filter_arg **parg, 860static struct filter_arg *collapse_tree(struct filter_arg *arg)
957 char **tok, char **error_str)
958{ 861{
959 struct filter_arg *arg; 862 enum filter_vals ret;
960 enum event_type type;
961 863
962 arg = allocate_arg(); 864 ret = test_arg(arg, arg);
963 arg->type = FILTER_ARG_OP; 865 switch (ret) {
964 arg->op.type = FILTER_OP_NOT; 866 case FILTER_VAL_NORM:
867 return arg;
965 868
966 arg->op.left = NULL; 869 case FILTER_VAL_TRUE:
967 type = process_token(event, &arg->op.right, tok, error_str); 870 case FILTER_VAL_FALSE:
968 if (type == EVENT_ERROR) {
969 free_arg(arg); 871 free_arg(arg);
970 *parg = NULL; 872 arg = allocate_arg();
971 free_token(*tok);
972 *tok = NULL;
973 return EVENT_ERROR;
974 }
975 /* If the bool value is NULL, then make this into TRUE */
976 if (!arg->op.right) {
977 arg->type = FILTER_ARG_BOOLEAN; 873 arg->type = FILTER_ARG_BOOLEAN;
978 arg->bool.value = FILTER_TRUE; 874 arg->bool.value = ret == FILTER_VAL_TRUE;
979 } 875 }
980 876
981 *parg = arg; 877 return arg;
982 free_token(*tok); 878}
983 *tok = NULL;
984 879
985 return type; 880static int
881process_filter(struct event_format *event, struct filter_arg **parg,
882 char **error_str, int not)
883{
884 enum event_type type;
885 char *token = NULL;
886 struct filter_arg *current_op = NULL;
887 struct filter_arg *current_exp = NULL;
888 struct filter_arg *left_item = NULL;
889 struct filter_arg *arg = NULL;
890 enum op_type op_type;
891 enum filter_op_type btype;
892 enum filter_exp_type etype;
893 enum filter_cmp_type ctype;
894 int ret;
895
896 *parg = NULL;
897
898 do {
899 free(token);
900 type = read_token(&token);
901 switch (type) {
902 case EVENT_SQUOTE:
903 case EVENT_DQUOTE:
904 case EVENT_ITEM:
905 arg = create_arg_item(event, token, type, error_str);
906 if (!arg)
907 goto fail;
908 if (!left_item)
909 left_item = arg;
910 else if (current_exp) {
911 ret = add_right(current_exp, arg, error_str);
912 if (ret < 0)
913 goto fail;
914 left_item = NULL;
915 /* Not's only one one expression */
916 if (not) {
917 arg = NULL;
918 if (current_op)
919 goto fail_print;
920 free(token);
921 *parg = current_exp;
922 return 0;
923 }
924 } else
925 goto fail_print;
926 arg = NULL;
927 break;
928
929 case EVENT_DELIM:
930 if (*token == ',') {
931 show_error(error_str,
932 "Illegal token ','");
933 goto fail;
934 }
935
936 if (*token == '(') {
937 if (left_item) {
938 show_error(error_str,
939 "Open paren can not come after item");
940 goto fail;
941 }
942 if (current_exp) {
943 show_error(error_str,
944 "Open paren can not come after expression");
945 goto fail;
946 }
947
948 ret = process_filter(event, &arg, error_str, 0);
949 if (ret != 1) {
950 if (ret == 0)
951 show_error(error_str,
952 "Unbalanced number of '('");
953 goto fail;
954 }
955 ret = 0;
956
957 /* A not wants just one expression */
958 if (not) {
959 if (current_op)
960 goto fail_print;
961 *parg = arg;
962 return 0;
963 }
964
965 if (current_op)
966 ret = add_right(current_op, arg, error_str);
967 else
968 current_exp = arg;
969
970 if (ret < 0)
971 goto fail;
972
973 } else { /* ')' */
974 if (!current_op && !current_exp)
975 goto fail_print;
976
977 /* Make sure everything is finished at this level */
978 if (current_exp && !check_op_done(current_exp))
979 goto fail_print;
980 if (current_op && !check_op_done(current_op))
981 goto fail_print;
982
983 if (current_op)
984 *parg = current_op;
985 else
986 *parg = current_exp;
987 return 1;
988 }
989 break;
990
991 case EVENT_OP:
992 op_type = process_op(token, &btype, &ctype, &etype);
993
994 /* All expect a left arg except for NOT */
995 switch (op_type) {
996 case OP_BOOL:
997 /* Logic ops need a left expression */
998 if (!current_exp && !current_op)
999 goto fail_print;
1000 /* fall through */
1001 case OP_NOT:
1002 /* logic only processes ops and exp */
1003 if (left_item)
1004 goto fail_print;
1005 break;
1006 case OP_EXP:
1007 case OP_CMP:
1008 if (!left_item)
1009 goto fail_print;
1010 break;
1011 case OP_NONE:
1012 show_error(error_str,
1013 "Unknown op token %s", token);
1014 goto fail;
1015 }
1016
1017 ret = 0;
1018 switch (op_type) {
1019 case OP_BOOL:
1020 arg = create_arg_op(btype);
1021 if (current_op)
1022 ret = add_left(arg, current_op);
1023 else
1024 ret = add_left(arg, current_exp);
1025 current_op = arg;
1026 current_exp = NULL;
1027 break;
1028
1029 case OP_NOT:
1030 arg = create_arg_op(btype);
1031 if (current_op)
1032 ret = add_right(current_op, arg, error_str);
1033 if (ret < 0)
1034 goto fail;
1035 current_exp = arg;
1036 ret = process_filter(event, &arg, error_str, 1);
1037 if (ret < 0)
1038 goto fail;
1039 ret = add_right(current_exp, arg, error_str);
1040 if (ret < 0)
1041 goto fail;
1042 break;
1043
1044 case OP_EXP:
1045 case OP_CMP:
1046 if (op_type == OP_EXP)
1047 arg = create_arg_exp(etype);
1048 else
1049 arg = create_arg_cmp(ctype);
1050
1051 if (current_op)
1052 ret = add_right(current_op, arg, error_str);
1053 if (ret < 0)
1054 goto fail;
1055 ret = add_left(arg, left_item);
1056 if (ret < 0) {
1057 arg = NULL;
1058 goto fail_print;
1059 }
1060 current_exp = arg;
1061 break;
1062 default:
1063 break;
1064 }
1065 arg = NULL;
1066 if (ret < 0)
1067 goto fail_print;
1068 break;
1069 case EVENT_NONE:
1070 break;
1071 default:
1072 goto fail_print;
1073 }
1074 } while (type != EVENT_NONE);
1075
1076 if (!current_op && !current_exp)
1077 goto fail_print;
1078
1079 if (!current_op)
1080 current_op = current_exp;
1081
1082 current_op = collapse_tree(current_op);
1083
1084 *parg = current_op;
1085
1086 return 0;
1087
1088 fail_print:
1089 show_error(error_str, "Syntax error");
1090 fail:
1091 free_arg(current_op);
1092 free_arg(current_exp);
1093 free_arg(arg);
1094 free(token);
1095 return -1;
986} 1096}
987 1097
988static int 1098static int
989process_event(struct event_format *event, const char *filter_str, 1099process_event(struct event_format *event, const char *filter_str,
990 struct filter_arg **parg, char **error_str) 1100 struct filter_arg **parg, char **error_str)
991{ 1101{
992 enum event_type type; 1102 int ret;
993 char *token;
994 1103
995 pevent_buffer_init(filter_str, strlen(filter_str)); 1104 pevent_buffer_init(filter_str, strlen(filter_str));
996 1105
997 type = process_filter(event, parg, &token, error_str); 1106 ret = process_filter(event, parg, error_str, 0);
998 1107 if (ret == 1) {
999 if (type == EVENT_ERROR)
1000 return -1;
1001
1002 if (type != EVENT_NONE) {
1003 show_error(error_str, 1108 show_error(error_str,
1004 "Expected end where %s was found", 1109 "Unbalanced number of ')'");
1005 token);
1006 free_token(token);
1007 free_arg(*parg);
1008 *parg = NULL;
1009 return -1; 1110 return -1;
1010 } 1111 }
1112 if (ret < 0)
1113 return ret;
1011 1114
1012 /* If parg is NULL, then make it into FALSE */ 1115 /* If parg is NULL, then make it into FALSE */
1013 if (!*parg) { 1116 if (!*parg) {
@@ -1031,6 +1134,7 @@ static int filter_event(struct event_filter *filter,
1031 ret = process_event(event, filter_str, &arg, error_str); 1134 ret = process_event(event, filter_str, &arg, error_str);
1032 if (ret < 0) 1135 if (ret < 0)
1033 return ret; 1136 return ret;
1137
1034 } else { 1138 } else {
1035 /* just add a TRUE arg */ 1139 /* just add a TRUE arg */
1036 arg = allocate_arg(); 1140 arg = allocate_arg();