main.c 23.3 KB
Newer Older
Bob Halley's avatar
add  
Bob Halley committed
1
/*
Automatic Updater's avatar
Automatic Updater committed
2
 * Copyright (C) 2004-2008  Internet Systems Consortium, Inc. ("ISC")
Mark Andrews's avatar
Mark Andrews committed
3
 * Copyright (C) 1999-2003  Internet Software Consortium.
4
 *
Automatic Updater's avatar
Automatic Updater committed
5
 * Permission to use, copy, modify, and/or distribute this software for any
Bob Halley's avatar
add  
Bob Halley committed
6 7
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
8
 *
Mark Andrews's avatar
Mark Andrews committed
9 10 11 12 13 14 15
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
Bob Halley's avatar
add  
Bob Halley committed
16 17
 */

18
/* $Id: main.c,v 1.162 2008/04/03 23:14:52 jinmei Exp $ */
19 20

/*! \file */
David Lawrence's avatar
David Lawrence committed
21

Bob Halley's avatar
add  
Bob Halley committed
22 23
#include <config.h>

24
#include <ctype.h>
Bob Halley's avatar
add  
Bob Halley committed
25
#include <stdlib.h>
26
#include <string.h>
Bob Halley's avatar
add  
Bob Halley committed
27 28

#include <isc/app.h>
29
#include <isc/commandline.h>
30
#include <isc/dir.h>
31
#include <isc/entropy.h>
32
#include <isc/file.h>
33
#include <isc/hash.h>
34
#include <isc/os.h>
35
#include <isc/platform.h>
36
#include <isc/resource.h>
37
#include <isc/stdio.h>
38
#include <isc/string.h>
Bob Halley's avatar
add  
Bob Halley committed
39 40
#include <isc/task.h>
#include <isc/timer.h>
Bob Halley's avatar
Bob Halley committed
41
#include <isc/util.h>
Bob Halley's avatar
add  
Bob Halley committed
42

43 44
#include <isccc/result.h>

45
#include <dns/dispatch.h>
46
#include <dns/name.h>
47
#include <dns/result.h>
David Lawrence's avatar
David Lawrence committed
48
#include <dns/view.h>
Bob Halley's avatar
add  
Bob Halley committed
49

50 51
#include <dst/result.h>

52
/*
53
 * Defining NS_MAIN provides storage declarations (rather than extern)
54 55
 * for variables in named/globals.h.
 */
56
#define NS_MAIN 1
Bob Halley's avatar
add  
Bob Halley committed
57

58
#include <named/builtin.h>
59
#include <named/control.h>
60
#include <named/globals.h>	/* Explicit, though named/log.h includes it. */
Bob Halley's avatar
add  
Bob Halley committed
61
#include <named/interfacemgr.h>
62
#include <named/log.h>
Bob Halley's avatar
Bob Halley committed
63
#include <named/os.h>
Bob Halley's avatar
add  
Bob Halley committed
64
#include <named/server.h>
65
#include <named/lwresd.h>
Bob Halley's avatar
Bob Halley committed
66
#include <named/main.h>
67 68 69
#ifdef HAVE_LIBSCF
#include <named/ns_smf_globals.h>
#endif
Bob Halley's avatar
add  
Bob Halley committed
70

71 72 73
/*
 * Include header files for database drivers here.
 */
74
/* #include "xxdb.h" */
75

76 77 78 79 80 81 82
/*
 * Include DLZ drivers if appropriate.
 */
#ifdef DLZ
#include <dlz/dlz_drivers.h>
#endif

David Lawrence's avatar
David Lawrence committed
83
static isc_boolean_t	want_stats = ISC_FALSE;
84 85
static char		program_name[ISC_DIR_NAMEMAX] = "named";
static char		absolute_conffile[ISC_DIR_PATHMAX];
86 87
static char		saved_command_line[512];
static char		version[512];
Bob Halley's avatar
add  
Bob Halley committed
88

89
void
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
ns_main_earlywarning(const char *format, ...) {
	va_list args;

	va_start(args, format);
	if (ns_g_lctx != NULL) {
		isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
			       NS_LOGMODULE_MAIN, ISC_LOG_WARNING,
			       format, args);
	} else {
		fprintf(stderr, "%s: ", program_name);
		vfprintf(stderr, format, args);
		fprintf(stderr, "\n");
		fflush(stderr);
	}
	va_end(args);
}

Bob Halley's avatar
Bob Halley committed
107 108
void
ns_main_earlyfatal(const char *format, ...) {
Bob Halley's avatar
add  
Bob Halley committed
109 110 111
	va_list args;

	va_start(args, format);
112 113 114 115
	if (ns_g_lctx != NULL) {
		isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
			       NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
			       format, args);
Bob Halley's avatar
Bob Halley committed
116 117 118
		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
			       NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
			       "exiting (due to early fatal error)");
