Add BIND 9.2.4rc7.
[dragonfly.git] / contrib / bind-9.2.4rc7 / bin / named / main.c
blob9c772c8f836f345a9f081dc656e6672f0c71bfde
1 /*
2 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: main.c,v 1.119.2.10 2004/04/20 13:54:17 marka Exp $ */
20 #include <config.h>
22 #include <ctype.h>
23 #include <stdlib.h>
24 #include <string.h>
26 #include <isc/app.h>
27 #include <isc/commandline.h>
28 #include <isc/dir.h>
29 #include <isc/entropy.h>
30 #include <isc/file.h>
31 #include <isc/hash.h>
32 #include <isc/os.h>
33 #include <isc/platform.h>
34 #include <isc/resource.h>
35 #include <isc/task.h>
36 #include <isc/timer.h>
37 #include <isc/util.h>
39 #include <isccc/result.h>
41 #include <dns/dispatch.h>
42 #include <dns/name.h>
43 #include <dns/result.h>
44 #include <dns/view.h>
46 #include <dst/result.h>
49 * Defining NS_MAIN provides storage declarations (rather than extern)
50 * for variables in named/globals.h.
52 #define NS_MAIN 1
54 #include <named/control.h>
55 #include <named/globals.h> /* Explicit, though named/log.h includes it. */
56 #include <named/interfacemgr.h>
57 #include <named/log.h>
58 #include <named/os.h>
59 #include <named/server.h>
60 #include <named/lwresd.h>
61 #include <named/main.h>
64 * Include header files for database drivers here.
66 /* #include "xxdb.h" */
68 static isc_boolean_t want_stats = ISC_FALSE;
69 static char program_name[ISC_DIR_NAMEMAX] = "named";
70 static char absolute_conffile[ISC_DIR_PATHMAX];
71 static char saved_command_line[512];
72 static char version[512];
74 void
75 ns_main_earlywarning(const char *format, ...) {
76 va_list args;
78 va_start(args, format);
79 if (ns_g_lctx != NULL) {
80 isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
81 NS_LOGMODULE_MAIN, ISC_LOG_WARNING,
82 format, args);
83 } else {
84 fprintf(stderr, "%s: ", program_name);
85 vfprintf(stderr, format, args);
86 fprintf(stderr, "\n");
87 fflush(stderr);
89 va_end(args);
92 void
93 ns_main_earlyfatal(const char *format, ...) {
94 va_list args;
96 va_start(args, format);
97 if (ns_g_lctx != NULL) {
98 isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
99 NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
100 format, args);
101 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
102 NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
103 "exiting (due to early fatal error)");
104 } else {
105 fprintf(stderr, "%s: ", program_name);
106 vfprintf(stderr, format, args);
107 fprintf(stderr, "\n");
108 fflush(stderr);
110 va_end(args);
112 exit(1);
115 static void
116 assertion_failed(const char *file, int line, isc_assertiontype_t type,
117 const char *cond)
120 * Handle assertion failures.
123 if (ns_g_lctx != NULL) {
125 * Reset the assetion callback in case it is the log
126 * routines causing the assertion.
128 isc_assertion_setcallback(NULL);
130 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
131 NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
132 "%s:%d: %s(%s) failed", file, line,
133 isc_assertion_typetotext(type), cond);
134 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
135 NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
136 "exiting (due to assertion failure)");
137 } else {
138 fprintf(stderr, "%s:%d: %s(%s) failed\n",
139 file, line, isc_assertion_typetotext(type), cond);
140 fflush(stderr);
143 if (ns_g_coreok)
144 abort();
145 exit(1);
148 static void
149 library_fatal_error(const char *file, int line, const char *format,
150 va_list args) ISC_FORMAT_PRINTF(3, 0);
152 static void
153 library_fatal_error(const char *file, int line, const char *format,
154 va_list args)
157 * Handle isc_error_fatal() calls from our libraries.
160 if (ns_g_lctx != NULL) {
162 * Reset the error callback in case it is the log
163 * routines causing the assertion.
165 isc_error_setfatal(NULL);
167 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
168 NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
169 "%s:%d: fatal error:", file, line);
170 isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
171 NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
172 format, args);
173 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
174 NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
175 "exiting (due to fatal error in library)");
176 } else {
177 fprintf(stderr, "%s:%d: fatal error: ", file, line);
178 vfprintf(stderr, format, args);
179 fprintf(stderr, "\n");
180 fflush(stderr);
183 if (ns_g_coreok)
184 abort();
185 exit(1);
188 static void
189 library_unexpected_error(const char *file, int line, const char *format,
190 va_list args) ISC_FORMAT_PRINTF(3, 0);
192 static void
193 library_unexpected_error(const char *file, int line, const char *format,
194 va_list args)
197 * Handle isc_error_unexpected() calls from our libraries.
200 if (ns_g_lctx != NULL) {
201 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
202 NS_LOGMODULE_MAIN, ISC_LOG_ERROR,
203 "%s:%d: unexpected error:", file, line);
204 isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
205 NS_LOGMODULE_MAIN, ISC_LOG_ERROR,
206 format, args);
207 } else {
208 fprintf(stderr, "%s:%d: fatal error: ", file, line);
209 vfprintf(stderr, format, args);
210 fprintf(stderr, "\n");
211 fflush(stderr);
215 static void
216 lwresd_usage(void) {
217 fprintf(stderr,
218 "usage: lwresd [-c conffile | -C resolvconffile] "
219 "[-d debuglevel] [-f|-g]\n"
220 " [-n number_of_cpus] [-p port]"
221 "[-P listen-port] [-s]\n"
222 " [-t chrootdir] [-u username] [-i pidfile]\n");
225 static void
226 usage(void) {
227 if (ns_g_lwresdonly) {
228 lwresd_usage();
229 return;
231 fprintf(stderr,
232 "usage: named [-c conffile] [-d debuglevel] "
233 "[-f|-g] [-n number_of_cpus]\n"
234 " [-p port] [-s] [-t chrootdir] [-u username]\n");
237 static void
238 save_command_line(int argc, char *argv[]) {
239 int i;
240 char *src;
241 char *dst;
242 char *eob;
243 const char truncated[] = "...";
244 isc_boolean_t quoted = ISC_FALSE;
246 dst = saved_command_line;
247 eob = saved_command_line + sizeof(saved_command_line);
249 for (i = 1; i < argc && dst < eob; i++) {
250 *dst++ = ' ';
252 src = argv[i];
253 while (*src != '\0' && dst < eob) {
255 * This won't perfectly produce a shell-independent
256 * pastable command line in all circumstances, but
257 * comes close, and for practical purposes will
258 * nearly always be fine.
260 if (quoted || isalnum(*src & 0xff) ||
261 *src == '-' || *src == '_' ||
262 *src == '.' || *src == '/') {
263 *dst++ = *src++;
264 quoted = ISC_FALSE;
265 } else {
266 *dst++ = '\\';
267 quoted = ISC_TRUE;
272 INSIST(sizeof(saved_command_line) >= sizeof(truncated));
274 if (dst == eob)
275 strcpy(eob - sizeof(truncated), truncated);
276 else
277 *dst = '\0';
280 static int
281 parse_int(char *arg, const char *desc) {
282 char *endp;
283 int tmp;
284 long int ltmp;
286 ltmp = strtol(arg, &endp, 10);
287 tmp = (int) ltmp;
288 if (*endp != '\0')
289 ns_main_earlyfatal("%s '%s' must be numeric", desc, arg);
290 if (tmp < 0 || tmp != ltmp)
291 ns_main_earlyfatal("%s '%s' out of range", desc, arg);
292 return (tmp);
295 static void
296 parse_command_line(int argc, char *argv[]) {
297 int ch;
298 int port;
300 save_command_line(argc, argv);
302 isc_commandline_errprint = ISC_FALSE;
303 while ((ch = isc_commandline_parse(argc, argv,
304 "c:C:d:fgi:ln:N:p:P:st:u:vx:")) !=
305 -1) {
306 switch (ch) {
307 case 'c':
308 ns_g_conffile = isc_commandline_argument;
309 lwresd_g_conffile = isc_commandline_argument;
310 if (lwresd_g_useresolvconf)
311 ns_main_earlyfatal("cannot specify -c and -C");
312 ns_g_conffileset = ISC_TRUE;
313 break;
314 case 'C':
315 lwresd_g_resolvconffile = isc_commandline_argument;
316 if (ns_g_conffileset)
317 ns_main_earlyfatal("cannot specify -c and -C");
318 lwresd_g_useresolvconf = ISC_TRUE;
319 break;
320 case 'd':
321 ns_g_debuglevel = parse_int(isc_commandline_argument,
322 "debug level");
323 break;
324 case 'f':
325 ns_g_foreground = ISC_TRUE;
326 break;
327 case 'g':
328 ns_g_foreground = ISC_TRUE;
329 ns_g_logstderr = ISC_TRUE;
330 break;
331 /* XXXBEW -i should be removed */
332 case 'i':
333 lwresd_g_defaultpidfile = isc_commandline_argument;
334 break;
335 case 'l':
336 ns_g_lwresdonly = ISC_TRUE;
337 break;
338 case 'N': /* Deprecated. */
339 case 'n':
340 ns_g_cpus = parse_int(isc_commandline_argument,
341 "number of cpus");
342 if (ns_g_cpus == 0)
343 ns_g_cpus = 1;
344 break;
345 case 'p':
346 port = parse_int(isc_commandline_argument, "port");
347 if (port < 1 || port > 65535)
348 ns_main_earlyfatal("port '%s' out of range",
349 isc_commandline_argument);
350 ns_g_port = port;
351 break;
352 /* XXXBEW Should -P be removed? */
353 case 'P':
354 port = parse_int(isc_commandline_argument, "port");
355 if (port < 1 || port > 65535)
356 ns_main_earlyfatal("port '%s' out of range",
357 isc_commandline_argument);
358 lwresd_g_listenport = port;
359 break;
360 case 's':
361 /* XXXRTH temporary syntax */
362 want_stats = ISC_TRUE;
363 break;
364 case 't':
365 /* XXXJAB should we make a copy? */
366 ns_g_chrootdir = isc_commandline_argument;
367 break;
368 case 'u':
369 ns_g_username = isc_commandline_argument;
370 break;
371 case 'v':
372 printf("BIND %s\n", ns_g_version);
373 exit(0);
374 case '?':
375 usage();
376 ns_main_earlyfatal("unknown option '-%c'",
377 isc_commandline_option);
378 default:
379 ns_main_earlyfatal("parsing options returned %d", ch);
383 argc -= isc_commandline_index;
384 argv += isc_commandline_index;
386 if (argc > 0) {
387 usage();
388 ns_main_earlyfatal("extra command line arguments");
394 static isc_result_t
395 create_managers(void) {
396 isc_result_t result;
398 #ifdef ISC_PLATFORM_USETHREADS
399 if (ns_g_cpus == 0)
400 ns_g_cpus = isc_os_ncpus();
401 #else
402 ns_g_cpus = 1;
403 #endif
404 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
405 ISC_LOG_INFO, "using %u CPU%s",
406 ns_g_cpus, ns_g_cpus == 1 ? "" : "s");
407 result = isc_taskmgr_create(ns_g_mctx, ns_g_cpus, 0, &ns_g_taskmgr);
408 if (result != ISC_R_SUCCESS) {
409 UNEXPECTED_ERROR(__FILE__, __LINE__,
410 "ns_taskmgr_create() failed: %s",
411 isc_result_totext(result));
412 return (ISC_R_UNEXPECTED);
415 result = isc_timermgr_create(ns_g_mctx, &ns_g_timermgr);
416 if (result != ISC_R_SUCCESS) {
417 UNEXPECTED_ERROR(__FILE__, __LINE__,
418 "ns_timermgr_create() failed: %s",
419 isc_result_totext(result));
420 return (ISC_R_UNEXPECTED);
423 result = isc_socketmgr_create(ns_g_mctx, &ns_g_socketmgr);
424 if (result != ISC_R_SUCCESS) {
425 UNEXPECTED_ERROR(__FILE__, __LINE__,
426 "isc_socketmgr_create() failed: %s",
427 isc_result_totext(result));
428 return (ISC_R_UNEXPECTED);
431 result = isc_entropy_create(ns_g_mctx, &ns_g_entropy);
432 if (result != ISC_R_SUCCESS) {
433 UNEXPECTED_ERROR(__FILE__, __LINE__,
434 "isc_entropy_create() failed: %s",
435 isc_result_totext(result));
436 return (ISC_R_UNEXPECTED);
439 result = isc_hash_create(ns_g_mctx, ns_g_entropy, DNS_NAME_MAXWIRE);
440 if (result != ISC_R_SUCCESS) {
441 UNEXPECTED_ERROR(__FILE__, __LINE__,
442 "isc_hash_create() failed: %s",
443 isc_result_totext(result));
444 return (ISC_R_UNEXPECTED);
447 return (ISC_R_SUCCESS);
450 static void
451 destroy_managers(void) {
452 ns_lwresd_shutdown();
454 isc_entropy_detach(&ns_g_entropy);
456 * isc_taskmgr_destroy() will block until all tasks have exited,
458 isc_taskmgr_destroy(&ns_g_taskmgr);
459 isc_timermgr_destroy(&ns_g_timermgr);
460 isc_socketmgr_destroy(&ns_g_socketmgr);
463 * isc_hash_destroy() cannot be called as long as a resolver may be
464 * running. Calling this after isc_taskmgr_destroy() ensures the
465 * call is safe.
467 isc_hash_destroy();
470 static void
471 setup(void) {
472 isc_result_t result;
475 * Get the user and group information before changing the root
476 * directory, so the administrator does not need to keep a copy
477 * of the user and group databases in the chroot'ed environment.
479 ns_os_inituserinfo(ns_g_username);
482 * Initialize time conversion information
484 ns_os_tzset();
486 ns_os_opendevnull();
488 ns_os_chroot(ns_g_chrootdir);
491 * For operating systems which have a capability mechanism, now
492 * is the time to switch to minimal privs and change our user id.
493 * On traditional UNIX systems, this call will be a no-op, and we
494 * will change the user ID after reading the config file the first
495 * time. (We need to read the config file to know which possibly
496 * privileged ports to bind() to.)
498 ns_os_minprivs();
500 result = ns_log_init(ISC_TF(ns_g_username != NULL));
501 if (result != ISC_R_SUCCESS)
502 ns_main_earlyfatal("ns_log_init() failed: %s",
503 isc_result_totext(result));
506 * Now is the time to daemonize (if we're not running in the
507 * foreground). We waited until now because we wanted to get
508 * a valid logging context setup. We cannot daemonize any later,
509 * because calling create_managers() will create threads, which
510 * would be lost after fork().
512 if (!ns_g_foreground)
513 ns_os_daemonize();
515 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
516 ISC_LOG_NOTICE, "starting BIND %s%s", ns_g_version,
517 saved_command_line);
520 * Get the initial resource limits.
522 (void)isc_resource_getlimit(isc_resource_stacksize,
523 &ns_g_initstacksize);
524 (void)isc_resource_getlimit(isc_resource_datasize,
525 &ns_g_initdatasize);
526 (void)isc_resource_getlimit(isc_resource_coresize,
527 &ns_g_initcoresize);
528 (void)isc_resource_getlimit(isc_resource_openfiles,
529 &ns_g_initopenfiles);
532 * If the named configuration filename is relative, prepend the current
533 * directory's name before possibly changing to another directory.
535 if (! isc_file_isabsolute(ns_g_conffile)) {
536 result = isc_file_absolutepath(ns_g_conffile,
537 absolute_conffile,
538 sizeof(absolute_conffile));
539 if (result != ISC_R_SUCCESS)
540 ns_main_earlyfatal("could not construct absolute path of "
541 "configuration file: %s",
542 isc_result_totext(result));
543 ns_g_conffile = absolute_conffile;
546 result = create_managers();
547 if (result != ISC_R_SUCCESS)
548 ns_main_earlyfatal("create_managers() failed: %s",
549 isc_result_totext(result));
552 * Add calls to register sdb drivers here.
554 /* xxdb_init(); */
556 ns_server_create(ns_g_mctx, &ns_g_server);
559 static void
560 cleanup(void) {
561 destroy_managers();
563 ns_server_destroy(&ns_g_server);
566 * Add calls to unregister sdb drivers here.
568 /* xxdb_clear(); */
570 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
571 ISC_LOG_NOTICE, "exiting");
572 ns_log_shutdown();
576 main(int argc, char *argv[]) {
577 isc_result_t result;
580 * Record version in core image.
581 * strings named.core | grep "named version:"
583 #ifdef __DATE__
584 strncat(version, "named version: BIND " VERSION " (" __DATE__ ")",
585 sizeof(version));
586 #else
587 strncat(version, "named version: BIND " VERSION, sizeof(version));
588 #endif
589 version[sizeof(version) - 1] = '\0';
590 result = isc_file_progname(*argv, program_name, sizeof(program_name));
591 if (result != ISC_R_SUCCESS)
592 ns_main_earlyfatal("program name too long");
594 if (strcmp(program_name, "lwresd") == 0)
595 ns_g_lwresdonly = ISC_TRUE;
597 isc_assertion_setcallback(assertion_failed);
598 isc_error_setfatal(library_fatal_error);
599 isc_error_setunexpected(library_unexpected_error);
601 ns_os_init(program_name);
603 result = isc_app_start();
604 if (result != ISC_R_SUCCESS)
605 ns_main_earlyfatal("isc_app_start() failed: %s",
606 isc_result_totext(result));
608 result = isc_mem_create(0, 0, &ns_g_mctx);
609 if (result != ISC_R_SUCCESS)
610 ns_main_earlyfatal("isc_mem_create() failed: %s",
611 isc_result_totext(result));
613 dns_result_register();
614 dst_result_register();
615 isccc_result_register();
617 parse_command_line(argc, argv);
619 setup();
622 * Start things running and then wait for a shutdown request
623 * or reload.
625 do {
626 result = isc_app_run();
628 if (result == ISC_R_RELOAD) {
629 ns_server_reloadwanted(ns_g_server);
630 } else if (result != ISC_R_SUCCESS) {
631 UNEXPECTED_ERROR(__FILE__, __LINE__,
632 "isc_app_run(): %s",
633 isc_result_totext(result));
635 * Force exit.
637 result = ISC_R_SUCCESS;
639 } while (result != ISC_R_SUCCESS);
641 cleanup();
643 if (want_stats) {
644 isc_mem_stats(ns_g_mctx, stdout);
645 isc_mutex_stats(stdout);
647 isc_mem_destroy(&ns_g_mctx);
649 isc_app_finish();
651 ns_os_closedevnull();
653 ns_os_shutdown();
655 return (0);