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