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