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 #include "cpp-common/bt2c/libc-up.hpp"
17 #include "../common/src/metadata/tsdl/decoder.hpp"
21 #define METADATA_TEXT_SIG "/* CTF 1.8"
30 bt_component_class_query_method_status
metadata_info_query(const bt_value
*params
,
31 const bt2c::Logger
& logger
,
32 const bt_value
**user_result
)
34 bt_component_class_query_method_status status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK
;
35 bt_value
*result
= NULL
;
36 const bt_value
*path_value
= NULL
;
37 bt2c::FileUP metadata_fp
;
42 struct ctf_metadata_decoder
*decoder
= NULL
;
43 ctf_metadata_decoder_config decoder_cfg
{logger
};
44 enum ctf_metadata_decoder_status decoder_status
;
45 GString
*g_metadata_text
= NULL
;
46 const char *plaintext
;
48 result
= bt_value_map_create();
50 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR
;
56 if (!bt_value_is_map(params
)) {
57 BT_CPPLOGE_APPEND_CAUSE_SPEC(logger
, "Query parameters is not a map value object.");
58 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
62 path_value
= bt_value_map_borrow_entry_value_const(params
, "path");
64 BT_CPPLOGE_APPEND_CAUSE_SPEC(logger
, "Mandatory `path` parameter missing");
65 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
69 if (!bt_value_is_string(path_value
)) {
70 BT_CPPLOGE_APPEND_CAUSE_SPEC(logger
, "`path` parameter is required to be a string value");
71 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
75 path
= bt_value_string_get(path_value
);
78 metadata_fp
.reset(ctf_fs_metadata_open_file(path
, logger
));
80 BT_CPPLOGE_APPEND_CAUSE_SPEC(logger
, "Cannot open trace metadata: path=\"{}\".", path
);
84 ret
= ctf_metadata_decoder_is_packetized(metadata_fp
.get(), &is_packetized
, &bo
, logger
);
86 BT_CPPLOGE_APPEND_CAUSE_SPEC(
87 logger
, "Cannot check whether or not the metadata stream is packetized: path=\"{}\".",
92 decoder_cfg
.keep_plain_text
= true;
93 decoder
= ctf_metadata_decoder_create(&decoder_cfg
);
95 BT_CPPLOGE_APPEND_CAUSE_SPEC(logger
, "Cannot create metadata decoder: path=\"{}\".", path
);
99 rewind(metadata_fp
.get());
100 decoder_status
= ctf_metadata_decoder_append_content(decoder
, metadata_fp
.get());
101 if (decoder_status
) {
102 BT_CPPLOGE_APPEND_CAUSE_SPEC(
103 logger
, "Cannot update metadata decoder's content: path=\"{}\".", path
);
107 plaintext
= ctf_metadata_decoder_get_text(decoder
);
108 g_metadata_text
= g_string_new(NULL
);
110 if (!g_metadata_text
) {
114 if (strncmp(plaintext
, METADATA_TEXT_SIG
, sizeof(METADATA_TEXT_SIG
) - 1) != 0) {
115 g_string_assign(g_metadata_text
, METADATA_TEXT_SIG
);
116 g_string_append(g_metadata_text
, " */\n\n");
119 g_string_append(g_metadata_text
, plaintext
);
121 ret
= bt_value_map_insert_string_entry(result
, "text", g_metadata_text
->str
);
123 BT_CPPLOGE_APPEND_CAUSE_SPEC(logger
, "Cannot insert metadata text into query result.");
127 ret
= bt_value_map_insert_bool_entry(result
, "is-packetized", is_packetized
);
129 BT_CPPLOGE_APPEND_CAUSE_SPEC(
130 logger
, "Cannot insert \"is-packetized\" attribute into query result.");
137 BT_VALUE_PUT_REF_AND_RESET(result
);
141 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
145 if (g_metadata_text
) {
146 g_string_free(g_metadata_text
, TRUE
);
148 ctf_metadata_decoder_destroy(decoder
);
150 *user_result
= result
;
154 static int add_range(bt_value
*info
, struct range
*range
, const char *range_name
)
157 bt_value_map_insert_entry_status status
;
165 status
= bt_value_map_insert_empty_map_entry(info
, range_name
, &range_map
);
166 if (status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
171 status
= bt_value_map_insert_signed_integer_entry(range_map
, "begin", range
->begin_ns
);
172 if (status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
177 status
= bt_value_map_insert_signed_integer_entry(range_map
, "end", range
->end_ns
);
178 if (status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
187 static int populate_stream_info(struct ctf_fs_ds_file_group
*group
, bt_value
*group_info
,
188 struct range
*stream_range
)
191 bt_value_map_insert_entry_status insert_status
;
192 struct ctf_fs_ds_index_entry
*first_ds_index_entry
, *last_ds_index_entry
;
193 bt2c::GCharUP port_name
;
196 * Since each `struct ctf_fs_ds_file_group` has a sorted array of
197 * `struct ctf_fs_ds_index_entry`, we can compute the stream range from
198 * the timestamp_begin of the first index entry and the timestamp_end
199 * of the last index entry.
201 BT_ASSERT(group
->index
);
202 BT_ASSERT(group
->index
->entries
);
203 BT_ASSERT(group
->index
->entries
->len
> 0);
206 first_ds_index_entry
=
207 (struct ctf_fs_ds_index_entry
*) g_ptr_array_index(group
->index
->entries
, 0);
210 last_ds_index_entry
= (struct ctf_fs_ds_index_entry
*) g_ptr_array_index(
211 group
->index
->entries
, group
->index
->entries
->len
- 1);
213 stream_range
->begin_ns
= first_ds_index_entry
->timestamp_begin_ns
;
214 stream_range
->end_ns
= last_ds_index_entry
->timestamp_end_ns
;
217 * If any of the begin and end timestamps is not set it means that
218 * packets don't include `timestamp_begin` _and_ `timestamp_end` fields
219 * in their packet context so we can't set the range.
222 stream_range
->begin_ns
!= UINT64_C(-1) && stream_range
->end_ns
!= UINT64_C(-1);
224 ret
= add_range(group_info
, stream_range
, "range-ns");
229 port_name
= ctf_fs_make_port_name(group
);
235 insert_status
= bt_value_map_insert_string_entry(group_info
, "port-name", port_name
.get());
236 if (insert_status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
245 static int populate_trace_info(const struct ctf_fs_trace
*trace
, bt_value
*trace_info
,
246 const bt2c::Logger
& logger
)
250 bt_value_map_insert_entry_status insert_status
;
251 bt_value_array_append_element_status append_status
;
252 bt_value
*file_groups
= NULL
;
254 BT_ASSERT(trace
->ds_file_groups
);
255 /* Add trace range info only if it contains streams. */
256 if (trace
->ds_file_groups
->len
== 0) {
258 BT_CPPLOGE_APPEND_CAUSE_SPEC(logger
, "Trace has no streams: trace-path={}",
263 insert_status
= bt_value_map_insert_empty_array_entry(trace_info
, "stream-infos", &file_groups
);
264 if (insert_status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
269 /* Find range of all stream groups, and of the trace. */
270 for (group_idx
= 0; group_idx
< trace
->ds_file_groups
->len
; group_idx
++) {
271 bt_value
*group_info
;
273 ctf_fs_ds_file_group
*group
=
274 (ctf_fs_ds_file_group
*) g_ptr_array_index(trace
->ds_file_groups
, group_idx
);
276 append_status
= bt_value_array_append_empty_map_element(file_groups
, &group_info
);
277 if (append_status
!= BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK
) {
282 ret
= populate_stream_info(group
, group_info
, &group_range
);
292 bt_component_class_query_method_status
293 trace_infos_query(const bt_value
*params
, const bt2c::Logger
& logger
, const bt_value
**user_result
)
295 ctf_fs_component::UP ctf_fs
;
296 bt_component_class_query_method_status status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK
;
297 bt_value
*result
= NULL
;
298 const bt_value
*inputs_value
= NULL
;
299 const bt_value
*trace_name_value
;
301 bt_value
*trace_info
= NULL
;
302 bt_value_array_append_element_status append_status
;
306 if (!bt_value_is_map(params
)) {
307 BT_CPPLOGE_APPEND_CAUSE_SPEC(logger
, "Query parameters is not a map value object.");
308 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
312 ctf_fs
= ctf_fs_component_create(logger
);
317 if (!read_src_fs_parameters(params
, &inputs_value
, &trace_name_value
, ctf_fs
.get())) {
318 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
322 if (ctf_fs_component_create_ctf_fs_trace(ctf_fs
.get(), inputs_value
, trace_name_value
, NULL
)) {
326 result
= bt_value_array_create();
328 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR
;
332 append_status
= bt_value_array_append_empty_map_element(result
, &trace_info
);
333 if (append_status
!= BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK
) {
334 BT_CPPLOGE_APPEND_CAUSE_SPEC(logger
, "Failed to create trace info map.");
338 ret
= populate_trace_info(ctf_fs
->trace
, trace_info
, logger
);
346 BT_VALUE_PUT_REF_AND_RESET(result
);
349 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
353 *user_result
= result
;
357 bt_component_class_query_method_status
358 support_info_query(const bt_value
*params
, const bt2c::Logger
& logger
, const bt_value
**user_result
)
360 const bt_value
*input_type_value
;
361 const char *input_type
;
362 bt_component_class_query_method_status status
;
363 bt_value_map_insert_entry_status insert_entry_status
;
365 bt2c::GCharUP metadata_path
;
366 bt_value
*result
= NULL
;
367 struct ctf_metadata_decoder
*metadata_decoder
= NULL
;
368 FILE *metadata_file
= NULL
;
369 char uuid_str
[BT_UUID_STR_LEN
+ 1];
370 bool has_uuid
= false;
371 const bt_value
*input_value
;
374 input_type_value
= bt_value_map_borrow_entry_value_const(params
, "type");
375 BT_ASSERT(input_type_value
);
376 BT_ASSERT(bt_value_get_type(input_type_value
) == BT_VALUE_TYPE_STRING
);
377 input_type
= bt_value_string_get(input_type_value
);
379 if (strcmp(input_type
, "directory") != 0) {
383 input_value
= bt_value_map_borrow_entry_value_const(params
, "input");
384 BT_ASSERT(input_value
);
385 BT_ASSERT(bt_value_get_type(input_value
) == BT_VALUE_TYPE_STRING
);
386 input
= bt_value_string_get(input_value
);
388 metadata_path
.reset(g_build_filename(input
, CTF_FS_METADATA_FILENAME
, NULL
));
389 if (!metadata_path
) {
390 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR
;
394 metadata_file
= g_fopen(metadata_path
.get(), "rb");
396 enum ctf_metadata_decoder_status decoder_status
;
399 ctf_metadata_decoder_config metadata_decoder_config
{logger
};
401 metadata_decoder
= ctf_metadata_decoder_create(&metadata_decoder_config
);
402 if (!metadata_decoder
) {
403 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
407 decoder_status
= ctf_metadata_decoder_append_content(metadata_decoder
, metadata_file
);
408 if (decoder_status
!= CTF_METADATA_DECODER_STATUS_OK
) {
409 BT_CPPLOGW_SPEC(logger
, "cannot append metadata content: metadata-decoder-status={}",
411 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_ERROR
;
416 * We were able to parse the metadata file, so we are
417 * confident it's a CTF trace.
421 /* If the trace has a UUID, return the stringified UUID as the group. */
422 if (ctf_metadata_decoder_get_trace_class_uuid(metadata_decoder
, uuid
) == 0) {
423 bt_uuid_to_str(uuid
, uuid_str
);
429 result
= bt_value_map_create();
431 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_MEMORY_ERROR
;
435 insert_entry_status
= bt_value_map_insert_real_entry(result
, "weight", weight
);
436 if (insert_entry_status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
437 status
= (bt_component_class_query_method_status
) insert_entry_status
;
441 /* We are not supposed to have weight == 0 and a UUID. */
442 BT_ASSERT(weight
> 0 || !has_uuid
);
444 if (weight
> 0 && has_uuid
) {
445 insert_entry_status
= bt_value_map_insert_string_entry(result
, "group", uuid_str
);
446 if (insert_entry_status
!= BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK
) {
447 status
= (bt_component_class_query_method_status
) insert_entry_status
;
452 *user_result
= result
;
454 status
= BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK
;
457 bt_value_put_ref(result
);
458 ctf_metadata_decoder_destroy(metadata_decoder
);