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