From eac144acdaca02f018bddde5f623fba3e8cd4ad9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?louiz=E2=80=99?= <louiz@louiz.org>
Date: Fri, 21 Apr 2017 11:19:36 +0200
Subject: Configuration options can be overridden by setting env values

---
 CHANGELOG.rst         |  1 +
 doc/biboumi.1.rst     | 10 +++++++---
 src/config/config.cpp | 46 +++++++++++++++++++++++++++++++++++-----------
 3 files changed, 43 insertions(+), 14 deletions(-)

diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 74d60f1..1e94d6c 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -14,6 +14,7 @@ Version 5.0
  - If the client doesn’t specify any limit, MAM results contain at most 100
    messages, instead of the whole archive.
  - Multiline topics are now properly handled
+ - Configuration options can be overridden by values found in the process env.
 
 Version 4.1 - 2017-03-21
 ========================
diff --git a/doc/biboumi.1.rst b/doc/biboumi.1.rst
index 3eaf235..aeeefec 100644
--- a/doc/biboumi.1.rst
+++ b/doc/biboumi.1.rst
@@ -35,15 +35,19 @@ details on its content.
 Configuration
 =============
 
-The configuration file uses a simple format of the form
-``option=value``.
+The configuration file uses a simple format of the form ``option=value``.
+
+The values from the configuration file can be overridden by environment
+variables, with the name all in upper case and prefixed with "BIBOUMI_".
+For example, if the environment contains “BIBOUMI_PASSWORD=blah", this will
+override the value of the “password” option in the configuration file.
 
 Sending SIGUSR1 or SIGUSR2 (see kill(1)) to the process will force it to
 re-read the configuration and make it close and re-open the log files. You
 can use this to change any configuration option at runtime, or do a log
 rotation.
 
-Here is a description of each possible option:
+Here is a description of every possible option:
 
 hostname
 --------
diff --git a/src/config/config.cpp b/src/config/config.cpp
index 0db5751..0f3d639 100644
--- a/src/config/config.cpp
+++ b/src/config/config.cpp
@@ -1,10 +1,15 @@
 #include <config/config.hpp>
+#include <utils/tolower.hpp>
 
 #include <iostream>
 #include <cstring>
 
 #include <cstdlib>
 
+using namespace std::string_literals;
+
+extern char** environ;
+
 std::string Config::filename{};
 std::map<std::string, std::string> Config::values{};
 std::vector<t_config_changed_callback> Config::callbacks{};
@@ -71,21 +76,40 @@ bool Config::read_conf(const std::string& name)
 
   Config::clear();
 
+  auto parse_line = [](const std::string& line, const bool env)
+  {
+    static const auto env_option_prefix = "BIBOUMI_"s;
+
+    if (line == "" || line[0] == '#')
+      return;
+    size_t pos = line.find('=');
+    if (pos == std::string::npos)
+      return;
+    std::string option = line.substr(0, pos);
+    std::string value = line.substr(pos+1);
+    if (env)
+      {
+        auto a = option.substr(0, env_option_prefix.size());
+        if (a == env_option_prefix)
+          option = utils::tolower(option.substr(env_option_prefix.size()));
+        else
+          return;
+      }
+    Config::values[option] = value;
+  };
+
   std::string line;
-  size_t pos;
-  std::string option;
-  std::string value;
   while (file.good())
     {
       std::getline(file, line);
-      if (line == "" || line[0] == '#')
-        continue ;
-      pos = line.find('=');
-      if (pos == std::string::npos)
-        continue ;
-      option = line.substr(0, pos);
-      value = line.substr(pos+1);
-      Config::values[option] = value;
+      parse_line(line, false);
+    }
+
+  char** env_line = environ;
+  while (*env_line)
+    {
+      parse_line(*env_line, true);
+      env_line++;
     }
   return true;
 }
-- 
cgit v1.2.3