From: David Goulet Date: Wed, 13 Apr 2011 20:15:24 +0000 (-0400) Subject: Initial import X-Git-Tag: v2.0-pre1~194 X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=commitdiff_plain;h=fac6795d6e2c60e79bdc7dab42da94d2025a57d3;ds=sidebyside Initial import This is the first import of the lttng-tools tree. Signed-off-by: David Goulet --- fac6795d6e2c60e79bdc7dab42da94d2025a57d3 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