3 * Linux Trace Toolkit Control
5 * Small program that controls LTT through libltt.
8 * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
10 * Copyright 2008 FUJITSU
11 * Zhao Lei <zhaolei@cn.fujitsu.com>
12 * Gui Jianfeng <guijianfeng@cn.fujitsu.com>
19 #include <liblttctl/lttctl.h>
30 #define OPT_MAX (1024)
31 #define OPT_NAMELEN (256)
32 #define OPT_VALSTRINGLEN (256)
38 struct channel_option
{
39 char chan_name
[OPT_NAMELEN
];
46 struct lttctl_option
{
48 struct channel_option chan_opt
;
51 struct lttctl_option
*next
;
54 struct lttctl_option
*opt_head
, *last_opt
;
56 static int opt_create
;
57 static int opt_destroy
;
61 static const char *opt_transport
;
62 static const char *opt_write
;
63 static int opt_append
;
64 static unsigned int opt_dump_threads
;
65 static char channel_root_default
[PATH_MAX
];
66 static const char *opt_channel_root
;
67 static const char *opt_tracename
;
72 static void show_arguments(void)
74 printf("Linux Trace Toolkit Trace Control " VERSION
"\n");
76 printf("Usage: lttctl [OPTION]... [TRACENAME]\n");
78 printf("Examples:\n");
79 printf(" lttctl -c trace1 "
80 "# Create a trace named trace1.\n");
81 printf(" lttctl -s trace1 "
82 "# start a trace named trace1.\n");
83 printf(" lttctl -p trace1 "
84 "# pause a trace named trace1.\n");
85 printf(" lttctl -d trace1 "
86 "# Destroy a trace named trace1.\n");
87 printf(" lttctl -C -w /tmp/trace1 trace1 "
88 "# Create a trace named trace1, start it and\n"
90 "# write non-overwrite channels' data to\n"
92 "# /tmp/trace1, debugfs must be mounted for\n"
95 printf(" lttctl -D -w /tmp/trace1 trace1 "
96 "# Pause and destroy a trace named trace1 and\n"
98 "# write overwrite channels' data to\n"
100 "# /tmp/trace1, debugfs must be mounted for\n"
104 printf(" Basic options:\n");
105 printf(" -c, --create\n");
106 printf(" Create a trace.\n");
107 printf(" -d, --destroy\n");
108 printf(" Destroy a trace.\n");
109 printf(" -s, --start\n");
110 printf(" Start a trace.\n");
111 printf(" -p, --pause\n");
112 printf(" Pause a trace.\n");
113 printf(" -h, --help\n");
114 printf(" Show this help.\n");
116 printf(" Advanced options:\n");
117 printf(" --transport TRANSPORT\n");
118 printf(" Set trace's transport. (ex. relay-locked or relay)\n");
119 printf(" -o, --option OPTION\n");
120 printf(" Set options, following operations are supported:\n");
121 printf(" channel.<channelname>.enable=\n");
122 printf(" channel.<channelname>.overwrite=\n");
123 printf(" channel.<channelname>.bufnum=\n");
124 printf(" channel.<channelname>.bufsize= (in bytes, rounded to "
125 "next power of 2)\n");
126 printf(" <channelname> can be set to all for all channels\n");
128 printf(" Integration options:\n");
129 printf(" -C, --create_start\n");
130 printf(" Create and start a trace.\n");
131 printf(" -D, --pause_destroy\n");
132 printf(" Pause and destroy a trace.\n");
133 printf(" -w, --write PATH\n");
134 printf(" Path for write trace datas.\n");
135 printf(" For -c, -C, -d, -D options\n");
136 printf(" -a, --append\n");
137 printf(" Append to trace, For -w option\n");
138 printf(" -n, --dump_threads NUMBER\n");
139 printf(" Number of lttd threads, For -w option\n");
140 printf(" --channel_root PATH\n");
141 printf(" Set channels root path, For -w option."
142 " (ex. /mnt/debugfs/ltt)\n");
147 * Separate option name to 3 fields
149 * Input: name = channel.cpu.bufsize
150 * Output: name1 = channel
157 * Make sure that name1~3 longer than OPT_NAMELEN.
158 * name1~3 can be NULL to discard value
161 static int separate_opt(const char *name
, char *name1
, char *name2
, char *name3
)
169 p
= strchr(name
, '.');
172 if (p
- name
>= OPT_NAMELEN
)
175 memcpy(name1
, name
, p
- name
);
181 p
= strchr(name
, '.');
184 if (p
- name
>= OPT_NAMELEN
)
187 memcpy(name2
, name
, p
- name
);
193 if (strlen(name
) >= OPT_NAMELEN
)
201 static void init_channel_opt(struct channel_option
*opt
, char *opt_name
)
203 if (opt
&& opt_name
) {
208 strcpy(opt
->chan_name
, opt_name
);
212 static struct lttctl_option
*find_insert_channel_opt(char *opt_name
)
214 struct lttctl_option
*iter
, *new_opt
;
217 opt_head
= (struct lttctl_option
*)malloc(sizeof(struct lttctl_option
));
218 init_channel_opt(&opt_head
->opt_mode
.chan_opt
, opt_name
);
219 opt_head
->type
= CHANNEL
;
220 opt_head
->next
= NULL
;
225 for (iter
= opt_head
; iter
; iter
= iter
->next
) {
226 if (iter
->type
!= CHANNEL
)
228 if (!strcmp(iter
->opt_mode
.chan_opt
.chan_name
, opt_name
))
232 new_opt
= (struct lttctl_option
*)malloc(sizeof(struct lttctl_option
));
233 init_channel_opt(&new_opt
->opt_mode
.chan_opt
, opt_name
);
234 new_opt
->type
= CHANNEL
;
235 new_opt
->next
= NULL
;
236 last_opt
->next
= new_opt
;
241 int set_channel_opt(struct channel_option
*opt
, char *opt_name
, char *opt_valstr
)
245 if (!strcmp("enable", opt_name
)) {
246 if (opt_valstr
[1] != 0) {
249 if (opt_valstr
[0] == 'Y' || opt_valstr
[0] == 'y'
250 || opt_valstr
[0] == '1')
252 else if (opt_valstr
[0] == 'N' || opt_valstr
[0] == 'n'
253 || opt_valstr
[0] == '0')
259 opt
->enable
= opt_val
;
261 } else if (!strcmp("overwrite", opt_name
)) {
262 if (opt_valstr
[1] != 0) {
265 if (opt_valstr
[0] == 'Y' || opt_valstr
[0] == 'y'
266 || opt_valstr
[0] == '1')
268 else if (opt_valstr
[0] == 'N' || opt_valstr
[0] == 'n'
269 || opt_valstr
[0] == '0')
275 opt
->overwrite
= opt_val
;
278 } else if (!strcmp("bufnum", opt_name
)) {
279 ret
= sscanf(opt_valstr
, "%d", &opt_val
);
280 if (ret
!= 1 || opt_val
< 0) {
284 opt
->bufnum
= opt_val
;
286 } else if (!strcmp("bufsize", opt_name
)) {
287 ret
= sscanf(opt_valstr
, "%d", &opt_val
);
288 if (ret
!= 1 || opt_val
< 0) {
292 opt
->bufsize
= opt_val
;
300 static int parst_opt(const char *optarg
)
303 char opt_name
[OPT_NAMELEN
* 3];
304 char opt_valstr
[OPT_VALSTRINGLEN
];
307 char name1
[OPT_NAMELEN
];
308 char name2
[OPT_NAMELEN
];
309 char name3
[OPT_NAMELEN
];
313 unsigned int opt_uintval
;
314 struct lttctl_option
*opt
;
317 fprintf(stderr
, "Option empty\n");
321 /* Get option name and val_str */
322 p
= strchr(optarg
, '=');
324 fprintf(stderr
, "Option format error: %s\n", optarg
);
328 if (p
- optarg
>= sizeof(opt_name
)/sizeof(opt_name
[0])) {
329 fprintf(stderr
, "Option name too long: %s\n", optarg
);
333 if (strlen(p
+1) >= OPT_VALSTRINGLEN
) {
334 fprintf(stderr
, "Option value too long: %s\n", optarg
);
338 memcpy(opt_name
, optarg
, p
- optarg
);
339 opt_name
[p
- optarg
] = 0;
340 strcpy(opt_valstr
, p
+1);
342 /* separate option name into 3 fields */
343 ret
= separate_opt(opt_name
, name1
, name2
, name3
);
345 fprintf(stderr
, "Option name error1: %s\n", optarg
);
349 if (!strcmp("channel", name1
)) {
350 opt
= find_insert_channel_opt(name2
);
351 if ((ret
= set_channel_opt(&opt
->opt_mode
.chan_opt
,
352 name3
, opt_valstr
) != 0)) {
353 fprintf(stderr
, "Option name error2: %s\n", optarg
);
357 fprintf(stderr
, "Option name error3: %s\n", optarg
);
366 * Parses the command line arguments.
368 * Returns -1 if the arguments were correct, but doesn't ask for program
369 * continuation. Returns EINVAL if the arguments are incorrect, or 0 if OK.
371 static int parse_arguments(int argc
, char **argv
)
375 static struct option longopts
[] = {
376 {"create", no_argument
, NULL
, 'c'},
377 {"destroy", no_argument
, NULL
, 'd'},
378 {"start", no_argument
, NULL
, 's'},
379 {"pause", no_argument
, NULL
, 'p'},
380 {"help", no_argument
, NULL
, 'h'},
381 {"transport", required_argument
, NULL
, 2},
382 {"option", required_argument
, NULL
, 'o'},
383 {"create_start", no_argument
, NULL
, 'C'},
384 {"pause_destroy", no_argument
, NULL
, 'D'},
385 {"write", required_argument
, NULL
, 'w'},
386 {"append", no_argument
, NULL
, 'a'},
387 {"dump_threads", required_argument
, NULL
, 'n'},
388 {"channel_root", required_argument
, NULL
, 3},
389 { NULL
, 0, NULL
, 0 },
393 * Enable all channels in default
394 * To make novice users happy
396 parst_opt("channel.all.enable=1");
398 opterr
= 1; /* Print error message on getopt_long */
401 c
= getopt_long(argc
, argv
, "cdspho:CDw:an:", longopts
, NULL
);
423 if (!opt_transport
) {
424 opt_transport
= optarg
;
427 "Please specify only 1 transport\n");
432 ret
= parst_opt(optarg
);
449 "Please specify only 1 write dir\n");
457 if (opt_dump_threads
) {
459 "Please specify only 1 dump threads\n");
463 ret
= sscanf(optarg
, "%u", &opt_dump_threads
);
466 "Dump threads not positive number\n");
471 if (!opt_channel_root
) {
472 opt_channel_root
= optarg
;
475 "Please specify only 1 channel root\n");
486 /* Don't check args when user needs help */
491 if (optind
< argc
- 1) {
492 fprintf(stderr
, "Please specify only 1 trace name\n");
495 if (optind
> argc
- 1) {
496 fprintf(stderr
, "Please specify trace name\n");
499 opt_tracename
= argv
[optind
];
504 if (!opt_create
&& !opt_start
&& !opt_destroy
&& !opt_pause
) {
506 "Please specify a option of "
507 "create, destroy, start, or pause\n");
511 if ((opt_create
|| opt_start
) && (opt_destroy
|| opt_pause
)) {
513 "Create and start conflict with destroy and pause\n");
519 opt_transport
= "relay";
525 "Transport option must be combine with create"
532 if (!opt_create
&& !opt_destroy
) {
534 "Write option must be combine with create or"
535 " destroy option\n");
539 if (!opt_channel_root
)
540 if (getdebugfsmntdir(channel_root_default
) == 0) {
541 strcat(channel_root_default
, "/ltt");
542 opt_channel_root
= channel_root_default
;
545 "Channel_root is necessary for -w"
546 " option, but neither --channel_root"
548 "specified, nor debugfs's mount dir"
549 " found, mount debugfs also failed\n");
553 if (opt_dump_threads
== 0)
554 opt_dump_threads
= 1;
560 "Append option must be combine with write"
566 if (opt_dump_threads
) {
569 "Dump_threads option must be combine with write"
575 if (opt_channel_root
) {
578 "Channel_root option must be combine with write"
587 static void show_info(void)
589 printf("Linux Trace Toolkit Trace Control " VERSION
"\n");
591 if (opt_tracename
!= NULL
) {
592 printf("Controlling trace : %s\n", opt_tracename
);
597 static int lttctl_channel_setup(struct channel_option
*opt
)
601 if (opt
->enable
!= -1) {
602 if ((ret
= lttctl_set_channel_enable(opt_tracename
,
607 if (opt
->overwrite
!= -1) {
608 if ((ret
= lttctl_set_channel_overwrite(opt_tracename
,
610 opt
->overwrite
)) != 0)
613 if (opt
->bufnum
!= -1) {
614 if ((ret
= lttctl_set_channel_subbuf_num(opt_tracename
,
619 if (opt
->bufsize
!= -1) {
620 if ((ret
= lttctl_set_channel_subbuf_size(opt_tracename
,
629 static int lttctl_create_trace(void)
633 struct lttctl_option
*opt
;
635 ret
= lttctl_setup_trace(opt_tracename
);
637 goto setup_trace_fail
;
639 for (opt
= opt_head
; opt
; opt
= opt
->next
) {
640 if (opt
->type
!= CHANNEL
)
642 ret
= lttctl_channel_setup(&opt
->opt_mode
.chan_opt
);
644 goto set_option_fail
;;
647 ret
= lttctl_set_trans(opt_tracename
, opt_transport
);
649 goto set_option_fail
;
651 ret
= lttctl_alloc_trace(opt_tracename
);
653 goto alloc_trace_fail
;
659 lttctl_destroy_trace(opt_tracename
);
665 * Start a lttd daemon to write trace datas
666 * Dump overwrite channels on overwrite!=0
667 * Dump normal(non-overwrite) channels on overwrite=0
672 static int lttctl_daemon(int overwrite
)
679 perror("Error in forking for lttd daemon");
687 char channel_path
[PATH_MAX
];
691 argv
[argc
] = getenv("LTT_DAEMON");
692 if (argv
[argc
] == NULL
)
693 argv
[argc
] = PACKAGE_BIN_DIR
"/lttd";
700 * we allow modify of opt_write's content in new process
701 * for get rid of warning of assign char * to const char *
703 argv
[argc
] = (char *)opt_write
;
707 strcpy(channel_path
, opt_channel_root
);
708 strcat(channel_path
, "/");
709 strcat(channel_path
, opt_tracename
);
712 argv
[argc
] = channel_path
;
716 sprintf(thread_num
, "%u", opt_dump_threads
);
719 argv
[argc
] = thread_num
;
732 /* overwrite option */
743 execvp(argv
[0], argv
);
745 perror("Error in executing the lttd daemon");
750 if (waitpid(pid
, &status
, 0) == -1) {
751 perror("Error in waitpid\n");
755 if (!WIFEXITED(status
)) {
756 fprintf(stderr
, "lttd process interrupted\n");
760 if (WEXITSTATUS(status
))
761 fprintf(stderr
, "lttd process running failed\n");
763 return WEXITSTATUS(status
);
766 int main(int argc
, char **argv
)
770 ret
= parse_arguments(argc
, argv
);
771 /* If user needs show help, we disregard other options */
777 /* exit program if arguments wrong */
788 printf("lttctl: Creating trace\n");
789 ret
= lttctl_create_trace();
794 printf("lttctl: Forking lttd\n");
795 ret
= lttctl_daemon(0);
802 printf("lttctl: Starting trace\n");
803 ret
= lttctl_start(opt_tracename
);
809 printf("lttctl: Pausing trace\n");
810 ret
= lttctl_pause(opt_tracename
);
817 printf("lttctl: Forking lttd\n");
818 ret
= lttctl_daemon(1);
823 printf("lttctl: Destroying trace\n");
824 ret
= lttctl_destroy_trace(opt_tracename
);
This page took 0.047673 seconds and 4 git commands to generate.