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