]>
Commit | Line | Data |
---|---|---|
12c86877 | 1 | /* |
12471842 PL |
2 | * This file is part of PowerDNS or dnsdist. |
3 | * Copyright -- PowerDNS.COM B.V. and its contributors | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of version 2 of the GNU General Public License as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * In addition, for the avoidance of any doubt, permission is granted to | |
10 | * link this program with OpenSSL and to (re)distribute the binaries | |
11 | * produced as the result of such linking. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
21 | */ | |
870a0fe4 AT |
22 | #ifdef HAVE_CONFIG_H |
23 | #include "config.h" | |
24 | #endif | |
12c86877 | 25 | #include "arguments.hh" |
5b2cb3be | 26 | #include <boost/algorithm/string.hpp> |
2dfec518 | 27 | #include <boost/algorithm/string/compare.hpp> |
4f6ef75f | 28 | #include <boost/algorithm/string/predicate.hpp> |
fa8fd4d2 | 29 | |
61b26744 | 30 | #include "namespaces.hh" |
4f6ef75f | 31 | #include "logger.hh" |
8a16d778 AT |
32 | #include <sys/types.h> |
33 | #include <dirent.h> | |
34 | #include <sys/stat.h> | |
35 | #include <unistd.h> | |
64f3490e | 36 | #include <limits.h> |
12c86877 | 37 | |
12c86877 BH |
38 | const ArgvMap::param_t::const_iterator ArgvMap::begin() |
39 | { | |
9d6e970b | 40 | return d_params.begin(); |
12c86877 BH |
41 | } |
42 | ||
43 | const ArgvMap::param_t::const_iterator ArgvMap::end() | |
44 | { | |
9d6e970b | 45 | return d_params.end(); |
12c86877 BH |
46 | } |
47 | ||
48 | string & ArgvMap::set(const string &var) | |
49 | { | |
9d6e970b | 50 | return d_params[var]; |
12c86877 BH |
51 | } |
52 | ||
8864bdf6 KM |
53 | void ArgvMap::setDefault(const string &var, const string &value) |
54 | { | |
55 | if(! defaultmap.count(var)) | |
56 | defaultmap.insert(pair<string, string>(var, value)); | |
57 | } | |
58 | ||
59 | void ArgvMap::setDefaults() | |
60 | { | |
9d6e970b CH |
61 | for (const auto& i: d_params) |
62 | if(! defaultmap.count(i.first)) | |
63 | defaultmap.insert(i); | |
8864bdf6 KM |
64 | } |
65 | ||
12c86877 | 66 | bool ArgvMap::mustDo(const string &var) |
bd11bd1d | 67 | { |
12c86877 BH |
68 | return ((*this)[var]!="no") && ((*this)[var]!="off"); |
69 | } | |
70 | ||
71 | vector<string>ArgvMap::list() | |
72 | { | |
73 | vector<string> ret; | |
9d6e970b CH |
74 | for (const auto& i: d_params) |
75 | ret.push_back(i.first); | |
12c86877 BH |
76 | return ret; |
77 | } | |
78 | ||
79 | string ArgvMap::getHelp(const string &item) | |
80 | { | |
81 | return helpmap[item]; | |
82 | } | |
83 | ||
84 | string & ArgvMap::set(const string &var, const string &help) | |
85 | { | |
86 | helpmap[var]=help; | |
87 | d_typeMap[var]="Parameter"; | |
88 | return set(var); | |
89 | } | |
90 | ||
91 | void ArgvMap::setCmd(const string &var, const string &help) | |
92 | { | |
93 | helpmap[var]=help; | |
94 | d_typeMap[var]="Command"; | |
95 | set(var)="no"; | |
96 | } | |
97 | ||
98 | string & ArgvMap::setSwitch(const string &var, const string &help) | |
99 | { | |
100 | helpmap[var]=help; | |
101 | d_typeMap[var]="Switch"; | |
102 | return set(var); | |
103 | } | |
104 | ||
105 | ||
12c86877 BH |
106 | bool ArgvMap::contains(const string &var, const string &val) |
107 | { | |
9d6e970b CH |
108 | const auto& param = d_params.find(var); |
109 | if(param == d_params.end() || param->second.empty()) { | |
102eb646 BH |
110 | return false; |
111 | } | |
562588a3 | 112 | vector<string> parts; |
562588a3 | 113 | |
9d6e970b | 114 | stringtok(parts, param->second, ", \t"); |
93a471a3 CHB |
115 | for (const auto& part: parts) { |
116 | if (part == val) { | |
562588a3 BH |
117 | return true; |
118 | } | |
119 | } | |
120 | ||
121 | return false; | |
12c86877 BH |
122 | } |
123 | ||
12c86877 BH |
124 | string ArgvMap::helpstring(string prefix) |
125 | { | |
126 | if(prefix=="no") | |
127 | prefix=""; | |
128 | ||
129 | string help; | |
93a471a3 CHB |
130 | |
131 | for (const auto& i: helpmap) { | |
132 | if(!prefix.empty() && i.first.find(prefix) != 0) // only print items with prefix | |
133 | continue; | |
12c86877 BH |
134 | |
135 | help+=" --"; | |
93a471a3 | 136 | help+=i.first; |
12c86877 | 137 | |
93a471a3 | 138 | string type=d_typeMap[i.first]; |
12c86877 BH |
139 | |
140 | if(type=="Parameter") | |
4957a608 | 141 | help+="=..."; |
12c86877 | 142 | else if(type=="Switch") |
4957a608 | 143 | { |
93a471a3 CHB |
144 | help+=" | --"+i.first+"=yes"; |
145 | help+=" | --"+i.first+"=no"; | |
4957a608 | 146 | } |
12c86877 BH |
147 | |
148 | ||
149 | help+="\n\t"; | |
93a471a3 | 150 | help+=i.second; |
12c86877 BH |
151 | help+="\n"; |
152 | ||
153 | } | |
154 | return help; | |
155 | } | |
156 | ||
9d6e970b CH |
157 | const string ArgvMap::formatOne(bool running, bool full, const string &var, const string &help, const string& theDefault, const string& current) |
158 | { | |
159 | string out; | |
160 | ||
161 | if (!running || full) { | |
162 | out += "#################################\n"; | |
163 | out += "# "; | |
164 | out += var; | |
165 | out += "\t"; | |
166 | out += help; | |
167 | out += "\n#\n"; | |
168 | } else { | |
169 | if (theDefault == current) { | |
170 | return ""; | |
171 | } | |
172 | } | |
173 | ||
174 | if (! running || theDefault == current) { | |
175 | out += "# "; | |
176 | } | |
177 | ||
178 | if (running) { | |
179 | out += var + "=" + current + "\n"; | |
180 | if (full) { | |
181 | out += "\n"; | |
182 | } | |
183 | } else { | |
184 | out += var + "=" + theDefault + "\n\n"; | |
185 | } | |
186 | ||
187 | return out; | |
188 | } | |
189 | ||
190 | // If running and full, only changed settings are returned. | |
8864bdf6 | 191 | string ArgvMap::configstring(bool running, bool full) |
12c86877 BH |
192 | { |
193 | string help; | |
6bef3d91 | 194 | |
8864bdf6 KM |
195 | if (running) |
196 | help="# Autogenerated configuration file based on running instance ("+nowTime()+")\n\n"; | |
6bef3d91 | 197 | else |
8864bdf6 KM |
198 | help="# Autogenerated configuration file template\n\n"; |
199 | ||
9d6e970b CH |
200 | // Affects parsing, should come first. |
201 | help += formatOne(running, full, "ignore-unknown-settings", helpmap["ignore-unknown-settings"], defaultmap["ignore-unknown-settings"], d_params["ignore-unknown-settings"]); | |
202 | ||
93a471a3 | 203 | for(const auto& i: helpmap) { |
9d6e970b CH |
204 | if (d_typeMap[i.first] == "Command") |
205 | continue; | |
206 | if (i.first == "ignore-unknown-settings") | |
c7efa8ff RA |
207 | continue; |
208 | ||
9d6e970b CH |
209 | if (!defaultmap.count(i.first)) { |
210 | throw ArgException(string("Default for setting '")+i.first+"' not set"); | |
8864bdf6 KM |
211 | } |
212 | ||
9d6e970b CH |
213 | help += formatOne(running, full, i.first, i.second, defaultmap[i.first], d_params[i.first]); |
214 | } | |
8864bdf6 | 215 | |
9d6e970b CH |
216 | if (running) { |
217 | for(const auto& i: d_unknownParams) { | |
218 | help += formatOne(running, full, i.first, "unknown setting", "", i.second); | |
12c86877 | 219 | } |
c7efa8ff | 220 | } |
9d6e970b | 221 | |
12c86877 BH |
222 | return help; |
223 | } | |
224 | ||
12c86877 BH |
225 | const string & ArgvMap::operator[](const string &arg) |
226 | { | |
227 | if(!parmIsset(arg)) | |
228 | throw ArgException(string("Undefined but needed argument: '")+arg+"'"); | |
229 | ||
9d6e970b | 230 | return d_params[arg]; |
12c86877 BH |
231 | } |
232 | ||
cc2978dc BH |
233 | mode_t ArgvMap::asMode(const string &arg) |
234 | { | |
235 | mode_t mode; | |
236 | const char *cptr_orig; | |
4646277d | 237 | char *cptr_ret = nullptr; |
cc2978dc BH |
238 | |
239 | if(!parmIsset(arg)) | |
240 | throw ArgException(string("Undefined but needed argument: '")+arg+"'"); | |
241 | ||
9d6e970b | 242 | cptr_orig = d_params[arg].c_str(); |
cc2978dc BH |
243 | mode = static_cast<mode_t>(strtol(cptr_orig, &cptr_ret, 8)); |
244 | if (mode == 0 && cptr_ret == cptr_orig) | |
245 | throw ArgException("'" + arg + string("' contains invalid octal mode")); | |
246 | return mode; | |
247 | } | |
248 | ||
249 | gid_t ArgvMap::asGid(const string &arg) | |
250 | { | |
251 | gid_t gid; | |
252 | const char *cptr_orig; | |
4646277d | 253 | char *cptr_ret = nullptr; |
cc2978dc BH |
254 | |
255 | if(!parmIsset(arg)) | |
256 | throw ArgException(string("Undefined but needed argument: '")+arg+"'"); | |
257 | ||
9d6e970b | 258 | cptr_orig = d_params[arg].c_str(); |
cc2978dc BH |
259 | gid = static_cast<gid_t>(strtol(cptr_orig, &cptr_ret, 0)); |
260 | if (gid == 0 && cptr_ret == cptr_orig) { | |
261 | // try to resolve | |
9d6e970b | 262 | struct group *group = getgrnam(d_params[arg].c_str()); |
4646277d | 263 | if (group == nullptr) |
cc2978dc BH |
264 | throw ArgException("'" + arg + string("' contains invalid group")); |
265 | gid = group->gr_gid; | |
266 | } | |
267 | return gid; | |
268 | } | |
269 | ||
270 | uid_t ArgvMap::asUid(const string &arg) | |
271 | { | |
272 | uid_t uid; | |
273 | const char *cptr_orig; | |
4646277d | 274 | char *cptr_ret = nullptr; |
cc2978dc BH |
275 | |
276 | if(!parmIsset(arg)) | |
277 | throw ArgException(string("Undefined but needed argument: '")+arg+"'"); | |
278 | ||
9d6e970b | 279 | cptr_orig = d_params[arg].c_str(); |
cc2978dc BH |
280 | uid = static_cast<uid_t>(strtol(cptr_orig, &cptr_ret, 0)); |
281 | if (uid == 0 && cptr_ret == cptr_orig) { | |
282 | // try to resolve | |
9d6e970b | 283 | struct passwd *pwent = getpwnam(d_params[arg].c_str()); |
4646277d | 284 | if (pwent == nullptr) |
cc2978dc BH |
285 | throw ArgException("'" + arg + string("' contains invalid group")); |
286 | uid = pwent->pw_uid; | |
287 | } | |
288 | return uid; | |
289 | } | |
cc2978dc | 290 | |
ff99a74b | 291 | int ArgvMap::asNum(const string &arg, int def) |
12c86877 | 292 | { |
cc2978dc BH |
293 | int retval; |
294 | const char *cptr_orig; | |
4646277d | 295 | char *cptr_ret = nullptr; |
cc2978dc | 296 | |
12c86877 BH |
297 | if(!parmIsset(arg)) |
298 | throw ArgException(string("Undefined but needed argument: '")+arg+"'"); | |
299 | ||
ff99a74b | 300 | // use default for empty values |
9d6e970b | 301 | if (d_params[arg].empty()) |
ff99a74b | 302 | return def; |
cc2978dc | 303 | |
9d6e970b | 304 | cptr_orig = d_params[arg].c_str(); |
cc2978dc BH |
305 | retval = static_cast<int>(strtol(cptr_orig, &cptr_ret, 0)); |
306 | if (!retval && cptr_ret == cptr_orig) | |
fd378ba9 | 307 | throw ArgException("'"+arg+"' value '"+string(cptr_orig) + string( "' is not a valid number")); |
cc2978dc BH |
308 | |
309 | return retval; | |
310 | } | |
311 | ||
312 | bool ArgvMap::isEmpty(const string &arg) | |
313 | { | |
314 | if(!parmIsset(arg)) | |
315 | return true; | |
9d6e970b | 316 | return d_params[arg].empty(); |
12c86877 BH |
317 | } |
318 | ||
319 | double ArgvMap::asDouble(const string &arg) | |
320 | { | |
cc2978dc BH |
321 | double retval; |
322 | const char *cptr_orig; | |
4646277d | 323 | char *cptr_ret = nullptr; |
cc2978dc | 324 | |
12c86877 BH |
325 | if(!parmIsset(arg)) |
326 | throw ArgException(string("Undefined but needed argument: '")+arg+"'"); | |
327 | ||
9d6e970b | 328 | if (d_params[arg].empty()) |
cc2978dc BH |
329 | return 0.0; |
330 | ||
9d6e970b | 331 | cptr_orig = d_params[arg].c_str(); |
cc2978dc BH |
332 | retval = strtod(cptr_orig, &cptr_ret); |
333 | ||
334 | if (retval == 0 && cptr_ret == cptr_orig) | |
335 | throw ArgException("'"+arg+string("' is not valid double")); | |
336 | ||
337 | return retval; | |
12c86877 BH |
338 | } |
339 | ||
340 | ArgvMap::ArgvMap() | |
341 | { | |
9d6e970b | 342 | set("ignore-unknown-settings","Configuration settings to ignore if they are unknown")=""; |
12c86877 BH |
343 | } |
344 | ||
345 | bool ArgvMap::parmIsset(const string &var) | |
346 | { | |
9d6e970b | 347 | return d_params.find(var) != d_params.end(); |
12c86877 BH |
348 | } |
349 | ||
3d324e00 O |
350 | // ATM Shared between Recursor and Auth, is that a good idea? |
351 | static const map<string,string> deprecateList = { | |
352 | { "stats-api-blacklist", "stats-api-disabled-list" }, | |
353 | { "stats-carbon-blacklist", "stats-carbon-disabled-list" }, | |
354 | { "stats-rec-control-blacklist", "stats-rec-control-disabled-list" }, | |
355 | { "stats-snmp-blacklist", "stats-snmp-disabled-list" }, | |
356 | { "edns-subnet-whitelist", "edns-subnet-allow-list" }, | |
357 | { "new-domain-whitelist", "new-domain-ignore-list" }, | |
358 | { "snmp-master-socket", "snmp-daemon-socket" } | |
359 | }; | |
360 | ||
ebaffe64 | 361 | void ArgvMap::warnIfDeprecated(const string& var) |
3d324e00 O |
362 | { |
363 | const auto msg = deprecateList.find(var); | |
364 | if (msg != deprecateList.end()) { | |
ebaffe64 OM |
365 | SLOG(g_log << Logger::Warning << "'" << var << "' is deprecated and will be removed in a future release, use '" << msg->second << "' instead" << endl, |
366 | d_log->info(Logr::Warning, "Option is deprecated and will be removed in a future release", "deprecatedName", Logging::Loggable(var), "name", Logging::Loggable(msg->second))); | |
3d324e00 O |
367 | } |
368 | } | |
369 | ||
12c86877 BH |
370 | void ArgvMap::parseOne(const string &arg, const string &parseOnly, bool lax) |
371 | { | |
372 | string var, val; | |
bdf40704 | 373 | string::size_type pos; |
5a177409 | 374 | bool incremental = false; |
4d752b05 | 375 | |
a350fc7a | 376 | if(arg.find("--") == 0 && (pos=arg.find("+="))!=string::npos) // this is a --port+=25 case |
4d752b05 KM |
377 | { |
378 | var=arg.substr(2,pos-2); | |
379 | val=arg.substr(pos+2); | |
380 | incremental = true; | |
381 | } | |
2e321dad | 382 | else if(arg.find("--") == 0 && (pos=arg.find('='))!=string::npos) // this is a --port=25 case |
4d752b05 KM |
383 | { |
384 | var=arg.substr(2,pos-2); | |
385 | val=arg.substr(pos+1); | |
386 | } | |
2e321dad | 387 | else if(arg.find("--") == 0 && (arg.find('=')==string::npos)) // this is a --daemon case |
4d752b05 KM |
388 | { |
389 | var=arg.substr(2); | |
390 | val=""; | |
391 | } | |
0e4bbf5d | 392 | else if(arg[0]=='-' && arg.length() > 1) |
4d752b05 KM |
393 | { |
394 | var=arg.substr(1); | |
395 | val=""; | |
12c86877 | 396 | } |
4d752b05 KM |
397 | else // command |
398 | d_cmds.push_back(arg); | |
c63f0951 AT |
399 | |
400 | boost::trim(var); | |
12c86877 BH |
401 | |
402 | if(var!="" && (parseOnly.empty() || var==parseOnly)) { | |
ebaffe64 OM |
403 | if (!lax) { |
404 | warnIfDeprecated(var); | |
405 | } | |
bd11bd1d | 406 | pos=val.find_first_not_of(" \t"); // strip leading whitespace |
3752660e | 407 | if(pos && pos!=string::npos) |
bd11bd1d | 408 | val=val.substr(pos); |
4d752b05 KM |
409 | if(parmIsset(var)) |
410 | { | |
411 | if(incremental) | |
412 | { | |
9d6e970b | 413 | if(d_params[var].empty()) |
4d752b05 KM |
414 | { |
415 | if(!d_cleared.count(var)) | |
9d6e970b CH |
416 | throw ArgException("Incremental setting '"+var+"' without a parent"); |
417 | d_params[var] = val; | |
4d752b05 KM |
418 | } |
419 | else | |
9d6e970b | 420 | d_params[var] += ", " + val; |
4d752b05 KM |
421 | } |
422 | else | |
423 | { | |
9d6e970b | 424 | d_params[var] = val; |
4d752b05 | 425 | d_cleared.insert(var); |
5a177409 | 426 | } |
3702b428 | 427 | } |
9d6e970b CH |
428 | else |
429 | { | |
430 | // unknown setting encountered. see if its on the ignore list before throwing. | |
6e01be56 | 431 | vector<string> parts; |
9d6e970b | 432 | stringtok(parts, d_params["ignore-unknown-settings"], " ,\t\n\r"); |
6e01be56 | 433 | if (find(parts.begin(), parts.end(), var) != parts.end()) { |
9d6e970b | 434 | d_unknownParams[var] = val; |
ebaffe64 OM |
435 | SLOG(g_log<<Logger::Warning<<"Ignoring unknown setting '"<<var<<"' as requested"<<endl, |
436 | d_log->info(Logr::Warning, "Ignoring unknown setting as requested", "name", Logging::Loggable(var))); | |
9d6e970b CH |
437 | return; |
438 | } | |
439 | ||
440 | if (!lax) { | |
441 | throw ArgException("Trying to set unknown setting '"+var+"'"); | |
442 | } | |
443 | } | |
12c86877 BH |
444 | } |
445 | } | |
446 | ||
447 | const vector<string>&ArgvMap::getCommands() | |
448 | { | |
449 | return d_cmds; | |
450 | } | |
451 | ||
452 | void ArgvMap::parse(int &argc, char **argv, bool lax) | |
453 | { | |
116cda91 | 454 | d_cmds.clear(); |
58a57699 | 455 | d_cleared.clear(); |
12c86877 BH |
456 | for(int n=1;n<argc;n++) { |
457 | parseOne(argv[n],"",lax); | |
458 | } | |
459 | } | |
460 | ||
461 | void ArgvMap::preParse(int &argc, char **argv, const string &arg) | |
462 | { | |
463 | for(int n=1;n<argc;n++) { | |
464 | string varval=argv[n]; | |
a350fc7a | 465 | if(varval.find("--"+arg) == 0) |
12c86877 BH |
466 | parseOne(argv[n]); |
467 | } | |
468 | } | |
469 | ||
d3002a04 AT |
470 | bool ArgvMap::parseFile(const char *fname, const string& arg, bool lax) { |
471 | string line; | |
07b7e0b5 AT |
472 | string pline; |
473 | string::size_type pos; | |
474 | ||
d3002a04 AT |
475 | ifstream f(fname); |
476 | if(!f) | |
477 | return false; | |
07b7e0b5 | 478 | |
d3002a04 | 479 | while(getline(f,pline)) { |
dc593046 | 480 | boost::trim_right(pline); |
d3002a04 | 481 | |
83281a74 | 482 | if(!pline.empty() && pline[pline.size()-1]=='\\') { |
d3002a04 AT |
483 | line+=pline.substr(0,pline.length()-1); |
484 | continue; | |
485 | } | |
486 | else | |
487 | line+=pline; | |
488 | ||
489 | // strip everything after a # | |
2e321dad | 490 | if((pos=line.find('#'))!=string::npos) { |
d3002a04 AT |
491 | // make sure it's either first char or has whitespace before |
492 | // fixes issue #354 | |
493 | if (pos == 0 || std::isspace(line[pos-1])) | |
494 | line=line.substr(0,pos); | |
495 | } | |
496 | ||
497 | // strip trailing spaces | |
dc593046 | 498 | boost::trim_right(line); |
07b7e0b5 | 499 | |
d3002a04 AT |
500 | // strip leading spaces |
501 | if((pos=line.find_first_not_of(" \t\r\n"))!=string::npos) | |
502 | line=line.substr(pos); | |
07b7e0b5 | 503 | |
d3002a04 AT |
504 | // gpgsql-basic-query=sdfsdfs dfsdfsdf sdfsdfsfd |
505 | ||
506 | parseOne( string("--") + line, arg, lax ); | |
507 | line=""; | |
508 | } | |
07b7e0b5 | 509 | |
07b7e0b5 AT |
510 | return true; |
511 | } | |
512 | ||
513 | ||
f64de501 | 514 | bool ArgvMap::preParseFile(const char *fname, const string &arg, const string& theDefault) |
12c86877 | 515 | { |
9d6e970b | 516 | d_params[arg] = theDefault; |
b56ac6fd | 517 | |
d3002a04 | 518 | return parseFile(fname, arg, false); |
12c86877 BH |
519 | } |
520 | ||
12c86877 | 521 | bool ArgvMap::file(const char *fname, bool lax) |
4f6ef75f AT |
522 | { |
523 | return file(fname,lax,false); | |
524 | } | |
525 | ||
526 | bool ArgvMap::file(const char *fname, bool lax, bool included) | |
12c86877 | 527 | { |
8a16d778 | 528 | if (!parmIsset("include-dir")) // inject include-dir |
4f6ef75f AT |
529 | set("include-dir","Directory to include configuration files from"); |
530 | ||
d3002a04 | 531 | if(!parseFile(fname, "", lax)) { |
ebaffe64 OM |
532 | SLOG(g_log << Logger::Warning << "Unable to open " << fname << std::endl, |
533 | d_log->error(Logr::Warning, "Unable to open", "name", Logging::Loggable(fname))); | |
d3002a04 AT |
534 | return false; |
535 | } | |
eefd15f9 | 536 | |
4f6ef75f | 537 | // handle include here (avoid re-include) |
9d6e970b | 538 | if (!included && !d_params["include-dir"].empty()) { |
93d7e233 AT |
539 | std::vector<std::string> extraConfigs; |
540 | gatherIncludes(extraConfigs); | |
ef7cd021 | 541 | for(const std::string& fn : extraConfigs) { |
93d7e233 | 542 | if (!file(fn.c_str(), lax, true)) { |
ebaffe64 OM |
543 | SLOG(g_log << Logger::Error << fn << " could not be parsed" << std::endl, |
544 | d_log->info(Logr::Error, "Could not be parsed", "name", Logging::Loggable(fn))); | |
93d7e233 | 545 | throw ArgException(fn + " could not be parsed"); |
4f6ef75f | 546 | } |
93d7e233 | 547 | } |
93d7e233 | 548 | } |
8a16d778 | 549 | |
93d7e233 AT |
550 | return true; |
551 | } | |
8a16d778 | 552 | |
93d7e233 AT |
553 | void ArgvMap::gatherIncludes(std::vector<std::string> &extraConfigs) { |
554 | extraConfigs.clear(); | |
9d6e970b | 555 | if (d_params["include-dir"].empty()) |
a73da04b OM |
556 | return; // nothing to do |
557 | ||
558 | DIR *dir; | |
9d6e970b | 559 | if (!(dir = opendir(d_params["include-dir"].c_str()))) { |
a73da04b | 560 | int err = errno; |
9d6e970b | 561 | string msg = d_params["include-dir"] + " is not accessible: " + strerror(err); |
ebaffe64 OM |
562 | SLOG(g_log << Logger::Error << msg << std::endl, |
563 | d_log->error(Logr::Error, err, "Directory is not accessible", "name", Logging::Loggable(d_params["include-dir"]))); | |
a73da04b OM |
564 | throw ArgException(msg); |
565 | } | |
93d7e233 | 566 | |
a73da04b | 567 | struct dirent *ent; |
4646277d | 568 | while ((ent = readdir(dir)) != nullptr) { |
a73da04b OM |
569 | if (ent->d_name[0] == '.') |
570 | continue; // skip any dots | |
571 | if (boost::ends_with(ent->d_name, ".conf")) { | |
572 | // build name | |
9d6e970b | 573 | string name = d_params["include-dir"] + "/" + ent->d_name; // FIXME: Use some path separator |
a73da04b OM |
574 | // ensure it's readable file |
575 | struct stat st; | |
576 | if (stat(name.c_str(), &st) || !S_ISREG(st.st_mode)) { | |
577 | string msg = name + " is not a regular file"; | |
ebaffe64 OM |
578 | SLOG(g_log << Logger::Error << msg << std::endl, |
579 | d_log->info(Logr::Error, "Is not a regular file", "name", Logging::Loggable(name))); | |
a73da04b OM |
580 | closedir(dir); |
581 | throw ArgException(msg); | |
93d7e233 | 582 | } |
a73da04b | 583 | extraConfigs.push_back(name); |
93d7e233 | 584 | } |
a73da04b OM |
585 | } |
586 | std::sort(extraConfigs.begin(), extraConfigs.end(), CIStringComparePOSIX()); | |
587 | closedir(dir); | |
12c86877 | 588 | } |