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