]>
Commit | Line | Data |
---|---|---|
12c86877 BH |
1 | /* |
2 | PowerDNS Versatile Database Driven Nameserver | |
ce19a815 | 3 | Copyright (C) 2002 - 2013 PowerDNS.COM BV |
12c86877 BH |
4 | |
5 | This program is free software; you can redistribute it and/or modify | |
22dc646a BH |
6 | it under the terms of the GNU General Public License version 2 |
7 | as published by the Free Software Foundation | |
ea44d9d3 | 8 | |
f782fe38 MH |
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. | |
12c86877 BH |
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 | |
06bd9ccf | 20 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
12c86877 | 21 | */ |
e8d78143 | 22 | #include "packetcache.hh" |
da44c9ea | 23 | |
12c86877 BH |
24 | #include <cstdio> |
25 | #include <signal.h> | |
26 | #include <cstring> | |
27 | #include <cstdlib> | |
28 | #include <sys/types.h> | |
29 | #include <sys/socket.h> | |
30 | #include <netinet/in.h> | |
31 | #include <arpa/inet.h> | |
32 | #include <iostream> | |
33 | #include <string> | |
34 | #include <sys/stat.h> | |
35 | #include <unistd.h> | |
36 | #include <sys/time.h> | |
37 | #include <sys/types.h> | |
38 | #include <sys/wait.h> | |
39 | #include <errno.h> | |
40 | #include <pthread.h> | |
41 | #include <unistd.h> | |
42 | #include <sys/mman.h> | |
43 | #include <fcntl.h> | |
44 | #include <fstream> | |
040712e0 | 45 | #include <boost/algorithm/string.hpp> |
12c86877 BH |
46 | |
47 | #include "config.h" | |
48 | #include "dns.hh" | |
49 | #include "dnsbackend.hh" | |
50 | #include "ueberbackend.hh" | |
51 | #include "dnspacket.hh" | |
52 | #include "nameserver.hh" | |
53 | #include "distributor.hh" | |
54 | #include "logger.hh" | |
55 | #include "arguments.hh" | |
56 | #include "packethandler.hh" | |
57 | #include "statbag.hh" | |
58 | #include "tcpreceiver.hh" | |
12c86877 BH |
59 | #include "misc.hh" |
60 | #include "dynlistener.hh" | |
61 | #include "dynhandler.hh" | |
62 | #include "communicator.hh" | |
63 | #include "dnsproxy.hh" | |
731f58b8 | 64 | #include "utility.hh" |
12c86877 | 65 | #include "common_startup.hh" |
02116dff | 66 | #include "dnsrecords.hh" |
ba1a571d | 67 | #include "version.hh" |
12c86877 BH |
68 | |
69 | time_t s_starttime; | |
70 | ||
71 | string s_programname="pdns"; // used in packethandler.cc | |
72 | ||
c4ac5865 | 73 | const char *funnytext= |
12c86877 BH |
74 | "*****************************************************************************\n"\ |
75 | "Ok, you just ran pdns_server through 'strings' hoping to find funny messages.\n"\ | |
76 | "Well, you found one. \n"\ | |
77 | "Two ions are flying through their particle accelerator, says the one to the\n" | |
78 | "other 'I think I've lost an electron!' \n"\ | |
79 | "So the other one says, 'Are you sure?'. 'YEAH! I'M POSITIVE!'\n"\ | |
80 | " the pdns crew - pdns@powerdns.com\n" | |
81 | "*****************************************************************************\n"; | |
82 | ||
83 | ||
84 | // start (sys)logging | |
85 | ||
86 | /** \var Logger L | |
87 | \brief All logging is done via L, a Logger instance | |
88 | */ | |
89 | ||
90 | ||
91 | /** | |
92 | \file receiver.cc | |
93 | \brief The main loop of powerdns | |
94 | ||
95 | This file is where it all happens - main is here, as are the two pivotal threads qthread() and athread() | |
96 | */ | |
97 | ||
98 | void daemonize(void) | |
99 | { | |
100 | if(fork()) | |
101 | exit(0); // bye bye | |
102 | ||
103 | setsid(); | |
104 | ||
dd8b6bd1 | 105 | int i=open("/dev/null",O_RDWR); /* open stdin */ |
11a2091b BH |
106 | if(i < 0) |
107 | L<<Logger::Critical<<"Unable to open /dev/null: "<<stringerror()<<endl; | |
108 | else { | |
109 | dup2(i,0); /* stdin */ | |
110 | dup2(i,1); /* stderr */ | |
111 | dup2(i,2); /* stderr */ | |
112 | close(i); | |
113 | } | |
12c86877 BH |
114 | } |
115 | ||
12c86877 | 116 | static int cpid; |
12c86877 BH |
117 | static void takedown(int i) |
118 | { | |
119 | if(cpid) { | |
120 | L<<Logger::Error<<"Guardian is killed, taking down children with us"<<endl; | |
5c663d99 IM |
121 | } else { |
122 | L<<Logger::Error<<"PDNS instance is going down, taking children with us"<<endl; | |
12c86877 | 123 | } |
5c663d99 IM |
124 | kill(-getpgid(cpid),SIGKILL); |
125 | exit(0); | |
12c86877 BH |
126 | } |
127 | ||
128 | static void writePid(void) | |
129 | { | |
e8d78143 | 130 | string fname=::arg()["socket-dir"]+"/"+s_programname+".pid"; |
12c86877 BH |
131 | ofstream of(fname.c_str()); |
132 | if(of) | |
133 | of<<getpid()<<endl; | |
134 | else | |
135 | L<<Logger::Error<<"Requested to write pid for "<<getpid()<<" to "<<fname<<" failed: "<<strerror(errno)<<endl; | |
136 | } | |
137 | ||
aced0e6c BH |
138 | int g_fd1[2], g_fd2[2]; |
139 | FILE *g_fp; | |
140 | pthread_mutex_t g_guardian_lock = PTHREAD_MUTEX_INITIALIZER; | |
12c86877 | 141 | |
64bcb6be RA |
142 | // The next two methods are not in dynhandler.cc because they use a few items declared in this file. |
143 | static string DLCycleHandler(const vector<string>&parts, pid_t ppid) | |
144 | { | |
ee443da2 | 145 | kill(-getpgid(cpid), SIGKILL); |
64bcb6be RA |
146 | sleep(1); |
147 | return "ok"; | |
148 | } | |
149 | ||
12c86877 BH |
150 | static string DLRestHandler(const vector<string>&parts, pid_t ppid) |
151 | { | |
152 | string line; | |
153 | ||
154 | for(vector<string>::const_iterator i=parts.begin();i!=parts.end();++i) { | |
155 | if(i!=parts.begin()) | |
156 | line.append(1,' '); | |
157 | line.append(*i); | |
158 | } | |
159 | line.append(1,'\n'); | |
160 | ||
aced0e6c BH |
161 | Lock l(&g_guardian_lock); |
162 | ||
163 | try { | |
164 | writen2(g_fd1[1],line.c_str(),line.size()+1); | |
165 | } | |
3f81d239 | 166 | catch(PDNSException &ae) { |
aced0e6c BH |
167 | return "Error communicating with instance: "+ae.reason; |
168 | } | |
12c86877 | 169 | char mesg[512]; |
20ca8e7d | 170 | string response; |
aced0e6c | 171 | while(fgets(mesg,sizeof(mesg),g_fp)) { |
188b28bd | 172 | if(*mesg=='\0') |
20ca8e7d BH |
173 | break; |
174 | response+=mesg; | |
175 | } | |
040712e0 | 176 | boost::trim_right(response); |
20ca8e7d | 177 | return response; |
12c86877 BH |
178 | } |
179 | ||
64bcb6be | 180 | |
12c86877 BH |
181 | |
182 | static int guardian(int argc, char **argv) | |
183 | { | |
184 | if(isGuarded(argv)) | |
185 | return 0; | |
186 | ||
187 | int infd=0, outfd=1; | |
188 | ||
189 | DynListener dlg(s_programname); | |
3c90953e PD |
190 | dlg.registerFunc("QUIT",&DLQuitHandler, "quit daemon"); |
191 | dlg.registerFunc("CYCLE",&DLCycleHandler, "restart instance"); | |
192 | dlg.registerFunc("PING",&DLPingHandler, "ping guardian"); | |
193 | dlg.registerFunc("STATUS",&DLStatusHandler, "get instance status from guardian"); | |
12c86877 BH |
194 | dlg.registerRestFunc(&DLRestHandler); |
195 | dlg.go(); | |
196 | string progname=argv[0]; | |
197 | ||
198 | bool first=true; | |
12c86877 | 199 | |
aced0e6c BH |
200 | pthread_mutex_lock(&g_guardian_lock); |
201 | ||
12c86877 BH |
202 | for(;;) { |
203 | int pid; | |
204 | setStatus("Launching child"); | |
aced0e6c BH |
205 | |
206 | if(pipe(g_fd1)<0 || pipe(g_fd2)<0) { | |
12c86877 BH |
207 | L<<Logger::Critical<<"Unable to open pipe for coprocess: "<<strerror(errno)<<endl; |
208 | exit(1); | |
209 | } | |
210 | ||
aced0e6c BH |
211 | if(!(g_fp=fdopen(g_fd2[0],"r"))) { |
212 | L<<Logger::Critical<<"Unable to associate a file pointer with pipe: "<<stringerror()<<endl; | |
213 | exit(1); | |
214 | } | |
215 | setbuf(g_fp,0); // no buffering please, confuses select | |
216 | ||
12c86877 | 217 | if(!(pid=fork())) { // child |
12c86877 BH |
218 | signal(SIGHUP, SIG_DFL); |
219 | signal(SIGUSR1, SIG_DFL); | |
220 | signal(SIGUSR2, SIG_DFL); | |
221 | ||
ee443da2 IM |
222 | // Set different pgrp for this child, |
223 | // so we could kill all of it's children | |
224 | // with one kill call | |
225 | setpgid(getpid(), 0); | |
226 | ||
12c86877 BH |
227 | char **const newargv=new char*[argc+2]; |
228 | int n; | |
229 | ||
e8d78143 | 230 | if(::arg()["config-name"]!="") { |
4957a608 BH |
231 | progname+="-"+::arg()["config-name"]; |
232 | L<<Logger::Error<<"Virtual configuration name: "<<::arg()["config-name"]<<endl; | |
12c86877 BH |
233 | } |
234 | ||
235 | newargv[0]=strdup(const_cast<char *>((progname+"-instance").c_str())); | |
236 | for(n=1;n<argc;n++) { | |
4957a608 | 237 | newargv[n]=argv[n]; |
12c86877 BH |
238 | } |
239 | newargv[n]=0; | |
240 | ||
241 | L<<Logger::Error<<"Guardian is launching an instance"<<endl; | |
aced0e6c BH |
242 | close(g_fd1[1]); |
243 | fclose(g_fp); // this closes g_fd2[0] for us | |
12c86877 | 244 | |
aced0e6c | 245 | if(g_fd1[0]!= infd) { |
4957a608 BH |
246 | dup2(g_fd1[0], infd); |
247 | close(g_fd1[0]); | |
12c86877 BH |
248 | } |
249 | ||
aced0e6c | 250 | if(g_fd2[1]!= outfd) { |
4957a608 BH |
251 | dup2(g_fd2[1], outfd); |
252 | close(g_fd2[1]); | |
12c86877 | 253 | } |
c1663439 | 254 | if(execvp(argv[0], newargv)<0) { |
4957a608 BH |
255 | L<<Logger::Error<<"Unable to execvp '"<<argv[0]<<"': "<<strerror(errno)<<endl; |
256 | char **p=newargv; | |
257 | while(*p) | |
258 | L<<Logger::Error<<*p++<<endl; | |
12c86877 | 259 | |
4957a608 | 260 | exit(1); |
12c86877 | 261 | } |
c1663439 | 262 | L<<Logger::Error<<"execvp returned!!"<<endl; |
12c86877 BH |
263 | // never reached |
264 | } | |
265 | else if(pid>0) { // parent | |
aced0e6c BH |
266 | close(g_fd1[0]); |
267 | close(g_fd2[1]); | |
12c86877 BH |
268 | |
269 | if(first) { | |
4957a608 | 270 | first=false; |
4957a608 BH |
271 | signal(SIGHUP, SIG_IGN); |
272 | signal(SIGUSR1, SIG_IGN); | |
273 | signal(SIGUSR2, SIG_IGN); | |
12c86877 | 274 | |
4957a608 | 275 | writePid(); |
12c86877 | 276 | } |
aced0e6c | 277 | pthread_mutex_unlock(&g_guardian_lock); |
12c86877 BH |
278 | int status; |
279 | cpid=pid; | |
280 | for(;;) { | |
4957a608 BH |
281 | int ret=waitpid(pid,&status,WNOHANG); |
282 | ||
283 | if(ret<0) { | |
284 | L<<Logger::Error<<"In guardian loop, waitpid returned error: "<<strerror(errno)<<endl; | |
285 | L<<Logger::Error<<"Dying"<<endl; | |
286 | exit(1); | |
287 | } | |
288 | else if(ret) // something exited | |
289 | break; | |
290 | else { // child is alive | |
291 | // execute some kind of ping here | |
292 | if(DLQuitPlease()) | |
293 | takedown(1); // needs a parameter.. | |
294 | setStatus("Child running on pid "+itoa(pid)); | |
295 | sleep(1); | |
296 | } | |
12c86877 | 297 | } |
aced0e6c BH |
298 | |
299 | pthread_mutex_lock(&g_guardian_lock); | |
300 | close(g_fd1[1]); | |
301 | fclose(g_fp); | |
302 | g_fp=0; | |
12c86877 BH |
303 | |
304 | if(WIFEXITED(status)) { | |
4957a608 BH |
305 | int ret=WEXITSTATUS(status); |
306 | ||
307 | if(ret==99) { | |
308 | L<<Logger::Error<<"Child requested a stop, exiting"<<endl; | |
309 | exit(1); | |
310 | } | |
311 | setStatus("Child died with code "+itoa(ret)); | |
312 | L<<Logger::Error<<"Our pdns instance exited with code "<<ret<<endl; | |
313 | L<<Logger::Error<<"Respawning"<<endl; | |
314 | ||
6f8e772b | 315 | goto respawn; |
12c86877 BH |
316 | } |
317 | if(WIFSIGNALED(status)) { | |
4957a608 BH |
318 | int sig=WTERMSIG(status); |
319 | setStatus("Child died because of signal "+itoa(sig)); | |
320 | L<<Logger::Error<<"Our pdns instance ("<<pid<<") exited after signal "<<sig<<endl; | |
12c86877 | 321 | #ifdef WCOREDUMP |
4957a608 BH |
322 | if(WCOREDUMP(status)) |
323 | L<<Logger::Error<<"Dumped core"<<endl; | |
12c86877 BH |
324 | #endif |
325 | ||
4957a608 | 326 | L<<Logger::Error<<"Respawning"<<endl; |
6f8e772b | 327 | goto respawn; |
12c86877 BH |
328 | } |
329 | L<<Logger::Error<<"No clue what happened! Respawning"<<endl; | |
6f8e772b IM |
330 | respawn: |
331 | if (cpid) { | |
332 | L<<Logger::Error<<"Cleaning up any remaining children with PGRP "<<cpid<<endl; | |
333 | kill(-cpid, SIGKILL); | |
334 | } | |
335 | sleep(1); | |
12c86877 BH |
336 | } |
337 | else { | |
338 | L<<Logger::Error<<"Unable to fork: "<<strerror(errno)<<endl; | |
339 | exit(1); | |
340 | } | |
341 | } | |
342 | } | |
343 | ||
344 | static void UNIX_declareArguments() | |
345 | { | |
65efcdbc | 346 | ::arg().set("config-dir","Location of configuration directory (pdns.conf)")=SYSCONFDIR; |
e8d78143 BH |
347 | ::arg().set("config-name","Name of this virtual configuration - will rename the binary image")=""; |
348 | ::arg().set("socket-dir","Where the controlsocket will live")=LOCALSTATEDIR; | |
0949b8ae | 349 | ::arg().set("module-dir","Default directory for modules")=PKGLIBDIR; |
e8d78143 BH |
350 | ::arg().set("chroot","If set, chroot to this directory for more security")=""; |
351 | ::arg().set("logging-facility","Log under a specific facility")=""; | |
352 | ::arg().set("daemon","Operate as a daemon")="no"; | |
12c86877 BH |
353 | } |
354 | ||
355 | static void loadModules() | |
356 | { | |
e8d78143 | 357 | if(!::arg()["load-modules"].empty()) { |
12c86877 BH |
358 | vector<string>modules; |
359 | ||
e8d78143 | 360 | stringtok(modules,::arg()["load-modules"],","); |
12c86877 BH |
361 | |
362 | for(vector<string>::const_iterator i=modules.begin();i!=modules.end();++i) { | |
363 | bool res; | |
364 | const string &module=*i; | |
365 | ||
366 | if(module.find(".")==string::npos) | |
4957a608 | 367 | res=UeberBackend::loadmodule(::arg()["module-dir"]+"/lib"+module+"backend.so"); |
12c86877 | 368 | else if(module[0]=='/' || (module[0]=='.' && module[1]=='/') || (module[0]=='.' && module[1]=='.')) // absolute or current path |
4957a608 | 369 | res=UeberBackend::loadmodule(module); |
12c86877 | 370 | else |
4957a608 | 371 | res=UeberBackend::loadmodule(::arg()["module-dir"]+"/"+module); |
12c86877 BH |
372 | |
373 | if(res==false) { | |
4957a608 BH |
374 | L<<Logger::Error<<"receiver unable to load module "<<module<<endl; |
375 | exit(1); | |
12c86877 BH |
376 | } |
377 | } | |
378 | } | |
379 | } | |
380 | ||
12c86877 BH |
381 | #ifdef __linux__ |
382 | #include <execinfo.h> | |
383 | static void tbhandler(int num) | |
384 | { | |
385 | L<<Logger::Critical<<"Got a signal "<<num<<", attempting to print trace: "<<endl; | |
386 | void *array[20]; //only care about last 17 functions (3 taken with tracing support) | |
387 | size_t size; | |
388 | char **strings; | |
389 | size_t i; | |
390 | ||
391 | size = backtrace (array, 20); | |
392 | strings = backtrace_symbols (array, size); //Need -rdynamic gcc (linker) flag for this to work | |
393 | ||
394 | for (i = 0; i < size; i++) //skip useless functions | |
395 | L<<Logger::Error<<strings[i]<<endl; | |
396 | ||
397 | ||
398 | signal(SIGABRT, SIG_DFL); | |
399 | abort();//hopefully will give core | |
400 | ||
401 | } | |
402 | #endif | |
403 | ||
404 | //! The main function of pdns, the pdns process | |
405 | int main(int argc, char **argv) | |
ba1a571d | 406 | { |
3e135495 | 407 | versionSetProduct(ProductAuthoritative); |
02116dff BH |
408 | reportAllTypes(); // init MOADNSParser |
409 | ||
1a3bbc1b IM |
410 | // Even if PDNS is not deamonized it must be |
411 | // the leader of the process group | |
412 | setpgid(getpid(), 0); | |
413 | ||
5c663d99 IM |
414 | // Initialize child PID var. It will remain 0 for pdns instance. |
415 | // It will have child value in the PDNS guardian instance. | |
416 | // cpid is needed to properly terminate PDNS process in | |
417 | // takedown function, and in Guardian's Cycle handler. | |
418 | cpid=0; | |
419 | ||
420 | signal(SIGINT, takedown); | |
421 | signal(SIGTERM, takedown); | |
422 | ||
12c86877 BH |
423 | s_programname="pdns"; |
424 | s_starttime=time(0); | |
425 | ||
426 | #ifdef __linux__ | |
427 | signal(SIGSEGV,tbhandler); | |
428 | signal(SIGFPE,tbhandler); | |
429 | signal(SIGABRT,tbhandler); | |
430 | signal(SIGILL,tbhandler); | |
431 | #endif | |
432 | ||
35b9a6ff PD |
433 | #if __GNUC__ >= 3 |
434 | std::ios_base::sync_with_stdio(false); | |
435 | #endif | |
12c86877 BH |
436 | |
437 | L.toConsole(Logger::Warning); | |
438 | try { | |
439 | declareArguments(); | |
440 | UNIX_declareArguments(); | |
c4db07b7 | 441 | |
e8d78143 | 442 | ::arg().laxParse(argc,argv); // do a lax parse |
12c86877 | 443 | |
c4db07b7 | 444 | if(::arg().mustDo("version")) { |
ba1a571d | 445 | showProductVersion(); |
3613a51c | 446 | showBuildConfiguration(); |
c4db07b7 PD |
447 | exit(99); |
448 | } | |
449 | ||
e8d78143 BH |
450 | if(::arg()["config-name"]!="") |
451 | s_programname+="-"+::arg()["config-name"]; | |
12c86877 BH |
452 | |
453 | (void)theL(s_programname); | |
454 | ||
e8d78143 | 455 | string configname=::arg()["config-dir"]+"/"+s_programname+".conf"; |
12c86877 BH |
456 | cleanSlashes(configname); |
457 | ||
e8d78143 BH |
458 | if(!::arg().mustDo("config") && !::arg().mustDo("no-config")) // "config" == print a configuration file |
459 | ::arg().laxFile(configname.c_str()); | |
12c86877 | 460 | |
e8d78143 BH |
461 | ::arg().laxParse(argc,argv); // reparse so the commandline still wins |
462 | if(!::arg()["logging-facility"].empty()) { | |
f8499e52 BH |
463 | int val=logFacilityToLOG(::arg().asNum("logging-facility") ); |
464 | if(val >= 0) | |
465 | theL().setFacility(val); | |
6e2514e4 | 466 | else |
4957a608 | 467 | L<<Logger::Error<<"Unknown logging facility "<<::arg().asNum("logging-facility") <<endl; |
12c86877 BH |
468 | } |
469 | ||
e8d78143 BH |
470 | L.setLoglevel((Logger::Urgency)(::arg().asNum("loglevel"))); |
471 | L.toConsole((Logger::Urgency)(::arg().asNum("loglevel"))); | |
12c86877 | 472 | |
e8d78143 BH |
473 | if(::arg().mustDo("help") || ::arg().mustDo("config")) { |
474 | ::arg().set("daemon")="no"; | |
475 | ::arg().set("guardian")="no"; | |
12c86877 BH |
476 | } |
477 | ||
e8d78143 BH |
478 | if(::arg().mustDo("guardian") && !isGuarded(argv)) { |
479 | if(::arg().mustDo("daemon")) { | |
4957a608 BH |
480 | L.toConsole(Logger::Critical); |
481 | daemonize(); | |
12c86877 BH |
482 | } |
483 | guardian(argc, argv); | |
484 | // never get here, guardian will reinvoke process | |
485 | cerr<<"Um, we did get here!"<<endl; | |
486 | } | |
45fdd612 | 487 | |
12c86877 BH |
488 | |
489 | // we really need to do work - either standalone or as an instance | |
5488e86b PD |
490 | |
491 | #ifdef __linux__ | |
492 | if(!::arg().mustDo("traceback-handler")) { | |
493 | L<<Logger::Warning<<"Disabling traceback handler"<<endl; | |
494 | signal(SIGSEGV,SIG_DFL); | |
495 | signal(SIGFPE,SIG_DFL); | |
496 | signal(SIGABRT,SIG_DFL); | |
497 | signal(SIGILL,SIG_DFL); | |
498 | } | |
499 | #endif | |
500 | ||
a28a204a BH |
501 | seedRandom(::arg()["entropy-source"]); |
502 | ||
12c86877 | 503 | loadModules(); |
e8d78143 | 504 | BackendMakers().launch(::arg()["launch"]); // vrooooom! |
f4137d84 | 505 | |
e8d78143 | 506 | if(!::arg().getCommands().empty()) { |
49daa3cd BH |
507 | cerr<<"Fatal: non-option on the command line, perhaps a '--setting=123' statement missed the '='?"<<endl; |
508 | exit(99); | |
509 | } | |
f4137d84 | 510 | |
e8d78143 | 511 | if(::arg().mustDo("help")) { |
ff5ba4f9 WA |
512 | cout<<"syntax:"<<endl<<endl; |
513 | cout<<::arg().helpstring(::arg()["help"])<<endl; | |
514 | exit(0); | |
12c86877 BH |
515 | } |
516 | ||
e8d78143 BH |
517 | if(::arg().mustDo("config")) { |
518 | cout<<::arg().configstring()<<endl; | |
12c86877 BH |
519 | exit(99); |
520 | } | |
521 | ||
e8d78143 | 522 | if(::arg().mustDo("list-modules")) { |
12c86877 BH |
523 | vector<string>modules=BackendMakers().getModules(); |
524 | cerr<<"Modules available:"<<endl; | |
525 | for(vector<string>::const_iterator i=modules.begin();i!=modules.end();++i) | |
4957a608 | 526 | cout<<*i<<endl; |
12c86877 BH |
527 | |
528 | exit(99); | |
529 | } | |
da44c9ea | 530 | |
e8d78143 | 531 | if(!::arg().asNum("local-port")) { |
da44c9ea BH |
532 | L<<Logger::Error<<"Unable to launch, binding to no port or port 0 makes no sense"<<endl; |
533 | exit(99); // this isn't going to fix itself either | |
534 | } | |
12c86877 BH |
535 | if(!BackendMakers().numLauncheable()) { |
536 | L<<Logger::Error<<"Unable to launch, no backends configured for querying"<<endl; | |
da44c9ea | 537 | exit(99); // this isn't going to fix itself either |
12c86877 | 538 | } |
e8d78143 | 539 | if(::arg().mustDo("daemon")) { |
12c86877 BH |
540 | L.toConsole(Logger::None); |
541 | if(!isGuarded(argv)) | |
4957a608 | 542 | daemonize(); |
12c86877 BH |
543 | } |
544 | ||
545 | if(isGuarded(argv)) { | |
546 | L<<Logger::Warning<<"This is a guarded instance of pdns"<<endl; | |
547 | dl=new DynListener; // listens on stdin | |
548 | } | |
549 | else { | |
550 | L<<Logger::Warning<<"This is a standalone pdns"<<endl; | |
551 | ||
e8d78143 | 552 | if(::arg().mustDo("control-console")) |
4957a608 | 553 | dl=new DynListener(); |
12c86877 | 554 | else |
4957a608 | 555 | dl=new DynListener(s_programname); |
12c86877 BH |
556 | |
557 | writePid(); | |
558 | } | |
3c90953e PD |
559 | DynListener::registerFunc("SHOW",&DLShowHandler, "show a specific statistic or * to get a list", "<statistic>"); |
560 | DynListener::registerFunc("RPING",&DLPingHandler, "ping instance"); | |
561 | DynListener::registerFunc("QUIT",&DLRQuitHandler, "quit daemon"); | |
562 | DynListener::registerFunc("UPTIME",&DLUptimeHandler, "get instance uptime"); | |
563 | DynListener::registerFunc("NOTIFY-HOST",&DLNotifyHostHandler, "notify host for specific domain", "<domain> <host>"); | |
564 | DynListener::registerFunc("NOTIFY",&DLNotifyHandler, "queue a notification", "<domain>"); | |
565 | DynListener::registerFunc("RELOAD",&DLReloadHandler, "reload all zones"); | |
566 | DynListener::registerFunc("REDISCOVER",&DLRediscoverHandler, "discover any new zones"); | |
567 | DynListener::registerFunc("VERSION",&DLVersionHandler, "get instance version"); | |
568 | DynListener::registerFunc("PURGE",&DLPurgeHandler, "purge entries from packet cache", "[<record>]"); | |
569 | DynListener::registerFunc("CCOUNTS",&DLCCHandler, "get cache statistics"); | |
ba7244a5 | 570 | DynListener::registerFunc("QTYPES", &DLQTypesHandler, "get QType statistics"); |
93698ef3 PD |
571 | DynListener::registerFunc("RESPSIZES", &DLRSizesHandler, "get histogram of response sizes"); |
572 | DynListener::registerFunc("REMOTES", &DLRemotesHandler, "get top remotes"); | |
3c90953e PD |
573 | DynListener::registerFunc("SET",&DLSettingsHandler, "set config variables", "<var> <value>"); |
574 | DynListener::registerFunc("RETRIEVE",&DLNotifyRetrieveHandler, "retrieve slave domain", "<domain>"); | |
64bcb6be | 575 | DynListener::registerFunc("CURRENT-CONFIG",&DLCurrentConfigHandler, "Retrieve the current configuration"); |
cd76677f | 576 | DynListener::registerFunc("LIST-ZONES",&DLListZones, "show list of zones", "[master|slave|native]"); |
040712e0 BH |
577 | |
578 | if(!::arg()["tcp-control-address"].empty()) { | |
579 | DynListener* dlTCP=new DynListener(ComboAddress(::arg()["tcp-control-address"], ::arg().asNum("tcp-control-port"))); | |
580 | dlTCP->go(); | |
581 | } | |
12c86877 | 582 | |
12c86877 | 583 | // reparse, with error checking |
e8d78143 BH |
584 | if(!::arg().mustDo("no-config")) |
585 | ::arg().file(configname.c_str()); | |
586 | ::arg().parse(argc,argv); | |
5bc3abe7 PD |
587 | |
588 | if(::arg()["server-id"].empty()) { | |
589 | char tmp[128]; | |
590 | gethostname(tmp, sizeof(tmp)-1); | |
591 | ::arg().set("server-id")=tmp; | |
592 | } | |
593 | ||
12c86877 BH |
594 | UeberBackend::go(); |
595 | N=new UDPNameserver; // this fails when we are not root, throws exception | |
596 | ||
e8d78143 | 597 | if(!::arg().mustDo("disable-tcp")) |
12c86877 BH |
598 | TN=new TCPNameserver; |
599 | } | |
600 | catch(const ArgException &A) { | |
601 | L<<Logger::Error<<"Fatal error: "<<A.reason<<endl; | |
602 | exit(1); | |
603 | } | |
604 | ||
605 | declareStats(); | |
606 | DLOG(L<<Logger::Warning<<"Verbose logging in effect"<<endl); | |
12c86877 | 607 | |
ba1a571d | 608 | showProductVersion(); |
12c86877 BH |
609 | |
610 | try { | |
12c86877 BH |
611 | mainthread(); |
612 | } | |
3f81d239 | 613 | catch(PDNSException &AE) { |
e8d78143 | 614 | if(!::arg().mustDo("daemon")) |
12c86877 BH |
615 | cerr<<"Exiting because: "<<AE.reason<<endl; |
616 | L<<Logger::Error<<"Exiting because: "<<AE.reason<<endl; | |
617 | } | |
adc10f99 | 618 | catch(std::exception &e) { |
e8d78143 | 619 | if(!::arg().mustDo("daemon")) |
12c86877 BH |
620 | cerr<<"Exiting because of STL error: "<<e.what()<<endl; |
621 | L<<Logger::Error<<"Exiting because of STL error: "<<e.what()<<endl; | |
622 | } | |
623 | catch(...) { | |
624 | cerr<<"Uncaught exception of unknown type - sorry"<<endl; | |
625 | } | |
626 | ||
627 | exit(1); | |
628 | ||
629 | } | |
630 | ||
631 |