119
	} else {
120
		fprintf(stderr, "%s: ", program_name);
121 122
		vfprintf(stderr, format, args);
		fprintf(stderr, "\n");
123
		fflush(stderr);
124
	}
Bob Halley's avatar
add  
Bob Halley committed
125 126 127 128 129
	va_end(args);

	exit(1);
}

130
static void
David Lawrence's avatar
David Lawrence committed
131 132 133
assertion_failed(const char *file, int line, isc_assertiontype_t type,
		 const char *cond)
{
134 135 136 137 138
	/*
	 * Handle assertion failures.
	 */

	if (ns_g_lctx != NULL) {
139 140 141 142 143 144
		/*
		 * Reset the assetion callback in case it is the log
		 * routines causing the assertion.
		 */
		isc_assertion_setcallback(NULL);

145 146 147 148 149
		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
			      NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
			      "%s:%d: %s(%s) failed", file, line,
			      isc_assertion_typetotext(type), cond);
		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
150
			      NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
151
			      "exiting (due to assertion failure)");
152 153 154 155 156 157 158 159 160 161 162
	} else {
		fprintf(stderr, "%s:%d: %s(%s) failed\n",
			file, line, isc_assertion_typetotext(type), cond);
		fflush(stderr);
	}

	if (ns_g_coreok)
		abort();
	exit(1);
}

163 164 165 166
static void
library_fatal_error(const char *file, int line, const char *format,
		    va_list args) ISC_FORMAT_PRINTF(3, 0);

167
static void
David Lawrence's avatar
David Lawrence committed
168 169 170
library_fatal_error(const char *file, int line, const char *format,
		    va_list args)
{
171 172 173 174 175
	/*
	 * Handle isc_error_fatal() calls from our libraries.
	 */

	if (ns_g_lctx != NULL) {
176 177 178 179 180 181
		/*
		 * Reset the error callback in case it is the log
		 * routines causing the assertion.
		 */
		isc_error_setfatal(NULL);

182 183
		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
			      NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
184
			      "%s:%d: fatal error:", file, line);
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
		isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
			       NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
			       format, args);
		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
			      NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
			      "exiting (due to fatal error in library)");
	} else {
		fprintf(stderr, "%s:%d: fatal error: ", file, line);
		vfprintf(stderr, format, args);
		fprintf(stderr, "\n");
		fflush(stderr);
	}

	if (ns_g_coreok)
		abort();
	exit(1);
}

203 204 205 206
static void
library_unexpected_error(const char *file, int line, const char *format,
			 va_list args) ISC_FORMAT_PRINTF(3, 0);

207
static void
David Lawrence's avatar
David Lawrence committed
208 209 210
library_unexpected_error(const char *file, int line, const char *format,
			 va_list args)
{
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
	/*
	 * Handle isc_error_unexpected() calls from our libraries.
	 */

	if (ns_g_lctx != NULL) {
		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
			      NS_LOGMODULE_MAIN, ISC_LOG_ERROR,
			      "%s:%d: unexpected error:", file, line);
		isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
			       NS_LOGMODULE_MAIN, ISC_LOG_ERROR,
			       format, args);
	} else {
		fprintf(stderr, "%s:%d: fatal error: ", file, line);
		vfprintf(stderr, format, args);
		fprintf(stderr, "\n");
		fflush(stderr);
	}
}

230 231 232
static void
lwresd_usage(void) {
	fprintf(stderr,
Mark Andrews's avatar
Mark Andrews committed
233 234 235
		"usage: lwresd [-4|-6] [-c conffile | -C resolvconffile] "
		"[-d debuglevel]\n"
		"              [-f|-g] [-n number_of_cpus] [-p port] "
236
		"[-P listen-port] [-s]\n"
Mark Andrews's avatar
Mark Andrews committed
237
		"              [-t chrootdir] [-u username] [-i pidfile]\n"
238
		"              [-m {usage|trace|record|size|mctx}]\n");
239 240
}

Bob Halley's avatar
add  
Bob Halley committed
241 242
static void
usage(void) {
243 244 245 246
	if (ns_g_lwresdonly) {
		lwresd_usage();
		return;
	}
Bob Halley's avatar
add  
Bob Halley committed
247
	fprintf(stderr,
Mark Andrews's avatar
Mark Andrews committed
248
		"usage: named [-4|-6] [-c conffile] [-d debuglevel] "
249
		"[-f|-g] [-n number_of_cpus]\n"
Mark Andrews's avatar
Mark Andrews committed
250
		"             [-p port] [-s] [-t chrootdir] [-u username]\n"
251
		"             [-m {usage|trace|record|size|mctx}]\n");
Bob Halley's avatar
add  
Bob Halley committed
252 253
}

