main.c 22.7 KB
Newer Older
Bob Halley's avatar
add    
Bob Halley committed
1
/*
Mark Andrews's avatar
Mark Andrews committed
2
 * Copyright (C) 2004-2006  Internet Systems Consortium, Inc. ("ISC")
Mark Andrews's avatar
Mark Andrews committed
3
 * Copyright (C) 1999-2003  Internet Software Consortium.
4
 *
Bob Halley's avatar
add    
Bob Halley committed
5
6
7
 * Permission to use, copy, modify, and distribute this software for any
 * 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
 */

Mark Andrews's avatar
Mark Andrews committed
18
/* $Id: main.c,v 1.152 2006/01/05 01:37:19 marka 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,
359
			           "46c:C:d:fgi:lm:n:N:p:P:st: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
		case 'u':
			ns_g_username = isc_commandline_argument;
			break;
445
446
447
		case 'v':
			printf("BIND %s\n", ns_g_version);
			exit(0);
448
		case '?':
449
			usage();
450
			ns_main_earlyfatal("unknown option '-%c'",
451
					   isc_commandline_option);
Bob Halley's avatar
add    
Bob Halley committed
452
		default:
Bob Halley's avatar
Bob Halley committed
453
			ns_main_earlyfatal("parsing options returned %d", ch);
Bob Halley's avatar
add    
Bob Halley committed
454
455
456
		}
	}

457
458
	argc -= isc_commandline_index;
	argv += isc_commandline_index;
Bob Halley's avatar
add    
Bob Halley committed
459

460
	if (argc > 0) {
Bob Halley's avatar
add    
Bob Halley committed
461
		usage();
Bob Halley's avatar
Bob Halley committed
462
		ns_main_earlyfatal("extra command line arguments");
Bob Halley's avatar
add    
Bob Halley committed
463
464
465
466
	}
}

static isc_result_t
467
create_managers(void) {
Bob Halley's avatar
add    
Bob Halley committed
468
	isc_result_t result;
469
470
471
#ifdef ISC_PLATFORM_USETHREADS
	unsigned int cpus_detected;
#endif
Bob Halley's avatar
add    
Bob Halley committed
472

473
#ifdef ISC_PLATFORM_USETHREADS
474
	cpus_detected = isc_os_ncpus();
475
	if (ns_g_cpus == 0)
476
477
478
479
480
		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");
481
482
483
#else
	ns_g_cpus = 1;
#endif
Bob Halley's avatar
add    
Bob Halley committed
484
485
486
	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
487
				 "isc_taskmgr_create() failed: %s",
Bob Halley's avatar
add    
Bob Halley committed
488
489
490
491
492
493
494
				 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
495
				 "isc_timermgr_create() failed: %s",
Bob Halley's avatar
add    
Bob Halley committed
496
497
498
499
500
501
502
				 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__,
503
				 "isc_socketmgr_create() failed: %s",
Bob Halley's avatar
add    
Bob Halley committed
504
505
506
507
				 isc_result_totext(result));
		return (ISC_R_UNEXPECTED);
	}

508
	result = isc_entropy_create(ns_g_mctx, &ns_g_entropy);
509
510
	if (result != ISC_R_SUCCESS) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
511
				 "isc_entropy_create() failed: %s",
512
513
514
515
				 isc_result_totext(result));
		return (ISC_R_UNEXPECTED);
	}

516
517
518
519
520
521
522
523
	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
524
525
526
527
528
	return (ISC_R_SUCCESS);
}

static void
destroy_managers(void) {
529
530
	ns_lwresd_shutdown();

531
	isc_entropy_detach(&ns_g_entropy);
532
533
534
	if (ns_g_fallbackentropy != NULL)
		isc_entropy_detach(&ns_g_fallbackentropy);

Bob Halley's avatar
add    
Bob Halley committed
535
	/*
Andreas Gustafsson's avatar
Andreas Gustafsson committed
536
	 * isc_taskmgr_destroy() will block until all tasks have exited,
Bob Halley's avatar
add    
Bob Halley committed
537
538
539
540
	 */
	isc_taskmgr_destroy(&ns_g_taskmgr);
	isc_timermgr_destroy(&ns_g_timermgr);
	isc_socketmgr_destroy(&ns_g_socketmgr);
541
542
543
544
545
546
547

	/*
	 * 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
548
549
550
}

static void
551
setup(void) {
Bob Halley's avatar
add    
Bob Halley committed
552
	isc_result_t result;
553
554
555
#ifdef HAVE_LIBSCF
	char *instance = NULL;
#endif
Bob Halley's avatar
add    
Bob Halley committed
556

557
558
559
560
561
562
563
	/*
	 * 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);

564
565
566
567
568
	/*
	 * Initialize time conversion information
	 */
	ns_os_tzset();

