| #include <stdio.h> |
| #include <stdlib.h> |
| #include <stdarg.h> |
| #include <string.h> |
| #include <errno.h> |
| #include <unistd.h> |
| #include <tracefs.h> |
| |
| #include "trace-local.h" |
| |
| enum action { |
| ACTION_DEFAULT = 0, |
| ACTION_SNAPSHOT = (1 << 0), |
| ACTION_TRACE = (1 << 1), |
| ACTION_SAVE = (1 << 2), |
| ACTION_MAX = (1 << 3), |
| ACTION_CHANGE = (1 << 4), |
| }; |
| |
| #define ACTIONS ((ACTION_MAX - 1)) |
| |
| static int do_sql(const char *instance_name, |
| const char *buffer, const char *name, const char *var, |
| const char *trace_dir, bool execute, int action, |
| char **save_fields) |
| { |
| struct tracefs_synth *synth; |
| struct tep_handle *tep; |
| struct trace_seq seq; |
| enum tracefs_synth_handler handler; |
| char *err = NULL; |
| int ret; |
| |
| if ((action & ACTIONS) && !var) |
| die("Error: -s, -S and -T not supported without -m or -c"); |
| |
| if (!name) |
| name = "Anonymous"; |
| |
| trace_seq_init(&seq); |
| tep = tracefs_local_events(trace_dir); |
| if (!tep) |
| die("Could not read %s", trace_dir ? trace_dir : "tracefs directory"); |
| |
| synth = tracefs_sql(tep, name, buffer, &err); |
| if (!synth) |
| die("Failed creating synthetic event!\n%s", err ? err : ""); |
| |
| if (tracefs_synth_complete(synth)) { |
| if (var) { |
| if (action & ACTION_MAX) |
| handler = TRACEFS_SYNTH_HANDLE_MAX; |
| else |
| handler = TRACEFS_SYNTH_HANDLE_CHANGE; |
| |
| /* Default to trace if other actions are not set */ |
| if (!(action & (ACTION_SAVE | ACTION_SNAPSHOT))) |
| action |= ACTION_TRACE; |
| |
| if (action & ACTION_SAVE) { |
| ret = tracefs_synth_save(synth, handler, var, save_fields); |
| if (ret < 0) { |
| err = "adding save"; |
| goto failed_action; |
| } |
| } |
| if (action & ACTION_TRACE) { |
| /* |
| * By doing the trace before snapshot, it will be included |
| * in the snapshot. |
| */ |
| ret = tracefs_synth_trace(synth, handler, var); |
| if (ret < 0) { |
| err = "adding trace"; |
| goto failed_action; |
| } |
| } |
| if (action & ACTION_SNAPSHOT) { |
| ret = tracefs_synth_snapshot(synth, handler, var); |
| if (ret < 0) { |
| err = "adding snapshot"; |
| failed_action: |
| perror(err); |
| if (errno == ENODEV) |
| fprintf(stderr, "ERROR: '%s' is not a variable\n", |
| var); |
| exit(-1); |
| } |
| } |
| } |
| tracefs_synth_echo_cmd(&seq, synth); |
| if (execute) { |
| ret = tracefs_synth_create(synth); |
| if (ret < 0) |
| die("%s\n", tracefs_error_last(NULL)); |
| } |
| } else { |
| struct tracefs_instance *instance = NULL; |
| struct tracefs_hist *hist; |
| |
| hist = tracefs_synth_get_start_hist(synth); |
| if (!hist) |
| die("get_start_hist"); |
| |
| if (instance_name) { |
| if (execute) |
| instance = tracefs_instance_create(instance_name); |
| else |
| instance = tracefs_instance_alloc(trace_dir, |
| instance_name); |
| if (!instance) |
| die("Failed to create instance"); |
| } |
| tracefs_hist_echo_cmd(&seq, instance, hist, 0); |
| if (execute) { |
| ret = tracefs_hist_start(instance, hist); |
| if (ret < 0) |
| die("%s\n", tracefs_error_last(instance)); |
| } |
| } |
| |
| tracefs_synth_free(synth); |
| |
| trace_seq_do_printf(&seq); |
| trace_seq_destroy(&seq); |
| return 0; |
| } |
| |
| void trace_sqlhist (int argc, char **argv) |
| { |
| char *trace_dir = NULL; |
| char *buffer = NULL; |
| char buf[BUFSIZ]; |
| int buffer_size = 0; |
| const char *file = NULL; |
| const char *instance = NULL; |
| bool execute = false; |
| char **save_fields = NULL; |
| const char *name = NULL; |
| const char *var = NULL; |
| char **save_argv; |
| int action = 0; |
| char *tok; |
| FILE *fp; |
| size_t r; |
| int c; |
| int i; |
| |
| /* Remove 'trace-cmd' */ |
| save_argv = argv; |
| argc -= 1; |
| argv += 1; |
| |
| if (argc < 2) |
| usage(save_argv); |
| |
| for (;;) { |
| c = getopt(argc, argv, "ht:f:en:m:c:sS:TB:"); |
| if (c == -1) |
| break; |
| |
| switch(c) { |
| case 'h': |
| usage(save_argv); |
| case 't': |
| trace_dir = optarg; |
| break; |
| case 'f': |
| file = optarg; |
| break; |
| case 'e': |
| execute = true; |
| break; |
| case 'm': |
| action |= ACTION_MAX; |
| var = optarg; |
| break; |
| case 'c': |
| action |= ACTION_CHANGE; |
| var = optarg; |
| break; |
| case 's': |
| action |= ACTION_SNAPSHOT; |
| break; |
| case 'S': |
| action |= ACTION_SAVE; |
| tok = strtok(optarg, ","); |
| while (tok) { |
| save_fields = tracefs_list_add(save_fields, tok); |
| tok = strtok(NULL, ","); |
| } |
| if (!save_fields) { |
| perror(optarg); |
| exit(-1); |
| } |
| break; |
| case 'T': |
| action |= ACTION_TRACE | ACTION_SNAPSHOT; |
| break; |
| case 'B': |
| instance = optarg; |
| break; |
| case 'n': |
| name = optarg; |
| break; |
| } |
| } |
| |
| if ((action & (ACTION_MAX|ACTION_CHANGE)) == (ACTION_MAX|ACTION_CHANGE)) { |
| fprintf(stderr, "Can not use both -m and -c together\n"); |
| exit(-1); |
| } |
| if (file) { |
| if (!strcmp(file, "-")) |
| fp = stdin; |
| else |
| fp = fopen(file, "r"); |
| if (!fp) { |
| perror(file); |
| exit(-1); |
| } |
| while ((r = fread(buf, 1, BUFSIZ, fp)) > 0) { |
| buffer = realloc(buffer, buffer_size + r + 1); |
| strncpy(buffer + buffer_size, buf, r); |
| buffer_size += r; |
| } |
| fclose(fp); |
| if (buffer_size) |
| buffer[buffer_size] = '\0'; |
| } else if (argc == optind) { |
| usage(save_argv); |
| } else { |
| for (i = optind; i < argc; i++) { |
| r = strlen(argv[i]); |
| buffer = realloc(buffer, buffer_size + r + 2); |
| if (i != optind) |
| buffer[buffer_size++] = ' '; |
| strcpy(buffer + buffer_size, argv[i]); |
| buffer_size += r; |
| } |
| } |
| |
| do_sql(instance, buffer, name, var, trace_dir, execute, action, save_fields); |
| free(buffer); |
| } |
| |