254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
static void
save_command_line(int argc, char *argv[]) {
	int i;
	char *src;
	char *dst;
	char *eob;
	const char truncated[] = "...";
	isc_boolean_t quoted = ISC_FALSE;

	dst = saved_command_line;
	eob = saved_command_line + sizeof(saved_command_line);

	for (i = 1; i < argc && dst < eob; i++) {
		*dst++ = ' ';

		src = argv[i];
		while (*src != '\0' && dst < eob) {
			/*
			 * This won't perfectly produce a shell-independent
			 * pastable command line in all circumstances, but
			 * comes close, and for practical purposes will
			 * nearly always be fine.
			 */
			if (quoted || isalnum(*src & 0xff) ||
			    *src == '-' || *src == '_' ||
			    *src == '.' || *src == '/') {
				*dst++ = *src++;
				quoted = ISC_FALSE;
			} else {
				*dst++ = '\\';
				quoted = ISC_TRUE;
			}
		}
	}

	INSIST(sizeof(saved_command_line) >= sizeof(truncated));

	if (dst == eob)
		strcpy(eob - sizeof(truncated), truncated);
	else
		*dst = '\0';
}

297 298 299 300 301 302
static int
parse_int(char *arg, const char *desc) {
	char *endp;
	int tmp;
	long int ltmp;

303
	ltmp = strtol(arg, &endp, 10);
304 305 306 307 308 309 310 311
	tmp = (int) ltmp;
	if (*endp != '\0')
		ns_main_earlyfatal("%s '%s' must be numeric", desc, arg);
	if (tmp < 0 || tmp != ltmp)
		ns_main_earlyfatal("%s '%s' out of range", desc, arg);
	return (tmp);
}

312 313 314 315 316 317
static struct flag_def {
	const char *name;
	unsigned int value;
} mem_debug_flags[] = {
	{ "trace",  ISC_MEM_DEBUGTRACE },
	{ "record", ISC_MEM_DEBUGRECORD },
Mark Andrews's avatar
Mark Andrews committed
318
	{ "usage", ISC_MEM_DEBUGUSAGE },
319 320
	{ "size", ISC_MEM_DEBUGSIZE },
	{ "mctx", ISC_MEM_DEBUGCTX },
321 322 323 324 325 326 327 328
	{ NULL, 0 }
};

static void
set_flags(const char *arg, struct flag_def *defs, unsigned int *ret) {
	for (;;) {
		const struct flag_def *def;
		const char *end = strchr(arg, ',');
Mark Andrews's avatar
Mark Andrews committed
329
		int arglen;
330 331
		if (end == NULL)
			end = arg + strlen(arg);
Mark Andrews's avatar
Mark Andrews committed
332
		arglen = end - arg;
333
		for (def = defs; def->name != NULL; def++) {
Mark Andrews's avatar
Mark Andrews committed
334 335
			if (arglen == (int)strlen(def->name) &&
			    memcmp(arg, def->name, arglen) == 0) {
336 337 338 339
				*ret |= def->value;
				goto found;
			}
		}
Mark Andrews's avatar
Mark Andrews committed
340
		ns_main_earlyfatal("unrecognized flag '%.*s'", arglen, arg);
341 342 343 344 345 346 347
	 found:
		if (*end == '\0')
			break;
		arg = end + 1;
	}
}

