Load relay daemon options from configuration file
authorJérémie Galarneau <jeremie.galarneau@efficios.com>
Mon, 16 Dec 2013 05:47:50 +0000 (00:47 -0500)
committerDavid Goulet <dgoulet@efficios.com>
Tue, 17 Dec 2013 20:10:26 +0000 (15:10 -0500)
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
Signed-off-by: David Goulet <dgoulet@efficios.com>
src/bin/lttng-relayd/Makefile.am
src/bin/lttng-relayd/lttng-relayd.h
src/bin/lttng-relayd/main.c

index 68a1f51667793d3d3e8ebbbd04ef0dbec2fc65ac..331b634b7bf03fa71e8ba0d5f902c3ad2d3f310c 100644 (file)
@@ -23,4 +23,5 @@ lttng_relayd_LDADD = -lrt -lurcu-common -lurcu \
                $(top_builddir)/src/common/libcommon.la \
                $(top_builddir)/src/common/compat/libcompat.la \
                $(top_builddir)/src/common/index/libindex.la \
-               $(top_builddir)/src/common/health/libhealth.la
+               $(top_builddir)/src/common/health/libhealth.la \
+               $(top_builddir)/src/common/config/libconfig.la
index 6840aba31edda4c7c2181613ce35c06d081ca73f..bb5b7a365aaae214a10bd3757e34f1074ce4e81f 100644 (file)
@@ -220,6 +220,8 @@ extern struct lttng_ht *indexes_ht;
 
 extern const char *tracing_group_name;
 
+extern const char * const config_section_name;
+
 struct relay_stream *relay_stream_find_by_id(uint64_t stream_id);
 
 #endif /* LTTNG_RELAYD_H */
index a6b408a90740943138e43ad69160d34a5395baa6..71d11ebdfa2be05c640c869799f553b35b1ea97f 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) 2012 - Julien Desfossez <jdesfossez@efficios.com>
  *                      David Goulet <dgoulet@efficios.com>
+ *               2013 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, version 2 only,
@@ -50,6 +51,7 @@
 #include <common/sessiond-comm/relayd.h>
 #include <common/uri.h>
 #include <common/utils.h>
+#include <common/config/config.h>
 
 #include "cmd.h"
 #include "ctf-trace.h"
@@ -69,6 +71,9 @@ static struct lttng_uri *live_uri;
 const char *progname;
 
 const char *tracing_group_name = DEFAULT_TRACING_GROUP;
+static int tracing_group_name_override;
+
+const char * const config_section_name = "relayd";
 
 /*
  * Quit pipe for all threads. This permits a single cancellation point
@@ -121,6 +126,20 @@ struct lttng_ht *indexes_ht;
 /* Relayd health monitoring */
 struct health_app *health_relayd;
 
+static struct option long_options[] = {
+       { "control-port", 1, 0, 'C', },
+       { "data-port", 1, 0, 'D', },
+       { "daemonize", 0, 0, 'd', },
+       { "group", 1, 0, 'g', },
+       { "help", 0, 0, 'h', },
+       { "output", 1, 0, 'o', },
+       { "verbose", 0, 0, 'v', },
+       { "config", 1, 0, 'f' },
+       { NULL, 0, 0, 0, },
+};
+
+static const char *config_ignore_options[] = { "help", "config" };
+
 /*
  * usage function on stderr
  */
@@ -135,85 +154,196 @@ void usage(void)
        fprintf(stderr, "  -o, --output PATH         Output path for traces. Must use an absolute path.\n");
        fprintf(stderr, "  -v, --verbose             Verbose mode. Activate DBG() macro.\n");
        fprintf(stderr, "  -g, --group NAME          Specify the tracing group name. (default: tracing)\n");
+       fprintf(stderr, "  -f  --config              Load daemon configuration file\n");
 }
 
+/*
+ * Take an option from the getopt output and set it in the right variable to be
+ * used later.
+ *
+ * Return 0 on success else a negative value.
+ */
 static
