Fix: return NULL on trace chunk registry failure
[lttng-tools.git] / src / common / trace-chunk.c
index 53cc08a2ca4d3eb5b2e624c618a4ebe48cef29ef..9f0919a8896b7756121ffe18d6580e0550637f37 100644 (file)
@@ -77,7 +77,7 @@ struct lttng_trace_chunk {
        struct lttng_dynamic_pointer_array top_level_directories;
        /* Is contained within an lttng_trace_chunk_registry_element? */
        bool in_registry_element;
-       bool name_overriden;
+       bool name_overridden;
        char *name;
        /* An unset id means the chunk is anonymous. */
        LTTNG_OPTIONAL(uint64_t) id;
@@ -209,7 +209,7 @@ void lttng_trace_chunk_init(struct lttng_trace_chunk *chunk)
 {
        urcu_ref_init(&chunk->ref);
        pthread_mutex_init(&chunk->lock, NULL);
-       lttng_dynamic_pointer_array_init(&chunk->top_level_directories);
+       lttng_dynamic_pointer_array_init(&chunk->top_level_directories, free);
 }
 
 static
@@ -224,7 +224,7 @@ void lttng_trace_chunk_fini(struct lttng_trace_chunk *chunk)
        }
        free(chunk->name);
        chunk->name = NULL;
-       lttng_dynamic_pointer_array_reset(&chunk->top_level_directories, free);
+       lttng_dynamic_pointer_array_reset(&chunk->top_level_directories);
        pthread_mutex_destroy(&chunk->lock);
 }
 
@@ -366,12 +366,14 @@ enum lttng_trace_chunk_status lttng_trace_chunk_set_close_timestamp(
                goto end;
        }
        LTTNG_OPTIONAL_SET(&chunk->timestamp_close, close_ts);