348
static void
Bob Halley's avatar
add  
Bob Halley committed
349 350
parse_command_line(int argc, char *argv[]) {
	int ch;
351
	int port;
352 353
	isc_boolean_t disable6 = ISC_FALSE;
	isc_boolean_t disable4 = ISC_FALSE;
354

355 356
	save_command_line(argc, argv);

357
	isc_commandline_errprint = ISC_FALSE;
358
	while ((ch = isc_commandline_parse(argc, argv,
Automatic Updater's avatar
Automatic Updater committed
359
				 "46c:C:d:fgi:lm:n:N:p:P:st:T:u:vx:")) != -1) {
Bob Halley's avatar
add  
Bob Halley committed
360
		switch (ch) {
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
		case '4':
			if (disable4)
				ns_main_earlyfatal("cannot specify -4 and -6");
			if (isc_net_probeipv4() != ISC_R_SUCCESS)
				ns_main_earlyfatal("IPv4 not supported by OS");
			isc_net_disableipv6();
			disable6 = ISC_TRUE;
			break;
		case '6':
			if (disable6)
				ns_main_earlyfatal("cannot specify -4 and -6");
			if (isc_net_probeipv6() != ISC_R_SUCCESS)
				ns_main_earlyfatal("IPv6 not supported by OS");
			isc_net_disableipv4();
			disable4 = ISC_TRUE;
			break;
Bob Halley's avatar
add  
Bob Halley committed
377
		case 'c':
378
			ns_g_conffile = isc_commandline_argument;
379
			lwresd_g_conffile = isc_commandline_argument;
380 381 382
			if (lwresd_g_useresolvconf)
				ns_main_earlyfatal("cannot specify -c and -C");
			ns_g_conffileset = ISC_TRUE;
383 384 385
			break;
		case 'C':
			lwresd_g_resolvconffile = isc_commandline_argument;
386 387
			if (ns_g_conffileset)
				ns_main_earlyfatal("cannot specify -c and -C");
388
			lwresd_g_useresolvconf = ISC_TRUE;
Bob Halley's avatar
add  
Bob Halley committed
389
			break;
Bob Halley's avatar
Bob Halley committed
390
		case 'd':
391 392
			ns_g_debuglevel = parse_int(isc_commandline_argument,
						    "debug level");
Bob Halley's avatar
Bob Halley committed
393
			break;
394 395 396
		case 'f':
			ns_g_foreground = ISC_TRUE;
			break;
397 398 399 400
		case 'g':
			ns_g_foreground = ISC_TRUE;
			ns_g_logstderr = ISC_TRUE;
			break;
401 402 403 404 405 406 407
		/* XXXBEW -i should be removed */
		case 'i':
			lwresd_g_defaultpidfile = isc_commandline_argument;
			break;
		case 'l':
			ns_g_lwresdonly = ISC_TRUE;
			break;
408 409 410 411
		case 'm':
			set_flags(isc_commandline_argument, mem_debug_flags,
				  &isc_mem_debugging);
			break;
412 413
		case 'N': /* Deprecated. */
		case 'n':
414 415
			ns_g_cpus = parse_int(isc_commandline_argument,
					      "number of cpus");
Bob Halley's avatar
add  
Bob Halley committed
416 417 418
			if (ns_g_cpus == 0)
				ns_g_cpus = 1;
			break;
Bob Halley's avatar
Bob Halley committed
419
		case 'p':
420
			port = parse_int(isc_commandline_argument, "port");
421
			if (port < 1 || port > 65535)
422
				ns_main_earlyfatal("port '%s' out of range",
423 424
						   isc_commandline_argument);
			ns_g_port = port;
Bob Halley's avatar
Bob Halley committed
425
			break;
426 427 428 429 430 431 432 433
		/* XXXBEW Should -P be removed? */
		case 'P':
			port = parse_int(isc_commandline_argument, "port");
			if (port < 1 || port > 65535)
				ns_main_earlyfatal("port '%s' out of range",
						   isc_commandline_argument);
			lwresd_g_listenport = port;
			break;
Bob Halley's avatar
add  
Bob Halley committed
434 435 436 437
		case 's':
			/* XXXRTH temporary syntax */
			want_stats = ISC_TRUE;
			break;
438
		case 't':
439
			/* XXXJAB should we make a copy? */
440 441
			ns_g_chrootdir = isc_commandline_argument;
			break;
442 443 444 445 446 447 448 449 450 451 452
		case 'T':
			/*
			 * clienttest: make clients single shot with their
			 * 	       own memory context.
			 */
			if (strcmp(isc_commandline_argument, "clienttest") == 0)
				ns_g_clienttest = ISC_TRUE;
			else
				fprintf(stderr, "unknown -T flag '%s\n",
					isc_commandline_argument);
			break;
453 454 455
		case 'u':
			ns_g_username = isc_commandline_argument;
			break;
456 457 458
		case 'v':
			printf("BIND %s\n", ns_g_version);
			exit(0);
459
		case '?':
460
			usage();
461 462
			if (isc_commandline_option == '?')
				exit(0);
463
			ns_main_earlyfatal("unknown option '-%c'",
464
					   isc_commandline_option);
Bob Halley's avatar
add  
Bob Halley committed
465
		default:
Bob Halley's avatar
Bob Halley committed
466
			ns_main_earlyfatal("parsing options returned %d", ch);
Bob Halley's avatar
add  
Bob Halley committed
467 468 469
		}
	}

470 471
	argc -= isc_commandline_index;
	argv += isc_commandline_index;
Bob Halley's avatar
add  
Bob Halley committed
472

473
	if (argc > 0) {
Bob Halley's avatar
add  
Bob Halley committed
474
		usage();
Bob Halley's avatar
Bob Halley committed
475
		ns_main_earlyfatal("extra command line arguments");
Bob Halley's avatar
add  
Bob Halley committed
476 477 478 479
	}
}

static isc_result_t
480
create_managers(void) {
Bob Halley's avatar
add  
Bob Halley committed
481
	isc_result_t result;
482 483 484
#ifdef ISC_PLATFORM_USETHREADS
	unsigned int cpus_detected;
#endif
Bob Halley's avatar
add  
Bob Halley committed
485

486
#ifdef ISC_PLATFORM_USETHREADS
487
	cpus_detected = isc_os_ncpus();
488
	if (ns_g_cpus == 0)
489 490 491 492 493
		ns_g_cpus = cpus_detected;
	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
		      ISC_LOG_INFO, "found %u CPU%s, using %u worker thread%s",
		      cpus_detected, cpus_detected == 1 ? "" : "s",
		      ns_g_cpus, ns_g_cpus == 1 ? "" : "s");
