Initial import
authorDavid Goulet <david.goulet@polymtl.ca>
Wed, 13 Apr 2011 20:15:24 +0000 (16:15 -0400)
committerDavid Goulet <david.goulet@polymtl.ca>
Wed, 13 Apr 2011 20:15:24 +0000 (16:15 -0400)
This is the first import of the lttng-tools tree.

Signed-off-by: David Goulet <david.goulet@polymtl.ca>
27 files changed:
.gitignore [new file with mode: 0644]
AUTHORS [new file with mode: 0644]
COPYING [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
NEWS [new file with mode: 0644]
README [new file with mode: 0644]
bootstrap [new file with mode: 0755]
configure.ac [new file with mode: 0644]
include/Makefile.am [new file with mode: 0644]
include/lttng/liblttngctl.h [new file with mode: 0644]
include/lttngerr.h [new file with mode: 0644]
liblttngctl/Makefile.am [new file with mode: 0644]
liblttngctl/liblttngctl.c [new file with mode: 0644]
liblttsessiondcomm/Makefile.am [new file with mode: 0644]
liblttsessiondcomm/liblttsessiondcomm.c [new file with mode: 0644]
liblttsessiondcomm/liblttsessiondcomm.h [new file with mode: 0644]
ltt-sessiond/Makefile.am [new file with mode: 0644]
ltt-sessiond/ltt-sessiond.c [new file with mode: 0644]
ltt-sessiond/ltt-sessiond.h [new file with mode: 0644]
lttng/Makefile.am [new file with mode: 0644]
lttng/lttng.c [new file with mode: 0644]
lttng/lttng.h [new file with mode: 0644]
lttng/options.c [new file with mode: 0644]
tests/Makefile.am [new file with mode: 0644]
tests/runall [new file with mode: 0755]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..82001ff
--- /dev/null
@@ -0,0 +1,27 @@
+*.o
+*.so
+*.swp
+*.o
+*.swo
+Makefile
+.libs/
+.deps/
+*~
+*.la
+*.lo
+Makefile.in
+*.loT
+*.info
+configure
+aclocal.m4
+autom4te.cache/
+config.h
+config.h.in
+config/
+config.log
+config.status
+stamp-h1
+libtool
+
+ltt-sessiond/ltt-sessiond
+lttng/lttng
diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..6c52344
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+David Goulet <david.goulet@polymtl.ca>
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..670dcf5
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,17 @@
+LTTng Tracing Tools
+
+Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..7d1c323
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,365 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
+2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+
+   Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.  This file is offered as-is,
+without warranty of any kind.
+
+Basic Installation
+==================
+
+   Briefly, the shell commands `./configure; make; make install' should
+configure, build, and install this package.  The following
+more-detailed instructions are generic; see the `README' file for
+instructions specific to this package.  Some packages provide this
+`INSTALL' file but do not implement all of the features documented
+below.  The lack of an optional feature in a given package is not
+necessarily a bug.  More recommendations for GNU packages can be found
+in *note Makefile Conventions: (standards)Makefile Conventions.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+   It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring.  Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'.  You need `configure.ac' if
+you want to change it or regenerate `configure' using a newer version
+of `autoconf'.
+
+   The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.
+
+     Running `configure' might take a while.  While running, it prints
+     some messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package, generally using the just-built uninstalled binaries.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.  When installing into a prefix owned by root, it is
+     recommended that the package be configured and built as a regular
+     user, and only the `make install' phase executed with root
+     privileges.
+
+  5. Optionally, type `make installcheck' to repeat any self-tests, but
+     this time using the binaries in their final installed location.
+     This target does not install anything.  Running this target as a
+     regular user, particularly if the prior `make install' required
+     root privileges, verifies that the installation completed
+     correctly.
+
+  6. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+  7. Often, you can also type `make uninstall' to remove the installed
+     files again.  In practice, not all packages have tested that
+     uninstallation works correctly, even though it is required by the
+     GNU Coding Standards.
+
+  8. Some packages, particularly those that use Automake, provide `make
+     distcheck', which can by used by developers to test that all other
+     targets like `make install' and `make uninstall' work correctly.
+     This target is generally not run by end users.
+
+Compilers and Options
+=====================
+
+   Some systems require unusual options for compilation or linking that
+the `configure' script does not know about.  Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+   You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here
+is an example:
+
+     ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+   *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+   You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you can use GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.  This
+is known as a "VPATH" build.
+
+   With a non-GNU `make', it is safer to compile the package for one
+architecture at a time in the source code directory.  After you have
+installed the package for one architecture, use `make distclean' before
+reconfiguring for another architecture.
+
+   On MacOS X 10.5 and later systems, you can create libraries and
+executables that work on multiple system types--known as "fat" or
+"universal" binaries--by specifying multiple `-arch' options to the
+compiler but only a single `-arch' option to the preprocessor.  Like
+this:
+
+     ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CPP="gcc -E" CXXCPP="g++ -E"
+
+   This is not guaranteed to produce working output in all cases, you
+may have to build one architecture at a time and combine the results
+using the `lipo' tool if you have problems.
+
+Installation Names
+==================
+
+   By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc.  You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX', where PREFIX must be an
+absolute file name.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.  In general, the
+default for these options is expressed in terms of `${prefix}', so that
+specifying just `--prefix' will affect all of the other directory
+specifications that were not explicitly provided.
+
+   The most portable way to affect installation locations is to pass the
+correct locations to `configure'; however, many packages provide one or
+both of the following shortcuts of passing variable assignments to the
+`make install' command line to change installation locations without
+having to reconfigure or recompile.
+
+   The first method involves providing an override variable for each
+affected directory.  For example, `make install
+prefix=/alternate/directory' will choose an alternate location for all
+directory configuration variables that were expressed in terms of
+`${prefix}'.  Any directories that were specified during `configure',
+but not in terms of `${prefix}', must each be overridden at install
+time for the entire installation to be relocated.  The approach of
+makefile variable overrides for each directory variable is required by
+the GNU Coding Standards, and ideally causes no recompilation.
+However, some platforms have known limitations with the semantics of
+shared libraries that end up requiring recompilation when using this
+method, particularly noticeable in packages that use GNU Libtool.
+
+   The second method involves providing the `DESTDIR' variable.  For
+example, `make install DESTDIR=/alternate/directory' will prepend
+`/alternate/directory' before all installation names.  The approach of
+`DESTDIR' overrides is not required by the GNU Coding Standards, and
+does not work on platforms that have drive letters.  On the other hand,
+it does better at avoiding recompilation issues, and works well even
+when some directory options were not specified in terms of `${prefix}'
+at `configure' time.
+
+Optional Features
+=================
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+   Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+   Some packages offer the ability to configure how verbose the
+execution of `make' will be.  For these packages, running `./configure
+--enable-silent-rules' sets the default to minimal output, which can be
+overridden with `make V=1'; while running `./configure
+--disable-silent-rules' sets the default to verbose, which can be
+overridden with `make V=0'.
+
+Particular systems
+==================
+
+   On HP-UX, the default C compiler is not ANSI C compatible.  If GNU
+CC is not installed, it is recommended to use the following options in
+order to use an ANSI C compiler:
+
+     ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
+
+and if that doesn't work, install pre-built binaries of GCC for HP-UX.
+
+   On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
+parse its `<wchar.h>' header file.  The option `-nodtk' can be used as
+a workaround.  If GNU CC is not installed, it is therefore recommended
+to try
+
+     ./configure CC="cc"
+
+and if that doesn't work, try
+
+     ./configure CC="cc -nodtk"
+
+   On Solaris, don't put `/usr/ucb' early in your `PATH'.  This
+directory contains several dysfunctional programs; working variants of
+these programs are available in `/usr/bin'.  So, if you need `/usr/ucb'
+in your `PATH', put it _after_ `/usr/bin'.
+
+   On Haiku, software installed for all users goes in `/boot/common',
+not `/usr/local'.  It is recommended to use the following options:
+
+     ./configure --prefix=/boot/common
+
+Specifying the System Type
+==========================
+
+   There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on.  Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+     CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+     OS
+     KERNEL-OS
+
+   See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+   If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+   If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+   If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+   Variables not defined in a site shell script can be set in the
+environment passed to `configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'.  For example:
+
+     ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf bug.  Until the bug is fixed you can use this workaround:
+
+     CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+   `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+     Print a summary of all of the options to `configure', and exit.
+
+`--help=short'
+`--help=recursive'
+     Print a summary of the options unique to this package's
+     `configure', and exit.  The `short' variant lists options used
+     only in the top level, while the `recursive' variant lists options
+     also present in any nested packages.
+
+`--version'
+`-V'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally `config.cache'.  FILE defaults to `/dev/null' to
+     disable caching.
+
+`--config-cache'
+`-C'
+     Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`--prefix=DIR'
+     Use DIR as the installation prefix.  *note Installation Names::
+     for more details, including other options available for fine-tuning
+     the installation locations.
+
+`--no-create'
+`-n'
+     Run the configure checks, but stop before creating any output
+     files.
+
+`configure' also accepts some other, not widely useful, options.  Run
+`configure --help' for more details.
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..e53d907
--- /dev/null
@@ -0,0 +1,3 @@
+ACLOCAL_AMFLAGS = -I config
+
+SUBDIRS = liblttsessiondcomm liblttngctl lttng ltt-sessiond tests
diff --git a/NEWS b/NEWS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..a9b6dcb
--- /dev/null
+++ b/README
@@ -0,0 +1,71 @@
+LTTng Trace Control
+----------------
+
+Please visit http://lttng.org for more information.
+
+Latest development can be found at:
+
+       * Gitweb :      http://git.lttng.org/lttng-tools.git/
+       * Git :         git://git.lttng.org/lttng-tools.git
+
+PREREQUISITES:
+
+       - libuuid
+         Universally unique id library - headers and static libraries libuuid
+         generates and parses 128-bit universally unique ids (UUIDs). See RFC
+         4122 for more information.
+
+         * Debian/Ubuntu package: uuid-dev
+
+       - liburcu
+         Userspace RCU library, by Mathieu Desnoyers and Paul E. McKenney
+         
+         -> Tested with liburcu >= v0.5.4
+
+         * Debian/Ubuntu package: liburcu-dev
+         * Git : git://lttng.org/userspace-rcu.git
+         * Website:  http://lttng.org/urcu
+
+       - libustctl
+         LTTng user-space tracer control library
+
+         Needed for interaction with that tracer.
+
+       - liblttctl
+         LTTng kernel tracer control library
+
+         Needed for interaction with that tracer.
+
+INSTALLATION INSTRUCTIONS:
+
+  - Download, compile and install liburcu, libuuid, libustctl and liblttctl
+  - In this package's tree, run ./configure.
+  - Run make.
+  - Run make install.
+  - Run ldconfig.
+
+  If compiling from the git repository, run ./bootstrap before running
+  the configure script, to generate it.
+
+PACKAGE CONTENTS:
+
+       This package contains the following elements:
+
+       - liblttngctl
+         The LTTng trace control library.
+
+       - liblttsessiondcomm
+         The ltt-sessiond communication library. In order to talk with ltt-sessiond,
+         thi library must be used.
+
+       - ltt-sessiond
+         The LTTng session daemon binary.
+
+       - lttng
+         The LTTng tracer command line control tool.
+
+       - include
+         The liblttngctl API header file.
+
+       - tests
+         Various test programs.
diff --git a/bootstrap b/bootstrap
new file mode 100755 (executable)
index 0000000..c71b862
--- /dev/null
+++ b/bootstrap
@@ -0,0 +1,8 @@
+#! /bin/sh
+
+set -x
+if [ ! -e config ]; then
+       mkdir config
+fi
+
+autoreconf -i
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..bbd5914
--- /dev/null
@@ -0,0 +1,56 @@
+AC_INIT([lttng-tools], [0.0.1], [david.goulet@polymtl.ca], [http://lttng.org])
+AC_CONFIG_AUX_DIR([config])
+AC_CONFIG_MACRO_DIR([config])
+AM_INIT_AUTOMAKE
+AM_SILENT_RULES([yes])
+
+AC_CHECK_HEADERS([ \
+       sys/types.h unistd.h fcntl.h string.h pthread.h limits.h \
+       signal.h stdlib.h sys/un.h sys/socket.h stdlib.h stdio.h \
+       getopt.h sys/ipc.h sys/shm.h popt.h grp.h \
+])
+
+# Check for pthread
+AC_CHECK_LIB([pthread], [pthread_create], [],
+       [AC_MSG_ERROR([Cannot find libpthread. Use [LDFLAGS]=-Ldir to specify its location.])]
+)
+
+# Check libpopt
+AC_CHECK_LIB([popt], [poptGetContext], [],
+       [AC_MSG_ERROR([Cannot find libpopt. Use [LDFLAGS]=-Ldir to specify its location.])]
+)
+
+# Check libuuid
+AC_CHECK_LIB([uuid], [uuid_generate], [],
+       [AC_MSG_ERROR([Cannot find libuuid. Use [LDFLAGS]=-Ldir to specify its location.])]
+)
+
+# Check libustctl
+AC_CHECK_LIB([ustctl], [ustctl_connect_pid], [],
+       [AC_MSG_ERROR([Cannot find libustctl. Use [LDFLAGS]=-Ldir to specify its location.])]
+)
+
+# Check liburcu
+AC_CHECK_LIB([urcu], [synchronize_rcu], [],
+       [AC_MSG_ERROR([Cannot find liburcu. Use [LDFLAGS]=-Ldir to specify its location.])]
+)
+AC_CHECK_DECL([cds_list_add], [],
+       [AC_MSG_ERROR([liburcu 0.5.4 or newer is needed])], [[#include <urcu/list.h>]]
+)
+
+CFLAGS="-Wall $CFLAGS -g"
+
+AC_PROG_CC
+AC_PROG_LIBTOOL
+
+AC_CONFIG_FILES([
+       Makefile
+       include/Makefile
+       liblttngctl/Makefile
+       liblttsessiondcomm/Makefile
+       lttng/Makefile
+       tests/Makefile
+       ltt-sessiond/Makefile
+])
+
+AC_OUTPUT
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644 (file)
index 0000000..8f0946b
--- /dev/null
@@ -0,0 +1,4 @@
+nobase_include_HEADERS = \
+       lttng/liblttngctl.h
+
+noinst_HEADERS = lttngerr.h
diff --git a/include/lttng/liblttngctl.h b/include/lttng/liblttngctl.h
new file mode 100644 (file)
index 0000000..cfe0cb5
--- /dev/null
@@ -0,0 +1,36 @@
+/* Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * 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.
+ * 
+ */
+
+#ifndef _LIBLTTNGCTL_H
+#define _LIBLTTNGCTL_H
+
+#define DEFAULT_TRACING_GROUP "tracing"
+
+/* 
+ * From libuuid
+ */
+#define UUID_STR_LEN 37
+
+extern int lttng_create_session(const char *name, char *session_id);
+extern int lttng_connect_sessiond(void);
+extern int lttng_set_tracing_group(const char *name);
+extern int lttng_check_session_daemon(void);
+extern const char *lttng_get_readable_code(int code);
+extern size_t lttng_ust_list_apps(pid_t **pids);
+
+#endif /* _LIBLTTNGCTL_H */
diff --git a/include/lttngerr.h b/include/lttngerr.h
new file mode 100644 (file)
index 0000000..5c3d8c4
--- /dev/null
@@ -0,0 +1,64 @@
+/* Copyright (C)  2011 - David Goulet <david.goulet@polymtl.ca>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * 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.
+ * 
+ */
+
+#ifndef _LTTNGERR_H
+#define _LTTNGERR_H
+
+#include <errno.h>
+#include <stdarg.h>
+
+extern int opt_quiet;
+extern int opt_verbose;
+
+enum __lttng_print_type {
+       PRINT_ERR,
+       PRINT_WARN,
+       PRINT_BUG,
+       PRINT_DBG,
+       PRINT_MSG,
+};
+
+/*
+ *  __lttng_print
+ *
+ *  Internal function for printing message
+ *  depending on command line option and verbosity.
+ */
+void __lttng_print(enum __lttng_print_type type, const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+
+       if (opt_quiet == 0) {
+               if (type == PRINT_MSG || (opt_verbose && type == PRINT_DBG)) {
+                       vfprintf(stdout, fmt, ap);
+               } else if (type != PRINT_MSG && type != PRINT_DBG) {
+                       vfprintf(stderr, fmt, ap);
+               }
+       }
+
+       va_end(ap);
+}
+
+#define MSG(fmt, args...) __lttng_print(PRINT_MSG, fmt "\n", ## args)
+#define ERR(fmt, args...) __lttng_print(PRINT_ERR, "Error: " fmt "\n", ## args)
+#define WARN(fmt, args...) __lttng_print(PRINT_WARN, "Warning: " fmt "\n", ## args)
+#define BUG(fmt, args...) __lttng_print(PRINT_BUG, "BUG: " fmt "\n", ## args)
+#define DBG(fmt, args...) __lttng_print(PRINT_DBG, "DEBUG: " fmt "\n", ## args)
+
+#endif /* _LTTNGERR_H */
diff --git a/liblttngctl/Makefile.am b/liblttngctl/Makefile.am
new file mode 100644 (file)
index 0000000..6fa83f1
--- /dev/null
@@ -0,0 +1,8 @@
+AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/liblttsessiondcomm
+
+lib_LTLIBRARIES = liblttngctl.la
+
+liblttngctl_la_SOURCES = liblttngctl.c
+
+liblttngctl_la_LIBADD = \
+               $(top_builddir)/liblttsessiondcomm/liblttsessiondcomm.la
diff --git a/liblttngctl/liblttngctl.c b/liblttngctl/liblttngctl.c
new file mode 100644 (file)
index 0000000..8258874
--- /dev/null
@@ -0,0 +1,334 @@
+/* Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * 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.
+ * 
+ */
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <grp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <lttng/liblttngctl.h>
+
+#include "liblttsessiondcomm.h"
+#include "lttngerr.h"
+
+/* Socket to session daemon for communication */
+static int sessiond_socket;
+static char sessiond_sock_path[PATH_MAX];
+
+/* Communication structure to ltt-sessiond */
+static struct lttcomm_lttng_msg llm;
+static struct lttcomm_session_msg lsm;
+
+/* Prototypes */
+static int check_tracing_group(const char *grp_name);
+static int ask_sessiond(void);
+static int set_session_daemon_path(void);
+static void reset_data_struct(void);
+
+int lttng_connect_sessiond(void);
+int lttng_create_session(const char *name, char *session_id);
+int lttng_check_session_daemon(void);
+
+/* Variables */
+static char *tracing_group;
+static int connected;
+
+/*
+ *  ask_sessiond
+ *
+ *  Send lttcomm_session_msg to the daemon and wait
+ *  for the reply. Data replied will be put in llm
+ *
+ *  On success, return 0
+ *  On error, return error code
+ */
+static int ask_sessiond(void)
+{
+       int ret;
+
+       if (!connected) {
+               ret = -ECONNREFUSED;
+               goto error;
+       }
+
+       ret = lttcomm_send_unix_sock(sessiond_socket, &lsm, sizeof(lsm));
+       if (ret < 0) {
+               goto error;
+       }
+
+       ret = lttcomm_recv_unix_sock(sessiond_socket, &llm, sizeof(llm));
+       if (ret < 0) {
+               goto error;
+       }
+
+       /* Check return code */
+       if (llm.ret_code != LTTCOMM_OK) {
+               ret = -llm.ret_code;
+               goto error;
+       }
+
+       return 0;
+
+error:
+       return ret;
+}
+
+/*
+ *  lttng_get_readable_code
+ *
+ *  Return a human readable string of code
+ */
+const char *lttng_get_readable_code(int code)
+{
+       if (code > -LTTCOMM_OK) {
+               return "Ended with errors";
+       }
+
+       return lttcomm_get_readable_code(code);
+}
+
+/*
+ *  lttng_create_session
+ *
+ *  Create a tracing session using "name" to the session daemon.
+ *  If no name is given, the auto session creation is set and
+ *  the daemon will take care of finding a name.
+ *
+ *  On success, return 0 and session_id point to the uuid str.
+ *  On error, negative value is returned.
+ */
+int lttng_create_session(const char *name, char *session_id)
+{
+       int ret;
+
+       lsm.cmd_type = LTTNG_CREATE_SESSION;
+       if (name == NULL) {
+               lsm.u.create_session.auto_session = 1;
+       } else {
+               strncpy(lsm.session_name, name, strlen(name));
+               lsm.u.create_session.auto_session = 0;
+       }
+
+       /* Ask the session daemon */
+       ret = ask_sessiond();
+       if (ret < 0) {
+               goto end;
+       }
+
+       /* Unparse session ID */
+       uuid_unparse(llm.session_id, session_id);
+
+end:
+       reset_data_struct();
+
+       return ret;
+}
+
+/*
+ *  lttng_ust_list_apps
+ *
+ *  Ask the session daemon for all UST traceable
+ *  applications.
+ *
+ *  Return the size of pids.
+ */
+size_t lttng_ust_list_apps(pid_t **pids)
+{
+       int ret;
+
+       lsm.cmd_type = UST_LIST_APPS;
+
+       ret = ask_sessiond();
+       if (ret < 0) {
+               goto error;
+       }
+
+       *pids = llm.u.list_apps.pids;
+
+       return llm.u.list_apps.size;
+
+error:
+       return ret;
+}
+
+/*
+ *  lttng_connect_sessiond
+ *
+ *  Connect to the LTTng session daemon.
+ *  On success, return 0
+ *  On error, return a negative value
+ */
+int lttng_connect_sessiond(void)
+{
+       int ret;
+
+       ret = set_session_daemon_path();
+       if (ret < 0) {
+               return ret;
+       }
+
+       /* Connect to the sesssion daemon */
+       ret = lttcomm_connect_unix_sock(sessiond_sock_path);
+       if (ret < 0) {
+               return ret;
+       }
+
+       sessiond_socket = ret;
+       connected = 1;
+
+       return 0;
+}
+
+/*
+ *  lttng_set_tracing_group
+ *
+ *  Set tracing group variable with name. This function
+ *  allocate memory pointed by tracing_group.
+ */
+int lttng_set_tracing_group(const char *name)
+{
+       if (asprintf(&tracing_group, "%s", name) < 0) {
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+/*
+ *  lttng_check_session_daemon
+ *
+ *  Return 0 if a sesssion daemon is available
+ *  else return -1
+ */
+int lttng_check_session_daemon(void)
+{
+       int ret;
+
+       ret = set_session_daemon_path();
+       if (ret < 0) {
+               return ret;
+       }
+
+       /* If socket exist, we consider the daemon started */
+       ret = access(sessiond_sock_path, F_OK);
+       if (ret < 0) {
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+ *  reset_data_struct
+ *
+ *  Reset session daemon structures.
+ */
+static void reset_data_struct(void)
+{
+       memset(&lsm, 0, sizeof(lsm));
+       memset(&llm, 0, sizeof(llm));
+}
+
+/*
+ *  set_session_daemon_path
+ *
+ *  Set sessiond socket path by putting it in 
+ *  the global sessiond_sock_path variable.
+ */
+static int set_session_daemon_path(void)
+{
+       int ret;
+
+       /* Are we in the tracing group ? */
+       ret = check_tracing_group(tracing_group);
+       if (ret < 0) {
+               if (sprintf(sessiond_sock_path, DEFAULT_HOME_CLIENT_UNIX_SOCK,
+                                       getenv("HOME")) < 0) {
+                       return -ENOMEM;
+               }
+       } else {
+               strncpy(sessiond_sock_path, DEFAULT_GLOBAL_CLIENT_UNIX_SOCK,
+                               sizeof(DEFAULT_GLOBAL_CLIENT_UNIX_SOCK));
+       }
+
+       return 0;
+}
+
+/*
+ *  check_tracing_group
+ *
+ *  Check if the specified group name exist.
+ *  If yes, 0, else -1
+ */
+static int check_tracing_group(const char *grp_name)
+{
+       struct group *grp_tracing;      /* no free(). See getgrnam(3) */
+       gid_t *grp_list;
+       int grp_list_size, grp_id, i;
+       int ret = -1;
+
+       /* Get GID of group 'tracing' */
+       grp_tracing = getgrnam(grp_name);
+       if (grp_tracing == NULL) {
+               /* NULL means not found also. getgrnam(3) */
+               if (errno != 0) {
+                       perror("getgrnam");
+               }
+               goto end;
+       }
+
+       /* Get number of supplementary group IDs */
+       grp_list_size = getgroups(0, NULL);
+       if (grp_list_size < 0) {
+               perror("getgroups");
+               goto end;
+       }
+
+       /* Alloc group list of the right size */
+       grp_list = malloc(grp_list_size * sizeof(gid_t));
+       grp_id = getgroups(grp_list_size, grp_list);
+       if (grp_id < -1) {
+               perror("getgroups");
+               goto free_list;
+       }
+
+       for (i = 0; i < grp_list_size; i++) {
+               if (grp_list[i] == grp_tracing->gr_gid) {
+                       ret = 0;
+                       break;
+               }
+       }
+
+free_list:
+       free(grp_list);
+
+end:
+       return ret;
+}
+
+/*
+ * lib constructor
+ */
+static void __attribute__((constructor)) init()
+{
+       /* Set default session group */
+       lttng_set_tracing_group(DEFAULT_TRACING_GROUP);
+}
diff --git a/liblttsessiondcomm/Makefile.am b/liblttsessiondcomm/Makefile.am
new file mode 100644 (file)
index 0000000..55105fe
--- /dev/null
@@ -0,0 +1,6 @@
+AM_CPPFLAGS = -I$(top_srcdir)/include
+
+lib_LTLIBRARIES = liblttsessiondcomm.la
+
+liblttsessiondcomm_la_SOURCES = \
+                               liblttsessiondcomm.c
diff --git a/liblttsessiondcomm/liblttsessiondcomm.c b/liblttsessiondcomm/liblttsessiondcomm.c
new file mode 100644 (file)
index 0000000..6bc8532
--- /dev/null
@@ -0,0 +1,225 @@
+/* Copyright (C)  2011 - David Goulet <david.goulet@polymtl.ca>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * 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.
+ * 
+ */
+
+#define _GNU_SOURCE
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "liblttsessiondcomm.h"
+
+/*
+ * Human readable error message.
+ */
+static const char *lttcomm_readable_code[] = {
+       [ LTTCOMM_ERR_INDEX(LTTCOMM_OK) ] = "Success",
+       [ LTTCOMM_ERR_INDEX(LTTCOMM_ERR) ] = "Unknown error",
+       [ LTTCOMM_ERR_INDEX(LTTCOMM_UND) ] = "Undefined command",
+       [ LTTCOMM_ERR_INDEX(LTTCOMM_NO_SESSION) ] = "No session found",
+       [ LTTCOMM_ERR_INDEX(LTTCOMM_LIST_FAIL) ] = "Unable to list traceable apps",
+};
+
+/*
+ *  lttcom_get_readable_code
+ *
+ *  Return ptr to string representing a human readable
+ *  error code from the lttcomm_return_code enum.
+ *
+ *  These code MUST be negative in other to treat that
+ *  as an error value.
+ */
+const char *lttcomm_get_readable_code(enum lttcomm_return_code code)
+{
+       int tmp_code = -code;
+
+       if (tmp_code >= LTTCOMM_OK && tmp_code < LTTCOMM_NR) {
+               return lttcomm_readable_code[LTTCOMM_ERR_INDEX(tmp_code)];
+       }
+
+       return "Unknown error code";
+}
+
+/*
+ *     lttcomm_connect_unix_sock
+ *
+ *     Connect to unix socket using the path name.
+ */
+int lttcomm_connect_unix_sock(const char *pathname)
+{
+    struct sockaddr_un sun;
+    int fd;
+       int ret = 1;
+
+    fd = socket(PF_UNIX, SOCK_STREAM, 0);
+       if (fd < 0) {
+               perror("socket");
+               goto error;
+       }
+
+    memset(&sun, 0, sizeof(sun));
+    sun.sun_family = AF_UNIX;
+    strncpy(sun.sun_path, pathname, sizeof(sun.sun_path));
+
+    ret = connect(fd, (struct sockaddr *) &sun, sizeof(sun));
+    if (ret < 0) {
+        perror("connect");
+               goto error;
+    }
+
+    return fd;
+
+error:
+       return -1;
+}
+
+/*
+ *     lttcomm_accept_unix_sock
+ *
+ *     Do an accept(2) on the sock and return the
+ *     new file descriptor. The socket MUST be bind(2) before.
+ */
+int lttcomm_accept_unix_sock(int sock)
+{
+       int new_fd;
+       struct sockaddr_un sun;
+       socklen_t len = 0;
+
+       /* Blocking call */
+       new_fd = accept(sock, (struct sockaddr *) &sun, &len);
+       if (new_fd < 0) {
+               perror("accept");
+               goto error;
+       }
+
+       return new_fd;
+
+error:
+       return -1;
+}
+
+/*
+ *     lttcomm_create_unix_sock
+ *
+ *     Creates a AF_UNIX local socket using pathname
+ *     bind the socket upon creation and return the fd.
+ */
+int lttcomm_create_unix_sock(const char *pathname)
+{
+       struct sockaddr_un sun;
+       int fd;
+       int ret = -1;
+
+       /* Create server socket */
+       if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
+               perror("socket");
+               goto error;
+       }
+
+       memset(&sun, 0, sizeof(sun));
+       sun.sun_family = AF_UNIX;
+       strncpy(sun.sun_path, pathname, strlen(pathname));
+
+       ret = bind(fd, (struct sockaddr *) &sun, sizeof(sun));
+       if (ret < 0) {
+               perror("bind");
+               goto error;
+       }
+
+       return fd;
+
+error:
+       return ret;
+}
+
+/*
+ *     lttcomm_listen_unix_sock
+ *
+ *     Make the socket listen using MAX_LISTEN.
+ */
+int lttcomm_listen_unix_sock(int sock)
+{
+       int ret;
+
+       ret = listen(sock, MAX_LISTEN);
+       if (ret < 0) {
+               perror("listen");
+       }
+
+       return ret;
+}
+
+/*
+ *     lttcomm_recv_unix_sock
+ *
+ *  Receive data of size len in put that data into
+ *  the buf param. Using recvmsg API.
+ *  Return the size of received data.
+ */
+ssize_t lttcomm_recv_unix_sock(int sock, void *buf, size_t len)
+{
+       struct msghdr msg;
+       struct iovec iov[1];
+       ssize_t ret = -1;
+
+       memset(&msg, 0, sizeof(msg));
+
+       iov[0].iov_base = buf;
+       iov[0].iov_len = len;
+       msg.msg_iov = iov;
+       msg.msg_iovlen = 1;
+
+       ret = recvmsg(sock, &msg, 0);
+       if (ret < 0) {
+               perror("recvmsg");
+       }
+
+       return ret;
+}
+
+/*
+ *     lttcomm_send_unix_sock
+ *
+ *     Send buf data of size len. Using sendmsg API.
+ *     Return the size of sent data.
+ */
+ssize_t lttcomm_send_unix_sock(int sock, void *buf, size_t len)
+{
+       struct msghdr msg;
+       struct iovec iov[1];
+       ssize_t ret = -1;
+
+       memset(&msg, 0, sizeof(msg));
+
+       iov[0].iov_base = buf;
+       iov[0].iov_len = len;
+       msg.msg_iov = iov;
+       msg.msg_iovlen = 1;
+
+       ret = sendmsg(sock, &msg, 0);
+       if (ret < 0) {
+               perror("sendmsg");
+       }
+
+       return ret;
+}
diff --git a/liblttsessiondcomm/liblttsessiondcomm.h b/liblttsessiondcomm/liblttsessiondcomm.h
new file mode 100644 (file)
index 0000000..b52d1dd
--- /dev/null
@@ -0,0 +1,146 @@
+/* Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * 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.
+ * 
+ */
+
+#ifndef _LIBLTTSESSIONDCOMM_H
+#define _LIBLTTSESSIONDCOMM_H
+
+#include <limits.h>
+#include <uuid/uuid.h>
+
+/* Default unix socket path */
+#define DEFAULT_GLOBAL_CLIENT_UNIX_SOCK                "/tmp/client-ltt-sessiond"
+#define DEFAULT_GLOBAL_APPS_UNIX_SOCK          "/tmp/apps-ltt-sessiond"
+#define DEFAULT_HOME_APPS_UNIX_SOCK                    "%s/.apps-ltt-sessiond"
+#define DEFAULT_HOME_CLIENT_UNIX_SOCK          "%s/.client-ltt-sessiond"
+
+/* Queue size of listen(2) */
+#define MAX_LISTEN 10
+
+/* Maximum amount of PID the list_apps command
+ * can send back to the lttng client.
+ */
+#define MAX_APPS_PID 20
+
+/* Get the error code index from 0 since
+ * LTTCOMM_OK start at 1000
+ */
+#define LTTCOMM_ERR_INDEX(code) code - LTTCOMM_OK
+
+enum lttcomm_command_type {
+       LTTNG_CREATE_SESSION,
+       LTTNG_DESTROY_SESSION,
+       LTTNG_FORCE_SUBBUF_SWITCH,
+       LTTNG_GET_ALL_SESSION,
+       LTTNG_GET_SOCK_PATH,
+       LTTNG_GET_SUBBUF_NUM_SIZE,
+       LTTNG_LIST_MARKERS,
+       LTTNG_LIST_SESSIONS,
+       LTTNG_LIST_TRACE_EVENTS,
+       LTTNG_SETUP_TRACE,
+       LTTNG_SET_SOCK_PATH,
+       LTTNG_SET_SUBBUF_NUM,
+       LTTNG_SET_SUBBUF_SIZE,
+       UST_ALLOC_TRACE,
+       UST_CREATE_TRACE,
+       UST_DESTROY_TRACE,
+       UST_DISABLE_MARKER,
+       UST_ENABLE_MARKER,
+       UST_LIST_APPS,
+       UST_START_TRACE,
+       UST_STOP_TRACE,
+};
+
+/*
+ * lttcomm error code.
+ */
+enum lttcomm_return_code {
+       LTTCOMM_OK = 1000,              /* Ok */
+       LTTCOMM_ERR,                    /* Unknown Error */
+       LTTCOMM_UND,                    /* Undefine command */
+       LTTCOMM_ALLOC_FAIL,             /* Trace allocation fail */
+       LTTCOMM_NO_SESSION,             /* No session found */
+       LTTCOMM_CREATE_FAIL,    /* Create trace fail */
+       LTTCOMM_SESSION_FAIL,   /* Create session fail */
+       LTTCOMM_START_FAIL,             /* Start tracing fail */
+       LTTCOMM_LIST_FAIL,              /* Listing apps fail */
+       LTTCOMM_NR,                             /* Last element */
+};
+
+/*
+ * Data structure for ltt-session received message
+ */
+struct lttcomm_session_msg {
+       /* Common data to almost all command */
+       enum lttcomm_command_type cmd_type;
+       uuid_t session_id;
+       char trace_name[NAME_MAX];
+       char session_name[NAME_MAX];
+       pid_t pid;
+       union {
+               struct {
+                       int auto_session;
+               } create_session;
+               /* Marker data */
+               struct {
+                       char channel[NAME_MAX];
+                       char marker[NAME_MAX];
+               } marker;
+               /* SET_SOCK_PATH */
+               struct {
+                       char sock_path[PATH_MAX];
+               } sock_path;
+               /* SET_SUBBUF_NUM */
+               struct {
+                       unsigned int subbuf_num;
+                       char channel[NAME_MAX];
+               } subbuf_num;
+               /* SET_SUBBUF_SIZE */
+               struct {
+                       unsigned int subbuf_size;
+                       char channel[NAME_MAX];
+               } subbuf_size;
+       } u;
+};
+
+/*
+ * Data structure for the lttng client response
+ */
+struct lttcomm_lttng_msg {
+       enum lttcomm_command_type cmd_type;
+       enum lttcomm_return_code ret_code;
+       uuid_t session_id;
+       pid_t pid;
+       char trace_name[NAME_MAX];
+       union {
+               /* UST_LIST_APPS */
+               struct {
+                       size_t size;
+                       pid_t pids[MAX_APPS_PID];
+               } list_apps;
+       } u;
+};
+
+extern int lttcomm_create_unix_sock(const char *pathname);
+extern int lttcomm_connect_unix_sock(const char *pathname);
+extern int lttcomm_accept_unix_sock(int sock);
+extern int lttcomm_listen_unix_sock(int sock);
+extern ssize_t lttcomm_recv_unix_sock(int sock, void *buf, size_t len);
+extern ssize_t lttcomm_send_unix_sock(int sock, void *buf, size_t len);
+extern const char *lttcomm_get_readable_code(enum lttcomm_return_code code);
+
+#endif /* _LIBLTTSESSIONDCOMM_H */
diff --git a/ltt-sessiond/Makefile.am b/ltt-sessiond/Makefile.am
new file mode 100644 (file)
index 0000000..4793091
--- /dev/null
@@ -0,0 +1,8 @@
+AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/liblttsessiondcomm
+
+bin_PROGRAMS = ltt-sessiond
+
+ltt_sessiond_SOURCES = ltt-sessiond.c
+
+ltt_sessiond_LDADD = \
+                $(top_builddir)/liblttsessiondcomm/liblttsessiondcomm.la
diff --git a/ltt-sessiond/ltt-sessiond.c b/ltt-sessiond/ltt-sessiond.c
new file mode 100644 (file)
index 0000000..08d1555
--- /dev/null
@@ -0,0 +1,851 @@
+/* Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * 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.
+ * 
+ */
+
+#define _GNU_SOURCE
+#include <fcntl.h>
+#include <getopt.h>
+#include <grp.h>
+#include <limits.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <urcu/list.h>         /* URCU list library (-lurcu) */
+#include <ust/ustctl.h>                /* UST control lib (-lust) */
+
+#include "liblttsessiondcomm.h"
+#include "ltt-sessiond.h"
+
+/* Static functions */
+static int set_signal_handler(void);
+static int set_socket_perms(void);
+static void sighandler(int);
+static void daemonize(void);
+static void cleanup(void);
+static int check_existing_daemon(void);
+static int notify_apps(const char*);
+static int connect_app(pid_t);
+static int init_daemon_socket(void);
+static struct lttcomm_lttng_msg *process_client_msg(struct lttcomm_session_msg*);
+
+static void *thread_manage_clients(void *);
+static void *thread_manage_apps(void *);
+
+static int create_session(const char*, uuid_t *);
+static void destroy_session(uuid_t);
+
+static struct ltt_session *find_session(uuid_t);
+
+/* Variables */
+const char *progname;
+const char *opt_tracing_group;
+static int opt_daemon;
+static int is_root;                    /* Set to 1 if the daemon is running as root */
+
+static char apps_unix_sock_path[PATH_MAX];                     /* Global application Unix socket path */
+static char client_unix_sock_path[PATH_MAX];           /* Global client Unix socket path */
+
+static int client_socket;
+static int apps_socket;
+
+static struct ltt_session *current_session;
+static int session_count;
+
+/* Init session's list */
+static struct ltt_session_list ltt_session_list = {
+       .head = CDS_LIST_HEAD_INIT(ltt_session_list.head),
+};
+
+static struct ltt_traceable_app_list ltt_traceable_app_list = {
+       .head = CDS_LIST_HEAD_INIT(ltt_traceable_app_list.head),
+};
+
+/*
+ *     thread_manage_apps
+ *
+ *     This thread manage the application socket communication
+ */
+static void *thread_manage_apps(void *data)
+{
+       int sock, ret;
+       struct ltt_traceable_app *lta;
+
+       /* TODO: Something more elegant is needed but fine for now */
+    struct {
+               int reg;        /* 1:register, 0:unregister */
+        pid_t pid;
+        uid_t uid;
+    } reg_msg;
+
+       /* Notify all applications to register */
+       notify_apps(default_global_apps_pipe);
+
+       ret = lttcomm_listen_unix_sock(apps_socket);
+       if (ret < 0) {
+               goto error;
+       }
+
+       while (1) {
+               /* Blocking call, waiting for transmission */
+               sock = lttcomm_accept_unix_sock(apps_socket);
+               if (sock < 0) {
+                       goto error;
+               }
+
+               /* Basic recv here to handle the very simple data
+                * that the libust send to register (reg_msg).
+                */
+               ret = recv(sock, &reg_msg, sizeof(reg_msg), 0);
+               if (ret < 0) {
+                       perror("recv");
+                       continue;
+               }
+
+               /* Add application to the global traceable list */
+               if (reg_msg.reg == 1) {
+                       /* Registering */
+                       lta = malloc(sizeof(struct ltt_traceable_app));
+                       lta->pid = reg_msg.pid;
+                       lta->uid = reg_msg.uid;
+                       cds_list_add(&lta->list, &ltt_traceable_app_list.head);
+               } else {
+                       /* Unregistering */
+                       lta = NULL;
+                       cds_list_for_each_entry(lta, &ltt_traceable_app_list.head, list) {
+                               if (lta->pid == reg_msg.pid && lta->uid == reg_msg.uid) {
+                                       cds_list_del(&lta->list);
+                                       break;
+                               }
+                       }
+
+                       /* If an item was found, free it from memory */
+                       if (lta) {
+                               free(lta);
+                       }
+               }
+       }
+
+error:
+
+       return NULL;
+}
+
+/*
+ *     thread_manage_clients
+ *
+ *     This thread manage all clients request using the unix
+ *     client socket for communication.
+ */
+static void *thread_manage_clients(void *data)
+{
+       int sock, ret;
+       struct lttcomm_session_msg lsm;
+       struct lttcomm_lttng_msg *llm;
+
+       ret = lttcomm_listen_unix_sock(client_socket);
+       if (ret < 0) {
+               goto error;
+       }
+
+       while (1) {
+               /* Blocking call, waiting for transmission */
+               sock = lttcomm_accept_unix_sock(client_socket);
+               if (sock < 0) {
+                       goto error;
+               }
+
+               /*
+                * Data is received from the lttng client. The struct
+                * lttcomm_session_msg (lsm) contains the command and data
+                * request of the client.
+                */
+               ret = lttcomm_recv_unix_sock(sock, &lsm, sizeof(lsm));
+               if (ret < 0) {
+                       continue;
+               }
+
+               /* This function dispatch the work to the LTTng or UST libs
+                * and make sure that the reply structure (llm) is filled.
+                */
+               llm = process_client_msg(&lsm);
+
+               /* Having a valid lttcomm_lttng_msg struct, reply is sent back
+                * to the client directly.
+                */
+               if (llm != NULL) {
+                       ret = lttcomm_send_unix_sock(sock, llm,
+                                       sizeof(struct lttcomm_lttng_msg));
+                       free(llm);
+                       if (ret < 0) {
+                               continue;
+                       }
+               } else {
+                       /* The lttcomm_lttng_msg struct was not allocated
+                        * correctly. Fatal error since the daemon is not able
+                        * to respond. However, we still permit client connection.
+                        *
+                        * TODO: We should have a default llm that tells the client
+                        * that the sessiond had a fatal error and thus the client could
+                        * take action to restart ltt-sessiond or inform someone.
+                        */
+               }
+       }
+
+error:
+       return NULL;
+}
+
+/*
+ *     connect_app
+ *
+ *     Return a socket connected to the libust communication socket
+ *     of the application identified by the pid.
+ */
+static int connect_app(pid_t pid)
+{
+       int sock;
+
+       sock = ustctl_connect_pid(pid);
+       if (sock < 0) {
+               fprintf(stderr, "Fail connecting to the PID %d\n", pid);
+       }
+
+       return sock;
+}
+
+/*
+ *     notify_apps
+ *
+ *  Notify apps by writing 42 to a named pipe using name.
+ *     Every applications waiting for a ltt-sessiond will be notified
+ *     and re-register automatically to the session daemon.
+ *
+ *     Return open or write error value.
+ */
+static int notify_apps(const char *name)
+{
+       int fd;
+       int ret = -1;
+
+       /* Try opening the global pipe */
+       fd = open(name, O_WRONLY);
+       if (fd < 0) {
+               goto error;
+       }
+
+       /* Notify by writing on the pipe */
+       ret = write(fd, "42", 2);
+       if (ret < 0) {
+               perror("write");
+       }
+
+error:
+       return ret;
+}
+
+/*
+ *     find_session
+ *
+ *     Return a ltt_session structure ptr that matches the uuid.
+ */
+static struct ltt_session *find_session(uuid_t session_id)
+{
+       struct ltt_session *iter = NULL;
+
+       /* Sanity check for NULL session_id */
+       if (uuid_is_null(session_id)) {
+               goto end;
+       }
+
+       cds_list_for_each_entry(iter, &ltt_session_list.head, list) {
+               if (uuid_compare(iter->uuid, session_id)) {
+                       break;
+               }
+       }
+
+end:
+       return iter;
+}
+
+/*
+ *     destroy_session
+ *
+ *  Delete session from the global session list
+ *  and free the memory.
+ */
+static void destroy_session(uuid_t session_id)
+{
+       struct ltt_session *iter = NULL;
+
+       cds_list_for_each_entry(iter, &ltt_session_list.head, list) {
+               if (uuid_compare(iter->uuid, session_id)) {
+                       cds_list_del(&iter->list);
+                       break;
+               }
+       }
+
+       if (iter) {
+               free(iter);
+               session_count--;
+       }
+}
+
+/*
+ *     create_session
+ *
+ *     Create a brand new session, 
+ */
+static int create_session(const char *name, uuid_t *session_id)
+{
+       struct ltt_session *new_session;
+
+       /* Allocate session data structure */
+       new_session = malloc(sizeof(struct ltt_session));
+       if (new_session == NULL) {
+               perror("malloc");
+               goto error;
+       }
+
+       if (name != NULL) {
+               if (asprintf(&new_session->name, "%s", name) < 0) {
+                       goto error;
+               }
+       } else {
+               /* Generate session name based on the session count */
+               if (asprintf(&new_session->name, "%s%d", "auto", session_count) < 0) {
+                       goto error;
+               }
+       }
+
+       /* UUID generation */
+       uuid_generate(new_session->uuid);
+       uuid_copy(*session_id, new_session->uuid);
+
+       /* Set consumer (identifier) to 0. This means that there is
+        * NO consumer attach to that session yet.
+        */
+       new_session->ust_consumer = 0;
+       new_session->lttng_consumer = 0;
+
+       /* Init list */
+       CDS_INIT_LIST_HEAD(&new_session->ust_traces);
+       CDS_INIT_LIST_HEAD(&new_session->lttng_traces);
+
+       /* Add new session to the global session list */
+       cds_list_add(&new_session->list, &ltt_session_list.head);
+
+       session_count++;
+
+       return 0;
+
+error:
+       return -1;
+}
+
+/*
+ *     ust_list_apps
+ *
+ *  List traceable user-space application and fill an
+ *  array of pids.
+ *
+ *  Return size of the array.
+ */
+static size_t ust_list_apps(pid_t *pids)
+{
+       size_t size = 0;
+       struct ltt_traceable_app *iter = NULL;
+
+       cds_list_for_each_entry(iter, &ltt_traceable_app_list.head, list) {
+               if (size >= MAX_APPS_PID) {
+                       break;
+               }
+
+               pids[size] = iter->pid;
+               size++;
+       }
+
+       return size;
+}
+
+/*
+ *     process_client_msg
+ *
+ *     This takes the lttcomm_session_msg struct and process the command requested
+ *     by the client. It then creates the reply by allocating a lttcomm_lttng_msg
+ *     and fill it with the necessary information.
+ *
+ *     It's the caller responsability to free that structure when done with it.
+ *     
+ *     Return pointer to lttcomm_lttng_msg allocated struct.
+ */
+static struct lttcomm_lttng_msg *process_client_msg(struct lttcomm_session_msg *lsm)
+{
+       struct lttcomm_lttng_msg *llm;
+
+       /* Allocate the reply message structure */
+       llm = malloc(sizeof(struct lttcomm_lttng_msg));
+       if (llm == NULL) {
+               perror("malloc");
+               goto end;
+       }
+
+       /* Copy common data to identify the response
+        * on the lttng client side.
+        */
+       llm->cmd_type = lsm->cmd_type;
+       llm->pid = lsm->pid;
+       if (!uuid_is_null(lsm->session_id)) {
+               uuid_copy(llm->session_id, lsm->session_id);
+       }
+       strncpy(llm->trace_name, lsm->trace_name, sizeof(llm->trace_name));
+
+       /* Default return code.
+        * In a our world, everything is OK... right?
+        */
+       llm->ret_code = LTTCOMM_OK;
+
+       /* Process by command type */
+       switch (lsm->cmd_type) {
+               case UST_LIST_APPS:
+               {
+                       llm->u.list_apps.size = ust_list_apps(llm->u.list_apps.pids);
+                       break;
+               }
+               default:
+                       /* Undefined command */
+                       llm->ret_code = LTTCOMM_UND;
+                       break;
+       }
+
+end:
+       return llm;
+}
+
+/*
+ * usage function on stderr
+ */
+static void usage(void)
+{
+       fprintf(stderr, "Usage:\n%s OPTIONS\n\nOptions:\n"
+                       "\t-h, --help\t\tDisplay this usage.\n"
+                       "\t-c, --client-sock PATH\t\tSpecify path for the client unix socket\n"
+                       "\t-a, --apps-sock PATH\t\tSpecify path for apps unix socket.\n"
+                       "\t-d, --daemonize\t\tStart as a daemon.\n"
+                       "\t-g, --group NAME\t\tSpecify the tracing group name. (default: tracing)\n"
+                       "\t-V, --version\t\tShow version number.\n",
+                       progname);
+}
+
+/*
+ * daemon argument parsing
+ */
+static int parse_args(int argc, char **argv)
+{
+       int c;
+
+       static struct option long_options[] = {
+               { "client-sock", 1, 0, 'c' },
+               { "apps-sock", 1, 0, 'a' },
+               { "daemonize", 0, 0, 'd' },
+               { "help", 0, 0, 'h' },
+               { "group", 1, 0, 'g' },
+               { "version", 0, 0, 'V' },
+               { NULL, 0, 0, 0 }
+       };
+
+       while (1) {
+               int option_index = 0;
+               c = getopt_long(argc, argv, "dhV" "a:c:g:s:", long_options, &option_index);
+               if (c == -1) {
+                       break;
+               }
+
+               switch (c) {
+               case 0:
+                       fprintf(stderr, "option %s", long_options[option_index].name);
+                       if (optarg) {
+                               fprintf(stderr, " with arg %s\n", optarg);
+                       }
+                       break;
+               case 's':
+                       snprintf(client_unix_sock_path, PATH_MAX, "%s", optarg);
+                       break;
+               case 'a':
+                       snprintf(apps_unix_sock_path, PATH_MAX, "%s", optarg);
+                       break;
+               case 'd':
+                       opt_daemon = 1;
+                       break;
+               case 'g':
+                       opt_tracing_group = strdup(optarg);
+                       break;
+               case 'h':
+                       usage();
+                       exit(EXIT_FAILURE);
+               case 'V':
+                       fprintf(stdout, "%s\n", VERSION);
+                       exit(EXIT_SUCCESS);
+               default:
+                       /* Unknown option or other error.
+                        * Error is printed by getopt, just return */
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ *     init_daemon_socket
+ *
+ *     Creates the two needed socket by the daemon.
+ *             apps_socket - The communication socket for all UST apps.
+ *             client_socket - The communication of the cli tool (lttng).
+ */
+static int init_daemon_socket()
+{
+       int ret = 0;
+       mode_t old_umask;
+
+       old_umask = umask(0);
+
+       /* Create client tool unix socket */
+       client_socket = lttcomm_create_unix_sock(client_unix_sock_path);
+       if (client_socket < 0) {
+               ret = -1;
+               goto end;
+       }
+
+       /* File permission MUST be 660 */
+       ret = chmod(client_unix_sock_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+       if (ret < 0) {
+               perror("chmod");
+               goto end;
+       }
+
+       /* Create the application unix socket */
+       apps_socket = lttcomm_create_unix_sock(apps_unix_sock_path);
+       if (apps_socket < 0) {
+               ret = -1;
+               goto end;
+       }
+
+       /* File permission MUST be 660 */
+       ret = chmod(apps_unix_sock_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+       if (ret < 0) {
+               perror("chmod");
+               goto end;
+       }
+
+end:
+       umask(old_umask);
+       return ret;
+}
+
+/*
+ *     check_existing_daemon
+ *
+ *     Check if the global socket is available.
+ *     If yes, error is returned.
+ */
+static int check_existing_daemon()
+{
+       int ret;
+
+       ret = access(client_unix_sock_path, F_OK);
+       if (ret == 0) {
+               ret = access(apps_unix_sock_path, F_OK);
+       }
+
+       return ret;
+}
+
+/*
+ *     get_home_dir
+ *
+ *     Return pointer to home directory path using
+ *     the env variable HOME.
+ *
+ *     Default : /tmp
+ */
+static const char *get_home_dir(void)
+{
+       const char *home_path;
+
+       if ((home_path = (const char*) getenv("HOME")) == NULL) {
+               home_path = default_home_dir;
+       }
+
+       return home_path;
+}
+
+/*
+ *  set_socket_perms
+ *
+ *     Set the tracing group gid onto the client socket.
+ */
+static int set_socket_perms(void)
+{
+       int ret;
+       struct group *grp;
+
+       /* Decide which group name to use */
+       (opt_tracing_group != NULL) ?
+               (grp = getgrnam(opt_tracing_group)) :
+               (grp = getgrnam(default_tracing_group));
+
+       if (grp == NULL) {
+               fprintf(stderr, "Missing tracing group. Aborting execution.\n");
+               ret = -1;
+               goto end;
+       }
+
+       ret = chown(client_unix_sock_path, 0, grp->gr_gid);
+       if (ret < 0) {
+               perror("chown");
+       }
+
+end:
+       return ret;
+}
+
+/*
+ *     daemonize
+ *
+ *     Daemonize ltt-sessiond.
+ */
+static void daemonize(void)
+{
+       pid_t pid, sid;
+       const char *home_dir = get_home_dir();
+
+       /* Fork off the parent process */
+       if ((pid = fork()) < 0) {
+               perror("fork");
+               exit(EXIT_FAILURE);
+       }
+
+       /* Parent can now exit */
+       if (pid > 0) {
+               exit(EXIT_SUCCESS);
+       }
+
+       /* Change the file mode mask */
+       umask(0);
+
+       /* Create a new SID for the child process */
+       if ((sid = setsid()) < 0) {
+               perror("setsid");
+               exit(EXIT_FAILURE);
+       }
+
+       /* Change the current working directory */
+       if ((chdir(home_dir)) < 0) {
+               perror("chdir");
+               exit(EXIT_FAILURE);
+       }
+
+       /* Close out the standard file descriptors */
+       close(STDIN_FILENO);
+       close(STDOUT_FILENO);
+       close(STDERR_FILENO);
+}
+
+/*
+ *     set_signal_handler
+ *
+ *     Setup signal handler for :
+ *             SIGINT, SIGTERM, SIGPIPE
+ */
+static int set_signal_handler(void)
+{
+       int ret = 0;
+       struct sigaction sa;
+       sigset_t sigset;
+
+       if ((ret = sigemptyset(&sigset)) < 0) {
+               perror("sigemptyset");
+               return ret;
+       }
+
+       sa.sa_handler = sighandler;
+       sa.sa_mask = sigset;
+       sa.sa_flags = 0;
+       if ((ret = sigaction(SIGTERM, &sa, NULL)) < 0) {
+               perror("sigaction");
+               return ret;
+       }
+
+       if ((ret = sigaction(SIGINT, &sa, NULL)) < 0) {
+               perror("sigaction");
+               return ret;
+       }
+
+       if ((ret = sigaction(SIGPIPE, &sa, NULL)) < 0) {
+               perror("sigaction");
+               return ret;
+       }
+
+       return ret;
+}
+
+/**
+ *     sighandler
+ *
+ *     Signal handler for the daemon
+ */
+static void sighandler(int sig)
+{
+       switch (sig) {
+               case SIGPIPE:
+               case SIGINT:
+               case SIGTERM:
+                       cleanup();
+               default:
+                       break;
+       }
+
+       exit(EXIT_SUCCESS);
+}
+
+/*
+ *     cleanup 
+ *
+ *     Cleanup the daemon on exit
+ */
+static void cleanup()
+{
+       /* <fun> */
+       fprintf(stdout, "\n\n%c[%d;%dm*** assert failed *** ==> %c[%dm", 27,1,31,27,0);
+       fprintf(stdout, "%c[%d;%dm Matthew, BEET driven development works!%c[%dm\n",27,1,33,27,0);
+       /* </fun> */
+
+       unlink(client_unix_sock_path);
+       unlink(apps_unix_sock_path);
+}
+
+/*
+ * main
+ */
+int main(int argc, char **argv)
+{
+       int i;
+       int ret = 0;
+       void *status;
+       pthread_t threads[2];
+
+       /* Parse arguments */
+       progname = argv[0];
+       if ((ret = parse_args(argc, argv) < 0)) {
+               goto error;
+       }
+
+       /* Daemonize */
+       if (opt_daemon) {
+               daemonize();
+       }
+
+       /* Check if daemon is UID = 0 */
+       is_root = !getuid();
+
+       /* Set all sockets path */
+       if (is_root) {
+               if (strlen(apps_unix_sock_path) == 0) {
+                       (snprintf(apps_unix_sock_path, PATH_MAX,
+                                       DEFAULT_GLOBAL_APPS_UNIX_SOCK));
+               }
+
+               if (strlen(client_unix_sock_path) == 0) {
+                       (snprintf(client_unix_sock_path, PATH_MAX,
+                                       DEFAULT_GLOBAL_CLIENT_UNIX_SOCK));
+               }
+       } else {
+               if (strlen(apps_unix_sock_path) == 0) {
+                       (snprintf(apps_unix_sock_path, PATH_MAX,
+                                       DEFAULT_HOME_APPS_UNIX_SOCK, get_home_dir()));
+               }
+
+               /* Set the cli tool unix socket path */
+               if (strlen(client_unix_sock_path) == 0) {
+                       (snprintf(client_unix_sock_path, PATH_MAX,
+                                       DEFAULT_HOME_CLIENT_UNIX_SOCK, get_home_dir()));
+               }
+       }
+
+       /* See if daemon already exist. If any of the two
+        * socket needed by the daemon are present, this test fails
+        */
+       if ((ret = check_existing_daemon()) == 0) {
+               fprintf(stderr, "Already running daemon.\n");
+               goto error;
+       }
+
+       if (set_signal_handler() < 0) {
+               goto error;
+       }
+
+       /* Setup the two needed unix socket */
+       if (init_daemon_socket() < 0) {
+               goto error;
+       }
+
+       /* Set credentials to socket */
+       if (is_root && (set_socket_perms() < 0)) {
+               goto error;
+       }
+
+       while (1) {
+               /* Create thread to manage the client socket */
+               ret = pthread_create(&threads[0], NULL, thread_manage_clients, (void *) NULL);
+               if (ret != 0) {
+                       perror("pthread_create");
+                       goto error;
+               }
+
+               /* Create thread to manage application socket */
+               ret = pthread_create(&threads[1], NULL, thread_manage_apps, (void *) NULL);
+               if (ret != 0) {
+                       perror("pthread_create");
+                       goto error;
+               }
+
+               for (i = 0; i < 2; i++) {
+                       ret = pthread_join(threads[i], &status);
+                       if (ret != 0) {
+                               perror("pthread_join");
+                               goto error;
+                       }
+               }
+       }
+
+       cleanup();
+       return 0;
+
+error:
+       cleanup();
+
+       return EXIT_FAILURE;
+}
diff --git a/ltt-sessiond/ltt-sessiond.h b/ltt-sessiond/ltt-sessiond.h
new file mode 100644 (file)
index 0000000..591e831
--- /dev/null
@@ -0,0 +1,83 @@
+/* Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * 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.
+ * 
+ */
+
+#ifndef _LTT_SESSIOND_H
+#define _LTT_SESSIOND_H
+
+const char default_home_dir[] = "/tmp";
+const char default_tracing_group[] = "tracing";
+const char default_ust_sock_dir[] = "/tmp/ust-app-socks";
+const char default_global_apps_pipe[] = "/tmp/ust-app-socks/global";
+
+/* LTTng trace representation */
+struct ltt_lttng_trace {
+       struct cds_list_head list;
+       char trace_name[NAME_MAX];
+       struct cds_list_head marker_list;
+};
+
+/* UST trace representation */
+struct ltt_ust_trace {
+       struct cds_list_head list;
+       int shmid;
+       char trace_name[NAME_MAX];
+       struct cds_list_head markers;
+};
+
+struct ltt_ust_marker {
+       struct cds_list_head list;
+       char *name;
+       char *channel;
+};
+
+/* Global session list */
+struct ltt_session_list {
+       struct cds_list_head head;
+};
+
+/* Traceable application list */
+struct ltt_traceable_app_list {
+       struct cds_list_head head;
+};
+
+/*
+ * Registered traceable applications. Libust registers
+ * to the session daemon and a linked list is kept
+ * of all running traceable app.
+ */
+struct ltt_traceable_app {
+       struct cds_list_head list;
+       pid_t pid;
+       uid_t uid;              /* User ID that owns the apps */
+};
+
+/*
+ * ltt-session - This data structure contains information needed
+ * to identify a tracing session for both LTTng and UST.
+ */
+struct ltt_session {
+       char *name;
+       struct cds_list_head list;
+       uuid_t uuid;
+       struct cds_list_head ust_traces;
+       struct cds_list_head lttng_traces;
+       pid_t ust_consumer;
+       pid_t lttng_consumer;
+};
+
+#endif /* _LTT_SESSIOND_H */
diff --git a/lttng/Makefile.am b/lttng/Makefile.am
new file mode 100644 (file)
index 0000000..947c750
--- /dev/null
@@ -0,0 +1,10 @@
+AM_CPPFLAGS = -I$(top_srcdir)/include
+#AM_CFLAGS = $(LTTNG_LIBS) -lpopt
+
+bin_PROGRAMS = lttng
+
+lttng_SOURCES = options.c lttng.c
+
+lttng_LDADD = \
+               $(top_builddir)/liblttngctl/liblttngctl.la
+#              $(top_builddir)/liblttsessiondcomm/liblttsessiondcomm.la
diff --git a/lttng/lttng.c b/lttng/lttng.c
new file mode 100644 (file)
index 0000000..188b13d
--- /dev/null
@@ -0,0 +1,188 @@
+/* Copyright (c)  2011 David Goulet <david.goulet@polymtl.ca>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <grp.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <lttng/liblttngctl.h>
+
+#include "lttng.h"
+#include "lttngerr.h"
+
+/* Variables */
+static char *progname;
+
+/* Prototypes */
+static int process_client_opt(void);
+static int process_opt_list_apps(void);
+
+/*
+ *  start_client
+ *
+ *  Process client request from the command line
+ *  options. Every tracing action is done by the
+ *  liblttngctl API.
+ */
+static int process_client_opt(void)
+{
+       int ret;
+
+       /* Connect to the session daemon */
+       ret = lttng_connect_sessiond();
+       if (ret < 0) {
+               ERR("%s", lttng_get_readable_code(ret));
+               goto end;
+       }
+
+       if (opt_list_apps) {
+               ret = process_opt_list_apps();
+               if (ret < 0) {
+                       ERR("%s", lttng_get_readable_code(ret));
+                       goto end;
+               }
+       }
+
+       return 0;
+
+end:
+       return ret;
+}
+
+/*
+ *  process_opt_list_apps
+ *
+ *  Get the UST traceable pid list and print
+ *  them to the user.
+ */
+static int process_opt_list_apps(void)
+{
+       int i, ret;
+       pid_t *pids;
+       FILE *fp;
+       char path[24];  /* Can't go bigger than /proc/65535/cmdline */
+       char cmdline[PATH_MAX];
+
+       ret = lttng_ust_list_apps(&pids);
+       if (ret < 0) {
+               goto error;
+       }
+
+       MSG("LTTng UST traceable application [name (pid)]:");
+       for (i=0; i < ret; i++) {
+               snprintf(path, sizeof(path), "/proc/%d/cmdline", pids[i]);
+               fp = fopen(path, "r");
+               if (fp == NULL) {
+                       continue;
+               }
+               ret = fread(cmdline, 1, sizeof(cmdline), fp);
+               MSG("\t%s (%d)", cmdline, pids[i]);
+               fclose(fp);
+       }
+
+       return 0;
+
+error:
+       return ret;
+}
+
+/*
+ *  check_ltt_sessiond
+ *
+ *  Check if the session daemon is available using
+ *  the liblttngctl API for the check.
+ */
+static int check_ltt_sessiond(void)
+{
+       int ret;
+
+       ret = lttng_check_session_daemon();
+       if (ret < 0) {
+               ERR("No session daemon found. Aborting.");
+       }
+
+       return ret;
+}
+
+
+/*
+ * clean_exit
+ */
+void clean_exit(int code)
+{
+       DBG("Clean exit");
+       exit(code);
+}
+
+/*
+ * main
+ */
+int main(int argc, char *argv[])
+{
+       int ret;
+
+       progname = argv[0] ? argv[0] : "lttng";
+
+       /* For Mathieu Desnoyers aka Dr Tracing */
+       if (strncmp(progname, "drtrace", 7) == 0) {
+               MSG("%c[%d;%dmWelcome back Dr Tracing!%c[%dm\n\n", 27,1,33,27,0);
+       }
+
+       ret = parse_args(argc, (const char **) argv);
+       if (ret < 0) {
+               return EXIT_FAILURE;
+       }
+
+       if (opt_tracing_group != NULL) {
+               DBG("Set tracing group to '%s'", opt_tracing_group);
+               lttng_set_tracing_group(opt_tracing_group);
+       }
+
+       /* If ask for kernel tracing, need root perms */
+       if (opt_trace_kernel) {
+               DBG("Kernel tracing activated");
+               if (getuid() != 0) {
+                       ERR("%s must be setuid root", progname);
+                       return -EPERM;
+               }
+       }
+
+       /* Check if the lttng session daemon is running.
+        * If no, a daemon will be spawned.
+        */
+       if (check_ltt_sessiond() < 0) {
+               return EXIT_FAILURE;
+       }
+
+       ret = process_client_opt();
+       if (ret < 0) {
+               return ret;
+       }
+
+       return 0;
+}
diff --git a/lttng/lttng.h b/lttng/lttng.h
new file mode 100644 (file)
index 0000000..587ff0e
--- /dev/null
@@ -0,0 +1,33 @@
+/* Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * 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.
+ */
+
+#ifndef _LTTNG_H
+#define _LTTNG_H
+
+/* Function prototypes */
+int parse_args(int argc, const char **argv);
+void clean_exit(int code);
+
+/* Command line options */
+extern int opt_trace_kernel;
+extern int opt_verbose;
+extern int opt_quiet;
+extern char *opt_tracing_group;
+extern char *opt_session_name;
+extern int opt_list_apps;
+
+#endif /* _LTTNG_H */
diff --git a/lttng/options.c b/lttng/options.c
new file mode 100644 (file)
index 0000000..3457f0b
--- /dev/null
@@ -0,0 +1,104 @@
+/* Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * 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.
+ * 
+ */
+
+#include <popt.h>
+#include <stdlib.h>
+
+#include "lttng.h"
+
+/* Option variables */
+char *opt_tracing_group;
+char *opt_session_name;
+int opt_trace_kernel = 0;
+int opt_quiet = 0;
+int opt_verbose = 0;
+int opt_list_apps = 0;
+
+enum {
+       OPT_HELP = 42,
+};
+
+static struct poptOption long_options[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       {"help",                        'h',    POPT_ARG_NONE,          0, OPT_HELP, 0, 0},
+       {"group",                       0,              POPT_ARG_STRING,        &opt_tracing_group, 0, 0},
+       {"kernel",                      0,              POPT_ARG_VAL,           &opt_trace_kernel, 1, 0, 0},
+       {"no-kernel",           0,              POPT_ARG_VAL,           &opt_trace_kernel, 0, 0, 0},
+       {"session",                     0,              POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_session_name, 0, 0},
+       {"quiet",                       'q',    POPT_ARG_VAL,           &opt_quiet, 1, 0},
+       {"verbose",                     'v',    POPT_ARG_VAL,           &opt_verbose, 1, 0},
+       {"list-apps",           'l',    POPT_ARG_VAL,           &opt_list_apps, 1, 0},
+       {0, 0, 0, 0, 0, 0}
+};
+
+
+/*
+ *     usage
+ */
+static void usage(FILE *ofp)
+{
+       fprintf(ofp, "LTTng Trace Control " VERSION"\n\n");
+       fprintf(ofp, "usage : lttng [OPTION]\n");
+       fprintf(ofp, "\n");
+       fprintf(ofp, "Options:\n");
+       fprintf(ofp, "  -v, --verbose           Verbose mode\n");
+       fprintf(ofp, "  -q, --quiet             Quiet mode\n");
+       fprintf(ofp, "      --help              Show help\n");
+       fprintf(ofp, "      --group NAME        Unix tracing group name. (default: tracing)\n");
+       fprintf(ofp, "\n");
+       fprintf(ofp, "Tracing options:\n");
+       //fprintf(ofp, "      --session [NAME]    Specify tracing session. If no NAME is given\n");
+       //fprintf(ofp, "                          or option is ommited, a session will be created\n");
+       //fprintf(ofp, "      --kernel            Enable kernel tracing\n");
+       //fprintf(ofp, "      --no-kernel         Disable kernel tracing\n");
+       fprintf(ofp, "  -l, --list-apps         List traceable UST applications\n");
+}
+
+/*
+ *  parse_args
+ *
+ *  Parse command line arguments.
+ *  Return 0 if OK, else -1
+ */
+int parse_args(int argc, const char **argv)
+{
+       static poptContext pc;
+       int opt;
+
+       pc = poptGetContext("lttng", argc, argv, long_options, 0);
+       poptReadDefaultConfig(pc, 0);
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+               case OPT_HELP:
+                       usage(stderr);
+                       clean_exit(EXIT_SUCCESS);
+                       break;
+               default:
+                       usage(stderr);
+                       clean_exit(EXIT_FAILURE);
+                       break;
+               }
+       }
+
+       if (pc) {
+               poptFreeContext(pc);
+       }
+
+       return 0;
+}
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644 (file)
index 0000000..4824e22
--- /dev/null
@@ -0,0 +1,3 @@
+SUBDIRS = .
+
+dist_noinst_SCRIPTS = runall
diff --git a/tests/runall b/tests/runall
new file mode 100755 (executable)
index 0000000..e69de29
This page took 0.0548 seconds and 4 git commands to generate.