*
* Linux Trace Toolkit Control Library
*
- * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ * Copyright (C) 2011 EfficiOS Inc.
* Copyright (C) 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
*
* SPDX-License-Identifier: LGPL-2.1-only
#define _LGPL_SOURCE
#include <assert.h>
#include <grp.h>
-#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
+#include <stdint.h>
#include <string.h>
#include <unistd.h>
+#include <common/bytecode/bytecode.h>
#include <common/common.h>
+#include <common/compat/errno.h>
#include <common/compat/string.h>
#include <common/defaults.h>
-#include <common/dynamic-buffer.h>
#include <common/dynamic-array.h>
-#include <common/payload.h>
+#include <common/dynamic-buffer.h>
#include <common/payload-view.h>
+#include <common/payload.h>
#include <common/sessiond-comm/sessiond-comm.h>
#include <common/tracker.h>
#include <common/unix.h>
#include <lttng/channel-internal.h>
#include <lttng/destruction-handle.h>
#include <lttng/endpoint.h>
+#include <lttng/error-query-internal.h>
#include <lttng/event-internal.h>
#include <lttng/health-internal.h>
+#include <lttng/lttng-error.h>
#include <lttng/lttng.h>
#include <lttng/session-descriptor-internal.h>
#include <lttng/session-internal.h>
#include <lttng/trigger/trigger-internal.h>
#include <lttng/userspace-probe-internal.h>
-#include <lttng/lttng-error.h>
-#include "filter/filter-ast.h"
-#include "filter/filter-parser.h"
-#include "filter/filter-bytecode.h"
-#include "filter/memstream.h"
#include "lttng-ctl-helper.h"
-
-#ifdef DEBUG
-static const int print_xml = 1;
-#define dbg_printf(fmt, args...) \
- printf("[debug liblttng-ctl] " fmt, ## args)
-#else
-static const int print_xml = 0;
-#define dbg_printf(fmt, args...) \
-do { \
- /* do nothing but check printf format */ \
- if (0) \
- printf("[debug liblttnctl] " fmt, ## args); \
-} while (0)
-#endif
+#include <common/filter/filter-ast.h>
+#include <common/filter/filter-parser.h>
+#include <common/filter/memstream.h>
#define COPY_DOMAIN_PACKED(dst, src) \
do { \
int lttng_opt_verbose;
int lttng_opt_mi;
-/*
- * Copy string from src to dst and enforce null terminated byte.
- */
-LTTNG_HIDDEN
-void lttng_ctl_copy_string(char *dst, const char *src, size_t len)
-{
- if (src && dst) {
- strncpy(dst, src, len);
- /* Enforce the NULL terminated byte */
- dst[len - 1] = '\0';
- } else if (dst) {
- dst[0] = '\0';
- }
-}
-
/*
* Copy domain to lttcomm_session_msg domain.
*
goto end;
}
- DBG("LSM cmd type : %d", lsm->cmd_type);
+ DBG("LSM cmd type: '%s' (%d)", lttcomm_sessiond_command_str(lsm->cmd_type),
+ lsm->cmd_type);
ret = lttcomm_send_creds_unix_sock(sessiond_socket, lsm,
sizeof(struct lttcomm_session_msg));
{
int ret;
+ assert(len > 0);
+
if (!connected) {
ret = -LTTNG_ERR_NO_SESSIOND;
goto end;
ret = lttcomm_recv_unix_sock(sessiond_socket, buf, len);
if (ret < 0) {
ret = -LTTNG_ERR_FATAL;
+ } else if (ret == 0) {
+ ret = -LTTNG_ERR_NO_SESSIOND;
}
end:
return ret;
}
-static int check_enough_available_memory(size_t num_bytes_requested_per_cpu)
+static enum lttng_error_code check_enough_available_memory(
+ uint64_t num_bytes_requested_per_cpu)
{
int ret;
+ enum lttng_error_code ret_code;
long num_cpu;
- size_t best_mem_info;
- size_t num_bytes_requested_total;
+ uint64_t best_mem_info;
+ uint64_t num_bytes_requested_total;
/*
* Get the number of CPU currently online to compute the amount of
*/
num_cpu = sysconf(_SC_NPROCESSORS_ONLN);
if (num_cpu == -1) {
- goto error;
+ ret_code = LTTNG_ERR_FATAL;
+ goto end;
+ }
+
+ if (num_bytes_requested_per_cpu > UINT64_MAX / (uint64_t) num_cpu) {
+ /* Overflow */
+ ret_code = LTTNG_ERR_OVERFLOW;
+ goto end;
}
- num_bytes_requested_total = num_bytes_requested_per_cpu * num_cpu;
+ num_bytes_requested_total =
+ num_bytes_requested_per_cpu * (uint64_t) num_cpu;
/*
* Try to get the `MemAvail` field of `/proc/meminfo`. This is the most
goto success;
}
-error:
- return -1;
+ /* No valid source of information. */
+ ret_code = LTTNG_ERR_NOMEM;
+ goto end;
+
success:
- return best_mem_info >= num_bytes_requested_total;
+ if (best_mem_info >= num_bytes_requested_total) {
+ ret_code = LTTNG_OK;
+ } else {
+ ret_code = LTTNG_ERR_NOMEM;
+ }
+end:
+ return ret_code;
}
/*
in_tgroup = lttng_check_tracing_group();
}
- if ((uid == 0) || in_tgroup) {
- lttng_ctl_copy_string(sessiond_sock_path,
- DEFAULT_GLOBAL_CLIENT_UNIX_SOCK, sizeof(sessiond_sock_path));
+ if ((uid == 0) || in_tgroup == 1) {
+ const int ret = lttng_strncpy(sessiond_sock_path,
+ DEFAULT_GLOBAL_CLIENT_UNIX_SOCK,
+ sizeof(sessiond_sock_path));
+
+ if (ret) {
+ goto error;
+ }
}
if (uid != 0) {
/* Check error code if OK */
if (llm.ret_code != LTTNG_OK) {
- ret = -llm.ret_code;
+ if (llm.ret_code < LTTNG_OK || llm.ret_code >= LTTNG_ERR_NR) {
+ /* Invalid error code received. */
+ ret = -LTTNG_ERR_UNK;
+ } else {
+ ret = -llm.ret_code;
+ }
goto end;
}
struct lttng_handle *lttng_create_handle(const char *session_name,
struct lttng_domain *domain)
{
+ int ret;
struct lttng_handle *handle = NULL;
handle = zmalloc(sizeof(struct lttng_handle));
}
/* Copy session name */
- lttng_ctl_copy_string(handle->session_name, session_name,
- sizeof(handle->session_name));
+ ret = lttng_strncpy(handle->session_name, session_name ? : "",
+ sizeof(handle->session_name));
+ if (ret) {
+ goto error;
+ }
/* Copy lttng domain or leave initialized to 0. */
if (domain) {
end:
return handle;
+error:
+ free(handle);
+ return NULL;
}
/*
int lttng_register_consumer(struct lttng_handle *handle,
const char *socket_path)
{
+ int ret;
struct lttcomm_session_msg lsm;
if (handle == NULL || socket_path == NULL) {
- return -LTTNG_ERR_INVALID;
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
}
memset(&lsm, 0, sizeof(lsm));
lsm.cmd_type = LTTNG_REGISTER_CONSUMER;
- lttng_ctl_copy_string(lsm.session.name, handle->session_name,
+ ret = lttng_strncpy(lsm.session.name, handle->session_name,
sizeof(lsm.session.name));
+ if (ret) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
COPY_DOMAIN_PACKED(lsm.domain, handle->domain);
- lttng_ctl_copy_string(lsm.u.reg.path, socket_path,
- sizeof(lsm.u.reg.path));
+ ret = lttng_strncpy(lsm.u.reg.path, socket_path,
+ sizeof(lsm.u.reg.path));
+ if (ret) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
- return lttng_ctl_ask_sessiond(&lsm, NULL);
+ ret = lttng_ctl_ask_sessiond(&lsm, NULL);
+end:
+ return ret;
}
/*
*/
int lttng_start_tracing(const char *session_name)
{
+ int ret;
struct lttcomm_session_msg lsm;
if (session_name == NULL) {
- return -LTTNG_ERR_INVALID;
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
}
memset(&lsm, 0, sizeof(lsm));
lsm.cmd_type = LTTNG_START_TRACE;
- lttng_ctl_copy_string(lsm.session.name, session_name,
- sizeof(lsm.session.name));
+ ret = lttng_strncpy(lsm.session.name, session_name,
+ sizeof(lsm.session.name));
+ if (ret) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
- return lttng_ctl_ask_sessiond(&lsm, NULL);
+ ret = lttng_ctl_ask_sessiond(&lsm, NULL);
+end:
+ return ret;
}
/*
struct lttcomm_session_msg lsm;
if (session_name == NULL) {
- return -LTTNG_ERR_INVALID;
+ ret = -LTTNG_ERR_INVALID;
+ goto error;
}
memset(&lsm, 0, sizeof(lsm));
lsm.cmd_type = LTTNG_STOP_TRACE;
- lttng_ctl_copy_string(lsm.session.name, session_name,
- sizeof(lsm.session.name));
+ ret = lttng_strncpy(lsm.session.name, session_name,
+ sizeof(lsm.session.name));
+ if (ret) {
+ ret = -LTTNG_ERR_INVALID;
+ goto error;
+ }
ret = lttng_ctl_ask_sessiond(&lsm, NULL);
if (ret < 0 && ret != -LTTNG_ERR_TRACE_ALREADY_STOPPED) {
lsm.cmd_type = LTTNG_ADD_CONTEXT;
/* If no channel name, send empty string. */
- if (channel_name == NULL) {
- lttng_ctl_copy_string(lsm.u.context.channel_name, "",
- sizeof(lsm.u.context.channel_name));
- } else {
- lttng_ctl_copy_string(lsm.u.context.channel_name, channel_name,
- sizeof(lsm.u.context.channel_name));
+ ret = lttng_strncpy(lsm.u.context.channel_name, channel_name ?: "",
+ sizeof(lsm.u.context.channel_name));
+ if (ret) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
}
COPY_DOMAIN_PACKED(lsm.domain, handle->domain);
- lttng_ctl_copy_string(lsm.session.name, handle->session_name,
+ ret = lttng_strncpy(lsm.session.name, handle->session_name,
sizeof(lsm.session.name));
+ if (ret) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
if (ctx->ctx == LTTNG_EVENT_CONTEXT_APP_CONTEXT) {
size_t provider_len, ctx_len;
return NULL;
}
-/*
- * Generate the filter bytecode from a given filter expression string. Put the
- * newly allocated parser context in ctxp and populate the lsm object with the
- * expression len.
- *
- * Return 0 on success else a LTTNG_ERR_* code and ctxp is untouched.
- */
-static int generate_filter(char *filter_expression,
- struct lttcomm_session_msg *lsm, struct filter_parser_ctx **ctxp)
-{
- int ret;
- struct filter_parser_ctx *ctx = NULL;
- FILE *fmem = NULL;
-
- assert(filter_expression);
- assert(lsm);
- assert(ctxp);
-
- /*
- * Casting const to non-const, as the underlying function will use it in
- * read-only mode.
- */
- fmem = lttng_fmemopen((void *) filter_expression,
- strlen(filter_expression), "r");
- if (!fmem) {
- fprintf(stderr, "Error opening memory as stream\n");
- ret = -LTTNG_ERR_FILTER_NOMEM;
- goto error;
- }
- ctx = filter_parser_ctx_alloc(fmem);
- if (!ctx) {
- fprintf(stderr, "Error allocating parser\n");
- ret = -LTTNG_ERR_FILTER_NOMEM;
- goto filter_alloc_error;
- }
- ret = filter_parser_ctx_append_ast(ctx);
- if (ret) {
- fprintf(stderr, "Parse error\n");
- ret = -LTTNG_ERR_FILTER_INVAL;
- goto parse_error;
- }
- if (print_xml) {
- ret = filter_visitor_print_xml(ctx, stdout, 0);
- if (ret) {
- fflush(stdout);
- fprintf(stderr, "XML print error\n");
- ret = -LTTNG_ERR_FILTER_INVAL;
- goto parse_error;
- }
- }
-
- dbg_printf("Generating IR... ");
- fflush(stdout);
- ret = filter_visitor_ir_generate(ctx);
- if (ret) {
- fprintf(stderr, "Generate IR error\n");
- ret = -LTTNG_ERR_FILTER_INVAL;
- goto parse_error;
- }
- dbg_printf("done\n");
-
- dbg_printf("Validating IR... ");
- fflush(stdout);
- ret = filter_visitor_ir_check_binary_op_nesting(ctx);
- if (ret) {
- ret = -LTTNG_ERR_FILTER_INVAL;
- goto parse_error;
- }
-
- /* Normalize globbing patterns in the expression. */
- ret = filter_visitor_ir_normalize_glob_patterns(ctx);
- if (ret) {
- ret = -LTTNG_ERR_FILTER_INVAL;
- goto parse_error;
- }
-
- /* Validate strings used as literals in the expression. */
- ret = filter_visitor_ir_validate_string(ctx);
- if (ret) {
- ret = -LTTNG_ERR_FILTER_INVAL;
- goto parse_error;
- }
-
- /* Validate globbing patterns in the expression. */
- ret = filter_visitor_ir_validate_globbing(ctx);
- if (ret) {
- ret = -LTTNG_ERR_FILTER_INVAL;
- goto parse_error;
- }
-
- dbg_printf("done\n");
-
- dbg_printf("Generating bytecode... ");
- fflush(stdout);
- ret = filter_visitor_bytecode_generate(ctx);
- if (ret) {
- fprintf(stderr, "Generate bytecode error\n");
- ret = -LTTNG_ERR_FILTER_INVAL;
- goto parse_error;
- }
- dbg_printf("done\n");
- dbg_printf("Size of bytecode generated: %u bytes.\n",
- bytecode_get_len(&ctx->bytecode->b));
-
- lsm->u.enable.bytecode_len = sizeof(ctx->bytecode->b)
- + bytecode_get_len(&ctx->bytecode->b);
- lsm->u.enable.expression_len = strlen(filter_expression) + 1;
-
- /* No need to keep the memory stream. */
- if (fclose(fmem) != 0) {
- PERROR("fclose");
- }
-
- *ctxp = ctx;
- return 0;
-
-parse_error:
- filter_ir_free(ctx);
- filter_parser_ctx_free(ctx);
-filter_alloc_error:
- if (fclose(fmem) != 0) {
- PERROR("fclose");
- }
-error:
- return ret;
-}
-
/*
* Enable event(s) for a channel, possibly with exclusions and a filter.
* If no event name is specified, all events are enabled.
memset(&lsm, 0, sizeof(lsm));
/* If no channel name, send empty string. */
- if (channel_name == NULL) {
- lttng_ctl_copy_string(lsm.u.enable.channel_name, "",
- sizeof(lsm.u.enable.channel_name));
- } else {
- lttng_ctl_copy_string(lsm.u.enable.channel_name, channel_name,
- sizeof(lsm.u.enable.channel_name));
+ ret = lttng_strncpy(lsm.u.enable.channel_name, channel_name ?: "",
+ sizeof(lsm.u.enable.channel_name));
+ if (ret) {
+ ret = -LTTNG_ERR_INVALID;
+ goto error;
}
lsm.cmd_type = LTTNG_ENABLE_EVENT;
if (ev->name[0] == '\0') {
- /* Enable all events */
- lttng_ctl_copy_string(ev->name, "*", sizeof(ev->name));
+ /* Enable all events. */
+ ret = lttng_strncpy(ev->name, "*", sizeof(ev->name));
+ assert(ret == 0);
}
COPY_DOMAIN_PACKED(lsm.domain, handle->domain);
memcpy(&lsm.u.enable.event, ev, sizeof(lsm.u.enable.event));
- lttng_ctl_copy_string(lsm.session.name, handle->session_name,
+ ret = lttng_strncpy(lsm.session.name, handle->session_name,
sizeof(lsm.session.name));
+ if (ret) {
+ ret = -LTTNG_ERR_INVALID;
+ goto error;
+ }
+
lsm.u.enable.exclusion_count = exclusion_count;
lsm.u.enable.bytecode_len = 0;
}
}
- ret = generate_filter(filter_expression, &lsm, &ctx);
+ ret = filter_parser_ctx_create_from_filter_expression(filter_expression, &ctx);
if (ret) {
goto filter_error;
}
+
+ lsm.u.enable.bytecode_len = sizeof(ctx->bytecode->b)
+ + bytecode_get_len(&ctx->bytecode->b);
+ lsm.u.enable.expression_len = strlen(filter_expression) + 1;
}
ret = lttng_dynamic_buffer_set_capacity(&payload.buffer,
for (i = 0; i < exclusion_count; i++) {
size_t exclusion_len;
- exclusion_len = lttng_strnlen(*(exclusion_list + i),
+ exclusion_len = lttng_strnlen(exclusion_list[i],
LTTNG_SYMBOL_NAME_LEN);
if (exclusion_len == LTTNG_SYMBOL_NAME_LEN) {
/* Exclusion is not NULL-terminated. */
}
ret = lttng_dynamic_buffer_append(&payload.buffer,
- *(exclusion_list + i), LTTNG_SYMBOL_NAME_LEN);
+ exclusion_list[i], exclusion_len);
+ if (ret) {
+ goto mem_error;
+ }
+
+ /*
+ * Padding the rest of the entry with zeros. Every exclusion
+ * entries take LTTNG_SYMBOL_NAME_LEN bytes in the buffer.
+ */
+ ret = lttng_dynamic_buffer_set_size(&payload.buffer,
+ LTTNG_SYMBOL_NAME_LEN * (i + 1));
if (ret) {
goto mem_error;
}
assert(fd_count == 0 || fd_count == 1);
if (fd_count == 1) {
- struct fd_handle *handle =
+ struct fd_handle *h =
lttng_payload_view_pop_fd_handle(&view);
- if (!handle) {
+ if (!h) {
goto mem_error;
}
- fd_to_send = fd_handle_get_fd(handle);
- fd_handle_put(handle);
+ fd_to_send = fd_handle_get_fd(h);
+ fd_handle_put(h);
}
ret = lttng_ctl_ask_sessiond_fds_varlen(&lsm,
memset(&lsm, 0, sizeof(lsm));
/* If no channel name, send empty string. */
- if (channel_name == NULL) {
- lttng_ctl_copy_string(lsm.u.disable.channel_name, "",
- sizeof(lsm.u.disable.channel_name));
- } else {
- lttng_ctl_copy_string(lsm.u.disable.channel_name, channel_name,
- sizeof(lsm.u.disable.channel_name));
+ ret = lttng_strncpy(lsm.u.disable.channel_name, channel_name ?: "",
+ sizeof(lsm.u.disable.channel_name));
+ if (ret) {
+ ret = -LTTNG_ERR_INVALID;
+ goto error;
}
lsm.cmd_type = LTTNG_DISABLE_EVENT;
COPY_DOMAIN_PACKED(lsm.domain, handle->domain);
memcpy(&lsm.u.disable.event, ev, sizeof(lsm.u.disable.event));
- lttng_ctl_copy_string(lsm.session.name, handle->session_name,
+ ret = lttng_strncpy(lsm.session.name, handle->session_name,
sizeof(lsm.session.name));
+ if (ret) {
+ ret = -LTTNG_ERR_INVALID;
+ goto error;
+ }
+
lsm.u.disable.bytecode_len = 0;
/*
}
}
- ret = generate_filter(filter_expression, &lsm, &ctx);
+ ret = filter_parser_ctx_create_from_filter_expression(filter_expression, &ctx);
if (ret) {
goto filter_error;
}
+
+ lsm.u.enable.bytecode_len = sizeof(ctx->bytecode->b)
+ + bytecode_get_len(&ctx->bytecode->b);
+ lsm.u.enable.expression_len = strlen(filter_expression) + 1;
}
varlen_data = zmalloc(lsm.u.disable.bytecode_len
int lttng_disable_event(struct lttng_handle *handle, const char *name,
const char *channel_name)
{
+ int ret;
struct lttng_event ev;
memset(&ev, 0, sizeof(ev));
ev.loglevel = -1;
ev.type = LTTNG_EVENT_ALL;
- lttng_ctl_copy_string(ev.name, name, sizeof(ev.name));
- return lttng_disable_event_ext(handle, &ev, channel_name, NULL);
+ ret = lttng_strncpy(ev.name, name ?: "", sizeof(ev.name));
+ if (ret) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ ret = lttng_disable_event_ext(handle, &ev, channel_name, NULL);
+end:
+ return ret;
}
struct lttng_channel *lttng_channel_create(struct lttng_domain *domain)
int lttng_enable_channel(struct lttng_handle *handle,
struct lttng_channel *in_chan)
{
+ enum lttng_error_code ret_code;
+ int ret;
struct lttcomm_session_msg lsm;
- size_t total_buffer_size_needed_per_cpu = 0;
+ uint64_t total_buffer_size_needed_per_cpu = 0;
/* NULL arguments are forbidden. No default values. */
if (handle == NULL || in_chan == NULL) {
* Verify that the amount of memory required to create the requested
* buffer is available on the system at the moment.
*/
+ if (lsm.u.channel.chan.attr.num_subbuf >
+ UINT64_MAX / lsm.u.channel.chan.attr.subbuf_size) {
+ /* Overflow */
+ ret = -LTTNG_ERR_OVERFLOW;
+ goto end;
+ }
+
total_buffer_size_needed_per_cpu = lsm.u.channel.chan.attr.num_subbuf *
lsm.u.channel.chan.attr.subbuf_size;
- if (!check_enough_available_memory(total_buffer_size_needed_per_cpu)) {
- return -LTTNG_ERR_NOMEM;
+ ret_code = check_enough_available_memory(
+ total_buffer_size_needed_per_cpu);
+ if (ret_code != LTTNG_OK) {
+ ret = -ret_code;
+ goto end;
}
lsm.cmd_type = LTTNG_ENABLE_CHANNEL;
COPY_DOMAIN_PACKED(lsm.domain, handle->domain);
- lttng_ctl_copy_string(lsm.session.name, handle->session_name,
- sizeof(lsm.session.name));
+ ret = lttng_strncpy(lsm.session.name, handle->session_name,
+ sizeof(lsm.session.name));
+ if (ret) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
- return lttng_ctl_ask_sessiond(&lsm, NULL);
+ ret = lttng_ctl_ask_sessiond(&lsm, NULL);
+end:
+ return ret;
}
/*
*/
int lttng_disable_channel(struct lttng_handle *handle, const char *name)
{
+ int ret;
struct lttcomm_session_msg lsm;
/* Safety check. Both are mandatory. */
lsm.cmd_type = LTTNG_DISABLE_CHANNEL;
- lttng_ctl_copy_string(lsm.u.disable.channel_name, name,
+ ret = lttng_strncpy(lsm.u.disable.channel_name, name,
sizeof(lsm.u.disable.channel_name));
+ if (ret) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
COPY_DOMAIN_PACKED(lsm.domain, handle->domain);
- lttng_ctl_copy_string(lsm.session.name, handle->session_name,
- sizeof(lsm.session.name));
+ ret = lttng_strncpy(lsm.session.name, handle->session_name,
+ sizeof(lsm.session.name));
+ if (ret) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
- return lttng_ctl_ask_sessiond(&lsm, NULL);
+ ret = lttng_ctl_ask_sessiond(&lsm, NULL);
+end:
+ return ret;
}
/*
enum lttng_error_code ret_code;
ret_code = lttng_destroy_session_ext(session_name, NULL);
- return ret_code == LTTNG_OK ? ret_code : -ret_code;
+ return ret_code == LTTNG_OK ? 0 : -ret_code;
}
/*
memset(&lsm, 0, sizeof(lsm));
lsm.cmd_type = LTTNG_LIST_SESSIONS;
+ /*
+ * Initialize out_sessions to NULL so it is initialized when
+ * lttng_list_sessions returns 0, thus allowing *out_sessions to
+ * be subsequently freed.
+ */
+ *out_sessions = NULL;
ret = lttng_ctl_ask_sessiond(&lsm, (void**) &sessions);
if (ret <= 0) {
goto end;
if (ret % session_size) {
ret = -LTTNG_ERR_UNK;
free(sessions);
- *out_sessions = NULL;
goto end;
}
session_count = (size_t) ret / session_size;
int lttng_set_session_shm_path(const char *session_name,
const char *shm_path)
{
+ int ret;
struct lttcomm_session_msg lsm;
if (session_name == NULL) {
memset(&lsm, 0, sizeof(lsm));
lsm.cmd_type = LTTNG_SET_SESSION_SHM_PATH;
- lttng_ctl_copy_string(lsm.session.name, session_name,
+ ret = lttng_strncpy(lsm.session.name, session_name,
sizeof(lsm.session.name));
- lttng_ctl_copy_string(lsm.u.set_shm_path.shm_path, shm_path,
+ if (ret) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ ret = lttng_strncpy(lsm.u.set_shm_path.shm_path, shm_path ?: "",
sizeof(lsm.u.set_shm_path.shm_path));
+ if (ret) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
- return lttng_ctl_ask_sessiond(&lsm, NULL);
+ ret = lttng_ctl_ask_sessiond(&lsm, NULL);
+end:
+ return ret;
}
/*
struct lttcomm_session_msg lsm;
if (session_name == NULL) {
- return -LTTNG_ERR_INVALID;
+ ret = -LTTNG_ERR_INVALID;
+ goto error;
}
memset(&lsm, 0, sizeof(lsm));
lsm.cmd_type = LTTNG_LIST_DOMAINS;
- lttng_ctl_copy_string(lsm.session.name, session_name,
+ ret = lttng_strncpy(lsm.session.name, session_name,
sizeof(lsm.session.name));
+ if (ret) {
+ ret = -LTTNG_ERR_INVALID;
+ goto error;
+ }
ret = lttng_ctl_ask_sessiond(&lsm, (void**) domains);
if (ret < 0) {
- return ret;
+ goto error;
}
return ret / sizeof(struct lttng_domain);
+error:
+ return ret;
}
/*
memset(&lsm, 0, sizeof(lsm));
lsm.cmd_type = LTTNG_LIST_CHANNELS;
- lttng_ctl_copy_string(lsm.session.name, handle->session_name,
+ ret = lttng_strncpy(lsm.session.name, handle->session_name,
sizeof(lsm.session.name));
+ if (ret) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
COPY_DOMAIN_PACKED(lsm.domain, handle->domain);
lttng_payload_init(&payload_copy);
lsm.cmd_type = LTTNG_LIST_EVENTS;
- lttng_ctl_copy_string(lsm.session.name, handle->session_name,
+ ret = lttng_strncpy(lsm.session.name, handle->session_name,
sizeof(lsm.session.name));
- lttng_ctl_copy_string(lsm.u.list.channel_name, channel_name,
+ if (ret) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ ret = lttng_strncpy(lsm.u.list.channel_name, channel_name,
sizeof(lsm.u.list.channel_name));
+ if (ret) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
COPY_DOMAIN_PACKED(lsm.domain, handle->domain);
ret = lttng_ctl_ask_sessiond_payload(&lsm_view, &payload);
cmd_header_view = lttng_buffer_view_from_dynamic_buffer(
&payload.buffer, 0, sizeof(*cmd_header));
- if (!cmd_header_view.data) {
+ if (!lttng_buffer_view_is_valid(&cmd_header_view)) {
ret = -LTTNG_ERR_INVALID_PROTOCOL;
goto end;
}
payload_view.buffer.data,
ext_comm->userspace_probe_location_len);
+ if (!lttng_payload_view_is_valid(&probe_location_view)) {
+ ret = -LTTNG_ERR_PROBE_LOCATION_INVAL;
+ goto end;
+ }
+
/*
* Create a temporary userspace probe location
* to determine the size needed by a "flattened"
payload_copy_view.buffer.data,
ext_comm->userspace_probe_location_len);
+ if (!lttng_payload_view_is_valid(&probe_location_view)) {
+ ret = -LTTNG_ERR_PROBE_LOCATION_INVAL;
+ goto free_dynamic_buffer;
+ }
+
ret = lttng_userspace_probe_location_create_from_payload(
&probe_location_view,
&probe_location);
*/
int lttng_set_tracing_group(const char *name)
{
+ char *new_group;
if (name == NULL) {
return -LTTNG_ERR_INVALID;
}
- if (asprintf(&tracing_group, "%s", name) < 0) {
+ if (asprintf(&new_group, "%s", name) < 0) {
return -LTTNG_ERR_FATAL;
}
+ free(tracing_group);
+ tracing_group = new_group;
+ new_group = NULL;
+
return 0;
}
struct lttng_uri *uris = NULL;
if (handle == NULL || (control_url == NULL && data_url == NULL)) {
- return -LTTNG_ERR_INVALID;
+ ret = -LTTNG_ERR_INVALID;
+ goto error;
}
memset(&lsm, 0, sizeof(lsm));
lsm.cmd_type = LTTNG_SET_CONSUMER_URI;
- lttng_ctl_copy_string(lsm.session.name, handle->session_name,
+ ret = lttng_strncpy(lsm.session.name, handle->session_name,
sizeof(lsm.session.name));
+ if (ret) {
+ ret = -LTTNG_ERR_INVALID;
+ goto error;
+ }
+
COPY_DOMAIN_PACKED(lsm.domain, handle->domain);
size = uri_parse_str_urls(control_url, data_url, &uris);
if (size < 0) {
- return -LTTNG_ERR_INVALID;
+ ret = -LTTNG_ERR_INVALID;
+ goto error;
}
lsm.u.uri.size = size;
sizeof(struct lttng_uri) * size, NULL);
free(uris);
+error:
return ret;
}
memset(&lsm, 0, sizeof(lsm));
lsm.cmd_type = LTTNG_DATA_PENDING;
- lttng_ctl_copy_string(lsm.session.name, session_name,
+ ret = lttng_strncpy(lsm.session.name, session_name,
sizeof(lsm.session.name));
+ if (ret) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
ret = lttng_ctl_ask_sessiond(&lsm, (void **) &pending);
if (ret < 0) {
memset(&lsm, 0, sizeof(lsm));
lsm.cmd_type = LTTNG_REGENERATE_METADATA;
- lttng_ctl_copy_string(lsm.session.name, session_name,
+ ret = lttng_strncpy(lsm.session.name, session_name,
sizeof(lsm.session.name));
+ if (ret) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
ret = lttng_ctl_ask_sessiond(&lsm, NULL);
if (ret < 0) {
memset(&lsm, 0, sizeof(lsm));
lsm.cmd_type = LTTNG_REGENERATE_STATEDUMP;
- lttng_ctl_copy_string(lsm.session.name, session_name,
+ ret = lttng_strncpy(lsm.session.name, session_name,
sizeof(lsm.session.name));
+ if (ret) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
ret = lttng_ctl_ask_sessiond(&lsm, NULL);
if (ret < 0) {
return ret;
}
-int lttng_register_trigger(struct lttng_trigger *trigger)
+static
+int _lttng_register_trigger(struct lttng_trigger *trigger, const char *name,
+ bool generate_name)
{
int ret;
struct lttcomm_session_msg lsm = {
.cmd_type = LTTNG_REGISTER_TRIGGER,
+ .u.trigger.is_trigger_anonymous = !name && !generate_name,
};
struct lttcomm_session_msg *message_lsm;
struct lttng_payload message;
struct lttng_payload reply;
+ struct lttng_trigger *reply_trigger = NULL;
+ enum lttng_domain_type domain_type;
+ const struct lttng_credentials user_creds = {
+ .uid = LTTNG_OPTIONAL_INIT_VALUE(geteuid()),
+ .gid = LTTNG_OPTIONAL_INIT_UNSET,
+ };
+ const char *unused_trigger_name = NULL;
+ enum lttng_trigger_status trigger_status;
lttng_payload_init(&message);
lttng_payload_init(&reply);
goto end;
}
+ trigger_status = lttng_trigger_get_name(trigger, &unused_trigger_name);
+ if (trigger_status != LTTNG_TRIGGER_STATUS_UNSET) {
+ /* Re-using already registered trigger. */
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ if (name) {
+ trigger_status = lttng_trigger_set_name(trigger, name);
+ if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
+ ret = -LTTNG_ERR_NOMEM;
+ goto end;
+ }
+ }
+
+ if (!trigger->creds.uid.is_set) {
+ /* Use the client's credentials as the trigger credentials. */
+ lttng_trigger_set_credentials(trigger, &user_creds);
+ } else {
+ /*
+ * Validate that either the current trigger credentials and the
+ * client credentials are identical or that the current user is
+ * root. The root user can register, unregister triggers for
+ * himself and other users.
+ *
+ * This check is also present on the sessiond side, using the
+ * credentials passed on the socket. These check are all
+ * "safety" checks.
+ */
+ const struct lttng_credentials *trigger_creds =
+ lttng_trigger_get_credentials(trigger);
+
+ if (!lttng_credentials_is_equal_uid(trigger_creds, &user_creds)) {
+ if (lttng_credentials_get_uid(&user_creds) != 0) {
+ ret = -LTTNG_ERR_EPERM;
+ goto end_unset_name;
+ }
+ }
+ }
+
if (!lttng_trigger_validate(trigger)) {
ret = -LTTNG_ERR_INVALID_TRIGGER;
- goto end;
+ goto end_unset_name;
}
- lttng_dynamic_buffer_append(&message.buffer, &lsm, sizeof(lsm));
+ domain_type = lttng_trigger_get_underlying_domain_type_restriction(
+ trigger);
- /*
- * This is needed to populate the trigger object size for the command
- * header.
- */
- message_lsm = (struct lttcomm_session_msg *) message.buffer.data;
+ lsm.domain.type = domain_type;
+
+ ret = lttng_dynamic_buffer_append(&message.buffer, &lsm, sizeof(lsm));
+ if (ret) {
+ ret = -LTTNG_ERR_NOMEM;
+ goto end_unset_name;
+ }
ret = lttng_trigger_serialize(trigger, &message);
if (ret < 0) {
ret = -LTTNG_ERR_UNK;
- goto end;
+ goto end_unset_name;
}
+ /*
+ * This is needed to populate the trigger object size for the command
+ * header.
+ */
+ message_lsm = (struct lttcomm_session_msg *) message.buffer.data;
+
message_lsm->u.trigger.length = (uint32_t) message.buffer.size - sizeof(lsm);
{
&message_view);
ret = lttng_ctl_ask_sessiond_payload(&message_view, &reply);
if (ret < 0) {
+ goto end_unset_name;
+ }
+ }
+
+ {
+ struct lttng_payload_view reply_view =
+ lttng_payload_view_from_payload(
+ &reply, 0, reply.buffer.size);
+
+ ret = lttng_trigger_create_from_payload(
+ &reply_view, &reply_trigger);
+ if (ret < 0) {
+ ret = -LTTNG_ERR_INVALID_PROTOCOL;
+ goto end_unset_name;
+ }
+ }
+
+ if (name || generate_name) {
+ ret = lttng_trigger_assign_name(trigger, reply_trigger);
+ if (ret < 0) {
+ ret = -LTTNG_ERR_NOMEM;
goto end;
}
}
ret = 0;
+ goto end;
+
+end_unset_name:
+ trigger_status = lttng_trigger_set_name(trigger, NULL);
+ if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
+ ret = -LTTNG_ERR_UNK;
+ }
end:
lttng_payload_reset(&message);
lttng_payload_reset(&reply);
+ lttng_trigger_destroy(reply_trigger);
return ret;
}
-int lttng_unregister_trigger(struct lttng_trigger *trigger)
+int lttng_register_trigger(struct lttng_trigger *trigger)
+{
+ /* Register an anonymous trigger. */
+ return _lttng_register_trigger(trigger, NULL, false);
+}
+
+enum lttng_error_code lttng_register_trigger_with_name(
+ struct lttng_trigger *trigger, const char *name)
+{
+ const int ret = _lttng_register_trigger(trigger, name, false);
+
+ return ret == 0 ? LTTNG_OK : (enum lttng_error_code) -ret;
+}
+
+enum lttng_error_code lttng_register_trigger_with_automatic_name(
+ struct lttng_trigger *trigger)
+{
+ const int ret = _lttng_register_trigger(trigger, false, true);
+
+ return ret == 0 ? LTTNG_OK : (enum lttng_error_code) -ret;
+}
+
+enum lttng_error_code lttng_error_query_execute(
+ const struct lttng_error_query *query,
+ const struct lttng_endpoint *endpoint,
+ struct lttng_error_query_results **results)
+{
+ int ret;
+ enum lttng_error_code ret_code;
+ struct lttcomm_session_msg lsm = {
+ .cmd_type = LTTNG_EXECUTE_ERROR_QUERY,
+ };
+ struct lttng_payload message;
+ struct lttng_payload reply;
+ struct lttcomm_session_msg *message_lsm;
+
+ lttng_payload_init(&message);
+ lttng_payload_init(&reply);
+
+ if (!query || !results) {
+ ret_code = LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ if (endpoint != lttng_session_daemon_command_endpoint) {
+ ret_code = LTTNG_ERR_INVALID_ERROR_QUERY_TARGET;
+ goto end;
+ }
+
+ ret = lttng_dynamic_buffer_append(&message.buffer, &lsm, sizeof(lsm));
+ if (ret) {
+ ret_code = LTTNG_ERR_NOMEM;
+ goto end;
+ }
+
+ ret = lttng_error_query_serialize(query, &message);
+ if (ret) {
+ ret_code = LTTNG_ERR_UNK;
+ goto end;
+ }
+
+ message_lsm = (struct lttcomm_session_msg *) message.buffer.data;
+ message_lsm->u.error_query.length =
+ (uint32_t) message.buffer.size - sizeof(lsm);
+
+ {
+ struct lttng_payload_view message_view =
+ lttng_payload_view_from_payload(
+ &message, 0, -1);
+
+ message_lsm->fd_count = lttng_payload_view_get_fd_handle_count(
+ &message_view);
+ ret = lttng_ctl_ask_sessiond_payload(&message_view, &reply);
+ if (ret < 0) {
+ ret_code = -ret;
+ goto end;
+ }
+ }
+
+ {
+ ssize_t reply_create_ret;
+ struct lttng_payload_view reply_view =
+ lttng_payload_view_from_payload(
+ &reply, 0, reply.buffer.size);
+
+ reply_create_ret = lttng_error_query_results_create_from_payload(
+ &reply_view, results);
+ if (reply_create_ret < 0) {
+ ret_code = LTTNG_ERR_INVALID_PROTOCOL;
+ goto end;
+ }
+ }
+
+ ret_code = LTTNG_OK;
+end:
+ lttng_payload_reset(&message);
+ lttng_payload_reset(&reply);
+ return ret_code;
+}
+
+int lttng_unregister_trigger(const struct lttng_trigger *trigger)
{
int ret;
struct lttcomm_session_msg lsm;
struct lttcomm_session_msg *message_lsm;
struct lttng_payload message;
struct lttng_payload reply;
+ struct lttng_trigger *copy = NULL;
+ const struct lttng_credentials user_creds = {
+ .uid = LTTNG_OPTIONAL_INIT_VALUE(geteuid()),
+ .gid = LTTNG_OPTIONAL_INIT_UNSET,
+ };
lttng_payload_init(&message);
lttng_payload_init(&reply);
goto end;
}
- if (!lttng_trigger_validate(trigger)) {
+ copy = lttng_trigger_copy(trigger);
+ if (!copy) {
+ ret = -LTTNG_ERR_UNK;
+ goto end;
+ }
+
+ if (!copy->creds.uid.is_set) {
+ /* Use the client credentials as the trigger credentials */
+ lttng_trigger_set_credentials(copy, &user_creds);
+ } else {
+ /*
+ * Validate that either the current trigger credentials and the
+ * client credentials are identical or that the current user is
+ * root. The root user can register, unregister triggers for
+ * himself and other users.
+ *
+ * This check is also present on the sessiond side, using the
+ * credentials passed on the socket. These check are all
+ * "safety" checks.
+ */
+ const struct lttng_credentials *trigger_creds =
+ lttng_trigger_get_credentials(copy);
+ if (!lttng_credentials_is_equal_uid(trigger_creds, &user_creds)) {
+ if (lttng_credentials_get_uid(&user_creds) != 0) {
+ ret = -LTTNG_ERR_EPERM;
+ goto end;
+ }
+ }
+ }
+
+ if (!lttng_trigger_validate(copy)) {
ret = -LTTNG_ERR_INVALID_TRIGGER;
goto end;
}
memset(&lsm, 0, sizeof(lsm));
lsm.cmd_type = LTTNG_UNREGISTER_TRIGGER;
- lttng_dynamic_buffer_append(&message.buffer, &lsm, sizeof(lsm));
+ ret = lttng_dynamic_buffer_append(&message.buffer, &lsm, sizeof(lsm));
+ if (ret) {
+ ret = -LTTNG_ERR_NOMEM;
+ goto end;
+ }
+
+ ret = lttng_trigger_serialize(copy, &message);
+ if (ret < 0) {
+ ret = -LTTNG_ERR_UNK;
+ goto end;
+ }
/*
* This is needed to populate the trigger object size for the command
*/
message_lsm = (struct lttcomm_session_msg *) message.buffer.data;
- ret = lttng_trigger_serialize(trigger, &message);
- if (ret < 0) {
- ret = -LTTNG_ERR_UNK;
- goto end;
- }
-
message_lsm->u.trigger.length = (uint32_t) message.buffer.size - sizeof(lsm);
{
ret = 0;
end:
+ lttng_trigger_destroy(copy);
lttng_payload_reset(&message);
lttng_payload_reset(&reply);
return ret;
}
+/*
+ * Ask the session daemon for all registered triggers for the current user.
+ *
+ * Allocates and return an lttng_triggers set.
+ * On error, returns a suitable lttng_error_code.
+ */
+enum lttng_error_code lttng_list_triggers(struct lttng_triggers **triggers)
+{
+ int ret;
+ enum lttng_error_code ret_code = LTTNG_OK;
+ struct lttcomm_session_msg lsm = { .cmd_type = LTTNG_LIST_TRIGGERS };
+ struct lttng_triggers *local_triggers = NULL;
+ struct lttng_payload reply;
+ struct lttng_payload_view lsm_view =
+ lttng_payload_view_init_from_buffer(
+ (const char *) &lsm, 0, sizeof(lsm));
+
+ lttng_payload_init(&reply);
+
+ ret = lttng_ctl_ask_sessiond_payload(&lsm_view, &reply);
+ if (ret < 0) {
+ ret_code = (enum lttng_error_code) -ret;
+ goto end;
+ }
+
+ {
+ struct lttng_payload_view reply_view =
+ lttng_payload_view_from_payload(
+ &reply, 0, reply.buffer.size);
+
+ ret = lttng_triggers_create_from_payload(
+ &reply_view, &local_triggers);
+ if (ret < 0) {
+ ret_code = LTTNG_ERR_FATAL;
+ goto end;
+ }
+ }
+
+ *triggers = local_triggers;
+ local_triggers = NULL;
+end:
+ lttng_payload_reset(&reply);
+ lttng_triggers_destroy(local_triggers);
+ return ret_code;
+}
+
/*
* lib constructor.
*/