494 495 496
#else
	ns_g_cpus = 1;
#endif
Bob Halley's avatar
add  
Bob Halley committed
497 498 499
	result = isc_taskmgr_create(ns_g_mctx, ns_g_cpus, 0, &ns_g_taskmgr);
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
Mark Andrews's avatar
Mark Andrews committed
500
				 "isc_taskmgr_create() failed: %s",
Bob Halley's avatar
add  
Bob Halley committed
501 502 503 504 505 506 507
				 isc_result_totext(result));
		return (ISC_R_UNEXPECTED);
	}

	result = isc_timermgr_create(ns_g_mctx, &ns_g_timermgr);
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
Mark Andrews's avatar
Mark Andrews committed
508
				 "isc_timermgr_create() failed: %s",
Bob Halley's avatar
add  
Bob Halley committed
509 510 511 512 513 514 515
				 isc_result_totext(result));
		return (ISC_R_UNEXPECTED);
	}

	result = isc_socketmgr_create(ns_g_mctx, &ns_g_socketmgr);
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
516
				 "isc_socketmgr_create() failed: %s",
Bob Halley's avatar
add  
Bob Halley committed
517 518 519 520
				 isc_result_totext(result));
		return (ISC_R_UNEXPECTED);
	}

521
	result = isc_entropy_create(ns_g_mctx, &ns_g_entropy);
522 523
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
524
				 "isc_entropy_create() failed: %s",
525 526 527 528
				 isc_result_totext(result));
		return (ISC_R_UNEXPECTED);
	}

529 530 531 532 533 534 535 536
	result = isc_hash_create(ns_g_mctx, ns_g_entropy, DNS_NAME_MAXWIRE);
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
				 "isc_hash_create() failed: %s",
				 isc_result_totext(result));
		return (ISC_R_UNEXPECTED);
	}

Bob Halley's avatar
add  
Bob Halley committed
537 538 539 540 541
	return (ISC_R_SUCCESS);
}

static void
destroy_managers(void) {
542 543
	ns_lwresd_shutdown();

544
	isc_entropy_detach(&ns_g_entropy);
545 546 547
	if (ns_g_fallbackentropy != NULL)
		isc_entropy_detach(&ns_g_fallbackentropy);

Bob Halley's avatar
add  
Bob Halley committed
548
	/*
Andreas Gustafsson's avatar
Andreas Gustafsson committed
549
	 * isc_taskmgr_destroy() will block until all tasks have exited,
Bob Halley's avatar
add  
Bob Halley committed
550 551 552 553
	 */
	isc_taskmgr_destroy(&ns_g_taskmgr);
	isc_timermgr_destroy(&ns_g_timermgr);
	isc_socketmgr_destroy(&ns_g_socketmgr);
554 555 556 557 558 559 560

	/*
	 * isc_hash_destroy() cannot be called as long as a resolver may be
	 * running.  Calling this after isc_taskmgr_destroy() ensures the
	 * call is safe.
	 */
	isc_hash_destroy();
Bob Halley's avatar
add  
Bob Halley committed
561 562 563
}

