2 * SPDX-License-Identifier: MIT
4 * Copyright 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
6 * Babeltrace CTF file system Reader Component queries
10 #include <glib/gstdio.h>
11 #include <sys/types.h>
13 #include <babeltrace2/babeltrace.h>
15 #define BT_LOG_OUTPUT_LEVEL ((enum bt_log_level) log_level)
16 #define BT_LOG_TAG "PLUGIN/SRC.CTF.FS/QUERY"
17 #include "logging/comp-logging.h"
18 #include "logging/log.h"
20 #include "common/assert.h"
22 #include "../common/metadata/decoder.hpp"
24 #include "metadata.hpp"
27 #define METADATA_TEXT_SIG "/* CTF 1.8"
36 bt_component_class_query_method_status
37 metadata_info_query(bt_self_component_class_source
*self_comp_class_src
, const bt_value
*params
,
38 bt_logging_level log_level
, const bt_value
**user_result
)
40 bt_component_class_query_method_status status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK
;
41 bt_self_component_class
*self_comp_class
=
42 bt_self_component_class_source_as_self_component_class(self_comp_class_src
);
43 bt_value
*result
= NULL
;
44 const bt_value
*path_value
= NULL
;
45 FILE *metadata_fp
= NULL
;
50 struct ctf_metadata_decoder
*decoder
= NULL
;
51 ctf_metadata_decoder_config decoder_cfg
{};
52 enum ctf_metadata_decoder_status decoder_status
;
53 GString
*g_metadata_text
= NULL
;
54 const char *plaintext
;
56 result
= bt_value_map_create();
58 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR
;
64 if (!bt_value_is_map(params
)) {
65 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
66 "Query parameters is not a map value object.");
67 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
71 path_value
= bt_value_map_borrow_entry_value_const(params
, "path");
73 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
, "Mandatory `path` parameter missing");
74 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
78 if (!bt_value_is_string(path_value
)) {
79 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
80 "`path` parameter is required to be a string value");
81 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
85 path
= bt_value_string_get(path_value
);
88 metadata_fp
= ctf_fs_metadata_open_file(path
, log_level
, self_comp_class
);
90 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
, "Cannot open trace metadata: path=\"%s\".",
95 ret
= ctf_metadata_decoder_is_packetized(metadata_fp
, &is_packetized
, &bo
, log_level
, NULL
);
97 BT_COMP_CLASS_LOGE_APPEND_CAUSE(
99 "Cannot check whether or not the metadata stream is packetized: path=\"%s\".", path
);
103 decoder_cfg
.log_level
= log_level
;
104 decoder_cfg
.self_comp_class
= self_comp_class
;
105 decoder_cfg
.keep_plain_text
= true;
106 decoder
= ctf_metadata_decoder_create(&decoder_cfg
);
108 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
109 "Cannot create metadata decoder: path=\"%s\".", path
);
114 decoder_status
= ctf_metadata_decoder_append_content(decoder
, metadata_fp
);
115 if (decoder_status
) {
116 BT_COMP_CLASS_LOGE_APPEND_CAUSE(
117 self_comp_class
, "Cannot update metadata decoder's content: path=\"%s\".", path
);
121 plaintext
= ctf_metadata_decoder_get_text(decoder
);
122 g_metadata_text
= g_string_new(NULL
);
124 if (!g_metadata_text
) {
128 if (strncmp(plaintext
, METADATA_TEXT_SIG
, sizeof(METADATA_TEXT_SIG
) - 1) != 0) {
129 g_string_assign(g_metadata_text
, METADATA_TEXT_SIG
);
130 g_string_append(g_metadata_text
, " */\n\n");
133 g_string_append(g_metadata_text
, plaintext
);
135 ret
= bt_value_map_insert_string_entry(result
, "text", g_metadata_text
->str
);
137 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
138 "Cannot insert metadata text into query result.");
142 ret
= bt_value_map_insert_bool_entry(result
, "is-packetized", is_packetized
);
144 BT_COMP_CLASS_LOGE_APPEND_CAUSE(
145 self_comp_class
, "Cannot insert \"is-packetized\" attribute into query result.");
152 BT_VALUE_PUT_REF_AND_RESET(result
);
156 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
160 if (g_metadata_text
) {
161 g_string_free(g_metadata_text
, TRUE
);
163 ctf_metadata_decoder_destroy(decoder
);
166 ret
= fclose(metadata_fp
);
168 BT_LOGE_ERRNO("Cannot close metadata file stream", ": path=\"%s\"", path
);
172 *user_result
= result
;
176 static int add_range(bt_value
*info
, struct range
*range
, const char *range_name
)
179 bt_value_map_insert_entry_status status
;
187 status
= bt_value_map_insert_empty_map_entry(info
, range_name
, &range_map
);
188 if (status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
193 status
= bt_value_map_insert_signed_integer_entry(range_map
, "begin", range
->begin_ns
);
194 if (status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
199 status
= bt_value_map_insert_signed_integer_entry(range_map
, "end", range
->end_ns
);
200 if (status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
209 static int populate_stream_info(struct ctf_fs_ds_file_group
*group
, bt_value
*group_info
,
210 struct range
*stream_range
)
213 bt_value_map_insert_entry_status insert_status
;
214 struct ctf_fs_ds_index_entry
*first_ds_index_entry
, *last_ds_index_entry
;
215 gchar
*port_name
= NULL
;
218 * Since each `struct ctf_fs_ds_file_group` has a sorted array of
219 * `struct ctf_fs_ds_index_entry`, we can compute the stream range from
220 * the timestamp_begin of the first index entry and the timestamp_end
221 * of the last index entry.
223 BT_ASSERT(group
->index
);
224 BT_ASSERT(group
->index
->entries
);
225 BT_ASSERT(group
->index
->entries
->len
> 0);
228 first_ds_index_entry
=
229 (struct ctf_fs_ds_index_entry
*) g_ptr_array_index(group
->index
->entries
, 0);
232 last_ds_index_entry
= (struct ctf_fs_ds_index_entry
*) g_ptr_array_index(
233 group
->index
->entries
, group
->index
->entries
->len
- 1);
235 stream_range
->begin_ns
= first_ds_index_entry
->timestamp_begin_ns
;
236 stream_range
->end_ns
= last_ds_index_entry
->timestamp_end_ns
;
239 * If any of the begin and end timestamps is not set it means that
240 * packets don't include `timestamp_begin` _and_ `timestamp_end` fields
241 * in their packet context so we can't set the range.
244 stream_range
->begin_ns
!= UINT64_C(-1) && stream_range
->end_ns
!= UINT64_C(-1);
246 ret
= add_range(group_info
, stream_range
, "range-ns");
251 port_name
= ctf_fs_make_port_name(group
);
257 insert_status
= bt_value_map_insert_string_entry(group_info
, "port-name", port_name
);
258 if (insert_status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
268 static int populate_trace_info(const struct ctf_fs_trace
*trace
, bt_value
*trace_info
,
269 bt_logging_level log_level
, bt_self_component_class
*self_comp_class
)
273 bt_value_map_insert_entry_status insert_status
;
274 bt_value_array_append_element_status append_status
;
275 bt_value
*file_groups
= NULL
;
277 BT_ASSERT(trace
->ds_file_groups
);
278 /* Add trace range info only if it contains streams. */
279 if (trace
->ds_file_groups
->len
== 0) {
281 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
, "Trace has no streams: trace-path=%s",
286 insert_status
= bt_value_map_insert_empty_array_entry(trace_info
, "stream-infos", &file_groups
);
287 if (insert_status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
292 /* Find range of all stream groups, and of the trace. */
293 for (group_idx
= 0; group_idx
< trace
->ds_file_groups
->len
; group_idx
++) {
294 bt_value
*group_info
;
296 ctf_fs_ds_file_group
*group
=
297 (ctf_fs_ds_file_group
*) g_ptr_array_index(trace
->ds_file_groups
, group_idx
);
299 append_status
= bt_value_array_append_empty_map_element(file_groups
, &group_info
);
300 if (append_status
!= BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK
) {
305 ret
= populate_stream_info(group
, group_info
, &group_range
);
315 bt_component_class_query_method_status
316 trace_infos_query(bt_self_component_class_source
*self_comp_class_src
, const bt_value
*params
,
317 bt_logging_level log_level
, const bt_value
**user_result
)
319 struct ctf_fs_component
*ctf_fs
= NULL
;
320 bt_component_class_query_method_status status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK
;
321 bt_self_component_class
*self_comp_class
=
322 bt_self_component_class_source_as_self_component_class(self_comp_class_src
);
323 bt_value
*result
= NULL
;
324 const bt_value
*inputs_value
= NULL
;
325 const bt_value
*trace_name_value
;
327 bt_value
*trace_info
= NULL
;
328 bt_value_array_append_element_status append_status
;
332 if (!bt_value_is_map(params
)) {
333 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
,
334 "Query parameters is not a map value object.");
335 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
339 ctf_fs
= ctf_fs_component_create(log_level
);
344 if (!read_src_fs_parameters(params
, &inputs_value
, &trace_name_value
, ctf_fs
, NULL
,
346 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
350 if (ctf_fs_component_create_ctf_fs_trace(ctf_fs
, inputs_value
, trace_name_value
, NULL
,
355 result
= bt_value_array_create();
357 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR
;
361 append_status
= bt_value_array_append_empty_map_element(result
, &trace_info
);
362 if (append_status
!= BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK
) {
363 BT_COMP_CLASS_LOGE_APPEND_CAUSE(self_comp_class
, "Failed to create trace info map.");
367 ret
= populate_trace_info(ctf_fs
->trace
, trace_info
, log_level
, self_comp_class
);
375 BT_VALUE_PUT_REF_AND_RESET(result
);
378 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
383 ctf_fs_destroy(ctf_fs
);
387 *user_result
= result
;
391 bt_component_class_query_method_status
392 support_info_query(bt_self_component_class_source
*comp_class
, const bt_value
*params
,
393 bt_logging_level log_level
, const bt_value
**user_result
)
395 const bt_value
*input_type_value
;
396 const char *input_type
;
397 bt_component_class_query_method_status status
;
398 bt_value_map_insert_entry_status insert_entry_status
;
400 gchar
*metadata_path
= NULL
;
401 bt_value
*result
= NULL
;
402 struct ctf_metadata_decoder
*metadata_decoder
= NULL
;
403 FILE *metadata_file
= NULL
;
404 char uuid_str
[BT_UUID_STR_LEN
+ 1];
405 bool has_uuid
= false;
406 const bt_value
*input_value
;
409 input_type_value
= bt_value_map_borrow_entry_value_const(params
, "type");
410 BT_ASSERT(input_type_value
);
411 BT_ASSERT(bt_value_get_type(input_type_value
) == BT_VALUE_TYPE_STRING
);
412 input_type
= bt_value_string_get(input_type_value
);
414 if (strcmp(input_type
, "directory") != 0) {
418 input_value
= bt_value_map_borrow_entry_value_const(params
, "input");
419 BT_ASSERT(input_value
);
420 BT_ASSERT(bt_value_get_type(input_value
) == BT_VALUE_TYPE_STRING
);
421 input
= bt_value_string_get(input_value
);
423 metadata_path
= g_build_filename(input
, CTF_FS_METADATA_FILENAME
, NULL
);
424 if (!metadata_path
) {
425 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR
;
429 metadata_file
= g_fopen(metadata_path
, "rb");
431 ctf_metadata_decoder_config metadata_decoder_config
{};
432 enum ctf_metadata_decoder_status decoder_status
;
435 metadata_decoder_config
.log_level
= log_level
;
436 metadata_decoder_config
.self_comp_class
=
437 bt_self_component_class_source_as_self_component_class(comp_class
);
439 metadata_decoder
= ctf_metadata_decoder_create(&metadata_decoder_config
);
440 if (!metadata_decoder
) {
441 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
445 decoder_status
= ctf_metadata_decoder_append_content(metadata_decoder
, metadata_file
);
446 if (decoder_status
!= CTF_METADATA_DECODER_STATUS_OK
) {
447 BT_LOGW("cannot append metadata content: metadata-decoder-status=%d", decoder_status
);
448 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
453 * We were able to parse the metadata file, so we are
454 * confident it's a CTF trace.
458 /* If the trace has a UUID, return the stringified UUID as the group. */
459 if (ctf_metadata_decoder_get_trace_class_uuid(metadata_decoder
, uuid
) == 0) {
460 bt_uuid_to_str(uuid
, uuid_str
);
466 result
= bt_value_map_create();
468 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR
;
472 insert_entry_status
= bt_value_map_insert_real_entry(result
, "weight", weight
);
473 if (insert_entry_status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
474 status
= (bt_component_class_query_method_status
) insert_entry_status
;
478 /* We are not supposed to have weight == 0 and a UUID. */
479 BT_ASSERT(weight
> 0 || !has_uuid
);
481 if (weight
> 0 && has_uuid
) {
482 insert_entry_status
= bt_value_map_insert_string_entry(result
, "group", uuid_str
);
483 if (insert_entry_status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
484 status
= (bt_component_class_query_method_status
) insert_entry_status
;
489 *user_result
= result
;
491 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK
;
494 g_free(metadata_path
);
495 bt_value_put_ref(result
);
496 ctf_metadata_decoder_destroy(metadata_decoder
);