Fix: add missing semicolons after MSG, DBG, ERR print macros
[lttng-tools.git] / src / lib / lttng-ctl / lttng-ctl.c
index 03b74c0b74771a9d0be8158f152a617123799c47..d0deade2e5b2d0216c5012153d7b587b744ae9eb 100644 (file)
@@ -150,7 +150,7 @@ end:
  * On success, returns the number of bytes sent (>=0)
  * On error, returns -1
  */
-static int send_session_varlen(void *data, size_t len)
+static int send_session_varlen(const void *data, size_t len)
 {
        int ret;
 
@@ -392,6 +392,54 @@ static int disconnect_sessiond(void)
        return ret;
 }
 
+static int recv_sessiond_optional_data(size_t len, void **user_buf,
+       size_t *user_len)
+{
+       int ret = 0;
+       void *buf = NULL;
+
+       if (len) {
+               if (!user_len) {
+                       ret = -LTTNG_ERR_INVALID;
+                       goto end;
+               }
+
+               buf = zmalloc(len);
+               if (!buf) {
+                       ret = -ENOMEM;
+                       goto end;
+               }
+
+               ret = recv_data_sessiond(buf, len);
+               if (ret < 0) {
+                       goto end;
+               }
+
+               if (!user_buf) {
+                       ret = -LTTNG_ERR_INVALID;
+                       goto end;
+               }
+
+               /* Move ownership of command header buffer to user. */
+               *user_buf = buf;
+               buf = NULL;
+               *user_len = len;
+       } else {
+               /* No command header. */
+               if (user_len) {
+                       *user_len = 0;
+               }
+
+               if (user_buf) {
+                       *user_buf = NULL;
+               }
+       }
+
+end:
+       free(buf);
+       return ret;
+}
+
 /*
  * 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.
@@ -400,11 +448,12 @@ static int disconnect_sessiond(void)
  */
 LTTNG_HIDDEN
 int lttng_ctl_ask_sessiond_varlen(struct lttcomm_session_msg *lsm,
-               void *vardata, size_t varlen, void **buf)
+               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 size;
-       void *data = NULL;
+       size_t payload_len;
        struct lttcomm_lttng_msg llm;
 
        ret = connect_sessiond();
@@ -420,7 +469,7 @@ int lttng_ctl_ask_sessiond_varlen(struct lttcomm_session_msg *lsm,
                goto end;
        }
        /* Send var len data */
