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(); |