2 * Copyright (C) 2004-2016 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or 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.
27 #include <isc/backtrace.h>
28 #include <isc/commandline.h>
30 #include <isc/entropy.h>
34 #include <isc/platform.h>
35 #include <isc/print.h>
36 #include <isc/resource.h>
37 #include <isc/stdio.h>
38 #include <isc/string.h>
40 #include <isc/timer.h>
43 #include <isccc/result.h>
45 #include <dns/dispatch.h>
47 #include <dns/result.h>
50 #include <dst/result.h>
52 #include <dlz/dlz_dlopen_driver.h>
54 #ifdef HAVE_GPERFTOOLS_PROFILER
55 #include <gperftools/profiler.h>
59 * Defining NS_MAIN provides storage declarations (rather than extern)
60 * for variables in named/globals.h.
64 #include <named/builtin.h>
65 #include <named/control.h>
66 #include <named/globals.h> /* Explicit, though named/log.h includes it. */
67 #include <named/interfacemgr.h>
68 #include <named/log.h>
70 #include <named/server.h>
71 #include <named/lwresd.h>
72 #include <named/main.h>
74 #include <named/ns_smf_globals.h>
78 #include <openssl/opensslv.h>
79 #include <openssl/crypto.h>
82 #include <libxml/xmlversion.h>
85 * Include header files for database drivers here.
87 /* #include "xxdb.h" */
91 * Include contributed DLZ drivers if appropriate.
93 #include <dlz/dlz_drivers.h>
97 * The maximum number of stack frames to dump on assertion failure.
99 #ifndef BACKTRACE_MAXFRAME
100 #define BACKTRACE_MAXFRAME 128
103 extern unsigned int dns_zone_mkey_hour;
104 extern unsigned int dns_zone_mkey_day;
105 extern unsigned int dns_zone_mkey_month;
107 static isc_boolean_t want_stats = ISC_FALSE;
108 static char program_name[ISC_DIR_NAMEMAX] = "named";
109 static char absolute_conffile[ISC_DIR_PATHMAX];
110 static char saved_command_line[512];
111 static char version[512];
112 static unsigned int maxsocks = 0;
113 static int maxudp = 0;
116 ns_main_earlywarning(const char *format, ...) {
119 va_start(args, format);
120 if (ns_g_lctx != NULL) {
121 isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
122 NS_LOGMODULE_MAIN, ISC_LOG_WARNING,
125 fprintf(stderr, "%s: ", program_name);
126 vfprintf(stderr, format, args);
127 fprintf(stderr, "\n");
134 ns_main_earlyfatal(const char *format, ...) {
137 va_start(args, format);
138 if (ns_g_lctx != NULL) {
139 isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
140 NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
142 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
143 NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
144 "exiting (due to early fatal error)");
146 fprintf(stderr, "%s: ", program_name);
147 vfprintf(stderr, format, args);
148 fprintf(stderr, "\n");
156 ISC_PLATFORM_NORETURN_PRE static void
157 assertion_failed(const char *file, int line, isc_assertiontype_t type,
158 const char *cond) ISC_PLATFORM_NORETURN_POST;
161 assertion_failed(const char *file, int line, isc_assertiontype_t type,
164 void *tracebuf[BACKTRACE_MAXFRAME];
167 const char *logsuffix = "";
171 * Handle assertion failures.
174 if (ns_g_lctx != NULL) {
176 * Reset the assertion callback in case it is the log
177 * routines causing the assertion.
179 isc_assertion_setcallback(NULL);
181 result = isc_backtrace_gettrace(tracebuf, BACKTRACE_MAXFRAME,
183 if (result == ISC_R_SUCCESS && nframes > 0)
184 logsuffix = ", back trace";
185 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
186 NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
187 "%s:%d: %s(%s) failed%s", file, line,
188 isc_assertion_typetotext(type), cond, logsuffix);
189 if (result == ISC_R_SUCCESS) {
190 for (i = 0; i < nframes; i++) {
191 unsigned long offset;
194 result = isc_backtrace_getsymbol(tracebuf[i],
197 if (result == ISC_R_SUCCESS) {
198 isc_log_write(ns_g_lctx,
199 NS_LOGCATEGORY_GENERAL,
202 "#%d %p in %s()+0x%lx", i,
206 isc_log_write(ns_g_lctx,
207 NS_LOGCATEGORY_GENERAL,
215 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
216 NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
217 "exiting (due to assertion failure)");
219 fprintf(stderr, "%s:%d: %s(%s) failed\n",
220 file, line, isc_assertion_typetotext(type), cond);
229 ISC_PLATFORM_NORETURN_PRE static void
230 library_fatal_error(const char *file, int line, const char *format,
232 ISC_FORMAT_PRINTF(3, 0) ISC_PLATFORM_NORETURN_POST;
235 library_fatal_error(const char *file, int line, const char *format,
239 * Handle isc_error_fatal() calls from our libraries.
242 if (ns_g_lctx != NULL) {
244 * Reset the error callback in case it is the log
245 * routines causing the assertion.
247 isc_error_setfatal(NULL);
249 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
250 NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
251 "%s:%d: fatal error:", file, line);
252 isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
253 NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
255 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
256 NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
257 "exiting (due to fatal error in library)");
259 fprintf(stderr, "%s:%d: fatal error: ", file, line);
260 vfprintf(stderr, format, args);
261 fprintf(stderr, "\n");
271 library_unexpected_error(const char *file, int line, const char *format,
272 va_list args) ISC_FORMAT_PRINTF(3, 0);
275 library_unexpected_error(const char *file, int line, const char *format,
279 * Handle isc_error_unexpected() calls from our libraries.
282 if (ns_g_lctx != NULL) {
283 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
284 NS_LOGMODULE_MAIN, ISC_LOG_ERROR,
285 "%s:%d: unexpected error:", file, line);
286 isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
287 NS_LOGMODULE_MAIN, ISC_LOG_ERROR,
290 fprintf(stderr, "%s:%d: fatal error: ", file, line);
291 vfprintf(stderr, format, args);
292 fprintf(stderr, "\n");
300 "usage: lwresd [-4|-6] [-c conffile | -C resolvconffile] "
301 "[-d debuglevel] [-f|-g]\n"
302 " [-i pidfile] [-n number_of_cpus] "
303 "[-p port] [-P listen-port]\n"
304 " [-s] [-S sockets] [-t chrootdir] [-u username] "
306 " [-m {usage|trace|record|size|mctx}]\n"
307 "usage: lwresd [-v|-V]\n");
312 if (ns_g_lwresdonly) {
317 "usage: named [-4|-6] [-c conffile] [-d debuglevel] "
318 "[-E engine] [-f|-g]\n"
319 " [-n number_of_cpus] [-p port] [-s] "
320 "[-S sockets] [-t chrootdir]\n"
321 " [-u username] [-U listeners] "
322 "[-m {usage|trace|record|size|mctx}]\n"
323 "usage: named [-v|-V]\n");
327 save_command_line(int argc, char *argv[]) {
332 const char truncated[] = "...";
333 isc_boolean_t quoted = ISC_FALSE;
335 dst = saved_command_line;
336 eob = saved_command_line + sizeof(saved_command_line);
338 for (i = 1; i < argc && dst < eob; i++) {
342 while (*src != '\0' && dst < eob) {
344 * This won't perfectly produce a shell-independent
345 * pastable command line in all circumstances, but
346 * comes close, and for practical purposes will
347 * nearly always be fine.
349 if (quoted || isalnum(*src & 0xff) ||
350 *src == '-' || *src == '_' ||
351 *src == '.' || *src == '/') {
361 INSIST(sizeof(saved_command_line) >= sizeof(truncated));
364 strcpy(eob - sizeof(truncated), truncated);
370 parse_int(char *arg, const char *desc) {
375 ltmp = strtol(arg, &endp, 10);
378 ns_main_earlyfatal("%s '%s' must be numeric", desc, arg);
379 if (tmp < 0 || tmp != ltmp)
380 ns_main_earlyfatal("%s '%s' out of range", desc, arg);
384 static struct flag_def {
387 } mem_debug_flags[] = {
389 { "trace", ISC_MEM_DEBUGTRACE },
390 { "record", ISC_MEM_DEBUGRECORD },
391 { "usage", ISC_MEM_DEBUGUSAGE },
392 { "size", ISC_MEM_DEBUGSIZE },
393 { "mctx", ISC_MEM_DEBUGCTX },
398 set_flags(const char *arg, struct flag_def *defs, unsigned int *ret) {
399 isc_boolean_t clear = ISC_FALSE;
402 const struct flag_def *def;
403 const char *end = strchr(arg, ',');
406 end = arg + strlen(arg);
407 arglen = (int)(end - arg);
408 for (def = defs; def->name != NULL; def++) {
409 if (arglen == (int)strlen(def->name) &&
410 memcmp(arg, def->name, arglen) == 0) {
417 ns_main_earlyfatal("unrecognized flag '%.*s'", arglen, arg);
419 if (clear || (*end == '\0'))
429 parse_command_line(int argc, char *argv[]) {
434 save_command_line(argc, argv);
437 * NS_MAIN_ARGS is defined in main.h, so that it can be used
438 * both by named and by ntservice hooks.
440 isc_commandline_errprint = ISC_FALSE;
441 while ((ch = isc_commandline_parse(argc, argv, NS_MAIN_ARGS)) != -1) {
445 ns_main_earlyfatal("cannot specify -4 and -6");
446 if (isc_net_probeipv4() != ISC_R_SUCCESS)
447 ns_main_earlyfatal("IPv4 not supported by OS");
448 isc_net_disableipv6();
449 ns_g_disable6 = ISC_TRUE;
453 ns_main_earlyfatal("cannot specify -4 and -6");
454 if (isc_net_probeipv6() != ISC_R_SUCCESS)
455 ns_main_earlyfatal("IPv6 not supported by OS");
456 isc_net_disableipv4();
457 ns_g_disable4 = ISC_TRUE;
460 ns_g_conffile = isc_commandline_argument;
461 lwresd_g_conffile = isc_commandline_argument;
462 if (lwresd_g_useresolvconf)
463 ns_main_earlyfatal("cannot specify -c and -C");
464 ns_g_conffileset = ISC_TRUE;
467 lwresd_g_resolvconffile = isc_commandline_argument;
468 if (ns_g_conffileset)
469 ns_main_earlyfatal("cannot specify -c and -C");
470 lwresd_g_useresolvconf = ISC_TRUE;
473 ns_g_debuglevel = parse_int(isc_commandline_argument,
477 ns_g_engine = isc_commandline_argument;
480 ns_g_foreground = ISC_TRUE;
483 ns_g_foreground = ISC_TRUE;
484 ns_g_logstderr = ISC_TRUE;
486 /* XXXBEW -i should be removed */
488 lwresd_g_defaultpidfile = isc_commandline_argument;
491 ns_g_lwresdonly = ISC_TRUE;
494 if (strcmp(isc_commandline_argument, "external") == 0)
495 isc_mem_defaultflags = 0;
498 set_flags(isc_commandline_argument, mem_debug_flags,
501 case 'N': /* Deprecated. */
503 ns_g_cpus = parse_int(isc_commandline_argument,
509 port = parse_int(isc_commandline_argument, "port");
510 if (port < 1 || port > 65535)
511 ns_main_earlyfatal("port '%s' out of range",
512 isc_commandline_argument);
515 /* XXXBEW Should -P be removed? */
517 port = parse_int(isc_commandline_argument, "port");
518 if (port < 1 || port > 65535)
519 ns_main_earlyfatal("port '%s' out of range",
520 isc_commandline_argument);
521 lwresd_g_listenport = port;
524 /* XXXRTH temporary syntax */
525 want_stats = ISC_TRUE;
528 maxsocks = parse_int(isc_commandline_argument,
529 "max number of sockets");
532 /* XXXJAB should we make a copy? */
533 ns_g_chrootdir = isc_commandline_argument;
535 case 'T': /* NOT DOCUMENTED */
537 * clienttest: make clients single shot with their
538 * own memory context.
540 if (!strcmp(isc_commandline_argument, "clienttest"))
541 ns_g_clienttest = ISC_TRUE;
542 else if (!strcmp(isc_commandline_argument, "nosoa"))
543 ns_g_nosoa = ISC_TRUE;
544 else if (!strcmp(isc_commandline_argument, "noaa"))
545 ns_g_noaa = ISC_TRUE;
546 else if (!strcmp(isc_commandline_argument, "maxudp512"))
548 else if (!strcmp(isc_commandline_argument, "maxudp1460"))
550 else if (!strcmp(isc_commandline_argument, "dropedns"))
551 ns_g_dropedns = ISC_TRUE;
552 else if (!strcmp(isc_commandline_argument, "noedns"))
553 ns_g_noedns = ISC_TRUE;
554 else if (!strncmp(isc_commandline_argument,
556 maxudp = atoi(isc_commandline_argument + 7);
557 else if (!strcmp(isc_commandline_argument, "nosyslog"))
558 ns_g_nosyslog = ISC_TRUE;
559 else if (!strcmp(isc_commandline_argument, "nonearest"))
560 ns_g_nonearest = ISC_TRUE;
561 else if (!strncmp(isc_commandline_argument,
564 p = strtok(isc_commandline_argument + 11, "/");
566 ns_main_earlyfatal("bad mkeytimer");
567 dns_zone_mkey_hour = atoi(p);
568 if (dns_zone_mkey_hour == 0)
569 ns_main_earlyfatal("bad mkeytimer");
571 p = strtok(NULL, "/");
574 (24 * dns_zone_mkey_hour);
575 dns_zone_mkey_month =
576 (30 * dns_zone_mkey_day);
579 dns_zone_mkey_day = atoi(p);
580 if (dns_zone_mkey_day < dns_zone_mkey_hour)
581 ns_main_earlyfatal("bad mkeytimer");
583 p = strtok(NULL, "/");
585 dns_zone_mkey_month =
586 (30 * dns_zone_mkey_day);
589 dns_zone_mkey_month = atoi(p);
590 if (dns_zone_mkey_month < dns_zone_mkey_day)
591 ns_main_earlyfatal("bad mkeytimer");
592 } else if (!strcmp(isc_commandline_argument, "notcp"))
593 ns_g_notcp = ISC_TRUE;
595 fprintf(stderr, "unknown -T flag '%s\n",
596 isc_commandline_argument);
599 ns_g_udpdisp = parse_int(isc_commandline_argument,
600 "number of UDP listeners "
604 ns_g_username = isc_commandline_argument;
607 printf("%s %s%s%s <id:%s>\n",
608 ns_g_product, ns_g_version,
609 (*ns_g_description != '\0') ? " " : "",
610 ns_g_description, ns_g_srcid);
613 printf("%s %s%s%s <id:%s>\n", ns_g_product, ns_g_version,
614 (*ns_g_description != '\0') ? " " : "",
615 ns_g_description, ns_g_srcid);
616 printf("running on %s\n", ns_os_uname());
617 printf("built by %s with %s\n",
618 ns_g_builder, ns_g_configargs);
620 printf("compiled by CLANG %s\n", __VERSION__);
622 #if defined(__ICC) || defined(__INTEL_COMPILER)
623 printf("compiled by ICC %s\n", __VERSION__);
626 printf("compiled by GCC %s\n", __VERSION__);
631 printf("compiled by MSVC %d\n", _MSC_VER);
634 printf("compiled by Solaris Studio %x\n", __SUNPRO_C);
637 printf("compiled with OpenSSL version: %s\n",
638 OPENSSL_VERSION_TEXT);
639 printf("linked to OpenSSL version: %s\n",
640 SSLeay_version(SSLEAY_VERSION));
643 printf("compiled with libxml2 version: %s\n",
644 LIBXML_DOTTED_VERSION);
645 printf("linked to libxml2 version: %s\n",
650 /* Reserved for FIPS mode */
654 if (isc_commandline_option == '?')
656 p = strchr(NS_MAIN_ARGS, isc_commandline_option);
657 if (p == NULL || *++p != ':')
658 ns_main_earlyfatal("unknown option '-%c'",
659 isc_commandline_option);
661 ns_main_earlyfatal("option '-%c' requires "
663 isc_commandline_option);
666 ns_main_earlyfatal("parsing options returned %d", ch);
670 argc -= isc_commandline_index;
671 argv += isc_commandline_index;
676 ns_main_earlyfatal("extra command line arguments");
681 create_managers(void) {
685 INSIST(ns_g_cpus_detected > 0);
687 #ifdef ISC_PLATFORM_USETHREADS
689 ns_g_cpus = ns_g_cpus_detected;
690 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
691 ISC_LOG_INFO, "found %u CPU%s, using %u worker thread%s",
692 ns_g_cpus_detected, ns_g_cpus_detected == 1 ? "" : "s",
693 ns_g_cpus, ns_g_cpus == 1 ? "" : "s");
700 if (ns_g_udpdisp == 0) {
701 if (ns_g_cpus_detected == 1)
704 ns_g_udpdisp = ns_g_cpus_detected - 1;
706 if (ns_g_udpdisp > ns_g_cpus)
707 ns_g_udpdisp = ns_g_cpus;
709 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
710 ISC_LOG_INFO, "using %u UDP listener%s per interface",
711 ns_g_udpdisp, ns_g_udpdisp == 1 ? "" : "s");
713 result = isc_taskmgr_create(ns_g_mctx, ns_g_cpus, 0, &ns_g_taskmgr);
714 if (result != ISC_R_SUCCESS) {
715 UNEXPECTED_ERROR(__FILE__, __LINE__,
716 "isc_taskmgr_create() failed: %s",
717 isc_result_totext(result));
718 return (ISC_R_UNEXPECTED);
721 result = isc_timermgr_create(ns_g_mctx, &ns_g_timermgr);
722 if (result != ISC_R_SUCCESS) {
723 UNEXPECTED_ERROR(__FILE__, __LINE__,
724 "isc_timermgr_create() failed: %s",
725 isc_result_totext(result));
726 return (ISC_R_UNEXPECTED);
729 result = isc_socketmgr_create2(ns_g_mctx, &ns_g_socketmgr, maxsocks);
730 if (result != ISC_R_SUCCESS) {
731 UNEXPECTED_ERROR(__FILE__, __LINE__,
732 "isc_socketmgr_create() failed: %s",
733 isc_result_totext(result));
734 return (ISC_R_UNEXPECTED);
736 isc__socketmgr_maxudp(ns_g_socketmgr, maxudp);
737 result = isc_socketmgr_getmaxsockets(ns_g_socketmgr, &socks);
738 if (result == ISC_R_SUCCESS) {
739 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
741 ISC_LOG_INFO, "using up to %u sockets", socks);
744 result = isc_entropy_create(ns_g_mctx, &ns_g_entropy);
745 if (result != ISC_R_SUCCESS) {
746 UNEXPECTED_ERROR(__FILE__, __LINE__,
747 "isc_entropy_create() failed: %s",
748 isc_result_totext(result));
749 return (ISC_R_UNEXPECTED);
752 result = isc_hash_create(ns_g_mctx, ns_g_entropy, DNS_NAME_MAXWIRE);
753 if (result != ISC_R_SUCCESS) {
754 UNEXPECTED_ERROR(__FILE__, __LINE__,
755 "isc_hash_create() failed: %s",
756 isc_result_totext(result));
757 return (ISC_R_UNEXPECTED);
760 return (ISC_R_SUCCESS);
764 destroy_managers(void) {
765 ns_lwresd_shutdown();
768 * isc_taskmgr_destroy() will block until all tasks have exited,
770 isc_taskmgr_destroy(&ns_g_taskmgr);
771 isc_timermgr_destroy(&ns_g_timermgr);
772 isc_socketmgr_destroy(&ns_g_socketmgr);
775 * isc_hash_destroy() cannot be called as long as a resolver may be
776 * running. Calling this after isc_taskmgr_destroy() ensures the
783 dump_symboltable(void) {
789 if (isc__backtrace_nsymbols == 0)
792 if (!isc_log_wouldlog(ns_g_lctx, ISC_LOG_DEBUG(99)))
795 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
796 ISC_LOG_DEBUG(99), "Symbol table:");
798 for (i = 0, result = ISC_R_SUCCESS; result == ISC_R_SUCCESS; i++) {
801 result = isc_backtrace_getsymbolfromindex(i, &addr, &fname);
802 if (result == ISC_R_SUCCESS) {
803 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
804 NS_LOGMODULE_MAIN, ISC_LOG_DEBUG(99),
805 "[%d] %p %s", i, addr, fname);
813 isc_resourcevalue_t old_openfiles;
815 char *instance = NULL;
819 * Get the user and group information before changing the root
820 * directory, so the administrator does not need to keep a copy
821 * of the user and group databases in the chroot'ed environment.
823 ns_os_inituserinfo(ns_g_username);
826 * Initialize time conversion information
833 /* Check if named is under smf control, before chroot. */
834 result = ns_smf_get_instance(&instance, 0, ns_g_mctx);
835 /* We don't care about instance, just check if we got one. */
836 if (result == ISC_R_SUCCESS)
837 ns_smf_got_instance = 1;
839 ns_smf_got_instance = 0;
840 if (instance != NULL)
841 isc_mem_free(ns_g_mctx, instance);
842 #endif /* HAVE_LIBSCF */
844 #ifdef PATH_RANDOMDEV
846 * Initialize system's random device as fallback entropy source
847 * if running chroot'ed.
849 if (ns_g_chrootdir != NULL) {
850 result = isc_entropy_create(ns_g_mctx, &ns_g_fallbackentropy);
851 if (result != ISC_R_SUCCESS)
852 ns_main_earlyfatal("isc_entropy_create() failed: %s",
853 isc_result_totext(result));
855 result = isc_entropy_createfilesource(ns_g_fallbackentropy,
857 if (result != ISC_R_SUCCESS) {
858 ns_main_earlywarning("could not open pre-chroot "
859 "entropy source %s: %s",
861 isc_result_totext(result));
862 isc_entropy_detach(&ns_g_fallbackentropy);
867 #ifdef ISC_PLATFORM_USETHREADS
869 * Check for the number of cpu's before ns_os_chroot().
871 ns_g_cpus_detected = isc_os_ncpus();
874 ns_os_chroot(ns_g_chrootdir);
877 * For operating systems which have a capability mechanism, now
878 * is the time to switch to minimal privs and change our user id.
879 * On traditional UNIX systems, this call will be a no-op, and we
880 * will change the user ID after reading the config file the first
881 * time. (We need to read the config file to know which possibly
882 * privileged ports to bind() to.)
886 result = ns_log_init(ISC_TF(ns_g_username != NULL));
887 if (result != ISC_R_SUCCESS)
888 ns_main_earlyfatal("ns_log_init() failed: %s",
889 isc_result_totext(result));
892 * Now is the time to daemonize (if we're not running in the
893 * foreground). We waited until now because we wanted to get
894 * a valid logging context setup. We cannot daemonize any later,
895 * because calling create_managers() will create threads, which
896 * would be lost after fork().
898 if (!ns_g_foreground)
902 * We call isc_app_start() here as some versions of FreeBSD's fork()
903 * destroys all the signal handling it sets up.
905 result = isc_app_start();
906 if (result != ISC_R_SUCCESS)
907 ns_main_earlyfatal("isc_app_start() failed: %s",
908 isc_result_totext(result));
910 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
911 ISC_LOG_NOTICE, "starting %s %s%s%s <id:%s>%s",
912 ns_g_product, ns_g_version,
913 *ns_g_description ? " " : "", ns_g_description,
914 ns_g_srcid, saved_command_line);
916 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
917 ISC_LOG_NOTICE, "running on %s", ns_os_uname());
919 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
920 ISC_LOG_NOTICE, "built with %s", ns_g_configargs);
922 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
924 "----------------------------------------------------");
925 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
927 "BIND 9 is maintained by Internet Systems Consortium,");
928 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
930 "Inc. (ISC), a non-profit 501(c)(3) public-benefit ");
931 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
933 "corporation. Support and training for BIND 9 are ");
934 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
936 "available at https://www.isc.org/support");
937 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
939 "----------------------------------------------------");
944 * Get the initial resource limits.
946 (void)isc_resource_getlimit(isc_resource_stacksize,
947 &ns_g_initstacksize);
948 (void)isc_resource_getlimit(isc_resource_datasize,
950 (void)isc_resource_getlimit(isc_resource_coresize,
952 (void)isc_resource_getlimit(isc_resource_openfiles,
953 &ns_g_initopenfiles);
956 * System resources cannot effectively be tuned on some systems.
957 * Raise the limit in such cases for safety.
959 old_openfiles = ns_g_initopenfiles;
960 ns_os_adjustnofile();
961 (void)isc_resource_getlimit(isc_resource_openfiles,
962 &ns_g_initopenfiles);
963 if (old_openfiles != ns_g_initopenfiles) {
964 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
965 NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
966 "adjusted limit on open files from "
967 "%" ISC_PRINT_QUADFORMAT "u to "
968 "%" ISC_PRINT_QUADFORMAT "u",
969 old_openfiles, ns_g_initopenfiles);
973 * If the named configuration filename is relative, prepend the current
974 * directory's name before possibly changing to another directory.
976 if (! isc_file_isabsolute(ns_g_conffile)) {
977 result = isc_file_absolutepath(ns_g_conffile,
979 sizeof(absolute_conffile));
980 if (result != ISC_R_SUCCESS)
981 ns_main_earlyfatal("could not construct absolute path "
982 "of configuration file: %s",
983 isc_result_totext(result));
984 ns_g_conffile = absolute_conffile;
988 * Record the server's startup time.
990 result = isc_time_now(&ns_g_boottime);
991 if (result != ISC_R_SUCCESS)
992 ns_main_earlyfatal("isc_time_now() failed: %s",
993 isc_result_totext(result));
995 result = create_managers();
996 if (result != ISC_R_SUCCESS)
997 ns_main_earlyfatal("create_managers() failed: %s",
998 isc_result_totext(result));
1003 * Add calls to register sdb drivers here.
1007 #ifdef ISC_DLZ_DLOPEN
1009 * Register the DLZ "dlopen" driver.
1011 result = dlz_dlopen_init(ns_g_mctx);
1012 if (result != ISC_R_SUCCESS)
1013 ns_main_earlyfatal("dlz_dlopen_init() failed: %s",
1014 isc_result_totext(result));
1019 * Register any other contributed DLZ drivers.
1021 result = dlz_drivers_init();
1022 if (result != ISC_R_SUCCESS)
1023 ns_main_earlyfatal("dlz_drivers_init() failed: %s",
1024 isc_result_totext(result));
1027 ns_server_create(ns_g_mctx, &ns_g_server);
1034 ns_server_destroy(&ns_g_server);
1036 isc_entropy_detach(&ns_g_entropy);
1037 if (ns_g_fallbackentropy != NULL)
1038 isc_entropy_detach(&ns_g_fallbackentropy);
1040 ns_builtin_deinit();
1043 * Add calls to unregister sdb drivers here.
1049 * Unregister contributed DLZ drivers.
1051 dlz_drivers_clear();
1053 #ifdef ISC_DLZ_DLOPEN
1055 * Unregister "dlopen" DLZ driver.
1062 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
1063 ISC_LOG_NOTICE, "exiting");
1067 static char *memstats = NULL;
1070 ns_main_setmemstats(const char *filename) {
1072 * Caller has to ensure locking.
1075 if (memstats != NULL) {
1079 if (filename == NULL)
1081 memstats = malloc(strlen(filename) + 1);
1083 strcpy(memstats, filename);
1088 * Get FMRI for the named process.
1091 ns_smf_get_instance(char **ins_name, int debug, isc_mem_t *mctx) {
1092 scf_handle_t *h = NULL;
1096 REQUIRE(ins_name != NULL && *ins_name == NULL);
1098 if ((h = scf_handle_create(SCF_VERSION)) == NULL) {
1100 UNEXPECTED_ERROR(__FILE__, __LINE__,
1101 "scf_handle_create() failed: %s",
1102 scf_strerror(scf_error()));
1103 return (ISC_R_FAILURE);
1106 if (scf_handle_bind(h) == -1) {
1108 UNEXPECTED_ERROR(__FILE__, __LINE__,
1109 "scf_handle_bind() failed: %s",
1110 scf_strerror(scf_error()));
1111 scf_handle_destroy(h);
1112 return (ISC_R_FAILURE);
1115 if ((namelen = scf_myname(h, NULL, 0)) == -1) {
1117 UNEXPECTED_ERROR(__FILE__, __LINE__,
1118 "scf_myname() failed: %s",
1119 scf_strerror(scf_error()));
1120 scf_handle_destroy(h);
1121 return (ISC_R_FAILURE);
1124 if ((instance = isc_mem_allocate(mctx, namelen + 1)) == NULL) {
1125 UNEXPECTED_ERROR(__FILE__, __LINE__,
1126 "ns_smf_get_instance memory "
1127 "allocation failed: %s",
1128 isc_result_totext(ISC_R_NOMEMORY));
1129 scf_handle_destroy(h);
1130 return (ISC_R_FAILURE);
1133 if (scf_myname(h, instance, namelen + 1) == -1) {
1135 UNEXPECTED_ERROR(__FILE__, __LINE__,
1136 "scf_myname() failed: %s",
1137 scf_strerror(scf_error()));
1138 scf_handle_destroy(h);
1139 isc_mem_free(mctx, instance);
1140 return (ISC_R_FAILURE);
1143 scf_handle_destroy(h);
1144 *ins_name = instance;
1145 return (ISC_R_SUCCESS);
1147 #endif /* HAVE_LIBSCF */
1149 /* main entry point, possibly hooked */
1152 main(int argc, char *argv[]) {
1153 isc_result_t result;
1155 char *instance = NULL;
1158 #ifdef HAVE_GPERFTOOLS_PROFILER
1159 (void) ProfilerStart(NULL);
1163 * Record version in core image.
1164 * strings named.core | grep "named version:"
1167 #if defined(NO_VERSION_DATE) || !defined(__DATE__)
1168 "named version: BIND " VERSION " <" SRCID ">",
1170 "named version: BIND " VERSION " <" SRCID "> (" __DATE__ ")",
1173 result = isc_file_progname(*argv, program_name, sizeof(program_name));
1174 if (result != ISC_R_SUCCESS)
1175 ns_main_earlyfatal("program name too long");
1177 if (strcmp(program_name, "lwresd") == 0)
1178 ns_g_lwresdonly = ISC_TRUE;
1180 if (result != ISC_R_SUCCESS)
1181 ns_main_earlyfatal("failed to build internal symbol table");
1183 isc_assertion_setcallback(assertion_failed);
1184 isc_error_setfatal(library_fatal_error);
1185 isc_error_setunexpected(library_unexpected_error);
1187 ns_os_init(program_name);
1189 dns_result_register();
1190 dst_result_register();
1191 isccc_result_register();
1193 parse_command_line(argc, argv);
1196 * Warn about common configuration error.
1198 if (ns_g_chrootdir != NULL) {
1199 int len = strlen(ns_g_chrootdir);
1200 if (strncmp(ns_g_chrootdir, ns_g_conffile, len) == 0 &&
1201 (ns_g_conffile[len] == '/' || ns_g_conffile[len] == '\\'))
1202 ns_main_earlywarning("config filename (-c %s) contains "
1203 "chroot path (-t %s)",
1204 ns_g_conffile, ns_g_chrootdir);
1207 result = isc_mem_create(0, 0, &ns_g_mctx);
1208 if (result != ISC_R_SUCCESS)
1209 ns_main_earlyfatal("isc_mem_create() failed: %s",
1210 isc_result_totext(result));
1211 isc_mem_setname(ns_g_mctx, "main", NULL);
1216 * Start things running and then wait for a shutdown request
1220 result = isc_app_run();
1222 if (result == ISC_R_RELOAD) {
1223 ns_server_reloadwanted(ns_g_server);
1224 } else if (result != ISC_R_SUCCESS) {
1225 UNEXPECTED_ERROR(__FILE__, __LINE__,
1226 "isc_app_run(): %s",
1227 isc_result_totext(result));
1231 result = ISC_R_SUCCESS;
1233 } while (result != ISC_R_SUCCESS);
1236 if (ns_smf_want_disable == 1) {
1237 result = ns_smf_get_instance(&instance, 1, ns_g_mctx);
1238 if (result == ISC_R_SUCCESS && instance != NULL) {
1239 if (smf_disable_instance(instance, 0) != 0)
1240 UNEXPECTED_ERROR(__FILE__, __LINE__,
1241 "smf_disable_instance() "
1242 "failed for %s : %s",
1244 scf_strerror(scf_error()));
1246 if (instance != NULL)
1247 isc_mem_free(ns_g_mctx, instance);
1249 #endif /* HAVE_LIBSCF */
1254 isc_mem_stats(ns_g_mctx, stdout);
1255 isc_mutex_stats(stdout);
1258 if (ns_g_memstatistics && memstats != NULL) {
1260 result = isc_stdio_open(memstats, "w", &fp);
1261 if (result == ISC_R_SUCCESS) {
1262 isc_mem_stats(ns_g_mctx, fp);
1263 isc_mutex_stats(fp);
1264 isc_stdio_close(fp);
1267 isc_mem_destroy(&ns_g_mctx);
1268 isc_mem_checkdestroyed(stderr);
1270 ns_main_setmemstats(NULL);
1274 ns_os_closedevnull();
1278 #ifdef HAVE_GPERFTOOLS_PROFILER