| // SPDX-License-Identifier: GPL-2.0 | |
| /* | |
| * Copyright (C) 2008, 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | |
| * | |
| */ | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include <getopt.h> | |
| #include <unistd.h> | |
| #include <dirent.h> | |
| #include <errno.h> | |
| #include <stdlib.h> | |
| #include <sys/syscall.h> | |
| #include "trace-local.h" | |
| int silence_warnings; | |
| int show_status; | |
| #ifndef gettid | |
| #define gettid() syscall(__NR_gettid) | |
| #endif | |
| void warning(const char *fmt, ...) | |
| { | |
| va_list ap; | |
| if (silence_warnings) | |
| return; | |
| if (errno) | |
| perror("trace-cmd"); | |
| errno = 0; | |
| va_start(ap, fmt); | |
| fprintf(stderr, " "); | |
| vfprintf(stderr, fmt, ap); | |
| va_end(ap); | |
| fprintf(stderr, "\n"); | |
| } | |
| void *malloc_or_die(unsigned int size) | |
| { | |
| void *data; | |
| data = malloc(size); | |
| if (!data) | |
| die("malloc"); | |
| return data; | |
| } | |
| /* Same as strtok_r(), but allows empty tokens */ | |
| char *strparse(char *str, char delim, char **save) | |
| { | |
| char *next; | |
| if (!str) { | |
| str = *save; | |
| if ((*save)[0] == '\0') | |
| return NULL; | |
| } | |
| next = strchr(str, delim); | |
| if (next) { | |
| *next = '\0'; | |
| *save = next + 1; | |
| } else { | |
| *save = str + strlen(str); | |
| } | |
| return str; | |
| } | |
| void tracecmd_debug(const char *fmt, ...) | |
| { | |
| va_list ap; | |
| if (!tracecmd_get_debug()) | |
| return; | |
| va_start(ap, fmt); | |
| printf("[%d] ", (int)gettid()); | |
| vprintf(fmt, ap); | |
| va_end(ap); | |
| } | |
| static struct trace_log_severity { | |
| int id; | |
| const char *name; | |
| } log_severity[] = { | |
| { .id = TEP_LOG_NONE, .name = "none" }, | |
| { .id = TEP_LOG_CRITICAL, .name = "crit" }, | |
| { .id = TEP_LOG_ERROR, .name = "err" }, | |
| { .id = TEP_LOG_WARNING, .name = "warn" }, | |
| { .id = TEP_LOG_INFO, .name = "info" }, | |
| { .id = TEP_LOG_DEBUG, .name = "debug" }, | |
| { .id = TEP_LOG_ALL, .name = "all" }, | |
| }; | |
| void trace_set_loglevel(int level) | |
| { | |
| tracecmd_set_loglevel(level); | |
| tracefs_set_loglevel(level); | |
| tep_set_loglevel(level); | |
| } | |
| int trace_set_verbose(char *level) | |
| { | |
| int id; | |
| /* Default level is info */ | |
| if (!level) | |
| level = "info"; | |
| if (isdigit(level[0])) { | |
| id = atoi(level); | |
| if (id >= TEP_LOG_NONE) { | |
| if (id > TEP_LOG_ALL) | |
| id = TEP_LOG_ALL; | |
| trace_set_loglevel(id); | |
| return 0; | |
| } | |
| } else { | |
| int size = ARRAY_SIZE(log_severity); | |
| int i; | |
| for (i = 0; i < size; i++) { | |
| if (!strncmp(level, log_severity[i].name, strlen(log_severity[i].name))) { | |
| trace_set_loglevel(log_severity[i].id); | |
| return 0; | |
| } | |
| } | |
| } | |
| return -1; | |
| } | |
| /** | |
| * struct command | |
| * @name command name | |
| * @run function to execute on command `name` | |
| */ | |
| struct command { | |
| char *name; | |
| void (*run)(int argc, char **argv); | |
| }; | |
| /** | |
| * Lookup table that maps command names to functions | |
| */ | |
| struct command commands[] = { | |
| {"report", trace_report}, | |
| {"snapshot", trace_snapshot}, | |
| {"hist", trace_hist}, | |
| {"mem", trace_mem}, | |
| {"listen", trace_listen}, | |
| {"agent", trace_agent}, | |
| {"setup-guest", trace_setup_guest}, | |
| {"split", trace_split}, | |
| {"restore", trace_restore}, | |
| {"stack", trace_stack}, | |
| {"check-events", trace_check_events}, | |
| {"record", trace_record}, | |
| {"start", trace_start}, | |
| {"set", trace_set}, | |
| {"extract", trace_extract}, | |
| {"stop", trace_stop}, | |
| {"stream", trace_stream}, | |
| {"profile", trace_profile}, | |
| {"restart", trace_restart}, | |
| {"clear", trace_clear}, | |
| {"reset", trace_reset}, | |
| {"stat", trace_stat}, | |
| {"options", trace_option}, | |
| {"show", trace_show}, | |
| {"list", trace_list}, | |
| {"help", trace_usage}, | |
| {"dump", trace_dump}, | |
| {"attach", trace_attach}, | |
| {"convert", trace_convert}, | |
| {"sqlhist", trace_sqlhist}, | |
| {"-h", trace_usage}, | |
| }; | |
| int main (int argc, char **argv) | |
| { | |
| int i; | |
| errno = 0; | |
| if (argc < 2) | |
| trace_usage(argc, argv); | |
| for (i = 0; i < ARRAY_SIZE(commands); ++i) { | |
| if (strcmp(argv[1], commands[i].name) == 0 ){ | |
| commands[i].run(argc, argv); | |
| goto out; | |
| } | |
| } | |
| /* No valid command found, show help */ | |
| trace_usage(argc, argv); | |
| out: | |
| exit(0); | |
| } |