From 366ebe807eb22cd9480583f12eec527db0498987 Mon Sep 17 00:00:00 2001 From: compudj Date: Tue, 12 Aug 2008 14:41:26 +0000 Subject: [PATCH] add tags git-svn-id: http://ltt.polymtl.ca/svn@3000 04897980-b3bd-0310-b5e0-8ef037075253 --- tags/ltt-control-0.51-12082008/AUTHORS | 25 + tags/ltt-control-0.51-12082008/ChangeLog | 0 tags/ltt-control-0.51-12082008/Makefile.am | 2 + tags/ltt-control-0.51-12082008/NEWS | 0 tags/ltt-control-0.51-12082008/README | 60 ++ tags/ltt-control-0.51-12082008/autogen.sh | 169 ++++ tags/ltt-control-0.51-12082008/configure.in | 90 ++ .../liblttctl/Makefile.am | 7 + .../liblttctl/liblttctl.c | 491 +++++++++ .../liblttctl/lttctl.h | 99 ++ .../lttctl/Makefile.am | 53 + .../lttctl/ltt-armall.sh | 52 + .../lttctl/ltt-armalluser.sh | 18 + .../lttctl/ltt-armtap.sh | 34 + .../lttctl/ltt-disarmall.sh | 19 + .../lttctl/ltt-disarmalluser.sh | 16 + .../lttctl/ltt-disarmtap.sh | 33 + .../ltt-control-0.51-12082008/lttctl/lttctl.c | 537 ++++++++++ .../lttctl/lttctl_distributed.sh | 293 ++++++ .../lttd/Makefile.am | 8 + tags/ltt-control-0.51-12082008/lttd/lttd.c | 938 ++++++++++++++++++ .../specs/Makefile.am | 1 + .../specs/ltt-control.spec | 58 ++ 23 files changed, 3003 insertions(+) create mode 100644 tags/ltt-control-0.51-12082008/AUTHORS create mode 100644 tags/ltt-control-0.51-12082008/ChangeLog create mode 100644 tags/ltt-control-0.51-12082008/Makefile.am create mode 100644 tags/ltt-control-0.51-12082008/NEWS create mode 100644 tags/ltt-control-0.51-12082008/README create mode 100755 tags/ltt-control-0.51-12082008/autogen.sh create mode 100644 tags/ltt-control-0.51-12082008/configure.in create mode 100644 tags/ltt-control-0.51-12082008/liblttctl/Makefile.am create mode 100644 tags/ltt-control-0.51-12082008/liblttctl/liblttctl.c create mode 100644 tags/ltt-control-0.51-12082008/liblttctl/lttctl.h create mode 100644 tags/ltt-control-0.51-12082008/lttctl/Makefile.am create mode 100755 tags/ltt-control-0.51-12082008/lttctl/ltt-armall.sh create mode 100755 tags/ltt-control-0.51-12082008/lttctl/ltt-armalluser.sh create mode 100755 tags/ltt-control-0.51-12082008/lttctl/ltt-armtap.sh create mode 100755 tags/ltt-control-0.51-12082008/lttctl/ltt-disarmall.sh create mode 100755 tags/ltt-control-0.51-12082008/lttctl/ltt-disarmalluser.sh create mode 100755 tags/ltt-control-0.51-12082008/lttctl/ltt-disarmtap.sh create mode 100644 tags/ltt-control-0.51-12082008/lttctl/lttctl.c create mode 100644 tags/ltt-control-0.51-12082008/lttctl/lttctl_distributed.sh create mode 100644 tags/ltt-control-0.51-12082008/lttd/Makefile.am create mode 100644 tags/ltt-control-0.51-12082008/lttd/lttd.c create mode 100644 tags/ltt-control-0.51-12082008/specs/Makefile.am create mode 100644 tags/ltt-control-0.51-12082008/specs/ltt-control.spec diff --git a/tags/ltt-control-0.51-12082008/AUTHORS b/tags/ltt-control-0.51-12082008/AUTHORS new file mode 100644 index 0000000..032edf0 --- /dev/null +++ b/tags/ltt-control-0.51-12082008/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/tags/ltt-control-0.51-12082008/ChangeLog b/tags/ltt-control-0.51-12082008/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/tags/ltt-control-0.51-12082008/Makefile.am b/tags/ltt-control-0.51-12082008/Makefile.am new file mode 100644 index 0000000..8f9974d --- /dev/null +++ b/tags/ltt-control-0.51-12082008/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = liblttctl lttctl lttd specs + diff --git a/tags/ltt-control-0.51-12082008/NEWS b/tags/ltt-control-0.51-12082008/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/tags/ltt-control-0.51-12082008/README b/tags/ltt-control-0.51-12082008/README new file mode 100644 index 0000000..9fce197 --- /dev/null +++ b/tags/ltt-control-0.51-12082008/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/tags/ltt-control-0.51-12082008/autogen.sh b/tags/ltt-control-0.51-12082008/autogen.sh new file mode 100755 index 0000000..f0c7b68 --- /dev/null +++ b/tags/ltt-control-0.51-12082008/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/tags/ltt-control-0.51-12082008/configure.in b/tags/ltt-control-0.51-12082008/configure.in new file mode 100644 index 0000000..9fb72fe --- /dev/null +++ b/tags/ltt-control-0.51-12082008/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.51-12082008) +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/tags/ltt-control-0.51-12082008/liblttctl/Makefile.am b/tags/ltt-control-0.51-12082008/liblttctl/Makefile.am new file mode 100644 index 0000000..1c650f0 --- /dev/null +++ b/tags/ltt-control-0.51-12082008/liblttctl/Makefile.am @@ -0,0 +1,7 @@ + + +lib_LTLIBRARIES = liblttctl.la +liblttctl_la_SOURCES = liblttctl.c + +lttctlinclude_HEADERS = \ + lttctl.h diff --git a/tags/ltt-control-0.51-12082008/liblttctl/liblttctl.c b/tags/ltt-control-0.51-12082008/liblttctl/liblttctl.c new file mode 100644 index 0000000..61bca62 --- /dev/null +++ b/tags/ltt-control-0.51-12082008/liblttctl/liblttctl.c @@ -0,0 +1,491 @@ +/* libltt + * + * Linux Trace Toolkit Netlink Control Library + * + * Controls the ltt-control kernel module through a netlink socket. + * + * Heavily inspired from libipq.c (iptables) made by + * James Morris + * + * 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 + + + +/* Private interface */ + +enum { + LTTCTL_ERR_NONE = 0, + LTTCTL_ERR_IMPL, + LTTCTL_ERR_HANDLE, + LTTCTL_ERR_SOCKET, + LTTCTL_ERR_BIND, + LTTCTL_ERR_BUFFER, + LTTCTL_ERR_RECV, + LTTCTL_ERR_NLEOF, + LTTCTL_ERR_ADDRLEN, + LTTCTL_ERR_STRUNC, + LTTCTL_ERR_RTRUNC, + LTTCTL_ERR_NLRECV, + LTTCTL_ERR_SEND, + LTTCTL_ERR_SUPP, + LTTCTL_ERR_RECVBUF, + LTTCTL_ERR_TIMEOUT, + LTTCTL_ERR_PROTOCOL +}; +#define LTTCTL_MAXERR LTTCTL_ERR_PROTOCOL + + +struct lttctl_errmap_t { + int errcode; + char *message; +} lttctl_errmap[] = { + { LTTCTL_ERR_NONE, "Unknown error" }, + { LTTCTL_ERR_IMPL, "Implementation error" }, + { LTTCTL_ERR_HANDLE, "Unable to create netlink handle" }, + { LTTCTL_ERR_SOCKET, "Unable to create netlink socket" }, + { LTTCTL_ERR_BIND, "Unable to bind netlink socket" }, + { LTTCTL_ERR_BUFFER, "Unable to allocate buffer" }, + { LTTCTL_ERR_RECV, "Failed to receive netlink message" }, + { LTTCTL_ERR_NLEOF, "Received EOF on netlink socket" }, + { LTTCTL_ERR_ADDRLEN, "Invalid peer address length" }, + { LTTCTL_ERR_STRUNC, "Sent message truncated" }, + { LTTCTL_ERR_RTRUNC, "Received message truncated" }, + { LTTCTL_ERR_NLRECV, "Received error from netlink" }, + { LTTCTL_ERR_SEND, "Failed to send netlink message" }, + { LTTCTL_ERR_SUPP, "Operation not supported" }, + { LTTCTL_ERR_RECVBUF, "Receive buffer size invalid" }, + { LTTCTL_ERR_TIMEOUT, "Timeout"}, + { LTTCTL_ERR_PROTOCOL, "Invalid protocol specified" } +}; + +static int lttctl_errno = LTTCTL_ERR_NONE; + + +static ssize_t lttctl_netlink_sendto(const struct lttctl_handle *h, + const void *msg, size_t len); + +static ssize_t lttctl_netlink_recvfrom(const struct lttctl_handle *h, + unsigned char *buf, size_t len, + int timeout); + +static ssize_t lttctl_netlink_sendmsg(const struct lttctl_handle *h, + const struct msghdr *msg, + unsigned int flags); + +static char *lttctl_strerror(int errcode); + +void lttctl_perror(const char *s); + +static ssize_t lttctl_netlink_sendto(const struct lttctl_handle *h, + const void *msg, size_t len) +{ + int status = sendto(h->fd, msg, len, 0, + (struct sockaddr *)&h->peer, sizeof(h->peer)); + if (status < 0) + lttctl_errno = LTTCTL_ERR_SEND; + + return status; +} + +static ssize_t lttctl_netlink_sendmsg(const struct lttctl_handle *h, + const struct msghdr *msg, + unsigned int flags) +{ + int status = sendmsg(h->fd, msg, flags); + if (status < 0) + lttctl_errno = LTTCTL_ERR_SEND; + return status; +} + +static ssize_t lttctl_netlink_recvfrom(const struct lttctl_handle *h, + unsigned char *buf, size_t len, + int timeout) +{ + int addrlen, status; + struct nlmsghdr *nlh; + + if (len < sizeof(struct nlmsghdr)) { + lttctl_errno = LTTCTL_ERR_RECVBUF; + lttctl_perror("Netlink recvfrom"); + return -1; + } + addrlen = sizeof(h->peer); + + if (timeout != 0) { + int ret; + struct timeval tv; + fd_set read_fds; + + if (timeout < 0) { + /* non-block non-timeout */ + tv.tv_sec = 0; + tv.tv_usec = 0; + } else { + tv.tv_sec = timeout / 1000000; + tv.tv_usec = timeout % 1000000; + } + + FD_ZERO(&read_fds); + FD_SET(h->fd, &read_fds); + ret = select(h->fd+1, &read_fds, NULL, NULL, &tv); + if (ret < 0) { + if (errno == EINTR) { + printf("eintr\n"); + return 0; + } else { + lttctl_errno = LTTCTL_ERR_RECV; + lttctl_perror("Netlink recvfrom"); + return -1; + } + } + if (!FD_ISSET(h->fd, &read_fds)) { + lttctl_errno = LTTCTL_ERR_TIMEOUT; + printf("timeout\n"); + return 0; + } + } + status = recvfrom(h->fd, buf, len, 0, + (struct sockaddr *)&h->peer, &addrlen); + + if (status < 0) { + lttctl_errno = LTTCTL_ERR_RECV; + lttctl_perror("Netlink recvfrom"); + return status; + } + if (addrlen != sizeof(h->peer)) { + lttctl_errno = LTTCTL_ERR_RECV; + lttctl_perror("Netlink recvfrom"); + return -1; + } + if (h->peer.nl_pid != 0) { + lttctl_errno = LTTCTL_ERR_RECV; + lttctl_perror("Netlink recvfrom"); + return -1; + } + if (status == 0) { + lttctl_errno = LTTCTL_ERR_NLEOF; + lttctl_perror("Netlink recvfrom"); + return -1; + } + nlh = (struct nlmsghdr *)buf; + if (nlh->nlmsg_flags & MSG_TRUNC || nlh->nlmsg_len > status) { + lttctl_errno = LTTCTL_ERR_RTRUNC; + lttctl_perror("Netlink recvfrom"); + return -1; + } + + + return status; +} + + +static char *lttctl_strerror(int errcode) +{ + if (errcode < 0 || errcode > LTTCTL_MAXERR) + errcode = LTTCTL_ERR_IMPL; + return lttctl_errmap[errcode].message; +} + + +char *lttctl_errstr(void) +{ + return lttctl_strerror(lttctl_errno); +} + +void lttctl_perror(const char *s) +{ + if (s) + fputs(s, stderr); + else + fputs("ERROR", stderr); + if (lttctl_errno) + fprintf(stderr, ": %s", lttctl_errstr()); + if (errno) + fprintf(stderr, ": %s", strerror(errno)); + fputc('\n', stderr); +} + +/* public interface */ + +/* + * Create and initialise an lttctl handle. + */ +struct lttctl_handle *lttctl_create_handle(void) +{ + int status; + struct lttctl_handle *h; + + h = (struct lttctl_handle *)malloc(sizeof(struct lttctl_handle)); + if (h == NULL) { + lttctl_errno = LTTCTL_ERR_HANDLE; + lttctl_perror("Create handle"); + goto alloc_error; + } + + memset(h, 0, sizeof(struct lttctl_handle)); + + h->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_LTT); + + if (h->fd == -1) { + lttctl_errno = LTTCTL_ERR_SOCKET; + lttctl_perror("Create handle"); + goto socket_error; + } + memset(&h->local, 0, sizeof(struct sockaddr_nl)); + h->local.nl_family = AF_NETLINK; + h->local.nl_pid = getpid(); + h->local.nl_groups = 0; + status = bind(h->fd, (struct sockaddr *)&h->local, sizeof(h->local)); + if (status == -1) { + lttctl_errno = LTTCTL_ERR_BIND; + lttctl_perror("Create handle"); + goto bind_error; + } + memset(&h->peer, 0, sizeof(struct sockaddr_nl)); + h->peer.nl_family = AF_NETLINK; + h->peer.nl_pid = 0; + h->peer.nl_groups = 0; + return h; + + /* Error condition */ +bind_error: +socket_error: + close(h->fd); +alloc_error: + free(h); + return NULL; +} + +/* + * No error condition is checked here at this stage, but it may happen + * if/when reliable messaging is implemented. + */ +int lttctl_destroy_handle(struct lttctl_handle *h) +{ + if (h) { + close(h->fd); + free(h); + } + return 0; +} + + +int lttctl_create_trace(const struct lttctl_handle *h, + char *name, enum trace_mode mode, char *trace_type, + unsigned subbuf_size_low, unsigned n_subbufs_low, + unsigned subbuf_size_med, unsigned n_subbufs_med, + unsigned subbuf_size_high, unsigned n_subbufs_high) +{ + int err; + + struct { + struct nlmsghdr nlh; + lttctl_peer_msg_t msg; + } req; + struct { + struct nlmsghdr nlh; + struct nlmsgerr nlerr; + lttctl_peer_msg_t msg; + } ack; + + memset(&req, 0, sizeof(req)); + req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(lttctl_peer_msg_t)); + req.nlh.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; + req.nlh.nlmsg_type = LTTCTLM_CONTROL; + req.nlh.nlmsg_pid = h->local.nl_pid; + req.nlh.nlmsg_seq = 0; + + strncpy(req.msg.trace_name, name, NAME_MAX); + strncpy(req.msg.trace_type, trace_type, NAME_MAX); + req.msg.op = OP_CREATE; + req.msg.args.new_trace.mode = mode; + req.msg.args.new_trace.subbuf_size_low = subbuf_size_low; + req.msg.args.new_trace.n_subbufs_low = n_subbufs_low; + req.msg.args.new_trace.subbuf_size_med = subbuf_size_med; + req.msg.args.new_trace.n_subbufs_med = n_subbufs_med; + req.msg.args.new_trace.subbuf_size_high = subbuf_size_high; + req.msg.args.new_trace.n_subbufs_high = n_subbufs_high; + + err = lttctl_netlink_sendto(h, (void *)&req, req.nlh.nlmsg_len); + if(err < 0) goto senderr; + + err = lttctl_netlink_recvfrom(h, (void*)&ack, sizeof(ack), 0); + if(err < 0) goto senderr; + + err = ack.nlerr.error; + if(err != 0) { + errno = err; + lttctl_perror("Create Trace Error"); + return err; + } + + return 0; + +senderr: + lttctl_perror("Create Trace Error"); + err = EPERM; + return err; +} + +int lttctl_destroy_trace(const struct lttctl_handle *h, + char *name) +{ + struct { + struct nlmsghdr nlh; + lttctl_peer_msg_t msg; + } req; + struct { + struct nlmsghdr nlh; + struct nlmsgerr nlerr; + lttctl_peer_msg_t msg; + } ack; + int err; + + memset(&req, 0, sizeof(req)); + req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(lttctl_peer_msg_t)); + req.nlh.nlmsg_flags = NLM_F_REQUEST; + req.nlh.nlmsg_type = LTTCTLM_CONTROL; + req.nlh.nlmsg_pid = h->local.nl_pid; + + strncpy(req.msg.trace_name, name, NAME_MAX); + req.msg.op = OP_DESTROY; + + err = lttctl_netlink_sendto(h, (void *)&req, req.nlh.nlmsg_len); + if(err < 0) goto senderr; + + err = lttctl_netlink_recvfrom(h, (void*)&ack, sizeof(ack), 0); + if(err < 0) goto senderr; + + err = ack.nlerr.error; + if(err != 0) { + errno = err; + lttctl_perror("Destroy Trace Channels Error"); + return err; + } + + return 0; + +senderr: + lttctl_perror("Destroy Trace Channels Error"); + err = EPERM; + return err; + +} + +int lttctl_start(const struct lttctl_handle *h, + char *name) +{ + struct { + struct nlmsghdr nlh; + lttctl_peer_msg_t msg; + } req; + struct { + struct nlmsghdr nlh; + struct nlmsgerr nlerr; + lttctl_peer_msg_t msg; + } ack; + + int err; + + memset(&req, 0, sizeof(req)); + req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(lttctl_peer_msg_t)); + req.nlh.nlmsg_flags = NLM_F_REQUEST; + req.nlh.nlmsg_type = LTTCTLM_CONTROL; + req.nlh.nlmsg_pid = h->local.nl_pid; + + strncpy(req.msg.trace_name, name, NAME_MAX); + req.msg.op = OP_START; + + err = lttctl_netlink_sendto(h, (void *)&req, req.nlh.nlmsg_len); + if(err < 0) goto senderr; + + err = lttctl_netlink_recvfrom(h, (void*)&ack, sizeof(ack), 0); + if(err < 0) goto senderr; + + err = ack.nlerr.error; + if(err != 0) { + errno = err; + lttctl_perror("Start Trace Error"); + return err; + } + + return 0; + +senderr: + err = EPERM; + lttctl_perror("Start Trace Error"); + return err; + +} + +int lttctl_stop(const struct lttctl_handle *h, + char *name) +{ + struct { + struct nlmsghdr nlh; + lttctl_peer_msg_t msg; + } req; + struct { + struct nlmsghdr nlh; + struct nlmsgerr nlerr; + lttctl_peer_msg_t msg; + } ack; + int err; + + memset(&req, 0, sizeof(req)); + req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(lttctl_peer_msg_t)); + req.nlh.nlmsg_flags = NLM_F_REQUEST; + req.nlh.nlmsg_type = LTTCTLM_CONTROL; + req.nlh.nlmsg_pid = h->local.nl_pid; + + strncpy(req.msg.trace_name, name, NAME_MAX); + req.msg.op = OP_STOP; + + err = lttctl_netlink_sendto(h, (void *)&req, req.nlh.nlmsg_len); + if(err < 0) goto senderr; + + err = lttctl_netlink_recvfrom(h, (void*)&ack, sizeof(ack), 0); + if(err < 0) goto senderr; + + err = ack.nlerr.error; + if(err != 0) { + errno = err; + lttctl_perror("Stop Trace Error"); + return err; + } + + return 0; + +senderr: + err = EPERM; + lttctl_perror("Stop Trace Error"); + return err; +} + diff --git a/tags/ltt-control-0.51-12082008/liblttctl/lttctl.h b/tags/ltt-control-0.51-12082008/liblttctl/lttctl.h new file mode 100644 index 0000000..053c0f4 --- /dev/null +++ b/tags/ltt-control-0.51-12082008/liblttctl/lttctl.h @@ -0,0 +1,99 @@ +/* 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. + * + * + * Inspired from iptables, by James Morris . + * + */ + +#ifndef _LIBLTT_H +#define _LIBLTT_H + +#include +#include +#include +#include + +#ifndef NETLINK_LTT +#define NETLINK_LTT 31 +#endif + + +enum trace_op { + OP_CREATE, + OP_DESTROY, + OP_START, + OP_STOP, + OP_NONE +}; + +enum trace_mode { + LTT_TRACE_NORMAL, + LTT_TRACE_FLIGHT, + LTT_TRACE_HYBRID +}; + +typedef struct lttctl_peer_msg { + char trace_name[NAME_MAX]; + char trace_type[NAME_MAX]; + enum trace_op op; + union { + struct { + enum trace_mode mode; + unsigned subbuf_size_low; + unsigned n_subbufs_low; + unsigned subbuf_size_med; + unsigned n_subbufs_med; + unsigned subbuf_size_high; + unsigned n_subbufs_high; + } new_trace; + } args; +} lttctl_peer_msg_t; + + +struct lttctl_handle +{ + int fd; + //u_int8_t blocking; + struct sockaddr_nl local; + struct sockaddr_nl peer; +}; + +typedef struct lttctl_resp_msg { + int err; +} lttctl_resp_msg_t; + +struct lttctl_handle *lttctl_create_handle(void); + +int lttctl_destroy_handle(struct lttctl_handle *h); + + +int lttctl_create_trace(const struct lttctl_handle *h, + char *name, enum trace_mode mode, char *trace_type, + unsigned subbuf_size_low, unsigned n_subbufs_low, + unsigned subbuf_size_med, unsigned n_subbufs_med, + unsigned subbuf_size_high, unsigned n_subbufs_high); + +int lttctl_destroy_trace(const struct lttctl_handle *handle, char *name); + +int lttctl_start(const struct lttctl_handle *handle, char *name); + +int lttctl_stop(const struct lttctl_handle *handle, char *name); + +#define LTTCTLM_BASE 0x10 +#define LTTCTLM_CONTROL (LTTCTLM_BASE + 1) /* LTT control message */ + +#endif //_LIBLTT_H diff --git a/tags/ltt-control-0.51-12082008/lttctl/Makefile.am b/tags/ltt-control-0.51-12082008/lttctl/Makefile.am new file mode 100644 index 0000000..12ad501 --- /dev/null +++ b/tags/ltt-control-0.51-12082008/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/tags/ltt-control-0.51-12082008/lttctl/ltt-armall.sh b/tags/ltt-control-0.51-12082008/lttctl/ltt-armall.sh new file mode 100755 index 0000000..ae6867d --- /dev/null +++ b/tags/ltt-control-0.51-12082008/lttctl/ltt-armall.sh @@ -0,0 +1,52 @@ +#excluding core markers (already connected) +#excluding locking markers (high traffic) + +echo Connecting all markers +MARKERS=`cat /proc/ltt|grep -v %k|awk '{print $2}'|sort -u|grep -v ^core_|grep -v ^locking_|grep -v ^lockdep_` + +for a in $MARKERS; do + echo Connecting $a + + #redirect markers carrying state information to dedicated channels + case $a in + list_process_state|user_generic_thread_brand|fs_exec|kernel_process_fork|kernel_process_free|kernel_process_exit|kernel_arch_kthread_create|list_statedump_end|list_vm_map) + CHANNEL=processes + ;; + list_interrupt|statedump_idt_table|statedump_sys_call_table) + CHANNEL=interrupts + ;; + list_network_ipv4_interface|list_network_ip_interface) + CHANNEL=network + ;; + kernel_module_load|kernel_module_free) + CHANNEL=modules + ;; + *) + CHANNEL= + ;; + esac + + echo "connect $a default dynamic $CHANNEL" > /proc/ltt +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 ^tap_` + +#Uncomment the following to also record lockdep events. +#MARKERS=`cat /proc/ltt | grep -e ^tap_ -e ^lockdep` + +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 dynamic $CHANNEL" > /proc/ltt +done diff --git a/tags/ltt-control-0.51-12082008/lttctl/ltt-armalluser.sh b/tags/ltt-control-0.51-12082008/lttctl/ltt-armalluser.sh new file mode 100755 index 0000000..290e360 --- /dev/null +++ b/tags/ltt-control-0.51-12082008/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/tags/ltt-control-0.51-12082008/lttctl/ltt-armtap.sh b/tags/ltt-control-0.51-12082008/lttctl/ltt-armtap.sh new file mode 100755 index 0000000..84f91d6 --- /dev/null +++ b/tags/ltt-control-0.51-12082008/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/tags/ltt-control-0.51-12082008/lttctl/ltt-disarmall.sh b/tags/ltt-control-0.51-12082008/lttctl/ltt-disarmall.sh new file mode 100755 index 0000000..4a3f92e --- /dev/null +++ b/tags/ltt-control-0.51-12082008/lttctl/ltt-disarmall.sh @@ -0,0 +1,19 @@ +#excluding locking +#excluding core markers, not connected to default. +echo Disconnecting all markers +MARKERS=`cat /proc/ltt|grep -v %k|awk '{print $2}'|sort -u|grep -v ^core_|grep -v ^locking_|grep -v ^lockdep_|grep -v ^lockdep|grep -v ^tap_` +for a in $MARKERS; do echo Disconnecting $a; echo "disconnect $a" > /proc/ltt; done + + +# Markers starting with "tap_" are considered high-speed. +echo Disconnecting high-rate markers from tap +MARKERS=`cat /proc/ltt | grep ^tap_` + +#Uncomment the following to also stop recording lockdep events. +#MARKERS=`cat /proc/ltt | grep -e ^tap_ -e ^lockdep` + +for a in $MARKERS; do + echo Disconnecting $a + + echo "disconnect $a ltt_tap_marker" > /proc/ltt +done diff --git a/tags/ltt-control-0.51-12082008/lttctl/ltt-disarmalluser.sh b/tags/ltt-control-0.51-12082008/lttctl/ltt-disarmalluser.sh new file mode 100755 index 0000000..0d0f1eb --- /dev/null +++ b/tags/ltt-control-0.51-12082008/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/tags/ltt-control-0.51-12082008/lttctl/ltt-disarmtap.sh b/tags/ltt-control-0.51-12082008/lttctl/ltt-disarmtap.sh new file mode 100755 index 0000000..b41f70c --- /dev/null +++ b/tags/ltt-control-0.51-12082008/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/tags/ltt-control-0.51-12082008/lttctl/lttctl.c b/tags/ltt-control-0.51-12082008/lttctl/lttctl.c new file mode 100644 index 0000000..46dc289 --- /dev/null +++ b/tags/ltt-control-0.51-12082008/lttctl/lttctl.c @@ -0,0 +1,537 @@ +/* lttctl + * + * Linux Trace Toolkit Control + * + * Small program that controls LTT through libltt. + * + * Copyright 2005 - + * Mathieu Desnoyers + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Buffer for file copy : 4k seems optimal. */ +#define BUF_SIZE 4096 + +enum trace_ctl_op { + CTL_OP_CREATE_START, + CTL_OP_CREATE, + CTL_OP_DESTROY, + CTL_OP_STOP_DESTROY, + CTL_OP_START, + CTL_OP_STOP, + CTL_OP_DAEMON, + CTL_OP_DAEMON_HYBRID_FINISH, + CTL_OP_NONE +}; + +static char *trace_name = NULL; +static char *trace_type = "relay"; +static char *mode_name = NULL; +static unsigned subbuf_size_low = 0; +static unsigned n_subbufs_low = 0; +static unsigned subbuf_size_med = 0; +static unsigned n_subbufs_med = 0; +static unsigned subbuf_size_high = 0; +static unsigned n_subbufs_high = 0; +static unsigned append_trace = 0; +static enum trace_mode mode = LTT_TRACE_NORMAL; +static enum trace_ctl_op op = CTL_OP_NONE; +static char *channel_root = NULL; +static char *trace_root = NULL; +static char *num_threads = "1"; + +/* Args : + * + */ +void show_arguments(void) +{ + printf("Please use the following arguments :\n"); + printf("\n"); + printf("-n name Name of the trace.\n"); + printf("-b Create trace channels and start tracing (no daemon).\n"); + printf("-c Create trace channels.\n"); + printf("-m mode Normal, flight recorder or hybrid mode.\n"); + printf(" Mode values : normal (default), flight or hybrid.\n"); + printf("-r Destroy trace channels.\n"); + printf("-R Stop tracing and destroy trace channels.\n"); + printf("-s Start tracing.\n"); + //printf(" Note : will automatically create a normal trace if " + // "none exists.\n"); + printf("-q Stop tracing.\n"); + printf("-d Create trace, spawn a lttd daemon, start tracing.\n"); + printf(" (optionally, you can set LTT_DAEMON\n"); + printf(" env. var.)\n"); + printf("-f Stop tracing, dump flight recorder trace, destroy channels\n"); + printf(" (for hybrid traces)\n"); + printf("-t Trace root path. (ex. /root/traces/example_trace)\n"); + printf("-T Type of trace (ex. relay)\n"); + printf("-l LTT channels root path. (ex. /mnt/debugfs/ltt)\n"); + printf("-Z Size of the low data rate subbuffers (will be rounded to next page size)\n"); + printf("-X Number of low data rate subbuffers\n"); + printf("-V Size of the medium data rate subbuffers (will be rounded to next page size)\n"); + printf("-B Number of medium data rate subbuffers\n"); + printf("-z Size of the high data rate subbuffers (will be rounded to next page size)\n"); + printf("-x Number of high data rate subbuffers\n"); + printf("-a Append to trace\n"); + printf("-N Number of lttd threads\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 EINVAL 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 'n': + if(argn+1 < argc) { + trace_name = argv[argn+1]; + argn++; + } else { + printf("Specify a trace name after -n.\n"); + printf("\n"); + ret = EINVAL; + } + + break; + case 'b': + op = CTL_OP_CREATE_START; + break; + case 'c': + op = CTL_OP_CREATE; + break; + case 'm': + if(argn+1 < argc) { + mode_name = argv[argn+1]; + argn++; + if(strcmp(mode_name, "normal") == 0) + mode = LTT_TRACE_NORMAL; + else if(strcmp(mode_name, "flight") == 0) + mode = LTT_TRACE_FLIGHT; + else if(strcmp(mode_name, "hybrid") == 0) + mode = LTT_TRACE_HYBRID; + else { + printf("Invalid mode '%s'.\n", argv[argn]); + printf("\n"); + ret = EINVAL; + } + } else { + printf("Specify a mode after -m.\n"); + printf("\n"); + ret = EINVAL; + } + break; + case 'r': + op = CTL_OP_DESTROY; + break; + case 'R': + op = CTL_OP_STOP_DESTROY; + break; + case 's': + op = CTL_OP_START; + break; + case 'q': + op = CTL_OP_STOP; + break; + case 'Z': + if(argn+1 < argc) { + subbuf_size_low = (unsigned)atoi(argv[argn+1]); + argn++; + } else { + printf("Specify a number of low traffic subbuffers after -Z.\n"); + printf("\n"); + ret = EINVAL; + } + break; + case 'X': + if(argn+1 < argc) { + n_subbufs_low = (unsigned)atoi(argv[argn+1]); + argn++; + } else { + printf("Specify a low traffic subbuffer size after -X.\n"); + printf("\n"); + ret = EINVAL; + } + break; + case 'V': + if(argn+1 < argc) { + subbuf_size_med = (unsigned)atoi(argv[argn+1]); + argn++; + } else { + printf("Specify a number of medium traffic subbuffers after -V.\n"); + printf("\n"); + ret = EINVAL; + } + break; + case 'B': + if(argn+1 < argc) { + n_subbufs_med = (unsigned)atoi(argv[argn+1]); + argn++; + } else { + printf("Specify a medium traffic subbuffer size after -B.\n"); + printf("\n"); + ret = EINVAL; + } + break; + case 'z': + if(argn+1 < argc) { + subbuf_size_high = (unsigned)atoi(argv[argn+1]); + argn++; + } else { + printf("Specify a number of high traffic subbuffers after -z.\n"); + printf("\n"); + ret = EINVAL; + } + break; + case 'x': + if(argn+1 < argc) { + n_subbufs_high = (unsigned)atoi(argv[argn+1]); + argn++; + } else { + printf("Specify a high traffic subbuffer size after -x.\n"); + printf("\n"); + ret = EINVAL; + } + break; + case 'd': + op = CTL_OP_DAEMON; + break; + case 'f': + op = CTL_OP_DAEMON_HYBRID_FINISH; + break; + case 't': + if(argn+1 < argc) { + trace_root = argv[argn+1]; + argn++; + } else { + printf("Specify a trace root path after -t.\n"); + printf("\n"); + ret = EINVAL; + } + break; + case 'l': + if(argn+1 < argc) { + channel_root = argv[argn+1]; + argn++; + } else { + printf("Specify a channel root path after -l.\n"); + printf("\n"); + ret = EINVAL; + } + break; + case 'a': + append_trace = 1; + break; + case 'N': + if(argn+1 < argc) { + num_threads = argv[argn+1]; + argn++; + } + break; + case 'T': + if(argn+1 < argc) { + trace_type = argv[argn+1]; + argn++; + } else { + printf("Specify a trace type after -T.\n"); + printf("\n"); + ret = EINVAL; + } + break; + default: + printf("Invalid argument '%s'.\n", argv[argn]); + printf("\n"); + ret = EINVAL; + } + break; + default: + printf("Invalid argument '%s'.\n", argv[argn]); + printf("\n"); + ret = EINVAL; + } + argn++; + } + + if(trace_name == NULL) { + printf("Please specify a trace name.\n"); + printf("\n"); + ret = EINVAL; + } + + if(op == CTL_OP_NONE) { + printf("Please specify an operation.\n"); + printf("\n"); + ret = EINVAL; + } + + if(op == CTL_OP_DAEMON || op == CTL_OP_DAEMON_HYBRID_FINISH) { + if(trace_root == NULL) { + printf("Please specify -t trace_root_path with the -d option.\n"); + printf("\n"); + ret = EINVAL; + } + if(channel_root == NULL) { + printf("Please specify -l ltt_root_path with the -d option.\n"); + printf("\n"); + ret = EINVAL; + } + } + + return ret; +} + +void show_info(void) +{ + printf("Linux Trace Toolkit Trace Control " VERSION"\n"); + printf("\n"); + if(trace_name != NULL) { + printf("Controlling trace : %s\n", trace_name); + printf("\n"); + } +} + +int lttctl_daemon(struct lttctl_handle *handle, char *trace_name) +{ + char channel_path[PATH_MAX] = ""; + pid_t pid; + int ret; + char *lttd_path = getenv("LTT_DAEMON"); + + if(lttd_path == NULL) lttd_path = + PACKAGE_BIN_DIR "/lttd"; + + strcat(channel_path, channel_root); + strcat(channel_path, "/"); + strcat(channel_path, trace_name); + + + ret = lttctl_create_trace(handle, trace_name, mode, trace_type, + subbuf_size_low, n_subbufs_low, + subbuf_size_med, n_subbufs_med, + subbuf_size_high, n_subbufs_high); + if(ret != 0) goto create_error; + + pid = fork(); + + if(pid > 0) { + int status = 0; + /* parent */ + + ret = waitpid(pid, &status, 0); + if(ret == -1) { + ret = errno; + perror("Error in waitpid"); + goto start_error; + } + + ret = 0; + if(WIFEXITED(status)) + ret = WEXITSTATUS(status); + if(ret) goto start_error; + + } else if(pid == 0) { + /* child */ + int ret; + if(mode != LTT_TRACE_HYBRID) { + if(append_trace) + ret = execlp(lttd_path, lttd_path, "-t", trace_root, "-c", + channel_path, "-d", "-a", "-N", num_threads, NULL); + else + ret = execlp(lttd_path, lttd_path, "-t", trace_root, "-c", + channel_path, "-d", "-N", num_threads, NULL); + } else { + if(append_trace) + ret = execlp(lttd_path, lttd_path, "-t", trace_root, "-c", + channel_path, "-d", "-a", "-N", num_threads, "-n", NULL); + else + ret = execlp(lttd_path, lttd_path, "-t", trace_root, "-c", + channel_path, "-d", "-N", num_threads, "-n", NULL); + } + if(ret) { + ret = errno; + perror("Error in executing the lttd daemon"); + exit(ret); + } + } else { + /* error */ + perror("Error in forking for lttd daemon"); + } + + ret = lttctl_start(handle, trace_name); + if(ret != 0) goto start_error; + + return 0; + + /* error handling */ +start_error: + printf("Trace start error\n"); + ret |= lttctl_destroy_trace(handle, trace_name); +create_error: + return ret; +} + + + + +int lttctl_daemon_hybrid_finish(struct lttctl_handle *handle, char *trace_name) +{ + char channel_path[PATH_MAX] = ""; + pid_t pid; + int ret; + char *lttd_path = getenv("LTT_DAEMON"); + + if(lttd_path == NULL) lttd_path = + PACKAGE_BIN_DIR "/lttd"; + + strcat(channel_path, channel_root); + strcat(channel_path, "/"); + strcat(channel_path, trace_name); + + + ret = lttctl_stop(handle, trace_name); + if(ret != 0) goto stop_error; + + pid = fork(); + + if(pid > 0) { + int status = 0; + /* parent */ + + ret = waitpid(pid, &status, 0); + if(ret == -1) { + ret = errno; + perror("Error in waitpid"); + goto destroy_error; + } + + ret = 0; + if(WIFEXITED(status)) + ret = WEXITSTATUS(status); + if(ret) goto destroy_error; + + } else if(pid == 0) { + /* child */ + int ret; + if(append_trace) + ret = execlp(lttd_path, lttd_path, "-t", trace_root, "-c", + channel_path, "-d", "-a", "-N", num_threads, "-f", NULL); + else + ret = execlp(lttd_path, lttd_path, "-t", trace_root, "-c", + channel_path, "-d", "-N", num_threads, "-f", NULL); + if(ret) { + ret = errno; + perror("Error in executing the lttd daemon"); + exit(ret); + } + } else { + /* error */ + perror("Error in forking for lttd daemon"); + } + + ret = lttctl_destroy_trace(handle, trace_name); + if(ret != 0) goto destroy_error; + + return 0; + + /* error handling */ +destroy_error: + printf("Hybrid trace destroy error\n"); +stop_error: + return ret; +} + + + +int main(int argc, char ** argv) +{ + int ret; + struct lttctl_handle *handle; + + ret = parse_arguments(argc, argv); + + if(ret != 0) show_arguments(); + if(ret == EINVAL) return EINVAL; + if(ret == -1) return 0; + + show_info(); + + handle = lttctl_create_handle(); + + if(handle == NULL) return -1; + + switch(op) { + case CTL_OP_CREATE_START: + ret = lttctl_create_trace(handle, trace_name, mode, trace_type, + subbuf_size_low, n_subbufs_low, + subbuf_size_med, n_subbufs_med, + subbuf_size_high, n_subbufs_high); + if(!ret) + ret = lttctl_start(handle, trace_name); + break; + case CTL_OP_CREATE: + ret = lttctl_create_trace(handle, trace_name, mode, trace_type, + subbuf_size_low, n_subbufs_low, + subbuf_size_med, n_subbufs_med, + subbuf_size_high, n_subbufs_high); + break; + case CTL_OP_DESTROY: + ret = lttctl_destroy_trace(handle, trace_name); + break; + case CTL_OP_STOP_DESTROY: + ret = lttctl_stop(handle, trace_name); + if(!ret) + ret = lttctl_destroy_trace(handle, trace_name); + break; + case CTL_OP_START: + ret = lttctl_start(handle, trace_name); + break; + case CTL_OP_STOP: + ret = lttctl_stop(handle, trace_name); + break; + case CTL_OP_DAEMON: + ret = lttctl_daemon(handle, trace_name); + break; + case CTL_OP_DAEMON_HYBRID_FINISH: + ret = lttctl_daemon_hybrid_finish(handle, trace_name); + break; + case CTL_OP_NONE: + break; + } + + ret |= lttctl_destroy_handle(handle); + + return ret; +} diff --git a/tags/ltt-control-0.51-12082008/lttctl/lttctl_distributed.sh b/tags/ltt-control-0.51-12082008/lttctl/lttctl_distributed.sh new file mode 100644 index 0000000..4e75182 --- /dev/null +++ b/tags/ltt-control-0.51-12082008/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/tags/ltt-control-0.51-12082008/lttd/Makefile.am b/tags/ltt-control-0.51-12082008/lttd/Makefile.am new file mode 100644 index 0000000..bb860bc --- /dev/null +++ b/tags/ltt-control-0.51-12082008/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/tags/ltt-control-0.51-12082008/lttd/lttd.c b/tags/ltt-control-0.51-12082008/lttd/lttd.c new file mode 100644 index 0000000..b001426 --- /dev/null +++ b/tags/ltt-control-0.51-12082008/lttd/lttd.c @@ -0,0 +1,938 @@ +/* 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 +/* 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); +} +#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; +}; + + + +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; + +/* 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("\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; + 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("Skipping normal channel %s\n", path_channel); + return 0; + } + } else { + if(dump_normal_only) { + printf("Skipping flight channel %s\n", path_channel); + return 0; + } + } + printf("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("Appending to file %s as requested\n", path_trace); + + fd_pairs->pair[fd_pairs->num_pairs-1].trace = + open(path_trace, O_WRONLY|O_APPEND, + S_IRWXU|S_IRWXG|S_IRWXO); + + if(fd_pairs->pair[fd_pairs->num_pairs-1].trace == -1) { + 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("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("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("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("Channel file : %s\n", path_channel); + + if(S_ISDIR(stat_buf.st_mode)) { + + printf("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, ret=0; + + + err = ioctl(pair->channel, RELAY_GET_SUBBUF, + &consumed_old); + printf("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; + } + + 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; + } +#if 0 + err = fsync(pair->trace); + if(err < 0) { + ret = errno; + perror("Error in writing to file"); + goto write_error; + } +#endif //0 +write_error: + 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; + } + } + + /* 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; + } + +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; + + err_ret = munmap(pair->mmap, pair->subbuf_size * pair->n_subbufs); + if(err_ret != 0) { + perror("Error in munmap"); + } + ret |= err_ret; + 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("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("Data received\n"); +#ifdef HAS_INOTIFY + switch(pollfd[0].revents) { + case POLLERR: + printf("Error returned in polling inotify fd %d.\n", pollfd[0].fd); + break; + case POLLHUP: + printf("Polling inotify fd %d tells it has hung up.\n", pollfd[0].fd); + break; + case POLLNVAL: + printf("Polling inotify fd %d tells fd is not open.\n", pollfd[0].fd); + break; + case POLLPRI: + case POLLIN: + + printf("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("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("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 = read_channels(thread_num, &fd_pairs, inotify_fd, &inotify_watch_array); + + 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(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(); + + if(daemon_mode) { + ret = daemon(0, 0); + + if(ret == -1) { + perror("An error occured while daemonizing."); + exit(-1); + } + } + + /* 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; + + tids = malloc(sizeof(pthread_t) * num_threads); + for(i=0; i= 0) + close(inotify_fd); + + return ret; +} diff --git a/tags/ltt-control-0.51-12082008/specs/Makefile.am b/tags/ltt-control-0.51-12082008/specs/Makefile.am new file mode 100644 index 0000000..c6ae90e --- /dev/null +++ b/tags/ltt-control-0.51-12082008/specs/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST = ltt-control.spec diff --git a/tags/ltt-control-0.51-12082008/specs/ltt-control.spec b/tags/ltt-control-0.51-12082008/specs/ltt-control.spec new file mode 100644 index 0000000..8b0a2a3 --- /dev/null +++ b/tags/ltt-control-0.51-12082008/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 -- 2.34.1