📄 main.c
字号:
/************************************************************************************************** $Id: main.c,v 1.122 2005/12/08 17:45:56 bboy Exp $ Copyright (C) 2002-2005 Don Moore <bboy@bboy.net> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at Your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA**************************************************************************************************/#include "named.h"QUEUE *Tasks; /* Task queue */time_t current_time; /* Current time */static int multicpu; /* If multi-CPU, number of CPUs */static pid_t *pidlist; /* List of related PIDs */static int is_master; /* Is the current process the master? */static int got_sigusr1 = 0, got_sigusr2 = 0, got_sighup = 0, got_sigalrm = 0, /* Signal flags */ got_sigchld = 0; /* Signal flags */static int shutting_down = 0; /* Shutdown in progress? */int run_as_root = 0; /* Run as root user? */uint32_t answer_then_quit = 0; /* Answer this many queries then quit */char hostname[256]; /* Hostname of local machine */extern int *tcp4_fd, *udp4_fd; /* Listening FD's (IPv4) */extern int num_tcp4_fd, num_udp4_fd; /* Number of listening FD's (IPv4) */#if HAVE_IPV6extern int *tcp6_fd, *udp6_fd; /* Listening FD's (IPv6) */extern int num_tcp6_fd, num_udp6_fd; /* Number of listening FD's (IPv6) */#endifint show_data_errors = 1; /* Output data errors? */SERVERSTATUS Status; /* Server status information */extern void create_listeners(void);extern void db_check_optional(void);extern int opt_daemon;extern char *opt_conf;extern uid_t perms_uid;extern gid_t perms_gid;/************************************************************************************************** USAGE Display program usage information.**************************************************************************************************/static voidusage(int status){ if (status != EXIT_SUCCESS) { fprintf(stderr, _("Try `%s --help' for more information."), progname); fputs("\n", stderr); } else { printf(_("Usage: %s [OPTION]..."), progname); puts(""); puts(_("Listen for and respond to Internet domain name queries.")); puts("");/* puts("----------------------------------------------------------------------------78"); */ puts(_(" -b, --background run as a daemon (move process into background)")); puts(_(" -c, --conf=FILE read config from FILE instead of the default")); puts(_(" --create-tables output table creation SQL and exit")); puts(_(" --dump-config output configuration and exit")); printf(" (%s: \"%s\")\n", _("default"), MYDNS_CONF); puts(""); puts(_(" -D, --database=DB database name to use")); puts(_(" -h, --host=HOST connect to database at HOST")); puts(_(" -p, --password=PASS password for database (or prompt from tty)")); puts(_(" -u, --user=USER username for database if not current user")); puts("");#if DEBUG_ENABLED puts(_(" -d, --debug enable debug output"));#endif puts(_(" -v, --verbose be more verbose while running")); puts(_(" --no-data-errors don't output errors about bad data")); puts(_(" --help display this help and exit")); puts(_(" --version output version information and exit")); puts(""); printf(_("The %s homepage is at %s\n"), PACKAGE_NAME, PACKAGE_HOMEPAGE); puts(""); printf(_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT); } exit(status);}/*--- usage() -----------------------------------------------------------------------------------*//************************************************************************************************** CMDLINE Process command line options.**************************************************************************************************/static voidcmdline(int argc, char **argv){ char *optstr; int want_dump_config = 0, optc, optindex; struct option const longopts[] = { {"background", no_argument, NULL, 'b'}, {"conf", required_argument, NULL, 'c'}, {"create-tables", no_argument, NULL, 0}, {"dump-config", no_argument, NULL, 0}, {"database", required_argument, NULL, 'D'}, {"host", required_argument, NULL, 'h'}, {"password", optional_argument, NULL, 'p'}, {"user", required_argument, NULL, 'u'}, {"debug", no_argument, NULL, 'd'}, {"verbose", no_argument, NULL, 'v'}, {"help", no_argument, NULL, 0}, {"version", no_argument, NULL, 0}, {"quit-after", required_argument, NULL, 0}, /* Undocumented.. Useful when debugging */ {"run-as-root", no_argument, NULL, 0}, /* Undocumented.. */ {"no-data-errors",no_argument, NULL, 0}, {NULL, 0, NULL, 0} }; error_init(argv[0], LOG_DAEMON); /* Init output/logging routines */ optstr = getoptstr(longopts); while ((optc = getopt_long(argc, argv, optstr, longopts, &optindex)) != -1) { switch (optc) { case 0: { const char *opt = longopts[optindex].name; if (!strcmp(opt, "version")) /* --version */ { printf("%s ("PACKAGE_NAME") "PACKAGE_VERSION" ("SQL_VERSION_STR")\n", progname); puts("\n" PACKAGE_COPYRIGHT); puts(_("This is free software; see the source for copying conditions. There is NO")); puts(_("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.")); exit(EXIT_SUCCESS); } else if (!strcmp(opt, "help")) /* --help */ usage(EXIT_SUCCESS); else if (!strcmp(opt, "dump-config")) /* --dump-config */ want_dump_config++; else if (!strcmp(opt, "create-tables")) /* --create-tables */ db_output_create_tables(); else if (!strcmp(opt, "quit-after")) /* --quit-after */ answer_then_quit = strtoul(optarg, (char **)NULL, 10); else if (!strcmp(opt, "run-as-root")) /* --run-as-root */ run_as_root = 1; else if (!strcmp(opt, "no-data-errors")) /* --no-data-errors */ show_data_errors = 0; } break; case 'b': /* -b, --background */ opt_daemon = 1; break; case 'c': /* -c, --conf=FILE */ opt_conf = optarg; break; case 'd': /* -d, --debug */#if DEBUG_ENABLED err_verbose = err_debug = 1;#endif break; case 'D': /* -D, --database=DB */ conf_set(&Conf, "database", optarg, 0); break; case 'h': /* -h, --host=HOST */ conf_set(&Conf, "db-host", optarg, 0); break; case 'p': /* -p, --password=PASS */ if (optarg) { conf_set(&Conf, "db-password", optarg, 0); memset(optarg, 'X', strlen(optarg)); } else conf_set(&Conf, "db-password", passinput(_("Enter password")), 0); break; case 'u': /* -u, --user=USER */ conf_set(&Conf, "db-user", optarg, 0); break; case 'v': /* -v, --verbose */ err_verbose = 1; break; default: usage(EXIT_FAILURE); } } if (optind < argc) fprintf(stderr, "%s: %s\n", progname, _("Extraneous command-line arguments ignored")); load_config(); if (want_dump_config) { dump_config(); exit(EXIT_SUCCESS); } db_verify_tables(); /* Make sure tables are OK */ /* Random numbers are just for round robin and load balancing */ srand(time(NULL));}/*--- cmdline() ---------------------------------------------------------------------------------*//************************************************************************************************** SET_SIGHANDLER**************************************************************************************************/typedef void (*sig_handler)(int);static voidset_sighandler(int sig, sig_handler h){ struct sigaction act; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (sig == SIGALRM) {#ifdef SA_INTERRUPT act.sa_flags |= SA_INTERRUPT;#endif } else {#ifdef SA_RESTART act.sa_flags |= SA_RESTART;#endif } act.sa_handler = h; sigaction(sig, &act, 0);}/*--- set_sighandler() --------------------------------------------------------------------------*//************************************************************************************************** BECOME_DAEMON**************************************************************************************************/static voidbecome_daemon(void){ int pid; struct rlimit rl; sql_close(sql); if ((pid = fork()) < 0) Err("fork"); if (pid) _exit(EXIT_SUCCESS); close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); setsid(); if (getrlimit(RLIMIT_NOFILE, &rl) < 0) Err("getrlimit"); rl.rlim_cur = rl.rlim_max; setrlimit(RLIMIT_NOFILE, &rl); if (getrlimit(RLIMIT_CORE, &rl) < 0) Err("getrlimit"); rl.rlim_cur = rl.rlim_max; setrlimit(RLIMIT_CORE, &rl); db_connect();}/*--- become_daemon() ---------------------------------------------------------------------------*//************************************************************************************************** CREATE_PIDFILE Creates the PID file.**************************************************************************************************/static voidcreate_pidfile(void){ char *name = conf_get(&Conf, "pidfile", NULL); FILE *fp; if (!(fp = fopen(name, "w"))) Err("%s", name); fprintf(fp, "%lu\n", (unsigned long)getpid()); fclose(fp); /* Change ownership so we can delete it later */ chown(name, perms_uid, perms_gid);}/*--- create_pidfile() --------------------------------------------------------------------------*//************************************************************************************************** SERVER_STATUS**************************************************************************************************/voidserver_status(void){ char buf[1024], *b = buf; time_t uptime = time(NULL) - Status.start_time; unsigned long requests = Status.udp_requests + Status.tcp_requests; b += snprintf(b, sizeof(buf)-(b-buf), "%s ", hostname); b += snprintf(b, sizeof(buf)-(b-buf), "%s %s (%lus) ", _("up"), strsecs(uptime), (unsigned long)uptime); b += snprintf(b, sizeof(buf)-(b-buf), "%lu %s ", requests, _("questions")); b += snprintf(b, sizeof(buf)-(b-buf), "(%.0f/s) ", requests ? AVG(requests, uptime) : 0.0); b += snprintf(b, sizeof(buf)-(b-buf), "NOERROR=%u ", Status.results[DNS_RCODE_NOERROR]); b += snprintf(b, sizeof(buf)-(b-buf), "SERVFAIL=%u ", Status.results[DNS_RCODE_SERVFAIL]); b += snprintf(b, sizeof(buf)-(b-buf), "NXDOMAIN=%u ", Status.results[DNS_RCODE_NXDOMAIN]); b += snprintf(b, sizeof(buf)-(b-buf), "NOTIMP=%u ", Status.results[DNS_RCODE_NOTIMP]); b += snprintf(b, sizeof(buf)-(b-buf), "REFUSED=%u ", Status.results[DNS_RCODE_REFUSED]); /* If the server is getting TCP queries, report on the percentage of TCP queries */ if (Status.tcp_requests) b += snprintf(b, sizeof(buf)-(b-buf), "(%d%% TCP, %lu queries)", (int)PCT(requests, Status.tcp_requests), (unsigned long)Status.tcp_requests); Notice("%s", buf);}/*--- server_status() ---------------------------------------------------------------------------*//************************************************************************************************** SIGUSR1 Outputs server stats.**************************************************************************************************/voidsigusr1(int dummy){ if (is_master) { int n; for (n = 0; n < multicpu - 1; n++) kill(pidlist[n], SIGUSR1); } server_status(); got_sigusr1 = 0;}/*--- sigusr1() ---------------------------------------------------------------------------------*//************************************************************************************************** SIGUSR2 Outputs cache stats.**************************************************************************************************/voidsigusr2(int dummy){ if (is_master) { int n; for (n = 0; n < multicpu - 1; n++) kill(pidlist[n], SIGUSR2); } cache_status(ZoneCache);#if USE_NEGATIVE_CACHE cache_status(NegativeCache);#endif cache_status(ReplyCache); got_sigusr2 = 0;}/*--- sigusr2() ---------------------------------------------------------------------------------*//************************************************************************************************** PERIODIC_TASK**************************************************************************************************/voidperiodic_task(int dummy){ alarm(ALARM_INTERVAL); got_sigalrm = 0;}/*--- periodic_task() ---------------------------------------------------------------------------*//************************************************************************************************** SIGHUP**************************************************************************************************/voidsighup(int dummy){ if (is_master) { int n; for (n = 0; n < multicpu - 1; n++) kill(pidlist[n], SIGHUP); } cache_empty(ZoneCache);#if USE_NEGATIVE_CACHE cache_empty(NegativeCache);#endif cache_empty(ReplyCache); db_check_optional(); Notice(_("SIGHUP received: cache emptied, tables reloaded")); got_sighup = 0;}/*--- sighup() ----------------------------------------------------------------------------------*//************************************************************************************************** SIGNAL_HANDLER**************************************************************************************************/voidsignal_handler(int signo){ switch (signo) { case SIGHUP: got_sighup = 1; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -