Fix: print usage even if omit arguments are received
[babeltrace.git] / converter / babeltrace-cfg.c
index 6c50d824caf924c84c43413dddb657c2924efebf..6beaf383bfdfef77c2f69f0be9020986699a9891 100644 (file)
 #include <babeltrace/values.h>
 #include <popt.h>
 #include <glib.h>
+#include <sys/types.h>
+#include <pwd.h>
 #include "babeltrace-cfg.h"
 
+#define SYSTEM_PLUGIN_PATH             INSTALL_LIBDIR "/babeltrace/plugins"
+#define DEFAULT_SOURCE_COMPONENT_NAME  "ctf.fs"
+#define DEFAULT_SINK_COMPONENT_NAME    "text.text"
+#define HOME_ENV_VAR                   "HOME"
+#define HOME_SUBPATH                   "/.babeltrace/plugins"
+
 /*
  * Error printf() macro which prepends "Error: " the first time it's
  * called. This gives a nicer feel than having a bunch of error prefixes
@@ -140,6 +148,9 @@ enum legacy_output_format {
        LEGACY_OUTPUT_FORMAT_DUMMY,
 };
 
+static bool omit_system_plugin_path;
+static bool omit_home_plugin_path;
+
 /*
  * Prints the "out of memory" error.
  */
@@ -780,6 +791,8 @@ void print_usage(FILE *fp)
        fprintf(fp, "      --begin                       Start time: [YYYY-MM-DD [hh:mm:]]ss[.nnnnnnnnn]\n");
        fprintf(fp, "      --end                         End time: [YYYY-MM-DD [hh:mm:]]ss[.nnnnnnnnn]\n");
        fprintf(fp, "      --timerange                   Time range: begin,end or [begin,end] (where [] are actual brackets)\n");
+       fprintf(fp, "      --omit-system-plugin-path     Omit system plugins from plugin search path\n");
+       fprintf(fp, "      --omit-home-plugin-path       Omit home plugins from plugin search path\n");
        fprintf(fp, "  -h  --help                        Show this help\n");
        fprintf(fp, "      --help-legacy                 Show Babeltrace 1.x legacy options\n");
        fprintf(fp, "  -v, --verbose                     Enable verbose output\n");
@@ -954,6 +967,12 @@ end:
        return;
 }
 
+static
+bool is_setuid_setgid(void)
+{
+       return (geteuid() != getuid() || getegid() != getgid());
+}
+
 /*
  * Extracts the various paths from the string arg, delimited by ':',
  * and converts them to an array value object.
@@ -963,18 +982,12 @@ end:
  * Return value is owned by the caller.
  */
 static
-struct bt_value *plugin_paths_from_arg(const char *arg)
+enum bt_value_status plugin_paths_from_arg(struct bt_value *plugin_paths,
+               const char *arg)
 {
-       struct bt_value *plugin_paths;
        const char *at = arg;
        const char *end = arg + strlen(arg);
 
-       plugin_paths = bt_value_array_create();
-       if (!plugin_paths) {
-               print_err_oom();
-               goto error;
-       }
-
        while (at < end) {
                int ret;
                GString *path;
@@ -1009,13 +1022,9 @@ struct bt_value *plugin_paths_from_arg(const char *arg)
                }
        }
 
-       goto end;
-
+       return BT_VALUE_STATUS_OK;
 error:
-       BT_PUT(plugin_paths);
-
-end:
-       return plugin_paths;
+       return BT_VALUE_STATUS_ERROR;
 }
 
 /*
@@ -2003,14 +2012,12 @@ bool validate_cfg(struct bt_config *cfg,
 
        /* Determine if the input and output should be legacy-style */
        if (*legacy_input_format != LEGACY_INPUT_FORMAT_NONE ||
-                       cfg->sources->len == 0 ||
                        !bt_value_array_is_empty(legacy_input_paths) ||
                        ctf_legacy_opts_is_any_set(ctf_legacy_opts)) {
                legacy_input = true;
        }
 
        if (*legacy_output_format != LEGACY_OUTPUT_FORMAT_NONE ||
-                       cfg->sinks->len == 0 ||
                        text_legacy_opts_is_any_set(text_legacy_opts)) {
                legacy_output = true;
        }
