diff options
| author | Steven Rostedt <srostedt@redhat.com> | 2011-01-17 19:05:10 -0500 |
|---|---|---|
| committer | Steven Rostedt <rostedt@goodmis.org> | 2011-02-01 21:00:59 -0500 |
| commit | 749f8c9a993d1feb059cabf35a35b64153bd68ea (patch) | |
| tree | 4329bf294cd99e16d0e7b95e0b098c389ea42b5d | |
| parent | e941806a43c2eb46769959e44b3c54f332d4418b (diff) | |
trace-cmd: Restructure the enable and filtering of events
Use glob to expand the events given on the command line into
separate entities on the event_selection list. This will allow
easier settings of the filters during execution time.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
| -rw-r--r-- | trace-cmd.c | 382 |
1 files changed, 215 insertions, 167 deletions
diff --git a/trace-cmd.c b/trace-cmd.c index 9965428..ad3ac91 100644 --- a/trace-cmd.c +++ b/trace-cmd.c | |||
| @@ -99,6 +99,8 @@ struct event_list { | |||
| 99 | struct event_list *next; | 99 | struct event_list *next; |
| 100 | const char *event; | 100 | const char *event; |
| 101 | char *filter; | 101 | char *filter; |
| 102 | char *filter_file; | ||
| 103 | char *enable_file; | ||
| 102 | int neg; | 104 | int neg; |
| 103 | }; | 105 | }; |
| 104 | 106 | ||
| @@ -521,6 +523,29 @@ static void set_options(void) | |||
| 521 | } | 523 | } |
| 522 | } | 524 | } |
| 523 | 525 | ||
| 526 | static int use_old_event_method(void) | ||
| 527 | { | ||
| 528 | static int old_event_method; | ||
| 529 | static int processed; | ||
| 530 | struct stat st; | ||
| 531 | char *path; | ||
| 532 | int ret; | ||
| 533 | |||
| 534 | if (processed) | ||
| 535 | return old_event_method; | ||
| 536 | |||
| 537 | /* Check if the kernel has the events/enable file */ | ||
| 538 | path = tracecmd_get_tracing_file("events/enable"); | ||
| 539 | ret = stat(path, &st); | ||
| 540 | tracecmd_put_tracing_file(path); | ||
| 541 | if (ret < 0) | ||
| 542 | old_event_method = 1; | ||
| 543 | |||
| 544 | processed = 1; | ||
| 545 | |||
| 546 | return old_event_method; | ||
| 547 | } | ||
| 548 | |||
| 524 | static void old_update_events(const char *name, char update) | 549 | static void old_update_events(const char *name, char update) |
| 525 | { | 550 | { |
| 526 | char *path; | 551 | char *path; |
| @@ -554,6 +579,47 @@ static void old_update_events(const char *name, char update) | |||
| 554 | return; | 579 | return; |
| 555 | } | 580 | } |
| 556 | 581 | ||
| 582 | static void reset_events() | ||
| 583 | { | ||
| 584 | glob_t globbuf; | ||
| 585 | char *path; | ||
| 586 | char c; | ||
| 587 | int fd; | ||
| 588 | int i; | ||
| 589 | int ret; | ||
| 590 | |||
| 591 | if (use_old_event_method()) { | ||
| 592 | old_update_events("all", '0'); | ||
| 593 | return; | ||
| 594 | } | ||
| 595 | |||
| 596 | c = '0'; | ||
| 597 | path = tracecmd_get_tracing_file("events/enable"); | ||
| 598 | fd = open(path, O_WRONLY); | ||
| 599 | if (fd < 0) | ||
| 600 | die("opening to '%s'", path); | ||
| 601 | ret = write(fd, &c, 1); | ||
| 602 | close(fd); | ||
| 603 | tracecmd_put_tracing_file(path); | ||
| 604 | |||
| 605 | path = tracecmd_get_tracing_file("events/*/filter"); | ||
| 606 | globbuf.gl_offs = 0; | ||
| 607 | ret = glob(path, 0, NULL, &globbuf); | ||
| 608 | tracecmd_put_tracing_file(path); | ||
| 609 | if (ret < 0) | ||
| 610 | return; | ||
| 611 | |||
| 612 | for (i = 0; i < globbuf.gl_pathc; i++) { | ||
| 613 | path = globbuf.gl_pathv[i]; | ||
| 614 | fd = open(path, O_WRONLY); | ||
| 615 | if (fd < 0) | ||
| 616 | die("opening to '%s'", path); | ||
| 617 | ret = write(fd, &c, 1); | ||
| 618 | close(fd); | ||
| 619 | } | ||
| 620 | globfree(&globbuf); | ||
| 621 | } | ||
| 622 | |||
| 557 | static void write_filter(const char *file, const char *filter) | 623 | static void write_filter(const char *file, const char *filter) |
| 558 | { | 624 | { |
| 559 | char buf[BUFSIZ]; | 625 | char buf[BUFSIZ]; |
| @@ -578,182 +644,35 @@ static void write_filter(const char *file, const char *filter) | |||
| 578 | } | 644 | } |
| 579 | } | 645 | } |
| 580 | 646 | ||
| 581 | static int update_glob(const char *name, const char *filter, | 647 | static void |
| 582 | int filter_only, char update) | 648 | update_event(struct event_list *event, const char *filter, |
| 649 | int filter_only, char update) | ||
| 583 | { | 650 | { |
| 584 | glob_t globbuf; | 651 | const char *name = event->event; |
| 585 | FILE *fp; | 652 | FILE *fp; |
| 586 | char *filter_file; | ||
| 587 | char *path; | 653 | char *path; |
| 588 | char *str; | ||
| 589 | int len; | ||
| 590 | int ret; | 654 | int ret; |
| 591 | int i; | ||
| 592 | int count = 0; | ||
| 593 | |||
| 594 | len = strlen(name) + strlen("events//enable") + 1; | ||
| 595 | str = malloc_or_die(len); | ||
| 596 | snprintf(str, len, "events/%s/enable", name); | ||
| 597 | path = tracecmd_get_tracing_file(str); | ||
| 598 | free(str); | ||
| 599 | 655 | ||
| 600 | globbuf.gl_offs = 0; | 656 | if (use_old_event_method()) { |
| 601 | printf("path = %s\n", path); | ||
| 602 | ret = glob(path, GLOB_ONLYDIR, NULL, &globbuf); | ||
| 603 | tracecmd_put_tracing_file(path); | ||
| 604 | if (ret < 0) | ||
| 605 | return 0; | ||
| 606 | |||
| 607 | for (i = 0; i < globbuf.gl_pathc; i++) { | ||
| 608 | path = globbuf.gl_pathv[i]; | ||
| 609 | |||
| 610 | filter_file = strdup(path); | ||
| 611 | if (!filter_file) | ||
| 612 | die("Allocating memory"); | ||
| 613 | |||
| 614 | /* s/enable/filter/ */ | ||
| 615 | memcpy(filter_file + strlen(filter_file) - 6, | ||
| 616 | "filter", 6); | ||
| 617 | if (filter) | ||
| 618 | write_filter(filter_file, filter); | ||
| 619 | else if (update == '1') | ||
| 620 | write_filter(filter_file, "0"); | ||
| 621 | free(filter_file); | ||
| 622 | count++; | ||
| 623 | |||
| 624 | if (filter_only) | ||
| 625 | continue; | ||
| 626 | |||
| 627 | fp = fopen(path, "w"); | ||
| 628 | if (!fp) | ||
| 629 | die("writing to '%s'", path); | ||
| 630 | ret = fwrite(&update, 1, 1, fp); | ||
| 631 | fclose(fp); | ||
| 632 | if (ret < 0) | ||
| 633 | die("writing to '%s'", path); | ||
| 634 | } | ||
| 635 | globfree(&globbuf); | ||
| 636 | return count; | ||
| 637 | } | ||
| 638 | |||
| 639 | static void filter_all_systems(const char *filter) | ||
| 640 | { | ||
| 641 | glob_t globbuf; | ||
| 642 | char *path; | ||
| 643 | int ret; | ||
| 644 | int i; | ||
| 645 | |||
| 646 | path = tracecmd_get_tracing_file("events/*/filter"); | ||
| 647 | |||
| 648 | globbuf.gl_offs = 0; | ||
| 649 | ret = glob(path, 0, NULL, &globbuf); | ||
| 650 | tracecmd_put_tracing_file(path); | ||
| 651 | if (ret < 0) | ||
| 652 | die("No filters found"); | ||
| 653 | |||
| 654 | for (i = 0; i < globbuf.gl_pathc; i++) { | ||
| 655 | path = globbuf.gl_pathv[i]; | ||
| 656 | |||
| 657 | write_filter(path, filter); | ||
| 658 | } | ||
| 659 | globfree(&globbuf); | ||
| 660 | } | ||
| 661 | |||
| 662 | static void update_event(const char *name, const char *filter, | ||
| 663 | int filter_only, char update) | ||
| 664 | { | ||
| 665 | struct stat st; | ||
| 666 | FILE *fp; | ||
| 667 | char *path; | ||
| 668 | char *str; | ||
| 669 | char *ptr; | ||
| 670 | int len; | ||
| 671 | int ret; | ||
| 672 | int ret2; | ||
| 673 | |||
| 674 | /* Check if the kernel has the events/enable file */ | ||
| 675 | path = tracecmd_get_tracing_file("events/enable"); | ||
| 676 | ret = stat(path, &st); | ||
| 677 | if (ret < 0) { | ||
| 678 | if (filter_only) | ||
| 679 | return; | ||
| 680 | tracecmd_put_tracing_file(path); | ||
| 681 | /* old kernel */ | ||
| 682 | old_update_events(name, update); | 657 | old_update_events(name, update); |
| 683 | return; | 658 | return; |
| 684 | } | 659 | } |
| 685 | 660 | ||
| 686 | if (!filter_only) | 661 | if (filter && event->filter_file) |
| 687 | fprintf(stderr, "%s %s\n", | 662 | write_filter(event->filter_file, filter); |
| 688 | update == '1' ? "enable" : "disable", name); | ||
| 689 | |||
| 690 | /* We allow the user to use "all" to enable all events */ | ||
| 691 | |||
| 692 | if (strcmp(name, "all") == 0) { | ||
| 693 | if (filter) | ||
| 694 | filter_all_systems(filter); | ||
| 695 | else if (update == '1') | ||
| 696 | filter_all_systems("0"); | ||
| 697 | |||
| 698 | if (filter_only) { | ||
| 699 | tracecmd_put_tracing_file(path); | ||
| 700 | return; | ||
| 701 | } | ||
| 702 | |||
| 703 | fp = fopen(path, "w"); | ||
| 704 | if (!fp) | ||
| 705 | die("writing to '%s'", path); | ||
| 706 | tracecmd_put_tracing_file(path); | ||
| 707 | ret = fwrite(&update, 1, 1, fp); | ||
| 708 | fclose(fp); | ||
| 709 | if (ret < 0) | ||
| 710 | die("writing to '%s'", path); | ||
| 711 | return; | ||
| 712 | } | ||
| 713 | |||
| 714 | ptr = strchr(name, ':'); | ||
| 715 | |||
| 716 | if (ptr) { | ||
| 717 | len = ptr - name; | ||
| 718 | str = strdup(name); | ||
| 719 | if (!str) | ||
| 720 | die("could not allocate memory"); | ||
| 721 | str[len] = 0; | ||
| 722 | ptr++; | ||
| 723 | if (!strlen(ptr) || strcmp(ptr, "*") == 0) { | ||
| 724 | ret = update_glob(str, filter, filter_only, update); | ||
| 725 | free(str); | ||
| 726 | tracecmd_put_tracing_file(path); | ||
| 727 | if (!ret) | ||
| 728 | goto fail; | ||
| 729 | return; | ||
| 730 | } | ||
| 731 | |||
| 732 | str[len] = '/'; | ||
| 733 | 663 | ||
| 734 | ret = update_glob(str, filter, filter_only, update); | 664 | if (filter_only || !event->enable_file) |
| 735 | free(str); | ||
| 736 | if (!ret && !ignore_event_not_found) | ||
| 737 | die("No events enabled with %s", name); | ||
| 738 | return; | 665 | return; |
| 739 | } | ||
| 740 | |||
| 741 | /* No ':' so enable all matching systems and events */ | ||
| 742 | ret = update_glob(name, filter, filter_only, update); | ||
| 743 | |||
| 744 | len = strlen(name) + strlen("*/") + 1; | ||
| 745 | str = malloc_or_die(len); | ||
| 746 | snprintf(str, len, "*/%s", name); | ||
| 747 | ret2 = update_glob(str, filter, filter_only, update); | ||
| 748 | free(str); | ||
| 749 | 666 | ||
| 750 | if (!ret && !ret2 && !ignore_event_not_found) | 667 | path = event->enable_file; |
| 751 | goto fail; | ||
| 752 | |||
| 753 | return; | ||
| 754 | fail: | ||
| 755 | die("No events enabled with %s", name); | ||
| 756 | 668 | ||
| 669 | fp = fopen(path, "w"); | ||
| 670 | if (!fp) | ||
| 671 | die("writing to '%s'", path); | ||
| 672 | ret = fwrite(&update, 1, 1, fp); | ||
| 673 | fclose(fp); | ||
| 674 | if (ret < 0) | ||
| 675 | die("writing to '%s'", path); | ||
| 757 | } | 676 | } |
| 758 | 677 | ||
| 759 | /* | 678 | /* |
| @@ -855,7 +774,7 @@ static void disable_all(void) | |||
| 855 | disable_tracing(); | 774 | disable_tracing(); |
| 856 | 775 | ||
| 857 | set_plugin("nop"); | 776 | set_plugin("nop"); |
| 858 | update_event("all", "0", 0, '0'); | 777 | reset_events(); |
| 859 | 778 | ||
| 860 | /* Force close and reset of ftrace pid file */ | 779 | /* Force close and reset of ftrace pid file */ |
| 861 | update_ftrace_pid("", 1); | 780 | update_ftrace_pid("", 1); |
| @@ -935,7 +854,7 @@ static void update_pid_event_filters(const char *pid) | |||
| 935 | strcat(event->filter, filter); | 854 | strcat(event->filter, filter); |
| 936 | } else | 855 | } else |
| 937 | event->filter = strdup(filter); | 856 | event->filter = strdup(filter); |
| 938 | update_event(event->event, event->filter, 1, '1'); | 857 | update_event(event, event->filter, 1, '1'); |
| 939 | } | 858 | } |
| 940 | } | 859 | } |
| 941 | 860 | ||
| @@ -955,13 +874,138 @@ static void enable_events(void) | |||
| 955 | 874 | ||
| 956 | for (event = event_selection; event; event = event->next) { | 875 | for (event = event_selection; event; event = event->next) { |
| 957 | if (!event->neg) | 876 | if (!event->neg) |
| 958 | update_event(event->event, event->filter, 0, '1'); | 877 | update_event(event, event->filter, 0, '1'); |
| 959 | } | 878 | } |
| 960 | 879 | ||
| 961 | /* Now disable any events */ | 880 | /* Now disable any events */ |
| 962 | for (event = event_selection; event; event = event->next) { | 881 | for (event = event_selection; event; event = event->next) { |
| 963 | if (event->neg) | 882 | if (event->neg) |
| 964 | update_event(event->event, NULL, 0, '0'); | 883 | update_event(event, NULL, 0, '0'); |
| 884 | } | ||
| 885 | } | ||
| 886 | |||
| 887 | static int expand_event_files(const char *file, struct event_list *old_event) | ||
| 888 | { | ||
| 889 | struct event_list *save_events = event_selection; | ||
| 890 | struct event_list *event; | ||
| 891 | glob_t globbuf; | ||
| 892 | struct stat st; | ||
| 893 | char *path; | ||
| 894 | char *p; | ||
| 895 | int ret; | ||
| 896 | int i; | ||
| 897 | |||
| 898 | p = malloc_or_die(strlen(file) + strlen("events//filter") + 1); | ||
| 899 | sprintf(p, "events/%s/filter", file); | ||
| 900 | |||
| 901 | path = tracecmd_get_tracing_file(p); | ||
| 902 | printf("%s\n", path); | ||
| 903 | |||
| 904 | globbuf.gl_offs = 0; | ||
| 905 | ret = glob(path, 0, NULL, &globbuf); | ||
| 906 | tracecmd_put_tracing_file(path); | ||
| 907 | free(p); | ||
| 908 | |||
| 909 | if (ret < 0) | ||
| 910 | die("No filters found"); | ||
| 911 | |||
| 912 | for (i = 0; i < globbuf.gl_pathc; i++) { | ||
| 913 | path = globbuf.gl_pathv[i]; | ||
| 914 | |||
| 915 | event = malloc_or_die(sizeof(*event)); | ||
| 916 | *event = *old_event; | ||
| 917 | event->next = event_selection; | ||
| 918 | event_selection = event; | ||
| 919 | if (event->filter || filter_task || filter_pid) { | ||
| 920 | event->filter_file = strdup(path); | ||
| 921 | if (!event->filter_file) | ||
| 922 | die("malloc filter file"); | ||
| 923 | } | ||
| 924 | for (p = path + strlen(path) - 1; p > path; p--) | ||
| 925 | if (*p == '/') | ||
| 926 | break; | ||
| 927 | *p = '\0'; | ||
| 928 | p = malloc_or_die(strlen(path) + strlen("/enable") + 1); | ||
| 929 | sprintf(p, "%s/enable", path); | ||
| 930 | ret = stat(p, &st); | ||
| 931 | if (ret >= 0) | ||
| 932 | event->enable_file = p; | ||
| 933 | else | ||
| 934 | free(p); | ||
| 935 | } | ||
| 936 | globfree(&globbuf); | ||
| 937 | |||
| 938 | return save_events == event_selection; | ||
| 939 | } | ||
| 940 | |||
| 941 | static void expand_event(struct event_list *event) | ||
| 942 | { | ||
| 943 | const char *name = event->event; | ||
| 944 | char *str; | ||
| 945 | char *ptr; | ||
| 946 | int len; | ||
| 947 | int ret; | ||
| 948 | int ret2; | ||
| 949 | |||
| 950 | /* | ||
| 951 | * We allow the user to use "all" to enable all events. | ||
| 952 | * Expand event_selection to all systems. | ||
| 953 | */ | ||
| 954 | if (strcmp(name, "all") == 0) { | ||
| 955 | expand_event_files("*", event); | ||
| 956 | return; | ||
| 957 | } | ||
| 958 | |||
| 959 | ptr = strchr(name, ':'); | ||
| 960 | |||
| 961 | if (ptr) { | ||
| 962 | len = ptr - name; | ||
| 963 | str = malloc_or_die(strlen(name) + 1); /* may add '*' */ | ||
| 964 | strcpy(str, name); | ||
| 965 | str[len] = '/'; | ||
| 966 | ptr++; | ||
| 967 | if (!strlen(ptr)) { | ||
| 968 | str[len + 1] = '*'; | ||
| 969 | str[len + 2] = '\0'; | ||
| 970 | } | ||
| 971 | |||
| 972 | ret = expand_event_files(str, event); | ||
| 973 | if (!ignore_event_not_found && ret) | ||
| 974 | die("No events enabled with %s", name); | ||
| 975 | free(str); | ||
| 976 | return; | ||
| 977 | } | ||
| 978 | |||
| 979 | /* No ':' so enable all matching systems and events */ | ||
| 980 | ret = expand_event_files(name, event); | ||
| 981 | |||
| 982 | len = strlen(name) + strlen("*/") + 1; | ||
| 983 | str = malloc_or_die(len); | ||
| 984 | snprintf(str, len, "*/%s", name); | ||
| 985 | ret2 = expand_event_files(str, event); | ||
| 986 | free(str); | ||
| 987 | |||
| 988 | if (!ignore_event_not_found && ret && ret2) | ||
| 989 | die("No events enabled with %s", name); | ||
| 990 | |||
| 991 | return; | ||
| 992 | } | ||
| 993 | |||
| 994 | static void expand_event_list(void) | ||
| 995 | { | ||
| 996 | struct event_list *compressed_list = event_selection; | ||
| 997 | struct event_list *event; | ||
| 998 | |||
| 999 | if (use_old_event_method()) | ||
| 1000 | return; | ||
| 1001 | |||
| 1002 | event_selection = NULL; | ||
| 1003 | |||
| 1004 | while (compressed_list) { | ||
| 1005 | event = compressed_list; | ||
| 1006 | compressed_list = event->next; | ||
| 1007 | expand_event(event); | ||
| 1008 | free(event); | ||
| 965 | } | 1009 | } |
| 966 | } | 1010 | } |
| 967 | 1011 | ||
| @@ -1465,6 +1509,7 @@ int main (int argc, char **argv) | |||
| 1465 | usage(argv); | 1509 | usage(argv); |
| 1466 | events = 1; | 1510 | events = 1; |
| 1467 | event = malloc_or_die(sizeof(*event)); | 1511 | event = malloc_or_die(sizeof(*event)); |
| 1512 | memset(event, 0, sizeof(*event)); | ||
| 1468 | event->event = optarg; | 1513 | event->event = optarg; |
| 1469 | event->next = event_selection; | 1514 | event->next = event_selection; |
| 1470 | event->neg = neg_event; | 1515 | event->neg = neg_event; |
| @@ -1667,6 +1712,9 @@ int main (int argc, char **argv) | |||
| 1667 | 1712 | ||
| 1668 | tracing_on_init_val = read_tracing_on(); | 1713 | tracing_on_init_val = read_tracing_on(); |
| 1669 | 1714 | ||
| 1715 | if (event_selection) | ||
| 1716 | expand_event_list(); | ||
| 1717 | |||
| 1670 | if (!extract) { | 1718 | if (!extract) { |
| 1671 | fset = set_ftrace(!disable); | 1719 | fset = set_ftrace(!disable); |
| 1672 | disable_all(); | 1720 | disable_all(); |
