ctf.fs source: recurse to find multiples CTF traces
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Mon, 22 May 2017 19:33:03 +0000 (15:33 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Sun, 28 May 2017 16:57:44 +0000 (12:57 -0400)
One port per CTF data stream amongst all the traces that are found
from the user's starting path is created.

The traces are named so as to be able to replicate the original tree
by stripping their common prefix within slash boundaries.

For example: user passes `hello` as the starting path, the component
finds the following traces:

    hello/world/kilo
    hello/yes
    hello/ispep/zero/mini

These traces would be named:

    world/kilo
    yes
    ispep/zero/mini

Another example: user passes `hello` as the starting path, the
component finds the following trace:

    hello/world/kilo

In this case, the trace is named `kilo`.

I used realpath() to normalize the paths and make sure that there aren't
`.` or `..` in the trace's name. Opening a trace located directly in `/`
is not supported.

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
plugins/ctf/common/metadata/ast.h
plugins/ctf/common/metadata/decoder.c
plugins/ctf/common/metadata/decoder.h
plugins/ctf/common/metadata/visitor-generate-ir.c
plugins/ctf/fs-src/data-stream.c
plugins/ctf/fs-src/data-stream.h
plugins/ctf/fs-src/fs.c
plugins/ctf/fs-src/fs.h
plugins/ctf/fs-src/metadata.c
plugins/ctf/fs-src/metadata.h
plugins/ctf/lttng-live/metadata.c

index 3ab552aa1966de743ed9b68868d9508581a4c811..b06eb73fdbe8108b4cb2f719cc6831b2a1bcc264 100644 (file)
@@ -309,7 +309,7 @@ const char *node_type(struct ctf_node *node);
 
 BT_HIDDEN
 struct ctf_visitor_generate_ir *ctf_visitor_generate_ir_create(FILE *efd,
-               uint64_t clock_class_offset_ns);
+               uint64_t clock_class_offset_ns, const char *name);
 
 void ctf_visitor_generate_ir_destroy(struct ctf_visitor_generate_ir *visitor);
 
