PageRenderTime 234ms CodeModel.GetById 184ms app.highlight 42ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/bind9/bin/named/main.c

https://bitbucket.org/freebsd/freebsd-head/
C | 1143 lines | 844 code | 135 blank | 164 comment | 202 complexity | 4e5d0d5a4989c4d1c8761a6582b2f7ab MD5 | raw file
   1/*
   2 * Copyright (C) 2004-2011  Internet Systems Consortium, Inc. ("ISC")
   3 * Copyright (C) 1999-2003  Internet Software Consortium.
   4 *
   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.
   8 *
   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.
  16 */
  17
  18/* $Id: main.c,v 1.180.14.4 2011/11/05 00:45:52 each Exp $ */
  19
  20/*! \file */
  21
  22#include <config.h>
  23
  24#include <ctype.h>
  25#include <stdlib.h>
  26#include <string.h>
  27
  28#include <isc/app.h>
  29#include <isc/backtrace.h>
  30#include <isc/commandline.h>
  31#include <isc/dir.h>
  32#include <isc/entropy.h>
  33#include <isc/file.h>
  34#include <isc/hash.h>
  35#include <isc/os.h>
  36#include <isc/platform.h>
  37#include <isc/print.h>
  38#include <isc/resource.h>
  39#include <isc/stdio.h>
  40#include <isc/string.h>
  41#include <isc/task.h>
  42#include <isc/timer.h>
  43#include <isc/util.h>
  44
  45#include <isccc/result.h>
  46
  47#include <dns/dispatch.h>
  48#include <dns/name.h>
  49#include <dns/result.h>
  50#include <dns/view.h>
  51
  52#include <dst/result.h>
  53
  54#include <dlz/dlz_dlopen_driver.h>
  55
  56/*
  57 * Defining NS_MAIN provides storage declarations (rather than extern)
  58 * for variables in named/globals.h.
  59 */
  60#define NS_MAIN 1
  61
  62#include <named/builtin.h>
  63#include <named/control.h>
  64#include <named/globals.h>	/* Explicit, though named/log.h includes it. */
  65#include <named/interfacemgr.h>
  66#include <named/log.h>
  67#include <named/os.h>
  68#include <named/server.h>
  69#include <named/lwresd.h>
  70#include <named/main.h>
  71#ifdef HAVE_LIBSCF
  72#include <named/ns_smf_globals.h>
  73#endif
  74
  75#ifdef OPENSSL
  76#include <openssl/opensslv.h>
  77#endif
  78#ifdef HAVE_LIBXML2
  79#include <libxml/xmlversion.h>
  80#endif
  81/*
  82 * Include header files for database drivers here.
  83 */
  84/* #include "xxdb.h" */
  85
  86#ifdef CONTRIB_DLZ
  87/*
  88 * Include contributed DLZ drivers if appropriate.
  89 */
  90#include <dlz/dlz_drivers.h>
  91#endif
  92
  93/*
  94 * The maximum number of stack frames to dump on assertion failure.
  95 */
  96#ifndef BACKTRACE_MAXFRAME
  97#define BACKTRACE_MAXFRAME 128
  98#endif
  99
 100static isc_boolean_t	want_stats = ISC_FALSE;
 101static char		program_name[ISC_DIR_NAMEMAX] = "named";
 102static char		absolute_conffile[ISC_DIR_PATHMAX];
 103static char		saved_command_line[512];
 104static char		version[512];
 105static unsigned int	maxsocks = 0;
 106static int		maxudp = 0;
 107
 108void
 109ns_main_earlywarning(const char *format, ...) {
 110	va_list args;
 111
 112	va_start(args, format);
 113	if (ns_g_lctx != NULL) {
 114		isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
 115			       NS_LOGMODULE_MAIN, ISC_LOG_WARNING,
 116			       format, args);
 117	} else {
 118		fprintf(stderr, "%s: ", program_name);
 119		vfprintf(stderr, format, args);
 120		fprintf(stderr, "\n");
 121		fflush(stderr);
 122	}
 123	va_end(args);
 124}
 125
 126void
 127ns_main_earlyfatal(const char *format, ...) {
 128	va_list args;
 129
 130	va_start(args, format);
 131	if (ns_g_lctx != NULL) {
 132		isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
 133			       NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
 134			       format, args);
 135		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
 136			       NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
 137			       "exiting (due to early fatal error)");
 138	} else {
 139		fprintf(stderr, "%s: ", program_name);
 140		vfprintf(stderr, format, args);
 141		fprintf(stderr, "\n");
 142		fflush(stderr);
 143	}
 144	va_end(args);
 145
 146	exit(1);
 147}
 148
 149ISC_PLATFORM_NORETURN_PRE static void
 150assertion_failed(const char *file, int line, isc_assertiontype_t type,
 151		 const char *cond) ISC_PLATFORM_NORETURN_POST;
 152
 153static void
 154assertion_failed(const char *file, int line, isc_assertiontype_t type,
 155		 const char *cond)
 156{
 157	void *tracebuf[BACKTRACE_MAXFRAME];
 158	int i, nframes;
 159	isc_result_t result;
 160	const char *logsuffix = "";
 161	const char *fname;
 162
 163	/*
 164	 * Handle assertion failures.
 165	 */
 166
 167	if (ns_g_lctx != NULL) {
 168		/*
 169		 * Reset the assertion callback in case it is the log
 170		 * routines causing the assertion.
 171		 */
 172		isc_assertion_setcallback(NULL);
 173
 174		result = isc_backtrace_gettrace(tracebuf, BACKTRACE_MAXFRAME,
 175						&nframes);
 176		if (result == ISC_R_SUCCESS && nframes > 0)
 177			logsuffix = ", back trace";
 178		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
 179			      NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
 180			      "%s:%d: %s(%s) failed%s", file, line,
 181			      isc_assertion_typetotext(type), cond, logsuffix);
 182		if (result == ISC_R_SUCCESS) {
 183			for (i = 0; i < nframes; i++) {
 184				unsigned long offset;
 185
 186				fname = NULL;
 187				result = isc_backtrace_getsymbol(tracebuf[i],
 188								 &fname,
 189								 &offset);
 190				if (result == ISC_R_SUCCESS) {
 191					isc_log_write(ns_g_lctx,
 192						      NS_LOGCATEGORY_GENERAL,
 193						      NS_LOGMODULE_MAIN,
 194						      ISC_LOG_CRITICAL,
 195						      "#%d %p in %s()+0x%lx", i,
 196						      tracebuf[i], fname,
 197						      offset);
 198				} else {
 199					isc_log_write(ns_g_lctx,
 200						      NS_LOGCATEGORY_GENERAL,
 201						      NS_LOGMODULE_MAIN,
 202						      ISC_LOG_CRITICAL,
 203						      "#%d %p in ??", i,
 204						      tracebuf[i]);
 205				}
 206			}
 207		}
 208		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
 209			      NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
 210			      "exiting (due to assertion failure)");
 211	} else {
 212		fprintf(stderr, "%s:%d: %s(%s) failed\n",
 213			file, line, isc_assertion_typetotext(type), cond);
 214		fflush(stderr);
 215	}
 216
 217	if (ns_g_coreok)
 218		abort();
 219	exit(1);
 220}
 221
 222ISC_PLATFORM_NORETURN_PRE static void
 223library_fatal_error(const char *file, int line, const char *format,
 224		    va_list args)
 225ISC_FORMAT_PRINTF(3, 0) ISC_PLATFORM_NORETURN_POST;
 226
 227static void
 228library_fatal_error(const char *file, int line, const char *format,
 229		    va_list args)
 230{
 231	/*
 232	 * Handle isc_error_fatal() calls from our libraries.
 233	 */
 234
 235	if (ns_g_lctx != NULL) {
 236		/*
 237		 * Reset the error callback in case it is the log
 238		 * routines causing the assertion.
 239		 */
 240		isc_error_setfatal(NULL);
 241
 242		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
 243			      NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
 244			      "%s:%d: fatal error:", file, line);
 245		isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
 246			       NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
 247			       format, args);
 248		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
 249			      NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
 250			      "exiting (due to fatal error in library)");
 251	} else {
 252		fprintf(stderr, "%s:%d: fatal error: ", file, line);
 253		vfprintf(stderr, format, args);
 254		fprintf(stderr, "\n");
 255		fflush(stderr);
 256	}
 257
 258	if (ns_g_coreok)
 259		abort();
 260	exit(1);
 261}
 262
 263static void
 264library_unexpected_error(const char *file, int line, const char *format,
 265			 va_list args) ISC_FORMAT_PRINTF(3, 0);
 266
 267static void
 268library_unexpected_error(const char *file, int line, const char *format,
 269			 va_list args)
 270{
 271	/*
 272	 * Handle isc_error_unexpected() calls from our libraries.
 273	 */
 274
 275	if (ns_g_lctx != NULL) {
 276		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
 277			      NS_LOGMODULE_MAIN, ISC_LOG_ERROR,
 278			      "%s:%d: unexpected error:", file, line);
 279		isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
 280			       NS_LOGMODULE_MAIN, ISC_LOG_ERROR,
 281			       format, args);
 282	} else {
 283		fprintf(stderr, "%s:%d: fatal error: ", file, line);
 284		vfprintf(stderr, format, args);
 285		fprintf(stderr, "\n");
 286		fflush(stderr);
 287	}
 288}
 289
 290static void
 291lwresd_usage(void) {
 292	fprintf(stderr,
 293		"usage: lwresd [-4|-6] [-c conffile | -C resolvconffile] "
 294		"[-d debuglevel]\n"
 295		"              [-f|-g] [-n number_of_cpus] [-p port] "
 296		"[-P listen-port] [-s]\n"
 297		"              [-t chrootdir] [-u username] [-i pidfile]\n"
 298		"              [-m {usage|trace|record|size|mctx}]\n");
 299}
 300
 301static void
 302usage(void) {
 303	if (ns_g_lwresdonly) {
 304		lwresd_usage();
 305		return;
 306	}
 307	fprintf(stderr,
 308		"usage: named [-4|-6] [-c conffile] [-d debuglevel] "
 309		"[-E engine] [-f|-g]\n"
 310		"             [-n number_of_cpus] [-p port] [-s] "
 311		"[-t chrootdir] [-u username]\n"
 312		"             [-m {usage|trace|record|size|mctx}]\n");
 313}
 314
 315static void
 316save_command_line(int argc, char *argv[]) {
 317	int i;
 318	char *src;
 319	char *dst;
 320	char *eob;
 321	const char truncated[] = "...";
 322	isc_boolean_t quoted = ISC_FALSE;
 323
 324	dst = saved_command_line;
 325	eob = saved_command_line + sizeof(saved_command_line);
 326
 327	for (i = 1; i < argc && dst < eob; i++) {
 328		*dst++ = ' ';
 329
 330		src = argv[i];
 331		while (*src != '\0' && dst < eob) {
 332			/*
 333			 * This won't perfectly produce a shell-independent
 334			 * pastable command line in all circumstances, but
 335			 * comes close, and for practical purposes will
 336			 * nearly always be fine.
 337			 */
 338			if (quoted || isalnum(*src & 0xff) ||
 339			    *src == '-' || *src == '_' ||
 340			    *src == '.' || *src == '/') {
 341				*dst++ = *src++;
 342				quoted = ISC_FALSE;
 343			} else {
 344				*dst++ = '\\';
 345				quoted = ISC_TRUE;
 346			}
 347		}
 348	}
 349
 350	INSIST(sizeof(saved_command_line) >= sizeof(truncated));
 351
 352	if (dst == eob)
 353		strcpy(eob - sizeof(truncated), truncated);
 354	else
 355		*dst = '\0';
 356}
 357
 358static int
 359parse_int(char *arg, const char *desc) {
 360	char *endp;
 361	int tmp;
 362	long int ltmp;
 363
 364	ltmp = strtol(arg, &endp, 10);
 365	tmp = (int) ltmp;
 366	if (*endp != '\0')
 367		ns_main_earlyfatal("%s '%s' must be numeric", desc, arg);
 368	if (tmp < 0 || tmp != ltmp)
 369		ns_main_earlyfatal("%s '%s' out of range", desc, arg);
 370	return (tmp);
 371}
 372
 373static struct flag_def {
 374	const char *name;
 375	unsigned int value;
 376} mem_debug_flags[] = {
 377	{ "trace",  ISC_MEM_DEBUGTRACE },
 378	{ "record", ISC_MEM_DEBUGRECORD },
 379	{ "usage", ISC_MEM_DEBUGUSAGE },
 380	{ "size", ISC_MEM_DEBUGSIZE },
 381	{ "mctx", ISC_MEM_DEBUGCTX },
 382	{ NULL, 0 }
 383};
 384
 385static void
 386set_flags(const char *arg, struct flag_def *defs, unsigned int *ret) {
 387	for (;;) {
 388		const struct flag_def *def;
 389		const char *end = strchr(arg, ',');
 390		int arglen;
 391		if (end == NULL)
 392			end = arg + strlen(arg);
 393		arglen = end - arg;
 394		for (def = defs; def->name != NULL; def++) {
 395			if (arglen == (int)strlen(def->name) &&
 396			    memcmp(arg, def->name, arglen) == 0) {
 397				*ret |= def->value;
 398				goto found;
 399			}
 400		}
 401		ns_main_earlyfatal("unrecognized flag '%.*s'", arglen, arg);
 402	 found:
 403		if (*end == '\0')
 404			break;
 405		arg = end + 1;
 406	}
 407}
 408
 409static void
 410parse_command_line(int argc, char *argv[]) {
 411	int ch;
 412	int port;
 413	isc_boolean_t disable6 = ISC_FALSE;
 414	isc_boolean_t disable4 = ISC_FALSE;
 415
 416	save_command_line(argc, argv);
 417
 418	isc_commandline_errprint = ISC_FALSE;
 419	while ((ch = isc_commandline_parse(argc, argv,
 420					   "46c:C:d:E:fFgi:lm:n:N:p:P:"
 421					   "sS:t:T:u:vVx:")) != -1) {
 422		switch (ch) {
 423		case '4':
 424			if (disable4)
 425				ns_main_earlyfatal("cannot specify -4 and -6");
 426			if (isc_net_probeipv4() != ISC_R_SUCCESS)
 427				ns_main_earlyfatal("IPv4 not supported by OS");
 428			isc_net_disableipv6();
 429			disable6 = ISC_TRUE;
 430			break;
 431		case '6':
 432			if (disable6)
 433				ns_main_earlyfatal("cannot specify -4 and -6");
 434			if (isc_net_probeipv6() != ISC_R_SUCCESS)
 435				ns_main_earlyfatal("IPv6 not supported by OS");
 436			isc_net_disableipv4();
 437			disable4 = ISC_TRUE;
 438			break;
 439		case 'c':
 440			ns_g_conffile = isc_commandline_argument;
 441			lwresd_g_conffile = isc_commandline_argument;
 442			if (lwresd_g_useresolvconf)
 443				ns_main_earlyfatal("cannot specify -c and -C");
 444			ns_g_conffileset = ISC_TRUE;
 445			break;
 446		case 'C':
 447			lwresd_g_resolvconffile = isc_commandline_argument;
 448			if (ns_g_conffileset)
 449				ns_main_earlyfatal("cannot specify -c and -C");
 450			lwresd_g_useresolvconf = ISC_TRUE;
 451			break;
 452		case 'd':
 453			ns_g_debuglevel = parse_int(isc_commandline_argument,
 454						    "debug level");
 455			break;
 456		case 'E':
 457			ns_g_engine = isc_commandline_argument;
 458			break;
 459		case 'f':
 460			ns_g_foreground = ISC_TRUE;
 461			break;
 462		case 'g':
 463			ns_g_foreground = ISC_TRUE;
 464			ns_g_logstderr = ISC_TRUE;
 465			break;
 466		/* XXXBEW -i should be removed */
 467		case 'i':
 468			lwresd_g_defaultpidfile = isc_commandline_argument;
 469			break;
 470		case 'l':
 471			ns_g_lwresdonly = ISC_TRUE;
 472			break;
 473		case 'm':
 474			set_flags(isc_commandline_argument, mem_debug_flags,
 475				  &isc_mem_debugging);
 476			break;
 477		case 'N': /* Deprecated. */
 478		case 'n':
 479			ns_g_cpus = parse_int(isc_commandline_argument,
 480					      "number of cpus");
 481			if (ns_g_cpus == 0)
 482				ns_g_cpus = 1;
 483			break;
 484		case 'p':
 485			port = parse_int(isc_commandline_argument, "port");
 486			if (port < 1 || port > 65535)
 487				ns_main_earlyfatal("port '%s' out of range",
 488						   isc_commandline_argument);
 489			ns_g_port = port;
 490			break;
 491		/* XXXBEW Should -P be removed? */
 492		case 'P':
 493			port = parse_int(isc_commandline_argument, "port");
 494			if (port < 1 || port > 65535)
 495				ns_main_earlyfatal("port '%s' out of range",
 496						   isc_commandline_argument);
 497			lwresd_g_listenport = port;
 498			break;
 499		case 's':
 500			/* XXXRTH temporary syntax */
 501			want_stats = ISC_TRUE;
 502			break;
 503		case 'S':
 504			maxsocks = parse_int(isc_commandline_argument,
 505					     "max number of sockets");
 506			break;
 507		case 't':
 508			/* XXXJAB should we make a copy? */
 509			ns_g_chrootdir = isc_commandline_argument;
 510			break;
 511		case 'T':	/* NOT DOCUMENTED */
 512			/*
 513			 * clienttest: make clients single shot with their
 514			 * 	       own memory context.
 515			 */
 516			if (!strcmp(isc_commandline_argument, "clienttest"))
 517				ns_g_clienttest = ISC_TRUE;
 518			else if (!strcmp(isc_commandline_argument, "nosoa"))
 519				ns_g_nosoa = ISC_TRUE;
 520			else if (!strcmp(isc_commandline_argument, "noaa"))
 521				ns_g_noaa = ISC_TRUE;
 522			else if (!strcmp(isc_commandline_argument, "maxudp512"))
 523				maxudp = 512;
 524			else if (!strcmp(isc_commandline_argument, "maxudp1460"))
 525				maxudp = 1460;
 526			else
 527				fprintf(stderr, "unknown -T flag '%s\n",
 528					isc_commandline_argument);
 529			break;
 530		case 'u':
 531			ns_g_username = isc_commandline_argument;
 532			break;
 533		case 'v':
 534			printf("BIND %s\n", ns_g_version);
 535			exit(0);
 536		case 'V':
 537			printf("BIND %s built with %s\n", ns_g_version,
 538				ns_g_configargs);
 539#ifdef OPENSSL
 540			printf("using OpenSSL version: %s\n",
 541			       OPENSSL_VERSION_TEXT);
 542#endif
 543#ifdef HAVE_LIBXML2
 544			printf("using libxml2 version: %s\n",
 545			       LIBXML_DOTTED_VERSION);
 546#endif
 547			exit(0);
 548		case 'F':
 549			/* Reserved for FIPS mode */
 550			/* FALLTHROUGH */
 551		case '?':
 552			usage();
 553			if (isc_commandline_option == '?')
 554				exit(0);
 555			ns_main_earlyfatal("unknown option '-%c'",
 556					   isc_commandline_option);
 557			/* FALLTHROUGH */
 558		default:
 559			ns_main_earlyfatal("parsing options returned %d", ch);
 560		}
 561	}
 562
 563	argc -= isc_commandline_index;
 564	argv += isc_commandline_index;
 565	POST(argv);
 566
 567	if (argc > 0) {
 568		usage();
 569		ns_main_earlyfatal("extra command line arguments");
 570	}
 571}
 572
 573static isc_result_t
 574create_managers(void) {
 575	isc_result_t result;
 576	unsigned int socks;
 577
 578#ifdef ISC_PLATFORM_USETHREADS
 579	if (ns_g_cpus == 0)
 580		ns_g_cpus = ns_g_cpus_detected;
 581	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
 582		      ISC_LOG_INFO, "found %u CPU%s, using %u worker thread%s",
 583		      ns_g_cpus_detected, ns_g_cpus_detected == 1 ? "" : "s",
 584		      ns_g_cpus, ns_g_cpus == 1 ? "" : "s");
 585#else
 586	ns_g_cpus = 1;
 587#endif
 588	result = isc_taskmgr_create(ns_g_mctx, ns_g_cpus, 0, &ns_g_taskmgr);
 589	if (result != ISC_R_SUCCESS) {
 590		UNEXPECTED_ERROR(__FILE__, __LINE__,
 591				 "isc_taskmgr_create() failed: %s",
 592				 isc_result_totext(result));
 593		return (ISC_R_UNEXPECTED);
 594	}
 595
 596	result = isc_timermgr_create(ns_g_mctx, &ns_g_timermgr);
 597	if (result != ISC_R_SUCCESS) {
 598		UNEXPECTED_ERROR(__FILE__, __LINE__,
 599				 "isc_timermgr_create() failed: %s",
 600				 isc_result_totext(result));
 601		return (ISC_R_UNEXPECTED);
 602	}
 603
 604	result = isc_socketmgr_create2(ns_g_mctx, &ns_g_socketmgr, maxsocks);
 605	if (result != ISC_R_SUCCESS) {
 606		UNEXPECTED_ERROR(__FILE__, __LINE__,
 607				 "isc_socketmgr_create() failed: %s",
 608				 isc_result_totext(result));
 609		return (ISC_R_UNEXPECTED);
 610	}
 611	isc__socketmgr_maxudp(ns_g_socketmgr, maxudp);
 612	result = isc_socketmgr_getmaxsockets(ns_g_socketmgr, &socks);
 613	if (result == ISC_R_SUCCESS) {
 614		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
 615			      NS_LOGMODULE_SERVER,
 616			      ISC_LOG_INFO, "using up to %u sockets", socks);
 617	}
 618
 619	result = isc_entropy_create(ns_g_mctx, &ns_g_entropy);
 620	if (result != ISC_R_SUCCESS) {
 621		UNEXPECTED_ERROR(__FILE__, __LINE__,
 622				 "isc_entropy_create() failed: %s",
 623				 isc_result_totext(result));
 624		return (ISC_R_UNEXPECTED);
 625	}
 626
 627	result = isc_hash_create(ns_g_mctx, ns_g_entropy, DNS_NAME_MAXWIRE);
 628	if (result != ISC_R_SUCCESS) {
 629		UNEXPECTED_ERROR(__FILE__, __LINE__,
 630				 "isc_hash_create() failed: %s",
 631				 isc_result_totext(result));
 632		return (ISC_R_UNEXPECTED);
 633	}
 634
 635	return (ISC_R_SUCCESS);
 636}
 637
 638static void
 639destroy_managers(void) {
 640	ns_lwresd_shutdown();
 641
 642	isc_entropy_detach(&ns_g_entropy);
 643	if (ns_g_fallbackentropy != NULL)
 644		isc_entropy_detach(&ns_g_fallbackentropy);
 645
 646	/*
 647	 * isc_taskmgr_destroy() will block until all tasks have exited,
 648	 */
 649	isc_taskmgr_destroy(&ns_g_taskmgr);
 650	isc_timermgr_destroy(&ns_g_timermgr);
 651	isc_socketmgr_destroy(&ns_g_socketmgr);
 652
 653	/*
 654	 * isc_hash_destroy() cannot be called as long as a resolver may be
 655	 * running.  Calling this after isc_taskmgr_destroy() ensures the
 656	 * call is safe.
 657	 */
 658	isc_hash_destroy();
 659}
 660
 661static void
 662dump_symboltable() {
 663	int i;
 664	isc_result_t result;
 665	const char *fname;
 666	const void *addr;
 667
 668	if (isc__backtrace_nsymbols == 0)
 669		return;
 670
 671	if (!isc_log_wouldlog(ns_g_lctx, ISC_LOG_DEBUG(99)))
 672		return;
 673
 674	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
 675		      ISC_LOG_DEBUG(99), "Symbol table:");
 676
 677	for (i = 0, result = ISC_R_SUCCESS; result == ISC_R_SUCCESS; i++) {
 678		addr = NULL;
 679		fname = NULL;
 680		result = isc_backtrace_getsymbolfromindex(i, &addr, &fname);
 681		if (result == ISC_R_SUCCESS) {
 682			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
 683				      NS_LOGMODULE_MAIN, ISC_LOG_DEBUG(99),
 684				      "[%d] %p %s", i, addr, fname);
 685		}
 686	}
 687}
 688
 689static void
 690setup(void) {
 691	isc_result_t result;
 692	isc_resourcevalue_t old_openfiles;
 693#ifdef HAVE_LIBSCF
 694	char *instance = NULL;
 695#endif
 696
 697	/*
 698	 * Get the user and group information before changing the root
 699	 * directory, so the administrator does not need to keep a copy
 700	 * of the user and group databases in the chroot'ed environment.
 701	 */
 702	ns_os_inituserinfo(ns_g_username);
 703
 704	/*
 705	 * Initialize time conversion information
 706	 */
 707	ns_os_tzset();
 708
 709	ns_os_opendevnull();
 710
 711#ifdef HAVE_LIBSCF
 712	/* Check if named is under smf control, before chroot. */
 713	result = ns_smf_get_instance(&instance, 0, ns_g_mctx);
 714	/* We don't care about instance, just check if we got one. */
 715	if (result == ISC_R_SUCCESS)
 716		ns_smf_got_instance = 1;
 717	else
 718		ns_smf_got_instance = 0;
 719	if (instance != NULL)
 720		isc_mem_free(ns_g_mctx, instance);
 721#endif /* HAVE_LIBSCF */
 722
 723#ifdef PATH_RANDOMDEV
 724	/*
 725	 * Initialize system's random device as fallback entropy source
 726	 * if running chroot'ed.
 727	 */
 728	if (ns_g_chrootdir != NULL) {
 729		result = isc_entropy_create(ns_g_mctx, &ns_g_fallbackentropy);
 730		if (result != ISC_R_SUCCESS)
 731			ns_main_earlyfatal("isc_entropy_create() failed: %s",
 732					   isc_result_totext(result));
 733
 734		result = isc_entropy_createfilesource(ns_g_fallbackentropy,
 735						      PATH_RANDOMDEV);
 736		if (result != ISC_R_SUCCESS) {
 737			ns_main_earlywarning("could not open pre-chroot "
 738					     "entropy source %s: %s",
 739					     PATH_RANDOMDEV,
 740					     isc_result_totext(result));
 741			isc_entropy_detach(&ns_g_fallbackentropy);
 742		}
 743	}
 744#endif
 745
 746#ifdef ISC_PLATFORM_USETHREADS
 747	/*
 748	 * Check for the number of cpu's before ns_os_chroot().
 749	 */
 750	ns_g_cpus_detected = isc_os_ncpus();
 751#endif
 752
 753	ns_os_chroot(ns_g_chrootdir);
 754
 755	/*
 756	 * For operating systems which have a capability mechanism, now
 757	 * is the time to switch to minimal privs and change our user id.
 758	 * On traditional UNIX systems, this call will be a no-op, and we
 759	 * will change the user ID after reading the config file the first
 760	 * time.  (We need to read the config file to know which possibly
 761	 * privileged ports to bind() to.)
 762	 */
 763	ns_os_minprivs();
 764
 765	result = ns_log_init(ISC_TF(ns_g_username != NULL));
 766	if (result != ISC_R_SUCCESS)
 767		ns_main_earlyfatal("ns_log_init() failed: %s",
 768				   isc_result_totext(result));
 769
 770	/*
 771	 * Now is the time to daemonize (if we're not running in the
 772	 * foreground).  We waited until now because we wanted to get
 773	 * a valid logging context setup.  We cannot daemonize any later,
 774	 * because calling create_managers() will create threads, which
 775	 * would be lost after fork().
 776	 */
 777	if (!ns_g_foreground)
 778		ns_os_daemonize();
 779
 780	/*
 781	 * We call isc_app_start() here as some versions of FreeBSD's fork()
 782	 * destroys all the signal handling it sets up.
 783	 */
 784	result = isc_app_start();
 785	if (result != ISC_R_SUCCESS)
 786		ns_main_earlyfatal("isc_app_start() failed: %s",
 787				   isc_result_totext(result));
 788
 789	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
 790		      ISC_LOG_NOTICE, "starting BIND %s%s", ns_g_version,
 791		      saved_command_line);
 792
 793	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
 794		      ISC_LOG_NOTICE, "built with %s", ns_g_configargs);
 795
 796	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
 797		      ISC_LOG_NOTICE,
 798		      "----------------------------------------------------");
 799	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
 800		      ISC_LOG_NOTICE,
 801		      "BIND 9 is maintained by Internet Systems Consortium,");
 802	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
 803		      ISC_LOG_NOTICE,
 804		      "Inc. (ISC), a non-profit 501(c)(3) public-benefit ");
 805	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
 806		      ISC_LOG_NOTICE,
 807		      "corporation.  Support and training for BIND 9 are ");
 808	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
 809		      ISC_LOG_NOTICE,
 810		      "available at https://www.isc.org/support");
 811	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
 812		      ISC_LOG_NOTICE,
 813		      "----------------------------------------------------");
 814
 815	dump_symboltable();
 816
 817	/*
 818	 * Get the initial resource limits.
 819	 */
 820	(void)isc_resource_getlimit(isc_resource_stacksize,
 821				    &ns_g_initstacksize);
 822	(void)isc_resource_getlimit(isc_resource_datasize,
 823				    &ns_g_initdatasize);
 824	(void)isc_resource_getlimit(isc_resource_coresize,
 825				    &ns_g_initcoresize);
 826	(void)isc_resource_getlimit(isc_resource_openfiles,
 827				    &ns_g_initopenfiles);
 828
 829	/*
 830	 * System resources cannot effectively be tuned on some systems.
 831	 * Raise the limit in such cases for safety.
 832	 */
 833	old_openfiles = ns_g_initopenfiles;
 834	ns_os_adjustnofile();
 835	(void)isc_resource_getlimit(isc_resource_openfiles,
 836				    &ns_g_initopenfiles);
 837	if (old_openfiles != ns_g_initopenfiles) {
 838		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
 839			      NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
 840			      "adjusted limit on open files from "
 841			      "%" ISC_PRINT_QUADFORMAT "u to "
 842			      "%" ISC_PRINT_QUADFORMAT "u",
 843			      old_openfiles, ns_g_initopenfiles);
 844	}
 845
 846	/*
 847	 * If the named configuration filename is relative, prepend the current
 848	 * directory's name before possibly changing to another directory.
 849	 */
 850	if (! isc_file_isabsolute(ns_g_conffile)) {
 851		result = isc_file_absolutepath(ns_g_conffile,
 852					       absolute_conffile,
 853					       sizeof(absolute_conffile));
 854		if (result != ISC_R_SUCCESS)
 855			ns_main_earlyfatal("could not construct absolute path "
 856					   "of configuration file: %s",
 857					   isc_result_totext(result));
 858		ns_g_conffile = absolute_conffile;
 859	}
 860
 861	/*
 862	 * Record the server's startup time.
 863	 */
 864	result = isc_time_now(&ns_g_boottime);
 865	if (result != ISC_R_SUCCESS)
 866		ns_main_earlyfatal("isc_time_now() failed: %s",
 867				   isc_result_totext(result));
 868
 869	result = create_managers();
 870	if (result != ISC_R_SUCCESS)
 871		ns_main_earlyfatal("create_managers() failed: %s",
 872				   isc_result_totext(result));
 873
 874	ns_builtin_init();
 875
 876	/*
 877	 * Add calls to register sdb drivers here.
 878	 */
 879	/* xxdb_init(); */
 880
 881#ifdef ISC_DLZ_DLOPEN
 882	/*
 883	 * Register the DLZ "dlopen" driver.
 884	 */
 885	result = dlz_dlopen_init(ns_g_mctx);
 886	if (result != ISC_R_SUCCESS)
 887		ns_main_earlyfatal("dlz_dlopen_init() failed: %s",
 888				   isc_result_totext(result));
 889#endif
 890
 891#if CONTRIB_DLZ
 892	/*
 893	 * Register any other contributed DLZ drivers.
 894	 */
 895	result = dlz_drivers_init();
 896	if (result != ISC_R_SUCCESS)
 897		ns_main_earlyfatal("dlz_drivers_init() failed: %s",
 898				   isc_result_totext(result));
 899#endif
 900
 901	ns_server_create(ns_g_mctx, &ns_g_server);
 902}
 903
 904static void
 905cleanup(void) {
 906	destroy_managers();
 907
 908	ns_server_destroy(&ns_g_server);
 909
 910	ns_builtin_deinit();
 911
 912	/*
 913	 * Add calls to unregister sdb drivers here.
 914	 */
 915	/* xxdb_clear(); */
 916
 917#ifdef CONTRIB_DLZ
 918	/*
 919	 * Unregister contributed DLZ drivers.
 920	 */
 921	dlz_drivers_clear();
 922#endif
 923#ifdef ISC_DLZ_DLOPEN
 924	/*
 925	 * Unregister "dlopen" DLZ driver.
 926	 */
 927	dlz_dlopen_clear();
 928#endif
 929
 930	dns_name_destroy();
 931
 932	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
 933		      ISC_LOG_NOTICE, "exiting");
 934	ns_log_shutdown();
 935}
 936
 937static char *memstats = NULL;
 938
 939void
 940ns_main_setmemstats(const char *filename) {
 941	/*
 942	 * Caller has to ensure locking.
 943	 */
 944
 945	if (memstats != NULL) {
 946		free(memstats);
 947		memstats = NULL;
 948	}
 949	if (filename == NULL)
 950		return;
 951	memstats = malloc(strlen(filename) + 1);
 952	if (memstats)
 953		strcpy(memstats, filename);
 954}
 955
 956#ifdef HAVE_LIBSCF
 957/*
 958 * Get FMRI for the named process.
 959 */
 960isc_result_t
 961ns_smf_get_instance(char **ins_name, int debug, isc_mem_t *mctx) {
 962	scf_handle_t *h = NULL;
 963	int namelen;
 964	char *instance;
 965
 966	REQUIRE(ins_name != NULL && *ins_name == NULL);
 967
 968	if ((h = scf_handle_create(SCF_VERSION)) == NULL) {
 969		if (debug)
 970			UNEXPECTED_ERROR(__FILE__, __LINE__,
 971					 "scf_handle_create() failed: %s",
 972					 scf_strerror(scf_error()));
 973		return (ISC_R_FAILURE);
 974	}
 975
 976	if (scf_handle_bind(h) == -1) {
 977		if (debug)
 978			UNEXPECTED_ERROR(__FILE__, __LINE__,
 979					 "scf_handle_bind() failed: %s",
 980					 scf_strerror(scf_error()));
 981		scf_handle_destroy(h);
 982		return (ISC_R_FAILURE);
 983	}
 984
 985	if ((namelen = scf_myname(h, NULL, 0)) == -1) {
 986		if (debug)
 987			UNEXPECTED_ERROR(__FILE__, __LINE__,
 988					 "scf_myname() failed: %s",
 989					 scf_strerror(scf_error()));
 990		scf_handle_destroy(h);
 991		return (ISC_R_FAILURE);
 992	}
 993
 994	if ((instance = isc_mem_allocate(mctx, namelen + 1)) == NULL) {
 995		UNEXPECTED_ERROR(__FILE__, __LINE__,
 996				 "ns_smf_get_instance memory "
 997				 "allocation failed: %s",
 998				 isc_result_totext(ISC_R_NOMEMORY));
 999		scf_handle_destroy(h);
1000		return (ISC_R_FAILURE);
1001	}
1002
1003	if (scf_myname(h, instance, namelen + 1) == -1) {
1004		if (debug)
1005			UNEXPECTED_ERROR(__FILE__, __LINE__,
1006					 "scf_myname() failed: %s",
1007					 scf_strerror(scf_error()));
1008		scf_handle_destroy(h);
1009		isc_mem_free(mctx, instance);
1010		return (ISC_R_FAILURE);
1011	}
1012
1013	scf_handle_destroy(h);
1014	*ins_name = instance;
1015	return (ISC_R_SUCCESS);
1016}
1017#endif /* HAVE_LIBSCF */
1018
1019int
1020main(int argc, char *argv[]) {
1021	isc_result_t result;
1022#ifdef HAVE_LIBSCF
1023	char *instance = NULL;
1024#endif
1025
1026	/*
1027	 * Record version in core image.
1028	 * strings named.core | grep "named version:"
1029	 */
1030	strlcat(version,
1031#if defined(NO_VERSION_DATE) || !defined(__DATE__)
1032		"named version: BIND " VERSION,
1033#else
1034		"named version: BIND " VERSION " (" __DATE__ ")",
1035#endif
1036		sizeof(version));
1037	result = isc_file_progname(*argv, program_name, sizeof(program_name));
1038	if (result != ISC_R_SUCCESS)
1039		ns_main_earlyfatal("program name too long");
1040
1041	if (strcmp(program_name, "lwresd") == 0)
1042		ns_g_lwresdonly = ISC_TRUE;
1043
1044	if (result != ISC_R_SUCCESS)
1045		ns_main_earlyfatal("failed to build internal symbol table");
1046
1047	isc_assertion_setcallback(assertion_failed);
1048	isc_error_setfatal(library_fatal_error);
1049	isc_error_setunexpected(library_unexpected_error);
1050
1051	ns_os_init(program_name);
1052
1053	dns_result_register();
1054	dst_result_register();
1055	isccc_result_register();
1056
1057	parse_command_line(argc, argv);
1058
1059	/*
1060	 * Warn about common configuration error.
1061	 */
1062	if (ns_g_chrootdir != NULL) {
1063		int len = strlen(ns_g_chrootdir);
1064		if (strncmp(ns_g_chrootdir, ns_g_conffile, len) == 0 &&
1065		    (ns_g_conffile[len] == '/' || ns_g_conffile[len] == '\\'))
1066			ns_main_earlywarning("config filename (-c %s) contains "
1067					     "chroot path (-t %s)",
1068					     ns_g_conffile, ns_g_chrootdir);
1069	}
1070
1071	result = isc_mem_create(0, 0, &ns_g_mctx);
1072	if (result != ISC_R_SUCCESS)
1073		ns_main_earlyfatal("isc_mem_create() failed: %s",
1074				   isc_result_totext(result));
1075	isc_mem_setname(ns_g_mctx, "main", NULL);
1076
1077	setup();
1078
1079	/*
1080	 * Start things running and then wait for a shutdown request
1081	 * or reload.
1082	 */
1083	do {
1084		result = isc_app_run();
1085
1086		if (result == ISC_R_RELOAD) {
1087			ns_server_reloadwanted(ns_g_server);
1088		} else if (result != ISC_R_SUCCESS) {
1089			UNEXPECTED_ERROR(__FILE__, __LINE__,
1090					 "isc_app_run(): %s",
1091					 isc_result_totext(result));
1092			/*
1093			 * Force exit.
1094			 */
1095			result = ISC_R_SUCCESS;
1096		}
1097	} while (result != ISC_R_SUCCESS);
1098
1099#ifdef HAVE_LIBSCF
1100	if (ns_smf_want_disable == 1) {
1101		result = ns_smf_get_instance(&instance, 1, ns_g_mctx);
1102		if (result == ISC_R_SUCCESS && instance != NULL) {
1103			if (smf_disable_instance(instance, 0) != 0)
1104				UNEXPECTED_ERROR(__FILE__, __LINE__,
1105						 "smf_disable_instance() "
1106						 "failed for %s : %s",
1107						 instance,
1108						 scf_strerror(scf_error()));
1109		}
1110		if (instance != NULL)
1111			isc_mem_free(ns_g_mctx, instance);
1112	}
1113#endif /* HAVE_LIBSCF */
1114
1115	cleanup();
1116
1117	if (want_stats) {
1118		isc_mem_stats(ns_g_mctx, stdout);
1119		isc_mutex_stats(stdout);
1120	}
1121
1122	if (ns_g_memstatistics && memstats != NULL) {
1123		FILE *fp = NULL;
1124		result = isc_stdio_open(memstats, "w", &fp);
1125		if (result == ISC_R_SUCCESS) {
1126			isc_mem_stats(ns_g_mctx, fp);
1127			isc_mutex_stats(fp);
1128			isc_stdio_close(fp);
1129		}
1130	}
1131	isc_mem_destroy(&ns_g_mctx);
1132	isc_mem_checkdestroyed(stderr);
1133
1134	ns_main_setmemstats(NULL);
1135
1136	isc_app_finish();
1137
1138	ns_os_closedevnull();
1139
1140	ns_os_shutdown();
1141
1142	return (0);
1143}