]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/arguments.cc
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
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.
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.
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.
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.
25 #include "arguments.hh"
26 #include <boost/algorithm/string.hpp>
27 #include <boost/algorithm/string/compare.hpp>
28 #include <boost/algorithm/string/predicate.hpp>
30 #include "namespaces.hh"
32 #include <sys/types.h>
38 const ArgvMap::param_t::const_iterator
ArgvMap::begin()
40 return params
.begin();
43 const ArgvMap::param_t::const_iterator
ArgvMap::end()
48 string
& ArgvMap::set(const string
&var
)
53 bool ArgvMap::mustDo(const string
&var
)
55 return ((*this)[var
]!="no") && ((*this)[var
]!="off");
58 vector
<string
>ArgvMap::list()
61 for(map
<string
,string
>::const_iterator i
=params
.begin();i
!=params
.end();++i
)
62 ret
.push_back(i
->first
);
66 string
ArgvMap::getHelp(const string
&item
)
71 string
& ArgvMap::set(const string
&var
, const string
&help
)
74 d_typeMap
[var
]="Parameter";
78 void ArgvMap::setCmd(const string
&var
, const string
&help
)
81 d_typeMap
[var
]="Command";
85 string
& ArgvMap::setSwitch(const string
&var
, const string
&help
)
88 d_typeMap
[var
]="Switch";
93 bool ArgvMap::contains(const string
&var
, const string
&val
)
95 params_t::const_iterator param
= params
.find(var
);
96 if(param
== params
.end() || param
->second
.empty()) {
100 vector
<string
>::const_iterator i
;
102 stringtok( parts
, param
->second
, ", \t" );
103 for( i
= parts
.begin(); i
!= parts
.end(); i
++ ) {
112 string
ArgvMap::helpstring(string prefix
)
119 for(map
<string
,string
>::const_iterator i
=helpmap
.begin();
123 if(!prefix
.empty() && i
->first
.find(prefix
)) // only print items with prefix
129 string type
=d_typeMap
[i
->first
];
131 if(type
=="Parameter")
133 else if(type
=="Switch")
135 help
+=" | --"+i
->first
+"=yes";
136 help
+=" | --"+i
->first
+"=no";
148 string
ArgvMap::configstring(bool current
)
153 help
="# Autogenerated configuration file based on running instance\n";
155 help
="# Autogenerated configuration file template\n";
157 for(map
<string
,string
>::const_iterator i
=helpmap
.begin(); i
!=helpmap
.end(); i
++) {
158 if(d_typeMap
[i
->first
]=="Command")
161 help
+="#################################\n";
168 help
+=i
->first
+"="+params
[i
->first
]+"\n\n";
170 help
+="# "+i
->first
+"="+params
[i
->first
]+"\n\n";
176 const string
& ArgvMap::operator[](const string
&arg
)
179 throw ArgException(string("Undefined but needed argument: '")+arg
+"'");
184 mode_t
ArgvMap::asMode(const string
&arg
)
187 const char *cptr_orig
;
188 char *cptr_ret
= NULL
;
191 throw ArgException(string("Undefined but needed argument: '")+arg
+"'");
193 cptr_orig
= params
[arg
].c_str();
194 mode
= static_cast<mode_t
>(strtol(cptr_orig
, &cptr_ret
, 8));
195 if (mode
== 0 && cptr_ret
== cptr_orig
)
196 throw ArgException("'" + arg
+ string("' contains invalid octal mode"));
200 gid_t
ArgvMap::asGid(const string
&arg
)
203 const char *cptr_orig
;
204 char *cptr_ret
= NULL
;
207 throw ArgException(string("Undefined but needed argument: '")+arg
+"'");
209 cptr_orig
= params
[arg
].c_str();
210 gid
= static_cast<gid_t
>(strtol(cptr_orig
, &cptr_ret
, 0));
211 if (gid
== 0 && cptr_ret
== cptr_orig
) {
213 struct group
*group
= getgrnam(params
[arg
].c_str());
215 throw ArgException("'" + arg
+ string("' contains invalid group"));
221 uid_t
ArgvMap::asUid(const string
&arg
)
224 const char *cptr_orig
;
225 char *cptr_ret
= NULL
;
228 throw ArgException(string("Undefined but needed argument: '")+arg
+"'");
230 cptr_orig
= params
[arg
].c_str();
231 uid
= static_cast<uid_t
>(strtol(cptr_orig
, &cptr_ret
, 0));
232 if (uid
== 0 && cptr_ret
== cptr_orig
) {
234 struct passwd
*pwent
= getpwnam(params
[arg
].c_str());
236 throw ArgException("'" + arg
+ string("' contains invalid group"));
242 int ArgvMap::asNum(const string
&arg
, int def
)
245 const char *cptr_orig
;
246 char *cptr_ret
= NULL
;
249 throw ArgException(string("Undefined but needed argument: '")+arg
+"'");
251 // use default for empty values
252 if (params
[arg
].empty())
255 cptr_orig
= params
[arg
].c_str();
256 retval
= static_cast<int>(strtol(cptr_orig
, &cptr_ret
, 0));
257 if (!retval
&& cptr_ret
== cptr_orig
)
258 throw ArgException("'"+arg
+"' value '"+string(cptr_orig
) + string( "' is not a valid number"));
263 bool ArgvMap::isEmpty(const string
&arg
)
267 return params
[arg
].empty();
270 double ArgvMap::asDouble(const string
&arg
)
273 const char *cptr_orig
;
274 char *cptr_ret
= NULL
;
277 throw ArgException(string("Undefined but needed argument: '")+arg
+"'");
279 if (params
[arg
].empty())
282 cptr_orig
= params
[arg
].c_str();
283 retval
= strtod(cptr_orig
, &cptr_ret
);
285 if (retval
== 0 && cptr_ret
== cptr_orig
)
286 throw ArgException("'"+arg
+string("' is not valid double"));
296 bool ArgvMap::parmIsset(const string
&var
)
298 return (params
.find(var
)!=params
.end());
301 void ArgvMap::parseOne(const string
&arg
, const string
&parseOnly
, bool lax
)
304 string::size_type pos
;
305 bool incremental
= false;
307 if(!arg
.find("--") && (pos
=arg
.find("+="))!=string::npos
) // this is a --port+=25 case
309 var
=arg
.substr(2,pos
-2);
310 val
=arg
.substr(pos
+2);
313 else if(!arg
.find("--") && (pos
=arg
.find("="))!=string::npos
) // this is a --port=25 case
315 var
=arg
.substr(2,pos
-2);
316 val
=arg
.substr(pos
+1);
318 else if(!arg
.find("--") && (arg
.find("=")==string::npos
)) // this is a --daemon case
329 d_cmds
.push_back(arg
);
333 if(var
!="" && (parseOnly
.empty() || var
==parseOnly
)) {
334 pos
=val
.find_first_not_of(" \t"); // strip leading whitespace
335 if(pos
&& pos
!=string::npos
)
341 if(params
[var
].empty())
343 if(!d_cleared
.count(var
))
344 throw ArgException("Incremental parameter '"+var
+"' without a parent");
348 params
[var
]+=", " + val
;
353 d_cleared
.insert(var
);
357 throw ArgException("Trying to set unknown parameter '"+var
+"'");
361 const vector
<string
>&ArgvMap::getCommands()
366 void ArgvMap::parse(int &argc
, char **argv
, bool lax
)
370 for(int n
=1;n
<argc
;n
++) {
371 parseOne(argv
[n
],"",lax
);
375 void ArgvMap::preParse(int &argc
, char **argv
, const string
&arg
)
377 for(int n
=1;n
<argc
;n
++) {
378 string varval
=argv
[n
];
379 if(!varval
.find("--"+arg
))
384 bool ArgvMap::parseFile(const char *fname
, const string
& arg
, bool lax
) {
387 string::size_type pos
;
393 while(getline(f
,pline
)) {
396 if(!pline
.empty() && pline
[pline
.size()-1]=='\\') {
397 line
+=pline
.substr(0,pline
.length()-1);
403 // strip everything after a #
404 if((pos
=line
.find("#"))!=string::npos
) {
405 // make sure it's either first char or has whitespace before
407 if (pos
== 0 || std::isspace(line
[pos
-1]))
408 line
=line
.substr(0,pos
);
411 // strip trailing spaces
414 // strip leading spaces
415 if((pos
=line
.find_first_not_of(" \t\r\n"))!=string::npos
)
416 line
=line
.substr(pos
);
418 // gpgsql-basic-query=sdfsdfs dfsdfsdf sdfsdfsfd
420 parseOne( string("--") + line
, arg
, lax
);
428 bool ArgvMap::preParseFile(const char *fname
, const string
&arg
, const string
& theDefault
)
430 params
[arg
]=theDefault
;
432 return parseFile(fname
, arg
, false);
435 bool ArgvMap::file(const char *fname
, bool lax
)
437 return file(fname
,lax
,false);
440 bool ArgvMap::file(const char *fname
, bool lax
, bool included
)
442 if (!parmIsset("include-dir")) // inject include-dir
443 set("include-dir","Directory to include configuration files from");
445 if(!parseFile(fname
, "", lax
)) {
446 L
<< Logger::Warning
<< "Unable to open " << fname
<< std::endl
;
450 // handle include here (avoid re-include)
451 if (!included
&& !params
["include-dir"].empty()) {
452 std::vector
<std::string
> extraConfigs
;
453 gatherIncludes(extraConfigs
);
454 for(const std::string
& fn
: extraConfigs
) {
455 if (!file(fn
.c_str(), lax
, true)) {
456 L
<< Logger::Error
<< fn
<< " could not be parsed" << std::endl
;
457 throw ArgException(fn
+ " could not be parsed");
465 void ArgvMap::gatherIncludes(std::vector
<std::string
> &extraConfigs
) {
466 extraConfigs
.clear();
467 if (params
["include-dir"].empty()) return; // nothing to do
473 if (stat(params
["include-dir"].c_str(), &st
)) {
474 L
<< Logger::Error
<< params
["include-dir"] << " does not exist!" << std::endl
;
475 throw ArgException(params
["include-dir"] + " does not exist!");
478 // wonder if it's accessible directory
479 if (!S_ISDIR(st
.st_mode
)) {
480 L
<< Logger::Error
<< params
["include-dir"] << " is not a directory" << std::endl
;
481 throw ArgException(params
["include-dir"] + " is not a directory");
484 if (!(dir
= opendir(params
["include-dir"].c_str()))) {
485 L
<< Logger::Error
<< params
["include-dir"] << " is not accessible" << std::endl
;
486 throw ArgException(params
["include-dir"] + " is not accessible");
489 while((ent
= readdir(dir
)) != NULL
) {
490 if (ent
->d_name
[0] == '.') continue; // skip any dots
491 if (boost::ends_with(ent
->d_name
, ".conf")) {
493 std::ostringstream namebuf
;
494 namebuf
<< params
["include-dir"].c_str() << "/" << ent
->d_name
; // FIXME: Use some path separator
495 // ensure it's readable file
496 if (stat(namebuf
.str().c_str(), &st
) || !S_ISREG(st
.st_mode
)) {
497 L
<< Logger::Error
<< namebuf
.str() << " is not a file" << std::endl
;
499 throw ArgException(namebuf
.str() + " does not exist!");
501 extraConfigs
.push_back(namebuf
.str());
504 std::sort(extraConfigs
.begin(), extraConfigs
.end(), CIStringComparePOSIX());