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