569
570
	ns_os_opendevnull();

571
572
573
574
575
576
577
578
579
#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)
580
		isc_mem_free(ns_g_mctx, instance);
581
582
#endif /* HAVE_LIBSCF */

583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
#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

606
607
	ns_os_chroot(ns_g_chrootdir);

Bob Halley's avatar
Bob Halley committed
608
609
610
611
612
613
614
615
	/*
	 * 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.)
	 */
616
	ns_os_minprivs();
Bob Halley's avatar
Bob Halley committed
617

618
	result = ns_log_init(ISC_TF(ns_g_username != NULL));
619
	if (result != ISC_R_SUCCESS)
Bob Halley's avatar
Bob Halley committed
620
621
		ns_main_earlyfatal("ns_log_init() failed: %s",
				   isc_result_totext(result));
622

Bob Halley's avatar
Bob Halley committed
623
624
625
626
627
628
629
	/*
	 * 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().
	 */
630
631
	if (!ns_g_foreground)
		ns_os_daemonize();
Bob Halley's avatar
Bob Halley committed
632

633
634
635
636
637
638
639
640
641
	/*
	 * 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));

642
	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
643
644
		      ISC_LOG_NOTICE, "starting BIND %s%s", ns_g_version,
		      saved_command_line);
Bob Halley's avatar
add    
Bob Halley committed
645

646
647
648
	/*
	 * Get the initial resource limits.
	 */
649
650
651
652
653
654
655
656
	(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);
657

658
659
660
661
662
	/*
	 * 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)) {
663
664
665
		result = isc_file_absolutepath(ns_g_conffile,
					       absolute_conffile,
					       sizeof(absolute_conffile));
666
		if (result != ISC_R_SUCCESS)
667
668
669
			ns_main_earlyfatal("could not construct absolute path of "
					   "configuration file: %s", 
					   isc_result_totext(result));
670
671
672
		ns_g_conffile = absolute_conffile;
	}

Bob Halley's avatar
add    
Bob Halley committed
673
674
	result = create_managers();
	if (result != ISC_R_SUCCESS)
Bob Halley's avatar
Bob Halley committed
675
676
		ns_main_earlyfatal("create_managers() failed: %s",
				   isc_result_totext(result));
Bob Halley's avatar
add    
Bob Halley committed
677

678
679
	ns_builtin_init();

680
681
682
	/*
	 * Add calls to register sdb drivers here.
	 */
683
	/* xxdb_init(); */
684

685
686
687
688
689
690
691
692
693
694
#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

695
	ns_server_create(ns_g_mctx, &ns_g_server);
Bob Halley's avatar
add    
Bob Halley committed
696
697
698
}

static void
699
cleanup(void) {
Bob Halley's avatar
add    
Bob Halley committed
700
	destroy_managers();
701

702
	ns_server_destroy(&ns_g_server);
703

704
705
	ns_builtin_deinit();

706
707
708
	/*
	 * Add calls to unregister sdb drivers here.
	 */
709
	/* xxdb_clear(); */
710

711
712
713
714
715
716
717
#ifdef DLZ
	/*
	 * Unregister any DLZ drivers.
	 */
	dlz_drivers_clear();
#endif

718
719
	dns_name_destroy();

720
	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
Bob Halley's avatar
Bob Halley committed
721
		      ISC_LOG_NOTICE, "exiting");
722
	ns_log_shutdown();
Bob Halley's avatar
add    
Bob Halley committed
723
724
}

725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
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);
}

744
745
#ifdef HAVE_LIBSCF
/*
746
 * Get FMRI for the named process.
747
 */