@@ -2143,6 +2150,8 @@ enum {
        OPT_TIMERANGE,
        OPT_VERBOSE,
        OPT_VERSION,
+       OPT_OMIT_SYSTEM_PLUGIN_PATH,
+       OPT_OMIT_HOME_PLUGIN_PATH,
 };
 
 /* popt long option descriptions */
@@ -2181,6 +2190,8 @@ static struct poptOption long_options[] = {
        { "timerange", '\0', POPT_ARG_STRING, NULL, OPT_TIMERANGE, NULL, NULL },
        { "verbose", 'v', POPT_ARG_NONE, NULL, OPT_VERBOSE, NULL, NULL },
        { "version", 'V', POPT_ARG_NONE, NULL, OPT_VERSION, NULL, NULL },
+       { "omit-system-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_SYSTEM_PLUGIN_PATH, NULL, NULL },
+       { "omit-home-plugin-path", '\0', POPT_ARG_NONE, NULL, OPT_OMIT_HOME_PLUGIN_PATH, NULL, NULL },
        { NULL, 0, 0, NULL, 0, NULL, NULL },
 };
 
@@ -2246,6 +2257,96 @@ not_found:
        return -1;
 }
 
+static char *bt_secure_getenv(const char *name)
+{
+       if (is_setuid_setgid()) {
+               printf_err("Disregarding %s environment variable for setuid/setgid binary", name);
+               return NULL;
+       }
+       return getenv(name);
+}
+
+static const char *get_home_dir(void)
+{
+       char *val = NULL;
+       struct passwd *pwd;
+
+       val = bt_secure_getenv(HOME_ENV_VAR);
+       if (val) {
+               goto end;
+       }
+       /* Fallback on password file. */
+       pwd = getpwuid(getuid());
+       if (!pwd) {
+               goto end;
+       }
+       val = pwd->pw_dir;
+end:
+       return val;
+}
+
+static int add_internal_plugin_paths(struct bt_config *cfg)
+{
+       if (!omit_home_plugin_path) {
+               char path[PATH_MAX];
+               const char *home_dir;
+
+               if (is_setuid_setgid()) {
+                       printf_debug("Skipping non-system plugin paths for setuid/setgid binary.");
+               } else {
+                       home_dir = get_home_dir();
+                       if (home_dir) {
+                               if (strlen(home_dir) + strlen(HOME_SUBPATH) + 1
+                                               >= PATH_MAX) {
+                                       printf_err("Home directory path too long\n");
+                                       goto error;
+                               }
+                               strcpy(path, home_dir);
+                               strcat(path, HOME_SUBPATH);
+                               if (plugin_paths_from_arg(cfg->plugin_paths, path)) {
+                                       printf_err("Invalid home plugin path\n");
+                                       goto error;
+                               }
+                       }
+               }
+       }
+
+       if (!omit_system_plugin_path) {
+               if (plugin_paths_from_arg(cfg->plugin_paths,
+                               SYSTEM_PLUGIN_PATH)) {
+                       printf_err("Invalid system plugin path\n");
+                       goto error;
+               }
+       }
+       return 0;
+error:
+       return -1;
+}
+
+static int append_sources_from_implicit_params(GPtrArray *sources,
+               struct bt_config_component *implicit_source_comp)
+{
+       size_t i;
+       size_t len = sources->len;
+
+       for (i = 0; i < len; i++) {
+               struct bt_config_component *comp;
+               struct bt_value *params_to_set;
+
+               comp = g_ptr_array_index(sources, i);
+               params_to_set = bt_value_map_extend(comp->params,
+                       implicit_source_comp->params);
+               if (!params_to_set) {
+                       printf_err("Cannot extend legacy component parameters with non-legacy parameters\n");
+                       goto error;
+               }
+               BT_MOVE(comp->params, params_to_set);
+       }
+       return 0;
+error:
+       return -1;
+}
+
 /*
  * Returns a Babeltrace configuration, out of command-line arguments,
  * containing everything that is needed to instanciate specific
@@ -2267,22 +2368,19 @@ struct bt_config *bt_config_from_args(int argc, const char *argv[], int *exit_co
        enum legacy_output_format legacy_output_format =
                LEGACY_OUTPUT_FORMAT_NONE;
        struct bt_value *legacy_input_paths = NULL;
+       struct bt_config_component *implicit_source_comp = NULL;
        struct bt_config_component *cur_cfg_comp = NULL;
+       bool cur_is_implicit_source = false;
+       bool use_implicit_source = false;
        enum bt_config_component_dest cur_cfg_comp_dest =
                BT_CONFIG_COMPONENT_DEST_SOURCE;
        struct bt_value *cur_base_params = NULL;
-       int opt;
-       bool cur_cfg_comp_params_set = false;
+       int opt, nr_omit_opt = 0;
 
        memset(&ctf_legacy_opts, 0, sizeof(ctf_legacy_opts));
        memset(&text_legacy_opts, 0, sizeof(text_legacy_opts));
        *exit_code = 0;
 
-       if (argc <= 1) {
-               print_usage(stdout);
-               goto end;
-       }
-
        text_legacy_opts.output = g_string_new(NULL);
        if (!text_legacy_opts.output) {
                print_err_oom();
@@ -2333,6 +2431,23 @@ struct bt_config *bt_config_from_args(int argc, const char *argv[], int *exit_co
                goto error;
        }
 
+       /* Note: implicit source never gets positional base params. */
+       implicit_source_comp = bt_config_component_from_arg(DEFAULT_SOURCE_COMPONENT_NAME);
+       if (implicit_source_comp) {
+               cur_cfg_comp = implicit_source_comp;
+               cur_is_implicit_source = true;
+               use_implicit_source = true;
+       } else {
+               printf_debug("Cannot find implicit source plugin \"%s\"",
+                       DEFAULT_SOURCE_COMPONENT_NAME);
+       }
+
+       cfg->plugin_paths = bt_value_array_create();
+       if (!cfg->plugin_paths) {
+               print_err_oom();
+               goto error;
+       }
+
        /* Parse options */
        pc = poptGetContext(NULL, argc, (const char **) argv, long_options, 0);
        if (!pc) {
@@ -2347,17 +2462,23 @@ struct bt_config *bt_config_from_args(int argc, const char *argv[], int *exit_co
 
                switch (opt) {
                case OPT_PLUGIN_PATH:
-                       if (cfg->plugin_paths) {
-                               printf_err("Duplicate --plugin-path option\n");
-                               goto error;
-                       }
-
-                       cfg->plugin_paths = plugin_paths_from_arg(arg);
-                       if (!cfg->plugin_paths) {
-                               printf_err("Invalid --plugin-path option's argument\n");
-                               goto error;
+                       if (is_setuid_setgid()) {
+                               printf_debug("Skipping non-system plugin paths for setuid/setgid binary.");
+                       } else {
+                               if (plugin_paths_from_arg(cfg->plugin_paths, arg)) {
+                                       printf_err("Invalid --plugin-path option's argument\n");
+                                       goto error;
+                               }
                        }
                        break;
+               case OPT_OMIT_SYSTEM_PLUGIN_PATH:
+                       omit_system_plugin_path = true;
+                       nr_omit_opt += 2;
+                       break;
+               case OPT_OMIT_HOME_PLUGIN_PATH:
+                       omit_home_plugin_path = true;
+                       nr_omit_opt += 2;
+                       break;
                case OPT_OUTPUT_PATH:
                        if (text_legacy_opts.output->len > 0) {
                                printf_err("Duplicate --output option\n");
@@ -2409,8 +2530,10 @@ struct bt_config *bt_config_from_args(int argc, const char *argv[], int *exit_co
                                }
                        }
 
+                       use_implicit_source = false;
+
                        /* Non-legacy: try to create a component config */
-                       if (cur_cfg_comp) {
+                       if (cur_cfg_comp && !cur_is_implicit_source) {
                                add_cfg_comp(cfg, cur_cfg_comp,
                                        cur_cfg_comp_dest);
                        }
@@ -2421,17 +2544,17 @@ struct bt_config *bt_config_from_args(int argc, const char *argv[], int *exit_co
                                        arg);
                                goto error;
                        }
+                       cur_is_implicit_source = false;
 
                        assert(cur_base_params);
                        bt_put(cur_cfg_comp->params);
                        cur_cfg_comp->params = bt_value_copy(cur_base_params);
-                       if (!cur_cfg_comp) {
+                       if (!cur_cfg_comp->params) {
                                print_err_oom();
                                goto end;
                        }
 
                        cur_cfg_comp_dest = BT_CONFIG_COMPONENT_DEST_SOURCE;
-                       cur_cfg_comp_params_set = false;
                        break;
                }
                case OPT_OUTPUT_FORMAT:
@@ -2472,7 +2595,7 @@ struct bt_config *bt_config_from_args(int argc, const char *argv[], int *exit_co
                        }
 
                        /* Non-legacy: try to create a component config */
-                       if (cur_cfg_comp) {
+                       if (cur_cfg_comp && !cur_is_implicit_source) {
                                add_cfg_comp(cfg, cur_cfg_comp,
                                        cur_cfg_comp_dest);
                        }
@@ -2483,17 +2606,17 @@ struct bt_config *bt_config_from_args(int argc, const char *argv[], int *exit_co
                                        arg);
                                goto error;
                        }
+                       cur_is_implicit_source = false;
 
                        assert(cur_base_params);
                        bt_put(cur_cfg_comp->params);
                        cur_cfg_comp->params = bt_value_copy(cur_base_params);
-                       if (!cur_cfg_comp) {
+                       if (!cur_cfg_comp->params) {
                                print_err_oom();
                                goto end;
                        }
 
                        cur_cfg_comp_dest = BT_CONFIG_COMPONENT_DEST_SINK;
-                       cur_cfg_comp_params_set = false;
                        break;
                }
                case OPT_PARAMS:
@@ -2502,14 +2625,8 @@ struct bt_config *bt_config_from_args(int argc, const char *argv[], int *exit_co
                        struct bt_value *params_to_set;
 
                        if (!cur_cfg_comp) {
-                               printf_err("--params option must follow a --source or --sink option\n");
-                               goto error;
-                       }
-
-                       if (cur_cfg_comp_params_set) {
-                               printf_err("Duplicate --params option for the same current component\ninstance (class %s.%s)\n",
-                                       cur_cfg_comp->plugin_name->str,
-                                       cur_cfg_comp->component_name->str);
+                               printf_err("Can not apply parameter to unavailable default source component \"%s\".\n",
+                                       DEFAULT_SOURCE_COMPONENT_NAME);
                                goto error;
                        }
 
@@ -2520,22 +2637,22 @@ struct bt_config *bt_config_from_args(int argc, const char *argv[], int *exit_co
                                goto error;
                        }
 
-                       params_to_set = bt_value_map_extend(cur_base_params,
+                       params_to_set = bt_value_map_extend(cur_cfg_comp->params,
                                params);
                        BT_PUT(params);
                        if (!params_to_set) {
-                               printf_err("Cannot extend current base parameters with --params option's argument:\n    %s\n",
+                               printf_err("Cannot extend current component parameters with --params option's argument:\n    %s\n",
                                        arg);
                                goto error;
                        }
 
                        BT_MOVE(cur_cfg_comp->params, params_to_set);
-                       cur_cfg_comp_params_set = true;
                        break;
                }
                case OPT_PATH:
                        if (!cur_cfg_comp) {
-                               printf_err("--path option must follow a --source or --sink option\n");
+                               printf_err("Can not apply parameter to unavailable default source component \"%s\".\n",
+                                       DEFAULT_SOURCE_COMPONENT_NAME);
                                goto error;
                        }
 
@@ -2652,8 +2769,8 @@ struct bt_config *bt_config_from_args(int argc, const char *argv[], int *exit_co
                        break;
                case OPT_BEGIN:
                        if (!cur_cfg_comp) {
-                               //TODO
-                               printf_err("Unimplemented: apply to default source\n");
+                               printf_err("Can not apply parameter to unavailable default source component \"%s\".\n",
+                                       DEFAULT_SOURCE_COMPONENT_NAME);
                                goto error;
                        }
                        if (cur_cfg_comp_dest != BT_CONFIG_COMPONENT_DEST_SOURCE) {
@@ -2668,8 +2785,8 @@ struct bt_config *bt_config_from_args(int argc, const char *argv[], int *exit_co
                        break;
                case OPT_END:
                        if (!cur_cfg_comp) {
-                               //TODO
-                               printf_err("Unimplemented: apply to default source\n");
+                               printf_err("Can not apply parameter to unavailable default source component \"%s\".\n",
+                                       DEFAULT_SOURCE_COMPONENT_NAME);
                                goto error;
                        }
                        if (cur_cfg_comp_dest != BT_CONFIG_COMPONENT_DEST_SOURCE) {
@@ -2687,8 +2804,8 @@ struct bt_config *bt_config_from_args(int argc, const char *argv[], int *exit_co
                        const char *begin, *end;
 
                        if (!cur_cfg_comp) {
-                               //TODO
-                               printf_err("Unimplemented: apply to default source\n");
+                               printf_err("Can not apply parameter to unavailable default source component \"%s\".\n",
+                                       DEFAULT_SOURCE_COMPONENT_NAME);
                                goto error;
                        }
                        if (cur_cfg_comp_dest != BT_CONFIG_COMPONENT_DEST_SOURCE) {
@@ -2742,10 +2859,9 @@ struct bt_config *bt_config_from_args(int argc, const char *argv[], int *exit_co
                arg = NULL;
        }
 
-       /* Append current component configuration, if any */
-       if (cur_cfg_comp) {
-               add_cfg_comp(cfg, cur_cfg_comp, cur_cfg_comp_dest);
-               cur_cfg_comp = NULL;
+       if (argc - nr_omit_opt <= 1) {
+               print_usage(stdout);
+               goto put_cfg;
        }
 
        /* Check for option parsing error */
@@ -2770,6 +2886,16 @@ struct bt_config *bt_config_from_args(int argc, const char *argv[], int *exit_co
                }
        }
 
+       if (add_internal_plugin_paths(cfg)) {
+               goto error;
+       }
+
+       /* Append current component configuration, if any */
+       if (cur_cfg_comp && !cur_is_implicit_source) {
+               add_cfg_comp(cfg, cur_cfg_comp, cur_cfg_comp_dest);
+       }
+       cur_cfg_comp = NULL;
+
        /* Validate legacy/non-legacy options */
        if (!validate_cfg(cfg, &legacy_input_format, &legacy_output_format,
                        legacy_input_paths, &ctf_legacy_opts,
@@ -2789,6 +2915,24 @@ struct bt_config *bt_config_from_args(int argc, const char *argv[], int *exit_co
                        printf_err("Cannot convert legacy input format options to source component instance(s)\n");
                        goto error;
                }
+               if (append_sources_from_implicit_params(cfg->sources,
+                               implicit_source_comp)) {
+                       printf_err("Cannot initialize legacy component parameters\n");
+                       goto error;
+               }
+               use_implicit_source = false;
+       } else {
+               if (use_implicit_source) {
+                       add_cfg_comp(cfg, implicit_source_comp,
+                               BT_CONFIG_COMPONENT_DEST_SOURCE);
+                       implicit_source_comp = NULL;
+               } else {
+                       if (implicit_source_comp
+                                       && !bt_value_map_is_empty(implicit_source_comp->params)) {
+                               printf_err("Arguments specified for implicit source, but an explicit source has been specified, overriding it\n");
+                               goto error;
+                       }
+               }
        }
 
        /*
@@ -2803,13 +2947,25 @@ struct bt_config *bt_config_from_args(int argc, const char *argv[], int *exit_co
                }
        }
 
+       if (cfg->sinks->len == 0) {
+               /* Use implicit sink as default. */
+               cur_cfg_comp = bt_config_component_from_arg(DEFAULT_SINK_COMPONENT_NAME);
+               if (!cur_cfg_comp) {
+                       printf_error("Cannot find implicit sink plugin \"%s\"\n",
+                               DEFAULT_SINK_COMPONENT_NAME);
+               }
+               add_cfg_comp(cfg, cur_cfg_comp,
+                       BT_CONFIG_COMPONENT_DEST_SINK);
+               cur_cfg_comp = NULL;
+       }
+
        goto end;
 
 error:
+       *exit_code = 1;
+put_cfg:
        BT_PUT(cfg);
        cfg = NULL;
-       *exit_code = 1;
-
 end:
        if (pc) {
                poptFreeContext(pc);
@@ -2828,6 +2984,7 @@ end:
        }
 
        free(arg);
+       BT_PUT(implicit_source_comp);
        BT_PUT(cur_cfg_comp);
        BT_PUT(cur_base_params);
        BT_PUT(text_legacy_opts.names);
This page took 0.033092 seconds and 4 git commands to generate.