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