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