apply zhaolei updates
[ltt-control.git] / trunk / ltt-control / 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");
c928825d 87 return 1;
2727692a 88 }
2727692a 89
354b34fd 90 ret = initmodule();
91 if (ret) {
92 fprintf(stderr, "Control module seems not work\n");
93 return 1;
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) {
121 fprintf(stderr, "%s: write %s to %s failed: %s\n", __func__, op,
122 fname, strerror(errno));
123 close(fd);
124 return 1;
125 }
2727692a 126
c928825d 127 close(fd);
128
129 return 0;
130}
2727692a 131
132/*
c928825d 133 * check is trace exist(check debugfsmntdir too)
134 * expect:
135 * 0: expect that trace not exist
136 * !0: expect that trace exist
137 *
138 * ret:
139 * 0: check pass
140 * 1: check failed
141 * -ERRNO: error happened (no check)
2727692a 142 */
c928825d 143static int lttctl_check_trace(const char *name, int expect)
2727692a 144{
c928825d 145 char tracedirname[PATH_MAX];
146 DIR *dir;
147 int exist;
2727692a 148
c928825d 149 if (!name) {
150 fprintf(stderr, "%s: args invalid\n", __func__);
151 return -EINVAL;
2727692a 152 }
c928825d 153
154 if (!debugfsmntdir[0]) {
155 fprintf(stderr, "%s: debugfsmntdir not valid\n", __func__);
156 return -EINVAL;
157 }
158
159 sprintf(tracedirname, "%s/ltt/control/%s", debugfsmntdir, name);
160
161 dir = opendir(tracedirname);
162 if (dir) {
163 exist = 1;
164 } else {
165 if (errno != ENOENT) {
166 fprintf(stderr, "%s: %s\n", __func__, strerror(errno));
167 return -EINVAL;
168 }
169 exist = 0;
170 }
171
172 closedir(dir);
173
174 if (!expect != !exist) {
175 if (exist)
176 fprintf(stderr, "Trace %s already exist\n", name);
177 else
178 fprintf(stderr, "Trace %s not exist\n", name);
179 return 1;
180 }
181
182 return 0;
2727692a 183}
184
185/*
c928825d 186 * get channel list of a trace
187 * don't include metadata channel when metadata is 0
188 *
189 * return number of channel on success
190 * return negative number on fail
191 * Caller must free channellist.
2727692a 192 */
c928825d 193static int lttctl_get_channellist(const char *tracename,
194 char ***channellist, int metadata)
2727692a 195{
c928825d 196 char tracedirname[PATH_MAX];
197 struct dirent *dirent;
198 DIR *dir;
199 char **list = NULL, **old_list;
200 int nr_chan = 0;
201
202 sprintf(tracedirname, "%s/ltt/control/%s/channel", debugfsmntdir,
203 tracename);
204
205 dir = opendir(tracedirname);
206 if (!dir) {
207 nr_chan = -ENOENT;
208 goto error;
209 }
210
211 for (;;) {
212 dirent = readdir(dir);
213 if (!dirent)
214 break;
215 if (!strcmp(dirent->d_name, ".")
216 || !strcmp(dirent->d_name, ".."))
217 continue;
218 if (!metadata && !strcmp(dirent->d_name, "metadata"))
219 continue;
220 old_list = list;
221 list = malloc(sizeof(char *) * ++nr_chan);
222 memcpy(list, old_list, sizeof(*list) * (nr_chan - 1));
223 free(old_list);
224 list[nr_chan - 1] = strdup(dirent->d_name);
225 }
226
227 closedir(dir);
228
229 *channellist = list;
230 return nr_chan;
231error:
232 free(list);
233 *channellist = NULL;
234 return nr_chan;
235}
236
237int lttctl_setup_trace(const char *name)
238{
239 int ret;
240 char ctlfname[PATH_MAX];
241
242 if (!name) {
243 fprintf(stderr, "%s: args invalid\n", __func__);
244 ret = -EINVAL;
245 goto arg_error;
246 }
247
248 ret = lttctl_check_trace(name, 0);
249 if (ret)
250 goto arg_error;
251
252 sprintf(ctlfname, "%s/ltt/setup_trace", debugfsmntdir);
253
254 ret = lttctl_sendop(ctlfname, name);
255 if (ret) {
256 fprintf(stderr, "Setup trace failed\n");
257 goto op_err;
2727692a 258 }
c928825d 259
2727692a 260 return 0;
c928825d 261
262op_err:
263arg_error:
264 return ret;
2727692a 265}
266
c928825d 267int lttctl_destroy_trace(const char *name)
268{
269 int ret;
270 char ctlfname[PATH_MAX];
271
272 if (!name) {
273 fprintf(stderr, "%s: args invalid\n", __func__);
274 ret = -EINVAL;
275 goto arg_error;
276 }
277
278 ret = lttctl_check_trace(name, 1);
279 if (ret)
280 goto arg_error;
281
282 sprintf(ctlfname, "%s/ltt/destroy_trace", debugfsmntdir);
283
284 ret = lttctl_sendop(ctlfname, name);
285 if (ret) {
286 fprintf(stderr, "Destroy trace failed\n");
287 goto op_err;
288 }
289
290 return 0;
291
292op_err:
293arg_error:
294 return ret;
295}
2727692a 296
c928825d 297int lttctl_alloc_trace(const char *name)
2727692a 298{
c928825d 299 int ret;
300 char ctlfname[PATH_MAX];
301
302 if (!name) {
303 fprintf(stderr, "%s: args invalid\n", __func__);
304 ret = -EINVAL;
305 goto arg_error;
306 }
307
308 ret = lttctl_check_trace(name, 1);
309 if (ret)
310 goto arg_error;
311
312 sprintf(ctlfname, "%s/ltt/control/%s/alloc", debugfsmntdir, name);
313
314 ret = lttctl_sendop(ctlfname, "1");
315 if (ret) {
316 fprintf(stderr, "Allocate trace failed\n");
317 goto op_err;
318 }
319
320 return 0;
321
322op_err:
323arg_error:
324 return ret;
325}
326
327int lttctl_start(const char *name)
328{
329 int ret;
330 char ctlfname[PATH_MAX];
331
332 if (!name) {
333 fprintf(stderr, "%s: args invalid\n", __func__);
334 ret = -EINVAL;
335 goto arg_error;
336 }
337
338 ret = lttctl_check_trace(name, 1);
339 if (ret)
340 goto arg_error;
341
342 sprintf(ctlfname, "%s/ltt/control/%s/enabled", debugfsmntdir, name);
343
344 ret = lttctl_sendop(ctlfname, "1");
345 if (ret) {
346 fprintf(stderr, "Start trace failed\n");
347 goto op_err;
2727692a 348 }
349
350 return 0;
351
c928825d 352op_err:
353arg_error:
354 return ret;
2727692a 355}
356
c928825d 357int lttctl_pause(const char *name)
2727692a 358{
c928825d 359 int ret;
360 char ctlfname[PATH_MAX];
361
362 if (!name) {
363 fprintf(stderr, "%s: args invalid\n", __func__);
364 ret = -EINVAL;
365 goto arg_error;
366 }
367
368 ret = lttctl_check_trace(name, 1);
369 if (ret)
370 goto arg_error;
371
372 sprintf(ctlfname, "%s/ltt/control/%s/enabled", debugfsmntdir, name);
373
374 ret = lttctl_sendop(ctlfname, "0");
375 if (ret) {
376 fprintf(stderr, "Pause trace failed\n");
377 goto op_err;
2727692a 378 }
379
380 return 0;
381
c928825d 382op_err:
383arg_error:
384 return ret;
385}
386
387int lttctl_set_trans(const char *name, const char *trans)
388{
389 int ret;
390 char ctlfname[PATH_MAX];
391
392 if (!name) {
393 fprintf(stderr, "%s: args invalid\n", __func__);
394 ret = -EINVAL;
395 goto arg_error;
396 }
397
398 ret = lttctl_check_trace(name, 1);
399 if (ret)
400 goto arg_error;
401
402 sprintf(ctlfname, "%s/ltt/control/%s/trans", debugfsmntdir, name);
2727692a 403
c928825d 404 ret = lttctl_sendop(ctlfname, trans);
405 if (ret) {
406 fprintf(stderr, "Set transport failed\n");
407 goto op_err;
408 }
409
410 return 0;
411
412op_err:
413arg_error:
414 return ret;
2727692a 415}
416
c928825d 417static int __lttctl_set_channel_enable(const char *name, const char *channel,
418 int enable)
2727692a 419{
c928825d 420 int ret;
421 char ctlfname[PATH_MAX];
2727692a 422
c928825d 423 sprintf(ctlfname, "%s/ltt/control/%s/channel/%s/enable", debugfsmntdir,
424 name, channel);
2727692a 425
c928825d 426 ret = lttctl_sendop(ctlfname, enable ? "1" : "0");
427 if (ret)
428 fprintf(stderr, "Set channel's enable mode failed\n");
2727692a 429
c928825d 430 return ret;
431}
432int lttctl_set_channel_enable(const char *name, const char *channel,
433 int enable)
434{
435 int ret;
2727692a 436
c928825d 437 if (!name || !channel) {
438 fprintf(stderr, "%s: args invalid\n", __func__);
439 ret = -EINVAL;
440 goto arg_error;
441 }
2727692a 442
c928825d 443 ret = lttctl_check_trace(name, 1);
444 if (ret)
445 goto arg_error;
446
447 if (strcmp(channel, "all")) {
448 ret = __lttctl_set_channel_enable(name, channel, enable);
449 if (ret)
450 goto op_err;
451 } else {
452 char **channellist;
453 int n_channel;
454
455 /* Don't allow set enable state for metadata channel */
456 n_channel = lttctl_get_channellist(name, &channellist, 0);
457 if (n_channel < 0) {
458 fprintf(stderr, "%s: lttctl_get_channellist failed\n",
459 __func__);
460 ret = -ENOENT;
461 goto op_err;
462 }
2727692a 463
c928825d 464 for (; n_channel > 0; n_channel--) {
465 ret = __lttctl_set_channel_enable(name,
466 channellist[n_channel - 1], enable);
467 if (ret)
468 goto op_err;
469 }
470 free(channellist);
2727692a 471 }
472
473 return 0;
474
c928825d 475op_err:
476arg_error:
477 return ret;
478}
479
480static int __lttctl_set_channel_overwrite(const char *name, const char *channel,
481 int overwrite)
482{
483 int ret;
484 char ctlfname[PATH_MAX];
485
486 sprintf(ctlfname, "%s/ltt/control/%s/channel/%s/overwrite",
487 debugfsmntdir, name, channel);
488
489 ret = lttctl_sendop(ctlfname, overwrite ? "1" : "0");
490 if (ret)
491 fprintf(stderr, "Set channel's overwrite mode failed\n");
492
493 return ret;
494}
495int lttctl_set_channel_overwrite(const char *name, const char *channel,
496 int overwrite)
497{
498 int ret;
499
500 if (!name || !channel) {
501 fprintf(stderr, "%s: args invalid\n", __func__);
502 ret = -EINVAL;
503 goto arg_error;
504 }
505
506 ret = lttctl_check_trace(name, 1);
507 if (ret)
508 goto arg_error;
509
510 if (strcmp(channel, "all")) {
511 ret = __lttctl_set_channel_overwrite(name, channel, overwrite);
512 if (ret)
513 goto op_err;
514 } else {
515 char **channellist;
516 int n_channel;
517
518 /* Don't allow set overwrite for metadata channel */
519 n_channel = lttctl_get_channellist(name, &channellist, 0);
520 if (n_channel < 0) {
521 fprintf(stderr, "%s: lttctl_get_channellist failed\n",
522 __func__);
523 ret = -ENOENT;
524 goto op_err;
525 }
526
527 for (; n_channel > 0; n_channel--) {
528 ret = __lttctl_set_channel_overwrite(name,
529 channellist[n_channel - 1], overwrite);
530 if (ret)
531 goto op_err;
532 }
533 free(channellist);
534 }
535
536 return 0;
2727692a 537
c928825d 538op_err:
539arg_error:
540 return ret;
2727692a 541}
542
c928825d 543static int __lttctl_set_channel_subbuf_num(const char *name,
544 const char *channel, unsigned subbuf_num)
545{
546 int ret;
547 char ctlfname[PATH_MAX];
548 char opstr[32];
549
550 sprintf(ctlfname, "%s/ltt/control/%s/channel/%s/subbuf_num",
551 debugfsmntdir, name, channel);
552
553 sprintf(opstr, "%u", subbuf_num);
554
555 ret = lttctl_sendop(ctlfname, opstr);
556 if (ret)
557 fprintf(stderr, "Set channel's subbuf number failed\n");
558
559 return ret;
560}
561int lttctl_set_channel_subbuf_num(const char *name, const char *channel,
562 unsigned subbuf_num)
2727692a 563{
c928825d 564 int ret;
565
566 if (!name || !channel) {
567 fprintf(stderr, "%s: args invalid\n", __func__);
568 ret = -EINVAL;
569 goto arg_error;
570 }
571
572 ret = lttctl_check_trace(name, 1);
573 if (ret)
574 goto arg_error;
575
576 if (strcmp(channel, "all")) {
577 ret = __lttctl_set_channel_subbuf_num(name, channel,
578 subbuf_num);
579 if (ret)
580 goto op_err;
581 } else {
582 char **channellist;
583 int n_channel;
584
585 /* allow set subbuf_num for metadata channel */
586 n_channel = lttctl_get_channellist(name, &channellist, 1);
587 if (n_channel < 0) {
588 fprintf(stderr, "%s: lttctl_get_channellist failed\n",
589 __func__);
590 ret = -ENOENT;
591 goto op_err;
592 }
593
594 for (; n_channel > 0; n_channel--) {
595 ret = __lttctl_set_channel_subbuf_num(name,
596 channellist[n_channel - 1], subbuf_num);
597 if (ret)
598 goto op_err;
599 }
600 free(channellist);
2727692a 601 }
602
603 return 0;
604
c928825d 605op_err:
606arg_error:
607 return ret;
608}
609
610static int __lttctl_set_channel_subbuf_size(const char *name,
611 const char *channel, unsigned subbuf_size)
612{
613 int ret;
614 char ctlfname[PATH_MAX];
615 char opstr[32];
616
617 sprintf(ctlfname, "%s/ltt/control/%s/channel/%s/subbuf_size",
618 debugfsmntdir, name, channel);
619
620 sprintf(opstr, "%u", subbuf_size);
621
622 ret = lttctl_sendop(ctlfname, opstr);
623 if (ret)
624 fprintf(stderr, "Set channel's subbuf size failed\n");
2727692a 625}
c928825d 626int lttctl_set_channel_subbuf_size(const char *name, const char *channel,
627 unsigned subbuf_size)
628{
629 int ret;
2727692a 630
c928825d 631 if (!name || !channel) {
632 fprintf(stderr, "%s: args invalid\n", __func__);
633 ret = -EINVAL;
634 goto arg_error;
635 }
636
637 ret = lttctl_check_trace(name, 1);
638 if (ret)
639 goto arg_error;
640
641 if (strcmp(channel, "all")) {
642 ret = __lttctl_set_channel_subbuf_size(name, channel,
643 subbuf_size);
644 if (ret)
645 goto op_err;
646 } else {
647 char **channellist;
648 int n_channel;
649
650 /* allow set subbuf_size for metadata channel */
651 n_channel = lttctl_get_channellist(name, &channellist, 1);
652 if (n_channel < 0) {
653 fprintf(stderr, "%s: lttctl_get_channellist failed\n",
654 __func__);
655 ret = -ENOENT;
656 goto op_err;
657 }
658
659 for (; n_channel > 0; n_channel--) {
660 ret = __lttctl_set_channel_subbuf_size(name,
661 channellist[n_channel - 1], subbuf_size);
662 if (ret)
663 goto op_err;
664 }
665 free(channellist);
666 }
667
668 return 0;
669
670op_err:
671arg_error:
672 return ret;
673}
354b34fd 674
675int getdebugfsmntdir(char *mntdir)
676{
677 char mnt_dir[PATH_MAX];
678 char mnt_type[PATH_MAX];
679 int trymount_done = 0;
680
681 FILE *fp = fopen("/proc/mounts", "r");
682 if (!fp)
683 return -EINVAL;
684
685find_again:
686 while (1) {
687 if (fscanf(fp, "%*s %s %s %*s %*s %*s", mnt_dir, mnt_type) <= 0)
688 break;
689
690 if (!strcmp(mnt_type, "debugfs")) {
691 strcpy(mntdir, mnt_dir);
692 return 0;
693 }
694 }
695
696 if (!trymount_done) {
697 mount("debugfs", "/sys/kernel/debug/", "debugfs", 0, NULL);
698 trymount_done = 1;
699 goto find_again;
700 }
701
702 return -ENOENT;
703}
This page took 0.050527 seconds and 4 git commands to generate.