xref: /minix/external/bsd/bind/dist/bin/named/main.c (revision 00b67f09)
1 /*	$NetBSD: main.c,v 1.18 2015/07/08 17:28:55 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2004-2015  Internet Systems Consortium, Inc. ("ISC")
5  * Copyright (C) 1999-2003  Internet Software Consortium.
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
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 #ifdef PKCS11CRYPTO
54 #include <pk11/result.h>
55 #endif
56 
57 #include <dlz/dlz_dlopen_driver.h>
58 
59 #ifdef HAVE_GPERFTOOLS_PROFILER
60 #include <gperftools/profiler.h>
61 #endif
62 
63 
64 /*
65  * Defining NS_MAIN provides storage declarations (rather than extern)
66  * for variables in named/globals.h.
67  */
68 #define NS_MAIN 1
69 
70 #include <named/builtin.h>
71 #include <named/control.h>
72 #include <named/globals.h>	/* Explicit, though named/log.h includes it. */
73 #include <named/interfacemgr.h>
74 #include <named/log.h>
75 #include <named/os.h>
76 #include <named/server.h>
77 #include <named/lwresd.h>
78 #include <named/main.h>
79 #include <named/seccomp.h>
80 #ifdef HAVE_LIBSCF
81 #include <named/ns_smf_globals.h>
82 #endif
83 
84 #ifdef OPENSSL
85 #include <openssl/opensslv.h>
86 #include <openssl/crypto.h>
87 #endif
88 #ifdef HAVE_LIBXML2
89 #include <libxml/xmlversion.h>
90 #endif
91 
92 #include "pfilter.h"
93 
94 /*
95  * Include header files for database drivers here.
96  */
97 /* #include "xxdb.h" */
98 
99 #ifdef CONTRIB_DLZ
100 /*
101  * Include contributed DLZ drivers if appropriate.
102  */
103 #include <dlz/dlz_drivers.h>
104 #endif
105 
106 /*
107  * The maximum number of stack frames to dump on assertion failure.
108  */
109 #ifndef BACKTRACE_MAXFRAME
110 #define BACKTRACE_MAXFRAME 128
111 #endif
112 
113 extern int isc_dscp_check_value;
114 extern unsigned int dns_zone_mkey_hour;
115 extern unsigned int dns_zone_mkey_day;
116 extern unsigned int dns_zone_mkey_month;
117 
118 static isc_boolean_t	want_stats = ISC_FALSE;
119 static char		program_name[ISC_DIR_NAMEMAX] = "named";
120 static char		absolute_conffile[ISC_DIR_PATHMAX];
121 static char		saved_command_line[512];
122 static char		version[512];
123 static unsigned int	maxsocks = 0;
124 static int		maxudp = 0;
125 
126 void
ns_main_earlywarning(const char * format,...)127 ns_main_earlywarning(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_WARNING,
134 			       format, args);
135 	} else {
136 		fprintf(stderr, "%s: ", program_name);
137 		vfprintf(stderr, format, args);
138 		fprintf(stderr, "\n");
139 		fflush(stderr);
140 	}
141 	va_end(args);
142 }
143 
144 void
ns_main_earlyfatal(const char * format,...)145 ns_main_earlyfatal(const char *format, ...) {
146 	va_list args;
147 
148 	va_start(args, format);
149 	if (ns_g_lctx != NULL) {
150 		isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
151 			       NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
152 			       format, args);
153 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
154 			       NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
155 			       "exiting (due to early fatal error)");
156 	} else {
157 		fprintf(stderr, "%s: ", program_name);
158 		vfprintf(stderr, format, args);
159 		fprintf(stderr, "\n");
160 		fflush(stderr);
161 	}
162 	va_end(args);
163 
164 	exit(1);
165 }
166 
167 ISC_PLATFORM_NORETURN_PRE static void
168 assertion_failed(const char *file, int line, isc_assertiontype_t type,
169 		 const char *cond) ISC_PLATFORM_NORETURN_POST;
170 
171 static void
assertion_failed(const char * file,int line,isc_assertiontype_t type,const char * cond)172 assertion_failed(const char *file, int line, isc_assertiontype_t type,
173 		 const char *cond)
174 {
175 	void *tracebuf[BACKTRACE_MAXFRAME];
176 	int i, nframes;
177 	isc_result_t result;
178 	const char *logsuffix = "";
179 	const char *fname;
180 
181 	/*
182 	 * Handle assertion failures.
183 	 */
184 
185 	if (ns_g_lctx != NULL) {
186 		/*
187 		 * Reset the assertion callback in case it is the log
188 		 * routines causing the assertion.
189 		 */
190 		isc_assertion_setcallback(NULL);
191 
192 		result = isc_backtrace_gettrace(tracebuf, BACKTRACE_MAXFRAME,
193 						&nframes);
194 		if (result == ISC_R_SUCCESS && nframes > 0)
195 			logsuffix = ", back trace";
196 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
197 			      NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
198 			      "%s:%d: %s(%s) failed%s", file, line,
199 			      isc_assertion_typetotext(type), cond, logsuffix);
200 		if (result == ISC_R_SUCCESS) {
201 			for (i = 0; i < nframes; i++) {
202 				unsigned long offset;
203 
204 				fname = NULL;
205 				result = isc_backtrace_getsymbol(tracebuf[i],
206 								 &fname,
207 								 &offset);
208 				if (result == ISC_R_SUCCESS) {
209 					isc_log_write(ns_g_lctx,
210 						      NS_LOGCATEGORY_GENERAL,
211 						      NS_LOGMODULE_MAIN,
212 						      ISC_LOG_CRITICAL,
213 						      "#%d %p in %s()+0x%lx", i,
214 						      tracebuf[i], fname,
215 						      offset);
216 				} else {
217 					isc_log_write(ns_g_lctx,
218 						      NS_LOGCATEGORY_GENERAL,
219 						      NS_LOGMODULE_MAIN,
220 						      ISC_LOG_CRITICAL,
221 						      "#%d %p in ??", i,
222 						      tracebuf[i]);
223 				}
224 			}
225 		}
226 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
227 			      NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
228 			      "exiting (due to assertion failure)");
229 	} else {
230 		fprintf(stderr, "%s:%d: %s(%s) failed\n",
231 			file, line, isc_assertion_typetotext(type), cond);
232 		fflush(stderr);
233 	}
234 
235 	if (ns_g_coreok)
236 		abort();
237 	exit(1);
238 }
239 
240 ISC_PLATFORM_NORETURN_PRE static void
241 library_fatal_error(const char *file, int line, const char *format,
242 		    va_list args)
243 ISC_FORMAT_PRINTF(3, 0) ISC_PLATFORM_NORETURN_POST;
244 
245 static void
library_fatal_error(const char * file,int line,const char * format,va_list args)246 library_fatal_error(const char *file, int line, const char *format,
247 		    va_list args)
248 {
249 	/*
250 	 * Handle isc_error_fatal() calls from our libraries.
251 	 */
252 
253 	if (ns_g_lctx != NULL) {
254 		/*
255 		 * Reset the error callback in case it is the log
256 		 * routines causing the assertion.
257 		 */
258 		isc_error_setfatal(NULL);
259 
260 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
261 			      NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
262 			      "%s:%d: fatal error:", file, line);
263 		isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
264 			       NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
265 			       format, args);
266 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
267 			      NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
268 			      "exiting (due to fatal error in library)");
269 	} else {
270 		fprintf(stderr, "%s:%d: fatal error: ", file, line);
271 		vfprintf(stderr, format, args);
272 		fprintf(stderr, "\n");
273 		fflush(stderr);
274 	}
275 
276 	if (ns_g_coreok)
277 		abort();
278 	exit(1);
279 }
280 
281 static void
282 library_unexpected_error(const char *file, int line, const char *format,
283 			 va_list args) ISC_FORMAT_PRINTF(3, 0);
284 
285 static void
library_unexpected_error(const char * file,int line,const char * format,va_list args)286 library_unexpected_error(const char *file, int line, const char *format,
287 			 va_list args)
288 {
289 	/*
290 	 * Handle isc_error_unexpected() calls from our libraries.
291 	 */
292 
293 	if (ns_g_lctx != NULL) {
294 		char fmt[2048];
295 		snprintf(fmt, sizeof(fmt),
296 		    "%s:%d: unexpected error: %s", file, line, format);
297 		isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
298 			       NS_LOGMODULE_MAIN, ISC_LOG_ERROR,
299 			       fmt, args);
300 	} else {
301 		fprintf(stderr, "%s:%d: fatal error: ", file, line);
302 		vfprintf(stderr, format, args);
303 		fprintf(stderr, "\n");
304 		fflush(stderr);
305 	}
306 }
307 
308 static void
lwresd_usage(void)309 lwresd_usage(void) {
310 	fprintf(stderr,
311 		"usage: lwresd [-4|-6] [-c conffile | -C resolvconffile] "
312 		"[-d debuglevel]\n"
313 		"              [-f|-g] [-n number_of_cpus] [-p port] "
314 		"[-P listen-port] [-s]\n"
315 		"              [-t chrootdir] [-u username] [-i pidfile]\n"
316 		"              [-m {usage|trace|record|size|mctx}]\n");
317 }
318 
319 static void
usage(void)320 usage(void) {
321 	if (ns_g_lwresdonly) {
322 		lwresd_usage();
323 		return;
324 	}
325 	fprintf(stderr,
326 		"usage: named [-4|-6] [-c conffile] [-d debuglevel] "
327 		"[-E engine] [-f|-g]\n"
328 		"             [-n number_of_cpus] [-p port] [-s] "
329 		"[-t chrootdir] [-u username]\n"
330 		"             [-m {usage|trace|record|size|mctx}]\n");
331 }
332 
333 static void
save_command_line(int argc,char * argv[])334 save_command_line(int argc, char *argv[]) {
335 	int i;
336 	char *src;
337 	char *dst;
338 	char *eob;
339 	const char truncated[] = "...";
340 	isc_boolean_t quoted = ISC_FALSE;
341 
342 	dst = saved_command_line;
343 	eob = saved_command_line + sizeof(saved_command_line);
344 
345 	for (i = 1; i < argc && dst < eob; i++) {
346 		*dst++ = ' ';
347 
348 		src = argv[i];
349 		while (*src != '\0' && dst < eob) {
350 			/*
351 			 * This won't perfectly produce a shell-independent
352 			 * pastable command line in all circumstances, but
353 			 * comes close, and for practical purposes will
354 			 * nearly always be fine.
355 			 */
356 			if (quoted || isalnum(*src & 0xff) ||
357 			    *src == '-' || *src == '_' ||
358 			    *src == '.' || *src == '/') {
359 				*dst++ = *src++;
360 				quoted = ISC_FALSE;
361 			} else {
362 				*dst++ = '\\';
363 				quoted = ISC_TRUE;
364 			}
365 		}
366 	}
367 
368 	INSIST(sizeof(saved_command_line) >= sizeof(truncated));
369 
370 	if (dst == eob)
371 		strcpy(eob - sizeof(truncated), truncated);
372 	else
373 		*dst = '\0';
374 }
375 
376 static int
parse_int(char * arg,const char * desc)377 parse_int(char *arg, const char *desc) {
378 	char *endp;
379 	int tmp;
380 	long int ltmp;
381 
382 	ltmp = strtol(arg, &endp, 10);
383 	tmp = (int) ltmp;
384 	if (*endp != '\0')
385 		ns_main_earlyfatal("%s '%s' must be numeric", desc, arg);
386 	if (tmp < 0 || tmp != ltmp)
387 		ns_main_earlyfatal("%s '%s' out of range", desc, arg);
388 	return (tmp);
389 }
390 
391 static struct flag_def {
392 	const char *name;
393 	unsigned int value;
394 } mem_debug_flags[] = {
395 	{ "trace",  ISC_MEM_DEBUGTRACE },
396 	{ "record", ISC_MEM_DEBUGRECORD },
397 	{ "usage", ISC_MEM_DEBUGUSAGE },
398 	{ "size", ISC_MEM_DEBUGSIZE },
399 	{ "mctx", ISC_MEM_DEBUGCTX },
400 	{ NULL, 0 }
401 };
402 
403 static void
set_flags(const char * arg,struct flag_def * defs,unsigned int * ret)404 set_flags(const char *arg, struct flag_def *defs, unsigned int *ret) {
405 	for (;;) {
406 		const struct flag_def *def;
407 		const char *end = strchr(arg, ',');
408 		int arglen;
409 		if (end == NULL)
410 			end = arg + strlen(arg);
411 		arglen = (int)(end - arg);
412 		for (def = defs; def->name != NULL; def++) {
413 			if (arglen == (int)strlen(def->name) &&
414 			    memcmp(arg, def->name, arglen) == 0) {
415 				*ret |= def->value;
416 				goto found;
417 			}
418 		}
419 		ns_main_earlyfatal("unrecognized flag '%.*s'", arglen, arg);
420 	 found:
421 		if (*end == '\0')
422 			break;
423 		arg = end + 1;
424 	}
425 }
426 
427 static void
parse_command_line(int argc,char * argv[])428 parse_command_line(int argc, char *argv[]) {
429 	int ch;
430 	int port;
431 	const char *p;
432 
433 	save_command_line(argc, argv);
434 
435 	/* PLEASE keep options synchronized when main is hooked! */
436 #define CMDLINE_FLAGS "46c:C:d:D:E:fFgi:lm:n:N:p:P:sS:t:T:U:u:vVx:"
437 	isc_commandline_errprint = ISC_FALSE;
438 	while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
439 		switch (ch) {
440 		case '4':
441 			if (ns_g_disable4)
442 				ns_main_earlyfatal("cannot specify -4 and -6");
443 			if (isc_net_probeipv4() != ISC_R_SUCCESS)
444 				ns_main_earlyfatal("IPv4 not supported by OS");
445 			isc_net_disableipv6();
446 			ns_g_disable6 = ISC_TRUE;
447 			break;
448 		case '6':
449 			if (ns_g_disable6)
450 				ns_main_earlyfatal("cannot specify -4 and -6");
451 			if (isc_net_probeipv6() != ISC_R_SUCCESS)
452 				ns_main_earlyfatal("IPv6 not supported by OS");
453 			isc_net_disableipv4();
454 			ns_g_disable4 = ISC_TRUE;
455 			break;
456 		case 'c':
457 			ns_g_conffile = isc_commandline_argument;
458 			lwresd_g_conffile = isc_commandline_argument;
459 			if (lwresd_g_useresolvconf)
460 				ns_main_earlyfatal("cannot specify -c and -C");
461 			ns_g_conffileset = ISC_TRUE;
462 			break;
463 		case 'C':
464 			lwresd_g_resolvconffile = isc_commandline_argument;
465 			if (ns_g_conffileset)
466 				ns_main_earlyfatal("cannot specify -c and -C");
467 			lwresd_g_useresolvconf = ISC_TRUE;
468 			break;
469 		case 'd':
470 			ns_g_debuglevel = parse_int(isc_commandline_argument,
471 						    "debug level");
472 			break;
473 		case 'D':
474 			/* Descriptive comment for 'ps'. */
475 			break;
476 		case 'E':
477 			ns_g_engine = isc_commandline_argument;
478 			break;
479 		case 'f':
480 			ns_g_foreground = ISC_TRUE;
481 			break;
482 		case 'g':
483 			ns_g_foreground = ISC_TRUE;
484 			ns_g_logstderr = ISC_TRUE;
485 			break;
486 		/* XXXBEW -i should be removed */
487 		case 'i':
488 			lwresd_g_defaultpidfile = isc_commandline_argument;
489 			break;
490 		case 'l':
491 			ns_g_lwresdonly = ISC_TRUE;
492 			break;
493 		case 'm':
494 			set_flags(isc_commandline_argument, mem_debug_flags,
495 				  &isc_mem_debugging);
496 			break;
497 		case 'N': /* Deprecated. */
498 		case 'n':
499 			ns_g_cpus = parse_int(isc_commandline_argument,
500 					      "number of cpus");
501 			if (ns_g_cpus == 0)
502 				ns_g_cpus = 1;
503 			break;
504 		case 'p':
505 			port = parse_int(isc_commandline_argument, "port");
506 			if (port < 1 || port > 65535)
507 				ns_main_earlyfatal("port '%s' out of range",
508 						   isc_commandline_argument);
509 			ns_g_port = port;
510 			break;
511 		/* XXXBEW Should -P be removed? */
512 		case 'P':
513 			port = parse_int(isc_commandline_argument, "port");
514 			if (port < 1 || port > 65535)
515 				ns_main_earlyfatal("port '%s' out of range",
516 						   isc_commandline_argument);
517 			lwresd_g_listenport = port;
518 			break;
519 		case 's':
520 			/* XXXRTH temporary syntax */
521 			want_stats = ISC_TRUE;
522 			break;
523 		case 'S':
524 			maxsocks = parse_int(isc_commandline_argument,
525 					     "max number of sockets");
526 			break;
527 		case 't':
528 			/* XXXJAB should we make a copy? */
529 			ns_g_chrootdir = isc_commandline_argument;
530 			break;
531 		case 'T':	/* NOT DOCUMENTED */
532 			/*
533 			 * force the server to behave (or misbehave) in
534 			 * specified ways for testing purposes.
535 			 *
536 			 * clienttest: make clients single shot with their
537 			 * 	       own memory context.
538 			 * delay=xxxx: delay client responses by xxxx ms to
539 			 *	       simulate remote servers.
540 			 * dscp=x:     check that dscp values are as
541 			 * 	       expected and assert otherwise.
542 			 */
543 			if (!strcmp(isc_commandline_argument, "clienttest"))
544 				ns_g_clienttest = ISC_TRUE;
545 			else if (!strcmp(isc_commandline_argument, "nosoa"))
546 				ns_g_nosoa = ISC_TRUE;
547 			else if (!strcmp(isc_commandline_argument, "noaa"))
548 				ns_g_noaa = ISC_TRUE;
549 			else if (!strcmp(isc_commandline_argument, "maxudp512"))
550 				maxudp = 512;
551 			else if (!strcmp(isc_commandline_argument, "maxudp1460"))
552 				maxudp = 1460;
553 			else if (!strcmp(isc_commandline_argument, "dropedns"))
554 				ns_g_dropedns = ISC_TRUE;
555 			else if (!strcmp(isc_commandline_argument, "noedns"))
556 				ns_g_noedns = ISC_TRUE;
557 			else if (!strncmp(isc_commandline_argument,
558 					  "maxudp=", 7))
559 				maxudp = atoi(isc_commandline_argument + 7);
560 			else if (!strncmp(isc_commandline_argument,
561 					  "delay=", 6))
562 				ns_g_delay = atoi(isc_commandline_argument + 6);
563 			else if (!strcmp(isc_commandline_argument, "nosyslog"))
564 				ns_g_nosyslog = ISC_TRUE;
565 			else if (!strcmp(isc_commandline_argument, "nonearest"))
566 				ns_g_nonearest = ISC_TRUE;
567 			else if (!strncmp(isc_commandline_argument, "dscp=", 5))
568 				isc_dscp_check_value =
569 					   atoi(isc_commandline_argument + 5);
570 			else if (!strncmp(isc_commandline_argument,
571 					  "mkeytimers=", 11))
572 			{
573 				p = strtok(isc_commandline_argument + 11, "/");
574 				if (p == NULL)
575 					ns_main_earlyfatal("bad mkeytimer");
576 				dns_zone_mkey_hour = atoi(p);
577 				if (dns_zone_mkey_hour == 0)
578 					ns_main_earlyfatal("bad mkeytimer");
579 
580 				p = strtok(NULL, "/");
581 				if (p == NULL) {
582 					dns_zone_mkey_day =
583 						(24 * dns_zone_mkey_hour);
584 					dns_zone_mkey_month =
585 						(30 * dns_zone_mkey_day);
586 					break;
587 				}
588 				dns_zone_mkey_day = atoi(p);
589 				if (dns_zone_mkey_day < dns_zone_mkey_hour)
590 					ns_main_earlyfatal("bad mkeytimer");
591 
592 				p = strtok(NULL, "/");
593 				if (p == NULL) {
594 					dns_zone_mkey_month =
595 						(30 * dns_zone_mkey_day);
596 					break;
597 				}
598 				dns_zone_mkey_month = atoi(p);
599 				if (dns_zone_mkey_month < dns_zone_mkey_day)
600 					ns_main_earlyfatal("bad mkeytimer");
601 			} else if (!strcmp(isc_commandline_argument, "notcp"))
602 				ns_g_notcp = ISC_TRUE;
603 			else
604 				fprintf(stderr, "unknown -T flag '%s\n",
605 					isc_commandline_argument);
606 			break;
607 		case 'U':
608 			ns_g_udpdisp = parse_int(isc_commandline_argument,
609 						 "number of UDP listeners "
610 						 "per interface");
611 			break;
612 		case 'u':
613 			ns_g_username = isc_commandline_argument;
614 			break;
615 		case 'v':
616 			printf("%s %s", ns_g_product, ns_g_version);
617 			if (*ns_g_description != 0)
618 				printf(" %s", ns_g_description);
619 			printf("\n");
620 			exit(0);
621 		case 'V':
622 			printf("%s %s", ns_g_product, ns_g_version);
623 			if (*ns_g_description != 0)
624 				printf(" %s", ns_g_description);
625 			printf(" <id:%s> built by %s with %s\n", ns_g_srcid,
626 			       ns_g_builder, ns_g_configargs);
627 #ifdef __clang__
628 			printf("compiled by CLANG %s\n", __VERSION__);
629 #else
630 #if defined(__ICC) || defined(__INTEL_COMPILER)
631 			printf("compiled by ICC %s\n", __VERSION__);
632 #else
633 #ifdef __GNUC__
634 			printf("compiled by GCC %s\n", __VERSION__);
635 #endif
636 #endif
637 #endif
638 #ifdef _MSC_VER
639 			printf("compiled by MSVC %d\n", _MSC_VER);
640 #endif
641 #ifdef __SUNPRO_C
642 			printf("compiled by Solaris Studio %x\n", __SUNPRO_C);
643 #endif
644 #ifdef OPENSSL
645 			printf("compiled with OpenSSL version: %s\n",
646 			       OPENSSL_VERSION_TEXT);
647 #ifndef WIN32
648 			printf("linked to OpenSSL version: %s\n",
649 			       SSLeay_version(SSLEAY_VERSION));
650 #endif
651 #endif
652 #ifdef HAVE_LIBXML2
653 			printf("compiled with libxml2 version: %s\n",
654 			       LIBXML_DOTTED_VERSION);
655 #ifndef WIN32
656 			printf("linked to libxml2 version: %s\n",
657 			       xmlParserVersion);
658 #endif
659 #endif
660 			exit(0);
661 		case 'F':
662 			/* Reserved for FIPS mode */
663 			/* FALLTHROUGH */
664 		case '?':
665 			usage();
666 			if (isc_commandline_option == '?')
667 				exit(0);
668 			p = strchr(CMDLINE_FLAGS, isc_commandline_option);
669 			if (p == NULL || *++p != ':')
670 				ns_main_earlyfatal("unknown option '-%c'",
671 						   isc_commandline_option);
672 			else
673 				ns_main_earlyfatal("option '-%c' requires "
674 						   "an argument",
675 						   isc_commandline_option);
676 			/* FALLTHROUGH */
677 		default:
678 			ns_main_earlyfatal("parsing options returned %d", ch);
679 		}
680 	}
681 
682 	argc -= isc_commandline_index;
683 	argv += isc_commandline_index;
684 	POST(argv);
685 
686 	if (argc > 0) {
687 		usage();
688 		ns_main_earlyfatal("extra command line arguments");
689 	}
690 }
691 
692 static isc_result_t
create_managers(void)693 create_managers(void) {
694 	isc_result_t result;
695 	unsigned int socks;
696 
697 #ifdef ISC_PLATFORM_USETHREADS
698 	if (ns_g_cpus == 0)
699 		ns_g_cpus = ns_g_cpus_detected;
700 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
701 		      ISC_LOG_INFO, "found %u CPU%s, using %u worker thread%s",
702 		      ns_g_cpus_detected, ns_g_cpus_detected == 1 ? "" : "s",
703 		      ns_g_cpus, ns_g_cpus == 1 ? "" : "s");
704 #else
705 	ns_g_cpus = 1;
706 #endif
707 #ifdef WIN32
708 	ns_g_udpdisp = 1;
709 #else
710 	if (ns_g_udpdisp == 0) {
711 		if (ns_g_cpus_detected == 1)
712 			ns_g_udpdisp = 1;
713 		else if (ns_g_cpus_detected < 4)
714 			ns_g_udpdisp = 2;
715 		else
716 			ns_g_udpdisp = ns_g_cpus_detected / 2;
717 	}
718 	if (ns_g_udpdisp > ns_g_cpus)
719 		ns_g_udpdisp = ns_g_cpus;
720 #endif
721 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
722 		      ISC_LOG_INFO, "using %u UDP listener%s per interface",
723 		      ns_g_udpdisp, ns_g_udpdisp == 1 ? "" : "s");
724 
725 	result = isc_taskmgr_create(ns_g_mctx, ns_g_cpus, 0, &ns_g_taskmgr);
726 	if (result != ISC_R_SUCCESS) {
727 		UNEXPECTED_ERROR(__FILE__, __LINE__,
728 				 "isc_taskmgr_create() failed: %s",
729 				 isc_result_totext(result));
730 		return (ISC_R_UNEXPECTED);
731 	}
732 
733 	result = isc_timermgr_create(ns_g_mctx, &ns_g_timermgr);
734 	if (result != ISC_R_SUCCESS) {
735 		UNEXPECTED_ERROR(__FILE__, __LINE__,
736 				 "isc_timermgr_create() failed: %s",
737 				 isc_result_totext(result));
738 		return (ISC_R_UNEXPECTED);
739 	}
740 
741 	result = isc_socketmgr_create2(ns_g_mctx, &ns_g_socketmgr, maxsocks);
742 	if (result != ISC_R_SUCCESS) {
743 		UNEXPECTED_ERROR(__FILE__, __LINE__,
744 				 "isc_socketmgr_create() failed: %s",
745 				 isc_result_totext(result));
746 		return (ISC_R_UNEXPECTED);
747 	}
748 	isc__socketmgr_maxudp(ns_g_socketmgr, maxudp);
749 	result = isc_socketmgr_getmaxsockets(ns_g_socketmgr, &socks);
750 	if (result == ISC_R_SUCCESS) {
751 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
752 			      NS_LOGMODULE_SERVER,
753 			      ISC_LOG_INFO, "using up to %u sockets", socks);
754 	}
755 
756 	result = isc_entropy_create(ns_g_mctx, &ns_g_entropy);
757 	if (result != ISC_R_SUCCESS) {
758 		UNEXPECTED_ERROR(__FILE__, __LINE__,
759 				 "isc_entropy_create() failed: %s",
760 				 isc_result_totext(result));
761 		return (ISC_R_UNEXPECTED);
762 	}
763 
764 	result = isc_hash_create(ns_g_mctx, ns_g_entropy, DNS_NAME_MAXWIRE);
765 	if (result != ISC_R_SUCCESS) {
766 		UNEXPECTED_ERROR(__FILE__, __LINE__,
767 				 "isc_hash_create() failed: %s",
768 				 isc_result_totext(result));
769 		return (ISC_R_UNEXPECTED);
770 	}
771 
772 	return (ISC_R_SUCCESS);
773 }
774 
775 static void
destroy_managers(void)776 destroy_managers(void) {
777 	ns_lwresd_shutdown();
778 
779 	isc_entropy_detach(&ns_g_entropy);
780 	if (ns_g_fallbackentropy != NULL)
781 		isc_entropy_detach(&ns_g_fallbackentropy);
782 
783 	/*
784 	 * isc_taskmgr_destroy() will block until all tasks have exited,
785 	 */
786 	isc_taskmgr_destroy(&ns_g_taskmgr);
787 	isc_timermgr_destroy(&ns_g_timermgr);
788 	isc_socketmgr_destroy(&ns_g_socketmgr);
789 
790 	/*
791 	 * isc_hash_destroy() cannot be called as long as a resolver may be
792 	 * running.  Calling this after isc_taskmgr_destroy() ensures the
793 	 * call is safe.
794 	 */
795 	isc_hash_destroy();
796 }
797 
798 static void
dump_symboltable(void)799 dump_symboltable(void) {
800 	int i;
801 	isc_result_t result;
802 	const char *fname;
803 	const void *addr;
804 
805 	if (isc__backtrace_nsymbols == 0)
806 		return;
807 
808 	if (!isc_log_wouldlog(ns_g_lctx, ISC_LOG_DEBUG(99)))
809 		return;
810 
811 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
812 		      ISC_LOG_DEBUG(99), "Symbol table:");
813 
814 	for (i = 0, result = ISC_R_SUCCESS; result == ISC_R_SUCCESS; i++) {
815 		addr = NULL;
816 		fname = NULL;
817 		result = isc_backtrace_getsymbolfromindex(i, &addr, &fname);
818 		if (result == ISC_R_SUCCESS) {
819 			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
820 				      NS_LOGMODULE_MAIN, ISC_LOG_DEBUG(99),
821 				      "[%d] %p %s", i, addr, fname);
822 		}
823 	}
824 }
825 
826 #ifdef HAVE_LIBSECCOMP
827 static void
setup_seccomp()828 setup_seccomp() {
829 	scmp_filter_ctx ctx;
830 	unsigned int i;
831 	int ret;
832 
833 	/* Make sure the lists are in sync */
834 	INSIST((sizeof(scmp_syscalls) / sizeof(int)) ==
835 	       (sizeof(scmp_syscall_names) / sizeof(const char *)));
836 
837 	ctx = seccomp_init(SCMP_ACT_KILL);
838 	if (ctx == NULL) {
839 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
840 			      NS_LOGMODULE_MAIN, ISC_LOG_WARNING,
841 			      "libseccomp activation failed");
842 		return;
843 	}
844 
845 	for (i = 0 ; i < sizeof(scmp_syscalls)/sizeof(*(scmp_syscalls)); i++) {
846 		ret = seccomp_rule_add(ctx, SCMP_ACT_ALLOW,
847 				       scmp_syscalls[i], 0);
848 		if (ret < 0)
849 			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
850 				      NS_LOGMODULE_MAIN, ISC_LOG_WARNING,
851 				      "libseccomp rule failed: %s",
852 				      scmp_syscall_names[i]);
853 
854 		else
855 			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
856 				      NS_LOGMODULE_MAIN, ISC_LOG_DEBUG(9),
857 				      "added libseccomp rule: %s",
858 				      scmp_syscall_names[i]);
859 	}
860 
861 	ret = seccomp_load(ctx);
862 	if (ret < 0) {
863 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
864 			      NS_LOGMODULE_MAIN, ISC_LOG_WARNING,
865 			      "libseccomp unable to load filter");
866 	} else {
867 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
868 			      NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
869 			      "libseccomp sandboxing active");
870 	}
871 
872 	/*
873 	 * Release filter in ctx. Filters already loaded are not
874 	 * affected.
875 	 */
876 	seccomp_release(ctx);
877 }
878 #endif /* HAVE_LIBSECCOMP */
879 
880 static void
setup(void)881 setup(void) {
882 	isc_result_t result;
883 	isc_resourcevalue_t old_openfiles;
884 #ifdef HAVE_LIBSCF
885 	char *instance = NULL;
886 #endif
887 
888 	/*
889 	 * Get the user and group information before changing the root
890 	 * directory, so the administrator does not need to keep a copy
891 	 * of the user and group databases in the chroot'ed environment.
892 	 */
893 	ns_os_inituserinfo(ns_g_username);
894 
895 	/*
896 	 * Initialize time conversion information
897 	 */
898 	ns_os_tzset();
899 
900 	ns_os_opendevnull();
901 
902 #ifdef HAVE_LIBSCF
903 	/* Check if named is under smf control, before chroot. */
904 	result = ns_smf_get_instance(&instance, 0, ns_g_mctx);
905 	/* We don't care about instance, just check if we got one. */
906 	if (result == ISC_R_SUCCESS)
907 		ns_smf_got_instance = 1;
908 	else
909 		ns_smf_got_instance = 0;
910 	if (instance != NULL)
911 		isc_mem_free(ns_g_mctx, instance);
912 #endif /* HAVE_LIBSCF */
913 
914 #ifdef PATH_RANDOMDEV
915 	/*
916 	 * Initialize system's random device as fallback entropy source
917 	 * if running chroot'ed.
918 	 */
919 	if (ns_g_chrootdir != NULL) {
920 		result = isc_entropy_create(ns_g_mctx, &ns_g_fallbackentropy);
921 		if (result != ISC_R_SUCCESS)
922 			ns_main_earlyfatal("isc_entropy_create() failed: %s",
923 					   isc_result_totext(result));
924 
925 		result = isc_entropy_createfilesource(ns_g_fallbackentropy,
926 						      PATH_RANDOMDEV);
927 		if (result != ISC_R_SUCCESS) {
928 			ns_main_earlywarning("could not open pre-chroot "
929 					     "entropy source %s: %s",
930 					     PATH_RANDOMDEV,
931 					     isc_result_totext(result));
932 			isc_entropy_detach(&ns_g_fallbackentropy);
933 		}
934 	}
935 #endif
936 
937 #ifdef ISC_PLATFORM_USETHREADS
938 	/*
939 	 * Check for the number of cpu's before ns_os_chroot().
940 	 */
941 	ns_g_cpus_detected = isc_os_ncpus();
942 #endif
943 
944 	ns_os_chroot(ns_g_chrootdir);
945 
946 	/*
947 	 * For operating systems which have a capability mechanism, now
948 	 * is the time to switch to minimal privs and change our user id.
949 	 * On traditional UNIX systems, this call will be a no-op, and we
950 	 * will change the user ID after reading the config file the first
951 	 * time.  (We need to read the config file to know which possibly
952 	 * privileged ports to bind() to.)
953 	 */
954 	ns_os_minprivs();
955 
956 	result = ns_log_init(ISC_TF(ns_g_username != NULL));
957 	if (result != ISC_R_SUCCESS)
958 		ns_main_earlyfatal("ns_log_init() failed: %s",
959 				   isc_result_totext(result));
960 
961 	/*
962 	 * Now is the time to daemonize (if we're not running in the
963 	 * foreground).  We waited until now because we wanted to get
964 	 * a valid logging context setup.  We cannot daemonize any later,
965 	 * because calling create_managers() will create threads, which
966 	 * would be lost after fork().
967 	 */
968 	if (!ns_g_foreground)
969 		ns_os_daemonize();
970 
971 	/*
972 	 * We call isc_app_start() here as some versions of FreeBSD's fork()
973 	 * destroys all the signal handling it sets up.
974 	 */
975 	result = isc_app_start();
976 	if (result != ISC_R_SUCCESS)
977 		ns_main_earlyfatal("isc_app_start() failed: %s",
978 				   isc_result_totext(result));
979 
980 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
981 		      ISC_LOG_NOTICE, "starting %s %s%s", ns_g_product,
982 		      ns_g_version, saved_command_line);
983 
984 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
985 		      ISC_LOG_NOTICE, "built with %s", ns_g_configargs);
986 
987 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
988 		      ISC_LOG_NOTICE,
989 		      "----------------------------------------------------");
990 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
991 		      ISC_LOG_NOTICE,
992 		      "BIND 9 is maintained by Internet Systems Consortium,");
993 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
994 		      ISC_LOG_NOTICE,
995 		      "Inc. (ISC), a non-profit 501(c)(3) public-benefit ");
996 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
997 		      ISC_LOG_NOTICE,
998 		      "corporation.  Support and training for BIND 9 are ");
999 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
1000 		      ISC_LOG_NOTICE,
1001 		      "available at https://www.isc.org/support");
1002 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
1003 		      ISC_LOG_NOTICE,
1004 		      "----------------------------------------------------");
1005 
1006 	dump_symboltable();
1007 
1008 	/*
1009 	 * Get the initial resource limits.
1010 	 */
1011 	(void)isc_resource_getlimit(isc_resource_stacksize,
1012 				    &ns_g_initstacksize);
1013 	(void)isc_resource_getlimit(isc_resource_datasize,
1014 				    &ns_g_initdatasize);
1015 	(void)isc_resource_getlimit(isc_resource_coresize,
1016 				    &ns_g_initcoresize);
1017 	(void)isc_resource_getlimit(isc_resource_openfiles,
1018 				    &ns_g_initopenfiles);
1019 
1020 	/*
1021 	 * System resources cannot effectively be tuned on some systems.
1022 	 * Raise the limit in such cases for safety.
1023 	 */
1024 	old_openfiles = ns_g_initopenfiles;
1025 	ns_os_adjustnofile();
1026 	(void)isc_resource_getlimit(isc_resource_openfiles,
1027 				    &ns_g_initopenfiles);
1028 	if (old_openfiles != ns_g_initopenfiles) {
1029 		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
1030 			      NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
1031 			      "adjusted limit on open files from "
1032 			      "%" ISC_PRINT_QUADFORMAT "u to "
1033 			      "%" ISC_PRINT_QUADFORMAT "u",
1034 			      old_openfiles, ns_g_initopenfiles);
1035 	}
1036 
1037 	/*
1038 	 * If the named configuration filename is relative, prepend the current
1039 	 * directory's name before possibly changing to another directory.
1040 	 */
1041 	if (! isc_file_isabsolute(ns_g_conffile)) {
1042 		result = isc_file_absolutepath(ns_g_conffile,
1043 					       absolute_conffile,
1044 					       sizeof(absolute_conffile));
1045 		if (result != ISC_R_SUCCESS)
1046 			ns_main_earlyfatal("could not construct absolute path "
1047 					   "of configuration file: %s",
1048 					   isc_result_totext(result));
1049 		ns_g_conffile = absolute_conffile;
1050 	}
1051 
1052 	/*
1053 	 * Record the server's startup time.
1054 	 */
1055 	result = isc_time_now(&ns_g_boottime);
1056 	if (result != ISC_R_SUCCESS)
1057 		ns_main_earlyfatal("isc_time_now() failed: %s",
1058 				   isc_result_totext(result));
1059 
1060 	result = create_managers();
1061 	if (result != ISC_R_SUCCESS)
1062 		ns_main_earlyfatal("create_managers() failed: %s",
1063 				   isc_result_totext(result));
1064 
1065 	ns_builtin_init();
1066 
1067 	/*
1068 	 * Add calls to register sdb drivers here.
1069 	 */
1070 	/* xxdb_init(); */
1071 
1072 #ifdef ISC_DLZ_DLOPEN
1073 	/*
1074 	 * Register the DLZ "dlopen" driver.
1075 	 */
1076 	result = dlz_dlopen_init(ns_g_mctx);
1077 	if (result != ISC_R_SUCCESS)
1078 		ns_main_earlyfatal("dlz_dlopen_init() failed: %s",
1079 				   isc_result_totext(result));
1080 #endif
1081 
1082 #if CONTRIB_DLZ
1083 	/*
1084 	 * Register any other contributed DLZ drivers.
1085 	 */
1086 	result = dlz_drivers_init();
1087 	if (result != ISC_R_SUCCESS)
1088 		ns_main_earlyfatal("dlz_drivers_init() failed: %s",
1089 				   isc_result_totext(result));
1090 #endif
1091 
1092 	ns_server_create(ns_g_mctx, &ns_g_server);
1093 
1094 #ifdef HAVE_LIBSECCOMP
1095 	setup_seccomp();
1096 #endif /* HAVE_LIBSECCOMP */
1097 }
1098 
1099 static void
cleanup(void)1100 cleanup(void) {
1101 	destroy_managers();
1102 
1103 	ns_server_destroy(&ns_g_server);
1104 
1105 	ns_builtin_deinit();
1106 
1107 	/*
1108 	 * Add calls to unregister sdb drivers here.
1109 	 */
1110 	/* xxdb_clear(); */
1111 
1112 #ifdef CONTRIB_DLZ
1113 	/*
1114 	 * Unregister contributed DLZ drivers.
1115 	 */
1116 	dlz_drivers_clear();
1117 #endif
1118 #ifdef ISC_DLZ_DLOPEN
1119 	/*
1120 	 * Unregister "dlopen" DLZ driver.
1121 	 */
1122 	dlz_dlopen_clear();
1123 #endif
1124 
1125 	dns_name_destroy();
1126 
1127 	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
1128 		      ISC_LOG_NOTICE, "exiting");
1129 	ns_log_shutdown();
1130 }
1131 
1132 static char *memstats = NULL;
1133 
1134 void
ns_main_setmemstats(const char * filename)1135 ns_main_setmemstats(const char *filename) {
1136 	/*
1137 	 * Caller has to ensure locking.
1138 	 */
1139 
1140 	if (memstats != NULL) {
1141 		free(memstats);
1142 		memstats = NULL;
1143 	}
1144 	if (filename == NULL)
1145 		return;
1146 	memstats = malloc(strlen(filename) + 1);
1147 	if (memstats)
1148 		strcpy(memstats, filename);
1149 }
1150 
1151 #ifdef HAVE_LIBSCF
1152 /*
1153  * Get FMRI for the named process.
1154  */
1155 isc_result_t
ns_smf_get_instance(char ** ins_name,int debug,isc_mem_t * mctx)1156 ns_smf_get_instance(char **ins_name, int debug, isc_mem_t *mctx) {
1157 	scf_handle_t *h = NULL;
1158 	int namelen;
1159 	char *instance;
1160 
1161 	REQUIRE(ins_name != NULL && *ins_name == NULL);
1162 
1163 	if ((h = scf_handle_create(SCF_VERSION)) == NULL) {
1164 		if (debug)
1165 			UNEXPECTED_ERROR(__FILE__, __LINE__,
1166 					 "scf_handle_create() failed: %s",
1167 					 scf_strerror(scf_error()));
1168 		return (ISC_R_FAILURE);
1169 	}
1170 
1171 	if (scf_handle_bind(h) == -1) {
1172 		if (debug)
1173 			UNEXPECTED_ERROR(__FILE__, __LINE__,
1174 					 "scf_handle_bind() failed: %s",
1175 					 scf_strerror(scf_error()));
1176 		scf_handle_destroy(h);
1177 		return (ISC_R_FAILURE);
1178 	}
1179 
1180 	if ((namelen = scf_myname(h, NULL, 0)) == -1) {
1181 		if (debug)
1182 			UNEXPECTED_ERROR(__FILE__, __LINE__,
1183 					 "scf_myname() failed: %s",
1184 					 scf_strerror(scf_error()));
1185 		scf_handle_destroy(h);
1186 		return (ISC_R_FAILURE);
1187 	}
1188 
1189 	if ((instance = isc_mem_allocate(mctx, namelen + 1)) == NULL) {
1190 		UNEXPECTED_ERROR(__FILE__, __LINE__,
1191 				 "ns_smf_get_instance memory "
1192 				 "allocation failed: %s",
1193 				 isc_result_totext(ISC_R_NOMEMORY));
1194 		scf_handle_destroy(h);
1195 		return (ISC_R_FAILURE);
1196 	}
1197 
1198 	if (scf_myname(h, instance, namelen + 1) == -1) {
1199 		if (debug)
1200 			UNEXPECTED_ERROR(__FILE__, __LINE__,
1201 					 "scf_myname() failed: %s",
1202 					 scf_strerror(scf_error()));
1203 		scf_handle_destroy(h);
1204 		isc_mem_free(mctx, instance);
1205 		return (ISC_R_FAILURE);
1206 	}
1207 
1208 	scf_handle_destroy(h);
1209 	*ins_name = instance;
1210 	return (ISC_R_SUCCESS);
1211 }
1212 #endif /* HAVE_LIBSCF */
1213 
1214 /* main entry point, possibly hooked */
1215 
1216 int
main(int argc,char * argv[])1217 main(int argc, char *argv[]) {
1218 	isc_result_t result;
1219 #ifdef HAVE_LIBSCF
1220 	char *instance = NULL;
1221 #endif
1222 
1223 #ifdef HAVE_GPERFTOOLS_PROFILER
1224 	(void) ProfilerStart(NULL);
1225 #endif
1226 
1227 	/*
1228 	 * Record version in core image.
1229 	 * strings named.core | grep "named version:"
1230 	 */
1231 	strlcat(version,
1232 #if defined(NO_VERSION_DATE) || !defined(__DATE__)
1233 		"named version: BIND " VERSION " <" SRCID ">",
1234 #else
1235 		"named version: BIND " VERSION " <" SRCID "> (" __DATE__ ")",
1236 #endif
1237 		sizeof(version));
1238 	result = isc_file_progname(*argv, program_name, sizeof(program_name));
1239 	if (result != ISC_R_SUCCESS)
1240 		ns_main_earlyfatal("program name too long");
1241 
1242 	if (strcmp(program_name, "lwresd") == 0)
1243 		ns_g_lwresdonly = ISC_TRUE;
1244 
1245 	if (result != ISC_R_SUCCESS)
1246 		ns_main_earlyfatal("failed to build internal symbol table");
1247 
1248 	isc_assertion_setcallback(assertion_failed);
1249 	isc_error_setfatal(library_fatal_error);
1250 	isc_error_setunexpected(library_unexpected_error);
1251 
1252 	ns_os_init(program_name);
1253 
1254 	dns_result_register();
1255 	dst_result_register();
1256 	isccc_result_register();
1257 #ifdef PKCS11CRYPTO
1258 	pk11_result_register();
1259 #endif
1260 
1261 	parse_command_line(argc, argv);
1262 
1263 	pfilter_open();
1264 
1265 	/*
1266 	 * Warn about common configuration error.
1267 	 */
1268 	if (ns_g_chrootdir != NULL) {
1269 		int len = strlen(ns_g_chrootdir);
1270 		if (strncmp(ns_g_chrootdir, ns_g_conffile, len) == 0 &&
1271 		    (ns_g_conffile[len] == '/' || ns_g_conffile[len] == '\\'))
1272 			ns_main_earlywarning("config filename (-c %s) contains "
1273 					     "chroot path (-t %s)",
1274 					     ns_g_conffile, ns_g_chrootdir);
1275 	}
1276 
1277 	result = isc_mem_create(0, 0, &ns_g_mctx);
1278 	if (result != ISC_R_SUCCESS)
1279 		ns_main_earlyfatal("isc_mem_create() failed: %s",
1280 				   isc_result_totext(result));
1281 	isc_mem_setname(ns_g_mctx, "main", NULL);
1282 
1283 	setup();
1284 
1285 	/*
1286 	 * Start things running and then wait for a shutdown request
1287 	 * or reload.
1288 	 */
1289 	do {
1290 		result = isc_app_run();
1291 
1292 		if (result == ISC_R_RELOAD) {
1293 			ns_server_reloadwanted(ns_g_server);
1294 		} else if (result != ISC_R_SUCCESS) {
1295 			UNEXPECTED_ERROR(__FILE__, __LINE__,
1296 					 "isc_app_run(): %s",
1297 					 isc_result_totext(result));
1298 			/*
1299 			 * Force exit.
1300 			 */
1301 			result = ISC_R_SUCCESS;
1302 		}
1303 	} while (result != ISC_R_SUCCESS);
1304 
1305 #ifdef HAVE_LIBSCF
1306 	if (ns_smf_want_disable == 1) {
1307 		result = ns_smf_get_instance(&instance, 1, ns_g_mctx);
1308 		if (result == ISC_R_SUCCESS && instance != NULL) {
1309 			if (smf_disable_instance(instance, 0) != 0)
1310 				UNEXPECTED_ERROR(__FILE__, __LINE__,
1311 						 "smf_disable_instance() "
1312 						 "failed for %s : %s",
1313 						 instance,
1314 						 scf_strerror(scf_error()));
1315 		}
1316 		if (instance != NULL)
1317 			isc_mem_free(ns_g_mctx, instance);
1318 	}
1319 #endif /* HAVE_LIBSCF */
1320 
1321 	cleanup();
1322 
1323 	if (want_stats) {
1324 		isc_mem_stats(ns_g_mctx, stdout);
1325 		isc_mutex_stats(stdout);
1326 	}
1327 
1328 	if (ns_g_memstatistics && memstats != NULL) {
1329 		FILE *fp = NULL;
1330 		result = isc_stdio_open(memstats, "w", &fp);
1331 		if (result == ISC_R_SUCCESS) {
1332 			isc_mem_stats(ns_g_mctx, fp);
1333 			isc_mutex_stats(fp);
1334 			isc_stdio_close(fp);
1335 		}
1336 	}
1337 	isc_mem_destroy(&ns_g_mctx);
1338 	isc_mem_checkdestroyed(stderr);
1339 
1340 	ns_main_setmemstats(NULL);
1341 
1342 	isc_app_finish();
1343 
1344 	ns_os_closedevnull();
1345 
1346 	ns_os_shutdown();
1347 
1348 #ifdef HAVE_GPERFTOOLS_PROFILER
1349 	ProfilerStop();
1350 #endif
1351 
1352 	return (0);
1353 }
1354