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