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