update the readme files for bind-9.3.4 import
[dragonfly.git] / contrib / bind-9.2.4rc7 / bin / named / main.c
1 /*
2  * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* $Id: main.c,v 1.119.2.10 2004/04/20 13:54:17 marka Exp $ */
19
20 #include <config.h>
21
22 #include <ctype.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include <isc/app.h>
27 #include <isc/commandline.h>
28 #include <isc/dir.h>
29 #include <isc/entropy.h>
30 #include <isc/file.h>
31 #include <isc/hash.h>
32 #include <isc/os.h>
33 #include <isc/platform.h>
34 #include <isc/resource.h>
35 #include <isc/task.h>
36 #include <isc/timer.h>
37 #include <isc/util.h>
38
39 #include <isccc/result.h>
40
41 #include <dns/dispatch.h>
42 #include <dns/name.h>
43 #include <dns/result.h>
44 #include <dns/view.h>
45
46 #include <dst/result.h>
47
48 /*
49  * Defining NS_MAIN provides storage declarations (rather than extern)
50  * for variables in named/globals.h.
51  */
52 #define NS_MAIN 1
53
54 #include <named/control.h>
55 #include <named/globals.h>      /* Explicit, though named/log.h includes it. */
56 #include <named/interfacemgr.h>
57 #include <named/log.h>
58 #include <named/os.h>
59 #include <named/server.h>
60 #include <named/lwresd.h>
61 #include <named/main.h>
62
63 /*
64  * Include header files for database drivers here.
65  */
66 /* #include "xxdb.h" */
67
68 static isc_boolean_t    want_stats = ISC_FALSE;
69 static char             program_name[ISC_DIR_NAMEMAX] = "named";
70 static char             absolute_conffile[ISC_DIR_PATHMAX];
71 static char             saved_command_line[512];
72 static char             version[512];
73
74 void
75 ns_main_earlywarning(const char *format, ...) {
76         va_list args;
77
78         va_start(args, format);
79         if (ns_g_lctx != NULL) {
80                 isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
81                                NS_LOGMODULE_MAIN, ISC_LOG_WARNING,
82                                format, args);
83         } else {
84                 fprintf(stderr, "%s: ", program_name);
85                 vfprintf(stderr, format, args);
86                 fprintf(stderr, "\n");
87                 fflush(stderr);
88         }
89         va_end(args);
90 }
91
92 void
93 ns_main_earlyfatal(const char *format, ...) {
94         va_list args;
95
96         va_start(args, format);
97         if (ns_g_lctx != NULL) {
98                 isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
99                                NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
100                                format, args);
101                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
102                                NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
103                                "exiting (due to early fatal error)");
104         } else {
105                 fprintf(stderr, "%s: ", program_name);
106                 vfprintf(stderr, format, args);
107                 fprintf(stderr, "\n");
108                 fflush(stderr);
109         }
110         va_end(args);
111
112         exit(1);
113 }
114
115 static void
116 assertion_failed(const char *file, int line, isc_assertiontype_t type,
117                  const char *cond)
118 {
119         /*
120          * Handle assertion failures.
121          */
122
123         if (ns_g_lctx != NULL) {
124                 /*
125                  * Reset the assetion callback in case it is the log
126                  * routines causing the assertion.
127                  */
128                 isc_assertion_setcallback(NULL);
129
130                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
131                               NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
132                               "%s:%d: %s(%s) failed", file, line,
133                               isc_assertion_typetotext(type), cond);
134                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
135                               NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
136                               "exiting (due to assertion failure)");
137         } else {
138                 fprintf(stderr, "%s:%d: %s(%s) failed\n",
139                         file, line, isc_assertion_typetotext(type), cond);
140                 fflush(stderr);
141         }
142
143         if (ns_g_coreok)
144                 abort();
145         exit(1);
146 }
147
148 static void
149 library_fatal_error(const char *file, int line, const char *format,
150                     va_list args) ISC_FORMAT_PRINTF(3, 0);
151
152 static void
153 library_fatal_error(const char *file, int line, const char *format,
154                     va_list args)
155 {
156         /*
157          * Handle isc_error_fatal() calls from our libraries.
158          */
159
160         if (ns_g_lctx != NULL) {
161                 /*
162                  * Reset the error callback in case it is the log
163                  * routines causing the assertion.
164                  */
165                 isc_error_setfatal(NULL);
166
167                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
168                               NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
169                               "%s:%d: fatal error:", file, line);
170                 isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
171                                NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
172                                format, args);
173                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
174                               NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
175                               "exiting (due to fatal error in library)");
176         } else {
177                 fprintf(stderr, "%s:%d: fatal error: ", file, line);
178                 vfprintf(stderr, format, args);
179                 fprintf(stderr, "\n");
180                 fflush(stderr);
181         }
182
183         if (ns_g_coreok)
184                 abort();
185         exit(1);
186 }
187
188 static void
189 library_unexpected_error(const char *file, int line, const char *format,
190                          va_list args) ISC_FORMAT_PRINTF(3, 0);
191
192 static void
193 library_unexpected_error(const char *file, int line, const char *format,
194                          va_list args)
195 {
196         /*
197          * Handle isc_error_unexpected() calls from our libraries.
198          */
199
200         if (ns_g_lctx != NULL) {
201                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
202                               NS_LOGMODULE_MAIN, ISC_LOG_ERROR,
203                               "%s:%d: unexpected error:", file, line);
204                 isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
205                                NS_LOGMODULE_MAIN, ISC_LOG_ERROR,
206                                format, args);
207         } else {
208                 fprintf(stderr, "%s:%d: fatal error: ", file, line);
209                 vfprintf(stderr, format, args);
210                 fprintf(stderr, "\n");
211                 fflush(stderr);
212         }
213 }
214
215 static void
216 lwresd_usage(void) {
217         fprintf(stderr,
218                 "usage: lwresd [-c conffile | -C resolvconffile] "
219                 "[-d debuglevel] [-f|-g]\n"
220                 "              [-n number_of_cpus] [-p port]"
221                 "[-P listen-port] [-s]\n"
222                 "              [-t chrootdir] [-u username] [-i pidfile]\n");
223 }
224
225 static void
226 usage(void) {
227         if (ns_g_lwresdonly) {
228                 lwresd_usage();
229                 return;
230         }
231         fprintf(stderr,
232                 "usage: named [-c conffile] [-d debuglevel] "
233                 "[-f|-g] [-n number_of_cpus]\n"
234                 "             [-p port] [-s] [-t chrootdir] [-u username]\n");
235 }
236
237 static void
238 save_command_line(int argc, char *argv[]) {
239         int i;
240         char *src;
241         char *dst;
242         char *eob;
243         const char truncated[] = "...";
244         isc_boolean_t quoted = ISC_FALSE;
245
246         dst = saved_command_line;
247         eob = saved_command_line + sizeof(saved_command_line);
248
249         for (i = 1; i < argc && dst < eob; i++) {
250                 *dst++ = ' ';
251
252                 src = argv[i];
253                 while (*src != '\0' && dst < eob) {
254                         /*
255                          * This won't perfectly produce a shell-independent
256                          * pastable command line in all circumstances, but
257                          * comes close, and for practical purposes will
258                          * nearly always be fine.
259                          */
260                         if (quoted || isalnum(*src & 0xff) ||
261                             *src == '-' || *src == '_' ||
262                             *src == '.' || *src == '/') {
263                                 *dst++ = *src++;
264                                 quoted = ISC_FALSE;
265                         } else {
266                                 *dst++ = '\\';
267                                 quoted = ISC_TRUE;
268                         }
269                 }
270         }
271
272         INSIST(sizeof(saved_command_line) >= sizeof(truncated));
273
274         if (dst == eob)
275                 strcpy(eob - sizeof(truncated), truncated);
276         else
277                 *dst = '\0';
278 }
279
280 static int
281 parse_int(char *arg, const char *desc) {
282         char *endp;
283         int tmp;
284         long int ltmp;
285
286         ltmp = strtol(arg, &endp, 10);
287         tmp = (int) ltmp;
288         if (*endp != '\0')
289                 ns_main_earlyfatal("%s '%s' must be numeric", desc, arg);
290         if (tmp < 0 || tmp != ltmp)
291                 ns_main_earlyfatal("%s '%s' out of range", desc, arg);
292         return (tmp);
293 }
294
295 static void
296 parse_command_line(int argc, char *argv[]) {
297         int ch;
298         int port;
299
300         save_command_line(argc, argv);
301
302         isc_commandline_errprint = ISC_FALSE;
303         while ((ch = isc_commandline_parse(argc, argv,
304                                            "c:C:d:fgi:ln:N:p:P:st:u:vx:")) !=
305                -1) {
306                 switch (ch) {
307                 case 'c':
308                         ns_g_conffile = isc_commandline_argument;
309                         lwresd_g_conffile = isc_commandline_argument;
310                         if (lwresd_g_useresolvconf)
311                                 ns_main_earlyfatal("cannot specify -c and -C");
312                         ns_g_conffileset = ISC_TRUE;
313                         break;
314                 case 'C':
315                         lwresd_g_resolvconffile = isc_commandline_argument;
316                         if (ns_g_conffileset)
317                                 ns_main_earlyfatal("cannot specify -c and -C");
318                         lwresd_g_useresolvconf = ISC_TRUE;
319                         break;
320                 case 'd':
321                         ns_g_debuglevel = parse_int(isc_commandline_argument,
322                                                     "debug level");
323                         break;
324                 case 'f':
325                         ns_g_foreground = ISC_TRUE;
326                         break;
327                 case 'g':
328                         ns_g_foreground = ISC_TRUE;
329                         ns_g_logstderr = ISC_TRUE;
330                         break;
331                 /* XXXBEW -i should be removed */
332                 case 'i':
333                         lwresd_g_defaultpidfile = isc_commandline_argument;
334                         break;
335                 case 'l':
336                         ns_g_lwresdonly = ISC_TRUE;
337                         break;
338                 case 'N': /* Deprecated. */
339                 case 'n':
340                         ns_g_cpus = parse_int(isc_commandline_argument,
341                                               "number of cpus");
342                         if (ns_g_cpus == 0)
343                                 ns_g_cpus = 1;
344                         break;
345                 case 'p':
346                         port = parse_int(isc_commandline_argument, "port");
347                         if (port < 1 || port > 65535)
348                                 ns_main_earlyfatal("port '%s' out of range",
349                                                    isc_commandline_argument);
350                         ns_g_port = port;
351                         break;
352                 /* XXXBEW Should -P be removed? */
353                 case 'P':
354                         port = parse_int(isc_commandline_argument, "port");
355                         if (port < 1 || port > 65535)
356                                 ns_main_earlyfatal("port '%s' out of range",
357                                                    isc_commandline_argument);
358                         lwresd_g_listenport = port;
359                         break;
360                 case 's':
361                         /* XXXRTH temporary syntax */
362                         want_stats = ISC_TRUE;
363                         break;
364                 case 't':
365                         /* XXXJAB should we make a copy? */
366                         ns_g_chrootdir = isc_commandline_argument;
367                         break;
368                 case 'u':
369                         ns_g_username = isc_commandline_argument;
370                         break;
371                 case 'v':
372                         printf("BIND %s\n", ns_g_version);
373                         exit(0);
374                 case '?':
375                         usage();
376                         ns_main_earlyfatal("unknown option '-%c'",
377                                            isc_commandline_option);
378                 default:
379                         ns_main_earlyfatal("parsing options returned %d", ch);
380                 }
381         }
382
383         argc -= isc_commandline_index;
384         argv += isc_commandline_index;
385
386         if (argc > 0) {
387                 usage();
388                 ns_main_earlyfatal("extra command line arguments");
389         }
390
391         
392 }
393
394 static isc_result_t
395 create_managers(void) {
396         isc_result_t result;
397
398 #ifdef ISC_PLATFORM_USETHREADS
399         if (ns_g_cpus == 0)
400                 ns_g_cpus = isc_os_ncpus();
401 #else
402         ns_g_cpus = 1;
403 #endif
404         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
405                       ISC_LOG_INFO, "using %u CPU%s",
406                       ns_g_cpus, ns_g_cpus == 1 ? "" : "s");
407         result = isc_taskmgr_create(ns_g_mctx, ns_g_cpus, 0, &ns_g_taskmgr);
408         if (result != ISC_R_SUCCESS) {
409                 UNEXPECTED_ERROR(__FILE__, __LINE__,
410                                  "ns_taskmgr_create() failed: %s",
411                                  isc_result_totext(result));
412                 return (ISC_R_UNEXPECTED);
413         }
414
415         result = isc_timermgr_create(ns_g_mctx, &ns_g_timermgr);
416         if (result != ISC_R_SUCCESS) {
417                 UNEXPECTED_ERROR(__FILE__, __LINE__,
418                                  "ns_timermgr_create() failed: %s",
419                                  isc_result_totext(result));
420                 return (ISC_R_UNEXPECTED);
421         }
422
423         result = isc_socketmgr_create(ns_g_mctx, &ns_g_socketmgr);
424         if (result != ISC_R_SUCCESS) {
425                 UNEXPECTED_ERROR(__FILE__, __LINE__,
426                                  "isc_socketmgr_create() failed: %s",
427                                  isc_result_totext(result));
428                 return (ISC_R_UNEXPECTED);
429         }
430
431         result = isc_entropy_create(ns_g_mctx, &ns_g_entropy);
432         if (result != ISC_R_SUCCESS) {
433                 UNEXPECTED_ERROR(__FILE__, __LINE__,
434                                  "isc_entropy_create() failed: %s",
435                                  isc_result_totext(result));
436                 return (ISC_R_UNEXPECTED);
437         }
438
439         result = isc_hash_create(ns_g_mctx, ns_g_entropy, DNS_NAME_MAXWIRE);
440         if (result != ISC_R_SUCCESS) {
441                 UNEXPECTED_ERROR(__FILE__, __LINE__,
442                                  "isc_hash_create() failed: %s",
443                                  isc_result_totext(result));
444                 return (ISC_R_UNEXPECTED);
445         }
446
447         return (ISC_R_SUCCESS);
448 }
449
450 static void
451 destroy_managers(void) {
452         ns_lwresd_shutdown();
453
454         isc_entropy_detach(&ns_g_entropy);
455         /*
456          * isc_taskmgr_destroy() will block until all tasks have exited,
457          */
458         isc_taskmgr_destroy(&ns_g_taskmgr);
459         isc_timermgr_destroy(&ns_g_timermgr);
460         isc_socketmgr_destroy(&ns_g_socketmgr);
461
462         /*
463          * isc_hash_destroy() cannot be called as long as a resolver may be
464          * running.  Calling this after isc_taskmgr_destroy() ensures the
465          * call is safe.
466          */
467         isc_hash_destroy();
468 }
469
470 static void
471 setup(void) {
472         isc_result_t result;
473
474         /*
475          * Get the user and group information before changing the root
476          * directory, so the administrator does not need to keep a copy
477          * of the user and group databases in the chroot'ed environment.
478          */
479         ns_os_inituserinfo(ns_g_username);
480
481         /*
482          * Initialize time conversion information
483          */
484         ns_os_tzset();
485
486         ns_os_opendevnull();
487
488         ns_os_chroot(ns_g_chrootdir);
489
490         /*
491          * For operating systems which have a capability mechanism, now
492          * is the time to switch to minimal privs and change our user id.
493          * On traditional UNIX systems, this call will be a no-op, and we
494          * will change the user ID after reading the config file the first
495          * time.  (We need to read the config file to know which possibly
496          * privileged ports to bind() to.)
497          */
498         ns_os_minprivs();
499
500         result = ns_log_init(ISC_TF(ns_g_username != NULL));
501         if (result != ISC_R_SUCCESS)
502                 ns_main_earlyfatal("ns_log_init() failed: %s",
503                                    isc_result_totext(result));
504
505         /*
506          * Now is the time to daemonize (if we're not running in the
507          * foreground).  We waited until now because we wanted to get
508          * a valid logging context setup.  We cannot daemonize any later,
509          * because calling create_managers() will create threads, which
510          * would be lost after fork().
511          */
512         if (!ns_g_foreground)
513                 ns_os_daemonize();
514
515         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
516                       ISC_LOG_NOTICE, "starting BIND %s%s", ns_g_version,
517                       saved_command_line);
518
519         /*
520          * Get the initial resource limits.
521          */
522         (void)isc_resource_getlimit(isc_resource_stacksize,
523                                     &ns_g_initstacksize);
524         (void)isc_resource_getlimit(isc_resource_datasize,
525                                     &ns_g_initdatasize);
526         (void)isc_resource_getlimit(isc_resource_coresize,
527                                     &ns_g_initcoresize);
528         (void)isc_resource_getlimit(isc_resource_openfiles,
529                                     &ns_g_initopenfiles);
530
531         /*
532          * If the named configuration filename is relative, prepend the current
533          * directory's name before possibly changing to another directory.
534          */
535         if (! isc_file_isabsolute(ns_g_conffile)) {
536                 result = isc_file_absolutepath(ns_g_conffile,
537                                                absolute_conffile,
538                                                sizeof(absolute_conffile));
539                 if (result != ISC_R_SUCCESS)
540                         ns_main_earlyfatal("could not construct absolute path of "
541                                            "configuration file: %s", 
542                                            isc_result_totext(result));
543                 ns_g_conffile = absolute_conffile;
544         }
545
546         result = create_managers();
547         if (result != ISC_R_SUCCESS)
548                 ns_main_earlyfatal("create_managers() failed: %s",
549                                    isc_result_totext(result));
550
551         /*
552          * Add calls to register sdb drivers here.
553          */
554         /* xxdb_init(); */
555
556         ns_server_create(ns_g_mctx, &ns_g_server);
557 }
558
559 static void
560 cleanup(void) {
561         destroy_managers();
562
563         ns_server_destroy(&ns_g_server);
564
565         /*
566          * Add calls to unregister sdb drivers here.
567          */
568         /* xxdb_clear(); */
569
570         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
571                       ISC_LOG_NOTICE, "exiting");
572         ns_log_shutdown();
573 }
574
575 int
576 main(int argc, char *argv[]) {
577         isc_result_t result;
578
579         /*
580          * Record version in core image.
581          * strings named.core | grep "named version:"
582          */
583 #ifdef __DATE__
584         strncat(version, "named version: BIND " VERSION " (" __DATE__ ")", 
585                 sizeof(version));
586 #else
587         strncat(version, "named version: BIND " VERSION, sizeof(version));
588 #endif
589         version[sizeof(version) - 1] = '\0';
590         result = isc_file_progname(*argv, program_name, sizeof(program_name));
591         if (result != ISC_R_SUCCESS)
592                 ns_main_earlyfatal("program name too long");
593
594         if (strcmp(program_name, "lwresd") == 0)
595                 ns_g_lwresdonly = ISC_TRUE;
596
597         isc_assertion_setcallback(assertion_failed);
598         isc_error_setfatal(library_fatal_error);
599         isc_error_setunexpected(library_unexpected_error);
600
601         ns_os_init(program_name);
602
603         result = isc_app_start();
604         if (result != ISC_R_SUCCESS)
605                 ns_main_earlyfatal("isc_app_start() failed: %s",
606                                    isc_result_totext(result));
607
608         result = isc_mem_create(0, 0, &ns_g_mctx);
609         if (result != ISC_R_SUCCESS)
610                 ns_main_earlyfatal("isc_mem_create() failed: %s",
611                                    isc_result_totext(result));
612
613         dns_result_register();
614         dst_result_register();
615         isccc_result_register();
616
617         parse_command_line(argc, argv);
618
619         setup();
620
621         /*
622          * Start things running and then wait for a shutdown request
623          * or reload.
624          */
625         do {
626                 result = isc_app_run();
627
628                 if (result == ISC_R_RELOAD) {
629                         ns_server_reloadwanted(ns_g_server);
630                 } else if (result != ISC_R_SUCCESS) {
631                         UNEXPECTED_ERROR(__FILE__, __LINE__,
632                                          "isc_app_run(): %s",
633                                          isc_result_totext(result));
634                         /*
635                          * Force exit.
636                          */
637                         result = ISC_R_SUCCESS;
638                 }
639         } while (result != ISC_R_SUCCESS);
640
641         cleanup();
642
643         if (want_stats) {
644                 isc_mem_stats(ns_g_mctx, stdout);
645                 isc_mutex_stats(stdout);
646         }
647         isc_mem_destroy(&ns_g_mctx);
648
649         isc_app_finish();
650
651         ns_os_closedevnull();
652
653         ns_os_shutdown();
654
655         return (0);
656 }