static void
564
setup(void) {
Bob Halley's avatar
add  
Bob Halley committed
565
	isc_result_t result;
566 567 568
#ifdef HAVE_LIBSCF
	char *instance = NULL;
#endif
Bob Halley's avatar
add  
Bob Halley committed
569

570 571 572 573 574 575 576
	/*
	 * Get the user and group information before changing the root
	 * directory, so the administrator does not need to keep a copy
	 * of the user and group databases in the chroot'ed environment.
	 */
	ns_os_inituserinfo(ns_g_username);

577 578 579 580 581
	/*
	 * Initialize time conversion information
	 */
	ns_os_tzset();

582 583
	ns_os_opendevnull();

584 585 586 587 588 589 590 591 592
#ifdef HAVE_LIBSCF
	/* Check if named is under smf control, before chroot. */
	result = ns_smf_get_instance(&instance, 0, ns_g_mctx);
	/* We don't care about instance, just check if we got one. */
	if (result == ISC_R_SUCCESS)
		ns_smf_got_instance = 1;
	else
		ns_smf_got_instance = 0;
	if (instance != NULL)
593
		isc_mem_free(ns_g_mctx, instance);
594 595
#endif /* HAVE_LIBSCF */

596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618
#ifdef PATH_RANDOMDEV
	/*
	 * Initialize system's random device as fallback entropy source
	 * if running chroot'ed.
	 */
	if (ns_g_chrootdir != NULL) {
		result = isc_entropy_create(ns_g_mctx, &ns_g_fallbackentropy);
		if (result != ISC_R_SUCCESS)
			ns_main_earlyfatal("isc_entropy_create() failed: %s",
					   isc_result_totext(result));

		result = isc_entropy_createfilesource(ns_g_fallbackentropy,
						      PATH_RANDOMDEV);
		if (result != ISC_R_SUCCESS) {
			ns_main_earlywarning("could not open pre-chroot "
					     "entropy source %s: %s",
					     PATH_RANDOMDEV,
					     isc_result_totext(result));
			isc_entropy_detach(&ns_g_fallbackentropy);
		}
	}
#endif

619 620
	ns_os_chroot(ns_g_chrootdir);

Bob Halley's avatar
Bob Halley committed
621 622 623 624 625 626 627 628
	/*
	 * For operating systems which have a capability mechanism, now
	 * is the time to switch to minimal privs and change our user id.
	 * On traditional UNIX systems, this call will be a no-op, and we
	 * will change the user ID after reading the config file the first
	 * time.  (We need to read the config file to know which possibly
	 * privileged ports to bind() to.)
	 */
629
	ns_os_minprivs();
Bob Halley's avatar
Bob Halley committed
630

631
	result = ns_log_init(ISC_TF(ns_g_username != NULL));
632
	if (result != ISC_R_SUCCESS)
Bob Halley's avatar
Bob Halley committed
633 634
		ns_main_earlyfatal("ns_log_init() failed: %s",
				   isc_result_totext(result));
635

Bob Halley's avatar
Bob Halley committed
636 637 638 639 640 641 642
	/*
	 * Now is the time to daemonize (if we're not running in the
	 * foreground).  We waited until now because we wanted to get
	 * a valid logging context setup.  We cannot daemonize any later,
	 * because calling create_managers() will create threads, which
	 * would be lost after fork().
	 */
643 644
	if (!ns_g_foreground)
		ns_os_daemonize();
Bob Halley's avatar
Bob Halley committed
645

646 647 648 649 650 651 652 653 654
	/*
	 * We call isc_app_start() here as some versions of FreeBSD's fork()
	 * destroys all the signal handling it sets up.
	 */
	result = isc_app_start();
	if (result != ISC_R_SUCCESS)
		ns_main_earlyfatal("isc_app_start() failed: %s",
				   isc_result_totext(result));

655
	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
656 657
		      ISC_LOG_NOTICE, "starting BIND %s%s", ns_g_version,
		      saved_command_line);
Bob Halley's avatar
add  
Bob Halley committed
658

659 660 661
	/*
	 * Get the initial resource limits.
	 */
662 663 664 665 666 667 668 669
	(void)isc_resource_getlimit(isc_resource_stacksize,
				    &ns_g_initstacksize);
	(void)isc_resource_getlimit(isc_resource_datasize,
				    &ns_g_initdatasize);
	(void)isc_resource_getlimit(isc_resource_coresize,
				    &ns_g_initcoresize);
	(void)isc_resource_getlimit(isc_resource_openfiles,
				    &ns_g_initopenfiles);
670

671 672 673 674 675
	/*
	 * If the named configuration filename is relative, prepend the current
	 * directory's name before possibly changing to another directory.
	 */
	if (! isc_file_isabsolute(ns_g_conffile)) {
676 677 678
		result = isc_file_absolutepath(ns_g_conffile,
					       absolute_conffile,
					       sizeof(absolute_conffile));
679
		if (result != ISC_R_SUCCESS)
680
			ns_main_earlyfatal("could not construct absolute path of "
Automatic Updater's avatar
Automatic Updater committed
681
					   "configuration file: %s",
682
					   isc_result_totext(result));
683 684 685
		ns_g_conffile = absolute_conffile;
	}

686 687 688 689 690 691 692 693
	/*
	 * Record the server's startup time.
	 */
	result = isc_time_now(&ns_g_boottime);
	if (result != ISC_R_SUCCESS)
		ns_main_earlyfatal("isc_time_now() failed: %s",
				   isc_result_totext(result));

Bob Halley's avatar
add  
Bob Halley committed
694 695
	result = create_managers();
	if (result != ISC_R_SUCCESS)
Bob Halley's avatar
Bob Halley committed
696 697
		ns_main_earlyfatal("create_managers() failed: %s",
				   isc_result_totext(result));
Bob Halley's avatar
add  
Bob Halley committed
698

699 700
	ns_builtin_init();

701 702 703
	/*
	 * Add calls to register sdb drivers here.
	 */
704
	/* xxdb_init(); */
705

706 707 708 709 710 711 712 713 714 715
#ifdef DLZ
	/*
	 * Registyer any DLZ drivers.
	 */
	result = dlz_drivers_init();
	if (result != ISC_R_SUCCESS)
		ns_main_earlyfatal("dlz_drivers_init() failed: %s",
				   isc_result_totext(result));
