From f3ed775ef4842019b396f06095b053c3a70bc3c8 Mon Sep 17 00:00:00 2001 From: David Goulet Date: Wed, 15 Jun 2011 17:29:58 -0400 Subject: [PATCH] Major changes ltt-sessiond ------------- Change command type to add the LTTNG_ prefix. Only kernel command at this point working with the new kernel tracer lttng 2.0. Adds support for the default channel. Kernel tracer session, metadata and streams opening are now handled by the session daemon by removing the public commands for those options. This means that the public API of lttng-tools DO NOT permit to control these three actions anymore. Adds ulimit setting for open files (65535) for sessiond running as UID=0. lttng.h ------------- As mention before, create_session, create_stream and open_metadata is removed from the public API. UUIDs are not exposed anymore by the API. Everything is done with the session name. New lttng event structure added in order to support kernel tracepoints, kprobes and function tracer. New lttng channel structure to create a kernel channel. Add the lttng channel attribute structure also where to put the channel attributes. libkernelctl ------------- Adds flush buffer function and wait quiescent for kernel tracer. Uses the new enable/disable kernel ioctl that replaces create event. lttng ------------- *MAJOR*: This is the inital import of the git-alike UI. Some features are still not implemented but all the basics and more are there. This commit introduce a new feature where the session name is kept in the current directory where the create command was executed (or specified by the user with --path). A .lttng directory is created and a config file that contains, for now, the session name. So, in order to apply command on a session, you either specify it on the command line or go in the directory where your .lttng dir reside. A lot of code was changed/added/removed from all over the lttng-tools tree to fit this big change. Consider this commit to be an almost complete rewrite of the original git command line UI and a big part of the public API. Signed-off-by: David Goulet --- doc/dev/lttng-cli.txt | 2 + include/lttng-kernel.h | 22 +- include/lttng-share.h | 16 + include/lttng/lttng.h | 116 +++- libkernelctl/kernel-ioctl.h | 49 +- libkernelctl/libkernelctl.c | 27 +- libkernelctl/libkernelctl.h | 10 +- liblttngctl/liblttngctl.c | 185 +++-- liblttsessiondcomm/liblttsessiondcomm.c | 3 +- liblttsessiondcomm/liblttsessiondcomm.h | 70 +- ltt-sessiond/kernel-ctl.c | 113 +++- ltt-sessiond/kernel-ctl.h | 11 +- ltt-sessiond/main.c | 632 ++++++++++------- ltt-sessiond/session.c | 57 +- ltt-sessiond/session.h | 5 +- ltt-sessiond/trace.c | 69 +- ltt-sessiond/trace.h | 20 +- ltt-sessiond/ust-ctl.c | 4 +- ltt-sessiond/ust-ctl.h | 2 +- lttng/Makefile.am | 7 +- lttng/cmd.h | 48 ++ lttng/commands/add_channel.c | 217 ++++++ lttng/commands/create.c | 163 +++++ lttng/commands/destroy.c | 137 ++++ lttng/commands/enable_events.c | 240 +++++++ lttng/commands/list.c | 284 ++++++++ lttng/commands/start.c | 125 ++++ lttng/commands/stop.c | 123 ++++ lttng/config.c | 301 +++++++++ lttng/lttng.c | 859 ++++++------------------ lttng/options.c | 202 ------ lttng/options.h | 52 -- lttng/utils.c | 103 +++ lttng/utils.h | 26 + 34 files changed, 2831 insertions(+), 1469 deletions(-) create mode 100644 lttng/cmd.h create mode 100644 lttng/commands/add_channel.c create mode 100644 lttng/commands/create.c create mode 100644 lttng/commands/destroy.c create mode 100644 lttng/commands/enable_events.c create mode 100644 lttng/commands/list.c create mode 100644 lttng/commands/start.c create mode 100644 lttng/commands/stop.c create mode 100644 lttng/config.c delete mode 100644 lttng/options.c delete mode 100644 lttng/options.h create mode 100644 lttng/utils.c create mode 100644 lttng/utils.h diff --git a/doc/dev/lttng-cli.txt b/doc/dev/lttng-cli.txt index 154d0a327..3f3fa4a4f 100644 --- a/doc/dev/lttng-cli.txt +++ b/doc/dev/lttng-cli.txt @@ -94,3 +94,5 @@ lttng disable-event name --userspace [--channel name] [--all/--pid n/cmd_name] lttng add-context name --kernel [--event name] [--channel name] --type context_type [context options] lttng add-context name --userspace [--event name] [--channel name] [--all/--pid n/cmd_name] --type context_type [context options] + +lttng consume [PATH] --continue --snapshot --stop diff --git a/include/lttng-kernel.h b/include/lttng-kernel.h index 1ce9fc5e4..6fa4e3925 100644 --- a/include/lttng-kernel.h +++ b/include/lttng-kernel.h @@ -28,27 +28,16 @@ enum lttng_kernel_instrumentation { LTTNG_KERNEL_TRACEPOINTS, LTTNG_KERNEL_KPROBES, - LTTNG_KERNEL_FUNCTION_TRACER, + LTTNG_KERNEL_FUNCTION, }; /* * LTTng DebugFS ABI structures. + * + * This is the kernel ABI copied from lttng-modules tree. */ -struct lttng_kernel_channel { - int overwrite; /* 1: overwrite, 0: discard */ - uint64_t subbuf_size; /* in bytes */ - uint64_t num_subbuf; - unsigned int switch_timer_interval; /* usecs */ - unsigned int read_timer_interval; /* usecs */ -}; - -struct lttng_kernel_tracepoint { -}; - -/* - * Either addr is used, or symbol_name and offset. - */ +/* Either addr is used or symbol_name and offset. */ struct lttng_kernel_kprobe { uint64_t addr; @@ -61,11 +50,10 @@ struct lttng_kernel_function_tracer { }; struct lttng_kernel_event { - char name[LTTNG_SYM_NAME_LEN]; /* event name */ + char name[LTTNG_SYM_NAME_LEN]; enum lttng_kernel_instrumentation instrumentation; /* Per instrumentation type configuration */ union { - struct lttng_kernel_tracepoint tracepoint; struct lttng_kernel_kprobe kprobe; struct lttng_kernel_function_tracer ftrace; } u; diff --git a/include/lttng-share.h b/include/lttng-share.h index 812a0f05c..d6bb0532a 100644 --- a/include/lttng-share.h +++ b/include/lttng-share.h @@ -29,4 +29,20 @@ typedef __s64 s64; #define LTTNG_RUNDIR "/var/run/lttng" +/* Default channel attributes */ +#define DEFAULT_CHANNEL_NAME "channel0" +#define DEFAULT_CHANNEL_OVERWRITE 0 +#define DEFAULT_CHANNEL_SUBBUF_SIZE 4096 /* bytes */ +#define DEFAULT_CHANNEL_SUBBUF_NUM 8 /* Must always be a power of 2 */ +#define DEFAULT_CHANNEL_SWITCH_TIMER 0 /* usec */ +#define DEFAULT_CHANNEL_READ_TIMER 200 /* usec */ + +/* + * lttng user-space instrumentation type + */ +enum lttng_ust_instrumentation { + LTTNG_UST_TRACEPOINT, + LTTNG_UST_MARKER, +}; + #endif /* _LTTNG_SHARE_H */ diff --git a/include/lttng/lttng.h b/include/lttng/lttng.h index d76340dc8..a8b7ac09a 100644 --- a/include/lttng/lttng.h +++ b/include/lttng/lttng.h @@ -23,8 +23,9 @@ #ifndef _LTTNG_H #define _LTTNG_H +#include +#include #include -#include /* Default unix group name for tracing. */ #define LTTNG_DEFAULT_TRACING_GROUP "tracing" @@ -33,68 +34,115 @@ #define LTTNG_SESSIOND_PATH_ENV "LTTNG_SESSIOND_PATH" /* - * Trace type for lttng_trace. + * Event symbol length. */ -enum lttng_trace_type { - KERNEL, - USERSPACE, +#define LTTNG_SYMBOL_NAME_LEN 128 + +enum lttng_event_type { + LTTNG_EVENT_TRACEPOINTS, + LTTNG_EVENT_KPROBES, + LTTNG_EVENT_FUNCTION, }; /* - * Basic trace information exposed. + * Either addr is used or symbol_name and offset. */ -struct lttng_trace { - char name[NAME_MAX]; - pid_t pid; /* Only useful for user-space trace */ - enum lttng_trace_type type; +struct lttng_event_kprobe_attr { + uint64_t addr; + + uint64_t offset; + char symbol_name[LTTNG_SYMBOL_NAME_LEN]; }; /* - * Basic session information exposed. + * Function tracer + */ +struct lttng_event_function_attr { + char symbol_name[LTTNG_SYMBOL_NAME_LEN]; +}; + +/* + * Generic lttng event + */ +struct lttng_event { + char name[LTTNG_SYMBOL_NAME_LEN]; + enum lttng_event_type type; + /* Per event type configuration */ + union { + struct lttng_event_kprobe_attr kprobe; + struct lttng_event_function_attr ftrace; + } attr; +}; + +/* Tracer channel attributes */ +struct lttng_channel_attr { + int overwrite; /* 1: overwrite, 0: discard */ + uint64_t subbuf_size; /* bytes */ + uint64_t num_subbuf; /* power of 2 */ + unsigned int switch_timer_interval; /* usec */ + unsigned int read_timer_interval; /* usec */ +}; + +/* + * Basic session information. */ struct lttng_session { char name[NAME_MAX]; - uuid_t uuid; + char path[PATH_MAX]; +}; + +/* Channel information structure */ +struct lttng_channel { + char name[NAME_MAX]; + struct lttng_channel_attr attr; }; /* * Session daemon control */ extern int lttng_connect_sessiond(void); -extern int lttng_create_session(char *name); -extern int lttng_destroy_session(uuid_t *uuid); + +extern int lttng_create_session(char *name, char *path); + +extern int lttng_destroy_session(char *name); + extern int lttng_disconnect_sessiond(void); + /* Return an allocated array of lttng_session */ extern int lttng_list_sessions(struct lttng_session **sessions); -/* Return an allocated array of lttng_traces */ -extern int lttng_list_traces(uuid_t *uuid, struct lttng_trace **traces); + extern int lttng_session_daemon_alive(void); + /* Set tracing group for the current execution */ extern int lttng_set_tracing_group(const char *name); -/* Set session uuid for the current execution */ -extern void lttng_set_current_session_uuid(uuid_t *uuid); + +extern void lttng_set_session_name(char *name); + extern const char *lttng_get_readable_code(int code); +extern int lttng_start_tracing(char *session_name); + +extern int lttng_stop_tracing(char *session_name); + +//extern int lttng_ust_list_traceable_apps(pid_t **pids); + /* - * User-space tracer control + * LTTng Kernel tracer control */ -extern int lttng_ust_create_trace(pid_t pid); -/* Return an allocated array of pids */ -extern int lttng_ust_list_apps(pid_t **pids); -extern int lttng_ust_start_trace(pid_t pid); -extern int lttng_ust_stop_trace(pid_t pid); +extern int lttng_kernel_create_channel(struct lttng_channel *chan); + +extern int lttng_kernel_enable_event(struct lttng_event *ev, char *channel_name); + +extern int lttng_kernel_enable_channel(char *name); + +extern int lttng_kernel_disable_event(char *name, char *channel_name); + +extern int lttng_kernel_disable_channel(char *name); + +extern int lttng_kernel_list_events(char **event_list); /* - * Kernel tracer control + * LTTng User-space tracer control */ -extern int lttng_kernel_create_channel(void); -extern int lttng_kernel_create_session(void); -extern int lttng_kernel_create_stream(void); -extern int lttng_kernel_disable_event(char *event_name); -extern int lttng_kernel_enable_event(char *event_name); -extern int lttng_kernel_list_events(char **event_list); -extern int lttng_kernel_open_metadata(void); -extern int lttng_kernel_start_tracing(void); -extern int lttng_kernel_stop_tracing(void); #endif /* _LTTNG_H */ diff --git a/libkernelctl/kernel-ioctl.h b/libkernelctl/kernel-ioctl.h index 0db8383b0..809ce0d32 100644 --- a/libkernelctl/kernel-ioctl.h +++ b/libkernelctl/kernel-ioctl.h @@ -21,47 +21,58 @@ #define _LTT_KERNEL_IOCTL_H /* Get a snapshot of the current ring buffer producer and consumer positions */ -#define RING_BUFFER_SNAPSHOT _IO(0xF6, 0x00) +#define RING_BUFFER_SNAPSHOT _IO(0xF6, 0x00) /* Get the consumer position (iteration start) */ #define RING_BUFFER_SNAPSHOT_GET_CONSUMED _IOR(0xF6, 0x01, unsigned long) /* Get the producer position (iteration end) */ #define RING_BUFFER_SNAPSHOT_GET_PRODUCED _IOR(0xF6, 0x02, unsigned long) /* Get exclusive read access to the specified sub-buffer position */ -#define RING_BUFFER_GET_SUBBUF _IOW(0xF6, 0x03, unsigned long) +#define RING_BUFFER_GET_SUBBUF _IOW(0xF6, 0x03, unsigned long) /* Release exclusive sub-buffer access */ -#define RING_BUFFER_PUT_SUBBUF _IO(0xF6, 0x04) +#define RING_BUFFER_PUT_SUBBUF _IO(0xF6, 0x04) /* Get exclusive read access to the next sub-buffer that can be read. */ -#define RING_BUFFER_GET_NEXT_SUBBUF _IO(0xF6, 0x05) +#define RING_BUFFER_GET_NEXT_SUBBUF _IO(0xF6, 0x05) /* Release exclusive sub-buffer access, move consumer forward. */ -#define RING_BUFFER_PUT_NEXT_SUBBUF _IO(0xF6, 0x06) +#define RING_BUFFER_PUT_NEXT_SUBBUF _IO(0xF6, 0x06) /* returns the size of the current sub-buffer, without padding (for mmap). */ -#define RING_BUFFER_GET_SUBBUF_SIZE _IOR(0xF6, 0x07, unsigned long) +#define RING_BUFFER_GET_SUBBUF_SIZE _IOR(0xF6, 0x07, unsigned long) /* returns the size of the current sub-buffer, with padding (for splice). */ #define RING_BUFFER_GET_PADDED_SUBBUF_SIZE _IOR(0xF6, 0x08, unsigned long) /* returns the maximum size for sub-buffers. */ #define RING_BUFFER_GET_MAX_SUBBUF_SIZE _IOR(0xF6, 0x09, unsigned long) /* returns the length to mmap. */ -#define RING_BUFFER_GET_MMAP_LEN _IOR(0xF6, 0x0A, unsigned long) +#define RING_BUFFER_GET_MMAP_LEN _IOR(0xF6, 0x0A, unsigned long) /* returns the offset of the subbuffer belonging to the mmap reader. */ #define RING_BUFFER_GET_MMAP_READ_OFFSET _IOR(0xF6, 0x0B, unsigned long) +/* flush the current sub-buffer */ +#define RING_BUFFER_FLUSH _IO(0xF6, 0x0C) + +#define LTTNG_KERNEL_SESSION _IO(0xF6, 0x40) +#define LTTNG_KERNEL_TRACER_VERSION \ + _IOR(0xF6, 0x41, struct lttng_kernel_tracer_version) -#define LTTNG_KERNEL_SESSION _IO(0xF6, 0x40) -#define LTTNG_KERNEL_TRACER_VERSION \ - _IOR(0xF6, 0x41, struct lttng_kernel_tracer_version) #define LTTNG_KERNEL_TRACEPOINT_LIST _IO(0xF6, 0x42) +#define LTTNG_KERNEL_WAIT_QUIESCENT _IO(0xF6, 0x43) /* Session FD ioctl */ -#define LTTNG_KERNEL_METADATA \ - _IOW(0xF6, 0x50, struct lttng_kernel_channel) -#define LTTNG_KERNEL_CHANNEL \ - _IOW(0xF6, 0x51, struct lttng_kernel_channel) -#define LTTNG_KERNEL_SESSION_START _IO(0xF6, 0x52) -#define LTTNG_KERNEL_SESSION_STOP _IO(0xF6, 0x53) +#define LTTNG_KERNEL_METADATA \ + _IOW(0xF6, 0x50, struct lttng_channel_attr) + +#define LTTNG_KERNEL_CHANNEL \ + _IOW(0xF6, 0x51, struct lttng_channel_attr) + +#define LTTNG_KERNEL_SESSION_START _IO(0xF6, 0x52) +#define LTTNG_KERNEL_SESSION_STOP _IO(0xF6, 0x53) /* Channel FD ioctl */ -#define LTTNG_KERNEL_STREAM _IO(0xF6, 0x60) -#define LTTNG_KERNEL_EVENT \ - _IOW(0xF6, 0x61, struct lttng_kernel_event) +#define LTTNG_KERNEL_STREAM _IO(0xF6, 0x60) + +#define LTTNG_KERNEL_EVENT \ + _IOW(0xF6, 0x61, struct lttng_kernel_event) + +/* Event, Channel and Session ioctl */ +#define LTTNG_KERNEL_ENABLE _IO(0xF6, 0x80) +#define LTTNG_KERNEL_DISABLE _IO(0xF6, 0x81) #endif /* _LTT_KERNEL_IOCTL_H */ diff --git a/libkernelctl/libkernelctl.c b/libkernelctl/libkernelctl.c index cfac1fa5c..f51618d1e 100644 --- a/libkernelctl/libkernelctl.c +++ b/libkernelctl/libkernelctl.c @@ -21,9 +21,13 @@ #include "kernel-ioctl.h" #include "libkernelctl.h" -#include "lttngerr.h" -int kernctl_create_channel(int fd, struct lttng_kernel_channel *chops) +int kernctl_buffer_flush(int fd) +{ + return ioctl(fd, RING_BUFFER_FLUSH); +} + +int kernctl_create_channel(int fd, struct lttng_channel_attr *chops) { return ioctl(fd, LTTNG_KERNEL_CHANNEL, chops); } @@ -43,6 +47,18 @@ int kernctl_create_stream(int fd) return ioctl(fd, LTTNG_KERNEL_STREAM); } +/* Enable event, channel and session ioctl */ +int kernctl_enable(int fd) +{ + return ioctl(fd, LTTNG_KERNEL_ENABLE); +} + +/* Disable event, channel and session ioctl */ +int kernctl_disable(int fd) +{ + return ioctl(fd, LTTNG_KERNEL_DISABLE); +} + /* returns the maximum size for sub-buffers. */ int kernctl_get_max_subbuf_size(int fd, unsigned long *len) { @@ -86,7 +102,7 @@ int kernctl_get_subbuf_size(int fd, unsigned long *len) } /* open the metadata global channel */ -int kernctl_open_metadata(int fd, struct lttng_kernel_channel *chops) +int kernctl_open_metadata(int fd, struct lttng_channel_attr *chops) { return ioctl(fd, LTTNG_KERNEL_METADATA, chops); } @@ -140,3 +156,8 @@ int kernctl_tracer_version(int fd, struct lttng_kernel_tracer_version *v) { return ioctl(fd, LTTNG_KERNEL_TRACER_VERSION, v); } + +int kernctl_wait_quiescent(int fd) +{ + return ioctl(fd, LTTNG_KERNEL_WAIT_QUIESCENT); +} diff --git a/libkernelctl/libkernelctl.h b/libkernelctl/libkernelctl.h index 938c079dc..930cb892e 100644 --- a/libkernelctl/libkernelctl.h +++ b/libkernelctl/libkernelctl.h @@ -20,10 +20,15 @@ #ifndef _LTT_LIBKERNELCTL_H #define _LTT_LIBKERNELCTL_H +#include + #include "lttng-kernel.h" -int kernctl_create_channel(int fd, struct lttng_kernel_channel *chops); +int kernctl_buffer_flush(int fd); +int kernctl_create_channel(int fd, struct lttng_channel_attr *chops); int kernctl_create_event(int fd, struct lttng_kernel_event *ev); +int kernctl_enable(int fd); +int kernctl_disable(int fd); int kernctl_create_session(int fd); int kernctl_create_stream(int fd); int kernctl_get_max_subbuf_size(int fd, unsigned long *len); @@ -33,7 +38,7 @@ int kernctl_get_next_subbuf(int fd); int kernctl_get_padded_subbuf_size(int fd, unsigned long *len); int kernctl_get_subbuf(int fd, unsigned long *len); int kernctl_get_subbuf_size(int fd, unsigned long *len); -int kernctl_open_metadata(int fd, struct lttng_kernel_channel *chops); +int kernctl_open_metadata(int fd, struct lttng_channel_attr *chops); int kernctl_put_next_subbuf(int fd); int kernctl_put_subbuf(int fd); int kernctl_snapshot(int fd); @@ -43,5 +48,6 @@ int kernctl_start_session(int fd); int kernctl_stop_session(int fd); int kernctl_tracepoint_list(int fd); int kernctl_tracer_version(int fd, struct lttng_kernel_tracer_version *v); +int kernctl_wait_quiescent(int fd); #endif /* _LTT_LIBKERNELCTL_H */ diff --git a/liblttngctl/liblttngctl.c b/liblttngctl/liblttngctl.c index eb606166c..7a480d2c7 100644 --- a/liblttngctl/liblttngctl.c +++ b/liblttngctl/liblttngctl.c @@ -28,6 +28,7 @@ #include "liblttsessiondcomm.h" #include "lttngerr.h" +#include "lttng-share.h" /* Socket to session daemon for communication */ static int sessiond_socket; @@ -125,7 +126,7 @@ static int ask_sessiond(enum lttcomm_sessiond_command lct, void **buf) goto end; } - size = llm.trace_name_offset + llm.data_size; + size = llm.data_size; if (size == 0) { goto end; } @@ -225,23 +226,49 @@ static int set_session_daemon_path(void) } /* - * BEGIN KERNEL CONTROL + * lttng_start_tracing + * + * Start tracing for all trace of the session. */ +int lttng_start_tracing(char *session_name) +{ + strncpy(lsm.session_name, session_name, NAME_MAX); + return ask_sessiond(LTTNG_START_TRACE, NULL); +} /* - * lttng_kernel_enable_event + * lttng_stop_tracing * - * Enable an event in the kernel tracer. + * Stop tracing for all trace of the session. + */ +int lttng_stop_tracing(char *session_name) +{ + strncpy(lsm.session_name, session_name, NAME_MAX); + return ask_sessiond(LTTNG_STOP_TRACE, NULL); +} + +/* + * BEGIN Kernel control API */ -int lttng_kernel_enable_event(char *event_name) + +/* + * lttng_kernel_enable_event + */ +int lttng_kernel_enable_event(struct lttng_event *ev, char *channel_name) { int ret; - if (event_name == NULL) { - ret = ask_sessiond(KERNEL_ENABLE_ALL_EVENT, NULL); + if (strlen(channel_name) == 0) { + strncpy(lsm.u.enable.channel_name, DEFAULT_CHANNEL_NAME, NAME_MAX); } else { - strncpy(lsm.u.event.event_name, event_name, NAME_MAX); - ret = ask_sessiond(KERNEL_ENABLE_EVENT, NULL); + strncpy(lsm.u.enable.channel_name, channel_name, NAME_MAX); + } + + if (ev == NULL) { + ret = ask_sessiond(LTTNG_KERNEL_ENABLE_ALL_EVENT, NULL); + } else { + memcpy(&lsm.u.enable.event, ev, sizeof(struct lttng_event)); + ret = ask_sessiond(LTTNG_KERNEL_ENABLE_EVENT, NULL); } return ret; @@ -252,54 +279,59 @@ int lttng_kernel_enable_event(char *event_name) * * Disable an event in the kernel tracer. */ -int lttng_kernel_disable_event(char *event_name) +int lttng_kernel_disable_event(char *name, char *channel_name) { - strncpy(lsm.u.event.event_name, event_name, NAME_MAX); - return ask_sessiond(KERNEL_DISABLE_EVENT, NULL); -} + int ret; -/* - * lttng_kernel_create_session - * - * Create a session in the kernel tracer. - */ -int lttng_kernel_create_session(void) -{ - return ask_sessiond(KERNEL_CREATE_SESSION, NULL); + if (strlen(channel_name) == 0) { + strncpy(lsm.u.disable.channel_name, DEFAULT_CHANNEL_NAME, NAME_MAX); + } else { + strncpy(lsm.u.disable.channel_name, channel_name, NAME_MAX); + } + + if (name == NULL) { + ret = ask_sessiond(LTTNG_KERNEL_DISABLE_ALL_EVENT, NULL); + } else { + strncpy(lsm.u.disable.name, name, NAME_MAX); + ret = ask_sessiond(LTTNG_KERNEL_DISABLE_EVENT, NULL); + } + + return ret; } /* - * lttng_kernel_create_channel + * lttng_kernel_enable_channel * - * Create a channel in the kernel tracer. + * Enable recording for a channel for the kernel tracer. */ -int lttng_kernel_create_channel(void) +int lttng_kernel_enable_channel(char *name) { - return ask_sessiond(KERNEL_CREATE_CHANNEL, NULL); + return ask_sessiond(LTTNG_KERNEL_ENABLE_CHANNEL, NULL); } /* - * lttng_kernel_open_metadata + * lttng_kernel_disable_channel * - * Open metadata in the kernel tracer. + * Disable recording for the channel for the kernel tracer. */ -int lttng_kernel_open_metadata(void) +int lttng_kernel_disable_channel(char *name) { - return ask_sessiond(KERNEL_OPEN_METADATA, NULL); + return ask_sessiond(LTTNG_KERNEL_DISABLE_CHANNEL, NULL); } /* - * lttng_kernel_create_stream + * lttng_kernel_create_channel * - * Create stream in the kernel tracer. + * Create a channel in the kernel tracer. */ -int lttng_kernel_create_stream(void) +int lttng_kernel_create_channel(struct lttng_channel *chan) { - return ask_sessiond(KERNEL_CREATE_STREAM, NULL); + memcpy(&lsm.u.channel.chan, chan, sizeof(struct lttng_channel)); + return ask_sessiond(LTTNG_KERNEL_CREATE_CHANNEL, NULL); } /* - * lttng_kernel_list_events + * lttng_list_events * * List all available events in the kernel. * @@ -308,31 +340,11 @@ int lttng_kernel_create_stream(void) */ int lttng_kernel_list_events(char **event_list) { - return ask_sessiond(KERNEL_LIST_EVENTS, (void **) event_list); + return ask_sessiond(LTTNG_KERNEL_LIST_EVENTS, (void **) event_list); } /* - * lttng_kernel_start_tracing - * - * Start kernel tracing. - */ -int lttng_kernel_start_tracing(void) -{ - return ask_sessiond(KERNEL_START_TRACE, NULL); -} - -/* - * lttng_kernel_stop_tracing - * - * Stop kernel tracing. - */ -int lttng_kernel_stop_tracing(void) -{ - return ask_sessiond(KERNEL_STOP_TRACE, NULL); -} - -/* - * END KERNEL CONTROL + * END Kernel control API */ /* @@ -349,39 +361,6 @@ const char *lttng_get_readable_code(int code) return lttcomm_get_readable_code(code); } -/* - * lttng_ust_start_trace - * - * Request a trace start for pid. - */ -int lttng_ust_start_trace(pid_t pid) -{ - lsm.pid = pid; - return ask_sessiond(UST_START_TRACE, NULL); -} - -/* - * lttng_ust_stop_trace - * - * Request a trace stop for pid. - */ -int lttng_ust_stop_trace(pid_t pid) -{ - lsm.pid = pid; - return ask_sessiond(UST_STOP_TRACE, NULL); -} - -/* - * lttng_ust_create_trace - * - * Request a trace creation for pid. - */ -int lttng_ust_create_trace(pid_t pid) -{ - lsm.pid = pid; - return ask_sessiond(UST_CREATE_TRACE, NULL); -} - /* * lttng_ust_list_apps * @@ -390,11 +369,11 @@ int lttng_ust_create_trace(pid_t pid) * Return the number of pids. * On error, return negative value. */ -int lttng_ust_list_apps(pid_t **pids) +int lttng_ust_list_traceable_apps(pid_t **pids) { int ret; - ret = ask_sessiond(UST_LIST_APPS, (void**) pids); + ret = ask_sessiond(LTTNG_LIST_TRACEABLE_APPS, (void**) pids); if (ret < 0) { return ret; } @@ -406,16 +385,17 @@ int lttng_ust_list_apps(pid_t **pids) * lttng_list_traces * * Ask the session daemon for all traces (kernel and ust) for the session - * identified by uuid. + * identified by name. * * Return the number of traces. * On error, return negative value. */ -int lttng_list_traces(uuid_t *uuid, struct lttng_trace **traces) +/* +int lttng_list_traces(char *session_name, struct lttng_trace **traces) { int ret; - uuid_copy(lsm.session_uuid, *uuid); + strncpy(lsm.session_name, session_name, NAME_MAX); ret = ask_sessiond(LTTNG_LIST_TRACES, (void **) traces); if (ret < 0) { @@ -424,15 +404,17 @@ int lttng_list_traces(uuid_t *uuid, struct lttng_trace **traces) return ret / sizeof(struct lttng_trace); } +*/ /* * lttng_create_session * * Create a brand new session using name. */ -int lttng_create_session(char *name) +int lttng_create_session(char *name, char *path) { strncpy(lsm.session_name, name, NAME_MAX); + strncpy(lsm.path, path, PATH_MAX); return ask_sessiond(LTTNG_CREATE_SESSION, NULL); } @@ -441,9 +423,9 @@ int lttng_create_session(char *name) * * Destroy session using name. */ -int lttng_destroy_session(uuid_t *uuid) +int lttng_destroy_session(char *name) { - uuid_copy(lsm.session_uuid, *uuid); + strncpy(lsm.session_name, name, NAME_MAX); return ask_sessiond(LTTNG_DESTROY_SESSION, NULL); } @@ -513,14 +495,9 @@ int lttng_disconnect_sessiond(void) return ret; } -/* - * lttng_set_current_session_uuid - * - * Set the session uuid for current lsm. - */ -void lttng_set_current_session_uuid(uuid_t *uuid) +void lttng_set_session_name(char *name) { - uuid_copy(lsm.session_uuid, *uuid); + strncpy(lsm.session_name, name, NAME_MAX); } /* diff --git a/liblttsessiondcomm/liblttsessiondcomm.c b/liblttsessiondcomm/liblttsessiondcomm.c index ce7bd9145..7dfdbb438 100644 --- a/liblttsessiondcomm/liblttsessiondcomm.c +++ b/liblttsessiondcomm/liblttsessiondcomm.c @@ -39,7 +39,7 @@ static const char *lttcomm_readable_code[] = { [ LTTCOMM_ERR_INDEX(LTTCOMM_NO_SESSION) ] = "No session found", [ LTTCOMM_ERR_INDEX(LTTCOMM_LIST_FAIL) ] = "Unable to list traceable apps", [ LTTCOMM_ERR_INDEX(LTTCOMM_NO_APPS) ] = "No traceable apps found", - [ LTTCOMM_ERR_INDEX(LTTCOMM_NO_SESS) ] = "No session found", + [ LTTCOMM_ERR_INDEX(LTTCOMM_SESS_NOT_FOUND) ] = "Session name not found", [ LTTCOMM_ERR_INDEX(LTTCOMM_NO_TRACE) ] = "No trace found", [ LTTCOMM_ERR_INDEX(LTTCOMM_FATAL) ] = "Fatal error of the session daemon", [ LTTCOMM_ERR_INDEX(LTTCOMM_CREATE_FAIL) ] = "Create trace failed", @@ -51,6 +51,7 @@ static const char *lttcomm_readable_code[] = { [ LTTCOMM_ERR_INDEX(LTTCOMM_KERN_NA) ] = "Kernel tracer not available", [ LTTCOMM_ERR_INDEX(LTTCOMM_KERN_SESS_FAIL) ] = "Kernel create session failed", [ LTTCOMM_ERR_INDEX(LTTCOMM_KERN_CHAN_FAIL) ] = "Kernel create channel failed", + [ LTTCOMM_ERR_INDEX(LTTCOMM_KERN_CHAN_NOT_FOUND) ] = "Kernel channel not found", [ LTTCOMM_ERR_INDEX(LTTCOMM_KERN_ENABLE_FAIL) ] = "Enable kernel event failed", [ LTTCOMM_ERR_INDEX(LTTCOMM_KERN_DISABLE_FAIL) ] = "Disable kernel event failed", [ LTTCOMM_ERR_INDEX(LTTCOMM_KERN_META_FAIL) ] = "Opening metadata failed", diff --git a/liblttsessiondcomm/liblttsessiondcomm.h b/liblttsessiondcomm/liblttsessiondcomm.h index 195040822..8f7ce0317 100644 --- a/liblttsessiondcomm/liblttsessiondcomm.h +++ b/liblttsessiondcomm/liblttsessiondcomm.h @@ -22,8 +22,8 @@ #define _LIBLTTSESSIONDCOMM_H #include -#include +#include #include "lttng-share.h" /* Default unix socket path */ @@ -41,38 +41,24 @@ #define LTTCOMM_ERR_INDEX(code) (code - LTTCOMM_OK) enum lttcomm_sessiond_command { - KERNEL_CREATE_CHANNEL, - KERNEL_CREATE_SESSION, - KERNEL_CREATE_STREAM, - KERNEL_DISABLE_EVENT, - KERNEL_ENABLE_EVENT, - KERNEL_ENABLE_ALL_EVENT, - KERNEL_LIST_EVENTS, - KERNEL_OPEN_METADATA, - KERNEL_START_TRACE, - KERNEL_STOP_TRACE, + /* Tracer context command */ + LTTNG_KERNEL_CREATE_CHANNEL, + LTTNG_KERNEL_DISABLE_CHANNEL, + LTTNG_KERNEL_DISABLE_EVENT, + LTTNG_KERNEL_DISABLE_ALL_EVENT, + LTTNG_KERNEL_ENABLE_CHANNEL, + LTTNG_KERNEL_ENABLE_EVENT, + LTTNG_KERNEL_ENABLE_ALL_EVENT, + LTTNG_KERNEL_LIST_EVENTS, + /* Session daemon context command */ 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_TRACES, - 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, + LTTNG_LIST_EVENTS, + LTTNG_LIST_TRACEABLE_APPS, + LTTNG_START_TRACE, + LTTNG_STOP_TRACE, }; /* @@ -90,7 +76,7 @@ enum lttcomm_return_code { LTTCOMM_STOP_FAIL, /* Stop tracing fail */ LTTCOMM_LIST_FAIL, /* Listing apps fail */ LTTCOMM_NO_APPS, /* No traceable application */ - LTTCOMM_NO_SESS, /* No sessions available */ + LTTCOMM_SESS_NOT_FOUND, /* Session name not found */ LTTCOMM_NO_TRACE, /* No trace exist */ LTTCOMM_FATAL, /* Session daemon had a fatal error */ LTTCOMM_NO_TRACEABLE, /* Error for non traceable app */ @@ -100,6 +86,7 @@ enum lttcomm_return_code { LTTCOMM_KERN_NA, /* Kernel tracer unavalable */ LTTCOMM_KERN_SESS_FAIL, /* Kernel create session failed */ LTTCOMM_KERN_CHAN_FAIL, /* Kernel create channel failed */ + LTTCOMM_KERN_CHAN_NOT_FOUND, /* Kernel channel not found */ LTTCOMM_KERN_ENABLE_FAIL, /* Kernel enable event failed */ LTTCOMM_KERN_DISABLE_FAIL, /* Kernel disable event failed */ LTTCOMM_KERN_META_FAIL, /* Kernel open metadata failed */ @@ -133,18 +120,23 @@ enum lttcomm_return_code { */ struct lttcomm_session_msg { u32 cmd_type; /* enum lttcomm_sessiond_command */ - uuid_t session_uuid; - char trace_name[NAME_MAX]; char session_name[NAME_MAX]; - u32 pid; /* pid_t */ + char path[PATH_MAX]; + pid_t pid; union { struct { - int auto_session; - } create_session; - /* Marker data */ + char channel_name[NAME_MAX]; + char name[NAME_MAX]; + } disable; + /* Event data */ struct { - char event_name[NAME_MAX]; - } event; + char channel_name[NAME_MAX]; + struct lttng_event event; + } enable; + /* Create channel */ + struct { + struct lttng_channel chan; + } channel; } u; }; @@ -155,9 +147,7 @@ struct lttcomm_lttng_msg { u32 cmd_type; /* enum lttcomm_sessiond_command */ u32 ret_code; /* enum lttcomm_return_code */ u32 pid; /* pid_t */ - u32 trace_name_offset; u32 data_size; - uuid_t session_uuid; /* Contains: trace_name + data */ char payload[]; }; diff --git a/ltt-sessiond/kernel-ctl.c b/ltt-sessiond/kernel-ctl.c index 1abd4cef1..db97dee20 100644 --- a/ltt-sessiond/kernel-ctl.c +++ b/ltt-sessiond/kernel-ctl.c @@ -54,6 +54,7 @@ int kernel_create_session(struct ltt_session *session, int tracer_fd) } lks->fd = ret; + lks->kconsumer_fds_sent = 0; session->kernel_session = lks; session->kern_session_count++; @@ -71,19 +72,19 @@ error: * Create a kernel channel, register it to the kernel tracer and add it to the * kernel session. */ -int kernel_create_channel(struct ltt_kernel_session *session) +int kernel_create_channel(struct ltt_kernel_session *session, struct lttng_channel *chan) { int ret; struct ltt_kernel_channel *lkc; /* Allocate kernel channel */ - lkc = trace_create_kernel_channel(); + lkc = trace_create_kernel_channel(chan); if (lkc == NULL) { goto error; } /* Kernel tracer channel creation */ - ret = kernctl_create_channel(session->fd, lkc->channel); + ret = kernctl_create_channel(session->fd, &lkc->channel->attr); if (ret < 0) { perror("ioctl kernel create channel"); goto error; @@ -95,7 +96,8 @@ int kernel_create_channel(struct ltt_kernel_session *session) cds_list_add(&lkc->list, &session->channel_list.head); session->channel_count++; - DBG("Kernel channel created (fd: %d and path: %s)", lkc->fd, lkc->pathname); + DBG("Kernel channel %s created (fd: %d and path: %s)", + lkc->channel->name, lkc->fd, lkc->pathname); return 0; @@ -104,35 +106,32 @@ error: } /* - * kernel_enable_event + * kernel_create_event * * Create a kernel event, enable it to the kernel tracer and add it to the * channel event list of the kernel session. */ -int kernel_enable_event(struct ltt_kernel_session *session, char *name) +int kernel_create_event(struct ltt_kernel_channel *channel, struct lttng_event *ev) { int ret; - struct ltt_kernel_channel *chan; struct ltt_kernel_event *event; - event = trace_create_kernel_event(name, LTTNG_KERNEL_TRACEPOINTS); + event = trace_create_kernel_event(ev); if (event == NULL) { goto error; } - cds_list_for_each_entry(chan, &session->channel_list.head, list) { - ret = kernctl_create_event(chan->fd, event->event); - if (ret < 0) { - ERR("Unable to enable event %s", name); - goto error; - } - - event->fd = ret; - /* Add event to event list */ - cds_list_add(&event->list, &chan->events_list.head); - DBG("Event %s enabled (fd: %d)", name, event->fd); + ret = kernctl_create_event(channel->fd, event->event); + if (ret < 0) { + ERR("Unable to enable event %s for channel %s", ev->name, channel->channel->name); + goto error; } + event->fd = ret; + /* Add event to event list */ + cds_list_add(&event->list, &channel->events_list.head); + DBG("Event %s enabled (fd: %d)", ev->name, event->fd); + return 0; error: @@ -157,7 +156,7 @@ int kernel_open_metadata(struct ltt_kernel_session *session) } /* Kernel tracer metadata creation */ - ret = kernctl_open_metadata(session->fd, lkm->conf); + ret = kernctl_open_metadata(session->fd, &lkm->conf->attr); if (ret < 0) { goto error; } @@ -184,6 +183,7 @@ int kernel_start_session(struct ltt_kernel_session *session) ret = kernctl_start_session(session->fd); if (ret < 0) { + perror("ioctl start session"); goto error; } @@ -195,6 +195,66 @@ error: return ret; } +/* + * kernel_wait_quiescent + * + * Make a kernel wait to make sure in-flight probe have completed. + */ +void kernel_wait_quiescent(int fd) +{ + int ret; + + DBG("Kernel quiescent wait on %d", fd); + + ret = kernctl_wait_quiescent(fd); + if (ret < 0) { + perror("wait quiescent ioctl"); + ERR("Kernel quiescent wait failed"); + } +} + +/* + * kernel_metadata_flush_buffer + * + * Force flush buffer of metadata. + */ +int kernel_metadata_flush_buffer(int fd) +{ + int ret; + + ret = kernctl_buffer_flush(fd); + if (ret < 0) { + ERR("Fail to flush metadata buffers %d (ret: %d", fd, ret); + } + + return 0; +} + +/* + * kernel_flush_buffer + * + * Force flush buffer for channel. + */ +int kernel_flush_buffer(struct ltt_kernel_channel *channel) +{ + int ret; + struct ltt_kernel_stream *stream; + + DBG("Flush buffer for channel %s", channel->channel->name); + + cds_list_for_each_entry(stream, &channel->stream_list.head, list) { + DBG("Flushing channel stream %d", stream->fd); + ret = kernctl_buffer_flush(stream->fd); + if (ret < 0) { + perror("ioctl"); + ERR("Fail to flush buffer for stream %d (ret: %d)", + stream->fd, ret); + } + } + + return 0; +} + /* * kernel_stop_session * @@ -218,14 +278,14 @@ error: } /* - * kernel_create_channel_stream + * kernel_open_channel_stream * - * Create a stream for a channel, register it to the kernel tracer and add it + * Open stream of channel, register it to the kernel tracer and add it * to the stream list of the channel. * * Return the number of created stream. Else, a negative value. */ -int kernel_create_channel_stream(struct ltt_kernel_channel *channel) +int kernel_open_channel_stream(struct ltt_kernel_channel *channel) { int ret; struct ltt_kernel_stream *lks; @@ -260,11 +320,11 @@ error: } /* - * kernel_create_metadata_stream + * kernel_open_metadata_stream * - * Create the metadata stream and set it to the kernel session. + * Open the metadata stream and set it to the kernel session. */ -int kernel_create_metadata_stream(struct ltt_kernel_session *session) +int kernel_open_metadata_stream(struct ltt_kernel_session *session) { int ret; @@ -341,4 +401,3 @@ ssize_t kernel_list_events(int tracer_fd, char **list) error: return -1; } - diff --git a/ltt-sessiond/kernel-ctl.h b/ltt-sessiond/kernel-ctl.h index 3b18fe8e0..e100c1b08 100644 --- a/ltt-sessiond/kernel-ctl.h +++ b/ltt-sessiond/kernel-ctl.h @@ -31,13 +31,16 @@ #define KERNEL_EVENT_LIST_SIZE 2000 int kernel_create_session(struct ltt_session *session, int tracer_fd); -int kernel_create_channel(struct ltt_kernel_session *session); -int kernel_enable_event(struct ltt_kernel_session *session, char *name); +int kernel_create_channel(struct ltt_kernel_session *session, struct lttng_channel *chan); +int kernel_create_event(struct ltt_kernel_channel *channel, struct lttng_event *ev); int kernel_open_metadata(struct ltt_kernel_session *session); -int kernel_create_metadata_stream(struct ltt_kernel_session *session); -int kernel_create_channel_stream(struct ltt_kernel_channel *channel); +int kernel_open_metadata_stream(struct ltt_kernel_session *session); +int kernel_open_channel_stream(struct ltt_kernel_channel *channel); +int kernel_flush_buffer(struct ltt_kernel_channel *channel); +int kernel_metadata_flush_buffer(int fd); int kernel_start_session(struct ltt_kernel_session *session); int kernel_stop_session(struct ltt_kernel_session *session); ssize_t kernel_list_events(int tracer_fd, char **event_list); +void kernel_wait_quiescent(int fd); #endif /* _LTT_KERNEL_CTL_H */ diff --git a/ltt-sessiond/main.c b/ltt-sessiond/main.c index 987389284..46e6fff45 100644 --- a/ltt-sessiond/main.c +++ b/ltt-sessiond/main.c @@ -1,4 +1,7 @@ /* + DBG("Creating kernel event %s for channel %s.", + cmd_ctx->lsm->u.enable.event.name, cmd_ctx->lsm->u.enable.channel_name); + * Copyright (C) 2011 - David Goulet * * This program is free software; you can redistribute it and/or @@ -32,6 +35,8 @@ #include #include #include +#include +#include #include #include /* URCU list library (-lurcu) */ @@ -159,6 +164,7 @@ static void cleanup() // TODO complete session cleanup (including UST) } + DBG("Closing kernel fd"); close(kernel_tracer_fd); } @@ -199,6 +205,103 @@ static void clean_command_ctx(struct command_ctx *cmd_ctx) } } +/* + * send_kconsumerd_fds + * + * Send all stream fds of the kernel session to the consumer. + */ +static int send_kconsumerd_fds(int sock, struct ltt_kernel_session *session) +{ + int ret; + size_t nb_fd; + struct ltt_kernel_stream *stream; + struct ltt_kernel_channel *chan; + struct lttcomm_kconsumerd_header lkh; + struct lttcomm_kconsumerd_msg lkm; + + nb_fd = session->stream_count_global; + + /* Setup header */ + lkh.payload_size = (nb_fd + 1) * sizeof(struct lttcomm_kconsumerd_msg); + lkh.cmd_type = ADD_STREAM; + + DBG("Sending kconsumerd header"); + + ret = lttcomm_send_unix_sock(sock, &lkh, sizeof(struct lttcomm_kconsumerd_header)); + if (ret < 0) { + perror("send kconsumerd header"); + goto error; + } + + DBG("Sending metadata stream fd"); + + /* Send metadata stream fd first */ + lkm.fd = session->metadata_stream_fd; + lkm.state = ACTIVE_FD; + lkm.max_sb_size = session->metadata->conf->attr.subbuf_size; + strncpy(lkm.path_name, session->metadata->pathname, PATH_MAX); + + ret = lttcomm_send_fds_unix_sock(sock, &lkm, &lkm.fd, 1, sizeof(lkm)); + if (ret < 0) { + perror("send kconsumerd fd"); + goto error; + } + + cds_list_for_each_entry(chan, &session->channel_list.head, list) { + cds_list_for_each_entry(stream, &chan->stream_list.head, list) { + lkm.fd = stream->fd; + lkm.state = stream->state; + lkm.max_sb_size = chan->channel->attr.subbuf_size; + strncpy(lkm.path_name, stream->pathname, PATH_MAX); + + DBG("Sending fd %d to kconsumerd", lkm.fd); + + ret = lttcomm_send_fds_unix_sock(sock, &lkm, &lkm.fd, 1, sizeof(lkm)); + if (ret < 0) { + perror("send kconsumerd fd"); + goto error; + } + } + } + + DBG("Kconsumerd fds sent"); + + return 0; + +error: + return ret; +} + +/* + * create_trace_dir + * + * Create the trace output directory. + */ +static int create_trace_dir(struct ltt_kernel_session *session) +{ + int ret; + struct ltt_kernel_channel *chan; + + /* Create all channel directories */ + cds_list_for_each_entry(chan, &session->channel_list.head, list) { + DBG("Creating trace directory at %s", chan->pathname); + // TODO: recursive create dir + ret = mkdir(chan->pathname, S_IRWXU | S_IRWXG ); + if (ret < 0) { + if (ret != EEXIST) { + perror("mkdir trace path"); + ret = -errno; + goto error; + } + } + } + + return 0; + +error: + return ret; +} + /* * ust_connect_app * @@ -273,14 +376,9 @@ error: */ static int setup_lttng_msg(struct command_ctx *cmd_ctx, size_t size) { - int ret, buf_size, trace_name_size; + int ret, buf_size; - /* - * Check for the trace_name. If defined, it's part of the payload data of - * the llm structure. - */ - trace_name_size = strlen(cmd_ctx->lsm->trace_name); - buf_size = trace_name_size + size; + buf_size = size; cmd_ctx->llm = malloc(sizeof(struct lttcomm_lttng_msg) + buf_size); if (cmd_ctx->llm == NULL) { @@ -292,17 +390,10 @@ static int setup_lttng_msg(struct command_ctx *cmd_ctx, size_t size) /* Copy common data */ cmd_ctx->llm->cmd_type = cmd_ctx->lsm->cmd_type; cmd_ctx->llm->pid = cmd_ctx->lsm->pid; - if (!uuid_is_null(cmd_ctx->lsm->session_uuid)) { - uuid_copy(cmd_ctx->llm->session_uuid, cmd_ctx->lsm->session_uuid); - } - cmd_ctx->llm->trace_name_offset = trace_name_size; cmd_ctx->llm->data_size = size; cmd_ctx->lttng_msg_size = sizeof(struct lttcomm_lttng_msg) + buf_size; - /* Copy trace name to the llm structure. Begining of the payload. */ - memcpy(cmd_ctx->llm->payload, cmd_ctx->lsm->trace_name, trace_name_size); - return buf_size; error: @@ -555,117 +646,122 @@ error: } /* - * send_kconsumerd_fds + * init_kernel_tracer * - * Send all stream fds of the kernel session to the consumer. + * Setup necessary data for kernel tracer action. */ -static int send_kconsumerd_fds(int sock, struct ltt_kernel_session *session) +static void init_kernel_tracer(void) { - int ret; - size_t nb_fd; - struct ltt_kernel_stream *stream; - struct ltt_kernel_channel *chan; - struct lttcomm_kconsumerd_header lkh; - struct lttcomm_kconsumerd_msg lkm; - - nb_fd = session->stream_count_global; - - /* Setup header */ - lkh.payload_size = (nb_fd + 1) * sizeof(struct lttcomm_kconsumerd_msg); - lkh.cmd_type = ADD_STREAM; - - DBG("Sending kconsumerd header"); - - ret = lttcomm_send_unix_sock(sock, &lkh, sizeof(struct lttcomm_kconsumerd_header)); - if (ret < 0) { - perror("send kconsumerd header"); - goto error; + /* Set the global kernel tracer fd */ + kernel_tracer_fd = open(DEFAULT_KERNEL_TRACER_PATH, O_RDWR); + if (kernel_tracer_fd < 0) { + WARN("No kernel tracer available"); + kernel_tracer_fd = 0; } - DBG("Sending metadata stream fd"); + DBG("Kernel tracer fd %d", kernel_tracer_fd); +} - /* Send metadata stream fd first */ - lkm.fd = session->metadata_stream_fd; - lkm.state = ACTIVE_FD; - lkm.max_sb_size = session->metadata->conf->subbuf_size; - strncpy(lkm.path_name, session->metadata->pathname, PATH_MAX); +/* + * start_kernel_trace + * + * Start tracing by creating trace directory and sending FDs to the kernel + * consumer. + */ +static int start_kernel_trace(struct ltt_kernel_session *session) +{ + int ret; - ret = lttcomm_send_fds_unix_sock(sock, &lkm, &lkm.fd, 1, sizeof(lkm)); + /* Create trace directory */ + ret = create_trace_dir(session); if (ret < 0) { - perror("send kconsumerd fd"); - goto error; - } - - cds_list_for_each_entry(chan, &session->channel_list.head, list) { - cds_list_for_each_entry(stream, &chan->stream_list.head, list) { - lkm.fd = stream->fd; - lkm.state = stream->state; - lkm.max_sb_size = chan->channel->subbuf_size; - strncpy(lkm.path_name, stream->pathname, PATH_MAX); - - DBG("Sending fd %d to kconsumerd", lkm.fd); - - ret = lttcomm_send_fds_unix_sock(sock, &lkm, &lkm.fd, 1, sizeof(lkm)); - if (ret < 0) { - perror("send kconsumerd fd"); - goto error; - } + if (ret == -EEXIST) { + ret = LTTCOMM_KERN_DIR_EXIST; + } else { + ret = LTTCOMM_KERN_DIR_FAIL; + goto error; } } - DBG("Kconsumerd fds sent"); + if (session->kconsumer_fds_sent == 0) { + ret = send_kconsumerd_fds(kconsumerd_cmd_sock, session); + if (ret < 0) { + ERR("Send kconsumerd fds failed"); + ret = LTTCOMM_KERN_CONSUMER_FAIL; + goto error; + } - return 0; + session->kconsumer_fds_sent = 1; + } error: return ret; } /* - * create_trace_dir + * init_default_channel * - * Create the trace output directory. + * Allocate a channel structure and fill it. */ -static int create_trace_dir(struct ltt_kernel_session *session) +static struct lttng_channel *init_default_channel(void) { - int ret; - struct ltt_kernel_channel *chan; + struct lttng_channel *chan; - /* Create all channel directories */ - cds_list_for_each_entry(chan, &session->channel_list.head, list) { - DBG("Creating trace directory at %s", chan->pathname); - // TODO: recursive create dir - ret = mkdir(chan->pathname, S_IRWXU | S_IRWXG ); - if (ret < 0) { - if (ret != EEXIST) { - perror("mkdir trace path"); - ret = -errno; - goto error; - } - } + chan = malloc(sizeof(struct lttng_channel)); + if (chan == NULL) { + perror("init channel malloc"); + goto error; } - return 0; + if (snprintf(chan->name, NAME_MAX, DEFAULT_CHANNEL_NAME) < 0) { + perror("snprintf defautl channel name"); + return NULL; + } + + chan->attr.overwrite = DEFAULT_CHANNEL_OVERWRITE; + chan->attr.subbuf_size = DEFAULT_CHANNEL_SUBBUF_SIZE; + chan->attr.num_subbuf = DEFAULT_CHANNEL_SUBBUF_NUM; + chan->attr.switch_timer_interval = DEFAULT_CHANNEL_SWITCH_TIMER; + chan->attr.read_timer_interval = DEFAULT_CHANNEL_READ_TIMER; error: - return ret; + return chan; } /* - * init_kernel_tracer + * create_kernel_session * - * Setup necessary data for kernel tracer action. + * Create a kernel tracer session then create the default channel. */ -static void init_kernel_tracer(void) +static int create_kernel_session(struct ltt_session *session) { - /* Set the global kernel tracer fd */ - kernel_tracer_fd = open(DEFAULT_KERNEL_TRACER_PATH, O_RDWR); - if (kernel_tracer_fd < 0) { - WARN("No kernel tracer available"); - kernel_tracer_fd = 0; + int ret; + struct lttng_channel *chan; + + DBG("Creating kernel session"); + + ret = kernel_create_session(session, kernel_tracer_fd); + if (ret < 0) { + ret = LTTCOMM_KERN_SESS_FAIL; + goto error; } - DBG("Kernel tracer fd %d", kernel_tracer_fd); + chan = init_default_channel(); + if (chan == NULL) { + ret = LTTCOMM_FATAL; + goto error; + } + + DBG("Creating default kernel channel %s", DEFAULT_CHANNEL_NAME); + + ret = kernel_create_channel(session->kernel_session, chan); + if (ret < 0) { + ret = LTTCOMM_KERN_CHAN_FAIL; + goto error; + } + +error: + return ret; } /* @@ -683,33 +779,41 @@ static int process_client_msg(struct command_ctx *cmd_ctx) DBG("Processing client command %d", cmd_ctx->lsm->cmd_type); - /* Check command that needs a session */ + /* Listing commands don't need a session */ switch (cmd_ctx->lsm->cmd_type) { case LTTNG_CREATE_SESSION: case LTTNG_LIST_SESSIONS: - case KERNEL_LIST_EVENTS: - case UST_LIST_APPS: + case LTTNG_LIST_EVENTS: + case LTTNG_KERNEL_LIST_EVENTS: + case LTTNG_LIST_TRACEABLE_APPS: break; default: - cmd_ctx->session = find_session_by_uuid(cmd_ctx->lsm->session_uuid); + DBG("Getting session %s by name", cmd_ctx->lsm->session_name); + cmd_ctx->session = find_session_by_name(cmd_ctx->lsm->session_name); if (cmd_ctx->session == NULL) { - ret = LTTCOMM_SELECT_SESS; + /* If session name not found */ + if (cmd_ctx->lsm->session_name != NULL) { + ret = LTTCOMM_SESS_NOT_FOUND; + } else { /* If no session name specified */ + ret = LTTCOMM_SELECT_SESS; + } goto error; } break; } - /* Check command for kernel tracing */ + /* + * Check kernel command for kernel session. + */ switch (cmd_ctx->lsm->cmd_type) { - case KERNEL_CREATE_SESSION: - case KERNEL_CREATE_CHANNEL: - case KERNEL_CREATE_STREAM: - case KERNEL_DISABLE_EVENT: - case KERNEL_ENABLE_EVENT: - case KERNEL_LIST_EVENTS: - case KERNEL_OPEN_METADATA: - case KERNEL_START_TRACE: - case KERNEL_STOP_TRACE: + case LTTNG_KERNEL_CREATE_CHANNEL: + case LTTNG_KERNEL_DISABLE_ALL_EVENT: + case LTTNG_KERNEL_DISABLE_CHANNEL: + case LTTNG_KERNEL_DISABLE_EVENT: + case LTTNG_KERNEL_ENABLE_ALL_EVENT: + case LTTNG_KERNEL_ENABLE_CHANNEL: + case LTTNG_KERNEL_ENABLE_EVENT: + case LTTNG_KERNEL_LIST_EVENTS: /* Kernel tracer check */ if (kernel_tracer_fd == 0) { init_kernel_tracer(); @@ -718,7 +822,23 @@ static int process_client_msg(struct command_ctx *cmd_ctx) goto error; } } - break; + + /* Need a session for kernel command */ + if (cmd_ctx->lsm->cmd_type != LTTNG_KERNEL_LIST_EVENTS && + cmd_ctx->session->kernel_session == NULL) { + ret = create_kernel_session(cmd_ctx->session); + if (ret < 0) { + ret = LTTCOMM_KERN_SESS_FAIL; + goto error; + } + + if (kconsumerd_pid == 0) { + ret = start_kconsumerd(); + if (ret < 0) { + goto error; + } + } + } } /* Connect to ust apps if available pid */ @@ -733,40 +853,19 @@ static int process_client_msg(struct command_ctx *cmd_ctx) /* Process by command type */ switch (cmd_ctx->lsm->cmd_type) { - case KERNEL_CREATE_SESSION: - { - ret = setup_lttng_msg(cmd_ctx, 0); - if (ret < 0) { - goto setup_error; - } - - ret = start_kconsumerd(); - if (ret < 0) { - goto error; - } - - DBG("Creating kernel session"); - - ret = kernel_create_session(cmd_ctx->session, kernel_tracer_fd); - if (ret < 0) { - ret = LTTCOMM_KERN_SESS_FAIL; - goto error; - } - - ret = LTTCOMM_OK; - break; - } - case KERNEL_CREATE_CHANNEL: + case LTTNG_KERNEL_CREATE_CHANNEL: { + /* Setup lttng message with no payload */ ret = setup_lttng_msg(cmd_ctx, 0); if (ret < 0) { goto setup_error; } + /* Kernel tracer */ DBG("Creating kernel channel"); - ret = kernel_create_channel(cmd_ctx->session->kernel_session); - + ret = kernel_create_channel(cmd_ctx->session->kernel_session, + &cmd_ctx->lsm->u.channel.chan); if (ret < 0) { ret = LTTCOMM_KERN_CHAN_FAIL; goto error; @@ -775,29 +874,47 @@ static int process_client_msg(struct command_ctx *cmd_ctx) ret = LTTCOMM_OK; break; } - case KERNEL_ENABLE_EVENT: + case LTTNG_KERNEL_ENABLE_EVENT: { + int found = 0; + struct ltt_kernel_channel *chan; + /* Setup lttng message with no payload */ ret = setup_lttng_msg(cmd_ctx, 0); if (ret < 0) { goto setup_error; } - DBG("Enabling kernel event %s", cmd_ctx->lsm->u.event.event_name); - - ret = kernel_enable_event(cmd_ctx->session->kernel_session, cmd_ctx->lsm->u.event.event_name); - if (ret < 0) { - ret = LTTCOMM_KERN_ENABLE_FAIL; - goto error; + /* Get channel by name and create event for that channel */ + cds_list_for_each_entry(chan, &cmd_ctx->session->kernel_session->channel_list.head, list) { + if (strcmp(cmd_ctx->lsm->u.enable.channel_name, chan->channel->name) == 0) { + DBG("Creating kernel event %s for channel %s.", + cmd_ctx->lsm->u.enable.event.name, cmd_ctx->lsm->u.enable.channel_name); + + ret = kernel_create_event(chan, &cmd_ctx->lsm->u.enable.event); + if (ret < 0) { + ret = LTTCOMM_KERN_ENABLE_FAIL; + goto error; + } + found = 1; + break; + } } - ret = LTTCOMM_OK; + if (!found) { + ret = LTTCOMM_KERN_CHAN_NOT_FOUND; + } else { + kernel_wait_quiescent(kernel_tracer_fd); + ret = LTTCOMM_OK; + } break; } - case KERNEL_ENABLE_ALL_EVENT: + case LTTNG_KERNEL_ENABLE_ALL_EVENT: { - int pos, size; + int pos, size, found; char *event_list, *event, *ptr; + struct ltt_kernel_channel *chan; + struct lttng_event ev; /* Setup lttng message with no payload */ ret = setup_lttng_msg(cmd_ctx, 0); @@ -813,10 +930,26 @@ static int process_client_msg(struct command_ctx *cmd_ctx) goto error; } + /* Get channel by name and create event for that channel */ + cds_list_for_each_entry(chan, &cmd_ctx->session->kernel_session->channel_list.head, list) { + if (strcmp(cmd_ctx->lsm->u.enable.channel_name, chan->channel->name) == 0) { + found = 1; + break; + } + } + + if (!found) { + ret = LTTCOMM_KERN_CHAN_NOT_FOUND; + goto error; + } + ptr = event_list; while ((size = sscanf(ptr, "event { name = %m[^;]; };%n\n", &event, &pos)) == 1) { - /* Enable each single event */ - ret = kernel_enable_event(cmd_ctx->session->kernel_session, event); + strncpy(ev.name, event, LTTNG_SYM_NAME_LEN); + /* Default event type for enable all */ + ev.type = LTTNG_EVENT_TRACEPOINTS; + /* Enable each single tracepoint event */ + ret = kernel_create_event(chan, &ev); if (ret < 0) { ret = LTTCOMM_KERN_ENABLE_FAIL; goto error; @@ -828,13 +961,17 @@ static int process_client_msg(struct command_ctx *cmd_ctx) free(event_list); + /* Quiescent wait after event enable */ + kernel_wait_quiescent(kernel_tracer_fd); ret = LTTCOMM_OK; break; } - case KERNEL_LIST_EVENTS: + case LTTNG_KERNEL_LIST_EVENTS: { char *event_list; - ssize_t size; + ssize_t size = 0; + + DBG("Listing kernel events"); size = kernel_list_events(kernel_tracer_fd, &event_list); if (size < 0) { @@ -859,119 +996,113 @@ static int process_client_msg(struct command_ctx *cmd_ctx) ret = LTTCOMM_OK; break; } - case KERNEL_OPEN_METADATA: - { - /* Setup lttng message with no payload */ - ret = setup_lttng_msg(cmd_ctx, 0); - if (ret < 0) { - goto setup_error; - } - - DBG("Open kernel metadata"); - - ret = kernel_open_metadata(cmd_ctx->session->kernel_session); - if (ret < 0) { - ret = LTTCOMM_KERN_META_FAIL; - goto error; - } - - ret = LTTCOMM_OK; - break; - } - case KERNEL_CREATE_STREAM: + case LTTNG_START_TRACE: { struct ltt_kernel_channel *chan; + /* Setup lttng message with no payload */ ret = setup_lttng_msg(cmd_ctx, 0); if (ret < 0) { goto setup_error; } - DBG("Creating kernel stream"); + /* Kernel tracing */ + if (cmd_ctx->session->kernel_session != NULL) { + if (cmd_ctx->session->kernel_session->metadata == NULL) { + DBG("Open kernel metadata"); + ret = kernel_open_metadata(cmd_ctx->session->kernel_session); + if (ret < 0) { + ret = LTTCOMM_KERN_META_FAIL; + goto error; + } + } - ret = kernel_create_metadata_stream(cmd_ctx->session->kernel_session); - if (ret < 0) { - ERR("Kernel create metadata stream failed"); - ret = LTTCOMM_KERN_STREAM_FAIL; - goto error; - } + if (cmd_ctx->session->kernel_session->metadata_stream_fd == 0) { + DBG("Opening kernel metadata stream"); + if (cmd_ctx->session->kernel_session->metadata_stream_fd == 0) { + ret = kernel_open_metadata_stream(cmd_ctx->session->kernel_session); + if (ret < 0) { + ERR("Kernel create metadata stream failed"); + ret = LTTCOMM_KERN_STREAM_FAIL; + goto error; + } + } + } - /* For each channel */ - cds_list_for_each_entry(chan, &cmd_ctx->session->kernel_session->channel_list.head, list) { - ret = kernel_create_channel_stream(chan); + /* For each channel */ + cds_list_for_each_entry(chan, &cmd_ctx->session->kernel_session->channel_list.head, list) { + if (chan->stream_count == 0) { + ret = kernel_open_channel_stream(chan); + if (ret < 0) { + ERR("Kernel create channel stream failed"); + ret = LTTCOMM_KERN_STREAM_FAIL; + goto error; + } + /* Update the stream global counter */ + cmd_ctx->session->kernel_session->stream_count_global += ret; + } + } + + DBG("Start kernel tracing"); + ret = kernel_start_session(cmd_ctx->session->kernel_session); if (ret < 0) { - ERR("Kernel create channel stream failed"); - ret = LTTCOMM_KERN_STREAM_FAIL; + ERR("Kernel start session failed"); + ret = LTTCOMM_KERN_START_FAIL; goto error; } - /* Update the stream global counter */ - cmd_ctx->session->kernel_session->stream_count_global += ret; - } - - ret = LTTCOMM_OK; - break; - } - case KERNEL_START_TRACE: - { - /* Setup lttng message with no payload */ - ret = setup_lttng_msg(cmd_ctx, 0); - if (ret < 0) { - goto setup_error; - } - DBG("Start kernel tracing"); - - ret = create_trace_dir(cmd_ctx->session->kernel_session); - if (ret < 0) { - if (ret == -EEXIST) { - ret = LTTCOMM_KERN_DIR_EXIST; - } else { - ret = LTTCOMM_KERN_DIR_FAIL; + ret = start_kernel_trace(cmd_ctx->session->kernel_session); + if (ret < 0) { + ret = LTTCOMM_KERN_START_FAIL; goto error; } - } - ret = kernel_start_session(cmd_ctx->session->kernel_session); - if (ret < 0) { - ERR("Kernel start session failed"); - ret = LTTCOMM_KERN_START_FAIL; - goto error; + /* Quiescent wait after starting trace */ + kernel_wait_quiescent(kernel_tracer_fd); } - ret = send_kconsumerd_fds(kconsumerd_cmd_sock, cmd_ctx->session->kernel_session); - if (ret < 0) { - ERR("Send kconsumerd fds failed"); - ret = LTTCOMM_KERN_CONSUMER_FAIL; - goto error; - } + /* TODO: Start all UST traces */ ret = LTTCOMM_OK; break; } - case KERNEL_STOP_TRACE: + case LTTNG_STOP_TRACE: { + struct ltt_kernel_channel *chan; /* Setup lttng message with no payload */ ret = setup_lttng_msg(cmd_ctx, 0); if (ret < 0) { goto setup_error; } - if (cmd_ctx->session->kernel_session == NULL) { - ret = LTTCOMM_KERN_NO_SESSION; - goto error; - } + /* Kernel tracer */ + if (cmd_ctx->session->kernel_session != NULL) { + DBG("Stop kernel tracing"); - DBG("Stop kernel tracing"); + ret = kernel_metadata_flush_buffer(cmd_ctx->session->kernel_session->metadata_stream_fd); + if (ret < 0) { + ERR("Kernel metadata flush failed"); + } - ret = kernel_stop_session(cmd_ctx->session->kernel_session); - if (ret < 0) { - ERR("Kernel stop session failed"); - ret = LTTCOMM_KERN_STOP_FAIL; - goto error; + cds_list_for_each_entry(chan, &cmd_ctx->session->kernel_session->channel_list.head, list) { + ret = kernel_flush_buffer(chan); + if (ret < 0) { + ERR("Kernel flush buffer error"); + } + } + + ret = kernel_stop_session(cmd_ctx->session->kernel_session); + if (ret < 0) { + ERR("Kernel stop session failed"); + ret = LTTCOMM_KERN_STOP_FAIL; + goto error; + } + + /* Quiescent wait after stopping trace */ + kernel_wait_quiescent(kernel_tracer_fd); } - /* Clean kernel session teardown */ - teardown_kernel_session(cmd_ctx->session); + /* TODO : User-space tracer */ ret = LTTCOMM_OK; break; @@ -984,9 +1115,9 @@ static int process_client_msg(struct command_ctx *cmd_ctx) goto setup_error; } - ret = create_session(cmd_ctx->lsm->session_name, &cmd_ctx->llm->session_uuid); + ret = create_session(cmd_ctx->lsm->session_name, cmd_ctx->lsm->path); if (ret < 0) { - if (ret == -1) { + if (ret == -EEXIST) { ret = LTTCOMM_EXIST_SESS; } else { ret = LTTCOMM_FATAL; @@ -1005,15 +1136,19 @@ static int process_client_msg(struct command_ctx *cmd_ctx) goto setup_error; } - ret = destroy_session(&cmd_ctx->lsm->session_uuid); + /* Clean kernel session teardown */ + teardown_kernel_session(cmd_ctx->session); + + ret = destroy_session(cmd_ctx->lsm->session_name); if (ret < 0) { - ret = LTTCOMM_NO_SESS; + ret = LTTCOMM_FATAL; goto error; } ret = LTTCOMM_OK; break; } + /* case LTTNG_LIST_TRACES: { unsigned int trace_count; @@ -1035,9 +1170,10 @@ static int process_client_msg(struct command_ctx *cmd_ctx) ret = LTTCOMM_OK; break; } + */ + /* case UST_CREATE_TRACE: { - /* Setup lttng message with no payload */ ret = setup_lttng_msg(cmd_ctx, 0); if (ret < 0) { goto setup_error; @@ -1045,11 +1181,12 @@ static int process_client_msg(struct command_ctx *cmd_ctx) ret = ust_create_trace(cmd_ctx); if (ret < 0) { - goto setup_error; + goto error; } break; } - case UST_LIST_APPS: + */ + case LTTNG_LIST_TRACEABLE_APPS: { unsigned int app_count; @@ -1070,9 +1207,9 @@ static int process_client_msg(struct command_ctx *cmd_ctx) ret = LTTCOMM_OK; break; } + /* case UST_START_TRACE: { - /* Setup lttng message with no payload */ ret = setup_lttng_msg(cmd_ctx, 0); if (ret < 0) { goto setup_error; @@ -1086,7 +1223,6 @@ static int process_client_msg(struct command_ctx *cmd_ctx) } case UST_STOP_TRACE: { - /* Setup lttng message with no payload */ ret = setup_lttng_msg(cmd_ctx, 0); if (ret < 0) { goto setup_error; @@ -1098,13 +1234,14 @@ static int process_client_msg(struct command_ctx *cmd_ctx) } break; } + */ case LTTNG_LIST_SESSIONS: { unsigned int session_count; session_count = get_session_count(); if (session_count == 0) { - ret = LTTCOMM_NO_SESS; + ret = LTTCOMM_NO_SESSION; goto error; } @@ -1609,6 +1746,26 @@ static int set_signal_handler(void) return ret; } +/* + * set_ulimit + * + * Set open files limit to unlimited. This daemon can open a large number of + * file descriptors in order to consumer multiple kernel traces. + */ +static void set_ulimit(void) +{ + int ret; + struct rlimit lim; + + lim.rlim_cur = 65535; + lim.rlim_max = 65535; + + ret = setrlimit(RLIMIT_NOFILE, &lim); + if (ret < 0) { + perror("failed to set open files limit"); + } +} + /* * main */ @@ -1659,6 +1816,9 @@ int main(int argc, char **argv) /* Setup kernel tracer */ init_kernel_tracer(); + + /* Set ulimit for open files */ + set_ulimit(); } else { if (strlen(apps_unix_sock_path) == 0) { snprintf(apps_unix_sock_path, PATH_MAX, diff --git a/ltt-sessiond/session.c b/ltt-sessiond/session.c index ae09625a4..a4101d2ee 100644 --- a/ltt-sessiond/session.c +++ b/ltt-sessiond/session.c @@ -145,13 +145,13 @@ struct ltt_session *find_session_by_name(char *name) * Return -1 if no session is found. * On success, return 1; */ -int destroy_session(uuid_t *uuid) +int destroy_session(char *name) { int found = -1; struct ltt_session *iter; cds_list_for_each_entry(iter, <t_session_list.head, list) { - if (uuid_compare(iter->uuid, *uuid) == 0) { + if (strcmp(iter->name, name) == 0) { DBG("Destroying session %s", iter->name); del_session_list(iter); free(iter); @@ -166,41 +166,55 @@ int destroy_session(uuid_t *uuid) /* * create_session * - * Create a brand new session and add it to the - * global session list. + * Create a brand new session and add it to the global session list. */ -int create_session(char *name, uuid_t *session_id) +int create_session(char *name, char *path) { + int ret; struct ltt_session *new_session; - DBG("Creating session %s", name); + DBG("Creating session %s at %s", name, path); new_session = find_session_by_name(name); if (new_session != NULL) { - goto error; + ret = -EEXIST; + goto error_exist; } /* Allocate session data structure */ new_session = malloc(sizeof(struct ltt_session)); if (new_session == NULL) { perror("malloc"); - goto error_mem; + ret = -ENOMEM; + goto error_malloc; } + /* Define session name */ if (name != NULL) { if (asprintf(&new_session->name, "%s", name) < 0) { - goto error_mem; + ret = -ENOMEM; + goto error_asprintf; } } else { - /* Generate session name based on the session count */ - if (asprintf(&new_session->name, "%s%d", "lttng-", session_count) < 0) { - goto error_mem; + ERR("No session name given"); + ret = -1; + goto error; + } + + /* Define session system path */ + if (path != NULL) { + if (asprintf(&new_session->path, "%s", path) < 0) { + ret = -ENOMEM; + goto error_asprintf; } + } else { + ERR("No session path given"); + ret = -1; + 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 @@ -224,17 +238,20 @@ int create_session(char *name, uuid_t *session_id) return 0; error: - return -1; +error_asprintf: + if (new_session != NULL) { + free(new_session); + } -error_mem: - return -ENOMEM; +error_exist: +error_malloc: + return ret; } /* * get_lttng_session * - * Iterate over the global session list and - * fill the lttng_session array. + * Iterate over the global session list and fill the lttng_session array. */ void get_lttng_session(struct lttng_session *sessions) { @@ -248,8 +265,8 @@ void get_lttng_session(struct lttng_session *sessions) * the control struct in the buffer. */ cds_list_for_each_entry(iter, <t_session_list.head, list) { - /* Copy name and uuid */ - uuid_copy(lsess.uuid, iter->uuid); + strncpy(lsess.path, iter->path, sizeof(lsess.path)); + lsess.path[sizeof(lsess.path) - 1] = '\0'; strncpy(lsess.name, iter->name, sizeof(lsess.name)); lsess.name[sizeof(lsess.name) - 1] = '\0'; memcpy(&sessions[i], &lsess, sizeof(lsess)); diff --git a/ltt-sessiond/session.h b/ltt-sessiond/session.h index 25ac3fb90..1e274b411 100644 --- a/ltt-sessiond/session.h +++ b/ltt-sessiond/session.h @@ -36,6 +36,7 @@ extern struct ltt_session_list ltt_session_list; struct ltt_session { struct cds_list_head list; char *name; + char *path; uuid_t uuid; struct cds_list_head ust_traces; struct ltt_kernel_session *kernel_session; @@ -45,8 +46,8 @@ struct ltt_session { }; /* Prototypes */ -int create_session(char *name, uuid_t *session_id); -int destroy_session(uuid_t *uuid); +int create_session(char *name, char *path); +int destroy_session(char *name); void get_lttng_session(struct lttng_session *sessions); struct ltt_session *find_session_by_uuid(uuid_t session_id); struct ltt_session *find_session_by_name(char *name); diff --git a/ltt-sessiond/trace.c b/ltt-sessiond/trace.c index 5cd053652..40ba95136 100644 --- a/ltt-sessiond/trace.c +++ b/ltt-sessiond/trace.c @@ -66,29 +66,26 @@ error: * * Return pointer to structure or NULL. */ -struct ltt_kernel_channel *trace_create_kernel_channel(void) +struct ltt_kernel_channel *trace_create_kernel_channel(struct lttng_channel *chan) { int ret; struct ltt_kernel_channel *lkc; - struct lttng_kernel_channel *chan; lkc = malloc(sizeof(struct ltt_kernel_channel)); - chan = malloc(sizeof(struct lttng_kernel_channel)); - if (lkc == NULL || chan == NULL) { - perror("kernel channel malloc"); + if (lkc == NULL) { + perror("ltt_kernel_channel malloc"); goto error; } - /* Default value to channel */ - chan->overwrite = DEFAULT_KERNEL_OVERWRITE; - chan->subbuf_size = DEFAULT_KERNEL_SUBBUF_SIZE; - chan->num_subbuf = DEFAULT_KERNEL_SUBBUF_NUM; - chan->switch_timer_interval = DEFAULT_KERNEL_SWITCH_TIMER; - chan->read_timer_interval = DEFAULT_KERNEL_READ_TIMER; + lkc->channel = malloc(sizeof(struct lttng_channel)); + if (lkc->channel == NULL) { + perror("lttng_channel malloc"); + goto error; + } + memcpy(lkc->channel, chan, sizeof(struct lttng_channel)); lkc->fd = 0; lkc->stream_count = 0; - lkc->channel = chan; /* Init linked list */ CDS_INIT_LIST_HEAD(&lkc->events_list.head); CDS_INIT_LIST_HEAD(&lkc->stream_list.head); @@ -112,8 +109,7 @@ error: * * Return pointer to structure or NULL. */ -struct ltt_kernel_event *trace_create_kernel_event(char *name, - enum lttng_kernel_instrumentation type) +struct ltt_kernel_event *trace_create_kernel_event(struct lttng_event *ev) { struct ltt_kernel_event *lke; struct lttng_kernel_event *attr; @@ -125,9 +121,30 @@ struct ltt_kernel_event *trace_create_kernel_event(char *name, goto error; } - /* Init event attribute */ - attr->instrumentation = type; - strncpy(attr->name, name, LTTNG_SYM_NAME_LEN); + switch (ev->type) { + case LTTNG_EVENT_KPROBES: + attr->instrumentation = LTTNG_KERNEL_KPROBES; + attr->u.kprobe.addr = ev->attr.kprobe.addr; + attr->u.kprobe.offset = ev->attr.kprobe.offset; + strncpy(attr->u.kprobe.symbol_name, + ev->attr.kprobe.symbol_name, LTTNG_SYM_NAME_LEN); + break; + case LTTNG_EVENT_FUNCTION: + attr->instrumentation = LTTNG_KERNEL_FUNCTION; + strncpy(attr->u.ftrace.symbol_name, + ev->attr.ftrace.symbol_name, LTTNG_SYM_NAME_LEN); + break; + case LTTNG_EVENT_TRACEPOINTS: + attr->instrumentation = LTTNG_KERNEL_TRACEPOINTS; + break; + default: + ERR("Unknown kernel instrumentation type (%d)", ev->type); + goto error; + } + + /* Copy event name */ + strncpy(attr->name, ev->name, LTTNG_SYM_NAME_LEN); + /* Setting up a kernel event */ lke->fd = 0; lke->event = attr; @@ -149,25 +166,25 @@ struct ltt_kernel_metadata *trace_create_kernel_metadata(void) { int ret; struct ltt_kernel_metadata *lkm; - struct lttng_kernel_channel *attr; + struct lttng_channel *chan; lkm = malloc(sizeof(struct ltt_kernel_metadata)); - attr = malloc(sizeof(struct lttng_kernel_channel)); - if (lkm == NULL || attr == NULL) { + chan = malloc(sizeof(struct lttng_channel)); + if (lkm == NULL || chan == NULL) { perror("kernel metadata malloc"); goto error; } /* Set default attributes */ - attr->overwrite = DEFAULT_KERNEL_OVERWRITE; - attr->subbuf_size = DEFAULT_KERNEL_SUBBUF_SIZE; - attr->num_subbuf = DEFAULT_KERNEL_SUBBUF_NUM; - attr->switch_timer_interval = DEFAULT_KERNEL_SWITCH_TIMER; - attr->read_timer_interval = DEFAULT_KERNEL_READ_TIMER; + chan->attr.overwrite = DEFAULT_CHANNEL_OVERWRITE; + chan->attr.subbuf_size = DEFAULT_CHANNEL_SUBBUF_SIZE; + chan->attr.num_subbuf = DEFAULT_CHANNEL_SUBBUF_NUM; + chan->attr.switch_timer_interval = DEFAULT_CHANNEL_SWITCH_TIMER; + chan->attr.read_timer_interval = DEFAULT_CHANNEL_READ_TIMER; /* Init metadata */ lkm->fd = 0; - lkm->conf = attr; + lkm->conf = chan; /* Set default metadata path */ ret = asprintf(&lkm->pathname, "%s/metadata", DEFAULT_TRACE_OUTPUT); if (ret < 0) { diff --git a/ltt-sessiond/trace.h b/ltt-sessiond/trace.h index 444126ba0..8fdef2a37 100644 --- a/ltt-sessiond/trace.h +++ b/ltt-sessiond/trace.h @@ -21,14 +21,10 @@ #include #include -#include "lttng-kernel.h" -/* Default kernel channel attributes */ -#define DEFAULT_KERNEL_OVERWRITE 0 -#define DEFAULT_KERNEL_SUBBUF_SIZE 4096 /* bytes */ -#define DEFAULT_KERNEL_SUBBUF_NUM 8 /* Must always be a power of 2 */ -#define DEFAULT_KERNEL_SWITCH_TIMER 0 /* usec */ -#define DEFAULT_KERNEL_READ_TIMER 200 /* usec */ +#include + +#include "lttng-kernel.h" /* Kernel event list */ struct ltt_kernel_event_list { @@ -57,7 +53,7 @@ struct ltt_kernel_channel { int fd; char *pathname; unsigned int stream_count; - struct lttng_kernel_channel *channel; + struct lttng_channel *channel; struct ltt_kernel_event_list events_list; struct ltt_kernel_stream_list stream_list; struct cds_list_head list; @@ -67,7 +63,7 @@ struct ltt_kernel_channel { struct ltt_kernel_metadata { int fd; char *pathname; - struct lttng_kernel_channel *conf; + struct lttng_channel *conf; }; /* Channel stream */ @@ -82,6 +78,7 @@ struct ltt_kernel_stream { struct ltt_kernel_session { int fd; int metadata_stream_fd; + int kconsumer_fds_sent; unsigned int channel_count; unsigned int stream_count_global; struct ltt_kernel_metadata *metadata; @@ -107,9 +104,8 @@ struct ltt_ust_marker { * Create functions malloc() the data structure. */ struct ltt_kernel_session *trace_create_kernel_session(void); -struct ltt_kernel_channel *trace_create_kernel_channel(void); -struct ltt_kernel_event *trace_create_kernel_event(char *name, - enum lttng_kernel_instrumentation type); +struct ltt_kernel_channel *trace_create_kernel_channel(struct lttng_channel *chan); +struct ltt_kernel_event *trace_create_kernel_event(struct lttng_event *ev); struct ltt_kernel_metadata *trace_create_kernel_metadata(void); struct ltt_kernel_stream *trace_create_kernel_stream(void); diff --git a/ltt-sessiond/ust-ctl.c b/ltt-sessiond/ust-ctl.c index a23d3c5ac..b5f2ce411 100644 --- a/ltt-sessiond/ust-ctl.c +++ b/ltt-sessiond/ust-ctl.c @@ -66,6 +66,7 @@ int get_trace_count_per_session(struct ltt_session *session) * Fill the lttng_trace array of all the * available trace of the session. */ +/* void get_traces_per_session(struct ltt_session *session, struct lttng_trace *traces) { int i = 0; @@ -74,7 +75,6 @@ void get_traces_per_session(struct ltt_session *session, struct lttng_trace *tra DBG("Getting userspace traces for session %s", session->name); - /* Getting userspace traces */ cds_list_for_each_entry(ust_iter, &session->ust_traces, list) { trace.type = USERSPACE; trace.pid = ust_iter->pid; @@ -87,13 +87,13 @@ void get_traces_per_session(struct ltt_session *session, struct lttng_trace *tra DBG("Getting kernel traces for session %s", session->name); - /* Getting kernel traces */ if (session->kern_session_count > 0) { trace.type = KERNEL; strncpy(trace.name, "kernel", 6); memcpy(&traces[i], &trace, sizeof(trace)); } } +*/ /* * ust_create_trace diff --git a/ltt-sessiond/ust-ctl.h b/ltt-sessiond/ust-ctl.h index 72e5fb7b2..28b319da6 100644 --- a/ltt-sessiond/ust-ctl.h +++ b/ltt-sessiond/ust-ctl.h @@ -24,7 +24,7 @@ #include "trace.h" int get_trace_count_per_session(struct ltt_session *session); -void get_traces_per_session(struct ltt_session *session, struct lttng_trace *traces); +//void get_traces_per_session(struct ltt_session *session, struct lttng_trace *traces); int ust_create_trace(struct command_ctx *cmd_ctx); int ust_start_trace(struct command_ctx *cmd_ctx); int ust_stop_trace(struct command_ctx *cmd_ctx); diff --git a/lttng/Makefile.am b/lttng/Makefile.am index 947c750d4..de2f22cdc 100644 --- a/lttng/Makefile.am +++ b/lttng/Makefile.am @@ -1,10 +1,11 @@ AM_CPPFLAGS = -I$(top_srcdir)/include -#AM_CFLAGS = $(LTTNG_LIBS) -lpopt bin_PROGRAMS = lttng -lttng_SOURCES = options.c lttng.c +lttng_SOURCES = config.c commands/start.c commands/add_channel.c \ + commands/list.c commands/create.c commands/destroy.c \ + commands/stop.c commands/enable_events.c \ + utils.c lttng.c lttng_LDADD = \ $(top_builddir)/liblttngctl/liblttngctl.la -# $(top_builddir)/liblttsessiondcomm/liblttsessiondcomm.la diff --git a/lttng/cmd.h b/lttng/cmd.h new file mode 100644 index 000000000..02ebfcc1d --- /dev/null +++ b/lttng/cmd.h @@ -0,0 +1,48 @@ +/* + * 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_CMD_H +#define _LTTNG_CMD_H + +#include +#include "lttngerr.h" +#include "lttng-share.h" +#include "lttng-kernel.h" + +enum cmd_error_code { + CMD_SUCCESS, + CMD_ERROR, + CMD_UNDEFINED, + CMD_NOT_IMPLEMENTED, + CMD_FATAL, +}; + +struct cmd_struct { + const char *name; + int (*func)(int argc, const char **argv); +}; + +extern int cmd_list(int argc, const char **argv); +extern int cmd_create(int argc, const char **argv); +extern int cmd_destroy(int argc, const char **argv); +extern int cmd_add_channel(int argc, const char **argv); +extern int cmd_start(int argc, const char **argv); +extern int cmd_stop(int argc, const char **argv); +extern int cmd_enable_events(int argc, const char **argv); + +#endif /* _LTTNG_CMD_H */ diff --git a/lttng/commands/add_channel.c b/lttng/commands/add_channel.c new file mode 100644 index 000000000..6b41e875a --- /dev/null +++ b/lttng/commands/add_channel.c @@ -0,0 +1,217 @@ +/* + * 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 "cmd.h" +#include "config.h" +#include "utils.h" + +static char *opt_channel_name; +static char *opt_kernel; +static char *opt_cmd_name; +static int opt_pid_all; +static int opt_userspace; +static pid_t opt_pid; +static struct lttng_channel chan; + +enum { + OPT_HELP = 1, + OPT_DISCARD, + OPT_OVERWRITE, + OPT_SUBBUF_SIZE, + OPT_NUM_SUBBUF, + OPT_SWITCH_TIMER, + OPT_READ_TIMER, + OPT_USERSPACE, +}; + +static struct poptOption long_options[] = { + /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ + {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0}, + {"kernel", 'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0}, + {"userspace", 'u', POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, 0, OPT_USERSPACE, 0, 0}, + {"all", 0, POPT_ARG_VAL, &opt_pid_all, 1, 0, 0}, + {"pid", 'p', POPT_ARG_INT, &opt_pid, 0, 0, 0}, + {"discard", 0, POPT_ARG_NONE, 0, OPT_DISCARD, 0, 0}, + {"overwrite", 0, POPT_ARG_NONE, 0, OPT_OVERWRITE, 0, 0}, + {"subbuf_size", 0, POPT_ARG_DOUBLE, 0, OPT_SUBBUF_SIZE, 0, 0}, + {"num_subbuf", 0, POPT_ARG_INT, 0, OPT_NUM_SUBBUF, 0, 0}, + {"switch_timer", 0, POPT_ARG_INT, 0, OPT_SWITCH_TIMER, 0, 0}, + {"read_timer", 0, POPT_ARG_INT, 0, OPT_READ_TIMER, 0, 0}, + {0, 0, 0, 0, 0, 0, 0} +}; + +/* + * usage + */ +static void usage(FILE *ofp) +{ + fprintf(ofp, "usage: lttng add-channel NAME [options] [channel_options]\n"); + fprintf(ofp, "\n"); + fprintf(ofp, " -h, --help Show this help\n"); + fprintf(ofp, " -k, --kernel Apply on the kernel tracer\n"); + fprintf(ofp, " -u, --userspace [CMD] Apply on the user-space tracer\n"); + fprintf(ofp, " --all If -u, apply on all traceable apps\n"); + fprintf(ofp, " -p, --pid PID If -u, apply on a specific PID\n"); + fprintf(ofp, "\n"); + fprintf(ofp, "Channel options:\n"); + fprintf(ofp, " --discard Discard event when buffers are full (default)\n"); + fprintf(ofp, " --overwrite Flight recorder mode\n"); + fprintf(ofp, " --subbuf_size Subbuffer size in bytes (default: 4096)\n"); + fprintf(ofp, " --num_subbuf Number of subbufers (default: 2)\n"); + fprintf(ofp, " --switch_timer Switch timer interval in usec (default: 0)\n"); + fprintf(ofp, " --read_timer Read timer interval in usec (default: 200)\n"); + fprintf(ofp, "\n"); +} + +/* + * add_channel + * + * Adding channel using the lttng API. + */ +static int add_channel(void) +{ + int ret = CMD_SUCCESS; + + if (set_session_name() < 0) { + ret = CMD_ERROR; + goto error; + } + + /* Copy channel name and normalize it */ + strncpy(chan.name, opt_channel_name, NAME_MAX); + chan.name[NAME_MAX - 1] = '\0'; + + /* Kernel tracer action */ + if (opt_kernel) { + /* Create kernel channel */ + ret = lttng_kernel_create_channel(&chan); + if (ret < 0) { + goto error; + } + } else if (opt_userspace) { /* User-space tracer action */ + /* + * TODO: Waiting on lttng UST 2.0 + */ + if (opt_pid_all) { + } else if (opt_pid != 0) { + } + ret = CMD_NOT_IMPLEMENTED; + goto error; + } else { + ERR("Please specify a tracer (kernel or user-space)"); + goto error; + } + + MSG("Channel %s created", opt_channel_name); + +error: + return ret; +} + +/* + * init_channel_config + * + * Default value for channel configuration. + */ +static void init_channel_config(void) +{ + chan.attr.overwrite = DEFAULT_CHANNEL_OVERWRITE; + chan.attr.subbuf_size = DEFAULT_CHANNEL_SUBBUF_SIZE; + chan.attr.num_subbuf = DEFAULT_CHANNEL_SUBBUF_NUM; + chan.attr.switch_timer_interval = DEFAULT_CHANNEL_SWITCH_TIMER; + chan.attr.read_timer_interval = DEFAULT_CHANNEL_READ_TIMER; +} + +/* + * cmd_add_channel + * + * Add channel to trace session + */ +int cmd_add_channel(int argc, const char **argv) +{ + int opt, ret; + static poptContext pc; + + init_channel_config(); + + pc = poptGetContext(NULL, argc, argv, long_options, 0); + poptReadDefaultConfig(pc, 0); + + while ((opt = poptGetNextOpt(pc)) != -1) { + switch (opt) { + case OPT_HELP: + usage(stderr); + ret = CMD_SUCCESS; + goto end; + case OPT_USERSPACE: + opt_userspace = 1; + opt_cmd_name = poptGetOptArg(pc); + break; + case OPT_DISCARD: + chan.attr.overwrite = 0; + DBG("Channel set to discard"); + break; + case OPT_OVERWRITE: + chan.attr.overwrite = 1; + DBG("Channel set to overwrite"); + break; + case OPT_SUBBUF_SIZE: + chan.attr.subbuf_size = atol(poptGetOptArg(pc)); + DBG("Channel subbuf size set to %lu", chan.attr.subbuf_size); + break; + case OPT_NUM_SUBBUF: + chan.attr.num_subbuf = atoi(poptGetOptArg(pc)); + DBG("Channel subbuf num set to %lu", chan.attr.num_subbuf); + break; + case OPT_SWITCH_TIMER: + chan.attr.switch_timer_interval = atoi(poptGetOptArg(pc)); + DBG("Channel switch timer interval set to %d", chan.attr.switch_timer_interval); + break; + case OPT_READ_TIMER: + chan.attr.read_timer_interval = atoi(poptGetOptArg(pc)); + DBG("Channel read timer interval set to %d", chan.attr.read_timer_interval); + break; + default: + usage(stderr); + ret = CMD_UNDEFINED; + goto end; + } + } + + opt_channel_name = (char*) poptGetArg(pc); + if (opt_channel_name == NULL) { + ERR("Missing channel name.\n"); + usage(stderr); + ret = CMD_SUCCESS; + goto end; + } + + ret = add_channel(); + +end: + return ret; +} diff --git a/lttng/commands/create.c b/lttng/commands/create.c new file mode 100644 index 000000000..522ebc9c3 --- /dev/null +++ b/lttng/commands/create.c @@ -0,0 +1,163 @@ +/* + * 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 "cmd.h" +#include "config.h" + +static char *opt_output_path; +static char *opt_session_name; + +enum { + OPT_HELP = 1, +}; + +static struct poptOption long_options[] = { + /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ + {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0}, + {"output", 'o', POPT_ARG_STRING, &opt_output_path, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0} +}; + +/* + * usage + */ +static void usage(FILE *ofp) +{ + fprintf(ofp, "usage: lttng create [options] [NAME]\n"); + fprintf(ofp, "\n"); + fprintf(ofp, " -h, --help Show this help\n"); + fprintf(ofp, " -o, --output PATH Specify output path\n"); + fprintf(ofp, "\n"); +} + +/* + * create_session + * + * Create a tracing session. If no name specified, a default name will be + * generated. + */ +static int create_session() +{ + int ret; + char name[NAME_MAX]; + char *session_name, *path = NULL, *alloc_path; + time_t rawtime; + struct tm *timeinfo; + + /* Auto session name creation */ + if (opt_session_name == NULL) { + time(&rawtime); + timeinfo = localtime(&rawtime); + strftime(name, sizeof(name), "auto-%Y%m%d-%H%M%S", timeinfo); + session_name = name; + DBG("Auto session name set to %s", session_name); + } else { + session_name = opt_session_name; + } + + /* Auto output path */ + if (opt_output_path == NULL) { + alloc_path = config_get_default_path(); + if (alloc_path == NULL) { + ret = CMD_FATAL; + goto error; + } + } else { + alloc_path = opt_output_path; + } + + path = config_generate_dir_path(alloc_path); + if (path == NULL) { + ret = CMD_FATAL; + goto error; + } + + /* Init lttng session config */ + ret = config_init(path); + if (ret < 0) { + goto error; + } + + ret = config_add_session_name(path, session_name); + if (ret < 0) { + goto error; + } + + ret = lttng_create_session(session_name, path); + if (ret < 0) { + goto error; + } + + MSG("Session %s created.", session_name); + MSG("Working directory of created session is %s", path); + + ret = CMD_SUCCESS; + +error: + if (alloc_path) { + free(alloc_path); + } + + if (path) { + free(path); + } + return ret; +} + +/* + * cmd_list + * + * The 'list ' first level command + */ +int cmd_create(int argc, const char **argv) +{ + int opt, ret = CMD_SUCCESS; + static poptContext pc; + + pc = poptGetContext(NULL, argc, argv, long_options, 0); + poptReadDefaultConfig(pc, 0); + + while ((opt = poptGetNextOpt(pc)) != -1) { + switch (opt) { + case OPT_HELP: + usage(stderr); + goto end; + default: + usage(stderr); + ret = CMD_UNDEFINED; + goto end; + } + } + + opt_session_name = (char*) poptGetArg(pc); + + ret = create_session(); + +end: + return ret; +} diff --git a/lttng/commands/destroy.c b/lttng/commands/destroy.c new file mode 100644 index 000000000..9519403ad --- /dev/null +++ b/lttng/commands/destroy.c @@ -0,0 +1,137 @@ +/* + * 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 "cmd.h" +#include "config.h" +#include "utils.h" + +static char *opt_session_name; + +enum { + OPT_HELP = 1, +}; + +static struct poptOption long_options[] = { + /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ + {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0}, + {0, 0, 0, 0, 0, 0, 0} +}; + +/* + * usage + */ +static void usage(FILE *ofp) +{ + fprintf(ofp, "usage: lttng destroy [options] [NAME]\n"); + fprintf(ofp, "\n"); + fprintf(ofp, "Where NAME is an optional session name. If not specified, lttng will\n"); + fprintf(ofp, "get it from the configuration directory (.lttng).\n"); + fprintf(ofp, "\n"); + fprintf(ofp, " -h, --help Show this help\n"); + fprintf(ofp, "\n"); +} + +/* + * destroy_session + * + * Destroy a session removing the config directory and unregistering to the + * session daemon. + */ +static int destroy_session() +{ + int ret; + char *session_name, *path; + + if (opt_session_name == NULL) { + session_name = get_session_name(); + if (session_name == NULL) { + ret = CMD_ERROR; + goto error; + } + } else { + session_name = opt_session_name; + } + + ret = lttng_destroy_session(session_name); + if (ret < 0) { + goto free_name; + } + + path = get_config_file_path(); + if (path == NULL) { + ret = CMD_FATAL; + goto free_name; + } + + if (opt_session_name == NULL) { + config_destroy(path); + MSG("Session %s destroyed at %s", session_name, path); + } else { + MSG("Session %s destroyed", session_name); + } + + free(path); + ret = CMD_SUCCESS; + +free_name: + free(session_name); +error: + return ret; +} + +/* + * cmd_destroy + * + * The 'destroy ' first level command + */ +int cmd_destroy(int argc, const char **argv) +{ + int opt, ret = CMD_SUCCESS; + static poptContext pc; + + pc = poptGetContext(NULL, argc, argv, long_options, 0); + poptReadDefaultConfig(pc, 0); + + while ((opt = poptGetNextOpt(pc)) != -1) { + switch (opt) { + case OPT_HELP: + usage(stderr); + goto end; + default: + usage(stderr); + ret = CMD_UNDEFINED; + goto end; + } + } + + opt_session_name = (char*) poptGetArg(pc); + + ret = destroy_session(); + +end: + return ret; +} diff --git a/lttng/commands/enable_events.c b/lttng/commands/enable_events.c new file mode 100644 index 000000000..f9b51b14d --- /dev/null +++ b/lttng/commands/enable_events.c @@ -0,0 +1,240 @@ +/* + * 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 "cmd.h" +#include "config.h" +#include "utils.h" + +static char *opt_event_list; +static int opt_event_type; +static char *opt_kernel; +static char *opt_cmd_name; +static int opt_pid_all; +static int opt_userspace; +static int opt_enable_all; +static pid_t opt_pid; +static char *opt_kprobe_addr; +static char *opt_function_symbol; +static char *opt_channel_name; + +enum { + OPT_HELP = 1, + OPT_USERSPACE, + OPT_TRACEPOINT, + OPT_MARKER, + OPT_KPROBE, + OPT_FUNCTION, +}; + +static struct poptOption long_options[] = { + /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ + {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0}, + {"all-events", 'a', POPT_ARG_VAL, &opt_enable_all, 1, 0, 0}, + {"channel", 'c', POPT_ARG_STRING, &opt_channel_name, 0, 0, 0}, + {"kernel", 'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0}, + {"userspace", 'u', POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, 0, OPT_USERSPACE, 0, 0}, + {"all", 0, POPT_ARG_VAL, &opt_pid_all, 1, 0, 0}, + {"pid", 'p', POPT_ARG_INT, &opt_pid, 0, 0, 0}, + {"tracepoint", 0, POPT_ARG_NONE, 0, OPT_TRACEPOINT, 0, 0}, + {"marker", 0, POPT_ARG_NONE, 0, OPT_MARKER, 0, 0}, + {"kprobe", 0, POPT_ARG_STRING, 0, OPT_KPROBE, 0, 0}, + {"function", 0, POPT_ARG_STRING, 0, OPT_FUNCTION, 0, 0}, + {0, 0, 0, 0, 0, 0, 0} +}; + +/* + * usage + */ +static void usage(FILE *ofp) +{ + fprintf(ofp, "usage: lttng enable-event NAME[,NAME2,...] [options] [event_options]\n"); + fprintf(ofp, "\n"); + fprintf(ofp, " -h, --help Show this help\n"); + fprintf(ofp, " -c, --channel Apply on this channel\n"); + fprintf(ofp, " -a, --all-events Enable all tracepoints\n"); + fprintf(ofp, " -k, --kernel Apply for the kernel tracer\n"); + fprintf(ofp, " -u, --userspace [CMD] Apply for the user-space tracer\n"); + fprintf(ofp, " --all If -u, apply on all traceable apps\n"); + fprintf(ofp, " -p, --pid PID If -u, apply on a specific PID\n"); + fprintf(ofp, "\n"); + fprintf(ofp, "Event options:\n"); + fprintf(ofp, " --tracepoint Tracepoint event (default)\n"); + fprintf(ofp, " --kprobe ADDR Kernel Kprobe\n"); + fprintf(ofp, " --function SYMBOL Function tracer event\n"); + fprintf(ofp, " --marker User-space marker (deprecated)\n"); + fprintf(ofp, "\n"); +} + +/* + * enable_events + * + * Enabling event using the lttng API. + */ +static int enable_events(void) +{ + int err, ret = CMD_SUCCESS; + char *event_name, *channel_name; + struct lttng_event ev; + + if (set_session_name() < 0) { + ret = CMD_ERROR; + goto error; + } + + if (opt_channel_name == NULL) { + err = asprintf(&channel_name, DEFAULT_CHANNEL_NAME); + if (err < 0) { + ret = CMD_FATAL; + goto error; + } + } else { + channel_name = opt_channel_name; + } + + if (opt_enable_all) { + if (opt_kernel) { + ret = lttng_kernel_enable_event(NULL, channel_name); + goto error; + } + + /* TODO: User-space tracer */ + } + + /* Strip event list */ + event_name = strtok(opt_event_list, ","); + while (event_name != NULL) { + /* Kernel tracer action */ + if (opt_kernel) { + DBG("Enabling kernel event %s for channel %s", + event_name, channel_name); + /* Copy name and type of the event */ + strncpy(ev.name, event_name, LTTNG_SYMBOL_NAME_LEN); + ev.type = opt_event_type; + + switch (opt_event_type) { + case LTTNG_EVENT_TRACEPOINTS: + ret = lttng_kernel_enable_event(&ev, channel_name); + break; + case LTTNG_EVENT_KPROBES: + /* FIXME: check addr format */ + ev.attr.kprobe.addr = atoll(opt_kprobe_addr); + ret = lttng_kernel_enable_event(&ev, channel_name); + break; + case LTTNG_EVENT_FUNCTION: + strncpy(ev.attr.ftrace.symbol_name, opt_function_symbol, LTTNG_SYMBOL_NAME_LEN); + ret = lttng_kernel_enable_event(&ev, channel_name); + break; + default: + ret = CMD_NOT_IMPLEMENTED; + goto error; + } + + if (ret > 0) { + MSG("Kernel event %s created in channel %s", event_name, channel_name); + } + } else if (opt_userspace) { /* User-space tracer action */ + /* + * TODO: Waiting on lttng UST 2.0 + */ + if (opt_pid_all) { + } else if (opt_pid != 0) { + } + ret = CMD_NOT_IMPLEMENTED; + goto error; + } else { + ERR("Please specify a tracer (kernel or user-space)"); + goto error; + } + + /* Next event */ + event_name = strtok(NULL, ","); + } + +error: + return ret; +} + +/* + * cmd_enable_events + * + * Add event to trace session + */ +int cmd_enable_events(int argc, const char **argv) +{ + int opt, ret; + static poptContext pc; + + pc = poptGetContext(NULL, argc, argv, long_options, 0); + poptReadDefaultConfig(pc, 0); + + /* Default event type */ + opt_event_type = LTTNG_KERNEL_TRACEPOINTS; + + while ((opt = poptGetNextOpt(pc)) != -1) { + switch (opt) { + case OPT_HELP: + usage(stderr); + ret = CMD_SUCCESS; + goto end; + case OPT_USERSPACE: + opt_userspace = 1; + opt_cmd_name = poptGetOptArg(pc); + break; + case OPT_TRACEPOINT: + opt_event_type = LTTNG_EVENT_TRACEPOINTS; + break; + case OPT_MARKER: + ret = CMD_NOT_IMPLEMENTED; + goto end; + case OPT_KPROBE: + opt_event_type = LTTNG_EVENT_KPROBES; + opt_kprobe_addr = poptGetOptArg(pc); + break; + case OPT_FUNCTION: + opt_event_type = LTTNG_EVENT_FUNCTION; + opt_function_symbol = poptGetOptArg(pc); + break; + default: + usage(stderr); + ret = CMD_UNDEFINED; + goto end; + } + } + + opt_event_list = (char*) poptGetArg(pc); + if (opt_event_list == NULL && opt_enable_all == 0) { + ERR("Missing event name(s).\n"); + usage(stderr); + ret = CMD_SUCCESS; + goto end; + } + + ret = enable_events(); + +end: + return ret; +} diff --git a/lttng/commands/list.c b/lttng/commands/list.c new file mode 100644 index 000000000..191d2e7a2 --- /dev/null +++ b/lttng/commands/list.c @@ -0,0 +1,284 @@ +/* + * 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 "cmd.h" + +static int opt_pid; +static int opt_channels; + +enum { + OPT_HELP = 1, + OPT_EVENTS, + OPT_KERNEL, + OPT_APPS, + OPT_SESSIONS, + OPT_CHANNEL, +}; + +static struct poptOption long_options[] = { + /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ + {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0}, + {"events", 'e', POPT_ARG_NONE, 0, OPT_EVENTS, 0, 0}, + {"kernel", 'k', POPT_ARG_NONE, 0, OPT_KERNEL, 0, 0}, + {"pid", 'p', POPT_ARG_INT, &opt_pid, 0, 0, 0}, + {"apps", 'a', POPT_ARG_NONE, 0, OPT_APPS, 0, 0}, + {"session", 's', POPT_ARG_NONE, 0, OPT_SESSIONS, 0, 0}, + {"channel", 'c', POPT_ARG_VAL, &opt_channels, 1, 0, 0}, + {0, 0, 0, 0, 0, 0, 0} +}; + +/* + * usage + */ +static void usage(FILE *ofp) +{ + fprintf(ofp, "usage: lttng list [options] []\n"); + fprintf(ofp, "\n"); + fprintf(ofp, " -h, --help Show this help\n"); + fprintf(ofp, " -e, --events List all available instrumentation\n"); + fprintf(ofp, " -k, --kernel List kernel instrumentation\n"); + fprintf(ofp, " -p, --pid PID List user-space instrumentation by PID\n"); + fprintf(ofp, " -a, --apps List traceable user-space applications/pids\n"); + fprintf(ofp, " -s, --sessions List tracing session\n"); + fprintf(ofp, "\n"); +} + +/* + * get_cmdline_by_pid + * + * Get command line from /proc for a specific pid. + * + * On success, return an allocated string pointer pointing to the proc + * cmdline. + * On error, return NULL. + */ +static char *get_cmdline_by_pid(pid_t pid) +{ + int ret; + FILE *fp; + char *cmdline = NULL; + char path[24]; /* Can't go bigger than /proc/65535/cmdline */ + + snprintf(path, sizeof(path), "/proc/%d/cmdline", pid); + fp = fopen(path, "r"); + if (fp == NULL) { + goto end; + } + + /* Caller must free() *cmdline */ + cmdline = malloc(PATH_MAX); + ret = fread(cmdline, 1, PATH_MAX, fp); + fclose(fp); + +end: + return cmdline; +} + +/* + * list_kernel + * + * Ask for all trace events in the kernel and pretty print them. + */ +static int list_kernel(void) +{ + int ret, pos, size; + char *event_list, *event, *ptr; + + DBG("Getting all tracing events"); + + ret = lttng_kernel_list_events(&event_list); + if (ret < 0) { + ERR("Unable to list kernel instrumentation"); + return ret; + } + + MSG("Kernel tracepoints:\n-------------"); + + ptr = event_list; + while ((size = sscanf(ptr, "event { name = %m[^;]; };%n\n", &event, &pos)) == 1) { + MSG(" - %s", event); + /* Move pointer to the next line */ + ptr += pos + 1; + free(event); + } + + free(event_list); + + return CMD_SUCCESS; +} + +/* + * list_sessions + * + * Get the list of available sessions from the session daemon and print it to + * user. + */ +static int list_sessions(void) +{ + int ret, count, i; + struct lttng_session *sessions; + + count = lttng_list_sessions(&sessions); + DBG("Session count %d", count); + if (count < 0) { + ret = count; + goto error; + } + + MSG("Available sessions:"); + for (i = 0; i < count; i++) { + MSG(" %d) %s (%s)", i+1, sessions[i].name, sessions[i].path); + } + + free(sessions); + + return CMD_SUCCESS; + +error: + return ret; +} + +/* + * list_apps + * + * Get the UST traceable pid list and print them to the user. + */ +static int list_apps(void) +{ + int i, ret, count; + pid_t *pids; + char *cmdline; + + count = 0; + //count = lttng_ust_list_traceable_apps(&pids); + if (count < 0) { + ret = count; + goto error; + } + + MSG("LTTng UST traceable application [name (pid)]:"); + for (i=0; i < count; i++) { + cmdline = get_cmdline_by_pid(pids[i]); + if (cmdline == NULL) { + MSG("\t(not running) (%d)", pids[i]); + continue; + } + MSG("\t%s (%d)", cmdline, pids[i]); + free(cmdline); + } + + /* Allocated by lttng_ust_list_apps() */ + free(pids); + + return CMD_SUCCESS; + +error: + return ret; +} + +/* + * list_pid + * + * List all instrumentation for a specific pid + */ +/* +static int list_pid(int pid) +{ + int ret; + + return CMD_SUCCESS; + +error: + return ret; +} +*/ + +/* + * list_executable + * + * List all instrumentation for an executable on the system + */ +/* +static int list_executable(char *name) +{ +} +*/ + +/* + * cmd_list + * + * The 'list ' first level command + */ +int cmd_list(int argc, const char **argv) +{ + int opt, ret = CMD_SUCCESS; + const char *command_name; + static poptContext pc; + + if (argc < 2) { + usage(stderr); + goto end; + } + + pc = poptGetContext(NULL, argc, argv, long_options, 0); + poptReadDefaultConfig(pc, 0); + + while ((opt = poptGetNextOpt(pc)) != -1) { + switch (opt) { + case OPT_HELP: + usage(stderr); + goto end; + case OPT_EVENTS: + ret = CMD_NOT_IMPLEMENTED; + goto end; + case OPT_APPS: + ret = list_apps(); + break; + case OPT_KERNEL: + ret = list_kernel(); + break; + case OPT_SESSIONS: + ret = list_sessions(); + break; + default: + usage(stderr); + ret = CMD_UNDEFINED; + goto end; + } + } + + if (opt_pid != 0) { + //ret = list_pid(pid); + ret = CMD_NOT_IMPLEMENTED; + } + + command_name = poptGetArg(pc); + if (command_name != NULL) { + // ret = list_executable(command_name); + ret = CMD_NOT_IMPLEMENTED; + } + +end: + return ret; +} diff --git a/lttng/commands/start.c b/lttng/commands/start.c new file mode 100644 index 000000000..3a4febe4f --- /dev/null +++ b/lttng/commands/start.c @@ -0,0 +1,125 @@ +/* + * 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 "cmd.h" +#include "config.h" +#include "utils.h" + +static char *opt_session_name; + +enum { + OPT_HELP = 1, +}; + +static struct poptOption long_options[] = { + /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ + {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0}, + {0, 0, 0, 0, 0, 0, 0} +}; + +/* + * usage + */ +static void usage(FILE *ofp) +{ + fprintf(ofp, "usage: lttng start [options] [NAME]\n"); + fprintf(ofp, "\n"); + fprintf(ofp, "Where NAME is an optional session name. If not specified, lttng will\n"); + fprintf(ofp, "get it from the configuration directory (.lttng).\n"); + fprintf(ofp, "\n"); + fprintf(ofp, " -h, --help Show this help\n"); + fprintf(ofp, "\n"); +} + +/* + * start_tracing + * + * Start tracing for all trace of the session. + */ +static int start_tracing(void) +{ + int ret = CMD_SUCCESS; + char *session_name; + + if (opt_session_name == NULL) { + session_name = get_session_name(); + if (session_name == NULL) { + ret = CMD_ERROR; + goto error; + } + } else { + session_name = opt_session_name; + } + + DBG("Starting tracing for session %s", session_name); + + ret = lttng_start_tracing(session_name); + if (ret < 0) { + goto free_name; + } + + MSG("Tracing started for session %s", session_name); + +free_name: + free(session_name); +error: + return ret; +} + +/* + * cmd_start + * + * The 'start ' first level command + */ +int cmd_start(int argc, const char **argv) +{ + int opt, ret; + static poptContext pc; + + pc = poptGetContext(NULL, argc, argv, long_options, 0); + poptReadDefaultConfig(pc, 0); + + while ((opt = poptGetNextOpt(pc)) != -1) { + switch (opt) { + case OPT_HELP: + usage(stderr); + ret = CMD_SUCCESS; + goto end; + default: + usage(stderr); + ret = CMD_UNDEFINED; + goto end; + } + } + + opt_session_name = (char*) poptGetArg(pc); + + ret = start_tracing(); + +end: + return ret; +} diff --git a/lttng/commands/stop.c b/lttng/commands/stop.c new file mode 100644 index 000000000..0245296a4 --- /dev/null +++ b/lttng/commands/stop.c @@ -0,0 +1,123 @@ +/* + * 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 "cmd.h" +#include "config.h" +#include "utils.h" + +static char *opt_session_name; + +enum { + OPT_HELP = 1, +}; + +static struct poptOption long_options[] = { + /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ + {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0}, + {0, 0, 0, 0, 0, 0, 0} +}; + +/* + * usage + */ +static void usage(FILE *ofp) +{ + fprintf(ofp, "usage: lttng stop [options] [NAME]\n"); + fprintf(ofp, "\n"); + fprintf(ofp, "Where NAME is an optional session name. If not specified, lttng will\n"); + fprintf(ofp, "get it from the configuration directory (.lttng).\n"); + fprintf(ofp, "\n"); + fprintf(ofp, " -h, --help Show this help\n"); + fprintf(ofp, "\n"); +} + +/* + * stop_tracing + * + * Start tracing for all trace of the session. + */ +static int stop_tracing(void) +{ + int ret = CMD_SUCCESS; + char *session_name; + + if (opt_session_name == NULL) { + session_name = get_session_name(); + if (session_name == NULL) { + ret = CMD_ERROR; + goto error; + } + } else { + session_name = opt_session_name; + } + + ret = lttng_stop_tracing(session_name); + if (ret < 0) { + goto free_name; + } + + MSG("Tracing stopped for session %s", session_name); + +free_name: + free(session_name); +error: + return ret; +} + +/* + * cmd_stop + * + * The 'stop ' first level command + */ +int cmd_stop(int argc, const char **argv) +{ + int opt, ret; + static poptContext pc; + + pc = poptGetContext(NULL, argc, argv, long_options, 0); + poptReadDefaultConfig(pc, 0); + + while ((opt = poptGetNextOpt(pc)) != -1) { + switch (opt) { + case OPT_HELP: + usage(stderr); + ret = CMD_SUCCESS; + goto end; + default: + usage(stderr); + ret = CMD_UNDEFINED; + goto end; + } + } + + opt_session_name = (char*) poptGetArg(pc); + + ret = stop_tracing(); + +end: + return ret; +} diff --git a/lttng/config.c b/lttng/config.c new file mode 100644 index 000000000..224bd1a1b --- /dev/null +++ b/lttng/config.c @@ -0,0 +1,301 @@ +/* + * 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 "config.h" +#include "lttngerr.h" + +/* + * get_config_file_path + * + * Return the path with '/CONFIG_FILENAME' added to it. + */ +static char *get_config_file_path(char *path) +{ + int ret; + char *file_path; + + ret = asprintf(&file_path, "%s/%s", path, CONFIG_FILENAME); + if (ret < 0) { + ERR("Fail allocating config file path"); + } + + return file_path; +} + +/* + * open_config + * + * Return an open FILE pointer to the config file. + */ +static FILE *open_config(char *path, const char *mode) +{ + FILE *fp = NULL; + char *file_path; + + file_path = get_config_file_path(path); + if (file_path == NULL) { + goto error; + } + + fp = fopen(file_path, mode); + if (fp == NULL) { + perror("config file"); + goto error; + } + +error: + if (file_path) { + free(file_path); + } + return fp; +} + +/* + * create_config_file + * + * Create the empty config file a the path. + */ +static int create_config_file(char *path) +{ + int ret; + FILE *fp; + + fp = open_config(path, "w+"); + if (fp == NULL) { + ERR("Unable to create config file"); + ret = -1; + goto error; + } + + ret = fclose(fp); + +error: + return ret; +} + +/* + * create_config_dir + * + * Create the empty config dir. + */ +static int create_config_dir(char *path) +{ + int ret; + + /* Create session directory .lttng */ + ret = mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP); + if (ret < 0) { + if (errno == EEXIST) { + ERR("Session already exist at %s", path); + } else { + perror("mkdir config"); + ERR("Couldn't init config directory at %s", path); + } + ret = -errno; + goto error; + } + +error: + return ret; +} + +/* + * write_config + * + * Append data to the config file in file_path + */ +static void write_config(char *file_path, size_t size, char *data) +{ + FILE *fp; + + fp = open_config(file_path, "a"); + if (fp == NULL) { + goto error; + } + + /* Write session name into config file */ + fwrite(data, size, 1, fp); + fclose(fp); + +error: + return; +} + +/* + * config_get_default_path + * + * Return the default path to config directory which is the current working + * directory. User must free() the returned allocated string. + */ +char *config_get_default_path(void) +{ + char *alloc_path; + + alloc_path = getcwd(NULL, 0); + if (alloc_path == NULL) { + perror("getcwd"); + } + + return alloc_path; +} + +/* + * config_destroy + * + * Destroy directory config and file config. + */ +void config_destroy(char *path) +{ + int ret; + char *config_path; + + config_path = get_config_file_path(path); + + ret = remove(config_path); + if (ret < 0) { + perror("remove config file"); + } + + ret = rmdir(path); + if (ret < 0) { + perror("rmdir config dir"); + } + + free(config_path); +} + +/* + * config_read_session_name + * + * Return sesson name from the config file. + */ +char *config_read_session_name(char *path) +{ + int ret; + FILE *fp; + char var[NAME_MAX], *session_name; + + fp = open_config(path, "r"); + if (fp == NULL) { + ERR("Can't find valid lttng config in %s", path); + goto error; + } + + session_name = malloc(NAME_MAX); + while (!feof(fp)) { + if ((ret = fscanf(fp, "%[^'=']=%s\n", var, session_name)) != 2) { + if (ret == -1) { + ERR("Missing session=NAME in config file."); + goto error; + } + continue; + } + + if (strcmp(var, "session") == 0) { + goto found; + } + } + + fclose(fp); + +error: + return NULL; + +found: + fclose(fp); + return session_name; + +} + +/* + * config_add_session_name + * + * Write session name option to the config file. + */ +int config_add_session_name(char *path, char *name) +{ + int ret; + char session_name[NAME_MAX]; + + ret = snprintf(session_name, NAME_MAX, "session=%s\n", name); + if (ret < 0) { + goto error; + } + + write_config(path, ret, session_name); + ret = 0; + +error: + return ret; +} + +/* + * config_generate_dir_path + * + * Return allocated path string to path/CONFIG_DIRNAME. + */ +char *config_generate_dir_path(char *path) +{ + int ret; + char *new_path; + + ret = asprintf(&new_path, "%s/%s", path, CONFIG_DIRNAME); + if (ret < 0) { + perror("config path problem"); + goto error; + } + +error: + return new_path; +} + +/* + * config_init + * + * Init configuration directory and file. + */ +int config_init(char *path) +{ + int ret; + + /* Create config directory (.lttng) */ + ret = create_config_dir(path); + if (ret < 0) { + goto error; + } + + /* Create default config file */ + ret = create_config_file(path); + if (ret < 0) { + goto error; + } + + DBG("Init config session in %s", path); + +error: + return ret; +} diff --git a/lttng/lttng.c b/lttng/lttng.c index b523960c3..09e336803 100644 --- a/lttng/lttng.c +++ b/lttng/lttng.c @@ -17,636 +17,198 @@ */ #define _GNU_SOURCE -#include -#include #include -#include -#include +#include #include #include #include -#include -#include -#include #include #include +#include "cmd.h" +#include "config.h" #include "lttngerr.h" -#include "options.h" /* Variables */ static char *progname; -static char *session_name; -static uuid_t current_uuid; -static int auto_session; -static int auto_trace; - -/* Prototypes */ -static int process_client_opt(void); -static int process_opt_list_apps(void); -static int process_opt_list_sessions(void); -static int process_opt_list_traces(void); -static int process_opt_kernel_list_events(void); -static int process_opt_create_session(void); -static int process_kernel_create_trace(void); -static int process_opt_kernel_event(void); -static int process_kernel_start_trace(void); -static int set_session_uuid(void); -static void sighandler(int sig); -static int set_signal_handler(void); -static int validate_options(void); -static char *get_cmdline_by_pid(pid_t pid); -static void set_opt_session_info(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; - - set_opt_session_info(); - - if (opt_list_apps) { - ret = process_opt_list_apps(); - if (ret < 0) { - goto end; - } - goto error; - } - - if (opt_list_session) { - ret = process_opt_list_sessions(); - if (ret < 0) { - goto end; - } - goto error; - } - - if (opt_list_events) { - if (opt_trace_kernel) { - ret = process_opt_kernel_list_events(); - if (ret < 0) { - goto end; - } - } else if (opt_trace_pid != 0) { - // TODO - } - goto error; - } - - /* Session creation or auto session set on */ - if (auto_session || opt_create_session) { - DBG("Creating a new session"); - ret = process_opt_create_session(); - if (ret < 0) { - goto end; - } - } - - ret = set_session_uuid(); - if (ret < 0) { - ERR("Session %s not found", opt_session_name); - goto error; - } - - if (opt_destroy_session) { - ret = lttng_destroy_session(¤t_uuid); - if (ret < 0) { - goto end; - } - MSG("Session %s destroyed.", opt_session_name); - } - - if (opt_list_traces) { - ret = process_opt_list_traces(); - if (ret < 0) { - goto end; - } - } - - /* - * Action on traces (kernel or/and userspace). - */ - - if (opt_trace_kernel) { - if (auto_trace || opt_create_trace) { - DBG("Creating a kernel trace"); - ret = process_kernel_create_trace(); - if (ret < 0) { - goto end; - } - } - - if (opt_event_list != NULL || opt_enable_all_event) { - ret = process_opt_kernel_event(); - if (ret < 0) { - goto end; - } - } - - if (auto_trace || opt_start_trace) { - DBG("Starting kernel tracing"); - ret = process_kernel_start_trace(); - if (ret < 0) { - goto end; - } - } - - if (opt_stop_trace) { - DBG("Stopping kernel tracing"); - ret = lttng_kernel_stop_tracing(); - if (ret < 0) { - goto end; - } - } - } - - if (opt_trace_pid != 0) { - if (auto_trace || opt_create_trace) { - DBG("Create a userspace trace for pid %d", opt_trace_pid); - ret = lttng_ust_create_trace(opt_trace_pid); - if (ret < 0) { - goto end; - } - MSG("Trace created successfully!"); - } - - if (auto_trace || opt_start_trace) { - DBG("Start trace for pid %d", opt_trace_pid); - ret = lttng_ust_start_trace(opt_trace_pid); - if (ret < 0) { - goto end; - } - MSG("Trace started successfully!"); - } else if (opt_stop_trace) { - DBG("Stop trace for pid %d", opt_trace_pid); - ret = lttng_ust_stop_trace(opt_trace_pid); - if (ret < 0) { - goto end; - } - MSG("Trace stopped successfully!"); - } - - } - - return 0; - -end: - ERR("%s", lttng_get_readable_code(ret)); -error: /* fall through */ - return ret; -} - -/* - * process_kernel_start_trace - * - * Start a kernel trace. - */ -static int process_kernel_start_trace(void) +int opt_quiet; +int opt_verbose; +static int opt_no_sessiond; +static char *opt_sessiond_path; + +enum { + OPT_NO_SESSIOND, + OPT_SESSION_PATH, +}; + +/* Getopt options. No first level command. */ +static struct option long_options[] = { + {"help", 0, NULL, 'h'}, + {"group", 1, NULL, 'g'}, + {"verbose", 0, NULL, 'v'}, + {"quiet", 0, NULL, 'q'}, + {"no-sessiond", 0, NULL, OPT_NO_SESSIOND}, + {"sessiond-path", 1, NULL, OPT_SESSION_PATH}, + {NULL, 0, NULL, 0} +}; + +/* First level command */ +static struct cmd_struct commands[] = { + { "list", cmd_list}, + { "create", cmd_create}, + { "destroy", cmd_destroy}, + { "add-channel", cmd_add_channel}, + { "start", cmd_start}, + { "stop", cmd_stop}, + { "enable-event", cmd_enable_events}, + { NULL, NULL} /* Array closure */ +}; + +static void usage(FILE *ofp) { - int ret; - - ret = lttng_kernel_create_stream(); - if (ret < 0) { - goto error; - } - - ret = lttng_kernel_start_tracing(); - if (ret < 0) { - goto error; - } - - MSG("Kernel tracing started"); - - return 0; - -error: - return ret; + fprintf(ofp, "LTTng Trace Control " VERSION"\n\n"); + fprintf(ofp, "usage: lttng [options] \n"); + fprintf(ofp, "\n"); + fprintf(ofp, "Options:\n"); + fprintf(ofp, " -h, --help Show this help\n"); + fprintf(ofp, " -g, --group NAME Unix tracing group name. (default: tracing)\n"); + fprintf(ofp, " -v, --verbose Verbose mode\n"); + fprintf(ofp, " -q, --quiet Quiet mode\n"); + fprintf(ofp, " --no-sessiond Don't spawn a session daemon\n"); + fprintf(ofp, " --sessiond-path Session daemon full path\n"); + fprintf(ofp, "\n"); + fprintf(ofp, "Commands:\n"); + fprintf(ofp, " add-channel Add channel to tracer\n"); + fprintf(ofp, " create Create tracing session\n"); + fprintf(ofp, " destroy Teardown tracing session\n"); + fprintf(ofp, " enable-event Enable tracing event\n"); + fprintf(ofp, " disable-event Disable tracing event\n"); + fprintf(ofp, " list List possible tracing options\n"); + fprintf(ofp, " start Start tracing\n"); + fprintf(ofp, " stop Stop tracing\n"); + fprintf(ofp, " version Show version information\n"); + fprintf(ofp, "\n"); + fprintf(ofp, "Please see the lttng(1) man page for full documentation.\n"); + fprintf(ofp, "See http://lttng.org for updates, bug reports and news.\n"); } /* - * process_kernel_create_trace - * - * Create a kernel trace. + * clean_exit */ -static int process_kernel_create_trace(void) +static void clean_exit(int code) { - int ret; - - /* Setup kernel session */ - ret = lttng_kernel_create_session(); - if (ret < 0) { - goto error; - } - - /* Create an empty channel (with no event) */ - ret = lttng_kernel_create_channel(); - if (ret < 0) { - goto error; - } - - /* Opening metadata for session */ - ret = lttng_kernel_open_metadata(); - if (ret < 0) { - goto error; - } - - return 0; - -error: - return ret; + DBG("Clean exit"); + exit(code); } /* - * process_opt_kernel_list_events + * sighandler * - * Ask for all trace events in the kernel and pretty print them. + * Signal handler for the daemon */ -static int process_opt_kernel_list_events(void) +static void sighandler(int sig) { - int ret, pos, size; - char *event_list, *event, *ptr; - - DBG("Getting all tracing events"); - - ret = lttng_kernel_list_events(&event_list); - if (ret < 0) { - ERR("Unable to list events."); - return ret; - } - - MSG("Kernel tracepoints:\n-------------"); - - ptr = event_list; - while ((size = sscanf(ptr, "event { name = %m[^;]; };%n\n", &event, &pos)) == 1) { - MSG(" - %s", event); - /* Move pointer to the next line */ - ptr += pos + 1; - free(event); + switch (sig) { + case SIGTERM: + DBG("SIGTERM catched"); + clean_exit(EXIT_FAILURE); + break; + case SIGCHLD: + /* Notify is done */ + DBG("SIGCHLD catched"); + break; + default: + DBG("Unknown signal %d catched", sig); + break; } - free(event_list); - - return 0; + return; } /* - * process_opt_kernel_event + * set_signal_handler * - * Enable kernel event from the command line list given. + * Setup signal handler for SIGCHLD and SIGTERM. */ -static int process_opt_kernel_event(void) +static int set_signal_handler(void) { - int ret; - char *event_name; - - if (opt_enable_all_event) { - ret = lttng_kernel_enable_event(NULL); - if (ret < 0) { - ERR("%s", lttng_get_readable_code(ret)); - } else { - MSG("All kernel event enabled"); - } + int ret = 0; + struct sigaction sa; + sigset_t sigset; + if ((ret = sigemptyset(&sigset)) < 0) { + perror("sigemptyset"); goto end; } - event_name = strtok(opt_event_list, ","); - while (event_name != NULL) { - DBG("Enabling kernel event %s", event_name); - ret = lttng_kernel_enable_event(event_name); - if (ret < 0) { - ERR("%s %s", lttng_get_readable_code(ret), event_name); - } else { - MSG("Kernel event %s enabled.", event_name); - } - /* Next event */ - event_name = strtok(NULL, ","); - } - -end: - return 0; -} - -/* - * set_opt_session_info - * - * Setup session_name, current_uuid, short_str_uuid and - * long_str_uuid using the command line options. - */ -static void set_opt_session_info(void) -{ - if (opt_session_name != NULL) { - session_name = strndup(opt_session_name, NAME_MAX); - DBG("Session name set to %s", session_name); - } -} - -/* - * set_session_uuid - * - * Set current session uuid to the current flow of command(s) using the - * session_name. - */ -static int set_session_uuid(void) -{ - int ret, count, i, found = 0; - struct lttng_session *sessions; - - if (!uuid_is_null(current_uuid)) { - lttng_set_current_session_uuid(¤t_uuid); + sa.sa_handler = sighandler; + sa.sa_mask = sigset; + sa.sa_flags = 0; + if ((ret = sigaction(SIGCHLD, &sa, NULL)) < 0) { + perror("sigaction"); goto end; } - count = lttng_list_sessions(&sessions); - if (count < 0) { - ret = count; - goto error; - } - - for (i = 0; i < count; i++) { - if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) { - lttng_set_current_session_uuid(&sessions[i].uuid); - uuid_copy(current_uuid, sessions[i].uuid); - found = 1; - break; - } - } - - free(sessions); - - if (!found) { - return -1; + if ((ret = sigaction(SIGTERM, &sa, NULL)) < 0) { + perror("sigaction"); + goto end; } end: - DBG("Session UUID set"); - return 0; - -error: - return ret; -} - -/* - * process_opt_list_traces - * - * Get list of all traces for a specific session uuid. - */ -static int process_opt_list_traces(void) -{ - int ret, i; - struct lttng_trace *traces; - - ret = lttng_list_traces(¤t_uuid, &traces); - DBG("Number of traces to list %d", ret); - if (ret < 0) { - goto error; - } - - /* No traces */ - if (ret == 0) { - MSG("No traces found."); - goto error; - } - - MSG("Userspace traces:"); - for (i = 0; i < ret; i++) { - if (traces[i].type == USERSPACE) { - MSG("\t%d) %s (pid: %d): %s", - i, traces[i].name, traces[i].pid, - get_cmdline_by_pid(traces[i].pid)); - } else { - break; - } - } - - MSG("Kernel traces:"); - for (;i < ret; i++) { - if (traces[i].type == KERNEL) { - MSG("\t%d) %s", i, traces[i].name); - } - } - - free(traces); - -error: - return ret; -} - -/* - * process_opt_create_session - * - * Create a new session using the name pass - * to the command line. - */ -static int process_opt_create_session(void) -{ - int ret; - char name[NAME_MAX]; - time_t rawtime; - struct tm *timeinfo; - - /* Auto session name creation */ - if (opt_session_name == NULL) { - time(&rawtime); - timeinfo = localtime(&rawtime); - strftime(name, sizeof(name), "auto-%Y%m%d-%H%M%S", timeinfo); - session_name = strndup(name, sizeof(name)); - DBG("Auto session name set to %s", session_name); - } - - ret = lttng_create_session(session_name); - if (ret < 0) { - goto error; - } - - MSG("Session created: %s", session_name); - -error: - return ret; -} - -/* - * process_opt_list_sessions - * - * Get the list of available sessions from - * the session daemon and print it to user. - */ -static int process_opt_list_sessions(void) -{ - int ret, count, i; - struct lttng_session *sessions; - - count = lttng_list_sessions(&sessions); - DBG("Session count %d", count); - if (count < 0) { - ret = count; - goto error; - } - - MSG("Available sessions (UUIDs):"); - for (i = 0; i < count; i++) { - MSG(" %d) %s", i+1, sessions[i].name); - } - - free(sessions); - MSG("\nTo select a session, use -s, --session UUID."); - - return 0; - -error: return ret; } /* - * process_opt_list_apps + * handle_command * - * Get the UST traceable pid list and print - * them to the user. - */ -static int process_opt_list_apps(void) -{ - int i, ret, count; - pid_t *pids; - char *cmdline; - - count = lttng_ust_list_apps(&pids); - if (count < 0) { - ret = count; - goto error; - } - - MSG("LTTng UST traceable application [name (pid)]:"); - for (i=0; i < count; i++) { - cmdline = get_cmdline_by_pid(pids[i]); - if (cmdline == NULL) { - MSG("\t(not running) (%d)", pids[i]); - continue; - } - MSG("\t%s (%d)", cmdline, pids[i]); - free(cmdline); - } - - /* Allocated by lttng_ust_list_apps() */ - free(pids); - - return 0; - -error: - return ret; -} - -/* - * get_cmdline_by_pid - * - * Get command line from /proc for a specific pid. + * Handle the full argv list of a first level command. Will find the command + * in the global commands array and call the function callback associated. * - * On success, return an allocated string pointer pointing to - * the proc cmdline. - * On error, return NULL. + * If command not found, return -1 + * else, return function command error code. */ -static char *get_cmdline_by_pid(pid_t pid) +static int handle_command(int argc, char **argv) { - int ret; - FILE *fp; - char *cmdline = NULL; - char path[24]; /* Can't go bigger than /proc/65535/cmdline */ + int i = 0, ret; + struct cmd_struct *cmd; - snprintf(path, sizeof(path), "/proc/%d/cmdline", pid); - fp = fopen(path, "r"); - if (fp == NULL) { + if (*argv == NULL) { + ret = CMD_SUCCESS; goto end; } - /* Caller must free() *cmdline */ - cmdline = malloc(PATH_MAX); - ret = fread(cmdline, 1, PATH_MAX, fp); - fclose(fp); - -end: - return cmdline; -} - -/* - * validate_options - * - * Make sure that all options passed to the command line are compatible with - * each others. - * - * On error, return -1 - * On success, return 0 - */ -static int validate_options(void) -{ - /* If listing options, jump validation */ - if (opt_list_apps || opt_list_session) { - goto end; - } - /* Conflicting command */ - if (opt_start_trace && opt_stop_trace) { - ERR("Can't use --start and --stop together."); - goto error; - /* If no PID specified and trace_kernel is off */ - } else if ((opt_trace_pid == 0 && !opt_trace_kernel) && - (opt_create_trace || opt_start_trace || opt_stop_trace || opt_destroy_trace)) { - ERR("Please specify for which tracer (-k or -p PID)."); - goto error; - /* List traces, we need a session name */ - } else if (opt_list_traces && opt_session_name == NULL) { - ERR("Can't use -t without -s, --session option."); - goto error; - /* Can't set event for both kernel and userspace at the same time */ - } else if (opt_event_list != NULL && (opt_trace_kernel && opt_trace_pid)) { - ERR("Please don't use --event for both kernel and userspace.\nOne at a time to enable events."); - goto error; - /* Don't need a trace name for kernel tracig */ - } else if (opt_trace_name != NULL && opt_trace_kernel) { - ERR("For action on a kernel trace, please don't specify a trace name."); - goto error; - } else if (opt_destroy_trace && opt_session_name == NULL) { - ERR("Please specify a session in order to destroy a trace"); - goto error; - } else if (opt_create_trace || opt_destroy_trace) { - /* Both kernel and user-space are denied for these options */ - if (opt_trace_pid != 0 && opt_trace_kernel) { - ERR("Kernel and user-space trace creation and destruction can't be used together."); - goto error; - /* Need a trace name for user-space tracing */ - } else if (opt_trace_name == NULL && opt_trace_pid != 0) { - ERR("Please specify a trace name for user-space tracing"); - goto error; + cmd = &commands[i]; + while (cmd->func != NULL) { + /* Find command */ + if (strcmp(argv[0], cmd->name) == 0) { + ret = cmd->func(argc, (const char**) argv); + switch (ret) { + case CMD_ERROR: + ERR("Command error"); + break; + case CMD_NOT_IMPLEMENTED: + ERR("Options not implemented"); + break; + case CMD_UNDEFINED: + ERR("Undefined command"); + break; + case CMD_FATAL: + ERR("Fatal error"); + break; + } + goto end; } - } else if (opt_stop_trace && opt_trace_pid != 0 && opt_trace_name == NULL) { - ERR("Please specify a trace name for user-space tracing"); - goto error; - } else if (opt_stop_trace && opt_session_name == NULL) { - ERR("Please specify a session to stop tracing"); - goto error; - } - - /* If start trace, auto start tracing */ - if (opt_start_trace || opt_event_list != NULL || opt_enable_all_event) { - DBG("Requesting auto tracing"); - auto_trace = 1; + i++; + cmd = &commands[i]; } - /* If no session, auto create one */ - if (opt_session_name == NULL) { - DBG("Requesting an auto session creation"); - auto_session = 1; - } + /* Command not found */ + ret = -1; end: - return 0; - -error: - return -1; + return ret; } /* @@ -659,7 +221,7 @@ static int spawn_sessiond(char *pathname) int ret = 0; pid_t pid; - MSG("Spawning session daemon"); + MSG("Spawning a session daemon"); pid = fork(); if (pid == 0) { /* @@ -690,13 +252,13 @@ end: } /* - * check_ltt_sessiond + * check_sessiond * * Check if the session daemon is available using * the liblttngctl API for the check. If not, try to * spawn a daemon. */ -static int check_ltt_sessiond(void) +static int check_sessiond(void) { int ret; char *pathname = NULL, *alloc_pathname = NULL; @@ -738,75 +300,83 @@ end: } /* - * set_signal_handler + * parse_args * - * Setup signal handler for SIGCHLD and SIGTERM. + * Parse command line arguments. + * Return 0 if OK, else -1 */ -static int set_signal_handler(void) +static int parse_args(int argc, char **argv) { - int ret = 0; - struct sigaction sa; - sigset_t sigset; + int opt, ret; - if ((ret = sigemptyset(&sigset)) < 0) { - perror("sigemptyset"); - goto end; + if (argc < 2) { + usage(stderr); + clean_exit(EXIT_FAILURE); } - sa.sa_handler = sighandler; - sa.sa_mask = sigset; - sa.sa_flags = 0; - if ((ret = sigaction(SIGCHLD, &sa, NULL)) < 0) { - perror("sigaction"); - goto end; + while ((opt = getopt_long(argc, argv, "+hvqg:", long_options, NULL)) != -1) { + switch (opt) { + case 'h': + usage(stderr); + goto error; + case 'v': + opt_verbose = 1; + break; + case 'q': + opt_quiet = 1; + break; + case 'g': + lttng_set_tracing_group(optarg); + break; + case OPT_NO_SESSIOND: + opt_no_sessiond = 1; + break; + case OPT_SESSION_PATH: + opt_sessiond_path = strdup(optarg); + break; + default: + usage(stderr); + goto error; + } } - if ((ret = sigaction(SIGTERM, &sa, NULL)) < 0) { - perror("sigaction"); - goto end; + /* If both options are specified, quiet wins */ + if (opt_verbose && opt_quiet) { + opt_verbose = 0; } -end: - return ret; -} - -/* - * sighandler - * - * Signal handler for the daemon - */ -static void sighandler(int sig) -{ - switch (sig) { - case SIGTERM: - DBG("SIGTERM catched"); - clean_exit(EXIT_FAILURE); - break; - case SIGCHLD: - /* Notify is done */ - DBG("SIGCHLD catched"); - break; - default: - DBG("Unknown signal %d catched", sig); - break; + /* Spawn session daemon if needed */ + if (opt_no_sessiond == 0 && (check_sessiond() < 0)) { + goto error; } - return; -} + /* No leftovers, print usage and quit */ + if ((argc - optind) == 0) { + usage(stderr); + goto error; + } -/* - * clean_exit - */ -void clean_exit(int code) -{ - DBG("Clean exit"); - if (session_name) { - free(session_name); + /* + * Handle leftovers which is a first level command with the trailing + * options. + */ + ret = handle_command(argc - optind, argv + optind); + if (ret < 0) { + if (ret == -1) { + usage(stderr); + goto error; + } else { + ERR("%s", lttng_get_readable_code(ret)); + } } - exit(code); + return ret; + +error: + return -1; } + /* * main */ @@ -821,48 +391,13 @@ int main(int argc, char *argv[]) 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) { - clean_exit(EXIT_FAILURE); - } - - ret = validate_options(); - if (ret < 0) { - return EXIT_FAILURE; - } - ret = set_signal_handler(); if (ret < 0) { clean_exit(ret); } - 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); - clean_exit(-EPERM); - } - } - - /* Check if the lttng session daemon is running. - * If no, a daemon will be spawned. - */ - if (opt_no_sessiond == 0 && (check_ltt_sessiond() < 0)) { - clean_exit(EXIT_FAILURE); - } - - ret = process_client_opt(); - if (ret < 0) { - clean_exit(ret); - } - - clean_exit(0); + ret = parse_args(argc, argv); + clean_exit(ret); return 0; } diff --git a/lttng/options.c b/lttng/options.c deleted file mode 100644 index a24de7189..000000000 --- a/lttng/options.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * 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 "options.h" - -/* Option variables */ -char *opt_event_list; -char *opt_tracing_group; -char *opt_sessiond_path; -char *opt_session_name; -char *opt_trace_name; -int opt_destroy_trace; -int opt_create_session; -int opt_destroy_session; -int opt_trace_kernel; -int opt_quiet; -int opt_verbose; -int opt_list_apps; -int opt_list_events; -int opt_no_sessiond; -int opt_list_session; -int opt_list_traces; -int opt_create_trace; -int opt_start_trace; -int opt_stop_trace; -int opt_enable_event; -int opt_enable_all_event; -int opt_disable_event; -int opt_kern_create_channel; -pid_t opt_trace_pid; - -enum { - OPT_HELP = 1, - OPT_ENABLE_EVENT, - OPT_DISABLE_EVENT, - OPT_CREATE_SESSION, - OPT_CREATE_TRACE, - OPT_DESTROY_SESSION, - OPT_DESTROY_TRACE, - OPT_START_TRACE, - OPT_STOP_TRACE, -}; - -static struct poptOption long_options[] = { - /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ - {"create-session", 'c', POPT_ARG_STRING, 0, OPT_CREATE_SESSION, 0, 0}, - {"create-trace", 'C', POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, 0, OPT_CREATE_TRACE, 0, 0}, - {"destroy-trace", 'D', POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, 0, OPT_DESTROY_TRACE, 0, 0}, - {"destroy-session", 'd', POPT_ARG_STRING, 0, OPT_DESTROY_SESSION, 0, 0}, - {"disable-event", 0, POPT_ARG_STRING, 0, OPT_DISABLE_EVENT, 0, 0}, - {"enable-event", 'e', POPT_ARG_STRING, 0, OPT_ENABLE_EVENT, 0, 0}, - {"enable-all-event",'a', POPT_ARG_VAL, &opt_enable_all_event, 1, 0, 0}, - {"group", 0, POPT_ARG_STRING, &opt_tracing_group, 0, 0, 0}, - {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0}, - {"kernel", 'k', POPT_ARG_VAL, &opt_trace_kernel, 1, 0, 0}, - {"kern-create-channel",0, POPT_ARG_VAL, &opt_kern_create_channel, 1, 0, 0}, - {"list-apps", 'L', POPT_ARG_VAL, &opt_list_apps, 1, 0, 0}, - {"list-events", 0, POPT_ARG_VAL, &opt_list_events, 1, 0, 0}, - {"list-sessions", 'l', POPT_ARG_VAL, &opt_list_session, 1, 0, 0}, - {"list-traces", 't', POPT_ARG_VAL, &opt_list_traces, 1, 0, 0}, - {"no-kernel", 0, POPT_ARG_VAL, &opt_trace_kernel, 0, 0, 0}, - {"no-sessiond", 0, POPT_ARG_VAL, &opt_no_sessiond, 1, 0, 0}, - {"pid", 'p', POPT_ARG_INT, &opt_trace_pid, 0, 0, 0}, - {"quiet", 'q', POPT_ARG_VAL, &opt_quiet, 1, 0, 0}, - {"session", 's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0}, - {"sessiond-path", 0, POPT_ARG_STRING, &opt_sessiond_path, 0, 0, 0}, - {"start", 0, POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, 0, OPT_START_TRACE, 0, 0}, - {"stop", 0, POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, 0, OPT_STOP_TRACE, 0, 0}, - {"verbose", 'v', POPT_ARG_VAL, &opt_verbose, 1, 0, 0}, - {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, " --no-sessiond Don't spawn a session daemon\n"); - fprintf(ofp, " --sessiond-path Session daemon full path\n"); - fprintf(ofp, " -L, --list-apps List traceable user-space applications\n"); - fprintf(ofp, "\n"); - fprintf(ofp, "Session options:\n"); - fprintf(ofp, " -c, --create-session NAME Create a new session\n"); - fprintf(ofp, " -l, --list-sessions List all available sessions by name\n"); - fprintf(ofp, " -s, --session UUID Specify tracing session using UUID\n"); - fprintf(ofp, " -d, --destroy-session NAME Destroy the session specified by NAME\n"); - fprintf(ofp, " -t, --list-traces List session's traces. Use -s to specify the session\n"); - fprintf(ofp, "\n"); - fprintf(ofp, "Tracing options:\n"); - fprintf(ofp, " -p, --pid PID Specify action on user-space tracer for PID\n"); - fprintf(ofp, " -k, --kernel Specify action on kernel tracer\n"); - fprintf(ofp, " --list-events List all available tracing events\n"); - fprintf(ofp, " -e, --enable-event LIST Enable tracing event (support marker and tracepoint)\n"); - fprintf(ofp, " -a, --enable-all-event Enable all tracing event\n"); - fprintf(ofp, " --disable-event LIST Disable tracing event (support marker and tracepoint)\n"); - fprintf(ofp, " -C, --create-trace Create a trace. Allocate and setup a trace\n"); - fprintf(ofp, " -D, --destroy-trace [NAME] Destroy a trace. Use NAME to identify user-space trace\n"); - fprintf(ofp, " --start [NAME] Start tracing. Use NAME to identify user-space trace\n"); - fprintf(ofp, " --stop [NAME] Stop tracing. Use NAME to identify user-space trace\n"); - fprintf(ofp, "\n"); - fprintf(ofp, "Kernel tracing options:\n"); - fprintf(ofp, " --kern-create-channel Create a kernel channel\n"); - fprintf(ofp, "\n"); - fprintf(ofp, "User-space tracing options:\n"); - fprintf(ofp, "\n"); - fprintf(ofp, "Please see the lttng(1) man page for full documentation.\n"); - fprintf(ofp, "See http://lttng.org for updates, bug reports and news.\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; - - /* If no options, fail */ - if (argc < 2) { - return -1; - } - - pc = poptGetContext(NULL, 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; - case OPT_CREATE_SESSION: - opt_create_session = 1; - opt_session_name = poptGetOptArg(pc); - break; - case OPT_DESTROY_SESSION: - opt_destroy_session = 1; - opt_session_name = poptGetOptArg(pc); - break; - case OPT_ENABLE_EVENT: - opt_enable_event = 1; - opt_event_list = poptGetOptArg(pc); - break; - case OPT_DESTROY_TRACE: - opt_destroy_trace = 1; - opt_trace_name = poptGetOptArg(pc); - break; - case OPT_START_TRACE: - opt_start_trace = 1; - opt_trace_name = poptGetOptArg(pc); - break; - case OPT_STOP_TRACE: - opt_stop_trace = 1; - opt_trace_name = poptGetOptArg(pc); - break; - case OPT_CREATE_TRACE: - opt_create_trace = 1; - opt_trace_name = poptGetOptArg(pc); - break; - default: - usage(stderr); - clean_exit(EXIT_FAILURE); - break; - } - } - - if (pc) { - poptFreeContext(pc); - } - - return 0; -} diff --git a/lttng/options.h b/lttng/options.h deleted file mode 100644 index 612043d0a..000000000 --- a/lttng/options.h +++ /dev/null @@ -1,52 +0,0 @@ -/* 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_OPTIONS_H -#define _LTTNG_OPTIONS_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_uuid; -extern char *opt_sessiond_path; -extern char *opt_session_name; -extern char *opt_event_list; -extern char *opt_trace_name; -extern int opt_destroy_trace; -extern int opt_enable_event; -extern int opt_enable_all_event; -extern int opt_disable_event; -extern int opt_destroy_session; -extern int opt_create_session; -extern int opt_kern_create_channel; -extern int opt_list_apps; -extern int opt_list_events; -extern int opt_no_sessiond; -extern int opt_list_session; -extern int opt_list_traces; -extern int opt_create_trace; -extern int opt_start_trace; -extern int opt_stop_trace; -extern pid_t opt_trace_pid; - -#endif /* _LTTNG_OPTIONS_H */ diff --git a/lttng/utils.c b/lttng/utils.c new file mode 100644 index 000000000..b05fd2283 --- /dev/null +++ b/lttng/utils.c @@ -0,0 +1,103 @@ +/* + * 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. + */ + +#include + +#include + +#include "config.h" + +/* + * get_config_file_path + * + * Return absolute path to the configuration file. + */ +char *get_config_file_path(void) +{ + char *alloc_path, *path = NULL; + + /* Get path to config directory */ + alloc_path = config_get_default_path(); + if (alloc_path == NULL) { + goto error; + } + + /* Get path to config file */ + path = config_generate_dir_path(alloc_path); + if (path == NULL) { + goto free_alloc_path; + } + +free_alloc_path: + free(alloc_path); +error: + return path; +} + +/* + * get_session_name + * + * Return allocated string with the session name found in the config + * directory. + */ +char *get_session_name(void) +{ + char *path, *session_name = NULL; + + /* Get path to config file */ + path = get_config_file_path(); + if (path == NULL) { + goto error; + } + + /* Get session name from config */ + session_name = config_read_session_name(path); + if (session_name == NULL) { + goto free_path; + } + +free_path: + free(path); +error: + return session_name; +} + +/* + * set_session_name + * + * Get session name and set it for the lttng control lib. + */ +int set_session_name(void) +{ + int ret; + char *session_name; + + session_name = get_session_name(); + if (session_name == NULL) { + ret = -1; + goto error; + } + + lttng_set_session_name(session_name); + free(session_name); + + ret = 0; + +error: + return ret; +} diff --git a/lttng/utils.h b/lttng/utils.h new file mode 100644 index 000000000..90f7f46b1 --- /dev/null +++ b/lttng/utils.h @@ -0,0 +1,26 @@ +/* + * 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_UTILS_H +#define _LTTNG_UTILS_H + +char *get_config_file_path(void); +char *get_session_name(void); +int set_session_name(void); + +#endif /* _LTTNG_UTILS_H */ -- 2.34.1