liblttctl: fix missing return value
[ltt-control.git] / liblttctl / liblttctl.c
1 /* libltt
2 *
3 * Linux Trace Toolkit Netlink Control Library
4 *
5 * Controls the ltt-control kernel module through debugfs.
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
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
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>
30 #include <string.h>
31 #include <dirent.h>
32 #include <limits.h>
33 #include <fcntl.h>
34 #include <stdlib.h>
35
36 #define MAX_CHANNEL (256)
37
38 static char debugfsmntdir[PATH_MAX];
39
40 static int initdebugfsmntdir(void)
41 {
42 return getdebugfsmntdir(debugfsmntdir);
43 }
44
45 /*
46 * This function must called posterior to initdebugfsmntdir(),
47 * because it need to use debugfsmntdir[] which is inited in initdebugfsmntdir()
48 */
49 static 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
57 check_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;
68 }
69
70 if (!tryload_done) {
71 system("modprobe ltt-trace-control");
72 tryload_done = 1;
73 goto check_again;
74 }
75
76 return -ENOENT;
77 }
78
79 int lttctl_init(void)
80 {
81 int ret;
82
83
84 ret = initdebugfsmntdir();
85 if (ret) {
86 fprintf(stderr, "Get debugfs mount point failed\n");
87 return ret;
88 }
89
90 ret = initmodule();
91 if (ret) {
92 fprintf(stderr, "Control module seems not work\n");
93 return ret;
94 }
95
96 return 0;
97 }
98
99 int lttctl_destroy(void)
100 {
101 return 0;
102 }
103
104 static int lttctl_sendop(const char *fname, const char *op)
105 {
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) {
121 int ret = errno;
122 fprintf(stderr, "%s: write %s to %s failed: %s\n", __func__, op,
123 fname, strerror(errno));
124 close(fd);
125 return ret;
126 }
127
128 close(fd);
129
130 return 0;
131 }
132
133 /*
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
141 * -(EEXIST | ENOENT): check failed
142 * -ERRNO: error happened (no check)
143 */
144 static int lttctl_check_trace(const char *name, int expect)
145 {
146 char tracedirname[PATH_MAX];
147 DIR *dir;
148 int exist;
149
150 if (!name) {
151 fprintf(stderr, "%s: args invalid\n", __func__);
152 return -EINVAL;
153 }
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;
165 closedir(dir);
166 } else {
167 if (errno != ENOENT) {
168 fprintf(stderr, "%s: %s\n", __func__, strerror(errno));
169 return -EINVAL;
170 }
171 exist = 0;
172 }
173
174 if (!expect != !exist) {
175 if (exist)
176 {
177 fprintf(stderr, "Trace %s already exist\n", name);
178 return -EEXIST;
179 }
180 else
181 {
182 fprintf(stderr, "Trace %s not exist\n", name);
183 return -ENOENT;
184 }
185
186 }
187
188 return 0;
189 }
190
191 /*
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.
198 */
199 static int lttctl_get_channellist(const char *tracename,
200 char ***channellist, int metadata)
201 {
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;
237 error:
238 free(list);
239 *channellist = NULL;
240 return nr_chan;
241 }
242
243 static 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
251 int 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;
272 }
273
274 return 0;
275
276 op_err:
277 arg_error:
278 return ret;
279 }
280
281 int 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
306 op_err:
307 arg_error:
308 return ret;
309 }
310
311 int lttctl_alloc_trace(const char *name)
312 {
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
336 op_err:
337 arg_error:
338 return ret;
339 }
340
341 int 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;
362 }
363
364 return 0;
365
366 op_err:
367 arg_error:
368 return ret;
369 }
370
371 int lttctl_pause(const char *name)
372 {
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;
392 }
393
394 return 0;
395
396 op_err:
397 arg_error:
398 return ret;
399 }
400
401 int 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);
417
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
426 op_err:
427 arg_error:
428 return ret;
429 }
430
431 static int __lttctl_set_channel_enable(const char *name, const char *channel,
432 int enable)
433 {
434 int ret;
435 char ctlfname[PATH_MAX];
436
437 sprintf(ctlfname, "%s/ltt/control/%s/channel/%s/enable", debugfsmntdir,
438 name, channel);
439
440 ret = lttctl_sendop(ctlfname, enable ? "1" : "0");
441 if (ret)
442 fprintf(stderr, "Set channel's enable mode failed\n");
443
444 return ret;
445 }
446
447 int lttctl_set_channel_enable(const char *name, const char *channel,
448 int enable)
449 {
450 int ret;
451 char **channellist;
452 int n_channel;
453
454 if (!name || !channel) {
455 fprintf(stderr, "%s: args invalid\n", __func__);
456 ret = -EINVAL;
457 goto arg_error;
458 }
459
460 ret = lttctl_check_trace(name, 1);
461 if (ret)
462 goto arg_error;
463
464 if (strcmp(channel, "all")) {
465 ret = __lttctl_set_channel_enable(name, channel, enable);
466 if (ret)
467 goto op_err;
468 } else {
469 /* Don't allow set enable state for metadata channel */
470 n_channel = lttctl_get_channellist(name, &channellist, 0);
471 if (n_channel < 0) {
472 fprintf(stderr, "%s: lttctl_get_channellist failed\n",
473 __func__);
474 ret = -ENOENT;
475 goto op_err;
476 }
477
478 for (; n_channel > 0; n_channel--) {
479 ret = __lttctl_set_channel_enable(name,
480 channellist[n_channel - 1], enable);
481 if (ret)
482 goto op_err_clean;
483 }
484 lttctl_free_channellist(channellist, n_channel);
485 }
486
487 return 0;
488
489 op_err_clean:
490 lttctl_free_channellist(channellist, n_channel);
491 op_err:
492 arg_error:
493 return ret;
494 }
495
496 static int __lttctl_set_channel_overwrite(const char *name, const char *channel,
497 int overwrite)
498 {
499 int ret;
500 char ctlfname[PATH_MAX];
501
502 sprintf(ctlfname, "%s/ltt/control/%s/channel/%s/overwrite",
503 debugfsmntdir, name, channel);
504
505 ret = lttctl_sendop(ctlfname, overwrite ? "1" : "0");
506 if (ret)
507 fprintf(stderr, "Set channel's overwrite mode failed\n");
508
509 return ret;
510 }
511 int lttctl_set_channel_overwrite(const char *name, const char *channel,
512 int overwrite)
513 {
514 int ret;
515 char **channellist;
516 int n_channel;
517
518 if (!name || !channel) {
519 fprintf(stderr, "%s: args invalid\n", __func__);
520 ret = -EINVAL;
521 goto arg_error;
522 }
523
524 ret = lttctl_check_trace(name, 1);
525 if (ret)
526 goto arg_error;
527
528 if (strcmp(channel, "all")) {
529 ret = __lttctl_set_channel_overwrite(name, channel, overwrite);
530 if (ret)
531 goto op_err;
532 } else {
533 /* Don't allow set overwrite for metadata channel */
534 n_channel = lttctl_get_channellist(name, &channellist, 0);
535 if (n_channel < 0) {
536 fprintf(stderr, "%s: lttctl_get_channellist failed\n",
537 __func__);
538 ret = -ENOENT;
539 goto op_err;
540 }
541
542 for (; n_channel > 0; n_channel--) {
543 ret = __lttctl_set_channel_overwrite(name,
544 channellist[n_channel - 1], overwrite);
545 if (ret)
546 goto op_err_clean;
547 }
548 lttctl_free_channellist(channellist, n_channel);
549 }
550
551 return 0;
552
553 op_err_clean:
554 lttctl_free_channellist(channellist, n_channel);
555 op_err:
556 arg_error:
557 return ret;
558 }
559
560 static int __lttctl_set_channel_subbuf_num(const char *name,
561 const char *channel, unsigned subbuf_num)
562 {
563 int ret;
564 char ctlfname[PATH_MAX];
565 char opstr[32];
566
567 sprintf(ctlfname, "%s/ltt/control/%s/channel/%s/subbuf_num",
568 debugfsmntdir, name, channel);
569
570 sprintf(opstr, "%u", subbuf_num);
571
572 ret = lttctl_sendop(ctlfname, opstr);
573 if (ret)
574 fprintf(stderr, "Set channel's subbuf number failed\n");
575
576 return ret;
577 }
578 int lttctl_set_channel_subbuf_num(const char *name, const char *channel,
579 unsigned subbuf_num)
580 {
581 int ret;
582 char **channellist;
583 int n_channel;
584
585 if (!name || !channel) {
586 fprintf(stderr, "%s: args invalid\n", __func__);
587 ret = -EINVAL;
588 goto arg_error;
589 }
590
591 ret = lttctl_check_trace(name, 1);
592 if (ret)
593 goto arg_error;
594
595 if (strcmp(channel, "all")) {
596 ret = __lttctl_set_channel_subbuf_num(name, channel,
597 subbuf_num);
598 if (ret)
599 goto op_err;
600 } else {
601 /* allow set subbuf_num for metadata channel */
602 n_channel = lttctl_get_channellist(name, &channellist, 1);
603 if (n_channel < 0) {
604 fprintf(stderr, "%s: lttctl_get_channellist failed\n",
605 __func__);
606 ret = -ENOENT;
607 goto op_err;
608 }
609
610 for (; n_channel > 0; n_channel--) {
611 ret = __lttctl_set_channel_subbuf_num(name,
612 channellist[n_channel - 1], subbuf_num);
613 if (ret)
614 goto op_err_clean;
615 }
616 lttctl_free_channellist(channellist, n_channel);
617 }
618
619 return 0;
620
621 op_err_clean:
622 lttctl_free_channellist(channellist, n_channel);
623 op_err:
624 arg_error:
625 return ret;
626 }
627
628 static int __lttctl_set_channel_subbuf_size(const char *name,
629 const char *channel, unsigned subbuf_size)
630 {
631 int ret;
632 char ctlfname[PATH_MAX];
633 char opstr[32];
634
635 sprintf(ctlfname, "%s/ltt/control/%s/channel/%s/subbuf_size",
636 debugfsmntdir, name, channel);
637
638 sprintf(opstr, "%u", subbuf_size);
639
640 ret = lttctl_sendop(ctlfname, opstr);
641 if (ret)
642 fprintf(stderr, "Set channel's subbuf size failed\n");
643 return ret;
644 }
645
646 int lttctl_set_channel_subbuf_size(const char *name, const char *channel,
647 unsigned subbuf_size)
648 {
649 int ret;
650 char **channellist;
651 int n_channel;
652
653 if (!name || !channel) {
654 fprintf(stderr, "%s: args invalid\n", __func__);
655 ret = -EINVAL;
656 goto arg_error;
657 }
658
659 ret = lttctl_check_trace(name, 1);
660 if (ret)
661 goto arg_error;
662
663 if (strcmp(channel, "all")) {
664 ret = __lttctl_set_channel_subbuf_size(name, channel,
665 subbuf_size);
666 if (ret)
667 goto op_err;
668 } else {
669 /* allow set subbuf_size for metadata channel */
670 n_channel = lttctl_get_channellist(name, &channellist, 1);
671 if (n_channel < 0) {
672 fprintf(stderr, "%s: lttctl_get_channellist failed\n",
673 __func__);
674 ret = -ENOENT;
675 goto op_err;
676 }
677
678 for (; n_channel > 0; n_channel--) {
679 ret = __lttctl_set_channel_subbuf_size(name,
680 channellist[n_channel - 1], subbuf_size);
681 if (ret)
682 goto op_err_clean;
683 }
684 lttctl_free_channellist(channellist, n_channel);
685 }
686
687 return 0;
688
689 op_err_clean:
690 lttctl_free_channellist(channellist, n_channel);
691 op_err:
692 arg_error:
693 return ret;
694 }
695
696 static int __lttctl_set_channel_switch_timer(const char *name,
697 const char *channel, unsigned switch_timer)
698 {
699 int ret;
700 char ctlfname[PATH_MAX];
701 char opstr[32];
702
703 sprintf(ctlfname, "%s/ltt/control/%s/channel/%s/switch_timer",
704 debugfsmntdir, name, channel);
705
706 sprintf(opstr, "%u", switch_timer);
707
708 ret = lttctl_sendop(ctlfname, opstr);
709 if (ret)
710 fprintf(stderr, "Set channel's switch timer failed\n");
711 return ret;
712 }
713
714 int lttctl_set_channel_switch_timer(const char *name, const char *channel,
715 unsigned switch_timer)
716 {
717 int ret;
718 char **channellist;
719 int n_channel;
720
721 if (!name || !channel) {
722 fprintf(stderr, "%s: args invalid\n", __func__);
723 ret = -EINVAL;
724 goto arg_error;
725 }
726
727 ret = lttctl_check_trace(name, 1);
728 if (ret)
729 goto arg_error;
730
731 if (strcmp(channel, "all")) {
732 ret = __lttctl_set_channel_subbuf_size(name, channel,
733 switch_timer);
734 if (ret)
735 goto op_err;
736 } else {
737 /* allow set subbuf_size for metadata channel */
738 n_channel = lttctl_get_channellist(name, &channellist, 1);
739 if (n_channel < 0) {
740 fprintf(stderr, "%s: lttctl_get_channellist failed\n",
741 __func__);
742 ret = -ENOENT;
743 goto op_err;
744 }
745
746 for (; n_channel > 0; n_channel--) {
747 ret = __lttctl_set_channel_switch_timer(name,
748 channellist[n_channel - 1], switch_timer);
749 if (ret)
750 goto op_err_clean;
751 }
752 lttctl_free_channellist(channellist, n_channel);
753 }
754
755 return 0;
756
757 op_err_clean:
758 lttctl_free_channellist(channellist, n_channel);
759 op_err:
760 arg_error:
761 return ret;
762 }
763
764 int getdebugfsmntdir(char *mntdir)
765 {
766 char mnt_dir[PATH_MAX];
767 char mnt_type[PATH_MAX];
768 int trymount_done = 0;
769
770 FILE *fp = fopen("/proc/mounts", "r");
771 if (!fp)
772 return -EINVAL;
773
774 find_again:
775 while (1) {
776 if (fscanf(fp, "%*s %s %s %*s %*s %*s", mnt_dir, mnt_type) <= 0)
777 break;
778
779 if (!strcmp(mnt_type, "debugfs")) {
780 strcpy(mntdir, mnt_dir);
781 return 0;
782 }
783 }
784
785 if (!trymount_done) {
786 mount("debugfs", "/sys/kernel/debug/", "debugfs", 0, NULL);
787 trymount_done = 1;
788 goto find_again;
789 }
790
791 return -ENOENT;
792 }
This page took 0.045532 seconds and 4 git commands to generate.