-       ret = send_session_varlen(vardata, varlen);
+       ret = send_session_varlen(vardata, vardata_len);
        if (ret < 0) {
                /* Ret value is a valid lttng error code. */
                goto end;
@@ -439,41 +488,21 @@ int lttng_ctl_ask_sessiond_varlen(struct lttcomm_session_msg *lsm,
                goto end;
        }
 
-       size = llm.data_size;
-       if (size == 0) {
-               /* If client free with size 0 */
-               if (buf != NULL) {
-                       *buf = NULL;
-               }
-               ret = 0;
-               goto end;
-       }
-
-       data = zmalloc(size);
-       if (!data) {
-               ret = -ENOMEM;
-               goto end;
-       }
-
-       /* Get payload data */
-       ret = recv_data_sessiond(data, size);
+       /* Get command header from data transmission */
+       ret = recv_sessiond_optional_data(llm.cmd_header_size,
+               user_cmd_header_buf, user_cmd_header_len);
        if (ret < 0) {
-               free(data);
                goto end;
        }
 
-       /*
-        * Extra protection not to dereference a NULL pointer. If buf is NULL at
-        * this point, an error is returned and data is freed.
-        */
-       if (buf == NULL) {
-               ret = -LTTNG_ERR_INVALID;
-               free(data);
+       /* Get payload from data transmission */
+       ret = recv_sessiond_optional_data(llm.data_size, user_payload_buf,
+               &payload_len);
+       if (ret < 0) {
                goto end;
        }
 
-       *buf = data;
-       ret = size;
+       ret = llm.data_size;
 
 end:
        disconnect_sessiond();
@@ -490,10 +519,6 @@ struct lttng_handle *lttng_create_handle(const char *session_name,
 {
        struct lttng_handle *handle = NULL;
 
-       if (domain == NULL) {
-               goto end;
-       }
-
        handle = zmalloc(sizeof(struct lttng_handle));
        if (handle == NULL) {
                PERROR("malloc handle");
@@ -504,8 +529,10 @@ struct lttng_handle *lttng_create_handle(const char *session_name,
        lttng_ctl_copy_string(handle->session_name, session_name,
                        sizeof(handle->session_name));
 
-       /* Copy lttng domain */
-       lttng_ctl_copy_lttng_domain(&handle->domain, domain);
+       /* Copy lttng domain or leave initialized to 0. */
+       if (domain) {
+               lttng_ctl_copy_lttng_domain(&handle->domain, domain);
+       }
 
 end:
        return handle;
@@ -707,11 +734,18 @@ int lttng_add_context(struct lttng_handle *handle,
                memcpy(buf + provider_len, ctx_name, ctx_len);
        }
        memcpy(&lsm.u.context.ctx, ctx, sizeof(struct lttng_event_context));
-       /* Don't leak application addresses to the sessiond. */
-       lsm.u.context.ctx.u.app_ctx.provider_name = NULL;
-       lsm.u.context.ctx.u.app_ctx.ctx_name = NULL;
 
-       ret = lttng_ctl_ask_sessiond_varlen(&lsm, buf, len, NULL);
+       if (ctx->ctx == LTTNG_EVENT_CONTEXT_APP_CONTEXT) {
+               /*
+                * Don't leak application addresses to the sessiond.
+                * This is only necessary when ctx is for an app ctx otherwise
+                * the values inside the union (type & config) are overwritten.
+                */
+               lsm.u.context.ctx.u.app_ctx.provider_name = NULL;
+               lsm.u.context.ctx.u.app_ctx.ctx_name = NULL;
+       }
+
+       ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(&lsm, buf, len, NULL);
 end:
        free(buf);
        return ret;
@@ -1075,7 +1109,7 @@ int lttng_enable_event_with_exclusions(struct lttng_handle *handle,
                        lsm.u.enable.bytecode_len);
        }
 
-       ret = lttng_ctl_ask_sessiond_varlen(&lsm, varlen_data,
+       ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(&lsm, varlen_data,
                        (LTTNG_SYMBOL_NAME_LEN * lsm.u.enable.exclusion_count) +
                        lsm.u.enable.bytecode_len + lsm.u.enable.expression_len,
                        NULL);
@@ -1234,7 +1268,7 @@ int lttng_disable_event_ext(struct lttng_handle *handle,
                        lsm.u.disable.bytecode_len);
        }
 
-       ret = lttng_ctl_ask_sessiond_varlen(&lsm, varlen_data,
+       ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(&lsm, varlen_data,
                        lsm.u.disable.bytecode_len + lsm.u.disable.expression_len, NULL);
        free(varlen_data);
 
@@ -1514,7 +1548,7 @@ int lttng_create_session(const char *name, const char *url)
 
        lsm.u.uri.size = size;
 
-       ret = lttng_ctl_ask_sessiond_varlen(&lsm, uris,
+       ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(&lsm, uris,
                        sizeof(struct lttng_uri) * size, NULL);
 
        free(uris);
@@ -1525,7 +1559,8 @@ int lttng_create_session(const char *name, const char *url)
  * Destroy session using name.
  * Returns size of returned session payload data or a negative error code.
  */
-int lttng_destroy_session(const char *session_name)
+static
+int _lttng_destroy_session(const char *session_name)
 {
        struct lttcomm_session_msg lsm;
 
@@ -1542,6 +1577,48 @@ int lttng_destroy_session(const char *session_name)
        return lttng_ctl_ask_sessiond(&lsm, NULL);
 }
 
+/*
+ * Stop the session and wait for the data before destroying it
+ */
+int lttng_destroy_session(const char *session_name)
+{
+       int ret;
+
+       /*
+        * Stop the tracing and wait for the data.
+        */
+       ret = _lttng_stop_tracing(session_name, 1);
+       if (ret && ret != -LTTNG_ERR_TRACE_ALREADY_STOPPED) {
+               goto end;
+       }
+
+       ret = _lttng_destroy_session(session_name);
+end:
+       return ret;
+}
+
+/*
+ * Destroy the session without waiting for the data.
+ */
+int lttng_destroy_session_no_wait(const char *session_name)
+{
+       int ret;
+
+       /*
+        * Stop the tracing without waiting for the data.
+        * The session might already have been stopped, so just
+        * skip this error.
+        */
+       ret = _lttng_stop_tracing(session_name, 0);
+       if (ret && ret != -LTTNG_ERR_TRACE_ALREADY_STOPPED) {
+               goto end;
+       }
+
+       ret = _lttng_destroy_session(session_name);
+end:
+       return ret;
+}
+
 /*
  * Ask the session daemon for all available sessions.
  * Sets the contents of the sessions array.
@@ -1623,10 +1700,15 @@ 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 lttcomm_channel_extended);
        struct lttcomm_session_msg lsm;
+       void *extended_at;
 
        if (handle == NULL) {
-               return -LTTNG_ERR_INVALID;
+               ret = -LTTNG_ERR_INVALID;
+               goto end;
        }
 
        memset(&lsm, 0, sizeof(lsm));
@@ -1638,10 +1720,30 @@ int lttng_list_channels(struct lttng_handle *handle,
 
        ret = lttng_ctl_ask_sessiond(&lsm, (void**) channels);
        if (ret < 0) {
-               return ret;
+               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 lttcomm_channel_extended);
        }
 
-       return ret / sizeof(struct lttng_channel);
+       ret = (int) channel_count;
+end:
+       return ret;
 }
 
 /*
@@ -1655,6 +1757,10 @@ int lttng_list_events(struct lttng_handle *handle,
 {
        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) {
@@ -1667,15 +1773,140 @@ int lttng_list_events(struct lttng_handle *handle,
                        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(&lsm, (void**) events);
+       ret = lttng_ctl_ask_sessiond_varlen(&lsm, NULL, 0, (void **) events,
+               (void **) &cmd_header, &cmd_header_len);
        if (ret < 0) {
-               return ret;
+               goto error;
        }
 
-       return ret / sizeof(struct lttng_event);
+       /* 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;
 }
 
 /*
@@ -1774,6 +2005,58 @@ void lttng_channel_set_default_attr(struct lttng_domain *domain,
        }
 }
 
+int lttng_channel_get_discarded_event_count(struct lttng_channel *channel,
+               uint64_t *discarded_events)
+{
+       int ret = 0;
+       struct lttcomm_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 lttcomm_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;
+}
+
 /*
  * Check if session daemon is alive.
  *
@@ -1840,7 +2123,7 @@ int lttng_set_consumer_url(struct lttng_handle *handle,
 
        lsm.u.uri.size = size;
 
-       ret = lttng_ctl_ask_sessiond_varlen(&lsm, uris,
+       ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(&lsm, uris,
                        sizeof(struct lttng_uri) * size, NULL);
 
        free(uris);
@@ -1923,7 +2206,7 @@ int _lttng_create_session_ext(const char *name, const char *url,
                }
        }
 
-       ret = lttng_ctl_ask_sessiond_varlen(&lsm, uris,
+       ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(&lsm, uris,
                        sizeof(struct lttng_uri) * size, NULL);
 
 error:
@@ -1995,7 +2278,7 @@ int lttng_create_session_snapshot(const char *name, const char *snapshot_url)
 
        lsm.u.uri.size = size;
 
-       ret = lttng_ctl_ask_sessiond_varlen(&lsm, uris,
+       ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(&lsm, uris,
                        sizeof(struct lttng_uri) * size, NULL);
 
        free(uris);
@@ -2043,7 +2326,7 @@ int lttng_create_session_live(const char *name, const char *url,
        lsm.u.session_live.nb_uri = size;
        lsm.u.session_live.timer_interval = timer_interval;
 
-       ret = lttng_ctl_ask_sessiond_varlen(&lsm, uris,
+       ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(&lsm, uris,
                        sizeof(struct lttng_uri) * size, NULL);
 
 end:
@@ -2097,6 +2380,36 @@ int lttng_list_tracker_pids(struct lttng_handle *handle,
        return 0;
 }
 
+/*
+ * Regenerate the metadata for a session.
+ * Return 0 on success, a negative error code on error.
+ */
+int lttng_metadata_regenerate(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_METADATA_REGENERATE;
+
+       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;
+}
+
 /*
  * lib constructor.
  */
This page took 0.029448 seconds and 4 git commands to generate.