* all copies or substantial portions of the Software.
*/
-#define _XOPEN_SOURCE 700
+#define _GNU_SOURCE
#include <config.h>
#include <babeltrace/babeltrace.h>
#include <babeltrace/format.h>
#include <babeltrace/context.h>
#include <babeltrace/ctf/types.h>
+#include <babeltrace/ctf/events.h>
#include <babeltrace/ctf-text/types.h>
#include <babeltrace/iterator.h>
#include <popt.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
-#include <ftw.h>
-#include <dirent.h>
#include <unistd.h>
#include <inttypes.h>
+#include <fts.h>
#include <babeltrace/ctf-ir/metadata.h> /* for clocks */
OPT_CLOCK_SECONDS,
OPT_CLOCK_DATE,
OPT_CLOCK_GMT,
+ OPT_CLOCK_FORCE_CORRELATE,
};
static struct poptOption long_options[] = {
{ "clock-seconds", 0, POPT_ARG_NONE, NULL, OPT_CLOCK_SECONDS, NULL, NULL },
{ "clock-date", 0, POPT_ARG_NONE, NULL, OPT_CLOCK_DATE, NULL, NULL },
{ "clock-gmt", 0, POPT_ARG_NONE, NULL, OPT_CLOCK_GMT, NULL, NULL },
+ { "clock-force-correlate", 0, POPT_ARG_NONE, NULL, OPT_CLOCK_FORCE_CORRELATE, NULL, NULL },
{ NULL, 0, 0, NULL, 0, NULL, NULL },
};
fprintf(fp, " (default is: [hh:mm:ss.ns])\n");
fprintf(fp, " --clock-date Print clock date\n");
fprintf(fp, " --clock-gmt Print clock in GMT time zone (default: local time zone)\n");
+ fprintf(fp, " --clock-force-correlate Assume that clocks are inherently correlated\n");
+ fprintf(fp, " across traces.\n");
list_formats(fp);
fprintf(fp, "\n");
}
case OPT_CLOCK_GMT:
opt_clock_gmt = 1;
break;
+ case OPT_CLOCK_FORCE_CORRELATE:
+ opt_clock_force_correlate = 1;
+ break;
default:
ret = -EINVAL;
}
+/*
+ * bt_context_add_traces_recursive: Open a trace recursively
+ *
+ * Find each trace present in the subdirectory starting from the given
+ * path, and add them to the context. The packet_seek parameter can be
+ * NULL: this specify to use the default format packet_seek.
+ *
+ * Return: 0 on success, nonzero on failure.
+ * Unable to open toplevel: failure.
+ * Unable to open some subdirectory or file: warn and continue;
+ */
+int bt_context_add_traces_recursive(struct bt_context *ctx, const char *path,
+ const char *format_str,
+ void (*packet_seek)(struct stream_pos *pos,
+ size_t offset, int whence))
+{
+ FTS *tree;
+ FTSENT *node;
+ GArray *trace_ids;
+ char lpath[PATH_MAX];
+ char * const paths[2] = { lpath, NULL };
+ int ret;
+
+ /*
+ * Need to copy path, because fts_open can change it.
+ * It is the pointer array, not the strings, that are constant.
+ */
+ strncpy(lpath, path, PATH_MAX);
+ lpath[PATH_MAX - 1] = '\0';
+
+ tree = fts_open(paths, FTS_NOCHDIR | FTS_LOGICAL, 0);
+ if (tree == NULL) {
+ fprintf(stderr, "[error] [Context] Cannot traverse \"%s\" for reading.\n",
+ path);
+ return -EINVAL;
+ }
+
+ trace_ids = g_array_new(FALSE, TRUE, sizeof(int));
+
+ while ((node = fts_read(tree))) {
+ int dirfd, metafd;
+
+ if (!(node->fts_info & FTS_D))
+ continue;
+
+ dirfd = open(node->fts_accpath, 0);
+ if (dirfd < 0) {
+ fprintf(stderr, "[error] [Context] Unable to open trace "
+ "directory file descriptor.\n");
+ ret = dirfd;
+ goto error;
+ }
+ metafd = openat(dirfd, "metadata", O_RDONLY);
+ if (metafd < 0) {
+ ret = close(dirfd);
+ if (ret < 0) {
+ perror("close");
+ goto error;
+ }
+ } else {
+ int trace_id;
+
+ ret = close(metafd);
+ if (ret < 0) {
+ perror("close");
+ goto error;
+ }
+ ret = close(dirfd);
+ if (ret < 0) {
+ perror("close");
+ goto error;
+ }
+
+ trace_id = bt_context_add_trace(ctx,
+ node->fts_accpath, format_str,
+ packet_seek);
+ if (trace_id < 0) {
+ fprintf(stderr, "[error] [Context] opening trace \"%s\" from %s "
+ "for reading.\n", node->fts_accpath, path);
+ ret = trace_id;
+ goto error;
+ }
+ g_array_append_val(trace_ids, trace_id);
+ }
+ }
+
+ g_array_free(trace_ids, TRUE);
+ return 0;
+
+error:
+ return ret;
+}
int convert_trace(struct trace_descriptor *td_write,
struct bt_context *ctx)
{
- struct bt_iter *iter;
- struct ctf_stream *stream;
- struct ctf_stream_event *event;
+ struct bt_ctf_iter *iter;
struct ctf_text_stream_pos *sout;
struct bt_iter_pos begin_pos;
+ struct bt_ctf_event *ctf_event;
int ret;
sout = container_of(td_write, struct ctf_text_stream_pos,
trace_descriptor);
begin_pos.type = BT_SEEK_BEGIN;
- iter = bt_iter_create(ctx, &begin_pos, NULL);
+ iter = bt_ctf_iter_create(ctx, &begin_pos, NULL);
if (!iter) {
ret = -1;
goto error_iter;
}
- while (bt_iter_read_event(iter, &stream, &event) == 0) {
- ret = sout->parent.event_cb(&sout->parent, stream);
+ while ((ctf_event = bt_ctf_iter_read_event(iter))) {
+ ret = sout->parent.event_cb(&sout->parent, ctf_event->stream);
if (ret) {
fprintf(stderr, "[error] Writing event failed.\n");
goto end;
}
- ret = bt_iter_next(iter);
+ ret = bt_iter_next(bt_ctf_get_iter(iter));
if (ret < 0)
goto end;
}
ret = 0;
end:
- bt_iter_destroy(iter);
+ bt_ctf_iter_destroy(iter);
error_iter:
return ret;
}
ctx = bt_context_create();
- ret = bt_context_add_traces(ctx, opt_input_path,
- opt_input_format);
+ ret = bt_context_add_traces_recursive(ctx, opt_input_path,
+ opt_input_format, NULL);
if (ret) {
fprintf(stderr, "[error] opening trace \"%s\" for reading.\n\n",
opt_input_path);