Hi Mathieu,
[ltt-control.git] / trunk / ltt-control / lttctl / lttctl.c
CommitLineData
2727692a 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>
a9c10be2 25#include <limits.h>
2727692a 26#include <sys/stat.h>
27
28/* Buffer for file copy : 4k seems optimal. */
29#define BUF_SIZE 4096
30
31enum trace_ctl_op {
900b24a9 32 CTL_OP_CREATE_START,
2727692a 33 CTL_OP_CREATE,
34 CTL_OP_DESTROY,
900b24a9 35 CTL_OP_STOP_DESTROY,
2727692a 36 CTL_OP_START,
37 CTL_OP_STOP,
38 CTL_OP_DAEMON,
89565b43 39 CTL_OP_DAEMON_HYBRID_FINISH,
2727692a 40 CTL_OP_NONE
41};
42
43static char *trace_name = NULL;
9f46b64c 44static char *trace_type = "relay";
2727692a 45static char *mode_name = NULL;
89565b43 46static unsigned subbuf_size_low = 0;
47static unsigned n_subbufs_low = 0;
48static unsigned subbuf_size_med = 0;
49static unsigned n_subbufs_med = 0;
50static unsigned subbuf_size_high = 0;
51static unsigned n_subbufs_high = 0;
2727692a 52static unsigned append_trace = 0;
53static enum trace_mode mode = LTT_TRACE_NORMAL;
54static enum trace_ctl_op op = CTL_OP_NONE;
55static char *channel_root = NULL;
a9c10be2 56static char channel_root_default[PATH_MAX];
2727692a 57static char *trace_root = NULL;
58static char *num_threads = "1";
59
2727692a 60/* Args :
61 *
62 */
63void show_arguments(void)
64{
65 printf("Please use the following arguments :\n");
66 printf("\n");
cd2e0b6d 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");
89565b43 70 printf("-m mode Normal, flight recorder or hybrid mode.\n");
71 printf(" Mode values : normal (default), flight or hybrid.\n");
cd2e0b6d 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");
89565b43 79 printf(" (optionally, you can set LTT_DAEMON\n");
6623c176 80 printf(" env. var.)\n");
89565b43 81 printf("-f Stop tracing, dump flight recorder trace, destroy channels\n");
82 printf(" (for hybrid traces)\n");
cd2e0b6d 83 printf("-t Trace root path. (ex. /root/traces/example_trace)\n");
84 printf("-T Type of trace (ex. relay)\n");
c2ffa20f 85 printf("-l LTT channels root path. (ex. /mnt/debugfs/ltt)\n");
89565b43 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");
cd2e0b6d 92 printf("-a Append to trace\n");
93 printf("-N Number of lttd threads\n");
2727692a 94 printf("\n");
95}
96
a9c10be2 97int 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}
2727692a 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 */
125int 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;
900b24a9 152 case 'b':
153 op = CTL_OP_CREATE_START;
2727692a 154 break;
155 case 'c':
156 op = CTL_OP_CREATE;
900b24a9 157 break;
2727692a 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;
89565b43 166 else if(strcmp(mode_name, "hybrid") == 0)
167 mode = LTT_TRACE_HYBRID;
2727692a 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;
89565b43 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;
2727692a 231 case 'z':
232 if(argn+1 < argc) {
89565b43 233 subbuf_size_high = (unsigned)atoi(argv[argn+1]);
2727692a 234 argn++;
235 } else {
89565b43 236 printf("Specify a number of high traffic subbuffers after -z.\n");
2727692a 237 printf("\n");
238 ret = EINVAL;
239 }
240 break;
241 case 'x':
242 if(argn+1 < argc) {
89565b43 243 n_subbufs_high = (unsigned)atoi(argv[argn+1]);
2727692a 244 argn++;
245 } else {
89565b43 246 printf("Specify a high traffic subbuffer size after -x.\n");
2727692a 247 printf("\n");
248 ret = EINVAL;
249 }
250 break;
251 case 'd':
252 op = CTL_OP_DAEMON;
253 break;
89565b43 254 case 'f':
255 op = CTL_OP_DAEMON_HYBRID_FINISH;
256 break;
2727692a 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;
900b24a9 277 case 'a':
278 append_trace = 1;
279 break;
280 case 'N':
2727692a 281 if(argn+1 < argc) {
282 num_threads = argv[argn+1];
283 argn++;
284 }
285 break;
9f46b64c 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;
2727692a 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
6623c176 310 if(trace_name == NULL) {
2727692a 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
89565b43 322 if(op == CTL_OP_DAEMON || op == CTL_OP_DAEMON_HYBRID_FINISH) {
2727692a 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) {
a9c10be2 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 }
2727692a 339 }
340 }
341
2727692a 342 return ret;
343}
344
345void show_info(void)
346{
15061ecb 347 printf("Linux Trace Toolkit Trace Control " VERSION"\n");
2727692a 348 printf("\n");
900b24a9 349 if(trace_name != NULL) {
350 printf("Controlling trace : %s\n", trace_name);
351 printf("\n");
352 }
2727692a 353}
354
2727692a 355int 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");
2727692a 361
362 if(lttd_path == NULL) lttd_path =
900b24a9 363 PACKAGE_BIN_DIR "/lttd";
2727692a 364
365 strcat(channel_path, channel_root);
366 strcat(channel_path, "/");
367 strcat(channel_path, trace_name);
368
369
89565b43 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);
2727692a 374 if(ret != 0) goto create_error;
375
2727692a 376 pid = fork();
377
378 if(pid > 0) {
cd2e0b6d 379 int status = 0;
2727692a 380 /* parent */
cd2e0b6d 381
900b24a9 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;
2727692a 393
2727692a 394 } else if(pid == 0) {
395 /* child */
900b24a9 396 int ret;
89565b43 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 }
2727692a 412 if(ret) {
900b24a9 413 ret = errno;
2727692a 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 */
428start_error:
900b24a9 429 printf("Trace start error\n");
2727692a 430 ret |= lttctl_destroy_trace(handle, trace_name);
431create_error:
432 return ret;
433}
434
89565b43 435
436
437
438int 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 */
499destroy_error:
500 printf("Hybrid trace destroy error\n");
501stop_error:
502 return ret;
503}
504
505
506
2727692a 507int 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) {
900b24a9 525 case CTL_OP_CREATE_START:
89565b43 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);
900b24a9 530 if(!ret)
531 ret = lttctl_start(handle, trace_name);
532 break;
533 case CTL_OP_CREATE:
89565b43 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);
900b24a9 538 break;
2727692a 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);
900b24a9 544 if(!ret)
545 ret = lttctl_destroy_trace(handle, trace_name);
2727692a 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;
89565b43 556 case CTL_OP_DAEMON_HYBRID_FINISH:
557 ret = lttctl_daemon_hybrid_finish(handle, trace_name);
558 break;
2727692a 559 case CTL_OP_NONE:
560 break;
561 }
562
563 ret |= lttctl_destroy_handle(handle);
564
565 return ret;
566}
This page took 0.045491 seconds and 4 git commands to generate.