X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;f=src%2Flib%2Flttng-ctl%2Flttng-ctl.c;h=197e52e8f7a1d6befe81a03ed07541a69c4dc631;hb=de453daa7054455a39fac38fb74306fc12349f54;hp=a8c6c9b24adc33a3b13a14b2f206ffea5edc8230;hpb=eac4828d8ade08ce1a55c871aa52437aaa9b36e5;p=lttng-tools.git diff --git a/src/lib/lttng-ctl/lttng-ctl.c b/src/lib/lttng-ctl/lttng-ctl.c index a8c6c9b24..197e52e8f 100644 --- a/src/lib/lttng-ctl/lttng-ctl.c +++ b/src/lib/lttng-ctl/lttng-ctl.c @@ -1,5 +1,5 @@ /* - * liblttngctl.c + * lttng-ctl.c * * Linux Trace Toolkit Control Library * @@ -34,11 +34,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include "filter/filter-ast.h" #include "filter/filter-parser.h" @@ -176,6 +178,35 @@ end: return ret; } +/* + * Send file descriptors to the session daemon. + * + * On success, returns the number of bytes sent (>=0) + * On error, returns -1 + */ +static int send_session_fds(const int *fds, size_t nb_fd) +{ + int ret; + + if (!connected) { + ret = -LTTNG_ERR_NO_SESSIOND; + goto end; + } + + if (!fds || !nb_fd) { + ret = 0; + goto end; + } + + ret = lttcomm_send_fds_unix_sock(sessiond_socket, fds, nb_fd); + if (ret < 0) { + ret = -LTTNG_ERR_FATAL; + } + +end: + return ret; +} + /* * Receive data from the sessiond socket. * @@ -445,15 +476,16 @@ end: /* * Ask the session daemon a specific command and put the data into buf. - * Takes extra var. len. data as input to send to the session daemon. + * Takes extra var. len. data and file descriptors as input to send to the + * session daemon. * * Return size of data (only payload, not header) or a negative error code. */ LTTNG_HIDDEN -int lttng_ctl_ask_sessiond_varlen(struct lttcomm_session_msg *lsm, - const void *vardata, size_t vardata_len, - void **user_payload_buf, void **user_cmd_header_buf, - size_t *user_cmd_header_len) +int lttng_ctl_ask_sessiond_fds_varlen(struct lttcomm_session_msg *lsm, + const int *fds, size_t nb_fd, const void *vardata, + size_t vardata_len, void **user_payload_buf, + void **user_cmd_header_buf, size_t *user_cmd_header_len) { int ret; size_t payload_len; @@ -478,6 +510,13 @@ int lttng_ctl_ask_sessiond_varlen(struct lttcomm_session_msg *lsm, goto end; } + /* Send fds */ + ret = send_session_fds(fds, nb_fd); + if (ret < 0) { + /* Ret value is a valid lttng error code. */ + goto end; + } + /* Get header from data transmission */ ret = recv_data_sessiond(&llm, sizeof(llm)); if (ret < 0) { @@ -887,12 +926,6 @@ static int generate_filter(char *filter_expression, ret = -LTTNG_ERR_FILTER_INVAL; goto parse_error; } - ret = filter_visitor_set_parent(ctx); - if (ret) { - fprintf(stderr, "Set parent error\n"); - ret = -LTTNG_ERR_FILTER_INVAL; - goto parse_error; - } if (print_xml) { ret = filter_visitor_print_xml(ctx, stdout, 0); if (ret) { @@ -1864,7 +1897,11 @@ int lttng_list_events(struct lttng_handle *handle, struct lttcomm_event_command_header *cmd_header = NULL; size_t cmd_header_len; uint32_t nb_events, i; - void *extended_at; + void *comm_ext_at; + void *listing_at; + char *reception_buffer = NULL; + char *listing = NULL; + size_t storage_req; /* Safety check. An handle and channel name are mandatory */ if (handle == NULL || channel_name == NULL) { @@ -1879,137 +1916,111 @@ int lttng_list_events(struct lttng_handle *handle, sizeof(lsm.u.list.channel_name)); lttng_ctl_copy_lttng_domain(&lsm.domain, &handle->domain); - ret = lttng_ctl_ask_sessiond_varlen(&lsm, NULL, 0, (void **) events, - (void **) &cmd_header, &cmd_header_len); + 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 error; + goto end; } /* Set number of events and free command header */ nb_events = cmd_header->nb_events; if (nb_events > INT_MAX) { ret = -EOVERFLOW; - goto error; + goto end; } - ret = (int) nb_events; free(cmd_header); cmd_header = NULL; - /* Set extended info pointers */ - extended_at = ((void*) (*events)) + - nb_events * sizeof(struct lttng_event); + /* + * The buffer that is returned must contain a "flat" version of + * the events that are returned. In other words, all pointers + * within an lttng_event must point to a location within the returned + * buffer so that the user may free by simply calling free() on the + * returned buffer. This is needed in order to maintain API + * compatibility. + * + * A first pass is performed to figure the size of the buffer that + * must be returned. A second pass is then performed to setup + * the returned events so that their members always point within the + * buffer. + * + * The layout of the returned buffer is as follows: + * - struct lttng_event[nb_events], + * - nb_events times the following: + * - struct lttng_event_extended, + * - flattened version of userspace_probe_location + * - filter_expression + * - exclusions + * - padding to align to 64-bits + */ + comm_ext_at = reception_buffer + + (nb_events * sizeof(struct lttng_event)); + storage_req = nb_events * sizeof(struct lttng_event); for (i = 0; i < nb_events; i++) { - struct lttcomm_event_extended_header *ext_header; - struct lttng_event *event = &(*events)[i]; - - event->extended.ptr = extended_at; - ext_header = - (struct lttcomm_event_extended_header *) extended_at; - extended_at += sizeof(*ext_header); - extended_at += ext_header->filter_len; - extended_at += - ext_header->nb_exclusions * LTTNG_SYMBOL_NAME_LEN; - } - - return ret; -error: - free(cmd_header); - free(*events); - return ret; -} - -int lttng_event_get_filter_expression(struct lttng_event *event, - const char **filter_expression) -{ - int ret = 0; - struct lttcomm_event_extended_header *ext_header; - - if (!event || !filter_expression) { - ret = -LTTNG_ERR_INVALID; - goto end; - } - - ext_header = event->extended.ptr; - - if (!ext_header) { - /* - * This can happen since the lttng_event structure is - * used for other tasks where this pointer is never set. - */ - *filter_expression = NULL; - goto end; - } - - if (ext_header->filter_len) { - *filter_expression = ((const char *) (ext_header)) + - sizeof(*ext_header); - } else { - *filter_expression = NULL; - } - -end: - return ret; -} + struct lttcomm_event_extended_header *ext_comm = + (struct lttcomm_event_extended_header *) comm_ext_at; -int lttng_event_get_exclusion_name_count(struct lttng_event *event) -{ - int ret; - struct lttcomm_event_extended_header *ext_header; - - if (!event) { - ret = -LTTNG_ERR_INVALID; - goto end; - } - - ext_header = event->extended.ptr; - if (!ext_header) { - /* - * This can happen since the lttng_event structure is - * used for other tasks where this pointer is never set. - */ - ret = 0; - goto end; - } - - if (ext_header->nb_exclusions > INT_MAX) { - ret = -LTTNG_ERR_OVERFLOW; - goto end; - } - ret = (int) ext_header->nb_exclusions; -end: - return ret; -} - -int lttng_event_get_exclusion_name(struct lttng_event *event, - size_t index, const char **exclusion_name) -{ - int ret = 0; - struct lttcomm_event_extended_header *ext_header; - void *at; - - if (!event || !exclusion_name) { - ret = -LTTNG_ERR_INVALID; - goto end; - } + comm_ext_at += sizeof(*ext_comm); + comm_ext_at += ext_comm->filter_len; + comm_ext_at += + ext_comm->nb_exclusions * LTTNG_SYMBOL_NAME_LEN; - ext_header = event->extended.ptr; - if (!ext_header) { - ret = -LTTNG_ERR_INVALID; - goto end; + storage_req += sizeof(struct lttng_event_extended); + /* TODO: missing size of flat userspace probe. */ + storage_req += ext_comm->filter_len; + storage_req += ext_comm->nb_exclusions * LTTNG_SYMBOL_NAME_LEN; + storage_req += storage_req % 8; } - if (index >= ext_header->nb_exclusions) { - ret = -LTTNG_ERR_INVALID; + listing = zmalloc(storage_req); + if (!listing) { goto end; } + memcpy(listing, reception_buffer, + nb_events * sizeof(struct lttng_event)); - at = (void *) ext_header + sizeof(*ext_header); - at += ext_header->filter_len; - at += index * LTTNG_SYMBOL_NAME_LEN; - *exclusion_name = at; - + comm_ext_at = reception_buffer + + (nb_events * sizeof(struct lttng_event)); + listing_at = listing + + (nb_events * sizeof(struct lttng_event)); + for (i = 0; i < nb_events; i++) { + struct lttng_event *event = (struct lttng_event *) + (listing + (sizeof(struct lttng_event) * i)); + struct lttcomm_event_extended_header *ext_comm = + (struct lttcomm_event_extended_header *) comm_ext_at; + struct lttng_event_extended *event_extended = + (struct lttng_event_extended *) listing_at; + + event->extended.ptr = event_extended; + listing_at += sizeof(*event_extended); + comm_ext_at += sizeof(*ext_comm); + + /* Copy filter expression. */ + memcpy(listing_at, comm_ext_at, ext_comm->filter_len); + event_extended->filter_expression = listing_at; + comm_ext_at += ext_comm->filter_len; + listing_at += ext_comm->filter_len; + + /* Copy exclusions. */ + event_extended->exclusions.count = ext_comm->nb_exclusions; + event_extended->exclusions.strings = listing_at; + memcpy(listing_at, comm_ext_at, + ext_comm->nb_exclusions * LTTNG_SYMBOL_NAME_LEN); + listing_at += ext_comm->nb_exclusions * LTTNG_SYMBOL_NAME_LEN; + comm_ext_at += ext_comm->nb_exclusions * LTTNG_SYMBOL_NAME_LEN; + + listing_at += ((uintptr_t) listing_at) % 8; + } + + *events = (struct lttng_event *) listing; + listing = NULL; + ret = (int) nb_events; end: + free(cmd_header); + free(reception_buffer); + free(listing); return ret; } @@ -2073,6 +2084,8 @@ void lttng_channel_set_default_attr(struct lttng_domain *domain, if (extended) { extended->monitor_timer_interval = DEFAULT_KERNEL_CHANNEL_MONITOR_TIMER; + extended->blocking_timeout = + DEFAULT_KERNEL_CHANNEL_BLOCKING_TIMEOUT; } break; case LTTNG_DOMAIN_UST: @@ -2088,6 +2101,8 @@ void lttng_channel_set_default_attr(struct lttng_domain *domain, 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: @@ -2102,6 +2117,8 @@ void lttng_channel_set_default_attr(struct lttng_domain *domain, if (extended) { extended->monitor_timer_interval = DEFAULT_UST_PID_CHANNEL_MONITOR_TIMER; + extended->blocking_timeout = + DEFAULT_UST_PID_CHANNEL_BLOCKING_TIMEOUT; } break; } @@ -2203,6 +2220,61 @@ end: return ret; } +int lttng_channel_get_blocking_timeout(struct lttng_channel *chan, + int64_t *blocking_timeout) +{ + int ret = 0; + + if (!chan || !blocking_timeout) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + if (!chan->attr.extended.ptr) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + *blocking_timeout = ((struct lttng_channel_extended *) + chan->attr.extended.ptr)->blocking_timeout; +end: + return ret; +} + +int lttng_channel_set_blocking_timeout(struct lttng_channel *chan, + int64_t blocking_timeout) +{ + int ret = 0; + int64_t msec_timeout; + + if (!chan || !chan->attr.extended.ptr) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + if (blocking_timeout < 0 && blocking_timeout != -1) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + /* + * LTTng-ust's use of poll() to implement this timeout mechanism forces + * us to accept a narrower range of values (msecs expressed as a signed + * 32-bit integer). + */ + msec_timeout = blocking_timeout / 1000; + if (msec_timeout != (int32_t) msec_timeout) { + ret = -LTTNG_ERR_INVALID; + goto end; + } + + ((struct lttng_channel_extended *) + chan->attr.extended.ptr)->blocking_timeout = + blocking_timeout; +end: + return ret; +} + /* * Check if session daemon is alive. * @@ -2424,9 +2496,22 @@ int lttng_create_session_snapshot(const char *name, const char *snapshot_url) lsm.u.uri.size = size; + /* + * If the user does not specify a custom subdir, use the session name. + */ + if (size > 0 && uris[0].dtype != LTTNG_DST_PATH && strlen(uris[0].subdir) == 0) { + ret = snprintf(uris[0].subdir, sizeof(uris[0].subdir), "%s", name); + if (ret < 0) { + PERROR("snprintf uri subdir"); + ret = -LTTNG_ERR_FATAL; + goto error; + } + } + ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(&lsm, uris, sizeof(struct lttng_uri) * size, NULL); +error: free(uris); return ret; } @@ -2598,9 +2683,9 @@ int lttng_register_trigger(struct lttng_trigger *trigger) { int ret; struct lttcomm_session_msg lsm; - char *trigger_buf = NULL; - ssize_t trigger_size; + struct lttng_dynamic_buffer buffer; + lttng_dynamic_buffer_init(&buffer); if (!trigger) { ret = -LTTNG_ERR_INVALID; goto end; @@ -2611,30 +2696,19 @@ int lttng_register_trigger(struct lttng_trigger *trigger) goto end; } - trigger_size = lttng_trigger_serialize(trigger, NULL); - if (trigger_size < 0) { + ret = lttng_trigger_serialize(trigger, &buffer); + if (ret < 0) { ret = -LTTNG_ERR_UNK; goto end; } - trigger_buf = zmalloc(trigger_size); - if (!trigger_buf) { - ret = -LTTNG_ERR_NOMEM; - goto end; - } - memset(&lsm, 0, sizeof(lsm)); lsm.cmd_type = LTTNG_REGISTER_TRIGGER; - if (lttng_trigger_serialize(trigger, trigger_buf) < 0) { - ret = -LTTNG_ERR_UNK; - goto end; - } - - lsm.u.trigger.length = (uint32_t) trigger_size; - ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(&lsm, trigger_buf, - trigger_size, NULL); + lsm.u.trigger.length = (uint32_t) buffer.size; + ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(&lsm, buffer.data, + buffer.size, NULL); end: - free(trigger_buf); + lttng_dynamic_buffer_reset(&buffer); return ret; } @@ -2642,43 +2716,76 @@ int lttng_unregister_trigger(struct lttng_trigger *trigger) { int ret; struct lttcomm_session_msg lsm; - char *trigger_buf = NULL; - ssize_t trigger_size; + struct lttng_dynamic_buffer buffer; + lttng_dynamic_buffer_init(&buffer); if (!trigger) { ret = -LTTNG_ERR_INVALID; goto end; } if (!lttng_trigger_validate(trigger)) { - ret = -LTTNG_ERR_INVALID; + ret = -LTTNG_ERR_INVALID_TRIGGER; goto end; } - trigger_size = lttng_trigger_serialize(trigger, NULL); - if (trigger_size < 0) { + ret = lttng_trigger_serialize(trigger, &buffer); + if (ret < 0) { ret = -LTTNG_ERR_UNK; goto end; } - trigger_buf = zmalloc(trigger_size); - if (!trigger_buf) { - ret = -LTTNG_ERR_NOMEM; + memset(&lsm, 0, sizeof(lsm)); + lsm.cmd_type = LTTNG_UNREGISTER_TRIGGER; + lsm.u.trigger.length = (uint32_t) buffer.size; + ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(&lsm, buffer.data, + buffer.size, NULL); +end: + lttng_dynamic_buffer_reset(&buffer); + return ret; +} + +int lttng_session_get_current_archive_location(const char *session_name, + char **chunk_path) +{ + struct lttcomm_session_msg lsm; + struct lttng_session_get_current_output_return *output_return = NULL; + int ret; + size_t path_len; + + memset(&lsm, 0, sizeof(lsm)); + lsm.cmd_type = LTTNG_SESSION_GET_CURRENT_OUTPUT; + 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 **) &output_return); + if (ret < 0) { + ret = -1; goto end; } - memset(&lsm, 0, sizeof(lsm)); - lsm.cmd_type = LTTNG_UNREGISTER_TRIGGER; - if (lttng_trigger_serialize(trigger, trigger_buf) < 0) { - ret = -LTTNG_ERR_UNK; + path_len = lttng_strnlen(output_return->path, + sizeof(output_return->path)); + if (path_len == 0 || path_len == sizeof(output_return->path)) { + ret = -LTTNG_ERR_NO_SESSION_OUTPUT; + goto end; + } + + *chunk_path = zmalloc(path_len + 1); + if (!*chunk_path) { + ret = -1; goto end; } + memcpy(*chunk_path, output_return->path, path_len); + + ret = 0; - lsm.u.trigger.length = (uint32_t) trigger_size; - ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(&lsm, trigger_buf, - trigger_size, NULL); end: - free(trigger_buf); + free(output_return); return ret; }