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