*/
#define _GNU_SOURCE
+#define _LGPL_SOURCE
#include <assert.h>
#include <inttypes.h>
#include <string.h>
#include <common/defaults.h>
#include <common/error.h>
#include <common/config/config.h>
-#include <common/config/config-session-internal.h>
#include <common/utils.h>
#include <common/runas.h>
#include <lttng/save-internal.h>
#include "save.h"
#include "session.h"
+#include "syscall.h"
#include "trace-ust.h"
static
case LTTNG_UST_CONTEXT_PTHREAD_ID:
context_type_string = config_event_context_pthread_id;
break;
+ case LTTNG_UST_CONTEXT_PERF_THREAD_COUNTER:
+ /*
+ * Error, should not be stored in the XML, perf contexts
+ * are stored as a node of type event_perf_context_type.
+ */
default:
context_type_string = NULL;
+ break;
}
return context_type_string;
}
switch (event->event->instrumentation) {
+ case LTTNG_KERNEL_SYSCALL:
case LTTNG_KERNEL_FUNCTION:
ret = config_writer_open_element(writer,
config_element_function_attributes);
return ret;
}
+static
+int save_kernel_syscall(struct config_writer *writer,
+ struct ltt_kernel_channel *kchan)
+{
+ int ret, i;
+ ssize_t count;
+ struct lttng_event *events = NULL;
+
+ assert(writer);
+ assert(kchan);
+
+ count = syscall_list_channel(kchan, &events, 0);
+ if (!count) {
+ /* No syscalls, just gracefully return. */
+ ret = 0;
+ goto end;
+ }
+
+ for (i = 0; i < count; i++) {
+ struct ltt_kernel_event *kevent;
+
+ /* Create a temporary kevent in order to save it. */
+ kevent = trace_kernel_create_event(&events[i]);
+ if (!kevent) {
+ ret = -ENOMEM;
+ goto end;
+ }
+ /* Init list in order so the destroy call can del the node. */
+ CDS_INIT_LIST_HEAD(&kevent->list);
+
+ ret = save_kernel_event(writer, kevent);
+ trace_kernel_destroy_event(kevent);
+ if (ret) {
+ goto end;
+ }
+ }
+
+ /* Everything went well */
+ ret = 0;
+
+end:
+ free(events);
+ return ret;
+}
+
static
int save_kernel_events(struct config_writer *writer,
- struct ltt_kernel_event_list *event_list)
+ struct ltt_kernel_channel *kchan)
{
int ret;
struct ltt_kernel_event *event;
goto end;
}
- cds_list_for_each_entry(event, &event_list->head, list) {
+ cds_list_for_each_entry(event, &kchan->events_list.head, list) {
ret = save_kernel_event(writer, event);
if (ret) {
goto end;
}
}
+ /* Save syscalls if any. */
+ ret = save_kernel_syscall(writer, kchan);
+ if (ret) {
+ goto end;
+ }
+
/* /events */
ret = config_writer_close_element(writer);
if (ret) {
return ret;
}
+/* TODO: save/restore tracker pid */
+
static
int save_kernel_context(struct config_writer *writer,
struct lttng_kernel_context *ctx)
goto end;
}
- ret = config_writer_open_element(writer, config_element_contexts);
- if (ret) {
- ret = LTTNG_ERR_SAVE_IO_FAIL;
- goto end;
- }
-
ret = config_writer_open_element(writer, config_element_context);
if (ret) {
ret = LTTNG_ERR_SAVE_IO_FAIL;
goto end;
}
- if (ctx->ctx == LTTNG_KERNEL_CONTEXT_PERF_COUNTER) {
+ if (ctx->ctx == LTTNG_KERNEL_CONTEXT_PERF_CPU_COUNTER) {
ret = config_writer_open_element(writer, config_element_perf);
if (ret) {
ret = LTTNG_ERR_SAVE_IO_FAIL;
goto end;
}
+end:
+ return ret;
+}
+
+static
+int save_kernel_contexts(struct config_writer *writer,
+ struct ltt_kernel_channel *kchan)
+{
+ int ret;
+ struct ltt_kernel_context *ctx;
+
+ if (cds_list_empty(&kchan->ctx_list)) {
+ ret = 0;
+ goto end;
+ }
+
+ ret = config_writer_open_element(writer, config_element_contexts);
+ if (ret) {
+ ret = LTTNG_ERR_SAVE_IO_FAIL;
+ goto end;
+ }
+
+ cds_list_for_each_entry(ctx, &kchan->ctx_list, list) {
+ ret = save_kernel_context(writer, &ctx->ctx);
+ if (ret) {
+ goto end;
+ }
+ }
+
/* /contexts */
ret = config_writer_close_element(writer);
if (ret) {
cds_list_for_each_entry(ctx, ctx_list, list) {
const char *context_type_string;
- context_type_string = get_ust_context_type_string(ctx->ctx.ctx);
- if (!context_type_string) {
- ERR("Unsupported UST context type.")
- ret = LTTNG_ERR_INVALID;
- goto end;
- }
ret = config_writer_open_element(writer,
config_element_context);
goto end;
}
- ret = config_writer_write_element_string(writer,
- config_element_type, context_type_string);
- if (ret) {
- ret = LTTNG_ERR_SAVE_IO_FAIL;
- goto end;
+ if (ctx->ctx.ctx == LTTNG_UST_CONTEXT_PERF_THREAD_COUNTER) {
+ /* Perf contexts are saved as event_perf_context_type */
+ ret = config_writer_open_element(writer,
+ config_element_perf);
+ if (ret) {
+ ret = LTTNG_ERR_SAVE_IO_FAIL;
+ goto end;
+ }
+
+ ret = config_writer_write_element_unsigned_int(writer,
+ config_element_type,
+ ctx->ctx.u.perf_counter.type);
+ if (ret) {
+ ret = LTTNG_ERR_SAVE_IO_FAIL;
+ goto end;
+ }
+
+ ret = config_writer_write_element_unsigned_int(writer,
+ config_element_config,
+ ctx->ctx.u.perf_counter.config);
+ if (ret) {
+ ret = LTTNG_ERR_SAVE_IO_FAIL;
+ goto end;
+ }
+
+ ret = config_writer_write_element_string(writer,
+ config_element_name,
+ ctx->ctx.u.perf_counter.name);
+ if (ret) {
+ ret = LTTNG_ERR_SAVE_IO_FAIL;
+ goto end;
+ }
+
+ /* /perf */
+ ret = config_writer_close_element(writer);
+ if (ret) {
+ ret = LTTNG_ERR_SAVE_IO_FAIL;
+ goto end;
+ }
+ } else {
+ /* Save context as event_context_type_type */
+ context_type_string = get_ust_context_type_string(
+ ctx->ctx.ctx);
+ if (!context_type_string) {
+ ERR("Unsupported UST context type.")
+ ret = LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ ret = config_writer_write_element_string(writer,
+ config_element_type, context_type_string);
+ if (ret) {
+ ret = LTTNG_ERR_SAVE_IO_FAIL;
+ goto end;
+ }
}
/* /context */
goto end;
}
- ret = save_kernel_events(writer, &kchan->events_list);
+ ret = save_kernel_events(writer, kchan);
if (ret) {
goto end;
}
- ret = save_kernel_context(writer, kchan->ctx);
+ ret = save_kernel_contexts(writer, kchan);
if (ret) {
goto end;
}
static
int save_ust_session(struct config_writer *writer,
- struct ltt_session *session, int save_jul)
+ struct ltt_session *session, int save_agent)
{
int ret;
struct ltt_ust_channel *ust_chan;
assert(session);
ret = config_writer_write_element_string(writer, config_element_type,
- save_jul ? config_domain_type_jul : config_domain_type_ust);
+ save_agent ? config_domain_type_jul : config_domain_type_ust);
if (ret) {
ret = LTTNG_ERR_SAVE_IO_FAIL;
goto end;
rcu_read_lock();
cds_lfht_for_each_entry(session->ust_session->domain_global.channels->ht,
&iter.iter, node, node) {
- int jul_channel;
+ int agent_channel;
ust_chan = caa_container_of(node, struct ltt_ust_channel, node);
- jul_channel = !strcmp(DEFAULT_JUL_CHANNEL_NAME, ust_chan->name);
- if (!(save_jul ^ jul_channel)) {
+ agent_channel = !strcmp(DEFAULT_JUL_CHANNEL_NAME, ust_chan->name) ||
+ !strcmp(DEFAULT_LOG4J_CHANNEL_NAME, ust_chan->name) ||
+ !strcmp(DEFAULT_PYTHON_CHANNEL_NAME, ust_chan->name);
+ if (!(save_agent ^ agent_channel)) {
ret = save_ust_channel(writer, ust_chan, session->ust_session);
if (ret) {
rcu_read_unlock();
}
if (session->ust_session) {
+ unsigned long agent_count;
+
ret = config_writer_open_element(writer,
config_element_domain);
if (ret) {
ret = LTTNG_ERR_SAVE_IO_FAIL;
goto end;
}
- }
- if (session->ust_session &&
- session->ust_session->domain_jul.being_used) {
- ret = config_writer_open_element(writer,
- config_element_domain);
- if (ret) {
- ret = LTTNG_ERR_SAVE_IO_FAIL;
- goto end;
- }
+ rcu_read_lock();
+ agent_count =
+ lttng_ht_get_count(session->ust_session->agents);
+ rcu_read_unlock();
- ret = save_ust_session(writer, session, 1);
- if (ret) {
- goto end;
- }
+ if (agent_count > 0) {
+ ret = config_writer_open_element(writer,
+ config_element_domain);
+ if (ret) {
+ ret = LTTNG_ERR_SAVE_IO_FAIL;
+ goto end;
+ }
- /* /domain */
- ret = config_writer_close_element(writer);
- if (ret) {
- ret = LTTNG_ERR_SAVE_IO_FAIL;
- goto end;
+ ret = save_ust_session(writer, session, 1);
+ if (ret) {
+ goto end;
+ }
+
+ /* /domain */
+ ret = config_writer_close_element(writer);
+ if (ret) {
+ ret = LTTNG_ERR_SAVE_IO_FAIL;
+ goto end;
+ }
}
}
+ if (session->ust_session) {
+ }
+
/* /domains */
ret = config_writer_close_element(writer);
if (ret) {
ret = !output->dst.net.control_isset ?
LTTNG_ERR_URL_CTRL_MISS :
LTTNG_ERR_URL_DATA_MISS;
+ free(uri);
goto end;
}
struct lttng_save_session_attr *attr, lttng_sock_cred *creds)
{
int ret, fd;
+ unsigned int file_opened = 0; /* Indicate if the file has been opened */
char config_file_path[PATH_MAX];
size_t len;
struct config_writer *writer = NULL;
assert(creds);
session_name_len = strlen(session->name);
+ memset(config_file_path, 0, sizeof(config_file_path));
if (!session_access_ok(session,
LTTNG_SOCK_GET_UID_CRED(creds),
provided_path = lttng_save_session_attr_get_output_url(attr);
if (provided_path) {
+ DBG3("Save session in provided path %s", provided_path);
len = strlen(provided_path);
- if (len > PATH_MAX) {
+ if (len >= sizeof(config_file_path)) {
ret = LTTNG_ERR_SET_URL;
goto end;
}
strncpy(config_file_path, provided_path, len);
} else {
+ ssize_t ret_len;
char *home_dir = utils_get_user_home_dir(
LTTNG_SOCK_GET_UID_CRED(creds));
if (!home_dir) {
goto end;
}
- len = snprintf(config_file_path, PATH_MAX,
+ ret_len = snprintf(config_file_path, sizeof(config_file_path),
DEFAULT_SESSION_HOME_CONFIGPATH, home_dir);
free(home_dir);
- if (len < 0) {
+ if (ret_len < 0) {
PERROR("snprintf save session");
ret = LTTNG_ERR_SET_URL;
goto end;
}
+ len = ret_len;
}
/*
- * Check the path fits in PATH_MAX, including the / followed by trailing
- * .lttng extension and the NULL terminated string.
+ * Check the path fits in the config file path dst including the '/'
+ * followed by trailing .lttng extension and the NULL terminated string.
*/
- if (len + session_name_len + 2 +
- sizeof(DEFAULT_SESSION_CONFIG_FILE_EXTENSION) > PATH_MAX) {
+ if ((len + session_name_len + 2 +
+ sizeof(DEFAULT_SESSION_CONFIG_FILE_EXTENSION))
+ > sizeof(config_file_path)) {
ret = LTTNG_ERR_SET_URL;
goto end;
}
goto end;
}
+ /*
+ * At this point, we know that everything fits in the buffer. Validation
+ * was done just above.
+ */
config_file_path[len++] = '/';
strncpy(config_file_path + len, session->name, session_name_len);
len += session_name_len;
strcpy(config_file_path + len, DEFAULT_SESSION_CONFIG_FILE_EXTENSION);
+ len += sizeof(DEFAULT_SESSION_CONFIG_FILE_EXTENSION);
+ config_file_path[len] = '\0';
if (!access(config_file_path, F_OK) && !attr->overwrite) {
- /* A file with the same name already exists, skip */
+ /* File exists, notify the user since the overwrite flag is off. */
+ ret = LTTNG_ERR_SAVE_FILE_EXIST;
goto end;
}
ret = LTTNG_ERR_SAVE_IO_FAIL;
goto end;
}
+ file_opened = 1;
- writer = config_writer_create(fd);
+ writer = config_writer_create(fd, 1);
if (!writer) {
ret = LTTNG_ERR_NOMEM;
goto end;
}
ret = config_writer_write_element_bool(writer, config_element_started,
- session->enabled);
+ session->active);
if (ret) {
ret = LTTNG_ERR_SAVE_IO_FAIL;
goto end;
goto end;
}
} else {
- ret = config_writer_write_element_signed_int(writer,
+ ret = config_writer_write_element_unsigned_int(writer,
config_element_live_timer_interval, session->live_timer);
if (ret) {
ret = LTTNG_ERR_SAVE_IO_FAIL;
}
if (ret) {
/* Delete file in case of error */
- if (unlink(config_file_path)) {
+ if (file_opened && unlink(config_file_path)) {
PERROR("Unlinking XML session configuration.");
}
}