#endif

716
	ns_server_create(ns_g_mctx, &ns_g_server);
Bob Halley's avatar
add  
Bob Halley committed
717 718 719
}

static void
720
cleanup(void) {
Bob Halley's avatar
add  
Bob Halley committed
721
	destroy_managers();
722

723
	ns_server_destroy(&ns_g_server);
724

725 726
	ns_builtin_deinit();

727 728 729
	/*
	 * Add calls to unregister sdb drivers here.
	 */
730
	/* xxdb_clear(); */
731

732 733 734 735 736 737 738
#ifdef DLZ
	/*
	 * Unregister any DLZ drivers.
	 */
	dlz_drivers_clear();
#endif

739 740
	dns_name_destroy();

741
	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
Bob Halley's avatar
Bob Halley committed
742
		      ISC_LOG_NOTICE, "exiting");
743
	ns_log_shutdown();
Bob Halley's avatar
add  
Bob Halley committed
744 745
}

746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764
static char *memstats = NULL;

void
ns_main_setmemstats(const char *filename) {
	/*
	 * Caller has to ensure locking.
	 */

	if (memstats != NULL) {
		free(memstats);
		memstats = NULL;
	}
	if (filename == NULL)
		return;
	memstats = malloc(strlen(filename) + 1);
	if (memstats)
		strcpy(memstats, filename);
}

765 766
#ifdef HAVE_LIBSCF
/*
767
 * Get FMRI for the named process.
768
 */
769 770
isc_result_t
ns_smf_get_instance(char **ins_name, int debug, isc_mem_t *mctx) {
771 772
	scf_handle_t *h = NULL;
	int namelen;
773 774 775
	char *instance;

	REQUIRE(ins_name != NULL && *ins_name == NULL);
776 777

	if ((h = scf_handle_create(SCF_VERSION)) == NULL) {
778 779 780
		if (debug)
			UNEXPECTED_ERROR(__FILE__, __LINE__,
					 "scf_handle_create() failed: %s",
Automatic Updater's avatar
Automatic Updater committed
781
					 scf_strerror(scf_error()));
782
		return (ISC_R_FAILURE);
783 784 785
	}

	if (scf_handle_bind(h) == -1) {
786 787 788 789
		if (debug)
			UNEXPECTED_ERROR(__FILE__, __LINE__,
					 "scf_handle_bind() failed: %s",
					 scf_strerror(scf_error()));
790
		scf_handle_destroy(h);
791
		return (ISC_R_FAILURE);
792 793 794
	}

	if ((namelen = scf_myname(h, NULL, 0)) == -1) {
795 796 797 798
		if (debug)
			UNEXPECTED_ERROR(__FILE__, __LINE__,
					 "scf_myname() failed: %s",
					 scf_strerror(scf_error()));
799
		scf_handle_destroy(h);
800
		return (ISC_R_FAILURE);
801 802
	}

803
	if ((instance = isc_mem_allocate(mctx, namelen + 1)) == NULL) {
804
		UNEXPECTED_ERROR(__FILE__, __LINE__,
805
				 "ns_smf_get_instance memory "
806 807 808
				 "allocation failed: %s",
				 isc_result_totext(ISC_R_NOMEMORY));
		scf_handle_destroy(h);
809
		return (ISC_R_FAILURE);
810 811
	}

812 813 814 815 816
	if (scf_myname(h, instance, namelen + 1) == -1) {
		if (debug)
			UNEXPECTED_ERROR(__FILE__, __LINE__,
					 "scf_myname() failed: %s",
					 scf_strerror(scf_error()));
817
		scf_handle_destroy(h);
818 819
		isc_mem_free(mctx, instance);
		return (ISC_R_FAILURE);
820 821 822
	}

	scf_handle_destroy(h);
823 824
	*ins_name = instance;
	return (ISC_R_SUCCESS);
825
}
826
#endif /* HAVE_LIBSCF */
827

