Hi Mathieu,
[ltt-control.git] / trunk / ltt-control / 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 <limits.h>
26 #include <sys/stat.h>
27
28 /* Buffer for file copy : 4k seems optimal. */
29 #define BUF_SIZE 4096
30
31 enum trace_ctl_op {
32 CTL_OP_CREATE_START,
33 CTL_OP_CREATE,
34 CTL_OP_DESTROY,
35 CTL_OP_STOP_DESTROY,
36 CTL_OP_START,
37 CTL_OP_STOP,
38 CTL_OP_DAEMON,
39 CTL_OP_DAEMON_HYBRID_FINISH,
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 channel_root_default[PATH_MAX];
57 static char *trace_root = NULL;
58 static char *num_threads = "1";
59
60 /* Args :
61 *
62 */
63 void show_arguments(void)
64 {
65 printf("Please use the following arguments :\n");
66 printf("\n");
67 printf("-n name Name of the trace.\n");
68 printf("-b Create trace channels and start tracing (no daemon).\n");
69 printf("-c Create trace channels.\n");
70 printf("-m mode Normal, flight recorder or hybrid mode.\n");
71 printf(" Mode values : normal (default), flight or hybrid.\n");
72 printf("-r Destroy trace channels.\n");
73 printf("-R Stop tracing and destroy trace channels.\n");
74 printf("-s Start tracing.\n");
75 //printf(" Note : will automatically create a normal trace if "
76 // "none exists.\n");
77 printf("-q Stop tracing.\n");
78 printf("-d Create trace, spawn a lttd daemon, start tracing.\n");
79 printf(" (optionally, you can set LTT_DAEMON\n");
80 printf(" env. var.)\n");
81 printf("-f Stop tracing, dump flight recorder trace, destroy channels\n");
82 printf(" (for hybrid traces)\n");
83 printf("-t Trace root path. (ex. /root/traces/example_trace)\n");
84 printf("-T Type of trace (ex. relay)\n");
85 printf("-l LTT channels root path. (ex. /mnt/debugfs/ltt)\n");
86 printf("-Z Size of the low data rate subbuffers (will be rounded to next page size)\n");
87 printf("-X Number of low data rate subbuffers\n");
88 printf("-V Size of the medium data rate subbuffers (will be rounded to next page size)\n");
89 printf("-B Number of medium data rate subbuffers\n");
90 printf("-z Size of the high data rate subbuffers (will be rounded to next page size)\n");
91 printf("-x Number of high data rate subbuffers\n");
92 printf("-a Append to trace\n");
93 printf("-N Number of lttd threads\n");
94 printf("\n");
95 }
96
97 int getdebugfsmntdir(char *mntdir)
98 {
99 char mnt_dir[PATH_MAX];
100 char mnt_type[PATH_MAX];
101
102 FILE *fp = fopen("/proc/mounts", "r");
103 if (!fp) {
104 return EINVAL;
105 }
106
107 while (1) {
108 if (fscanf(fp, "%*s %s %s %*s %*s %*s", mnt_dir, mnt_type) <= 0) {
109 return ENOENT;
110 }
111 if (!strcmp(mnt_type, "debugfs")) {
112 strcpy(mntdir, mnt_dir);
113 return 0;
114 }
115 }
116 }
117
118 /* parse_arguments
119 *
120 * Parses the command line arguments.
121 *
122 * Returns -1 if the arguments were correct, but doesn't ask for program
123 * continuation. Returns EINVAL if the arguments are incorrect, or 0 if OK.
124 */
125 int parse_arguments(int argc, char **argv)
126 {
127 int ret = 0;
128 int argn = 1;
129
130 if(argc == 2) {
131 if(strcmp(argv[1], "-h") == 0) {
132 return -1;
133 }
134 }
135
136 while(argn < argc) {
137
138 switch(argv[argn][0]) {
139 case '-':
140 switch(argv[argn][1]) {
141 case 'n':
142 if(argn+1 < argc) {
143 trace_name = argv[argn+1];
144 argn++;
145 } else {
146 printf("Specify a trace name after -n.\n");
147 printf("\n");
148 ret = EINVAL;
149 }
150
151 break;
152 case 'b':
153 op = CTL_OP_CREATE_START;
154 break;
155 case 'c':
156 op = CTL_OP_CREATE;
157 break;
158 case 'm':
159 if(argn+1 < argc) {
160 mode_name = argv[argn+1];
161 argn++;
162 if(strcmp(mode_name, "normal") == 0)
163 mode = LTT_TRACE_NORMAL;
164 else if(strcmp(mode_name, "flight") == 0)
165 mode = LTT_TRACE_FLIGHT;
166 else if(strcmp(mode_name, "hybrid") == 0)
167 mode = LTT_TRACE_HYBRID;
168 else {
169 printf("Invalid mode '%s'.\n", argv[argn]);
170 printf("\n");
171 ret = EINVAL;
172 }
173 } else {
174 printf("Specify a mode after -m.\n");
175 printf("\n");
176 ret = EINVAL;
177 }
178 break;
179 case 'r':
180 op = CTL_OP_DESTROY;
181 break;
182 case 'R':
183 op = CTL_OP_STOP_DESTROY;
184 break;
185 case 's':
186 op = CTL_OP_START;
187 break;
188 case 'q':
189 op = CTL_OP_STOP;
190 break;
191 case 'Z':
192 if(argn+1 < argc) {
193 subbuf_size_low = (unsigned)atoi(argv[argn+1]);
194 argn++;
195 } else {
196 printf("Specify a number of low traffic subbuffers after -Z.\n");
197 printf("\n");
198 ret = EINVAL;
199 }
200 break;
201 case 'X':
202 if(argn+1 < argc) {
203 n_subbufs_low = (unsigned)atoi(argv[argn+1]);
204 argn++;
205 } else {
206 printf("Specify a low traffic subbuffer size after -X.\n");
207 printf("\n");
208 ret = EINVAL;
209 }
210 break;
211 case 'V':
212 if(argn+1 < argc) {
213 subbuf_size_med = (unsigned)atoi(argv[argn+1]);
214 argn++;
215 } else {
216 printf("Specify a number of medium traffic subbuffers after -V.\n");
217 printf("\n");
218 ret = EINVAL;
219 }
220 break;
221 case 'B':
222 if(argn+1 < argc) {
223 n_subbufs_med = (unsigned)atoi(argv[argn+1]);
224 argn++;
225 } else {
226 printf("Specify a medium traffic subbuffer size after -B.\n");
227 printf("\n");
228 ret = EINVAL;
229 }
230 break;
231 case 'z':
232 if(argn+1 < argc) {
233 subbuf_size_high = (unsigned)atoi(argv[argn+1]);
234 argn++;
235 } else {
236 printf("Specify a number of high traffic subbuffers after -z.\n");
237 printf("\n");
238 ret = EINVAL;
239 }
240 break;
241 case 'x':
242 if(argn+1 < argc) {
243 n_subbufs_high = (unsigned)atoi(argv[argn+1]);
244 argn++;
245 } else {
246 printf("Specify a high traffic subbuffer size after -x.\n");
247 printf("\n");
248 ret = EINVAL;
249 }
250 break;
251 case 'd':
252 op = CTL_OP_DAEMON;
253 break;
254 case 'f':
255 op = CTL_OP_DAEMON_HYBRID_FINISH;
256 break;
257 case 't':
258 if(argn+1 < argc) {
259 trace_root = argv[argn+1];
260 argn++;
261 } else {
262 printf("Specify a trace root path after -t.\n");
263 printf("\n");
264 ret = EINVAL;
265 }
266 break;
267 case 'l':
268 if(argn+1 < argc) {
269 channel_root = argv[argn+1];
270 argn++;
271 } else {
272 printf("Specify a channel root path after -l.\n");
273 printf("\n");
274 ret = EINVAL;
275 }
276 break;
277 case 'a':
278 append_trace = 1;
279 break;
280 case 'N':
281 if(argn+1 < argc) {
282 num_threads = argv[argn+1];
283 argn++;
284 }
285 break;
286 case 'T':
287 if(argn+1 < argc) {
288 trace_type = argv[argn+1];
289 argn++;
290 } else {
291 printf("Specify a trace type after -T.\n");
292 printf("\n");
293 ret = EINVAL;
294 }
295 break;
296 default:
297 printf("Invalid argument '%s'.\n", argv[argn]);
298 printf("\n");
299 ret = EINVAL;
300 }
301 break;
302 default:
303 printf("Invalid argument '%s'.\n", argv[argn]);
304 printf("\n");
305 ret = EINVAL;
306 }
307 argn++;
308 }
309
310 if(trace_name == NULL) {
311 printf("Please specify a trace name.\n");
312 printf("\n");
313 ret = EINVAL;
314 }
315
316 if(op == CTL_OP_NONE) {
317 printf("Please specify an operation.\n");
318 printf("\n");
319 ret = EINVAL;
320 }
321
322 if(op == CTL_OP_DAEMON || op == CTL_OP_DAEMON_HYBRID_FINISH) {
323 if(trace_root == NULL) {
324 printf("Please specify -t trace_root_path with the -d option.\n");
325 printf("\n");
326 ret = EINVAL;
327 }
328 if(channel_root == NULL) {
329 if (getdebugfsmntdir(channel_root_default) == 0) {
330 strcat(channel_root_default, "/ltt");
331 printf("No -l ltt_root_path with the -d option, using default: %s\n", channel_root_default);
332 printf("\n");
333 channel_root=channel_root_default;
334 } else {
335 printf("Please specify -l ltt_root_path with the -d option.\n");
336 printf("\n");
337 ret = EINVAL;
338 }
339 }
340 }
341
342 return ret;
343 }
344
345 void show_info(void)
346 {
347 printf("Linux Trace Toolkit Trace Control " VERSION"\n");
348 printf("\n");
349 if(trace_name != NULL) {
350 printf("Controlling trace : %s\n", trace_name);
351 printf("\n");
352 }
353 }
354
355 int lttctl_daemon(struct lttctl_handle *handle, char *trace_name)
356 {
357 char channel_path[PATH_MAX] = "";
358 pid_t pid;
359 int ret;
360 char *lttd_path = getenv("LTT_DAEMON");
361
362 if(lttd_path == NULL) lttd_path =
363 PACKAGE_BIN_DIR "/lttd";
364
365 strcat(channel_path, channel_root);
366 strcat(channel_path, "/");
367 strcat(channel_path, trace_name);
368
369
370 ret = lttctl_create_trace(handle, trace_name, mode, trace_type,
371 subbuf_size_low, n_subbufs_low,
372 subbuf_size_med, n_subbufs_med,
373 subbuf_size_high, n_subbufs_high);
374 if(ret != 0) goto create_error;
375
376 pid = fork();
377
378 if(pid > 0) {
379 int status = 0;
380 /* parent */
381
382 ret = waitpid(pid, &status, 0);
383 if(ret == -1) {
384 ret = errno;
385 perror("Error in waitpid");
386 goto start_error;
387 }
388
389 ret = 0;
390 if(WIFEXITED(status))
391 ret = WEXITSTATUS(status);
392 if(ret) goto start_error;
393
394 } else if(pid == 0) {
395 /* child */
396 int ret;
397 if(mode != LTT_TRACE_HYBRID) {
398 if(append_trace)
399 ret = execlp(lttd_path, lttd_path, "-t", trace_root, "-c",
400 channel_path, "-d", "-a", "-N", num_threads, NULL);
401 else
402 ret = execlp(lttd_path, lttd_path, "-t", trace_root, "-c",
403 channel_path, "-d", "-N", num_threads, NULL);
404 } else {
405 if(append_trace)
406 ret = execlp(lttd_path, lttd_path, "-t", trace_root, "-c",
407 channel_path, "-d", "-a", "-N", num_threads, "-n", NULL);
408 else
409 ret = execlp(lttd_path, lttd_path, "-t", trace_root, "-c",
410 channel_path, "-d", "-N", num_threads, "-n", NULL);
411 }
412 if(ret) {
413 ret = errno;
414 perror("Error in executing the lttd daemon");
415 exit(ret);
416 }
417 } else {
418 /* error */
419 perror("Error in forking for lttd daemon");
420 }
421
422 ret = lttctl_start(handle, trace_name);
423 if(ret != 0) goto start_error;
424
425 return 0;
426
427 /* error handling */
428 start_error:
429 printf("Trace start error\n");
430 ret |= lttctl_destroy_trace(handle, trace_name);
431 create_error:
432 return ret;
433 }
434
435
436
437
438 int lttctl_daemon_hybrid_finish(struct lttctl_handle *handle, char *trace_name)
439 {
440 char channel_path[PATH_MAX] = "";
441 pid_t pid;
442 int ret;
443 char *lttd_path = getenv("LTT_DAEMON");
444
445 if(lttd_path == NULL) lttd_path =
446 PACKAGE_BIN_DIR "/lttd";
447
448 strcat(channel_path, channel_root);
449 strcat(channel_path, "/");
450 strcat(channel_path, trace_name);
451
452
453 ret = lttctl_stop(handle, trace_name);
454 if(ret != 0) goto stop_error;
455
456 pid = fork();
457
458 if(pid > 0) {
459 int status = 0;
460 /* parent */
461
462 ret = waitpid(pid, &status, 0);
463 if(ret == -1) {
464 ret = errno;
465 perror("Error in waitpid");
466 goto destroy_error;
467 }
468
469 ret = 0;
470 if(WIFEXITED(status))
471 ret = WEXITSTATUS(status);
472 if(ret) goto destroy_error;
473
474 } else if(pid == 0) {
475 /* child */
476 int ret;
477 if(append_trace)
478 ret = execlp(lttd_path, lttd_path, "-t", trace_root, "-c",
479 channel_path, "-d", "-a", "-N", num_threads, "-f", NULL);
480 else
481 ret = execlp(lttd_path, lttd_path, "-t", trace_root, "-c",
482 channel_path, "-d", "-N", num_threads, "-f", NULL);
483 if(ret) {
484 ret = errno;
485 perror("Error in executing the lttd daemon");
486 exit(ret);
487 }
488 } else {
489 /* error */
490 perror("Error in forking for lttd daemon");
491 }
492
493 ret = lttctl_destroy_trace(handle, trace_name);
494 if(ret != 0) goto destroy_error;
495
496 return 0;
497
498 /* error handling */
499 destroy_error:
500 printf("Hybrid trace destroy error\n");
501 stop_error:
502 return ret;
503 }
504
505
506
507 int main(int argc, char ** argv)
508 {
509 int ret;
510 struct lttctl_handle *handle;
511
512 ret = parse_arguments(argc, argv);
513
514 if(ret != 0) show_arguments();
515 if(ret == EINVAL) return EINVAL;
516 if(ret == -1) return 0;
517
518 show_info();
519
520 handle = lttctl_create_handle();
521
522 if(handle == NULL) return -1;
523
524 switch(op) {
525 case CTL_OP_CREATE_START:
526 ret = lttctl_create_trace(handle, trace_name, mode, trace_type,
527 subbuf_size_low, n_subbufs_low,
528 subbuf_size_med, n_subbufs_med,
529 subbuf_size_high, n_subbufs_high);
530 if(!ret)
531 ret = lttctl_start(handle, trace_name);
532 break;
533 case CTL_OP_CREATE:
534 ret = lttctl_create_trace(handle, trace_name, mode, trace_type,
535 subbuf_size_low, n_subbufs_low,
536 subbuf_size_med, n_subbufs_med,
537 subbuf_size_high, n_subbufs_high);
538 break;
539 case CTL_OP_DESTROY:
540 ret = lttctl_destroy_trace(handle, trace_name);
541 break;
542 case CTL_OP_STOP_DESTROY:
543 ret = lttctl_stop(handle, trace_name);
544 if(!ret)
545 ret = lttctl_destroy_trace(handle, trace_name);
546 break;
547 case CTL_OP_START:
548 ret = lttctl_start(handle, trace_name);
549 break;
550 case CTL_OP_STOP:
551 ret = lttctl_stop(handle, trace_name);
552 break;
553 case CTL_OP_DAEMON:
554 ret = lttctl_daemon(handle, trace_name);
555 break;
556 case CTL_OP_DAEMON_HYBRID_FINISH:
557 ret = lttctl_daemon_hybrid_finish(handle, trace_name);
558 break;
559 case CTL_OP_NONE:
560 break;
561 }
562
563 ret |= lttctl_destroy_handle(handle);
564
565 return ret;
566 }
This page took 0.039794 seconds and 4 git commands to generate.