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