Fix: print usage even if omit arguments are received
[babeltrace.git] / converter / babeltrace-cfg.c
index 804b73390ac745b83e45cb63b17728e55e7bfc8f..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
@@ -142,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.
  */
@@ -782,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");
@@ -956,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.
@@ -965,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;
@@ -1011,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;
 }
 
 /*
@@ -2005,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;
        }
@@ -2145,6 +2150,8 @@ enum {
        OPT_TIMERANGE,
        OPT_VERBOSE,
        OPT_VERSION,
+       OPT_OMIT_SYSTEM_PLUGIN_PATH,
+       OPT_OMIT_HOME_PLUGIN_PATH,
 };
 
 /* popt long option descriptions */
@@ -2183,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 },
 };
 
@@ -2248,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
@@ -2276,18 +2375,12 @@ struct bt_config *bt_config_from_args(int argc, const char *argv[], int *exit_co
        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();
@@ -2349,6 +2442,12 @@ struct bt_config *bt_config_from_args(int argc, const char *argv[], int *exit_co
                        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) {
@@ -2363,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");
@@ -2444,13 +2549,12 @@ struct bt_config *bt_config_from_args(int argc, const char *argv[], int *exit_co
                        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:
@@ -2507,13 +2611,12 @@ struct bt_config *bt_config_from_args(int argc, const char *argv[], int *exit_co
                        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:
@@ -2527,13 +2630,6 @@ struct bt_config *bt_config_from_args(int argc, const char *argv[], int *exit_co
                                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);
-                               goto error;
-                       }
-
                        params = bt_value_from_arg(arg);
                        if (!params) {
                                printf_err("Invalid format for --params option's argument:\n    %s\n",
@@ -2541,17 +2637,16 @@ 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:
@@ -2764,22 +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 && !cur_is_implicit_source) {
-               add_cfg_comp(cfg, cur_cfg_comp, cur_cfg_comp_dest);
-       }
-       cur_cfg_comp = NULL;
-
-       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;
-               }
+       if (argc - nr_omit_opt <= 1) {
+               print_usage(stdout);
+               goto put_cfg;
        }
 
        /* Check for option parsing error */
@@ -2804,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,
@@ -2823,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;
+                       }
+               }
        }
 
        /*
@@ -2837,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);
This page took 0.029042 seconds and 4 git commands to generate.