Bob Halley's avatar
add  
Bob Halley committed
828 829 830
int
main(int argc, char *argv[]) {
	isc_result_t result;
Mark Andrews's avatar
Mark Andrews committed
831 832 833
#ifdef HAVE_LIBSCF
	char *instance = NULL;
#endif
Bob Halley's avatar
add  
Bob Halley committed
834

835 836 837 838 839 840 841 842 843 844 845
	/*
	 * Record version in core image.
	 * strings named.core | grep "named version:"
	 */
	strlcat(version,
#ifdef __DATE__
		"named version: BIND " VERSION " (" __DATE__ ")",
#else
		"named version: BIND " VERSION,
#endif
		sizeof(version));
846
	result = isc_file_progname(*argv, program_name, sizeof(program_name));
847 848 849 850 851 852
	if (result != ISC_R_SUCCESS)
		ns_main_earlyfatal("program name too long");

	if (strcmp(program_name, "lwresd") == 0)
		ns_g_lwresdonly = ISC_TRUE;

853 854
	isc_assertion_setcallback(assertion_failed);
	isc_error_setfatal(library_fatal_error);
855
	isc_error_setunexpected(library_unexpected_error);
856

857
	ns_os_init(program_name);
Bob Halley's avatar
Bob Halley committed
858

Bob Halley's avatar
add  
Bob Halley committed
859 860
	dns_result_register();
	dst_result_register();
861
	isccc_result_register();
Bob Halley's avatar
add  
Bob Halley committed
862 863 864

	parse_command_line(argc, argv);

865 866 867 868 869 870 871 872 873 874 875 876
	/*
	 * Warn about common configuration error.
	 */
	if (ns_g_chrootdir != NULL) {
		int len = strlen(ns_g_chrootdir);
		if (strncmp(ns_g_chrootdir, ns_g_conffile, len) == 0 &&
		    (ns_g_conffile[len] == '/' || ns_g_conffile[len] == '\\'))
			ns_main_earlywarning("config filename (-c %s) contains "
					     "chroot path (-t %s)",
					     ns_g_conffile, ns_g_chrootdir);
	}

877 878 879 880
	result = isc_mem_create(0, 0, &ns_g_mctx);
	if (result != ISC_R_SUCCESS)
		ns_main_earlyfatal("isc_mem_create() failed: %s",
				   isc_result_totext(result));
881
	isc_mem_setname(ns_g_mctx, "main", NULL);
882

Bob Halley's avatar
add  
Bob Halley committed
883 884 885
	setup();

	/*
Bob Halley's avatar
Bob Halley committed
886 887
	 * Start things running and then wait for a shutdown request
	 * or reload.
Bob Halley's avatar
add  
Bob Halley committed
888
	 */
Bob Halley's avatar
Bob Halley committed
889 890
	do {
		result = isc_app_run();
891

Bob Halley's avatar
Bob Halley committed
892
		if (result == ISC_R_RELOAD) {
893
			ns_server_reloadwanted(ns_g_server);
Bob Halley's avatar
Bob Halley committed
894 895 896 897 898 899 900 901 902 903
		} else if (result != ISC_R_SUCCESS) {
			UNEXPECTED_ERROR(__FILE__, __LINE__,
					 "isc_app_run(): %s",
					 isc_result_totext(result));
			/*
			 * Force exit.
			 */
			result = ISC_R_SUCCESS;
		}
	} while (result != ISC_R_SUCCESS);
Bob Halley's avatar
add  
Bob Halley committed
904

Mark Andrews's avatar
Mark Andrews committed
905 906 907 908 909 910
#ifdef HAVE_LIBSCF
	if (ns_smf_want_disable == 1) {
		result = ns_smf_get_instance(&instance, 1, ns_g_mctx);
		if (result == ISC_R_SUCCESS && instance != NULL) {
			if (smf_disable_instance(instance, 0) != 0)
				UNEXPECTED_ERROR(__FILE__, __LINE__,
911
						 "smf_disable_instance() "
Mark Andrews's avatar
Mark Andrews committed
912 913 914 915 916 917 918 919 920
						 "failed for %s : %s",
						 instance,
						 scf_strerror(scf_error()));
		}
		if (instance != NULL)
			isc_mem_free(ns_g_mctx, instance);
	}
#endif /* HAVE_LIBSCF */

Bob Halley's avatar
add  
Bob Halley committed
921 922
	cleanup();

923
	if (want_stats) {
Bob Halley's avatar
add  
Bob Halley committed
924
		isc_mem_stats(ns_g_mctx, stdout);
925 926
		isc_mutex_stats(stdout);
	}
927 928

	if (ns_g_memstatistics && memstats != NULL) {
929 930 931 932 933 934 935 936
		FILE *fp = NULL;
		result = isc_stdio_open(memstats, "w", &fp);
		if (result == ISC_R_SUCCESS) {
			isc_mem_stats(ns_g_mctx, fp);
			isc_mutex_stats(fp);
			isc_stdio_close(fp);
		}
	}
Bob Halley's avatar
add  
Bob Halley committed
937
	isc_mem_destroy(&ns_g_mctx);
938
	isc_mem_checkdestroyed(stderr);
Bob Halley's avatar
add  
Bob Halley committed
939

940 941
	ns_main_setmemstats(NULL);

Bob Halley's avatar
add  
Bob Halley committed
942 943
	isc_app_finish();

944 945
	ns_os_closedevnull();

Bob Halley's avatar
Bob Halley committed
946 947
	ns_os_shutdown();

Bob Halley's avatar
add  
Bob Halley committed
948 949
	return (0);
}