+ int ret;
+ struct lttcomm_session_msg lsm;
+
+ if (session_name == NULL) {
+ return -LTTNG_ERR_INVALID;
+ }
+
+ memset(&lsm, 0, sizeof(lsm));
+ lsm.cmd_type = LTTNG_LIST_DOMAINS;
+
+ lttng_ctl_copy_string(lsm.session.name, session_name,
+ sizeof(lsm.session.name));
+
+ ret = lttng_ctl_ask_sessiond(&lsm, (void**) domains);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return ret / sizeof(struct lttng_domain);
+}
+
+/*
+ * Ask the session daemon for all available channels of a session.
+ * Sets the contents of the channels array.
+ * Returns the number of lttng_channel entries in channels;
+ * on error, returns a negative value.
+ */
+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);
+ struct lttcomm_session_msg lsm;
+ void *extended_at;
+
+ if (handle == NULL) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ memset(&lsm, 0, sizeof(lsm));
+ lsm.cmd_type = LTTNG_LIST_CHANNELS;
+ lttng_ctl_copy_string(lsm.session.name, handle->session_name,
+ sizeof(lsm.session.name));
+
+ lttng_ctl_copy_lttng_domain(&lsm.domain, &handle->domain);
+
+ ret = lttng_ctl_ask_sessiond(&lsm, (void**) channels);
+ if (ret < 0) {
+ goto end;
+ }
+
+ if (ret % channel_size) {
+ ret = -LTTNG_ERR_UNK;
+ free(*channels);
+ *channels = NULL;
+ 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];
+
+ chan->attr.extended.ptr = extended_at;
+ extended_at += sizeof(struct lttng_channel_extended);
+ }
+
+ ret = (int) channel_count;
+end:
+ return ret;
+}
+
+/*
+ * Ask the session daemon for all available events of a session channel.
+ * Sets the contents of the events array.
+ * Returns the number of lttng_event entries in events;
+ * on error, returns a negative value.
+ */
+int lttng_list_events(struct lttng_handle *handle,
+ const char *channel_name, struct lttng_event **events)
+{
+ int ret;
+ struct lttcomm_session_msg lsm;
+ struct lttcomm_event_command_header *cmd_header = NULL;
+ size_t cmd_header_len;
+ uint32_t nb_events, i;
+ void *extended_at;
+
+ /* Safety check. An handle and channel name are mandatory */
+ if (handle == NULL || channel_name == NULL) {
+ return -LTTNG_ERR_INVALID;
+ }
+
+ memset(&lsm, 0, sizeof(lsm));
+ lsm.cmd_type = LTTNG_LIST_EVENTS;
+ lttng_ctl_copy_string(lsm.session.name, handle->session_name,
+ sizeof(lsm.session.name));
+ lttng_ctl_copy_string(lsm.u.list.channel_name, channel_name,
+ 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);
+ if (ret < 0) {
+ goto error;
+ }
+
+ /* Set number of events and free command header */
+ nb_events = cmd_header->nb_events;
+ if (nb_events > INT_MAX) {
+ ret = -EOVERFLOW;
+ goto error;
+ }
+ ret = (int) nb_events;
+ free(cmd_header);
+ cmd_header = NULL;
+
+ /* Set extended info pointers */
+ extended_at = ((void*) (*events)) +
+ 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;
+}
+
+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;
+ }
+
+ ext_header = event->extended.ptr;
+ if (!ext_header) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ if (index >= ext_header->nb_exclusions) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ at = (void *) ext_header + sizeof(*ext_header);
+ at += ext_header->filter_len;
+ at += index * LTTNG_SYMBOL_NAME_LEN;
+ *exclusion_name = at;
+
+end:
+ return ret;
+}
+
+/*
+ * Sets the tracing_group variable with name.
+ * This function allocates memory pointed to by tracing_group.
+ * On success, returns 0, on error, returns -1 (null name) or -ENOMEM.
+ */
+int lttng_set_tracing_group(const char *name)
+{
+ if (name == NULL) {
+ return -LTTNG_ERR_INVALID;
+ }
+
+ if (asprintf(&tracing_group, "%s", name) < 0) {
+ return -LTTNG_ERR_FATAL;
+ }
+
+ return 0;
+}
+
+int lttng_calibrate(struct lttng_handle *handle,
+ struct lttng_calibrate *calibrate)
+{
+ /*
+ * This command was removed in LTTng 2.9.
+ */
+ return -LTTNG_ERR_UND;
+}
+
+/*
+ * Set default channel attributes.
+ * If either or both of the arguments are null, attr content is zeroe'd.
+ */
+void lttng_channel_set_default_attr(struct lttng_domain *domain,
+ struct lttng_channel_attr *attr)
+{
+ struct lttng_channel_extended *extended =
+ (struct lttng_channel_extended *) attr->extended.ptr;
+
+ /* Safety check */
+ if (attr == NULL || domain == NULL) {
+ return;
+ }
+
+ memset(attr, 0, sizeof(struct lttng_channel_attr));
+
+ /* Same for all domains. */
+ attr->overwrite = DEFAULT_CHANNEL_OVERWRITE;
+ attr->tracefile_size = DEFAULT_CHANNEL_TRACEFILE_SIZE;
+ attr->tracefile_count = DEFAULT_CHANNEL_TRACEFILE_COUNT;
+
+ switch (domain->type) {
+ case LTTNG_DOMAIN_KERNEL:
+ attr->switch_timer_interval =
+ DEFAULT_KERNEL_CHANNEL_SWITCH_TIMER;
+ attr->read_timer_interval = DEFAULT_KERNEL_CHANNEL_READ_TIMER;
+ 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;
+ }
+ break;
+ case LTTNG_DOMAIN_UST:
+ switch (domain->buf_type) {
+ case LTTNG_BUFFER_PER_UID:
+ attr->subbuf_size = default_get_ust_uid_channel_subbuf_size();
+ attr->num_subbuf = DEFAULT_UST_UID_CHANNEL_SUBBUF_NUM;
+ attr->output = DEFAULT_UST_UID_CHANNEL_OUTPUT;
+ attr->switch_timer_interval =
+ 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;
+ }
+ break;
+ case LTTNG_BUFFER_PER_PID:
+ default:
+ attr->subbuf_size = default_get_ust_pid_channel_subbuf_size();
+ attr->num_subbuf = DEFAULT_UST_PID_CHANNEL_SUBBUF_NUM;
+ attr->output = DEFAULT_UST_PID_CHANNEL_OUTPUT;
+ attr->switch_timer_interval =
+ 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;
+ }
+ break;
+ }
+ default:
+ /* Default behavior: leave set to 0. */
+ break;
+ }
+
+ attr->extended.ptr = extended;
+}
+
+int lttng_channel_get_discarded_event_count(struct lttng_channel *channel,
+ uint64_t *discarded_events)
+{
+ int ret = 0;
+ struct lttng_channel_extended *chan_ext;
+
+ if (!channel || !discarded_events) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ chan_ext = channel->attr.extended.ptr;
+ if (!chan_ext) {
+ /*
+ * This can happen since the lttng_channel structure is
+ * used for other tasks where this pointer is never set.
+ */
+ *discarded_events = 0;
+ goto end;
+ }
+
+ *discarded_events = chan_ext->discarded_events;
+end:
+ return ret;
+}
+
+int lttng_channel_get_lost_packet_count(struct lttng_channel *channel,
+ uint64_t *lost_packets)
+{
+ int ret = 0;
+ struct lttng_channel_extended *chan_ext;
+
+ if (!channel || !lost_packets) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ chan_ext = channel->attr.extended.ptr;
+ if (!chan_ext) {
+ /*
+ * This can happen since the lttng_channel structure is
+ * used for other tasks where this pointer is never set.
+ */
+ *lost_packets = 0;
+ goto end;
+ }
+
+ *lost_packets = chan_ext->lost_packets;
+end:
+ return ret;
+}
+
+int lttng_channel_get_monitor_timer_interval(struct lttng_channel *chan,
+ uint64_t *monitor_timer_interval)
+{
+ int ret = 0;
+
+ if (!chan || !monitor_timer_interval) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ if (!chan->attr.extended.ptr) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ *monitor_timer_interval = ((struct lttng_channel_extended *)
+ chan->attr.extended.ptr)->monitor_timer_interval;
+end:
+ return ret;
+}
+
+int lttng_channel_set_monitor_timer_interval(struct lttng_channel *chan,
+ uint64_t monitor_timer_interval)
+{
+ int ret = 0;
+
+ if (!chan || !chan->attr.extended.ptr) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ ((struct lttng_channel_extended *)
+ chan->attr.extended.ptr)->monitor_timer_interval =
+ monitor_timer_interval;
+end:
+ return ret;
+}
+
+/*
+ * Check if session daemon is alive.
+ *
+ * Return 1 if alive or 0 if not.
+ * On error returns a negative value.
+ */
+int lttng_session_daemon_alive(void)
+{
+ int ret;
+
+ ret = set_session_daemon_path();
+ if (ret < 0) {
+ /* Error. */
+ return ret;
+ }
+
+ if (*sessiond_sock_path == '\0') {
+ /*
+ * No socket path set. Weird error which means the constructor
+ * was not called.
+ */
+ assert(0);
+ }
+
+ ret = try_connect_sessiond(sessiond_sock_path);
+ if (ret < 0) {
+ /* Not alive. */
+ return 0;
+ }
+
+ /* Is alive. */
+ return 1;
+}
+
+/*
+ * Set URL for a consumer for a session and domain.
+ *
+ * Return 0 on success, else a negative value.
+ */
+int lttng_set_consumer_url(struct lttng_handle *handle,
+ const char *control_url, const char *data_url)
+{
+ int ret;
+ ssize_t size;
+ struct lttcomm_session_msg lsm;
+ struct lttng_uri *uris = NULL;
+
+ if (handle == NULL || (control_url == NULL && data_url == NULL)) {
+ return -LTTNG_ERR_INVALID;
+ }
+
+ memset(&lsm, 0, sizeof(lsm));
+
+ lsm.cmd_type = LTTNG_SET_CONSUMER_URI;
+
+ lttng_ctl_copy_string(lsm.session.name, handle->session_name,
+ sizeof(lsm.session.name));
+ lttng_ctl_copy_lttng_domain(&lsm.domain, &handle->domain);
+
+ size = uri_parse_str_urls(control_url, data_url, &uris);
+ if (size < 0) {
+ return -LTTNG_ERR_INVALID;
+ }
+
+ lsm.u.uri.size = size;
+
+ ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(&lsm, uris,
+ sizeof(struct lttng_uri) * size, NULL);
+
+ free(uris);
+ return ret;
+}
+
+/*
+ * [OBSOLETE]
+ */
+int lttng_enable_consumer(struct lttng_handle *handle)
+{
+ return -ENOSYS;
+}
+
+/*
+ * [OBSOLETE]
+ */
+int lttng_disable_consumer(struct lttng_handle *handle)
+{
+ return -ENOSYS;
+}
+
+/*
+ * This is an extension of create session that is ONLY and SHOULD only be used
+ * by the lttng command line program. It exists to avoid using URI parsing in
+ * the lttng client.
+ *
+ * We need the date and time for the trace path subdirectory for the case where
+ * the user does NOT define one using either -o or -U. Using the normal
+ * lttng_create_session API call, we have no clue on the session daemon side if
+ * the URL was generated automatically by the client or define by the user.
+ *
+ * So this function "wrapper" is hidden from the public API, takes the datetime
+ * string and appends it if necessary to the URI subdirectory before sending it
+ * to the session daemon.
+ *
+ * With this extra function, the lttng_create_session call behavior is not
+ * changed and the timestamp is appended to the URI on the session daemon side
+ * if necessary.
+ */
+int _lttng_create_session_ext(const char *name, const char *url,
+ const char *datetime)
+{
+ int ret;
+ ssize_t size;
+ struct lttcomm_session_msg lsm;
+ struct lttng_uri *uris = NULL;
+
+ if (name == NULL || datetime == NULL) {
+ return -LTTNG_ERR_INVALID;
+ }
+
+ memset(&lsm, 0, sizeof(lsm));
+
+ lsm.cmd_type = LTTNG_CREATE_SESSION;
+ lttng_ctl_copy_string(lsm.session.name, name, sizeof(lsm.session.name));
+
+ /* There should never be a data URL. */
+ size = uri_parse_str_urls(url, NULL, &uris);
+ if (size < 0) {
+ ret = -LTTNG_ERR_INVALID;
+ goto error;
+ }
+
+ lsm.u.uri.size = size;
+
+ if (size > 0 && uris[0].dtype != LTTNG_DST_PATH && strlen(uris[0].subdir) == 0) {
+ /* Don't append datetime if the name was automatically created. */
+ if (strncmp(name, DEFAULT_SESSION_NAME "-",
+ strlen(DEFAULT_SESSION_NAME) + 1)) {
+ ret = snprintf(uris[0].subdir, sizeof(uris[0].subdir), "%s-%s",
+ name, datetime);
+ } else {
+ 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;
+}
+
+/*
+ * For a given session name, this call checks if the data is ready to be read
+ * or is still being extracted by the consumer(s) hence not ready to be used by
+ * any readers.
+ */
+int lttng_data_pending(const char *session_name)
+{
+ int ret;
+ struct lttcomm_session_msg lsm;
+ uint8_t *pending = NULL;
+
+ if (session_name == NULL) {
+ return -LTTNG_ERR_INVALID;
+ }
+
+ memset(&lsm, 0, sizeof(lsm));
+ lsm.cmd_type = LTTNG_DATA_PENDING;
+
+ lttng_ctl_copy_string(lsm.session.name, session_name,
+ sizeof(lsm.session.name));
+
+ ret = lttng_ctl_ask_sessiond(&lsm, (void **) &pending);
+ if (ret < 0) {
+ goto end;
+ } else if (ret != 1) {
+ /* Unexpected payload size */
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ ret = (int) *pending;
+end:
+ free(pending);
+ return ret;
+}
+
+/*
+ * Create a session exclusively used for snapshot.
+ *
+ * Returns LTTNG_OK on success or a negative error code.
+ */
+int lttng_create_session_snapshot(const char *name, const char *snapshot_url)
+{
+ int ret;
+ ssize_t size;
+ struct lttcomm_session_msg lsm;
+ struct lttng_uri *uris = NULL;
+
+ if (name == NULL) {
+ return -LTTNG_ERR_INVALID;
+ }
+
+ memset(&lsm, 0, sizeof(lsm));
+
+ lsm.cmd_type = LTTNG_CREATE_SESSION_SNAPSHOT;
+ lttng_ctl_copy_string(lsm.session.name, name, sizeof(lsm.session.name));
+
+ size = uri_parse_str_urls(snapshot_url, NULL, &uris);
+ if (size < 0) {
+ return -LTTNG_ERR_INVALID;
+ }
+
+ lsm.u.uri.size = size;
+
+ ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(&lsm, uris,
+ sizeof(struct lttng_uri) * size, NULL);
+
+ free(uris);
+ return ret;
+}
+
+/*
+ * Create a session exclusively used for live.
+ *
+ * Returns LTTNG_OK on success or a negative error code.
+ */
+int lttng_create_session_live(const char *name, const char *url,
+ unsigned int timer_interval)
+{
+ int ret;
+ ssize_t size;
+ struct lttcomm_session_msg lsm;
+ struct lttng_uri *uris = NULL;
+
+ if (name == NULL || timer_interval == 0) {
+ return -LTTNG_ERR_INVALID;
+ }
+
+ memset(&lsm, 0, sizeof(lsm));
+
+ lsm.cmd_type = LTTNG_CREATE_SESSION_LIVE;
+ lttng_ctl_copy_string(lsm.session.name, name, sizeof(lsm.session.name));
+
+ if (url) {
+ size = uri_parse_str_urls(url, NULL, &uris);
+ if (size <= 0) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ /* file:// is not accepted for live session. */
+ if (uris[0].dtype == LTTNG_DST_PATH) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+ } else {
+ size = 0;
+ }
+
+ lsm.u.session_live.nb_uri = size;
+ lsm.u.session_live.timer_interval = timer_interval;
+
+ ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(&lsm, uris,
+ sizeof(struct lttng_uri) * size, NULL);
+
+end:
+ free(uris);
+ return ret;
+}
+
+/*
+ * List PIDs in the tracker.
+ *
+ * enabled is set to whether the PID tracker is enabled.
+ * pids is set to an allocated array of PIDs currently tracked. On
+ * success, pids must be freed by the caller.
+ * nr_pids is set to the number of entries contained by the pids array.
+ *
+ * Returns 0 on success, else a negative LTTng error code.
+ */
+int lttng_list_tracker_pids(struct lttng_handle *handle,
+ int *_enabled, int32_t **_pids, size_t *_nr_pids)
+{
+ int ret;
+ int enabled = 1;
+ struct lttcomm_session_msg lsm;
+ size_t nr_pids;
+ int32_t *pids;
+
+ if (handle == NULL) {
+ return -LTTNG_ERR_INVALID;
+ }
+
+ memset(&lsm, 0, sizeof(lsm));
+ lsm.cmd_type = LTTNG_LIST_TRACKER_PIDS;
+ lttng_ctl_copy_string(lsm.session.name, handle->session_name,
+ sizeof(lsm.session.name));
+ lttng_ctl_copy_lttng_domain(&lsm.domain, &handle->domain);
+
+ ret = lttng_ctl_ask_sessiond(&lsm, (void **) &pids);
+ if (ret < 0) {
+ return ret;
+ }
+ nr_pids = ret / sizeof(int32_t);
+ if (nr_pids == 1 && pids[0] == -1) {
+ free(pids);
+ pids = NULL;
+ enabled = 0;
+ nr_pids = 0;
+ }
+ *_enabled = enabled;
+ *_pids = pids;
+ *_nr_pids = nr_pids;
+ return 0;
+}
+
+/*
+ * Regenerate the metadata for a session.
+ * Return 0 on success, a negative error code on error.
+ */
+int lttng_regenerate_metadata(const char *session_name)
+{
+ int ret;
+ struct lttcomm_session_msg lsm;
+
+ if (!session_name) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ memset(&lsm, 0, sizeof(lsm));
+ lsm.cmd_type = LTTNG_REGENERATE_METADATA;
+
+ lttng_ctl_copy_string(lsm.session.name, session_name,
+ sizeof(lsm.session.name));
+
+ ret = lttng_ctl_ask_sessiond(&lsm, NULL);
+ if (ret < 0) {
+ goto end;
+ }
+
+ ret = 0;
+end:
+ return ret;
+}
+
+/*
+ * Deprecated, replaced by lttng_regenerate_metadata.
+ */
+int lttng_metadata_regenerate(const char *session_name)
+{
+ return lttng_regenerate_metadata(session_name);
+}
+
+/*
+ * Regenerate the statedump of a session.
+ * Return 0 on success, a negative error code on error.
+ */
+int lttng_regenerate_statedump(const char *session_name)
+{
+ int ret;
+ struct lttcomm_session_msg lsm;
+
+ if (!session_name) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ memset(&lsm, 0, sizeof(lsm));
+ lsm.cmd_type = LTTNG_REGENERATE_STATEDUMP;
+
+ lttng_ctl_copy_string(lsm.session.name, session_name,
+ sizeof(lsm.session.name));
+
+ ret = lttng_ctl_ask_sessiond(&lsm, NULL);
+ if (ret < 0) {
+ goto end;
+ }
+
+ ret = 0;
+end:
+ return ret;
+}
+
+int lttng_register_trigger(struct lttng_trigger *trigger)
+{
+ int ret;
+ struct lttcomm_session_msg lsm;
+ char *trigger_buf = NULL;
+ ssize_t trigger_size;
+
+ if (!trigger) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ if (!lttng_trigger_validate(trigger)) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ trigger_size = lttng_trigger_serialize(trigger, NULL);
+ if (trigger_size < 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);
+end:
+ free(trigger_buf);
+ return ret;
+}
+
+int lttng_unregister_trigger(struct lttng_trigger *trigger)
+{
+ int ret;
+ struct lttcomm_session_msg lsm;
+ char *trigger_buf = NULL;
+ ssize_t trigger_size;
+
+ if (!trigger) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ if (!lttng_trigger_validate(trigger)) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ trigger_size = lttng_trigger_serialize(trigger, NULL);
+ if (trigger_size < 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_UNREGISTER_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);
+end:
+ free(trigger_buf);
+ return ret;
+}
+
+/*
+ * lib constructor.
+ */
+static void __attribute__((constructor)) init(void)
+{
+ /* Set default session group */
+ lttng_set_tracing_group(DEFAULT_TRACING_GROUP);
+}
+
+/*
+ * lib destructor.
+ */
+static void __attribute__((destructor)) lttng_ctl_exit(void)
+{
+ free(tracing_group);