From fac6795d6e2c60e79bdc7dab42da94d2025a57d3 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Wed, 13 Apr 2011 16:15:24 -0400 Subject: [PATCH 1/1] Initial import This is the first import of the lttng-tools tree. Signed-off-by: David Goulet --- .gitignore | 27 + AUTHORS | 1 + COPYING | 17 + ChangeLog | 0 INSTALL | 365 ++++++++++ Makefile.am | 3 + NEWS | 0 README | 71 ++ bootstrap | 8 + configure.ac | 56 ++ include/Makefile.am | 4 + include/lttng/liblttngctl.h | 36 + include/lttngerr.h | 64 ++ liblttngctl/Makefile.am | 8 + liblttngctl/liblttngctl.c | 334 ++++++++++ liblttsessiondcomm/Makefile.am | 6 + liblttsessiondcomm/liblttsessiondcomm.c | 225 +++++++ liblttsessiondcomm/liblttsessiondcomm.h | 146 ++++ ltt-sessiond/Makefile.am | 8 + ltt-sessiond/ltt-sessiond.c | 851 ++++++++++++++++++++++++ ltt-sessiond/ltt-sessiond.h | 83 +++ lttng/Makefile.am | 10 + lttng/lttng.c | 188 ++++++ lttng/lttng.h | 33 + lttng/options.c | 104 +++ tests/Makefile.am | 3 + tests/runall | 0 27 files changed, 2651 insertions(+) create mode 100644 .gitignore create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 INSTALL create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 README create mode 100755 bootstrap create mode 100644 configure.ac create mode 100644 include/Makefile.am create mode 100644 include/lttng/liblttngctl.h create mode 100644 include/lttngerr.h create mode 100644 liblttngctl/Makefile.am create mode 100644 liblttngctl/liblttngctl.c create mode 100644 liblttsessiondcomm/Makefile.am create mode 100644 liblttsessiondcomm/liblttsessiondcomm.c create mode 100644 liblttsessiondcomm/liblttsessiondcomm.h create mode 100644 ltt-sessiond/Makefile.am create mode 100644 ltt-sessiond/ltt-sessiond.c create mode 100644 ltt-sessiond/ltt-sessiond.h create mode 100644 lttng/Makefile.am create mode 100644 lttng/lttng.c create mode 100644 lttng/lttng.h create mode 100644 lttng/options.c create mode 100644 tests/Makefile.am create mode 100755 tests/runall diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..82001ff50 --- /dev/null +++ b/.gitignore @@ -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 index 000000000..6c5234463 --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +David Goulet diff --git a/COPYING b/COPYING new file mode 100644 index 000000000..670dcf584 --- /dev/null +++ b/COPYING @@ -0,0 +1,17 @@ +LTTng Tracing Tools + +Copyright (C) 2011 David Goulet + +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 index 000000000..e69de29bb diff --git a/INSTALL b/INSTALL new file mode 100644 index 000000000..7d1c323be --- /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 `' 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 index 000000000..e53d9079e --- /dev/null +++ b/Makefile.am @@ -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 index 000000000..e69de29bb diff --git a/README b/README new file mode 100644 index 000000000..a9b6dcb8c --- /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 index 000000000..c71b862a5 --- /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 index 000000000..bbd591445 --- /dev/null +++ b/configure.ac @@ -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 ]] +) + +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 index 000000000..8f0946be5 --- /dev/null +++ b/include/Makefile.am @@ -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 index 000000000..cfe0cb59e --- /dev/null +++ b/include/lttng/liblttngctl.h @@ -0,0 +1,36 @@ +/* Copyright (C) 2011 - David Goulet + * + * 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 index 000000000..5c3d8c4fb --- /dev/null +++ b/include/lttngerr.h @@ -0,0 +1,64 @@ +/* Copyright (C) 2011 - David Goulet + * + * 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 +#include + +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 index 000000000..6fa83f1c2 --- /dev/null +++ b/liblttngctl/Makefile.am @@ -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 index 000000000..8258874dc --- /dev/null +++ b/liblttngctl/liblttngctl.c @@ -0,0 +1,334 @@ +/* Copyright (C) 2011 David Goulet + * + * 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 +#include +#include +#include +#include +#include + +#include + +#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 index 000000000..55105fedd --- /dev/null +++ b/liblttsessiondcomm/Makefile.am @@ -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 index 000000000..6bc853268 --- /dev/null +++ b/liblttsessiondcomm/liblttsessiondcomm.c @@ -0,0 +1,225 @@ +/* Copyright (C) 2011 - David Goulet + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 000000000..b52d1dd5b --- /dev/null +++ b/liblttsessiondcomm/liblttsessiondcomm.h @@ -0,0 +1,146 @@ +/* Copyright (C) 2011 - David Goulet + * + * 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 +#include + +/* 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 index 000000000..479309189 --- /dev/null +++ b/ltt-sessiond/Makefile.am @@ -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 index 000000000..08d1555a8 --- /dev/null +++ b/ltt-sessiond/ltt-sessiond.c @@ -0,0 +1,851 @@ +/* Copyright (C) 2011 - David Goulet + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* URCU list library (-lurcu) */ +#include /* 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, ®_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(<a->list, <t_traceable_app_list.head); + } else { + /* Unregistering */ + lta = NULL; + cds_list_for_each_entry(lta, <t_traceable_app_list.head, list) { + if (lta->pid == reg_msg.pid && lta->uid == reg_msg.uid) { + cds_list_del(<a->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, <t_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, <t_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, <t_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, <t_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() +{ + /* */ + 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); + /* */ + + 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 index 000000000..591e83104 --- /dev/null +++ b/ltt-sessiond/ltt-sessiond.h @@ -0,0 +1,83 @@ +/* Copyright (C) 2011 - David Goulet + * + * 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 index 000000000..947c750d4 --- /dev/null +++ b/lttng/Makefile.am @@ -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 index 000000000..188b13dd6 --- /dev/null +++ b/lttng/lttng.c @@ -0,0 +1,188 @@ +/* Copyright (c) 2011 David Goulet + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#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 index 000000000..587ff0e6d --- /dev/null +++ b/lttng/lttng.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2011 - David Goulet + * + * 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 index 000000000..3457f0bc2 --- /dev/null +++ b/lttng/options.c @@ -0,0 +1,104 @@ +/* Copyright (C) 2011 - David Goulet + * + * 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 +#include + +#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 index 000000000..4824e2215 --- /dev/null +++ b/tests/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = . + +dist_noinst_SCRIPTS = runall diff --git a/tests/runall b/tests/runall new file mode 100755 index 000000000..e69de29bb -- 2.34.1