commit:     c09eeca49145b034df6527c500099ba22f28e824
Author:     William Hubbs <w.d.hubbs <AT> gmail <DOT> com>
AuthorDate: Fri Oct 30 17:32:32 2015 +0000
Commit:     William Hubbs <williamh <AT> gentoo <DOT> org>
CommitDate: Thu Nov  5 16:40:24 2015 +0000
URL:        https://gitweb.gentoo.org/proj/openrc.git/commit/?id=c09eeca4

Add rc.conf.d support

This makes it possible to override settings in rc.conf by adding a
directory @SYSCONFDIR <AT> /rc.conf.d and putting files in this directory.
The files will be processed in lexical order, and the last setting in
these files will be used.

 sh/openrc-run.sh.in    |   6 +++
 src/librc/librc-misc.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/librc/rc.h.in      |   1 +
 3 files changed, 110 insertions(+)

diff --git a/sh/openrc-run.sh.in b/sh/openrc-run.sh.in
index 8aba4e0..749af2c 100644
--- a/sh/openrc-run.sh.in
+++ b/sh/openrc-run.sh.in
@@ -184,6 +184,12 @@ unset _conf_d
 
 # Load any system overrides
 sourcex -e "@SYSCONFDIR@/rc.conf"
+if [ -d "@SYSCONFDIR@/rc.conf.d" ]; then
+       for _f in "@SYSCONFDIR@"/rc.conf.d/*.conf; do
+               sourcex -e "$_f"
+       done
+fi
+
 
 # load service supervisor functions
 sourcex "@LIBEXECDIR@/sh/s6.sh"

diff --git a/src/librc/librc-misc.c b/src/librc/librc-misc.c
index 2e9de80..1eedc96 100644
--- a/src/librc/librc-misc.c
+++ b/src/librc/librc-misc.c
@@ -28,6 +28,8 @@
  * SUCH DAMAGE.
  */
 
+#include <fnmatch.h>
+
 #include "queue.h"
 #include "librc.h"
 
@@ -214,6 +216,69 @@ rc_config_list(const char *file)
 }
 librc_hidden_def(rc_config_list)
 
+static void rc_config_set_value(RC_STRINGLIST *config, char *value)
+{
+       RC_STRING *cline;
+       char *entry;
+       size_t i = 0;
+       char *newline;
+       char *p = value;
+       bool replaced;
+       char *token;
+
+       if (! p)
+               return;
+       if (strncmp(p, "export ", 7) == 0)
+               p += 7;
+       if (! (token = strsep(&p, "=")))
+               return;
+
+       entry = xstrdup(token);
+       /* Preserve shell coloring */
+       if (*p == '$')
+               token = value;
+       else
+               do {
+                       /* Bash variables are usually quoted */
+                       token = strsep(&p, "\"\'");
+               } while (token && *token == '\0');
+
+       /* Drop a newline if that's all we have */
+       if (token) {
+               i = strlen(token) - 1;
+               if (token[i] == '\n')
+                       token[i] = 0;
+
+               i = strlen(entry) + strlen(token) + 2;
+               newline = xmalloc(sizeof(char) * i);
+               snprintf(newline, i, "%s=%s", entry, token);
+       } else {
+               i = strlen(entry) + 2;
+               newline = xmalloc(sizeof(char) * i);
+               snprintf(newline, i, "%s=", entry);
+       }
+
+       replaced = false;
+       /* In shells the last item takes precedence, so we need to remove
+          any prior values we may already have */
+       TAILQ_FOREACH(cline, config, entries) {
+               i = strlen(entry);
+               if (strncmp(entry, cline->value, i) == 0 && cline->value[i] == 
'=') {
+                       /* We have a match now - to save time we directly 
replace it */
+                       free(cline->value);
+                       cline->value = newline;
+                       replaced = true;
+                       break;
+               }
+       }
+
+       if (!replaced) {
+               rc_stringlist_add(config, newline);
+               free(newline);
+       }
+       free(entry);
+}
+
 /*
  * Override some specific rc.conf options on the kernel command line
  */
@@ -272,6 +337,42 @@ static RC_STRINGLIST *rc_config_override(RC_STRINGLIST 
*config)
 }
 #endif
 
+static RC_STRINGLIST * rc_config_directory(RC_STRINGLIST *config)
+{
+       DIR *dp;
+       struct dirent *d;
+       RC_STRINGLIST *rc_conf_d_files = rc_stringlist_new();
+       RC_STRING *fname;
+       RC_STRINGLIST *rc_conf_d_list;
+       char path[PATH_MAX];
+       RC_STRING *line;
+
+       if ((dp = opendir(RC_CONF_D)) != NULL) {
+               while ((d = readdir(dp)) != NULL) {
+                       if (fnmatch("*.conf", d->d_name, FNM_PATHNAME) == 0) {
+                               rc_stringlist_addu(rc_conf_d_files, d->d_name);
+                       }
+               }
+               closedir(dp);
+
+               if (rc_conf_d_files) {
+                       rc_stringlist_sort(&rc_conf_d_files);
+                       TAILQ_FOREACH(fname, rc_conf_d_files, entries) {
+                               if (! fname->value)
+                                       continue;
+                               sprintf(path, "%s/%s", RC_CONF_D, fname->value);
+                               rc_conf_d_list = rc_config_list(path);
+                               TAILQ_FOREACH(line, rc_conf_d_list, entries)
+                                       if (line->value)
+                                               rc_config_set_value(config, 
line->value);
+                               rc_stringlist_free(rc_conf_d_list);
+                       }
+                       rc_stringlist_free(rc_conf_d_files);
+               }
+       }
+       return config;
+}
+
 RC_STRINGLIST *
 rc_config_load(const char *file)
 {
@@ -401,6 +502,8 @@ rc_conf_value(const char *setting)
 #endif
                }
 
+               rc_conf = rc_config_directory(rc_conf);
+
                /* Convert old uppercase to lowercase */
                TAILQ_FOREACH(s, rc_conf, entries) {
                        p = s->value;

diff --git a/src/librc/rc.h.in b/src/librc/rc.h.in
index 13e1b5b..e3a586f 100644
--- a/src/librc/rc.h.in
+++ b/src/librc/rc.h.in
@@ -56,6 +56,7 @@ extern "C" {
 #define RC_SYS_WHITELIST   RC_LIBEXECDIR "/conf.d/env_whitelist"
 #define RC_USR_WHITELIST   RC_SYSCONFDIR "/conf.d/env_whitelist"
 #define RC_CONF         RC_SYSCONFDIR "/rc.conf"
+#define RC_CONF_D         RC_SYSCONFDIR "/rc.conf.d"
 #define RC_CONF_OLD     RC_SYSCONFDIR "/conf.d/rc"
 
 #define RC_PATH_PREFIX     RC_LIBEXECDIR "/bin:/bin:/sbin:/usr/bin:/usr/sbin"

Reply via email to