3 * Linux Trace Toolkit Control
5 * Small program that controls LTT through libltt.
8 * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
15 #include <liblttctl/lttctl.h>
19 #include <sys/types.h>
27 /* Buffer for file copy : 4k seems optimal. */
38 CTL_OP_DAEMON_HYBRID_FINISH
,
43 static char *trace_name
= NULL
;
44 static char *trace_type
= "relay";
45 static char *mode_name
= NULL
;
46 static unsigned subbuf_size_low
= 0;
47 static unsigned n_subbufs_low
= 0;
48 static unsigned subbuf_size_med
= 0;
49 static unsigned n_subbufs_med
= 0;
50 static unsigned subbuf_size_high
= 0;
51 static unsigned n_subbufs_high
= 0;
52 static unsigned append_trace
= 0;
53 static enum trace_mode mode
= LTT_TRACE_NORMAL
;
54 static enum trace_ctl_op op
= CTL_OP_NONE
;
55 static char *channel_root
= NULL
;
56 static char *trace_root
= NULL
;
57 static char *num_threads
= "1";
62 void show_arguments(void)
64 printf("Please use the following arguments :\n");
66 printf("-n name Name of the trace.\n");
67 printf("-b Create trace channels and start tracing (no daemon).\n");
68 printf("-c Create trace channels.\n");
69 printf("-m mode Normal, flight recorder or hybrid mode.\n");
70 printf(" Mode values : normal (default), flight or hybrid.\n");
71 printf("-r Destroy trace channels.\n");
72 printf("-R Stop tracing and destroy trace channels.\n");
73 printf("-s Start tracing.\n");
74 //printf(" Note : will automatically create a normal trace if "
76 printf("-q Stop tracing.\n");
77 printf("-d Create trace, spawn a lttd daemon, start tracing.\n");
78 printf(" (optionally, you can set LTT_DAEMON\n");
79 printf(" and the LTT_FACILITIES env. vars.)\n");
80 printf("-f Stop tracing, dump flight recorder trace, destroy channels\n");
81 printf(" (for hybrid traces)\n");
82 printf("-t Trace root path. (ex. /root/traces/example_trace)\n");
83 printf("-T Type of trace (ex. relay)\n");
84 printf("-l LTT channels root path. (ex. /mnt/debugfs/ltt)\n");
85 printf("-Z Size of the low data rate subbuffers (will be rounded to next page size)\n");
86 printf("-X Number of low data rate subbuffers\n");
87 printf("-V Size of the medium data rate subbuffers (will be rounded to next page size)\n");
88 printf("-B Number of medium data rate subbuffers\n");
89 printf("-z Size of the high data rate subbuffers (will be rounded to next page size)\n");
90 printf("-x Number of high data rate subbuffers\n");
91 printf("-e Get XML facilities description\n");
92 printf("-a Append to trace\n");
93 printf("-N Number of lttd threads\n");
100 * Parses the command line arguments.
102 * Returns -1 if the arguments were correct, but doesn't ask for program
103 * continuation. Returns EINVAL if the arguments are incorrect, or 0 if OK.
105 int parse_arguments(int argc
, char **argv
)
111 if(strcmp(argv
[1], "-h") == 0) {
118 switch(argv
[argn
][0]) {
120 switch(argv
[argn
][1]) {
123 trace_name
= argv
[argn
+1];
126 printf("Specify a trace name after -n.\n");
133 op
= CTL_OP_CREATE_START
;
140 mode_name
= argv
[argn
+1];
142 if(strcmp(mode_name
, "normal") == 0)
143 mode
= LTT_TRACE_NORMAL
;
144 else if(strcmp(mode_name
, "flight") == 0)
145 mode
= LTT_TRACE_FLIGHT
;
146 else if(strcmp(mode_name
, "hybrid") == 0)
147 mode
= LTT_TRACE_HYBRID
;
149 printf("Invalid mode '%s'.\n", argv
[argn
]);
154 printf("Specify a mode after -m.\n");
163 op
= CTL_OP_STOP_DESTROY
;
173 subbuf_size_low
= (unsigned)atoi(argv
[argn
+1]);
176 printf("Specify a number of low traffic subbuffers after -Z.\n");
183 n_subbufs_low
= (unsigned)atoi(argv
[argn
+1]);
186 printf("Specify a low traffic subbuffer size after -X.\n");
193 subbuf_size_med
= (unsigned)atoi(argv
[argn
+1]);
196 printf("Specify a number of medium traffic subbuffers after -V.\n");
203 n_subbufs_med
= (unsigned)atoi(argv
[argn
+1]);
206 printf("Specify a medium traffic subbuffer size after -B.\n");
213 subbuf_size_high
= (unsigned)atoi(argv
[argn
+1]);
216 printf("Specify a number of high traffic subbuffers after -z.\n");
223 n_subbufs_high
= (unsigned)atoi(argv
[argn
+1]);
226 printf("Specify a high traffic subbuffer size after -x.\n");
235 op
= CTL_OP_DAEMON_HYBRID_FINISH
;
238 op
= CTL_OP_DESCRIPTION
;
242 trace_root
= argv
[argn
+1];
245 printf("Specify a trace root path after -t.\n");
252 channel_root
= argv
[argn
+1];
255 printf("Specify a channel root path after -l.\n");
265 num_threads
= argv
[argn
+1];
271 trace_type
= argv
[argn
+1];
274 printf("Specify a trace type after -T.\n");
280 printf("Invalid argument '%s'.\n", argv
[argn
]);
286 printf("Invalid argument '%s'.\n", argv
[argn
]);
293 if(op
!= CTL_OP_DESCRIPTION
&& trace_name
== NULL
) {
294 printf("Please specify a trace name.\n");
299 if(op
== CTL_OP_NONE
) {
300 printf("Please specify an operation.\n");
305 if(op
== CTL_OP_DAEMON
|| op
== CTL_OP_DAEMON_HYBRID_FINISH
) {
306 if(trace_root
== NULL
) {
307 printf("Please specify -t trace_root_path with the -d option.\n");
311 if(channel_root
== NULL
) {
312 printf("Please specify -l ltt_root_path with the -d option.\n");
318 if(op
== CTL_OP_DESCRIPTION
) {
319 if(trace_root
== NULL
) {
320 printf("Please specify -t trace_root_path with the -e option.\n");
331 printf("Linux Trace Toolkit Trace Control " VERSION
"\n");
333 if(trace_name
!= NULL
) {
334 printf("Controlling trace : %s\n", trace_name
);
339 int create_eventdefs(void)
342 char eventdefs_path
[PATH_MAX
];
343 char eventdefs_file
[PATH_MAX
];
344 char facilities_file
[PATH_MAX
];
345 char read_buf
[BUF_SIZE
];
346 struct dirent
*entry
;
347 char *facilities_path
= getenv("LTT_FACILITIES");
348 if(facilities_path
== NULL
) facilities_path
=
349 PACKAGE_DATA_DIR
"/" PACKAGE
"/facilities";
351 ret
= mkdir(trace_root
, S_IRWXU
|S_IRWXG
|S_IRWXO
);
352 if(ret
== -1 && errno
!= EEXIST
) {
354 perror("Cannot create trace_root directory");
355 printf("trace_root is %s\n", trace_root
);
360 size_t trace_root_len
= strlen(trace_root
);
361 strncpy(eventdefs_path
, trace_root
, PATH_MAX
);
362 strncat(eventdefs_path
, "/eventdefs/", PATH_MAX
- trace_root_len
);
363 size_t eventdefs_path_len
= strlen(eventdefs_path
);
364 ret
= mkdir(eventdefs_path
, S_IRWXU
|S_IRWXG
|S_IRWXO
);
365 if(ret
== -1 && (!append_trace
|| errno
!= EEXIST
)) {
367 perror("Cannot create eventdefs directory");
372 DIR *facilities_dir
= opendir(facilities_path
);
374 if(facilities_dir
== NULL
) {
375 perror("Cannot open facilities directory");
380 while((entry
= readdir(facilities_dir
)) != NULL
) {
381 if(entry
->d_name
[0] == '.') continue;
383 printf("Appending facility file %s\n", entry
->d_name
);
384 strncpy(eventdefs_file
, eventdefs_path
, PATH_MAX
);
385 strncat(eventdefs_file
, entry
->d_name
, PATH_MAX
- eventdefs_path_len
);
386 /* Append to the file */
387 FILE *dest
= fopen(eventdefs_file
, "a");
389 perror("Cannot create eventdefs file");
392 strncpy(facilities_file
, facilities_path
, PATH_MAX
);
393 size_t facilities_dir_len
= strlen(facilities_path
);
394 strncat(facilities_file
, "/", PATH_MAX
- facilities_dir_len
);
395 strncat(facilities_file
, entry
->d_name
, PATH_MAX
- facilities_dir_len
-1);
396 FILE *src
= fopen(facilities_file
, "r");
399 perror("Cannot open eventdefs file for reading");
404 size_t read_size
, write_size
;
405 read_size
= fread(read_buf
, sizeof(char), BUF_SIZE
, src
);
408 perror("Cannot read eventdefs file");
411 write_size
= fwrite(read_buf
, sizeof(char), read_size
, dest
);
414 perror("Cannot write eventdefs file");
419 /* Add spacing between facilities */
420 fwrite("\n", 1, 1, dest
);
428 closedir(facilities_dir
);
436 int lttctl_daemon(struct lttctl_handle
*handle
, char *trace_name
)
438 char channel_path
[PATH_MAX
] = "";
441 char *lttd_path
= getenv("LTT_DAEMON");
443 if(lttd_path
== NULL
) lttd_path
=
444 PACKAGE_BIN_DIR
"/lttd";
446 strcat(channel_path
, channel_root
);
447 strcat(channel_path
, "/");
448 strcat(channel_path
, trace_name
);
451 ret
= lttctl_create_trace(handle
, trace_name
, mode
, trace_type
,
452 subbuf_size_low
, n_subbufs_low
,
453 subbuf_size_med
, n_subbufs_med
,
454 subbuf_size_high
, n_subbufs_high
);
455 if(ret
!= 0) goto create_error
;
463 ret
= waitpid(pid
, &status
, 0);
466 perror("Error in waitpid");
471 if(WIFEXITED(status
))
472 ret
= WEXITSTATUS(status
);
473 if(ret
) goto start_error
;
475 printf("Creating supplementary trace files\n");
476 ret
= create_eventdefs();
477 if(ret
) goto start_error
;
479 } else if(pid
== 0) {
482 if(mode
!= LTT_TRACE_HYBRID
) {
484 ret
= execlp(lttd_path
, lttd_path
, "-t", trace_root
, "-c",
485 channel_path
, "-d", "-a", "-N", num_threads
, NULL
);
487 ret
= execlp(lttd_path
, lttd_path
, "-t", trace_root
, "-c",
488 channel_path
, "-d", "-N", num_threads
, NULL
);
491 ret
= execlp(lttd_path
, lttd_path
, "-t", trace_root
, "-c",
492 channel_path
, "-d", "-a", "-N", num_threads
, "-n", NULL
);
494 ret
= execlp(lttd_path
, lttd_path
, "-t", trace_root
, "-c",
495 channel_path
, "-d", "-N", num_threads
, "-n", NULL
);
499 perror("Error in executing the lttd daemon");
504 perror("Error in forking for lttd daemon");
507 ret
= lttctl_start(handle
, trace_name
);
508 if(ret
!= 0) goto start_error
;
514 printf("Trace start error\n");
515 ret
|= lttctl_destroy_trace(handle
, trace_name
);
523 int lttctl_daemon_hybrid_finish(struct lttctl_handle
*handle
, char *trace_name
)
525 char channel_path
[PATH_MAX
] = "";
528 char *lttd_path
= getenv("LTT_DAEMON");
530 if(lttd_path
== NULL
) lttd_path
=
531 PACKAGE_BIN_DIR
"/lttd";
533 strcat(channel_path
, channel_root
);
534 strcat(channel_path
, "/");
535 strcat(channel_path
, trace_name
);
538 ret
= lttctl_stop(handle
, trace_name
);
539 if(ret
!= 0) goto stop_error
;
547 ret
= waitpid(pid
, &status
, 0);
550 perror("Error in waitpid");
555 if(WIFEXITED(status
))
556 ret
= WEXITSTATUS(status
);
557 if(ret
) goto destroy_error
;
559 } else if(pid
== 0) {
563 ret
= execlp(lttd_path
, lttd_path
, "-t", trace_root
, "-c",
564 channel_path
, "-d", "-a", "-N", num_threads
, "-f", NULL
);
566 ret
= execlp(lttd_path
, lttd_path
, "-t", trace_root
, "-c",
567 channel_path
, "-d", "-N", num_threads
, "-f", NULL
);
570 perror("Error in executing the lttd daemon");
575 perror("Error in forking for lttd daemon");
578 ret
= lttctl_destroy_trace(handle
, trace_name
);
579 if(ret
!= 0) goto destroy_error
;
585 printf("Hybrid trace destroy error\n");
592 int main(int argc
, char ** argv
)
595 struct lttctl_handle
*handle
;
597 ret
= parse_arguments(argc
, argv
);
599 if(ret
!= 0) show_arguments();
600 if(ret
== EINVAL
) return EINVAL
;
601 if(ret
== -1) return 0;
605 handle
= lttctl_create_handle();
607 if(handle
== NULL
) return -1;
610 case CTL_OP_CREATE_START
:
611 ret
= lttctl_create_trace(handle
, trace_name
, mode
, trace_type
,
612 subbuf_size_low
, n_subbufs_low
,
613 subbuf_size_med
, n_subbufs_med
,
614 subbuf_size_high
, n_subbufs_high
);
616 ret
= lttctl_start(handle
, trace_name
);
619 ret
= lttctl_create_trace(handle
, trace_name
, mode
, trace_type
,
620 subbuf_size_low
, n_subbufs_low
,
621 subbuf_size_med
, n_subbufs_med
,
622 subbuf_size_high
, n_subbufs_high
);
625 ret
= lttctl_destroy_trace(handle
, trace_name
);
627 case CTL_OP_STOP_DESTROY
:
628 ret
= lttctl_stop(handle
, trace_name
);
630 ret
= lttctl_destroy_trace(handle
, trace_name
);
633 ret
= lttctl_start(handle
, trace_name
);
636 ret
= lttctl_stop(handle
, trace_name
);
639 ret
= lttctl_daemon(handle
, trace_name
);
641 case CTL_OP_DAEMON_HYBRID_FINISH
:
642 ret
= lttctl_daemon_hybrid_finish(handle
, trace_name
);
644 case CTL_OP_DESCRIPTION
:
645 ret
= create_eventdefs();
651 ret
|= lttctl_destroy_handle(handle
);