cli: apply parameters (`--params` option) to leftovers
[babeltrace.git] / src / cli / babeltrace2-cfg-cli-args.c
1 /*
2 * Babeltrace trace converter - parameter parsing
3 *
4 * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25 #define BT_LOG_TAG "CLI/CFG-CLI-ARGS"
26 #include "logging.h"
27
28 #include <errno.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include "common/assert.h"
32 #include <stdio.h>
33 #include <stdbool.h>
34 #include <inttypes.h>
35 #include <babeltrace2/babeltrace.h>
36 #include "common/common.h"
37 #include <glib.h>
38 #include <sys/types.h>
39 #include "argpar/argpar.h"
40 #include "babeltrace2-cfg.h"
41 #include "babeltrace2-cfg-cli-args.h"
42 #include "babeltrace2-cfg-cli-args-connect.h"
43 #include "babeltrace2-cfg-cli-params-arg.h"
44 #include "babeltrace2-plugins.h"
45 #include "babeltrace2-cfg-src-auto-disc.h"
46 #include "common/version.h"
47
48 static const int cli_default_log_level = BT_LOG_WARNING;
49
50 /* INI-style parsing FSM states */
51 enum ini_parsing_fsm_state {
52 /* Expect a map key (identifier) */
53 INI_EXPECT_MAP_KEY,
54
55 /* Expect an equal character ('=') */
56 INI_EXPECT_EQUAL,
57
58 /* Expect a value */
59 INI_EXPECT_VALUE,
60
61 /* Expect a comma character (',') */
62 INI_EXPECT_COMMA,
63 };
64
65 /* INI-style parsing state variables */
66 struct ini_parsing_state {
67 /* Lexical scanner (owned by this) */
68 GScanner *scanner;
69
70 /* Output map value object being filled (owned by this) */
71 bt_value *params;
72
73 /* Next expected FSM state */
74 enum ini_parsing_fsm_state expecting;
75
76 /* Last decoded map key (owned by this) */
77 char *last_map_key;
78
79 /* Complete INI-style string to parse (not owned by this) */
80 const char *arg;
81
82 /* Error buffer (not owned by this) */
83 GString *ini_error;
84 };
85
86 /* Offset option with "is set" boolean */
87 struct offset_opt {
88 int64_t value;
89 bool is_set;
90 };
91
92 /* Legacy "ctf"/"lttng-live" format options */
93 struct ctf_legacy_opts {
94 struct offset_opt offset_s;
95 struct offset_opt offset_ns;
96 bool stream_intersection;
97 };
98
99 /* Legacy "text" format options */
100 struct text_legacy_opts {
101 /*
102 * output, dbg_info_dir, dbg_info_target_prefix, names,
103 * and fields are owned by this.
104 */
105 GString *output;
106 GString *dbg_info_dir;
107 GString *dbg_info_target_prefix;
108 const bt_value *names;
109 const bt_value *fields;
110
111 /* Flags */
112 bool no_delta;
113 bool clock_cycles;
114 bool clock_seconds;
115 bool clock_date;
116 bool clock_gmt;
117 bool dbg_info_full_path;
118 bool verbose;
119 };
120
121 /* Legacy input format format */
122 enum legacy_input_format {
123 LEGACY_INPUT_FORMAT_NONE = 0,
124 LEGACY_INPUT_FORMAT_CTF,
125 LEGACY_INPUT_FORMAT_LTTNG_LIVE,
126 };
127
128 /* Legacy output format format */
129 enum legacy_output_format {
130 LEGACY_OUTPUT_FORMAT_NONE = 0,
131 LEGACY_OUTPUT_FORMAT_TEXT,
132 LEGACY_OUTPUT_FORMAT_DUMMY,
133 };
134
135 #define BT_CLI_LOGE_APPEND_CAUSE_OOM() BT_CLI_LOGE_APPEND_CAUSE("Out of memory.")
136
137 /*
138 * Returns the plugin name, component class name, component class type,
139 * and component name from a command-line --component option's argument.
140 * arg must have the following format:
141 *
142 * [NAME:]TYPE.PLUGIN.CLS
143 *
144 * where NAME is the optional component name, TYPE is either `source`,
145 * `filter`, or `sink`, PLUGIN is the plugin name, and CLS is the
146 * component class name.
147 *
148 * On success, both *plugin and *component are not NULL. *plugin
149 * and *comp_cls are owned by the caller. On success, *name can be NULL
150 * if no component class name was found, and *comp_cls_type is set.
151 */
152 static
153 void plugin_comp_cls_names(const char *arg, char **name, char **plugin,
154 char **comp_cls, bt_component_class_type *comp_cls_type)
155 {
156 const char *at = arg;
157 GString *gs_name = NULL;
158 GString *gs_comp_cls_type = NULL;
159 GString *gs_plugin = NULL;
160 GString *gs_comp_cls = NULL;
161 size_t end_pos;
162
163 BT_ASSERT(arg);
164 BT_ASSERT(plugin);
165 BT_ASSERT(comp_cls);
166 BT_ASSERT(comp_cls_type);
167
168 if (!bt_common_string_is_printable(arg)) {
169 BT_CLI_LOGE_APPEND_CAUSE("Argument contains a non-printable character.");
170 goto error;
171 }
172
173 /* Parse the component name */
174 gs_name = bt_common_string_until(at, ".:\\", ":", &end_pos);
175 if (!gs_name) {
176 goto error;
177 }
178
179 if (arg[end_pos] == ':') {
180 at += end_pos + 1;
181 } else {
182 /* No name */
183 g_string_assign(gs_name, "");
184 }
185
186 /* Parse the component class type */
187 gs_comp_cls_type = bt_common_string_until(at, ".:\\", ".", &end_pos);
188 if (!gs_comp_cls_type || at[end_pos] == '\0') {
189 BT_CLI_LOGE_APPEND_CAUSE("Missing component class type (`source`, `filter`, or `sink`).");
190 goto error;
191 }
192
193 if (strcmp(gs_comp_cls_type->str, "source") == 0 ||
194 strcmp(gs_comp_cls_type->str, "src") == 0) {
195 *comp_cls_type = BT_COMPONENT_CLASS_TYPE_SOURCE;
196 } else if (strcmp(gs_comp_cls_type->str, "filter") == 0 ||
197 strcmp(gs_comp_cls_type->str, "flt") == 0) {
198 *comp_cls_type = BT_COMPONENT_CLASS_TYPE_FILTER;
199 } else if (strcmp(gs_comp_cls_type->str, "sink") == 0) {
200 *comp_cls_type = BT_COMPONENT_CLASS_TYPE_SINK;
201 } else {
202 BT_CLI_LOGE_APPEND_CAUSE("Unknown component class type: `%s`.",
203 gs_comp_cls_type->str);
204 goto error;
205 }
206
207 at += end_pos + 1;
208
209 /* Parse the plugin name */
210 gs_plugin = bt_common_string_until(at, ".:\\", ".", &end_pos);
211 if (!gs_plugin || gs_plugin->len == 0 || at[end_pos] == '\0') {
212 BT_CLI_LOGE_APPEND_CAUSE("Missing plugin or component class name.");
213 goto error;
214 }
215
216 at += end_pos + 1;
217
218 /* Parse the component class name */
219 gs_comp_cls = bt_common_string_until(at, ".:\\", ".", &end_pos);
220 if (!gs_comp_cls || gs_comp_cls->len == 0) {
221 BT_CLI_LOGE_APPEND_CAUSE("Missing component class name.");
222 goto error;
223 }
224
225 if (at[end_pos] != '\0') {
226 /* Found a non-escaped `.` */
227 goto error;
228 }
229
230 if (name) {
231 if (gs_name->len == 0) {
232 *name = NULL;
233 g_string_free(gs_name, TRUE);
234 } else {
235 *name = gs_name->str;
236 g_string_free(gs_name, FALSE);
237 }
238 } else {
239 g_string_free(gs_name, TRUE);
240 }
241
242 *plugin = gs_plugin->str;
243 *comp_cls = gs_comp_cls->str;
244 g_string_free(gs_plugin, FALSE);
245 g_string_free(gs_comp_cls, FALSE);
246 gs_name = NULL;
247 gs_plugin = NULL;
248 gs_comp_cls = NULL;
249 goto end;
250
251 error:
252 if (name) {
253 *name = NULL;
254 }
255
256 *plugin = NULL;
257 *comp_cls = NULL;
258
259 end:
260 if (gs_name) {
261 g_string_free(gs_name, TRUE);
262 }
263
264 if (gs_plugin) {
265 g_string_free(gs_plugin, TRUE);
266 }
267
268 if (gs_comp_cls) {
269 g_string_free(gs_comp_cls, TRUE);
270 }
271
272 if (gs_comp_cls_type) {
273 g_string_free(gs_comp_cls_type, TRUE);
274 }
275
276 return;
277 }
278
279 /*
280 * Prints the Babeltrace version.
281 */
282 static
283 void print_version(void)
284 {
285 if (GIT_VERSION[0] == '\0') {
286 puts("Babeltrace " VERSION);
287 } else {
288 puts("Babeltrace " VERSION " - " GIT_VERSION);
289 }
290 }
291
292 /*
293 * Destroys a component configuration.
294 */
295 static
296 void bt_config_component_destroy(bt_object *obj)
297 {
298 struct bt_config_component *bt_config_component =
299 container_of(obj, struct bt_config_component, base);
300
301 if (!obj) {
302 goto end;
303 }
304
305 if (bt_config_component->plugin_name) {
306 g_string_free(bt_config_component->plugin_name, TRUE);
307 }
308
309 if (bt_config_component->comp_cls_name) {
310 g_string_free(bt_config_component->comp_cls_name, TRUE);
311 }
312
313 if (bt_config_component->instance_name) {
314 g_string_free(bt_config_component->instance_name, TRUE);
315 }
316
317 BT_VALUE_PUT_REF_AND_RESET(bt_config_component->params);
318 g_free(bt_config_component);
319
320 end:
321 return;
322 }
323
324 /*
325 * Creates a component configuration using the given plugin name and
326 * component name. `plugin_name` and `comp_cls_name` are copied (belong
327 * to the return value).
328 *
329 * Return value is owned by the caller.
330 */
331 static
332 struct bt_config_component *bt_config_component_create(
333 bt_component_class_type type,
334 const char *plugin_name, const char *comp_cls_name,
335 int init_log_level)
336 {
337 struct bt_config_component *cfg_component = NULL;
338
339 cfg_component = g_new0(struct bt_config_component, 1);
340 if (!cfg_component) {
341 BT_CLI_LOGE_APPEND_CAUSE_OOM();
342 goto error;
343 }
344
345 bt_object_init_shared(&cfg_component->base,
346 bt_config_component_destroy);
347 cfg_component->type = type;
348 cfg_component->plugin_name = g_string_new(plugin_name);
349 if (!cfg_component->plugin_name) {
350 BT_CLI_LOGE_APPEND_CAUSE_OOM();
351 goto error;
352 }
353
354 cfg_component->comp_cls_name = g_string_new(comp_cls_name);
355 if (!cfg_component->comp_cls_name) {
356 BT_CLI_LOGE_APPEND_CAUSE_OOM();
357 goto error;
358 }
359
360 cfg_component->instance_name = g_string_new(NULL);
361 if (!cfg_component->instance_name) {
362 BT_CLI_LOGE_APPEND_CAUSE_OOM();
363 goto error;
364 }
365
366 cfg_component->log_level = init_log_level;
367
368 /* Start with empty parameters */
369 cfg_component->params = bt_value_map_create();
370 if (!cfg_component->params) {
371 BT_CLI_LOGE_APPEND_CAUSE_OOM();
372 goto error;
373 }
374
375 goto end;
376
377 error:
378 BT_OBJECT_PUT_REF_AND_RESET(cfg_component);
379
380 end:
381 return cfg_component;
382 }
383
384 /*
385 * Creates a component configuration from a command-line --component
386 * option's argument.
387 */
388 static
389 struct bt_config_component *bt_config_component_from_arg(const char *arg,
390 int init_log_level)
391 {
392 struct bt_config_component *cfg_comp = NULL;
393 char *name = NULL;
394 char *plugin_name = NULL;
395 char *comp_cls_name = NULL;
396 bt_component_class_type type;
397
398 plugin_comp_cls_names(arg, &name, &plugin_name, &comp_cls_name, &type);
399 if (!plugin_name || !comp_cls_name) {
400 goto error;
401 }
402
403 cfg_comp = bt_config_component_create(type, plugin_name, comp_cls_name,
404 init_log_level);
405 if (!cfg_comp) {
406 goto error;
407 }
408
409 if (name) {
410 g_string_assign(cfg_comp->instance_name, name);
411 }
412
413 goto end;
414
415 error:
416 BT_OBJECT_PUT_REF_AND_RESET(cfg_comp);
417
418 end:
419 g_free(name);
420 g_free(plugin_name);
421 g_free(comp_cls_name);
422 return cfg_comp;
423 }
424
425 /*
426 * Destroys a configuration.
427 */
428 static
429 void bt_config_destroy(bt_object *obj)
430 {
431 struct bt_config *cfg =
432 container_of(obj, struct bt_config, base);
433
434 if (!obj) {
435 goto end;
436 }
437
438 BT_VALUE_PUT_REF_AND_RESET(cfg->plugin_paths);
439
440 switch (cfg->command) {
441 case BT_CONFIG_COMMAND_RUN:
442 if (cfg->cmd_data.run.sources) {
443 g_ptr_array_free(cfg->cmd_data.run.sources, TRUE);
444 }
445
446 if (cfg->cmd_data.run.filters) {
447 g_ptr_array_free(cfg->cmd_data.run.filters, TRUE);
448 }
449
450 if (cfg->cmd_data.run.sinks) {
451 g_ptr_array_free(cfg->cmd_data.run.sinks, TRUE);
452 }
453
454 if (cfg->cmd_data.run.connections) {
455 g_ptr_array_free(cfg->cmd_data.run.connections,
456 TRUE);
457 }
458 break;
459 case BT_CONFIG_COMMAND_LIST_PLUGINS:
460 break;
461 case BT_CONFIG_COMMAND_HELP:
462 BT_OBJECT_PUT_REF_AND_RESET(cfg->cmd_data.help.cfg_component);
463 break;
464 case BT_CONFIG_COMMAND_QUERY:
465 BT_OBJECT_PUT_REF_AND_RESET(cfg->cmd_data.query.cfg_component);
466
467 if (cfg->cmd_data.query.object) {
468 g_string_free(cfg->cmd_data.query.object, TRUE);
469 }
470 break;
471 case BT_CONFIG_COMMAND_PRINT_CTF_METADATA:
472 if (cfg->cmd_data.print_ctf_metadata.path) {
473 g_string_free(cfg->cmd_data.print_ctf_metadata.path,
474 TRUE);
475 g_string_free(
476 cfg->cmd_data.print_ctf_metadata.output_path,
477 TRUE);
478 }
479 break;
480 case BT_CONFIG_COMMAND_PRINT_LTTNG_LIVE_SESSIONS:
481 if (cfg->cmd_data.print_lttng_live_sessions.url) {
482 g_string_free(
483 cfg->cmd_data.print_lttng_live_sessions.url,
484 TRUE);
485 g_string_free(
486 cfg->cmd_data.print_lttng_live_sessions.output_path,
487 TRUE);
488 }
489 break;
490 default:
491 abort();
492 }
493
494 g_free(cfg);
495
496 end:
497 return;
498 }
499
500 static
501 void destroy_glist_of_gstring(GList *list)
502 {
503 GList *at;
504
505 if (!list) {
506 return;
507 }
508
509 for (at = list; at; at = g_list_next(at)) {
510 g_string_free(at->data, TRUE);
511 }
512
513 g_list_free(list);
514 }
515
516 /*
517 * Creates a simple lexical scanner for parsing comma-delimited names
518 * and fields.
519 *
520 * Return value is owned by the caller.
521 */
522 static
523 GScanner *create_csv_identifiers_scanner(void)
524 {
525 GScanner *scanner;
526 GScannerConfig scanner_config = {
527 .cset_skip_characters = " \t\n",
528 .cset_identifier_first = G_CSET_a_2_z G_CSET_A_2_Z "_",
529 .cset_identifier_nth = G_CSET_a_2_z G_CSET_A_2_Z ":_-",
530 .case_sensitive = TRUE,
531 .cpair_comment_single = NULL,
532 .skip_comment_multi = TRUE,
533 .skip_comment_single = TRUE,
534 .scan_comment_multi = FALSE,
535 .scan_identifier = TRUE,
536 .scan_identifier_1char = TRUE,
537 .scan_identifier_NULL = FALSE,
538 .scan_symbols = FALSE,
539 .symbol_2_token = FALSE,
540 .scope_0_fallback = FALSE,
541 .scan_binary = FALSE,
542 .scan_octal = FALSE,
543 .scan_float = FALSE,
544 .scan_hex = FALSE,
545 .scan_hex_dollar = FALSE,
546 .numbers_2_int = FALSE,
547 .int_2_float = FALSE,
548 .store_int64 = FALSE,
549 .scan_string_sq = FALSE,
550 .scan_string_dq = FALSE,
551 .identifier_2_string = FALSE,
552 .char_2_token = TRUE,
553 };
554
555 scanner = g_scanner_new(&scanner_config);
556 if (!scanner) {
557 BT_CLI_LOGE_APPEND_CAUSE_OOM();
558 }
559
560 return scanner;
561 }
562
563 /*
564 * Converts a comma-delimited list of known names (--names option) to
565 * an array value object containing those names as string value objects.
566 *
567 * Return value is owned by the caller.
568 */
569 static
570 bt_value *names_from_arg(const char *arg)
571 {
572 GScanner *scanner = NULL;
573 bt_value *names = NULL;
574 bool found_all = false, found_none = false, found_item = false;
575
576 names = bt_value_array_create();
577 if (!names) {
578 BT_CLI_LOGE_APPEND_CAUSE_OOM();
579 goto error;
580 }
581
582 scanner = create_csv_identifiers_scanner();
583 if (!scanner) {
584 goto error;
585 }
586
587 g_scanner_input_text(scanner, arg, strlen(arg));
588
589 while (true) {
590 GTokenType token_type = g_scanner_get_next_token(scanner);
591
592 switch (token_type) {
593 case G_TOKEN_IDENTIFIER:
594 {
595 const char *identifier = scanner->value.v_identifier;
596
597 if (strcmp(identifier, "payload") == 0 ||
598 strcmp(identifier, "args") == 0 ||
599 strcmp(identifier, "arg") == 0) {
600 found_item = true;
601 if (bt_value_array_append_string_element(names,
602 "payload")) {
603 goto error;
604 }
605 } else if (strcmp(identifier, "context") == 0 ||
606 strcmp(identifier, "ctx") == 0) {
607 found_item = true;
608 if (bt_value_array_append_string_element(names,
609 "context")) {
610 goto error;
611 }
612 } else if (strcmp(identifier, "scope") == 0 ||
613 strcmp(identifier, "header") == 0) {
614 found_item = true;
615 if (bt_value_array_append_string_element(names,
616 identifier)) {
617 goto error;
618 }
619 } else if (strcmp(identifier, "all") == 0) {
620 found_all = true;
621 if (bt_value_array_append_string_element(names,
622 identifier)) {
623 goto error;
624 }
625 } else if (strcmp(identifier, "none") == 0) {
626 found_none = true;
627 if (bt_value_array_append_string_element(names,
628 identifier)) {
629 goto error;
630 }
631 } else {
632 BT_CLI_LOGE_APPEND_CAUSE("Unknown name: `%s`.",
633 identifier);
634 goto error;
635 }
636 break;
637 }
638 case G_TOKEN_COMMA:
639 continue;
640 case G_TOKEN_EOF:
641 goto end;
642 default:
643 goto error;
644 }
645 }
646
647 end:
648 if (found_none && found_all) {
649 BT_CLI_LOGE_APPEND_CAUSE("Only either `all` or `none` can be specified in the list given to the --names option, but not both.");
650 goto error;
651 }
652 /*
653 * Legacy behavior is to clear the defaults (show none) when at
654 * least one item is specified.
655 */
656 if (found_item && !found_none && !found_all) {
657 if (bt_value_array_append_string_element(names, "none")) {
658 goto error;
659 }
660 }
661 if (scanner) {
662 g_scanner_destroy(scanner);
663 }
664 return names;
665
666 error:
667 BT_VALUE_PUT_REF_AND_RESET(names);
668 if (scanner) {
669 g_scanner_destroy(scanner);
670 }
671 return names;
672 }
673
674 /*
675 * Converts a comma-delimited list of known fields (--fields option) to
676 * an array value object containing those fields as string
677 * value objects.
678 *
679 * Return value is owned by the caller.
680 */
681 static
682 bt_value *fields_from_arg(const char *arg)
683 {
684 GScanner *scanner = NULL;
685 bt_value *fields;
686
687 fields = bt_value_array_create();
688 if (!fields) {
689 BT_CLI_LOGE_APPEND_CAUSE_OOM();
690 goto error;
691 }
692
693 scanner = create_csv_identifiers_scanner();
694 if (!scanner) {
695 goto error;
696 }
697
698 g_scanner_input_text(scanner, arg, strlen(arg));
699
700 while (true) {
701 GTokenType token_type = g_scanner_get_next_token(scanner);
702
703 switch (token_type) {
704 case G_TOKEN_IDENTIFIER:
705 {
706 const char *identifier = scanner->value.v_identifier;
707
708 if (strcmp(identifier, "trace") == 0 ||
709 strcmp(identifier, "trace:hostname") == 0 ||
710 strcmp(identifier, "trace:domain") == 0 ||
711 strcmp(identifier, "trace:procname") == 0 ||
712 strcmp(identifier, "trace:vpid") == 0 ||
713 strcmp(identifier, "loglevel") == 0 ||
714 strcmp(identifier, "emf") == 0 ||
715 strcmp(identifier, "callsite") == 0 ||
716 strcmp(identifier, "all") == 0) {
717 if (bt_value_array_append_string_element(fields,
718 identifier)) {
719 goto error;
720 }
721 } else {
722 BT_CLI_LOGE_APPEND_CAUSE("Unknown field: `%s`.",
723 identifier);
724 goto error;
725 }
726 break;
727 }
728 case G_TOKEN_COMMA:
729 continue;
730 case G_TOKEN_EOF:
731 goto end;
732 default:
733 goto error;
734 }
735 }
736
737 goto end;
738
739 error:
740 BT_VALUE_PUT_REF_AND_RESET(fields);
741
742 end:
743 if (scanner) {
744 g_scanner_destroy(scanner);
745 }
746 return fields;
747 }
748
749 static
750 void append_param_arg(GString *params_arg, const char *key, const char *value)
751 {
752 BT_ASSERT(params_arg);
753 BT_ASSERT(key);
754 BT_ASSERT(value);
755
756 if (params_arg->len != 0) {
757 g_string_append_c(params_arg, ',');
758 }
759
760 g_string_append(params_arg, key);
761 g_string_append_c(params_arg, '=');
762 g_string_append(params_arg, value);
763 }
764
765 /*
766 * Inserts the equivalent "prefix-NAME=yes" strings into params_arg
767 * where the names are in names_array.
768 */
769 static
770 int insert_flat_params_from_array(GString *params_arg,
771 const bt_value *names_array, const char *prefix)
772 {
773 int ret = 0;
774 int i;
775 GString *tmpstr = NULL, *default_value = NULL;
776 bool default_set = false, non_default_set = false;
777
778 /*
779 * names_array may be NULL if no CLI options were specified to
780 * trigger its creation.
781 */
782 if (!names_array) {
783 goto end;
784 }
785
786 tmpstr = g_string_new(NULL);
787 if (!tmpstr) {
788 BT_CLI_LOGE_APPEND_CAUSE_OOM();
789 ret = -1;
790 goto end;
791 }
792
793 default_value = g_string_new(NULL);
794 if (!default_value) {
795 BT_CLI_LOGE_APPEND_CAUSE_OOM();
796 ret = -1;
797 goto end;
798 }
799
800 for (i = 0; i < bt_value_array_get_size(names_array); i++) {
801 const bt_value *str_obj =
802 bt_value_array_borrow_element_by_index_const(names_array,
803 i);
804 const char *suffix;
805 bool is_default = false;
806
807 if (!str_obj) {
808 BT_CLI_LOGE_APPEND_CAUSE("Unexpected error.");
809 ret = -1;
810 goto end;
811 }
812
813 suffix = bt_value_string_get(str_obj);
814
815 g_string_assign(tmpstr, prefix);
816 g_string_append(tmpstr, "-");
817
818 /* Special-case for "all" and "none". */
819 if (strcmp(suffix, "all") == 0) {
820 is_default = true;
821 g_string_assign(default_value, "show");
822 } else if (strcmp(suffix, "none") == 0) {
823 is_default = true;
824 g_string_assign(default_value, "hide");
825 }
826 if (is_default) {
827 default_set = true;
828 g_string_append(tmpstr, "default");
829 append_param_arg(params_arg, tmpstr->str,
830 default_value->str);
831 } else {
832 non_default_set = true;
833 g_string_append(tmpstr, suffix);
834 append_param_arg(params_arg, tmpstr->str, "yes");
835 }
836 }
837
838 /* Implicit field-default=hide if any non-default option is set. */
839 if (non_default_set && !default_set) {
840 g_string_assign(tmpstr, prefix);
841 g_string_append(tmpstr, "-default");
842 g_string_assign(default_value, "hide");
843 append_param_arg(params_arg, tmpstr->str, default_value->str);
844 }
845
846 end:
847 if (default_value) {
848 g_string_free(default_value, TRUE);
849 }
850
851 if (tmpstr) {
852 g_string_free(tmpstr, TRUE);
853 }
854
855 return ret;
856 }
857
858 /* argpar options */
859 enum {
860 OPT_NONE = 0,
861 OPT_BASE_PARAMS,
862 OPT_BEGIN,
863 OPT_CLOCK_CYCLES,
864 OPT_CLOCK_DATE,
865 OPT_CLOCK_FORCE_CORRELATE,
866 OPT_CLOCK_GMT,
867 OPT_CLOCK_OFFSET,
868 OPT_CLOCK_OFFSET_NS,
869 OPT_CLOCK_SECONDS,
870 OPT_COLOR,
871 OPT_COMPONENT,
872 OPT_CONNECT,
873 OPT_DEBUG,
874 OPT_DEBUG_INFO,
875 OPT_DEBUG_INFO_DIR,
876 OPT_DEBUG_INFO_FULL_PATH,
877 OPT_DEBUG_INFO_TARGET_PREFIX,
878 OPT_END,
879 OPT_FIELDS,
880 OPT_HELP,
881 OPT_INPUT_FORMAT,
882 OPT_LIST,
883 OPT_LOG_LEVEL,
884 OPT_NAMES,
885 OPT_NO_DELTA,
886 OPT_OMIT_HOME_PLUGIN_PATH,
887 OPT_OMIT_SYSTEM_PLUGIN_PATH,
888 OPT_OUTPUT,
889 OPT_OUTPUT_FORMAT,
890 OPT_PARAMS,
891 OPT_PLUGIN_PATH,
892 OPT_RESET_BASE_PARAMS,
893 OPT_RETRY_DURATION,
894 OPT_RUN_ARGS,
895 OPT_RUN_ARGS_0,
896 OPT_STREAM_INTERSECTION,
897 OPT_TIMERANGE,
898 OPT_VERBOSE,
899 OPT_VERSION,
900 };
901
902 enum bt_config_component_dest {
903 BT_CONFIG_COMPONENT_DEST_UNKNOWN = -1,
904 BT_CONFIG_COMPONENT_DEST_SOURCE,
905 BT_CONFIG_COMPONENT_DEST_FILTER,
906 BT_CONFIG_COMPONENT_DEST_SINK,
907 };
908
909 /*
910 * Adds a configuration component to the appropriate configuration
911 * array depending on the destination.
912 */
913 static
914 void add_run_cfg_comp(struct bt_config *cfg,
915 struct bt_config_component *cfg_comp,
916 enum bt_config_component_dest dest)
917 {
918 bt_object_get_ref(cfg_comp);
919
920 switch (dest) {
921 case BT_CONFIG_COMPONENT_DEST_SOURCE:
922 g_ptr_array_add(cfg->cmd_data.run.sources, cfg_comp);
923 break;
924 case BT_CONFIG_COMPONENT_DEST_FILTER:
925 g_ptr_array_add(cfg->cmd_data.run.filters, cfg_comp);
926 break;
927 case BT_CONFIG_COMPONENT_DEST_SINK:
928 g_ptr_array_add(cfg->cmd_data.run.sinks, cfg_comp);
929 break;
930 default:
931 abort();
932 }
933 }
934
935 static
936 int add_run_cfg_comp_check_name(struct bt_config *cfg,
937 struct bt_config_component *cfg_comp,
938 enum bt_config_component_dest dest,
939 bt_value *instance_names)
940 {
941 int ret = 0;
942
943 if (cfg_comp->instance_name->len == 0) {
944 BT_CLI_LOGE_APPEND_CAUSE("Found an unnamed component.");
945 ret = -1;
946 goto end;
947 }
948
949 if (bt_value_map_has_entry(instance_names,
950 cfg_comp->instance_name->str)) {
951 BT_CLI_LOGE_APPEND_CAUSE("Duplicate component instance name:\n %s",
952 cfg_comp->instance_name->str);
953 ret = -1;
954 goto end;
955 }
956
957 if (bt_value_map_insert_entry(instance_names,
958 cfg_comp->instance_name->str, bt_value_null)) {
959 BT_CLI_LOGE_APPEND_CAUSE_OOM();
960 ret = -1;
961 goto end;
962 }
963
964 add_run_cfg_comp(cfg, cfg_comp, dest);
965
966 end:
967 return ret;
968 }
969
970 static
971 int append_env_var_plugin_paths(bt_value *plugin_paths)
972 {
973 int ret = 0;
974 const char *envvar;
975
976 if (bt_common_is_setuid_setgid()) {
977 BT_LOGI_STR("Skipping non-system plugin paths for setuid/setgid binary.");
978 goto end;
979 }
980
981 envvar = getenv("BABELTRACE_PLUGIN_PATH");
982 if (!envvar) {
983 goto end;
984 }
985
986 ret = bt_config_append_plugin_paths(plugin_paths, envvar);
987
988 end:
989 if (ret) {
990 BT_CLI_LOGE_APPEND_CAUSE("Cannot append plugin paths from BABELTRACE_PLUGIN_PATH.");
991 }
992
993 return ret;
994 }
995
996 static
997 int append_home_and_system_plugin_paths(bt_value *plugin_paths,
998 bool omit_system_plugin_path, bool omit_home_plugin_path)
999 {
1000 int ret;
1001
1002 if (!omit_home_plugin_path) {
1003 if (bt_common_is_setuid_setgid()) {
1004 BT_LOGI_STR("Skipping non-system plugin paths for setuid/setgid binary.");
1005 } else {
1006 char *home_plugin_dir = bt_common_get_home_plugin_path(
1007 BT_LOG_OUTPUT_LEVEL);
1008
1009 if (home_plugin_dir) {
1010 ret = bt_config_append_plugin_paths(
1011 plugin_paths, home_plugin_dir);
1012 free(home_plugin_dir);
1013
1014 if (ret) {
1015 BT_CLI_LOGE_APPEND_CAUSE("Invalid home plugin path.");
1016 goto error;
1017 }
1018 }
1019 }
1020 }
1021
1022 if (!omit_system_plugin_path) {
1023 if (bt_config_append_plugin_paths(plugin_paths,
1024 bt_common_get_system_plugin_path())) {
1025 BT_CLI_LOGE_APPEND_CAUSE("Invalid system plugin path.");
1026 goto error;
1027 }
1028 }
1029 return 0;
1030 error:
1031 BT_CLI_LOGE_APPEND_CAUSE("Cannot append home and system plugin paths.");
1032 return -1;
1033 }
1034
1035 static
1036 int append_home_and_system_plugin_paths_cfg(struct bt_config *cfg)
1037 {
1038 return append_home_and_system_plugin_paths(cfg->plugin_paths,
1039 cfg->omit_system_plugin_path, cfg->omit_home_plugin_path);
1040 }
1041
1042 static
1043 struct bt_config *bt_config_base_create(enum bt_config_command command,
1044 const bt_value *initial_plugin_paths,
1045 bool needs_plugins)
1046 {
1047 struct bt_config *cfg;
1048
1049 /* Create config */
1050 cfg = g_new0(struct bt_config, 1);
1051 if (!cfg) {
1052 BT_CLI_LOGE_APPEND_CAUSE_OOM();
1053 goto error;
1054 }
1055
1056 bt_object_init_shared(&cfg->base, bt_config_destroy);
1057 cfg->command = command;
1058 cfg->command_needs_plugins = needs_plugins;
1059
1060 if (initial_plugin_paths) {
1061 bt_value *initial_plugin_paths_copy;
1062
1063 (void) bt_value_copy(initial_plugin_paths,
1064 &initial_plugin_paths_copy);
1065 cfg->plugin_paths = initial_plugin_paths_copy;
1066 } else {
1067 cfg->plugin_paths = bt_value_array_create();
1068 if (!cfg->plugin_paths) {
1069 BT_CLI_LOGE_APPEND_CAUSE_OOM();
1070 goto error;
1071 }
1072 }
1073
1074 goto end;
1075
1076 error:
1077 BT_OBJECT_PUT_REF_AND_RESET(cfg);
1078
1079 end:
1080 return cfg;
1081 }
1082
1083 static
1084 struct bt_config *bt_config_run_create(
1085 const bt_value *initial_plugin_paths)
1086 {
1087 struct bt_config *cfg;
1088
1089 /* Create config */
1090 cfg = bt_config_base_create(BT_CONFIG_COMMAND_RUN,
1091 initial_plugin_paths, true);
1092 if (!cfg) {
1093 goto error;
1094 }
1095
1096 cfg->cmd_data.run.sources = g_ptr_array_new_with_free_func(
1097 (GDestroyNotify) bt_object_put_ref);
1098 if (!cfg->cmd_data.run.sources) {
1099 BT_CLI_LOGE_APPEND_CAUSE_OOM();
1100 goto error;
1101 }
1102
1103 cfg->cmd_data.run.filters = g_ptr_array_new_with_free_func(
1104 (GDestroyNotify) bt_object_put_ref);
1105 if (!cfg->cmd_data.run.filters) {
1106 BT_CLI_LOGE_APPEND_CAUSE_OOM();
1107 goto error;
1108 }
1109
1110 cfg->cmd_data.run.sinks = g_ptr_array_new_with_free_func(
1111 (GDestroyNotify) bt_object_put_ref);
1112 if (!cfg->cmd_data.run.sinks) {
1113 BT_CLI_LOGE_APPEND_CAUSE_OOM();
1114 goto error;
1115 }
1116
1117 cfg->cmd_data.run.connections = g_ptr_array_new_with_free_func(
1118 (GDestroyNotify) bt_config_connection_destroy);
1119 if (!cfg->cmd_data.run.connections) {
1120 BT_CLI_LOGE_APPEND_CAUSE_OOM();
1121 goto error;
1122 }
1123
1124 goto end;
1125
1126 error:
1127 BT_OBJECT_PUT_REF_AND_RESET(cfg);
1128
1129 end:
1130 return cfg;
1131 }
1132
1133 static
1134 struct bt_config *bt_config_list_plugins_create(
1135 const bt_value *initial_plugin_paths)
1136 {
1137 struct bt_config *cfg;
1138
1139 /* Create config */
1140 cfg = bt_config_base_create(BT_CONFIG_COMMAND_LIST_PLUGINS,
1141 initial_plugin_paths, true);
1142 if (!cfg) {
1143 goto error;
1144 }
1145
1146 goto end;
1147
1148 error:
1149 BT_OBJECT_PUT_REF_AND_RESET(cfg);
1150
1151 end:
1152 return cfg;
1153 }
1154
1155 static
1156 struct bt_config *bt_config_help_create(
1157 const bt_value *initial_plugin_paths,
1158 int default_log_level)
1159 {
1160 struct bt_config *cfg;
1161
1162 /* Create config */
1163 cfg = bt_config_base_create(BT_CONFIG_COMMAND_HELP,
1164 initial_plugin_paths, true);
1165 if (!cfg) {
1166 goto error;
1167 }
1168
1169 cfg->cmd_data.help.cfg_component =
1170 bt_config_component_create(-1, NULL, NULL, default_log_level);
1171 if (!cfg->cmd_data.help.cfg_component) {
1172 goto error;
1173 }
1174
1175 goto end;
1176
1177 error:
1178 BT_OBJECT_PUT_REF_AND_RESET(cfg);
1179
1180 end:
1181 return cfg;
1182 }
1183
1184 static
1185 struct bt_config *bt_config_query_create(
1186 const bt_value *initial_plugin_paths)
1187 {
1188 struct bt_config *cfg;
1189
1190 /* Create config */
1191 cfg = bt_config_base_create(BT_CONFIG_COMMAND_QUERY,
1192 initial_plugin_paths, true);
1193 if (!cfg) {
1194 goto error;
1195 }
1196
1197 cfg->cmd_data.query.object = g_string_new(NULL);
1198 if (!cfg->cmd_data.query.object) {
1199 BT_CLI_LOGE_APPEND_CAUSE_OOM();
1200 goto error;
1201 }
1202
1203 goto end;
1204
1205 error:
1206 BT_OBJECT_PUT_REF_AND_RESET(cfg);
1207
1208 end:
1209 return cfg;
1210 }
1211
1212 static
1213 struct bt_config *bt_config_print_ctf_metadata_create(
1214 const bt_value *initial_plugin_paths)
1215 {
1216 struct bt_config *cfg;
1217
1218 /* Create config */
1219 cfg = bt_config_base_create(BT_CONFIG_COMMAND_PRINT_CTF_METADATA,
1220 initial_plugin_paths, true);
1221 if (!cfg) {
1222 goto error;
1223 }
1224
1225 cfg->cmd_data.print_ctf_metadata.path = g_string_new(NULL);
1226 if (!cfg->cmd_data.print_ctf_metadata.path) {
1227 BT_CLI_LOGE_APPEND_CAUSE_OOM();
1228 goto error;
1229 }
1230
1231 cfg->cmd_data.print_ctf_metadata.output_path = g_string_new(NULL);
1232 if (!cfg->cmd_data.print_ctf_metadata.output_path) {
1233 BT_CLI_LOGE_APPEND_CAUSE_OOM();
1234 goto error;
1235 }
1236
1237 goto end;
1238
1239 error:
1240 BT_OBJECT_PUT_REF_AND_RESET(cfg);
1241
1242 end:
1243 return cfg;
1244 }
1245
1246 static
1247 struct bt_config *bt_config_print_lttng_live_sessions_create(
1248 const bt_value *initial_plugin_paths)
1249 {
1250 struct bt_config *cfg;
1251
1252 /* Create config */
1253 cfg = bt_config_base_create(BT_CONFIG_COMMAND_PRINT_LTTNG_LIVE_SESSIONS,
1254 initial_plugin_paths, true);
1255 if (!cfg) {
1256 goto error;
1257 }
1258
1259 cfg->cmd_data.print_lttng_live_sessions.url = g_string_new(NULL);
1260 if (!cfg->cmd_data.print_lttng_live_sessions.url) {
1261 BT_CLI_LOGE_APPEND_CAUSE_OOM();
1262 goto error;
1263 }
1264
1265 cfg->cmd_data.print_lttng_live_sessions.output_path =
1266 g_string_new(NULL);
1267 if (!cfg->cmd_data.print_lttng_live_sessions.output_path) {
1268 BT_CLI_LOGE_APPEND_CAUSE_OOM();
1269 goto error;
1270 }
1271
1272 goto end;
1273
1274 error:
1275 BT_OBJECT_PUT_REF_AND_RESET(cfg);
1276
1277 end:
1278 return cfg;
1279 }
1280
1281 static
1282 int bt_config_append_plugin_paths_check_setuid_setgid(
1283 bt_value *plugin_paths, const char *arg)
1284 {
1285 int ret = 0;
1286
1287 if (bt_common_is_setuid_setgid()) {
1288 BT_LOGI_STR("Skipping non-system plugin paths for setuid/setgid binary.");
1289 goto end;
1290 }
1291
1292 if (bt_config_append_plugin_paths(plugin_paths, arg)) {
1293 BT_CLI_LOGE_APPEND_CAUSE("Invalid --plugin-path option's argument:\n %s",
1294 arg);
1295 ret = -1;
1296 goto end;
1297 }
1298
1299 end:
1300 return ret;
1301 }
1302
1303 /*
1304 * Prints the expected format for a --params option.
1305 */
1306 static
1307 void print_expected_params_format(FILE *fp)
1308 {
1309 fprintf(fp, "Expected format of PARAMS\n");
1310 fprintf(fp, "-------------------------\n");
1311 fprintf(fp, "\n");
1312 fprintf(fp, " PARAM=VALUE[,PARAM=VALUE]...\n");
1313 fprintf(fp, "\n");
1314 fprintf(fp, "The parameter string is a comma-separated list of PARAM=VALUE assignments,\n");
1315 fprintf(fp, "where PARAM is the parameter name (C identifier plus the [:.-] characters),\n");
1316 fprintf(fp, "and VALUE can be one of:\n");
1317 fprintf(fp, "\n");
1318 fprintf(fp, "* `null`, `nul`, `NULL`: null value (no backticks).\n");
1319 fprintf(fp, "* `true`, `TRUE`, `yes`, `YES`: true boolean value (no backticks).\n");
1320 fprintf(fp, "* `false`, `FALSE`, `no`, `NO`: false boolean value (no backticks).\n");
1321 fprintf(fp, "* Binary (`0b` prefix), octal (`0` prefix), decimal, or hexadecimal\n");
1322 fprintf(fp, " (`0x` prefix) unsigned (with `+` prefix) or signed 64-bit integer.\n");
1323 fprintf(fp, "* Double precision floating point number (scientific notation is accepted).\n");
1324 fprintf(fp, "* Unquoted string with no special characters, and not matching any of\n");
1325 fprintf(fp, " the null and boolean value symbols above.\n");
1326 fprintf(fp, "* Double-quoted string (accepts escape characters).\n");
1327 fprintf(fp, "* Array, formatted as an opening `[`, a list of comma-separated values\n");
1328 fprintf(fp, " (as described by the current list) and a closing `]`.\n");
1329 fprintf(fp, "\n");
1330 fprintf(fp, "You can put whitespaces allowed around individual `=` and `,` symbols.\n");
1331 fprintf(fp, "\n");
1332 fprintf(fp, "Example:\n");
1333 fprintf(fp, "\n");
1334 fprintf(fp, " many=null, fresh=yes, condition=false, squirrel=-782329,\n");
1335 fprintf(fp, " play=+23, observe=3.14, simple=beef, needs-quotes=\"some string\",\n");
1336 fprintf(fp, " escape.chars-are:allowed=\"this is a \\\" double quote\",\n");
1337 fprintf(fp, " things=[1, \"2\", 3]\n");
1338 fprintf(fp, "\n");
1339 fprintf(fp, "IMPORTANT: Make sure to single-quote the whole argument when you run\n");
1340 fprintf(fp, "babeltrace2 from a shell.\n");
1341 }
1342
1343 static
1344 bool help_option_is_specified(
1345 const struct bt_argpar_parse_ret *argpar_parse_ret)
1346 {
1347 int i;
1348 bool specified = false;
1349
1350 for (i = 0; i < argpar_parse_ret->items->len; i++) {
1351 struct bt_argpar_item *argpar_item =
1352 g_ptr_array_index(argpar_parse_ret->items, i);
1353 struct bt_argpar_item_opt *argpar_item_opt;
1354
1355 if (argpar_item->type != BT_ARGPAR_ITEM_TYPE_OPT) {
1356 continue;
1357 }
1358
1359 argpar_item_opt = (struct bt_argpar_item_opt *) argpar_item;
1360 if (argpar_item_opt->descr->id == OPT_HELP) {
1361 specified = true;
1362 break;
1363 }
1364 }
1365
1366 return specified;
1367 }
1368
1369 /*
1370 * Prints the help command usage.
1371 */
1372 static
1373 void print_help_usage(FILE *fp)
1374 {
1375 fprintf(fp, "Usage: babeltrace2 [GENERAL OPTIONS] help [OPTIONS] PLUGIN\n");
1376 fprintf(fp, " babeltrace2 [GENERAL OPTIONS] help [OPTIONS] TYPE.PLUGIN.CLS\n");
1377 fprintf(fp, "\n");
1378 fprintf(fp, "Options:\n");
1379 fprintf(fp, "\n");
1380 fprintf(fp, " --omit-home-plugin-path Omit home plugins from plugin search path\n");
1381 fprintf(fp, " (~/.local/lib/babeltrace2/plugins)\n");
1382 fprintf(fp, " --omit-system-plugin-path Omit system plugins from plugin search path\n");
1383 fprintf(fp, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n");
1384 fprintf(fp, " dynamic plugins can be loaded\n");
1385 fprintf(fp, " -h, --help Show this help and quit\n");
1386 fprintf(fp, "\n");
1387 fprintf(fp, "See `babeltrace2 --help` for the list of general options.\n");
1388 fprintf(fp, "\n");
1389 fprintf(fp, "Use `babeltrace2 list-plugins` to show the list of available plugins.\n");
1390 }
1391
1392 static
1393 const struct bt_argpar_opt_descr help_options[] = {
1394 /* id, short_name, long_name, with_arg */
1395 { OPT_HELP, 'h', "help", false },
1396 { OPT_OMIT_HOME_PLUGIN_PATH, '\0', "omit-home-plugin-path", false },
1397 { OPT_OMIT_SYSTEM_PLUGIN_PATH, '\0', "omit-system-plugin-path", false },
1398 { OPT_PLUGIN_PATH, '\0', "plugin-path", true },
1399 BT_ARGPAR_OPT_DESCR_SENTINEL
1400 };
1401
1402 /*
1403 * Creates a Babeltrace config object from the arguments of a help
1404 * command.
1405 *
1406 * *retcode is set to the appropriate exit code to use.
1407 */
1408 static
1409 struct bt_config *bt_config_help_from_args(int argc, const char *argv[],
1410 int *retcode, bool force_omit_system_plugin_path,
1411 bool force_omit_home_plugin_path,
1412 const bt_value *initial_plugin_paths, int default_log_level)
1413 {
1414 int ret, i;
1415 struct bt_config *cfg = NULL;
1416 const char *leftover = NULL;
1417 char *plugin_name = NULL, *comp_cls_name = NULL;
1418 struct bt_argpar_parse_ret argpar_parse_ret;
1419
1420 *retcode = 0;
1421 cfg = bt_config_help_create(initial_plugin_paths, default_log_level);
1422 if (!cfg) {
1423 goto error;
1424 }
1425
1426 cfg->omit_system_plugin_path = force_omit_system_plugin_path;
1427 cfg->omit_home_plugin_path = force_omit_home_plugin_path;
1428 ret = append_env_var_plugin_paths(cfg->plugin_paths);
1429 if (ret) {
1430 goto error;
1431 }
1432
1433 /* Parse options */
1434 argpar_parse_ret = bt_argpar_parse(argc, argv, help_options, true);
1435 if (argpar_parse_ret.error) {
1436 BT_CLI_LOGE_APPEND_CAUSE(
1437 "While parsing `help` command's command-line arguments: %s",
1438 argpar_parse_ret.error->str);
1439 goto error;
1440 }
1441
1442 if (help_option_is_specified(&argpar_parse_ret)) {
1443 print_help_usage(stdout);
1444 *retcode = -1;
1445 BT_OBJECT_PUT_REF_AND_RESET(cfg);
1446 goto end;
1447 }
1448
1449 for (i = 0; i < argpar_parse_ret.items->len; i++) {
1450 struct bt_argpar_item *argpar_item =
1451 g_ptr_array_index(argpar_parse_ret.items, i);
1452
1453 if (argpar_item->type == BT_ARGPAR_ITEM_TYPE_OPT) {
1454 struct bt_argpar_item_opt *argpar_item_opt;
1455 const char *arg;
1456 argpar_item_opt = (struct bt_argpar_item_opt *) argpar_item;
1457 arg = argpar_item_opt->arg;
1458
1459 switch (argpar_item_opt->descr->id) {
1460 case OPT_PLUGIN_PATH:
1461 if (bt_config_append_plugin_paths_check_setuid_setgid(
1462 cfg->plugin_paths, arg)) {
1463 goto error;
1464 }
1465 break;
1466 case OPT_OMIT_SYSTEM_PLUGIN_PATH:
1467 cfg->omit_system_plugin_path = true;
1468 break;
1469 case OPT_OMIT_HOME_PLUGIN_PATH:
1470 cfg->omit_home_plugin_path = true;
1471 break;
1472 default:
1473 BT_CLI_LOGE_APPEND_CAUSE("Unknown command-line option specified (option code %d).",
1474 argpar_item_opt->descr->id);
1475 goto error;
1476 }
1477 } else {
1478 struct bt_argpar_item_non_opt *argpar_item_non_opt
1479 = (struct bt_argpar_item_non_opt *) argpar_item;
1480
1481 if (leftover) {
1482 BT_CLI_LOGE_APPEND_CAUSE("Extraneous command-line argument specified to `help` command: `%s`.",
1483 argpar_item_non_opt->arg);
1484 goto error;
1485 }
1486
1487 leftover = argpar_item_non_opt->arg;
1488 }
1489 }
1490
1491 if (leftover) {
1492 plugin_comp_cls_names(leftover, NULL,
1493 &plugin_name, &comp_cls_name,
1494 &cfg->cmd_data.help.cfg_component->type);
1495 if (plugin_name && comp_cls_name) {
1496 /* Component class help */
1497 g_string_assign(
1498 cfg->cmd_data.help.cfg_component->plugin_name,
1499 plugin_name);
1500 g_string_assign(
1501 cfg->cmd_data.help.cfg_component->comp_cls_name,
1502 comp_cls_name);
1503 } else {
1504 /* Fall back to plugin help */
1505 g_string_assign(
1506 cfg->cmd_data.help.cfg_component->plugin_name,
1507 leftover);
1508 }
1509 } else {
1510 print_help_usage(stdout);
1511 *retcode = -1;
1512 BT_OBJECT_PUT_REF_AND_RESET(cfg);
1513 goto end;
1514 }
1515
1516 if (append_home_and_system_plugin_paths_cfg(cfg)) {
1517 goto error;
1518 }
1519
1520 goto end;
1521
1522 error:
1523 *retcode = 1;
1524 BT_OBJECT_PUT_REF_AND_RESET(cfg);
1525
1526 end:
1527 g_free(plugin_name);
1528 g_free(comp_cls_name);
1529
1530 bt_argpar_parse_ret_fini(&argpar_parse_ret);
1531
1532 return cfg;
1533 }
1534
1535 /*
1536 * Prints the help command usage.
1537 */
1538 static
1539 void print_query_usage(FILE *fp)
1540 {
1541 fprintf(fp, "Usage: babeltrace2 [GEN OPTS] query [OPTS] TYPE.PLUGIN.CLS OBJECT\n");
1542 fprintf(fp, "\n");
1543 fprintf(fp, "Options:\n");
1544 fprintf(fp, "\n");
1545 fprintf(fp, " --omit-home-plugin-path Omit home plugins from plugin search path\n");
1546 fprintf(fp, " (~/.local/lib/babeltrace2/plugins)\n");
1547 fprintf(fp, " --omit-system-plugin-path Omit system plugins from plugin search path\n");
1548 fprintf(fp, " -p, --params=PARAMS Set the query parameters to PARAMS\n");
1549 fprintf(fp, " (see the expected format of PARAMS below)\n");
1550 fprintf(fp, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n");
1551 fprintf(fp, " dynamic plugins can be loaded\n");
1552 fprintf(fp, " -h, --help Show this help and quit\n");
1553 fprintf(fp, "\n\n");
1554 print_expected_params_format(fp);
1555 }
1556
1557 static
1558 const struct bt_argpar_opt_descr query_options[] = {
1559 /* id, short_name, long_name, with_arg */
1560 { OPT_HELP, 'h', "help", false },
1561 { OPT_OMIT_HOME_PLUGIN_PATH, '\0', "omit-home-plugin-path", false },
1562 { OPT_OMIT_SYSTEM_PLUGIN_PATH, '\0', "omit-system-plugin-path", false },
1563 { OPT_PARAMS, 'p', "params", true },
1564 { OPT_PLUGIN_PATH, '\0', "plugin-path", true },
1565 BT_ARGPAR_OPT_DESCR_SENTINEL
1566 };
1567
1568 /*
1569 * Creates a Babeltrace config object from the arguments of a query
1570 * command.
1571 *
1572 * *retcode is set to the appropriate exit code to use.
1573 */
1574 static
1575 struct bt_config *bt_config_query_from_args(int argc, const char *argv[],
1576 int *retcode, bool force_omit_system_plugin_path,
1577 bool force_omit_home_plugin_path,
1578 const bt_value *initial_plugin_paths,
1579 int default_log_level)
1580 {
1581 int ret, i;
1582 struct bt_config *cfg = NULL;
1583 const char *component_class_spec = NULL;
1584 const char *query_object = NULL;
1585 bt_value *params;
1586 GString *error_str = NULL;
1587 struct bt_argpar_parse_ret argpar_parse_ret;
1588
1589 params = bt_value_null;
1590 bt_value_get_ref(bt_value_null);
1591
1592 *retcode = 0;
1593 cfg = bt_config_query_create(initial_plugin_paths);
1594 if (!cfg) {
1595 goto error;
1596 }
1597
1598 error_str = g_string_new(NULL);
1599 if (!error_str) {
1600 BT_CLI_LOGE_APPEND_CAUSE_OOM();
1601 goto error;
1602 }
1603
1604 cfg->omit_system_plugin_path = force_omit_system_plugin_path;
1605 cfg->omit_home_plugin_path = force_omit_home_plugin_path;
1606 ret = append_env_var_plugin_paths(cfg->plugin_paths);
1607 if (ret) {
1608 goto error;
1609 }
1610
1611 /* Parse options */
1612 argpar_parse_ret = bt_argpar_parse(argc, argv, query_options, true);
1613 if (argpar_parse_ret.error) {
1614 BT_CLI_LOGE_APPEND_CAUSE(
1615 "While parsing `query` command's command-line arguments: %s",
1616 argpar_parse_ret.error->str);
1617 goto error;
1618 }
1619
1620 if (help_option_is_specified(&argpar_parse_ret)) {
1621 print_query_usage(stdout);
1622 *retcode = -1;
1623 BT_OBJECT_PUT_REF_AND_RESET(cfg);
1624 goto end;
1625 }
1626
1627 for (i = 0; i < argpar_parse_ret.items->len; i++) {
1628 struct bt_argpar_item *argpar_item =
1629 g_ptr_array_index(argpar_parse_ret.items, i);
1630
1631 if (argpar_item->type == BT_ARGPAR_ITEM_TYPE_OPT) {
1632 struct bt_argpar_item_opt *argpar_item_opt =
1633 (struct bt_argpar_item_opt *) argpar_item;
1634 const char *arg = argpar_item_opt->arg;
1635
1636 switch (argpar_item_opt->descr->id) {
1637 case OPT_PLUGIN_PATH:
1638 if (bt_config_append_plugin_paths_check_setuid_setgid(
1639 cfg->plugin_paths, arg)) {
1640 goto error;
1641 }
1642 break;
1643 case OPT_OMIT_SYSTEM_PLUGIN_PATH:
1644 cfg->omit_system_plugin_path = true;
1645 break;
1646 case OPT_OMIT_HOME_PLUGIN_PATH:
1647 cfg->omit_home_plugin_path = true;
1648 break;
1649 case OPT_PARAMS:
1650 {
1651 bt_value_put_ref(params);
1652 params = cli_value_from_arg(arg, error_str);
1653 if (!params) {
1654 BT_CLI_LOGE_APPEND_CAUSE("Invalid format for --params option's argument:\n %s",
1655 error_str->str);
1656 goto error;
1657 }
1658 break;
1659 }
1660 default:
1661 BT_CLI_LOGE_APPEND_CAUSE("Unknown command-line option specified (option code %d).",
1662 argpar_item_opt->descr->id);
1663 goto error;
1664 }
1665 } else {
1666 struct bt_argpar_item_non_opt *argpar_item_non_opt
1667 = (struct bt_argpar_item_non_opt *) argpar_item;
1668
1669 /*
1670 * We need exactly two leftover arguments which are the
1671 * mandatory component class specification and query object.
1672 */
1673 if (!component_class_spec) {
1674 component_class_spec = argpar_item_non_opt->arg;
1675 } else if (!query_object) {
1676 query_object = argpar_item_non_opt->arg;
1677 } else {
1678 BT_CLI_LOGE_APPEND_CAUSE("Extraneous command-line argument specified to `query` command: `%s`.",
1679 argpar_item_non_opt->arg);
1680 goto error;
1681 }
1682 }
1683 }
1684
1685 if (!component_class_spec || !query_object) {
1686 print_query_usage(stdout);
1687 *retcode = -1;
1688 BT_OBJECT_PUT_REF_AND_RESET(cfg);
1689 goto end;
1690 }
1691
1692 cfg->cmd_data.query.cfg_component =
1693 bt_config_component_from_arg(component_class_spec,
1694 default_log_level);
1695 if (!cfg->cmd_data.query.cfg_component) {
1696 BT_CLI_LOGE_APPEND_CAUSE("Invalid format for component class specification:\n %s",
1697 component_class_spec);
1698 goto error;
1699 }
1700
1701 BT_ASSERT(params);
1702 BT_OBJECT_MOVE_REF(cfg->cmd_data.query.cfg_component->params, params);
1703
1704 if (strlen(query_object) == 0) {
1705 BT_CLI_LOGE_APPEND_CAUSE("Invalid empty object.");
1706 goto error;
1707 }
1708
1709 g_string_assign(cfg->cmd_data.query.object, query_object);
1710
1711 if (append_home_and_system_plugin_paths_cfg(cfg)) {
1712 goto error;
1713 }
1714
1715 goto end;
1716
1717 error:
1718 *retcode = 1;
1719 BT_OBJECT_PUT_REF_AND_RESET(cfg);
1720
1721 end:
1722 bt_argpar_parse_ret_fini(&argpar_parse_ret);
1723
1724 if (error_str) {
1725 g_string_free(error_str, TRUE);
1726 }
1727
1728 bt_value_put_ref(params);
1729 return cfg;
1730 }
1731
1732 /*
1733 * Prints the list-plugins command usage.
1734 */
1735 static
1736 void print_list_plugins_usage(FILE *fp)
1737 {
1738 fprintf(fp, "Usage: babeltrace2 [GENERAL OPTIONS] list-plugins [OPTIONS]\n");
1739 fprintf(fp, "\n");
1740 fprintf(fp, "Options:\n");
1741 fprintf(fp, "\n");
1742 fprintf(fp, " --omit-home-plugin-path Omit home plugins from plugin search path\n");
1743 fprintf(fp, " (~/.local/lib/babeltrace2/plugins)\n");
1744 fprintf(fp, " --omit-system-plugin-path Omit system plugins from plugin search path\n");
1745 fprintf(fp, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n");
1746 fprintf(fp, " dynamic plugins can be loaded\n");
1747 fprintf(fp, " -h, --help Show this help and quit\n");
1748 fprintf(fp, "\n");
1749 fprintf(fp, "See `babeltrace2 --help` for the list of general options.\n");
1750 fprintf(fp, "\n");
1751 fprintf(fp, "Use `babeltrace2 help` to get help for a specific plugin or component class.\n");
1752 }
1753
1754 static
1755 const struct bt_argpar_opt_descr list_plugins_options[] = {
1756 /* id, short_name, long_name, with_arg */
1757 { OPT_HELP, 'h', "help", false },
1758 { OPT_OMIT_HOME_PLUGIN_PATH, '\0', "omit-home-plugin-path", false },
1759 { OPT_OMIT_SYSTEM_PLUGIN_PATH, '\0', "omit-system-plugin-path", false },
1760 { OPT_PLUGIN_PATH, '\0', "plugin-path", true },
1761 BT_ARGPAR_OPT_DESCR_SENTINEL
1762 };
1763
1764 /*
1765 * Creates a Babeltrace config object from the arguments of a
1766 * list-plugins command.
1767 *
1768 * *retcode is set to the appropriate exit code to use.
1769 */
1770 static
1771 struct bt_config *bt_config_list_plugins_from_args(int argc, const char *argv[],
1772 int *retcode, bool force_omit_system_plugin_path,
1773 bool force_omit_home_plugin_path,
1774 const bt_value *initial_plugin_paths)
1775 {
1776 int ret, i;
1777 struct bt_config *cfg = NULL;
1778 struct bt_argpar_parse_ret argpar_parse_ret = { 0 };
1779
1780 *retcode = 0;
1781 cfg = bt_config_list_plugins_create(initial_plugin_paths);
1782 if (!cfg) {
1783 goto error;
1784 }
1785
1786 cfg->omit_system_plugin_path = force_omit_system_plugin_path;
1787 cfg->omit_home_plugin_path = force_omit_home_plugin_path;
1788 ret = append_env_var_plugin_paths(cfg->plugin_paths);
1789 if (ret) {
1790 goto error;
1791 }
1792
1793 /* Parse options */
1794 argpar_parse_ret = bt_argpar_parse(argc, argv, list_plugins_options, true);
1795 if (argpar_parse_ret.error) {
1796 BT_CLI_LOGE_APPEND_CAUSE(
1797 "While parsing `list-plugins` command's command-line arguments: %s",
1798 argpar_parse_ret.error->str);
1799 goto error;
1800 }
1801
1802 if (help_option_is_specified(&argpar_parse_ret)) {
1803 print_list_plugins_usage(stdout);
1804 *retcode = -1;
1805 BT_OBJECT_PUT_REF_AND_RESET(cfg);
1806 goto end;
1807 }
1808
1809 for (i = 0; i < argpar_parse_ret.items->len; i++) {
1810 struct bt_argpar_item *argpar_item =
1811 g_ptr_array_index(argpar_parse_ret.items, i);
1812 struct bt_argpar_item_opt *argpar_item_opt;
1813 const char *arg;
1814
1815 if (argpar_item->type == BT_ARGPAR_ITEM_TYPE_NON_OPT) {
1816 struct bt_argpar_item_non_opt *argpar_item_non_opt
1817 = (struct bt_argpar_item_non_opt *) argpar_item;
1818
1819 BT_CLI_LOGE_APPEND_CAUSE("Unexpected argument: `%s`.",
1820 argpar_item_non_opt->arg);
1821 goto error;
1822 }
1823
1824 argpar_item_opt = (struct bt_argpar_item_opt *) argpar_item;
1825 arg = argpar_item_opt->arg;
1826
1827 switch (argpar_item_opt->descr->id) {
1828 case OPT_PLUGIN_PATH:
1829 if (bt_config_append_plugin_paths_check_setuid_setgid(
1830 cfg->plugin_paths, arg)) {
1831 goto error;
1832 }
1833 break;
1834 case OPT_OMIT_SYSTEM_PLUGIN_PATH:
1835 cfg->omit_system_plugin_path = true;
1836 break;
1837 case OPT_OMIT_HOME_PLUGIN_PATH:
1838 cfg->omit_home_plugin_path = true;
1839 break;
1840 default:
1841 BT_CLI_LOGE_APPEND_CAUSE("Unknown command-line option specified (option code %d).",
1842 argpar_item_opt->descr->id);
1843 goto error;
1844 }
1845 }
1846
1847 if (append_home_and_system_plugin_paths_cfg(cfg)) {
1848 goto error;
1849 }
1850
1851 goto end;
1852
1853 error:
1854 *retcode = 1;
1855 BT_OBJECT_PUT_REF_AND_RESET(cfg);
1856
1857 end:
1858 bt_argpar_parse_ret_fini(&argpar_parse_ret);
1859
1860 return cfg;
1861 }
1862
1863 /*
1864 * Prints the run command usage.
1865 */
1866 static
1867 void print_run_usage(FILE *fp)
1868 {
1869 fprintf(fp, "Usage: babeltrace2 [GENERAL OPTIONS] run [OPTIONS]\n");
1870 fprintf(fp, "\n");
1871 fprintf(fp, "Options:\n");
1872 fprintf(fp, "\n");
1873 fprintf(fp, " -b, --base-params=PARAMS Set PARAMS as the current base parameters\n");
1874 fprintf(fp, " for all the following components until\n");
1875 fprintf(fp, " --reset-base-params is encountered\n");
1876 fprintf(fp, " (see the expected format of PARAMS below)\n");
1877 fprintf(fp, " -c, --component=NAME:TYPE.PLUGIN.CLS\n");
1878 fprintf(fp, " Instantiate the component class CLS of type\n");
1879 fprintf(fp, " TYPE (`source`, `filter`, or `sink`) found\n");
1880 fprintf(fp, " in the plugin PLUGIN, add it to the graph,\n");
1881 fprintf(fp, " and name it NAME");
1882 fprintf(fp, " -x, --connect=CONNECTION Connect two created components (see the\n");
1883 fprintf(fp, " expected format of CONNECTION below)\n");
1884 fprintf(fp, " -l, --log-level=LVL Set the log level of the current component to LVL\n");
1885 fprintf(fp, " (`N`, `V`, `D`, `I`, `W`, `E`, or `F`)\n");
1886 fprintf(fp, " --omit-home-plugin-path Omit home plugins from plugin search path\n");
1887 fprintf(fp, " (~/.local/lib/babeltrace2/plugins)\n");
1888 fprintf(fp, " --omit-system-plugin-path Omit system plugins from plugin search path\n");
1889 fprintf(fp, " -p, --params=PARAMS Add initialization parameters PARAMS to the\n");
1890 fprintf(fp, " current component (see the expected format\n");
1891 fprintf(fp, " of PARAMS below)\n");
1892 fprintf(fp, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n");
1893 fprintf(fp, " dynamic plugins can be loaded\n");
1894 fprintf(fp, " -r, --reset-base-params Reset the current base parameters to an\n");
1895 fprintf(fp, " empty map\n");
1896 fprintf(fp, " --retry-duration=DUR When babeltrace2(1) needs to retry to run\n");
1897 fprintf(fp, " the graph later, retry in DUR µs\n");
1898 fprintf(fp, " (default: 100000)\n");
1899 fprintf(fp, " -h, --help Show this help and quit\n");
1900 fprintf(fp, "\n");
1901 fprintf(fp, "See `babeltrace2 --help` for the list of general options.\n");
1902 fprintf(fp, "\n\n");
1903 fprintf(fp, "Expected format of CONNECTION\n");
1904 fprintf(fp, "-----------------------------\n");
1905 fprintf(fp, "\n");
1906 fprintf(fp, " UPSTREAM[.UPSTREAM-PORT]:DOWNSTREAM[.DOWNSTREAM-PORT]\n");
1907 fprintf(fp, "\n");
1908 fprintf(fp, "UPSTREAM and DOWNSTREAM are names of the upstream and downstream\n");
1909 fprintf(fp, "components to connect together. You must escape the following characters\n\n");
1910 fprintf(fp, "with `\\`: `\\`, `.`, and `:`. You must set the name of the current\n");
1911 fprintf(fp, "component using the NAME prefix of the --component option.\n");
1912 fprintf(fp, "\n");
1913 fprintf(fp, "UPSTREAM-PORT and DOWNSTREAM-PORT are optional globbing patterns to\n");
1914 fprintf(fp, "identify the upstream and downstream ports to use for the connection.\n");
1915 fprintf(fp, "When the port is not specified, `*` is used.\n");
1916 fprintf(fp, "\n");
1917 fprintf(fp, "When a component named UPSTREAM has an available port which matches the\n");
1918 fprintf(fp, "UPSTREAM-PORT globbing pattern, it is connected to the first port which\n");
1919 fprintf(fp, "matches the DOWNSTREAM-PORT globbing pattern of the component named\n");
1920 fprintf(fp, "DOWNSTREAM.\n");
1921 fprintf(fp, "\n");
1922 fprintf(fp, "The only special character in UPSTREAM-PORT and DOWNSTREAM-PORT is `*`\n");
1923 fprintf(fp, "which matches anything. You must escape the following characters\n");
1924 fprintf(fp, "with `\\`: `\\`, `*`, `?`, `[`, `.`, and `:`.\n");
1925 fprintf(fp, "\n");
1926 fprintf(fp, "You can connect a source component to a filter or sink component. You\n");
1927 fprintf(fp, "can connect a filter component to a sink component.\n");
1928 fprintf(fp, "\n");
1929 fprintf(fp, "Examples:\n");
1930 fprintf(fp, "\n");
1931 fprintf(fp, " my-src:my-sink\n");
1932 fprintf(fp, " ctf-fs.*stream*:utils-muxer:*\n");
1933 fprintf(fp, "\n");
1934 fprintf(fp, "IMPORTANT: Make sure to single-quote the whole argument when you run\n");
1935 fprintf(fp, "babeltrace2 from a shell.\n");
1936 fprintf(fp, "\n\n");
1937 print_expected_params_format(fp);
1938 }
1939
1940 /*
1941 * Creates a Babeltrace config object from the arguments of a run
1942 * command.
1943 *
1944 * *retcode is set to the appropriate exit code to use.
1945 */
1946 static
1947 struct bt_config *bt_config_run_from_args(int argc, const char *argv[],
1948 int *retcode, bool force_omit_system_plugin_path,
1949 bool force_omit_home_plugin_path,
1950 const bt_value *initial_plugin_paths, int default_log_level)
1951 {
1952 struct bt_config_component *cur_cfg_comp = NULL;
1953 bt_value *cur_base_params = NULL;
1954 int ret = 0;
1955 struct bt_config *cfg = NULL;
1956 bt_value *instance_names = NULL;
1957 bt_value *connection_args = NULL;
1958 char error_buf[256] = { 0 };
1959 long retry_duration = -1;
1960 bt_value_map_extend_status extend_status;
1961 GString *error_str = NULL;
1962 struct bt_argpar_parse_ret argpar_parse_ret = { 0 };
1963 int i;
1964
1965 static const struct bt_argpar_opt_descr run_options[] = {
1966 { OPT_BASE_PARAMS, 'b', "base-params", true },
1967 { OPT_COMPONENT, 'c', "component", true },
1968 { OPT_CONNECT, 'x', "connect", true },
1969 { OPT_HELP, 'h', "help", false },
1970 { OPT_LOG_LEVEL, 'l', "log-level", true },
1971 { OPT_OMIT_HOME_PLUGIN_PATH, '\0', "omit-home-plugin-path", false },
1972 { OPT_OMIT_SYSTEM_PLUGIN_PATH, '\0', "omit-system-plugin-path", false },
1973 { OPT_PARAMS, 'p', "params", true },
1974 { OPT_PLUGIN_PATH, '\0', "plugin-path", true },
1975 { OPT_RESET_BASE_PARAMS, 'r', "reset-base-params", false },
1976 { OPT_RETRY_DURATION, '\0', "retry-duration", true },
1977 BT_ARGPAR_OPT_DESCR_SENTINEL
1978 };
1979
1980 *retcode = 0;
1981
1982 error_str = g_string_new(NULL);
1983 if (!error_str) {
1984 BT_CLI_LOGE_APPEND_CAUSE_OOM();
1985 goto error;
1986 }
1987
1988 if (argc < 1) {
1989 print_run_usage(stdout);
1990 *retcode = -1;
1991 goto end;
1992 }
1993
1994 cfg = bt_config_run_create(initial_plugin_paths);
1995 if (!cfg) {
1996 goto error;
1997 }
1998
1999 cfg->cmd_data.run.retry_duration_us = 100000;
2000 cfg->omit_system_plugin_path = force_omit_system_plugin_path;
2001 cfg->omit_home_plugin_path = force_omit_home_plugin_path;
2002 cur_base_params = bt_value_map_create();
2003 if (!cur_base_params) {
2004 BT_CLI_LOGE_APPEND_CAUSE_OOM();
2005 goto error;
2006 }
2007
2008 instance_names = bt_value_map_create();
2009 if (!instance_names) {
2010 BT_CLI_LOGE_APPEND_CAUSE_OOM();
2011 goto error;
2012 }
2013
2014 connection_args = bt_value_array_create();
2015 if (!connection_args) {
2016 BT_CLI_LOGE_APPEND_CAUSE_OOM();
2017 goto error;
2018 }
2019
2020 ret = append_env_var_plugin_paths(cfg->plugin_paths);
2021 if (ret) {
2022 goto error;
2023 }
2024
2025 /* Parse options */
2026 argpar_parse_ret = bt_argpar_parse(argc, argv, run_options, true);
2027 if (argpar_parse_ret.error) {
2028 BT_CLI_LOGE_APPEND_CAUSE(
2029 "While parsing `run` command's command-line arguments: %s",
2030 argpar_parse_ret.error->str);
2031 goto error;
2032 }
2033
2034 if (help_option_is_specified(&argpar_parse_ret)) {
2035 print_run_usage(stdout);
2036 *retcode = -1;
2037 BT_OBJECT_PUT_REF_AND_RESET(cfg);
2038 goto end;
2039 }
2040
2041 for (i = 0; i < argpar_parse_ret.items->len; i++) {
2042 struct bt_argpar_item *argpar_item =
2043 g_ptr_array_index(argpar_parse_ret.items, i);
2044 struct bt_argpar_item_opt *argpar_item_opt;
2045 const char *arg;
2046
2047 /* This command does not accept leftover arguments. */
2048 if (argpar_item->type == BT_ARGPAR_ITEM_TYPE_NON_OPT) {
2049 struct bt_argpar_item_non_opt *argpar_nonopt_item =
2050 (struct bt_argpar_item_non_opt *) argpar_item;
2051
2052 BT_CLI_LOGE_APPEND_CAUSE("Unexpected argument: `%s`",
2053 argpar_nonopt_item->arg);
2054 goto error;
2055 }
2056
2057 argpar_item_opt = (struct bt_argpar_item_opt *) argpar_item;
2058 arg = argpar_item_opt->arg;
2059
2060 switch (argpar_item_opt->descr->id) {
2061 case OPT_PLUGIN_PATH:
2062 if (bt_config_append_plugin_paths_check_setuid_setgid(
2063 cfg->plugin_paths, arg)) {
2064 goto error;
2065 }
2066 break;
2067 case OPT_OMIT_SYSTEM_PLUGIN_PATH:
2068 cfg->omit_system_plugin_path = true;
2069 break;
2070 case OPT_OMIT_HOME_PLUGIN_PATH:
2071 cfg->omit_home_plugin_path = true;
2072 break;
2073 case OPT_COMPONENT:
2074 {
2075 enum bt_config_component_dest dest;
2076
2077 BT_OBJECT_PUT_REF_AND_RESET(cur_cfg_comp);
2078 cur_cfg_comp = bt_config_component_from_arg(arg,
2079 default_log_level);
2080 if (!cur_cfg_comp) {
2081 BT_CLI_LOGE_APPEND_CAUSE("Invalid format for --component option's argument:\n %s",
2082 arg);
2083 goto error;
2084 }
2085
2086 switch (cur_cfg_comp->type) {
2087 case BT_COMPONENT_CLASS_TYPE_SOURCE:
2088 dest = BT_CONFIG_COMPONENT_DEST_SOURCE;
2089 break;
2090 case BT_COMPONENT_CLASS_TYPE_FILTER:
2091 dest = BT_CONFIG_COMPONENT_DEST_FILTER;
2092 break;
2093 case BT_COMPONENT_CLASS_TYPE_SINK:
2094 dest = BT_CONFIG_COMPONENT_DEST_SINK;
2095 break;
2096 default:
2097 abort();
2098 }
2099
2100 BT_ASSERT(cur_base_params);
2101 bt_value_put_ref(cur_cfg_comp->params);
2102 if (bt_value_copy(cur_base_params,
2103 &cur_cfg_comp->params) < 0) {
2104 BT_CLI_LOGE_APPEND_CAUSE_OOM();
2105 goto error;
2106 }
2107
2108 ret = add_run_cfg_comp_check_name(cfg,
2109 cur_cfg_comp, dest,
2110 instance_names);
2111 if (ret) {
2112 goto error;
2113 }
2114
2115 break;
2116 }
2117 case OPT_PARAMS:
2118 {
2119 bt_value *params;
2120 bt_value *params_to_set;
2121
2122 if (!cur_cfg_comp) {
2123 BT_CLI_LOGE_APPEND_CAUSE("Cannot add parameters to unavailable component:\n %s",
2124 arg);
2125 goto error;
2126 }
2127
2128 params = cli_value_from_arg(arg, error_str);
2129 if (!params) {
2130 BT_CLI_LOGE_APPEND_CAUSE("Invalid format for --params option's argument:\n %s",
2131 error_str->str);
2132 goto error;
2133 }
2134
2135 extend_status = bt_value_map_extend(
2136 cur_cfg_comp->params, params, &params_to_set);
2137 BT_VALUE_PUT_REF_AND_RESET(params);
2138 if (extend_status != BT_VALUE_MAP_EXTEND_STATUS_OK) {
2139 BT_CLI_LOGE_APPEND_CAUSE("Cannot extend current component parameters with --params option's argument:\n %s",
2140 arg);
2141 goto error;
2142 }
2143
2144 BT_OBJECT_MOVE_REF(cur_cfg_comp->params, params_to_set);
2145 break;
2146 }
2147 case OPT_LOG_LEVEL:
2148 if (!cur_cfg_comp) {
2149 BT_CLI_LOGE_APPEND_CAUSE("Cannot set the log level of unavailable component:\n %s",
2150 arg);
2151 goto error;
2152 }
2153
2154 cur_cfg_comp->log_level =
2155 bt_log_get_level_from_string(arg);
2156 if (cur_cfg_comp->log_level < 0) {
2157 BT_CLI_LOGE_APPEND_CAUSE("Invalid argument for --log-level option:\n %s",
2158 arg);
2159 goto error;
2160 }
2161 break;
2162 case OPT_BASE_PARAMS:
2163 {
2164 bt_value *params = cli_value_from_arg(arg, error_str);
2165
2166 if (!params) {
2167 BT_CLI_LOGE_APPEND_CAUSE("Invalid format for --base-params option's argument:\n %s",
2168 error_str->str);
2169 goto error;
2170 }
2171
2172 BT_OBJECT_MOVE_REF(cur_base_params, params);
2173 break;
2174 }
2175 case OPT_RESET_BASE_PARAMS:
2176 BT_VALUE_PUT_REF_AND_RESET(cur_base_params);
2177 cur_base_params = bt_value_map_create();
2178 if (!cur_base_params) {
2179 BT_CLI_LOGE_APPEND_CAUSE_OOM();
2180 goto error;
2181 }
2182 break;
2183 case OPT_CONNECT:
2184 if (bt_value_array_append_string_element(
2185 connection_args, arg)) {
2186 BT_CLI_LOGE_APPEND_CAUSE_OOM();
2187 goto error;
2188 }
2189 break;
2190 case OPT_RETRY_DURATION: {
2191 gchar *end;
2192 size_t arg_len = strlen(argpar_item_opt->arg);
2193
2194 retry_duration = g_ascii_strtoll(argpar_item_opt->arg, &end, 10);
2195
2196 if (arg_len == 0 || end != (argpar_item_opt->arg + arg_len)) {
2197 BT_CLI_LOGE_APPEND_CAUSE(
2198 "Could not parse --retry-duration option's argument as an unsigned integer: `%s`",
2199 argpar_item_opt->arg);
2200 goto error;
2201 }
2202
2203 if (retry_duration < 0) {
2204 BT_CLI_LOGE_APPEND_CAUSE("--retry-duration option's argument must be positive or 0: %ld",
2205 retry_duration);
2206 goto error;
2207 }
2208
2209 cfg->cmd_data.run.retry_duration_us =
2210 (uint64_t) retry_duration;
2211 break;
2212 }
2213 default:
2214 BT_CLI_LOGE_APPEND_CAUSE("Unknown command-line option specified (option code %d).",
2215 argpar_item_opt->descr->id);
2216 goto error;
2217 }
2218 }
2219
2220 BT_OBJECT_PUT_REF_AND_RESET(cur_cfg_comp);
2221
2222 if (cfg->cmd_data.run.sources->len == 0) {
2223 BT_CLI_LOGE_APPEND_CAUSE("Incomplete graph: no source component.");
2224 goto error;
2225 }
2226
2227 if (cfg->cmd_data.run.sinks->len == 0) {
2228 BT_CLI_LOGE_APPEND_CAUSE("Incomplete graph: no sink component.");
2229 goto error;
2230 }
2231
2232 if (append_home_and_system_plugin_paths_cfg(cfg)) {
2233 goto error;
2234 }
2235
2236 ret = bt_config_cli_args_create_connections(cfg,
2237 connection_args,
2238 error_buf, 256);
2239 if (ret) {
2240 BT_CLI_LOGE_APPEND_CAUSE("Cannot creation connections:\n%s", error_buf);
2241 goto error;
2242 }
2243
2244 goto end;
2245
2246 error:
2247 *retcode = 1;
2248 BT_OBJECT_PUT_REF_AND_RESET(cfg);
2249
2250 end:
2251 if (error_str) {
2252 g_string_free(error_str, TRUE);
2253 }
2254
2255 bt_argpar_parse_ret_fini(&argpar_parse_ret);
2256 BT_OBJECT_PUT_REF_AND_RESET(cur_cfg_comp);
2257 BT_VALUE_PUT_REF_AND_RESET(cur_base_params);
2258 BT_VALUE_PUT_REF_AND_RESET(instance_names);
2259 BT_VALUE_PUT_REF_AND_RESET(connection_args);
2260 return cfg;
2261 }
2262
2263 static
2264 struct bt_config *bt_config_run_from_args_array(const bt_value *run_args,
2265 int *retcode, bool force_omit_system_plugin_path,
2266 bool force_omit_home_plugin_path,
2267 const bt_value *initial_plugin_paths, int default_log_level)
2268 {
2269 struct bt_config *cfg = NULL;
2270 const char **argv;
2271 int64_t i, len;
2272 const size_t argc = bt_value_array_get_size(run_args);
2273
2274 argv = calloc(argc, sizeof(*argv));
2275 if (!argv) {
2276 BT_CLI_LOGE_APPEND_CAUSE_OOM();
2277 goto end;
2278 }
2279
2280 len = bt_value_array_get_size(run_args);
2281 if (len < 0) {
2282 BT_CLI_LOGE_APPEND_CAUSE("Invalid executable arguments.");
2283 goto end;
2284 }
2285 for (i = 0; i < len; i++) {
2286 const bt_value *arg_value =
2287 bt_value_array_borrow_element_by_index_const(run_args,
2288 i);
2289 const char *arg;
2290
2291 BT_ASSERT(arg_value);
2292 arg = bt_value_string_get(arg_value);
2293 BT_ASSERT(arg);
2294 argv[i] = arg;
2295 }
2296
2297 cfg = bt_config_run_from_args(argc, argv, retcode,
2298 force_omit_system_plugin_path, force_omit_home_plugin_path,
2299 initial_plugin_paths, default_log_level);
2300
2301 end:
2302 free(argv);
2303 return cfg;
2304 }
2305
2306 /*
2307 * Prints the convert command usage.
2308 */
2309 static
2310 void print_convert_usage(FILE *fp)
2311 {
2312 fprintf(fp, "Usage: babeltrace2 [GENERAL OPTIONS] [convert] [OPTIONS] [PATH/URL]\n");
2313 fprintf(fp, "\n");
2314 fprintf(fp, "Options:\n");
2315 fprintf(fp, "\n");
2316 fprintf(fp, " -c, --component=[NAME:]TYPE.PLUGIN.CLS\n");
2317 fprintf(fp, " Instantiate the component class CLS of type\n");
2318 fprintf(fp, " TYPE (`source`, `filter`, or `sink`) found\n");
2319 fprintf(fp, " in the plugin PLUGIN, add it to the\n");
2320 fprintf(fp, " conversion graph, and optionally name it\n");
2321 fprintf(fp, " NAME\n");
2322 fprintf(fp, " -l, --log-level=LVL Set the log level of the current component to LVL\n");
2323 fprintf(fp, " (`N`, `V`, `D`, `I`, `W`, `E`, or `F`)\n");
2324 fprintf(fp, " --omit-home-plugin-path Omit home plugins from plugin search path\n");
2325 fprintf(fp, " (~/.local/lib/babeltrace2/plugins)\n");
2326 fprintf(fp, " --omit-system-plugin-path Omit system plugins from plugin search path\n");
2327 fprintf(fp, " -p, --params=PARAMS Add initialization parameters PARAMS to the\n");
2328 fprintf(fp, " current component (see the expected format\n");
2329 fprintf(fp, " of PARAMS below)\n");
2330 fprintf(fp, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n");
2331 fprintf(fp, " dynamic plugins can be loaded\n");
2332 fprintf(fp, " --retry-duration=DUR When babeltrace2(1) needs to retry to run\n");
2333 fprintf(fp, " the graph later, retry in DUR µs\n");
2334 fprintf(fp, " (default: 100000)\n");
2335 fprintf(fp, " dynamic plugins can be loaded\n");
2336 fprintf(fp, " --run-args Print the equivalent arguments for the\n");
2337 fprintf(fp, " `run` command to the standard output,\n");
2338 fprintf(fp, " formatted for a shell, and quit\n");
2339 fprintf(fp, " --run-args-0 Print the equivalent arguments for the\n");
2340 fprintf(fp, " `run` command to the standard output,\n");
2341 fprintf(fp, " formatted for `xargs -0`, and quit\n");
2342 fprintf(fp, " --stream-intersection Only process events when all streams\n");
2343 fprintf(fp, " are active\n");
2344 fprintf(fp, " -h, --help Show this help and quit\n");
2345 fprintf(fp, "\n");
2346 fprintf(fp, "Implicit `source.ctf.fs` component options:\n");
2347 fprintf(fp, "\n");
2348 fprintf(fp, " --clock-offset=SEC Set clock offset to SEC seconds\n");
2349 fprintf(fp, " --clock-offset-ns=NS Set clock offset to NS ns\n");
2350 fprintf(fp, "\n");
2351 fprintf(fp, "Implicit `sink.text.pretty` component options:\n");
2352 fprintf(fp, "\n");
2353 fprintf(fp, " --clock-cycles Print timestamps in clock cycles\n");
2354 fprintf(fp, " --clock-date Print timestamp dates\n");
2355 fprintf(fp, " --clock-gmt Print and parse timestamps in the GMT\n");
2356 fprintf(fp, " time zone instead of the local time zone\n");
2357 fprintf(fp, " --clock-seconds Print the timestamps as `SEC.NS` instead\n");
2358 fprintf(fp, " of `hh:mm:ss.nnnnnnnnn`\n");
2359 fprintf(fp, " --color=(never | auto | always)\n");
2360 fprintf(fp, " Never, automatically, or always emit\n");
2361 fprintf(fp, " console color codes\n");
2362 fprintf(fp, " -f, --fields=FIELD[,FIELD]... Print additional fields; FIELD can be:\n");
2363 fprintf(fp, " `all`, `trace`, `trace:hostname`,\n");
2364 fprintf(fp, " `trace:domain`, `trace:procname`,\n");
2365 fprintf(fp, " `trace:vpid`, `loglevel`, `emf`\n");
2366 fprintf(fp, " -n, --names=NAME[,NAME]... Print field names; NAME can be:\n");
2367 fprintf(fp, " `payload` (or `arg` or `args`), `none`,\n");
2368 fprintf(fp, " `all`, `scope`, `header`, `context`\n");
2369 fprintf(fp, " (or `ctx`)\n");
2370 fprintf(fp, " --no-delta Do not print time delta between\n");
2371 fprintf(fp, " consecutive events\n");
2372 fprintf(fp, " -w, --output=PATH Write output text to PATH instead of\n");
2373 fprintf(fp, " the standard output\n");
2374 fprintf(fp, "\n");
2375 fprintf(fp, "Implicit `filter.utils.muxer` component options:\n");
2376 fprintf(fp, "\n");
2377 fprintf(fp, " --clock-force-correlate Assume that clocks are inherently\n");
2378 fprintf(fp, " correlated across traces\n");
2379 fprintf(fp, "\n");
2380 fprintf(fp, "Implicit `filter.utils.trimmer` component options:\n");
2381 fprintf(fp, "\n");
2382 fprintf(fp, " -b, --begin=BEGIN Set the beginning time of the conversion\n");
2383 fprintf(fp, " time range to BEGIN (see the format of\n");
2384 fprintf(fp, " BEGIN below)\n");
2385 fprintf(fp, " -e, --end=END Set the end time of the conversion time\n");
2386 fprintf(fp, " range to END (see the format of END below)\n");
2387 fprintf(fp, " -t, --timerange=TIMERANGE Set conversion time range to TIMERANGE:\n");
2388 fprintf(fp, " BEGIN,END or [BEGIN,END] (literally `[` and\n");
2389 fprintf(fp, " `]`) (see the format of BEGIN/END below)\n");
2390 fprintf(fp, "\n");
2391 fprintf(fp, "Implicit `filter.lttng-utils.debug-info` component options:\n");
2392 fprintf(fp, "\n");
2393 fprintf(fp, " --debug-info Create an implicit\n");
2394 fprintf(fp, " `filter.lttng-utils.debug-info` component\n");
2395 fprintf(fp, " --debug-info-dir=DIR Search for debug info in directory DIR\n");
2396 fprintf(fp, " instead of `/usr/lib/debug`\n");
2397 fprintf(fp, " --debug-info-full-path Show full debug info source and\n");
2398 fprintf(fp, " binary paths instead of just names\n");
2399 fprintf(fp, " --debug-info-target-prefix=DIR\n");
2400 fprintf(fp, " Use directory DIR as a prefix when\n");
2401 fprintf(fp, " looking up executables during debug\n");
2402 fprintf(fp, " info analysis\n");
2403 fprintf(fp, "\n");
2404 fprintf(fp, "Legacy options that still work:\n");
2405 fprintf(fp, "\n");
2406 fprintf(fp, " -i, --input-format=(ctf | lttng-live)\n");
2407 fprintf(fp, " `ctf`:\n");
2408 fprintf(fp, " Create an implicit `source.ctf.fs`\n");
2409 fprintf(fp, " component\n");
2410 fprintf(fp, " `lttng-live`:\n");
2411 fprintf(fp, " Create an implicit `source.ctf.lttng-live`\n");
2412 fprintf(fp, " component\n");
2413 fprintf(fp, " -o, --output-format=(text | ctf | dummy | ctf-metadata)\n");
2414 fprintf(fp, " `text`:\n");
2415 fprintf(fp, " Create an implicit `sink.text.pretty`\n");
2416 fprintf(fp, " component\n");
2417 fprintf(fp, " `ctf`:\n");
2418 fprintf(fp, " Create an implicit `sink.ctf.fs`\n");
2419 fprintf(fp, " component\n");
2420 fprintf(fp, " `dummy`:\n");
2421 fprintf(fp, " Create an implicit `sink.utils.dummy`\n");
2422 fprintf(fp, " component\n");
2423 fprintf(fp, " `ctf-metadata`:\n");
2424 fprintf(fp, " Query the `source.ctf.fs` component class\n");
2425 fprintf(fp, " for metadata text and quit\n");
2426 fprintf(fp, "\n");
2427 fprintf(fp, "See `babeltrace2 --help` for the list of general options.\n");
2428 fprintf(fp, "\n\n");
2429 fprintf(fp, "Format of BEGIN and END\n");
2430 fprintf(fp, "-----------------------\n");
2431 fprintf(fp, "\n");
2432 fprintf(fp, " [YYYY-MM-DD [hh:mm:]]ss[.nnnnnnnnn]\n");
2433 fprintf(fp, "\n\n");
2434 print_expected_params_format(fp);
2435 }
2436
2437 static
2438 const struct bt_argpar_opt_descr convert_options[] = {
2439 /* id, short_name, long_name, with_arg */
2440 { OPT_BEGIN, 'b', "begin", true },
2441 { OPT_CLOCK_CYCLES, '\0', "clock-cycles", false },
2442 { OPT_CLOCK_DATE, '\0', "clock-date", false },
2443 { OPT_CLOCK_FORCE_CORRELATE, '\0', "clock-force-correlate", false },
2444 { OPT_CLOCK_GMT, '\0', "clock-gmt", false },
2445 { OPT_CLOCK_OFFSET, '\0', "clock-offset", true },
2446 { OPT_CLOCK_OFFSET_NS, '\0', "clock-offset-ns", true },
2447 { OPT_CLOCK_SECONDS, '\0', "clock-seconds", false },
2448 { OPT_COLOR, '\0', "color", true },
2449 { OPT_COMPONENT, 'c', "component", true },
2450 { OPT_DEBUG, 'd', "debug", false },
2451 { OPT_DEBUG_INFO_DIR, '\0', "debug-info-dir", true },
2452 { OPT_DEBUG_INFO_FULL_PATH, '\0', "debug-info-full-path", false },
2453 { OPT_DEBUG_INFO_TARGET_PREFIX, '\0', "debug-info-target-prefix", true },
2454 { OPT_END, 'e', "end", true },
2455 { OPT_FIELDS, 'f', "fields", true },
2456 { OPT_HELP, 'h', "help", false },
2457 { OPT_INPUT_FORMAT, 'i', "input-format", true },
2458 { OPT_LOG_LEVEL, 'l', "log-level", true },
2459 { OPT_NAMES, 'n', "names", true },
2460 { OPT_DEBUG_INFO, '\0', "debug-info", false },
2461 { OPT_NO_DELTA, '\0', "no-delta", false },
2462 { OPT_OMIT_HOME_PLUGIN_PATH, '\0', "omit-home-plugin-path", false },
2463 { OPT_OMIT_SYSTEM_PLUGIN_PATH, '\0', "omit-system-plugin-path", false },
2464 { OPT_OUTPUT, 'w', "output", true },
2465 { OPT_OUTPUT_FORMAT, 'o', "output-format", true },
2466 { OPT_PARAMS, 'p', "params", true },
2467 { OPT_PLUGIN_PATH, '\0', "plugin-path", true },
2468 { OPT_RETRY_DURATION, '\0', "retry-duration", true },
2469 { OPT_RUN_ARGS, '\0', "run-args", false },
2470 { OPT_RUN_ARGS_0, '\0', "run-args-0", false },
2471 { OPT_STREAM_INTERSECTION, '\0', "stream-intersection", false },
2472 { OPT_TIMERANGE, '\0', "timerange", true },
2473 { OPT_VERBOSE, 'v', "verbose", false },
2474 BT_ARGPAR_OPT_DESCR_SENTINEL
2475 };
2476
2477 static
2478 GString *get_component_auto_name(const char *prefix,
2479 const bt_value *existing_names)
2480 {
2481 unsigned int i = 0;
2482 GString *auto_name = g_string_new(NULL);
2483
2484 if (!auto_name) {
2485 BT_CLI_LOGE_APPEND_CAUSE_OOM();
2486 goto end;
2487 }
2488
2489 if (!bt_value_map_has_entry(existing_names, prefix)) {
2490 g_string_assign(auto_name, prefix);
2491 goto end;
2492 }
2493
2494 do {
2495 g_string_printf(auto_name, "%s-%d", prefix, i);
2496 i++;
2497 } while (bt_value_map_has_entry(existing_names, auto_name->str));
2498
2499 end:
2500 return auto_name;
2501 }
2502
2503 struct implicit_component_args {
2504 bool exists;
2505
2506 /* The component class name (e.g. src.ctf.fs). */
2507 GString *comp_arg;
2508
2509 /* The component instance name. */
2510 GString *name_arg;
2511
2512 GString *params_arg;
2513 bt_value *extra_params;
2514 };
2515
2516 static
2517 int assign_name_to_implicit_component(struct implicit_component_args *args,
2518 const char *prefix, bt_value *existing_names,
2519 GList **comp_names, bool append_to_comp_names)
2520 {
2521 int ret = 0;
2522 GString *name = NULL;
2523
2524 if (!args->exists) {
2525 goto end;
2526 }
2527
2528 name = get_component_auto_name(prefix,
2529 existing_names);
2530
2531 if (!name) {
2532 ret = -1;
2533 goto end;
2534 }
2535
2536 g_string_assign(args->name_arg, name->str);
2537
2538 if (bt_value_map_insert_entry(existing_names, name->str,
2539 bt_value_null)) {
2540 BT_CLI_LOGE_APPEND_CAUSE_OOM();
2541 ret = -1;
2542 goto end;
2543 }
2544
2545 if (append_to_comp_names) {
2546 *comp_names = g_list_append(*comp_names, name);
2547 name = NULL;
2548 }
2549
2550 end:
2551 if (name) {
2552 g_string_free(name, TRUE);
2553 }
2554
2555 return ret;
2556 }
2557
2558 static
2559 int append_run_args_for_implicit_component(
2560 struct implicit_component_args *impl_args,
2561 bt_value *run_args)
2562 {
2563 int ret = 0;
2564 size_t i;
2565 GString *component_arg_for_run = NULL;
2566
2567 if (!impl_args->exists) {
2568 goto end;
2569 }
2570
2571 component_arg_for_run = g_string_new(NULL);
2572 if (!component_arg_for_run) {
2573 BT_CLI_LOGE_APPEND_CAUSE_OOM();
2574 goto error;
2575 }
2576
2577 /* Build the full `name:type.plugin.cls`. */
2578 BT_ASSERT(!strchr(impl_args->name_arg->str, '\\'));
2579 BT_ASSERT(!strchr(impl_args->name_arg->str, ':'));
2580 g_string_printf(component_arg_for_run, "%s:%s",
2581 impl_args->name_arg->str, impl_args->comp_arg->str);
2582
2583 if (bt_value_array_append_string_element(run_args, "--component")) {
2584 BT_CLI_LOGE_APPEND_CAUSE_OOM();
2585 goto error;
2586 }
2587
2588 if (bt_value_array_append_string_element(run_args,
2589 component_arg_for_run->str)) {
2590 BT_CLI_LOGE_APPEND_CAUSE_OOM();
2591 goto error;
2592 }
2593
2594 if (impl_args->params_arg->len > 0) {
2595 if (bt_value_array_append_string_element(run_args, "--params")) {
2596 BT_CLI_LOGE_APPEND_CAUSE_OOM();
2597 goto error;
2598 }
2599
2600 if (bt_value_array_append_string_element(run_args,
2601 impl_args->params_arg->str)) {
2602 BT_CLI_LOGE_APPEND_CAUSE_OOM();
2603 goto error;
2604 }
2605 }
2606
2607 for (i = 0; i < bt_value_array_get_size(impl_args->extra_params);
2608 i++) {
2609 const bt_value *elem;
2610 const char *arg;
2611
2612 elem = bt_value_array_borrow_element_by_index(impl_args->extra_params,
2613 i);
2614 if (!elem) {
2615 goto error;
2616 }
2617
2618 BT_ASSERT(bt_value_is_string(elem));
2619 arg = bt_value_string_get(elem);
2620 ret = bt_value_array_append_string_element(run_args, arg);
2621 if (ret) {
2622 BT_CLI_LOGE_APPEND_CAUSE_OOM();
2623 goto error;
2624 }
2625 }
2626
2627 goto end;
2628
2629 error:
2630 ret = -1;
2631
2632 end:
2633 if (component_arg_for_run) {
2634 g_string_free(component_arg_for_run, TRUE);
2635 }
2636
2637 return ret;
2638 }
2639
2640 /* Free the fields of a `struct implicit_component_args`. */
2641
2642 static
2643 void finalize_implicit_component_args(struct implicit_component_args *args)
2644 {
2645 BT_ASSERT(args);
2646
2647 if (args->comp_arg) {
2648 g_string_free(args->comp_arg, TRUE);
2649 }
2650
2651 if (args->name_arg) {
2652 g_string_free(args->name_arg, TRUE);
2653 }
2654
2655 if (args->params_arg) {
2656 g_string_free(args->params_arg, TRUE);
2657 }
2658
2659 bt_value_put_ref(args->extra_params);
2660 }
2661
2662 /* Destroy a dynamically-allocated `struct implicit_component_args`. */
2663
2664 static
2665 void destroy_implicit_component_args(struct implicit_component_args *args)
2666 {
2667 finalize_implicit_component_args(args);
2668 g_free(args);
2669 }
2670
2671 /* Initialize the fields of an already allocated `struct implicit_component_args`. */
2672
2673 static
2674 int init_implicit_component_args(struct implicit_component_args *args,
2675 const char *comp_arg, bool exists)
2676 {
2677 int ret = 0;
2678
2679 args->exists = exists;
2680 args->comp_arg = g_string_new(comp_arg);
2681 args->name_arg = g_string_new(NULL);
2682 args->params_arg = g_string_new(NULL);
2683 args->extra_params = bt_value_array_create();
2684
2685 if (!args->comp_arg || !args->name_arg ||
2686 !args->params_arg || !args->extra_params) {
2687 ret = -1;
2688 finalize_implicit_component_args(args);
2689 BT_CLI_LOGE_APPEND_CAUSE_OOM();
2690 goto end;
2691 }
2692
2693 end:
2694 return ret;
2695 }
2696
2697 /* Dynamically allocate and initialize a `struct implicit_component_args`. */
2698
2699 static
2700 struct implicit_component_args *create_implicit_component_args(
2701 const char *comp_arg)
2702 {
2703 struct implicit_component_args *args;
2704 int status;
2705
2706 args = g_new(struct implicit_component_args, 1);
2707 if (!args) {
2708 BT_CLI_LOGE_APPEND_CAUSE_OOM();
2709 goto end;
2710 }
2711
2712 status = init_implicit_component_args(args, comp_arg, true);
2713 if (status != 0) {
2714 g_free(args);
2715 args = NULL;
2716 }
2717
2718 end:
2719 return args;
2720 }
2721
2722 static
2723 void append_implicit_component_param(struct implicit_component_args *args,
2724 const char *key, const char *value)
2725 {
2726 BT_ASSERT(args);
2727 BT_ASSERT(key);
2728 BT_ASSERT(value);
2729 append_param_arg(args->params_arg, key, value);
2730 }
2731
2732 /*
2733 * Append the given parameter (`key=value`) to all component specifications
2734 * in `implicit_comp_args` (an array of `struct implicit_component_args *`)
2735 * which match `comp_arg`.
2736 *
2737 * Return the number of matching components.
2738 */
2739
2740 static
2741 int append_multiple_implicit_components_param(GPtrArray *implicit_comp_args,
2742 const char *comp_arg, const char *key, const char *value)
2743 {
2744 int i;
2745 int n = 0;
2746
2747 for (i = 0; i < implicit_comp_args->len; i++) {
2748 struct implicit_component_args *args = implicit_comp_args->pdata[i];
2749
2750 if (strcmp(args->comp_arg->str, comp_arg) == 0) {
2751 append_implicit_component_param(args, key, value);
2752 n++;
2753 }
2754 }
2755
2756 return n;
2757 }
2758
2759 /* Escape value to make it suitable to use as a string parameter value. */
2760 static
2761 gchar *escape_string_value(const char *value)
2762 {
2763 GString *ret;
2764 const char *in;
2765
2766 ret = g_string_new(NULL);
2767 if (!ret) {
2768 BT_CLI_LOGE_APPEND_CAUSE_OOM();
2769 goto end;
2770 }
2771
2772 in = value;
2773 while (*in) {
2774 switch (*in) {
2775 case '"':
2776 case '\\':
2777 g_string_append_c(ret, '\\');
2778 break;
2779 }
2780
2781 g_string_append_c(ret, *in);
2782
2783 in++;
2784 }
2785
2786 end:
2787 return g_string_free(ret, FALSE);
2788 }
2789
2790 static
2791 int bt_value_to_cli_param_value_append(const bt_value *value, GString *buf)
2792 {
2793 BT_ASSERT(buf);
2794
2795 int ret = -1;
2796
2797 switch (bt_value_get_type(value)) {
2798 case BT_VALUE_TYPE_STRING:
2799 {
2800 const char *str_value = bt_value_string_get(value);
2801 gchar *escaped_str_value;
2802
2803 escaped_str_value = escape_string_value(str_value);
2804 if (!escaped_str_value) {
2805 goto end;
2806 }
2807
2808 g_string_append_printf(buf, "\"%s\"", escaped_str_value);
2809
2810 g_free(escaped_str_value);
2811 break;
2812 }
2813 case BT_VALUE_TYPE_ARRAY: {
2814 g_string_append_c(buf, '[');
2815 uint64_t sz = bt_value_array_get_size(value);
2816 for (uint64_t i = 0; i < sz; i++) {
2817 const bt_value *item;
2818 int ret;
2819
2820 if (i > 0) {
2821 g_string_append(buf, ", ");
2822 }
2823
2824 item = bt_value_array_borrow_element_by_index_const(
2825 value, i);
2826 ret = bt_value_to_cli_param_value_append(item, buf);
2827
2828 if (ret) {
2829 goto end;
2830 }
2831 }
2832 g_string_append_c(buf, ']');
2833 break;
2834 }
2835 default:
2836 abort();
2837 }
2838
2839 ret = 0;
2840
2841 end:
2842 return ret;
2843 }
2844
2845 /*
2846 * Convert `value` to its equivalent representation as a command line parameter
2847 * value.
2848 */
2849
2850 static
2851 gchar *bt_value_to_cli_param_value(bt_value *value)
2852 {
2853 GString *buf;
2854 gchar *result = NULL;
2855
2856 buf = g_string_new(NULL);
2857 if (!buf) {
2858 BT_CLI_LOGE_APPEND_CAUSE_OOM();
2859 goto error;
2860 }
2861
2862 if (bt_value_to_cli_param_value_append(value, buf)) {
2863 goto error;
2864 }
2865
2866 result = g_string_free(buf, FALSE);
2867 buf = NULL;
2868
2869 goto end;
2870
2871 error:
2872 if (buf) {
2873 g_string_free(buf, TRUE);
2874 }
2875
2876 end:
2877 return result;
2878 }
2879
2880 static
2881 int append_parameter_to_args(bt_value *args, const char *key, bt_value *value)
2882 {
2883 BT_ASSERT(args);
2884 BT_ASSERT(bt_value_get_type(args) == BT_VALUE_TYPE_ARRAY);
2885 BT_ASSERT(key);
2886 BT_ASSERT(value);
2887
2888 int ret = 0;
2889 gchar *str_value = NULL;
2890 GString *parameter = NULL;
2891
2892 if (bt_value_array_append_string_element(args, "--params")) {
2893 BT_CLI_LOGE_APPEND_CAUSE_OOM();
2894 ret = -1;
2895 goto end;
2896 }
2897
2898 str_value = bt_value_to_cli_param_value(value);
2899 if (!str_value) {
2900 ret = -1;
2901 goto end;
2902 }
2903
2904 parameter = g_string_new(NULL);
2905 if (!parameter) {
2906 BT_CLI_LOGE_APPEND_CAUSE_OOM();
2907 ret = -1;
2908 goto end;
2909 }
2910
2911 g_string_printf(parameter, "%s=%s", key, str_value);
2912
2913 if (bt_value_array_append_string_element(args, parameter->str)) {
2914 BT_CLI_LOGE_APPEND_CAUSE_OOM();
2915 ret = -1;
2916 goto end;
2917 }
2918
2919 end:
2920 if (parameter) {
2921 g_string_free(parameter, TRUE);
2922 parameter = NULL;
2923 }
2924
2925 if (str_value) {
2926 g_free(str_value);
2927 str_value = NULL;
2928 }
2929
2930 return ret;
2931 }
2932
2933 static
2934 int append_string_parameter_to_args(bt_value *args, const char *key, const char *value)
2935 {
2936 bt_value *str_value;
2937 int ret;
2938
2939 str_value = bt_value_string_create_init(value);
2940
2941 if (!str_value) {
2942 BT_CLI_LOGE_APPEND_CAUSE_OOM();
2943 ret = -1;
2944 goto end;
2945 }
2946
2947 ret = append_parameter_to_args(args, key, str_value);
2948
2949 end:
2950 BT_VALUE_PUT_REF_AND_RESET(str_value);
2951 return ret;
2952 }
2953
2954 static
2955 int append_implicit_component_extra_param(struct implicit_component_args *args,
2956 const char *key, const char *value)
2957 {
2958 return append_string_parameter_to_args(args->extra_params, key, value);
2959 }
2960
2961 /*
2962 * Escapes `.`, `:`, and `\` of `input` with `\`.
2963 */
2964 static
2965 GString *escape_dot_colon(const char *input)
2966 {
2967 GString *output = g_string_new(NULL);
2968 const char *ch;
2969
2970 if (!output) {
2971 BT_CLI_LOGE_APPEND_CAUSE_OOM();
2972 goto end;
2973 }
2974
2975 for (ch = input; *ch != '\0'; ch++) {
2976 if (*ch == '\\' || *ch == '.' || *ch == ':') {
2977 g_string_append_c(output, '\\');
2978 }
2979
2980 g_string_append_c(output, *ch);
2981 }
2982
2983 end:
2984 return output;
2985 }
2986
2987 /*
2988 * Appends a --connect option to a list of arguments. `upstream_name`
2989 * and `downstream_name` are escaped with escape_dot_colon() in this
2990 * function.
2991 */
2992 static
2993 int append_connect_arg(bt_value *run_args,
2994 const char *upstream_name, const char *downstream_name)
2995 {
2996 int ret = 0;
2997 GString *e_upstream_name = escape_dot_colon(upstream_name);
2998 GString *e_downstream_name = escape_dot_colon(downstream_name);
2999 GString *arg = g_string_new(NULL);
3000
3001 if (!e_upstream_name || !e_downstream_name || !arg) {
3002 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3003 ret = -1;
3004 goto end;
3005 }
3006
3007 ret = bt_value_array_append_string_element(run_args, "--connect");
3008 if (ret) {
3009 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3010 ret = -1;
3011 goto end;
3012 }
3013
3014 g_string_append(arg, e_upstream_name->str);
3015 g_string_append_c(arg, ':');
3016 g_string_append(arg, e_downstream_name->str);
3017 ret = bt_value_array_append_string_element(run_args, arg->str);
3018 if (ret) {
3019 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3020 ret = -1;
3021 goto end;
3022 }
3023
3024 end:
3025 if (arg) {
3026 g_string_free(arg, TRUE);
3027 }
3028
3029 if (e_upstream_name) {
3030 g_string_free(e_upstream_name, TRUE);
3031 }
3032
3033 if (e_downstream_name) {
3034 g_string_free(e_downstream_name, TRUE);
3035 }
3036
3037 return ret;
3038 }
3039
3040 /*
3041 * Appends the run command's --connect options for the convert command.
3042 */
3043 static
3044 int convert_auto_connect(bt_value *run_args,
3045 GList *source_names, GList *filter_names,
3046 GList *sink_names)
3047 {
3048 int ret = 0;
3049 GList *source_at = source_names;
3050 GList *filter_at = filter_names;
3051 GList *filter_prev;
3052 GList *sink_at = sink_names;
3053
3054 BT_ASSERT(source_names);
3055 BT_ASSERT(filter_names);
3056 BT_ASSERT(sink_names);
3057
3058 /* Connect all sources to the first filter */
3059 for (source_at = source_names; source_at; source_at = g_list_next(source_at)) {
3060 GString *source_name = source_at->data;
3061 GString *filter_name = filter_at->data;
3062
3063 ret = append_connect_arg(run_args, source_name->str,
3064 filter_name->str);
3065 if (ret) {
3066 goto error;
3067 }
3068 }
3069
3070 filter_prev = filter_at;
3071 filter_at = g_list_next(filter_at);
3072
3073 /* Connect remaining filters */
3074 for (; filter_at; filter_prev = filter_at, filter_at = g_list_next(filter_at)) {
3075 GString *filter_name = filter_at->data;
3076 GString *filter_prev_name = filter_prev->data;
3077
3078 ret = append_connect_arg(run_args, filter_prev_name->str,
3079 filter_name->str);
3080 if (ret) {
3081 goto error;
3082 }
3083 }
3084
3085 /* Connect last filter to all sinks */
3086 for (sink_at = sink_names; sink_at; sink_at = g_list_next(sink_at)) {
3087 GString *filter_name = filter_prev->data;
3088 GString *sink_name = sink_at->data;
3089
3090 ret = append_connect_arg(run_args, filter_name->str,
3091 sink_name->str);
3092 if (ret) {
3093 goto error;
3094 }
3095 }
3096
3097 goto end;
3098
3099 error:
3100 ret = -1;
3101
3102 end:
3103 return ret;
3104 }
3105
3106 static
3107 int split_timerange(const char *arg, char **begin, char **end)
3108 {
3109 int ret = 0;
3110 const char *ch = arg;
3111 size_t end_pos;
3112 GString *g_begin = NULL;
3113 GString *g_end = NULL;
3114
3115 BT_ASSERT(arg);
3116
3117 if (*ch == '[') {
3118 ch++;
3119 }
3120
3121 g_begin = bt_common_string_until(ch, "", ",", &end_pos);
3122 if (!g_begin || ch[end_pos] != ',' || g_begin->len == 0) {
3123 goto error;
3124 }
3125
3126 ch += end_pos + 1;
3127
3128 g_end = bt_common_string_until(ch, "", "]", &end_pos);
3129 if (!g_end || g_end->len == 0) {
3130 goto error;
3131 }
3132
3133 BT_ASSERT(begin);
3134 BT_ASSERT(end);
3135 *begin = g_begin->str;
3136 *end = g_end->str;
3137 g_string_free(g_begin, FALSE);
3138 g_string_free(g_end, FALSE);
3139 g_begin = NULL;
3140 g_end = NULL;
3141 goto end;
3142
3143 error:
3144 ret = -1;
3145
3146 end:
3147 if (g_begin) {
3148 g_string_free(g_begin, TRUE);
3149 }
3150
3151 if (g_end) {
3152 g_string_free(g_end, TRUE);
3153 }
3154
3155 return ret;
3156 }
3157
3158 static
3159 int g_list_prepend_gstring(GList **list, const char *string)
3160 {
3161 int ret = 0;
3162 GString *gs = g_string_new(string);
3163
3164 BT_ASSERT(list);
3165
3166 if (!gs) {
3167 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3168 goto end;
3169 }
3170
3171 *list = g_list_prepend(*list, gs);
3172
3173 end:
3174 return ret;
3175 }
3176
3177 /*
3178 * Create `struct implicit_component_args` structures for each of the source
3179 * components we identified. Add them to `component_args`.
3180 *
3181 * `leftover_params` is an array where each element is an array of strings
3182 * containing all the arguments to `--params` that apply to the leftover at the
3183 * same index. For example, if, for a leftover, the following `--params`
3184 * options applied:
3185 *
3186 * --params=a=2 --params=b=3,c=4
3187 *
3188 * its entry in `leftover_params` would contain
3189 *
3190 * ["a=2", "b=3,c=4"]
3191 */
3192
3193 static
3194 int create_implicit_component_args_from_auto_discovered_sources(
3195 const struct auto_source_discovery *auto_disc,
3196 const bt_value *leftover_params,
3197 GPtrArray *component_args)
3198 {
3199 gchar *cc_name = NULL;
3200 struct implicit_component_args *comp = NULL;
3201 int status;
3202 guint i, len;
3203
3204 len = auto_disc->results->len;
3205
3206 for (i = 0; i < len; i++) {
3207 struct auto_source_discovery_result *res =
3208 g_ptr_array_index(auto_disc->results, i);
3209 uint64_t orig_indices_i, orig_indices_count;
3210
3211 g_free(cc_name);
3212 cc_name = g_strdup_printf("source.%s.%s", res->plugin_name, res->source_cc_name);
3213 if (!cc_name) {
3214 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3215 goto error;
3216 }
3217
3218 comp = create_implicit_component_args(cc_name);
3219 if (!comp) {
3220 goto error;
3221 }
3222
3223 /*
3224 * Append parameters of all the leftovers that contributed to
3225 * this component instance coming into existence.
3226 */
3227 orig_indices_count = bt_value_array_get_size(res->original_input_indices);
3228 for (orig_indices_i = 0; orig_indices_i < orig_indices_count; orig_indices_i++) {
3229 const bt_value *orig_idx_value =
3230 bt_value_array_borrow_element_by_index(
3231 res->original_input_indices, orig_indices_i);
3232 uint64_t orig_idx = bt_value_integer_unsigned_get(orig_idx_value);
3233 const bt_value *params_array =
3234 bt_value_array_borrow_element_by_index_const(
3235 leftover_params, orig_idx);
3236 uint64_t params_i, params_count;
3237
3238 params_count = bt_value_array_get_size(params_array);
3239 for (params_i = 0; params_i < params_count; params_i++) {
3240 const bt_value *params_value =
3241 bt_value_array_borrow_element_by_index_const(
3242 params_array, params_i);
3243 const char *params = bt_value_string_get(params_value);
3244 bt_value_array_append_element_status append_status;
3245
3246 append_status = bt_value_array_append_string_element(
3247 comp->extra_params, "--params");
3248 if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) {
3249 BT_CLI_LOGE_APPEND_CAUSE("Failed to append array element.");
3250 goto error;
3251 }
3252
3253 append_status = bt_value_array_append_string_element(
3254 comp->extra_params, params);
3255 if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) {
3256 BT_CLI_LOGE_APPEND_CAUSE("Failed to append array element.");
3257 goto error;
3258 }
3259 }
3260 }
3261
3262 status = append_parameter_to_args(comp->extra_params, "inputs", res->inputs);
3263 if (status != 0) {
3264 goto error;
3265 }
3266
3267 g_ptr_array_add(component_args, comp);
3268 comp = NULL;
3269 }
3270
3271 status = 0;
3272 goto end;
3273
3274 error:
3275 status = -1;
3276
3277 end:
3278 g_free(cc_name);
3279
3280 if (comp) {
3281 destroy_implicit_component_args(comp);
3282 }
3283
3284 return status;
3285 }
3286
3287 /*
3288 * As we iterate the arguments to the convert command, this tracks what is the
3289 * type of the current item, to which some contextual options (e.g. --params)
3290 * apply to.
3291 */
3292 enum convert_current_item_type {
3293 /* There is no current item. */
3294 CONVERT_CURRENT_ITEM_TYPE_NONE,
3295
3296 /* Current item is a component. */
3297 CONVERT_CURRENT_ITEM_TYPE_COMPONENT,
3298
3299 /* Current item is a leftover. */
3300 CONVERT_CURRENT_ITEM_TYPE_LEFTOVER,
3301 };
3302
3303 /*
3304 * Creates a Babeltrace config object from the arguments of a convert
3305 * command.
3306 *
3307 * *retcode is set to the appropriate exit code to use.
3308 */
3309 static
3310 struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
3311 int *retcode, bool force_omit_system_plugin_path,
3312 bool force_omit_home_plugin_path,
3313 const bt_value *initial_plugin_paths, int *default_log_level)
3314 {
3315 enum convert_current_item_type current_item_type =
3316 CONVERT_CURRENT_ITEM_TYPE_NONE;
3317 int ret = 0;
3318 struct bt_config *cfg = NULL;
3319 bool got_input_format_opt = false;
3320 bool got_output_format_opt = false;
3321 bool trimmer_has_begin = false;
3322 bool trimmer_has_end = false;
3323 bool stream_intersection_mode = false;
3324 bool print_run_args = false;
3325 bool print_run_args_0 = false;
3326 bool print_ctf_metadata = false;
3327 bt_value *run_args = NULL;
3328 bt_value *all_names = NULL;
3329 GList *source_names = NULL;
3330 GList *filter_names = NULL;
3331 GList *sink_names = NULL;
3332 bt_value *leftovers = NULL;
3333 bt_value *leftover_params = NULL;
3334 struct implicit_component_args implicit_ctf_output_args = { 0 };
3335 struct implicit_component_args implicit_lttng_live_args = { 0 };
3336 struct implicit_component_args implicit_dummy_args = { 0 };
3337 struct implicit_component_args implicit_text_args = { 0 };
3338 struct implicit_component_args implicit_debug_info_args = { 0 };
3339 struct implicit_component_args implicit_muxer_args = { 0 };
3340 struct implicit_component_args implicit_trimmer_args = { 0 };
3341 bt_value *plugin_paths;
3342 char error_buf[256] = { 0 };
3343 size_t i;
3344 struct bt_common_lttng_live_url_parts lttng_live_url_parts = { 0 };
3345 char *output = NULL;
3346 struct auto_source_discovery auto_disc = { NULL };
3347 GString *auto_disc_comp_name = NULL;
3348 struct bt_argpar_parse_ret argpar_parse_ret = { 0 };
3349 GString *name_gstr = NULL;
3350 GString *component_arg_for_run = NULL;
3351
3352 /*
3353 * Array of `struct implicit_component_args *` created for the sources
3354 * we have auto-discovered.
3355 */
3356 GPtrArray *discovered_source_args = NULL;
3357
3358 /*
3359 * If set, restrict automatic source discovery to this component class
3360 * of this plugin.
3361 */
3362 const char *auto_source_discovery_restrict_plugin_name = NULL;
3363 const char *auto_source_discovery_restrict_component_class_name = NULL;
3364
3365 gchar *ctf_fs_source_clock_class_offset_arg = NULL;
3366 gchar *ctf_fs_source_clock_class_offset_ns_arg = NULL;
3367
3368 (void) bt_value_copy(initial_plugin_paths, &plugin_paths);
3369
3370 *retcode = 0;
3371
3372 if (argc < 1) {
3373 print_convert_usage(stdout);
3374 *retcode = -1;
3375 goto end;
3376 }
3377
3378 if (init_implicit_component_args(&implicit_ctf_output_args,
3379 "sink.ctf.fs", false)) {
3380 goto error;
3381 }
3382
3383 if (init_implicit_component_args(&implicit_lttng_live_args,
3384 "source.ctf.lttng-live", false)) {
3385 goto error;
3386 }
3387
3388 if (init_implicit_component_args(&implicit_text_args,
3389 "sink.text.pretty", false)) {
3390 goto error;
3391 }
3392
3393 if (init_implicit_component_args(&implicit_dummy_args,
3394 "sink.utils.dummy", false)) {
3395 goto error;
3396 }
3397
3398 if (init_implicit_component_args(&implicit_debug_info_args,
3399 "filter.lttng-utils.debug-info", false)) {
3400 goto error;
3401 }
3402
3403 if (init_implicit_component_args(&implicit_muxer_args,
3404 "filter.utils.muxer", true)) {
3405 goto error;
3406 }
3407
3408 if (init_implicit_component_args(&implicit_trimmer_args,
3409 "filter.utils.trimmer", false)) {
3410 goto error;
3411 }
3412
3413 all_names = bt_value_map_create();
3414 if (!all_names) {
3415 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3416 goto error;
3417 }
3418
3419 run_args = bt_value_array_create();
3420 if (!run_args) {
3421 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3422 goto error;
3423 }
3424
3425 component_arg_for_run = g_string_new(NULL);
3426 if (!component_arg_for_run) {
3427 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3428 goto error;
3429 }
3430
3431 ret = append_env_var_plugin_paths(plugin_paths);
3432 if (ret) {
3433 goto error;
3434 }
3435
3436 leftovers = bt_value_array_create();
3437 if (!leftovers) {
3438 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3439 goto error;
3440 }
3441
3442 leftover_params = bt_value_array_create();
3443 if (!leftover_params) {
3444 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3445 goto error;
3446 }
3447
3448 if (auto_source_discovery_init(&auto_disc) != 0) {
3449 goto error;
3450 }
3451
3452 discovered_source_args =
3453 g_ptr_array_new_with_free_func((GDestroyNotify) destroy_implicit_component_args);
3454 if (!discovered_source_args) {
3455 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3456 goto error;
3457 }
3458
3459 auto_disc_comp_name = g_string_new(NULL);
3460 if (!auto_disc_comp_name) {
3461 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3462 goto error;
3463 }
3464
3465 /*
3466 * First pass: collect all arguments which need to be passed
3467 * as is to the run command. This pass can also add --name
3468 * arguments if needed to automatically name unnamed component
3469 * instances.
3470 *
3471 * Also it appends the plugin paths of --plugin-path to
3472 * `plugin_paths`.
3473 */
3474 argpar_parse_ret = bt_argpar_parse(argc, argv, convert_options, true);
3475 if (argpar_parse_ret.error) {
3476 BT_CLI_LOGE_APPEND_CAUSE(
3477 "While parsing `convert` command's command-line arguments: %s",
3478 argpar_parse_ret.error->str);
3479 goto error;
3480 }
3481
3482 if (help_option_is_specified(&argpar_parse_ret)) {
3483 print_convert_usage(stdout);
3484 *retcode = -1;
3485 BT_OBJECT_PUT_REF_AND_RESET(cfg);
3486 goto end;
3487 }
3488
3489 for (i = 0; i < argpar_parse_ret.items->len; i++) {
3490 struct bt_argpar_item *argpar_item =
3491 g_ptr_array_index(argpar_parse_ret.items, i);
3492 struct bt_argpar_item_opt *argpar_item_opt;
3493 char *name = NULL;
3494 char *plugin_name = NULL;
3495 char *comp_cls_name = NULL;
3496 const char *arg;
3497
3498 if (argpar_item->type == BT_ARGPAR_ITEM_TYPE_OPT) {
3499 argpar_item_opt = (struct bt_argpar_item_opt *) argpar_item;
3500 arg = argpar_item_opt->arg;
3501
3502 switch (argpar_item_opt->descr->id) {
3503 case OPT_COMPONENT:
3504 {
3505 bt_component_class_type type;
3506
3507 current_item_type = CONVERT_CURRENT_ITEM_TYPE_COMPONENT;
3508
3509 /* Parse the argument */
3510 plugin_comp_cls_names(arg, &name, &plugin_name,
3511 &comp_cls_name, &type);
3512 if (!plugin_name || !comp_cls_name) {
3513 BT_CLI_LOGE_APPEND_CAUSE(
3514 "Invalid format for --component option's argument:\n %s",
3515 arg);
3516 goto error;
3517 }
3518
3519 if (name) {
3520 /*
3521 * Name was given by the user, verify it isn't
3522 * taken.
3523 */
3524 if (bt_value_map_has_entry(all_names, name)) {
3525 BT_CLI_LOGE_APPEND_CAUSE(
3526 "Duplicate component instance name:\n %s",
3527 name);
3528 goto error;
3529 }
3530
3531 name_gstr = g_string_new(name);
3532 if (!name_gstr) {
3533 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3534 goto error;
3535 }
3536
3537 g_string_assign(component_arg_for_run, arg);
3538 } else {
3539 /* Name not given by user, generate one. */
3540 name_gstr = get_component_auto_name(arg, all_names);
3541 if (!name_gstr) {
3542 goto error;
3543 }
3544
3545 g_string_printf(component_arg_for_run, "%s:%s",
3546 name_gstr->str, arg);
3547 }
3548
3549 if (bt_value_array_append_string_element(run_args,
3550 "--component")) {
3551 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3552 goto error;
3553 }
3554
3555 if (bt_value_array_append_string_element(run_args,
3556 component_arg_for_run->str)) {
3557 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3558 goto error;
3559 }
3560
3561 /*
3562 * Remember this name globally, for the uniqueness of
3563 * all component names.
3564 */
3565 if (bt_value_map_insert_entry(all_names,
3566 name_gstr->str, bt_value_null)) {
3567 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3568 goto error;
3569 }
3570
3571 /*
3572 * Remember this name specifically for the type of the
3573 * component. This is to create connection arguments.
3574 *
3575 * The list takes ownership of `name_gstr`.
3576 */
3577 switch (type) {
3578 case BT_COMPONENT_CLASS_TYPE_SOURCE:
3579 source_names = g_list_append(source_names, name_gstr);
3580 break;
3581 case BT_COMPONENT_CLASS_TYPE_FILTER:
3582 filter_names = g_list_append(filter_names, name_gstr);
3583 break;
3584 case BT_COMPONENT_CLASS_TYPE_SINK:
3585 sink_names = g_list_append(sink_names, name_gstr);
3586 break;
3587 default:
3588 abort();
3589 }
3590 name_gstr = NULL;
3591
3592 free(name);
3593 free(plugin_name);
3594 free(comp_cls_name);
3595 name = NULL;
3596 plugin_name = NULL;
3597 comp_cls_name = NULL;
3598 break;
3599 }
3600 case OPT_PARAMS:
3601 if (current_item_type == CONVERT_CURRENT_ITEM_TYPE_COMPONENT) {
3602 /*
3603 * The current item is a component (--component option),
3604 * pass it directly to the run args.
3605 */
3606 if (bt_value_array_append_string_element(run_args,
3607 "--params")) {
3608 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3609 goto error;
3610 }
3611
3612 if (bt_value_array_append_string_element(run_args, arg)) {
3613 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3614 goto error;
3615 }
3616 } else if (current_item_type == CONVERT_CURRENT_ITEM_TYPE_LEFTOVER) {
3617 /* The current item is a leftover, record it in `leftover_params`. */
3618 bt_value *array;
3619 uint64_t idx = bt_value_array_get_size(leftover_params) - 1;
3620
3621 array = bt_value_array_borrow_element_by_index(leftover_params, idx);
3622 bt_value_array_append_string_element(array, arg);
3623 } else {
3624 BT_CLI_LOGE_APPEND_CAUSE(
3625 "No current component (--component option) or non-option argument of which to set parameters:\n %s",
3626 arg);
3627 goto error;
3628 }
3629 break;
3630 case OPT_LOG_LEVEL:
3631 if (current_item_type != CONVERT_CURRENT_ITEM_TYPE_COMPONENT) {
3632 BT_CLI_LOGE_APPEND_CAUSE(
3633 "No current component (--component option) to assign a log level to:\n %s",
3634 arg);
3635 goto error;
3636 }
3637
3638 if (bt_value_array_append_string_element(run_args, "--log-level")) {
3639 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3640 goto error;
3641 }
3642
3643 if (bt_value_array_append_string_element(run_args, arg)) {
3644 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3645 goto error;
3646 }
3647
3648 break;
3649 case OPT_OMIT_HOME_PLUGIN_PATH:
3650 force_omit_home_plugin_path = true;
3651
3652 if (bt_value_array_append_string_element(run_args,
3653 "--omit-home-plugin-path")) {
3654 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3655 goto error;
3656 }
3657 break;
3658 case OPT_RETRY_DURATION:
3659 if (bt_value_array_append_string_element(run_args,
3660 "--retry-duration")) {
3661 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3662 goto error;
3663 }
3664
3665 if (bt_value_array_append_string_element(run_args, arg)) {
3666 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3667 goto error;
3668 }
3669 break;
3670 case OPT_OMIT_SYSTEM_PLUGIN_PATH:
3671 force_omit_system_plugin_path = true;
3672
3673 if (bt_value_array_append_string_element(run_args,
3674 "--omit-system-plugin-path")) {
3675 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3676 goto error;
3677 }
3678 break;
3679 case OPT_PLUGIN_PATH:
3680 if (bt_config_append_plugin_paths_check_setuid_setgid(
3681 plugin_paths, arg)) {
3682 goto error;
3683 }
3684
3685 if (bt_value_array_append_string_element(run_args,
3686 "--plugin-path")) {
3687 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3688 goto error;
3689 }
3690
3691 if (bt_value_array_append_string_element(run_args, arg)) {
3692 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3693 goto error;
3694 }
3695 break;
3696 case OPT_BEGIN:
3697 case OPT_CLOCK_CYCLES:
3698 case OPT_CLOCK_DATE:
3699 case OPT_CLOCK_FORCE_CORRELATE:
3700 case OPT_CLOCK_GMT:
3701 case OPT_CLOCK_OFFSET:
3702 case OPT_CLOCK_OFFSET_NS:
3703 case OPT_CLOCK_SECONDS:
3704 case OPT_COLOR:
3705 case OPT_DEBUG:
3706 case OPT_DEBUG_INFO:
3707 case OPT_DEBUG_INFO_DIR:
3708 case OPT_DEBUG_INFO_FULL_PATH:
3709 case OPT_DEBUG_INFO_TARGET_PREFIX:
3710 case OPT_END:
3711 case OPT_FIELDS:
3712 case OPT_INPUT_FORMAT:
3713 case OPT_NAMES:
3714 case OPT_NO_DELTA:
3715 case OPT_OUTPUT_FORMAT:
3716 case OPT_OUTPUT:
3717 case OPT_RUN_ARGS:
3718 case OPT_RUN_ARGS_0:
3719 case OPT_STREAM_INTERSECTION:
3720 case OPT_TIMERANGE:
3721 case OPT_VERBOSE:
3722 /* Ignore in this pass */
3723 break;
3724 default:
3725 BT_CLI_LOGE_APPEND_CAUSE("Unknown command-line option specified (option code %d).",
3726 argpar_item_opt->descr->id);
3727 goto error;
3728 }
3729 } else if (argpar_item->type == BT_ARGPAR_ITEM_TYPE_NON_OPT) {
3730 struct bt_argpar_item_non_opt *argpar_item_non_opt;
3731 bt_value_array_append_element_status append_status;
3732
3733 current_item_type = CONVERT_CURRENT_ITEM_TYPE_LEFTOVER;
3734
3735 argpar_item_non_opt = (struct bt_argpar_item_non_opt *) argpar_item;
3736
3737 append_status = bt_value_array_append_string_element(leftovers,
3738 argpar_item_non_opt->arg);
3739 if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) {
3740 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3741 goto error;
3742 }
3743
3744 append_status = bt_value_array_append_empty_array_element(leftover_params);
3745 if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) {
3746 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3747 goto error;
3748 }
3749 } else {
3750 abort();
3751 }
3752 }
3753
3754 /*
3755 * Second pass: transform the convert-specific options and
3756 * arguments into implicit component instances for the run
3757 * command.
3758 */
3759 for (i = 0; i < argpar_parse_ret.items->len; i++) {
3760 struct bt_argpar_item *argpar_item =
3761 g_ptr_array_index(argpar_parse_ret.items, i);
3762 struct bt_argpar_item_opt *argpar_item_opt;
3763 const char *arg;
3764
3765 if (argpar_item->type != BT_ARGPAR_ITEM_TYPE_OPT) {
3766 continue;
3767 }
3768
3769 argpar_item_opt = (struct bt_argpar_item_opt *) argpar_item;
3770 arg = argpar_item_opt->arg;
3771
3772 switch (argpar_item_opt->descr->id) {
3773 case OPT_BEGIN:
3774 if (trimmer_has_begin) {
3775 printf("At --begin option: --begin or --timerange option already specified\n %s\n",
3776 arg);
3777 goto error;
3778 }
3779
3780 trimmer_has_begin = true;
3781 ret = append_implicit_component_extra_param(
3782 &implicit_trimmer_args, "begin", arg);
3783 implicit_trimmer_args.exists = true;
3784 if (ret) {
3785 goto error;
3786 }
3787 break;
3788 case OPT_END:
3789 if (trimmer_has_end) {
3790 printf("At --end option: --end or --timerange option already specified\n %s\n",
3791 arg);
3792 goto error;
3793 }
3794
3795 trimmer_has_end = true;
3796 ret = append_implicit_component_extra_param(
3797 &implicit_trimmer_args, "end", arg);
3798 implicit_trimmer_args.exists = true;
3799 if (ret) {
3800 goto error;
3801 }
3802 break;
3803 case OPT_TIMERANGE:
3804 {
3805 char *begin;
3806 char *end;
3807
3808 if (trimmer_has_begin || trimmer_has_end) {
3809 printf("At --timerange option: --begin, --end, or --timerange option already specified\n %s\n",
3810 arg);
3811 goto error;
3812 }
3813
3814 ret = split_timerange(arg, &begin, &end);
3815 if (ret) {
3816 BT_CLI_LOGE_APPEND_CAUSE("Invalid --timerange option's argument: expecting BEGIN,END or [BEGIN,END]:\n %s",
3817 arg);
3818 goto error;
3819 }
3820
3821 ret = append_implicit_component_extra_param(
3822 &implicit_trimmer_args, "begin", begin);
3823 ret |= append_implicit_component_extra_param(
3824 &implicit_trimmer_args, "end", end);
3825 implicit_trimmer_args.exists = true;
3826 free(begin);
3827 free(end);
3828 if (ret) {
3829 goto error;
3830 }
3831 break;
3832 }
3833 case OPT_CLOCK_CYCLES:
3834 append_implicit_component_param(
3835 &implicit_text_args, "clock-cycles", "yes");
3836 implicit_text_args.exists = true;
3837 break;
3838 case OPT_CLOCK_DATE:
3839 append_implicit_component_param(
3840 &implicit_text_args, "clock-date", "yes");
3841 implicit_text_args.exists = true;
3842 break;
3843 case OPT_CLOCK_FORCE_CORRELATE:
3844 append_implicit_component_param(
3845 &implicit_muxer_args,
3846 "assume-absolute-clock-classes", "yes");
3847 break;
3848 case OPT_CLOCK_GMT:
3849 append_implicit_component_param(
3850 &implicit_text_args, "clock-gmt", "yes");
3851 append_implicit_component_param(
3852 &implicit_trimmer_args, "gmt", "yes");
3853 implicit_text_args.exists = true;
3854 break;
3855 case OPT_CLOCK_OFFSET:
3856 if (ctf_fs_source_clock_class_offset_arg) {
3857 BT_CLI_LOGE_APPEND_CAUSE("Duplicate --clock-offset option\n");
3858 goto error;
3859 }
3860
3861 ctf_fs_source_clock_class_offset_arg = g_strdup(arg);
3862 if (!ctf_fs_source_clock_class_offset_arg) {
3863 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3864 goto error;
3865 }
3866 break;
3867 case OPT_CLOCK_OFFSET_NS:
3868 if (ctf_fs_source_clock_class_offset_ns_arg) {
3869 BT_CLI_LOGE_APPEND_CAUSE("Duplicate --clock-offset-ns option\n");
3870 goto error;
3871 }
3872
3873 ctf_fs_source_clock_class_offset_ns_arg = g_strdup(arg);
3874 if (!ctf_fs_source_clock_class_offset_ns_arg) {
3875 BT_CLI_LOGE_APPEND_CAUSE_OOM();
3876 goto error;
3877 }
3878 break;
3879 case OPT_CLOCK_SECONDS:
3880 append_implicit_component_param(
3881 &implicit_text_args, "clock-seconds", "yes");
3882 implicit_text_args.exists = true;
3883 break;
3884 case OPT_COLOR:
3885 implicit_text_args.exists = true;
3886 ret = append_implicit_component_extra_param(
3887 &implicit_text_args, "color", arg);
3888 if (ret) {
3889 goto error;
3890 }
3891 break;
3892 case OPT_DEBUG_INFO:
3893 implicit_debug_info_args.exists = true;
3894 break;
3895 case OPT_DEBUG_INFO_DIR:
3896 implicit_debug_info_args.exists = true;
3897 ret = append_implicit_component_extra_param(
3898 &implicit_debug_info_args, "debug-info-dir", arg);
3899 if (ret) {
3900 goto error;
3901 }
3902 break;
3903 case OPT_DEBUG_INFO_FULL_PATH:
3904 implicit_debug_info_args.exists = true;
3905 append_implicit_component_param(
3906 &implicit_debug_info_args, "full-path", "yes");
3907 break;
3908 case OPT_DEBUG_INFO_TARGET_PREFIX:
3909 implicit_debug_info_args.exists = true;
3910 ret = append_implicit_component_extra_param(
3911 &implicit_debug_info_args,
3912 "target-prefix", arg);
3913 if (ret) {
3914 goto error;
3915 }
3916 break;
3917 case OPT_FIELDS:
3918 {
3919 bt_value *fields = fields_from_arg(arg);
3920
3921 if (!fields) {
3922 goto error;
3923 }
3924
3925 implicit_text_args.exists = true;
3926 ret = insert_flat_params_from_array(
3927 implicit_text_args.params_arg,
3928 fields, "field");
3929 bt_value_put_ref(fields);
3930 if (ret) {
3931 goto error;
3932 }
3933 break;
3934 }
3935 case OPT_NAMES:
3936 {
3937 bt_value *names = names_from_arg(arg);
3938
3939 if (!names) {
3940 goto error;
3941 }
3942
3943 implicit_text_args.exists = true;
3944 ret = insert_flat_params_from_array(
3945 implicit_text_args.params_arg,
3946 names, "name");
3947 bt_value_put_ref(names);
3948 if (ret) {
3949 goto error;
3950 }
3951 break;
3952 }
3953 case OPT_NO_DELTA:
3954 append_implicit_component_param(
3955 &implicit_text_args, "no-delta", "yes");
3956 implicit_text_args.exists = true;
3957 break;
3958 case OPT_INPUT_FORMAT:
3959 if (got_input_format_opt) {
3960 BT_CLI_LOGE_APPEND_CAUSE("Duplicate --input-format option.");
3961 goto error;
3962 }
3963
3964 got_input_format_opt = true;
3965
3966 if (strcmp(arg, "ctf") == 0) {
3967 auto_source_discovery_restrict_plugin_name = "ctf";
3968 auto_source_discovery_restrict_component_class_name = "fs";
3969 } else if (strcmp(arg, "lttng-live") == 0) {
3970 auto_source_discovery_restrict_plugin_name = "ctf";
3971 auto_source_discovery_restrict_component_class_name = "lttng-live";
3972 implicit_lttng_live_args.exists = true;
3973 } else {
3974 BT_CLI_LOGE_APPEND_CAUSE("Unknown legacy input format:\n %s",
3975 arg);
3976 goto error;
3977 }
3978 break;
3979 case OPT_OUTPUT_FORMAT:
3980 if (got_output_format_opt) {
3981 BT_CLI_LOGE_APPEND_CAUSE("Duplicate --output-format option.");
3982 goto error;
3983 }
3984
3985 got_output_format_opt = true;
3986
3987 if (strcmp(arg, "text") == 0) {
3988 implicit_text_args.exists = true;
3989 } else if (strcmp(arg, "ctf") == 0) {
3990 implicit_ctf_output_args.exists = true;
3991 } else if (strcmp(arg, "dummy") == 0) {
3992 implicit_dummy_args.exists = true;
3993 } else if (strcmp(arg, "ctf-metadata") == 0) {
3994 print_ctf_metadata = true;
3995 } else {
3996 BT_CLI_LOGE_APPEND_CAUSE("Unknown legacy output format:\n %s",
3997 arg);
3998 goto error;
3999 }
4000 break;
4001 case OPT_OUTPUT:
4002 if (output) {
4003 BT_CLI_LOGE_APPEND_CAUSE("Duplicate --output option");
4004 goto error;
4005 }
4006
4007 output = strdup(arg);
4008 if (!output) {
4009 BT_CLI_LOGE_APPEND_CAUSE_OOM();
4010 goto error;
4011 }
4012 break;
4013 case OPT_RUN_ARGS:
4014 if (print_run_args_0) {
4015 BT_CLI_LOGE_APPEND_CAUSE("Cannot specify --run-args and --run-args-0.");
4016 goto error;
4017 }
4018
4019 print_run_args = true;
4020 break;
4021 case OPT_RUN_ARGS_0:
4022 if (print_run_args) {
4023 BT_CLI_LOGE_APPEND_CAUSE("Cannot specify --run-args and --run-args-0.");
4024 goto error;
4025 }
4026
4027 print_run_args_0 = true;
4028 break;
4029 case OPT_STREAM_INTERSECTION:
4030 /*
4031 * Applies to all traces implementing the
4032 * babeltrace.trace-info query.
4033 */
4034 stream_intersection_mode = true;
4035 break;
4036 case OPT_VERBOSE:
4037 if (*default_log_level != BT_LOG_TRACE &&
4038 *default_log_level != BT_LOG_DEBUG) {
4039 *default_log_level = BT_LOG_INFO;
4040 }
4041 break;
4042 case OPT_DEBUG:
4043 *default_log_level = BT_LOG_TRACE;
4044 break;
4045 default:
4046 break;
4047 }
4048 }
4049
4050 /*
4051 * Legacy behaviour: --verbose used to make the `text` output
4052 * format print more information. --verbose is now equivalent to
4053 * the INFO log level, which is why we compare to `BT_LOG_INFO`
4054 * here.
4055 */
4056 if (*default_log_level == BT_LOG_INFO) {
4057 append_implicit_component_param(&implicit_text_args,
4058 "verbose", "yes");
4059 }
4060
4061 /*
4062 * Append home and system plugin paths now that we possibly got
4063 * --plugin-path.
4064 */
4065 if (append_home_and_system_plugin_paths(plugin_paths,
4066 force_omit_system_plugin_path,
4067 force_omit_home_plugin_path)) {
4068 goto error;
4069 }
4070
4071 /* Print CTF metadata or print LTTng live sessions */
4072 if (print_ctf_metadata) {
4073 const bt_value *bt_val_leftover;
4074
4075 if (bt_value_array_is_empty(leftovers)) {
4076 BT_CLI_LOGE_APPEND_CAUSE("--output-format=ctf-metadata specified without a path.");
4077 goto error;
4078 }
4079
4080 if (bt_value_array_get_size(leftovers) > 1) {
4081 BT_CLI_LOGE_APPEND_CAUSE("Too many paths specified for --output-format=ctf-metadata.");
4082 goto error;
4083 }
4084
4085 cfg = bt_config_print_ctf_metadata_create(plugin_paths);
4086 if (!cfg) {
4087 goto error;
4088 }
4089
4090 bt_val_leftover = bt_value_array_borrow_element_by_index_const(leftovers, 0);
4091 g_string_assign(cfg->cmd_data.print_ctf_metadata.path,
4092 bt_value_string_get(bt_val_leftover));
4093
4094 if (output) {
4095 g_string_assign(
4096 cfg->cmd_data.print_ctf_metadata.output_path,
4097 output);
4098 }
4099
4100 goto end;
4101 }
4102
4103 /*
4104 * If -o ctf was specified, make sure an output path (--output)
4105 * was also specified. --output does not imply -o ctf because
4106 * it's also used for the default, implicit -o text if -o ctf
4107 * is not specified.
4108 */
4109 if (implicit_ctf_output_args.exists) {
4110 if (!output) {
4111 BT_CLI_LOGE_APPEND_CAUSE("--output-format=ctf specified without --output (trace output path).");
4112 goto error;
4113 }
4114
4115 /*
4116 * At this point we know that -o ctf AND --output were
4117 * specified. Make sure that no options were specified
4118 * which would imply -o text because --output would be
4119 * ambiguous in this case. For example, this is wrong:
4120 *
4121 * babeltrace2 --names=all -o ctf --output=/tmp/path my-trace
4122 *
4123 * because --names=all implies -o text, and --output
4124 * could apply to both the sink.text.pretty and
4125 * sink.ctf.fs implicit components.
4126 */
4127 if (implicit_text_args.exists) {
4128 BT_CLI_LOGE_APPEND_CAUSE("Ambiguous --output option: --output-format=ctf specified but another option implies --output-format=text.");
4129 goto error;
4130 }
4131 }
4132
4133 /*
4134 * If -o dummy and -o ctf were not specified, and if there are
4135 * no explicit sink components, then use an implicit
4136 * `sink.text.pretty` component.
4137 */
4138 if (!implicit_dummy_args.exists && !implicit_ctf_output_args.exists &&
4139 !sink_names) {
4140 implicit_text_args.exists = true;
4141 }
4142
4143 /*
4144 * Set implicit `sink.text.pretty` or `sink.ctf.fs` component's
4145 * `path` parameter if --output was specified.
4146 */
4147 if (output) {
4148 if (implicit_text_args.exists) {
4149 append_implicit_component_extra_param(&implicit_text_args,
4150 "path", output);
4151 } else if (implicit_ctf_output_args.exists) {
4152 append_implicit_component_extra_param(&implicit_ctf_output_args,
4153 "path", output);
4154 }
4155 }
4156
4157 /* Decide where the leftover argument(s) go */
4158 if (bt_value_array_get_size(leftovers) > 0) {
4159 if (implicit_lttng_live_args.exists) {
4160 const bt_value *bt_val_leftover;
4161
4162 if (bt_value_array_get_size(leftovers) > 1) {
4163 BT_CLI_LOGE_APPEND_CAUSE("Too many URLs specified for --input-format=lttng-live.");
4164 goto error;
4165 }
4166
4167 bt_val_leftover = bt_value_array_borrow_element_by_index_const(leftovers, 0);
4168 lttng_live_url_parts =
4169 bt_common_parse_lttng_live_url(bt_value_string_get(bt_val_leftover),
4170 error_buf, sizeof(error_buf));
4171 if (!lttng_live_url_parts.proto) {
4172 BT_CLI_LOGE_APPEND_CAUSE("Invalid LTTng live URL format: %s.",
4173 error_buf);
4174 goto error;
4175 }
4176
4177 if (!lttng_live_url_parts.session_name) {
4178 /* Print LTTng live sessions */
4179 cfg = bt_config_print_lttng_live_sessions_create(
4180 plugin_paths);
4181 if (!cfg) {
4182 goto error;
4183 }
4184
4185 g_string_assign(cfg->cmd_data.print_lttng_live_sessions.url,
4186 bt_value_string_get(bt_val_leftover));
4187
4188 if (output) {
4189 g_string_assign(
4190 cfg->cmd_data.print_lttng_live_sessions.output_path,
4191 output);
4192 }
4193
4194 goto end;
4195 }
4196
4197 ret = append_implicit_component_extra_param(
4198 &implicit_lttng_live_args, "url",
4199 bt_value_string_get(bt_val_leftover));
4200 if (ret) {
4201 goto error;
4202 }
4203
4204 ret = append_implicit_component_extra_param(
4205 &implicit_lttng_live_args,
4206 "session-not-found-action", "end");
4207 if (ret) {
4208 goto error;
4209 }
4210 } else {
4211 int status;
4212
4213 status = auto_discover_source_components(plugin_paths, leftovers,
4214 auto_source_discovery_restrict_plugin_name,
4215 auto_source_discovery_restrict_component_class_name,
4216 *default_log_level >= 0 ? *default_log_level : cli_default_log_level,
4217 &auto_disc);
4218
4219 if (status != 0) {
4220 goto error;
4221 }
4222
4223 status = create_implicit_component_args_from_auto_discovered_sources(
4224 &auto_disc, leftover_params, discovered_source_args);
4225 if (status != 0) {
4226 goto error;
4227 }
4228 }
4229 }
4230
4231 /* If --clock-offset was given, apply it to any src.ctf.fs component. */
4232 if (ctf_fs_source_clock_class_offset_arg) {
4233 int n;
4234
4235 n = append_multiple_implicit_components_param(
4236 discovered_source_args, "source.ctf.fs", "clock-class-offset-s",
4237 ctf_fs_source_clock_class_offset_arg);
4238
4239 if (n == 0) {
4240 BT_CLI_LOGE_APPEND_CAUSE("--clock-offset specified, but no source.ctf.fs component instantiated.");
4241 goto error;
4242 }
4243 }
4244
4245 /* If --clock-offset-ns was given, apply it to any src.ctf.fs component. */
4246 if (ctf_fs_source_clock_class_offset_ns_arg) {
4247 int n;
4248
4249 n = append_multiple_implicit_components_param(
4250 discovered_source_args, "source.ctf.fs", "clock-class-offset-ns",
4251 ctf_fs_source_clock_class_offset_ns_arg);
4252
4253 if (n == 0) {
4254 BT_CLI_LOGE_APPEND_CAUSE("--clock-offset-ns specified, but no source.ctf.fs component instantiated.");
4255 goto error;
4256 }
4257 }
4258
4259 /*
4260 * If the implicit `source.ctf.lttng-live` component exists, make sure
4261 * there's at least one leftover (which is the URL).
4262 */
4263 if (implicit_lttng_live_args.exists && bt_value_array_is_empty(leftovers)) {
4264 BT_CLI_LOGE_APPEND_CAUSE("Missing URL for implicit `%s` component.",
4265 implicit_lttng_live_args.comp_arg->str);
4266 goto error;
4267 }
4268
4269 /* Assign names to implicit components */
4270 for (i = 0; i < discovered_source_args->len; i++) {
4271 struct implicit_component_args *args;
4272 int j;
4273
4274 args = discovered_source_args->pdata[i];
4275
4276 g_string_printf(auto_disc_comp_name, "auto-disc-%s", args->comp_arg->str);
4277
4278 /* Give it a name like `auto-disc-src-ctf-fs`. */
4279 for (j = 0; j < auto_disc_comp_name->len; j++) {
4280 if (auto_disc_comp_name->str[j] == '.') {
4281 auto_disc_comp_name->str[j] = '-';
4282 }
4283 }
4284
4285 ret = assign_name_to_implicit_component(args,
4286 auto_disc_comp_name->str, all_names, &source_names, true);
4287 if (ret) {
4288 goto error;
4289 }
4290 }
4291
4292 ret = assign_name_to_implicit_component(&implicit_lttng_live_args,
4293 "lttng-live", all_names, &source_names, true);
4294 if (ret) {
4295 goto error;
4296 }
4297
4298 ret = assign_name_to_implicit_component(&implicit_text_args,
4299 "pretty", all_names, &sink_names, true);
4300 if (ret) {
4301 goto error;
4302 }
4303
4304 ret = assign_name_to_implicit_component(&implicit_ctf_output_args,
4305 "sink-ctf-fs", all_names, &sink_names, true);
4306 if (ret) {
4307 goto error;
4308 }
4309
4310 ret = assign_name_to_implicit_component(&implicit_dummy_args,
4311 "dummy", all_names, &sink_names, true);
4312 if (ret) {
4313 goto error;
4314 }
4315
4316 ret = assign_name_to_implicit_component(&implicit_muxer_args,
4317 "muxer", all_names, NULL, false);
4318 if (ret) {
4319 goto error;
4320 }
4321
4322 ret = assign_name_to_implicit_component(&implicit_trimmer_args,
4323 "trimmer", all_names, NULL, false);
4324 if (ret) {
4325 goto error;
4326 }
4327
4328 ret = assign_name_to_implicit_component(&implicit_debug_info_args,
4329 "debug-info", all_names, NULL, false);
4330 if (ret) {
4331 goto error;
4332 }
4333
4334 /* Make sure there's at least one source and one sink */
4335 if (!source_names) {
4336 BT_CLI_LOGE_APPEND_CAUSE("No source component.");
4337 goto error;
4338 }
4339
4340 if (!sink_names) {
4341 BT_CLI_LOGE_APPEND_CAUSE("No sink component.");
4342 goto error;
4343 }
4344
4345 /*
4346 * Prepend the muxer, the trimmer, and the debug info to the
4347 * filter chain so that we have:
4348 *
4349 * sources -> muxer -> [trimmer] -> [debug info] ->
4350 * [user filters] -> sinks
4351 */
4352 if (implicit_debug_info_args.exists) {
4353 if (g_list_prepend_gstring(&filter_names,
4354 implicit_debug_info_args.name_arg->str)) {
4355 goto error;
4356 }
4357 }
4358
4359 if (implicit_trimmer_args.exists) {
4360 if (g_list_prepend_gstring(&filter_names,
4361 implicit_trimmer_args.name_arg->str)) {
4362 goto error;
4363 }
4364 }
4365
4366 if (g_list_prepend_gstring(&filter_names,
4367 implicit_muxer_args.name_arg->str)) {
4368 goto error;
4369 }
4370
4371 /*
4372 * Append the equivalent run arguments for the implicit
4373 * components.
4374 */
4375 for (i = 0; i < discovered_source_args->len; i++) {
4376 struct implicit_component_args *args =
4377 discovered_source_args->pdata[i];
4378
4379 ret = append_run_args_for_implicit_component(args, run_args);
4380 if (ret) {
4381 goto error;
4382 }
4383 }
4384
4385 ret = append_run_args_for_implicit_component(&implicit_lttng_live_args,
4386 run_args);
4387 if (ret) {
4388 goto error;
4389 }
4390
4391 ret = append_run_args_for_implicit_component(&implicit_text_args,
4392 run_args);
4393 if (ret) {
4394 goto error;
4395 }
4396
4397 ret = append_run_args_for_implicit_component(&implicit_ctf_output_args,
4398 run_args);
4399 if (ret) {
4400 goto error;
4401 }
4402
4403 ret = append_run_args_for_implicit_component(&implicit_dummy_args,
4404 run_args);
4405 if (ret) {
4406 goto error;
4407 }
4408
4409 ret = append_run_args_for_implicit_component(&implicit_muxer_args,
4410 run_args);
4411 if (ret) {
4412 goto error;
4413 }
4414
4415 ret = append_run_args_for_implicit_component(&implicit_trimmer_args,
4416 run_args);
4417 if (ret) {
4418 goto error;
4419 }
4420
4421 ret = append_run_args_for_implicit_component(&implicit_debug_info_args,
4422 run_args);
4423 if (ret) {
4424 goto error;
4425 }
4426
4427 /* Auto-connect components */
4428 ret = convert_auto_connect(run_args, source_names, filter_names,
4429 sink_names);
4430 if (ret) {
4431 BT_CLI_LOGE_APPEND_CAUSE("Cannot auto-connect components.");
4432 goto error;
4433 }
4434
4435 /*
4436 * We have all the run command arguments now. Depending on
4437 * --run-args, we pass this to the run command or print them
4438 * here.
4439 */
4440 if (print_run_args || print_run_args_0) {
4441 if (stream_intersection_mode) {
4442 BT_CLI_LOGE_APPEND_CAUSE("Cannot specify --stream-intersection with --run-args or --run-args-0.");
4443 goto error;
4444 }
4445
4446 for (i = 0; i < bt_value_array_get_size(run_args); i++) {
4447 const bt_value *arg_value =
4448 bt_value_array_borrow_element_by_index(run_args,
4449 i);
4450 const char *arg;
4451 GString *quoted = NULL;
4452 const char *arg_to_print;
4453
4454 BT_ASSERT(arg_value);
4455 arg = bt_value_string_get(arg_value);
4456
4457 if (print_run_args) {
4458 quoted = bt_common_shell_quote(arg, true);
4459 if (!quoted) {
4460 goto error;
4461 }
4462
4463 arg_to_print = quoted->str;
4464 } else {
4465 arg_to_print = arg;
4466 }
4467
4468 printf("%s", arg_to_print);
4469
4470 if (quoted) {
4471 g_string_free(quoted, TRUE);
4472 }
4473
4474 if (i < bt_value_array_get_size(run_args) - 1) {
4475 if (print_run_args) {
4476 putchar(' ');
4477 } else {
4478 putchar('\0');
4479 }
4480 }
4481 }
4482
4483 *retcode = -1;
4484 BT_OBJECT_PUT_REF_AND_RESET(cfg);
4485 goto end;
4486 }
4487
4488 /*
4489 * If the log level is still unset at this point, set it to
4490 * the program's default.
4491 */
4492 if (*default_log_level < 0) {
4493 *default_log_level = cli_default_log_level;
4494 }
4495
4496 cfg = bt_config_run_from_args_array(run_args, retcode,
4497 force_omit_system_plugin_path,
4498 force_omit_home_plugin_path,
4499 initial_plugin_paths, *default_log_level);
4500 if (!cfg) {
4501 goto error;
4502 }
4503
4504 cfg->cmd_data.run.stream_intersection_mode = stream_intersection_mode;
4505 goto end;
4506
4507 error:
4508 *retcode = 1;
4509 BT_OBJECT_PUT_REF_AND_RESET(cfg);
4510
4511 end:
4512 /*
4513 * If the log level is still unset at this point, set it to
4514 * the program's default.
4515 */
4516 if (*default_log_level < 0) {
4517 *default_log_level = cli_default_log_level;
4518 }
4519
4520 bt_argpar_parse_ret_fini(&argpar_parse_ret);
4521
4522 free(output);
4523
4524 if (component_arg_for_run) {
4525 g_string_free(component_arg_for_run, TRUE);
4526 }
4527
4528 if (name_gstr) {
4529 g_string_free(name_gstr, TRUE);
4530 }
4531
4532 bt_value_put_ref(run_args);
4533 bt_value_put_ref(all_names);
4534 destroy_glist_of_gstring(source_names);
4535 destroy_glist_of_gstring(filter_names);
4536 destroy_glist_of_gstring(sink_names);
4537 bt_value_put_ref(leftovers);
4538 finalize_implicit_component_args(&implicit_ctf_output_args);
4539 finalize_implicit_component_args(&implicit_lttng_live_args);
4540 finalize_implicit_component_args(&implicit_dummy_args);
4541 finalize_implicit_component_args(&implicit_text_args);
4542 finalize_implicit_component_args(&implicit_debug_info_args);
4543 finalize_implicit_component_args(&implicit_muxer_args);
4544 finalize_implicit_component_args(&implicit_trimmer_args);
4545 bt_value_put_ref(plugin_paths);
4546 bt_common_destroy_lttng_live_url_parts(&lttng_live_url_parts);
4547 auto_source_discovery_fini(&auto_disc);
4548
4549 if (discovered_source_args) {
4550 g_ptr_array_free(discovered_source_args, TRUE);
4551 }
4552
4553 g_free(ctf_fs_source_clock_class_offset_arg);
4554 g_free(ctf_fs_source_clock_class_offset_ns_arg);
4555
4556 if (auto_disc_comp_name) {
4557 g_string_free(auto_disc_comp_name, TRUE);
4558 }
4559
4560 return cfg;
4561 }
4562
4563 /*
4564 * Prints the Babeltrace 2.x general usage.
4565 */
4566 static
4567 void print_gen_usage(FILE *fp)
4568 {
4569 fprintf(fp, "Usage: babeltrace2 [GENERAL OPTIONS] [COMMAND] [COMMAND ARGUMENTS]\n");
4570 fprintf(fp, "\n");
4571 fprintf(fp, "General options:\n");
4572 fprintf(fp, "\n");
4573 fprintf(fp, " -d, --debug Enable debug mode (same as --log-level=V)\n");
4574 fprintf(fp, " -h, --help Show this help and quit\n");
4575 fprintf(fp, " -l, --log-level=LVL Set the default log level to LVL (`N`, `V`, `D`,\n");
4576 fprintf(fp, " `I`, `W` (default), `E`, or `F`)\n");
4577 fprintf(fp, " -v, --verbose Enable verbose mode (same as --log-level=I)\n");
4578 fprintf(fp, " -V, --version Show version and quit\n");
4579 fprintf(fp, "\n");
4580 fprintf(fp, "Available commands:\n");
4581 fprintf(fp, "\n");
4582 fprintf(fp, " convert Convert and trim traces (default)\n");
4583 fprintf(fp, " help Get help for a plugin or a component class\n");
4584 fprintf(fp, " list-plugins List available plugins and their content\n");
4585 fprintf(fp, " query Query objects from a component class\n");
4586 fprintf(fp, " run Build a processing graph and run it\n");
4587 fprintf(fp, "\n");
4588 fprintf(fp, "Use `babeltrace2 COMMAND --help` to show the help of COMMAND.\n");
4589 }
4590
4591 struct bt_config *bt_config_cli_args_create(int argc, const char *argv[],
4592 int *retcode, bool force_omit_system_plugin_path,
4593 bool force_omit_home_plugin_path,
4594 const bt_value *initial_plugin_paths)
4595 {
4596 struct bt_config *config = NULL;
4597 int i;
4598 int top_level_argc;
4599 const char **top_level_argv;
4600 int command_argc = -1;
4601 const char **command_argv = NULL;
4602 const char *command_name = NULL;
4603 int default_log_level = -1;
4604 struct bt_argpar_parse_ret argpar_parse_ret = { 0 };
4605
4606 /* Top-level option descriptions. */
4607 static const struct bt_argpar_opt_descr descrs[] = {
4608 { OPT_DEBUG, 'd', "debug", false },
4609 { OPT_HELP, 'h', "help", false },
4610 { OPT_LOG_LEVEL, 'l', "log-level", true },
4611 { OPT_VERBOSE, 'v', "verbose", false },
4612 { OPT_VERSION, 'V', "version", false},
4613 BT_ARGPAR_OPT_DESCR_SENTINEL
4614 };
4615
4616 enum command_type {
4617 COMMAND_TYPE_NONE = -1,
4618 COMMAND_TYPE_RUN = 0,
4619 COMMAND_TYPE_CONVERT,
4620 COMMAND_TYPE_LIST_PLUGINS,
4621 COMMAND_TYPE_HELP,
4622 COMMAND_TYPE_QUERY,
4623 } command_type = COMMAND_TYPE_NONE;
4624
4625 *retcode = -1;
4626
4627 if (!initial_plugin_paths) {
4628 initial_plugin_paths = bt_value_array_create();
4629 if (!initial_plugin_paths) {
4630 *retcode = 1;
4631 goto end;
4632 }
4633 } else {
4634 bt_value_get_ref(initial_plugin_paths);
4635 }
4636
4637 if (argc <= 1) {
4638 print_version();
4639 puts("");
4640 print_gen_usage(stdout);
4641 goto end;
4642 }
4643
4644 /* Skip first argument, the name of the program. */
4645 top_level_argc = argc - 1;
4646 top_level_argv = argv + 1;
4647 argpar_parse_ret = bt_argpar_parse(top_level_argc, top_level_argv,
4648 descrs, false);
4649
4650 if (argpar_parse_ret.error) {
4651 BT_CLI_LOGE_APPEND_CAUSE(
4652 "While parsing command-line arguments: %s",
4653 argpar_parse_ret.error->str);
4654 goto error;
4655 }
4656
4657 for (i = 0; i < argpar_parse_ret.items->len; i++) {
4658 struct bt_argpar_item *item;
4659
4660 item = g_ptr_array_index(argpar_parse_ret.items, i);
4661
4662 if (item->type == BT_ARGPAR_ITEM_TYPE_OPT) {
4663 struct bt_argpar_item_opt *item_opt =
4664 (struct bt_argpar_item_opt *) item;
4665
4666 switch (item_opt->descr->id) {
4667 case OPT_DEBUG:
4668 default_log_level = BT_LOG_TRACE;
4669 break;
4670 case OPT_VERBOSE:
4671 /*
4672 * Legacy: do not override a previous
4673 * --debug because --verbose and --debug
4674 * can be specified together (in this
4675 * case we want the lowest log level to
4676 * apply, TRACE).
4677 */
4678 default_log_level = BT_LOG_INFO;
4679 break;
4680 case OPT_LOG_LEVEL:
4681 default_log_level =
4682 bt_log_get_level_from_string(item_opt->arg);
4683 if (default_log_level < 0) {
4684 BT_CLI_LOGE_APPEND_CAUSE(
4685 "Invalid argument for --log-level option:\n %s",
4686 item_opt->arg);
4687 goto error;
4688 }
4689 break;
4690 case OPT_VERSION:
4691 print_version();
4692 goto end;
4693 case OPT_HELP:
4694 print_gen_usage(stdout);
4695 goto end;
4696 }
4697 } else if (item->type == BT_ARGPAR_ITEM_TYPE_NON_OPT) {
4698 struct bt_argpar_item_non_opt *item_non_opt =
4699 (struct bt_argpar_item_non_opt *) item;
4700 /*
4701 * First unknown argument: is it a known command
4702 * name?
4703 */
4704 command_argc =
4705 top_level_argc - item_non_opt->orig_index - 1;
4706 command_argv =
4707 &top_level_argv[item_non_opt->orig_index + 1];
4708
4709 if (strcmp(item_non_opt->arg, "convert") == 0) {
4710 command_type = COMMAND_TYPE_CONVERT;
4711 } else if (strcmp(item_non_opt->arg, "list-plugins") == 0) {
4712 command_type = COMMAND_TYPE_LIST_PLUGINS;
4713 } else if (strcmp(item_non_opt->arg, "help") == 0) {
4714 command_type = COMMAND_TYPE_HELP;
4715 } else if (strcmp(item_non_opt->arg, "query") == 0) {
4716 command_type = COMMAND_TYPE_QUERY;
4717 } else if (strcmp(item_non_opt->arg, "run") == 0) {
4718 command_type = COMMAND_TYPE_RUN;
4719 } else {
4720 /*
4721 * Non-option argument, but not a known
4722 * command name: assume the default
4723 * `convert` command.
4724 */
4725 command_type = COMMAND_TYPE_CONVERT;
4726 command_name = "convert";
4727 command_argc++;
4728 command_argv--;
4729 }
4730 break;
4731 }
4732 }
4733
4734 if (command_type == COMMAND_TYPE_NONE) {
4735 if (argpar_parse_ret.ingested_orig_args == top_level_argc) {
4736 /*
4737 * We only got non-help, non-version general options
4738 * like --verbose and --debug, without any other
4739 * arguments, so we can't do anything useful: print the
4740 * usage and quit.
4741 */
4742 print_gen_usage(stdout);
4743 goto end;
4744 }
4745
4746 /*
4747 * We stopped on an unknown option argument (and therefore
4748 * didn't see a command name). Assume `convert` command.
4749 */
4750 command_type = COMMAND_TYPE_CONVERT;
4751 command_name = "convert";
4752 command_argc =
4753 top_level_argc - argpar_parse_ret.ingested_orig_args;
4754 command_argv =
4755 &top_level_argv[argpar_parse_ret.ingested_orig_args];
4756 }
4757
4758 BT_ASSERT(command_argv);
4759 BT_ASSERT(command_argc >= 0);
4760
4761 /*
4762 * The convert command can set its own default log level for
4763 * backward compatibility reasons. It only does so if there's no
4764 * log level yet, so do not force one for this command.
4765 */
4766 if (command_type != COMMAND_TYPE_CONVERT && default_log_level < 0) {
4767 /* Default log level */
4768 default_log_level = cli_default_log_level;
4769 }
4770
4771 switch (command_type) {
4772 case COMMAND_TYPE_RUN:
4773 config = bt_config_run_from_args(command_argc, command_argv,
4774 retcode, force_omit_system_plugin_path,
4775 force_omit_home_plugin_path, initial_plugin_paths,
4776 default_log_level);
4777 break;
4778 case COMMAND_TYPE_CONVERT:
4779 config = bt_config_convert_from_args(command_argc, command_argv,
4780 retcode, force_omit_system_plugin_path,
4781 force_omit_home_plugin_path,
4782 initial_plugin_paths, &default_log_level);
4783 break;
4784 case COMMAND_TYPE_LIST_PLUGINS:
4785 config = bt_config_list_plugins_from_args(command_argc,
4786 command_argv, retcode, force_omit_system_plugin_path,
4787 force_omit_home_plugin_path, initial_plugin_paths);
4788 break;
4789 case COMMAND_TYPE_HELP:
4790 config = bt_config_help_from_args(command_argc,
4791 command_argv, retcode, force_omit_system_plugin_path,
4792 force_omit_home_plugin_path, initial_plugin_paths,
4793 default_log_level);
4794 break;
4795 case COMMAND_TYPE_QUERY:
4796 config = bt_config_query_from_args(command_argc,
4797 command_argv, retcode, force_omit_system_plugin_path,
4798 force_omit_home_plugin_path, initial_plugin_paths,
4799 default_log_level);
4800 break;
4801 default:
4802 abort();
4803 }
4804
4805 if (config) {
4806 BT_ASSERT(default_log_level >= BT_LOG_TRACE);
4807 config->log_level = default_log_level;
4808 config->command_name = command_name;
4809 }
4810
4811 goto end;
4812
4813 error:
4814 *retcode = 1;
4815
4816 end:
4817 bt_argpar_parse_ret_fini(&argpar_parse_ret);
4818 bt_value_put_ref(initial_plugin_paths);
4819 return config;
4820 }
This page took 0.217502 seconds and 4 git commands to generate.