update roadmap
[lttv.git] / ltt-control / lttctl / lttctl.c
CommitLineData
2cdb6fcb 1/* lttctl
2 *
3 * Linux Trace Toolkit Control
4 *
5 * Small program that controls LTT through libltt.
6 *
7 * Copyright 2005 -
8 * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
9 */
10
4e4d11b3 11#ifdef HAVE_CONFIG_H
12#include <config.h>
13#endif
14
5cec0a15 15#include <liblttctl/lttctl.h>
5adba60f 16#include <errno.h>
17#include <stdio.h>
18#include <stdlib.h>
19#include <sys/types.h>
86a65fdb 20#include <sys/wait.h>
5adba60f 21#include <unistd.h>
22#include <signal.h>
d5fbdb60 23#include <dirent.h>
24#include <string.h>
25#include <sys/stat.h>
26
27/* Buffer for file copy : 4k seems optimal. */
2312de30 28#define BUF_SIZE 4096
2cdb6fcb 29
5adba60f 30enum trace_ctl_op {
b7f08766 31 CTL_OP_CREATE_START,
5adba60f 32 CTL_OP_CREATE,
33 CTL_OP_DESTROY,
b7f08766 34 CTL_OP_STOP_DESTROY,
5adba60f 35 CTL_OP_START,
36 CTL_OP_STOP,
37 CTL_OP_DAEMON,
129fd24a 38 CTL_OP_DESCRIPTION,
5adba60f 39 CTL_OP_NONE
40};
2cdb6fcb 41
5adba60f 42static char *trace_name = NULL;
43static char *mode_name = NULL;
988614ed 44static unsigned subbuf_size = 0;
45static unsigned n_subbufs = 0;
45653836 46static unsigned append_trace = 0;
5adba60f 47static enum trace_mode mode = LTT_TRACE_NORMAL;
48static enum trace_ctl_op op = CTL_OP_NONE;
49static char *channel_root = NULL;
50static char *trace_root = NULL;
22acb617 51static char *num_threads = "1";
5adba60f 52
86a65fdb 53static int sigchld_received = 0;
ada84671 54
86a65fdb 55void sigchld_handler(int signo)
5adba60f 56{
57 printf("signal %d received\n", signo);
86a65fdb 58 sigchld_received = 1;
5adba60f 59}
60
61
62/* Args :
63 *
64 */
65void show_arguments(void)
66{
67 printf("Please use the following arguments :\n");
68 printf("\n");
69 printf("-n name Name of the trace.\n");
b7f08766 70 printf("-b Create trace channels and start tracing (no daemon).\n");
bc0fcb31 71 printf("-c Create trace channels.\n");
72 printf("-m mode Normal or flight recorder mode.\n");
5adba60f 73 printf(" Mode values : normal (default) or flight.\n");
74 printf("-r Destroy trace channels.\n");
b7f08766 75 printf("-R Stop tracing and destroy trace channels.\n");
5adba60f 76 printf("-s Start tracing.\n");
77 //printf(" Note : will automatically create a normal trace if "
78 // "none exists.\n");
79 printf("-q Stop tracing.\n");
80 printf("-d Create trace, spawn a lttd daemon, start tracing.\n");
d5fbdb60 81 printf(" (optionnaly, you can set LTT_DAEMON\n");
82 printf(" and the LTT_FACILITIES env. vars.)\n");
5adba60f 83 printf("-t Trace root path. (ex. /root/traces/example_trace)\n");
84 printf("-l LTT channels root path. (ex. /mnt/relayfs/ltt)\n");
4085af66 85 printf("-z Size of the subbuffers (will be rounded to next page size)\n");
988614ed 86 printf("-x Number of subbuffers\n");
129fd24a 87 printf("-e Get XML facilities description\n");
45653836 88 printf("-a Append to trace\n");
b8d28629 89 printf("-N Number of lttd threads\n");
5adba60f 90 printf("\n");
91}
92
93
94/* parse_arguments
95 *
96 * Parses the command line arguments.
97 *
2baf08e5 98 * Returns -1 if the arguments were correct, but doesn't ask for program
99 * continuation. Returns EINVAL if the arguments are incorrect, or 0 if OK.
5adba60f 100 */
101int parse_arguments(int argc, char **argv)
102{
103 int ret = 0;
104 int argn = 1;
105
106 if(argc == 2) {
107 if(strcmp(argv[1], "-h") == 0) {
2baf08e5 108 return -1;
5adba60f 109 }
110 }
111
112 while(argn < argc) {
113
114 switch(argv[argn][0]) {
115 case '-':
116 switch(argv[argn][1]) {
117 case 'n':
118 if(argn+1 < argc) {
119 trace_name = argv[argn+1];
120 argn++;
121 } else {
8eab4866 122 printf("Specify a trace name after -n.\n");
5adba60f 123 printf("\n");
2baf08e5 124 ret = EINVAL;
5adba60f 125 }
126
127 break;
b7f08766 128 case 'b':
129 op = CTL_OP_CREATE_START;
cd39bb61 130 break;
5adba60f 131 case 'c':
132 op = CTL_OP_CREATE;
bc0fcb31 133 break;
134 case 'm':
5adba60f 135 if(argn+1 < argc) {
136 mode_name = argv[argn+1];
137 argn++;
138 if(strcmp(mode_name, "normal") == 0)
139 mode = LTT_TRACE_NORMAL;
140 else if(strcmp(mode_name, "flight") == 0)
141 mode = LTT_TRACE_FLIGHT;
142 else {
143 printf("Invalid mode '%s'.\n", argv[argn]);
144 printf("\n");
2baf08e5 145 ret = EINVAL;
5adba60f 146 }
147 } else {
bc0fcb31 148 printf("Specify a mode after -m.\n");
5adba60f 149 printf("\n");
2baf08e5 150 ret = EINVAL;
5adba60f 151 }
152 break;
153 case 'r':
154 op = CTL_OP_DESTROY;
155 break;
b7f08766 156 case 'R':
157 op = CTL_OP_STOP_DESTROY;
158 break;
5adba60f 159 case 's':
160 op = CTL_OP_START;
161 break;
162 case 'q':
163 op = CTL_OP_STOP;
164 break;
988614ed 165 case 'z':
166 if(argn+1 < argc) {
167 subbuf_size = (unsigned)atoi(argv[argn+1]);
168 argn++;
169 } else {
170 printf("Specify a number of subbuffers after -z.\n");
171 printf("\n");
2baf08e5 172 ret = EINVAL;
988614ed 173 }
174 break;
175 case 'x':
176 if(argn+1 < argc) {
177 n_subbufs = (unsigned)atoi(argv[argn+1]);
178 argn++;
179 } else {
180 printf("Specify a subbuffer size after -x.\n");
181 printf("\n");
2baf08e5 182 ret = EINVAL;
988614ed 183 }
184 break;
5adba60f 185 case 'd':
186 op = CTL_OP_DAEMON;
187 break;
129fd24a 188 case 'e':
189 op = CTL_OP_DESCRIPTION;
190 break;
5adba60f 191 case 't':
192 if(argn+1 < argc) {
193 trace_root = argv[argn+1];
194 argn++;
195 } else {
988614ed 196 printf("Specify a trace root path after -t.\n");
5adba60f 197 printf("\n");
2baf08e5 198 ret = EINVAL;
5adba60f 199 }
200 break;
201 case 'l':
202 if(argn+1 < argc) {
203 channel_root = argv[argn+1];
204 argn++;
205 } else {
988614ed 206 printf("Specify a channel root path after -l.\n");
5adba60f 207 printf("\n");
2baf08e5 208 ret = EINVAL;
5adba60f 209 }
210 break;
45653836 211 case 'a':
212 append_trace = 1;
213 break;
22acb617 214 case 'N':
215 if(argn+1 < argc) {
216 num_threads = argv[argn+1];
217 argn++;
218 }
219 break;
5adba60f 220 default:
221 printf("Invalid argument '%s'.\n", argv[argn]);
222 printf("\n");
2baf08e5 223 ret = EINVAL;
5adba60f 224 }
225 break;
226 default:
227 printf("Invalid argument '%s'.\n", argv[argn]);
228 printf("\n");
2baf08e5 229 ret = EINVAL;
5adba60f 230 }
231 argn++;
232 }
233
129fd24a 234 if(op != CTL_OP_DESCRIPTION && trace_name == NULL) {
5adba60f 235 printf("Please specify a trace name.\n");
236 printf("\n");
2baf08e5 237 ret = EINVAL;
5adba60f 238 }
239
240 if(op == CTL_OP_NONE) {
241 printf("Please specify an operation.\n");
242 printf("\n");
2baf08e5 243 ret = EINVAL;
5adba60f 244 }
245
246 if(op == CTL_OP_DAEMON) {
247 if(trace_root == NULL) {
248 printf("Please specify -t trace_root_path with the -d option.\n");
249 printf("\n");
2baf08e5 250 ret = EINVAL;
5adba60f 251 }
252 if(channel_root == NULL) {
253 printf("Please specify -l ltt_root_path with the -d option.\n");
254 printf("\n");
2baf08e5 255 ret = EINVAL;
5adba60f 256 }
257 }
258
129fd24a 259 if(op == CTL_OP_DESCRIPTION) {
260 if(trace_root == NULL) {
261 printf("Please specify -t trace_root_path with the -e option.\n");
262 printf("\n");
2baf08e5 263 ret = EINVAL;
129fd24a 264 }
265 }
266
5adba60f 267 return ret;
268}
269
270void show_info(void)
271{
272 printf("Linux Trace Toolkit Trace Control\n");
273 printf("\n");
129fd24a 274 if(trace_name != NULL) {
275 printf("Controlling trace : %s\n", trace_name);
276 printf("\n");
277 }
278}
279
280int create_eventdefs(void)
281{
282 int ret = 0;
283 char eventdefs_path[PATH_MAX];
284 char eventdefs_file[PATH_MAX];
285 char facilities_file[PATH_MAX];
286 char read_buf[BUF_SIZE];
287 struct dirent *entry;
288 char *facilities_path = getenv("LTT_FACILITIES");
289 if(facilities_path == NULL) facilities_path =
86a65fdb 290 PACKAGE_DATA_DIR "/" PACKAGE "/facilities";
129fd24a 291
292 ret = mkdir(trace_root, S_IRWXU|S_IRWXG|S_IRWXO);
293 if(ret == -1 && errno != EEXIST) {
618fbcc1 294 ret = errno;
129fd24a 295 perror("Cannot create trace_root directory");
296 printf("trace_root is %s\n", trace_root);
297 goto error;
298 }
bd55296c 299 ret = 0;
129fd24a 300
301 size_t trace_root_len = strlen(trace_root);
302 strncpy(eventdefs_path, trace_root, PATH_MAX);
303 strncat(eventdefs_path, "/eventdefs/", PATH_MAX - trace_root_len);
304 size_t eventdefs_path_len = strlen(eventdefs_path);
305 ret = mkdir(eventdefs_path, S_IRWXU|S_IRWXG|S_IRWXO);
45653836 306 if(ret == -1 && (!append_trace || errno != EEXIST)) {
2baf08e5 307 ret = errno;
618fbcc1 308 perror("Cannot create eventdefs directory");
129fd24a 309 goto error;
310 }
bd55296c 311 ret = 0;
129fd24a 312
313 DIR *facilities_dir = opendir(facilities_path);
314
86a65fdb 315 if(facilities_dir == NULL) {
316 perror("Cannot open facilities directory");
2baf08e5 317 ret = EEXIST;
86a65fdb 318 goto error;
319 }
320
129fd24a 321 while((entry = readdir(facilities_dir)) != NULL) {
322 if(entry->d_name[0] == '.') continue;
323
324 printf("Appending facility file %s\n", entry->d_name);
325 strncpy(eventdefs_file, eventdefs_path, PATH_MAX);
326 strncat(eventdefs_file, entry->d_name, PATH_MAX - eventdefs_path_len);
327 /* Append to the file */
328 FILE *dest = fopen(eventdefs_file, "a");
329 if(!dest) {
330 perror("Cannot create eventdefs file");
331 continue;
332 }
333 strncpy(facilities_file, facilities_path, PATH_MAX);
334 size_t facilities_dir_len = strlen(facilities_path);
335 strncat(facilities_file, "/", PATH_MAX - facilities_dir_len);
336 strncat(facilities_file, entry->d_name, PATH_MAX - facilities_dir_len-1);
337 FILE *src = fopen(facilities_file, "r");
338 if(!src) {
2baf08e5 339 ret = errno;
618fbcc1 340 perror("Cannot open eventdefs file for reading");
129fd24a 341 goto close_dest;
342 }
343
344 do {
345 size_t read_size, write_size;
346 read_size = fread(read_buf, sizeof(char), BUF_SIZE, src);
347 if(ferror(src)) {
2baf08e5 348 ret = errno;
618fbcc1 349 perror("Cannot read eventdefs file");
129fd24a 350 goto close_src;
351 }
352 write_size = fwrite(read_buf, sizeof(char), read_size, dest);
353 if(ferror(dest)) {
2baf08e5 354 ret = errno;
618fbcc1 355 perror("Cannot write eventdefs file");
129fd24a 356 goto close_src;
357 }
358 } while(!feof(src));
359
360 /* Add spacing between facilities */
361 fwrite("\n", 1, 1, dest);
362
363close_src:
364 fclose(src);
365close_dest:
366 fclose(dest);
367 }
368
369 closedir(facilities_dir);
370
86a65fdb 371error:
129fd24a 372 return ret;
373
5adba60f 374}
375
129fd24a 376
5adba60f 377int lttctl_daemon(struct lttctl_handle *handle, char *trace_name)
378{
379 char channel_path[PATH_MAX] = "";
380 pid_t pid;
381 int ret;
382 char *lttd_path = getenv("LTT_DAEMON");
383 struct sigaction act;
384
86a65fdb 385 if(lttd_path == NULL) lttd_path =
386 PACKAGE_BIN_DIR "/lttd";
5adba60f 387
388 strcat(channel_path, channel_root);
389 strcat(channel_path, "/");
390 strcat(channel_path, trace_name);
391
392
988614ed 393 ret = lttctl_create_trace(handle, trace_name, mode, subbuf_size, n_subbufs);
5adba60f 394 if(ret != 0) goto create_error;
395
86a65fdb 396 act.sa_handler = sigchld_handler;
5adba60f 397 sigemptyset(&(act.sa_mask));
86a65fdb 398 sigaddset(&(act.sa_mask), SIGCHLD);
399 sigaction(SIGCHLD, &act, NULL);
ada84671 400
5adba60f 401 pid = fork();
402
403 if(pid > 0) {
86a65fdb 404 int status;
5adba60f 405 /* parent */
86a65fdb 406 while(!(sigchld_received)) pause();
407
408 waitpid(pid, &status, 0);
409 ret = 0;
410 if(WIFEXITED(status))
411 ret = WEXITSTATUS(status);
412 if(ret) goto start_error;
5adba60f 413
5adba60f 414 printf("Creating supplementary trace files\n");
129fd24a 415 ret = create_eventdefs();
416 if(ret) goto start_error;
5adba60f 417
418 } else if(pid == 0) {
419 /* child */
45653836 420 int ret;
421 if(append_trace)
422 ret = execlp(lttd_path, lttd_path, "-t", trace_root, "-c",
22acb617 423 channel_path, "-d", "-a", "-N", num_threads, NULL);
45653836 424 else
425 ret = execlp(lttd_path, lttd_path, "-t", trace_root, "-c",
22acb617 426 channel_path, "-d", "-N", num_threads, NULL);
5adba60f 427 if(ret) {
618fbcc1 428 ret = errno;
5adba60f 429 perror("Error in executing the lttd daemon");
618fbcc1 430 exit(ret);
5adba60f 431 }
432 } else {
433 /* error */
434 perror("Error in forking for lttd daemon");
5adba60f 435 }
436
437 ret = lttctl_start(handle, trace_name);
438 if(ret != 0) goto start_error;
439
440 return 0;
441
442 /* error handling */
443start_error:
86a65fdb 444 printf("Trace start error\n");
5adba60f 445 ret |= lttctl_destroy_trace(handle, trace_name);
446create_error:
447 return ret;
448}
449
450int main(int argc, char ** argv)
451{
452 int ret;
453 struct lttctl_handle *handle;
454
455 ret = parse_arguments(argc, argv);
456
457 if(ret != 0) show_arguments();
2baf08e5 458 if(ret == EINVAL) return EINVAL;
459 if(ret == -1) return 0;
5adba60f 460
461 show_info();
462
463 handle = lttctl_create_handle();
464
465 if(handle == NULL) return -1;
466
467 switch(op) {
b7f08766 468 case CTL_OP_CREATE_START:
469 ret = lttctl_create_trace(handle, trace_name, mode, subbuf_size,
470 n_subbufs);
471 if(!ret)
472 ret = lttctl_start(handle, trace_name);
473 break;
5adba60f 474 case CTL_OP_CREATE:
988614ed 475 ret = lttctl_create_trace(handle, trace_name, mode, subbuf_size,
476 n_subbufs);
24ba6df0 477 break;
5adba60f 478 case CTL_OP_DESTROY:
479 ret = lttctl_destroy_trace(handle, trace_name);
480 break;
b7f08766 481 case CTL_OP_STOP_DESTROY:
482 ret = lttctl_stop(handle, trace_name);
483 if(!ret)
484 ret = lttctl_destroy_trace(handle, trace_name);
485 break;
5adba60f 486 case CTL_OP_START:
487 ret = lttctl_start(handle, trace_name);
488 break;
489 case CTL_OP_STOP:
490 ret = lttctl_stop(handle, trace_name);
491 break;
492 case CTL_OP_DAEMON:
493 ret = lttctl_daemon(handle, trace_name);
494 break;
129fd24a 495 case CTL_OP_DESCRIPTION:
496 ret = create_eventdefs();
497 break;
5adba60f 498 case CTL_OP_NONE:
499 break;
500 }
501
502 ret |= lttctl_destroy_handle(handle);
503
504 return ret;
505}
This page took 0.055249 seconds and 4 git commands to generate.