create directories branches, tags, trunk
[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 {
24331c3d 31 CTL_OP_CREATE_START,
5adba60f 32 CTL_OP_CREATE,
33 CTL_OP_DESTROY,
24331c3d 34 CTL_OP_STOP_DESTROY,
5adba60f 35 CTL_OP_START,
36 CTL_OP_STOP,
37 CTL_OP_DAEMON,
d24c12e7 38 CTL_OP_DAEMON_HYBRID_FINISH,
5adba60f 39 CTL_OP_NONE
40};
2cdb6fcb 41
5adba60f 42static char *trace_name = NULL;
313b3771 43static char *trace_type = "relay";
5adba60f 44static char *mode_name = NULL;
d24c12e7 45static unsigned subbuf_size_low = 0;
46static unsigned n_subbufs_low = 0;
47static unsigned subbuf_size_med = 0;
48static unsigned n_subbufs_med = 0;
49static unsigned subbuf_size_high = 0;
50static unsigned n_subbufs_high = 0;
45653836 51static unsigned append_trace = 0;
5adba60f 52static enum trace_mode mode = LTT_TRACE_NORMAL;
53static enum trace_ctl_op op = CTL_OP_NONE;
54static char *channel_root = NULL;
55static char *trace_root = NULL;
22acb617 56static char *num_threads = "1";
5adba60f 57
5adba60f 58/* Args :
59 *
60 */
61void show_arguments(void)
62{
63 printf("Please use the following arguments :\n");
64 printf("\n");
2299770f 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");
d24c12e7 68 printf("-m mode Normal, flight recorder or hybrid mode.\n");
69 printf(" Mode values : normal (default), flight or hybrid.\n");
2299770f 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");
d24c12e7 77 printf(" (optionally, you can set LTT_DAEMON\n");
741f0397 78 printf(" env. var.)\n");
d24c12e7 79 printf("-f Stop tracing, dump flight recorder trace, destroy channels\n");
80 printf(" (for hybrid traces)\n");
2299770f 81 printf("-t Trace root path. (ex. /root/traces/example_trace)\n");
82 printf("-T Type of trace (ex. relay)\n");
bb01fdc6 83 printf("-l LTT channels root path. (ex. /mnt/debugfs/ltt)\n");
d24c12e7 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");
2299770f 90 printf("-a Append to trace\n");
91 printf("-N Number of lttd threads\n");
5adba60f 92 printf("\n");
93}
94
95
96/* parse_arguments
97 *
98 * Parses the command line arguments.
99 *
2baf08e5 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.
5adba60f 102 */
103int 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) {
2baf08e5 110 return -1;
5adba60f 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 {
8eab4866 124 printf("Specify a trace name after -n.\n");
5adba60f 125 printf("\n");
2baf08e5 126 ret = EINVAL;
5adba60f 127 }
128
129 break;
24331c3d 130 case 'b':
131 op = CTL_OP_CREATE_START;
cd39bb61 132 break;
5adba60f 133 case 'c':
134 op = CTL_OP_CREATE;
24331c3d 135 break;
bc0fcb31 136 case 'm':
5adba60f 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;
d24c12e7 144 else if(strcmp(mode_name, "hybrid") == 0)
145 mode = LTT_TRACE_HYBRID;
5adba60f 146 else {
147 printf("Invalid mode '%s'.\n", argv[argn]);
148 printf("\n");
2baf08e5 149 ret = EINVAL;
5adba60f 150 }
151 } else {
bc0fcb31 152 printf("Specify a mode after -m.\n");
5adba60f 153 printf("\n");
2baf08e5 154 ret = EINVAL;
5adba60f 155 }
156 break;
157 case 'r':
158 op = CTL_OP_DESTROY;
159 break;
b7f08766 160 case 'R':
161 op = CTL_OP_STOP_DESTROY;
162 break;
5adba60f 163 case 's':
164 op = CTL_OP_START;
165 break;
166 case 'q':
167 op = CTL_OP_STOP;
168 break;
d24c12e7 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;
988614ed 209 case 'z':
210 if(argn+1 < argc) {
d24c12e7 211 subbuf_size_high = (unsigned)atoi(argv[argn+1]);
988614ed 212 argn++;
213 } else {
d24c12e7 214 printf("Specify a number of high traffic subbuffers after -z.\n");
988614ed 215 printf("\n");
2baf08e5 216 ret = EINVAL;
988614ed 217 }
218 break;
219 case 'x':
220 if(argn+1 < argc) {
d24c12e7 221 n_subbufs_high = (unsigned)atoi(argv[argn+1]);
988614ed 222 argn++;
223 } else {
d24c12e7 224 printf("Specify a high traffic subbuffer size after -x.\n");
988614ed 225 printf("\n");
2baf08e5 226 ret = EINVAL;
988614ed 227 }
228 break;
5adba60f 229 case 'd':
230 op = CTL_OP_DAEMON;
231 break;
d24c12e7 232 case 'f':
233 op = CTL_OP_DAEMON_HYBRID_FINISH;
234 break;
5adba60f 235 case 't':
236 if(argn+1 < argc) {
237 trace_root = argv[argn+1];
238 argn++;
239 } else {
988614ed 240 printf("Specify a trace root path after -t.\n");
5adba60f 241 printf("\n");
2baf08e5 242 ret = EINVAL;
5adba60f 243 }
244 break;
245 case 'l':
246 if(argn+1 < argc) {
247 channel_root = argv[argn+1];
248 argn++;
249 } else {
988614ed 250 printf("Specify a channel root path after -l.\n");
5adba60f 251 printf("\n");
2baf08e5 252 ret = EINVAL;
5adba60f 253 }
254 break;
24331c3d 255 case 'a':
256 append_trace = 1;
257 break;
258 case 'N':
22acb617 259 if(argn+1 < argc) {
260 num_threads = argv[argn+1];
261 argn++;
262 }
263 break;
313b3771 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;
5adba60f 274 default:
275 printf("Invalid argument '%s'.\n", argv[argn]);
276 printf("\n");
2baf08e5 277 ret = EINVAL;
5adba60f 278 }
279 break;
280 default:
281 printf("Invalid argument '%s'.\n", argv[argn]);
282 printf("\n");
2baf08e5 283 ret = EINVAL;
5adba60f 284 }
285 argn++;
286 }
287
741f0397 288 if(trace_name == NULL) {
5adba60f 289 printf("Please specify a trace name.\n");
290 printf("\n");
2baf08e5 291 ret = EINVAL;
5adba60f 292 }
293
294 if(op == CTL_OP_NONE) {
295 printf("Please specify an operation.\n");
296 printf("\n");
2baf08e5 297 ret = EINVAL;
5adba60f 298 }
299
d24c12e7 300 if(op == CTL_OP_DAEMON || op == CTL_OP_DAEMON_HYBRID_FINISH) {
5adba60f 301 if(trace_root == NULL) {
302 printf("Please specify -t trace_root_path with the -d option.\n");
303 printf("\n");
2baf08e5 304 ret = EINVAL;
5adba60f 305 }
306 if(channel_root == NULL) {
307 printf("Please specify -l ltt_root_path with the -d option.\n");
308 printf("\n");
2baf08e5 309 ret = EINVAL;
5adba60f 310 }
311 }
312
313 return ret;
314}
315
316void show_info(void)
317{
e7480f75 318 printf("Linux Trace Toolkit Trace Control " VERSION"\n");
5adba60f 319 printf("\n");
24331c3d 320 if(trace_name != NULL) {
321 printf("Controlling trace : %s\n", trace_name);
322 printf("\n");
323 }
129fd24a 324}
325
5adba60f 326int 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");
5adba60f 332
86a65fdb 333 if(lttd_path == NULL) lttd_path =
24331c3d 334 PACKAGE_BIN_DIR "/lttd";
5adba60f 335
336 strcat(channel_path, channel_root);
337 strcat(channel_path, "/");
338 strcat(channel_path, trace_name);
339
340
d24c12e7 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);
5adba60f 345 if(ret != 0) goto create_error;
346
5adba60f 347 pid = fork();
348
349 if(pid > 0) {
2299770f 350 int status = 0;
5adba60f 351 /* parent */
2299770f 352
24331c3d 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;
5adba60f 364
5adba60f 365 } else if(pid == 0) {
366 /* child */
24331c3d 367 int ret;
d24c12e7 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 }
5adba60f 383 if(ret) {
24331c3d 384 ret = errno;
5adba60f 385 perror("Error in executing the lttd daemon");
618fbcc1 386 exit(ret);
5adba60f 387 }
388 } else {
389 /* error */
390 perror("Error in forking for lttd daemon");
5adba60f 391 }
392
393 ret = lttctl_start(handle, trace_name);
394 if(ret != 0) goto start_error;
395
396 return 0;
397
398 /* error handling */
399start_error:
24331c3d 400 printf("Trace start error\n");
5adba60f 401 ret |= lttctl_destroy_trace(handle, trace_name);
402create_error:
403 return ret;
404}
405
d24c12e7 406
407
408
409int 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 */
470destroy_error:
471 printf("Hybrid trace destroy error\n");
472stop_error:
473 return ret;
474}
475
476
477
5adba60f 478int 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();
2baf08e5 486 if(ret == EINVAL) return EINVAL;
487 if(ret == -1) return 0;
5adba60f 488
489 show_info();
490
491 handle = lttctl_create_handle();
492
493 if(handle == NULL) return -1;
494
495 switch(op) {
24331c3d 496 case CTL_OP_CREATE_START:
d24c12e7 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);
24331c3d 501 if(!ret)
502 ret = lttctl_start(handle, trace_name);
503 break;
504 case CTL_OP_CREATE:
d24c12e7 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);
24331c3d 509 break;
5adba60f 510 case CTL_OP_DESTROY:
511 ret = lttctl_destroy_trace(handle, trace_name);
512 break;
b7f08766 513 case CTL_OP_STOP_DESTROY:
514 ret = lttctl_stop(handle, trace_name);
24331c3d 515 if(!ret)
516 ret = lttctl_destroy_trace(handle, trace_name);
b7f08766 517 break;
5adba60f 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;
d24c12e7 527 case CTL_OP_DAEMON_HYBRID_FINISH:
528 ret = lttctl_daemon_hybrid_finish(handle, trace_name);
529 break;
5adba60f 530 case CTL_OP_NONE:
531 break;
532 }
533
534 ret |= lttctl_destroy_handle(handle);
535
536 return ret;
537}
This page took 0.061373 seconds and 4 git commands to generate.