-       free(chunk->name);
-       chunk->name = generate_chunk_name(LTTNG_OPTIONAL_GET(chunk->id),
-                       LTTNG_OPTIONAL_GET(chunk->timestamp_creation),
-                       &close_ts);
-       if (!chunk->name) {
-               status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+       if (!chunk->name_overridden) {
+               free(chunk->name);
+               chunk->name = generate_chunk_name(LTTNG_OPTIONAL_GET(chunk->id),
+                               LTTNG_OPTIONAL_GET(chunk->timestamp_creation),
+                               &close_ts);
+               if (!chunk->name) {
+                       status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+               }
        }
 end:
        pthread_mutex_unlock(&chunk->lock);
@@ -381,13 +383,13 @@ end:
 LTTNG_HIDDEN
 enum lttng_trace_chunk_status lttng_trace_chunk_get_name(
                struct lttng_trace_chunk *chunk, const char **name,
-               bool *name_overriden)
+               bool *name_overridden)
 {
        enum lttng_trace_chunk_status status = LTTNG_TRACE_CHUNK_STATUS_OK;
 
        pthread_mutex_lock(&chunk->lock);
-        if (name_overriden) {
-               *name_overriden = chunk->name_overriden;
+        if (name_overridden) {
+               *name_overridden = chunk->name_overridden;
         }
         if (!chunk->name) {
                status = LTTNG_TRACE_CHUNK_STATUS_NONE;
@@ -399,6 +401,27 @@ end:
        return status;
 }
 
+static
+bool is_valid_chunk_name(const char *name)
+{
+       size_t len;
+
+       if (!name) {
+               return false;
+       }
+
+       len = lttng_strnlen(name, LTTNG_NAME_MAX);
+       if (len == 0 || len == LTTNG_NAME_MAX) {
+               return false;
+       }
+
+       if (strchr(name, '/') || strchr(name, '.')) {
+               return false;
+       }
+
+       return true;
+}
+
 LTTNG_HIDDEN
 enum lttng_trace_chunk_status lttng_trace_chunk_override_name(
                struct lttng_trace_chunk *chunk, const char *name)
@@ -407,7 +430,7 @@ enum lttng_trace_chunk_status lttng_trace_chunk_override_name(
        char *new_name;
        enum lttng_trace_chunk_status status = LTTNG_TRACE_CHUNK_STATUS_OK;
 
-       if (!name || !*name || strnlen(name, LTTNG_NAME_MAX) == LTTNG_NAME_MAX) {
+       if (!is_valid_chunk_name(name)) {
                ERR("Attempted to set an invalid name on a trace chunk: name = %s",
                                name ? : "NULL");
                status = LTTNG_TRACE_CHUNK_STATUS_INVALID_ARGUMENT;
@@ -429,7 +452,7 @@ enum lttng_trace_chunk_status lttng_trace_chunk_override_name(
        }
        free(chunk->name);
        chunk->name = new_name;
-       chunk->name_overriden = true;
+       chunk->name_overridden = true;
 end_unlock:    
        pthread_mutex_unlock(&chunk->lock);
 end:
@@ -633,7 +656,7 @@ int add_top_level_directory_unique(struct lttng_trace_chunk *chunk,
        }
 
        if (!found) {
-               char *copy = strndup(new_path, new_path_top_level_len);
+               char *copy = lttng_strndup(new_path, new_path_top_level_len);
 
                DBG("Adding new top-level directory \"%s\" to trace chunk \"%s\"",
                                new_path, chunk->name ? : "(unnamed)");
@@ -800,19 +823,26 @@ void lttng_trace_chunk_move_to_completed(struct lttng_trace_chunk *trace_chunk)
        int ret;
        char *directory_to_rename = NULL;
        bool free_directory_to_rename = false;
-       const int session_dirfd =
-                       trace_chunk->session_output_directory.value.dirfd;
        char *archived_chunk_name = NULL;
        const uint64_t chunk_id = LTTNG_OPTIONAL_GET(trace_chunk->id);
        const time_t creation_timestamp =
                        LTTNG_OPTIONAL_GET(trace_chunk->timestamp_creation);
        const time_t close_timestamp =
                        LTTNG_OPTIONAL_GET(trace_chunk->timestamp_close);
-       LTTNG_OPTIONAL(struct lttng_directory_handle) archived_chunks_directory;
+       LTTNG_OPTIONAL(struct lttng_directory_handle) archived_chunks_directory = {};
+
+       if (!trace_chunk->mode.is_set ||
+                       trace_chunk->mode.value != TRACE_CHUNK_MODE_OWNER ||
+                       !trace_chunk->session_output_directory.is_set) {
+               /*
+                * This command doesn't need to run if the output is remote
+                * or if the trace chunk is not owned by this process.
+                */
+               goto end;
+       }
 
-       assert(trace_chunk->mode.is_set);
        assert(trace_chunk->mode.value == TRACE_CHUNK_MODE_OWNER);
-       assert(!trace_chunk->name_overriden);
+       assert(!trace_chunk->name_overridden);
 
        /*
         * The fist trace chunk of a session is directly output to the
@@ -845,17 +875,18 @@ void lttng_trace_chunk_move_to_completed(struct lttng_trace_chunk *trace_chunk)
                }
 
                for (i = 0; i < count; i++) {
-                       const int temp_dirfd = temporary_rename_directory.dirfd;
                        const char *top_level_name =
                                        lttng_dynamic_pointer_array_get_pointer(
                                                &trace_chunk->top_level_directories, i);
 
-                       /*
-                        * FIXME replace renamat() use by directory handle
-                        * wrapper for non-POSIX 2008 systems.
-                        */
-                       ret = renameat(session_dirfd, top_level_name,
-                                       temp_dirfd, top_level_name);
+                       ret = lttng_directory_handle_rename_as_user(
+                                       &trace_chunk->session_output_directory.value,
+                                       top_level_name,
+                                       &temporary_rename_directory,
+                                       top_level_name,
+                                       LTTNG_OPTIONAL_GET(trace_chunk->credentials).use_current_user ?
+                                               NULL :
+                                               &trace_chunk->credentials.value.user);
                        if (ret) {
                                PERROR("Failed to move \"%s\" to temporary trace chunk rename directory",
                                                top_level_name);
@@ -906,13 +937,14 @@ void lttng_trace_chunk_move_to_completed(struct lttng_trace_chunk *trace_chunk)
        }
        archived_chunks_directory.is_set = true;
 
-       /*
-        * FIXME replace renamat() use by directory handle
-        * wrapper for non-POSIX 2008 systems.
-        */
-       ret = renameat(session_dirfd, directory_to_rename,
-                       archived_chunks_directory.value.dirfd,
-                       archived_chunk_name);
+       ret = lttng_directory_handle_rename_as_user(
+                       &trace_chunk->session_output_directory.value,
+                       directory_to_rename,
+                       &archived_chunks_directory.value,
+                       archived_chunk_name,
+                       LTTNG_OPTIONAL_GET(trace_chunk->credentials).use_current_user ?
+                               NULL :
+                               &trace_chunk->credentials.value.user);
        if (ret) {
                PERROR("Failed to rename folder \"%s\" to \"%s\"",
                                directory_to_rename, archived_chunk_name);
@@ -928,6 +960,24 @@ end:
        }
 }
 
+LTTNG_HIDDEN
+enum lttng_trace_chunk_status lttng_trace_chunk_get_close_command(
+               struct lttng_trace_chunk *chunk,
+               enum lttng_trace_chunk_command_type *command_type)
+{
+       enum lttng_trace_chunk_status status = LTTNG_TRACE_CHUNK_STATUS_OK;
+
+       pthread_mutex_lock(&chunk->lock);
+       if (chunk->close_command.is_set) {
+               *command_type = chunk->close_command.value;
+               status = LTTNG_TRACE_CHUNK_STATUS_OK;
+       } else {
+               status = LTTNG_TRACE_CHUNK_STATUS_NONE;
+       }
+       pthread_mutex_unlock(&chunk->lock);
+       return status;
+}
+
 LTTNG_HIDDEN
 enum lttng_trace_chunk_status lttng_trace_chunk_set_close_command(
                struct lttng_trace_chunk *chunk,
@@ -956,6 +1006,18 @@ end_unlock:
        return status;
 }
 
+LTTNG_HIDDEN
+const char *lttng_trace_chunk_command_type_get_name(
+               enum lttng_trace_chunk_command_type command)
+{
+       switch (command) {
+       case LTTNG_TRACE_CHUNK_COMMAND_TYPE_MOVE_TO_COMPLETED:
+               return "move to completed trace chunk folder";
+       default:
+               abort();
+       }
+}
+
 LTTNG_HIDDEN
 bool lttng_trace_chunk_get(struct lttng_trace_chunk *chunk)
 {
@@ -1034,7 +1096,7 @@ end:
        return registry;
 error:
        lttng_trace_chunk_registry_destroy(registry);
-       goto end;
+       return NULL;
 }
 
 LTTNG_HIDDEN
@@ -1233,3 +1295,49 @@ lttng_trace_chunk_registry_find_anonymous_chunk(
         return _lttng_trace_chunk_registry_find_chunk(registry,
                        session_id, NULL);
 }
+
+unsigned int lttng_trace_chunk_registry_put_each_chunk(
+               struct lttng_trace_chunk_registry *registry)
+{
+       struct cds_lfht_iter iter;
+       struct lttng_trace_chunk_registry_element *chunk_element;
+       unsigned int trace_chunks_left = 0;
+
+       DBG("Releasing trace chunk registry to all trace chunks");
+       rcu_read_lock();
+       cds_lfht_for_each_entry(registry->ht,
+                       &iter, chunk_element, trace_chunk_registry_ht_node) {
+               const char *chunk_id_str = "none";
+               char chunk_id_buf[MAX_INT_DEC_LEN(uint64_t)];
+
+               pthread_mutex_lock(&chunk_element->chunk.lock);
+               if (chunk_element->chunk.id.is_set) {
+                       int fmt_ret;
+
+                       fmt_ret = snprintf(chunk_id_buf, sizeof(chunk_id_buf),
+                                       "%" PRIu64,
+                                       chunk_element->chunk.id.value);
+                       if (fmt_ret < 0 || fmt_ret >= sizeof(chunk_id_buf)) {
+                               chunk_id_str = "formatting error";
+                       } else {
+                               chunk_id_str = chunk_id_buf;
+                       }
+               }
+
+               DBG("Releasing reference to trace chunk: session_id = %" PRIu64
+                               "chunk_id = %s, name = \"%s\", status = %s",
+                               chunk_element->session_id,
+                               chunk_id_str,
+                               chunk_element->chunk.name ? : "none",
+                               chunk_element->chunk.close_command.is_set ?
+                                               "open" : "closed");
+               pthread_mutex_unlock(&chunk_element->chunk.lock);
+               lttng_trace_chunk_put(&chunk_element->chunk);
+               trace_chunks_left++;
+       }
+       rcu_read_unlock();
+       DBG("Released reference to %u trace chunks in %s()", trace_chunks_left,
+                       __FUNCTION__);
+
+       return trace_chunks_left;
+}
This page took 0.027109 seconds and 4 git commands to generate.