Fix: unreported error in relay_close_trace_chunk
[lttng-tools.git] / src / bin / lttng-relayd / main.c
index a2904eb08ae044faa2109338f4af5fe1d0c764b2..62a5bd7cefc16026ff05f3e3741e4b4258837fd1 100644 (file)
@@ -40,6 +40,7 @@
 #include <urcu/rculist.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <strings.h>
 
 #include <lttng/lttng.h>
 #include <common/common.h>
@@ -1068,7 +1069,7 @@ static int relay_create_session(const struct lttcomm_relayd_hdr *recv_hdr,
        int ret = 0;
        ssize_t send_ret;
        struct relay_session *session = NULL;
-       struct lttcomm_relayd_status_session reply = {};
+       struct lttcomm_relayd_create_session_reply_2_11 reply = {};
        char session_name[LTTNG_NAME_MAX] = {};
        char hostname[LTTNG_HOST_NAME_MAX] = {};
        uint32_t live_timer = 0;
@@ -1080,6 +1081,9 @@ static int relay_create_session(const struct lttcomm_relayd_hdr *recv_hdr,
        LTTNG_OPTIONAL(uint64_t) id_sessiond = {};
        LTTNG_OPTIONAL(uint64_t) current_chunk_id = {};
        LTTNG_OPTIONAL(time_t) creation_time = {};
+       struct lttng_dynamic_buffer reply_payload;
+
+       lttng_dynamic_buffer_init(&reply_payload);
 
        if (conn->minor < 4) {
                /* From 2.1 to 2.3 */
@@ -1133,24 +1137,59 @@ static int relay_create_session(const struct lttcomm_relayd_hdr *recv_hdr,
        conn->session = session;
        DBG("Created session %" PRIu64, session->id);
 
-       reply.session_id = htobe64(session->id);
+       reply.generic.session_id = htobe64(session->id);
 
 send_reply:
        if (ret < 0) {
-               reply.ret_code = htobe32(LTTNG_ERR_FATAL);
+               reply.generic.ret_code = htobe32(LTTNG_ERR_FATAL);
        } else {
-               reply.ret_code = htobe32(LTTNG_OK);
+               reply.generic.ret_code = htobe32(LTTNG_OK);
        }
 
-       send_ret = conn->sock->ops->sendmsg(conn->sock, &reply, sizeof(reply), 0);
-       if (send_ret < (ssize_t) sizeof(reply)) {
-               ERR("Failed to send \"create session\" command reply (ret = %zd)",
-                               send_ret);
+       if (conn->minor < 11) {
+               /* From 2.1 to 2.10 */
+               ret = lttng_dynamic_buffer_append(&reply_payload,
+                               &reply.generic, sizeof(reply.generic));
+               if (ret) {
+                       ERR("Failed to append \"create session\" command reply header to payload buffer");
+                       ret = -1;
+                       goto end;
+               }
+       } else {
+               const uint32_t output_path_length =
+                               session ? strlen(session->output_path) + 1 : 0;
+
+               reply.output_path_length = htobe32(output_path_length);
+               ret = lttng_dynamic_buffer_append(
+                               &reply_payload, &reply, sizeof(reply));
+               if (ret) {
+                       ERR("Failed to append \"create session\" command reply header to payload buffer");
+                       goto end;
+               }
+
+               if (output_path_length) {
+                       ret = lttng_dynamic_buffer_append(&reply_payload,
+                                       session->output_path,
+                                       output_path_length);
+                       if (ret) {
+                               ERR("Failed to append \"create session\" command reply path to payload buffer");
+                               goto end;
+                       }
+               }
+       }
+
+       send_ret = conn->sock->ops->sendmsg(conn->sock, reply_payload.data,
+                       reply_payload.size, 0);
+       if (send_ret < (ssize_t) reply_payload.size) {
+               ERR("Failed to send \"create session\" command reply of %zu bytes (ret = %zd)",
+                               reply_payload.size, send_ret);
                ret = -1;
        }
+end:
        if (ret < 0 && session) {
                session_put(session);
        }
+       lttng_dynamic_buffer_reset(&reply_payload);
        return ret;
 }
 
@@ -2195,6 +2234,7 @@ static int relay_rotate_session_streams(
                } else {
                        chunk_id_str = chunk_id_buf;
                }
+               session->has_rotated = true;
        }
 
        DBG("Rotate %" PRIu32 " streams of session \"%s\" to chunk \"%s\"",
@@ -2262,113 +2302,7 @@ end_no_reply:
        return ret;
 }
 
-static int init_session_output_directory_handle(struct relay_session *session,
-               struct lttng_directory_handle *handle)
-{
-       int ret;
-       /*
-        * session_directory:
-        *
-        * if base_path is \0'
-        *   hostname/session_name
-        * else
-        *   hostname/base_path
-        */
-       char *session_directory = NULL;
-       /*
-        * relayd_output_path/session_directory
-        * e.g. /home/user/lttng-traces/hostname/session_name
-        */
-       char *full_session_path = NULL;
 
-       /*
-        * If base path is set, it overrides the session name for the
-        * session relative base path. No timestamp is appended if the
-        * base path is overridden.
-        *
-        * If the session name already contains the creation time (e.g.
-        * auto-<timestamp>, don't append yet another timestamp after
-        * the session name in the generated path.
-        *
-        * Otherwise, generate the path with session_name-<timestamp>.
-        */
-       if (session->base_path[0] != '\0') {
-               pthread_mutex_lock(&session->lock);
-               ret = asprintf(&session_directory, "%s/%s", session->hostname,
-                               session->base_path);
-               pthread_mutex_unlock(&session->lock);
-       } else if (session->session_name_contains_creation_time) {
-               pthread_mutex_lock(&session->lock);
-               ret = asprintf(&session_directory, "%s/%s", session->hostname,
-                               session->session_name);
-               pthread_mutex_unlock(&session->lock);
-       } else {
-               char session_creation_datetime[16];
-               size_t strftime_ret;
-               struct tm *timeinfo;
-               time_t creation_time;
-
-               /*
-                * The 2.11+ protocol guarantees that a creation time
-                * is provided for a session. This would indicate a
-                * protocol error or an improper use of this util.
-                */
-               if (!session->creation_time.is_set) {
-                       ERR("Creation time missing for session \"%s\" (protocol error)",
-                                       session->session_name);
-                       ret = -1;
-                       goto end;
-               }
-               creation_time = LTTNG_OPTIONAL_GET(session->creation_time);
-
-               timeinfo = localtime(&creation_time);
-               if (!timeinfo) {
-                       ERR("Failed to get timeinfo while initializing session output directory handle");
-                       ret = -1;
-                       goto end;
-               }
-               strftime_ret = strftime(session_creation_datetime,
-                               sizeof(session_creation_datetime),
-                               "%Y%m%d-%H%M%S", timeinfo);
-               if (strftime_ret == 0) {
-                       ERR("Failed to format session creation timestamp while initializing session output directory handle");
-                       ret = -1;
-                       goto end;
-               }
-               pthread_mutex_lock(&session->lock);
-               ret = asprintf(&session_directory, "%s/%s-%s",
-                               session->hostname, session->session_name,
-                               session_creation_datetime);
-               pthread_mutex_unlock(&session->lock);
-       }
-       if (ret < 0) {
-               PERROR("Failed to format session directory name");
-               goto end;
-       }
-
-       full_session_path = create_output_path(session_directory);
-       if (!full_session_path) {
-               ret = -1;
-               goto end;
-       }
-
-       ret = utils_mkdir_recursive(
-                       full_session_path, S_IRWXU | S_IRWXG, -1, -1);
-       if (ret) {
-               ERR("Failed to create session output path \"%s\"",
-                               full_session_path);
-               goto end;
-       }
-
-       ret = lttng_directory_handle_init(handle, full_session_path);
-       if (ret) {
-               goto end;
-       }
-end:
-       free(session_directory);
-       free(full_session_path);
-       return ret;
-}
 
 /*
  * relay_create_trace_chunk: create a new trace chunk
@@ -2455,13 +2389,6 @@ static int relay_create_trace_chunk(const struct lttcomm_relayd_hdr *recv_hdr,
                }
        }
 
-       ret = init_session_output_directory_handle(
-                       conn->session, &session_output);
-       if (ret) {
-               reply_code = LTTNG_ERR_CREATE_DIR_FAIL;
-               goto end;
-       }
-
        chunk_status = lttng_trace_chunk_set_credentials_current_user(chunk);
        if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
                reply_code = LTTNG_ERR_UNK;
@@ -2469,7 +2396,14 @@ static int relay_create_trace_chunk(const struct lttcomm_relayd_hdr *recv_hdr,
                goto end;
        }
 
+       ret = session_init_output_directory_handle(
+                       conn->session, &session_output);
+       if (ret) {
+               reply_code = LTTNG_ERR_CREATE_DIR_FAIL;
+               goto end;
+       }
        chunk_status = lttng_trace_chunk_set_as_owner(chunk, &session_output);
+       lttng_directory_handle_fini(&session_output);
        if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
                reply_code = LTTNG_ERR_UNK;
                ret = -1;
@@ -2525,7 +2459,6 @@ end:
 end_no_reply:
        lttng_trace_chunk_put(chunk);
        lttng_trace_chunk_put(published_chunk);
-       lttng_directory_handle_fini(&session_output);
        return ret;
 }
 
@@ -2536,11 +2469,11 @@ static int relay_close_trace_chunk(const struct lttcomm_relayd_hdr *recv_hdr,
                struct relay_connection *conn,
                const struct lttng_buffer_view *payload)
 {
-       int ret = 0;
+       int ret = 0, buf_ret;
        ssize_t send_ret;
        struct relay_session *session = conn->session;
        struct lttcomm_relayd_close_trace_chunk *msg;
-       struct lttcomm_relayd_generic_reply reply = {};
+       struct lttcomm_relayd_close_trace_chunk_reply reply = {};
        struct lttng_buffer_view header_view;
        struct lttng_trace_chunk *chunk = NULL;
        enum lttng_error_code reply_code = LTTNG_OK;
@@ -2548,6 +2481,12 @@ static int relay_close_trace_chunk(const struct lttcomm_relayd_hdr *recv_hdr,
        uint64_t chunk_id;
        LTTNG_OPTIONAL(enum lttng_trace_chunk_command_type) close_command = {};
        time_t close_timestamp;
+       char closed_trace_chunk_path[LTTNG_PATH_MAX];
+       size_t path_length = 0;
+       const char *chunk_name = NULL;
+       struct lttng_dynamic_buffer reply_payload;
+
+       lttng_dynamic_buffer_init(&reply_payload);
 
        if (!session || !conn->version_check_done) {
                ERR("Trying to close a trace chunk before version check");
@@ -2623,6 +2562,53 @@ static int relay_close_trace_chunk(const struct lttcomm_relayd_hdr *recv_hdr,
                        goto end_unlock_session;
                }
        }
+       chunk_status = lttng_trace_chunk_get_name(chunk, &chunk_name, NULL);
+       if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
+               ERR("Failed to get chunk name");
+               ret = -1;
+               reply_code = LTTNG_ERR_UNK;
+               goto end_unlock_session;
+       }
+       if (!session->has_rotated && !session->snapshot) {
+               ret = lttng_strncpy(closed_trace_chunk_path,
+                               session->output_path,
+                               sizeof(closed_trace_chunk_path));
+               if (ret) {
+                       ERR("Failed to send trace chunk path: path length of %zu bytes exceeds the maximal allowed length of %zu bytes",
+                                       strlen(session->output_path),
+                                       sizeof(closed_trace_chunk_path));
+                       reply_code = LTTNG_ERR_NOMEM;
+                       ret = -1;
+                       goto end_unlock_session;
+               }
+       } else {
+               if (session->snapshot) {
+                       ret = snprintf(closed_trace_chunk_path,
+                                       sizeof(closed_trace_chunk_path),
+                                       "%s/%s", session->output_path,
+                                       chunk_name);
+               } else {
+                       ret = snprintf(closed_trace_chunk_path,
+                                       sizeof(closed_trace_chunk_path),
+                                       "%s/" DEFAULT_ARCHIVED_TRACE_CHUNKS_DIRECTORY
+                                       "/%s",
+                                       session->output_path, chunk_name);
+               }
+               if (ret < 0 || ret == sizeof(closed_trace_chunk_path)) {
+                       ERR("Failed to format closed trace chunk resulting path");
+                       reply_code = ret < 0 ? LTTNG_ERR_UNK : LTTNG_ERR_NOMEM;
+                       ret = -1;
+                       goto end_unlock_session;
+               }
+       }
+       DBG("Reply chunk path on close: %s", closed_trace_chunk_path);
+       path_length = strlen(closed_trace_chunk_path) + 1;
+       if (path_length > UINT32_MAX) {
+               ERR("Closed trace chunk path exceeds the maximal length allowed by the protocol");
+               ret = -1;
+               reply_code = LTTNG_ERR_INVALID_PROTOCOL;
+               goto end_unlock_session;
+       }
 
        if (session->current_trace_chunk == chunk) {
                /*
@@ -2642,18 +2628,37 @@ end_unlock_session:
        pthread_mutex_unlock(&session->lock);
 
 end:
-       reply.ret_code = htobe32((uint32_t) reply_code);
+       reply.generic.ret_code = htobe32((uint32_t) reply_code);
+       reply.path_length = htobe32((uint32_t) path_length);
+       buf_ret = lttng_dynamic_buffer_append(
+                       &reply_payload, &reply, sizeof(reply));
+       if (buf_ret) {
+               ERR("Failed to append \"close trace chunk\" command reply header to payload buffer");
+               goto end_no_reply;
+       }
+
+       if (reply_code == LTTNG_OK) {
+               buf_ret = lttng_dynamic_buffer_append(&reply_payload,
+                               closed_trace_chunk_path, path_length);
+               if (buf_ret) {
+                       ERR("Failed to append \"close trace chunk\" command reply path to payload buffer");
+                       goto end_no_reply;
+               }
+       }
+
        send_ret = conn->sock->ops->sendmsg(conn->sock,
-                       &reply,
-                       sizeof(struct lttcomm_relayd_generic_reply),
+                       reply_payload.data,
+                       reply_payload.size,
                        0);
-       if (send_ret < (ssize_t) sizeof(reply)) {
-               ERR("Failed to send \"create trace chunk\" command reply (ret = %zd)",
-                               send_ret);
+       if (send_ret < reply_payload.size) {
+               ERR("Failed to send \"close trace chunk\" command reply of %zu bytes (ret = %zd)",
+                               reply_payload.size, send_ret);
                ret = -1;
+               goto end_no_reply;
        }
 end_no_reply:
        lttng_trace_chunk_put(chunk);
+       lttng_dynamic_buffer_reset(&reply_payload);
        return ret;
 }
 
This page took 0.027935 seconds and 4 git commands to generate.