index 41badbb6412719ab063ce90b282b309f2436f89a..6d60c619a2828e8db1d7e5025430b628844e445f 100644 (file)
@@ -265,7 +265,7 @@ int ctf_metadata_decoder_packetized_file_stream_to_buf(
 
 BT_HIDDEN
 struct ctf_metadata_decoder *ctf_metadata_decoder_create(FILE *err,
-               uint64_t clock_class_offset_ns)
+               uint64_t clock_class_offset_ns, const char *name)
 {
        struct ctf_metadata_decoder *mdec =
                g_new0(struct ctf_metadata_decoder, 1);
@@ -276,7 +276,7 @@ struct ctf_metadata_decoder *ctf_metadata_decoder_create(FILE *err,
 
        mdec->err_stream = err;
        mdec->visitor = ctf_visitor_generate_ir_create(err,
-               clock_class_offset_ns);
+               clock_class_offset_ns, name);
        if (!mdec->visitor) {
                ctf_metadata_decoder_destroy(mdec);
                mdec = NULL;
index dd60c219c3e82ff878d64438fc0a1c920f300a41..cf8ed00d9a9ce92759d265581fd98e3898872cff 100644 (file)
@@ -34,13 +34,14 @@ enum ctf_metadata_decoder_status {
 /*
  * Creates a CTF metadata decoder with `err` as the error stream (can
  * be `NULL` to disable error output). `clock_class_offset_ns` is an
- * offset to apply to the decoded clock classes's offsets.
+ * offset to apply to the decoded clock classes's offsets. `name` is
+ * this decoder's trace's name.
  *
  * Returns `NULL` on error.
  */
 BT_HIDDEN
 struct ctf_metadata_decoder *ctf_metadata_decoder_create(FILE *err,
-               uint64_t clock_class_offset_ns);
+               uint64_t clock_class_offset_ns, const char *name);
 
 /*
  * Destroys a CTF metadata decoder that you created with
index c8d8e7802f90482f8532bd5a1431873594780c57..12e28398ef24a7781670e8c335b1841742ef6ca7 100644 (file)
@@ -4641,7 +4641,7 @@ end:
 
 BT_HIDDEN
 struct ctf_visitor_generate_ir *ctf_visitor_generate_ir_create(FILE *efd,
-               uint64_t clock_class_offset_ns)
+               uint64_t clock_class_offset_ns, const char *name)
 {
        int ret;
        struct ctx *ctx = NULL;
@@ -4653,6 +4653,12 @@ struct ctf_visitor_generate_ir *ctf_visitor_generate_ir_create(FILE *efd,
                goto error;
        }
 
+       ret = bt_ctf_trace_set_name(trace, name);
+       if (ret) {
+               _FPERROR(efd, "cannot set trace's name to `%s`", name);
+               goto error;
+       }
+
        /* Set packet header to NULL to override the default one */
        ret = bt_ctf_trace_set_packet_header_type(trace, NULL);
        if (ret) {
index bc0d12178f839dafbc7600085a7697e6fae2a497..851c094e5179e5e984ab7dff13cc1a0595dc714c 100644 (file)
@@ -350,74 +350,78 @@ end:
 
 BT_HIDDEN
 struct ctf_fs_stream *ctf_fs_stream_create(
-               struct ctf_fs_component *ctf_fs, const char *path)
+               struct ctf_fs_trace *ctf_fs_trace, const char *path)
 {
        int ret;
-       struct ctf_fs_stream *stream = g_new0(struct ctf_fs_stream, 1);
+       struct ctf_fs_stream *ctf_fs_stream = g_new0(struct ctf_fs_stream, 1);
 
-       if (!stream) {
+       if (!ctf_fs_stream) {
                goto error;
        }
 
-       stream->file = ctf_fs_file_create(ctf_fs);
-       if (!stream->file) {
+       ctf_fs_stream->file = ctf_fs_file_create(ctf_fs_trace->ctf_fs);
+       if (!ctf_fs_stream->file) {
                goto error;
        }
 
-       stream->cc_prio_map = bt_get(ctf_fs->cc_prio_map);
-       g_string_assign(stream->file->path, path);
-       ret = ctf_fs_file_open(ctf_fsstream->file, "rb");
+       ctf_fs_stream->cc_prio_map = bt_get(ctf_fs_trace->cc_prio_map);
+       g_string_assign(ctf_fs_stream->file->path, path);
+       ret = ctf_fs_file_open(ctf_fs_trace->ctf_fs, ctf_fs_stream->file, "rb");
        if (ret) {
                goto error;
        }
 
-       stream->notif_iter = bt_ctf_notif_iter_create(ctf_fs->metadata->trace,
-                       ctf_fs->page_size, medops, stream,
-                       ctf_fs->error_fp);
-       if (!stream->notif_iter) {
+       ctf_fs_stream->notif_iter = bt_ctf_notif_iter_create(
+               ctf_fs_trace->metadata->trace,
+               ctf_fs_trace->ctf_fs->page_size, medops, ctf_fs_stream,
+               ctf_fs_trace->ctf_fs->error_fp);
+       if (!ctf_fs_stream->notif_iter) {
                goto error;
        }
 
-       stream->mmap_max_len = ctf_fs->page_size * 2048;
-       ret = init_stream_index(stream);
+       ctf_fs_stream->mmap_max_len = ctf_fs_trace->ctf_fs->page_size * 2048;
+       ret = init_stream_index(ctf_fs_stream);
        if (ret) {
                goto error;
        }
+
        goto end;
+
 error:
        /* Do not touch "borrowed" file. */
-       ctf_fs_stream_destroy(stream);
-       stream = NULL;
+       ctf_fs_stream_destroy(ctf_fs_stream);
+       ctf_fs_stream = NULL;
+
 end:
-       return stream;
+       return ctf_fs_stream;
 }
 
 BT_HIDDEN
-void ctf_fs_stream_destroy(struct ctf_fs_stream *stream)
+void ctf_fs_stream_destroy(struct ctf_fs_stream *ctf_fs_stream)
 {
-       if (!stream) {
+       if (!ctf_fs_stream) {
                return;
        }
 
-       bt_put(stream->cc_prio_map);
+       bt_put(ctf_fs_stream->cc_prio_map);
 
-       if (stream->file) {
-               ctf_fs_file_destroy(stream->file);
+       if (ctf_fs_stream->file) {
+               ctf_fs_file_destroy(ctf_fs_stream->file);
        }
 
-       if (stream->stream) {
-               BT_PUT(stream->stream);
+       if (ctf_fs_stream->stream) {
+               BT_PUT(ctf_fs_stream->stream);
        }
 
-       if (stream->notif_iter) {
-               bt_ctf_notif_iter_destroy(stream->notif_iter);
+       if (ctf_fs_stream->notif_iter) {
+               bt_ctf_notif_iter_destroy(ctf_fs_stream->notif_iter);
        }
 
-       if (stream->index.entries) {
-               g_array_free(stream->index.entries, TRUE);
+       if (ctf_fs_stream->index.entries) {
+               g_array_free(ctf_fs_stream->index.entries, TRUE);
        }
 
-       g_free(stream);
+       g_free(ctf_fs_stream);
 }
 
 BT_HIDDEN
index 3d484425d1b72209c86ea60ee3e1586af288f207..60a3110bcd9560ccb3c752e49bed01450443a4eb 100644 (file)
@@ -33,6 +33,7 @@
 
 struct ctf_fs_component;
 struct ctf_fs_file;
+struct ctf_fs_trace;
 struct ctf_fs_stream;
 
 struct index_entry {
@@ -48,7 +49,7 @@ struct index {
 
 BT_HIDDEN
 struct ctf_fs_stream *ctf_fs_stream_create(
-               struct ctf_fs_component *ctf_fs, const char *path);
+               struct ctf_fs_trace *ctf_fs_trace, const char *path);
 
 BT_HIDDEN
 void ctf_fs_stream_destroy(struct ctf_fs_stream *stream);
index d50966f7cbf28956f6a39bb459fe33233605dff3..6fc53e3c30da2f47f917e09c735defdbdd03b2eb 100644 (file)
@@ -3,10 +3,9 @@
  *
  * Babeltrace CTF file system Reader Component
  *
+ * Copyright 2015-2017 Philippe Proulx <pproulx@efficios.com>
  * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
  *
- * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -76,39 +75,29 @@ enum bt_notification_iterator_status ctf_fs_iterator_init(
                struct bt_private_notification_iterator *it,
                struct bt_private_port *port)
 {
-       struct ctf_fs_stream *stream = NULL;
-       struct ctf_fs_component *ctf_fs;
+       struct ctf_fs_stream *ctf_fs_stream = NULL;
        struct ctf_fs_port_data *port_data;
-       struct bt_private_component *priv_comp =
-               bt_private_notification_iterator_get_private_component(it);
        enum bt_notification_iterator_status ret =
                BT_NOTIFICATION_ITERATOR_STATUS_OK;
 
-       assert(priv_comp);
-
-       ctf_fs = bt_private_component_get_user_data(priv_comp);
-       if (!ctf_fs) {
-               ret = BT_NOTIFICATION_ITERATOR_STATUS_INVALID;
-               goto error;
-       }
-
        port_data = bt_private_port_get_user_data(port);
        if (!port_data) {
                ret = BT_NOTIFICATION_ITERATOR_STATUS_INVALID;
                goto error;
        }
 
-       stream = ctf_fs_stream_create(ctf_fs, port_data->path->str);
-       if (!stream) {
+       ctf_fs_stream = ctf_fs_stream_create(port_data->ctf_fs_trace,
+               port_data->path->str);
+       if (!ctf_fs_stream) {
                goto error;
        }
 
-       ret = bt_private_notification_iterator_set_user_data(it, stream);
+       ret = bt_private_notification_iterator_set_user_data(it, ctf_fs_stream);
        if (ret) {
                goto error;
        }
 
-       stream = NULL;
+       ctf_fs_stream = NULL;
        goto end;
 
 error:
@@ -119,40 +108,59 @@ error:
        }
 
 end:
-       ctf_fs_stream_destroy(stream);
-       bt_put(priv_comp);
+       ctf_fs_stream_destroy(ctf_fs_stream);
        return ret;
 }
 
 static
-void ctf_fs_destroy_data(struct ctf_fs_component *ctf_fs)
+void ctf_fs_destroy(struct ctf_fs_component *ctf_fs)
 {
        if (!ctf_fs) {
                return;
        }
 
-       if (ctf_fs->trace_path) {
-               g_string_free(ctf_fs->trace_path, TRUE);
+       if (ctf_fs->traces) {
+               g_ptr_array_free(ctf_fs->traces, TRUE);
        }
 
        if (ctf_fs->port_data) {
                g_ptr_array_free(ctf_fs->port_data, TRUE);
        }
 
-       if (ctf_fs->metadata) {
-               ctf_fs_metadata_fini(ctf_fs->metadata);
-               g_free(ctf_fs->metadata);
+       g_free(ctf_fs);
+}
+
+static
+void ctf_fs_trace_destroy(void *data)
+{
+       struct ctf_fs_trace *ctf_fs_trace = data;
+
+       if (!ctf_fs_trace) {
+               return;
        }
 
-       bt_put(ctf_fs->cc_prio_map);
-       g_free(ctf_fs);
+       if (ctf_fs_trace->path) {
+               g_string_free(ctf_fs_trace->path, TRUE);
+       }
+
+       if (ctf_fs_trace->name) {
+               g_string_free(ctf_fs_trace->name, TRUE);
+       }
+
+       if (ctf_fs_trace->metadata) {
+               ctf_fs_metadata_fini(ctf_fs_trace->metadata);
+               g_free(ctf_fs_trace->metadata);
+       }
+
+       bt_put(ctf_fs_trace->cc_prio_map);
+       g_free(ctf_fs_trace);
 }
 
 void ctf_fs_finalize(struct bt_private_component *component)
 {
        void *data = bt_private_component_get_user_data(component);
 
-       ctf_fs_destroy_data(data);
+       ctf_fs_destroy(data);
 }
 
 static
@@ -171,13 +179,14 @@ void port_data_destroy(void *data) {
 }
 
 static
-int create_one_port(struct ctf_fs_component *ctf_fs,
-               const char *stream_basename, const char *stream_path)
+int create_one_port_for_trace(struct ctf_fs_trace *ctf_fs_trace,
+               const char *stream_path)
 {
        int ret = 0;
        struct bt_private_port *port = NULL;
        struct ctf_fs_port_data *port_data = NULL;
        GString *port_name = NULL;
+       struct ctf_fs_component *ctf_fs = ctf_fs_trace->ctf_fs;
 
        port_name = g_string_new(NULL);
        if (!port_name) {
@@ -185,10 +194,8 @@ int create_one_port(struct ctf_fs_component *ctf_fs,
        }
 
        /* Assign the name for the new output port */
-       g_string_assign(port_name, "");
-       g_string_printf(port_name, "trace0-stream-%s", stream_basename);
-       PDBG("Creating one port named `%s` associated with path `%s`\n",
-               port_name->str, stream_path);
+       g_string_printf(port_name, "%s", stream_path);
+       PDBG("Creating one port named `%s`\n", port_name->str);
 
        /* Create output port for this file */
        port_data = g_new0(struct ctf_fs_port_data, 1);
@@ -196,6 +203,7 @@ int create_one_port(struct ctf_fs_component *ctf_fs,
                goto error;
        }
 
+       port_data->ctf_fs_trace = ctf_fs_trace;
        port_data->path = g_string_new(stream_path);
        if (!port_data->path) {
                goto error;
@@ -225,19 +233,20 @@ end:
 }
 
 static
-int create_ports(struct ctf_fs_component *ctf_fs)
+int create_ports_for_trace(struct ctf_fs_trace *ctf_fs_trace)
 {
        int ret = 0;
        const char *basename;
        GError *error = NULL;
        GDir *dir = NULL;
        struct ctf_fs_file *file = NULL;
+       struct ctf_fs_component *ctf_fs = ctf_fs_trace->ctf_fs;
 
        /* Create one output port for each stream file */
-       dir = g_dir_open(ctf_fs->trace_path->str, 0, &error);
+       dir = g_dir_open(ctf_fs_trace->path->str, 0, &error);
        if (!dir) {
                PERR("Cannot open directory `%s`: %s (code %d)\n",
-                       ctf_fs->trace_path->str, error->message,
+                       ctf_fs_trace->path->str, error->message,
                        error->code);
                goto error;
        }
@@ -245,28 +254,31 @@ int create_ports(struct ctf_fs_component *ctf_fs)
        while ((basename = g_dir_read_name(dir))) {
                if (!strcmp(basename, CTF_FS_METADATA_FILENAME)) {
                        /* Ignore the metadata stream. */
-                       PDBG("Ignoring metadata file `%s`\n", basename);
+                       PDBG("Ignoring metadata file `%s/%s`\n",
+                               ctf_fs_trace->path->str, basename);
                        continue;
                }
 
                if (basename[0] == '.') {
-                       PDBG("Ignoring hidden file `%s`\n", basename);
+                       PDBG("Ignoring hidden file `%s/%s`\n",
+                               ctf_fs_trace->path->str, basename);
                        continue;
                }
 
                /* Create the file. */
                file = ctf_fs_file_create(ctf_fs);
                if (!file) {
-                       PERR("Cannot create stream file object for file `%s`\n",
-                               basename);
+                       PERR("Cannot create stream file object for file `%s/%s`\n",
+                               ctf_fs_trace->path->str, basename);
                        goto error;
                }
 
                /* Create full path string. */
                g_string_append_printf(file->path, "%s/%s",
-                               ctf_fs->trace_path->str, basename);
+                               ctf_fs_trace->path->str, basename);
                if (!g_file_test(file->path->str, G_FILE_TEST_IS_REGULAR)) {
-                       PDBG("Ignoring non-regular file `%s`\n", basename);
+                       PDBG("Ignoring non-regular file `%s`\n",
+                               file->path->str);
                        ctf_fs_file_destroy(file);
                        file = NULL;
                        continue;
@@ -274,22 +286,22 @@ int create_ports(struct ctf_fs_component *ctf_fs)
 
                ret = ctf_fs_file_open(ctf_fs, file, "rb");
                if (ret) {
-                       PERR("Cannot open stream file `%s`\n", basename);
+                       PERR("Cannot open stream file `%s`\n", file->path->str);
                        goto error;
                }
 
                if (file->size == 0) {
                        /* Skip empty stream. */
-                       PDBG("Ignoring empty file `%s`\n", basename);
+                       PDBG("Ignoring empty file `%s`\n", file->path->str);
                        ctf_fs_file_destroy(file);
                        file = NULL;
                        continue;
                }
 
-               ret = create_one_port(ctf_fs, basename, file->path->str);
+               ret = create_one_port_for_trace(ctf_fs_trace, file->path->str);
                if (ret) {
                        PERR("Cannot create output port for file `%s`\n",
-                               basename);
+                               file->path->str);
                        goto error;
                }
 
@@ -317,30 +329,31 @@ end:
 }
 
 static
-int create_cc_prio_map(struct ctf_fs_component *ctf_fs)
+int create_cc_prio_map(struct ctf_fs_trace *ctf_fs_trace)
 {
        int ret = 0;
        size_t i;
        int count;
 
-       assert(ctf_fs);
-       ctf_fs->cc_prio_map = bt_clock_class_priority_map_create();
-       if (!ctf_fs->cc_prio_map) {
+       assert(ctf_fs_trace);
+       ctf_fs_trace->cc_prio_map = bt_clock_class_priority_map_create();
+       if (!ctf_fs_trace->cc_prio_map) {
                ret = -1;
                goto end;
        }
 
-       count = bt_ctf_trace_get_clock_class_count(ctf_fs->metadata->trace);
+       count = bt_ctf_trace_get_clock_class_count(
+               ctf_fs_trace->metadata->trace);
        assert(count >= 0);
 
        for (i = 0; i < count; i++) {
                struct bt_ctf_clock_class *clock_class =
                        bt_ctf_trace_get_clock_class_by_index(
-                               ctf_fs->metadata->trace, i);
+                               ctf_fs_trace->metadata->trace, i);
 
                assert(clock_class);
                ret = bt_clock_class_priority_map_add_clock_class(
-                       ctf_fs->cc_prio_map, clock_class, 0);
+                       ctf_fs_trace->cc_prio_map, clock_class, 0);
                BT_PUT(clock_class);
 
                if (ret) {
@@ -352,13 +365,344 @@ end:
        return ret;
 }
 
+static
+struct ctf_fs_trace *ctf_fs_trace_create(struct ctf_fs_component *ctf_fs,
+               const char *path, const char *name)
+{
+       struct ctf_fs_trace *ctf_fs_trace;
+       int ret;
+
+       ctf_fs_trace = g_new0(struct ctf_fs_trace, 1);
+       if (!ctf_fs_trace) {
+               goto end;
+       }
+
+       ctf_fs_trace->ctf_fs = ctf_fs;
+       ctf_fs_trace->path = g_string_new(path);
+       if (!ctf_fs_trace->path) {
+               goto error;
+       }
+
+       ctf_fs_trace->name = g_string_new(name);
+       if (!ctf_fs_trace->name) {
+               goto error;
+       }
+
+       ctf_fs_trace->metadata = g_new0(struct ctf_fs_metadata, 1);
+       if (!ctf_fs_trace->metadata) {
+               goto error;
+       }
+
+       ret = ctf_fs_metadata_set_trace(ctf_fs_trace);
+       if (ret) {
+               goto error;
+       }
+
+       ret = create_cc_prio_map(ctf_fs_trace);
+       if (ret) {
+               goto error;
+       }
+
+       ret = create_ports_for_trace(ctf_fs_trace);
+       if (ret) {
+               goto error;
+       }
+
+       goto end;
+
+error:
+       ctf_fs_trace_destroy(ctf_fs_trace);
+       ctf_fs_trace = NULL;
+end:
+       return ctf_fs_trace;
+}
+
+static
+int path_is_ctf_trace(const char *path)
+{
+       GString *metadata_path = g_string_new(NULL);
+       int ret = 0;
+
+       if (!metadata_path) {
+               ret = -1;
+               goto end;
+       }
+
+       g_string_printf(metadata_path, "%s/%s", path, CTF_FS_METADATA_FILENAME);
+
+       if (g_file_test(metadata_path->str, G_FILE_TEST_IS_REGULAR)) {
+               ret = 1;
+               goto end;
+       }
+
+end:
+       g_string_free(metadata_path, TRUE);
+       return ret;
+}
+
+static
+int add_trace_path(struct ctf_fs_component *ctf_fs, GList **trace_paths,
+               const char *path)
+{
+       GString *path_str = g_string_new(NULL);
+       int ret = 0;
+       char *rp = NULL;
+
+       if (!path_str) {
+               ret = -1;
+               goto end;
+       }
+
+       /*
+        * Find the real path so that we don't have relative components
+        * in the trace name. This also squashes consecutive slashes and
+        * removes any slash at the end.
+        */
+       rp = realpath(path, NULL);
+       if (!rp) {
+               PERR("realpath() failed: %s (%d)\n", strerror(errno), errno);
+               ret = -1;
+               goto end;
+       }
+
+       if (strcmp(rp, "/") == 0) {
+               PERR("Opening a trace in `/` is not supported.\n");
+               ret = -1;
+               goto end;
+       }
+
+       g_string_assign(path_str, rp);
+       *trace_paths = g_list_prepend(*trace_paths, path_str);
+       assert(*trace_paths);
+
+end:
+       free(rp);
+       return ret;
+}
+
+static
+int find_ctf_traces(struct ctf_fs_component *ctf_fs,
+               GList **trace_paths, const char *start_path)
+{
+       int ret;
+       GError *error = NULL;
+       GDir *dir = NULL;
+       const char *basename = NULL;
+
+       /* Check if the starting path is a CTF trace itself */
+       ret = path_is_ctf_trace(start_path);
+       if (ret < 0) {
+               goto end;
+       }
+
+       if (ret) {
+               /*
+                * Do not even recurse: a CTF trace cannot contain
+                * another CTF trace.
+                */
+               ret = add_trace_path(ctf_fs, trace_paths, start_path);
+               goto end;
+       }
+
+       /* Look for subdirectories */
+       if (!g_file_test(start_path, G_FILE_TEST_IS_DIR)) {
+               /* Starting path is not a directory: end of recursion */
+               goto end;
+       }
+
+       dir = g_dir_open(start_path, 0, &error);
+       if (!dir) {
+               if (error->code == G_FILE_ERROR_ACCES) {
+                       PDBG("Cannot open directory `%s`: %s (code %d): continuing\n",
+                               start_path, error->message, error->code);
+                       goto end;
+               }
+
+               PERR("Cannot open directory `%s`: %s (code %d)\n",
+                       start_path, error->message, error->code);
+               ret = -1;
+               goto end;
+       }
+
+       while ((basename = g_dir_read_name(dir))) {
+               GString *sub_path = g_string_new(NULL);
+
+               if (!sub_path) {
+                       ret = -1;
+                       goto end;
+               }
+
+               g_string_printf(sub_path, "%s/%s", start_path, basename);
+               ret = find_ctf_traces(ctf_fs, trace_paths, sub_path->str);
+               g_string_free(sub_path, TRUE);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+end:
+       if (dir) {
+               g_dir_close(dir);
+       }
+
+       if (error) {
+               g_error_free(error);
+       }
+
+       return ret;
+}
+
+static
+GList *create_trace_names(GList *trace_paths) {
+       GList *trace_names = NULL;
+       size_t chars_to_strip = 0;
+       size_t at = 0;
+       GList *node;
+       bool done = false;
+
+       /*
+        * Find the number of characters to strip from the beginning,
+        * that is, the longest prefix until a common slash (also
+        * stripped).
+        */
+       while (true) {
+               gchar common_ch = '\0';
+
+               for (node = trace_paths; node; node = g_list_next(node)) {
+                       GString *gstr = node->data;
+                       gchar this_ch = gstr->str[at];
+
+                       if (this_ch == '\0') {
+                               done = true;
+                               break;
+                       }
+
+                       if (common_ch == '\0') {
+                               /*
+                                * Establish the expected common
+                                * character at this position.
+                                */
+                               common_ch = this_ch;
+                               continue;
+                       }
+
+                       if (this_ch != common_ch) {
+                               done = true;
+                               break;
+                       }
+               }
+
+               if (done) {
+                       break;
+               }
+
+               if (common_ch == '/') {
+                       /*
+                        * Common character is a slash: safe to include
+                        * this slash in the number of characters to
+                        * strip because the paths are guaranteed not to
+                        * end with slash.
+                        */
+                       chars_to_strip = at + 1;
+               }
+
+               at++;
+       }
+
+       /* Create the trace names */
+       for (node = trace_paths; node; node = g_list_next(node)) {
+               GString *trace_name = g_string_new(NULL);
+               GString *trace_path = node->data;
+
+               g_string_assign(trace_name, &trace_path->str[chars_to_strip]);
+               trace_names = g_list_append(trace_names, trace_name);
+       }
+
+       return trace_names;
+}
+
+static
+int create_ctf_fs_traces(struct ctf_fs_component *ctf_fs,
+               const char *path_param)
+{
+       struct ctf_fs_trace *ctf_fs_trace = NULL;
+       int ret = 0;
+       GList *trace_paths = NULL;
+       GList *trace_names = NULL;
+       GList *tp_node;
+       GList *tn_node;
+
+       ret = find_ctf_traces(ctf_fs, &trace_paths, path_param);
+       if (ret) {
+               goto error;
+       }
+
+       if (!trace_paths) {
+               PERR("No CTF traces recursively found in `%s`.\n",
+                       path_param);
+               goto error;
+       }
+
+       trace_names = create_trace_names(trace_paths);
+       if (!trace_names) {
+               PERR("Cannot create trace names from trace paths.\n");
+               goto error;
+       }
+
+       for (tp_node = trace_paths, tn_node = trace_names; tp_node;
+                       tp_node = g_list_next(tp_node),
+                       tn_node = g_list_next(tn_node)) {
+               GString *trace_path = tp_node->data;
+               GString *trace_name = tn_node->data;
+
+               ctf_fs_trace = ctf_fs_trace_create(ctf_fs, trace_path->str,
+                       trace_name->str);
+               if (!ctf_fs_trace) {
+                       PERR("Cannot create trace for `%s`.\n",
+                               trace_path->str);
+                       goto error;
+               }
+       }
+
+       g_ptr_array_add(ctf_fs->traces, ctf_fs_trace);
+       ctf_fs_trace = NULL;
+       goto end;
+
+error:
+       ret = -1;
+       ctf_fs_trace_destroy(ctf_fs_trace);
+
+end:
+       for (tp_node = trace_paths; tp_node; tp_node = g_list_next(tp_node)) {
+               if (tp_node->data) {
+                       g_string_free(tp_node->data, TRUE);
+               }
+       }
+
+       for (tn_node = trace_names; tn_node; tn_node = g_list_next(tn_node)) {
+               if (tn_node->data) {
+                       g_string_free(tn_node->data, TRUE);
+               }
+       }
+
+       if (trace_paths) {
+               g_list_free(trace_paths);
+       }
+
+       if (trace_names) {
+               g_list_free(trace_names);
+       }
+
+       return ret;
+}
+
 static
 struct ctf_fs_component *ctf_fs_create(struct bt_private_component *priv_comp,
                struct bt_value *params)
 {
        struct ctf_fs_component *ctf_fs;
        struct bt_value *value = NULL;
-       const char *path;
+       const char *path_param;
        int ret;
 
        ctf_fs = g_new0(struct ctf_fs_component, 1);
@@ -366,36 +710,23 @@ struct ctf_fs_component *ctf_fs_create(struct bt_private_component *priv_comp,
                goto end;
        }
 
+       ret = bt_private_component_set_user_data(priv_comp, ctf_fs);
+       assert(ret == 0);
+
        /*
         * We don't need to get a new reference here because as long as
         * our private ctf_fs_component object exists, the containing
         * private component should also exist.
         */
        ctf_fs->priv_comp = priv_comp;
-
-       /* FIXME: should probably look for a source URI */
        value = bt_value_map_get(params, "path");
-       if (!value || bt_value_is_null(value) || !bt_value_is_string(value)) {
-               goto error;
-       }
-
-       ret = bt_value_string_get(value, &path);
-       if (ret) {
-               goto error;
-       }
-
-       ctf_fs->port_data = g_ptr_array_new_with_free_func(port_data_destroy);
-       if (!ctf_fs->port_data) {
+       if (!bt_value_is_string(value)) {
                goto error;
        }
 
-       ctf_fs->trace_path = g_string_new(path);
-       if (!ctf_fs->trace_path) {
-               BT_PUT(value);
-               goto error;
-       }
-       bt_put(value);
-
+       ret = bt_value_string_get(value, &path_param);
+       assert(ret == 0);
+       BT_PUT(value);
        value = bt_value_map_get(params, "offset-s");
        if (value) {
                int64_t offset;
@@ -406,13 +737,9 @@ struct ctf_fs_component *ctf_fs_create(struct bt_private_component *priv_comp,
                        goto error;
                }
                ret = bt_value_integer_get(value, &offset);
-               if (ret != BT_VALUE_STATUS_OK) {
-                       fprintf(stderr,
-                               "Failed to get offset-s value\n");
-                       goto error;
-               }
+               assert(ret == 0);
                ctf_fs->options.clock_offset = offset;
-               bt_put(value);
+               BT_PUT(value);
        }
 
        value = bt_value_map_get(params, "offset-ns");
@@ -425,35 +752,24 @@ struct ctf_fs_component *ctf_fs_create(struct bt_private_component *priv_comp,
                        goto error;
                }
                ret = bt_value_integer_get(value, &offset);
-               if (ret != BT_VALUE_STATUS_OK) {
-                       fprintf(stderr,
-                               "Failed to get offset-ns value\n");
-                       goto error;
-               }
+               assert(ret == 0);
                ctf_fs->options.clock_offset_ns = offset;
-               bt_put(value);
+               BT_PUT(value);
        }
 
        ctf_fs->error_fp = stderr;
        ctf_fs->page_size = (size_t) getpagesize();
-
-       // FIXME: check error.
-       ctf_fs->metadata = g_new0(struct ctf_fs_metadata, 1);
-       if (!ctf_fs->metadata) {
-               goto error;
-       }
-
-       ret = ctf_fs_metadata_set_trace(ctf_fs);
-       if (ret) {
+       ctf_fs->port_data = g_ptr_array_new_with_free_func(port_data_destroy);
+       if (!ctf_fs->port_data) {
                goto error;
        }
 
-       ret = create_cc_prio_map(ctf_fs);
-       if (ret) {
+       ctf_fs->traces = g_ptr_array_new_with_free_func(ctf_fs_trace_destroy);
+       if (!ctf_fs->traces) {
                goto error;
        }
 
-       ret = create_ports(ctf_fs);
+       ret = create_ctf_fs_traces(ctf_fs, path_param);
        if (ret) {
                goto error;
        }
@@ -461,9 +777,13 @@ struct ctf_fs_component *ctf_fs_create(struct bt_private_component *priv_comp,
        goto end;
 
 error:
-       ctf_fs_destroy_data(ctf_fs);
+       ctf_fs_destroy(ctf_fs);
        ctf_fs = NULL;
+       ret = bt_private_component_set_user_data(priv_comp, NULL);
+       assert(ret == 0);
+
 end:
+       bt_put(value);
        return ctf_fs;
 }
 
@@ -474,23 +794,12 @@ enum bt_component_status ctf_fs_init(struct bt_private_component *priv_comp,
        struct ctf_fs_component *ctf_fs;
        enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
 
-       assert(priv_comp);
        ctf_fs_debug = g_strcmp0(getenv("CTF_FS_DEBUG"), "1") == 0;
        ctf_fs = ctf_fs_create(priv_comp, params);
        if (!ctf_fs) {
-               ret = BT_COMPONENT_STATUS_NOMEM;
-               goto end;
+               ret = BT_COMPONENT_STATUS_ERROR;
        }
 
-       ret = bt_private_component_set_user_data(priv_comp, ctf_fs);
-       if (ret != BT_COMPONENT_STATUS_OK) {
-               goto error;
-       }
-end:
-       return ret;
-error:
-       (void) bt_private_component_set_user_data(priv_comp, NULL);
-        ctf_fs_destroy_data(ctf_fs);
        return ret;
 }
 
index acc14a1a674bb60c0c32cf4ee798097f6df4533a..63b299a09288bae6187b3bd6eaf389628eb52cd2 100644 (file)
@@ -38,25 +38,43 @@ BT_HIDDEN
 extern bool ctf_fs_debug;
 
 struct ctf_fs_file {
+       /* Weak */
        struct ctf_fs_component *ctf_fs;
+
+       /* Owned by this */
        GString *path;
+
+       /* Owned by this */
        FILE *fp;
+
        off_t size;
 };
 
 struct ctf_fs_metadata {
+       /* Owned by this */
        struct bt_ctf_trace *trace;
+
+       /* Owned by this */
+       char *text;
+
        uint8_t uuid[16];
        bool is_uuid_set;
        int bo;
-       char *text;
 };
 
 struct ctf_fs_stream {
+       /* Owned by this */
        struct ctf_fs_file *file;
+
+       /* Owned by this */
        struct bt_ctf_stream *stream;
+
+       /* Owned by this */
        struct bt_clock_class_priority_map *cc_prio_map;
+
+       /* Owned by this */
        struct bt_ctf_notif_iter *notif_iter;
+
        /* A stream is assumed to be indexed. */
        struct index index;
        void *mmap_addr;
@@ -81,21 +99,44 @@ struct ctf_fs_component_options {
        uint64_t clock_offset_ns;
 };
 
-struct ctf_fs_port_data {
-       GString *path;
-};
-
 struct ctf_fs_component {
+       /* Weak */
        struct bt_private_component *priv_comp;
-       GString *trace_path;
+
+       /* Array of struct ctf_fs_port_data *, owned by this */
+       GPtrArray *port_data;
+
+       /* Array of struct ctf_fs_trace *, owned by this */
+       GPtrArray *traces;
+
+       struct ctf_fs_component_options options;
        FILE *error_fp;
        size_t page_size;
-       struct ctf_fs_component_options options;
+};
+
+struct ctf_fs_trace {
+       /* Weak */
+       struct ctf_fs_component *ctf_fs;
+
+       /* Owned by this */
        struct ctf_fs_metadata *metadata;
+
+       /* Owned by this */
        struct bt_clock_class_priority_map *cc_prio_map;
 
-       /* Array of struct ctf_fs_port_data *, owned by this */
-       GPtrArray *port_data;
+       /* Owned by this */
+       GString *path;
+
+       /* Owned by this */
+       GString *name;
+};
+
+struct ctf_fs_port_data {
+       /* Owned by this */
+       GString *path;
+
+       /* Weak */
+       struct ctf_fs_trace *ctf_fs_trace;
 };
 
 BT_HIDDEN
index 2425273328bd9cf70ad5f77877f6c8a3bf4f6b33..c6b50953c6f85f4ff4c36dfb8aed4b9fe81a9ceb 100644 (file)
@@ -101,13 +101,14 @@ end:
        return file;
 }
 
-int ctf_fs_metadata_set_trace(struct ctf_fs_component *ctf_fs)
+int ctf_fs_metadata_set_trace(struct ctf_fs_trace *ctf_fs_trace)
 {
        int ret = 0;
+       struct ctf_fs_component *ctf_fs = ctf_fs_trace->ctf_fs;
        struct ctf_fs_file *file = NULL;
        struct ctf_metadata_decoder *metadata_decoder = NULL;
 
-       file = get_file(ctf_fs, ctf_fs->trace_path->str);
+       file = get_file(ctf_fs, ctf_fs_trace->path->str);
        if (!file) {
                PERR("Cannot create metadata file object\n");
                ret = -1;
@@ -116,7 +117,7 @@ int ctf_fs_metadata_set_trace(struct ctf_fs_component *ctf_fs)
 
        metadata_decoder = ctf_metadata_decoder_create(ctf_fs->error_fp,
                ctf_fs->options.clock_offset * NSEC_PER_SEC +
-               ctf_fs->options.clock_offset_ns);
+               ctf_fs->options.clock_offset_ns, ctf_fs_trace->name->str);
        if (!metadata_decoder) {
                PERR("Cannot create metadata decoder object\n");
                ret = -1;
@@ -129,9 +130,9 @@ int ctf_fs_metadata_set_trace(struct ctf_fs_component *ctf_fs)
                goto end;
        }
 
-       ctf_fs->metadata->trace = ctf_metadata_decoder_get_trace(
+       ctf_fs_trace->metadata->trace = ctf_metadata_decoder_get_trace(
                metadata_decoder);
-       assert(ctf_fs->metadata->trace);
+       assert(ctf_fs_trace->metadata->trace);
 
 end:
        ctf_fs_file_destroy(file);
index 85a7726834d5e1943af9d7868e253543e398703c..cb822ad4bdc8bb637633befc96ced90e65a363a8 100644 (file)
@@ -38,7 +38,7 @@ BT_HIDDEN
 void ctf_fs_metadata_fini(struct ctf_fs_metadata *metadata);
 
 BT_HIDDEN
-int ctf_fs_metadata_set_trace(struct ctf_fs_component *ctf_fs);
+int ctf_fs_metadata_set_trace(struct ctf_fs_trace *ctf_fs_trace);
 
 BT_HIDDEN
 FILE *ctf_fs_metadata_open_file(const char *trace_path);
index d3b7b09567b04ebd8d4583234b618d04a3535624..7c8ce4dddb49498fdd8f82a5a34999c5ea3b74ab 100644 (file)
@@ -239,7 +239,9 @@ int lttng_live_metadata_create_stream(struct lttng_live_session *session,
        }
        metadata->stream_id = stream_id;
        //TODO: add clock offset option
-       metadata->decoder = ctf_metadata_decoder_create(stderr, 0);
+       //TODO: add (preferably unique) trace's name
+       metadata->decoder = ctf_metadata_decoder_create(stderr, 0,
+               "lttng-live");
        if (!metadata->decoder) {
                goto error;
        }
This page took 0.042712 seconds and 4 git commands to generate.