liblttctl: switch_timer for all channels fix
[ltt-control.git] / liblttctl / liblttctl.c
1 /*
2 * liblttctl
3 *
4 * Linux Trace Toolkit Control Library
5 *
6 * Controls the ltt-control kernel module through debugfs.
7 *
8 * Copyright (c) 2005-2010 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <liblttctl/lttctl.h>
30 #include <errno.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <dirent.h>
34 #include <limits.h>
35 #include <fcntl.h>
36 #include <stdlib.h>
37
38 #define MAX_CHANNEL (256)
39
40 static char debugfsmntdir[PATH_MAX];
41
42 static int initdebugfsmntdir(void)
43 {
44 return getdebugfsmntdir(debugfsmntdir);
45 }
46
47 /*
48 * This function must called posterior to initdebugfsmntdir(),
49 * because it need to use debugfsmntdir[] which is inited in initdebugfsmntdir()
50 */
51 static int initmodule(void)
52 {
53 char controldirname[PATH_MAX];
54 DIR *dir;
55 int tryload_done = 0;
56
57 sprintf(controldirname, "%s/ltt/control/", debugfsmntdir);
58
59 check_again:
60 /*
61 * Check ltt control's debugfs dir
62 *
63 * We don't check is ltt-trace-control module exist, because it maybe
64 * compiled into kernel.
65 */
66 dir = opendir(controldirname);
67 if (dir) {
68 closedir(dir);
69 return 0;
70 }
71
72 if (!tryload_done) {
73 system("modprobe ltt-trace-control");
74 tryload_done = 1;
75 goto check_again;
76 }
77
78 return -ENOENT;
79 }
80
81 int lttctl_init(void)
82 {
83 int ret;
84
85
86 ret = initdebugfsmntdir();
87 if (ret) {
88 fprintf(stderr, "Get debugfs mount point failed\n");
89 return ret;
90 }
91
92 ret = initmodule();
93 if (ret) {
94 fprintf(stderr, "Control module seems not work\n");
95 return ret;
96 }
97
98 return 0;
99 }
100
101 int lttctl_destroy(void)
102 {
103 return 0;
104 }
105
106 static int lttctl_sendop(const char *fname, const char *op)
107 {
108 int fd;
109
110 if (!fname) {
111 fprintf(stderr, "%s: args invalid\n", __func__);
112 return 1;
113 }
114
115 fd = open(fname, O_WRONLY);
116 if (fd == -1) {
117 fprintf(stderr, "%s: open %s failed: %s\n", __func__, fname,
118 strerror(errno));
119 return errno;
120 }
121
122 if (write(fd, op, strlen(op)) == -1) {
123 int ret = errno;
124 fprintf(stderr, "%s: write %s to %s failed: %s\n", __func__, op,
125 fname, strerror(errno));
126 close(fd);
127 return ret;
128 }
129
130 close(fd);
131
132 return 0;
133 }
134
135 /*
136 * check is trace exist(check debugfsmntdir too)
137 * expect:
138 * 0: expect that trace not exist
139 * !0: expect that trace exist
140 *
141 * ret:
142 * 0: check pass
143 * -(EEXIST | ENOENT): check failed
144 * -ERRNO: error happened (no check)
145 */
146 static int lttctl_check_trace(const char *name, int expect)
147 {
148 char tracedirname[PATH_MAX];
149 DIR *dir;
150 int exist;
151
152 if (!name) {
153 fprintf(stderr, "%s: args invalid\n", __func__);
154 return -EINVAL;
155 }
156
157 if (!debugfsmntdir[0]) {
158 fprintf(stderr, "%s: debugfsmntdir not valid\n", __func__);
159 return -EINVAL;
160 }
161
162 sprintf(tracedirname, "%s/ltt/control/%s", debugfsmntdir, name);
163
164 dir = opendir(tracedirname);
165 if (dir) {
166 exist = 1;
167 closedir(dir);
168 } else {
169 if (errno != ENOENT) {
170 fprintf(stderr, "%s: %s\n", __func__, strerror(errno));
171 return -EINVAL;
172 }
173 exist = 0;
174 }
175
176 if (!expect != !exist) {
177 if (exist)
178 {
179 fprintf(stderr, "Trace %s already exist\n", name);
180 return -EEXIST;
181 }
182 else
183 {
184 fprintf(stderr, "Trace %s not exist\n", name);
185 return -ENOENT;
186 }
187
188 }
189
190 return 0;
191 }
192
193 /*
194 * get channel list of a trace
195 * don't include metadata channel when metadata is 0
196 *
197 * return number of channel on success
198 * return negative number on fail
199 * Caller must free channellist.
200 */
201 static int lttctl_get_channellist(const char *tracename,
202 char ***channellist, int metadata)
203 {
204 char tracedirname[PATH_MAX];
205 struct dirent *dirent;
206 DIR *dir;
207 char **list = NULL, **old_list;
208 int nr_chan = 0;
209
210 sprintf(tracedirname, "%s/ltt/control/%s/channel", debugfsmntdir,
211 tracename);
212
213 dir = opendir(tracedirname);
214 if (!dir) {
215 nr_chan = -ENOENT;
216 goto error;
217 }
218
219 for (;;) {
220 dirent = readdir(dir);
221 if (!dirent)
222 break;
223 if (!strcmp(dirent->d_name, ".")
224 || !strcmp(dirent->d_name, ".."))
225 continue;
226 if (!metadata && !strcmp(dirent->d_name, "metadata"))
227 continue;
228 old_list = list;
229 list = malloc(sizeof(char *) * ++nr_chan);
230 memcpy(list, old_list, sizeof(*list) * (nr_chan - 1));
231 free(old_list);
232 list[nr_chan - 1] = strdup(dirent->d_name);
233 }
234
235 closedir(dir);
236
237 *channellist = list;
238 return nr_chan;
239 error:
240 free(list);
241 *channellist = NULL;
242 return nr_chan;
243 }
244
245 static void lttctl_free_channellist(char **channellist, int n_channel)
246 {
247 int i = 0;
248 for(; i < n_channel; ++i)
249 free(channellist[i]);
250 free(channellist);
251 }
252
253 int lttctl_setup_trace(const char *name)
254 {
255 int ret;
256 char ctlfname[PATH_MAX];
257
258 if (!name) {
259 fprintf(stderr, "%s: args invalid\n", __func__);
260 ret = -EINVAL;
261 goto arg_error;
262 }
263
264 ret = lttctl_check_trace(name, 0);
265 if (ret)
266 goto arg_error;
267
268 sprintf(ctlfname, "%s/ltt/setup_trace", debugfsmntdir);
269
270 ret = lttctl_sendop(ctlfname, name);
271 if (ret) {
272 fprintf(stderr, "Setup trace failed\n");
273 goto op_err;
274 }
275
276 return 0;
277
278 op_err:
279 arg_error:
280 return ret;
281 }
282
283 int lttctl_destroy_trace(const char *name)
284 {
285 int ret;
286 char ctlfname[PATH_MAX];
287
288 if (!name) {
289 fprintf(stderr, "%s: args invalid\n", __func__);
290 ret = -EINVAL;
291 goto arg_error;
292 }
293
294 ret = lttctl_check_trace(name, 1);
295 if (ret)
296 goto arg_error;
297
298 sprintf(ctlfname, "%s/ltt/destroy_trace", debugfsmntdir);
299
300 ret = lttctl_sendop(ctlfname, name);
301 if (ret) {
302 fprintf(stderr, "Destroy trace failed\n");
303 goto op_err;
304 }
305
306 return 0;
307
308 op_err:
309 arg_error:
310 return ret;
311 }
312
313 int lttctl_alloc_trace(const char *name)
314 {
315 int ret;
316 char ctlfname[PATH_MAX];
317
318 if (!name) {
319 fprintf(stderr, "%s: args invalid\n", __func__);
320 ret = -EINVAL;
321 goto arg_error;
322 }
323
324 ret = lttctl_check_trace(name, 1);
325 if (ret)
326 goto arg_error;
327
328 sprintf(ctlfname, "%s/ltt/control/%s/alloc", debugfsmntdir, name);
329
330 ret = lttctl_sendop(ctlfname, "1");
331 if (ret) {
332 fprintf(stderr, "Allocate trace failed\n");
333 goto op_err;
334 }
335
336 return 0;
337
338 op_err:
339 arg_error:
340 return ret;
341 }
342
343 int lttctl_start(const char *name)
344 {
345 int ret;
346 char ctlfname[PATH_MAX];
347
348 if (!name) {
349 fprintf(stderr, "%s: args invalid\n", __func__);
350 ret = -EINVAL;
351 goto arg_error;
352 }
353
354 ret = lttctl_check_trace(name, 1);
355 if (ret)
356 goto arg_error;
357
358 sprintf(ctlfname, "%s/ltt/control/%s/enabled", debugfsmntdir, name);
359
360 ret = lttctl_sendop(ctlfname, "1");
361 if (ret) {
362 fprintf(stderr, "Start trace failed\n");
363 goto op_err;
364 }
365
366 return 0;
367
368 op_err:
369 arg_error:
370 return ret;
371 }
372
373 int lttctl_pause(const char *name)
374 {
375 int ret;
376 char ctlfname[PATH_MAX];
377
378 if (!name) {
379 fprintf(stderr, "%s: args invalid\n", __func__);
380 ret = -EINVAL;
381 goto arg_error;
382 }
383
384 ret = lttctl_check_trace(name, 1);
385 if (ret)
386 goto arg_error;
387
388 sprintf(ctlfname, "%s/ltt/control/%s/enabled", debugfsmntdir, name);
389
390 ret = lttctl_sendop(ctlfname, "0");
391 if (ret) {
392 fprintf(stderr, "Pause trace failed\n");
393 goto op_err;
394 }
395
396 return 0;
397
398 op_err:
399 arg_error:
400 return ret;
401 }
402
403 int lttctl_set_trans(const char *name, const char *trans)
404 {
405 int ret;
406 char ctlfname[PATH_MAX];
407
408 if (!name) {
409 fprintf(stderr, "%s: args invalid\n", __func__);
410 ret = -EINVAL;
411 goto arg_error;
412 }
413
414 ret = lttctl_check_trace(name, 1);
415 if (ret)
416 goto arg_error;
417
418 sprintf(ctlfname, "%s/ltt/control/%s/trans", debugfsmntdir, name);
419
420 ret = lttctl_sendop(ctlfname, trans);
421 if (ret) {
422 fprintf(stderr, "Set transport failed\n");
423 goto op_err;
424 }
425
426 return 0;
427
428 op_err:
429 arg_error:
430 return ret;
431 }
432
433 static int __lttctl_set_channel_enable(const char *name, const char *channel,
434 int enable)
435 {
436 int ret;
437 char ctlfname[PATH_MAX];
438
439 sprintf(ctlfname, "%s/ltt/control/%s/channel/%s/enable", debugfsmntdir,
440 name, channel);
441
442 ret = lttctl_sendop(ctlfname, enable ? "1" : "0");
443 if (ret)
444 fprintf(stderr, "Set channel's enable mode failed\n");
445
446 return ret;
447 }
448
449 int lttctl_set_channel_enable(const char *name, const char *channel,
450 int enable)
451 {
452 int ret;
453 char **channellist;
454 int n_channel;
455
456 if (!name || !channel) {
457 fprintf(stderr, "%s: args invalid\n", __func__);
458 ret = -EINVAL;
459 goto arg_error;
460 }
461
462 ret = lttctl_check_trace(name, 1);
463 if (ret)
464 goto arg_error;
465
466 if (strcmp(channel, "all")) {
467 ret = __lttctl_set_channel_enable(name, channel, enable);
468 if (ret)
469 goto op_err;
470 } else {
471 /* Don't allow set enable state for metadata channel */
472 n_channel = lttctl_get_channellist(name, &channellist, 0);
473 if (n_channel < 0) {
474 fprintf(stderr, "%s: lttctl_get_channellist failed\n",
475 __func__);
476 ret = -ENOENT;
477 goto op_err;
478 }
479
480 for (; n_channel > 0; n_channel--) {
481 ret = __lttctl_set_channel_enable(name,
482 channellist[n_channel - 1], enable);
483 if (ret)
484 goto op_err_clean;
485 }
486 lttctl_free_channellist(channellist, n_channel);
487 }
488
489 return 0;
490
491 op_err_clean:
492 lttctl_free_channellist(channellist, n_channel);
493 op_err:
494 arg_error:
495 return ret;
496 }
497
498 static int __lttctl_set_channel_overwrite(const char *name, const char *channel,
499 int overwrite)
500 {
501 int ret;
502 char ctlfname[PATH_MAX];
503
504 sprintf(ctlfname, "%s/ltt/control/%s/channel/%s/overwrite",
505 debugfsmntdir, name, channel);
506
507 ret = lttctl_sendop(ctlfname, overwrite ? "1" : "0");
508 if (ret)
509 fprintf(stderr, "Set channel's overwrite mode failed\n");
510
511 return ret;
512 }
513 int lttctl_set_channel_overwrite(const char *name, const char *channel,
514 int overwrite)
515 {
516 int ret;
517 char **channellist;
518 int n_channel;
519
520 if (!name || !channel) {
521 fprintf(stderr, "%s: args invalid\n", __func__);
522 ret = -EINVAL;
523 goto arg_error;
524 }
525
526 ret = lttctl_check_trace(name, 1);
527 if (ret)
528 goto arg_error;
529
530 if (strcmp(channel, "all")) {
531 ret = __lttctl_set_channel_overwrite(name, channel, overwrite);
532 if (ret)
533 goto op_err;
534 } else {
535 /* Don't allow set overwrite for metadata channel */
536 n_channel = lttctl_get_channellist(name, &channellist, 0);
537 if (n_channel < 0) {
538 fprintf(stderr, "%s: lttctl_get_channellist failed\n",
539 __func__);
540 ret = -ENOENT;
541 goto op_err;
542 }
543
544 for (; n_channel > 0; n_channel--) {
545 ret = __lttctl_set_channel_overwrite(name,
546 channellist[n_channel - 1], overwrite);
547 if (ret)
548 goto op_err_clean;
549 }
550 lttctl_free_channellist(channellist, n_channel);
551 }
552
553 return 0;
554
555 op_err_clean:
556 lttctl_free_channellist(channellist, n_channel);
557 op_err:
558 arg_error:
559 return ret;
560 }
561
562 static int __lttctl_set_channel_subbuf_num(const char *name,
563 const char *channel, unsigned subbuf_num)
564 {
565 int ret;
566 char ctlfname[PATH_MAX];
567 char opstr[32];
568
569 sprintf(ctlfname, "%s/ltt/control/%s/channel/%s/subbuf_num",
570 debugfsmntdir, name, channel);
571
572 sprintf(opstr, "%u", subbuf_num);
573
574 ret = lttctl_sendop(ctlfname, opstr);
575 if (ret)
576 fprintf(stderr, "Set channel's subbuf number failed\n");
577
578 return ret;
579 }
580 int lttctl_set_channel_subbuf_num(const char *name, const char *channel,
581 unsigned subbuf_num)
582 {
583 int ret;
584 char **channellist;
585 int n_channel;
586
587 if (!name || !channel) {
588 fprintf(stderr, "%s: args invalid\n", __func__);
589 ret = -EINVAL;
590 goto arg_error;
591 }
592
593 ret = lttctl_check_trace(name, 1);
594 if (ret)
595 goto arg_error;
596
597 if (strcmp(channel, "all")) {
598 ret = __lttctl_set_channel_subbuf_num(name, channel,
599 subbuf_num);
600 if (ret)
601 goto op_err;
602 } else {
603 /* allow set subbuf_num for metadata channel */
604 n_channel = lttctl_get_channellist(name, &channellist, 1);
605 if (n_channel < 0) {
606 fprintf(stderr, "%s: lttctl_get_channellist failed\n",
607 __func__);
608 ret = -ENOENT;
609 goto op_err;
610 }
611
612 for (; n_channel > 0; n_channel--) {
613 ret = __lttctl_set_channel_subbuf_num(name,
614 channellist[n_channel - 1], subbuf_num);
615 if (ret)
616 goto op_err_clean;
617 }
618 lttctl_free_channellist(channellist, n_channel);
619 }
620
621 return 0;
622
623 op_err_clean:
624 lttctl_free_channellist(channellist, n_channel);
625 op_err:
626 arg_error:
627 return ret;
628 }
629
630 static int __lttctl_set_channel_subbuf_size(const char *name,
631 const char *channel, unsigned subbuf_size)
632 {
633 int ret;
634 char ctlfname[PATH_MAX];
635 char opstr[32];
636
637 sprintf(ctlfname, "%s/ltt/control/%s/channel/%s/subbuf_size",
638 debugfsmntdir, name, channel);
639
640 sprintf(opstr, "%u", subbuf_size);
641
642 ret = lttctl_sendop(ctlfname, opstr);
643 if (ret)
644 fprintf(stderr, "Set channel's subbuf size failed\n");
645 return ret;
646 }
647
648 int lttctl_set_channel_subbuf_size(const char *name, const char *channel,
649 unsigned subbuf_size)
650 {
651 int ret;
652 char **channellist;
653 int n_channel;
654
655 if (!name || !channel) {
656 fprintf(stderr, "%s: args invalid\n", __func__);
657 ret = -EINVAL;
658 goto arg_error;
659 }
660
661 ret = lttctl_check_trace(name, 1);
662 if (ret)
663 goto arg_error;
664
665 if (strcmp(channel, "all")) {
666 ret = __lttctl_set_channel_subbuf_size(name, channel,
667 subbuf_size);
668 if (ret)
669 goto op_err;
670 } else {
671 /* allow set subbuf_size for metadata channel */
672 n_channel = lttctl_get_channellist(name, &channellist, 1);
673 if (n_channel < 0) {
674 fprintf(stderr, "%s: lttctl_get_channellist failed\n",
675 __func__);
676 ret = -ENOENT;
677 goto op_err;
678 }
679
680 for (; n_channel > 0; n_channel--) {
681 ret = __lttctl_set_channel_subbuf_size(name,
682 channellist[n_channel - 1], subbuf_size);
683 if (ret)
684 goto op_err_clean;
685 }
686 lttctl_free_channellist(channellist, n_channel);
687 }
688
689 return 0;
690
691 op_err_clean:
692 lttctl_free_channellist(channellist, n_channel);
693 op_err:
694 arg_error:
695 return ret;
696 }
697
698 static int __lttctl_set_channel_switch_timer(const char *name,
699 const char *channel, unsigned switch_timer)
700 {
701 int ret;
702 char ctlfname[PATH_MAX];
703 char opstr[32];
704
705 sprintf(ctlfname, "%s/ltt/control/%s/channel/%s/switch_timer",
706 debugfsmntdir, name, channel);
707
708 sprintf(opstr, "%u", switch_timer);
709
710 ret = lttctl_sendop(ctlfname, opstr);
711 if (ret)
712 fprintf(stderr, "Set channel's switch timer failed\n");
713 return ret;
714 }
715
716 int lttctl_set_channel_switch_timer(const char *name, const char *channel,
717 unsigned switch_timer)
718 {
719 int ret;
720 char **channellist;
721 int n_channel;
722
723 if (!name || !channel) {
724 fprintf(stderr, "%s: args invalid\n", __func__);
725 ret = -EINVAL;
726 goto arg_error;
727 }
728
729 ret = lttctl_check_trace(name, 1);
730 if (ret)
731 goto arg_error;
732
733 if (strcmp(channel, "all")) {
734 ret = __lttctl_set_channel_switch_timer(name, channel,
735 switch_timer);
736 if (ret)
737 goto op_err;
738 } else {
739 /* allow set subbuf_size for metadata channel */
740 n_channel = lttctl_get_channellist(name, &channellist, 1);
741 if (n_channel < 0) {
742 fprintf(stderr, "%s: lttctl_get_channellist failed\n",
743 __func__);
744 ret = -ENOENT;
745 goto op_err;
746 }
747
748 for (; n_channel > 0; n_channel--) {
749 ret = __lttctl_set_channel_switch_timer(name,
750 channellist[n_channel - 1], switch_timer);
751 if (ret)
752 goto op_err_clean;
753 }
754 lttctl_free_channellist(channellist, n_channel);
755 }
756
757 return 0;
758
759 op_err_clean:
760 lttctl_free_channellist(channellist, n_channel);
761 op_err:
762 arg_error:
763 return ret;
764 }
765
766 int getdebugfsmntdir(char *mntdir)
767 {
768 char mnt_dir[PATH_MAX];
769 char mnt_type[PATH_MAX];
770 int trymount_done = 0;
771
772 FILE *fp = fopen("/proc/mounts", "r");
773 if (!fp)
774 return -EINVAL;
775
776 find_again:
777 while (1) {
778 if (fscanf(fp, "%*s %s %s %*s %*s %*s", mnt_dir, mnt_type) <= 0)
779 break;
780
781 if (!strcmp(mnt_type, "debugfs")) {
782 strcpy(mntdir, mnt_dir);
783 return 0;
784 }
785 }
786
787 if (!trymount_done) {
788 mount("debugfs", "/sys/kernel/debug/", "debugfs", 0, NULL);
789 trymount_done = 1;
790 goto find_again;
791 }
792
793 return -ENOENT;
794 }
This page took 0.044399 seconds and 4 git commands to generate.