X-Git-Url: https://git.liburcu.org/?a=blobdiff_plain;f=src%2Flib%2Flttng-ctl%2Flttng-ctl.c;h=92593cfac878b983a32b8bbc3fce23c4cab570e3;hb=714363d38245d57d5fbb657f67bc069d6f4d8aff;hp=784597e20ef3188373dc898fe9a45976381ccbbf;hpb=242388e491e4219f967ee424d7bf02035a313e6f;p=lttng-tools.git diff --git a/src/lib/lttng-ctl/lttng-ctl.c b/src/lib/lttng-ctl/lttng-ctl.c index 784597e20..92593cfac 100644 --- a/src/lib/lttng-ctl/lttng-ctl.c +++ b/src/lib/lttng-ctl/lttng-ctl.c @@ -3,7 +3,7 @@ * * Linux Trace Toolkit Control Library * - * Copyright (C) 2011 David Goulet + * Copyright (C) 2011 EfficiOS Inc. * Copyright (C) 2016 Jérémie Galarneau * * SPDX-License-Identifier: LGPL-2.1-only @@ -15,17 +15,19 @@ #include #include #include +#include #include #include +#include #include #include #include #include -#include #include -#include +#include #include +#include #include #include #include @@ -34,20 +36,20 @@ #include #include #include +#include #include #include +#include #include #include #include #include #include -#include +#include "lttng-ctl-helper.h" #include #include -#include #include -#include "lttng-ctl-helper.h" #define COPY_DOMAIN_PACKED(dst, src) \ do { \ @@ -76,21 +78,6 @@ int lttng_opt_quiet; 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. * @@ -131,7 +118,8 @@ static int send_session_msg(struct lttcomm_session_msg *lsm) 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)); @@ -211,6 +199,8 @@ static int recv_data_sessiond(void *buf, size_t len) { int ret; + assert(len > 0); + if (!connected) { ret = -LTTNG_ERR_NO_SESSIOND; goto end; @@ -219,6 +209,8 @@ static int recv_data_sessiond(void *buf, size_t len) 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: @@ -301,12 +293,14 @@ 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 @@ -314,10 +308,18 @@ static int check_enough_available_memory(size_t num_bytes_requested_per_cpu) */ num_cpu = sysconf(_SC_NPROCESSORS_ONLN); if (num_cpu == -1) { - goto error; + ret_code = LTTNG_ERR_FATAL; + goto end; } - num_bytes_requested_total = num_bytes_requested_per_cpu * num_cpu; + 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 * (uint64_t) num_cpu; /* * Try to get the `MemAvail` field of `/proc/meminfo`. This is the most @@ -339,10 +341,18 @@ static int check_enough_available_memory(size_t num_bytes_requested_per_cpu) 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; } /* @@ -397,9 +407,14 @@ static int set_session_daemon_path(void) 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) { @@ -658,7 +673,12 @@ int lttng_ctl_ask_sessiond_payload(struct lttng_payload_view *message, /* 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; } @@ -710,6 +730,7 @@ 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)); @@ -719,8 +740,11 @@ struct lttng_handle *lttng_create_handle(const char *session_name, } /* 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) { @@ -729,6 +753,9 @@ struct lttng_handle *lttng_create_handle(const char *session_name, end: return handle; +error: + free(handle); + return NULL; } /* @@ -747,22 +774,35 @@ void lttng_destroy_handle(struct lttng_handle *handle) 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; } /* @@ -772,19 +812,27 @@ int lttng_register_consumer(struct lttng_handle *handle, */ 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; } /* @@ -796,14 +844,19 @@ static int _lttng_stop_tracing(const char *session_name, int wait) 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) { @@ -880,17 +933,20 @@ int lttng_add_context(struct lttng_handle *handle, 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; @@ -1086,25 +1142,30 @@ int lttng_enable_event_with_exclusions(struct lttng_handle *handle, 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; @@ -1162,7 +1223,7 @@ int lttng_enable_event_with_exclusions(struct lttng_handle *handle, 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. */ @@ -1171,7 +1232,17 @@ int lttng_enable_event_with_exclusions(struct lttng_handle *handle, } 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; } @@ -1229,15 +1300,15 @@ int lttng_enable_event_with_exclusions(struct lttng_handle *handle, 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, @@ -1308,12 +1379,11 @@ int lttng_disable_event_ext(struct lttng_handle *handle, 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; @@ -1321,8 +1391,13 @@ int lttng_disable_event_ext(struct lttng_handle *handle, 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; /* @@ -1443,22 +1518,29 @@ ask_sessiond: 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) { struct lttng_channel *channel = NULL; - struct lttng_channel_extended *extended = NULL; if (!domain) { - goto error; + goto end; } /* Validate domain. */ @@ -1469,36 +1551,26 @@ struct lttng_channel *lttng_channel_create(struct lttng_domain *domain) case LTTNG_BUFFER_PER_PID: break; default: - goto error; + goto end; } break; case LTTNG_DOMAIN_KERNEL: if (domain->buf_type != LTTNG_BUFFER_GLOBAL) { - goto error; + goto end; } break; default: - goto error; + goto end; } - channel = zmalloc(sizeof(*channel)); + channel = lttng_channel_create_internal(); if (!channel) { - goto error; - } - - extended = zmalloc(sizeof(*extended)); - if (!extended) { - goto error; + goto end; } - channel->attr.extended.ptr = extended; - lttng_channel_set_default_attr(domain, &channel->attr); +end: return channel; -error: - free(channel); - free(extended); - return NULL; } void lttng_channel_destroy(struct lttng_channel *channel) @@ -1520,60 +1592,90 @@ void lttng_channel_destroy(struct lttng_channel *channel) int lttng_enable_channel(struct lttng_handle *handle, struct lttng_channel *in_chan) { + enum lttng_error_code ret_code; + int ret; + struct lttng_dynamic_buffer buffer; struct lttcomm_session_msg lsm; - size_t total_buffer_size_needed_per_cpu = 0; + uint64_t total_buffer_size_needed_per_cpu = 0; + struct lttng_channel *channel = NULL; + + lttng_dynamic_buffer_init(&buffer); /* NULL arguments are forbidden. No default values. */ if (handle == NULL || in_chan == NULL) { - return -LTTNG_ERR_INVALID; + ret = -LTTNG_ERR_INVALID; + goto end; } - memset(&lsm, 0, sizeof(lsm)); - memcpy(&lsm.u.channel.chan, in_chan, sizeof(lsm.u.channel.chan)); - lsm.u.channel.chan.attr.extended.ptr = NULL; + /* + * Verify that the amount of memory required to create the requested + * buffer is available on the system at the moment. + */ + if (in_chan->attr.num_subbuf > + UINT64_MAX / in_chan->attr.subbuf_size) { + /* Overflow */ + ret = -LTTNG_ERR_OVERFLOW; + goto end; + } - if (!in_chan->attr.extended.ptr) { - struct lttng_channel *channel; - struct lttng_channel_extended *extended; + total_buffer_size_needed_per_cpu = + in_chan->attr.num_subbuf * in_chan->attr.subbuf_size; + ret_code = check_enough_available_memory( + total_buffer_size_needed_per_cpu); + if (ret_code != LTTNG_OK) { + ret = -ret_code; + goto end; + } - channel = lttng_channel_create(&handle->domain); - if (!channel) { - return -LTTNG_ERR_NOMEM; - } + /* Copy the channel for easier manipulation. */ + channel = lttng_channel_copy(in_chan); + if (!channel) { + ret = -LTTNG_ERR_NOMEM; + goto end; + } - /* - * Create a new channel in order to use default extended - * attribute values. - */ - extended = (struct lttng_channel_extended *) - channel->attr.extended.ptr; - memcpy(&lsm.u.channel.extended, extended, sizeof(*extended)); - lttng_channel_destroy(channel); - } else { - struct lttng_channel_extended *extended; + /* Populate the channel extended attribute if necessary. */ + if (!channel->attr.extended.ptr) { + struct lttng_channel_extended *extended = + (struct lttng_channel_extended *) zmalloc( + sizeof(*extended)); - extended = (struct lttng_channel_extended *) - in_chan->attr.extended.ptr; - memcpy(&lsm.u.channel.extended, extended, sizeof(*extended)); + if (!extended) { + ret = -LTTNG_ERR_NOMEM; + goto end; + } + lttng_channel_set_default_extended_attr( + &handle->domain, extended); + channel->attr.extended.ptr = extended; } - /* - * Verify that the amount of memory required to create the requested - * buffer is available on the system at the moment. - */ - 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; - } + /* Prepare the payload */ + memset(&lsm, 0, sizeof(lsm)); 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_channel_serialize(channel, &buffer); + if (ret) { + ret = -LTTNG_ERR_FATAL; + goto end; + } + + lsm.u.channel.length = buffer.size; + + ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header( + &lsm, buffer.data, buffer.size, NULL); +end: + lttng_channel_destroy(channel); + lttng_dynamic_buffer_reset(&buffer); + return ret; } /* @@ -1582,6 +1684,7 @@ int lttng_enable_channel(struct lttng_handle *handle, */ int lttng_disable_channel(struct lttng_handle *handle, const char *name) { + int ret; struct lttcomm_session_msg lsm; /* Safety check. Both are mandatory. */ @@ -1593,15 +1696,25 @@ int lttng_disable_channel(struct lttng_handle *handle, const char *name) 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; } /* @@ -1999,7 +2112,7 @@ int lttng_destroy_session_no_wait(const char *session_name) 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; } /* @@ -2020,6 +2133,12 @@ int lttng_list_sessions(struct lttng_session **out_sessions) 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; @@ -2032,7 +2151,6 @@ int lttng_list_sessions(struct lttng_session **out_sessions) if (ret % session_size) { ret = -LTTNG_ERR_UNK; free(sessions); - *out_sessions = NULL; goto end; } session_count = (size_t) ret / session_size; @@ -2079,6 +2197,7 @@ end: 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) { @@ -2088,12 +2207,23 @@ int lttng_set_session_shm_path(const char *session_name, 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; } /* @@ -2109,21 +2239,28 @@ int lttng_list_domains(const char *session_name, 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; } /* @@ -2135,12 +2272,14 @@ int lttng_list_domains(const char *session_name, int lttng_list_channels(struct lttng_handle *handle, struct lttng_channel **channels) { - int ret; - size_t channel_count, i; - const size_t channel_size = sizeof(struct lttng_channel) + - sizeof(struct lttng_channel_extended); + int ret, total_payload_received; struct lttcomm_session_msg lsm; - void *extended_at; + char *reception_buffer = NULL; + size_t cmd_header_len = 0; + struct lttcomm_list_command_header *cmd_header = NULL; + struct lttng_dynamic_buffer tmp_buffer; + + lttng_dynamic_buffer_init(&tmp_buffer); if (handle == NULL) { ret = -LTTNG_ERR_INVALID; @@ -2149,36 +2288,57 @@ int lttng_list_channels(struct lttng_handle *handle, 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); - ret = lttng_ctl_ask_sessiond(&lsm, (void**) channels); + ret = lttng_ctl_ask_sessiond_fds_varlen(&lsm, NULL, 0, NULL, 0, + (void **) &reception_buffer, (void **) &cmd_header, + &cmd_header_len); if (ret < 0) { goto end; } - if (ret % channel_size) { - ret = -LTTNG_ERR_UNK; - free(*channels); - *channels = NULL; + total_payload_received = ret; + + if (cmd_header_len != sizeof(*cmd_header)) { + ret = -LTTNG_ERR_FATAL; goto end; } - channel_count = (size_t) ret / channel_size; - /* Set extended info pointers */ - extended_at = ((void *) *channels) + - channel_count * sizeof(struct lttng_channel); - for (i = 0; i < channel_count; i++) { - struct lttng_channel *chan = &(*channels)[i]; + if (!cmd_header) { + ret = LTTNG_ERR_UNK; + goto end; + } - chan->attr.extended.ptr = extended_at; - extended_at += sizeof(struct lttng_channel_extended); + if (cmd_header->count > INT_MAX) { + ret = -LTTNG_ERR_OVERFLOW; + goto end; + } + + { + enum lttng_error_code ret_code; + const struct lttng_buffer_view events_view = + lttng_buffer_view_init(reception_buffer, 0, + total_payload_received); + + ret_code = lttng_channels_create_and_flatten_from_buffer( + &events_view, cmd_header->count, channels); + if (ret_code != LTTNG_OK) { + ret = -ret_code; + goto end; + } } - ret = (int) channel_count; + ret = (int) cmd_header->count; end: + free(cmd_header); + free(reception_buffer); return ret; } @@ -2218,10 +2378,20 @@ int lttng_list_events(struct lttng_handle *handle, 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); @@ -2243,7 +2413,7 @@ int lttng_list_events(struct lttng_handle *handle, 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; } @@ -2310,6 +2480,11 @@ int lttng_list_events(struct lttng_handle *handle, 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" @@ -2449,6 +2624,11 @@ int lttng_list_events(struct lttng_handle *handle, 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); @@ -2493,14 +2673,19 @@ end: */ 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; } @@ -2527,6 +2712,7 @@ void lttng_channel_set_default_attr(struct lttng_domain *domain, return; } + /* Save the pointer for later use */ extended = (struct lttng_channel_extended *) attr->extended.ptr; memset(attr, 0, sizeof(struct lttng_channel_attr)); @@ -2543,12 +2729,6 @@ void lttng_channel_set_default_attr(struct lttng_domain *domain, attr->subbuf_size = default_get_kernel_channel_subbuf_size(); attr->num_subbuf = DEFAULT_KERNEL_CHANNEL_SUBBUF_NUM; attr->output = DEFAULT_KERNEL_CHANNEL_OUTPUT; - if (extended) { - extended->monitor_timer_interval = - DEFAULT_KERNEL_CHANNEL_MONITOR_TIMER; - extended->blocking_timeout = - DEFAULT_KERNEL_CHANNEL_BLOCKING_TIMEOUT; - } break; case LTTNG_DOMAIN_UST: switch (domain->buf_type) { @@ -2560,12 +2740,6 @@ void lttng_channel_set_default_attr(struct lttng_domain *domain, DEFAULT_UST_UID_CHANNEL_SWITCH_TIMER; attr->read_timer_interval = DEFAULT_UST_UID_CHANNEL_READ_TIMER; - if (extended) { - extended->monitor_timer_interval = - DEFAULT_UST_UID_CHANNEL_MONITOR_TIMER; - extended->blocking_timeout = - DEFAULT_UST_UID_CHANNEL_BLOCKING_TIMEOUT; - } break; case LTTNG_BUFFER_PER_PID: default: @@ -2576,12 +2750,6 @@ void lttng_channel_set_default_attr(struct lttng_domain *domain, DEFAULT_UST_PID_CHANNEL_SWITCH_TIMER; attr->read_timer_interval = DEFAULT_UST_PID_CHANNEL_READ_TIMER; - if (extended) { - extended->monitor_timer_interval = - DEFAULT_UST_PID_CHANNEL_MONITOR_TIMER; - extended->blocking_timeout = - DEFAULT_UST_PID_CHANNEL_BLOCKING_TIMEOUT; - } break; } default: @@ -2589,6 +2757,11 @@ void lttng_channel_set_default_attr(struct lttng_domain *domain, break; } + if (extended) { + lttng_channel_set_default_extended_attr(domain, extended); + } + + /* Reassign the extended pointer. */ attr->extended.ptr = extended; } @@ -2785,20 +2958,27 @@ int lttng_set_consumer_url(struct lttng_handle *handle, 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; @@ -2807,6 +2987,7 @@ int lttng_set_consumer_url(struct lttng_handle *handle, sizeof(struct lttng_uri) * size, NULL); free(uris); +error: return ret; } @@ -2857,8 +3038,12 @@ int lttng_data_pending(const char *session_name) 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) { @@ -2896,8 +3081,12 @@ int lttng_regenerate_metadata(const char *session_name) 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) { @@ -2934,8 +3123,12 @@ int lttng_regenerate_statedump(const char *session_name) 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) { @@ -2947,21 +3140,26 @@ end: 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); @@ -2971,6 +3169,21 @@ int lttng_register_trigger(struct lttng_trigger *trigger) 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); @@ -2991,34 +3204,39 @@ int lttng_register_trigger(struct lttng_trigger *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; + goto end_unset_name; } } } if (!lttng_trigger_validate(trigger)) { ret = -LTTNG_ERR_INVALID_TRIGGER; - goto end; + goto end_unset_name; } + domain_type = lttng_trigger_get_underlying_domain_type_restriction( + trigger); + + lsm.domain.type = domain_type; + ret = lttng_dynamic_buffer_append(&message.buffer, &lsm, sizeof(lsm)); if (ret) { ret = -LTTNG_ERR_NOMEM; - 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; - 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); { @@ -3030,7 +3248,7 @@ int lttng_register_trigger(struct lttng_trigger *trigger) &message_view); ret = lttng_ctl_ask_sessiond_payload(&message_view, &reply); if (ret < 0) { - goto end; + goto end_unset_name; } } @@ -3042,18 +3260,27 @@ int lttng_register_trigger(struct lttng_trigger *trigger) ret = lttng_trigger_create_from_payload( &reply_view, &reply_trigger); if (ret < 0) { - ret = -LTTNG_ERR_FATAL; - goto end; + ret = -LTTNG_ERR_INVALID_PROTOCOL; + goto end_unset_name; } } - ret = lttng_trigger_assign_name(trigger, reply_trigger); - if (ret < 0) { - ret = -LTTNG_ERR_FATAL; - goto end; + 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); @@ -3061,13 +3288,114 @@ end: 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, @@ -3081,9 +3409,15 @@ int lttng_unregister_trigger(struct lttng_trigger *trigger) goto end; } - if (!trigger->creds.uid.is_set) { - /* Use the client's credentials as the trigger credentials. */ - lttng_trigger_set_credentials(trigger, &user_creds); + 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 @@ -3096,8 +3430,7 @@ int lttng_unregister_trigger(struct lttng_trigger *trigger) * "safety" checks. */ const struct lttng_credentials *trigger_creds = - lttng_trigger_get_credentials(trigger); - + 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; @@ -3106,7 +3439,7 @@ int lttng_unregister_trigger(struct lttng_trigger *trigger) } } - if (!lttng_trigger_validate(trigger)) { + if (!lttng_trigger_validate(copy)) { ret = -LTTNG_ERR_INVALID_TRIGGER; goto end; } @@ -3120,18 +3453,18 @@ int lttng_unregister_trigger(struct lttng_trigger *trigger) 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 * header and number of fds sent. */ 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); { @@ -3154,11 +3487,58 @@ int lttng_unregister_trigger(struct lttng_trigger *trigger) 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. */