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