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