cpp-common/bt2c/fmt.hpp: use `wise_enum::string_type` in `EnableIfIsWiseEnum` definition
[babeltrace.git] / src / cli / babeltrace2.c
CommitLineData
34ac0e6c 1/*
0235b0db 2 * SPDX-License-Identifier: MIT
34ac0e6c 3 *
0235b0db 4 * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation
34ac0e6c 5 */
4c8bfb7e 6
ea9f8b29
PP
7#define BT_LOG_TAG "CLI"
8#include "logging.h"
9
3fadfbc0 10#include <babeltrace2/babeltrace.h>
578e048b 11#include "common/common.h"
96c1b5fe 12#include "string-format/format-error.h"
ec532b44 13#include "string-format/format-plugin-comp-cls-name.h"
a8ff38ef 14#include <unistd.h>
34ac0e6c 15#include <stdlib.h>
7f26a816
PP
16#include <string.h>
17#include <stdio.h>
33b34c43 18#include <glib.h>
dc3fffef 19#include <inttypes.h>
7cdc2bab 20#include <unistd.h>
5401f780 21#include <signal.h>
ec2c5e50
MJ
22#include "babeltrace2-cfg.h"
23#include "babeltrace2-cfg-cli-args.h"
24#include "babeltrace2-cfg-cli-args-default.h"
ebddaeb8 25#include "babeltrace2-log-level.h"
743138a3 26#include "babeltrace2-plugins.h"
3c729b9a 27#include "babeltrace2-query.h"
9009cc24
PP
28
29#define ENV_BABELTRACE_WARN_COMMAND_NAME_DIRECTORY_CLASH "BABELTRACE_CLI_WARN_COMMAND_NAME_DIRECTORY_CLASH"
75a2cb9b 30#define NSEC_PER_SEC 1000000000LL
353c2524 31#define EXIT_INTERRUPTED 2
34ac0e6c 32
b5cd7d65
FD
33enum bt_cmd_status {
34 BT_CMD_STATUS_OK = 0,
35 BT_CMD_STATUS_ERROR = -1,
36 BT_CMD_STATUS_INTERRUPTED = -2,
37};
38
39static
40const char *bt_cmd_status_string(enum bt_cmd_status cmd_status)
41{
42 switch (cmd_status) {
43 case BT_CMD_STATUS_OK:
44 return "OK";
45 case BT_CMD_STATUS_ERROR:
46 return "ERROR";
47 case BT_CMD_STATUS_INTERRUPTED:
48 return "INTERRUPTED";
49 default:
50 bt_common_abort();
51 }
52}
53
9b4f9b42
PP
54/* Application's interrupter (owned by this) */
55static bt_interrupter *the_interrupter;
5401f780 56
65d3198f 57#ifdef __MINGW32__
a2d06fd5 58
65d3198f
MJ
59#include <windows.h>
60
61static
ecd7492f 62BOOL WINAPI signal_handler(DWORD signal __attribute__((unused))) {
9b4f9b42
PP
63 if (the_interrupter) {
64 bt_interrupter_set(the_interrupter);
65d3198f
MJ
65 }
66
65d3198f
MJ
67 return TRUE;
68}
69
5401f780 70static
65d3198f
MJ
71void set_signal_handler(void)
72{
73 if (!SetConsoleCtrlHandler(signal_handler, TRUE)) {
3f7d4d90 74 BT_LOGE("Failed to set the Ctrl+C handler.");
65d3198f
MJ
75 }
76}
a2d06fd5 77
65d3198f 78#else /* __MINGW32__ */
a2d06fd5 79
65d3198f
MJ
80static
81void signal_handler(int signum)
5401f780
PP
82{
83 if (signum != SIGINT) {
84 return;
85 }
86
9b4f9b42
PP
87 if (the_interrupter) {
88 bt_interrupter_set(the_interrupter);
c7eee084 89 }
5401f780
PP
90}
91
65d3198f
MJ
92static
93void set_signal_handler(void)
94{
95 struct sigaction new_action, old_action;
96
97 new_action.sa_handler = signal_handler;
98 sigemptyset(&new_action.sa_mask);
99 new_action.sa_flags = 0;
100 sigaction(SIGINT, NULL, &old_action);
101
102 if (old_action.sa_handler != SIG_IGN) {
103 sigaction(SIGINT, &new_action, NULL);
104 }
105}
a2d06fd5 106
65d3198f
MJ
107#endif /* __MINGW32__ */
108
c7eee084 109static
f4e38e70
PP
110int query(struct bt_config *cfg, const bt_component_class *comp_cls,
111 const char *obj, const bt_value *params,
112 const bt_value **user_result, const char **fail_reason)
c7eee084 113{
3c729b9a
PP
114 return cli_query(comp_cls, obj, params, cfg->log_level,
115 the_interrupter, user_result, fail_reason);
c7eee084
PP
116}
117
0d72b8c3 118typedef const void *(*plugin_borrow_comp_cls_func_t)(
b19ff26f 119 const bt_plugin *, const char *);
d94d92ac 120
33b34c43 121static
0d72b8c3 122const void *find_component_class_from_plugin(const char *plugin_name,
33b34c43 123 const char *comp_class_name,
d94d92ac 124 plugin_borrow_comp_cls_func_t plugin_borrow_comp_cls_func)
33b34c43 125{
0d72b8c3 126 const void *comp_class = NULL;
b19ff26f 127 const bt_plugin *plugin;
7213a328 128
3f7d4d90 129 BT_LOGI("Finding component class: plugin-name=\"%s\", "
d94d92ac 130 "comp-cls-name=\"%s\"", plugin_name, comp_class_name);
7213a328 131
97512754 132 plugin = borrow_loaded_plugin_by_name(plugin_name);
33b34c43
PP
133 if (!plugin) {
134 goto end;
135 }
136
398454ed
PP
137 comp_class = plugin_borrow_comp_cls_func(plugin, comp_class_name);
138 bt_object_get_ref(comp_class);
7213a328 139
33b34c43 140end:
3f7d4d90
PP
141 if (comp_class) {
142 BT_LOGI("Found component class: plugin-name=\"%s\", "
143 "comp-cls-name=\"%s\"", plugin_name, comp_class_name);
144 } else {
145 BT_LOGI("Cannot find source component class: "
146 "plugin-name=\"%s\", comp-cls-name=\"%s\"",
147 plugin_name, comp_class_name);
7213a328
PP
148 }
149
33b34c43
PP
150 return comp_class;
151}
6c2f3ee5 152
d94d92ac 153static
b19ff26f 154const bt_component_class_source *find_source_component_class(
d94d92ac
PP
155 const char *plugin_name, const char *comp_class_name)
156{
0d72b8c3
PP
157 return (const void *) find_component_class_from_plugin(
158 plugin_name, comp_class_name,
d94d92ac 159 (plugin_borrow_comp_cls_func_t)
92fed4e1 160 bt_plugin_borrow_source_component_class_by_name_const);
d94d92ac
PP
161}
162
163static
b19ff26f 164const bt_component_class_filter *find_filter_component_class(
d94d92ac
PP
165 const char *plugin_name, const char *comp_class_name)
166{
0d72b8c3
PP
167 return (const void *) find_component_class_from_plugin(
168 plugin_name, comp_class_name,
d94d92ac 169 (plugin_borrow_comp_cls_func_t)
92fed4e1 170 bt_plugin_borrow_filter_component_class_by_name_const);
d94d92ac
PP
171}
172
173static
b19ff26f 174const bt_component_class_sink *find_sink_component_class(
d94d92ac
PP
175 const char *plugin_name, const char *comp_class_name)
176{
0d72b8c3 177 return (const void *) find_component_class_from_plugin(plugin_name,
d94d92ac
PP
178 comp_class_name,
179 (plugin_borrow_comp_cls_func_t)
92fed4e1 180 bt_plugin_borrow_sink_component_class_by_name_const);
d94d92ac
PP
181}
182
183static
b19ff26f 184const bt_component_class *find_component_class(const char *plugin_name,
d94d92ac 185 const char *comp_class_name,
4cdfc5e8 186 bt_component_class_type comp_class_type)
d94d92ac 187{
b19ff26f 188 const bt_component_class *comp_cls = NULL;
d94d92ac
PP
189
190 switch (comp_class_type) {
191 case BT_COMPONENT_CLASS_TYPE_SOURCE:
0d72b8c3 192 comp_cls = bt_component_class_source_as_component_class_const(find_source_component_class(plugin_name, comp_class_name));
d94d92ac
PP
193 break;
194 case BT_COMPONENT_CLASS_TYPE_FILTER:
0d72b8c3 195 comp_cls = bt_component_class_filter_as_component_class_const(find_filter_component_class(plugin_name, comp_class_name));
d94d92ac
PP
196 break;
197 case BT_COMPONENT_CLASS_TYPE_SINK:
0d72b8c3 198 comp_cls = bt_component_class_sink_as_component_class_const(find_sink_component_class(plugin_name, comp_class_name));
d94d92ac
PP
199 break;
200 default:
498e7994 201 bt_common_abort();
d94d92ac
PP
202 }
203
204 return comp_cls;
205}
206
c42c79ea 207static
7213a328 208void print_indent(FILE *fp, size_t indent)
c42c79ea
PP
209{
210 size_t i;
211
212 for (i = 0; i < indent; i++) {
7213a328 213 fprintf(fp, " ");
c42c79ea
PP
214 }
215}
216
217static
b19ff26f 218void print_value(FILE *, const bt_value *, size_t);
c42c79ea 219
c1081aa6 220static
b19ff26f 221void print_value_rec(FILE *, const bt_value *, size_t);
7213a328 222
c42c79ea 223static
13763113
SM
224void print_map_value(const char *key, const bt_value *object, FILE *fp,
225 size_t indent)
c42c79ea 226{
13763113
SM
227 print_indent(fp, indent);
228 fprintf(fp, "%s: ", key);
f6ccaed9 229 BT_ASSERT(object);
290725f7
PP
230
231 if (bt_value_is_array(object) &&
232 bt_value_array_is_empty(object)) {
13763113
SM
233 fprintf(fp, "[ ]\n");
234 goto end;
290725f7
PP
235 }
236
237 if (bt_value_is_map(object) &&
238 bt_value_map_is_empty(object)) {
13763113
SM
239 fprintf(fp, "{ }\n");
240 goto end;
290725f7 241 }
c42c79ea 242
290725f7
PP
243 if (bt_value_is_array(object) ||
244 bt_value_is_map(object)) {
13763113 245 fprintf(fp, "\n");
290725f7 246 }
c42c79ea 247
13763113
SM
248 print_value_rec(fp, object, indent + 2);
249
250end:
251 return;
252}
253
254static
27c61ce8 255bt_value_map_foreach_entry_const_func_status collect_map_keys(
ecd7492f
MJ
256 const char *key,
257 const bt_value *object __attribute__((unused)),
258 void *data)
13763113
SM
259{
260 GPtrArray *map_keys = data;
261
262 g_ptr_array_add(map_keys, (gpointer *) key);
263
27c61ce8 264 return BT_VALUE_MAP_FOREACH_ENTRY_CONST_FUNC_STATUS_OK;
c42c79ea
PP
265}
266
13763113
SM
267static
268gint g_ptr_array_sort_strings(gconstpointer a, gconstpointer b) {
269 const char *s1 = *((const char **) a);
270 const char *s2 = *((const char **) b);
271
272 return g_strcmp0(s1, s2);
273}
274
c42c79ea 275static
b19ff26f 276void print_value_rec(FILE *fp, const bt_value *value, size_t indent)
c42c79ea 277{
c55a9f58 278 bt_bool bool_val;
c42c79ea 279 int64_t int_val;
fdd3a2da 280 uint64_t uint_val;
c42c79ea
PP
281 double dbl_val;
282 const char *str_val;
13763113 283 GPtrArray *map_keys = NULL;
c42c79ea 284
3eb16918 285 BT_ASSERT(value);
c42c79ea 286
c42c79ea
PP
287 switch (bt_value_get_type(value)) {
288 case BT_VALUE_TYPE_NULL:
7213a328 289 fprintf(fp, "%snull%s\n", bt_common_color_bold(),
c1081aa6 290 bt_common_color_reset());
c42c79ea
PP
291 break;
292 case BT_VALUE_TYPE_BOOL:
601b0d3c 293 bool_val = bt_value_bool_get(value);
7213a328 294 fprintf(fp, "%s%s%s%s\n", bt_common_color_bold(),
04609487 295 bt_common_color_fg_bright_cyan(), bool_val ? "yes" : "no",
c1081aa6 296 bt_common_color_reset());
c42c79ea 297 break;
fdd3a2da 298 case BT_VALUE_TYPE_UNSIGNED_INTEGER:
9c08c816 299 uint_val = bt_value_integer_unsigned_get(value);
fdd3a2da 300 fprintf(fp, "%s%s%" PRIu64 "%s\n", bt_common_color_bold(),
04609487 301 bt_common_color_fg_bright_red(), uint_val,
fdd3a2da
PP
302 bt_common_color_reset());
303 break;
304 case BT_VALUE_TYPE_SIGNED_INTEGER:
9c08c816 305 int_val = bt_value_integer_signed_get(value);
7213a328 306 fprintf(fp, "%s%s%" PRId64 "%s\n", bt_common_color_bold(),
04609487 307 bt_common_color_fg_bright_red(), int_val,
c1081aa6 308 bt_common_color_reset());
c42c79ea 309 break;
a373bf69 310 case BT_VALUE_TYPE_REAL:
601b0d3c 311 dbl_val = bt_value_real_get(value);
7213a328 312 fprintf(fp, "%s%s%lf%s\n", bt_common_color_bold(),
04609487 313 bt_common_color_fg_bright_red(), dbl_val,
c1081aa6 314 bt_common_color_reset());
c42c79ea
PP
315 break;
316 case BT_VALUE_TYPE_STRING:
601b0d3c 317 str_val = bt_value_string_get(value);
7213a328 318 fprintf(fp, "%s%s%s%s\n", bt_common_color_bold(),
04609487 319 bt_common_color_fg_bright_green(), str_val,
c1081aa6 320 bt_common_color_reset());
c42c79ea
PP
321 break;
322 case BT_VALUE_TYPE_ARRAY:
50233236 323 {
f80e9ec1 324 uint64_t i, size;
393729a6 325 size = bt_value_array_get_length(value);
290725f7 326 if (size == 0) {
7213a328
PP
327 print_indent(fp, indent);
328 fprintf(fp, "[ ]\n");
290725f7
PP
329 break;
330 }
c42c79ea
PP
331
332 for (i = 0; i < size; i++) {
b19ff26f 333 const bt_value *element =
05e21286 334 bt_value_array_borrow_element_by_index_const(
07208d85 335 value, i);
c42c79ea 336
7213a328
PP
337 print_indent(fp, indent);
338 fprintf(fp, "- ");
290725f7
PP
339
340 if (bt_value_is_array(element) &&
341 bt_value_array_is_empty(element)) {
7213a328 342 fprintf(fp, "[ ]\n");
290725f7
PP
343 continue;
344 }
345
346 if (bt_value_is_map(element) &&
347 bt_value_map_is_empty(element)) {
7213a328 348 fprintf(fp, "{ }\n");
290725f7
PP
349 continue;
350 }
351
352 if (bt_value_is_array(element) ||
353 bt_value_is_map(element)) {
7213a328 354 fprintf(fp, "\n");
290725f7
PP
355 }
356
7213a328 357 print_value_rec(fp, element, indent + 2);
c42c79ea 358 }
c42c79ea 359 break;
50233236 360 }
c42c79ea 361 case BT_VALUE_TYPE_MAP:
7213a328 362 {
13763113
SM
363 guint i;
364 bt_value_map_foreach_entry_const_status foreach_status;
7213a328 365
c42c79ea 366 if (bt_value_map_is_empty(value)) {
7213a328
PP
367 print_indent(fp, indent);
368 fprintf(fp, "{ }\n");
290725f7 369 break;
c42c79ea
PP
370 }
371
13763113
SM
372 map_keys = g_ptr_array_new();
373 if (!map_keys) {
374 BT_CLI_LOGE_APPEND_CAUSE("Failed to allocated on GPtrArray.");
375 goto end;
376 }
377
378 /*
379 * We want to print the map entries in a stable order. Collect
380 * all the map's keys in a GPtrArray, sort it, then print the
381 * entries in that order.
382 */
383 foreach_status = bt_value_map_foreach_entry_const(value,
384 collect_map_keys, map_keys);
385 if (foreach_status != BT_VALUE_MAP_FOREACH_ENTRY_CONST_STATUS_OK) {
386 BT_CLI_LOGE_APPEND_CAUSE("Failed to iterator on map value.");
387 goto end;
388 }
389
390 g_ptr_array_sort(map_keys, g_ptr_array_sort_strings);
391
392 for (i = 0; i < map_keys->len; i++) {
393 const char *map_key = g_ptr_array_index(map_keys, i);
394 const bt_value *map_value;
395
396 map_value = bt_value_map_borrow_entry_value_const(value, map_key);
397 BT_ASSERT(map_value);
398
399 print_map_value(map_key, map_value, fp, indent);
400 }
401
c42c79ea 402 break;
7213a328 403 }
c42c79ea 404 default:
498e7994 405 bt_common_abort();
c42c79ea 406 }
13763113
SM
407
408 goto end;
60a97734 409
13763113
SM
410end:
411 if (map_keys) {
412 g_ptr_array_free(map_keys, TRUE);
413 }
c42c79ea
PP
414}
415
c1081aa6 416static
b19ff26f 417void print_value(FILE *fp, const bt_value *value, size_t indent)
c1081aa6
PP
418{
419 if (!bt_value_is_array(value) && !bt_value_is_map(value)) {
7213a328 420 print_indent(fp, indent);
c1081aa6
PP
421 }
422
7213a328 423 print_value_rec(fp, value, indent);
c1081aa6
PP
424}
425
c42c79ea
PP
426static
427void print_bt_config_component(struct bt_config_component *bt_config_component)
428{
ec532b44
SM
429 gchar *comp_cls_str;
430
431 comp_cls_str = format_plugin_comp_cls_opt(
432 bt_config_component->plugin_name->str,
db0f160a 433 bt_config_component->comp_cls_name->str,
ec532b44
SM
434 bt_config_component->type,
435 BT_COMMON_COLOR_WHEN_AUTO);
436 BT_ASSERT(comp_cls_str);
437
438 fprintf(stderr, " %s:\n", comp_cls_str);
3b6cfcc5
PP
439
440 if (bt_config_component->instance_name->len > 0) {
7213a328 441 fprintf(stderr, " Name: %s\n",
3b6cfcc5
PP
442 bt_config_component->instance_name->str);
443 }
444
7213a328 445 fprintf(stderr, " Parameters:\n");
05e21286 446 print_value(stderr, bt_config_component->params, 8);
ec532b44
SM
447
448 g_free(comp_cls_str);
c42c79ea
PP
449}
450
451static
452void print_bt_config_components(GPtrArray *array)
453{
454 size_t i;
455
456 for (i = 0; i < array->len; i++) {
457 struct bt_config_component *cfg_component =
e5bc7f81 458 bt_config_get_component(array, i);
c42c79ea 459 print_bt_config_component(cfg_component);
65300d60 460 BT_OBJECT_PUT_REF_AND_RESET(cfg_component);
c42c79ea
PP
461 }
462}
463
290725f7 464static
b19ff26f 465void print_plugin_paths(const bt_value *plugin_paths)
290725f7 466{
7213a328
PP
467 fprintf(stderr, " Plugin paths:\n");
468 print_value(stderr, plugin_paths, 4);
290725f7
PP
469}
470
471static
db0f160a 472void print_cfg_run(struct bt_config *cfg)
290725f7 473{
ebba3338
PP
474 size_t i;
475
05e21286 476 print_plugin_paths(cfg->plugin_paths);
7213a328 477 fprintf(stderr, " Source component instances:\n");
db0f160a 478 print_bt_config_components(cfg->cmd_data.run.sources);
ebba3338 479
db0f160a 480 if (cfg->cmd_data.run.filters->len > 0) {
7213a328 481 fprintf(stderr, " Filter component instances:\n");
db0f160a 482 print_bt_config_components(cfg->cmd_data.run.filters);
ebba3338
PP
483 }
484
7213a328 485 fprintf(stderr, " Sink component instances:\n");
db0f160a 486 print_bt_config_components(cfg->cmd_data.run.sinks);
7213a328 487 fprintf(stderr, " Connections:\n");
ebba3338 488
db0f160a 489 for (i = 0; i < cfg->cmd_data.run.connections->len; i++) {
ebba3338 490 struct bt_config_connection *cfg_connection =
db0f160a 491 g_ptr_array_index(cfg->cmd_data.run.connections,
ebba3338
PP
492 i);
493
7213a328 494 fprintf(stderr, " %s%s%s -> %s%s%s\n",
9009cc24
PP
495 cfg_connection->upstream_comp_name->str,
496 cfg_connection->upstream_port_glob->len > 0 ? "." : "",
497 cfg_connection->upstream_port_glob->str,
498 cfg_connection->downstream_comp_name->str,
499 cfg_connection->downstream_port_glob->len > 0 ? "." : "",
500 cfg_connection->downstream_port_glob->str);
ebba3338 501 }
290725f7
PP
502}
503
504static
505void print_cfg_list_plugins(struct bt_config *cfg)
506{
05e21286 507 print_plugin_paths(cfg->plugin_paths);
290725f7
PP
508}
509
c1081aa6
PP
510static
511void print_cfg_help(struct bt_config *cfg)
512{
05e21286 513 print_plugin_paths(cfg->plugin_paths);
db0f160a
PP
514}
515
516static
517void print_cfg_print_ctf_metadata(struct bt_config *cfg)
518{
05e21286 519 print_plugin_paths(cfg->plugin_paths);
7213a328
PP
520 fprintf(stderr, " Path: %s\n",
521 cfg->cmd_data.print_ctf_metadata.path->str);
db0f160a
PP
522}
523
524static
525void print_cfg_print_lttng_live_sessions(struct bt_config *cfg)
526{
05e21286 527 print_plugin_paths(cfg->plugin_paths);
7213a328
PP
528 fprintf(stderr, " URL: %s\n",
529 cfg->cmd_data.print_lttng_live_sessions.url->str);
c1081aa6
PP
530}
531
532static
a67681c1 533void print_cfg_query(struct bt_config *cfg)
c1081aa6 534{
05e21286 535 print_plugin_paths(cfg->plugin_paths);
7213a328
PP
536 fprintf(stderr, " Object: `%s`\n", cfg->cmd_data.query.object->str);
537 fprintf(stderr, " Component class:\n");
a67681c1 538 print_bt_config_component(cfg->cmd_data.query.cfg_component);
c1081aa6
PP
539}
540
c42c79ea
PP
541static
542void print_cfg(struct bt_config *cfg)
543{
7213a328 544 if (!BT_LOG_ON_INFO) {
00447e45
PP
545 return;
546 }
547
3f7d4d90 548 BT_LOGI_STR("CLI configuration:");
290725f7
PP
549
550 switch (cfg->command) {
db0f160a
PP
551 case BT_CONFIG_COMMAND_RUN:
552 print_cfg_run(cfg);
290725f7
PP
553 break;
554 case BT_CONFIG_COMMAND_LIST_PLUGINS:
555 print_cfg_list_plugins(cfg);
c1081aa6
PP
556 break;
557 case BT_CONFIG_COMMAND_HELP:
558 print_cfg_help(cfg);
559 break;
a67681c1
PP
560 case BT_CONFIG_COMMAND_QUERY:
561 print_cfg_query(cfg);
290725f7 562 break;
db0f160a
PP
563 case BT_CONFIG_COMMAND_PRINT_CTF_METADATA:
564 print_cfg_print_ctf_metadata(cfg);
565 break;
566 case BT_CONFIG_COMMAND_PRINT_LTTNG_LIVE_SESSIONS:
567 print_cfg_print_lttng_live_sessions(cfg);
568 break;
290725f7 569 default:
498e7994 570 bt_common_abort();
290725f7 571 }
c42c79ea
PP
572}
573
9009cc24 574static
b19ff26f 575void print_plugin_info(const bt_plugin *plugin)
22e22462
PP
576{
577 unsigned int major, minor, patch;
578 const char *extra;
4cdfc5e8 579 bt_property_availability version_avail;
22e22462
PP
580 const char *plugin_name;
581 const char *path;
582 const char *author;
583 const char *license;
584 const char *plugin_description;
585
586 plugin_name = bt_plugin_get_name(plugin);
587 path = bt_plugin_get_path(plugin);
588 author = bt_plugin_get_author(plugin);
589 license = bt_plugin_get_license(plugin);
590 plugin_description = bt_plugin_get_description(plugin);
9724cce9 591 version_avail = bt_plugin_get_version(plugin, &major, &minor,
22e22462
PP
592 &patch, &extra);
593 printf("%s%s%s%s:\n", bt_common_color_bold(),
04609487 594 bt_common_color_fg_bright_blue(), plugin_name,
22e22462 595 bt_common_color_reset());
a157fea9
MJ
596 if (path) {
597 printf(" %sPath%s: %s\n", bt_common_color_bold(),
598 bt_common_color_reset(), path);
599 } else {
600 puts(" Built-in");
601 }
22e22462 602
9724cce9 603 if (version_avail == BT_PROPERTY_AVAILABILITY_AVAILABLE) {
22e22462
PP
604 printf(" %sVersion%s: %u.%u.%u",
605 bt_common_color_bold(), bt_common_color_reset(),
606 major, minor, patch);
607
608 if (extra) {
609 printf("%s", extra);
610 }
611
612 printf("\n");
613 }
614
615 printf(" %sDescription%s: %s\n", bt_common_color_bold(),
616 bt_common_color_reset(),
617 plugin_description ? plugin_description : "(None)");
618 printf(" %sAuthor%s: %s\n", bt_common_color_bold(),
619 bt_common_color_reset(), author ? author : "(Unknown)");
620 printf(" %sLicense%s: %s\n", bt_common_color_bold(),
621 bt_common_color_reset(),
622 license ? license : "(Unknown)");
623}
624
9009cc24 625static
b5cd7d65 626enum bt_cmd_status cmd_query(struct bt_config *cfg)
63ce0e1d 627{
db95fa29 628 int ret = 0;
b5cd7d65 629 enum bt_cmd_status cmd_status;
b19ff26f
PP
630 const bt_component_class *comp_cls = NULL;
631 const bt_value *results = NULL;
c7eee084 632 const char *fail_reason = NULL;
63ce0e1d 633
d94d92ac
PP
634 comp_cls = find_component_class(
635 cfg->cmd_data.query.cfg_component->plugin_name->str,
db0f160a 636 cfg->cmd_data.query.cfg_component->comp_cls_name->str,
a67681c1 637 cfg->cmd_data.query.cfg_component->type);
63ce0e1d 638 if (!comp_cls) {
cee05105
PP
639 BT_CLI_LOGE_APPEND_CAUSE(
640 "Cannot find component class: plugin-name=\"%s\", "
6375b942 641 "comp-cls-name=\"%s\", comp-cls-type=%s",
7213a328
PP
642 cfg->cmd_data.query.cfg_component->plugin_name->str,
643 cfg->cmd_data.query.cfg_component->comp_cls_name->str,
6375b942
SM
644 bt_common_component_class_type_string(
645 cfg->cmd_data.query.cfg_component->type));
b5cd7d65 646 goto error;
63ce0e1d
PP
647 }
648
f4e38e70 649 ret = query(cfg, comp_cls, cfg->cmd_data.query.object->str,
05e21286 650 cfg->cmd_data.query.cfg_component->params,
da91b29a 651 &results, &fail_reason);
c7eee084 652 if (ret) {
16cbfe32
FD
653 BT_CLI_LOGE_APPEND_CAUSE(
654 "Failed to query component class: %s: plugin-name=\"%s\", "
6375b942 655 "comp-cls-name=\"%s\", comp-cls-type=%s "
16cbfe32
FD
656 "object=\"%s\"", fail_reason,
657 cfg->cmd_data.query.cfg_component->plugin_name->str,
658 cfg->cmd_data.query.cfg_component->comp_cls_name->str,
6375b942
SM
659 bt_common_component_class_type_string(
660 cfg->cmd_data.query.cfg_component->type),
16cbfe32
FD
661 cfg->cmd_data.query.object->str);
662 goto error;
63ce0e1d
PP
663 }
664
7213a328 665 print_value(stdout, results, 0);
b5cd7d65 666 cmd_status = BT_CMD_STATUS_OK;
c7eee084
PP
667 goto end;
668
b5cd7d65
FD
669error:
670 cmd_status = BT_CMD_STATUS_ERROR;
63ce0e1d
PP
671
672end:
c5b9b441
PP
673 bt_component_class_put_ref(comp_cls);
674 bt_value_put_ref(results);
b5cd7d65 675 return cmd_status;
63ce0e1d
PP
676}
677
d94d92ac
PP
678static
679void print_component_class_help(const char *plugin_name,
b19ff26f 680 const bt_component_class *comp_cls)
d94d92ac
PP
681{
682 const char *comp_class_name =
683 bt_component_class_get_name(comp_cls);
684 const char *comp_class_description =
685 bt_component_class_get_description(comp_cls);
686 const char *comp_class_help =
687 bt_component_class_get_help(comp_cls);
4cdfc5e8 688 bt_component_class_type type =
d94d92ac 689 bt_component_class_get_type(comp_cls);
ec532b44 690 gchar *comp_cls_str;
d94d92ac 691
ec532b44
SM
692 comp_cls_str = format_plugin_comp_cls_opt(plugin_name, comp_class_name,
693 type, BT_COMMON_COLOR_WHEN_AUTO);
694 BT_ASSERT(comp_cls_str);
695
696 printf("%s\n", comp_cls_str);
d94d92ac
PP
697 printf(" %sDescription%s: %s\n", bt_common_color_bold(),
698 bt_common_color_reset(),
699 comp_class_description ? comp_class_description : "(None)");
700
701 if (comp_class_help) {
702 printf("\n%s\n", comp_class_help);
703 }
ec532b44
SM
704
705 g_free(comp_cls_str);
d94d92ac
PP
706}
707
9009cc24 708static
b5cd7d65 709enum bt_cmd_status cmd_help(struct bt_config *cfg)
22e22462 710{
b5cd7d65 711 enum bt_cmd_status cmd_status;
b19ff26f
PP
712 const bt_plugin *plugin = NULL;
713 const bt_component_class *needed_comp_cls = NULL;
22e22462 714
97512754 715 plugin = borrow_loaded_plugin_by_name(cfg->cmd_data.help.cfg_component->plugin_name->str);
22e22462 716 if (!plugin) {
cee05105
PP
717 BT_CLI_LOGE_APPEND_CAUSE(
718 "Cannot find plugin: plugin-name=\"%s\"",
7213a328 719 cfg->cmd_data.help.cfg_component->plugin_name->str);
b5cd7d65 720 goto error;
22e22462
PP
721 }
722
723 print_plugin_info(plugin);
d94d92ac
PP
724 printf(" %sSource component classes%s: %d\n",
725 bt_common_color_bold(),
726 bt_common_color_reset(),
727 (int) bt_plugin_get_source_component_class_count(plugin));
728 printf(" %sFilter component classes%s: %d\n",
22e22462
PP
729 bt_common_color_bold(),
730 bt_common_color_reset(),
d94d92ac
PP
731 (int) bt_plugin_get_filter_component_class_count(plugin));
732 printf(" %sSink component classes%s: %d\n",
733 bt_common_color_bold(),
734 bt_common_color_reset(),
735 (int) bt_plugin_get_sink_component_class_count(plugin));
22e22462 736
d94d92ac
PP
737 if (strlen(cfg->cmd_data.help.cfg_component->comp_cls_name->str) == 0) {
738 /* Plugin help only */
b5cd7d65 739 cmd_status = BT_CMD_STATUS_OK;
d94d92ac
PP
740 goto end;
741 }
22e22462 742
d94d92ac
PP
743 needed_comp_cls = find_component_class(
744 cfg->cmd_data.help.cfg_component->plugin_name->str,
745 cfg->cmd_data.help.cfg_component->comp_cls_name->str,
746 cfg->cmd_data.help.cfg_component->type);
747 if (!needed_comp_cls) {
cee05105
PP
748 BT_CLI_LOGE_APPEND_CAUSE(
749 "Cannot find component class: plugin-name=\"%s\", "
6375b942 750 "comp-cls-name=\"%s\", comp-cls-type=%s",
d94d92ac
PP
751 cfg->cmd_data.help.cfg_component->plugin_name->str,
752 cfg->cmd_data.help.cfg_component->comp_cls_name->str,
6375b942
SM
753 bt_common_component_class_type_string(
754 cfg->cmd_data.help.cfg_component->type));
b5cd7d65 755 goto error;
d94d92ac 756 }
22e22462 757
d94d92ac
PP
758 printf("\n");
759 print_component_class_help(
760 cfg->cmd_data.help.cfg_component->plugin_name->str,
761 needed_comp_cls);
b5cd7d65
FD
762 cmd_status = BT_CMD_STATUS_OK;
763 goto end;
764
765error:
766 cmd_status = BT_CMD_STATUS_ERROR;
d94d92ac
PP
767
768end:
c5b9b441 769 bt_component_class_put_ref(needed_comp_cls);
b5cd7d65 770 return cmd_status;
d94d92ac
PP
771}
772
b19ff26f 773typedef void *(* plugin_borrow_comp_cls_by_index_func_t)(const bt_plugin *,
d94d92ac 774 uint64_t);
b19ff26f 775typedef const bt_component_class *(* spec_comp_cls_borrow_comp_cls_func_t)(
d94d92ac
PP
776 void *);
777
7c7301d5 778static
b19ff26f 779void cmd_list_plugins_print_component_classes(const bt_plugin *plugin,
d94d92ac
PP
780 const char *cc_type_name, uint64_t count,
781 plugin_borrow_comp_cls_by_index_func_t borrow_comp_cls_by_index_func,
782 spec_comp_cls_borrow_comp_cls_func_t spec_comp_cls_borrow_comp_cls_func)
783{
784 uint64_t i;
ec532b44 785 gchar *comp_cls_str = NULL;
22e22462 786
d94d92ac 787 if (count == 0) {
8a7c9d06 788 printf(" %s%s component classes%s: (none)\n",
d94d92ac 789 bt_common_color_bold(),
8a7c9d06 790 cc_type_name,
d94d92ac
PP
791 bt_common_color_reset());
792 goto end;
793 } else {
8a7c9d06 794 printf(" %s%s component classes%s:\n",
d94d92ac 795 bt_common_color_bold(),
8a7c9d06 796 cc_type_name,
d94d92ac 797 bt_common_color_reset());
22e22462
PP
798 }
799
d94d92ac 800 for (i = 0; i < count; i++) {
b19ff26f 801 const bt_component_class *comp_class =
d94d92ac
PP
802 spec_comp_cls_borrow_comp_cls_func(
803 borrow_comp_cls_by_index_func(plugin, i));
22e22462 804 const char *comp_class_name =
d94d92ac 805 bt_component_class_get_name(comp_class);
22e22462 806 const char *comp_class_description =
d94d92ac 807 bt_component_class_get_description(comp_class);
4cdfc5e8 808 bt_component_class_type type =
d94d92ac 809 bt_component_class_get_type(comp_class);
22e22462 810
ec532b44
SM
811 g_free(comp_cls_str);
812 comp_cls_str = format_plugin_comp_cls_opt(
813 bt_plugin_get_name(plugin), comp_class_name, type,
814 BT_COMMON_COLOR_WHEN_AUTO);
815 printf(" %s", comp_cls_str);
22e22462 816
d94d92ac
PP
817 if (comp_class_description) {
818 printf(": %s", comp_class_description);
22e22462
PP
819 }
820
d94d92ac 821 printf("\n");
22e22462
PP
822 }
823
824end:
ec532b44 825 g_free(comp_cls_str);
22e22462
PP
826}
827
9009cc24 828static
b5cd7d65 829enum bt_cmd_status cmd_list_plugins(struct bt_config *cfg)
290725f7 830{
290725f7
PP
831 int plugins_count, component_classes_count = 0, i;
832
22e22462 833 printf("From the following plugin paths:\n\n");
05e21286 834 print_value(stdout, cfg->plugin_paths, 2);
22e22462 835 printf("\n");
743138a3 836 plugins_count = get_loaded_plugins_count();
290725f7 837 if (plugins_count == 0) {
7213a328 838 printf("No plugins found.\n");
56a1cced
JG
839 goto end;
840 }
841
290725f7 842 for (i = 0; i < plugins_count; i++) {
97512754 843 const bt_plugin *plugin = borrow_loaded_plugin_by_index(i);
290725f7 844
d94d92ac
PP
845 component_classes_count +=
846 bt_plugin_get_source_component_class_count(plugin) +
847 bt_plugin_get_filter_component_class_count(plugin) +
848 bt_plugin_get_sink_component_class_count(plugin);
290725f7 849 }
33bceaf8 850
290725f7
PP
851 printf("Found %s%d%s component classes in %s%d%s plugins.\n",
852 bt_common_color_bold(),
853 component_classes_count,
854 bt_common_color_reset(),
855 bt_common_color_bold(),
856 plugins_count,
857 bt_common_color_reset());
858
859 for (i = 0; i < plugins_count; i++) {
97512754 860 const bt_plugin *plugin = borrow_loaded_plugin_by_index(i);
290725f7 861
22e22462
PP
862 printf("\n");
863 print_plugin_info(plugin);
d94d92ac
PP
864 cmd_list_plugins_print_component_classes(plugin, "Source",
865 bt_plugin_get_source_component_class_count(plugin),
866 (plugin_borrow_comp_cls_by_index_func_t)
c3dd43ec 867 bt_plugin_borrow_source_component_class_by_index_const,
d94d92ac 868 (spec_comp_cls_borrow_comp_cls_func_t)
707b7d35 869 bt_component_class_source_as_component_class);
d94d92ac
PP
870 cmd_list_plugins_print_component_classes(plugin, "Filter",
871 bt_plugin_get_filter_component_class_count(plugin),
872 (plugin_borrow_comp_cls_by_index_func_t)
c3dd43ec 873 bt_plugin_borrow_filter_component_class_by_index_const,
d94d92ac 874 (spec_comp_cls_borrow_comp_cls_func_t)
707b7d35 875 bt_component_class_filter_as_component_class);
d94d92ac
PP
876 cmd_list_plugins_print_component_classes(plugin, "Sink",
877 bt_plugin_get_sink_component_class_count(plugin),
878 (plugin_borrow_comp_cls_by_index_func_t)
c3dd43ec 879 bt_plugin_borrow_sink_component_class_by_index_const,
d94d92ac 880 (spec_comp_cls_borrow_comp_cls_func_t)
707b7d35 881 bt_component_class_sink_as_component_class);
290725f7
PP
882 }
883
884end:
b5cd7d65 885 return BT_CMD_STATUS_OK;
290725f7
PP
886}
887
9009cc24 888static
b5cd7d65 889enum bt_cmd_status cmd_print_lttng_live_sessions(struct bt_config *cfg)
db0f160a 890{
96e8c7e1 891 int ret = 0;
b5cd7d65 892 enum bt_cmd_status cmd_status;
b19ff26f
PP
893 const bt_component_class *comp_cls = NULL;
894 const bt_value *results = NULL;
895 bt_value *params = NULL;
896 const bt_value *map = NULL;
897 const bt_value *v = NULL;
96e8c7e1
MD
898 static const char * const plugin_name = "ctf";
899 static const char * const comp_cls_name = "lttng-live";
4cdfc5e8 900 static const bt_component_class_type comp_cls_type =
96e8c7e1 901 BT_COMPONENT_CLASS_TYPE_SOURCE;
f80e9ec1 902 uint64_t array_size, i;
c7eee084 903 const char *fail_reason = NULL;
c327e427 904 FILE *out_stream = stdout;
96e8c7e1 905
f6ccaed9 906 BT_ASSERT(cfg->cmd_data.print_lttng_live_sessions.url);
96e8c7e1
MD
907 comp_cls = find_component_class(plugin_name, comp_cls_name,
908 comp_cls_type);
909 if (!comp_cls) {
cee05105
PP
910 BT_CLI_LOGE_APPEND_CAUSE(
911 "Cannot find component class: plugin-name=\"%s\", "
6375b942 912 "comp-cls-name=\"%s\", comp-cls-type=%s",
96e8c7e1 913 plugin_name, comp_cls_name,
6375b942
SM
914 bt_common_component_class_type_string(
915 BT_COMPONENT_CLASS_TYPE_SOURCE));
96e8c7e1
MD
916 goto error;
917 }
918
05e21286 919 params = bt_value_map_create();
96e8c7e1
MD
920 if (!params) {
921 goto error;
922 }
923
05e21286 924 ret = bt_value_map_insert_string_entry(params, "url",
96e8c7e1
MD
925 cfg->cmd_data.print_lttng_live_sessions.url->str);
926 if (ret) {
927 goto error;
928 }
929
f4e38e70 930 ret = query(cfg, comp_cls, "sessions", params,
05e21286 931 &results, &fail_reason);
c7eee084 932 if (ret) {
16cbfe32
FD
933 BT_CLI_LOGE_APPEND_CAUSE("Failed to query `sessions` object: %s",
934 fail_reason);
935 goto error;
96e8c7e1
MD
936 }
937
f6ccaed9
PP
938 BT_ASSERT(results);
939
96e8c7e1 940 if (!bt_value_is_array(results)) {
cee05105
PP
941 BT_CLI_LOGE_APPEND_CAUSE(
942 "Expecting an array for LTTng live `sessions` query.");
96e8c7e1
MD
943 goto error;
944 }
945
c327e427
PP
946 if (cfg->cmd_data.print_lttng_live_sessions.output_path->len > 0) {
947 out_stream =
948 fopen(cfg->cmd_data.print_lttng_live_sessions.output_path->str,
949 "w");
950 if (!out_stream) {
c327e427
PP
951 BT_LOGE_ERRNO("Cannot open file for writing",
952 ": path=\"%s\"",
953 cfg->cmd_data.print_lttng_live_sessions.output_path->str);
cee05105
PP
954 (void) BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN(
955 "Babeltrace CLI",
956 "Cannot open file for writing: path=\"%s\"",
957 cfg->cmd_data.print_lttng_live_sessions.output_path->str);
b5cd7d65 958 goto error;
c327e427
PP
959 }
960 }
961
393729a6 962 array_size = bt_value_array_get_length(results);
96e8c7e1
MD
963 for (i = 0; i < array_size; i++) {
964 const char *url_text;
965 int64_t timer_us, streams, clients;
966
05e21286 967 map = bt_value_array_borrow_element_by_index_const(results, i);
96e8c7e1 968 if (!bt_value_is_map(map)) {
cee05105 969 BT_CLI_LOGE_APPEND_CAUSE("Unexpected entry type.");
96e8c7e1
MD
970 goto error;
971 }
972
05e21286 973 v = bt_value_map_borrow_entry_value_const(map, "url");
96e8c7e1 974 if (!v) {
cee05105 975 BT_CLI_LOGE_APPEND_CAUSE("Missing `url` entry.");
96e8c7e1
MD
976 goto error;
977 }
601b0d3c 978 url_text = bt_value_string_get(v);
c327e427 979 fprintf(out_stream, "%s", url_text);
05e21286 980 v = bt_value_map_borrow_entry_value_const(map, "timer-us");
96e8c7e1 981 if (!v) {
cee05105 982 BT_CLI_LOGE_APPEND_CAUSE("Missing `timer-us` entry.");
96e8c7e1
MD
983 goto error;
984 }
a91cb83e 985 timer_us = bt_value_integer_unsigned_get(v);
c327e427 986 fprintf(out_stream, " (timer = %" PRIu64 ", ", timer_us);
05e21286 987 v = bt_value_map_borrow_entry_value_const(map, "stream-count");
96e8c7e1 988 if (!v) {
cee05105
PP
989 BT_CLI_LOGE_APPEND_CAUSE(
990 "Missing `stream-count` entry.");
96e8c7e1
MD
991 goto error;
992 }
a91cb83e 993 streams = bt_value_integer_unsigned_get(v);
c327e427 994 fprintf(out_stream, "%" PRIu64 " stream(s), ", streams);
05e21286 995 v = bt_value_map_borrow_entry_value_const(map, "client-count");
96e8c7e1 996 if (!v) {
cee05105
PP
997 BT_CLI_LOGE_APPEND_CAUSE(
998 "Missing `client-count` entry.");
96e8c7e1
MD
999 goto error;
1000 }
a91cb83e 1001 clients = bt_value_integer_unsigned_get(v);
c327e427 1002 fprintf(out_stream, "%" PRIu64 " client(s) connected)\n", clients);
96e8c7e1 1003 }
c7eee084 1004
b5cd7d65 1005 cmd_status = BT_CMD_STATUS_OK;
c7eee084
PP
1006 goto end;
1007
c7eee084 1008error:
b5cd7d65 1009 cmd_status = BT_CMD_STATUS_ERROR;
c7eee084 1010
96e8c7e1 1011end:
c5b9b441
PP
1012 bt_value_put_ref(results);
1013 bt_value_put_ref(params);
1014 bt_component_class_put_ref(comp_cls);
c327e427
PP
1015
1016 if (out_stream && out_stream != stdout) {
1017 int fclose_ret = fclose(out_stream);
1018
1019 if (fclose_ret) {
1020 BT_LOGE_ERRNO("Cannot close file stream",
1021 ": path=\"%s\"",
1022 cfg->cmd_data.print_lttng_live_sessions.output_path->str);
1023 }
1024 }
1025
b5cd7d65 1026 return cmd_status;
db0f160a
PP
1027}
1028
9009cc24 1029static
b5cd7d65 1030enum bt_cmd_status cmd_print_ctf_metadata(struct bt_config *cfg)
05a67631
PP
1031{
1032 int ret = 0;
b5cd7d65 1033 enum bt_cmd_status cmd_status;
b19ff26f
PP
1034 const bt_component_class *comp_cls = NULL;
1035 const bt_value *results = NULL;
1036 bt_value *params = NULL;
1037 const bt_value *metadata_text_value = NULL;
05a67631 1038 const char *metadata_text = NULL;
db0f160a
PP
1039 static const char * const plugin_name = "ctf";
1040 static const char * const comp_cls_name = "fs";
4cdfc5e8 1041 static const bt_component_class_type comp_cls_type =
db0f160a 1042 BT_COMPONENT_CLASS_TYPE_SOURCE;
c7eee084 1043 const char *fail_reason = NULL;
c327e427 1044 FILE *out_stream = stdout;
db0f160a 1045
f6ccaed9 1046 BT_ASSERT(cfg->cmd_data.print_ctf_metadata.path);
db0f160a
PP
1047 comp_cls = find_component_class(plugin_name, comp_cls_name,
1048 comp_cls_type);
05a67631 1049 if (!comp_cls) {
cee05105
PP
1050 BT_CLI_LOGE_APPEND_CAUSE(
1051 "Cannot find component class: plugin-name=\"%s\", "
6375b942 1052 "comp-cls-name=\"%s\", comp-cls-type=%s",
7213a328 1053 plugin_name, comp_cls_name,
6375b942
SM
1054 bt_common_component_class_type_string(
1055 BT_COMPONENT_CLASS_TYPE_SOURCE));
b5cd7d65 1056 goto error;
05a67631
PP
1057 }
1058
05e21286 1059 params = bt_value_map_create();
05a67631 1060 if (!params) {
b5cd7d65 1061 goto error;
05a67631
PP
1062 }
1063
05e21286 1064 ret = bt_value_map_insert_string_entry(params, "path",
db0f160a 1065 cfg->cmd_data.print_ctf_metadata.path->str);
05a67631 1066 if (ret) {
b5cd7d65 1067 goto error;
05a67631
PP
1068 }
1069
f4e38e70 1070 ret = query(cfg, comp_cls, "metadata-info",
05e21286 1071 params, &results, &fail_reason);
c7eee084 1072 if (ret) {
16cbfe32
FD
1073 BT_CLI_LOGE_APPEND_CAUSE(
1074 "Failed to query `metadata-info` object: %s", fail_reason);
1075 goto error;
05a67631
PP
1076 }
1077
05e21286 1078 metadata_text_value = bt_value_map_borrow_entry_value_const(results,
cee05105 1079 "text");
05a67631 1080 if (!metadata_text_value) {
cee05105
PP
1081 BT_CLI_LOGE_APPEND_CAUSE(
1082 "Cannot find `text` string value in the resulting metadata info object.");
b5cd7d65 1083 goto error;
05a67631
PP
1084 }
1085
601b0d3c 1086 metadata_text = bt_value_string_get(metadata_text_value);
c327e427
PP
1087
1088 if (cfg->cmd_data.print_ctf_metadata.output_path->len > 0) {
1089 out_stream =
1090 fopen(cfg->cmd_data.print_ctf_metadata.output_path->str,
1091 "w");
1092 if (!out_stream) {
c327e427
PP
1093 BT_LOGE_ERRNO("Cannot open file for writing",
1094 ": path=\"%s\"",
1095 cfg->cmd_data.print_ctf_metadata.output_path->str);
cee05105
PP
1096 (void) BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_UNKNOWN(
1097 "Babeltrace CLI",
1098 "Cannot open file for writing: path=\"%s\"",
1099 cfg->cmd_data.print_ctf_metadata.output_path->str);
b5cd7d65 1100 goto error;
c327e427
PP
1101 }
1102 }
1103
1104 ret = fprintf(out_stream, "%s\n", metadata_text);
1105 if (ret < 0) {
cee05105
PP
1106 BT_CLI_LOGE_APPEND_CAUSE(
1107 "Cannot write whole metadata text to output stream: "
c327e427 1108 "ret=%d", ret);
b5cd7d65 1109 goto error;
c327e427
PP
1110 }
1111
b5cd7d65 1112 cmd_status = BT_CMD_STATUS_OK;
c7eee084
PP
1113 goto end;
1114
b5cd7d65
FD
1115error:
1116 cmd_status = BT_CMD_STATUS_ERROR;
05a67631
PP
1117
1118end:
c5b9b441
PP
1119 bt_value_put_ref(results);
1120 bt_value_put_ref(params);
1121 bt_component_class_put_ref(comp_cls);
c327e427
PP
1122
1123 if (out_stream && out_stream != stdout) {
1124 int fclose_ret = fclose(out_stream);
1125
1126 if (fclose_ret) {
1127 BT_LOGE_ERRNO("Cannot close file stream",
1128 ": path=\"%s\"",
1129 cfg->cmd_data.print_ctf_metadata.output_path->str);
1130 }
1131 }
1132
b5cd7d65 1133 return cmd_status;
05a67631
PP
1134}
1135
75a2cb9b
JG
1136struct port_id {
1137 char *instance_name;
1138 char *port_name;
1139};
1140
1141struct trace_range {
1142 uint64_t intersection_range_begin_ns;
1143 uint64_t intersection_range_end_ns;
1144};
1145
1146static
1147guint port_id_hash(gconstpointer v)
1148{
1149 const struct port_id *id = v;
1150
f6ccaed9
PP
1151 BT_ASSERT(id->instance_name);
1152 BT_ASSERT(id->port_name);
75a2cb9b
JG
1153
1154 return g_str_hash(id->instance_name) ^ g_str_hash(id->port_name);
1155}
1156
1157static
1158gboolean port_id_equal(gconstpointer v1, gconstpointer v2)
1159{
1160 const struct port_id *id1 = v1;
1161 const struct port_id *id2 = v2;
1162
2242b43d
PP
1163 return strcmp(id1->instance_name, id2->instance_name) == 0 &&
1164 strcmp(id1->port_name, id2->port_name) == 0;
75a2cb9b
JG
1165}
1166
1167static
1168void port_id_destroy(gpointer data)
1169{
1170 struct port_id *id = data;
1171
1172 free(id->instance_name);
1173 free(id->port_name);
1174 free(id);
1175}
1176
1177static
1178void trace_range_destroy(gpointer data)
1179{
1180 free(data);
1181}
1182
9009cc24
PP
1183struct cmd_run_ctx {
1184 /* Owned by this */
d94d92ac
PP
1185 GHashTable *src_components;
1186
1187 /* Owned by this */
1188 GHashTable *flt_components;
1189
1190 /* Owned by this */
1191 GHashTable *sink_components;
9009cc24
PP
1192
1193 /* Owned by this */
b19ff26f 1194 bt_graph *graph;
9009cc24
PP
1195
1196 /* Weak */
1197 struct bt_config *cfg;
1198
1199 bool connect_ports;
75a2cb9b
JG
1200
1201 bool stream_intersection_mode;
1202
1203 /*
1204 * Association of struct port_id -> struct trace_range.
1205 */
1206 GHashTable *intersections;
9009cc24
PP
1207};
1208
75a2cb9b
JG
1209/* Returns a timestamp of the form "(-)s.ns" */
1210static
1211char *s_from_ns(int64_t ns)
1212{
1213 int ret;
1214 char *s_ret = NULL;
1215 bool is_negative;
1216 int64_t ts_sec_abs, ts_nsec_abs;
1217 int64_t ts_sec = ns / NSEC_PER_SEC;
1218 int64_t ts_nsec = ns % NSEC_PER_SEC;
1219
1220 if (ts_sec >= 0 && ts_nsec >= 0) {
1221 is_negative = false;
1222 ts_sec_abs = ts_sec;
1223 ts_nsec_abs = ts_nsec;
1224 } else if (ts_sec > 0 && ts_nsec < 0) {
1225 is_negative = false;
1226 ts_sec_abs = ts_sec - 1;
1227 ts_nsec_abs = NSEC_PER_SEC + ts_nsec;
1228 } else if (ts_sec == 0 && ts_nsec < 0) {
1229 is_negative = true;
1230 ts_sec_abs = ts_sec;
1231 ts_nsec_abs = -ts_nsec;
1232 } else if (ts_sec < 0 && ts_nsec > 0) {
1233 is_negative = true;
1234 ts_sec_abs = -(ts_sec + 1);
1235 ts_nsec_abs = NSEC_PER_SEC - ts_nsec;
1236 } else if (ts_sec < 0 && ts_nsec == 0) {
1237 is_negative = true;
1238 ts_sec_abs = -ts_sec;
1239 ts_nsec_abs = ts_nsec;
1240 } else { /* (ts_sec < 0 && ts_nsec < 0) */
1241 is_negative = true;
1242 ts_sec_abs = -ts_sec;
1243 ts_nsec_abs = -ts_nsec;
1244 }
1245
1246 ret = asprintf(&s_ret, "%s%" PRId64 ".%09" PRId64,
1247 is_negative ? "-" : "", ts_sec_abs, ts_nsec_abs);
1248 if (ret < 0) {
1249 s_ret = NULL;
1250 }
1251 return s_ret;
1252}
1253
9009cc24
PP
1254static
1255int cmd_run_ctx_connect_upstream_port_to_downstream_component(
d94d92ac 1256 struct cmd_run_ctx *ctx,
b19ff26f
PP
1257 const bt_component *upstream_comp,
1258 const bt_port_output *out_upstream_port,
9009cc24 1259 struct bt_config_connection *cfg_conn)
290725f7 1260{
d94d92ac 1261 typedef uint64_t (*input_port_count_func_t)(void *);
b19ff26f 1262 typedef const bt_port_input *(*borrow_input_port_by_index_func_t)(
0d72b8c3 1263 const void *, uint64_t);
b19ff26f 1264 const bt_port *upstream_port =
0d72b8c3 1265 bt_port_output_as_port_const(out_upstream_port);
d94d92ac 1266
290725f7 1267 int ret = 0;
9009cc24 1268 GQuark downstreamp_comp_name_quark;
d94d92ac
PP
1269 void *downstream_comp;
1270 uint64_t downstream_port_count;
9009cc24 1271 uint64_t i;
d94d92ac
PP
1272 input_port_count_func_t port_count_fn;
1273 borrow_input_port_by_index_func_t port_by_index_fn;
d24d5663
PP
1274 bt_graph_connect_ports_status connect_ports_status =
1275 BT_GRAPH_CONNECT_PORTS_STATUS_OK;
75a2cb9b 1276 bool insert_trimmer = false;
b19ff26f 1277 bt_value *trimmer_params = NULL;
75a2cb9b
JG
1278 char *intersection_begin = NULL;
1279 char *intersection_end = NULL;
b19ff26f
PP
1280 const bt_component_filter *trimmer = NULL;
1281 const bt_component_class_filter *trimmer_class = NULL;
1282 const bt_port_input *trimmer_input = NULL;
1283 const bt_port_output *trimmer_output = NULL;
75a2cb9b
JG
1284
1285 if (ctx->intersections &&
1286 bt_component_get_class_type(upstream_comp) ==
1287 BT_COMPONENT_CLASS_TYPE_SOURCE) {
1288 struct trace_range *range;
1289 struct port_id port_id = {
1290 .instance_name = (char *) bt_component_get_name(upstream_comp),
1291 .port_name = (char *) bt_port_get_name(upstream_port)
1292 };
1293
1294 if (!port_id.instance_name || !port_id.port_name) {
1295 goto error;
1296 }
1297
1298 range = (struct trace_range *) g_hash_table_lookup(
1299 ctx->intersections, &port_id);
1300 if (range) {
d24d5663 1301 bt_value_map_insert_entry_status insert_status;
75a2cb9b
JG
1302
1303 intersection_begin = s_from_ns(
1304 range->intersection_range_begin_ns);
1305 intersection_end = s_from_ns(
1306 range->intersection_range_end_ns);
1307 if (!intersection_begin || !intersection_end) {
cee05105
PP
1308 BT_CLI_LOGE_APPEND_CAUSE(
1309 "Cannot create trimmer argument timestamp string.");
75a2cb9b
JG
1310 goto error;
1311 }
1312
1313 insert_trimmer = true;
05e21286 1314 trimmer_params = bt_value_map_create();
75a2cb9b
JG
1315 if (!trimmer_params) {
1316 goto error;
1317 }
1318
d24d5663 1319 insert_status = bt_value_map_insert_string_entry(
07208d85 1320 trimmer_params, "begin", intersection_begin);
d24d5663 1321 if (insert_status < 0) {
75a2cb9b
JG
1322 goto error;
1323 }
d24d5663 1324 insert_status = bt_value_map_insert_string_entry(
07208d85 1325 trimmer_params,
75a2cb9b 1326 "end", intersection_end);
d24d5663 1327 if (insert_status < 0) {
75a2cb9b
JG
1328 goto error;
1329 }
1330 }
1331
d94d92ac 1332 trimmer_class = find_filter_component_class("utils", "trimmer");
75a2cb9b
JG
1333 if (!trimmer_class) {
1334 goto error;
1335 }
1336 }
9009cc24 1337
7213a328
PP
1338 BT_LOGI("Connecting upstream port to the next available downstream port: "
1339 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
1340 "downstream-comp-name=\"%s\", conn-arg=\"%s\"",
1341 upstream_port, bt_port_get_name(upstream_port),
1342 cfg_conn->downstream_comp_name->str,
1343 cfg_conn->arg->str);
9009cc24
PP
1344 downstreamp_comp_name_quark = g_quark_from_string(
1345 cfg_conn->downstream_comp_name->str);
f6ccaed9 1346 BT_ASSERT(downstreamp_comp_name_quark > 0);
d94d92ac 1347 downstream_comp = g_hash_table_lookup(ctx->flt_components,
71c7c95f 1348 GUINT_TO_POINTER(downstreamp_comp_name_quark));
d94d92ac
PP
1349 port_count_fn = (input_port_count_func_t)
1350 bt_component_filter_get_input_port_count;
1351 port_by_index_fn = (borrow_input_port_by_index_func_t)
0d72b8c3 1352 bt_component_filter_borrow_input_port_by_index_const;
d94d92ac
PP
1353
1354 if (!downstream_comp) {
1355 downstream_comp = g_hash_table_lookup(ctx->sink_components,
1356 GUINT_TO_POINTER(downstreamp_comp_name_quark));
1357 port_count_fn = (input_port_count_func_t)
1358 bt_component_sink_get_input_port_count;
1359 port_by_index_fn = (borrow_input_port_by_index_func_t)
0d72b8c3 1360 bt_component_sink_borrow_input_port_by_index_const;
d94d92ac
PP
1361 }
1362
9009cc24 1363 if (!downstream_comp) {
cee05105
PP
1364 BT_CLI_LOGE_APPEND_CAUSE("Cannot find downstream component: "
1365 "comp-name=\"%s\", conn-arg=\"%s\"",
1366 cfg_conn->downstream_comp_name->str,
9009cc24
PP
1367 cfg_conn->arg->str);
1368 goto error;
1369 }
1370
9009cc24 1371 downstream_port_count = port_count_fn(downstream_comp);
9009cc24
PP
1372
1373 for (i = 0; i < downstream_port_count; i++) {
b19ff26f 1374 const bt_port_input *in_downstream_port =
9009cc24 1375 port_by_index_fn(downstream_comp, i);
b19ff26f 1376 const bt_port *downstream_port =
0d72b8c3 1377 bt_port_input_as_port_const(in_downstream_port);
75a2cb9b 1378 const char *upstream_port_name;
9009cc24
PP
1379 const char *downstream_port_name;
1380
f6ccaed9 1381 BT_ASSERT(downstream_port);
9009cc24 1382
75a2cb9b 1383 /* Skip port if it's already connected. */
9009cc24 1384 if (bt_port_is_connected(downstream_port)) {
3f7d4d90 1385 BT_LOGI("Skipping downstream port: already connected: "
7213a328
PP
1386 "port-addr=%p, port-name=\"%s\"",
1387 downstream_port,
1388 bt_port_get_name(downstream_port));
9009cc24
PP
1389 continue;
1390 }
1391
1392 downstream_port_name = bt_port_get_name(downstream_port);
f6ccaed9 1393 BT_ASSERT(downstream_port_name);
75a2cb9b 1394 upstream_port_name = bt_port_get_name(upstream_port);
f6ccaed9 1395 BT_ASSERT(upstream_port_name);
9009cc24 1396
75a2cb9b 1397 if (!bt_common_star_glob_match(
1974687e
MJ
1398 cfg_conn->downstream_port_glob->str, SIZE_MAX,
1399 downstream_port_name, SIZE_MAX)) {
75a2cb9b
JG
1400 continue;
1401 }
1402
1403 if (insert_trimmer) {
1404 /*
d94d92ac
PP
1405 * In order to insert the trimmer between the
1406 * two components that were being connected, we
1407 * create a connection configuration entry which
1408 * describes a connection from the trimmer's
1409 * output to the original input that was being
1410 * connected.
75a2cb9b 1411 *
d94d92ac
PP
1412 * Hence, the creation of the trimmer will cause
1413 * the graph "new port" listener to establish
1414 * all downstream connections as its output port
1415 * is connected. We will then establish the
1416 * connection between the original upstream
1417 * source and the trimmer.
75a2cb9b
JG
1418 */
1419 char *trimmer_name = NULL;
d24d5663 1420 bt_graph_add_component_status add_comp_status;
75a2cb9b 1421
d94d92ac
PP
1422 ret = asprintf(&trimmer_name,
1423 "stream-intersection-trimmer-%s",
75a2cb9b
JG
1424 upstream_port_name);
1425 if (ret < 0) {
1426 goto error;
1427 }
1428 ret = 0;
1429
1430 ctx->connect_ports = false;
d24d5663 1431 add_comp_status = bt_graph_add_filter_component(
d94d92ac 1432 ctx->graph, trimmer_class, trimmer_name,
e874da19
PP
1433 trimmer_params, ctx->cfg->log_level,
1434 &trimmer);
a91462c9 1435 bt_component_filter_get_ref(trimmer);
75a2cb9b 1436 free(trimmer_name);
d24d5663
PP
1437 if (add_comp_status !=
1438 BT_GRAPH_ADD_COMPONENT_STATUS_OK) {
75a2cb9b
JG
1439 goto error;
1440 }
f6ccaed9 1441 BT_ASSERT(trimmer);
75a2cb9b
JG
1442
1443 trimmer_input =
0d72b8c3 1444 bt_component_filter_borrow_input_port_by_index_const(
75a2cb9b
JG
1445 trimmer, 0);
1446 if (!trimmer_input) {
1447 goto error;
1448 }
1449 trimmer_output =
0d72b8c3 1450 bt_component_filter_borrow_output_port_by_index_const(
75a2cb9b
JG
1451 trimmer, 0);
1452 if (!trimmer_output) {
9009cc24
PP
1453 goto error;
1454 }
1455
75a2cb9b
JG
1456 /*
1457 * Replace the current downstream port by the trimmer's
1458 * upstream port.
1459 */
d94d92ac
PP
1460 in_downstream_port = trimmer_input;
1461 downstream_port =
0d72b8c3 1462 bt_port_input_as_port_const(in_downstream_port);
75a2cb9b
JG
1463 downstream_port_name = bt_port_get_name(
1464 downstream_port);
d94d92ac 1465 BT_ASSERT(downstream_port_name);
75a2cb9b
JG
1466 }
1467
1468 /* We have a winner! */
d24d5663 1469 connect_ports_status = bt_graph_connect_ports(ctx->graph,
d94d92ac
PP
1470 out_upstream_port, in_downstream_port, NULL);
1471 downstream_port = NULL;
d24d5663
PP
1472 switch (connect_ports_status) {
1473 case BT_GRAPH_CONNECT_PORTS_STATUS_OK:
75a2cb9b 1474 break;
75a2cb9b 1475 default:
cee05105
PP
1476 BT_CLI_LOGE_APPEND_CAUSE(
1477 "Cannot create connection: graph refuses to connect ports: "
75a2cb9b
JG
1478 "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
1479 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
1480 "downstream-comp-addr=%p, downstream-comp-name=\"%s\", "
1481 "downstream-port-addr=%p, downstream-port-name=\"%s\", "
1482 "conn-arg=\"%s\"",
1483 upstream_comp, bt_component_get_name(upstream_comp),
1484 upstream_port, bt_port_get_name(upstream_port),
1485 downstream_comp, cfg_conn->downstream_comp_name->str,
1486 downstream_port, downstream_port_name,
1487 cfg_conn->arg->str);
75a2cb9b 1488 goto error;
9009cc24
PP
1489 }
1490
75a2cb9b
JG
1491 BT_LOGI("Connected component ports: "
1492 "upstream-comp-addr=%p, upstream-comp-name=\"%s\", "
1493 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
1494 "downstream-comp-addr=%p, downstream-comp-name=\"%s\", "
1495 "downstream-port-addr=%p, downstream-port-name=\"%s\", "
1496 "conn-arg=\"%s\"",
1497 upstream_comp, bt_component_get_name(upstream_comp),
1498 upstream_port, bt_port_get_name(upstream_port),
1499 downstream_comp, cfg_conn->downstream_comp_name->str,
1500 downstream_port, downstream_port_name,
1501 cfg_conn->arg->str);
1502
1503 if (insert_trimmer) {
1504 /*
1505 * The first connection, from the source to the trimmer,
1506 * has been done. We now connect the trimmer to the
1507 * original downstream port.
1508 */
1509 ret = cmd_run_ctx_connect_upstream_port_to_downstream_component(
d94d92ac 1510 ctx,
0d72b8c3 1511 bt_component_filter_as_component_const(trimmer),
d94d92ac 1512 trimmer_output, cfg_conn);
75a2cb9b
JG
1513 if (ret) {
1514 goto error;
1515 }
1516 ctx->connect_ports = true;
1517 }
9009cc24 1518
53bc54cd
PP
1519 /*
1520 * We found a matching downstream port: the search is
1521 * over.
1522 */
1523 goto end;
05a67631
PP
1524 }
1525
53bc54cd 1526 /* No downstream port found */
cee05105
PP
1527 BT_CLI_LOGE_APPEND_CAUSE(
1528 "Cannot create connection: cannot find a matching downstream port for upstream port: "
53bc54cd
PP
1529 "upstream-port-addr=%p, upstream-port-name=\"%s\", "
1530 "downstream-comp-name=\"%s\", conn-arg=\"%s\"",
1531 upstream_port, bt_port_get_name(upstream_port),
1532 cfg_conn->downstream_comp_name->str,
1533 cfg_conn->arg->str);
9009cc24
PP
1534
1535error:
1536 ret = -1;
1537
1538end:
75a2cb9b
JG
1539 free(intersection_begin);
1540 free(intersection_end);
c5b9b441
PP
1541 BT_VALUE_PUT_REF_AND_RESET(trimmer_params);
1542 BT_COMPONENT_CLASS_FILTER_PUT_REF_AND_RESET(trimmer_class);
1543 BT_COMPONENT_FILTER_PUT_REF_AND_RESET(trimmer);
9009cc24
PP
1544 return ret;
1545}
1546
1547static
1548int cmd_run_ctx_connect_upstream_port(struct cmd_run_ctx *ctx,
b19ff26f 1549 const bt_port_output *upstream_port)
9009cc24
PP
1550{
1551 int ret = 0;
1552 const char *upstream_port_name;
1553 const char *upstream_comp_name;
b19ff26f 1554 const bt_component *upstream_comp = NULL;
9009cc24
PP
1555 size_t i;
1556
f6ccaed9
PP
1557 BT_ASSERT(ctx);
1558 BT_ASSERT(upstream_port);
d94d92ac 1559 upstream_port_name = bt_port_get_name(
0d72b8c3 1560 bt_port_output_as_port_const(upstream_port));
f6ccaed9 1561 BT_ASSERT(upstream_port_name);
0d72b8c3
PP
1562 upstream_comp = bt_port_borrow_component_const(
1563 bt_port_output_as_port_const(upstream_port));
cee05105 1564 BT_ASSERT(upstream_comp);
9009cc24 1565 upstream_comp_name = bt_component_get_name(upstream_comp);
f6ccaed9 1566 BT_ASSERT(upstream_comp_name);
7213a328
PP
1567 BT_LOGI("Connecting upstream port: comp-addr=%p, comp-name=\"%s\", "
1568 "port-addr=%p, port-name=\"%s\"",
1569 upstream_comp, upstream_comp_name,
1570 upstream_port, upstream_port_name);
9009cc24
PP
1571
1572 for (i = 0; i < ctx->cfg->cmd_data.run.connections->len; i++) {
1573 struct bt_config_connection *cfg_conn =
1574 g_ptr_array_index(
1575 ctx->cfg->cmd_data.run.connections, i);
1576
1577 if (strcmp(cfg_conn->upstream_comp_name->str,
75a2cb9b
JG
1578 upstream_comp_name)) {
1579 continue;
1580 }
1581
1582 if (!bt_common_star_glob_match(
1583 cfg_conn->upstream_port_glob->str,
1974687e 1584 SIZE_MAX, upstream_port_name, SIZE_MAX)) {
75a2cb9b
JG
1585 continue;
1586 }
1587
1588 ret = cmd_run_ctx_connect_upstream_port_to_downstream_component(
1589 ctx, upstream_comp, upstream_port, cfg_conn);
1590 if (ret) {
cee05105
PP
1591 BT_CLI_LOGE_APPEND_CAUSE(
1592 "Cannot connect upstream port: "
75a2cb9b
JG
1593 "port-addr=%p, port-name=\"%s\"",
1594 upstream_port,
1595 upstream_port_name);
75a2cb9b 1596 goto error;
9009cc24 1597 }
75a2cb9b 1598 goto end;
9009cc24
PP
1599 }
1600
cee05105
PP
1601 BT_CLI_LOGE_APPEND_CAUSE(
1602 "Cannot connect upstream port: port does not match any connection argument: "
7213a328
PP
1603 "port-addr=%p, port-name=\"%s\"", upstream_port,
1604 upstream_port_name);
9009cc24
PP
1605
1606error:
1607 ret = -1;
1608
1609end:
9009cc24
PP
1610 return ret;
1611}
1612
1613static
d24d5663 1614bt_graph_listener_func_status
8cc56726 1615graph_output_port_added_listener(struct cmd_run_ctx *ctx,
b19ff26f 1616 const bt_port_output *out_port)
9009cc24 1617{
b19ff26f
PP
1618 const bt_component *comp;
1619 const bt_port *port = bt_port_output_as_port_const(out_port);
d24d5663
PP
1620 bt_graph_listener_func_status ret =
1621 BT_GRAPH_LISTENER_FUNC_STATUS_OK;
9009cc24 1622
0d72b8c3 1623 comp = bt_port_borrow_component_const(port);
e12720c0
PP
1624 BT_LOGI("Port added to a graph's component: comp-addr=%p, "
1625 "comp-name=\"%s\", port-addr=%p, port-name=\"%s\"",
1626 comp, comp ? bt_component_get_name(comp) : "",
7213a328 1627 port, bt_port_get_name(port));
36712f1d
PP
1628
1629 if (!ctx->connect_ports) {
1630 goto end;
1631 }
1632
cee05105 1633 BT_ASSERT(comp);
7c7c0433 1634
e12720c0
PP
1635 if (bt_port_is_connected(port)) {
1636 BT_LOGW_STR("Port is already connected.");
7c7c0433
JG
1637 goto end;
1638 }
1639
d94d92ac 1640 if (cmd_run_ctx_connect_upstream_port(ctx, out_port)) {
cee05105 1641 BT_CLI_LOGE_APPEND_CAUSE("Cannot connect upstream port.");
d24d5663 1642 ret = BT_GRAPH_LISTENER_FUNC_STATUS_ERROR;
8cc56726 1643 goto end;
9009cc24
PP
1644 }
1645
1646end:
8cc56726 1647 return ret;
9009cc24
PP
1648}
1649
1650static
d24d5663 1651bt_graph_listener_func_status graph_source_output_port_added_listener(
ecd7492f 1652 const bt_component_source *component __attribute__((unused)),
b19ff26f 1653 const bt_port_output *port, void *data)
9009cc24 1654{
8cc56726 1655 return graph_output_port_added_listener(data, port);
9009cc24
PP
1656}
1657
1658static
d24d5663 1659bt_graph_listener_func_status graph_filter_output_port_added_listener(
ecd7492f 1660 const bt_component_filter *component __attribute__((unused)),
b19ff26f 1661 const bt_port_output *port, void *data)
9009cc24 1662{
8cc56726 1663 return graph_output_port_added_listener(data, port);
9009cc24
PP
1664}
1665
1666static
1667void cmd_run_ctx_destroy(struct cmd_run_ctx *ctx)
1668{
1669 if (!ctx) {
1670 return;
1671 }
1672
d94d92ac
PP
1673 if (ctx->src_components) {
1674 g_hash_table_destroy(ctx->src_components);
1675 ctx->src_components = NULL;
1676 }
1677
1678 if (ctx->flt_components) {
1679 g_hash_table_destroy(ctx->flt_components);
1680 ctx->flt_components = NULL;
1681 }
1682
1683 if (ctx->sink_components) {
1684 g_hash_table_destroy(ctx->sink_components);
1685 ctx->sink_components = NULL;
9009cc24
PP
1686 }
1687
75a2cb9b
JG
1688 if (ctx->intersections) {
1689 g_hash_table_destroy(ctx->intersections);
a5302548 1690 ctx->intersections = NULL;
75a2cb9b
JG
1691 }
1692
c5b9b441 1693 BT_GRAPH_PUT_REF_AND_RESET(ctx->graph);
9009cc24
PP
1694 ctx->cfg = NULL;
1695}
1696
5fea82b8
PP
1697static
1698int add_descriptor_to_component_descriptor_set(
1699 bt_component_descriptor_set *comp_descr_set,
1700 const char *plugin_name, const char *comp_cls_name,
1701 bt_component_class_type comp_cls_type,
1702 const bt_value *params)
1703{
1704 const bt_component_class *comp_cls;
1705 int status = 0;
1706
1707 comp_cls = find_component_class(plugin_name, comp_cls_name,
1708 comp_cls_type);
1709 if (!comp_cls) {
1710 BT_CLI_LOGE_APPEND_CAUSE(
1711 "Cannot find component class: plugin-name=\"%s\", "
6375b942
SM
1712 "comp-cls-name=\"%s\", comp-cls-type=%s",
1713 plugin_name, comp_cls_name,
1714 bt_common_component_class_type_string(comp_cls_type));
5fea82b8
PP
1715 status = -1;
1716 goto end;
1717 }
1718
1719 status = bt_component_descriptor_set_add_descriptor(
1720 comp_descr_set, comp_cls, params);
1721 if (status != BT_COMPONENT_DESCRIPTOR_SET_ADD_DESCRIPTOR_STATUS_OK) {
1722 BT_CLI_LOGE_APPEND_CAUSE(
1723 "Cannot append descriptor to component descriptor set: "
1724 "status=%s", bt_common_func_status_string(status));
1725 goto end;
1726 }
1727
1728end:
1729 bt_component_class_put_ref(comp_cls);
1730 return status;
1731}
1732
1733static
1734int append_descriptors_from_bt_config_component_array(
1735 bt_component_descriptor_set *comp_descr_set,
1736 GPtrArray *component_configs)
1737{
1738 int ret = 0;
1739 uint64_t i;
1740
1741 for (i = 0; i < component_configs->len; i++) {
1742 struct bt_config_component *cfg_comp =
1743 component_configs->pdata[i];
1744
1745 ret = add_descriptor_to_component_descriptor_set(
1746 comp_descr_set,
1747 cfg_comp->plugin_name->str,
1748 cfg_comp->comp_cls_name->str,
1749 cfg_comp->type, cfg_comp->params);
1750 if (ret) {
1751 goto end;
1752 }
1753 }
1754
1755end:
1756 return ret;
1757}
1758
1759static
1760bt_get_greatest_operative_mip_version_status get_greatest_operative_mip_version(
1761 struct bt_config *cfg, uint64_t *mip_version)
1762{
1763 bt_get_greatest_operative_mip_version_status status =
1764 BT_GET_GREATEST_OPERATIVE_MIP_VERSION_STATUS_OK;
1765 bt_component_descriptor_set *comp_descr_set = NULL;
1766 int ret;
1767
1768 BT_ASSERT(cfg);
1769 BT_ASSERT(mip_version);
1770 comp_descr_set = bt_component_descriptor_set_create();
1771 if (!comp_descr_set) {
1772 BT_CLI_LOGE_APPEND_CAUSE(
1773 "Failed to create a component descriptor set object.");
1774 status = BT_GET_GREATEST_OPERATIVE_MIP_VERSION_STATUS_MEMORY_ERROR;
1775 goto end;
1776 }
1777
1778 ret = append_descriptors_from_bt_config_component_array(
1779 comp_descr_set, cfg->cmd_data.run.sources);
1780 if (ret) {
1781 status = BT_GET_GREATEST_OPERATIVE_MIP_VERSION_STATUS_ERROR;
1782 goto end;
1783 }
1784
1785 ret = append_descriptors_from_bt_config_component_array(
1786 comp_descr_set, cfg->cmd_data.run.filters);
1787 if (ret) {
1788 status = BT_GET_GREATEST_OPERATIVE_MIP_VERSION_STATUS_ERROR;
1789 goto end;
1790 }
1791
1792 ret = append_descriptors_from_bt_config_component_array(
1793 comp_descr_set, cfg->cmd_data.run.sinks);
1794 if (ret) {
1795 status = BT_GET_GREATEST_OPERATIVE_MIP_VERSION_STATUS_ERROR;
1796 goto end;
1797 }
1798
1799 if (cfg->cmd_data.run.stream_intersection_mode) {
1800 /*
1801 * Stream intersection mode adds `flt.utils.trimmer`
1802 * components; we need to include this type of component
1803 * in the component descriptor set to get the real
1804 * greatest operative MIP version.
1805 */
1806 ret = add_descriptor_to_component_descriptor_set(
1807 comp_descr_set, "utils", "trimmer",
1808 BT_COMPONENT_CLASS_TYPE_FILTER, NULL);
1809 if (ret) {
1810 status = BT_GET_GREATEST_OPERATIVE_MIP_VERSION_STATUS_ERROR;
1811 goto end;
1812 }
1813 }
1814
1815 status = bt_get_greatest_operative_mip_version(comp_descr_set,
71436ae4 1816 (bt_logging_level) bt_cli_log_level, mip_version);
5fea82b8
PP
1817
1818end:
1819 bt_component_descriptor_set_put_ref(comp_descr_set);
1820 return status;
1821}
1822
9009cc24
PP
1823static
1824int cmd_run_ctx_init(struct cmd_run_ctx *ctx, struct bt_config *cfg)
1825{
1826 int ret = 0;
9275bef4 1827 bt_graph_add_listener_status add_listener_status;
5fea82b8
PP
1828 bt_get_greatest_operative_mip_version_status mip_version_status;
1829 uint64_t mip_version = UINT64_C(-1);
9009cc24
PP
1830
1831 ctx->cfg = cfg;
1832 ctx->connect_ports = false;
d94d92ac 1833 ctx->src_components = g_hash_table_new_full(g_direct_hash,
398454ed 1834 g_direct_equal, NULL, (GDestroyNotify) bt_object_put_ref);
d94d92ac
PP
1835 if (!ctx->src_components) {
1836 goto error;
1837 }
1838
1839 ctx->flt_components = g_hash_table_new_full(g_direct_hash,
398454ed 1840 g_direct_equal, NULL, (GDestroyNotify) bt_object_put_ref);
d94d92ac
PP
1841 if (!ctx->flt_components) {
1842 goto error;
1843 }
1844
1845 ctx->sink_components = g_hash_table_new_full(g_direct_hash,
398454ed 1846 g_direct_equal, NULL, (GDestroyNotify) bt_object_put_ref);
d94d92ac 1847 if (!ctx->sink_components) {
9009cc24
PP
1848 goto error;
1849 }
1850
75a2cb9b
JG
1851 if (cfg->cmd_data.run.stream_intersection_mode) {
1852 ctx->stream_intersection_mode = true;
1853 ctx->intersections = g_hash_table_new_full(port_id_hash,
1854 port_id_equal, port_id_destroy, trace_range_destroy);
1855 if (!ctx->intersections) {
1856 goto error;
1857 }
1858 }
1859
5fea82b8
PP
1860 /*
1861 * Get the greatest operative MIP version to use to configure
1862 * the graph to create.
1863 */
1864 mip_version_status = get_greatest_operative_mip_version(
1865 cfg, &mip_version);
1866 if (mip_version_status == BT_GET_GREATEST_OPERATIVE_MIP_VERSION_STATUS_NO_MATCH) {
1867 BT_CLI_LOGE_APPEND_CAUSE(
1868 "Failed to find an operative message interchange "
1869 "protocol version to use to create the `run` command's "
1870 "graph (components are not interoperable).");
1871 goto error;
1872 } else if (mip_version_status < 0) {
1873 BT_CLI_LOGE_APPEND_CAUSE(
1874 "Cannot find an operative message interchange "
1875 "protocol version to use to create the `run` command's "
1876 "graph: status=%s",
1877 bt_common_func_status_string(mip_version_status));
1878 goto error;
1879 }
1880
1881 BT_ASSERT(mip_version_status == BT_GET_GREATEST_OPERATIVE_MIP_VERSION_STATUS_OK);
1882 BT_LOGI("Found operative message interchange protocol version to "
1883 "configure the `run` command's graph: mip-version=%" PRIu64,
1884 mip_version);
1885 ctx->graph = bt_graph_create(mip_version);
9009cc24
PP
1886 if (!ctx->graph) {
1887 goto error;
1888 }
1889
9b4f9b42 1890 bt_graph_add_interrupter(ctx->graph, the_interrupter);
9275bef4 1891 add_listener_status = bt_graph_add_source_component_output_port_added_listener(
f3d6b4c2 1892 ctx->graph, graph_source_output_port_added_listener, ctx,
d94d92ac 1893 NULL);
9275bef4 1894 if (add_listener_status != BT_GRAPH_ADD_LISTENER_STATUS_OK) {
cee05105
PP
1895 BT_CLI_LOGE_APPEND_CAUSE(
1896 "Cannot add \"port added\" listener to graph.");
9009cc24
PP
1897 goto error;
1898 }
1899
9275bef4 1900 add_listener_status = bt_graph_add_filter_component_output_port_added_listener(
f3d6b4c2 1901 ctx->graph, graph_filter_output_port_added_listener, ctx,
d94d92ac 1902 NULL);
9275bef4 1903 if (add_listener_status != BT_GRAPH_ADD_LISTENER_STATUS_OK) {
cee05105
PP
1904 BT_CLI_LOGE_APPEND_CAUSE(
1905 "Cannot add \"port added\" listener to graph.");
9009cc24
PP
1906 goto error;
1907 }
1908
1909 goto end;
1910
1911error:
1912 cmd_run_ctx_destroy(ctx);
1913 ret = -1;
1914
1915end:
1916 return ret;
1917}
1918
30947af0
SM
1919/*
1920 * Compute the intersection of all streams in the array `streams`, write it
1921 * in `range`.
1922 */
1923
1924static
1925int compute_stream_intersection(const bt_value *streams,
1926 struct trace_range *range)
1927{
f80e9ec1 1928 uint64_t i, stream_count;
30947af0
SM
1929 int ret;
1930
1931 BT_ASSERT(bt_value_get_type(streams) == BT_VALUE_TYPE_ARRAY);
1932
1933 stream_count = bt_value_array_get_length(streams);
1934
1935 BT_ASSERT(stream_count > 0);
1936
1937 range->intersection_range_begin_ns = 0;
1938 range->intersection_range_end_ns = UINT64_MAX;
1939
1940 for (i = 0; i < stream_count; i++) {
1941 int64_t begin_ns, end_ns;
1942 uint64_t begin_ns_u, end_ns_u;
1943 const bt_value *stream_value;
1944 const bt_value *range_ns_value;
1945 const bt_value *begin_value;
1946 const bt_value *end_value;
1947
1948 stream_value = bt_value_array_borrow_element_by_index_const(streams, i);
1949 if (bt_value_get_type(stream_value) != BT_VALUE_TYPE_MAP) {
5f2a1585 1950 BT_CLI_LOGE_APPEND_CAUSE("Unexpected format of `babeltrace.trace-infos` query result: "
30947af0
SM
1951 "expected streams array element to be a map, got %s.",
1952 bt_common_value_type_string(bt_value_get_type(stream_value)));
1953 goto error;
1954 }
1955
1956 range_ns_value = bt_value_map_borrow_entry_value_const(
1957 stream_value, "range-ns");
1958 if (!range_ns_value) {
5f2a1585 1959 BT_CLI_LOGE_APPEND_CAUSE("Unexpected format of `babeltrace.trace-infos` query result: "
30947af0
SM
1960 "missing expected `range-ns` key in stream map.");
1961 goto error;
1962 }
1963
1964 if (bt_value_get_type(range_ns_value) != BT_VALUE_TYPE_MAP) {
5f2a1585 1965 BT_CLI_LOGE_APPEND_CAUSE("Unexpected format of `babeltrace.trace-infos` query result: "
30947af0
SM
1966 "expected `range-ns` entry value of stream map to be a map, got %s.",
1967 bt_common_value_type_string(bt_value_get_type(range_ns_value)));
1968 goto error;
1969 }
1970
1971 begin_value = bt_value_map_borrow_entry_value_const(range_ns_value, "begin");
1972 if (!begin_value) {
5f2a1585 1973 BT_CLI_LOGE_APPEND_CAUSE("Unexpected format of `babeltrace.trace-infos` query result: "
30947af0
SM
1974 "missing expected `begin` key in range-ns map.");
1975 goto error;
1976 }
1977
1978 if (bt_value_get_type(begin_value) != BT_VALUE_TYPE_SIGNED_INTEGER) {
5f2a1585 1979 BT_CLI_LOGE_APPEND_CAUSE("Unexpected format of `babeltrace.trace-infos` query result: "
30947af0
SM
1980 "expected `begin` entry value of range-ns map to be a signed integer, got %s.",
1981 bt_common_value_type_string(bt_value_get_type(range_ns_value)));
1982 goto error;
1983 }
1984
1985 end_value = bt_value_map_borrow_entry_value_const(range_ns_value, "end");
1986 if (!end_value) {
5f2a1585 1987 BT_CLI_LOGE_APPEND_CAUSE("Unexpected format of `babeltrace.trace-infos` query result: "
30947af0
SM
1988 "missing expected `end` key in range-ns map.");
1989 goto error;
1990 }
1991
1992 if (bt_value_get_type(end_value) != BT_VALUE_TYPE_SIGNED_INTEGER) {
5f2a1585 1993 BT_CLI_LOGE_APPEND_CAUSE("Unexpected format of `babeltrace.trace-infos` query result: "
30947af0
SM
1994 "expected `end` entry value of range-ns map to be a signed integer, got %s.",
1995 bt_common_value_type_string(bt_value_get_type(range_ns_value)));
1996 goto error;
1997 }
1998
1999 begin_ns = bt_value_integer_signed_get(begin_value);
2000 end_ns = bt_value_integer_signed_get(end_value);
2001
2002 if (begin_ns < 0 || end_ns < 0 || end_ns < begin_ns) {
2003 BT_CLI_LOGE_APPEND_CAUSE(
2004 "Invalid stream range values: "
2005 "range-ns:begin=%" PRId64 ", "
2006 "range-ns:end=%" PRId64,
2007 begin_ns, end_ns);
30947af0
SM
2008 goto error;
2009 }
2010
2011 begin_ns_u = begin_ns;
2012 end_ns_u = end_ns;
2013
2014 range->intersection_range_begin_ns =
2015 MAX(range->intersection_range_begin_ns, begin_ns_u);
2016 range->intersection_range_end_ns =
2017 MIN(range->intersection_range_end_ns, end_ns_u);
2018 }
2019
2020 ret = 0;
2021 goto end;
2022error:
2023 ret = -1;
2024
2025end:
2026 return ret;
2027}
2028
75a2cb9b
JG
2029static
2030int set_stream_intersections(struct cmd_run_ctx *ctx,
2031 struct bt_config_component *cfg_comp,
b19ff26f 2032 const bt_component_class_source *src_comp_cls)
75a2cb9b
JG
2033{
2034 int ret = 0;
2035 uint64_t trace_idx;
f80e9ec1 2036 uint64_t trace_count;
b19ff26f
PP
2037 const bt_value *query_result = NULL;
2038 const bt_value *trace_info = NULL;
b19ff26f
PP
2039 const bt_value *stream_infos = NULL;
2040 const bt_value *stream_info = NULL;
75a2cb9b 2041 struct port_id *port_id = NULL;
30947af0 2042 struct trace_range *stream_intersection = NULL;
c7eee084 2043 const char *fail_reason = NULL;
b19ff26f 2044 const bt_component_class *comp_cls =
0d72b8c3 2045 bt_component_class_source_as_component_class_const(src_comp_cls);
75a2cb9b 2046
5f2a1585 2047 ret = query(ctx->cfg, comp_cls, "babeltrace.trace-infos",
f280892e 2048 cfg_comp->params, &query_result,
c7eee084
PP
2049 &fail_reason);
2050 if (ret) {
d4fb887f 2051 BT_CLI_LOGE_APPEND_CAUSE("Failed to execute `babeltrace.trace-infos` query: %s: "
c7eee084 2052 "comp-class-name=\"%s\"", fail_reason,
75a2cb9b
JG
2053 bt_component_class_get_name(comp_cls));
2054 ret = -1;
8dfb232c 2055 goto end;
75a2cb9b
JG
2056 }
2057
f6ccaed9
PP
2058 BT_ASSERT(query_result);
2059
75a2cb9b 2060 if (!bt_value_is_array(query_result)) {
5f2a1585 2061 BT_CLI_LOGE_APPEND_CAUSE("`babeltrace.trace-infos` query: expecting result to be an array: "
8dfb232c
SM
2062 "component-class-name=%s, actual-type=%s",
2063 bt_component_class_get_name(comp_cls),
2064 bt_common_value_type_string(bt_value_get_type(query_result)));
75a2cb9b 2065 ret = -1;
8dfb232c 2066 goto end;
75a2cb9b
JG
2067 }
2068
393729a6 2069 trace_count = bt_value_array_get_length(query_result);
f80e9ec1 2070 if (trace_count == 0) {
5f2a1585 2071 BT_CLI_LOGE_APPEND_CAUSE("`babeltrace.trace-infos` query: result is empty: "
8dfb232c 2072 "component-class-name=%s", bt_component_class_get_name(comp_cls));
75a2cb9b 2073 ret = -1;
8dfb232c 2074 goto end;
75a2cb9b
JG
2075 }
2076
2077 for (trace_idx = 0; trace_idx < trace_count; trace_idx++) {
75a2cb9b
JG
2078 uint64_t stream_idx;
2079 int64_t stream_count;
30947af0 2080 struct trace_range trace_intersection;
75a2cb9b 2081
05e21286 2082 trace_info = bt_value_array_borrow_element_by_index_const(
07208d85 2083 query_result, trace_idx);
8dfb232c 2084 if (!bt_value_is_map(trace_info)) {
75a2cb9b 2085 ret = -1;
5f2a1585 2086 BT_CLI_LOGE_APPEND_CAUSE("`babeltrace.trace-infos` query: expecting element to be a map: "
8dfb232c
SM
2087 "component-class-name=%s, actual-type=%s",
2088 bt_component_class_get_name(comp_cls),
2089 bt_common_value_type_string(bt_value_get_type(trace_info)));
2090 goto end;
75a2cb9b
JG
2091 }
2092
8dfb232c 2093 stream_infos = bt_value_map_borrow_entry_value_const(
5f2a1585 2094 trace_info, "stream-infos");
8dfb232c 2095 if (!stream_infos) {
75a2cb9b 2096 ret = -1;
5f2a1585 2097 BT_CLI_LOGE_APPEND_CAUSE("`babeltrace.trace-infos` query: missing `streams` key in trace info map: "
8dfb232c
SM
2098 "component-class-name=%s",
2099 bt_component_class_get_name(comp_cls));
2100 goto end;
2101 }
2102
2103 if (!bt_value_is_array(stream_infos)) {
2104 ret = -1;
5f2a1585 2105 BT_CLI_LOGE_APPEND_CAUSE("`babeltrace.trace-infos` query: expecting `streams` entry of trace info map to be an array: "
8dfb232c
SM
2106 "component-class-name=%s, actual-type=%s",
2107 bt_component_class_get_name(comp_cls),
2108 bt_common_value_type_string(bt_value_get_type(stream_infos)));
2109 goto end;
75a2cb9b
JG
2110 }
2111
393729a6 2112 stream_count = bt_value_array_get_length(stream_infos);
f80e9ec1 2113 if (stream_count == 0) {
75a2cb9b 2114 ret = -1;
5f2a1585 2115 BT_CLI_LOGE_APPEND_CAUSE("`babeltrace.trace-infos` query: list of streams is empty: "
8dfb232c
SM
2116 "component-class-name=%s",
2117 bt_component_class_get_name(comp_cls));
2118 goto end;
75a2cb9b
JG
2119 }
2120
30947af0
SM
2121 ret = compute_stream_intersection(stream_infos, &trace_intersection);
2122 if (ret != 0) {
2123 BT_CLI_LOGE_APPEND_CAUSE("Failed to compute trace streams intersection.");
8dfb232c 2124 goto end;
30947af0
SM
2125 }
2126
75a2cb9b 2127 for (stream_idx = 0; stream_idx < stream_count; stream_idx++) {
a38d7650 2128 const bt_value *port_name;
75a2cb9b
JG
2129
2130 port_id = g_new0(struct port_id, 1);
2131 if (!port_id) {
2132 ret = -1;
cee05105
PP
2133 BT_CLI_LOGE_APPEND_CAUSE(
2134 "Cannot allocate memory for port_id structure.");
8dfb232c 2135 goto end;
75a2cb9b
JG
2136 }
2137 port_id->instance_name = strdup(cfg_comp->instance_name->str);
2138 if (!port_id->instance_name) {
2139 ret = -1;
cee05105
PP
2140 BT_CLI_LOGE_APPEND_CAUSE(
2141 "Cannot allocate memory for port_id component instance name.");
8dfb232c 2142 goto end;
75a2cb9b
JG
2143 }
2144
30947af0
SM
2145 stream_intersection = g_new0(struct trace_range, 1);
2146 if (!stream_intersection) {
75a2cb9b 2147 ret = -1;
cee05105
PP
2148 BT_CLI_LOGE_APPEND_CAUSE(
2149 "Cannot allocate memory for trace_range structure.");
8dfb232c 2150 goto end;
75a2cb9b 2151 }
30947af0
SM
2152
2153 *stream_intersection = trace_intersection;
75a2cb9b 2154
05e21286 2155 stream_info = bt_value_array_borrow_element_by_index_const(
07208d85 2156 stream_infos, stream_idx);
8dfb232c 2157 if (!bt_value_is_map(stream_info)) {
75a2cb9b 2158 ret = -1;
5f2a1585 2159 BT_CLI_LOGE_APPEND_CAUSE("`babeltrace.trace-infos` query: "
8dfb232c
SM
2160 "expecting element of stream list to be a map: "
2161 "component-class-name=%s, actual-type=%s",
2162 bt_component_class_get_name(comp_cls),
2163 bt_common_value_type_string(bt_value_get_type(stream_info)));
2164 goto end;
75a2cb9b
JG
2165 }
2166
a38d7650 2167 port_name = bt_value_map_borrow_entry_value_const(stream_info, "port-name");
8dfb232c 2168 if (!port_name) {
75a2cb9b 2169 ret = -1;
5f2a1585 2170 BT_CLI_LOGE_APPEND_CAUSE("`babeltrace.trace-infos` query: "
8dfb232c
SM
2171 "missing `port-name` key in stream info map: "
2172 "component-class-name=%s",
2173 bt_component_class_get_name(comp_cls));
2174 goto end;
2175 }
2176
2177 if (!bt_value_is_string(port_name)) {
2178 ret = -1;
5f2a1585 2179 BT_CLI_LOGE_APPEND_CAUSE("`babeltrace.trace-infos` query: "
8dfb232c
SM
2180 "expecting `port-name` entry of stream info map to be a string: "
2181 "component-class-name=%s, actual-type=%s",
2182 bt_component_class_get_name(comp_cls),
2183 bt_common_value_type_string(bt_value_get_type(port_name)));
2184 goto end;
75a2cb9b
JG
2185 }
2186
a38d7650 2187 port_id->port_name = g_strdup(bt_value_string_get(port_name));
75a2cb9b
JG
2188 if (!port_id->port_name) {
2189 ret = -1;
cee05105
PP
2190 BT_CLI_LOGE_APPEND_CAUSE(
2191 "Cannot allocate memory for port_id port_name.");
8dfb232c 2192 goto end;
75a2cb9b
JG
2193 }
2194
2195 BT_LOGD("Inserting stream intersection ");
2196
30947af0 2197 g_hash_table_insert(ctx->intersections, port_id, stream_intersection);
75a2cb9b
JG
2198
2199 port_id = NULL;
30947af0 2200 stream_intersection = NULL;
75a2cb9b 2201 }
75a2cb9b
JG
2202 }
2203
8dfb232c 2204 ret = 0;
cee05105 2205
75a2cb9b 2206end:
c5b9b441 2207 bt_value_put_ref(query_result);
75a2cb9b 2208 g_free(port_id);
30947af0 2209 g_free(stream_intersection);
75a2cb9b
JG
2210 return ret;
2211}
2212
9009cc24
PP
2213static
2214int cmd_run_ctx_create_components_from_config_components(
2215 struct cmd_run_ctx *ctx, GPtrArray *cfg_components)
2216{
2217 size_t i;
0d72b8c3
PP
2218 const void *comp_cls = NULL;
2219 const void *comp = NULL;
9009cc24
PP
2220 int ret = 0;
2221
2222 for (i = 0; i < cfg_components->len; i++) {
2223 struct bt_config_component *cfg_comp =
2224 g_ptr_array_index(cfg_components, i);
2225 GQuark quark;
2226
d94d92ac
PP
2227 switch (cfg_comp->type) {
2228 case BT_COMPONENT_CLASS_TYPE_SOURCE:
2229 comp_cls = find_source_component_class(
2230 cfg_comp->plugin_name->str,
2231 cfg_comp->comp_cls_name->str);
2232 break;
2233 case BT_COMPONENT_CLASS_TYPE_FILTER:
2234 comp_cls = find_filter_component_class(
2235 cfg_comp->plugin_name->str,
2236 cfg_comp->comp_cls_name->str);
2237 break;
2238 case BT_COMPONENT_CLASS_TYPE_SINK:
2239 comp_cls = find_sink_component_class(
2240 cfg_comp->plugin_name->str,
2241 cfg_comp->comp_cls_name->str);
2242 break;
2243 default:
498e7994 2244 bt_common_abort();
d94d92ac
PP
2245 }
2246
9009cc24 2247 if (!comp_cls) {
cee05105
PP
2248 BT_CLI_LOGE_APPEND_CAUSE(
2249 "Cannot find component class: plugin-name=\"%s\", "
6375b942 2250 "comp-cls-name=\"%s\", comp-cls-type=%s",
7213a328
PP
2251 cfg_comp->plugin_name->str,
2252 cfg_comp->comp_cls_name->str,
6375b942 2253 bt_common_component_class_type_string(cfg_comp->type));
9009cc24
PP
2254 goto error;
2255 }
2256
ef267d12 2257 BT_ASSERT(cfg_comp->log_level >= BT_LOG_TRACE);
29da2ffc 2258
d94d92ac
PP
2259 switch (cfg_comp->type) {
2260 case BT_COMPONENT_CLASS_TYPE_SOURCE:
0d72b8c3 2261 ret = bt_graph_add_source_component(ctx->graph,
d94d92ac 2262 comp_cls, cfg_comp->instance_name->str,
29da2ffc 2263 cfg_comp->params, cfg_comp->log_level,
d94d92ac 2264 (void *) &comp);
a91462c9 2265 bt_component_source_get_ref(comp);
d94d92ac
PP
2266 break;
2267 case BT_COMPONENT_CLASS_TYPE_FILTER:
0d72b8c3 2268 ret = bt_graph_add_filter_component(ctx->graph,
d94d92ac 2269 comp_cls, cfg_comp->instance_name->str,
29da2ffc 2270 cfg_comp->params, cfg_comp->log_level,
d94d92ac 2271 (void *) &comp);
a91462c9 2272 bt_component_filter_get_ref(comp);
d94d92ac
PP
2273 break;
2274 case BT_COMPONENT_CLASS_TYPE_SINK:
0d72b8c3 2275 ret = bt_graph_add_sink_component(ctx->graph,
d94d92ac 2276 comp_cls, cfg_comp->instance_name->str,
29da2ffc 2277 cfg_comp->params, cfg_comp->log_level,
d94d92ac 2278 (void *) &comp);
a91462c9 2279 bt_component_sink_get_ref(comp);
d94d92ac
PP
2280 break;
2281 default:
498e7994 2282 bt_common_abort();
d94d92ac
PP
2283 }
2284
36712f1d 2285 if (ret) {
cee05105
PP
2286 BT_CLI_LOGE_APPEND_CAUSE(
2287 "Cannot create component: plugin-name=\"%s\", "
6375b942 2288 "comp-cls-name=\"%s\", comp-cls-type=%s, "
7213a328
PP
2289 "comp-name=\"%s\"",
2290 cfg_comp->plugin_name->str,
2291 cfg_comp->comp_cls_name->str,
6375b942
SM
2292 bt_common_component_class_type_string(cfg_comp->type),
2293 cfg_comp->instance_name->str);
9009cc24
PP
2294 goto error;
2295 }
2296
75a2cb9b
JG
2297 if (ctx->stream_intersection_mode &&
2298 cfg_comp->type == BT_COMPONENT_CLASS_TYPE_SOURCE) {
2299 ret = set_stream_intersections(ctx, cfg_comp, comp_cls);
2300 if (ret) {
8dfb232c
SM
2301 BT_CLI_LOGE_APPEND_CAUSE(
2302 "Cannot determine stream intersection of trace.");
75a2cb9b
JG
2303 goto error;
2304 }
2305 }
2306
7213a328
PP
2307 BT_LOGI("Created and inserted component: comp-addr=%p, comp-name=\"%s\"",
2308 comp, cfg_comp->instance_name->str);
9009cc24 2309 quark = g_quark_from_string(cfg_comp->instance_name->str);
f6ccaed9 2310 BT_ASSERT(quark > 0);
d94d92ac
PP
2311
2312 switch (cfg_comp->type) {
2313 case BT_COMPONENT_CLASS_TYPE_SOURCE:
2314 g_hash_table_insert(ctx->src_components,
0d72b8c3 2315 GUINT_TO_POINTER(quark), (void *) comp);
d94d92ac
PP
2316 break;
2317 case BT_COMPONENT_CLASS_TYPE_FILTER:
2318 g_hash_table_insert(ctx->flt_components,
0d72b8c3 2319 GUINT_TO_POINTER(quark), (void *) comp);
d94d92ac
PP
2320 break;
2321 case BT_COMPONENT_CLASS_TYPE_SINK:
2322 g_hash_table_insert(ctx->sink_components,
0d72b8c3 2323 GUINT_TO_POINTER(quark), (void *) comp);
d94d92ac
PP
2324 break;
2325 default:
498e7994 2326 bt_common_abort();
d94d92ac
PP
2327 }
2328
9009cc24 2329 comp = NULL;
65300d60 2330 BT_OBJECT_PUT_REF_AND_RESET(comp_cls);
9009cc24
PP
2331 }
2332
2333 goto end;
2334
2335error:
2336 ret = -1;
2337
2338end:
65300d60
PP
2339 bt_object_put_ref(comp);
2340 bt_object_put_ref(comp_cls);
9009cc24
PP
2341 return ret;
2342}
56a1cced 2343
9009cc24
PP
2344static
2345int cmd_run_ctx_create_components(struct cmd_run_ctx *ctx)
2346{
2347 int ret = 0;
2348
2349 /*
2350 * Make sure that, during this phase, our graph's "port added"
2351 * listener does not connect ports while we are creating the
2352 * components because we have a special, initial phase for
2353 * this.
2354 */
2355 ctx->connect_ports = false;
2356
2357 ret = cmd_run_ctx_create_components_from_config_components(
2358 ctx, ctx->cfg->cmd_data.run.sources);
2359 if (ret) {
7c7c0433 2360 ret = -1;
2e339de1
JG
2361 goto end;
2362 }
2363
9009cc24
PP
2364 ret = cmd_run_ctx_create_components_from_config_components(
2365 ctx, ctx->cfg->cmd_data.run.filters);
6c2f3ee5 2366 if (ret) {
290725f7 2367 ret = -1;
fec2a9f2
JG
2368 goto end;
2369 }
78586d8a 2370
9009cc24
PP
2371 ret = cmd_run_ctx_create_components_from_config_components(
2372 ctx, ctx->cfg->cmd_data.run.sinks);
2373 if (ret) {
2374 ret = -1;
2375 goto end;
2376 }
2377
2378end:
2379 return ret;
2380}
2381
0d72b8c3 2382typedef uint64_t (*output_port_count_func_t)(const void *);
b19ff26f 2383typedef const bt_port_output *(*borrow_output_port_by_index_func_t)(
0d72b8c3 2384 const void *, uint64_t);
d94d92ac 2385
9009cc24
PP
2386static
2387int cmd_run_ctx_connect_comp_ports(struct cmd_run_ctx *ctx,
d94d92ac
PP
2388 void *comp, output_port_count_func_t port_count_fn,
2389 borrow_output_port_by_index_func_t port_by_index_fn)
9009cc24
PP
2390{
2391 int ret = 0;
d94d92ac 2392 uint64_t count;
9009cc24
PP
2393 uint64_t i;
2394
2395 count = port_count_fn(comp);
9009cc24
PP
2396
2397 for (i = 0; i < count; i++) {
b19ff26f 2398 const bt_port_output *upstream_port = port_by_index_fn(comp, i);
9009cc24 2399
f6ccaed9 2400 BT_ASSERT(upstream_port);
9009cc24 2401 ret = cmd_run_ctx_connect_upstream_port(ctx, upstream_port);
9009cc24
PP
2402 if (ret) {
2403 goto end;
2404 }
2405 }
2406
2407end:
2408 return ret;
2409}
2410
2411static
2412int cmd_run_ctx_connect_ports(struct cmd_run_ctx *ctx)
2413{
2414 int ret = 0;
2415 GHashTableIter iter;
2416 gpointer g_name_quark, g_comp;
2417
2418 ctx->connect_ports = true;
d94d92ac 2419 g_hash_table_iter_init(&iter, ctx->src_components);
9009cc24
PP
2420
2421 while (g_hash_table_iter_next(&iter, &g_name_quark, &g_comp)) {
d94d92ac
PP
2422 ret = cmd_run_ctx_connect_comp_ports(ctx, g_comp,
2423 (output_port_count_func_t)
2424 bt_component_source_get_output_port_count,
2425 (borrow_output_port_by_index_func_t)
0d72b8c3 2426 bt_component_source_borrow_output_port_by_index_const);
d94d92ac
PP
2427 if (ret) {
2428 goto end;
9009cc24 2429 }
d94d92ac
PP
2430 }
2431
2432 g_hash_table_iter_init(&iter, ctx->flt_components);
9009cc24 2433
d94d92ac
PP
2434 while (g_hash_table_iter_next(&iter, &g_name_quark, &g_comp)) {
2435 ret = cmd_run_ctx_connect_comp_ports(ctx, g_comp,
2436 (output_port_count_func_t)
2437 bt_component_filter_get_output_port_count,
2438 (borrow_output_port_by_index_func_t)
0d72b8c3 2439 bt_component_filter_borrow_output_port_by_index_const);
9009cc24
PP
2440 if (ret) {
2441 goto end;
2442 }
2443 }
2444
2445end:
2446 return ret;
2447}
2448
2449static
b5cd7d65 2450enum bt_cmd_status cmd_run(struct bt_config *cfg)
9009cc24 2451{
b5cd7d65 2452 enum bt_cmd_status cmd_status;
9009cc24
PP
2453 struct cmd_run_ctx ctx = { 0 };
2454
9009cc24
PP
2455 /* Initialize the command's context and the graph object */
2456 if (cmd_run_ctx_init(&ctx, cfg)) {
cee05105
PP
2457 BT_CLI_LOGE_APPEND_CAUSE(
2458 "Cannot initialize the command's context.");
9009cc24
PP
2459 goto error;
2460 }
2461
aede8fc9 2462 if (bt_interrupter_is_set(the_interrupter)) {
63d355d2 2463 BT_CLI_LOGW_APPEND_CAUSE(
9b4f9b42 2464 "Interrupted by user before creating components.");
cc308374
PP
2465 goto error;
2466 }
2467
2468 BT_LOGI_STR("Creating components.");
2469
9009cc24
PP
2470 /* Create the requested component instances */
2471 if (cmd_run_ctx_create_components(&ctx)) {
cee05105 2472 BT_CLI_LOGE_APPEND_CAUSE("Cannot create components.");
9009cc24
PP
2473 goto error;
2474 }
2475
aede8fc9 2476 if (bt_interrupter_is_set(the_interrupter)) {
63d355d2 2477 BT_CLI_LOGW_APPEND_CAUSE(
9b4f9b42 2478 "Interrupted by user before connecting components.");
cc308374
PP
2479 goto error;
2480 }
2481
2482 BT_LOGI_STR("Connecting components.");
2483
9009cc24
PP
2484 /* Connect the initially visible component ports */
2485 if (cmd_run_ctx_connect_ports(&ctx)) {
cee05105
PP
2486 BT_CLI_LOGE_APPEND_CAUSE(
2487 "Cannot connect initial component ports.");
9009cc24
PP
2488 goto error;
2489 }
2490
7213a328
PP
2491 BT_LOGI_STR("Running the graph.");
2492
9009cc24 2493 /* Run the graph */
fec2a9f2 2494 while (true) {
d24d5663 2495 bt_graph_run_status run_status = bt_graph_run(ctx.graph);
61ddbc8a 2496
5669a3e7
PP
2497 /*
2498 * Reset console in case something messed with console
2499 * codes during the graph's execution.
2500 */
2501 printf("%s", bt_common_color_reset());
2502 fflush(stdout);
2503 fprintf(stderr, "%s", bt_common_color_reset());
ef267d12 2504 BT_LOGT("bt_graph_run() returned: status=%s",
d24d5663 2505 bt_common_func_status_string(run_status));
fd948396 2506
d24d5663
PP
2507 switch (run_status) {
2508 case BT_GRAPH_RUN_STATUS_OK:
b5cd7d65 2509 cmd_status = BT_CMD_STATUS_OK;
9669d693 2510 goto end;
d24d5663 2511 case BT_GRAPH_RUN_STATUS_AGAIN:
9b4f9b42 2512 if (bt_interrupter_is_set(the_interrupter)) {
b5cd7d65
FD
2513 /*
2514 * The graph was interrupted by a SIGINT.
2515 */
2516 cmd_status = BT_CMD_STATUS_INTERRUPTED;
2517 goto end;
5401f780
PP
2518 }
2519
9009cc24 2520 if (cfg->cmd_data.run.retry_duration_us > 0) {
d24d5663 2521 BT_LOGT("Got BT_GRAPH_RUN_STATUS_AGAIN: sleeping: "
7213a328
PP
2522 "time-us=%" PRIu64,
2523 cfg->cmd_data.run.retry_duration_us);
2524
9009cc24 2525 if (usleep(cfg->cmd_data.run.retry_duration_us)) {
9b4f9b42 2526 if (bt_interrupter_is_set(the_interrupter)) {
b5cd7d65
FD
2527 cmd_status = BT_CMD_STATUS_INTERRUPTED;
2528 goto end;
cfa4637b 2529 }
9009cc24
PP
2530 }
2531 }
78586d8a 2532 break;
fec2a9f2 2533 default:
9b4f9b42 2534 if (bt_interrupter_is_set(the_interrupter)) {
b5cd7d65
FD
2535 cmd_status = BT_CMD_STATUS_INTERRUPTED;
2536 goto end;
9b4f9b42
PP
2537 }
2538
cee05105
PP
2539 BT_CLI_LOGE_APPEND_CAUSE(
2540 "Graph failed to complete successfully");
9009cc24 2541 goto error;
78586d8a 2542 }
fec2a9f2 2543 }
9009cc24 2544error:
b5cd7d65 2545 cmd_status = BT_CMD_STATUS_ERROR;
9009cc24 2546
11e1d048 2547end:
9009cc24 2548 cmd_run_ctx_destroy(&ctx);
b5cd7d65 2549 return cmd_status;
290725f7
PP
2550}
2551
9009cc24
PP
2552static
2553void warn_command_name_and_directory_clash(struct bt_config *cfg)
290725f7 2554{
9009cc24
PP
2555 const char *env_clash;
2556
290725f7
PP
2557 if (!cfg->command_name) {
2558 return;
2559 }
2560
9009cc24
PP
2561 env_clash = getenv(ENV_BABELTRACE_WARN_COMMAND_NAME_DIRECTORY_CLASH);
2562 if (env_clash && strcmp(env_clash, "0") == 0) {
2563 return;
2564 }
2565
290725f7
PP
2566 if (g_file_test(cfg->command_name,
2567 G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
71436ae4 2568 bt_log_write_printf(__FILE__, __func__, __LINE__,
770538dd 2569 BT_LOG_WARNING, BT_LOG_TAG,
cee05105
PP
2570 "The `%s` command was executed. "
2571 "If you meant to convert a trace located in "
2572 "the local `%s` directory, please use:\n\n"
2573 " babeltrace2 convert %s [OPTIONS]",
2574 cfg->command_name, cfg->command_name,
2575 cfg->command_name);
290725f7
PP
2576 }
2577}
2578
7213a328
PP
2579static
2580void init_log_level(void)
2581{
c6d4d1ae 2582 bt_cli_log_level = bt_log_get_level_from_env(ENV_BABELTRACE_CLI_LOG_LEVEL);
7213a328
PP
2583}
2584
f393c19b
PP
2585static
2586void print_error_causes(void)
2587{
2588 const bt_error *error = bt_current_thread_take_error();
f393c19b 2589 unsigned int columns;
96c1b5fe 2590 gchar *error_str = NULL;
f393c19b
PP
2591
2592 if (!error || bt_error_get_cause_count(error) == 0) {
2593 fprintf(stderr, "%s%sUnknown command-line error.%s\n",
04609487 2594 bt_common_color_bold(), bt_common_color_fg_bright_red(),
f393c19b
PP
2595 bt_common_color_reset());
2596 goto end;
2597 }
2598
2599 /* Try to get terminal width to fold the error cause messages */
2600 if (bt_common_get_term_size(&columns, NULL) < 0) {
2601 /* Width not found: default to 80 */
2602 columns = 80;
2603 }
2604
2605 /*
2606 * This helps visually separate the error causes from the last
2607 * logging statement.
2608 */
96c1b5fe 2609 fputc('\n', stderr);
f393c19b 2610
71436ae4
SM
2611 error_str = format_bt_error(error, columns,
2612 (bt_logging_level) bt_cli_log_level, BT_COMMON_COLOR_WHEN_AUTO);
96c1b5fe 2613 BT_ASSERT(error_str);
f393c19b 2614
96c1b5fe 2615 fprintf(stderr, "%s\n", error_str);
f393c19b
PP
2616
2617end:
f393c19b
PP
2618 if (error) {
2619 bt_error_release(error);
2620 }
ec532b44 2621
96c1b5fe 2622 g_free(error_str);
f393c19b
PP
2623}
2624
290725f7
PP
2625int main(int argc, const char **argv)
2626{
353c2524
SM
2627 int retcode;
2628 enum bt_config_cli_args_status cli_args_status;
b5cd7d65 2629 enum bt_cmd_status cmd_status;
3dae1685 2630 struct bt_config *cfg = NULL;
290725f7 2631
7213a328 2632 init_log_level();
65d3198f 2633 set_signal_handler();
743138a3 2634 init_loaded_plugins();
3dae1685
SM
2635
2636 BT_ASSERT(!the_interrupter);
2637 the_interrupter = bt_interrupter_create();
2638 if (!the_interrupter) {
2639 BT_CLI_LOGE_APPEND_CAUSE("Failed to create an interrupter object.");
353c2524 2640 retcode = EXIT_FAILURE;
3dae1685
SM
2641 goto end;
2642 }
2643
353c2524 2644 cli_args_status = bt_config_cli_args_create_with_default(argc, argv, &cfg,
3dae1685 2645 the_interrupter);
353c2524 2646 if (cli_args_status == BT_CONFIG_CLI_ARGS_STATUS_INFO_ONLY) {
290725f7 2647 /* Quit without errors; typically usage/version */
353c2524 2648 retcode = EXIT_SUCCESS;
7213a328 2649 BT_LOGI_STR("Quitting without errors.");
290725f7
PP
2650 goto end;
2651 }
2652
353c2524
SM
2653 if (cli_args_status == BT_CONFIG_CLI_ARGS_STATUS_ERROR) {
2654 retcode = EXIT_FAILURE;
cee05105
PP
2655 BT_CLI_LOGE_APPEND_CAUSE(
2656 "Command-line error: retcode=%d", retcode);
290725f7
PP
2657 goto end;
2658 }
2659
353c2524
SM
2660 BT_ASSERT(cli_args_status == BT_CONFIG_CLI_ARGS_STATUS_OK);
2661 BT_ASSERT(cfg);
290725f7 2662
290725f7
PP
2663 print_cfg(cfg);
2664
db0f160a 2665 if (cfg->command_needs_plugins) {
353c2524
SM
2666 int ret = require_loaded_plugins(cfg->plugin_paths);
2667
db0f160a 2668 if (ret) {
cee05105
PP
2669 BT_CLI_LOGE_APPEND_CAUSE(
2670 "Failed to load plugins: ret=%d", ret);
353c2524 2671 retcode = EXIT_FAILURE;
db0f160a
PP
2672 goto end;
2673 }
2674 }
2675
7213a328
PP
2676 BT_LOGI("Executing command: cmd=%d, command-name=\"%s\"",
2677 cfg->command, cfg->command_name);
2678
290725f7 2679 switch (cfg->command) {
db0f160a 2680 case BT_CONFIG_COMMAND_RUN:
b5cd7d65 2681 cmd_status = cmd_run(cfg);
290725f7
PP
2682 break;
2683 case BT_CONFIG_COMMAND_LIST_PLUGINS:
b5cd7d65 2684 cmd_status = cmd_list_plugins(cfg);
290725f7 2685 break;
22e22462 2686 case BT_CONFIG_COMMAND_HELP:
b5cd7d65 2687 cmd_status = cmd_help(cfg);
22e22462 2688 break;
a67681c1 2689 case BT_CONFIG_COMMAND_QUERY:
b5cd7d65 2690 cmd_status = cmd_query(cfg);
63ce0e1d 2691 break;
db0f160a 2692 case BT_CONFIG_COMMAND_PRINT_CTF_METADATA:
b5cd7d65 2693 cmd_status = cmd_print_ctf_metadata(cfg);
db0f160a
PP
2694 break;
2695 case BT_CONFIG_COMMAND_PRINT_LTTNG_LIVE_SESSIONS:
b5cd7d65 2696 cmd_status = cmd_print_lttng_live_sessions(cfg);
db0f160a 2697 break;
290725f7 2698 default:
0fbb9a9f 2699 BT_LOGF("Invalid/unknown command: cmd=%d", cfg->command);
498e7994 2700 bt_common_abort();
290725f7
PP
2701 }
2702
b5cd7d65
FD
2703 BT_LOGI("Command completed: cmd=%d, command-name=\"%s\", command-status=\"%s\"",
2704 cfg->command, cfg->command_name, bt_cmd_status_string(cmd_status));
290725f7 2705 warn_command_name_and_directory_clash(cfg);
b5cd7d65
FD
2706
2707 switch (cmd_status) {
2708 case BT_CMD_STATUS_OK:
353c2524 2709 retcode = EXIT_SUCCESS;
b5cd7d65
FD
2710 break;
2711 case BT_CMD_STATUS_ERROR:
353c2524 2712 retcode = EXIT_FAILURE;
b5cd7d65
FD
2713 break;
2714 case BT_CMD_STATUS_INTERRUPTED:
353c2524 2715 retcode = EXIT_INTERRUPTED;
b5cd7d65
FD
2716 break;
2717 default:
2718 BT_LOGF("Invalid command status: cmd-status=%d", cmd_status);
2719 bt_common_abort();
2720 }
290725f7
PP
2721
2722end:
353c2524 2723 if (retcode == EXIT_FAILURE) {
927c0693
SM
2724 print_error_causes();
2725 }
2726
65300d60 2727 BT_OBJECT_PUT_REF_AND_RESET(cfg);
743138a3 2728 fini_loaded_plugins();
9b4f9b42 2729 bt_interrupter_put_ref(the_interrupter);
0232a535
PP
2730
2731 /*
2732 * Clear current thread's error in case there is one to avoid a
2733 * memory leak.
2734 */
2735 bt_current_thread_clear_error();
290725f7 2736 return retcode;
4c8bfb7e 2737}
This page took 0.296459 seconds and 4 git commands to generate.