]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - contrib/bind9/bin/named/main.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / contrib / bind9 / bin / named / main.c
1 /*
2  * Copyright (C) 2004-2006, 2008  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.136.18.21 2008/10/24 01:28:08 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/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 assetion 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:u:vx:")) != -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 'u':
450                         ns_g_username = isc_commandline_argument;
451                         break;
452                 case 'v':
453                         printf("BIND %s\n", ns_g_version);
454                         exit(0);
455                 case '?':
456                         usage();
457                         ns_main_earlyfatal("unknown option '-%c'",
458                                            isc_commandline_option);
459                 default:
460                         ns_main_earlyfatal("parsing options returned %d", ch);
461                 }
462         }
463
464         argc -= isc_commandline_index;
465         argv += isc_commandline_index;
466
467         if (argc > 0) {
468                 usage();
469                 ns_main_earlyfatal("extra command line arguments");
470         }
471 }
472
473 static isc_result_t
474 create_managers(void) {
475         isc_result_t result;
476         unsigned int socks;
477
478 #ifdef ISC_PLATFORM_USETHREADS
479         if (ns_g_cpus == 0)
480                 ns_g_cpus = ns_g_cpus_detected;
481         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
482                       ISC_LOG_INFO, "found %u CPU%s, using %u worker thread%s",
483                       ns_g_cpus_detected, ns_g_cpus_detected == 1 ? "" : "s",
484                       ns_g_cpus, ns_g_cpus == 1 ? "" : "s");
485 #else
486         ns_g_cpus = 1;
487 #endif
488         result = isc_taskmgr_create(ns_g_mctx, ns_g_cpus, 0, &ns_g_taskmgr);
489         if (result != ISC_R_SUCCESS) {
490                 UNEXPECTED_ERROR(__FILE__, __LINE__,
491                                  "isc_taskmgr_create() failed: %s",
492                                  isc_result_totext(result));
493                 return (ISC_R_UNEXPECTED);
494         }
495
496         result = isc_timermgr_create(ns_g_mctx, &ns_g_timermgr);
497         if (result != ISC_R_SUCCESS) {
498                 UNEXPECTED_ERROR(__FILE__, __LINE__,
499                                  "isc_timermgr_create() failed: %s",
500                                  isc_result_totext(result));
501                 return (ISC_R_UNEXPECTED);
502         }
503
504         result = isc_socketmgr_create2(ns_g_mctx, &ns_g_socketmgr, maxsocks);
505         if (result != ISC_R_SUCCESS) {
506                 UNEXPECTED_ERROR(__FILE__, __LINE__,
507                                  "isc_socketmgr_create() failed: %s",
508                                  isc_result_totext(result));
509                 return (ISC_R_UNEXPECTED);
510         }
511         result = isc_socketmgr_getmaxsockets(ns_g_socketmgr, &socks);
512         if (result == ISC_R_SUCCESS) {
513                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
514                               NS_LOGMODULE_SERVER,
515                               ISC_LOG_INFO, "using up to %u sockets", socks);
516         }
517
518         result = isc_entropy_create(ns_g_mctx, &ns_g_entropy);
519         if (result != ISC_R_SUCCESS) {
520                 UNEXPECTED_ERROR(__FILE__, __LINE__,
521                                  "isc_entropy_create() failed: %s",
522                                  isc_result_totext(result));
523                 return (ISC_R_UNEXPECTED);
524         }
525
526         result = isc_hash_create(ns_g_mctx, ns_g_entropy, DNS_NAME_MAXWIRE);
527         if (result != ISC_R_SUCCESS) {
528                 UNEXPECTED_ERROR(__FILE__, __LINE__,
529                                  "isc_hash_create() failed: %s",
530                                  isc_result_totext(result));
531                 return (ISC_R_UNEXPECTED);
532         }
533
534         return (ISC_R_SUCCESS);
535 }
536
537 static void
538 destroy_managers(void) {
539         ns_lwresd_shutdown();
540
541         isc_entropy_detach(&ns_g_entropy);
542         if (ns_g_fallbackentropy != NULL)
543                 isc_entropy_detach(&ns_g_fallbackentropy);
544
545         /*
546          * isc_taskmgr_destroy() will block until all tasks have exited,
547          */
548         isc_taskmgr_destroy(&ns_g_taskmgr);
549         isc_timermgr_destroy(&ns_g_timermgr);
550         isc_socketmgr_destroy(&ns_g_socketmgr);
551
552         /*
553          * isc_hash_destroy() cannot be called as long as a resolver may be
554          * running.  Calling this after isc_taskmgr_destroy() ensures the
555          * call is safe.
556          */
557         isc_hash_destroy();
558 }
559
560 static void
561 setup(void) {
562         isc_result_t result;
563         isc_resourcevalue_t old_openfiles;
564 #ifdef HAVE_LIBSCF
565         char *instance = NULL;
566 #endif
567
568         /*
569          * Get the user and group information before changing the root
570          * directory, so the administrator does not need to keep a copy
571          * of the user and group databases in the chroot'ed environment.
572          */
573         ns_os_inituserinfo(ns_g_username);
574
575         /*
576          * Initialize time conversion information
577          */
578         ns_os_tzset();
579
580         ns_os_opendevnull();
581
582 #ifdef HAVE_LIBSCF
583         /* Check if named is under smf control, before chroot. */
584         result = ns_smf_get_instance(&instance, 0, ns_g_mctx);
585         /* We don't care about instance, just check if we got one. */
586         if (result == ISC_R_SUCCESS)
587                 ns_smf_got_instance = 1;
588         else
589                 ns_smf_got_instance = 0;
590         if (instance != NULL)
591                 isc_mem_free(ns_g_mctx, instance);
592 #endif /* HAVE_LIBSCF */
593
594 #ifdef PATH_RANDOMDEV
595         /*
596          * Initialize system's random device as fallback entropy source
597          * if running chroot'ed.
598          */
599         if (ns_g_chrootdir != NULL) {
600                 result = isc_entropy_create(ns_g_mctx, &ns_g_fallbackentropy);
601                 if (result != ISC_R_SUCCESS)
602                         ns_main_earlyfatal("isc_entropy_create() failed: %s",
603                                            isc_result_totext(result));
604
605                 result = isc_entropy_createfilesource(ns_g_fallbackentropy,
606                                                       PATH_RANDOMDEV);
607                 if (result != ISC_R_SUCCESS) {
608                         ns_main_earlywarning("could not open pre-chroot "
609                                              "entropy source %s: %s",
610                                              PATH_RANDOMDEV,
611                                              isc_result_totext(result));
612                         isc_entropy_detach(&ns_g_fallbackentropy);
613                 }
614         }
615 #endif
616
617 #ifdef ISC_PLATFORM_USETHREADS
618         /*
619          * Check for the number of cpu's before ns_os_chroot().
620          */
621         ns_g_cpus_detected = isc_os_ncpus();
622 #endif
623
624         ns_os_chroot(ns_g_chrootdir);
625
626         /*
627          * For operating systems which have a capability mechanism, now
628          * is the time to switch to minimal privs and change our user id.
629          * On traditional UNIX systems, this call will be a no-op, and we
630          * will change the user ID after reading the config file the first
631          * time.  (We need to read the config file to know which possibly
632          * privileged ports to bind() to.)
633          */
634         ns_os_minprivs();
635
636         result = ns_log_init(ISC_TF(ns_g_username != NULL));
637         if (result != ISC_R_SUCCESS)
638                 ns_main_earlyfatal("ns_log_init() failed: %s",
639                                    isc_result_totext(result));
640
641         /*
642          * Now is the time to daemonize (if we're not running in the
643          * foreground).  We waited until now because we wanted to get
644          * a valid logging context setup.  We cannot daemonize any later,
645          * because calling create_managers() will create threads, which
646          * would be lost after fork().
647          */
648         if (!ns_g_foreground)
649                 ns_os_daemonize();
650
651         /*
652          * We call isc_app_start() here as some versions of FreeBSD's fork()
653          * destroys all the signal handling it sets up.
654          */
655         result = isc_app_start();
656         if (result != ISC_R_SUCCESS)
657                 ns_main_earlyfatal("isc_app_start() failed: %s",
658                                    isc_result_totext(result));
659
660         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
661                       ISC_LOG_NOTICE, "starting BIND %s%s", ns_g_version,
662                       saved_command_line);
663
664         /*
665          * Get the initial resource limits.
666          */
667         (void)isc_resource_getlimit(isc_resource_stacksize,
668                                     &ns_g_initstacksize);
669         (void)isc_resource_getlimit(isc_resource_datasize,
670                                     &ns_g_initdatasize);
671         (void)isc_resource_getlimit(isc_resource_coresize,
672                                     &ns_g_initcoresize);
673         (void)isc_resource_getlimit(isc_resource_openfiles,
674                                     &ns_g_initopenfiles);
675
676         /*
677          * System resources cannot effectively be tuned on some systems.
678          * Raise the limit in such cases for safety.
679          */
680         old_openfiles = ns_g_initopenfiles;
681         ns_os_adjustnofile();
682         (void)isc_resource_getlimit(isc_resource_openfiles,
683                                     &ns_g_initopenfiles);
684         if (old_openfiles != ns_g_initopenfiles) {
685                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
686                               NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
687                               "adjusted limit on open files from "
688                               "%" ISC_PRINT_QUADFORMAT "u to "
689                               "%" ISC_PRINT_QUADFORMAT "u",
690                               old_openfiles, ns_g_initopenfiles);
691         }
692
693         /*
694          * If the named configuration filename is relative, prepend the current
695          * directory's name before possibly changing to another directory.
696          */
697         if (! isc_file_isabsolute(ns_g_conffile)) {
698                 result = isc_file_absolutepath(ns_g_conffile,
699                                                absolute_conffile,
700                                                sizeof(absolute_conffile));
701                 if (result != ISC_R_SUCCESS)
702                         ns_main_earlyfatal("could not construct absolute path of "
703                                            "configuration file: %s",
704                                            isc_result_totext(result));
705                 ns_g_conffile = absolute_conffile;
706         }
707
708         result = create_managers();
709         if (result != ISC_R_SUCCESS)
710                 ns_main_earlyfatal("create_managers() failed: %s",
711                                    isc_result_totext(result));
712
713         ns_builtin_init();
714
715         /*
716          * Add calls to register sdb drivers here.
717          */
718         /* xxdb_init(); */
719
720 #ifdef DLZ
721         /*
722          * Registyer any DLZ drivers.
723          */
724         result = dlz_drivers_init();
725         if (result != ISC_R_SUCCESS)
726                 ns_main_earlyfatal("dlz_drivers_init() failed: %s",
727                                    isc_result_totext(result));
728 #endif
729
730         ns_server_create(ns_g_mctx, &ns_g_server);
731 }
732
733 static void
734 cleanup(void) {
735         destroy_managers();
736
737         ns_server_destroy(&ns_g_server);
738
739         ns_builtin_deinit();
740
741         /*
742          * Add calls to unregister sdb drivers here.
743          */
744         /* xxdb_clear(); */
745
746 #ifdef DLZ
747         /*
748          * Unregister any DLZ drivers.
749          */
750         dlz_drivers_clear();
751 #endif
752
753         dns_name_destroy();
754
755         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
756                       ISC_LOG_NOTICE, "exiting");
757         ns_log_shutdown();
758 }
759
760 static char *memstats = NULL;
761
762 void
763 ns_main_setmemstats(const char *filename) {
764         /*
765          * Caller has to ensure locking.
766          */
767
768         if (memstats != NULL) {
769                 free(memstats);
770                 memstats = NULL;
771         }
772         if (filename == NULL)
773                 return;
774         memstats = malloc(strlen(filename) + 1);
775         if (memstats)
776                 strcpy(memstats, filename);
777 }
778
779 #ifdef HAVE_LIBSCF
780 /*
781  * Get FMRI for the named process.
782  */
783 isc_result_t
784 ns_smf_get_instance(char **ins_name, int debug, isc_mem_t *mctx) {
785         scf_handle_t *h = NULL;
786         int namelen;
787         char *instance;
788
789         REQUIRE(ins_name != NULL && *ins_name == NULL);
790
791         if ((h = scf_handle_create(SCF_VERSION)) == NULL) {
792                 if (debug)
793                         UNEXPECTED_ERROR(__FILE__, __LINE__,
794                                          "scf_handle_create() failed: %s",
795                                          scf_strerror(scf_error()));
796                 return (ISC_R_FAILURE);
797         }
798
799         if (scf_handle_bind(h) == -1) {
800                 if (debug)
801                         UNEXPECTED_ERROR(__FILE__, __LINE__,
802                                          "scf_handle_bind() failed: %s",
803                                          scf_strerror(scf_error()));
804                 scf_handle_destroy(h);
805                 return (ISC_R_FAILURE);
806         }
807
808         if ((namelen = scf_myname(h, NULL, 0)) == -1) {
809                 if (debug)
810                         UNEXPECTED_ERROR(__FILE__, __LINE__,
811                                          "scf_myname() failed: %s",
812                                          scf_strerror(scf_error()));
813                 scf_handle_destroy(h);
814                 return (ISC_R_FAILURE);
815         }
816
817         if ((instance = isc_mem_allocate(mctx, namelen + 1)) == NULL) {
818                 UNEXPECTED_ERROR(__FILE__, __LINE__,
819                                  "ns_smf_get_instance memory "
820                                  "allocation failed: %s",
821                                  isc_result_totext(ISC_R_NOMEMORY));
822                 scf_handle_destroy(h);
823                 return (ISC_R_FAILURE);
824         }
825
826         if (scf_myname(h, instance, namelen + 1) == -1) {
827                 if (debug)
828                         UNEXPECTED_ERROR(__FILE__, __LINE__,
829                                          "scf_myname() failed: %s",
830                                          scf_strerror(scf_error()));
831                 scf_handle_destroy(h);
832                 isc_mem_free(mctx, instance);
833                 return (ISC_R_FAILURE);
834         }
835
836         scf_handle_destroy(h);
837         *ins_name = instance;
838         return (ISC_R_SUCCESS);
839 }
840 #endif /* HAVE_LIBSCF */
841
842 int
843 main(int argc, char *argv[]) {
844         isc_result_t result;
845 #ifdef HAVE_LIBSCF
846         char *instance = NULL;
847 #endif
848
849         /*
850          * Record version in core image.
851          * strings named.core | grep "named version:"
852          */
853         strlcat(version,
854 #ifdef __DATE__
855                 "named version: BIND " VERSION " (" __DATE__ ")",
856 #else
857                 "named version: BIND " VERSION,
858 #endif
859                 sizeof(version));
860         result = isc_file_progname(*argv, program_name, sizeof(program_name));
861         if (result != ISC_R_SUCCESS)
862                 ns_main_earlyfatal("program name too long");
863
864         if (strcmp(program_name, "lwresd") == 0)
865                 ns_g_lwresdonly = ISC_TRUE;
866
867         isc_assertion_setcallback(assertion_failed);
868         isc_error_setfatal(library_fatal_error);
869         isc_error_setunexpected(library_unexpected_error);
870
871         ns_os_init(program_name);
872
873         dns_result_register();
874         dst_result_register();
875         isccc_result_register();
876
877         parse_command_line(argc, argv);
878
879         /*
880          * Warn about common configuration error.
881          */
882         if (ns_g_chrootdir != NULL) {
883                 int len = strlen(ns_g_chrootdir);
884                 if (strncmp(ns_g_chrootdir, ns_g_conffile, len) == 0 &&
885                     (ns_g_conffile[len] == '/' || ns_g_conffile[len] == '\\'))
886                         ns_main_earlywarning("config filename (-c %s) contains "
887                                              "chroot path (-t %s)",
888                                              ns_g_conffile, ns_g_chrootdir);
889         }
890
891         result = isc_mem_create(0, 0, &ns_g_mctx);
892         if (result != ISC_R_SUCCESS)
893                 ns_main_earlyfatal("isc_mem_create() failed: %s",
894                                    isc_result_totext(result));
895
896         setup();
897
898         /*
899          * Start things running and then wait for a shutdown request
900          * or reload.
901          */
902         do {
903                 result = isc_app_run();
904
905                 if (result == ISC_R_RELOAD) {
906                         ns_server_reloadwanted(ns_g_server);
907                 } else if (result != ISC_R_SUCCESS) {
908                         UNEXPECTED_ERROR(__FILE__, __LINE__,
909                                          "isc_app_run(): %s",
910                                          isc_result_totext(result));
911                         /*
912                          * Force exit.
913                          */
914                         result = ISC_R_SUCCESS;
915                 }
916         } while (result != ISC_R_SUCCESS);
917
918 #ifdef HAVE_LIBSCF
919         if (ns_smf_want_disable == 1) {
920                 result = ns_smf_get_instance(&instance, 1, ns_g_mctx);
921                 if (result == ISC_R_SUCCESS && instance != NULL) {
922                         if (smf_disable_instance(instance, 0) != 0)
923                                 UNEXPECTED_ERROR(__FILE__, __LINE__,
924                                                  "smf_disable_instance() "
925                                                  "failed for %s : %s",
926                                                  instance,
927                                                  scf_strerror(scf_error()));
928                 }
929                 if (instance != NULL)
930                         isc_mem_free(ns_g_mctx, instance);
931         }
932 #endif /* HAVE_LIBSCF */
933
934         cleanup();
935
936         if (want_stats) {
937                 isc_mem_stats(ns_g_mctx, stdout);
938                 isc_mutex_stats(stdout);
939         }
940         if (memstats != NULL) {
941                 FILE *fp = NULL;
942                 result = isc_stdio_open(memstats, "w", &fp);
943                 if (result == ISC_R_SUCCESS) {
944                         isc_mem_stats(ns_g_mctx, fp);
945                         isc_mutex_stats(fp);
946                         isc_stdio_close(fp);
947                 }
948         }
949         isc_mem_destroy(&ns_g_mctx);
950         isc_mem_checkdestroyed(stderr);
951
952         ns_main_setmemstats(NULL);
953
954         isc_app_finish();
955
956         ns_os_closedevnull();
957
958         ns_os_shutdown();
959
960         return (0);
961 }