X-Git-Url: http://git.liburcu.org/?a=blobdiff_plain;ds=inline;f=trunk%2Fltt-control%2Flttctl%2Flttctl.c;fp=trunk%2Fltt-control%2Flttctl%2Flttctl.c;h=0000000000000000000000000000000000000000;hb=5e1fd42a8d1bbbe1e1283e4c652994ff738dd6a7;hp=e08280aab2e066cd19f3b8479df1e6ae8ad9397a;hpb=1c2291f5d2f79795da29153bd5b962f0539d3316;p=ltt-control.git diff --git a/trunk/ltt-control/lttctl/lttctl.c b/trunk/ltt-control/lttctl/lttctl.c deleted file mode 100644 index e08280a..0000000 --- a/trunk/ltt-control/lttctl/lttctl.c +++ /dev/null @@ -1,833 +0,0 @@ -/* lttctl - * - * Linux Trace Toolkit Control - * - * Small program that controls LTT through libltt. - * - * Copyright 2005 - - * Mathieu Desnoyers - * - * Copyright 2008 FUJITSU - * Zhao Lei - * Gui Jianfeng - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#define _GNU_SOURCE -#include - -#define OPT_MAX (1024) -#define OPT_NAMELEN (256) -#define OPT_VALSTRINGLEN (256) - -enum opt_type { - CHANNEL, -}; - -struct channel_option { - char chan_name[OPT_NAMELEN]; - int enable; - int overwrite; - int bufnum; - int bufsize; -}; - -struct lttctl_option { - union { - struct channel_option chan_opt; - } opt_mode; - enum opt_type type; - struct lttctl_option *next; -}; - -struct lttctl_option *opt_head, *last_opt; - -static int opt_create; -static int opt_destroy; -static int opt_start; -static int opt_pause; -static int opt_help; -static const char *opt_transport; -static const char *opt_write; -static int opt_append; -static unsigned int opt_dump_threads; -static char channel_root_default[PATH_MAX]; -static const char *opt_channel_root; -static const char *opt_tracename; - -/* Args : - * - */ -static void show_arguments(void) -{ - printf("Linux Trace Toolkit Trace Control " VERSION"\n"); - printf("\n"); - printf("Usage: lttctl [OPTION]... [TRACENAME]\n"); - printf("\n"); - printf("Examples:\n"); - printf(" lttctl -c trace1 " - "# Create a trace named trace1.\n"); - printf(" lttctl -s trace1 " - "# start a trace named trace1.\n"); - printf(" lttctl -p trace1 " - "# pause a trace named trace1.\n"); - printf(" lttctl -d trace1 " - "# Destroy a trace named trace1.\n"); - printf(" lttctl -C -w /tmp/trace1 trace1 " - "# Create a trace named trace1, start it and\n" - " " - "# write non-overwrite channels' data to\n" - " " - "# /tmp/trace1, debugfs must be mounted for\n" - " " - "# auto-find\n"); - printf(" lttctl -D -w /tmp/trace1 trace1 " - "# Pause and destroy a trace named trace1 and\n" - " " - "# write overwrite channels' data to\n" - " " - "# /tmp/trace1, debugfs must be mounted for\n" - " " - "# auto-find\n"); - printf("\n"); - printf(" Basic options:\n"); - printf(" -c, --create\n"); - printf(" Create a trace.\n"); - printf(" -d, --destroy\n"); - printf(" Destroy a trace.\n"); - printf(" -s, --start\n"); - printf(" Start a trace.\n"); - printf(" -p, --pause\n"); - printf(" Pause a trace.\n"); - printf(" -h, --help\n"); - printf(" Show this help.\n"); - printf("\n"); - printf(" Advanced options:\n"); - printf(" --transport TRANSPORT\n"); - printf(" Set trace's transport. (ex. relay-locked or relay)\n"); - printf(" -o, --option OPTION\n"); - printf(" Set options, following operations are supported:\n"); - printf(" channel..enable=\n"); - printf(" channel..overwrite=\n"); - printf(" channel..bufnum=\n"); - printf(" channel..bufsize= (in bytes, rounded to " - "next power of 2)\n"); - printf(" can be set to all for all channels\n"); - printf("\n"); - printf(" Integration options:\n"); - printf(" -C, --create_start\n"); - printf(" Create and start a trace.\n"); - printf(" -D, --pause_destroy\n"); - printf(" Pause and destroy a trace.\n"); - printf(" -w, --write PATH\n"); - printf(" Path for write trace datas.\n"); - printf(" For -c, -C, -d, -D options\n"); - printf(" -a, --append\n"); - printf(" Append to trace, For -w option\n"); - printf(" -n, --dump_threads NUMBER\n"); - printf(" Number of lttd threads, For -w option\n"); - printf(" --channel_root PATH\n"); - printf(" Set channels root path, For -w option." - " (ex. /mnt/debugfs/ltt)\n"); - printf("\n"); -} - -/* - * Separate option name to 3 fields - * Ex: - * Input: name = channel.cpu.bufsize - * Output: name1 = channel - * name2 = cpu - * name3 = bufsize - * Ret: 0 on success - * 1 on fail - * - * Note: - * Make sure that name1~3 longer than OPT_NAMELEN. - * name1~3 can be NULL to discard value - * - */ -static int separate_opt(const char *name, char *name1, char *name2, char *name3) -{ - char *p; - - if (!name) - return 1; - - /* segment1 */ - p = strchr(name, '.'); - if (!p) - return 1; - if (p - name >= OPT_NAMELEN) - return 1; - if (name1) { - memcpy(name1, name, p - name); - name1[p - name] = 0; - } - name = p + 1; - - /* segment2 */ - p = strchr(name, '.'); - if (!p) - return 1; - if (p - name >= OPT_NAMELEN) - return 1; - if (name2) { - memcpy(name2, name, p - name); - name2[p - name] = 0; - } - name = p + 1; - - /* segment3 */ - if (strlen(name) >= OPT_NAMELEN) - return 1; - if (name3) - strcpy(name3, name); - - return 0; -} - -static void init_channel_opt(struct channel_option *opt, char *opt_name) -{ - if (opt && opt_name) { - opt->enable = -1; - opt->overwrite = -1; - opt->bufnum = -1; - opt->bufsize = -1; - strcpy(opt->chan_name, opt_name); - } -} - -static struct lttctl_option *find_insert_channel_opt(char *opt_name) -{ - struct lttctl_option *iter, *new_opt; - - if (!opt_head) { - opt_head = (struct lttctl_option *)malloc(sizeof(struct lttctl_option)); - init_channel_opt(&opt_head->opt_mode.chan_opt, opt_name); - opt_head->type = CHANNEL; - opt_head->next = NULL; - last_opt = opt_head; - return opt_head; - } - - for (iter = opt_head; iter; iter = iter->next) { - if (iter->type != CHANNEL) - continue; - if (!strcmp(iter->opt_mode.chan_opt.chan_name, opt_name)) - return iter; - } - - new_opt = (struct lttctl_option *)malloc(sizeof(struct lttctl_option)); - init_channel_opt(&new_opt->opt_mode.chan_opt, opt_name); - new_opt->type = CHANNEL; - new_opt->next = NULL; - last_opt->next = new_opt; - last_opt = new_opt; - return new_opt; -} - -int set_channel_opt(struct channel_option *opt, char *opt_name, char *opt_valstr) -{ - int opt_val, ret; - - if (!strcmp("enable", opt_name)) { - if (opt_valstr[1] != 0) { - return -EINVAL; - } - if (opt_valstr[0] == 'Y' || opt_valstr[0] == 'y' - || opt_valstr[0] == '1') - opt_val = 1; - else if (opt_valstr[0] == 'N' || opt_valstr[0] == 'n' - || opt_valstr[0] == '0') - opt_val = 0; - else { - return -EINVAL; - } - - opt->enable = opt_val; - return 0; - } else if (!strcmp("overwrite", opt_name)) { - if (opt_valstr[1] != 0) { - return -EINVAL; - } - if (opt_valstr[0] == 'Y' || opt_valstr[0] == 'y' - || opt_valstr[0] == '1') - opt_val = 1; - else if (opt_valstr[0] == 'N' || opt_valstr[0] == 'n' - || opt_valstr[0] == '0') - opt_val = 0; - else { - return -EINVAL; - } - - opt->overwrite = opt_val; - return 0; - - } else if (!strcmp("bufnum", opt_name)) { - ret = sscanf(opt_valstr, "%d", &opt_val); - if (ret != 1 || opt_val < 0) { - return -EINVAL; - } - - opt->bufnum = opt_val; - return 0; - } else if (!strcmp("bufsize", opt_name)) { - ret = sscanf(opt_valstr, "%d", &opt_val); - if (ret != 1 || opt_val < 0) { - return -EINVAL; - } - - opt->bufsize = opt_val; - return 0; - } else { - return -EINVAL; - } - -} - -static int parst_opt(const char *optarg) -{ - int ret; - char opt_name[OPT_NAMELEN * 3]; - char opt_valstr[OPT_VALSTRINGLEN]; - char *p; - - char name1[OPT_NAMELEN]; - char name2[OPT_NAMELEN]; - char name3[OPT_NAMELEN]; - - int opt_intval; - int opt_val; - unsigned int opt_uintval; - struct lttctl_option *opt; - - if (!optarg) { - fprintf(stderr, "Option empty\n"); - return -EINVAL; - } - - /* Get option name and val_str */ - p = strchr(optarg, '='); - if (!p) { - fprintf(stderr, "Option format error: %s\n", optarg); - return -EINVAL; - } - - if (p - optarg >= sizeof(opt_name)/sizeof(opt_name[0])) { - fprintf(stderr, "Option name too long: %s\n", optarg); - return -EINVAL; - } - - if (strlen(p+1) >= OPT_VALSTRINGLEN) { - fprintf(stderr, "Option value too long: %s\n", optarg); - return -EINVAL; - } - - memcpy(opt_name, optarg, p - optarg); - opt_name[p - optarg] = 0; - strcpy(opt_valstr, p+1); - - /* separate option name into 3 fields */ - ret = separate_opt(opt_name, name1, name2, name3); - if (ret != 0) { - fprintf(stderr, "Option name error1: %s\n", optarg); - return -EINVAL; - } - - if (!strcmp("channel", name1)) { - opt = find_insert_channel_opt(name2); - if ((ret = set_channel_opt(&opt->opt_mode.chan_opt, - name3, opt_valstr) != 0)) { - fprintf(stderr, "Option name error2: %s\n", optarg); - return ret; - } - } else { - fprintf(stderr, "Option name error3: %s\n", optarg); - return -EINVAL; - } - - return 0; -} - -/* parse_arguments - * - * Parses the command line arguments. - * - * Returns -1 if the arguments were correct, but doesn't ask for program - * continuation. Returns EINVAL if the arguments are incorrect, or 0 if OK. - */ -static int parse_arguments(int argc, char **argv) -{ - int ret = 0; - - static struct option longopts[] = { - {"create", no_argument, NULL, 'c'}, - {"destroy", no_argument, NULL, 'd'}, - {"start", no_argument, NULL, 's'}, - {"pause", no_argument, NULL, 'p'}, - {"help", no_argument, NULL, 'h'}, - {"transport", required_argument, NULL, 2}, - {"option", required_argument, NULL, 'o'}, - {"create_start", no_argument, NULL, 'C'}, - {"pause_destroy", no_argument, NULL, 'D'}, - {"write", required_argument, NULL, 'w'}, - {"append", no_argument, NULL, 'a'}, - {"dump_threads", required_argument, NULL, 'n'}, - {"channel_root", required_argument, NULL, 3}, - { NULL, 0, NULL, 0 }, - }; - - /* - * Enable all channels in default - * To make novice users happy - */ - parst_opt("channel.all.enable=1"); - - opterr = 1; /* Print error message on getopt_long */ - while (1) { - int c; - c = getopt_long(argc, argv, "cdspho:CDw:an:", longopts, NULL); - if (-1 == c) { - /* parse end */ - break; - } - switch (c) { - case 'c': - opt_create = 1; - break; - case 'd': - opt_destroy = 1; - break; - case 's': - opt_start = 1; - break; - case 'p': - opt_pause = 1; - break; - case 'h': - opt_help = 1; - break; - case 2: - if (!opt_transport) { - opt_transport = optarg; - } else { - fprintf(stderr, - "Please specify only 1 transport\n"); - return -EINVAL; - } - break; - case 'o': - ret = parst_opt(optarg); - if (ret) - return ret; - break; - case 'C': - opt_create = 1; - opt_start = 1; - break; - case 'D': - opt_pause = 1; - opt_destroy = 1; - break; - case 'w': - if (!opt_write) { - opt_write = optarg; - } else { - fprintf(stderr, - "Please specify only 1 write dir\n"); - return -EINVAL; - } - break; - case 'a': - opt_append = 1; - break; - case 'n': - if (opt_dump_threads) { - fprintf(stderr, - "Please specify only 1 dump threads\n"); - return -EINVAL; - } - - ret = sscanf(optarg, "%u", &opt_dump_threads); - if (ret != 1) { - fprintf(stderr, - "Dump threads not positive number\n"); - return -EINVAL; - } - break; - case 3: - if (!opt_channel_root) { - opt_channel_root = optarg; - } else { - fprintf(stderr, - "Please specify only 1 channel root\n"); - return -EINVAL; - } - break; - case '?': - return -EINVAL; - default: - break; - }; - }; - - /* Don't check args when user needs help */ - if (opt_help) - return 0; - - /* Get tracename */ - if (optind < argc - 1) { - fprintf(stderr, "Please specify only 1 trace name\n"); - return -EINVAL; - } - if (optind > argc - 1) { - fprintf(stderr, "Please specify trace name\n"); - return -EINVAL; - } - opt_tracename = argv[optind]; - - /* - * Check arguments - */ - if (!opt_create && !opt_start && !opt_destroy && !opt_pause) { - fprintf(stderr, - "Please specify a option of " - "create, destroy, start, or pause\n"); - return -EINVAL; - } - - if ((opt_create || opt_start) && (opt_destroy || opt_pause)) { - fprintf(stderr, - "Create and start conflict with destroy and pause\n"); - return -EINVAL; - } - - if (opt_create) { - if (!opt_transport) - opt_transport = "relay"; - } - - if (opt_transport) { - if (!opt_create) { - fprintf(stderr, - "Transport option must be combine with create" - " option\n"); - return -EINVAL; - } - } - - if (opt_write) { - if (!opt_create && !opt_destroy) { - fprintf(stderr, - "Write option must be combine with create or" - " destroy option\n"); - return -EINVAL; - } - - if (!opt_channel_root) - if (getdebugfsmntdir(channel_root_default) == 0) { - strcat(channel_root_default, "/ltt"); - opt_channel_root = channel_root_default; - } else { - fprintf(stderr, - "Channel_root is necessary for -w" - " option, but neither --channel_root" - " option\n" - "specified, nor debugfs's mount dir" - " found, mount debugfs also failed\n"); - return -EINVAL; - } - - if (opt_dump_threads == 0) - opt_dump_threads = 1; - } - - if (opt_append) { - if (!opt_write) { - fprintf(stderr, - "Append option must be combine with write" - " option\n"); - return -EINVAL; - } - } - - if (opt_dump_threads) { - if (!opt_write) { - fprintf(stderr, - "Dump_threads option must be combine with write" - " option\n"); - return -EINVAL; - } - } - - if (opt_channel_root) { - if (!opt_write) { - fprintf(stderr, - "Channel_root option must be combine with write" - " option\n"); - return -EINVAL; - } - } - - return 0; -} - -static void show_info(void) -{ - printf("Linux Trace Toolkit Trace Control " VERSION"\n"); - printf("\n"); - if (opt_tracename != NULL) { - printf("Controlling trace : %s\n", opt_tracename); - printf("\n"); - } -} - -static int lttctl_channel_setup(struct channel_option *opt) -{ - int ret; - - if (opt->enable != -1) { - if ((ret = lttctl_set_channel_enable(opt_tracename, - opt->chan_name, - opt->enable)) != 0) - return ret; - } - if (opt->overwrite != -1) { - if ((ret = lttctl_set_channel_overwrite(opt_tracename, - opt->chan_name, - opt->overwrite)) != 0) - return ret; - } - if (opt->bufnum != -1) { - if ((ret = lttctl_set_channel_subbuf_num(opt_tracename, - opt->chan_name, - opt->bufnum)) != 0) - return ret; - } - if (opt->bufsize != -1) { - if ((ret = lttctl_set_channel_subbuf_size(opt_tracename, - opt->chan_name, - opt->bufsize)) != 0) - return ret; - } - - return 0; -} - -static int lttctl_create_trace(void) -{ - int ret; - int i; - struct lttctl_option *opt; - - ret = lttctl_setup_trace(opt_tracename); - if (ret) - goto setup_trace_fail; - - for (opt = opt_head; opt; opt = opt->next) { - if (opt->type != CHANNEL) - continue; - ret = lttctl_channel_setup(&opt->opt_mode.chan_opt); - if (ret) - goto set_option_fail;; - } - - ret = lttctl_set_trans(opt_tracename, opt_transport); - if (ret) - goto set_option_fail; - - ret = lttctl_alloc_trace(opt_tracename); - if (ret) - goto alloc_trace_fail; - - return 0; - -alloc_trace_fail: -set_option_fail: - lttctl_destroy_trace(opt_tracename); -setup_trace_fail: - return ret; -} - -/* - * Start a lttd daemon to write trace datas - * Dump overwrite channels on overwrite!=0 - * Dump normal(non-overwrite) channels on overwrite=0 - * - * ret: 0 on success - * !0 on fail - */ -static int lttctl_daemon(int overwrite) -{ - pid_t pid; - int status; - - pid = fork(); - if (pid < 0) { - perror("Error in forking for lttd daemon"); - return errno; - } - - if (pid == 0) { - /* child */ - char *argv[16]; - int argc = 0; - char channel_path[PATH_MAX]; - char thread_num[16]; - - /* prog path */ - argv[argc] = getenv("LTT_DAEMON"); - if (argv[argc] == NULL) - argv[argc] = PACKAGE_BIN_DIR "/lttd"; - argc++; - - /* -t option */ - argv[argc] = "-t"; - argc++; - /* - * we allow modify of opt_write's content in new process - * for get rid of warning of assign char * to const char * - */ - argv[argc] = (char *)opt_write; - argc++; - - /* -c option */ - strcpy(channel_path, opt_channel_root); - strcat(channel_path, "/"); - strcat(channel_path, opt_tracename); - argv[argc] = "-c"; - argc++; - argv[argc] = channel_path; - argc++; - - /* -N option */ - sprintf(thread_num, "%u", opt_dump_threads); - argv[argc] = "-N"; - argc++; - argv[argc] = thread_num; - argc++; - - /* -a option */ - if (opt_append) { - argv[argc] = "-a"; - argc++; - } - - /* -d option */ - argv[argc] = "-d"; - argc++; - - /* overwrite option */ - if (overwrite) { - argv[argc] = "-f"; - argc++; - } else { - argv[argc] = "-n"; - argc++; - } - - argv[argc] = NULL; - - execvp(argv[0], argv); - - perror("Error in executing the lttd daemon"); - exit(errno); - } - - /* parent */ - if (waitpid(pid, &status, 0) == -1) { - perror("Error in waitpid\n"); - return errno; - } - - if (!WIFEXITED(status)) { - fprintf(stderr, "lttd process interrupted\n"); - return status; - } - - if (WEXITSTATUS(status)) - fprintf(stderr, "lttd process running failed\n"); - - return WEXITSTATUS(status); -} - -int main(int argc, char **argv) -{ - int ret; - - ret = parse_arguments(argc, argv); - /* If user needs show help, we disregard other options */ - if (opt_help) { - show_arguments(); - return 0; - } - - /* exit program if arguments wrong */ - if (ret) - return 1; - - show_info(); - - ret = lttctl_init(); - if (ret != 0) - return ret; - - if (opt_create) { - printf("lttctl: Creating trace\n"); - ret = lttctl_create_trace(); - if (ret) - goto op_fail; - - if (opt_write) { - printf("lttctl: Forking lttd\n"); - ret = lttctl_daemon(0); - if (ret) - goto op_fail; - } - } - - if (opt_start) { - printf("lttctl: Starting trace\n"); - ret = lttctl_start(opt_tracename); - if (ret) - goto op_fail; - } - - if (opt_pause) { - printf("lttctl: Pausing trace\n"); - ret = lttctl_pause(opt_tracename); - if (ret) - goto op_fail; - } - - if (opt_destroy) { - if (opt_write) { - printf("lttctl: Forking lttd\n"); - ret = lttctl_daemon(1); - if (ret) - goto op_fail; - } - - printf("lttctl: Destroying trace\n"); - ret = lttctl_destroy_trace(opt_tracename); - if (ret) - goto op_fail; - } - -op_fail: - lttctl_destroy(); - - return ret; -}