+++ /dev/null
-/* libltt
- *
- * Linux Trace Toolkit Netlink Control Library
- *
- * Controls the ltt-control kernel module through debugfs.
- *
- * Copyright 2005 -
- * Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <liblttctl/lttctl.h>
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <dirent.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <stdlib.h>
-
-#define MAX_CHANNEL (256)
-
-static char debugfsmntdir[PATH_MAX];
-
-static int initdebugfsmntdir(void)
-{
- return getdebugfsmntdir(debugfsmntdir);
-}
-
-/*
- * This function must called posterior to initdebugfsmntdir(),
- * because it need to use debugfsmntdir[] which is inited in initdebugfsmntdir()
- */
-static int initmodule(void)
-{
- char controldirname[PATH_MAX];
- DIR *dir;
- int tryload_done = 0;
-
- sprintf(controldirname, "%s/ltt/control/", debugfsmntdir);
-
-check_again:
- /*
- * Check ltt control's debugfs dir
- *
- * We don't check is ltt-trace-control module exist, because it maybe
- * compiled into kernel.
- */
- dir = opendir(controldirname);
- if (dir) {
- closedir(dir);
- return 0;
- }
-
- if (!tryload_done) {
- system("modprobe ltt-trace-control");
- tryload_done = 1;
- goto check_again;
- }
-
- return -ENOENT;
-}
-
-int lttctl_init(void)
-{
- int ret;
-
-
- ret = initdebugfsmntdir();
- if (ret) {
- fprintf(stderr, "Get debugfs mount point failed\n");
- return ret;
- }
-
- ret = initmodule();
- if (ret) {
- fprintf(stderr, "Control module seems not work\n");
- return ret;
- }
-
- return 0;
-}
-
-int lttctl_destroy(void)
-{
- return 0;
-}
-
-static int lttctl_sendop(const char *fname, const char *op)
-{
- int fd;
-
- if (!fname) {
- fprintf(stderr, "%s: args invalid\n", __func__);
- return 1;
- }
-
- fd = open(fname, O_WRONLY);
- if (fd == -1) {
- fprintf(stderr, "%s: open %s failed: %s\n", __func__, fname,
- strerror(errno));
- return errno;
- }
-
- if (write(fd, op, strlen(op)) == -1) {
- int ret = errno;
- fprintf(stderr, "%s: write %s to %s failed: %s\n", __func__, op,
- fname, strerror(errno));
- close(fd);
- return ret;
- }
-
- close(fd);
-
- return 0;
-}
-
-/*
- * check is trace exist(check debugfsmntdir too)
- * expect:
- * 0: expect that trace not exist
- * !0: expect that trace exist
- *
- * ret:
- * 0: check pass
- * -(EEXIST | ENOENT): check failed
- * -ERRNO: error happened (no check)
- */
-static int lttctl_check_trace(const char *name, int expect)
-{
- char tracedirname[PATH_MAX];
- DIR *dir;
- int exist;
-
- if (!name) {
- fprintf(stderr, "%s: args invalid\n", __func__);
- return -EINVAL;
- }
-
- if (!debugfsmntdir[0]) {
- fprintf(stderr, "%s: debugfsmntdir not valid\n", __func__);
- return -EINVAL;
- }
-
- sprintf(tracedirname, "%s/ltt/control/%s", debugfsmntdir, name);
-
- dir = opendir(tracedirname);
- if (dir) {
- exist = 1;
- } else {
- if (errno != ENOENT) {
- fprintf(stderr, "%s: %s\n", __func__, strerror(errno));
- return -EINVAL;
- }
- exist = 0;
- }
-
- closedir(dir);
-
- if (!expect != !exist) {
- if (exist)
- {
- fprintf(stderr, "Trace %s already exist\n", name);
- return -EEXIST;
- }
- else
- {
- fprintf(stderr, "Trace %s not exist\n", name);
- return -ENOENT;
- }
-
- }
-
- return 0;
-}
-
-/*
- * get channel list of a trace
- * don't include metadata channel when metadata is 0
- *
- * return number of channel on success
- * return negative number on fail
- * Caller must free channellist.
- */
-static int lttctl_get_channellist(const char *tracename,
- char ***channellist, int metadata)
-{
- char tracedirname[PATH_MAX];
- struct dirent *dirent;
- DIR *dir;
- char **list = NULL, **old_list;
- int nr_chan = 0;
-
- sprintf(tracedirname, "%s/ltt/control/%s/channel", debugfsmntdir,
- tracename);
-
- dir = opendir(tracedirname);
- if (!dir) {
- nr_chan = -ENOENT;
- goto error;
- }
-
- for (;;) {
- dirent = readdir(dir);
- if (!dirent)
- break;
- if (!strcmp(dirent->d_name, ".")
- || !strcmp(dirent->d_name, ".."))
- continue;
- if (!metadata && !strcmp(dirent->d_name, "metadata"))
- continue;
- old_list = list;
- list = malloc(sizeof(char *) * ++nr_chan);
- memcpy(list, old_list, sizeof(*list) * (nr_chan - 1));
- free(old_list);
- list[nr_chan - 1] = strdup(dirent->d_name);
- }
-
- closedir(dir);
-
- *channellist = list;
- return nr_chan;
-error:
- free(list);
- *channellist = NULL;
- return nr_chan;
-}
-
-static void lttctl_free_channellist(char **channellist, int n_channel)
-{
- int i = 0;
- for(; i < n_channel; ++i)
- free(channellist[i]);
- free(channellist);
-}
-
-int lttctl_setup_trace(const char *name)
-{
- int ret;
- char ctlfname[PATH_MAX];
-
- if (!name) {
- fprintf(stderr, "%s: args invalid\n", __func__);
- ret = -EINVAL;
- goto arg_error;
- }
-
- ret = lttctl_check_trace(name, 0);
- if (ret)
- goto arg_error;
-
- sprintf(ctlfname, "%s/ltt/setup_trace", debugfsmntdir);
-
- ret = lttctl_sendop(ctlfname, name);
- if (ret) {
- fprintf(stderr, "Setup trace failed\n");
- goto op_err;
- }
-
- return 0;
-
-op_err:
-arg_error:
- return ret;
-}
-
-int lttctl_destroy_trace(const char *name)
-{
- int ret;
- char ctlfname[PATH_MAX];
-
- if (!name) {
- fprintf(stderr, "%s: args invalid\n", __func__);
- ret = -EINVAL;
- goto arg_error;
- }
-
- ret = lttctl_check_trace(name, 1);
- if (ret)
- goto arg_error;
-
- sprintf(ctlfname, "%s/ltt/destroy_trace", debugfsmntdir);
-
- ret = lttctl_sendop(ctlfname, name);
- if (ret) {
- fprintf(stderr, "Destroy trace failed\n");
- goto op_err;
- }
-
- return 0;
-
-op_err:
-arg_error:
- return ret;
-}
-
-int lttctl_alloc_trace(const char *name)
-{
- int ret;
- char ctlfname[PATH_MAX];
-
- if (!name) {
- fprintf(stderr, "%s: args invalid\n", __func__);
- ret = -EINVAL;
- goto arg_error;
- }
-
- ret = lttctl_check_trace(name, 1);
- if (ret)
- goto arg_error;
-
- sprintf(ctlfname, "%s/ltt/control/%s/alloc", debugfsmntdir, name);
-
- ret = lttctl_sendop(ctlfname, "1");
- if (ret) {
- fprintf(stderr, "Allocate trace failed\n");
- goto op_err;
- }
-
- return 0;
-
-op_err:
-arg_error:
- return ret;
-}
-
-int lttctl_start(const char *name)
-{
- int ret;
- char ctlfname[PATH_MAX];
-
- if (!name) {
- fprintf(stderr, "%s: args invalid\n", __func__);
- ret = -EINVAL;
- goto arg_error;
- }
-
- ret = lttctl_check_trace(name, 1);
- if (ret)
- goto arg_error;
-
- sprintf(ctlfname, "%s/ltt/control/%s/enabled", debugfsmntdir, name);
-
- ret = lttctl_sendop(ctlfname, "1");
- if (ret) {
- fprintf(stderr, "Start trace failed\n");
- goto op_err;
- }
-
- return 0;
-
-op_err:
-arg_error:
- return ret;
-}
-
-int lttctl_pause(const char *name)
-{
- int ret;
- char ctlfname[PATH_MAX];
-
- if (!name) {
- fprintf(stderr, "%s: args invalid\n", __func__);
- ret = -EINVAL;
- goto arg_error;
- }
-
- ret = lttctl_check_trace(name, 1);
- if (ret)
- goto arg_error;
-
- sprintf(ctlfname, "%s/ltt/control/%s/enabled", debugfsmntdir, name);
-
- ret = lttctl_sendop(ctlfname, "0");
- if (ret) {
- fprintf(stderr, "Pause trace failed\n");
- goto op_err;
- }
-
- return 0;
-
-op_err:
-arg_error:
- return ret;
-}
-
-int lttctl_set_trans(const char *name, const char *trans)
-{
- int ret;
- char ctlfname[PATH_MAX];
-
- if (!name) {
- fprintf(stderr, "%s: args invalid\n", __func__);
- ret = -EINVAL;
- goto arg_error;
- }
-
- ret = lttctl_check_trace(name, 1);
- if (ret)
- goto arg_error;
-
- sprintf(ctlfname, "%s/ltt/control/%s/trans", debugfsmntdir, name);
-
- ret = lttctl_sendop(ctlfname, trans);
- if (ret) {
- fprintf(stderr, "Set transport failed\n");
- goto op_err;
- }
-
- return 0;
-
-op_err:
-arg_error:
- return ret;
-}
-
-static int __lttctl_set_channel_enable(const char *name, const char *channel,
- int enable)
-{
- int ret;
- char ctlfname[PATH_MAX];
-
- sprintf(ctlfname, "%s/ltt/control/%s/channel/%s/enable", debugfsmntdir,
- name, channel);
-
- ret = lttctl_sendop(ctlfname, enable ? "1" : "0");
- if (ret)
- fprintf(stderr, "Set channel's enable mode failed\n");
-
- return ret;
-}
-int lttctl_set_channel_enable(const char *name, const char *channel,
- int enable)
-{
- int ret;
- char **channellist;
- int n_channel;
-
- if (!name || !channel) {
- fprintf(stderr, "%s: args invalid\n", __func__);
- ret = -EINVAL;
- goto arg_error;
- }
-
- ret = lttctl_check_trace(name, 1);
- if (ret)
- goto arg_error;
-
- if (strcmp(channel, "all")) {
- ret = __lttctl_set_channel_enable(name, channel, enable);
- if (ret)
- goto op_err;
- } else {
- /* Don't allow set enable state for metadata channel */
- n_channel = lttctl_get_channellist(name, &channellist, 0);
- if (n_channel < 0) {
- fprintf(stderr, "%s: lttctl_get_channellist failed\n",
- __func__);
- ret = -ENOENT;
- goto op_err;
- }
-
- for (; n_channel > 0; n_channel--) {
- ret = __lttctl_set_channel_enable(name,
- channellist[n_channel - 1], enable);
- if (ret)
- goto op_err_clean;
- }
- lttctl_free_channellist(channellist, n_channel);
- }
-
- return 0;
-
-op_err_clean:
- lttctl_free_channellist(channellist, n_channel);
-op_err:
-arg_error:
- return ret;
-}
-
-static int __lttctl_set_channel_overwrite(const char *name, const char *channel,
- int overwrite)
-{
- int ret;
- char ctlfname[PATH_MAX];
-
- sprintf(ctlfname, "%s/ltt/control/%s/channel/%s/overwrite",
- debugfsmntdir, name, channel);
-
- ret = lttctl_sendop(ctlfname, overwrite ? "1" : "0");
- if (ret)
- fprintf(stderr, "Set channel's overwrite mode failed\n");
-
- return ret;
-}
-int lttctl_set_channel_overwrite(const char *name, const char *channel,
- int overwrite)
-{
- int ret;
- char **channellist;
- int n_channel;
-
- if (!name || !channel) {
- fprintf(stderr, "%s: args invalid\n", __func__);
- ret = -EINVAL;
- goto arg_error;
- }
-
- ret = lttctl_check_trace(name, 1);
- if (ret)
- goto arg_error;
-
- if (strcmp(channel, "all")) {
- ret = __lttctl_set_channel_overwrite(name, channel, overwrite);
- if (ret)
- goto op_err;
- } else {
- /* Don't allow set overwrite for metadata channel */
- n_channel = lttctl_get_channellist(name, &channellist, 0);
- if (n_channel < 0) {
- fprintf(stderr, "%s: lttctl_get_channellist failed\n",
- __func__);
- ret = -ENOENT;
- goto op_err;
- }
-
- for (; n_channel > 0; n_channel--) {
- ret = __lttctl_set_channel_overwrite(name,
- channellist[n_channel - 1], overwrite);
- if (ret)
- goto op_err_clean;
- }
- lttctl_free_channellist(channellist, n_channel);
- }
-
- return 0;
-
-op_err_clean:
- lttctl_free_channellist(channellist, n_channel);
-op_err:
-arg_error:
- return ret;
-}
-
-static int __lttctl_set_channel_subbuf_num(const char *name,
- const char *channel, unsigned subbuf_num)
-{
- int ret;
- char ctlfname[PATH_MAX];
- char opstr[32];
-
- sprintf(ctlfname, "%s/ltt/control/%s/channel/%s/subbuf_num",
- debugfsmntdir, name, channel);
-
- sprintf(opstr, "%u", subbuf_num);
-
- ret = lttctl_sendop(ctlfname, opstr);
- if (ret)
- fprintf(stderr, "Set channel's subbuf number failed\n");
-
- return ret;
-}
-int lttctl_set_channel_subbuf_num(const char *name, const char *channel,
- unsigned subbuf_num)
-{
- int ret;
- char **channellist;
- int n_channel;
-
- if (!name || !channel) {
- fprintf(stderr, "%s: args invalid\n", __func__);
- ret = -EINVAL;
- goto arg_error;
- }
-
- ret = lttctl_check_trace(name, 1);
- if (ret)
- goto arg_error;
-
- if (strcmp(channel, "all")) {
- ret = __lttctl_set_channel_subbuf_num(name, channel,
- subbuf_num);
- if (ret)
- goto op_err;
- } else {
- /* allow set subbuf_num for metadata channel */
- n_channel = lttctl_get_channellist(name, &channellist, 1);
- if (n_channel < 0) {
- fprintf(stderr, "%s: lttctl_get_channellist failed\n",
- __func__);
- ret = -ENOENT;
- goto op_err;
- }
-
- for (; n_channel > 0; n_channel--) {
- ret = __lttctl_set_channel_subbuf_num(name,
- channellist[n_channel - 1], subbuf_num);
- if (ret)
- goto op_err_clean;
- }
- lttctl_free_channellist(channellist, n_channel);
- }
-
- return 0;
-
-op_err_clean:
- lttctl_free_channellist(channellist, n_channel);
-op_err:
-arg_error:
- return ret;
-}
-
-static int __lttctl_set_channel_subbuf_size(const char *name,
- const char *channel, unsigned subbuf_size)
-{
- int ret;
- char ctlfname[PATH_MAX];
- char opstr[32];
-
- sprintf(ctlfname, "%s/ltt/control/%s/channel/%s/subbuf_size",
- debugfsmntdir, name, channel);
-
- sprintf(opstr, "%u", subbuf_size);
-
- ret = lttctl_sendop(ctlfname, opstr);
- if (ret)
- fprintf(stderr, "Set channel's subbuf size failed\n");
-}
-int lttctl_set_channel_subbuf_size(const char *name, const char *channel,
- unsigned subbuf_size)
-{
- int ret;
- char **channellist;
- int n_channel;
-
- if (!name || !channel) {
- fprintf(stderr, "%s: args invalid\n", __func__);
- ret = -EINVAL;
- goto arg_error;
- }
-
- ret = lttctl_check_trace(name, 1);
- if (ret)
- goto arg_error;
-
- if (strcmp(channel, "all")) {
- ret = __lttctl_set_channel_subbuf_size(name, channel,
- subbuf_size);
- if (ret)
- goto op_err;
- } else {
- /* allow set subbuf_size for metadata channel */
- n_channel = lttctl_get_channellist(name, &channellist, 1);
- if (n_channel < 0) {
- fprintf(stderr, "%s: lttctl_get_channellist failed\n",
- __func__);
- ret = -ENOENT;
- goto op_err;
- }
-
- for (; n_channel > 0; n_channel--) {
- ret = __lttctl_set_channel_subbuf_size(name,
- channellist[n_channel - 1], subbuf_size);
- if (ret)
- goto op_err_clean;
- }
- lttctl_free_channellist(channellist, n_channel);
- }
-
- return 0;
-
-op_err_clean:
- lttctl_free_channellist(channellist, n_channel);
-op_err:
-arg_error:
- return ret;
-}
-
-int getdebugfsmntdir(char *mntdir)
-{
- char mnt_dir[PATH_MAX];
- char mnt_type[PATH_MAX];
- int trymount_done = 0;
-
- FILE *fp = fopen("/proc/mounts", "r");
- if (!fp)
- return -EINVAL;
-
-find_again:
- while (1) {
- if (fscanf(fp, "%*s %s %s %*s %*s %*s", mnt_dir, mnt_type) <= 0)
- break;
-
- if (!strcmp(mnt_type, "debugfs")) {
- strcpy(mntdir, mnt_dir);
- return 0;
- }
- }
-
- if (!trymount_done) {
- mount("debugfs", "/sys/kernel/debug/", "debugfs", 0, NULL);
- trymount_done = 1;
- goto find_again;
- }
-
- return -ENOENT;
-}