CLI: Add lttng_trace_format_descriptor to lttng_session_extended
[lttng-tools.git] / src / bin / lttng-sessiond / cmd.cpp
index 0b74920556d59230a5bf2a87adcef42590dd1627..214085c55a29bd11c4f548db101eb64e6c488989 100644 (file)
@@ -9,6 +9,7 @@
 
 #define _LGPL_SOURCE
 #include <algorithm>
+#include <exception>
 #include <inttypes.h>
 #include <stdio.h>
 #include <sys/stat.h>
@@ -760,9 +761,8 @@ error:
  * On success, the relayd_sock pointer is set to the created socket.
  * Else, it remains untouched and an LTTng error code is returned.
  */
-static enum lttng_error_code create_connect_relayd(struct lttng_uri *uri,
-               struct lttcomm_relayd_sock **relayd_sock,
-               struct consumer_output *consumer)
+static lttng_error_code create_connect_relayd(
+               struct lttng_uri *uri, struct lttcomm_relayd_sock **relayd_sock)
 {
        int ret;
        enum lttng_error_code status = LTTNG_OK;
@@ -791,8 +791,6 @@ static enum lttng_error_code create_connect_relayd(struct lttng_uri *uri,
 
        /* Create socket for control stream. */
        if (uri->stype == LTTNG_STREAM_CONTROL) {
-               uint64_t result_flags;
-
                DBG3("Creating relayd stream socket from URI");
 
                /* Check relayd version */
@@ -805,18 +803,6 @@ static enum lttng_error_code create_connect_relayd(struct lttng_uri *uri,
                        status = LTTNG_ERR_RELAYD_CONNECT_FAIL;
                        goto close_sock;
                }
-               consumer->relay_major_version = rsock->major;
-               consumer->relay_minor_version = rsock->minor;
-               ret = relayd_get_configuration(rsock, 0,
-                               &result_flags);
-               if (ret < 0) {
-                       ERR("Unable to get relayd configuration");
-                       status = LTTNG_ERR_RELAYD_CONNECT_FAIL;
-                       goto close_sock;
-               }
-               if (result_flags & LTTCOMM_RELAYD_CONFIGURATION_FLAG_CLEAR_ALLOWED) {
-                       consumer->relay_allows_clear = true;
-               }
        } else if (uri->stype == LTTNG_STREAM_DATA) {
                DBG3("Creating relayd data socket from URI");
        } else {
@@ -846,27 +832,21 @@ error:
  *
  * Returns LTTNG_OK on success or an LTTng error code on failure.
  */
-static enum lttng_error_code send_consumer_relayd_socket(
-               unsigned int session_id,
+static enum lttng_error_code send_consumer_relayd_socket(unsigned int session_id,
                struct lttng_uri *relayd_uri,
                struct consumer_output *consumer,
                struct consumer_socket *consumer_sock,
-               const char *session_name, const char *hostname,
-               const char *base_path, int session_live_timer,
+               const char *session_name,
+               const char *hostname,
+               const char *base_path,
+               int session_live_timer,
                const uint64_t *current_chunk_id,
                time_t session_creation_time,
-               bool session_name_contains_creation_time)
+               bool session_name_contains_creation_time,
+               struct lttcomm_relayd_sock& rsock)
 {
        int ret;
-       struct lttcomm_relayd_sock *rsock = NULL;
-       enum lttng_error_code status;
-
-       /* Connect to relayd and make version check if uri is the control. */
-       status = create_connect_relayd(relayd_uri, &rsock, consumer);
-       if (status != LTTNG_OK) {
-               goto relayd_comm_error;
-       }
-       LTTNG_ASSERT(rsock);
+       enum lttng_error_code status = LTTNG_OK;
 
        /* Set the network sequence index if not set. */
        if (consumer->net_seq_index == (uint64_t) -1ULL) {
@@ -881,14 +861,13 @@ static enum lttng_error_code send_consumer_relayd_socket(
        }
 
        /* Send relayd socket to consumer. */
-       ret = consumer_send_relayd_socket(consumer_sock, rsock, consumer,
-                       relayd_uri->stype, session_id,
-                       session_name, hostname, base_path,
-                       session_live_timer, current_chunk_id,
-                       session_creation_time, session_name_contains_creation_time);
+       ret = consumer_send_relayd_socket(consumer_sock, &rsock, consumer, relayd_uri->stype,
+                       session_id, session_name, hostname, base_path, session_live_timer,
+                       current_chunk_id, session_creation_time,
+                       session_name_contains_creation_time);
        if (ret < 0) {
                status = LTTNG_ERR_ENABLE_CONSUMER_FAIL;
-               goto close_sock;
+               goto error;
        }
 
        /* Flag that the corresponding socket was sent. */
@@ -898,12 +877,7 @@ static enum lttng_error_code send_consumer_relayd_socket(
                consumer_sock->data_sock_sent = 1;
        }
 
-       /*
-        * Close socket which was dup on the consumer side. The session daemon does
-        * NOT keep track of the relayd socket(s) once transfer to the consumer.
-        */
-
-close_sock:
+error:
        if (status != LTTNG_OK) {
                /*
                 * The consumer output for this session should not be used anymore
@@ -912,13 +886,34 @@ close_sock:
                 */
                consumer->enabled = 0;
        }
-       (void) relayd_close(rsock);
-       free(rsock);
 
-relayd_comm_error:
        return status;
 }
 
+static bool is_trace_format_configuration_supported(
+               uint64_t supported_trace_format, lttng::trace_format_descriptor& trace_format)
+{
+       static const std::unordered_map<enum lttng_trace_format_descriptor_type,
+                       enum lttcomm_relayd_configuration_trace_format_flag>
+                       mapping = {
+                                       {LTTNG_TRACE_FORMAT_DESCRIPTOR_TYPE_CTF_1,
+                                                       LTTCOMM_RELAYD_CONFIGURATION_TRACE_FORMAT_SUPPORTED_CTF1},
+                                       {LTTNG_TRACE_FORMAT_DESCRIPTOR_TYPE_CTF_2,
+                                                       LTTCOMM_RELAYD_CONFIGURATION_TRACE_FORMAT_SUPPORTED_CTF2},
+                       };
+
+       auto it = mapping.find(trace_format.type());
+       if (it == mapping.end()) {
+               return false;
+       }
+
+       if (!(supported_trace_format & it->second)) {
+               return false;
+       }
+
+       return true;
+}
+
 /*
  * Send both relayd sockets to a specific consumer and domain.  This is a
  * helper function to facilitate sending the information to the consumer for a
@@ -928,25 +923,57 @@ relayd_comm_error:
  *
  * Returns LTTNG_OK, or an LTTng error code on failure.
  */
-static enum lttng_error_code send_consumer_relayd_sockets(
-               unsigned int session_id, struct consumer_output *consumer,
-               struct consumer_socket *sock, const char *session_name,
-               const char *hostname, const char *base_path, int session_live_timer,
-               const uint64_t *current_chunk_id, time_t session_creation_time,
-               bool session_name_contains_creation_time)
+static lttng_error_code send_consumer_relayd_sockets(const ltt_session& session,
+               struct consumer_output *consumer,
+               struct consumer_socket *sock,
+               const char *base_path,
+               const uint64_t *current_chunk_id)
 {
        enum lttng_error_code status = LTTNG_OK;
+       struct lttcomm_relayd_sock *control_sock = nullptr;
+       struct lttcomm_relayd_sock *data_sock = nullptr;
 
        LTTNG_ASSERT(consumer);
        LTTNG_ASSERT(sock);
 
        /* Sending control relayd socket. */
        if (!sock->control_sock_sent) {
-               status = send_consumer_relayd_socket(session_id,
-                               &consumer->dst.net.control, consumer, sock,
-                               session_name, hostname, base_path, session_live_timer,
-                               current_chunk_id, session_creation_time,
-                               session_name_contains_creation_time);
+               int ret;
+               uint64_t result_flags = 0;
+               uint64_t supported_trace_format = 0;
+               /* Connect to relayd and make version check if uri is the control. */
+               status = create_connect_relayd(&consumer->dst.net.control, &control_sock);
+               if (status != LTTNG_OK) {
+                       goto error;
+               }
+               LTTNG_ASSERT(control_sock);
+
+               consumer->relay_major_version = control_sock->major;
+               consumer->relay_minor_version = control_sock->minor;
+
+               ret = relayd_get_configuration(control_sock, 0, result_flags, nullptr);
+               if (ret < 0) {
+                       ERR("Unable to get relayd configuration");
+                       status = LTTNG_ERR_RELAYD_CONNECT_FAIL;
+                       goto error;
+               }
+
+               if (result_flags & LTTCOMM_RELAYD_CONFIGURATION_FLAG_CLEAR_ALLOWED) {
+                       consumer->relay_allows_clear = true;
+               }
+
+               if (!is_trace_format_configuration_supported(
+                                   supported_trace_format, *session.trace_format)) {
+                       ERR("Relayd does not support the requested trace format");
+                       status = LTTNG_ERR_TRACE_FORMAT_UNSUPPORTED_RELAY_DAEMON;
+                       goto error;
+               }
+
+               status = send_consumer_relayd_socket(session.id, &consumer->dst.net.control,
+                               consumer, sock, session.name, session.hostname, base_path,
+                               session.live_timer, current_chunk_id, session.creation_time,
+                               session.name_contains_creation_time, *control_sock);
+
                if (status != LTTNG_OK) {
                        goto error;
                }
@@ -954,17 +981,34 @@ static enum lttng_error_code send_consumer_relayd_sockets(
 
        /* Sending data relayd socket. */
        if (!sock->data_sock_sent) {
-               status = send_consumer_relayd_socket(session_id,
-                               &consumer->dst.net.data, consumer, sock,
-                               session_name, hostname, base_path, session_live_timer,
-                               current_chunk_id, session_creation_time,
-                               session_name_contains_creation_time);
+               /* Connect to relayd and make version check if uri is the control. */
+               status = create_connect_relayd(&consumer->dst.net.data, &data_sock);
+               if (status != LTTNG_OK) {
+                       goto error;
+               }
+               LTTNG_ASSERT(data_sock);
+
+               status = send_consumer_relayd_socket(session.id, &consumer->dst.net.data, consumer,
+                               sock, session.name, session.hostname, base_path, session.live_timer,
+                               current_chunk_id, session.creation_time,
+                               session.name_contains_creation_time, *data_sock);
+
                if (status != LTTNG_OK) {
                        goto error;
                }
        }
 
 error:
+       if (control_sock != nullptr) {
+               relayd_close(control_sock);
+               free(control_sock);
+       }
+
+       if (data_sock != nullptr) {
+               relayd_close(data_sock);
+               free(data_sock);
+       }
+
        return status;
 }
 
@@ -1006,17 +1050,12 @@ int cmd_setup_relayd(struct ltt_session *session)
        if (usess && usess->consumer && usess->consumer->type == CONSUMER_DST_NET
                        && usess->consumer->enabled) {
                /* For each consumer socket, send relayd sockets */
-               cds_lfht_for_each_entry(usess->consumer->socks->ht, &iter.iter,
-                               socket, node.node) {
+               cds_lfht_for_each_entry (
+                               usess->consumer->socks->ht, &iter.iter, socket, node.node) {
                        pthread_mutex_lock(socket->lock);
-                       ret = send_consumer_relayd_sockets(session->id,
-                                       usess->consumer, socket,
-                                       session->name, session->hostname,
+                       ret = send_consumer_relayd_sockets(*session, usess->consumer, socket,
                                        session->base_path,
-                                       session->live_timer,
-                                       current_chunk_id.is_set ? &current_chunk_id.value : NULL,
-                                       session->creation_time,
-                                       session->name_contains_creation_time);
+                                       current_chunk_id.is_set ? &current_chunk_id.value : NULL);
                        pthread_mutex_unlock(socket->lock);
                        if (ret != LTTNG_OK) {
                                goto error;
@@ -1034,17 +1073,12 @@ int cmd_setup_relayd(struct ltt_session *session)
 
        if (ksess && ksess->consumer && ksess->consumer->type == CONSUMER_DST_NET
                        && ksess->consumer->enabled) {
-               cds_lfht_for_each_entry(ksess->consumer->socks->ht, &iter.iter,
-                               socket, node.node) {
+               cds_lfht_for_each_entry (
+                               ksess->consumer->socks->ht, &iter.iter, socket, node.node) {
                        pthread_mutex_lock(socket->lock);
-                       ret = send_consumer_relayd_sockets(session->id,
-                                       ksess->consumer, socket,
-                                       session->name, session->hostname,
+                       ret = send_consumer_relayd_sockets(*session, ksess->consumer, socket,
                                        session->base_path,
-                                       session->live_timer,
-                                       current_chunk_id.is_set ? &current_chunk_id.value : NULL,
-                                       session->creation_time,
-                                       session->name_contains_creation_time);
+                                       current_chunk_id.is_set ? &current_chunk_id.value : NULL);
                        pthread_mutex_unlock(socket->lock);
                        if (ret != LTTNG_OK) {
                                goto error;
@@ -1285,6 +1319,25 @@ end:
        return ret;
 }
 
+static enum lttng_error_code kernel_domain_check_trace_format_requirements(
+               const lttng::trace_format_descriptor& descriptor)
+{
+       enum lttng_error_code ret_code = LTTNG_OK;
+       switch (descriptor.type()) {
+       case LTTNG_TRACE_FORMAT_DESCRIPTOR_TYPE_CTF_1:
+               /* Supported by all kernel tracer. */
+               break;
+       case LTTNG_TRACE_FORMAT_DESCRIPTOR_TYPE_CTF_2:
+               if (!kernel_supports_ctf2()) {
+                       ret_code = LTTNG_ERR_TRACE_FORMAT_UNSUPPORTED_KERNEL_TRACER;
+               }
+               break;
+       default:
+               abort();
+       }
+       return ret_code;
+}
+
 static enum lttng_error_code cmd_enable_channel_internal(
                struct ltt_session *session,
                const struct lttng_domain *domain,
@@ -1342,6 +1395,13 @@ static enum lttng_error_code cmd_enable_channel_internal(
                                        attr->name, session->name);
                        lttng_channel_set_monitor_timer_interval(attr, 0);
                }
+
+               ret_code = kernel_domain_check_trace_format_requirements(*session->trace_format);
+               if (ret_code != LTTNG_OK) {
+                       WARN("Kernel tracer does not support the configured trace format of session '%s'",
+                                       session->name);
+                       goto error;
+               }
                break;
        }
        case LTTNG_DOMAIN_UST:
@@ -2751,7 +2811,7 @@ int cmd_start_trace(struct ltt_session *session)
                goto error;
        }
 
-       session->active = 1;
+       session->active = true;
        session->rotated_after_last_stop = false;
        session->cleared_after_last_stop = false;
        if (session->output_traces && !session->current_trace_chunk) {
@@ -2846,9 +2906,9 @@ int cmd_start_trace(struct ltt_session *session)
 error:
        if (ret == LTTNG_OK) {
                /* Flag this after a successful start. */
-               session->has_been_started |= 1;
+               session->has_been_started = true;
        } else {
-               session->active = 0;
+               session->active = false;
                /* Restore initial state on error. */
                session->rotated_after_last_stop =
                                session_rotated_after_last_stop;
@@ -3107,6 +3167,8 @@ enum lttng_error_code cmd_create_session_from_descriptor(
        const char *session_name;
        struct ltt_session *new_session = NULL;
        enum lttng_session_descriptor_status descriptor_status;
+       const lttng_trace_format_descriptor *trace_format_descriptor = NULL;
+       lttng::trace_format_descriptor::uptr trace_format_descriptor_ptr;
 
        session_lock_list();
        if (home_path) {
@@ -3130,7 +3192,25 @@ enum lttng_error_code cmd_create_session_from_descriptor(
                goto end;
        }
 
-       ret_code = session_create(session_name, creds->uid, creds->gid,
+       descriptor_status = lttng_session_descriptor_get_trace_format_descriptor(
+                       descriptor, &trace_format_descriptor);
+       if (descriptor_status != LTTNG_SESSION_DESCRIPTOR_STATUS_OK) {
+               ret_code = LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       try {
+               trace_format_descriptor_ptr =
+                               reinterpret_cast<const lttng::trace_format_descriptor *>(
+                                               trace_format_descriptor)
+                                               ->clone();
+       } catch (std::exception& e) {
+               ERR("%s", e.what());
+               ret_code = LTTNG_ERR_UNK;
+               goto end;
+       }
+
+       ret_code = session_create(session_name, creds->uid, creds->gid, trace_format_descriptor_ptr,
                        &new_session);
        if (ret_code != LTTNG_OK) {
                goto end;
@@ -3946,24 +4026,42 @@ end:
  * The session list lock MUST be acquired before calling this function. Use
  * session_lock_list() and session_unlock_list().
  */
-void cmd_list_lttng_sessions(struct lttng_session *sessions,
-               size_t session_count, uid_t uid, gid_t gid)
+enum lttng_error_code cmd_list_lttng_sessions(
+               struct lttng_payload *reply_payload, uid_t uid, gid_t gid)
 {
-       int ret;
-       unsigned int i = 0;
+       int buffer_resize_ret;
+       enum lttng_error_code ret_code = LTTNG_OK;
+       struct lttcomm_list_command_header reply_command_header = {};
+       size_t reply_command_header_offset;
        struct ltt_session *session;
        struct ltt_session_list *list = session_get_list();
-       struct lttng_session_extended *extended =
-                       (typeof(extended)) (&sessions[session_count]);
+       int ret;
+       unsigned int i = 0;
+
+       assert(reply_payload);
+
+       /* Reserve space for command reply header. */
+       reply_command_header_offset = reply_payload->buffer.size;
+       buffer_resize_ret = lttng_dynamic_buffer_set_size(&reply_payload->buffer,
+                       reply_command_header_offset + sizeof(struct lttcomm_list_command_header));
+       if (buffer_resize_ret) {
+               ret_code = LTTNG_ERR_NOMEM;
+               goto error;
+       }
 
        DBG("Getting all available session for UID %d GID %d",
                        uid, gid);
-       /*
-        * Iterate over session list and append data after the control struct in
-        * the buffer.
-        */
+
        cds_list_for_each_entry(session, &list->head, list) {
+               struct lttng_session tmp_session = {};
+               struct lttng_session_extended tmp_extended = {};
+               struct lttng_payload trace_format_buffer;
+               lttng_payload_init(&trace_format_buffer);
+
+               tmp_session.extended.ptr = &tmp_extended;
+
                if (!session_get(session)) {
+                       lttng_payload_reset(&trace_format_buffer);
                        continue;
                }
                /*
@@ -3972,6 +4070,7 @@ void cmd_list_lttng_sessions(struct lttng_session *sessions,
                if (!session_access_ok(session, uid) ||
                                session->destroyed) {
                        session_put(session);
+                       lttng_payload_reset(&trace_format_buffer);
                        continue;
                }
 
@@ -3981,10 +4080,10 @@ void cmd_list_lttng_sessions(struct lttng_session *sessions,
                if (session->consumer->type == CONSUMER_DST_NET ||
                                (ksess && ksess->consumer->type == CONSUMER_DST_NET) ||
                                (usess && usess->consumer->type == CONSUMER_DST_NET)) {
-                       ret = build_network_session_path(sessions[i].path,
-                                       sizeof(sessions[i].path), session);
+                       ret = build_network_session_path(
+                                       tmp_session.path, sizeof(tmp_session.path), session);
                } else {
-                       ret = snprintf(sessions[i].path, sizeof(sessions[i].path), "%s",
+                       ret = snprintf(tmp_session.path, sizeof(tmp_session.path), "%s",
                                        session->consumer->dst.session_root_path);
                }
                if (ret < 0) {
@@ -3993,16 +4092,39 @@ void cmd_list_lttng_sessions(struct lttng_session *sessions,
                        continue;
                }
 
-               strncpy(sessions[i].name, session->name, NAME_MAX);
-               sessions[i].name[NAME_MAX - 1] = '\0';
-               sessions[i].enabled = session->active;
-               sessions[i].snapshot_mode = session->snapshot_mode;
-               sessions[i].live_timer_interval = session->live_timer;
-               extended[i].creation_time.value = (uint64_t) session->creation_time;
-               extended[i].creation_time.is_set = 1;
+               session->trace_format->serialize(&trace_format_buffer);
+
+               strncpy(tmp_session.name, session->name, NAME_MAX);
+               tmp_session.name[NAME_MAX - 1] = '\0';
+               tmp_session.enabled = session->active;
+               tmp_session.snapshot_mode = session->snapshot_mode;
+               tmp_session.live_timer_interval = session->live_timer;
+               LTTNG_OPTIONAL_SET(&tmp_extended.creation_time, (uint64_t) session->creation_time);
+               tmp_extended.serialized_trace_format_descriptor =
+                               lttng_buffer_view_from_dynamic_buffer(&trace_format_buffer.buffer,
+                                               0, trace_format_buffer.buffer.size);
+               ret = lttng_session_serialize(&tmp_session, reply_payload);
+               lttng_payload_reset(&trace_format_buffer);
+               if (ret) {
+                       ret_code = LTTNG_ERR_FATAL;
+                       goto error;
+               }
                i++;
                session_put(session);
        }
+
+       if (i > UINT32_MAX) {
+               ret_code = LTTNG_ERR_OVERFLOW;
+               goto error;
+       }
+
+       /* Update command reply header. */
+       reply_command_header.count = (uint32_t) i;
+       memcpy(reply_payload->buffer.data + reply_command_header_offset, &reply_command_header,
+                       sizeof(reply_command_header));
+       ret_code = LTTNG_OK;
+error:
+       return ret_code;
 }
 
 /*
@@ -4979,17 +5101,10 @@ static enum lttng_error_code set_relayd_for_snapshot(
         * snapshot output.
         */
        rcu_read_lock();
-       cds_lfht_for_each_entry(output->socks->ht, &iter.iter,
-                       socket, node.node) {
+       cds_lfht_for_each_entry (output->socks->ht, &iter.iter, socket, node.node) {
                pthread_mutex_lock(socket->lock);
-               status = send_consumer_relayd_sockets(session->id,
-                               output, socket,
-                               session->name, session->hostname,
-                               base_path,
-                               session->live_timer,
-                               current_chunk_id.is_set ? &current_chunk_id.value : NULL,
-                               session->creation_time,
-                               session->name_contains_creation_time);
+               status = send_consumer_relayd_sockets(*session, output, socket, base_path,
+                               current_chunk_id.is_set ? &current_chunk_id.value : NULL);
                pthread_mutex_unlock(socket->lock);
                if (status != LTTNG_OK) {
                        rcu_read_unlock();
This page took 0.039743 seconds and 5 git commands to generate.