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