7380136fc6eefcbe1e0c4bb3da3e81e80815a438
[ltt-control.git] / 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 * Copyright 2008 FUJITSU
11 * Zhao Lei <zhaolei@cn.fujitsu.com>
12 * Gui Jianfeng <guijianfeng@cn.fujitsu.com>
13 */
14
15 #ifdef HAVE_CONFIG_H
16 #include <config.h>
17 #endif
18
19 #include <liblttctl/lttctl.h>
20 #include <errno.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <sys/wait.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include <limits.h>
27 #define _GNU_SOURCE
28 #include <getopt.h>
29
30 #define OPT_MAX (1024)
31 #define OPT_NAMELEN (256)
32 #define OPT_VALSTRINGLEN (256)
33
34 enum opt_type {
35 CHANNEL,
36 };
37
38 struct channel_option {
39 char chan_name[OPT_NAMELEN];
40 int enable;
41 int overwrite;
42 int bufnum;
43 int bufsize;
44 int switch_timer;
45 };
46
47 struct lttctl_option {
48 union {
49 struct channel_option chan_opt;
50 } opt_mode;
51 enum opt_type type;
52 struct lttctl_option *next;
53 };
54
55 struct lttctl_option *opt_head, *last_opt;
56
57 static int opt_create;
58 static int opt_destroy;
59 static int opt_start;
60 static int opt_pause;
61 static int opt_help;
62 static const char *opt_transport;
63 static const char *opt_write;
64 static int opt_append;
65 static unsigned int opt_dump_threads;
66 static char channel_root_default[PATH_MAX];
67 static const char *opt_channel_root;
68 static const char *opt_tracename;
69
70 /* Args :
71 *
72 */
73 static void show_arguments(void)
74 {
75 printf("Linux Trace Toolkit Trace Control " VERSION"\n");
76 printf("\n");
77 printf("Usage: lttctl [OPTION]... [TRACENAME]\n");
78 printf("\n");
79 printf("Examples:\n");
80 printf(" lttctl -c trace1 "
81 "# Create a trace named trace1.\n");
82 printf(" lttctl -s trace1 "
83 "# start a trace named trace1.\n");
84 printf(" lttctl -p trace1 "
85 "# pause a trace named trace1.\n");
86 printf(" lttctl -d trace1 "
87 "# Destroy a trace named trace1.\n");
88 printf(" lttctl -C -w /tmp/trace1 trace1 "
89 "# Create a trace named trace1, start it and\n"
90 " "
91 "# write non-overwrite channels' data to\n"
92 " "
93 "# /tmp/trace1, debugfs must be mounted for\n"
94 " "
95 "# auto-find\n");
96 printf(" lttctl -D -w /tmp/trace1 trace1 "
97 "# Pause and destroy a trace named trace1 and\n"
98 " "
99 "# write overwrite channels' data to\n"
100 " "
101 "# /tmp/trace1, debugfs must be mounted for\n"
102 " "
103 "# auto-find\n");
104 printf("\n");
105 printf(" Basic options:\n");
106 printf(" -c, --create\n");
107 printf(" Create a trace.\n");
108 printf(" -d, --destroy\n");
109 printf(" Destroy a trace.\n");
110 printf(" -s, --start\n");
111 printf(" Start a trace.\n");
112 printf(" -p, --pause\n");
113 printf(" Pause a trace.\n");
114 printf(" -h, --help\n");
115 printf(" Show this help.\n");
116 printf("\n");
117 printf(" Advanced options:\n");
118 printf(" --transport TRANSPORT\n");
119 printf(" Set trace's transport. (ex. relay-locked or relay)\n");
120 printf(" -o, --option OPTION\n");
121 printf(" Set options, following operations are supported:\n");
122 printf(" channel.<channelname>.enable=\n");
123 printf(" channel.<channelname>.overwrite=\n");
124 printf(" channel.<channelname>.bufnum=\n");
125 printf(" channel.<channelname>.bufsize= (in bytes, rounded to "
126 "next power of 2)\n");
127 printf(" <channelname> can be set to all for all channels\n");
128 printf(" channel.<channelname>.switch_timer= (timer interval in "
129 "ms)\n");
130 printf("\n");
131 printf(" Integration options:\n");
132 printf(" -C, --create_start\n");
133 printf(" Create and start a trace.\n");
134 printf(" -D, --pause_destroy\n");
135 printf(" Pause and destroy a trace.\n");
136 printf(" -w, --write PATH\n");
137 printf(" Path for write trace datas.\n");
138 printf(" For -c, -C, -d, -D options\n");
139 printf(" -a, --append\n");
140 printf(" Append to trace, For -w option\n");
141 printf(" -n, --dump_threads NUMBER\n");
142 printf(" Number of lttd threads, For -w option\n");
143 printf(" --channel_root PATH\n");
144 printf(" Set channels root path, For -w option."
145 " (ex. /mnt/debugfs/ltt)\n");
146 printf("\n");
147 }
148
149 /*
150 * Separate option name to 3 fields
151 * Ex:
152 * Input: name = channel.cpu.bufsize
153 * Output: name1 = channel
154 * name2 = cpu
155 * name3 = bufsize
156 * Ret: 0 on success
157 * 1 on fail
158 *
159 * Note:
160 * Make sure that name1~3 longer than OPT_NAMELEN.
161 * name1~3 can be NULL to discard value
162 *
163 */
164 static int separate_opt(const char *name, char *name1, char *name2, char *name3)
165 {
166 char *p;
167
168 if (!name)
169 return 1;
170
171 /* segment1 */
172 p = strchr(name, '.');
173 if (!p)
174 return 1;
175 if (p - name >= OPT_NAMELEN)
176 return 1;
177 if (name1) {
178 memcpy(name1, name, p - name);
179 name1[p - name] = 0;
180 }
181 name = p + 1;
182
183 /* segment2 */
184 p = strchr(name, '.');
185 if (!p)
186 return 1;
187 if (p - name >= OPT_NAMELEN)
188 return 1;
189 if (name2) {
190 memcpy(name2, name, p - name);
191 name2[p - name] = 0;
192 }
193 name = p + 1;
194
195 /* segment3 */
196 if (strlen(name) >= OPT_NAMELEN)
197 return 1;
198 if (name3)
199 strcpy(name3, name);
200
201 return 0;
202 }
203
204 static void init_channel_opt(struct channel_option *opt, char *opt_name)
205 {
206 if (opt && opt_name) {
207 opt->enable = -1;
208 opt->overwrite = -1;
209 opt->bufnum = -1;
210 opt->bufsize = -1;
211 opt->switch_timer = -1;
212 strcpy(opt->chan_name, opt_name);
213 }
214 }
215
216 static struct lttctl_option *find_insert_channel_opt(char *opt_name)
217 {
218 struct lttctl_option *iter, *new_opt;
219
220 if (!opt_head) {
221 opt_head = (struct lttctl_option *)malloc(sizeof(struct lttctl_option));
222 init_channel_opt(&opt_head->opt_mode.chan_opt, opt_name);
223 opt_head->type = CHANNEL;
224 opt_head->next = NULL;
225 last_opt = opt_head;
226 return opt_head;
227 }
228
229 for (iter = opt_head; iter; iter = iter->next) {
230 if (iter->type != CHANNEL)
231 continue;
232 if (!strcmp(iter->opt_mode.chan_opt.chan_name, opt_name))
233 return iter;
234 }
235
236 new_opt = (struct lttctl_option *)malloc(sizeof(struct lttctl_option));
237 init_channel_opt(&new_opt->opt_mode.chan_opt, opt_name);
238 new_opt->type = CHANNEL;
239 new_opt->next = NULL;
240 last_opt->next = new_opt;
241 last_opt = new_opt;
242 return new_opt;
243 }
244
245 int set_channel_opt(struct channel_option *opt, char *opt_name, char *opt_valstr)
246 {
247 int opt_val, ret;
248
249 if (!strcmp("enable", opt_name)) {
250 if (opt_valstr[1] != 0) {
251 return -EINVAL;
252 }
253 if (opt_valstr[0] == 'Y' || opt_valstr[0] == 'y'
254 || opt_valstr[0] == '1')
255 opt_val = 1;
256 else if (opt_valstr[0] == 'N' || opt_valstr[0] == 'n'
257 || opt_valstr[0] == '0')
258 opt_val = 0;
259 else {
260 return -EINVAL;
261 }
262
263 opt->enable = opt_val;
264 return 0;
265 } else if (!strcmp("overwrite", opt_name)) {
266 if (opt_valstr[1] != 0) {
267 return -EINVAL;
268 }
269 if (opt_valstr[0] == 'Y' || opt_valstr[0] == 'y'
270 || opt_valstr[0] == '1')
271 opt_val = 1;
272 else if (opt_valstr[0] == 'N' || opt_valstr[0] == 'n'
273 || opt_valstr[0] == '0')
274 opt_val = 0;
275 else {
276 return -EINVAL;
277 }
278
279 opt->overwrite = opt_val;
280 return 0;
281
282 } else if (!strcmp("bufnum", opt_name)) {
283 ret = sscanf(opt_valstr, "%d", &opt_val);
284 if (ret != 1 || opt_val < 0) {
285 return -EINVAL;
286 }
287
288 opt->bufnum = opt_val;
289 return 0;
290 } else if (!strcmp("bufsize", opt_name)) {
291 ret = sscanf(opt_valstr, "%d", &opt_val);
292 if (ret != 1 || opt_val < 0) {
293 return -EINVAL;
294 }
295
296 opt->bufsize = opt_val;
297 return 0;
298 } else if (!strcmp("switch_timer", opt_name)) {
299 ret = sscanf(opt_valstr, "%d", &opt_val);
300 if (ret != 1 || opt_val < 0) {
301 return -EINVAL;
302 }
303
304 opt->switch_timer = opt_val;
305 return 0;
306 } else {
307 return -EINVAL;
308 }
309
310 }
311
312 static int parst_opt(const char *optarg)
313 {
314 int ret;
315 char opt_name[OPT_NAMELEN * 3];
316 char opt_valstr[OPT_VALSTRINGLEN];
317 char *p;
318
319 char name1[OPT_NAMELEN];
320 char name2[OPT_NAMELEN];
321 char name3[OPT_NAMELEN];
322
323 int opt_intval;
324 int opt_val;
325 unsigned int opt_uintval;
326 struct lttctl_option *opt;
327
328 if (!optarg) {
329 fprintf(stderr, "Option empty\n");
330 return -EINVAL;
331 }
332
333 /* Get option name and val_str */
334 p = strchr(optarg, '=');
335 if (!p) {
336 fprintf(stderr, "Option format error: %s\n", optarg);
337 return -EINVAL;
338 }
339
340 if (p - optarg >= sizeof(opt_name)/sizeof(opt_name[0])) {
341 fprintf(stderr, "Option name too long: %s\n", optarg);
342 return -EINVAL;
343 }
344
345 if (strlen(p+1) >= OPT_VALSTRINGLEN) {
346 fprintf(stderr, "Option value too long: %s\n", optarg);
347 return -EINVAL;
348 }
349
350 memcpy(opt_name, optarg, p - optarg);
351 opt_name[p - optarg] = 0;
352 strcpy(opt_valstr, p+1);
353
354 /* separate option name into 3 fields */
355 ret = separate_opt(opt_name, name1, name2, name3);
356 if (ret != 0) {
357 fprintf(stderr, "Option name error1: %s\n", optarg);
358 return -EINVAL;
359 }
360
361 if (!strcmp("channel", name1)) {
362 opt = find_insert_channel_opt(name2);
363 if ((ret = set_channel_opt(&opt->opt_mode.chan_opt,
364 name3, opt_valstr) != 0)) {
365 fprintf(stderr, "Option name error2: %s\n", optarg);
366 return ret;
367 }
368 } else {
369 fprintf(stderr, "Option name error3: %s\n", optarg);
370 return -EINVAL;
371 }
372
373 return 0;
374 }
375
376 /* parse_arguments
377 *
378 * Parses the command line arguments.
379 *
380 * Returns -1 if the arguments were correct, but doesn't ask for program
381 * continuation. Returns EINVAL if the arguments are incorrect, or 0 if OK.
382 */
383 static int parse_arguments(int argc, char **argv)
384 {
385 int ret = 0;
386
387 static struct option longopts[] = {
388 {"create", no_argument, NULL, 'c'},
389 {"destroy", no_argument, NULL, 'd'},
390 {"start", no_argument, NULL, 's'},
391 {"pause", no_argument, NULL, 'p'},
392 {"help", no_argument, NULL, 'h'},
393 {"transport", required_argument, NULL, 2},
394 {"option", required_argument, NULL, 'o'},
395 {"create_start", no_argument, NULL, 'C'},
396 {"pause_destroy", no_argument, NULL, 'D'},
397 {"write", required_argument, NULL, 'w'},
398 {"append", no_argument, NULL, 'a'},
399 {"dump_threads", required_argument, NULL, 'n'},
400 {"channel_root", required_argument, NULL, 3},
401 { NULL, 0, NULL, 0 },
402 };
403
404 /*
405 * Enable all channels in default
406 * To make novice users happy
407 */
408 parst_opt("channel.all.enable=1");
409
410 opterr = 1; /* Print error message on getopt_long */
411 while (1) {
412 int c;
413 c = getopt_long(argc, argv, "cdspho:CDw:an:", longopts, NULL);
414 if (-1 == c) {
415 /* parse end */
416 break;
417 }
418 switch (c) {
419 case 'c':
420 opt_create = 1;
421 break;
422 case 'd':
423 opt_destroy = 1;
424 break;
425 case 's':
426 opt_start = 1;
427 break;
428 case 'p':
429 opt_pause = 1;
430 break;
431 case 'h':
432 opt_help = 1;
433 break;
434 case 2:
435 if (!opt_transport) {
436 opt_transport = optarg;
437 } else {
438 fprintf(stderr,
439 "Please specify only 1 transport\n");
440 return -EINVAL;
441 }
442 break;
443 case 'o':
444 ret = parst_opt(optarg);
445 if (ret)
446 return ret;
447 break;
448 case 'C':
449 opt_create = 1;
450 opt_start = 1;
451 break;
452 case 'D':
453 opt_pause = 1;
454 opt_destroy = 1;
455 break;
456 case 'w':
457 if (!opt_write) {
458 opt_write = optarg;
459 } else {
460 fprintf(stderr,
461 "Please specify only 1 write dir\n");
462 return -EINVAL;
463 }
464 break;
465 case 'a':
466 opt_append = 1;
467 break;
468 case 'n':
469 if (opt_dump_threads) {
470 fprintf(stderr,
471 "Please specify only 1 dump threads\n");
472 return -EINVAL;
473 }
474
475 ret = sscanf(optarg, "%u", &opt_dump_threads);
476 if (ret != 1) {
477 fprintf(stderr,
478 "Dump threads not positive number\n");
479 return -EINVAL;
480 }
481 break;
482 case 3:
483 if (!opt_channel_root) {
484 opt_channel_root = optarg;
485 } else {
486 fprintf(stderr,
487 "Please specify only 1 channel root\n");
488 return -EINVAL;
489 }
490 break;
491 case '?':
492 return -EINVAL;
493 default:
494 break;
495 };
496 };
497
498 /* Don't check args when user needs help */
499 if (opt_help)
500 return 0;
501
502 /* Get tracename */
503 if (optind < argc - 1) {
504 fprintf(stderr, "Please specify only 1 trace name\n");
505 return -EINVAL;
506 }
507 if (optind > argc - 1) {
508 fprintf(stderr, "Please specify trace name\n");
509 return -EINVAL;
510 }
511 opt_tracename = argv[optind];
512
513 /*
514 * Check arguments
515 */
516 if (!opt_create && !opt_start && !opt_destroy && !opt_pause) {
517 fprintf(stderr,
518 "Please specify a option of "
519 "create, destroy, start, or pause\n");
520 return -EINVAL;
521 }
522
523 if ((opt_create || opt_start) && (opt_destroy || opt_pause)) {
524 fprintf(stderr,
525 "Create and start conflict with destroy and pause\n");
526 return -EINVAL;
527 }
528
529 if (opt_create) {
530 if (!opt_transport)
531 opt_transport = "relay";
532 }
533
534 if (opt_transport) {
535 if (!opt_create) {
536 fprintf(stderr,
537 "Transport option must be combine with create"
538 " option\n");
539 return -EINVAL;
540 }
541 }
542
543 if (opt_write) {
544 if (!opt_create && !opt_destroy) {
545 fprintf(stderr,
546 "Write option must be combine with create or"
547 " destroy option\n");
548 return -EINVAL;
549 }
550
551 if (!opt_channel_root)
552 if (getdebugfsmntdir(channel_root_default) == 0) {
553 strcat(channel_root_default, "/ltt");
554 opt_channel_root = channel_root_default;
555 } else {
556 fprintf(stderr,
557 "Channel_root is necessary for -w"
558 " option, but neither --channel_root"
559 " option\n"
560 "specified, nor debugfs's mount dir"
561 " found, mount debugfs also failed\n");
562 return -EINVAL;
563 }
564
565 if (opt_dump_threads == 0)
566 opt_dump_threads = 1;
567 }
568
569 if (opt_append) {
570 if (!opt_write) {
571 fprintf(stderr,
572 "Append option must be combine with write"
573 " option\n");
574 return -EINVAL;
575 }
576 }
577
578 if (opt_dump_threads) {
579 if (!opt_write) {
580 fprintf(stderr,
581 "Dump_threads option must be combine with write"
582 " option\n");
583 return -EINVAL;
584 }
585 }
586
587 if (opt_channel_root) {
588 if (!opt_write) {
589 fprintf(stderr,
590 "Channel_root option must be combine with write"
591 " option\n");
592 return -EINVAL;
593 }
594 }
595
596 return 0;
597 }
598
599 static void show_info(void)
600 {
601 printf("Linux Trace Toolkit Trace Control " VERSION"\n");
602 printf("\n");
603 if (opt_tracename != NULL) {
604 printf("Controlling trace : %s\n", opt_tracename);
605 printf("\n");
606 }
607 }
608
609 static int lttctl_channel_setup(struct channel_option *opt)
610 {
611 int ret;
612
613 if (opt->enable != -1) {
614 if ((ret = lttctl_set_channel_enable(opt_tracename,
615 opt->chan_name,
616 opt->enable)) != 0)
617 return ret;
618 }
619 if (opt->overwrite != -1) {
620 if ((ret = lttctl_set_channel_overwrite(opt_tracename,
621 opt->chan_name,
622 opt->overwrite)) != 0)
623 return ret;
624 }
625 if (opt->bufnum != -1) {
626 if ((ret = lttctl_set_channel_subbuf_num(opt_tracename,
627 opt->chan_name,
628 opt->bufnum)) != 0)
629 return ret;
630 }
631 if (opt->bufsize != -1) {
632 if ((ret = lttctl_set_channel_subbuf_size(opt_tracename,
633 opt->chan_name,
634 opt->bufsize)) != 0)
635 return ret;
636 }
637 if (opt->switch_timer != -1) {
638 if ((ret = lttctl_set_channel_switch_timer(opt_tracename,
639 opt->chan_name, opt->switch_timer)) != 0)
640 return ret;
641 }
642
643 return 0;
644 }
645
646 static int lttctl_create_trace(void)
647 {
648 int ret;
649 int i;
650 struct lttctl_option *opt;
651
652 ret = lttctl_setup_trace(opt_tracename);
653 if (ret)
654 goto setup_trace_fail;
655
656 for (opt = opt_head; opt; opt = opt->next) {
657 if (opt->type != CHANNEL)
658 continue;
659 ret = lttctl_channel_setup(&opt->opt_mode.chan_opt);
660 if (ret)
661 goto set_option_fail;;
662 }
663
664 ret = lttctl_set_trans(opt_tracename, opt_transport);
665 if (ret)
666 goto set_option_fail;
667
668 ret = lttctl_alloc_trace(opt_tracename);
669 if (ret)
670 goto alloc_trace_fail;
671
672 return 0;
673
674 alloc_trace_fail:
675 set_option_fail:
676 lttctl_destroy_trace(opt_tracename);
677 setup_trace_fail:
678 return ret;
679 }
680
681 /*
682 * Start a lttd daemon to write trace datas
683 * Dump overwrite channels on overwrite!=0
684 * Dump normal(non-overwrite) channels on overwrite=0
685 *
686 * ret: 0 on success
687 * !0 on fail
688 */
689 static int lttctl_daemon(int overwrite)
690 {
691 pid_t pid;
692 int status;
693
694 pid = fork();
695 if (pid < 0) {
696 perror("Error in forking for lttd daemon");
697 return errno;
698 }
699
700 if (pid == 0) {
701 /* child */
702 char *argv[16];
703 int argc = 0;
704 char channel_path[PATH_MAX];
705 char thread_num[16];
706
707 /* prog path */
708 argv[argc] = getenv("LTT_DAEMON");
709 if (argv[argc] == NULL)
710 argv[argc] = PACKAGE_BIN_DIR "/lttd";
711 argc++;
712
713 /* -t option */
714 argv[argc] = "-t";
715 argc++;
716 /*
717 * we allow modify of opt_write's content in new process
718 * for get rid of warning of assign char * to const char *
719 */
720 argv[argc] = (char *)opt_write;
721 argc++;
722
723 /* -c option */
724 strcpy(channel_path, opt_channel_root);
725 strcat(channel_path, "/");
726 strcat(channel_path, opt_tracename);
727 argv[argc] = "-c";
728 argc++;
729 argv[argc] = channel_path;
730 argc++;
731
732 /* -N option */
733 sprintf(thread_num, "%u", opt_dump_threads);
734 argv[argc] = "-N";
735 argc++;
736 argv[argc] = thread_num;
737 argc++;
738
739 /* -a option */
740 if (opt_append) {
741 argv[argc] = "-a";
742 argc++;
743 }
744
745 /* -d option */
746 argv[argc] = "-d";
747 argc++;
748
749 /* overwrite option */
750 if (overwrite) {
751 argv[argc] = "-f";
752 argc++;
753 } else {
754 argv[argc] = "-n";
755 argc++;
756 }
757
758 argv[argc] = NULL;
759
760 execvp(argv[0], argv);
761
762 perror("Error in executing the lttd daemon");
763 exit(errno);
764 }
765
766 /* parent */
767 if (waitpid(pid, &status, 0) == -1) {
768 perror("Error in waitpid\n");
769 return errno;
770 }
771
772 if (!WIFEXITED(status)) {
773 fprintf(stderr, "lttd process interrupted\n");
774 return status;
775 }
776
777 if (WEXITSTATUS(status))
778 fprintf(stderr, "lttd process running failed\n");
779
780 return WEXITSTATUS(status);
781 }
782
783 int main(int argc, char **argv)
784 {
785 int ret;
786
787 ret = parse_arguments(argc, argv);
788 /* If user needs show help, we disregard other options */
789 if (opt_help) {
790 show_arguments();
791 return 0;
792 }
793
794 /* exit program if arguments wrong */
795 if (ret)
796 return 1;
797
798 show_info();
799
800 ret = lttctl_init();
801 if (ret != 0)
802 return ret;
803
804 if (opt_create) {
805 printf("lttctl: Creating trace\n");
806 ret = lttctl_create_trace();
807 if (ret)
808 goto op_fail;
809
810 if (opt_write) {
811 printf("lttctl: Forking lttd\n");
812 ret = lttctl_daemon(0);
813 if (ret)
814 goto op_fail;
815 }
816 }
817
818 if (opt_start) {
819 printf("lttctl: Starting trace\n");
820 ret = lttctl_start(opt_tracename);
821 if (ret)
822 goto op_fail;
823 }
824
825 if (opt_pause) {
826 printf("lttctl: Pausing trace\n");
827 ret = lttctl_pause(opt_tracename);
828 if (ret)
829 goto op_fail;
830 }
831
832 if (opt_destroy) {
833 if (opt_write) {
834 printf("lttctl: Forking lttd\n");
835 ret = lttctl_daemon(1);
836 if (ret)
837 goto op_fail;
838 }
839
840 printf("lttctl: Destroying trace\n");
841 ret = lttctl_destroy_trace(opt_tracename);
842 if (ret)
843 goto op_fail;
844 }
845
846 op_fail:
847 lttctl_destroy();
848
849 return ret;
850 }
This page took 0.043704 seconds and 3 git commands to generate.