748
749
isc_result_t
ns_smf_get_instance(char **ins_name, int debug, isc_mem_t *mctx) {
750
751
	scf_handle_t *h = NULL;
	int namelen;
752
753
754
	char *instance;

	REQUIRE(ins_name != NULL && *ins_name == NULL);
755
756

	if ((h = scf_handle_create(SCF_VERSION)) == NULL) {
757
758
759
760
761
		if (debug)
			UNEXPECTED_ERROR(__FILE__, __LINE__,
					 "scf_handle_create() failed: %s",
			 		 scf_strerror(scf_error()));
		return (ISC_R_FAILURE);
762
763
764
	}

	if (scf_handle_bind(h) == -1) {
765
766
767
768
		if (debug)
			UNEXPECTED_ERROR(__FILE__, __LINE__,
					 "scf_handle_bind() failed: %s",
					 scf_strerror(scf_error()));
769
		scf_handle_destroy(h);
770
		return (ISC_R_FAILURE);
771
772
773
	}

	if ((namelen = scf_myname(h, NULL, 0)) == -1) {
774
775
776
777
		if (debug)
			UNEXPECTED_ERROR(__FILE__, __LINE__,
					 "scf_myname() failed: %s",
					 scf_strerror(scf_error()));
778
		scf_handle_destroy(h);
779
		return (ISC_R_FAILURE);
780
781
	}

782
	if ((instance = isc_mem_allocate(mctx, namelen + 1)) == NULL) {
783
		UNEXPECTED_ERROR(__FILE__, __LINE__,
784
				 "ns_smf_get_instance memory "
785
786
787
				 "allocation failed: %s",
				 isc_result_totext(ISC_R_NOMEMORY));
		scf_handle_destroy(h);
788
		return (ISC_R_FAILURE);
789
790
	}

791
792
793
794
795
	if (scf_myname(h, instance, namelen + 1) == -1) {
		if (debug)
			UNEXPECTED_ERROR(__FILE__, __LINE__,
					 "scf_myname() failed: %s",
					 scf_strerror(scf_error()));
796
		scf_handle_destroy(h);
797
798
		isc_mem_free(mctx, instance);
		return (ISC_R_FAILURE);
799
800
801
	}

	scf_handle_destroy(h);
802
803
	*ins_name = instance;
	return (ISC_R_SUCCESS);
804
}
805
#endif /* HAVE_LIBSCF */
806

Bob Halley's avatar
add    
Bob Halley committed
807
808
809
int
main(int argc, char *argv[]) {
	isc_result_t result;
Mark Andrews's avatar
Mark Andrews committed
810
811
812
#ifdef HAVE_LIBSCF
	char *instance = NULL;
#endif
Bob Halley's avatar
add    
Bob Halley committed
813

814
815
816
817
818
819
820
821
822
823
824
	/*
	 * 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));
825
	result = isc_file_progname(*argv, program_name, sizeof(program_name));
826
827
828
829
830
831
	if (result != ISC_R_SUCCESS)
		ns_main_earlyfatal("program name too long");

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

832
833
	isc_assertion_setcallback(assertion_failed);
	isc_error_setfatal(library_fatal_error);
834
	isc_error_setunexpected(library_unexpected_error);
835

836
	ns_os_init(program_name);
Bob Halley's avatar
Bob Halley committed
837

Bob Halley's avatar
add    
Bob Halley committed
838
839
	dns_result_register();
	dst_result_register();
840
	isccc_result_register();
Bob Halley's avatar
add    
Bob Halley committed
841
842
843

	parse_command_line(argc, argv);

844
845
846
847
848
849
850
851
852
853
854
855
	/*
	 * 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);
	}

856
857
858
859
860
	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));

Bob Halley's avatar
add    
Bob Halley committed
861
862
863
	setup();

	/*
Bob Halley's avatar
Bob Halley committed
864
865
	 * Start things running and then wait for a shutdown request
	 * or reload.
Bob Halley's avatar
add    
Bob Halley committed
866
	 */
Bob Halley's avatar
Bob Halley committed
867
868
	do {
		result = isc_app_run();
869

Bob Halley's avatar
Bob Halley committed
870
		if (result == ISC_R_RELOAD) {
871
			ns_server_reloadwanted(ns_g_server);
Bob Halley's avatar
Bob Halley committed
872
873
874
875
876
877
878
879
880
881
		} 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
882

Mark Andrews's avatar
Mark Andrews committed
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
#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__,
						 "smf_disable_instance() ",
						 "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
899
900
	cleanup();

901
	if (want_stats) {
Bob Halley's avatar
add    
Bob Halley committed
902
		isc_mem_stats(ns_g_mctx, stdout);
903
904
		isc_mutex_stats(stdout);
	}
905
	if (memstats != NULL) {
906
907
908
909
910
911
912
913
		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
914
	isc_mem_destroy(&ns_g_mctx);
915
	isc_mem_checkdestroyed(stderr);
Bob Halley's avatar
add    
Bob Halley committed
916

917
918
	ns_main_setmemstats(NULL);

Bob Halley's avatar
add    
Bob Halley committed
919
920
	isc_app_finish();

921
922
	ns_os_closedevnull();

Bob Halley's avatar
Bob Halley committed
923
924
	ns_os_shutdown();

Bob Halley's avatar
add    
Bob Halley committed
925
926
	return (0);
}