]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/arguments.cc
2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2002 - 2008 PowerDNS.COM BV
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as published
7 by the Free Software Foundation
9 Additionally, the license of this program contains a special
10 exception which allows to distribute the program in binary form when
11 it is linked against OpenSSL.
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 St, 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>
29 #include <boost/foreach.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
+string("' is not 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::preParseFile(const char *fname
, const string
&arg
, const string
& theDefault
)
386 params
[arg
]=theDefault
;
394 string::size_type pos
;
396 while(getline(f
,pline
)) {
399 if(pline
[pline
.size()-1]=='\\') {
400 line
+=pline
.substr(0,pline
.length()-1);
406 // strip everything after a #
407 if((pos
=line
.find("#"))!=string::npos
)
408 line
=line
.substr(0,pos
);
410 // strip trailing spaces
413 // strip leading spaces
414 if((pos
=line
.find_first_not_of(" \t\r\n"))!=string::npos
)
415 line
=line
.substr(pos
);
417 // gpgsql-basic-query=sdfsdfs dfsdfsdf sdfsdfsfd
419 parseOne( string("--") + line
, arg
);
426 bool ArgvMap::file(const char *fname
, bool lax
)
428 return file(fname
,lax
,false);
431 bool ArgvMap::file(const char *fname
, bool lax
, bool included
)
435 L
<< Logger::Warning
<< "Unable to open " << fname
<< std::endl
;
439 if (!parmIsset("include-dir")) // inject include-dir
440 set("include-dir","Directory to include configuration files from");
444 string::size_type pos
;
446 while(getline(f
,pline
)) {
451 if(pline
[pline
.size()-1]=='\\') {
452 line
+=pline
.substr(0,pline
.length()-1);
459 // strip everything after a #
460 if((pos
=line
.find("#"))!=string::npos
)
461 line
=line
.substr(0,pos
);
463 // strip trailing spaces
466 parseOne(string("--")+line
,"",lax
);
470 // handle include here (avoid re-include)
471 if (!included
&& !params
["include-dir"].empty()) {
472 std::vector
<std::string
> extraConfigs
;
473 gatherIncludes(extraConfigs
);
474 BOOST_FOREACH(const std::string
& fn
, extraConfigs
) {
475 if (!file(fn
.c_str(), lax
, true)) {
476 L
<< Logger::Error
<< fn
<< " could not be parsed" << std::endl
;
477 throw ArgException(fn
+ " could not be parsed");
485 void ArgvMap::gatherIncludes(std::vector
<std::string
> &extraConfigs
) {
486 extraConfigs
.clear();
487 if (params
["include-dir"].empty()) return; // nothing to do
493 if (stat(params
["include-dir"].c_str(), &st
)) {
494 L
<< Logger::Error
<< params
["include-dir"] << " does not exist!" << std::endl
;
495 throw ArgException(params
["include-dir"] + " does not exist!");
498 // wonder if it's accessible directory
499 if (!S_ISDIR(st
.st_mode
)) {
500 L
<< Logger::Error
<< params
["include-dir"] << " is not a directory" << std::endl
;
501 throw ArgException(params
["include-dir"] + " is not a directory");
504 if (!(dir
= opendir(params
["include-dir"].c_str()))) {
505 L
<< Logger::Error
<< params
["include-dir"] << " is not accessible" << std::endl
;
506 throw ArgException(params
["include-dir"] + " is not accessible");
509 while((ent
= readdir(dir
)) != NULL
) {
510 if (ent
->d_name
[0] == '.') continue; // skip any dots
511 if (boost::ends_with(ent
->d_name
, ".conf")) {
513 std::ostringstream namebuf
;
514 namebuf
<< params
["include-dir"].c_str() << "/" << ent
->d_name
; // FIXME: Use some path separator
515 // ensure it's readable file
516 if (stat(namebuf
.str().c_str(), &st
) || !S_ISREG(st
.st_mode
)) {
517 L
<< Logger::Error
<< namebuf
.str() << " is not a file" << std::endl
;
518 throw ArgException(namebuf
.str() + " does not exist!");
520 extraConfigs
.push_back(namebuf
.str());
523 std::sort(extraConfigs
.begin(), extraConfigs
.end(), CIStringComparePOSIX());