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