-int parse_args(int argc, char **argv)
+int set_option(int opt, const char *arg, const char *optname)
 {
-       int c;
-       int ret = 0;
-       char *default_address;
-
-       static struct option long_options[] = {
-               { "control-port", 1, 0, 'C', },
-               { "data-port", 1, 0, 'D', },
-               { "daemonize", 0, 0, 'd', },
-               { "group", 1, 0, 'g', },
-               { "help", 0, 0, 'h', },
-               { "output", 1, 0, 'o', },
-               { "verbose", 0, 0, 'v', },
-               { NULL, 0, 0, 0, },
-       };
+       int ret;
+
+       switch (opt) {
+       case 0:
+               fprintf(stderr, "option %s", optname);
+               if (arg) {
+                       fprintf(stderr, " with arg %s\n", arg);
+               }
+               break;
+       case 'C':
+               ret = uri_parse(arg, &control_uri);
+               if (ret < 0) {
+                       ERR("Invalid control URI specified");
+                       goto end;
+               }
+               if (control_uri->port == 0) {
+                       control_uri->port = DEFAULT_NETWORK_CONTROL_PORT;
+               }
+               break;
+       case 'D':
+               ret = uri_parse(arg, &data_uri);
+               if (ret < 0) {
+                       ERR("Invalid data URI specified");
+                       goto end;
+               }
+               if (data_uri->port == 0) {
+                       data_uri->port = DEFAULT_NETWORK_DATA_PORT;
+               }
+               break;
+       case 'd':
+               opt_daemon = 1;
+               break;
+       case 'g':
+               tracing_group_name = strdup(arg);
+               tracing_group_name_override = 1;
+               break;
+       case 'h':
+               usage();
+               exit(EXIT_FAILURE);
+       case 'o':
+               ret = asprintf(&opt_output_path, "%s", arg);
+               if (ret < 0) {
+                       ret = -errno;
+                       PERROR("asprintf opt_output_path");
+                       goto end;
+               }
+               break;
+       case 'v':
+               /* Verbose level can increase using multiple -v */
+               if (arg) {
+                       lttng_opt_verbose = config_parse_value(arg);
+               } else {
+                       lttng_opt_verbose += 1;
+               }
+               break;
+       default:
+               /* Unknown option or other error.
+                * Error is printed by getopt, just return */
+               ret = -1;
+               goto end;
+       }
+
+       /* All good. */
+       ret = 0;
+
+end:
+       return ret;
+}
+
+/*
+ * config_entry_handler_cb used to handle options read from a config file.
+ * See config_entry_handler_cb comment in common/config/config.h for the
+ * return value conventions.
+ */
+static
+int config_entry_handler(const struct config_entry *entry, void *unused)
+{
+       int ret = 0, i;
+
+       if (!entry || !entry->name || !entry->value) {
+               ret = -EINVAL;
+               goto end;
+       }
+
+       /* Check if the option is to be ignored */
+       for (i = 0; i < sizeof(config_ignore_options) / sizeof(char *); i++) {
+               if (!strcmp(entry->name, config_ignore_options[i])) {
+                       goto end;
+               }
+       }
+
+       for (i = 0; i < (sizeof(long_options) / sizeof(struct option)) - 1; i++) {
+               /* Ignore if entry name is not fully matched. */
+               if (strcmp(entry->name, long_options[i].name)) {
+                       continue;
+               }
+
+               /*
+                * If the option takes no argument on the command line, we have to
+                * check if the value is "true". We support non-zero numeric values,
+                * true, on and yes.
+                */
+               if (!long_options[i].has_arg) {
+                       ret = config_parse_value(entry->value);
+                       if (ret <= 0) {
+                               if (ret) {
+                                       WARN("Invalid configuration value \"%s\" for option %s",
+                                                       entry->value, entry->name);
+                               }
+                               /* False, skip boolean config option. */
+                               goto end;
+                       }
+               }
+
+               ret = set_option(long_options[i].val, entry->value, entry->name);
+               goto end;
+       }
+
+       WARN("Unrecognized option \"%s\" in daemon configuration file.",
+                       entry->name);
+
+end:
+       return ret;
+}
+
+static
+int set_options(int argc, char **argv)
+{
+       int c, ret = 0, option_index = 0;
+       int orig_optopt = optopt, orig_optind = optind;
+       char *default_address, *optstring;
+       const char *config_path = NULL;
+
+       optstring = utils_generate_optstring(long_options,
+                       sizeof(long_options) / sizeof(struct option));
+       if (!optstring) {
+               ret = -ENOMEM;
+               goto exit;
+       }
+
+       /* Check for the --config option */
+
+       while ((c = getopt_long(argc, argv, optstring, long_options,
+                                       &option_index)) != -1) {
+               if (c == '?') {
+                       ret = -EINVAL;
+                       goto exit;
+               } else if (c != 'f') {
+                       continue;
+               }
+
+               config_path = utils_expand_path(optarg);
+               if (!config_path) {
+                       ERR("Failed to resolve path: %s", optarg);
+               }
+       }
+
+       ret = config_get_section_entries(config_path, config_section_name,
+                       config_entry_handler, NULL);
+       if (ret) {
+               if (ret > 0) {
+                       ERR("Invalid configuration option at line %i", ret);
+                       ret = -1;
+               }
+               goto exit;
+       }
 
+       /* Reset getopt's global state */
+       optopt = orig_optopt;
+       optind = orig_optind;
        while (1) {
-               int option_index = 0;
-               c = getopt_long(argc, argv, "dhv" "C:D:o:g:",
-                               long_options, &option_index);
+               c = getopt_long(argc, argv, optstring, long_options, &option_index);
                if (c == -1) {
                        break;
                }
 
-               switch (c) {
-               case 0:
-                       fprintf(stderr, "option %s", long_options[option_index].name);
-                       if (optarg) {
-                               fprintf(stderr, " with arg %s\n", optarg);
-                       }
-                       break;
-               case 'C':
-                       ret = uri_parse(optarg, &control_uri);
-                       if (ret < 0) {
-                               ERR("Invalid control URI specified");
-                               goto exit;
-                       }
-                       if (control_uri->port == 0) {
-                               control_uri->port = DEFAULT_NETWORK_CONTROL_PORT;
-                       }
-                       break;
-               case 'D':
-                       ret = uri_parse(optarg, &data_uri);
-                       if (ret < 0) {
-                               ERR("Invalid data URI specified");
-                               goto exit;
-                       }
-                       if (data_uri->port == 0) {
-                               data_uri->port = DEFAULT_NETWORK_DATA_PORT;
-                       }
-                       break;
-               case 'd':
-                       opt_daemon = 1;
-                       break;
-               case 'g':
-                       tracing_group_name = optarg;
-                       break;
-               case 'h':
-                       usage();
-                       exit(EXIT_FAILURE);
-               case 'o':
-                       ret = asprintf(&opt_output_path, "%s", optarg);
-                       if (ret < 0) {
-                               PERROR("asprintf opt_output_path");
-                               goto exit;
-                       }
-                       break;
-               case 'v':
-                       /* Verbose level can increase using multiple -v */
-                       lttng_opt_verbose += 1;
-                       break;
-               default:
-                       /* Unknown option or other error.
-                        * Error is printed by getopt, just return */
-                       ret = -1;
+               ret = set_option(c, optarg, long_options[option_index].name);
+               if (ret < 0) {
                        goto exit;
                }
        }
@@ -266,6 +396,7 @@ int parse_args(int argc, char **argv)
        }
 
 exit:
+       free(optstring);
        return ret;
 }
 
@@ -285,6 +416,10 @@ void cleanup(void)
 
        uri_free(control_uri);
        uri_free(data_uri);
+
+       if (tracing_group_name_override) {
+               free((void *) tracing_group_name);
+       }
 }
 
 /*
@@ -2555,7 +2690,7 @@ int main(int argc, char **argv)
 
        /* Parse arguments */
        progname = argv[0];
-       if ((ret = parse_args(argc, argv)) < 0) {
+       if ((ret = set_options(argc, argv)) < 0) {
                goto exit;
        }
 
This page took 0.04342 seconds and 4 git commands to generate.