fix leak, enhance error values
[ltt-control.git] / trunk / lttng-xenomai / ltt-control-0.24-xenoltt / lttctl / lttctl.c
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
11 #ifdef HAVE_CONFIG_H
12 #include <config.h>
13 #endif
14
15 #include <liblttctl/lttctl.h>
16 #include <errno.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <sys/types.h>
20 #include <sys/wait.h>
21 #include <unistd.h>
22 #include <signal.h>
23 #include <dirent.h>
24 #include <string.h>
25 #include <sys/stat.h>
26
27 /* Buffer for file copy : 4k seems optimal. */
28 #define BUF_SIZE 4096
29
30 enum trace_ctl_op {
31 CTL_OP_CREATE_START,
32 CTL_OP_CREATE,
33 CTL_OP_DESTROY,
34 CTL_OP_STOP_DESTROY,
35 CTL_OP_START,
36 CTL_OP_STOP,
37 CTL_OP_DAEMON,
38 CTL_OP_DAEMON_HYBRID_FINISH,
39 CTL_OP_DESCRIPTION,
40 CTL_OP_NONE
41 };
42
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";
58
59 /* Args :
60 *
61 */
62 void show_arguments(void)
63 {
64 printf("Please use the following arguments :\n");
65 printf("\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 "
75 // "none exists.\n");
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");
94 printf("\n");
95 }
96
97
98 /* parse_arguments
99 *
100 * Parses the command line arguments.
101 *
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.
104 */
105 int parse_arguments(int argc, char **argv)
106 {
107 int ret = 0;
108 int argn = 1;
109
110 if(argc == 2) {
111 if(strcmp(argv[1], "-h") == 0) {
112 return -1;
113 }
114 }
115
116 while(argn < argc) {
117
118 switch(argv[argn][0]) {
119 case '-':
120 switch(argv[argn][1]) {
121 case 'n':
122 if(argn+1 < argc) {
123 trace_name = argv[argn+1];
124 argn++;
125 } else {
126 printf("Specify a trace name after -n.\n");
127 printf("\n");
128 ret = EINVAL;
129 }
130
131 break;
132 case 'b':
133 op = CTL_OP_CREATE_START;
134 break;
135 case 'c':
136 op = CTL_OP_CREATE;
137 break;
138 case 'm':
139 if(argn+1 < argc) {
140 mode_name = argv[argn+1];
141 argn++;
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;
148 else {
149 printf("Invalid mode '%s'.\n", argv[argn]);
150 printf("\n");
151 ret = EINVAL;
152 }
153 } else {
154 printf("Specify a mode after -m.\n");
155 printf("\n");
156 ret = EINVAL;
157 }
158 break;
159 case 'r':
160 op = CTL_OP_DESTROY;
161 break;
162 case 'R':
163 op = CTL_OP_STOP_DESTROY;
164 break;
165 case 's':
166 op = CTL_OP_START;
167 break;
168 case 'q':
169 op = CTL_OP_STOP;
170 break;
171 case 'Z':
172 if(argn+1 < argc) {
173 subbuf_size_low = (unsigned)atoi(argv[argn+1]);
174 argn++;
175 } else {
176 printf("Specify a number of low traffic subbuffers after -Z.\n");
177 printf("\n");
178 ret = EINVAL;
179 }
180 break;
181 case 'X':
182 if(argn+1 < argc) {
183 n_subbufs_low = (unsigned)atoi(argv[argn+1]);
184 argn++;
185 } else {
186 printf("Specify a low traffic subbuffer size after -X.\n");
187 printf("\n");
188 ret = EINVAL;
189 }
190 break;
191 case 'V':
192 if(argn+1 < argc) {
193 subbuf_size_med = (unsigned)atoi(argv[argn+1]);
194 argn++;
195 } else {
196 printf("Specify a number of medium traffic subbuffers after -V.\n");
197 printf("\n");
198 ret = EINVAL;
199 }
200 break;
201 case 'B':
202 if(argn+1 < argc) {
203 n_subbufs_med = (unsigned)atoi(argv[argn+1]);
204 argn++;
205 } else {
206 printf("Specify a medium traffic subbuffer size after -B.\n");
207 printf("\n");
208 ret = EINVAL;
209 }
210 break;
211 case 'z':
212 if(argn+1 < argc) {
213 subbuf_size_high = (unsigned)atoi(argv[argn+1]);
214 argn++;
215 } else {
216 printf("Specify a number of high traffic subbuffers after -z.\n");
217 printf("\n");
218 ret = EINVAL;
219 }
220 break;
221 case 'x':
222 if(argn+1 < argc) {
223 n_subbufs_high = (unsigned)atoi(argv[argn+1]);
224 argn++;
225 } else {
226 printf("Specify a high traffic subbuffer size after -x.\n");
227 printf("\n");
228 ret = EINVAL;
229 }
230 break;
231 case 'd':
232 op = CTL_OP_DAEMON;
233 break;
234 case 'f':
235 op = CTL_OP_DAEMON_HYBRID_FINISH;
236 break;
237 case 'e':
238 op = CTL_OP_DESCRIPTION;
239 break;
240 case 't':
241 if(argn+1 < argc) {
242 trace_root = argv[argn+1];
243 argn++;
244 } else {
245 printf("Specify a trace root path after -t.\n");
246 printf("\n");
247 ret = EINVAL;
248 }
249 break;
250 case 'l':
251 if(argn+1 < argc) {
252 channel_root = argv[argn+1];
253 argn++;
254 } else {
255 printf("Specify a channel root path after -l.\n");
256 printf("\n");
257 ret = EINVAL;
258 }
259 break;
260 case 'a':
261 append_trace = 1;
262 break;
263 case 'N':
264 if(argn+1 < argc) {
265 num_threads = argv[argn+1];
266 argn++;
267 }
268 break;
269 case 'T':
270 if(argn+1 < argc) {
271 trace_type = argv[argn+1];
272 argn++;
273 } else {
274 printf("Specify a trace type after -T.\n");
275 printf("\n");
276 ret = EINVAL;
277 }
278 break;
279 default:
280 printf("Invalid argument '%s'.\n", argv[argn]);
281 printf("\n");
282 ret = EINVAL;
283 }
284 break;
285 default:
286 printf("Invalid argument '%s'.\n", argv[argn]);
287 printf("\n");
288 ret = EINVAL;
289 }
290 argn++;
291 }
292
293 if(op != CTL_OP_DESCRIPTION && trace_name == NULL) {
294 printf("Please specify a trace name.\n");
295 printf("\n");
296 ret = EINVAL;
297 }
298
299 if(op == CTL_OP_NONE) {
300 printf("Please specify an operation.\n");
301 printf("\n");
302 ret = EINVAL;
303 }
304
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");
308 printf("\n");
309 ret = EINVAL;
310 }
311 if(channel_root == NULL) {
312 printf("Please specify -l ltt_root_path with the -d option.\n");
313 printf("\n");
314 ret = EINVAL;
315 }
316 }
317
318 if(op == CTL_OP_DESCRIPTION) {
319 if(trace_root == NULL) {
320 printf("Please specify -t trace_root_path with the -e option.\n");
321 printf("\n");
322 ret = EINVAL;
323 }
324 }
325
326 return ret;
327 }
328
329 void show_info(void)
330 {
331 printf("Linux Trace Toolkit Trace Control\n");
332 printf("\n");
333 if(trace_name != NULL) {
334 printf("Controlling trace : %s\n", trace_name);
335 printf("\n");
336 }
337 }
338
339 int create_eventdefs(void)
340 {
341 int ret = 0;
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";
350
351 ret = mkdir(trace_root, S_IRWXU|S_IRWXG|S_IRWXO);
352 if(ret == -1 && errno != EEXIST) {
353 ret = errno;
354 perror("Cannot create trace_root directory");
355 printf("trace_root is %s\n", trace_root);
356 goto error;
357 }
358 ret = 0;
359
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)) {
366 ret = errno;
367 perror("Cannot create eventdefs directory");
368 goto error;
369 }
370 ret = 0;
371
372 DIR *facilities_dir = opendir(facilities_path);
373
374 if(facilities_dir == NULL) {
375 perror("Cannot open facilities directory");
376 ret = EEXIST;
377 goto error;
378 }
379
380 while((entry = readdir(facilities_dir)) != NULL) {
381 if(entry->d_name[0] == '.') continue;
382
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");
388 if(!dest) {
389 perror("Cannot create eventdefs file");
390 continue;
391 }
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");
397 if(!src) {
398 ret = errno;
399 perror("Cannot open eventdefs file for reading");
400 goto close_dest;
401 }
402
403 do {
404 size_t read_size, write_size;
405 read_size = fread(read_buf, sizeof(char), BUF_SIZE, src);
406 if(ferror(src)) {
407 ret = errno;
408 perror("Cannot read eventdefs file");
409 goto close_src;
410 }
411 write_size = fwrite(read_buf, sizeof(char), read_size, dest);
412 if(ferror(dest)) {
413 ret = errno;
414 perror("Cannot write eventdefs file");
415 goto close_src;
416 }
417 } while(!feof(src));
418
419 /* Add spacing between facilities */
420 fwrite("\n", 1, 1, dest);
421
422 close_src:
423 fclose(src);
424 close_dest:
425 fclose(dest);
426 }
427
428 closedir(facilities_dir);
429
430 error:
431 return ret;
432
433 }
434
435
436 int lttctl_daemon(struct lttctl_handle *handle, char *trace_name)
437 {
438 char channel_path[PATH_MAX] = "";
439 pid_t pid;
440 int ret;
441 char *lttd_path = getenv("LTT_DAEMON");
442
443 if(lttd_path == NULL) lttd_path =
444 PACKAGE_BIN_DIR "/lttd";
445
446 strcat(channel_path, channel_root);
447 strcat(channel_path, "/");
448 strcat(channel_path, trace_name);
449
450
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;
456
457 pid = fork();
458
459 if(pid > 0) {
460 int status = 0;
461 /* parent */
462
463 ret = waitpid(pid, &status, 0);
464 if(ret == -1) {
465 ret = errno;
466 perror("Error in waitpid");
467 goto start_error;
468 }
469
470 ret = 0;
471 if(WIFEXITED(status))
472 ret = WEXITSTATUS(status);
473 if(ret) goto start_error;
474
475 printf("Creating supplementary trace files\n");
476 ret = create_eventdefs();
477 if(ret) goto start_error;
478
479 } else if(pid == 0) {
480 /* child */
481 int ret;
482 if(mode != LTT_TRACE_HYBRID) {
483 if(append_trace)
484 ret = execlp(lttd_path, lttd_path, "-t", trace_root, "-c",
485 channel_path, "-d", "-a", "-N", num_threads, NULL);
486 else
487 ret = execlp(lttd_path, lttd_path, "-t", trace_root, "-c",
488 channel_path, "-d", "-N", num_threads, NULL);
489 } else {
490 if(append_trace)
491 ret = execlp(lttd_path, lttd_path, "-t", trace_root, "-c",
492 channel_path, "-d", "-a", "-N", num_threads, "-n", NULL);
493 else
494 ret = execlp(lttd_path, lttd_path, "-t", trace_root, "-c",
495 channel_path, "-d", "-N", num_threads, "-n", NULL);
496 }
497 if(ret) {
498 ret = errno;
499 perror("Error in executing the lttd daemon");
500 exit(ret);
501 }
502 } else {
503 /* error */
504 perror("Error in forking for lttd daemon");
505 }
506
507 ret = lttctl_start(handle, trace_name);
508 if(ret != 0) goto start_error;
509
510 return 0;
511
512 /* error handling */
513 start_error:
514 printf("Trace start error\n");
515 ret |= lttctl_destroy_trace(handle, trace_name);
516 create_error:
517 return ret;
518 }
519
520
521
522
523 int lttctl_daemon_hybrid_finish(struct lttctl_handle *handle, char *trace_name)
524 {
525 char channel_path[PATH_MAX] = "";
526 pid_t pid;
527 int ret;
528 char *lttd_path = getenv("LTT_DAEMON");
529
530 if(lttd_path == NULL) lttd_path =
531 PACKAGE_BIN_DIR "/lttd";
532
533 strcat(channel_path, channel_root);
534 strcat(channel_path, "/");
535 strcat(channel_path, trace_name);
536
537
538 ret = lttctl_stop(handle, trace_name);
539 if(ret != 0) goto stop_error;
540
541 pid = fork();
542
543 if(pid > 0) {
544 int status = 0;
545 /* parent */
546
547 ret = waitpid(pid, &status, 0);
548 if(ret == -1) {
549 ret = errno;
550 perror("Error in waitpid");
551 goto destroy_error;
552 }
553
554 ret = 0;
555 if(WIFEXITED(status))
556 ret = WEXITSTATUS(status);
557 if(ret) goto destroy_error;
558
559 } else if(pid == 0) {
560 /* child */
561 int ret;
562 if(append_trace)
563 ret = execlp(lttd_path, lttd_path, "-t", trace_root, "-c",
564 channel_path, "-d", "-a", "-N", num_threads, "-f", NULL);
565 else
566 ret = execlp(lttd_path, lttd_path, "-t", trace_root, "-c",
567 channel_path, "-d", "-N", num_threads, "-f", NULL);
568 if(ret) {
569 ret = errno;
570 perror("Error in executing the lttd daemon");
571 exit(ret);
572 }
573 } else {
574 /* error */
575 perror("Error in forking for lttd daemon");
576 }
577
578 ret = lttctl_destroy_trace(handle, trace_name);
579 if(ret != 0) goto destroy_error;
580
581 return 0;
582
583 /* error handling */
584 destroy_error:
585 printf("Hybrid trace destroy error\n");
586 stop_error:
587 return ret;
588 }
589
590
591
592 int main(int argc, char ** argv)
593 {
594 int ret;
595 struct lttctl_handle *handle;
596
597 ret = parse_arguments(argc, argv);
598
599 if(ret != 0) show_arguments();
600 if(ret == EINVAL) return EINVAL;
601 if(ret == -1) return 0;
602
603 show_info();
604
605 handle = lttctl_create_handle();
606
607 if(handle == NULL) return -1;
608
609 switch(op) {
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);
615 if(!ret)
616 ret = lttctl_start(handle, trace_name);
617 break;
618 case CTL_OP_CREATE:
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);
623 break;
624 case CTL_OP_DESTROY:
625 ret = lttctl_destroy_trace(handle, trace_name);
626 break;
627 case CTL_OP_STOP_DESTROY:
628 ret = lttctl_stop(handle, trace_name);
629 if(!ret)
630 ret = lttctl_destroy_trace(handle, trace_name);
631 break;
632 case CTL_OP_START:
633 ret = lttctl_start(handle, trace_name);
634 break;
635 case CTL_OP_STOP:
636 ret = lttctl_stop(handle, trace_name);
637 break;
638 case CTL_OP_DAEMON:
639 ret = lttctl_daemon(handle, trace_name);
640 break;
641 case CTL_OP_DAEMON_HYBRID_FINISH:
642 ret = lttctl_daemon_hybrid_finish(handle, trace_name);
643 break;
644 case CTL_OP_DESCRIPTION:
645 ret = create_eventdefs();
646 break;
647 case CTL_OP_NONE:
648 break;
649 }
650
651 ret |= lttctl_destroy_handle(handle);
652
653 return ret;
654 }
This page took 0.042157 seconds and 4 git commands to generate.