1 |
commit: c09eeca49145b034df6527c500099ba22f28e824 |
2 |
Author: William Hubbs <w.d.hubbs <AT> gmail <DOT> com> |
3 |
AuthorDate: Fri Oct 30 17:32:32 2015 +0000 |
4 |
Commit: William Hubbs <williamh <AT> gentoo <DOT> org> |
5 |
CommitDate: Thu Nov 5 16:40:24 2015 +0000 |
6 |
URL: https://gitweb.gentoo.org/proj/openrc.git/commit/?id=c09eeca4 |
7 |
|
8 |
Add rc.conf.d support |
9 |
|
10 |
This makes it possible to override settings in rc.conf by adding a |
11 |
directory @SYSCONFDIR <AT> /rc.conf.d and putting files in this directory. |
12 |
The files will be processed in lexical order, and the last setting in |
13 |
these files will be used. |
14 |
|
15 |
sh/openrc-run.sh.in | 6 +++ |
16 |
src/librc/librc-misc.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++ |
17 |
src/librc/rc.h.in | 1 + |
18 |
3 files changed, 110 insertions(+) |
19 |
|
20 |
diff --git a/sh/openrc-run.sh.in b/sh/openrc-run.sh.in |
21 |
index 8aba4e0..749af2c 100644 |
22 |
--- a/sh/openrc-run.sh.in |
23 |
+++ b/sh/openrc-run.sh.in |
24 |
@@ -184,6 +184,12 @@ unset _conf_d |
25 |
|
26 |
# Load any system overrides |
27 |
sourcex -e "@SYSCONFDIR@/rc.conf" |
28 |
+if [ -d "@SYSCONFDIR@/rc.conf.d" ]; then |
29 |
+ for _f in "@SYSCONFDIR@"/rc.conf.d/*.conf; do |
30 |
+ sourcex -e "$_f" |
31 |
+ done |
32 |
+fi |
33 |
+ |
34 |
|
35 |
# load service supervisor functions |
36 |
sourcex "@LIBEXECDIR@/sh/s6.sh" |
37 |
|
38 |
diff --git a/src/librc/librc-misc.c b/src/librc/librc-misc.c |
39 |
index 2e9de80..1eedc96 100644 |
40 |
--- a/src/librc/librc-misc.c |
41 |
+++ b/src/librc/librc-misc.c |
42 |
@@ -28,6 +28,8 @@ |
43 |
* SUCH DAMAGE. |
44 |
*/ |
45 |
|
46 |
+#include <fnmatch.h> |
47 |
+ |
48 |
#include "queue.h" |
49 |
#include "librc.h" |
50 |
|
51 |
@@ -214,6 +216,69 @@ rc_config_list(const char *file) |
52 |
} |
53 |
librc_hidden_def(rc_config_list) |
54 |
|
55 |
+static void rc_config_set_value(RC_STRINGLIST *config, char *value) |
56 |
+{ |
57 |
+ RC_STRING *cline; |
58 |
+ char *entry; |
59 |
+ size_t i = 0; |
60 |
+ char *newline; |
61 |
+ char *p = value; |
62 |
+ bool replaced; |
63 |
+ char *token; |
64 |
+ |
65 |
+ if (! p) |
66 |
+ return; |
67 |
+ if (strncmp(p, "export ", 7) == 0) |
68 |
+ p += 7; |
69 |
+ if (! (token = strsep(&p, "="))) |
70 |
+ return; |
71 |
+ |
72 |
+ entry = xstrdup(token); |
73 |
+ /* Preserve shell coloring */ |
74 |
+ if (*p == '$') |
75 |
+ token = value; |
76 |
+ else |
77 |
+ do { |
78 |
+ /* Bash variables are usually quoted */ |
79 |
+ token = strsep(&p, "\"\'"); |
80 |
+ } while (token && *token == '\0'); |
81 |
+ |
82 |
+ /* Drop a newline if that's all we have */ |
83 |
+ if (token) { |
84 |
+ i = strlen(token) - 1; |
85 |
+ if (token[i] == '\n') |
86 |
+ token[i] = 0; |
87 |
+ |
88 |
+ i = strlen(entry) + strlen(token) + 2; |
89 |
+ newline = xmalloc(sizeof(char) * i); |
90 |
+ snprintf(newline, i, "%s=%s", entry, token); |
91 |
+ } else { |
92 |
+ i = strlen(entry) + 2; |
93 |
+ newline = xmalloc(sizeof(char) * i); |
94 |
+ snprintf(newline, i, "%s=", entry); |
95 |
+ } |
96 |
+ |
97 |
+ replaced = false; |
98 |
+ /* In shells the last item takes precedence, so we need to remove |
99 |
+ any prior values we may already have */ |
100 |
+ TAILQ_FOREACH(cline, config, entries) { |
101 |
+ i = strlen(entry); |
102 |
+ if (strncmp(entry, cline->value, i) == 0 && cline->value[i] == '=') { |
103 |
+ /* We have a match now - to save time we directly replace it */ |
104 |
+ free(cline->value); |
105 |
+ cline->value = newline; |
106 |
+ replaced = true; |
107 |
+ break; |
108 |
+ } |
109 |
+ } |
110 |
+ |
111 |
+ if (!replaced) { |
112 |
+ rc_stringlist_add(config, newline); |
113 |
+ free(newline); |
114 |
+ } |
115 |
+ free(entry); |
116 |
+} |
117 |
+ |
118 |
/* |
119 |
* Override some specific rc.conf options on the kernel command line |
120 |
*/ |
121 |
@@ -272,6 +337,42 @@ static RC_STRINGLIST *rc_config_override(RC_STRINGLIST *config) |
122 |
} |
123 |
#endif |
124 |
|
125 |
+static RC_STRINGLIST * rc_config_directory(RC_STRINGLIST *config) |
126 |
+{ |
127 |
+ DIR *dp; |
128 |
+ struct dirent *d; |
129 |
+ RC_STRINGLIST *rc_conf_d_files = rc_stringlist_new(); |
130 |
+ RC_STRING *fname; |
131 |
+ RC_STRINGLIST *rc_conf_d_list; |
132 |
+ char path[PATH_MAX]; |
133 |
+ RC_STRING *line; |
134 |
+ |
135 |
+ if ((dp = opendir(RC_CONF_D)) != NULL) { |
136 |
+ while ((d = readdir(dp)) != NULL) { |
137 |
+ if (fnmatch("*.conf", d->d_name, FNM_PATHNAME) == 0) { |
138 |
+ rc_stringlist_addu(rc_conf_d_files, d->d_name); |
139 |
+ } |
140 |
+ } |
141 |
+ closedir(dp); |
142 |
+ |
143 |
+ if (rc_conf_d_files) { |
144 |
+ rc_stringlist_sort(&rc_conf_d_files); |
145 |
+ TAILQ_FOREACH(fname, rc_conf_d_files, entries) { |
146 |
+ if (! fname->value) |
147 |
+ continue; |
148 |
+ sprintf(path, "%s/%s", RC_CONF_D, fname->value); |
149 |
+ rc_conf_d_list = rc_config_list(path); |
150 |
+ TAILQ_FOREACH(line, rc_conf_d_list, entries) |
151 |
+ if (line->value) |
152 |
+ rc_config_set_value(config, line->value); |
153 |
+ rc_stringlist_free(rc_conf_d_list); |
154 |
+ } |
155 |
+ rc_stringlist_free(rc_conf_d_files); |
156 |
+ } |
157 |
+ } |
158 |
+ return config; |
159 |
+} |
160 |
+ |
161 |
RC_STRINGLIST * |
162 |
rc_config_load(const char *file) |
163 |
{ |
164 |
@@ -401,6 +502,8 @@ rc_conf_value(const char *setting) |
165 |
#endif |
166 |
} |
167 |
|
168 |
+ rc_conf = rc_config_directory(rc_conf); |
169 |
+ |
170 |
/* Convert old uppercase to lowercase */ |
171 |
TAILQ_FOREACH(s, rc_conf, entries) { |
172 |
p = s->value; |
173 |
|
174 |
diff --git a/src/librc/rc.h.in b/src/librc/rc.h.in |
175 |
index 13e1b5b..e3a586f 100644 |
176 |
--- a/src/librc/rc.h.in |
177 |
+++ b/src/librc/rc.h.in |
178 |
@@ -56,6 +56,7 @@ extern "C" { |
179 |
#define RC_SYS_WHITELIST RC_LIBEXECDIR "/conf.d/env_whitelist" |
180 |
#define RC_USR_WHITELIST RC_SYSCONFDIR "/conf.d/env_whitelist" |
181 |
#define RC_CONF RC_SYSCONFDIR "/rc.conf" |
182 |
+#define RC_CONF_D RC_SYSCONFDIR "/rc.conf.d" |
183 |
#define RC_CONF_OLD RC_SYSCONFDIR "/conf.d/rc" |
184 |
|
185 |
#define RC_PATH_PREFIX RC_LIBEXECDIR "/bin:/bin:/sbin:/usr/bin:/usr/sbin" |