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 $ */
27 #include <isc/commandline.h>
29 #include <isc/entropy.h>
33 #include <isc/platform.h>
34 #include <isc/resource.h>
36 #include <isc/timer.h>
39 #include <isccc/result.h>
41 #include <dns/dispatch.h>
43 #include <dns/result.h>
46 #include <dst/result.h>
49 * Defining NS_MAIN provides storage declarations (rather than extern)
50 * for variables in named/globals.h.
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>
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];
75 ns_main_earlywarning(const char *format
, ...) {
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
,
84 fprintf(stderr
, "%s: ", program_name
);
85 vfprintf(stderr
, format
, args
);
86 fprintf(stderr
, "\n");
93 ns_main_earlyfatal(const char *format
, ...) {
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
,
101 isc_log_write(ns_g_lctx
, NS_LOGCATEGORY_GENERAL
,
102 NS_LOGMODULE_MAIN
, ISC_LOG_CRITICAL
,
103 "exiting (due to early fatal error)");
105 fprintf(stderr
, "%s: ", program_name
);
106 vfprintf(stderr
, format
, args
);
107 fprintf(stderr
, "\n");
116 assertion_failed(const char *file
, int line
, isc_assertiontype_t type
,
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)");
138 fprintf(stderr
, "%s:%d: %s(%s) failed\n",
139 file
, line
, isc_assertion_typetotext(type
), cond
);
149 library_fatal_error(const char *file
, int line
, const char *format
,
150 va_list args
) ISC_FORMAT_PRINTF(3, 0);
153 library_fatal_error(const char *file
, int line
, const char *format
,
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
,
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)");
177 fprintf(stderr
, "%s:%d: fatal error: ", file
, line
);
178 vfprintf(stderr
, format
, args
);
179 fprintf(stderr
, "\n");
189 library_unexpected_error(const char *file
, int line
, const char *format
,
190 va_list args
) ISC_FORMAT_PRINTF(3, 0);
193 library_unexpected_error(const char *file
, int line
, const char *format
,
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
,
208 fprintf(stderr
, "%s:%d: fatal error: ", file
, line
);
209 vfprintf(stderr
, format
, args
);
210 fprintf(stderr
, "\n");
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");
227 if (ns_g_lwresdonly
) {
232 "usage: named [-c conffile] [-d debuglevel] "
233 "[-f|-g] [-n number_of_cpus]\n"
234 " [-p port] [-s] [-t chrootdir] [-u username]\n");
238 save_command_line(int argc
, char *argv
[]) {
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
++) {
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
== '/') {
272 INSIST(sizeof(saved_command_line
) >= sizeof(truncated
));
275 strcpy(eob
- sizeof(truncated
), truncated
);
281 parse_int(char *arg
, const char *desc
) {
286 ltmp
= strtol(arg
, &endp
, 10);
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
);
296 parse_command_line(int argc
, char *argv
[]) {
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:")) !=
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
;
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
;
321 ns_g_debuglevel
= parse_int(isc_commandline_argument
,
325 ns_g_foreground
= ISC_TRUE
;
328 ns_g_foreground
= ISC_TRUE
;
329 ns_g_logstderr
= ISC_TRUE
;
331 /* XXXBEW -i should be removed */
333 lwresd_g_defaultpidfile
= isc_commandline_argument
;
336 ns_g_lwresdonly
= ISC_TRUE
;
338 case 'N': /* Deprecated. */
340 ns_g_cpus
= parse_int(isc_commandline_argument
,
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
);
352 /* XXXBEW Should -P be removed? */
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
;
361 /* XXXRTH temporary syntax */
362 want_stats
= ISC_TRUE
;
365 /* XXXJAB should we make a copy? */
366 ns_g_chrootdir
= isc_commandline_argument
;
369 ns_g_username
= isc_commandline_argument
;
372 printf("BIND %s\n", ns_g_version
);
376 ns_main_earlyfatal("unknown option '-%c'",
377 isc_commandline_option
);
379 ns_main_earlyfatal("parsing options returned %d", ch
);
383 argc
-= isc_commandline_index
;
384 argv
+= isc_commandline_index
;
388 ns_main_earlyfatal("extra command line arguments");
395 create_managers(void) {
398 #ifdef ISC_PLATFORM_USETHREADS
400 ns_g_cpus
= isc_os_ncpus();
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
);
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
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
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.)
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
)
515 isc_log_write(ns_g_lctx
, NS_LOGCATEGORY_GENERAL
, NS_LOGMODULE_MAIN
,
516 ISC_LOG_NOTICE
, "starting BIND %s%s", ns_g_version
,
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
,
526 (void)isc_resource_getlimit(isc_resource_coresize
,
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
,
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.
556 ns_server_create(ns_g_mctx
, &ns_g_server
);
563 ns_server_destroy(&ns_g_server
);
566 * Add calls to unregister sdb drivers here.
570 isc_log_write(ns_g_lctx
, NS_LOGCATEGORY_GENERAL
, NS_LOGMODULE_MAIN
,
571 ISC_LOG_NOTICE
, "exiting");
576 main(int argc
, char *argv
[]) {
580 * Record version in core image.
581 * strings named.core | grep "named version:"
584 strncat(version
, "named version: BIND " VERSION
" (" __DATE__
")",
587 strncat(version
, "named version: BIND " VERSION
, sizeof(version
));
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
);
622 * Start things running and then wait for a shutdown request
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__
,
633 isc_result_totext(result
));
637 result
= ISC_R_SUCCESS
;
639 } while (result
!= ISC_R_SUCCESS
);
644 isc_mem_stats(ns_g_mctx
, stdout
);
645 isc_mutex_stats(stdout
);
647 isc_mem_destroy(&ns_g_mctx
);
651 ns_os_closedevnull();