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