From: Pierre-Marc Fournier Date: Wed, 12 Aug 2009 01:29:57 +0000 (-0400) Subject: move ltt-control out of trunk/ltt-control X-Git-Tag: 0.80~24 X-Git-Url: https://git.liburcu.org/?a=commitdiff_plain;h=5e1fd42a8d1bbbe1e1283e4c652994ff738dd6a7;p=ltt-control.git move ltt-control out of trunk/ltt-control --- diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..032edf0 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,25 @@ +Linux Trace Toolkit Viewer + +Contributors : + +Michel Dagenais (New trace format, lttv main) +Mathieu Desnoyers (Kernel Tracer, Directory structure, build with automake/conf, + lttv gui, control flow view, gui cooperative trace reading + scheduler with interruptible foreground and background + computation, detailed event list (rewrite), trace reading + library (rewrite)) +Benoit Des Ligneris, Éric Clement (Cluster adaptation, work in progress) +Xang-Xiu Yang (trace reading library and converter, lttv gui, + detailed event list and statistics view) +Tom Zanussi (RelayFS) + +Strongly inspired from the original Linux Trace Toolkit Visualizer made by +Karim Yaghmour. + +Linux Trace Toolkit Viewer, Copyright (C) 2004 + Michel Dagenais + Mathieu Desnoyers + Xang-Xiu Yang +Linux Trace Toolkit comes with ABSOLUTELY NO WARRANTY. +This is free software, and you are welcome to redistribute it +under certain conditions. See COPYING for details. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..8f9974d --- /dev/null +++ b/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = liblttctl lttctl lttd specs + diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/README b/README new file mode 100644 index 0000000..9fce197 --- /dev/null +++ b/README @@ -0,0 +1,60 @@ +ltt-control package README +-------------------------- +Mathieu Desnoyers +Last update: 2007/05/14 + + +This package contains the lttd, lttctl and liblttctl programs which are +necessary to obtain a trace. It also contains the facilities directory, where +sits the trace metainformation. + +* Compiling + +gcc 3.2 or better +glib 2.4 or better development libraries + (Debian : libglib2.0-0, libglib2.0-dev) + (Fedora : glib2, glib2-devel) +libc6 development librairies + (Debian : libc6, libc6-dev) + (Fedora : glibc, glibc) + + +To compile the source tree from a tarball, simply follow these steps : + +- ./configure +- make +- make install + +After running ./configure, you can also go in specific subdirectories and +use make, make install. + + +* Quick Start + +See the LTTV package QUICKSTART file. + + +* Source Tree Structure + +Here is the tree structure of the ltt-control package. + +ltt/ New trace format reading library. +liblttctl/ Library to communicate with the kernel tracer control module. +lttctl/ Command line program to use the liblttctl library. +lttd/ Linux Trace Toolkit daemon. +README This file. + + +* For Developers + +This source tree is based on the autotools suite from GNU to simplify +portability. Here are some things you should have on your system in order to +compile the subversion repository tree : + +- GNU autotools (automake >=1.7, autoconf >=2.50, autoheader >=2.50) + (make sure your system wide "automake" points to a recent version!) +- GNU Libtool + (for more information, go to http://www.gnu.org/software/autoconf/) + +If you get the tree from the repository, you will need to use the autogen.sh +script. It calls all the GNU tools needed to prepare the tree configuration. diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..f0c7b68 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,169 @@ +#!/bin/sh +# Run this to generate all the initial makefiles, etc. + +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +DIE=0 + +(test -f $srcdir/configure.in) || { + echo -n "**Error**: Directory "\`$srcdir\'" does not look like the" + echo " top-level package directory" + exit 1 +} + +(autoconf --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have \`autoconf' installed." + echo "Download the appropriate package for your distribution," + echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" + DIE=1 +} + +(grep "^AC_PROG_INTLTOOL" $srcdir/configure.in >/dev/null) && { + (intltoolize --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have \`intltool' installed." + echo "You can get it from:" + echo " ftp://ftp.gnome.org/pub/GNOME/" + DIE=1 + } +} + +(grep "^AM_PROG_XML_I18N_TOOLS" $srcdir/configure.in >/dev/null) && { + (xml-i18n-toolize --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have \`xml-i18n-toolize' installed." + echo "You can get it from:" + echo " ftp://ftp.gnome.org/pub/GNOME/" + DIE=1 + } +} + +(grep "^AM_PROG_LIBTOOL" $srcdir/configure.in >/dev/null) && { + (libtool --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have \`libtool' installed." + echo "You can get it from: ftp://ftp.gnu.org/pub/gnu/" + DIE=1 + } +} + +(grep "^AM_GLIB_GNU_GETTEXT" $srcdir/configure.in >/dev/null) && { + (grep "sed.*POTFILES" $srcdir/configure.in) > /dev/null || \ + (glib-gettextize --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have \`glib' installed." + echo "You can get it from: ftp://ftp.gtk.org/pub/gtk" + DIE=1 + } +} + +(automake --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have \`automake' installed." + echo "You can get it from: ftp://ftp.gnu.org/pub/gnu/" + DIE=1 + NO_AUTOMAKE=yes +} + + +# if no automake, don't bother testing for aclocal +test -n "$NO_AUTOMAKE" || (aclocal --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: Missing \`aclocal'. The version of \`automake'" + echo "installed doesn't appear recent enough." + echo "You can get automake from ftp://ftp.gnu.org/pub/gnu/" + DIE=1 +} + +if test "$DIE" -eq 1; then + exit 1 +fi + +if test -z "$*"; then + echo "**Warning**: I am going to run \`configure' with no arguments." + echo "If you wish to pass any to it, please specify them on the" + echo \`$0\'" command line." + echo +fi + +case $CC in +xlc ) + am_opt=--include-deps;; +esac + +for coin in `find $srcdir -path $srcdir/CVS -prune -o -name configure.in -print` +do + dr=`dirname $coin` + if test -f $dr/NO-AUTO-GEN; then + echo skipping $dr -- flagged as no auto-gen + else + echo processing $dr + ( cd $dr + + aclocalinclude="$ACLOCAL_FLAGS" + + if grep "^AM_GLIB_GNU_GETTEXT" configure.in >/dev/null; then + echo "Creating $dr/aclocal.m4 ..." + test -r $dr/aclocal.m4 || touch $dr/aclocal.m4 + echo "Running glib-gettextize... Ignore non-fatal messages." + echo "no" | glib-gettextize --force --copy + echo "Making $dr/aclocal.m4 writable ..." + test -r $dr/aclocal.m4 && chmod u+w $dr/aclocal.m4 + fi + if grep "^AC_PROG_INTLTOOL" configure.in >/dev/null; then + echo "Running intltoolize..." + intltoolize --copy --force --automake + fi + if grep "^AM_PROG_XML_I18N_TOOLS" configure.in >/dev/null; then + echo "Running xml-i18n-toolize..." + xml-i18n-toolize --copy --force --automake + fi + if grep "^AM_PROG_LIBTOOL" configure.in >/dev/null; then + if test -z "$NO_LIBTOOLIZE" ; then + echo "Running libtoolize..." + libtoolize --force --copy + fi + fi + echo "Running aclocal $aclocalinclude ..." + aclocal $aclocalinclude + if grep "^AM_CONFIG_HEADER" configure.in >/dev/null; then + echo "Running autoheader..." + autoheader + fi + echo "Running automake --gnu $am_opt ..." + automake --add-missing --gnu $am_opt + echo "Running autoconf ..." + autoconf + ) + fi +done + +conf_flags="--enable-maintainer-mode" + + +#if [ -a "$srcdir/include" ]; then +# echo -n Removing old system include behavior emulation... +# rm -rf $srcdir/include +# echo done. +#fi +#echo -n Creating the system include behavior emulation... +#mkdir $srcdir/include +#mkdir $srcdir/include/ltt +#ln -sf ../../LibLTT/ltt.h $srcdir/include/ltt/ltt.h +#mkdir $srcdir/include/lttv +#ln -sf ../../lttv/module.h $srcdir/include/lttv/module.h +#ln -sf ../../lttv/hook.h $srcdir/include/lttv/hook.h +#ln -sf ../../lttv/traceWindow.h $srcdir/include/lttv/traceWindow.h +#echo done. + + + +if test x$NOCONFIGURE = x; then + echo Running $srcdir/configure $conf_flags "$@" ... + $srcdir/configure $conf_flags "$@" \ + && echo Now type \`make\' to compile. || exit 1 +else + echo Skipping configure process. +fi diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..6adcbaa --- /dev/null +++ b/configure.in @@ -0,0 +1,90 @@ +# This file is part of the Linux Trace Toolkit viewer +# Copyright (C) 2003-2004 Mathieu Desnoyers +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License Version 2 as +# published by the Free Software Foundation; +# +# 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. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, +# MA 02111-1307, USA. + + + +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.57) +AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS) +#AC_WITH_LTDL # not needed ? +AM_INIT_AUTOMAKE(ltt-control,0.69-23072009) +AM_CONFIG_HEADER(config.h) +AM_PROG_LIBTOOL + +AC_PATH_PROGS(BASH, bash) + +AC_SYS_LARGEFILE + +# Checks for programs. +AC_PROG_CC + +AC_CHECK_LIB([util], [forkpty], UTIL_LIBS="-lutil", AC_MSG_ERROR([libutil is +required in order to compile LinuxTraceToolkit])) + + +# pthread for lttd +AC_CHECK_LIB(pthread, pthread_join,[THREAD_LIBS="-lpthread"], AC_MSG_ERROR([LinuxThreads is required in order to compile lttd])) + +# Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS([fcntl.h stdlib.h string.h sys/time.h unistd.h pthread.h]) + +AC_ISC_POSIX +AC_PROG_CC +AM_PROG_CC_STDC +AC_HEADER_STDC + +PACKAGE_CFLAGS="-Wall -Wformat" +AC_SUBST(PACKAGE_CFLAGS) +AC_SUBST(PACKAGE_LIBS) + +# Checks for typedefs, structures, and compiler characteristics. +AC_HEADER_STDBOOL +AC_C_CONST +AC_C_INLINE +AC_TYPE_OFF_T +AC_TYPE_SIZE_T +AC_HEADER_TIME + +# Checks for library functions. +AC_FUNC_ERROR_AT_LINE +#AC_FUNC_MALLOC +AC_FUNC_SELECT_ARGTYPES +AC_CHECK_FUNCS([select]) + +#CPPFLAGS="$CPPFLAGS -I" + +DEFAULT_INCLUDES="-I\$(top_srcdir) -I\$(top_builddir)" + +#CPPFLAGS="${GLIB_CFLAGS}" +#AC_SUBST(CPPFLAGS) + +lttctlincludedir="${includedir}/liblttctl" + +AC_SUBST(lttctlincludedir) +AC_SUBST(UTIL_LIBS) +AC_SUBST(THREAD_LIBS) +AC_SUBST(DEFAULT_INCLUDES) + +AC_CONFIG_FILES([Makefile + liblttctl/Makefile + lttctl/Makefile + lttd/Makefile + specs/Makefile]) +AC_OUTPUT diff --git a/liblttctl/Makefile.am b/liblttctl/Makefile.am new file mode 100644 index 0000000..1c650f0 --- /dev/null +++ b/liblttctl/Makefile.am @@ -0,0 +1,7 @@ + + +lib_LTLIBRARIES = liblttctl.la +liblttctl_la_SOURCES = liblttctl.c + +lttctlinclude_HEADERS = \ + lttctl.h diff --git a/liblttctl/liblttctl.c b/liblttctl/liblttctl.c new file mode 100644 index 0000000..6ee37a4 --- /dev/null +++ b/liblttctl/liblttctl.c @@ -0,0 +1,722 @@ +/* libltt + * + * Linux Trace Toolkit Netlink Control Library + * + * Controls the ltt-control kernel module through debugfs. + * + * Copyright 2005 - + * Mathieu Desnoyers + * + * + * 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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/liblttctl/lttctl.h b/liblttctl/lttctl.h new file mode 100644 index 0000000..facc8f0 --- /dev/null +++ b/liblttctl/lttctl.h @@ -0,0 +1,42 @@ +/* libltt header file + * + * Copyright 2005- + * Mathieu Desnoyers + * + * + * 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. + * + */ + +#ifndef _LIBLTT_H +#define _LIBLTT_H + +int lttctl_init(void); +int lttctl_destroy(void); +int lttctl_setup_trace(const char *name); +int lttctl_destroy_trace(const char *name); +int lttctl_alloc_trace(const char *name); +int lttctl_start(const char *name); +int lttctl_pause(const char *name); +int lttctl_set_trans(const char *name, const char *trans); +int lttctl_set_channel_enable(const char *name, const char *channel, + int enable); +int lttctl_set_channel_overwrite(const char *name, const char *channel, + int overwrite); +int lttctl_set_channel_subbuf_num(const char *name, const char *channel, + unsigned subbuf_num); +int lttctl_set_channel_subbuf_size(const char *name, const char *channel, + unsigned subbuf_size); + +/* Helper functions */ +int getdebugfsmntdir(char *mntdir); + +#endif /*_LIBLTT_H */ diff --git a/lttctl/Makefile.am b/lttctl/Makefile.am new file mode 100644 index 0000000..12ad501 --- /dev/null +++ b/lttctl/Makefile.am @@ -0,0 +1,53 @@ +## Process this file with automake to produce Makefile.in + +AM_CFLAGS = -DPACKAGE_DATA_DIR=\""$(datadir)"\" -DPACKAGE_BIN_DIR=\""$(bindir)"\" + +bin_PROGRAMS = lttctl +bin_SCRIPTS = ltt-armall ltt-disarmall ltt-armalluser ltt-disarmalluser \ + ltt-armtap ltt-disarmtap +CLEANFILES = $(bin_SCRIPTS) +EXTRA_DIST = ltt-armall.sh ltt-disarmall.sh \ + ltt-armalluser.sh ltt-disarmalluser.sh \ + ltt-armtap.sh ltt-disarmtap.sh + +ltt-armall: ltt-armall.sh + rm -f ltt-armall + echo "#!"$(BASH) > ltt-armall + cat $(srcdir)/ltt-armall.sh >> ltt-armall + chmod ugo+x ltt-armall + +ltt-disarmall: ltt-disarmall.sh + rm -f ltt-disarmall + echo "#!"$(BASH) > ltt-disarmall + cat $(srcdir)/ltt-disarmall.sh >> ltt-disarmall + chmod ugo+x ltt-disarmall + +ltt-armtap: ltt-armtap.sh + rm -f ltt-armtap + echo "#!"$(BASH) > ltt-armtap + cat $(srcdir)/ltt-armtap.sh >> ltt-armtap + chmod ugo+x ltt-armtap + +ltt-disarmtap: ltt-disarmtap.sh + rm -f ltt-disarmtap + echo "#!"$(BASH) > ltt-disarmtap + cat $(srcdir)/ltt-disarmtap.sh >> ltt-disarmtap + chmod ugo+x ltt-disarmtap + +ltt-armalluser: ltt-armalluser.sh + rm -f ltt-armalluser + echo "#!"$(BASH) > ltt-armalluser + cat $(srcdir)/ltt-armalluser.sh >> ltt-armalluser + chmod ugo+x ltt-armalluser + +ltt-disarmalluser: ltt-disarmalluser.sh + rm -f ltt-disarmalluser + echo "#!"$(BASH) > ltt-disarmalluser + cat $(srcdir)/ltt-disarmalluser.sh >> ltt-disarmalluser + chmod ugo+x ltt-disarmalluser + +lttctl_SOURCES = \ + lttctl.c +lttctl_DEPENDENCIES = ../liblttctl/liblttctl.la +lttctl_LDADD = $(lttctl_DEPENDENCIES) + diff --git a/lttctl/ltt-armall.sh b/lttctl/ltt-armall.sh new file mode 100755 index 0000000..f0824c8 --- /dev/null +++ b/lttctl/ltt-armall.sh @@ -0,0 +1,47 @@ +#excluding core markers (already connected) +#excluding locking markers (high traffic) + +DEBUGFSROOT=$(grep ^debugfs /proc/mounts | head -1 | awk '{print $2}') +MARKERSROOT=${DEBUGFSROOT}/ltt/markers + +echo Connecting all markers + +for c in ${MARKERSROOT}/*; do + case ${c} in + ${MARKERSROOT}/metadata) + ;; + ${MARKERSROOT}/locking) + ;; + ${MARKERSROOT}/lockdep) + ;; + *) + for m in ${c}/*; do + echo Connecting ${m} + echo 1 > ${m}/enable + done + ;; + esac +done + + +# Connect the interesting high-speed markers to the marker tap. +# Markers starting with "tap_" are considered high-speed. +#echo Connecting high-rate markers to tap +#MARKERS=`cat /proc/ltt|grep -v %k|awk '{print $2}'|sort -u |grep ^tap_` +# +##Uncomment the following to also record lockdep events. +##MARKERS=`cat /proc/ltt|grep -v %k|awk '{print $2}'|sort -u|grep -e ^tap_ -e ^lockdep` +# +#IFS=${N} +#for a in $MARKERS; do +# echo Connecting $a +# +# #redirect markers carrying state information to dedicated channels +# case $a in +# *) +# CHANNEL= +# ;; +# esac +# +# echo "connect $a ltt_tap_marker" > /proc/ltt +#done diff --git a/lttctl/ltt-armalluser.sh b/lttctl/ltt-armalluser.sh new file mode 100755 index 0000000..290e360 --- /dev/null +++ b/lttctl/ltt-armalluser.sh @@ -0,0 +1,18 @@ +#excluding core markers (already connected) +#excluding locking markers (high traffic) + +echo Connecting all userspace markers of _CURRENTLY RUNNING_ processes only ! +echo All the markers listed here will also automatically be enabled if +echo present in a newly created process. + +for a in /proc/[0-9]*; do + for marker in `cat $a/markers | awk '{print $2}'`; do + echo Connecting marker $a:$marker + case $marker in + *) + CHANNEL= + ;; + esac + echo "connect $marker default dynamic $CHANNEL" > /proc/ltt + done +done diff --git a/lttctl/ltt-armtap.sh b/lttctl/ltt-armtap.sh new file mode 100755 index 0000000..84f91d6 --- /dev/null +++ b/lttctl/ltt-armtap.sh @@ -0,0 +1,34 @@ +# This script will enable the system-wide tap on the given list of events passed +# as parameter, and stop the tap at each other "normal rate" events. + +#excluding core markers (already connected) +#excluding locking markers (high traffic) + +echo Connecting function markers + +# interesting period starts with the list of events passed as parameter. +START_FTRACE=$* + +# interesting period may stop with one specific event, but also try to keep the +# other START_FTRACE events triggers to the lowest possible overhead by stopping +# function trace at every other events. +# Do _not_ disable function tracing in ftrace_entry event unless you really only +# want the first function entry... +STOP_FTRACE=`cat /proc/ltt|grep -v %k|awk '{print $2}'|sort -u|grep -v ^core_|grep -v ^locking_|grep -v ^lockdep|grep -v ftrace_entry|grep -v ^tap_` + +for a in $START_FTRACE; do + STOP_FTRACE=`echo $STOP_FTRACE|sed 's/$a//'` +done + + +for a in $STOP_FTRACE; do + echo Connecting stop $a + echo "connect $a ftrace_system_stop" > /proc/ltt +done + +for a in $START_FTRACE; do + echo Connecting start $a + echo "connect $a ftrace_system_start" > /proc/ltt +done + + diff --git a/lttctl/ltt-disarmall.sh b/lttctl/ltt-disarmall.sh new file mode 100755 index 0000000..2473b81 --- /dev/null +++ b/lttctl/ltt-disarmall.sh @@ -0,0 +1,38 @@ +#excluding core markers (already connected) +#excluding locking markers (high traffic) + +DEBUGFSROOT=$(grep ^debugfs /proc/mounts | head -1 | awk '{print $2}') +MARKERSROOT=${DEBUGFSROOT}/ltt/markers + +echo Disconnecting all markers + +for c in ${MARKERSROOT}/*; do + case ${c} in + ${MARKERSROOT}/metadata) + ;; + ${MARKERSROOT}/locking) + ;; + ${MARKERSROOT}/lockdep) + ;; + *) + for m in ${c}/*; do + echo Disconnecting ${m} + echo 0 > ${m}/enable + done + ;; + esac +done + +## Markers starting with "tap_" are considered high-speed. +#echo Disconnecting high-rate markers to tap +#MARKERS=`cat /proc/ltt|grep -v %k|awk '{print $2 " " $4}'|sort -u |grep ^tap` +# +##Uncomment the following to also stop recording lockdep events. +##MARKERS=`cat /proc/ltt|grep -v %k|awk '{print $2}'|sort -u|grep -e ^tap_ -e ^lockdep` +# +#IFS=${N} +#for a in $MARKERS; do +# echo Disconnecting $a +# +# echo "disconnect $a ltt_tap_marker" > /proc/ltt +#done diff --git a/lttctl/ltt-disarmalluser.sh b/lttctl/ltt-disarmalluser.sh new file mode 100755 index 0000000..0d0f1eb --- /dev/null +++ b/lttctl/ltt-disarmalluser.sh @@ -0,0 +1,16 @@ +#excluding core markers (already connected) +#excluding locking markers (high traffic) + +echo Disconnecting all userspace markers of _RUNNING PROCESSES_ only ! + +for a in /proc/[0-9]*; do + for marker in `cat $a/markers | awk '{print $2}'`; do + echo Disonnecting marker $a:$marker + case $marker in + *) + CHANNEL= + ;; + esac + echo "disconnect $marker default dynamic $CHANNEL" > /proc/ltt + done +done diff --git a/lttctl/ltt-disarmtap.sh b/lttctl/ltt-disarmtap.sh new file mode 100755 index 0000000..b41f70c --- /dev/null +++ b/lttctl/ltt-disarmtap.sh @@ -0,0 +1,33 @@ +# This script will disable the system-wide tap on the given list of events +# passed as parameter, and stop the tap at each other "normal rate" events. + +#excluding core markers (already connected) +#excluding locking markers (high traffic) + +echo Disconnecting function markers + +# interesting period starts with the list of events passed as parameter. +START_FTRACE=$* + +# interesting period may stop with one specific event, but also try to keep the +# other START_FTRACE events triggers to the lowest possible overhead by stopping +# function trace at every other events. +# Do _not_ disable function tracing in ftrace_entry event unless you really only +# want the first function entry... +STOP_FTRACE=`cat /proc/ltt|grep -v %k|awk '{print $2}'|sort -u|grep -v ^core_|grep -v ^locking_|grep -v ^lockdep|grep -v ftrace_entry|grep -v ^tap_` + +for a in $START_FTRACE; do + STOP_FTRACE=`echo $STOP_FTRACE|sed 's/$a//'` +done + +for a in $START_FTRACE; do + echo Disconnecting start $a + echo "disconnect $a ftrace_system_start" > /proc/ltt +done + +for a in $STOP_FTRACE; do + echo Disconnecting stop $a + echo "disconnect $a ftrace_system_stop" > /proc/ltt +done + + diff --git a/lttctl/lttctl.c b/lttctl/lttctl.c new file mode 100644 index 0000000..e08280a --- /dev/null +++ b/lttctl/lttctl.c @@ -0,0 +1,833 @@ +/* lttctl + * + * Linux Trace Toolkit Control + * + * Small program that controls LTT through libltt. + * + * Copyright 2005 - + * Mathieu Desnoyers + * + * Copyright 2008 FUJITSU + * Zhao Lei + * Gui Jianfeng + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#define _GNU_SOURCE +#include + +#define OPT_MAX (1024) +#define OPT_NAMELEN (256) +#define OPT_VALSTRINGLEN (256) + +enum opt_type { + CHANNEL, +}; + +struct channel_option { + char chan_name[OPT_NAMELEN]; + int enable; + int overwrite; + int bufnum; + int bufsize; +}; + +struct lttctl_option { + union { + struct channel_option chan_opt; + } opt_mode; + enum opt_type type; + struct lttctl_option *next; +}; + +struct lttctl_option *opt_head, *last_opt; + +static int opt_create; +static int opt_destroy; +static int opt_start; +static int opt_pause; +static int opt_help; +static const char *opt_transport; +static const char *opt_write; +static int opt_append; +static unsigned int opt_dump_threads; +static char channel_root_default[PATH_MAX]; +static const char *opt_channel_root; +static const char *opt_tracename; + +/* Args : + * + */ +static void show_arguments(void) +{ + printf("Linux Trace Toolkit Trace Control " VERSION"\n"); + printf("\n"); + printf("Usage: lttctl [OPTION]... [TRACENAME]\n"); + printf("\n"); + printf("Examples:\n"); + printf(" lttctl -c trace1 " + "# Create a trace named trace1.\n"); + printf(" lttctl -s trace1 " + "# start a trace named trace1.\n"); + printf(" lttctl -p trace1 " + "# pause a trace named trace1.\n"); + printf(" lttctl -d trace1 " + "# Destroy a trace named trace1.\n"); + printf(" lttctl -C -w /tmp/trace1 trace1 " + "# Create a trace named trace1, start it and\n" + " " + "# write non-overwrite channels' data to\n" + " " + "# /tmp/trace1, debugfs must be mounted for\n" + " " + "# auto-find\n"); + printf(" lttctl -D -w /tmp/trace1 trace1 " + "# Pause and destroy a trace named trace1 and\n" + " " + "# write overwrite channels' data to\n" + " " + "# /tmp/trace1, debugfs must be mounted for\n" + " " + "# auto-find\n"); + printf("\n"); + printf(" Basic options:\n"); + printf(" -c, --create\n"); + printf(" Create a trace.\n"); + printf(" -d, --destroy\n"); + printf(" Destroy a trace.\n"); + printf(" -s, --start\n"); + printf(" Start a trace.\n"); + printf(" -p, --pause\n"); + printf(" Pause a trace.\n"); + printf(" -h, --help\n"); + printf(" Show this help.\n"); + printf("\n"); + printf(" Advanced options:\n"); + printf(" --transport TRANSPORT\n"); + printf(" Set trace's transport. (ex. relay-locked or relay)\n"); + printf(" -o, --option OPTION\n"); + printf(" Set options, following operations are supported:\n"); + printf(" channel..enable=\n"); + printf(" channel..overwrite=\n"); + printf(" channel..bufnum=\n"); + printf(" channel..bufsize= (in bytes, rounded to " + "next power of 2)\n"); + printf(" can be set to all for all channels\n"); + printf("\n"); + printf(" Integration options:\n"); + printf(" -C, --create_start\n"); + printf(" Create and start a trace.\n"); + printf(" -D, --pause_destroy\n"); + printf(" Pause and destroy a trace.\n"); + printf(" -w, --write PATH\n"); + printf(" Path for write trace datas.\n"); + printf(" For -c, -C, -d, -D options\n"); + printf(" -a, --append\n"); + printf(" Append to trace, For -w option\n"); + printf(" -n, --dump_threads NUMBER\n"); + printf(" Number of lttd threads, For -w option\n"); + printf(" --channel_root PATH\n"); + printf(" Set channels root path, For -w option." + " (ex. /mnt/debugfs/ltt)\n"); + printf("\n"); +} + +/* + * Separate option name to 3 fields + * Ex: + * Input: name = channel.cpu.bufsize + * Output: name1 = channel + * name2 = cpu + * name3 = bufsize + * Ret: 0 on success + * 1 on fail + * + * Note: + * Make sure that name1~3 longer than OPT_NAMELEN. + * name1~3 can be NULL to discard value + * + */ +static int separate_opt(const char *name, char *name1, char *name2, char *name3) +{ + char *p; + + if (!name) + return 1; + + /* segment1 */ + p = strchr(name, '.'); + if (!p) + return 1; + if (p - name >= OPT_NAMELEN) + return 1; + if (name1) { + memcpy(name1, name, p - name); + name1[p - name] = 0; + } + name = p + 1; + + /* segment2 */ + p = strchr(name, '.'); + if (!p) + return 1; + if (p - name >= OPT_NAMELEN) + return 1; + if (name2) { + memcpy(name2, name, p - name); + name2[p - name] = 0; + } + name = p + 1; + + /* segment3 */ + if (strlen(name) >= OPT_NAMELEN) + return 1; + if (name3) + strcpy(name3, name); + + return 0; +} + +static void init_channel_opt(struct channel_option *opt, char *opt_name) +{ + if (opt && opt_name) { + opt->enable = -1; + opt->overwrite = -1; + opt->bufnum = -1; + opt->bufsize = -1; + strcpy(opt->chan_name, opt_name); + } +} + +static struct lttctl_option *find_insert_channel_opt(char *opt_name) +{ + struct lttctl_option *iter, *new_opt; + + if (!opt_head) { + opt_head = (struct lttctl_option *)malloc(sizeof(struct lttctl_option)); + init_channel_opt(&opt_head->opt_mode.chan_opt, opt_name); + opt_head->type = CHANNEL; + opt_head->next = NULL; + last_opt = opt_head; + return opt_head; + } + + for (iter = opt_head; iter; iter = iter->next) { + if (iter->type != CHANNEL) + continue; + if (!strcmp(iter->opt_mode.chan_opt.chan_name, opt_name)) + return iter; + } + + new_opt = (struct lttctl_option *)malloc(sizeof(struct lttctl_option)); + init_channel_opt(&new_opt->opt_mode.chan_opt, opt_name); + new_opt->type = CHANNEL; + new_opt->next = NULL; + last_opt->next = new_opt; + last_opt = new_opt; + return new_opt; +} + +int set_channel_opt(struct channel_option *opt, char *opt_name, char *opt_valstr) +{ + int opt_val, ret; + + if (!strcmp("enable", opt_name)) { + if (opt_valstr[1] != 0) { + return -EINVAL; + } + if (opt_valstr[0] == 'Y' || opt_valstr[0] == 'y' + || opt_valstr[0] == '1') + opt_val = 1; + else if (opt_valstr[0] == 'N' || opt_valstr[0] == 'n' + || opt_valstr[0] == '0') + opt_val = 0; + else { + return -EINVAL; + } + + opt->enable = opt_val; + return 0; + } else if (!strcmp("overwrite", opt_name)) { + if (opt_valstr[1] != 0) { + return -EINVAL; + } + if (opt_valstr[0] == 'Y' || opt_valstr[0] == 'y' + || opt_valstr[0] == '1') + opt_val = 1; + else if (opt_valstr[0] == 'N' || opt_valstr[0] == 'n' + || opt_valstr[0] == '0') + opt_val = 0; + else { + return -EINVAL; + } + + opt->overwrite = opt_val; + return 0; + + } else if (!strcmp("bufnum", opt_name)) { + ret = sscanf(opt_valstr, "%d", &opt_val); + if (ret != 1 || opt_val < 0) { + return -EINVAL; + } + + opt->bufnum = opt_val; + return 0; + } else if (!strcmp("bufsize", opt_name)) { + ret = sscanf(opt_valstr, "%d", &opt_val); + if (ret != 1 || opt_val < 0) { + return -EINVAL; + } + + opt->bufsize = opt_val; + return 0; + } else { + return -EINVAL; + } + +} + +static int parst_opt(const char *optarg) +{ + int ret; + char opt_name[OPT_NAMELEN * 3]; + char opt_valstr[OPT_VALSTRINGLEN]; + char *p; + + char name1[OPT_NAMELEN]; + char name2[OPT_NAMELEN]; + char name3[OPT_NAMELEN]; + + int opt_intval; + int opt_val; + unsigned int opt_uintval; + struct lttctl_option *opt; + + if (!optarg) { + fprintf(stderr, "Option empty\n"); + return -EINVAL; + } + + /* Get option name and val_str */ + p = strchr(optarg, '='); + if (!p) { + fprintf(stderr, "Option format error: %s\n", optarg); + return -EINVAL; + } + + if (p - optarg >= sizeof(opt_name)/sizeof(opt_name[0])) { + fprintf(stderr, "Option name too long: %s\n", optarg); + return -EINVAL; + } + + if (strlen(p+1) >= OPT_VALSTRINGLEN) { + fprintf(stderr, "Option value too long: %s\n", optarg); + return -EINVAL; + } + + memcpy(opt_name, optarg, p - optarg); + opt_name[p - optarg] = 0; + strcpy(opt_valstr, p+1); + + /* separate option name into 3 fields */ + ret = separate_opt(opt_name, name1, name2, name3); + if (ret != 0) { + fprintf(stderr, "Option name error1: %s\n", optarg); + return -EINVAL; + } + + if (!strcmp("channel", name1)) { + opt = find_insert_channel_opt(name2); + if ((ret = set_channel_opt(&opt->opt_mode.chan_opt, + name3, opt_valstr) != 0)) { + fprintf(stderr, "Option name error2: %s\n", optarg); + return ret; + } + } else { + fprintf(stderr, "Option name error3: %s\n", optarg); + return -EINVAL; + } + + return 0; +} + +/* parse_arguments + * + * Parses the command line arguments. + * + * Returns -1 if the arguments were correct, but doesn't ask for program + * continuation. Returns EINVAL if the arguments are incorrect, or 0 if OK. + */ +static int parse_arguments(int argc, char **argv) +{ + int ret = 0; + + static struct option longopts[] = { + {"create", no_argument, NULL, 'c'}, + {"destroy", no_argument, NULL, 'd'}, + {"start", no_argument, NULL, 's'}, + {"pause", no_argument, NULL, 'p'}, + {"help", no_argument, NULL, 'h'}, + {"transport", required_argument, NULL, 2}, + {"option", required_argument, NULL, 'o'}, + {"create_start", no_argument, NULL, 'C'}, + {"pause_destroy", no_argument, NULL, 'D'}, + {"write", required_argument, NULL, 'w'}, + {"append", no_argument, NULL, 'a'}, + {"dump_threads", required_argument, NULL, 'n'}, + {"channel_root", required_argument, NULL, 3}, + { NULL, 0, NULL, 0 }, + }; + + /* + * Enable all channels in default + * To make novice users happy + */ + parst_opt("channel.all.enable=1"); + + opterr = 1; /* Print error message on getopt_long */ + while (1) { + int c; + c = getopt_long(argc, argv, "cdspho:CDw:an:", longopts, NULL); + if (-1 == c) { + /* parse end */ + break; + } + switch (c) { + case 'c': + opt_create = 1; + break; + case 'd': + opt_destroy = 1; + break; + case 's': + opt_start = 1; + break; + case 'p': + opt_pause = 1; + break; + case 'h': + opt_help = 1; + break; + case 2: + if (!opt_transport) { + opt_transport = optarg; + } else { + fprintf(stderr, + "Please specify only 1 transport\n"); + return -EINVAL; + } + break; + case 'o': + ret = parst_opt(optarg); + if (ret) + return ret; + break; + case 'C': + opt_create = 1; + opt_start = 1; + break; + case 'D': + opt_pause = 1; + opt_destroy = 1; + break; + case 'w': + if (!opt_write) { + opt_write = optarg; + } else { + fprintf(stderr, + "Please specify only 1 write dir\n"); + return -EINVAL; + } + break; + case 'a': + opt_append = 1; + break; + case 'n': + if (opt_dump_threads) { + fprintf(stderr, + "Please specify only 1 dump threads\n"); + return -EINVAL; + } + + ret = sscanf(optarg, "%u", &opt_dump_threads); + if (ret != 1) { + fprintf(stderr, + "Dump threads not positive number\n"); + return -EINVAL; + } + break; + case 3: + if (!opt_channel_root) { + opt_channel_root = optarg; + } else { + fprintf(stderr, + "Please specify only 1 channel root\n"); + return -EINVAL; + } + break; + case '?': + return -EINVAL; + default: + break; + }; + }; + + /* Don't check args when user needs help */ + if (opt_help) + return 0; + + /* Get tracename */ + if (optind < argc - 1) { + fprintf(stderr, "Please specify only 1 trace name\n"); + return -EINVAL; + } + if (optind > argc - 1) { + fprintf(stderr, "Please specify trace name\n"); + return -EINVAL; + } + opt_tracename = argv[optind]; + + /* + * Check arguments + */ + if (!opt_create && !opt_start && !opt_destroy && !opt_pause) { + fprintf(stderr, + "Please specify a option of " + "create, destroy, start, or pause\n"); + return -EINVAL; + } + + if ((opt_create || opt_start) && (opt_destroy || opt_pause)) { + fprintf(stderr, + "Create and start conflict with destroy and pause\n"); + return -EINVAL; + } + + if (opt_create) { + if (!opt_transport) + opt_transport = "relay"; + } + + if (opt_transport) { + if (!opt_create) { + fprintf(stderr, + "Transport option must be combine with create" + " option\n"); + return -EINVAL; + } + } + + if (opt_write) { + if (!opt_create && !opt_destroy) { + fprintf(stderr, + "Write option must be combine with create or" + " destroy option\n"); + return -EINVAL; + } + + if (!opt_channel_root) + if (getdebugfsmntdir(channel_root_default) == 0) { + strcat(channel_root_default, "/ltt"); + opt_channel_root = channel_root_default; + } else { + fprintf(stderr, + "Channel_root is necessary for -w" + " option, but neither --channel_root" + " option\n" + "specified, nor debugfs's mount dir" + " found, mount debugfs also failed\n"); + return -EINVAL; + } + + if (opt_dump_threads == 0) + opt_dump_threads = 1; + } + + if (opt_append) { + if (!opt_write) { + fprintf(stderr, + "Append option must be combine with write" + " option\n"); + return -EINVAL; + } + } + + if (opt_dump_threads) { + if (!opt_write) { + fprintf(stderr, + "Dump_threads option must be combine with write" + " option\n"); + return -EINVAL; + } + } + + if (opt_channel_root) { + if (!opt_write) { + fprintf(stderr, + "Channel_root option must be combine with write" + " option\n"); + return -EINVAL; + } + } + + return 0; +} + +static void show_info(void) +{ + printf("Linux Trace Toolkit Trace Control " VERSION"\n"); + printf("\n"); + if (opt_tracename != NULL) { + printf("Controlling trace : %s\n", opt_tracename); + printf("\n"); + } +} + +static int lttctl_channel_setup(struct channel_option *opt) +{ + int ret; + + if (opt->enable != -1) { + if ((ret = lttctl_set_channel_enable(opt_tracename, + opt->chan_name, + opt->enable)) != 0) + return ret; + } + if (opt->overwrite != -1) { + if ((ret = lttctl_set_channel_overwrite(opt_tracename, + opt->chan_name, + opt->overwrite)) != 0) + return ret; + } + if (opt->bufnum != -1) { + if ((ret = lttctl_set_channel_subbuf_num(opt_tracename, + opt->chan_name, + opt->bufnum)) != 0) + return ret; + } + if (opt->bufsize != -1) { + if ((ret = lttctl_set_channel_subbuf_size(opt_tracename, + opt->chan_name, + opt->bufsize)) != 0) + return ret; + } + + return 0; +} + +static int lttctl_create_trace(void) +{ + int ret; + int i; + struct lttctl_option *opt; + + ret = lttctl_setup_trace(opt_tracename); + if (ret) + goto setup_trace_fail; + + for (opt = opt_head; opt; opt = opt->next) { + if (opt->type != CHANNEL) + continue; + ret = lttctl_channel_setup(&opt->opt_mode.chan_opt); + if (ret) + goto set_option_fail;; + } + + ret = lttctl_set_trans(opt_tracename, opt_transport); + if (ret) + goto set_option_fail; + + ret = lttctl_alloc_trace(opt_tracename); + if (ret) + goto alloc_trace_fail; + + return 0; + +alloc_trace_fail: +set_option_fail: + lttctl_destroy_trace(opt_tracename); +setup_trace_fail: + return ret; +} + +/* + * Start a lttd daemon to write trace datas + * Dump overwrite channels on overwrite!=0 + * Dump normal(non-overwrite) channels on overwrite=0 + * + * ret: 0 on success + * !0 on fail + */ +static int lttctl_daemon(int overwrite) +{ + pid_t pid; + int status; + + pid = fork(); + if (pid < 0) { + perror("Error in forking for lttd daemon"); + return errno; + } + + if (pid == 0) { + /* child */ + char *argv[16]; + int argc = 0; + char channel_path[PATH_MAX]; + char thread_num[16]; + + /* prog path */ + argv[argc] = getenv("LTT_DAEMON"); + if (argv[argc] == NULL) + argv[argc] = PACKAGE_BIN_DIR "/lttd"; + argc++; + + /* -t option */ + argv[argc] = "-t"; + argc++; + /* + * we allow modify of opt_write's content in new process + * for get rid of warning of assign char * to const char * + */ + argv[argc] = (char *)opt_write; + argc++; + + /* -c option */ + strcpy(channel_path, opt_channel_root); + strcat(channel_path, "/"); + strcat(channel_path, opt_tracename); + argv[argc] = "-c"; + argc++; + argv[argc] = channel_path; + argc++; + + /* -N option */ + sprintf(thread_num, "%u", opt_dump_threads); + argv[argc] = "-N"; + argc++; + argv[argc] = thread_num; + argc++; + + /* -a option */ + if (opt_append) { + argv[argc] = "-a"; + argc++; + } + + /* -d option */ + argv[argc] = "-d"; + argc++; + + /* overwrite option */ + if (overwrite) { + argv[argc] = "-f"; + argc++; + } else { + argv[argc] = "-n"; + argc++; + } + + argv[argc] = NULL; + + execvp(argv[0], argv); + + perror("Error in executing the lttd daemon"); + exit(errno); + } + + /* parent */ + if (waitpid(pid, &status, 0) == -1) { + perror("Error in waitpid\n"); + return errno; + } + + if (!WIFEXITED(status)) { + fprintf(stderr, "lttd process interrupted\n"); + return status; + } + + if (WEXITSTATUS(status)) + fprintf(stderr, "lttd process running failed\n"); + + return WEXITSTATUS(status); +} + +int main(int argc, char **argv) +{ + int ret; + + ret = parse_arguments(argc, argv); + /* If user needs show help, we disregard other options */ + if (opt_help) { + show_arguments(); + return 0; + } + + /* exit program if arguments wrong */ + if (ret) + return 1; + + show_info(); + + ret = lttctl_init(); + if (ret != 0) + return ret; + + if (opt_create) { + printf("lttctl: Creating trace\n"); + ret = lttctl_create_trace(); + if (ret) + goto op_fail; + + if (opt_write) { + printf("lttctl: Forking lttd\n"); + ret = lttctl_daemon(0); + if (ret) + goto op_fail; + } + } + + if (opt_start) { + printf("lttctl: Starting trace\n"); + ret = lttctl_start(opt_tracename); + if (ret) + goto op_fail; + } + + if (opt_pause) { + printf("lttctl: Pausing trace\n"); + ret = lttctl_pause(opt_tracename); + if (ret) + goto op_fail; + } + + if (opt_destroy) { + if (opt_write) { + printf("lttctl: Forking lttd\n"); + ret = lttctl_daemon(1); + if (ret) + goto op_fail; + } + + printf("lttctl: Destroying trace\n"); + ret = lttctl_destroy_trace(opt_tracename); + if (ret) + goto op_fail; + } + +op_fail: + lttctl_destroy(); + + return ret; +} diff --git a/lttctl/lttctl_distributed.sh b/lttctl/lttctl_distributed.sh new file mode 100644 index 0000000..4e75182 --- /dev/null +++ b/lttctl/lttctl_distributed.sh @@ -0,0 +1,293 @@ +#!/bin/bash +# Copyright (C) 2006 Eric Clément +# +# 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. +# +# 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. +# +# purpose : automatic generation of traces with LTT in a network. +# usage : +# +# you need SSH connection without password for all computers that you want +# trace. You might put le name of those computers (uname -n) in a file +# (liste.txt by default). LTT might be installed in the same way for those +# computer. +# You can customize your path. This script can also generate traffic TCP and +# UDP. A UDP monitor is use to validate the result (this is the first computer +# in the file (liste.txt)). +# +# usage: ./lttclt_distributed.sh time freq mode_generator {options} +# +# time (seconds) : duration a the tracing +# freq (nb packet/second or nb packet/ms) : communication frequency when TCP +# generator is used, 0 otherwise +# mode_generator : 1 : traffic generator off +# 2 : traffic generator TCP on (nb packet/second) +# 3 : traffic generator TCP on (nb packet/ms) +# +# options (optional): 1 : enable the UDP monitor (1packet/second is generated +# by all UDP client) +# +# you need : ssh, scp and zip + +TCP_SERVER=tcpserver +TCP_CLIENT=tcpclient + +UDP_SERVER=udpserver +UDP_CLIENT=udpclient + +PATH_TRACE=/root/trace-ltt/ +PATH_DEBUGFS=/debugfs/ltt/ +SET_LTT_FACILITIES="export LTT_FACILITIES=/home/ercle/NEW_GENERATION_LTTV/share/LinuxTraceToolkitViewer/facilities/" +SET_LTT_DAEMON="export LTT_DAEMON=/home/ercle/NEW_GENERATION_LTTV/bin/lttd" + +START_DAEMON="/home/ercle/NEW_GENERATION_LTTV/bin/lttctl -d -n \ +trace1 -t $PATH_TRACE -l $PATH_DEBUGFS >/dev/null" + +STOP_DAEMON="/home/ercle/NEW_GENERATION_LTTV/bin/lttctl -n trace1 -q >/dev/null" +REMOVE_DAEMON="/home/ercle/NEW_GENERATION_LTTV/bin/lttctl -n trace1 -r >/dev/null" +REMOVE_TRACE="rm -rf $PATH_TRACE" + +E_FNEXIST=100 + +FILE_LISTE=liste.txt +TRACE_DAEMON=/tmp/daemon- + +if [ $# -lt 3 ] +then + echo "usage: $0 time freq mode_generator {options}" + exit 1 +elif [ $# -gt 4 ] +then + echo "usage: $0 time freq mode_generator {options}" + exit 1 +fi + +if [ -e $FILE_LISTE ] +then + + time=$1 + freq=$2 + mode_generator=$3 + if [ $# -eq 4 ] + then + mode_monitor=$4 + else + mode_monitor=0 + fi + +#create script generator + FILE_OUT=daemon- + + if [ $mode_generator -eq 3 ] + then + TCP_CLIENT=tcpclient_ms + fi + + nb_node=0 + for line in $( cat $FILE_LISTE ); + do + let nb_node+=1 + + echo $REMOVE_TRACE > "$FILE_OUT$line.sh" + echo mkdir $PATH_TRACE >> "$FILE_OUT$line.sh" + echo $SET_LTT_FACILITIES >> "$FILE_OUT$line.sh" + echo $SET_LTT_DAEMON >> "$FILE_OUT$line.sh" + echo $START_DAEMON >> "$FILE_OUT$line.sh" + + chmod +x "$FILE_OUT$line.sh" + + if [ $mode_generator -ge 2 ] #if generator de trafic enable (2 or 3) + then + if [ $nb_node -eq 1 -a $mode_monitor -eq 1 ] + then + monitor=$line + echo "/tmp/$UDP_SERVER >/dev/null &" >> "$FILE_OUT$line.sh" + scp "$UDP_SERVER" $line:/tmp/ + + echo "sleep $time" >> "$FILE_OUT$line.sh" + echo "kill \`ps -A |grep $UDP_SERVER | awk '{ print \$1 }'\`" >> "$FILE_OUT$line.sh" + else + if [ $mode_monitor -eq 1 ] + then + echo "/tmp/$UDP_CLIENT $monitor $time 1 >/dev/null & " >> "$FILE_OUT$line.sh" + scp "$UDP_CLIENT" $line:/tmp/ + fi + + echo "/tmp/$TCP_SERVER >/dev/null &" >> "$FILE_OUT$line.sh" + scp "$TCP_SERVER" $line:/tmp/ + compteur=0 + for line2 in $( cat $FILE_LISTE ); + do + let compteur+=1 + if [ $compteur -gt $nb_node ] + then + echo "/tmp/$TCP_CLIENT $line2 $time $freq >/dev/null &" >> "$FILE_OUT$line.sh" + scp "$TCP_CLIENT" $line:/tmp/ + fi + done + + echo "sleep $time" >> "$FILE_OUT$line.sh" + echo "kill \`ps -A |grep $TCP_SERVER | awk '{ print \$1 }'\`" >> "$FILE_OUT$line.sh" + fi + fi + + echo $STOP_DAEMON >> "$FILE_OUT$line.sh" + echo $REMOVE_DAEMON >> "$FILE_OUT$line.sh" + + #script for get node information + ENDIAN=endian + echo 'FILE_OUT=`uname -n`.info' >> "$FILE_OUT$line.sh" + echo 'ENDIAN=endian' >> "$FILE_OUT$line.sh" + echo ' exec 6>&1' >> "$FILE_OUT$line.sh" + echo ' exec > /tmp/$FILE_OUT' >> "$FILE_OUT$line.sh" + echo ' echo `uname -n`' >> "$FILE_OUT$line.sh" + echo '' >> "$FILE_OUT$line.sh" + echo ' /tmp/$ENDIAN || ( echo >&6 && echo "** ERROR **: problem occur with /tmp/$ENDIAN" >&6 && echo >&6)' >> "$FILE_OUT$line.sh" + echo '' >> "$FILE_OUT$line.sh" + echo -e ' /sbin/ifconfig | grep addr: | awk \047{print $2}\047 | sed /127.0.0.1/d | sed s/addr:// | sed /^$/d #english' >> "$FILE_OUT$line.sh" + echo -e ' /sbin/ifconfig | grep adr: | awk \047{print $2}\047 | sed /127.0.0.1/d | sed s/adr:// | sed /^$/d #french' >> "$FILE_OUT$line.sh" + echo ' echo END' >> "$FILE_OUT$line.sh" + echo '' >> "$FILE_OUT$line.sh" + echo ' exec 1>&6 6>&-' >> "$FILE_OUT$line.sh" + echo '' >> "$FILE_OUT$line.sh" + echo ' echo "$FILE_OUT done"' >> "$FILE_OUT$line.sh" + echo '' >> "$FILE_OUT$line.sh" + + #send files + if [ $mode_generator -ge 2 -a $nb_node -eq 1 -a $mode_monitor -eq 1 ] + then + echo mv /tmp/'`uname -n`'.info /tmp/'`uname -n`'.monitor >> "$FILE_OUT$line.sh" + echo scp /tmp/'`uname -n`'.monitor `uname -n`:`pwd`/ >> "$FILE_OUT$line.sh" + else + echo scp /tmp/'`uname -n`'.info `uname -n`:`pwd`/ >> "$FILE_OUT$line.sh" + fi + + echo ' exit 0' >> "$FILE_OUT$line.sh" + + scp "$FILE_OUT$line.sh" $line:/tmp/ + scp "$ENDIAN" $line:/tmp/ + rm "$FILE_OUT$line.sh" + done +#end script generator + +#start traces !! + sleep 1 + + for line in $( cat $FILE_LISTE ); + do + echo ssh -f "$line $TRACE_DAEMON$line.sh " + ssh -f $line "$TRACE_DAEMON$line.sh" + done + +else + echo "error: file $FILE_LISTE doesn't exist" + exit E_FNEXIST +fi + +date + +sleep $time + +# is all daemon stop ? +for line in $( cat $FILE_LISTE ); + do + + daemon_present="true" + wait_time=1 + while [ $daemon_present == "true" ] + do + daemon_present="false" + (ssh $line ps -A |grep lttd) && daemon_present="true" + sleep $wait_time + let wait_time+=1 + done + done + +#get all traces +nb_computer=0 +zip_path="" +for line in $( cat $FILE_LISTE ); + do + mkdir `pwd`/$line 2>/dev/null + scp -q -r $line:$PATH_TRACE/ `pwd`/$line + zip_path="$zip_path $line" + let nb_computer+=1 + done + +#get network informatioin +FILE_TMP=ls.tmp +FILE_OUT=network.trace + +exec 3> $FILE_TMP #open FILE_TMP (Write) + +ls *.monitor >&3 2>/dev/null + +#get the list of .info file to parse +ls *.info >&3 || (echo EMPTY >&3) +echo END >&3 + +exec 3>&- #close FILE_TMP + +exec 3< $FILE_TMP #open FILE_TMP (Read) +read line <&3 +if [ "$line" = "EMPTY" ] +then + echo "NO .info file" + exec 3>&- #close FILE_TMP + rm -rf $FILE_TMP + exit 1 +fi + +exec 5> $FILE_OUT #open FILE_OUT (Write) + +echo -e "Nb IP\tName\t\endianness\tIP ..." +echo -e "Nb IP\tName\tendianness\tIP ..." >&5 + +while [ "$line" != "END" ] +do + echo "++++++++++++++++++++" + echo "in file $line" + + output="" + nb_ip=-2 #1st line => name, 2 line => endianness + exec 4< $line + read answer <&4 + + while [ "$answer" != "END" ] + do + nb_ip=`expr $nb_ip + 1` + output="$output\n$answer" + read answer <&4 + done + + echo -e "$nb_ip$output" + echo -e "$nb_ip$output" >&5 + exec 4<&- + mv $line "$line.read" + read line <&3 + echo "---------------------" +done + +exec 3>&- #close FILE_TMP +rm -rf $FILE_TMP +echo END >&5 +exec 5<&- #close FILE_OUT + +#zip files + root=`pwd` + cd $root && echo $root + nomfic="trace__nb_computer"$nb_computer"__time"$time"__freq"$freq"__"`uname -n``date '+__%d%b__%H-%M-%S'`$options".zip" + + zip -r $nomfic $zip_path *.info.read *.monitor.read *.trace>/dev/null + echo -e "zip done $zip_path\n$root/$nomfic" + + exec 3<&- + +echo -e "\a$0 done!" +exit 0 diff --git a/lttd/Makefile.am b/lttd/Makefile.am new file mode 100644 index 0000000..bb860bc --- /dev/null +++ b/lttd/Makefile.am @@ -0,0 +1,8 @@ +# Empty TraceDaemon Makefile.am. Insert a real one here. + +LIBS += $(THREAD_LIBS) + +bin_PROGRAMS = lttd + +lttd_SOURCES = lttd.c + diff --git a/lttd/lttd.c b/lttd/lttd.c new file mode 100644 index 0000000..f21c411 --- /dev/null +++ b/lttd/lttd.c @@ -0,0 +1,1012 @@ +/* lttd + * + * Linux Trace Toolkit Daemon + * + * This is a simple daemon that reads a few relay+debugfs channels and save + * them in a trace. + * + * CPU hot-plugging is supported using inotify. + * + * Copyright 2005 - + * Mathieu Desnoyers + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#define _REENTRANT +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* Relayfs IOCTL */ +#include +#include + +/* Get the next sub buffer that can be read. */ +#define RELAY_GET_SUBBUF _IOR(0xF5, 0x00,__u32) +/* Release the oldest reserved (by "get") sub buffer. */ +#define RELAY_PUT_SUBBUF _IOW(0xF5, 0x01,__u32) +/* returns the number of sub buffers in the per cpu channel. */ +#define RELAY_GET_N_SUBBUFS _IOR(0xF5, 0x02,__u32) +/* returns the size of the sub buffers. */ +#define RELAY_GET_SUBBUF_SIZE _IOR(0xF5, 0x03,__u32) + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14) +#include +#if 0 /* should now be provided by libc. */ +/* From the inotify-tools 2.6 package */ +static inline int inotify_init (void) +{ + return syscall (__NR_inotify_init); +} + +static inline int inotify_add_watch (int fd, const char *name, __u32 mask) +{ + return syscall (__NR_inotify_add_watch, fd, name, mask); +} + +static inline int inotify_rm_watch (int fd, __u32 wd) +{ + return syscall (__NR_inotify_rm_watch, fd, wd); +} +#endif //0 +#define HAS_INOTIFY +#else +static inline int inotify_init (void) +{ + return -1; +} + +static inline int inotify_add_watch (int fd, const char *name, __u32 mask) +{ + return 0; +} + +static inline int inotify_rm_watch (int fd, __u32 wd) +{ + return 0; +} +#undef HAS_INOTIFY +#endif + +enum { + GET_SUBBUF, + PUT_SUBBUF, + GET_N_BUBBUFS, + GET_SUBBUF_SIZE +}; + +struct fd_pair { + int channel; + int trace; + unsigned int n_subbufs; + unsigned int subbuf_size; + void *mmap; + pthread_mutex_t mutex; +}; + +struct channel_trace_fd { + struct fd_pair *pair; + int num_pairs; +}; + +struct inotify_watch { + int wd; + char path_channel[PATH_MAX]; + char path_trace[PATH_MAX]; +}; + +struct inotify_watch_array { + struct inotify_watch *elem; + int num; +}; + +static __thread int thread_pipe[2]; + +struct channel_trace_fd fd_pairs = { NULL, 0 }; +int inotify_fd = -1; +struct inotify_watch_array inotify_watch_array = { NULL, 0 }; + +/* protects fd_pairs and inotify_watch_array */ +pthread_rwlock_t fd_pairs_lock = PTHREAD_RWLOCK_INITIALIZER; + + +static char *trace_name = NULL; +static char *channel_name = NULL; +static int daemon_mode = 0; +static int append_mode = 0; +static unsigned long num_threads = 1; +volatile static int quit_program = 0; /* For signal handler */ +static int dump_flight_only = 0; +static int dump_normal_only = 0; +static int verbose_mode = 0; + +#define printf_verbose(fmt, args...) \ + do { \ + if (verbose_mode) \ + printf(fmt, ##args); \ + } while (0) + +/* Args : + * + * -t directory Directory name of the trace to write to. Will be created. + * -c directory Root directory of the debugfs trace channels. + * -d Run in background (daemon). + * -a Trace append mode. + * -s Send SIGUSR1 to parent when ready for IO. + */ +void show_arguments(void) +{ + printf("Please use the following arguments :\n"); + printf("\n"); + printf("-t directory Directory name of the trace to write to.\n" + " It will be created.\n"); + printf("-c directory Root directory of the debugfs trace channels.\n"); + printf("-d Run in background (daemon).\n"); + printf("-a Append to an possibly existing trace.\n"); + printf("-N Number of threads to start.\n"); + printf("-f Dump only flight recorder channels.\n"); + printf("-n Dump only normal channels.\n"); + printf("-v Verbose mode.\n"); + printf("\n"); +} + + +/* parse_arguments + * + * Parses the command line arguments. + * + * Returns 1 if the arguments were correct, but doesn't ask for program + * continuation. Returns -1 if the arguments are incorrect, or 0 if OK. + */ +int parse_arguments(int argc, char **argv) +{ + int ret = 0; + int argn = 1; + + if(argc == 2) { + if(strcmp(argv[1], "-h") == 0) { + return 1; + } + } + + while(argn < argc) { + + switch(argv[argn][0]) { + case '-': + switch(argv[argn][1]) { + case 't': + if(argn+1 < argc) { + trace_name = argv[argn+1]; + argn++; + } + break; + case 'c': + if(argn+1 < argc) { + channel_name = argv[argn+1]; + argn++; + } + break; + case 'd': + daemon_mode = 1; + break; + case 'a': + append_mode = 1; + break; + case 'N': + if(argn+1 < argc) { + num_threads = strtoul(argv[argn+1], NULL, 0); + argn++; + } + break; + case 'f': + dump_flight_only = 1; + break; + case 'n': + dump_normal_only = 1; + break; + case 'v': + verbose_mode = 1; + break; + default: + printf("Invalid argument '%s'.\n", argv[argn]); + printf("\n"); + ret = -1; + } + break; + default: + printf("Invalid argument '%s'.\n", argv[argn]); + printf("\n"); + ret = -1; + } + argn++; + } + + if(trace_name == NULL) { + printf("Please specify a trace name.\n"); + printf("\n"); + ret = -1; + } + + if(channel_name == NULL) { + printf("Please specify a channel name.\n"); + printf("\n"); + ret = -1; + } + + return ret; +} + +void show_info(void) +{ + printf("Linux Trace Toolkit Trace Daemon " VERSION "\n"); + printf("\n"); + printf("Reading from debugfs directory : %s\n", channel_name); + printf("Writing to trace directory : %s\n", trace_name); + printf("\n"); +} + + +/* signal handling */ + +static void handler(int signo) +{ + printf("Signal %d received : exiting cleanly\n", signo); + quit_program = 1; +} + + +int open_buffer_file(char *filename, char *path_channel, char *path_trace, + struct channel_trace_fd *fd_pairs) +{ + int open_ret = 0; + int ret = 0; + struct stat stat_buf; + + if(strncmp(filename, "flight-", sizeof("flight-")-1) != 0) { + if(dump_flight_only) { + printf_verbose("Skipping normal channel %s\n", + path_channel); + return 0; + } + } else { + if(dump_normal_only) { + printf_verbose("Skipping flight channel %s\n", + path_channel); + return 0; + } + } + printf_verbose("Opening file.\n"); + + fd_pairs->pair = realloc(fd_pairs->pair, + ++fd_pairs->num_pairs * sizeof(struct fd_pair)); + + /* Open the channel in read mode */ + fd_pairs->pair[fd_pairs->num_pairs-1].channel = + open(path_channel, O_RDONLY | O_NONBLOCK); + if(fd_pairs->pair[fd_pairs->num_pairs-1].channel == -1) { + perror(path_channel); + fd_pairs->num_pairs--; + return 0; /* continue */ + } + /* Open the trace in write mode, only append if append_mode */ + ret = stat(path_trace, &stat_buf); + if(ret == 0) { + if(append_mode) { + printf_verbose("Appending to file %s as requested\n", + path_trace); + + fd_pairs->pair[fd_pairs->num_pairs-1].trace = + open(path_trace, O_WRONLY, + S_IRWXU|S_IRWXG|S_IRWXO); + if(fd_pairs->pair[fd_pairs->num_pairs-1].trace == -1) { + perror(path_trace); + } + ret = lseek(fd_pairs->pair[fd_pairs->num_pairs-1].trace, + 0, SEEK_END); + if (ret < 0) { + perror(path_trace); + } + } else { + printf("File %s exists, cannot open. Try append mode.\n", path_trace); + open_ret = -1; + goto end; + } + } else { + if(errno == ENOENT) { + fd_pairs->pair[fd_pairs->num_pairs-1].trace = + open(path_trace, O_WRONLY|O_CREAT|O_EXCL, + S_IRWXU|S_IRWXG|S_IRWXO); + if(fd_pairs->pair[fd_pairs->num_pairs-1].trace == -1) { + perror(path_trace); + } + } + } +end: + return open_ret; +} + +int open_channel_trace_pairs(char *subchannel_name, char *subtrace_name, + struct channel_trace_fd *fd_pairs, int *inotify_fd, + struct inotify_watch_array *iwatch_array) +{ + DIR *channel_dir = opendir(subchannel_name); + struct dirent *entry; + struct stat stat_buf; + int ret; + char path_channel[PATH_MAX]; + int path_channel_len; + char *path_channel_ptr; + char path_trace[PATH_MAX]; + int path_trace_len; + char *path_trace_ptr; + int open_ret = 0; + + if(channel_dir == NULL) { + perror(subchannel_name); + open_ret = ENOENT; + goto end; + } + + printf_verbose("Creating trace subdirectory %s\n", subtrace_name); + ret = mkdir(subtrace_name, S_IRWXU|S_IRWXG|S_IRWXO); + if(ret == -1) { + if(errno != EEXIST) { + perror(subtrace_name); + open_ret = -1; + goto end; + } + } + + strncpy(path_channel, subchannel_name, PATH_MAX-1); + path_channel_len = strlen(path_channel); + path_channel[path_channel_len] = '/'; + path_channel_len++; + path_channel_ptr = path_channel + path_channel_len; + + strncpy(path_trace, subtrace_name, PATH_MAX-1); + path_trace_len = strlen(path_trace); + path_trace[path_trace_len] = '/'; + path_trace_len++; + path_trace_ptr = path_trace + path_trace_len; + +#ifdef HAS_INOTIFY + iwatch_array->elem = realloc(iwatch_array->elem, + ++iwatch_array->num * sizeof(struct inotify_watch)); + + printf_verbose("Adding inotify for channel %s\n", path_channel); + iwatch_array->elem[iwatch_array->num-1].wd = inotify_add_watch(*inotify_fd, path_channel, IN_CREATE); + strcpy(iwatch_array->elem[iwatch_array->num-1].path_channel, path_channel); + strcpy(iwatch_array->elem[iwatch_array->num-1].path_trace, path_trace); + printf_verbose("Added inotify for channel %s, wd %u\n", + iwatch_array->elem[iwatch_array->num-1].path_channel, + iwatch_array->elem[iwatch_array->num-1].wd); +#endif + + while((entry = readdir(channel_dir)) != NULL) { + + if(entry->d_name[0] == '.') continue; + + strncpy(path_channel_ptr, entry->d_name, PATH_MAX - path_channel_len); + strncpy(path_trace_ptr, entry->d_name, PATH_MAX - path_trace_len); + + ret = stat(path_channel, &stat_buf); + if(ret == -1) { + perror(path_channel); + continue; + } + + printf_verbose("Channel file : %s\n", path_channel); + + if(S_ISDIR(stat_buf.st_mode)) { + + printf_verbose("Entering channel subdirectory...\n"); + ret = open_channel_trace_pairs(path_channel, path_trace, fd_pairs, + inotify_fd, iwatch_array); + if(ret < 0) continue; + } else if(S_ISREG(stat_buf.st_mode)) { + open_ret = open_buffer_file(entry->d_name, path_channel, path_trace, + fd_pairs); + if(open_ret) + goto end; + } + } + +end: + closedir(channel_dir); + + return open_ret; +} + + +int read_subbuffer(struct fd_pair *pair) +{ + unsigned int consumed_old; + int err; + long ret; + unsigned long len; + off_t offset; + + + err = ioctl(pair->channel, RELAY_GET_SUBBUF, &consumed_old); + printf_verbose("cookie : %u\n", consumed_old); + if(err != 0) { + ret = errno; + perror("Reserving sub buffer failed (everything is normal, it is due to concurrency)"); + goto get_error; + } +#if 0 + err = TEMP_FAILURE_RETRY(write(pair->trace, + pair->mmap + + (consumed_old & ((pair->n_subbufs * pair->subbuf_size)-1)), + pair->subbuf_size)); + + if(err < 0) { + ret = errno; + perror("Error in writing to file"); + goto write_error; + } +#endif //0 + len = pair->subbuf_size; + offset = 0; + while (len > 0) { + printf_verbose("splice chan to pipe offset %lu\n", + (unsigned long)offset); + ret = splice(pair->channel, &offset, thread_pipe[1], NULL, + len, SPLICE_F_MOVE); + printf_verbose("splice chan to pipe ret %ld\n", ret); + if (ret < 0) { + perror("Error in relay splice"); + goto write_error; + } + ret = splice(thread_pipe[0], NULL, pair->trace, NULL, + ret, SPLICE_F_MOVE); + printf_verbose("splice pipe to file %ld\n", ret); + if (ret < 0) { + perror("Error in file splice"); + goto write_error; + } + len -= ret; + } + +#if 0 + err = fsync(pair->trace); + if(err < 0) { + ret = errno; + perror("Error in writing to file"); + goto write_error; + } +#endif //0 +write_error: + ret = 0; + err = ioctl(pair->channel, RELAY_PUT_SUBBUF, &consumed_old); + if(err != 0) { + ret = errno; + if(errno == EFAULT) { + perror("Error in unreserving sub buffer\n"); + } else if(errno == EIO) { + perror("Reader has been pushed by the writer, last subbuffer corrupted."); + /* FIXME : we may delete the last written buffer if we wish. */ + } + goto get_error; + } + +get_error: + return ret; +} + + +int map_channels(struct channel_trace_fd *fd_pairs, + int idx_begin, int idx_end) +{ + int i,j; + int ret=0; + + if(fd_pairs->num_pairs <= 0) { + printf("No channel to read\n"); + goto end; + } + + /* Get the subbuf sizes and number */ + + for(i=idx_begin;ipair[i]; + + ret = ioctl(pair->channel, RELAY_GET_N_SUBBUFS, + &pair->n_subbufs); + if(ret != 0) { + perror("Error in getting the number of subbuffers"); + goto end; + } + ret = ioctl(pair->channel, RELAY_GET_SUBBUF_SIZE, + &pair->subbuf_size); + if(ret != 0) { + perror("Error in getting the size of the subbuffers"); + goto end; + } + ret = pthread_mutex_init(&pair->mutex, NULL); /* Fast mutex */ + if(ret != 0) { + perror("Error in mutex init"); + goto end; + } + } + +#if 0 + /* Mmap each FD */ + for(i=idx_begin;ipair[i]; + + pair->mmap = mmap(0, pair->subbuf_size * pair->n_subbufs, PROT_READ, + MAP_SHARED, pair->channel, 0); + if(pair->mmap == MAP_FAILED) { + perror("Mmap error"); + goto munmap; + } + } + + goto end; /* success */ + + /* Error handling */ + /* munmap only the successfully mmapped indexes */ +munmap: + /* Munmap each FD */ + for(j=idx_begin;jpair[j]; + int err_ret; + + err_ret = munmap(pair->mmap, pair->subbuf_size * pair->n_subbufs); + if(err_ret != 0) { + perror("Error in munmap"); + } + ret |= err_ret; + } + +#endif //0 +end: + return ret; +} + +int unmap_channels(struct channel_trace_fd *fd_pairs) +{ + int j; + int ret=0; + + /* Munmap each FD */ + for(j=0;jnum_pairs;j++) { + struct fd_pair *pair = &fd_pairs->pair[j]; + int err_ret; + +#if 0 + err_ret = munmap(pair->mmap, pair->subbuf_size * pair->n_subbufs); + if(err_ret != 0) { + perror("Error in munmap"); + } + ret |= err_ret; +#endif //0 + err_ret = pthread_mutex_destroy(&pair->mutex); + if(err_ret != 0) { + perror("Error in mutex destroy"); + } + ret |= err_ret; + } + + return ret; +} + +#ifdef HAS_INOTIFY +/* Inotify event arrived. + * + * Only support add file for now. + */ + +int read_inotify(int inotify_fd, + struct channel_trace_fd *fd_pairs, + struct inotify_watch_array *iwatch_array) +{ + char buf[sizeof(struct inotify_event) + PATH_MAX]; + char path_channel[PATH_MAX]; + char path_trace[PATH_MAX]; + ssize_t len; + struct inotify_event *ievent; + size_t offset; + unsigned int i; + int ret; + int old_num; + + offset = 0; + len = read(inotify_fd, buf, sizeof(struct inotify_event) + PATH_MAX); + if(len < 0) { + + if(errno == EAGAIN) + return 0; /* another thread got the data before us */ + + printf("Error in read from inotify FD %s.\n", strerror(len)); + return -1; + } + while(offset < len) { + ievent = (struct inotify_event *)&(buf[offset]); + for(i=0; inum; i++) { + if(iwatch_array->elem[i].wd == ievent->wd && + ievent->mask == IN_CREATE) { + printf_verbose( + "inotify wd %u event mask : %u for %s%s\n", + ievent->wd, ievent->mask, + iwatch_array->elem[i].path_channel, + ievent->name); + old_num = fd_pairs->num_pairs; + strcpy(path_channel, iwatch_array->elem[i].path_channel); + strcat(path_channel, ievent->name); + strcpy(path_trace, iwatch_array->elem[i].path_trace); + strcat(path_trace, ievent->name); + if(ret = open_buffer_file(ievent->name, path_channel, + path_trace, fd_pairs)) { + printf("Error opening buffer file\n"); + return -1; + } + if(ret = map_channels(fd_pairs, old_num, fd_pairs->num_pairs)) { + printf("Error mapping channel\n"); + return -1; + } + + } + } + offset += sizeof(*ievent) + ievent->len; + } +} +#endif //HAS_INOTIFY + +/* read_channels + * + * Thread worker. + * + * Read the debugfs channels and write them in the paired tracefiles. + * + * @fd_pairs : paired channels and trace files. + * + * returns 0 on success, -1 on error. + * + * Note that the high priority polled channels are consumed first. We then poll + * again to see if these channels are still in priority. Only when no + * high priority channel is left, we start reading low priority channels. + * + * Note that a channel is considered high priority when the buffer is almost + * full. + */ + +int read_channels(unsigned long thread_num, struct channel_trace_fd *fd_pairs, + int inotify_fd, struct inotify_watch_array *iwatch_array) +{ + struct pollfd *pollfd = NULL; + int num_pollfd; + int i,j; + int num_rdy, num_hup; + int high_prio; + int ret = 0; + int inotify_fds; + unsigned int old_num; + +#ifdef HAS_INOTIFY + inotify_fds = 1; +#else + inotify_fds = 0; +#endif + + pthread_rwlock_rdlock(&fd_pairs_lock); + + /* Start polling the FD. Keep one fd for inotify */ + pollfd = malloc((inotify_fds + fd_pairs->num_pairs) * sizeof(struct pollfd)); + +#ifdef HAS_INOTIFY + pollfd[0].fd = inotify_fd; + pollfd[0].events = POLLIN|POLLPRI; +#endif + + for(i=0;inum_pairs;i++) { + pollfd[inotify_fds+i].fd = fd_pairs->pair[i].channel; + pollfd[inotify_fds+i].events = POLLIN|POLLPRI; + } + num_pollfd = inotify_fds + fd_pairs->num_pairs; + + + pthread_rwlock_unlock(&fd_pairs_lock); + + while(1) { + high_prio = 0; + num_hup = 0; +#ifdef DEBUG + printf("Press a key for next poll...\n"); + char buf[1]; + read(STDIN_FILENO, &buf, 1); + printf("Next poll (polling %d fd) :\n", num_pollfd); +#endif //DEBUG + + /* Have we received a signal ? */ + if(quit_program) break; + + num_rdy = poll(pollfd, num_pollfd, -1); + + if(num_rdy == -1) { + perror("Poll error"); + goto free_fd; + } + + printf_verbose("Data received\n"); +#ifdef HAS_INOTIFY + switch(pollfd[0].revents) { + case POLLERR: + printf_verbose( + "Error returned in polling inotify fd %d.\n", + pollfd[0].fd); + break; + case POLLHUP: + printf_verbose( + "Polling inotify fd %d tells it has hung up.\n", + pollfd[0].fd); + break; + case POLLNVAL: + printf_verbose( + "Polling inotify fd %d tells fd is not open.\n", + pollfd[0].fd); + break; + case POLLPRI: + case POLLIN: + printf_verbose( + "Polling inotify fd %d : data ready.\n", + pollfd[0].fd); + + pthread_rwlock_wrlock(&fd_pairs_lock); + read_inotify(inotify_fd, fd_pairs, iwatch_array); + pthread_rwlock_unlock(&fd_pairs_lock); + + break; + } +#endif + + for(i=inotify_fds;ipair[i-inotify_fds].mutex) == 0) { + printf_verbose( + "Urgent read on fd %d\n", + pollfd[i].fd); + /* Take care of high priority channels first. */ + high_prio = 1; + /* it's ok to have an unavailable subbuffer */ + ret = read_subbuffer(&fd_pairs->pair[i-inotify_fds]); + if(ret == EAGAIN) ret = 0; + + ret = pthread_mutex_unlock(&fd_pairs->pair[i-inotify_fds].mutex); + if(ret) + printf("Error in mutex unlock : %s\n", strerror(ret)); + } + pthread_rwlock_unlock(&fd_pairs_lock); + break; + } + } + /* If every buffer FD has hung up, we end the read loop here */ + if(num_hup == num_pollfd - inotify_fds) break; + + if(!high_prio) { + for(i=inotify_fds;ipair[i-inotify_fds].mutex) == 0) { + /* Take care of low priority channels. */ + printf_verbose( + "Normal read on fd %d\n", + pollfd[i].fd); + /* it's ok to have an unavailable subbuffer */ + ret = read_subbuffer(&fd_pairs->pair[i-inotify_fds]); + if(ret == EAGAIN) ret = 0; + + ret = pthread_mutex_unlock(&fd_pairs->pair[i-inotify_fds].mutex); + if(ret) + printf("Error in mutex unlock : %s\n", strerror(ret)); + } + pthread_rwlock_unlock(&fd_pairs_lock); + break; + } + } + } + + /* Update pollfd array if an entry was added to fd_pairs */ + pthread_rwlock_rdlock(&fd_pairs_lock); + if((inotify_fds + fd_pairs->num_pairs) != num_pollfd) { + pollfd = realloc(pollfd, + (inotify_fds + fd_pairs->num_pairs) * sizeof(struct pollfd)); + for(i=num_pollfd-inotify_fds;inum_pairs;i++) { + pollfd[inotify_fds+i].fd = fd_pairs->pair[i].channel; + pollfd[inotify_fds+i].events = POLLIN|POLLPRI; + } + num_pollfd = fd_pairs->num_pairs + inotify_fds; + } + pthread_rwlock_unlock(&fd_pairs_lock); + + /* NB: If the fd_pairs structure is updated by another thread from this + * point forward, the current thread will wait in the poll without + * monitoring the new channel. However, this thread will add the + * new channel on next poll (and this should not take too much time + * on a loaded system). + * + * This event is quite unlikely and can only occur if a CPU is + * hot-plugged while multple lttd threads are running. + */ + } + +free_fd: + free(pollfd); + +end: + return ret; +} + + +void close_channel_trace_pairs(struct channel_trace_fd *fd_pairs, int inotify_fd, + struct inotify_watch_array *iwatch_array) +{ + int i; + int ret; + + for(i=0;inum_pairs;i++) { + ret = close(fd_pairs->pair[i].channel); + if(ret == -1) perror("Close error on channel"); + ret = close(fd_pairs->pair[i].trace); + if(ret == -1) perror("Close error on trace"); + } + free(fd_pairs->pair); + free(iwatch_array->elem); +} + +/* Thread worker */ +void * thread_main(void *arg) +{ + long ret; + unsigned long thread_num = (unsigned long)arg; + + ret = pipe(thread_pipe); + if (ret < 0) { + perror("Error creating pipe"); + return (void*)ret; + } + ret = read_channels(thread_num, &fd_pairs, inotify_fd, &inotify_watch_array); + close(thread_pipe[0]); /* close read end */ + close(thread_pipe[1]); /* close write end */ + return (void*)ret; +} + + +int channels_init() +{ + int ret = 0; + + inotify_fd = inotify_init(); + fcntl(inotify_fd, F_SETFL, O_NONBLOCK); + + if(ret = open_channel_trace_pairs(channel_name, trace_name, &fd_pairs, + &inotify_fd, &inotify_watch_array)) + goto close_channel; + if (fd_pairs.num_pairs == 0) { + printf("No channel available for reading, exiting\n"); + ret = -ENOENT; + goto close_channel; + } + if(ret = map_channels(&fd_pairs, 0, fd_pairs.num_pairs)) + goto close_channel; + return 0; + +close_channel: + close_channel_trace_pairs(&fd_pairs, inotify_fd, &inotify_watch_array); + if(inotify_fd >= 0) + close(inotify_fd); + return ret; +} + + +int main(int argc, char ** argv) +{ + int ret = 0; + struct sigaction act; + pthread_t *tids; + unsigned long i; + void *tret; + + ret = parse_arguments(argc, argv); + + if(ret != 0) show_arguments(); + if(ret < 0) return EINVAL; + if(ret > 0) return 0; + + show_info(); + + /* Connect the signal handlers */ + act.sa_handler = handler; + act.sa_flags = 0; + sigemptyset(&(act.sa_mask)); + sigaddset(&(act.sa_mask), SIGTERM); + sigaddset(&(act.sa_mask), SIGQUIT); + sigaddset(&(act.sa_mask), SIGINT); + sigaction(SIGTERM, &act, NULL); + sigaction(SIGQUIT, &act, NULL); + sigaction(SIGINT, &act, NULL); + + if(ret = channels_init()) + return ret; + + if(daemon_mode) { + ret = daemon(0, 0); + + if(ret == -1) { + perror("An error occured while daemonizing."); + exit(-1); + } + } + + tids = malloc(sizeof(pthread_t) * num_threads); + for(i=0; i= 0) + close(inotify_fd); + + return ret; +} diff --git a/specs/Makefile.am b/specs/Makefile.am new file mode 100644 index 0000000..c6ae90e --- /dev/null +++ b/specs/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST = ltt-control.spec diff --git a/specs/ltt-control.spec b/specs/ltt-control.spec new file mode 100644 index 0000000..8b0a2a3 --- /dev/null +++ b/specs/ltt-control.spec @@ -0,0 +1,58 @@ +# +# Spec file for ltt-control +# +Summary: LTT Control +Name: ltt-control +Version: 0.45 +Release: 11102007 +License: GPL +Group: Applications/Development +Source: http://ltt.polymtl.ca/lttng/ltt-control-%{version}-%{release}.tar.gz +URL: http://ltt.polymtl.ca +Packager: Martin Bisson +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) + +# Where do we install the libs +%ifarch x86_64 ppc64 ppc64iseries ia64 +%define libdir /usr/lib64 +%else +%define libdir /usr/lib +%endif + + +%description + +ltt-control is the part of the Linux Trace Toolkit Next Generation +that allows a machine to be traced. It holds the daemon with which +the kernel will communicate and the application that starts and +terminate tracing. + +%prep +%setup -q -n ltt-control-%{version}-%{release} + +%build +./configure --prefix=/usr --libdir=%{libdir} +make + +%install +rm -rf $RPM_BUILD_ROOT +make DESTDIR=$RPM_BUILD_ROOT install + +%post +echo "Running ldconfig (might take a while)" +ldconfig + +%postun +echo "Running ldconfig (might take a while)" +ldconfig + +%files +%{libdir}/liblttctl.so.0.0.0 +%{libdir}/liblttctl.so.0 +%{libdir}/liblttctl.so +%{libdir}/liblttctl.la +%{libdir}/liblttctl.a +/usr/bin/lttctl +/usr/bin/lttd +/usr/include/liblttctl +/usr/include/liblttctl/lttctl.h diff --git a/trunk/ltt-control/AUTHORS b/trunk/ltt-control/AUTHORS deleted file mode 100644 index 032edf0..0000000 --- a/trunk/ltt-control/AUTHORS +++ /dev/null @@ -1,25 +0,0 @@ -Linux Trace Toolkit Viewer - -Contributors : - -Michel Dagenais (New trace format, lttv main) -Mathieu Desnoyers (Kernel Tracer, Directory structure, build with automake/conf, - lttv gui, control flow view, gui cooperative trace reading - scheduler with interruptible foreground and background - computation, detailed event list (rewrite), trace reading - library (rewrite)) -Benoit Des Ligneris, Éric Clement (Cluster adaptation, work in progress) -Xang-Xiu Yang (trace reading library and converter, lttv gui, - detailed event list and statistics view) -Tom Zanussi (RelayFS) - -Strongly inspired from the original Linux Trace Toolkit Visualizer made by -Karim Yaghmour. - -Linux Trace Toolkit Viewer, Copyright (C) 2004 - Michel Dagenais - Mathieu Desnoyers - Xang-Xiu Yang -Linux Trace Toolkit comes with ABSOLUTELY NO WARRANTY. -This is free software, and you are welcome to redistribute it -under certain conditions. See COPYING for details. diff --git a/trunk/ltt-control/ChangeLog b/trunk/ltt-control/ChangeLog deleted file mode 100644 index e69de29..0000000 diff --git a/trunk/ltt-control/Makefile.am b/trunk/ltt-control/Makefile.am deleted file mode 100644 index 8f9974d..0000000 --- a/trunk/ltt-control/Makefile.am +++ /dev/null @@ -1,2 +0,0 @@ -SUBDIRS = liblttctl lttctl lttd specs - diff --git a/trunk/ltt-control/NEWS b/trunk/ltt-control/NEWS deleted file mode 100644 index e69de29..0000000 diff --git a/trunk/ltt-control/README b/trunk/ltt-control/README deleted file mode 100644 index 9fce197..0000000 --- a/trunk/ltt-control/README +++ /dev/null @@ -1,60 +0,0 @@ -ltt-control package README --------------------------- -Mathieu Desnoyers -Last update: 2007/05/14 - - -This package contains the lttd, lttctl and liblttctl programs which are -necessary to obtain a trace. It also contains the facilities directory, where -sits the trace metainformation. - -* Compiling - -gcc 3.2 or better -glib 2.4 or better development libraries - (Debian : libglib2.0-0, libglib2.0-dev) - (Fedora : glib2, glib2-devel) -libc6 development librairies - (Debian : libc6, libc6-dev) - (Fedora : glibc, glibc) - - -To compile the source tree from a tarball, simply follow these steps : - -- ./configure -- make -- make install - -After running ./configure, you can also go in specific subdirectories and -use make, make install. - - -* Quick Start - -See the LTTV package QUICKSTART file. - - -* Source Tree Structure - -Here is the tree structure of the ltt-control package. - -ltt/ New trace format reading library. -liblttctl/ Library to communicate with the kernel tracer control module. -lttctl/ Command line program to use the liblttctl library. -lttd/ Linux Trace Toolkit daemon. -README This file. - - -* For Developers - -This source tree is based on the autotools suite from GNU to simplify -portability. Here are some things you should have on your system in order to -compile the subversion repository tree : - -- GNU autotools (automake >=1.7, autoconf >=2.50, autoheader >=2.50) - (make sure your system wide "automake" points to a recent version!) -- GNU Libtool - (for more information, go to http://www.gnu.org/software/autoconf/) - -If you get the tree from the repository, you will need to use the autogen.sh -script. It calls all the GNU tools needed to prepare the tree configuration. diff --git a/trunk/ltt-control/autogen.sh b/trunk/ltt-control/autogen.sh deleted file mode 100755 index f0c7b68..0000000 --- a/trunk/ltt-control/autogen.sh +++ /dev/null @@ -1,169 +0,0 @@ -#!/bin/sh -# Run this to generate all the initial makefiles, etc. - -srcdir=`dirname $0` -test -z "$srcdir" && srcdir=. - -DIE=0 - -(test -f $srcdir/configure.in) || { - echo -n "**Error**: Directory "\`$srcdir\'" does not look like the" - echo " top-level package directory" - exit 1 -} - -(autoconf --version) < /dev/null > /dev/null 2>&1 || { - echo - echo "**Error**: You must have \`autoconf' installed." - echo "Download the appropriate package for your distribution," - echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" - DIE=1 -} - -(grep "^AC_PROG_INTLTOOL" $srcdir/configure.in >/dev/null) && { - (intltoolize --version) < /dev/null > /dev/null 2>&1 || { - echo - echo "**Error**: You must have \`intltool' installed." - echo "You can get it from:" - echo " ftp://ftp.gnome.org/pub/GNOME/" - DIE=1 - } -} - -(grep "^AM_PROG_XML_I18N_TOOLS" $srcdir/configure.in >/dev/null) && { - (xml-i18n-toolize --version) < /dev/null > /dev/null 2>&1 || { - echo - echo "**Error**: You must have \`xml-i18n-toolize' installed." - echo "You can get it from:" - echo " ftp://ftp.gnome.org/pub/GNOME/" - DIE=1 - } -} - -(grep "^AM_PROG_LIBTOOL" $srcdir/configure.in >/dev/null) && { - (libtool --version) < /dev/null > /dev/null 2>&1 || { - echo - echo "**Error**: You must have \`libtool' installed." - echo "You can get it from: ftp://ftp.gnu.org/pub/gnu/" - DIE=1 - } -} - -(grep "^AM_GLIB_GNU_GETTEXT" $srcdir/configure.in >/dev/null) && { - (grep "sed.*POTFILES" $srcdir/configure.in) > /dev/null || \ - (glib-gettextize --version) < /dev/null > /dev/null 2>&1 || { - echo - echo "**Error**: You must have \`glib' installed." - echo "You can get it from: ftp://ftp.gtk.org/pub/gtk" - DIE=1 - } -} - -(automake --version) < /dev/null > /dev/null 2>&1 || { - echo - echo "**Error**: You must have \`automake' installed." - echo "You can get it from: ftp://ftp.gnu.org/pub/gnu/" - DIE=1 - NO_AUTOMAKE=yes -} - - -# if no automake, don't bother testing for aclocal -test -n "$NO_AUTOMAKE" || (aclocal --version) < /dev/null > /dev/null 2>&1 || { - echo - echo "**Error**: Missing \`aclocal'. The version of \`automake'" - echo "installed doesn't appear recent enough." - echo "You can get automake from ftp://ftp.gnu.org/pub/gnu/" - DIE=1 -} - -if test "$DIE" -eq 1; then - exit 1 -fi - -if test -z "$*"; then - echo "**Warning**: I am going to run \`configure' with no arguments." - echo "If you wish to pass any to it, please specify them on the" - echo \`$0\'" command line." - echo -fi - -case $CC in -xlc ) - am_opt=--include-deps;; -esac - -for coin in `find $srcdir -path $srcdir/CVS -prune -o -name configure.in -print` -do - dr=`dirname $coin` - if test -f $dr/NO-AUTO-GEN; then - echo skipping $dr -- flagged as no auto-gen - else - echo processing $dr - ( cd $dr - - aclocalinclude="$ACLOCAL_FLAGS" - - if grep "^AM_GLIB_GNU_GETTEXT" configure.in >/dev/null; then - echo "Creating $dr/aclocal.m4 ..." - test -r $dr/aclocal.m4 || touch $dr/aclocal.m4 - echo "Running glib-gettextize... Ignore non-fatal messages." - echo "no" | glib-gettextize --force --copy - echo "Making $dr/aclocal.m4 writable ..." - test -r $dr/aclocal.m4 && chmod u+w $dr/aclocal.m4 - fi - if grep "^AC_PROG_INTLTOOL" configure.in >/dev/null; then - echo "Running intltoolize..." - intltoolize --copy --force --automake - fi - if grep "^AM_PROG_XML_I18N_TOOLS" configure.in >/dev/null; then - echo "Running xml-i18n-toolize..." - xml-i18n-toolize --copy --force --automake - fi - if grep "^AM_PROG_LIBTOOL" configure.in >/dev/null; then - if test -z "$NO_LIBTOOLIZE" ; then - echo "Running libtoolize..." - libtoolize --force --copy - fi - fi - echo "Running aclocal $aclocalinclude ..." - aclocal $aclocalinclude - if grep "^AM_CONFIG_HEADER" configure.in >/dev/null; then - echo "Running autoheader..." - autoheader - fi - echo "Running automake --gnu $am_opt ..." - automake --add-missing --gnu $am_opt - echo "Running autoconf ..." - autoconf - ) - fi -done - -conf_flags="--enable-maintainer-mode" - - -#if [ -a "$srcdir/include" ]; then -# echo -n Removing old system include behavior emulation... -# rm -rf $srcdir/include -# echo done. -#fi -#echo -n Creating the system include behavior emulation... -#mkdir $srcdir/include -#mkdir $srcdir/include/ltt -#ln -sf ../../LibLTT/ltt.h $srcdir/include/ltt/ltt.h -#mkdir $srcdir/include/lttv -#ln -sf ../../lttv/module.h $srcdir/include/lttv/module.h -#ln -sf ../../lttv/hook.h $srcdir/include/lttv/hook.h -#ln -sf ../../lttv/traceWindow.h $srcdir/include/lttv/traceWindow.h -#echo done. - - - -if test x$NOCONFIGURE = x; then - echo Running $srcdir/configure $conf_flags "$@" ... - $srcdir/configure $conf_flags "$@" \ - && echo Now type \`make\' to compile. || exit 1 -else - echo Skipping configure process. -fi diff --git a/trunk/ltt-control/configure.in b/trunk/ltt-control/configure.in deleted file mode 100644 index 6adcbaa..0000000 --- a/trunk/ltt-control/configure.in +++ /dev/null @@ -1,90 +0,0 @@ -# This file is part of the Linux Trace Toolkit viewer -# Copyright (C) 2003-2004 Mathieu Desnoyers -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License Version 2 as -# published by the Free Software Foundation; -# -# 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. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, -# MA 02111-1307, USA. - - - -# -*- Autoconf -*- -# Process this file with autoconf to produce a configure script. - -AC_PREREQ(2.57) -AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS) -#AC_WITH_LTDL # not needed ? -AM_INIT_AUTOMAKE(ltt-control,0.69-23072009) -AM_CONFIG_HEADER(config.h) -AM_PROG_LIBTOOL - -AC_PATH_PROGS(BASH, bash) - -AC_SYS_LARGEFILE - -# Checks for programs. -AC_PROG_CC - -AC_CHECK_LIB([util], [forkpty], UTIL_LIBS="-lutil", AC_MSG_ERROR([libutil is -required in order to compile LinuxTraceToolkit])) - - -# pthread for lttd -AC_CHECK_LIB(pthread, pthread_join,[THREAD_LIBS="-lpthread"], AC_MSG_ERROR([LinuxThreads is required in order to compile lttd])) - -# Checks for header files. -AC_HEADER_STDC -AC_CHECK_HEADERS([fcntl.h stdlib.h string.h sys/time.h unistd.h pthread.h]) - -AC_ISC_POSIX -AC_PROG_CC -AM_PROG_CC_STDC -AC_HEADER_STDC - -PACKAGE_CFLAGS="-Wall -Wformat" -AC_SUBST(PACKAGE_CFLAGS) -AC_SUBST(PACKAGE_LIBS) - -# Checks for typedefs, structures, and compiler characteristics. -AC_HEADER_STDBOOL -AC_C_CONST -AC_C_INLINE -AC_TYPE_OFF_T -AC_TYPE_SIZE_T -AC_HEADER_TIME - -# Checks for library functions. -AC_FUNC_ERROR_AT_LINE -#AC_FUNC_MALLOC -AC_FUNC_SELECT_ARGTYPES -AC_CHECK_FUNCS([select]) - -#CPPFLAGS="$CPPFLAGS -I" - -DEFAULT_INCLUDES="-I\$(top_srcdir) -I\$(top_builddir)" - -#CPPFLAGS="${GLIB_CFLAGS}" -#AC_SUBST(CPPFLAGS) - -lttctlincludedir="${includedir}/liblttctl" - -AC_SUBST(lttctlincludedir) -AC_SUBST(UTIL_LIBS) -AC_SUBST(THREAD_LIBS) -AC_SUBST(DEFAULT_INCLUDES) - -AC_CONFIG_FILES([Makefile - liblttctl/Makefile - lttctl/Makefile - lttd/Makefile - specs/Makefile]) -AC_OUTPUT diff --git a/trunk/ltt-control/liblttctl/Makefile.am b/trunk/ltt-control/liblttctl/Makefile.am deleted file mode 100644 index 1c650f0..0000000 --- a/trunk/ltt-control/liblttctl/Makefile.am +++ /dev/null @@ -1,7 +0,0 @@ - - -lib_LTLIBRARIES = liblttctl.la -liblttctl_la_SOURCES = liblttctl.c - -lttctlinclude_HEADERS = \ - lttctl.h diff --git a/trunk/ltt-control/liblttctl/liblttctl.c b/trunk/ltt-control/liblttctl/liblttctl.c deleted file mode 100644 index 6ee37a4..0000000 --- a/trunk/ltt-control/liblttctl/liblttctl.c +++ /dev/null @@ -1,722 +0,0 @@ -/* libltt - * - * Linux Trace Toolkit Netlink Control Library - * - * Controls the ltt-control kernel module through debugfs. - * - * Copyright 2005 - - * Mathieu Desnoyers - * - * - * 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 -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#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; -} diff --git a/trunk/ltt-control/liblttctl/lttctl.h b/trunk/ltt-control/liblttctl/lttctl.h deleted file mode 100644 index facc8f0..0000000 --- a/trunk/ltt-control/liblttctl/lttctl.h +++ /dev/null @@ -1,42 +0,0 @@ -/* libltt header file - * - * Copyright 2005- - * Mathieu Desnoyers - * - * - * 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. - * - */ - -#ifndef _LIBLTT_H -#define _LIBLTT_H - -int lttctl_init(void); -int lttctl_destroy(void); -int lttctl_setup_trace(const char *name); -int lttctl_destroy_trace(const char *name); -int lttctl_alloc_trace(const char *name); -int lttctl_start(const char *name); -int lttctl_pause(const char *name); -int lttctl_set_trans(const char *name, const char *trans); -int lttctl_set_channel_enable(const char *name, const char *channel, - int enable); -int lttctl_set_channel_overwrite(const char *name, const char *channel, - int overwrite); -int lttctl_set_channel_subbuf_num(const char *name, const char *channel, - unsigned subbuf_num); -int lttctl_set_channel_subbuf_size(const char *name, const char *channel, - unsigned subbuf_size); - -/* Helper functions */ -int getdebugfsmntdir(char *mntdir); - -#endif /*_LIBLTT_H */ diff --git a/trunk/ltt-control/lttctl/Makefile.am b/trunk/ltt-control/lttctl/Makefile.am deleted file mode 100644 index 12ad501..0000000 --- a/trunk/ltt-control/lttctl/Makefile.am +++ /dev/null @@ -1,53 +0,0 @@ -## Process this file with automake to produce Makefile.in - -AM_CFLAGS = -DPACKAGE_DATA_DIR=\""$(datadir)"\" -DPACKAGE_BIN_DIR=\""$(bindir)"\" - -bin_PROGRAMS = lttctl -bin_SCRIPTS = ltt-armall ltt-disarmall ltt-armalluser ltt-disarmalluser \ - ltt-armtap ltt-disarmtap -CLEANFILES = $(bin_SCRIPTS) -EXTRA_DIST = ltt-armall.sh ltt-disarmall.sh \ - ltt-armalluser.sh ltt-disarmalluser.sh \ - ltt-armtap.sh ltt-disarmtap.sh - -ltt-armall: ltt-armall.sh - rm -f ltt-armall - echo "#!"$(BASH) > ltt-armall - cat $(srcdir)/ltt-armall.sh >> ltt-armall - chmod ugo+x ltt-armall - -ltt-disarmall: ltt-disarmall.sh - rm -f ltt-disarmall - echo "#!"$(BASH) > ltt-disarmall - cat $(srcdir)/ltt-disarmall.sh >> ltt-disarmall - chmod ugo+x ltt-disarmall - -ltt-armtap: ltt-armtap.sh - rm -f ltt-armtap - echo "#!"$(BASH) > ltt-armtap - cat $(srcdir)/ltt-armtap.sh >> ltt-armtap - chmod ugo+x ltt-armtap - -ltt-disarmtap: ltt-disarmtap.sh - rm -f ltt-disarmtap - echo "#!"$(BASH) > ltt-disarmtap - cat $(srcdir)/ltt-disarmtap.sh >> ltt-disarmtap - chmod ugo+x ltt-disarmtap - -ltt-armalluser: ltt-armalluser.sh - rm -f ltt-armalluser - echo "#!"$(BASH) > ltt-armalluser - cat $(srcdir)/ltt-armalluser.sh >> ltt-armalluser - chmod ugo+x ltt-armalluser - -ltt-disarmalluser: ltt-disarmalluser.sh - rm -f ltt-disarmalluser - echo "#!"$(BASH) > ltt-disarmalluser - cat $(srcdir)/ltt-disarmalluser.sh >> ltt-disarmalluser - chmod ugo+x ltt-disarmalluser - -lttctl_SOURCES = \ - lttctl.c -lttctl_DEPENDENCIES = ../liblttctl/liblttctl.la -lttctl_LDADD = $(lttctl_DEPENDENCIES) - diff --git a/trunk/ltt-control/lttctl/ltt-armall.sh b/trunk/ltt-control/lttctl/ltt-armall.sh deleted file mode 100755 index f0824c8..0000000 --- a/trunk/ltt-control/lttctl/ltt-armall.sh +++ /dev/null @@ -1,47 +0,0 @@ -#excluding core markers (already connected) -#excluding locking markers (high traffic) - -DEBUGFSROOT=$(grep ^debugfs /proc/mounts | head -1 | awk '{print $2}') -MARKERSROOT=${DEBUGFSROOT}/ltt/markers - -echo Connecting all markers - -for c in ${MARKERSROOT}/*; do - case ${c} in - ${MARKERSROOT}/metadata) - ;; - ${MARKERSROOT}/locking) - ;; - ${MARKERSROOT}/lockdep) - ;; - *) - for m in ${c}/*; do - echo Connecting ${m} - echo 1 > ${m}/enable - done - ;; - esac -done - - -# Connect the interesting high-speed markers to the marker tap. -# Markers starting with "tap_" are considered high-speed. -#echo Connecting high-rate markers to tap -#MARKERS=`cat /proc/ltt|grep -v %k|awk '{print $2}'|sort -u |grep ^tap_` -# -##Uncomment the following to also record lockdep events. -##MARKERS=`cat /proc/ltt|grep -v %k|awk '{print $2}'|sort -u|grep -e ^tap_ -e ^lockdep` -# -#IFS=${N} -#for a in $MARKERS; do -# echo Connecting $a -# -# #redirect markers carrying state information to dedicated channels -# case $a in -# *) -# CHANNEL= -# ;; -# esac -# -# echo "connect $a ltt_tap_marker" > /proc/ltt -#done diff --git a/trunk/ltt-control/lttctl/ltt-armalluser.sh b/trunk/ltt-control/lttctl/ltt-armalluser.sh deleted file mode 100755 index 290e360..0000000 --- a/trunk/ltt-control/lttctl/ltt-armalluser.sh +++ /dev/null @@ -1,18 +0,0 @@ -#excluding core markers (already connected) -#excluding locking markers (high traffic) - -echo Connecting all userspace markers of _CURRENTLY RUNNING_ processes only ! -echo All the markers listed here will also automatically be enabled if -echo present in a newly created process. - -for a in /proc/[0-9]*; do - for marker in `cat $a/markers | awk '{print $2}'`; do - echo Connecting marker $a:$marker - case $marker in - *) - CHANNEL= - ;; - esac - echo "connect $marker default dynamic $CHANNEL" > /proc/ltt - done -done diff --git a/trunk/ltt-control/lttctl/ltt-armtap.sh b/trunk/ltt-control/lttctl/ltt-armtap.sh deleted file mode 100755 index 84f91d6..0000000 --- a/trunk/ltt-control/lttctl/ltt-armtap.sh +++ /dev/null @@ -1,34 +0,0 @@ -# This script will enable the system-wide tap on the given list of events passed -# as parameter, and stop the tap at each other "normal rate" events. - -#excluding core markers (already connected) -#excluding locking markers (high traffic) - -echo Connecting function markers - -# interesting period starts with the list of events passed as parameter. -START_FTRACE=$* - -# interesting period may stop with one specific event, but also try to keep the -# other START_FTRACE events triggers to the lowest possible overhead by stopping -# function trace at every other events. -# Do _not_ disable function tracing in ftrace_entry event unless you really only -# want the first function entry... -STOP_FTRACE=`cat /proc/ltt|grep -v %k|awk '{print $2}'|sort -u|grep -v ^core_|grep -v ^locking_|grep -v ^lockdep|grep -v ftrace_entry|grep -v ^tap_` - -for a in $START_FTRACE; do - STOP_FTRACE=`echo $STOP_FTRACE|sed 's/$a//'` -done - - -for a in $STOP_FTRACE; do - echo Connecting stop $a - echo "connect $a ftrace_system_stop" > /proc/ltt -done - -for a in $START_FTRACE; do - echo Connecting start $a - echo "connect $a ftrace_system_start" > /proc/ltt -done - - diff --git a/trunk/ltt-control/lttctl/ltt-disarmall.sh b/trunk/ltt-control/lttctl/ltt-disarmall.sh deleted file mode 100755 index 2473b81..0000000 --- a/trunk/ltt-control/lttctl/ltt-disarmall.sh +++ /dev/null @@ -1,38 +0,0 @@ -#excluding core markers (already connected) -#excluding locking markers (high traffic) - -DEBUGFSROOT=$(grep ^debugfs /proc/mounts | head -1 | awk '{print $2}') -MARKERSROOT=${DEBUGFSROOT}/ltt/markers - -echo Disconnecting all markers - -for c in ${MARKERSROOT}/*; do - case ${c} in - ${MARKERSROOT}/metadata) - ;; - ${MARKERSROOT}/locking) - ;; - ${MARKERSROOT}/lockdep) - ;; - *) - for m in ${c}/*; do - echo Disconnecting ${m} - echo 0 > ${m}/enable - done - ;; - esac -done - -## Markers starting with "tap_" are considered high-speed. -#echo Disconnecting high-rate markers to tap -#MARKERS=`cat /proc/ltt|grep -v %k|awk '{print $2 " " $4}'|sort -u |grep ^tap` -# -##Uncomment the following to also stop recording lockdep events. -##MARKERS=`cat /proc/ltt|grep -v %k|awk '{print $2}'|sort -u|grep -e ^tap_ -e ^lockdep` -# -#IFS=${N} -#for a in $MARKERS; do -# echo Disconnecting $a -# -# echo "disconnect $a ltt_tap_marker" > /proc/ltt -#done diff --git a/trunk/ltt-control/lttctl/ltt-disarmalluser.sh b/trunk/ltt-control/lttctl/ltt-disarmalluser.sh deleted file mode 100755 index 0d0f1eb..0000000 --- a/trunk/ltt-control/lttctl/ltt-disarmalluser.sh +++ /dev/null @@ -1,16 +0,0 @@ -#excluding core markers (already connected) -#excluding locking markers (high traffic) - -echo Disconnecting all userspace markers of _RUNNING PROCESSES_ only ! - -for a in /proc/[0-9]*; do - for marker in `cat $a/markers | awk '{print $2}'`; do - echo Disonnecting marker $a:$marker - case $marker in - *) - CHANNEL= - ;; - esac - echo "disconnect $marker default dynamic $CHANNEL" > /proc/ltt - done -done diff --git a/trunk/ltt-control/lttctl/ltt-disarmtap.sh b/trunk/ltt-control/lttctl/ltt-disarmtap.sh deleted file mode 100755 index b41f70c..0000000 --- a/trunk/ltt-control/lttctl/ltt-disarmtap.sh +++ /dev/null @@ -1,33 +0,0 @@ -# This script will disable the system-wide tap on the given list of events -# passed as parameter, and stop the tap at each other "normal rate" events. - -#excluding core markers (already connected) -#excluding locking markers (high traffic) - -echo Disconnecting function markers - -# interesting period starts with the list of events passed as parameter. -START_FTRACE=$* - -# interesting period may stop with one specific event, but also try to keep the -# other START_FTRACE events triggers to the lowest possible overhead by stopping -# function trace at every other events. -# Do _not_ disable function tracing in ftrace_entry event unless you really only -# want the first function entry... -STOP_FTRACE=`cat /proc/ltt|grep -v %k|awk '{print $2}'|sort -u|grep -v ^core_|grep -v ^locking_|grep -v ^lockdep|grep -v ftrace_entry|grep -v ^tap_` - -for a in $START_FTRACE; do - STOP_FTRACE=`echo $STOP_FTRACE|sed 's/$a//'` -done - -for a in $START_FTRACE; do - echo Disconnecting start $a - echo "disconnect $a ftrace_system_start" > /proc/ltt -done - -for a in $STOP_FTRACE; do - echo Disconnecting stop $a - echo "disconnect $a ftrace_system_stop" > /proc/ltt -done - - diff --git a/trunk/ltt-control/lttctl/lttctl.c b/trunk/ltt-control/lttctl/lttctl.c deleted file mode 100644 index e08280a..0000000 --- a/trunk/ltt-control/lttctl/lttctl.c +++ /dev/null @@ -1,833 +0,0 @@ -/* lttctl - * - * Linux Trace Toolkit Control - * - * Small program that controls LTT through libltt. - * - * Copyright 2005 - - * Mathieu Desnoyers - * - * Copyright 2008 FUJITSU - * Zhao Lei - * Gui Jianfeng - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#define _GNU_SOURCE -#include - -#define OPT_MAX (1024) -#define OPT_NAMELEN (256) -#define OPT_VALSTRINGLEN (256) - -enum opt_type { - CHANNEL, -}; - -struct channel_option { - char chan_name[OPT_NAMELEN]; - int enable; - int overwrite; - int bufnum; - int bufsize; -}; - -struct lttctl_option { - union { - struct channel_option chan_opt; - } opt_mode; - enum opt_type type; - struct lttctl_option *next; -}; - -struct lttctl_option *opt_head, *last_opt; - -static int opt_create; -static int opt_destroy; -static int opt_start; -static int opt_pause; -static int opt_help; -static const char *opt_transport; -static const char *opt_write; -static int opt_append; -static unsigned int opt_dump_threads; -static char channel_root_default[PATH_MAX]; -static const char *opt_channel_root; -static const char *opt_tracename; - -/* Args : - * - */ -static void show_arguments(void) -{ - printf("Linux Trace Toolkit Trace Control " VERSION"\n"); - printf("\n"); - printf("Usage: lttctl [OPTION]... [TRACENAME]\n"); - printf("\n"); - printf("Examples:\n"); - printf(" lttctl -c trace1 " - "# Create a trace named trace1.\n"); - printf(" lttctl -s trace1 " - "# start a trace named trace1.\n"); - printf(" lttctl -p trace1 " - "# pause a trace named trace1.\n"); - printf(" lttctl -d trace1 " - "# Destroy a trace named trace1.\n"); - printf(" lttctl -C -w /tmp/trace1 trace1 " - "# Create a trace named trace1, start it and\n" - " " - "# write non-overwrite channels' data to\n" - " " - "# /tmp/trace1, debugfs must be mounted for\n" - " " - "# auto-find\n"); - printf(" lttctl -D -w /tmp/trace1 trace1 " - "# Pause and destroy a trace named trace1 and\n" - " " - "# write overwrite channels' data to\n" - " " - "# /tmp/trace1, debugfs must be mounted for\n" - " " - "# auto-find\n"); - printf("\n"); - printf(" Basic options:\n"); - printf(" -c, --create\n"); - printf(" Create a trace.\n"); - printf(" -d, --destroy\n"); - printf(" Destroy a trace.\n"); - printf(" -s, --start\n"); - printf(" Start a trace.\n"); - printf(" -p, --pause\n"); - printf(" Pause a trace.\n"); - printf(" -h, --help\n"); - printf(" Show this help.\n"); - printf("\n"); - printf(" Advanced options:\n"); - printf(" --transport TRANSPORT\n"); - printf(" Set trace's transport. (ex. relay-locked or relay)\n"); - printf(" -o, --option OPTION\n"); - printf(" Set options, following operations are supported:\n"); - printf(" channel..enable=\n"); - printf(" channel..overwrite=\n"); - printf(" channel..bufnum=\n"); - printf(" channel..bufsize= (in bytes, rounded to " - "next power of 2)\n"); - printf(" can be set to all for all channels\n"); - printf("\n"); - printf(" Integration options:\n"); - printf(" -C, --create_start\n"); - printf(" Create and start a trace.\n"); - printf(" -D, --pause_destroy\n"); - printf(" Pause and destroy a trace.\n"); - printf(" -w, --write PATH\n"); - printf(" Path for write trace datas.\n"); - printf(" For -c, -C, -d, -D options\n"); - printf(" -a, --append\n"); - printf(" Append to trace, For -w option\n"); - printf(" -n, --dump_threads NUMBER\n"); - printf(" Number of lttd threads, For -w option\n"); - printf(" --channel_root PATH\n"); - printf(" Set channels root path, For -w option." - " (ex. /mnt/debugfs/ltt)\n"); - printf("\n"); -} - -/* - * Separate option name to 3 fields - * Ex: - * Input: name = channel.cpu.bufsize - * Output: name1 = channel - * name2 = cpu - * name3 = bufsize - * Ret: 0 on success - * 1 on fail - * - * Note: - * Make sure that name1~3 longer than OPT_NAMELEN. - * name1~3 can be NULL to discard value - * - */ -static int separate_opt(const char *name, char *name1, char *name2, char *name3) -{ - char *p; - - if (!name) - return 1; - - /* segment1 */ - p = strchr(name, '.'); - if (!p) - return 1; - if (p - name >= OPT_NAMELEN) - return 1; - if (name1) { - memcpy(name1, name, p - name); - name1[p - name] = 0; - } - name = p + 1; - - /* segment2 */ - p = strchr(name, '.'); - if (!p) - return 1; - if (p - name >= OPT_NAMELEN) - return 1; - if (name2) { - memcpy(name2, name, p - name); - name2[p - name] = 0; - } - name = p + 1; - - /* segment3 */ - if (strlen(name) >= OPT_NAMELEN) - return 1; - if (name3) - strcpy(name3, name); - - return 0; -} - -static void init_channel_opt(struct channel_option *opt, char *opt_name) -{ - if (opt && opt_name) { - opt->enable = -1; - opt->overwrite = -1; - opt->bufnum = -1; - opt->bufsize = -1; - strcpy(opt->chan_name, opt_name); - } -} - -static struct lttctl_option *find_insert_channel_opt(char *opt_name) -{ - struct lttctl_option *iter, *new_opt; - - if (!opt_head) { - opt_head = (struct lttctl_option *)malloc(sizeof(struct lttctl_option)); - init_channel_opt(&opt_head->opt_mode.chan_opt, opt_name); - opt_head->type = CHANNEL; - opt_head->next = NULL; - last_opt = opt_head; - return opt_head; - } - - for (iter = opt_head; iter; iter = iter->next) { - if (iter->type != CHANNEL) - continue; - if (!strcmp(iter->opt_mode.chan_opt.chan_name, opt_name)) - return iter; - } - - new_opt = (struct lttctl_option *)malloc(sizeof(struct lttctl_option)); - init_channel_opt(&new_opt->opt_mode.chan_opt, opt_name); - new_opt->type = CHANNEL; - new_opt->next = NULL; - last_opt->next = new_opt; - last_opt = new_opt; - return new_opt; -} - -int set_channel_opt(struct channel_option *opt, char *opt_name, char *opt_valstr) -{ - int opt_val, ret; - - if (!strcmp("enable", opt_name)) { - if (opt_valstr[1] != 0) { - return -EINVAL; - } - if (opt_valstr[0] == 'Y' || opt_valstr[0] == 'y' - || opt_valstr[0] == '1') - opt_val = 1; - else if (opt_valstr[0] == 'N' || opt_valstr[0] == 'n' - || opt_valstr[0] == '0') - opt_val = 0; - else { - return -EINVAL; - } - - opt->enable = opt_val; - return 0; - } else if (!strcmp("overwrite", opt_name)) { - if (opt_valstr[1] != 0) { - return -EINVAL; - } - if (opt_valstr[0] == 'Y' || opt_valstr[0] == 'y' - || opt_valstr[0] == '1') - opt_val = 1; - else if (opt_valstr[0] == 'N' || opt_valstr[0] == 'n' - || opt_valstr[0] == '0') - opt_val = 0; - else { - return -EINVAL; - } - - opt->overwrite = opt_val; - return 0; - - } else if (!strcmp("bufnum", opt_name)) { - ret = sscanf(opt_valstr, "%d", &opt_val); - if (ret != 1 || opt_val < 0) { - return -EINVAL; - } - - opt->bufnum = opt_val; - return 0; - } else if (!strcmp("bufsize", opt_name)) { - ret = sscanf(opt_valstr, "%d", &opt_val); - if (ret != 1 || opt_val < 0) { - return -EINVAL; - } - - opt->bufsize = opt_val; - return 0; - } else { - return -EINVAL; - } - -} - -static int parst_opt(const char *optarg) -{ - int ret; - char opt_name[OPT_NAMELEN * 3]; - char opt_valstr[OPT_VALSTRINGLEN]; - char *p; - - char name1[OPT_NAMELEN]; - char name2[OPT_NAMELEN]; - char name3[OPT_NAMELEN]; - - int opt_intval; - int opt_val; - unsigned int opt_uintval; - struct lttctl_option *opt; - - if (!optarg) { - fprintf(stderr, "Option empty\n"); - return -EINVAL; - } - - /* Get option name and val_str */ - p = strchr(optarg, '='); - if (!p) { - fprintf(stderr, "Option format error: %s\n", optarg); - return -EINVAL; - } - - if (p - optarg >= sizeof(opt_name)/sizeof(opt_name[0])) { - fprintf(stderr, "Option name too long: %s\n", optarg); - return -EINVAL; - } - - if (strlen(p+1) >= OPT_VALSTRINGLEN) { - fprintf(stderr, "Option value too long: %s\n", optarg); - return -EINVAL; - } - - memcpy(opt_name, optarg, p - optarg); - opt_name[p - optarg] = 0; - strcpy(opt_valstr, p+1); - - /* separate option name into 3 fields */ - ret = separate_opt(opt_name, name1, name2, name3); - if (ret != 0) { - fprintf(stderr, "Option name error1: %s\n", optarg); - return -EINVAL; - } - - if (!strcmp("channel", name1)) { - opt = find_insert_channel_opt(name2); - if ((ret = set_channel_opt(&opt->opt_mode.chan_opt, - name3, opt_valstr) != 0)) { - fprintf(stderr, "Option name error2: %s\n", optarg); - return ret; - } - } else { - fprintf(stderr, "Option name error3: %s\n", optarg); - return -EINVAL; - } - - return 0; -} - -/* parse_arguments - * - * Parses the command line arguments. - * - * Returns -1 if the arguments were correct, but doesn't ask for program - * continuation. Returns EINVAL if the arguments are incorrect, or 0 if OK. - */ -static int parse_arguments(int argc, char **argv) -{ - int ret = 0; - - static struct option longopts[] = { - {"create", no_argument, NULL, 'c'}, - {"destroy", no_argument, NULL, 'd'}, - {"start", no_argument, NULL, 's'}, - {"pause", no_argument, NULL, 'p'}, - {"help", no_argument, NULL, 'h'}, - {"transport", required_argument, NULL, 2}, - {"option", required_argument, NULL, 'o'}, - {"create_start", no_argument, NULL, 'C'}, - {"pause_destroy", no_argument, NULL, 'D'}, - {"write", required_argument, NULL, 'w'}, - {"append", no_argument, NULL, 'a'}, - {"dump_threads", required_argument, NULL, 'n'}, - {"channel_root", required_argument, NULL, 3}, - { NULL, 0, NULL, 0 }, - }; - - /* - * Enable all channels in default - * To make novice users happy - */ - parst_opt("channel.all.enable=1"); - - opterr = 1; /* Print error message on getopt_long */ - while (1) { - int c; - c = getopt_long(argc, argv, "cdspho:CDw:an:", longopts, NULL); - if (-1 == c) { - /* parse end */ - break; - } - switch (c) { - case 'c': - opt_create = 1; - break; - case 'd': - opt_destroy = 1; - break; - case 's': - opt_start = 1; - break; - case 'p': - opt_pause = 1; - break; - case 'h': - opt_help = 1; - break; - case 2: - if (!opt_transport) { - opt_transport = optarg; - } else { - fprintf(stderr, - "Please specify only 1 transport\n"); - return -EINVAL; - } - break; - case 'o': - ret = parst_opt(optarg); - if (ret) - return ret; - break; - case 'C': - opt_create = 1; - opt_start = 1; - break; - case 'D': - opt_pause = 1; - opt_destroy = 1; - break; - case 'w': - if (!opt_write) { - opt_write = optarg; - } else { - fprintf(stderr, - "Please specify only 1 write dir\n"); - return -EINVAL; - } - break; - case 'a': - opt_append = 1; - break; - case 'n': - if (opt_dump_threads) { - fprintf(stderr, - "Please specify only 1 dump threads\n"); - return -EINVAL; - } - - ret = sscanf(optarg, "%u", &opt_dump_threads); - if (ret != 1) { - fprintf(stderr, - "Dump threads not positive number\n"); - return -EINVAL; - } - break; - case 3: - if (!opt_channel_root) { - opt_channel_root = optarg; - } else { - fprintf(stderr, - "Please specify only 1 channel root\n"); - return -EINVAL; - } - break; - case '?': - return -EINVAL; - default: - break; - }; - }; - - /* Don't check args when user needs help */ - if (opt_help) - return 0; - - /* Get tracename */ - if (optind < argc - 1) { - fprintf(stderr, "Please specify only 1 trace name\n"); - return -EINVAL; - } - if (optind > argc - 1) { - fprintf(stderr, "Please specify trace name\n"); - return -EINVAL; - } - opt_tracename = argv[optind]; - - /* - * Check arguments - */ - if (!opt_create && !opt_start && !opt_destroy && !opt_pause) { - fprintf(stderr, - "Please specify a option of " - "create, destroy, start, or pause\n"); - return -EINVAL; - } - - if ((opt_create || opt_start) && (opt_destroy || opt_pause)) { - fprintf(stderr, - "Create and start conflict with destroy and pause\n"); - return -EINVAL; - } - - if (opt_create) { - if (!opt_transport) - opt_transport = "relay"; - } - - if (opt_transport) { - if (!opt_create) { - fprintf(stderr, - "Transport option must be combine with create" - " option\n"); - return -EINVAL; - } - } - - if (opt_write) { - if (!opt_create && !opt_destroy) { - fprintf(stderr, - "Write option must be combine with create or" - " destroy option\n"); - return -EINVAL; - } - - if (!opt_channel_root) - if (getdebugfsmntdir(channel_root_default) == 0) { - strcat(channel_root_default, "/ltt"); - opt_channel_root = channel_root_default; - } else { - fprintf(stderr, - "Channel_root is necessary for -w" - " option, but neither --channel_root" - " option\n" - "specified, nor debugfs's mount dir" - " found, mount debugfs also failed\n"); - return -EINVAL; - } - - if (opt_dump_threads == 0) - opt_dump_threads = 1; - } - - if (opt_append) { - if (!opt_write) { - fprintf(stderr, - "Append option must be combine with write" - " option\n"); - return -EINVAL; - } - } - - if (opt_dump_threads) { - if (!opt_write) { - fprintf(stderr, - "Dump_threads option must be combine with write" - " option\n"); - return -EINVAL; - } - } - - if (opt_channel_root) { - if (!opt_write) { - fprintf(stderr, - "Channel_root option must be combine with write" - " option\n"); - return -EINVAL; - } - } - - return 0; -} - -static void show_info(void) -{ - printf("Linux Trace Toolkit Trace Control " VERSION"\n"); - printf("\n"); - if (opt_tracename != NULL) { - printf("Controlling trace : %s\n", opt_tracename); - printf("\n"); - } -} - -static int lttctl_channel_setup(struct channel_option *opt) -{ - int ret; - - if (opt->enable != -1) { - if ((ret = lttctl_set_channel_enable(opt_tracename, - opt->chan_name, - opt->enable)) != 0) - return ret; - } - if (opt->overwrite != -1) { - if ((ret = lttctl_set_channel_overwrite(opt_tracename, - opt->chan_name, - opt->overwrite)) != 0) - return ret; - } - if (opt->bufnum != -1) { - if ((ret = lttctl_set_channel_subbuf_num(opt_tracename, - opt->chan_name, - opt->bufnum)) != 0) - return ret; - } - if (opt->bufsize != -1) { - if ((ret = lttctl_set_channel_subbuf_size(opt_tracename, - opt->chan_name, - opt->bufsize)) != 0) - return ret; - } - - return 0; -} - -static int lttctl_create_trace(void) -{ - int ret; - int i; - struct lttctl_option *opt; - - ret = lttctl_setup_trace(opt_tracename); - if (ret) - goto setup_trace_fail; - - for (opt = opt_head; opt; opt = opt->next) { - if (opt->type != CHANNEL) - continue; - ret = lttctl_channel_setup(&opt->opt_mode.chan_opt); - if (ret) - goto set_option_fail;; - } - - ret = lttctl_set_trans(opt_tracename, opt_transport); - if (ret) - goto set_option_fail; - - ret = lttctl_alloc_trace(opt_tracename); - if (ret) - goto alloc_trace_fail; - - return 0; - -alloc_trace_fail: -set_option_fail: - lttctl_destroy_trace(opt_tracename); -setup_trace_fail: - return ret; -} - -/* - * Start a lttd daemon to write trace datas - * Dump overwrite channels on overwrite!=0 - * Dump normal(non-overwrite) channels on overwrite=0 - * - * ret: 0 on success - * !0 on fail - */ -static int lttctl_daemon(int overwrite) -{ - pid_t pid; - int status; - - pid = fork(); - if (pid < 0) { - perror("Error in forking for lttd daemon"); - return errno; - } - - if (pid == 0) { - /* child */ - char *argv[16]; - int argc = 0; - char channel_path[PATH_MAX]; - char thread_num[16]; - - /* prog path */ - argv[argc] = getenv("LTT_DAEMON"); - if (argv[argc] == NULL) - argv[argc] = PACKAGE_BIN_DIR "/lttd"; - argc++; - - /* -t option */ - argv[argc] = "-t"; - argc++; - /* - * we allow modify of opt_write's content in new process - * for get rid of warning of assign char * to const char * - */ - argv[argc] = (char *)opt_write; - argc++; - - /* -c option */ - strcpy(channel_path, opt_channel_root); - strcat(channel_path, "/"); - strcat(channel_path, opt_tracename); - argv[argc] = "-c"; - argc++; - argv[argc] = channel_path; - argc++; - - /* -N option */ - sprintf(thread_num, "%u", opt_dump_threads); - argv[argc] = "-N"; - argc++; - argv[argc] = thread_num; - argc++; - - /* -a option */ - if (opt_append) { - argv[argc] = "-a"; - argc++; - } - - /* -d option */ - argv[argc] = "-d"; - argc++; - - /* overwrite option */ - if (overwrite) { - argv[argc] = "-f"; - argc++; - } else { - argv[argc] = "-n"; - argc++; - } - - argv[argc] = NULL; - - execvp(argv[0], argv); - - perror("Error in executing the lttd daemon"); - exit(errno); - } - - /* parent */ - if (waitpid(pid, &status, 0) == -1) { - perror("Error in waitpid\n"); - return errno; - } - - if (!WIFEXITED(status)) { - fprintf(stderr, "lttd process interrupted\n"); - return status; - } - - if (WEXITSTATUS(status)) - fprintf(stderr, "lttd process running failed\n"); - - return WEXITSTATUS(status); -} - -int main(int argc, char **argv) -{ - int ret; - - ret = parse_arguments(argc, argv); - /* If user needs show help, we disregard other options */ - if (opt_help) { - show_arguments(); - return 0; - } - - /* exit program if arguments wrong */ - if (ret) - return 1; - - show_info(); - - ret = lttctl_init(); - if (ret != 0) - return ret; - - if (opt_create) { - printf("lttctl: Creating trace\n"); - ret = lttctl_create_trace(); - if (ret) - goto op_fail; - - if (opt_write) { - printf("lttctl: Forking lttd\n"); - ret = lttctl_daemon(0); - if (ret) - goto op_fail; - } - } - - if (opt_start) { - printf("lttctl: Starting trace\n"); - ret = lttctl_start(opt_tracename); - if (ret) - goto op_fail; - } - - if (opt_pause) { - printf("lttctl: Pausing trace\n"); - ret = lttctl_pause(opt_tracename); - if (ret) - goto op_fail; - } - - if (opt_destroy) { - if (opt_write) { - printf("lttctl: Forking lttd\n"); - ret = lttctl_daemon(1); - if (ret) - goto op_fail; - } - - printf("lttctl: Destroying trace\n"); - ret = lttctl_destroy_trace(opt_tracename); - if (ret) - goto op_fail; - } - -op_fail: - lttctl_destroy(); - - return ret; -} diff --git a/trunk/ltt-control/lttctl/lttctl_distributed.sh b/trunk/ltt-control/lttctl/lttctl_distributed.sh deleted file mode 100644 index 4e75182..0000000 --- a/trunk/ltt-control/lttctl/lttctl_distributed.sh +++ /dev/null @@ -1,293 +0,0 @@ -#!/bin/bash -# Copyright (C) 2006 Eric Clément -# -# 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. -# -# 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. -# -# purpose : automatic generation of traces with LTT in a network. -# usage : -# -# you need SSH connection without password for all computers that you want -# trace. You might put le name of those computers (uname -n) in a file -# (liste.txt by default). LTT might be installed in the same way for those -# computer. -# You can customize your path. This script can also generate traffic TCP and -# UDP. A UDP monitor is use to validate the result (this is the first computer -# in the file (liste.txt)). -# -# usage: ./lttclt_distributed.sh time freq mode_generator {options} -# -# time (seconds) : duration a the tracing -# freq (nb packet/second or nb packet/ms) : communication frequency when TCP -# generator is used, 0 otherwise -# mode_generator : 1 : traffic generator off -# 2 : traffic generator TCP on (nb packet/second) -# 3 : traffic generator TCP on (nb packet/ms) -# -# options (optional): 1 : enable the UDP monitor (1packet/second is generated -# by all UDP client) -# -# you need : ssh, scp and zip - -TCP_SERVER=tcpserver -TCP_CLIENT=tcpclient - -UDP_SERVER=udpserver -UDP_CLIENT=udpclient - -PATH_TRACE=/root/trace-ltt/ -PATH_DEBUGFS=/debugfs/ltt/ -SET_LTT_FACILITIES="export LTT_FACILITIES=/home/ercle/NEW_GENERATION_LTTV/share/LinuxTraceToolkitViewer/facilities/" -SET_LTT_DAEMON="export LTT_DAEMON=/home/ercle/NEW_GENERATION_LTTV/bin/lttd" - -START_DAEMON="/home/ercle/NEW_GENERATION_LTTV/bin/lttctl -d -n \ -trace1 -t $PATH_TRACE -l $PATH_DEBUGFS >/dev/null" - -STOP_DAEMON="/home/ercle/NEW_GENERATION_LTTV/bin/lttctl -n trace1 -q >/dev/null" -REMOVE_DAEMON="/home/ercle/NEW_GENERATION_LTTV/bin/lttctl -n trace1 -r >/dev/null" -REMOVE_TRACE="rm -rf $PATH_TRACE" - -E_FNEXIST=100 - -FILE_LISTE=liste.txt -TRACE_DAEMON=/tmp/daemon- - -if [ $# -lt 3 ] -then - echo "usage: $0 time freq mode_generator {options}" - exit 1 -elif [ $# -gt 4 ] -then - echo "usage: $0 time freq mode_generator {options}" - exit 1 -fi - -if [ -e $FILE_LISTE ] -then - - time=$1 - freq=$2 - mode_generator=$3 - if [ $# -eq 4 ] - then - mode_monitor=$4 - else - mode_monitor=0 - fi - -#create script generator - FILE_OUT=daemon- - - if [ $mode_generator -eq 3 ] - then - TCP_CLIENT=tcpclient_ms - fi - - nb_node=0 - for line in $( cat $FILE_LISTE ); - do - let nb_node+=1 - - echo $REMOVE_TRACE > "$FILE_OUT$line.sh" - echo mkdir $PATH_TRACE >> "$FILE_OUT$line.sh" - echo $SET_LTT_FACILITIES >> "$FILE_OUT$line.sh" - echo $SET_LTT_DAEMON >> "$FILE_OUT$line.sh" - echo $START_DAEMON >> "$FILE_OUT$line.sh" - - chmod +x "$FILE_OUT$line.sh" - - if [ $mode_generator -ge 2 ] #if generator de trafic enable (2 or 3) - then - if [ $nb_node -eq 1 -a $mode_monitor -eq 1 ] - then - monitor=$line - echo "/tmp/$UDP_SERVER >/dev/null &" >> "$FILE_OUT$line.sh" - scp "$UDP_SERVER" $line:/tmp/ - - echo "sleep $time" >> "$FILE_OUT$line.sh" - echo "kill \`ps -A |grep $UDP_SERVER | awk '{ print \$1 }'\`" >> "$FILE_OUT$line.sh" - else - if [ $mode_monitor -eq 1 ] - then - echo "/tmp/$UDP_CLIENT $monitor $time 1 >/dev/null & " >> "$FILE_OUT$line.sh" - scp "$UDP_CLIENT" $line:/tmp/ - fi - - echo "/tmp/$TCP_SERVER >/dev/null &" >> "$FILE_OUT$line.sh" - scp "$TCP_SERVER" $line:/tmp/ - compteur=0 - for line2 in $( cat $FILE_LISTE ); - do - let compteur+=1 - if [ $compteur -gt $nb_node ] - then - echo "/tmp/$TCP_CLIENT $line2 $time $freq >/dev/null &" >> "$FILE_OUT$line.sh" - scp "$TCP_CLIENT" $line:/tmp/ - fi - done - - echo "sleep $time" >> "$FILE_OUT$line.sh" - echo "kill \`ps -A |grep $TCP_SERVER | awk '{ print \$1 }'\`" >> "$FILE_OUT$line.sh" - fi - fi - - echo $STOP_DAEMON >> "$FILE_OUT$line.sh" - echo $REMOVE_DAEMON >> "$FILE_OUT$line.sh" - - #script for get node information - ENDIAN=endian - echo 'FILE_OUT=`uname -n`.info' >> "$FILE_OUT$line.sh" - echo 'ENDIAN=endian' >> "$FILE_OUT$line.sh" - echo ' exec 6>&1' >> "$FILE_OUT$line.sh" - echo ' exec > /tmp/$FILE_OUT' >> "$FILE_OUT$line.sh" - echo ' echo `uname -n`' >> "$FILE_OUT$line.sh" - echo '' >> "$FILE_OUT$line.sh" - echo ' /tmp/$ENDIAN || ( echo >&6 && echo "** ERROR **: problem occur with /tmp/$ENDIAN" >&6 && echo >&6)' >> "$FILE_OUT$line.sh" - echo '' >> "$FILE_OUT$line.sh" - echo -e ' /sbin/ifconfig | grep addr: | awk \047{print $2}\047 | sed /127.0.0.1/d | sed s/addr:// | sed /^$/d #english' >> "$FILE_OUT$line.sh" - echo -e ' /sbin/ifconfig | grep adr: | awk \047{print $2}\047 | sed /127.0.0.1/d | sed s/adr:// | sed /^$/d #french' >> "$FILE_OUT$line.sh" - echo ' echo END' >> "$FILE_OUT$line.sh" - echo '' >> "$FILE_OUT$line.sh" - echo ' exec 1>&6 6>&-' >> "$FILE_OUT$line.sh" - echo '' >> "$FILE_OUT$line.sh" - echo ' echo "$FILE_OUT done"' >> "$FILE_OUT$line.sh" - echo '' >> "$FILE_OUT$line.sh" - - #send files - if [ $mode_generator -ge 2 -a $nb_node -eq 1 -a $mode_monitor -eq 1 ] - then - echo mv /tmp/'`uname -n`'.info /tmp/'`uname -n`'.monitor >> "$FILE_OUT$line.sh" - echo scp /tmp/'`uname -n`'.monitor `uname -n`:`pwd`/ >> "$FILE_OUT$line.sh" - else - echo scp /tmp/'`uname -n`'.info `uname -n`:`pwd`/ >> "$FILE_OUT$line.sh" - fi - - echo ' exit 0' >> "$FILE_OUT$line.sh" - - scp "$FILE_OUT$line.sh" $line:/tmp/ - scp "$ENDIAN" $line:/tmp/ - rm "$FILE_OUT$line.sh" - done -#end script generator - -#start traces !! - sleep 1 - - for line in $( cat $FILE_LISTE ); - do - echo ssh -f "$line $TRACE_DAEMON$line.sh " - ssh -f $line "$TRACE_DAEMON$line.sh" - done - -else - echo "error: file $FILE_LISTE doesn't exist" - exit E_FNEXIST -fi - -date - -sleep $time - -# is all daemon stop ? -for line in $( cat $FILE_LISTE ); - do - - daemon_present="true" - wait_time=1 - while [ $daemon_present == "true" ] - do - daemon_present="false" - (ssh $line ps -A |grep lttd) && daemon_present="true" - sleep $wait_time - let wait_time+=1 - done - done - -#get all traces -nb_computer=0 -zip_path="" -for line in $( cat $FILE_LISTE ); - do - mkdir `pwd`/$line 2>/dev/null - scp -q -r $line:$PATH_TRACE/ `pwd`/$line - zip_path="$zip_path $line" - let nb_computer+=1 - done - -#get network informatioin -FILE_TMP=ls.tmp -FILE_OUT=network.trace - -exec 3> $FILE_TMP #open FILE_TMP (Write) - -ls *.monitor >&3 2>/dev/null - -#get the list of .info file to parse -ls *.info >&3 || (echo EMPTY >&3) -echo END >&3 - -exec 3>&- #close FILE_TMP - -exec 3< $FILE_TMP #open FILE_TMP (Read) -read line <&3 -if [ "$line" = "EMPTY" ] -then - echo "NO .info file" - exec 3>&- #close FILE_TMP - rm -rf $FILE_TMP - exit 1 -fi - -exec 5> $FILE_OUT #open FILE_OUT (Write) - -echo -e "Nb IP\tName\t\endianness\tIP ..." -echo -e "Nb IP\tName\tendianness\tIP ..." >&5 - -while [ "$line" != "END" ] -do - echo "++++++++++++++++++++" - echo "in file $line" - - output="" - nb_ip=-2 #1st line => name, 2 line => endianness - exec 4< $line - read answer <&4 - - while [ "$answer" != "END" ] - do - nb_ip=`expr $nb_ip + 1` - output="$output\n$answer" - read answer <&4 - done - - echo -e "$nb_ip$output" - echo -e "$nb_ip$output" >&5 - exec 4<&- - mv $line "$line.read" - read line <&3 - echo "---------------------" -done - -exec 3>&- #close FILE_TMP -rm -rf $FILE_TMP -echo END >&5 -exec 5<&- #close FILE_OUT - -#zip files - root=`pwd` - cd $root && echo $root - nomfic="trace__nb_computer"$nb_computer"__time"$time"__freq"$freq"__"`uname -n``date '+__%d%b__%H-%M-%S'`$options".zip" - - zip -r $nomfic $zip_path *.info.read *.monitor.read *.trace>/dev/null - echo -e "zip done $zip_path\n$root/$nomfic" - - exec 3<&- - -echo -e "\a$0 done!" -exit 0 diff --git a/trunk/ltt-control/lttd/Makefile.am b/trunk/ltt-control/lttd/Makefile.am deleted file mode 100644 index bb860bc..0000000 --- a/trunk/ltt-control/lttd/Makefile.am +++ /dev/null @@ -1,8 +0,0 @@ -# Empty TraceDaemon Makefile.am. Insert a real one here. - -LIBS += $(THREAD_LIBS) - -bin_PROGRAMS = lttd - -lttd_SOURCES = lttd.c - diff --git a/trunk/ltt-control/lttd/lttd.c b/trunk/ltt-control/lttd/lttd.c deleted file mode 100644 index f21c411..0000000 --- a/trunk/ltt-control/lttd/lttd.c +++ /dev/null @@ -1,1012 +0,0 @@ -/* lttd - * - * Linux Trace Toolkit Daemon - * - * This is a simple daemon that reads a few relay+debugfs channels and save - * them in a trace. - * - * CPU hot-plugging is supported using inotify. - * - * Copyright 2005 - - * Mathieu Desnoyers - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#define _REENTRANT -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* Relayfs IOCTL */ -#include -#include - -/* Get the next sub buffer that can be read. */ -#define RELAY_GET_SUBBUF _IOR(0xF5, 0x00,__u32) -/* Release the oldest reserved (by "get") sub buffer. */ -#define RELAY_PUT_SUBBUF _IOW(0xF5, 0x01,__u32) -/* returns the number of sub buffers in the per cpu channel. */ -#define RELAY_GET_N_SUBBUFS _IOR(0xF5, 0x02,__u32) -/* returns the size of the sub buffers. */ -#define RELAY_GET_SUBBUF_SIZE _IOR(0xF5, 0x03,__u32) - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14) -#include -#if 0 /* should now be provided by libc. */ -/* From the inotify-tools 2.6 package */ -static inline int inotify_init (void) -{ - return syscall (__NR_inotify_init); -} - -static inline int inotify_add_watch (int fd, const char *name, __u32 mask) -{ - return syscall (__NR_inotify_add_watch, fd, name, mask); -} - -static inline int inotify_rm_watch (int fd, __u32 wd) -{ - return syscall (__NR_inotify_rm_watch, fd, wd); -} -#endif //0 -#define HAS_INOTIFY -#else -static inline int inotify_init (void) -{ - return -1; -} - -static inline int inotify_add_watch (int fd, const char *name, __u32 mask) -{ - return 0; -} - -static inline int inotify_rm_watch (int fd, __u32 wd) -{ - return 0; -} -#undef HAS_INOTIFY -#endif - -enum { - GET_SUBBUF, - PUT_SUBBUF, - GET_N_BUBBUFS, - GET_SUBBUF_SIZE -}; - -struct fd_pair { - int channel; - int trace; - unsigned int n_subbufs; - unsigned int subbuf_size; - void *mmap; - pthread_mutex_t mutex; -}; - -struct channel_trace_fd { - struct fd_pair *pair; - int num_pairs; -}; - -struct inotify_watch { - int wd; - char path_channel[PATH_MAX]; - char path_trace[PATH_MAX]; -}; - -struct inotify_watch_array { - struct inotify_watch *elem; - int num; -}; - -static __thread int thread_pipe[2]; - -struct channel_trace_fd fd_pairs = { NULL, 0 }; -int inotify_fd = -1; -struct inotify_watch_array inotify_watch_array = { NULL, 0 }; - -/* protects fd_pairs and inotify_watch_array */ -pthread_rwlock_t fd_pairs_lock = PTHREAD_RWLOCK_INITIALIZER; - - -static char *trace_name = NULL; -static char *channel_name = NULL; -static int daemon_mode = 0; -static int append_mode = 0; -static unsigned long num_threads = 1; -volatile static int quit_program = 0; /* For signal handler */ -static int dump_flight_only = 0; -static int dump_normal_only = 0; -static int verbose_mode = 0; - -#define printf_verbose(fmt, args...) \ - do { \ - if (verbose_mode) \ - printf(fmt, ##args); \ - } while (0) - -/* Args : - * - * -t directory Directory name of the trace to write to. Will be created. - * -c directory Root directory of the debugfs trace channels. - * -d Run in background (daemon). - * -a Trace append mode. - * -s Send SIGUSR1 to parent when ready for IO. - */ -void show_arguments(void) -{ - printf("Please use the following arguments :\n"); - printf("\n"); - printf("-t directory Directory name of the trace to write to.\n" - " It will be created.\n"); - printf("-c directory Root directory of the debugfs trace channels.\n"); - printf("-d Run in background (daemon).\n"); - printf("-a Append to an possibly existing trace.\n"); - printf("-N Number of threads to start.\n"); - printf("-f Dump only flight recorder channels.\n"); - printf("-n Dump only normal channels.\n"); - printf("-v Verbose mode.\n"); - printf("\n"); -} - - -/* parse_arguments - * - * Parses the command line arguments. - * - * Returns 1 if the arguments were correct, but doesn't ask for program - * continuation. Returns -1 if the arguments are incorrect, or 0 if OK. - */ -int parse_arguments(int argc, char **argv) -{ - int ret = 0; - int argn = 1; - - if(argc == 2) { - if(strcmp(argv[1], "-h") == 0) { - return 1; - } - } - - while(argn < argc) { - - switch(argv[argn][0]) { - case '-': - switch(argv[argn][1]) { - case 't': - if(argn+1 < argc) { - trace_name = argv[argn+1]; - argn++; - } - break; - case 'c': - if(argn+1 < argc) { - channel_name = argv[argn+1]; - argn++; - } - break; - case 'd': - daemon_mode = 1; - break; - case 'a': - append_mode = 1; - break; - case 'N': - if(argn+1 < argc) { - num_threads = strtoul(argv[argn+1], NULL, 0); - argn++; - } - break; - case 'f': - dump_flight_only = 1; - break; - case 'n': - dump_normal_only = 1; - break; - case 'v': - verbose_mode = 1; - break; - default: - printf("Invalid argument '%s'.\n", argv[argn]); - printf("\n"); - ret = -1; - } - break; - default: - printf("Invalid argument '%s'.\n", argv[argn]); - printf("\n"); - ret = -1; - } - argn++; - } - - if(trace_name == NULL) { - printf("Please specify a trace name.\n"); - printf("\n"); - ret = -1; - } - - if(channel_name == NULL) { - printf("Please specify a channel name.\n"); - printf("\n"); - ret = -1; - } - - return ret; -} - -void show_info(void) -{ - printf("Linux Trace Toolkit Trace Daemon " VERSION "\n"); - printf("\n"); - printf("Reading from debugfs directory : %s\n", channel_name); - printf("Writing to trace directory : %s\n", trace_name); - printf("\n"); -} - - -/* signal handling */ - -static void handler(int signo) -{ - printf("Signal %d received : exiting cleanly\n", signo); - quit_program = 1; -} - - -int open_buffer_file(char *filename, char *path_channel, char *path_trace, - struct channel_trace_fd *fd_pairs) -{ - int open_ret = 0; - int ret = 0; - struct stat stat_buf; - - if(strncmp(filename, "flight-", sizeof("flight-")-1) != 0) { - if(dump_flight_only) { - printf_verbose("Skipping normal channel %s\n", - path_channel); - return 0; - } - } else { - if(dump_normal_only) { - printf_verbose("Skipping flight channel %s\n", - path_channel); - return 0; - } - } - printf_verbose("Opening file.\n"); - - fd_pairs->pair = realloc(fd_pairs->pair, - ++fd_pairs->num_pairs * sizeof(struct fd_pair)); - - /* Open the channel in read mode */ - fd_pairs->pair[fd_pairs->num_pairs-1].channel = - open(path_channel, O_RDONLY | O_NONBLOCK); - if(fd_pairs->pair[fd_pairs->num_pairs-1].channel == -1) { - perror(path_channel); - fd_pairs->num_pairs--; - return 0; /* continue */ - } - /* Open the trace in write mode, only append if append_mode */ - ret = stat(path_trace, &stat_buf); - if(ret == 0) { - if(append_mode) { - printf_verbose("Appending to file %s as requested\n", - path_trace); - - fd_pairs->pair[fd_pairs->num_pairs-1].trace = - open(path_trace, O_WRONLY, - S_IRWXU|S_IRWXG|S_IRWXO); - if(fd_pairs->pair[fd_pairs->num_pairs-1].trace == -1) { - perror(path_trace); - } - ret = lseek(fd_pairs->pair[fd_pairs->num_pairs-1].trace, - 0, SEEK_END); - if (ret < 0) { - perror(path_trace); - } - } else { - printf("File %s exists, cannot open. Try append mode.\n", path_trace); - open_ret = -1; - goto end; - } - } else { - if(errno == ENOENT) { - fd_pairs->pair[fd_pairs->num_pairs-1].trace = - open(path_trace, O_WRONLY|O_CREAT|O_EXCL, - S_IRWXU|S_IRWXG|S_IRWXO); - if(fd_pairs->pair[fd_pairs->num_pairs-1].trace == -1) { - perror(path_trace); - } - } - } -end: - return open_ret; -} - -int open_channel_trace_pairs(char *subchannel_name, char *subtrace_name, - struct channel_trace_fd *fd_pairs, int *inotify_fd, - struct inotify_watch_array *iwatch_array) -{ - DIR *channel_dir = opendir(subchannel_name); - struct dirent *entry; - struct stat stat_buf; - int ret; - char path_channel[PATH_MAX]; - int path_channel_len; - char *path_channel_ptr; - char path_trace[PATH_MAX]; - int path_trace_len; - char *path_trace_ptr; - int open_ret = 0; - - if(channel_dir == NULL) { - perror(subchannel_name); - open_ret = ENOENT; - goto end; - } - - printf_verbose("Creating trace subdirectory %s\n", subtrace_name); - ret = mkdir(subtrace_name, S_IRWXU|S_IRWXG|S_IRWXO); - if(ret == -1) { - if(errno != EEXIST) { - perror(subtrace_name); - open_ret = -1; - goto end; - } - } - - strncpy(path_channel, subchannel_name, PATH_MAX-1); - path_channel_len = strlen(path_channel); - path_channel[path_channel_len] = '/'; - path_channel_len++; - path_channel_ptr = path_channel + path_channel_len; - - strncpy(path_trace, subtrace_name, PATH_MAX-1); - path_trace_len = strlen(path_trace); - path_trace[path_trace_len] = '/'; - path_trace_len++; - path_trace_ptr = path_trace + path_trace_len; - -#ifdef HAS_INOTIFY - iwatch_array->elem = realloc(iwatch_array->elem, - ++iwatch_array->num * sizeof(struct inotify_watch)); - - printf_verbose("Adding inotify for channel %s\n", path_channel); - iwatch_array->elem[iwatch_array->num-1].wd = inotify_add_watch(*inotify_fd, path_channel, IN_CREATE); - strcpy(iwatch_array->elem[iwatch_array->num-1].path_channel, path_channel); - strcpy(iwatch_array->elem[iwatch_array->num-1].path_trace, path_trace); - printf_verbose("Added inotify for channel %s, wd %u\n", - iwatch_array->elem[iwatch_array->num-1].path_channel, - iwatch_array->elem[iwatch_array->num-1].wd); -#endif - - while((entry = readdir(channel_dir)) != NULL) { - - if(entry->d_name[0] == '.') continue; - - strncpy(path_channel_ptr, entry->d_name, PATH_MAX - path_channel_len); - strncpy(path_trace_ptr, entry->d_name, PATH_MAX - path_trace_len); - - ret = stat(path_channel, &stat_buf); - if(ret == -1) { - perror(path_channel); - continue; - } - - printf_verbose("Channel file : %s\n", path_channel); - - if(S_ISDIR(stat_buf.st_mode)) { - - printf_verbose("Entering channel subdirectory...\n"); - ret = open_channel_trace_pairs(path_channel, path_trace, fd_pairs, - inotify_fd, iwatch_array); - if(ret < 0) continue; - } else if(S_ISREG(stat_buf.st_mode)) { - open_ret = open_buffer_file(entry->d_name, path_channel, path_trace, - fd_pairs); - if(open_ret) - goto end; - } - } - -end: - closedir(channel_dir); - - return open_ret; -} - - -int read_subbuffer(struct fd_pair *pair) -{ - unsigned int consumed_old; - int err; - long ret; - unsigned long len; - off_t offset; - - - err = ioctl(pair->channel, RELAY_GET_SUBBUF, &consumed_old); - printf_verbose("cookie : %u\n", consumed_old); - if(err != 0) { - ret = errno; - perror("Reserving sub buffer failed (everything is normal, it is due to concurrency)"); - goto get_error; - } -#if 0 - err = TEMP_FAILURE_RETRY(write(pair->trace, - pair->mmap - + (consumed_old & ((pair->n_subbufs * pair->subbuf_size)-1)), - pair->subbuf_size)); - - if(err < 0) { - ret = errno; - perror("Error in writing to file"); - goto write_error; - } -#endif //0 - len = pair->subbuf_size; - offset = 0; - while (len > 0) { - printf_verbose("splice chan to pipe offset %lu\n", - (unsigned long)offset); - ret = splice(pair->channel, &offset, thread_pipe[1], NULL, - len, SPLICE_F_MOVE); - printf_verbose("splice chan to pipe ret %ld\n", ret); - if (ret < 0) { - perror("Error in relay splice"); - goto write_error; - } - ret = splice(thread_pipe[0], NULL, pair->trace, NULL, - ret, SPLICE_F_MOVE); - printf_verbose("splice pipe to file %ld\n", ret); - if (ret < 0) { - perror("Error in file splice"); - goto write_error; - } - len -= ret; - } - -#if 0 - err = fsync(pair->trace); - if(err < 0) { - ret = errno; - perror("Error in writing to file"); - goto write_error; - } -#endif //0 -write_error: - ret = 0; - err = ioctl(pair->channel, RELAY_PUT_SUBBUF, &consumed_old); - if(err != 0) { - ret = errno; - if(errno == EFAULT) { - perror("Error in unreserving sub buffer\n"); - } else if(errno == EIO) { - perror("Reader has been pushed by the writer, last subbuffer corrupted."); - /* FIXME : we may delete the last written buffer if we wish. */ - } - goto get_error; - } - -get_error: - return ret; -} - - -int map_channels(struct channel_trace_fd *fd_pairs, - int idx_begin, int idx_end) -{ - int i,j; - int ret=0; - - if(fd_pairs->num_pairs <= 0) { - printf("No channel to read\n"); - goto end; - } - - /* Get the subbuf sizes and number */ - - for(i=idx_begin;ipair[i]; - - ret = ioctl(pair->channel, RELAY_GET_N_SUBBUFS, - &pair->n_subbufs); - if(ret != 0) { - perror("Error in getting the number of subbuffers"); - goto end; - } - ret = ioctl(pair->channel, RELAY_GET_SUBBUF_SIZE, - &pair->subbuf_size); - if(ret != 0) { - perror("Error in getting the size of the subbuffers"); - goto end; - } - ret = pthread_mutex_init(&pair->mutex, NULL); /* Fast mutex */ - if(ret != 0) { - perror("Error in mutex init"); - goto end; - } - } - -#if 0 - /* Mmap each FD */ - for(i=idx_begin;ipair[i]; - - pair->mmap = mmap(0, pair->subbuf_size * pair->n_subbufs, PROT_READ, - MAP_SHARED, pair->channel, 0); - if(pair->mmap == MAP_FAILED) { - perror("Mmap error"); - goto munmap; - } - } - - goto end; /* success */ - - /* Error handling */ - /* munmap only the successfully mmapped indexes */ -munmap: - /* Munmap each FD */ - for(j=idx_begin;jpair[j]; - int err_ret; - - err_ret = munmap(pair->mmap, pair->subbuf_size * pair->n_subbufs); - if(err_ret != 0) { - perror("Error in munmap"); - } - ret |= err_ret; - } - -#endif //0 -end: - return ret; -} - -int unmap_channels(struct channel_trace_fd *fd_pairs) -{ - int j; - int ret=0; - - /* Munmap each FD */ - for(j=0;jnum_pairs;j++) { - struct fd_pair *pair = &fd_pairs->pair[j]; - int err_ret; - -#if 0 - err_ret = munmap(pair->mmap, pair->subbuf_size * pair->n_subbufs); - if(err_ret != 0) { - perror("Error in munmap"); - } - ret |= err_ret; -#endif //0 - err_ret = pthread_mutex_destroy(&pair->mutex); - if(err_ret != 0) { - perror("Error in mutex destroy"); - } - ret |= err_ret; - } - - return ret; -} - -#ifdef HAS_INOTIFY -/* Inotify event arrived. - * - * Only support add file for now. - */ - -int read_inotify(int inotify_fd, - struct channel_trace_fd *fd_pairs, - struct inotify_watch_array *iwatch_array) -{ - char buf[sizeof(struct inotify_event) + PATH_MAX]; - char path_channel[PATH_MAX]; - char path_trace[PATH_MAX]; - ssize_t len; - struct inotify_event *ievent; - size_t offset; - unsigned int i; - int ret; - int old_num; - - offset = 0; - len = read(inotify_fd, buf, sizeof(struct inotify_event) + PATH_MAX); - if(len < 0) { - - if(errno == EAGAIN) - return 0; /* another thread got the data before us */ - - printf("Error in read from inotify FD %s.\n", strerror(len)); - return -1; - } - while(offset < len) { - ievent = (struct inotify_event *)&(buf[offset]); - for(i=0; inum; i++) { - if(iwatch_array->elem[i].wd == ievent->wd && - ievent->mask == IN_CREATE) { - printf_verbose( - "inotify wd %u event mask : %u for %s%s\n", - ievent->wd, ievent->mask, - iwatch_array->elem[i].path_channel, - ievent->name); - old_num = fd_pairs->num_pairs; - strcpy(path_channel, iwatch_array->elem[i].path_channel); - strcat(path_channel, ievent->name); - strcpy(path_trace, iwatch_array->elem[i].path_trace); - strcat(path_trace, ievent->name); - if(ret = open_buffer_file(ievent->name, path_channel, - path_trace, fd_pairs)) { - printf("Error opening buffer file\n"); - return -1; - } - if(ret = map_channels(fd_pairs, old_num, fd_pairs->num_pairs)) { - printf("Error mapping channel\n"); - return -1; - } - - } - } - offset += sizeof(*ievent) + ievent->len; - } -} -#endif //HAS_INOTIFY - -/* read_channels - * - * Thread worker. - * - * Read the debugfs channels and write them in the paired tracefiles. - * - * @fd_pairs : paired channels and trace files. - * - * returns 0 on success, -1 on error. - * - * Note that the high priority polled channels are consumed first. We then poll - * again to see if these channels are still in priority. Only when no - * high priority channel is left, we start reading low priority channels. - * - * Note that a channel is considered high priority when the buffer is almost - * full. - */ - -int read_channels(unsigned long thread_num, struct channel_trace_fd *fd_pairs, - int inotify_fd, struct inotify_watch_array *iwatch_array) -{ - struct pollfd *pollfd = NULL; - int num_pollfd; - int i,j; - int num_rdy, num_hup; - int high_prio; - int ret = 0; - int inotify_fds; - unsigned int old_num; - -#ifdef HAS_INOTIFY - inotify_fds = 1; -#else - inotify_fds = 0; -#endif - - pthread_rwlock_rdlock(&fd_pairs_lock); - - /* Start polling the FD. Keep one fd for inotify */ - pollfd = malloc((inotify_fds + fd_pairs->num_pairs) * sizeof(struct pollfd)); - -#ifdef HAS_INOTIFY - pollfd[0].fd = inotify_fd; - pollfd[0].events = POLLIN|POLLPRI; -#endif - - for(i=0;inum_pairs;i++) { - pollfd[inotify_fds+i].fd = fd_pairs->pair[i].channel; - pollfd[inotify_fds+i].events = POLLIN|POLLPRI; - } - num_pollfd = inotify_fds + fd_pairs->num_pairs; - - - pthread_rwlock_unlock(&fd_pairs_lock); - - while(1) { - high_prio = 0; - num_hup = 0; -#ifdef DEBUG - printf("Press a key for next poll...\n"); - char buf[1]; - read(STDIN_FILENO, &buf, 1); - printf("Next poll (polling %d fd) :\n", num_pollfd); -#endif //DEBUG - - /* Have we received a signal ? */ - if(quit_program) break; - - num_rdy = poll(pollfd, num_pollfd, -1); - - if(num_rdy == -1) { - perror("Poll error"); - goto free_fd; - } - - printf_verbose("Data received\n"); -#ifdef HAS_INOTIFY - switch(pollfd[0].revents) { - case POLLERR: - printf_verbose( - "Error returned in polling inotify fd %d.\n", - pollfd[0].fd); - break; - case POLLHUP: - printf_verbose( - "Polling inotify fd %d tells it has hung up.\n", - pollfd[0].fd); - break; - case POLLNVAL: - printf_verbose( - "Polling inotify fd %d tells fd is not open.\n", - pollfd[0].fd); - break; - case POLLPRI: - case POLLIN: - printf_verbose( - "Polling inotify fd %d : data ready.\n", - pollfd[0].fd); - - pthread_rwlock_wrlock(&fd_pairs_lock); - read_inotify(inotify_fd, fd_pairs, iwatch_array); - pthread_rwlock_unlock(&fd_pairs_lock); - - break; - } -#endif - - for(i=inotify_fds;ipair[i-inotify_fds].mutex) == 0) { - printf_verbose( - "Urgent read on fd %d\n", - pollfd[i].fd); - /* Take care of high priority channels first. */ - high_prio = 1; - /* it's ok to have an unavailable subbuffer */ - ret = read_subbuffer(&fd_pairs->pair[i-inotify_fds]); - if(ret == EAGAIN) ret = 0; - - ret = pthread_mutex_unlock(&fd_pairs->pair[i-inotify_fds].mutex); - if(ret) - printf("Error in mutex unlock : %s\n", strerror(ret)); - } - pthread_rwlock_unlock(&fd_pairs_lock); - break; - } - } - /* If every buffer FD has hung up, we end the read loop here */ - if(num_hup == num_pollfd - inotify_fds) break; - - if(!high_prio) { - for(i=inotify_fds;ipair[i-inotify_fds].mutex) == 0) { - /* Take care of low priority channels. */ - printf_verbose( - "Normal read on fd %d\n", - pollfd[i].fd); - /* it's ok to have an unavailable subbuffer */ - ret = read_subbuffer(&fd_pairs->pair[i-inotify_fds]); - if(ret == EAGAIN) ret = 0; - - ret = pthread_mutex_unlock(&fd_pairs->pair[i-inotify_fds].mutex); - if(ret) - printf("Error in mutex unlock : %s\n", strerror(ret)); - } - pthread_rwlock_unlock(&fd_pairs_lock); - break; - } - } - } - - /* Update pollfd array if an entry was added to fd_pairs */ - pthread_rwlock_rdlock(&fd_pairs_lock); - if((inotify_fds + fd_pairs->num_pairs) != num_pollfd) { - pollfd = realloc(pollfd, - (inotify_fds + fd_pairs->num_pairs) * sizeof(struct pollfd)); - for(i=num_pollfd-inotify_fds;inum_pairs;i++) { - pollfd[inotify_fds+i].fd = fd_pairs->pair[i].channel; - pollfd[inotify_fds+i].events = POLLIN|POLLPRI; - } - num_pollfd = fd_pairs->num_pairs + inotify_fds; - } - pthread_rwlock_unlock(&fd_pairs_lock); - - /* NB: If the fd_pairs structure is updated by another thread from this - * point forward, the current thread will wait in the poll without - * monitoring the new channel. However, this thread will add the - * new channel on next poll (and this should not take too much time - * on a loaded system). - * - * This event is quite unlikely and can only occur if a CPU is - * hot-plugged while multple lttd threads are running. - */ - } - -free_fd: - free(pollfd); - -end: - return ret; -} - - -void close_channel_trace_pairs(struct channel_trace_fd *fd_pairs, int inotify_fd, - struct inotify_watch_array *iwatch_array) -{ - int i; - int ret; - - for(i=0;inum_pairs;i++) { - ret = close(fd_pairs->pair[i].channel); - if(ret == -1) perror("Close error on channel"); - ret = close(fd_pairs->pair[i].trace); - if(ret == -1) perror("Close error on trace"); - } - free(fd_pairs->pair); - free(iwatch_array->elem); -} - -/* Thread worker */ -void * thread_main(void *arg) -{ - long ret; - unsigned long thread_num = (unsigned long)arg; - - ret = pipe(thread_pipe); - if (ret < 0) { - perror("Error creating pipe"); - return (void*)ret; - } - ret = read_channels(thread_num, &fd_pairs, inotify_fd, &inotify_watch_array); - close(thread_pipe[0]); /* close read end */ - close(thread_pipe[1]); /* close write end */ - return (void*)ret; -} - - -int channels_init() -{ - int ret = 0; - - inotify_fd = inotify_init(); - fcntl(inotify_fd, F_SETFL, O_NONBLOCK); - - if(ret = open_channel_trace_pairs(channel_name, trace_name, &fd_pairs, - &inotify_fd, &inotify_watch_array)) - goto close_channel; - if (fd_pairs.num_pairs == 0) { - printf("No channel available for reading, exiting\n"); - ret = -ENOENT; - goto close_channel; - } - if(ret = map_channels(&fd_pairs, 0, fd_pairs.num_pairs)) - goto close_channel; - return 0; - -close_channel: - close_channel_trace_pairs(&fd_pairs, inotify_fd, &inotify_watch_array); - if(inotify_fd >= 0) - close(inotify_fd); - return ret; -} - - -int main(int argc, char ** argv) -{ - int ret = 0; - struct sigaction act; - pthread_t *tids; - unsigned long i; - void *tret; - - ret = parse_arguments(argc, argv); - - if(ret != 0) show_arguments(); - if(ret < 0) return EINVAL; - if(ret > 0) return 0; - - show_info(); - - /* Connect the signal handlers */ - act.sa_handler = handler; - act.sa_flags = 0; - sigemptyset(&(act.sa_mask)); - sigaddset(&(act.sa_mask), SIGTERM); - sigaddset(&(act.sa_mask), SIGQUIT); - sigaddset(&(act.sa_mask), SIGINT); - sigaction(SIGTERM, &act, NULL); - sigaction(SIGQUIT, &act, NULL); - sigaction(SIGINT, &act, NULL); - - if(ret = channels_init()) - return ret; - - if(daemon_mode) { - ret = daemon(0, 0); - - if(ret == -1) { - perror("An error occured while daemonizing."); - exit(-1); - } - } - - tids = malloc(sizeof(pthread_t) * num_threads); - for(i=0; i= 0) - close(inotify_fd); - - return ret; -} diff --git a/trunk/ltt-control/specs/Makefile.am b/trunk/ltt-control/specs/Makefile.am deleted file mode 100644 index c6ae90e..0000000 --- a/trunk/ltt-control/specs/Makefile.am +++ /dev/null @@ -1 +0,0 @@ -EXTRA_DIST = ltt-control.spec diff --git a/trunk/ltt-control/specs/ltt-control.spec b/trunk/ltt-control/specs/ltt-control.spec deleted file mode 100644 index 8b0a2a3..0000000 --- a/trunk/ltt-control/specs/ltt-control.spec +++ /dev/null @@ -1,58 +0,0 @@ -# -# Spec file for ltt-control -# -Summary: LTT Control -Name: ltt-control -Version: 0.45 -Release: 11102007 -License: GPL -Group: Applications/Development -Source: http://ltt.polymtl.ca/lttng/ltt-control-%{version}-%{release}.tar.gz -URL: http://ltt.polymtl.ca -Packager: Martin Bisson -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) - -# Where do we install the libs -%ifarch x86_64 ppc64 ppc64iseries ia64 -%define libdir /usr/lib64 -%else -%define libdir /usr/lib -%endif - - -%description - -ltt-control is the part of the Linux Trace Toolkit Next Generation -that allows a machine to be traced. It holds the daemon with which -the kernel will communicate and the application that starts and -terminate tracing. - -%prep -%setup -q -n ltt-control-%{version}-%{release} - -%build -./configure --prefix=/usr --libdir=%{libdir} -make - -%install -rm -rf $RPM_BUILD_ROOT -make DESTDIR=$RPM_BUILD_ROOT install - -%post -echo "Running ldconfig (might take a while)" -ldconfig - -%postun -echo "Running ldconfig (might take a while)" -ldconfig - -%files -%{libdir}/liblttctl.so.0.0.0 -%{libdir}/liblttctl.so.0 -%{libdir}/liblttctl.so -%{libdir}/liblttctl.la -%{libdir}/liblttctl.a -/usr/bin/lttctl -/usr/bin/lttd -/usr/include/liblttctl -/usr/include/liblttctl/lttctl.h