From 6ca0eb99012c3c6bbe3da1f45086368403fcac30 Mon Sep 17 00:00:00 2001 From: Julien Desfossez Date: Thu, 15 Jun 2017 15:29:34 -0400 Subject: [PATCH] fs-sink: add the single-trace option MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This option allows the user to control the output directory of the trace written (instead of the path being derived from the source trace path and hostname). This implies that the component only receives one trace. If the output directory exists and is not empty, an error is returned. To use it: --component sink.ctf.fs --path /tmp/out -p single-trace=true Signed-off-by: Julien Desfossez Signed-off-by: Jérémie Galarneau --- plugins/ctf/fs-sink/write.c | 95 ++++++++++++++++++++++++++++++------ plugins/ctf/fs-sink/writer.c | 39 +++++++++++++++ plugins/ctf/fs-sink/writer.h | 2 + 3 files changed, 121 insertions(+), 15 deletions(-) diff --git a/plugins/ctf/fs-sink/write.c b/plugins/ctf/fs-sink/write.c index dd380f5b..0b0cea42 100644 --- a/plugins/ctf/fs-sink/write.c +++ b/plugins/ctf/fs-sink/write.c @@ -181,6 +181,48 @@ enum fs_writer_stream_state *insert_new_stream_state( return v; } +/* + * Make sure the output path is valid for a single trace: either it does + * not exists or it is empty. + * + * Return 0 if the path is valid, -1 otherwise. + */ +static +bool valid_single_trace_path(const char *path) +{ + int n = 0; + struct dirent *d; + DIR *dir = opendir(path); + int ret; + + /* non-existant directory */ + if (!dir) { + ret = 0; + goto end; + } + + while ((d = readdir(dir)) != NULL) { + if (++n > 2) { + break; + } + } + + ret = closedir(dir); + if (ret) { + perror("closedir"); + goto end; + } + + if (n <= 2) { + ret = 0; + } else { + ret = -1; + } + +end: + return ret; +} + static int make_trace_path(struct writer_component *writer_component, struct bt_ctf_trace *trace, char *trace_path) @@ -188,11 +230,14 @@ int make_trace_path(struct writer_component *writer_component, int ret; const char *trace_name; - trace_name = bt_ctf_trace_get_name(trace); - if (!trace_name) { - trace_name = writer_component->trace_name_base->str; + if (writer_component->single_trace) { + trace_name = "\0"; + } else { + trace_name = bt_ctf_trace_get_name(trace); + if (!trace_name) { + trace_name = writer_component->trace_name_base->str; + } } - /* XXX: we might have to skip the first level, TBD. */ /* Sanitize the trace name. */ if (strlen(trace_name) == 2 && !strcmp(trace_name, "..")) { @@ -212,22 +257,34 @@ int make_trace_path(struct writer_component *writer_component, snprintf(trace_path, PATH_MAX, "%s/%s", writer_component->base_path->str, trace_name); - if (g_file_test(trace_path, G_FILE_TEST_EXISTS)) { - int i = 0; - do { - snprintf(trace_path, PATH_MAX, "%s/%s-%d", - writer_component->base_path->str, - trace_name, ++i); - } while (g_file_test(trace_path, G_FILE_TEST_EXISTS) && i < INT_MAX); - if (i == INT_MAX) { - fprintf(writer_component->err, "[error] Unable to find " - "a unique trace path\n"); + /* + * Append a suffix if the trace_path exists and we are not in + * single-trace mode. + */ + if (writer_component->single_trace) { + if (valid_single_trace_path(trace_path) != 0) { + fprintf(writer_component->err, + "[error] Invalid output directory\n"); goto error; } + } else { + if (g_file_test(trace_path, G_FILE_TEST_EXISTS)) { + int i = 0; + + do { + snprintf(trace_path, PATH_MAX, "%s/%s-%d", + writer_component->base_path->str, + trace_name, ++i); + } while (g_file_test(trace_path, G_FILE_TEST_EXISTS) && i < INT_MAX); + if (i == INT_MAX) { + fprintf(writer_component->err, "[error] Unable to find " + "a unique trace path\n"); + goto error; + } + } } ret = 0; - goto end; error: @@ -249,6 +306,13 @@ struct fs_writer *insert_new_writer( struct fs_writer *fs_writer = NULL; int nr_stream, i; + if (writer_component->single_trace && writer_component->nr_traces > 0) { + fprintf(writer_component->err, "[error] Trying to process more " + "than one trace but --single-trace mode " + "enabled\n"); + goto error; + } + ret = make_trace_path(writer_component, trace, trace_path); if (ret) { fprintf(writer_component->err, "[error] %s in %s:%d\n", @@ -331,6 +395,7 @@ struct fs_writer *insert_new_writer( fs_writer->static_listener_id = ret; } + writer_component->nr_traces++; g_hash_table_insert(writer_component->trace_map, (gpointer) trace, fs_writer); diff --git a/plugins/ctf/fs-sink/writer.c b/plugins/ctf/fs-sink/writer.c index 788e3e14..36e35d92 100644 --- a/plugins/ctf/fs-sink/writer.c +++ b/plugins/ctf/fs-sink/writer.c @@ -281,6 +281,38 @@ end: return ret; } +static +enum bt_component_status apply_one_bool(const char *key, + struct bt_value *params, + bool *option, + bool *found) +{ + enum bt_component_status ret = BT_COMPONENT_STATUS_OK; + struct bt_value *value = NULL; + enum bt_value_status status; + bt_bool bool_val; + + value = bt_value_map_get(params, key); + if (!value) { + goto end; + } + status = bt_value_bool_get(value, &bool_val); + switch (status) { + case BT_VALUE_STATUS_OK: + break; + default: + ret = BT_COMPONENT_STATUS_ERROR; + goto end; + } + *option = (bool) bool_val; + if (found) { + *found = true; + } +end: + bt_put(value); + return ret; +} + BT_HIDDEN enum bt_component_status writer_component_init( struct bt_private_component *component, struct bt_value *params, @@ -324,6 +356,13 @@ enum bt_component_status writer_component_init( goto error; } + writer_component->single_trace = false; + ret = apply_one_bool("single-trace", params, + &writer_component->single_trace, NULL); + if (ret != BT_COMPONENT_STATUS_OK) { + goto end; + } + ret = bt_private_component_set_user_data(component, writer_component); if (ret != BT_COMPONENT_STATUS_OK) { goto error; diff --git a/plugins/ctf/fs-sink/writer.h b/plugins/ctf/fs-sink/writer.h index 81ca1ed9..33403dc6 100644 --- a/plugins/ctf/fs-sink/writer.h +++ b/plugins/ctf/fs-sink/writer.h @@ -42,6 +42,8 @@ struct writer_component { FILE *err; struct bt_notification_iterator *input_iterator; bool error; + bool single_trace; + unsigned int nr_traces; }; enum fs_writer_stream_state { -- 2.34.1