]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/bind9/bin/named/main.c
MFC r363988:
[FreeBSD/stable/9.git] / contrib / bind9 / bin / named / main.c
1 /*
2  * Copyright (C) 2004-2016  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 /*! \file */
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/backtrace.h>
28 #include <isc/commandline.h>
29 #include <isc/dir.h>
30 #include <isc/entropy.h>
31 #include <isc/file.h>
32 #include <isc/hash.h>
33 #include <isc/os.h>
34 #include <isc/platform.h>
35 #include <isc/print.h>
36 #include <isc/resource.h>
37 #include <isc/stdio.h>
38 #include <isc/string.h>
39 #include <isc/task.h>
40 #include <isc/timer.h>
41 #include <isc/util.h>
42
43 #include <isccc/result.h>
44
45 #include <dns/dispatch.h>
46 #include <dns/name.h>
47 #include <dns/result.h>
48 #include <dns/view.h>
49
50 #include <dst/result.h>
51
52 #include <dlz/dlz_dlopen_driver.h>
53
54 #ifdef HAVE_GPERFTOOLS_PROFILER
55 #include <gperftools/profiler.h>
56 #endif
57
58 /*
59  * Defining NS_MAIN provides storage declarations (rather than extern)
60  * for variables in named/globals.h.
61  */
62 #define NS_MAIN 1
63
64 #include <named/builtin.h>
65 #include <named/control.h>
66 #include <named/globals.h>      /* Explicit, though named/log.h includes it. */
67 #include <named/interfacemgr.h>
68 #include <named/log.h>
69 #include <named/os.h>
70 #include <named/server.h>
71 #include <named/lwresd.h>
72 #include <named/main.h>
73 #ifdef HAVE_LIBSCF
74 #include <named/ns_smf_globals.h>
75 #endif
76
77 #ifdef OPENSSL
78 #include <openssl/opensslv.h>
79 #include <openssl/crypto.h>
80 #endif
81 #ifdef HAVE_LIBXML2
82 #include <libxml/xmlversion.h>
83 #endif
84 /*
85  * Include header files for database drivers here.
86  */
87 /* #include "xxdb.h" */
88
89 #ifdef CONTRIB_DLZ
90 /*
91  * Include contributed DLZ drivers if appropriate.
92  */
93 #include <dlz/dlz_drivers.h>
94 #endif
95
96 /*
97  * The maximum number of stack frames to dump on assertion failure.
98  */
99 #ifndef BACKTRACE_MAXFRAME
100 #define BACKTRACE_MAXFRAME 128
101 #endif
102
103 extern unsigned int dns_zone_mkey_hour;
104 extern unsigned int dns_zone_mkey_day;
105 extern unsigned int dns_zone_mkey_month;
106
107 static isc_boolean_t    want_stats = ISC_FALSE;
108 static char             program_name[ISC_DIR_NAMEMAX] = "named";
109 static char             absolute_conffile[ISC_DIR_PATHMAX];
110 static char             saved_command_line[512];
111 static char             version[512];
112 static unsigned int     maxsocks = 0;
113 static int              maxudp = 0;
114
115 void
116 ns_main_earlywarning(const char *format, ...) {
117         va_list args;
118
119         va_start(args, format);
120         if (ns_g_lctx != NULL) {
121                 isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
122                                NS_LOGMODULE_MAIN, ISC_LOG_WARNING,
123                                format, args);
124         } else {
125                 fprintf(stderr, "%s: ", program_name);
126                 vfprintf(stderr, format, args);
127                 fprintf(stderr, "\n");
128                 fflush(stderr);
129         }
130         va_end(args);
131 }
132
133 void
134 ns_main_earlyfatal(const char *format, ...) {
135         va_list args;
136
137         va_start(args, format);
138         if (ns_g_lctx != NULL) {
139                 isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
140                                NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
141                                format, args);
142                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
143                                NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
144                                "exiting (due to early fatal error)");
145         } else {
146                 fprintf(stderr, "%s: ", program_name);
147                 vfprintf(stderr, format, args);
148                 fprintf(stderr, "\n");
149                 fflush(stderr);
150         }
151         va_end(args);
152
153         exit(1);
154 }
155
156 ISC_PLATFORM_NORETURN_PRE static void
157 assertion_failed(const char *file, int line, isc_assertiontype_t type,
158                  const char *cond) ISC_PLATFORM_NORETURN_POST;
159
160 static void
161 assertion_failed(const char *file, int line, isc_assertiontype_t type,
162                  const char *cond)
163 {
164         void *tracebuf[BACKTRACE_MAXFRAME];
165         int i, nframes;
166         isc_result_t result;
167         const char *logsuffix = "";
168         const char *fname;
169
170         /*
171          * Handle assertion failures.
172          */
173
174         if (ns_g_lctx != NULL) {
175                 /*
176                  * Reset the assertion callback in case it is the log
177                  * routines causing the assertion.
178                  */
179                 isc_assertion_setcallback(NULL);
180
181                 result = isc_backtrace_gettrace(tracebuf, BACKTRACE_MAXFRAME,
182                                                 &nframes);
183                 if (result == ISC_R_SUCCESS && nframes > 0)
184                         logsuffix = ", back trace";
185                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
186                               NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
187                               "%s:%d: %s(%s) failed%s", file, line,
188                               isc_assertion_typetotext(type), cond, logsuffix);
189                 if (result == ISC_R_SUCCESS) {
190                         for (i = 0; i < nframes; i++) {
191                                 unsigned long offset;
192
193                                 fname = NULL;
194                                 result = isc_backtrace_getsymbol(tracebuf[i],
195                                                                  &fname,
196                                                                  &offset);
197                                 if (result == ISC_R_SUCCESS) {
198                                         isc_log_write(ns_g_lctx,
199                                                       NS_LOGCATEGORY_GENERAL,
200                                                       NS_LOGMODULE_MAIN,
201                                                       ISC_LOG_CRITICAL,
202                                                       "#%d %p in %s()+0x%lx", i,
203                                                       tracebuf[i], fname,
204                                                       offset);
205                                 } else {
206                                         isc_log_write(ns_g_lctx,
207                                                       NS_LOGCATEGORY_GENERAL,
208                                                       NS_LOGMODULE_MAIN,
209                                                       ISC_LOG_CRITICAL,
210                                                       "#%d %p in ??", i,
211                                                       tracebuf[i]);
212                                 }
213                         }
214                 }
215                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
216                               NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
217                               "exiting (due to assertion failure)");
218         } else {
219                 fprintf(stderr, "%s:%d: %s(%s) failed\n",
220                         file, line, isc_assertion_typetotext(type), cond);
221                 fflush(stderr);
222         }
223
224         if (ns_g_coreok)
225                 abort();
226         exit(1);
227 }
228
229 ISC_PLATFORM_NORETURN_PRE static void
230 library_fatal_error(const char *file, int line, const char *format,
231                     va_list args)
232 ISC_FORMAT_PRINTF(3, 0) ISC_PLATFORM_NORETURN_POST;
233
234 static void
235 library_fatal_error(const char *file, int line, const char *format,
236                     va_list args)
237 {
238         /*
239          * Handle isc_error_fatal() calls from our libraries.
240          */
241
242         if (ns_g_lctx != NULL) {
243                 /*
244                  * Reset the error callback in case it is the log
245                  * routines causing the assertion.
246                  */
247                 isc_error_setfatal(NULL);
248
249                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
250                               NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
251                               "%s:%d: fatal error:", file, line);
252                 isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
253                                NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
254                                format, args);
255                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
256                               NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
257                               "exiting (due to fatal error in library)");
258         } else {
259                 fprintf(stderr, "%s:%d: fatal error: ", file, line);
260                 vfprintf(stderr, format, args);
261                 fprintf(stderr, "\n");
262                 fflush(stderr);
263         }
264
265         if (ns_g_coreok)
266                 abort();
267         exit(1);
268 }
269
270 static void
271 library_unexpected_error(const char *file, int line, const char *format,
272                          va_list args) ISC_FORMAT_PRINTF(3, 0);
273
274 static void
275 library_unexpected_error(const char *file, int line, const char *format,
276                          va_list args)
277 {
278         /*
279          * Handle isc_error_unexpected() calls from our libraries.
280          */
281
282         if (ns_g_lctx != NULL) {
283                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
284                               NS_LOGMODULE_MAIN, ISC_LOG_ERROR,
285                               "%s:%d: unexpected error:", file, line);
286                 isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
287                                NS_LOGMODULE_MAIN, ISC_LOG_ERROR,
288                                format, args);
289         } else {
290                 fprintf(stderr, "%s:%d: fatal error: ", file, line);
291                 vfprintf(stderr, format, args);
292                 fprintf(stderr, "\n");
293                 fflush(stderr);
294         }
295 }
296
297 static void
298 lwresd_usage(void) {
299         fprintf(stderr,
300                 "usage: lwresd [-4|-6] [-c conffile | -C resolvconffile] "
301                 "[-d debuglevel] [-f|-g]\n"
302                 "              [-i pidfile] [-n number_of_cpus] "
303                 "[-p port] [-P listen-port]\n"
304                 "              [-s] [-S sockets] [-t chrootdir] [-u username] "
305                 "[-U listeners]\n"
306                 "              [-m {usage|trace|record|size|mctx}]\n"
307                 "usage: lwresd [-v|-V]\n");
308 }
309
310 static void
311 usage(void) {
312         if (ns_g_lwresdonly) {
313                 lwresd_usage();
314                 return;
315         }
316         fprintf(stderr,
317                 "usage: named [-4|-6] [-c conffile] [-d debuglevel] "
318                 "[-E engine] [-f|-g]\n"
319                 "             [-n number_of_cpus] [-p port] [-s] "
320                 "[-S sockets] [-t chrootdir]\n"
321                 "             [-u username] [-U listeners] "
322                 "[-m {usage|trace|record|size|mctx}]\n"
323                 "usage: named [-v|-V]\n");
324 }
325
326 static void
327 save_command_line(int argc, char *argv[]) {
328         int i;
329         char *src;
330         char *dst;
331         char *eob;
332         const char truncated[] = "...";
333         isc_boolean_t quoted = ISC_FALSE;
334
335         dst = saved_command_line;
336         eob = saved_command_line + sizeof(saved_command_line);
337
338         for (i = 1; i < argc && dst < eob; i++) {
339                 *dst++ = ' ';
340
341                 src = argv[i];
342                 while (*src != '\0' && dst < eob) {
343                         /*
344                          * This won't perfectly produce a shell-independent
345                          * pastable command line in all circumstances, but
346                          * comes close, and for practical purposes will
347                          * nearly always be fine.
348                          */
349                         if (quoted || isalnum(*src & 0xff) ||
350                             *src == '-' || *src == '_' ||
351                             *src == '.' || *src == '/') {
352                                 *dst++ = *src++;
353                                 quoted = ISC_FALSE;
354                         } else {
355                                 *dst++ = '\\';
356                                 quoted = ISC_TRUE;
357                         }
358                 }
359         }
360
361         INSIST(sizeof(saved_command_line) >= sizeof(truncated));
362
363         if (dst == eob)
364                 strcpy(eob - sizeof(truncated), truncated);
365         else
366                 *dst = '\0';
367 }
368
369 static int
370 parse_int(char *arg, const char *desc) {
371         char *endp;
372         int tmp;
373         long int ltmp;
374
375         ltmp = strtol(arg, &endp, 10);
376         tmp = (int) ltmp;
377         if (*endp != '\0')
378                 ns_main_earlyfatal("%s '%s' must be numeric", desc, arg);
379         if (tmp < 0 || tmp != ltmp)
380                 ns_main_earlyfatal("%s '%s' out of range", desc, arg);
381         return (tmp);
382 }
383
384 static struct flag_def {
385         const char *name;
386         unsigned int value;
387 } mem_debug_flags[] = {
388         { "none", 0},
389         { "trace",  ISC_MEM_DEBUGTRACE },
390         { "record", ISC_MEM_DEBUGRECORD },
391         { "usage", ISC_MEM_DEBUGUSAGE },
392         { "size", ISC_MEM_DEBUGSIZE },
393         { "mctx", ISC_MEM_DEBUGCTX },
394         { NULL, 0 }
395 };
396
397 static void
398 set_flags(const char *arg, struct flag_def *defs, unsigned int *ret) {
399         isc_boolean_t clear = ISC_FALSE;
400
401         for (;;) {
402                 const struct flag_def *def;
403                 const char *end = strchr(arg, ',');
404                 int arglen;
405                 if (end == NULL)
406                         end = arg + strlen(arg);
407                 arglen = (int)(end - arg);
408                 for (def = defs; def->name != NULL; def++) {
409                         if (arglen == (int)strlen(def->name) &&
410                             memcmp(arg, def->name, arglen) == 0) {
411                                 if (def->value == 0)
412                                         clear = ISC_TRUE;
413                                 *ret |= def->value;
414                                 goto found;
415                         }
416                 }
417                 ns_main_earlyfatal("unrecognized flag '%.*s'", arglen, arg);
418          found:
419                 if (clear || (*end == '\0'))
420                         break;
421                 arg = end + 1;
422         }
423
424         if (clear)
425                 *ret = 0;
426 }
427
428 static void
429 parse_command_line(int argc, char *argv[]) {
430         int ch;
431         int port;
432         const char *p;
433
434         save_command_line(argc, argv);
435
436         /*
437          * NS_MAIN_ARGS is defined in main.h, so that it can be used
438          * both by named and by ntservice hooks.
439          */
440         isc_commandline_errprint = ISC_FALSE;
441         while ((ch = isc_commandline_parse(argc, argv, NS_MAIN_ARGS)) != -1) {
442                 switch (ch) {
443                 case '4':
444                         if (ns_g_disable4)
445                                 ns_main_earlyfatal("cannot specify -4 and -6");
446                         if (isc_net_probeipv4() != ISC_R_SUCCESS)
447                                 ns_main_earlyfatal("IPv4 not supported by OS");
448                         isc_net_disableipv6();
449                         ns_g_disable6 = ISC_TRUE;
450                         break;
451                 case '6':
452                         if (ns_g_disable6)
453                                 ns_main_earlyfatal("cannot specify -4 and -6");
454                         if (isc_net_probeipv6() != ISC_R_SUCCESS)
455                                 ns_main_earlyfatal("IPv6 not supported by OS");
456                         isc_net_disableipv4();
457                         ns_g_disable4 = ISC_TRUE;
458                         break;
459                 case 'c':
460                         ns_g_conffile = isc_commandline_argument;
461                         lwresd_g_conffile = isc_commandline_argument;
462                         if (lwresd_g_useresolvconf)
463                                 ns_main_earlyfatal("cannot specify -c and -C");
464                         ns_g_conffileset = ISC_TRUE;
465                         break;
466                 case 'C':
467                         lwresd_g_resolvconffile = isc_commandline_argument;
468                         if (ns_g_conffileset)
469                                 ns_main_earlyfatal("cannot specify -c and -C");
470                         lwresd_g_useresolvconf = ISC_TRUE;
471                         break;
472                 case 'd':
473                         ns_g_debuglevel = parse_int(isc_commandline_argument,
474                                                     "debug level");
475                         break;
476                 case 'E':
477                         ns_g_engine = isc_commandline_argument;
478                         break;
479                 case 'f':
480                         ns_g_foreground = ISC_TRUE;
481                         break;
482                 case 'g':
483                         ns_g_foreground = ISC_TRUE;
484                         ns_g_logstderr = ISC_TRUE;
485                         break;
486                 /* XXXBEW -i should be removed */
487                 case 'i':
488                         lwresd_g_defaultpidfile = isc_commandline_argument;
489                         break;
490                 case 'l':
491                         ns_g_lwresdonly = ISC_TRUE;
492                         break;
493                 case 'M':
494                         if (strcmp(isc_commandline_argument, "external") == 0)
495                                 isc_mem_defaultflags = 0;
496                         break;
497                 case 'm':
498                         set_flags(isc_commandline_argument, mem_debug_flags,
499                                   &isc_mem_debugging);
500                         break;
501                 case 'N': /* Deprecated. */
502                 case 'n':
503                         ns_g_cpus = parse_int(isc_commandline_argument,
504                                               "number of cpus");
505                         if (ns_g_cpus == 0)
506                                 ns_g_cpus = 1;
507                         break;
508                 case 'p':
509                         port = parse_int(isc_commandline_argument, "port");
510                         if (port < 1 || port > 65535)
511                                 ns_main_earlyfatal("port '%s' out of range",
512                                                    isc_commandline_argument);
513                         ns_g_port = port;
514                         break;
515                 /* XXXBEW Should -P be removed? */
516                 case 'P':
517                         port = parse_int(isc_commandline_argument, "port");
518                         if (port < 1 || port > 65535)
519                                 ns_main_earlyfatal("port '%s' out of range",
520                                                    isc_commandline_argument);
521                         lwresd_g_listenport = port;
522                         break;
523                 case 's':
524                         /* XXXRTH temporary syntax */
525                         want_stats = ISC_TRUE;
526                         break;
527                 case 'S':
528                         maxsocks = parse_int(isc_commandline_argument,
529                                              "max number of sockets");
530                         break;
531                 case 't':
532                         /* XXXJAB should we make a copy? */
533                         ns_g_chrootdir = isc_commandline_argument;
534                         break;
535                 case 'T':       /* NOT DOCUMENTED */
536                         /*
537                          * clienttest: make clients single shot with their
538                          *             own memory context.
539                          */
540                         if (!strcmp(isc_commandline_argument, "clienttest"))
541                                 ns_g_clienttest = ISC_TRUE;
542                         else if (!strcmp(isc_commandline_argument, "nosoa"))
543                                 ns_g_nosoa = ISC_TRUE;
544                         else if (!strcmp(isc_commandline_argument, "noaa"))
545                                 ns_g_noaa = ISC_TRUE;
546                         else if (!strcmp(isc_commandline_argument, "maxudp512"))
547                                 maxudp = 512;
548                         else if (!strcmp(isc_commandline_argument, "maxudp1460"))
549                                 maxudp = 1460;
550                         else if (!strcmp(isc_commandline_argument, "dropedns"))
551                                 ns_g_dropedns = ISC_TRUE;
552                         else if (!strcmp(isc_commandline_argument, "noedns"))
553                                 ns_g_noedns = ISC_TRUE;
554                         else if (!strncmp(isc_commandline_argument,
555                                           "maxudp=", 7))
556                                 maxudp = atoi(isc_commandline_argument + 7);
557                         else if (!strcmp(isc_commandline_argument, "nosyslog"))
558                                 ns_g_nosyslog = ISC_TRUE;
559                         else if (!strcmp(isc_commandline_argument, "nonearest"))
560                                 ns_g_nonearest = ISC_TRUE;
561                         else if (!strncmp(isc_commandline_argument,
562                                           "mkeytimers=", 11))
563                         {
564                                 p = strtok(isc_commandline_argument + 11, "/");
565                                 if (p == NULL)
566                                         ns_main_earlyfatal("bad mkeytimer");
567                                 dns_zone_mkey_hour = atoi(p);
568                                 if (dns_zone_mkey_hour == 0)
569                                         ns_main_earlyfatal("bad mkeytimer");
570
571                                 p = strtok(NULL, "/");
572                                 if (p == NULL) {
573                                         dns_zone_mkey_day =
574                                                 (24 * dns_zone_mkey_hour);
575                                         dns_zone_mkey_month =
576                                                 (30 * dns_zone_mkey_day);
577                                         break;
578                                 }
579                                 dns_zone_mkey_day = atoi(p);
580                                 if (dns_zone_mkey_day < dns_zone_mkey_hour)
581                                         ns_main_earlyfatal("bad mkeytimer");
582
583                                 p = strtok(NULL, "/");
584                                 if (p == NULL) {
585                                         dns_zone_mkey_month =
586                                                 (30 * dns_zone_mkey_day);
587                                         break;
588                                 }
589                                 dns_zone_mkey_month = atoi(p);
590                                 if (dns_zone_mkey_month < dns_zone_mkey_day)
591                                         ns_main_earlyfatal("bad mkeytimer");
592                         } else if (!strcmp(isc_commandline_argument, "notcp"))
593                                 ns_g_notcp = ISC_TRUE;
594                         else
595                                 fprintf(stderr, "unknown -T flag '%s\n",
596                                         isc_commandline_argument);
597                         break;
598                 case 'U':
599                         ns_g_udpdisp = parse_int(isc_commandline_argument,
600                                                  "number of UDP listeners "
601                                                  "per interface");
602                         break;
603                 case 'u':
604                         ns_g_username = isc_commandline_argument;
605                         break;
606                 case 'v':
607                         printf("%s %s%s%s <id:%s>\n",
608                                ns_g_product, ns_g_version,
609                                (*ns_g_description != '\0') ? " " : "",
610                                ns_g_description, ns_g_srcid);
611                         exit(0);
612                 case 'V':
613                         printf("%s %s%s%s <id:%s>\n", ns_g_product, ns_g_version,
614                                (*ns_g_description != '\0') ? " " : "",
615                                ns_g_description, ns_g_srcid);
616                         printf("running on %s\n", ns_os_uname());
617                         printf("built by %s with %s\n",
618                                ns_g_builder, ns_g_configargs);
619 #ifdef __clang__
620                         printf("compiled by CLANG %s\n", __VERSION__);
621 #else
622 #if defined(__ICC) || defined(__INTEL_COMPILER)
623                         printf("compiled by ICC %s\n", __VERSION__);
624 #else
625 #ifdef __GNUC__
626                         printf("compiled by GCC %s\n", __VERSION__);
627 #endif
628 #endif
629 #endif
630 #ifdef _MSC_VER
631                         printf("compiled by MSVC %d\n", _MSC_VER);
632 #endif
633 #ifdef __SUNPRO_C
634                         printf("compiled by Solaris Studio %x\n", __SUNPRO_C);
635 #endif
636 #ifdef OPENSSL
637                         printf("compiled with OpenSSL version: %s\n",
638                                OPENSSL_VERSION_TEXT);
639                         printf("linked to OpenSSL version: %s\n",
640                                SSLeay_version(SSLEAY_VERSION));
641 #endif
642 #ifdef HAVE_LIBXML2
643                         printf("compiled with libxml2 version: %s\n",
644                                LIBXML_DOTTED_VERSION);
645                         printf("linked to libxml2 version: %s\n",
646                                xmlParserVersion);
647 #endif
648                         exit(0);
649                 case 'F':
650                         /* Reserved for FIPS mode */
651                         /* FALLTHROUGH */
652                 case '?':
653                         usage();
654                         if (isc_commandline_option == '?')
655                                 exit(0);
656                         p = strchr(NS_MAIN_ARGS, isc_commandline_option);
657                         if (p == NULL || *++p != ':')
658                                 ns_main_earlyfatal("unknown option '-%c'",
659                                                    isc_commandline_option);
660                         else
661                                 ns_main_earlyfatal("option '-%c' requires "
662                                                    "an argument",
663                                                    isc_commandline_option);
664                         /* FALLTHROUGH */
665                 default:
666                         ns_main_earlyfatal("parsing options returned %d", ch);
667                 }
668         }
669
670         argc -= isc_commandline_index;
671         argv += isc_commandline_index;
672         POST(argv);
673
674         if (argc > 0) {
675                 usage();
676                 ns_main_earlyfatal("extra command line arguments");
677         }
678 }
679
680 static isc_result_t
681 create_managers(void) {
682         isc_result_t result;
683         unsigned int socks;
684
685         INSIST(ns_g_cpus_detected > 0);
686
687 #ifdef ISC_PLATFORM_USETHREADS
688         if (ns_g_cpus == 0)
689                 ns_g_cpus = ns_g_cpus_detected;
690         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
691                       ISC_LOG_INFO, "found %u CPU%s, using %u worker thread%s",
692                       ns_g_cpus_detected, ns_g_cpus_detected == 1 ? "" : "s",
693                       ns_g_cpus, ns_g_cpus == 1 ? "" : "s");
694 #else
695         ns_g_cpus = 1;
696 #endif
697 #ifdef WIN32
698         ns_g_udpdisp = 1;
699 #else
700         if (ns_g_udpdisp == 0) {
701                 if (ns_g_cpus_detected == 1)
702                         ns_g_udpdisp = 1;
703                 else
704                         ns_g_udpdisp = ns_g_cpus_detected - 1;
705         }
706         if (ns_g_udpdisp > ns_g_cpus)
707                 ns_g_udpdisp = ns_g_cpus;
708 #endif
709         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
710                       ISC_LOG_INFO, "using %u UDP listener%s per interface",
711                       ns_g_udpdisp, ns_g_udpdisp == 1 ? "" : "s");
712
713         result = isc_taskmgr_create(ns_g_mctx, ns_g_cpus, 0, &ns_g_taskmgr);
714         if (result != ISC_R_SUCCESS) {
715                 UNEXPECTED_ERROR(__FILE__, __LINE__,
716                                  "isc_taskmgr_create() failed: %s",
717                                  isc_result_totext(result));
718                 return (ISC_R_UNEXPECTED);
719         }
720
721         result = isc_timermgr_create(ns_g_mctx, &ns_g_timermgr);
722         if (result != ISC_R_SUCCESS) {
723                 UNEXPECTED_ERROR(__FILE__, __LINE__,
724                                  "isc_timermgr_create() failed: %s",
725                                  isc_result_totext(result));
726                 return (ISC_R_UNEXPECTED);
727         }
728
729         result = isc_socketmgr_create2(ns_g_mctx, &ns_g_socketmgr, maxsocks);
730         if (result != ISC_R_SUCCESS) {
731                 UNEXPECTED_ERROR(__FILE__, __LINE__,
732                                  "isc_socketmgr_create() failed: %s",
733                                  isc_result_totext(result));
734                 return (ISC_R_UNEXPECTED);
735         }
736         isc__socketmgr_maxudp(ns_g_socketmgr, maxudp);
737         result = isc_socketmgr_getmaxsockets(ns_g_socketmgr, &socks);
738         if (result == ISC_R_SUCCESS) {
739                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
740                               NS_LOGMODULE_SERVER,
741                               ISC_LOG_INFO, "using up to %u sockets", socks);
742         }
743
744         result = isc_entropy_create(ns_g_mctx, &ns_g_entropy);
745         if (result != ISC_R_SUCCESS) {
746                 UNEXPECTED_ERROR(__FILE__, __LINE__,
747                                  "isc_entropy_create() failed: %s",
748                                  isc_result_totext(result));
749                 return (ISC_R_UNEXPECTED);
750         }
751
752         result = isc_hash_create(ns_g_mctx, ns_g_entropy, DNS_NAME_MAXWIRE);
753         if (result != ISC_R_SUCCESS) {
754                 UNEXPECTED_ERROR(__FILE__, __LINE__,
755                                  "isc_hash_create() failed: %s",
756                                  isc_result_totext(result));
757                 return (ISC_R_UNEXPECTED);
758         }
759
760         return (ISC_R_SUCCESS);
761 }
762
763 static void
764 destroy_managers(void) {
765         ns_lwresd_shutdown();
766
767         /*
768          * isc_taskmgr_destroy() will block until all tasks have exited,
769          */
770         isc_taskmgr_destroy(&ns_g_taskmgr);
771         isc_timermgr_destroy(&ns_g_timermgr);
772         isc_socketmgr_destroy(&ns_g_socketmgr);
773
774         /*
775          * isc_hash_destroy() cannot be called as long as a resolver may be
776          * running.  Calling this after isc_taskmgr_destroy() ensures the
777          * call is safe.
778          */
779         isc_hash_destroy();
780 }
781
782 static void
783 dump_symboltable(void) {
784         int i;
785         isc_result_t result;
786         const char *fname;
787         const void *addr;
788
789         if (isc__backtrace_nsymbols == 0)
790                 return;
791
792         if (!isc_log_wouldlog(ns_g_lctx, ISC_LOG_DEBUG(99)))
793                 return;
794
795         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
796                       ISC_LOG_DEBUG(99), "Symbol table:");
797
798         for (i = 0, result = ISC_R_SUCCESS; result == ISC_R_SUCCESS; i++) {
799                 addr = NULL;
800                 fname = NULL;
801                 result = isc_backtrace_getsymbolfromindex(i, &addr, &fname);
802                 if (result == ISC_R_SUCCESS) {
803                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
804                                       NS_LOGMODULE_MAIN, ISC_LOG_DEBUG(99),
805                                       "[%d] %p %s", i, addr, fname);
806                 }
807         }
808 }
809
810 static void
811 setup(void) {
812         isc_result_t result;
813         isc_resourcevalue_t old_openfiles;
814 #ifdef HAVE_LIBSCF
815         char *instance = NULL;
816 #endif
817
818         /*
819          * Get the user and group information before changing the root
820          * directory, so the administrator does not need to keep a copy
821          * of the user and group databases in the chroot'ed environment.
822          */
823         ns_os_inituserinfo(ns_g_username);
824
825         /*
826          * Initialize time conversion information
827          */
828         ns_os_tzset();
829
830         ns_os_opendevnull();
831
832 #ifdef HAVE_LIBSCF
833         /* Check if named is under smf control, before chroot. */
834         result = ns_smf_get_instance(&instance, 0, ns_g_mctx);
835         /* We don't care about instance, just check if we got one. */
836         if (result == ISC_R_SUCCESS)
837                 ns_smf_got_instance = 1;
838         else
839                 ns_smf_got_instance = 0;
840         if (instance != NULL)
841                 isc_mem_free(ns_g_mctx, instance);
842 #endif /* HAVE_LIBSCF */
843
844 #ifdef PATH_RANDOMDEV
845         /*
846          * Initialize system's random device as fallback entropy source
847          * if running chroot'ed.
848          */
849         if (ns_g_chrootdir != NULL) {
850                 result = isc_entropy_create(ns_g_mctx, &ns_g_fallbackentropy);
851                 if (result != ISC_R_SUCCESS)
852                         ns_main_earlyfatal("isc_entropy_create() failed: %s",
853                                            isc_result_totext(result));
854
855                 result = isc_entropy_createfilesource(ns_g_fallbackentropy,
856                                                       PATH_RANDOMDEV);
857                 if (result != ISC_R_SUCCESS) {
858                         ns_main_earlywarning("could not open pre-chroot "
859                                              "entropy source %s: %s",
860                                              PATH_RANDOMDEV,
861                                              isc_result_totext(result));
862                         isc_entropy_detach(&ns_g_fallbackentropy);
863                 }
864         }
865 #endif
866
867 #ifdef ISC_PLATFORM_USETHREADS
868         /*
869          * Check for the number of cpu's before ns_os_chroot().
870          */
871         ns_g_cpus_detected = isc_os_ncpus();
872 #endif
873
874         ns_os_chroot(ns_g_chrootdir);
875
876         /*
877          * For operating systems which have a capability mechanism, now
878          * is the time to switch to minimal privs and change our user id.
879          * On traditional UNIX systems, this call will be a no-op, and we
880          * will change the user ID after reading the config file the first
881          * time.  (We need to read the config file to know which possibly
882          * privileged ports to bind() to.)
883          */
884         ns_os_minprivs();
885
886         result = ns_log_init(ISC_TF(ns_g_username != NULL));
887         if (result != ISC_R_SUCCESS)
888                 ns_main_earlyfatal("ns_log_init() failed: %s",
889                                    isc_result_totext(result));
890
891         /*
892          * Now is the time to daemonize (if we're not running in the
893          * foreground).  We waited until now because we wanted to get
894          * a valid logging context setup.  We cannot daemonize any later,
895          * because calling create_managers() will create threads, which
896          * would be lost after fork().
897          */
898         if (!ns_g_foreground)
899                 ns_os_daemonize();
900
901         /*
902          * We call isc_app_start() here as some versions of FreeBSD's fork()
903          * destroys all the signal handling it sets up.
904          */
905         result = isc_app_start();
906         if (result != ISC_R_SUCCESS)
907                 ns_main_earlyfatal("isc_app_start() failed: %s",
908                                    isc_result_totext(result));
909
910         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
911                       ISC_LOG_NOTICE, "starting %s %s%s%s <id:%s>%s",
912                       ns_g_product, ns_g_version,
913                       *ns_g_description ? " " : "", ns_g_description,
914                       ns_g_srcid, saved_command_line);
915
916         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
917                       ISC_LOG_NOTICE, "running on %s", ns_os_uname());
918
919         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
920                       ISC_LOG_NOTICE, "built with %s", ns_g_configargs);
921
922         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
923                       ISC_LOG_NOTICE,
924                       "----------------------------------------------------");
925         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
926                       ISC_LOG_NOTICE,
927                       "BIND 9 is maintained by Internet Systems Consortium,");
928         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
929                       ISC_LOG_NOTICE,
930                       "Inc. (ISC), a non-profit 501(c)(3) public-benefit ");
931         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
932                       ISC_LOG_NOTICE,
933                       "corporation.  Support and training for BIND 9 are ");
934         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
935                       ISC_LOG_NOTICE,
936                       "available at https://www.isc.org/support");
937         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
938                       ISC_LOG_NOTICE,
939                       "----------------------------------------------------");
940
941         dump_symboltable();
942
943         /*
944          * Get the initial resource limits.
945          */
946         (void)isc_resource_getlimit(isc_resource_stacksize,
947                                     &ns_g_initstacksize);
948         (void)isc_resource_getlimit(isc_resource_datasize,
949                                     &ns_g_initdatasize);
950         (void)isc_resource_getlimit(isc_resource_coresize,
951                                     &ns_g_initcoresize);
952         (void)isc_resource_getlimit(isc_resource_openfiles,
953                                     &ns_g_initopenfiles);
954
955         /*
956          * System resources cannot effectively be tuned on some systems.
957          * Raise the limit in such cases for safety.
958          */
959         old_openfiles = ns_g_initopenfiles;
960         ns_os_adjustnofile();
961         (void)isc_resource_getlimit(isc_resource_openfiles,
962                                     &ns_g_initopenfiles);
963         if (old_openfiles != ns_g_initopenfiles) {
964                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
965                               NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
966                               "adjusted limit on open files from "
967                               "%" ISC_PRINT_QUADFORMAT "u to "
968                               "%" ISC_PRINT_QUADFORMAT "u",
969                               old_openfiles, ns_g_initopenfiles);
970         }
971
972         /*
973          * If the named configuration filename is relative, prepend the current
974          * directory's name before possibly changing to another directory.
975          */
976         if (! isc_file_isabsolute(ns_g_conffile)) {
977                 result = isc_file_absolutepath(ns_g_conffile,
978                                                absolute_conffile,
979                                                sizeof(absolute_conffile));
980                 if (result != ISC_R_SUCCESS)
981                         ns_main_earlyfatal("could not construct absolute path "
982                                            "of configuration file: %s",
983                                            isc_result_totext(result));
984                 ns_g_conffile = absolute_conffile;
985         }
986
987         /*
988          * Record the server's startup time.
989          */
990         result = isc_time_now(&ns_g_boottime);
991         if (result != ISC_R_SUCCESS)
992                 ns_main_earlyfatal("isc_time_now() failed: %s",
993                                    isc_result_totext(result));
994
995         result = create_managers();
996         if (result != ISC_R_SUCCESS)
997                 ns_main_earlyfatal("create_managers() failed: %s",
998                                    isc_result_totext(result));
999
1000         ns_builtin_init();
1001
1002         /*
1003          * Add calls to register sdb drivers here.
1004          */
1005         /* xxdb_init(); */
1006
1007 #ifdef ISC_DLZ_DLOPEN
1008         /*
1009          * Register the DLZ "dlopen" driver.
1010          */
1011         result = dlz_dlopen_init(ns_g_mctx);
1012         if (result != ISC_R_SUCCESS)
1013                 ns_main_earlyfatal("dlz_dlopen_init() failed: %s",
1014                                    isc_result_totext(result));
1015 #endif
1016
1017 #if CONTRIB_DLZ
1018         /*
1019          * Register any other contributed DLZ drivers.
1020          */
1021         result = dlz_drivers_init();
1022         if (result != ISC_R_SUCCESS)
1023                 ns_main_earlyfatal("dlz_drivers_init() failed: %s",
1024                                    isc_result_totext(result));
1025 #endif
1026
1027         ns_server_create(ns_g_mctx, &ns_g_server);
1028 }
1029
1030 static void
1031 cleanup(void) {
1032         destroy_managers();
1033
1034         ns_server_destroy(&ns_g_server);
1035
1036         isc_entropy_detach(&ns_g_entropy);
1037         if (ns_g_fallbackentropy != NULL)
1038                 isc_entropy_detach(&ns_g_fallbackentropy);
1039
1040         ns_builtin_deinit();
1041
1042         /*
1043          * Add calls to unregister sdb drivers here.
1044          */
1045         /* xxdb_clear(); */
1046
1047 #ifdef CONTRIB_DLZ
1048         /*
1049          * Unregister contributed DLZ drivers.
1050          */
1051         dlz_drivers_clear();
1052 #endif
1053 #ifdef ISC_DLZ_DLOPEN
1054         /*
1055          * Unregister "dlopen" DLZ driver.
1056          */
1057         dlz_dlopen_clear();
1058 #endif
1059
1060         dns_name_destroy();
1061
1062         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
1063                       ISC_LOG_NOTICE, "exiting");
1064         ns_log_shutdown();
1065 }
1066
1067 static char *memstats = NULL;
1068
1069 void
1070 ns_main_setmemstats(const char *filename) {
1071         /*
1072          * Caller has to ensure locking.
1073          */
1074
1075         if (memstats != NULL) {
1076                 free(memstats);
1077                 memstats = NULL;
1078         }
1079         if (filename == NULL)
1080                 return;
1081         memstats = malloc(strlen(filename) + 1);
1082         if (memstats)
1083                 strcpy(memstats, filename);
1084 }
1085
1086 #ifdef HAVE_LIBSCF
1087 /*
1088  * Get FMRI for the named process.
1089  */
1090 isc_result_t
1091 ns_smf_get_instance(char **ins_name, int debug, isc_mem_t *mctx) {
1092         scf_handle_t *h = NULL;
1093         int namelen;
1094         char *instance;
1095
1096         REQUIRE(ins_name != NULL && *ins_name == NULL);
1097
1098         if ((h = scf_handle_create(SCF_VERSION)) == NULL) {
1099                 if (debug)
1100                         UNEXPECTED_ERROR(__FILE__, __LINE__,
1101                                          "scf_handle_create() failed: %s",
1102                                          scf_strerror(scf_error()));
1103                 return (ISC_R_FAILURE);
1104         }
1105
1106         if (scf_handle_bind(h) == -1) {
1107                 if (debug)
1108                         UNEXPECTED_ERROR(__FILE__, __LINE__,
1109                                          "scf_handle_bind() failed: %s",
1110                                          scf_strerror(scf_error()));
1111                 scf_handle_destroy(h);
1112                 return (ISC_R_FAILURE);
1113         }
1114
1115         if ((namelen = scf_myname(h, NULL, 0)) == -1) {
1116                 if (debug)
1117                         UNEXPECTED_ERROR(__FILE__, __LINE__,
1118                                          "scf_myname() failed: %s",
1119                                          scf_strerror(scf_error()));
1120                 scf_handle_destroy(h);
1121                 return (ISC_R_FAILURE);
1122         }
1123
1124         if ((instance = isc_mem_allocate(mctx, namelen + 1)) == NULL) {
1125                 UNEXPECTED_ERROR(__FILE__, __LINE__,
1126                                  "ns_smf_get_instance memory "
1127                                  "allocation failed: %s",
1128                                  isc_result_totext(ISC_R_NOMEMORY));
1129                 scf_handle_destroy(h);
1130                 return (ISC_R_FAILURE);
1131         }
1132
1133         if (scf_myname(h, instance, namelen + 1) == -1) {
1134                 if (debug)
1135                         UNEXPECTED_ERROR(__FILE__, __LINE__,
1136                                          "scf_myname() failed: %s",
1137                                          scf_strerror(scf_error()));
1138                 scf_handle_destroy(h);
1139                 isc_mem_free(mctx, instance);
1140                 return (ISC_R_FAILURE);
1141         }
1142
1143         scf_handle_destroy(h);
1144         *ins_name = instance;
1145         return (ISC_R_SUCCESS);
1146 }
1147 #endif /* HAVE_LIBSCF */
1148
1149 /* main entry point, possibly hooked */
1150
1151 int
1152 main(int argc, char *argv[]) {
1153         isc_result_t result;
1154 #ifdef HAVE_LIBSCF
1155         char *instance = NULL;
1156 #endif
1157
1158 #ifdef HAVE_GPERFTOOLS_PROFILER
1159         (void) ProfilerStart(NULL);
1160 #endif
1161
1162         /*
1163          * Record version in core image.
1164          * strings named.core | grep "named version:"
1165          */
1166         strlcat(version,
1167 #if defined(NO_VERSION_DATE) || !defined(__DATE__)
1168                 "named version: BIND " VERSION " <" SRCID ">",
1169 #else
1170                 "named version: BIND " VERSION " <" SRCID "> (" __DATE__ ")",
1171 #endif
1172                 sizeof(version));
1173         result = isc_file_progname(*argv, program_name, sizeof(program_name));
1174         if (result != ISC_R_SUCCESS)
1175                 ns_main_earlyfatal("program name too long");
1176
1177         if (strcmp(program_name, "lwresd") == 0)
1178                 ns_g_lwresdonly = ISC_TRUE;
1179
1180         if (result != ISC_R_SUCCESS)
1181                 ns_main_earlyfatal("failed to build internal symbol table");
1182
1183         isc_assertion_setcallback(assertion_failed);
1184         isc_error_setfatal(library_fatal_error);
1185         isc_error_setunexpected(library_unexpected_error);
1186
1187         ns_os_init(program_name);
1188
1189         dns_result_register();
1190         dst_result_register();
1191         isccc_result_register();
1192
1193         parse_command_line(argc, argv);
1194
1195         /*
1196          * Warn about common configuration error.
1197          */
1198         if (ns_g_chrootdir != NULL) {
1199                 int len = strlen(ns_g_chrootdir);
1200                 if (strncmp(ns_g_chrootdir, ns_g_conffile, len) == 0 &&
1201                     (ns_g_conffile[len] == '/' || ns_g_conffile[len] == '\\'))
1202                         ns_main_earlywarning("config filename (-c %s) contains "
1203                                              "chroot path (-t %s)",
1204                                              ns_g_conffile, ns_g_chrootdir);
1205         }
1206
1207         result = isc_mem_create(0, 0, &ns_g_mctx);
1208         if (result != ISC_R_SUCCESS)
1209                 ns_main_earlyfatal("isc_mem_create() failed: %s",
1210                                    isc_result_totext(result));
1211         isc_mem_setname(ns_g_mctx, "main", NULL);
1212
1213         setup();
1214
1215         /*
1216          * Start things running and then wait for a shutdown request
1217          * or reload.
1218          */
1219         do {
1220                 result = isc_app_run();
1221
1222                 if (result == ISC_R_RELOAD) {
1223                         ns_server_reloadwanted(ns_g_server);
1224                 } else if (result != ISC_R_SUCCESS) {
1225                         UNEXPECTED_ERROR(__FILE__, __LINE__,
1226                                          "isc_app_run(): %s",
1227                                          isc_result_totext(result));
1228                         /*
1229                          * Force exit.
1230                          */
1231                         result = ISC_R_SUCCESS;
1232                 }
1233         } while (result != ISC_R_SUCCESS);
1234
1235 #ifdef HAVE_LIBSCF
1236         if (ns_smf_want_disable == 1) {
1237                 result = ns_smf_get_instance(&instance, 1, ns_g_mctx);
1238                 if (result == ISC_R_SUCCESS && instance != NULL) {
1239                         if (smf_disable_instance(instance, 0) != 0)
1240                                 UNEXPECTED_ERROR(__FILE__, __LINE__,
1241                                                  "smf_disable_instance() "
1242                                                  "failed for %s : %s",
1243                                                  instance,
1244                                                  scf_strerror(scf_error()));
1245                 }
1246                 if (instance != NULL)
1247                         isc_mem_free(ns_g_mctx, instance);
1248         }
1249 #endif /* HAVE_LIBSCF */
1250
1251         cleanup();
1252
1253         if (want_stats) {
1254                 isc_mem_stats(ns_g_mctx, stdout);
1255                 isc_mutex_stats(stdout);
1256         }
1257
1258         if (ns_g_memstatistics && memstats != NULL) {
1259                 FILE *fp = NULL;
1260                 result = isc_stdio_open(memstats, "w", &fp);
1261                 if (result == ISC_R_SUCCESS) {
1262                         isc_mem_stats(ns_g_mctx, fp);
1263                         isc_mutex_stats(fp);
1264                         isc_stdio_close(fp);
1265                 }
1266         }
1267         isc_mem_destroy(&ns_g_mctx);
1268         isc_mem_checkdestroyed(stderr);
1269
1270         ns_main_setmemstats(NULL);
1271
1272         isc_app_finish();
1273
1274         ns_os_closedevnull();
1275
1276         ns_os_shutdown();
1277
1278 #ifdef HAVE_GPERFTOOLS_PROFILER
1279         ProfilerStop();
1280 #endif
1281
1282         return (0);
1283 }