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 <jdesfossez@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
+/*
+ * 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)
static
int make_trace_path(struct writer_component *writer_component,
struct bt_ctf_trace *trace, char *trace_path)
int ret;
const char *trace_name;
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, "..")) {
/* Sanitize the trace name. */
if (strlen(trace_name) == 2 && !strcmp(trace_name, "..")) {
snprintf(trace_path, PATH_MAX, "%s/%s",
writer_component->base_path->str,
trace_name);
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");
+ } 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;
+ }
+ }
struct fs_writer *fs_writer = NULL;
int nr_stream, i;
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",
ret = make_trace_path(writer_component, trace, trace_path);
if (ret) {
fprintf(writer_component->err, "[error] %s in %s:%d\n",
fs_writer->static_listener_id = ret;
}
fs_writer->static_listener_id = ret;
}
+ writer_component->nr_traces++;
g_hash_table_insert(writer_component->trace_map, (gpointer) trace,
fs_writer);
g_hash_table_insert(writer_component->trace_map, (gpointer) trace,
fs_writer);
+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,
BT_HIDDEN
enum bt_component_status writer_component_init(
struct bt_private_component *component, struct bt_value *params,
+ 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;
ret = bt_private_component_set_user_data(component, writer_component);
if (ret != BT_COMPONENT_STATUS_OK) {
goto error;
FILE *err;
struct bt_notification_iterator *input_iterator;
bool error;
FILE *err;
struct bt_notification_iterator *input_iterator;
bool error;
+ bool single_trace;
+ unsigned int nr_traces;
};
enum fs_writer_stream_state {
};
enum fs_writer_stream_state {