summaryrefslogtreecommitdiff
path: root/src/option.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/option.c')
-rw-r--r--src/option.c545
1 files changed, 379 insertions, 166 deletions
diff --git a/src/option.c b/src/option.c
index ec16b4b..214fd91 100644
--- a/src/option.c
+++ b/src/option.c
@@ -1,4 +1,4 @@
-/* dnsmasq is Copyright (c) 2000-2010 Simon Kelley
+/* dnsmasq is Copyright (c) 2000-2011 Simon Kelley
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
@@ -21,7 +21,7 @@
static volatile int mem_recover = 0;
static jmp_buf mem_jmp;
-static void one_file(char *file, int nest, int hard_opt);
+static void one_file(char *file, int hard_opt);
/* Solaris headers don't have facility names. */
#ifdef HAVE_SOLARIS_NETWORK
@@ -108,6 +108,8 @@ struct myoption {
#define LOPT_MAXTTL 297
#define LOPT_NO_REBIND 298
#define LOPT_LOC_REBND 299
+#define LOPT_ADD_MAC 300
+#define LOPT_DNSSEC 301
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
@@ -221,14 +223,16 @@ static const struct myoption opts[] =
{ "dhcp-proxy", 2, 0, LOPT_PROXY },
{ "dhcp-generate-names", 2, 0, LOPT_GEN_NAMES },
{ "rebind-localhost-ok", 0, 0, LOPT_LOC_REBND },
+ { "add-mac", 0, 0, LOPT_ADD_MAC },
+ { "proxy-dnssec", 0, 0, LOPT_DNSSEC },
{ NULL, 0, 0, 0 }
};
-/* These must have more the one '1' bit */
-#define ARG_DUP 3
-#define ARG_ONE 5
-#define ARG_USED_CL 7
-#define ARG_USED_FILE 9
+
+#define ARG_DUP OPT_LAST
+#define ARG_ONE OPT_LAST + 1
+#define ARG_USED_CL OPT_LAST + 2
+#define ARG_USED_FILE OPT_LAST + 3
static struct {
int opt;
@@ -251,8 +255,8 @@ static struct {
{ 'F', ARG_DUP, "ipaddr,ipaddr,time", gettext_noop("Enable DHCP in the range given with lease duration."), NULL },
{ 'g', ARG_ONE, "groupname", gettext_noop("Change to this group after startup (defaults to %s)."), CHGRP },
{ 'G', ARG_DUP, "<hostspec>", gettext_noop("Set address or hostname for a specified machine."), NULL },
- { LOPT_DHCP_HOST, ARG_ONE, "<filename>", gettext_noop("Read DHCP host specs from file."), NULL },
- { LOPT_DHCP_OPTS, ARG_ONE, "<filename>", gettext_noop("Read DHCP option specs from file."), NULL },
+ { LOPT_DHCP_HOST, ARG_DUP, "<filename>", gettext_noop("Read DHCP host specs from file."), NULL },
+ { LOPT_DHCP_OPTS, ARG_DUP, "<filename>", gettext_noop("Read DHCP option specs from file."), NULL },
{ LOPT_TAG_IF, ARG_DUP, "tag-expression", gettext_noop("Evaluate conditional tag expression."), NULL },
{ 'h', OPT_NO_HOSTS, NULL, gettext_noop("Do NOT load %s file."), HOSTSFILE },
{ 'H', ARG_DUP, "path", gettext_noop("Specify a hosts file to be read in addition to %s."), HOSTSFILE },
@@ -341,15 +345,17 @@ static struct {
{ LOPT_PXE_PROMT, ARG_DUP, "<prompt>,[<timeout>]", gettext_noop("Prompt to send to PXE clients."), NULL },
{ LOPT_PXE_SERV, ARG_DUP, "<service>", gettext_noop("Boot service for PXE menu."), NULL },
{ LOPT_TEST, 0, NULL, gettext_noop("Check configuration syntax."), NULL },
+ { LOPT_ADD_MAC, OPT_ADD_MAC, NULL, gettext_noop("Add requestor's MAC address to forwarded DNS queries"), NULL },
+ { LOPT_DNSSEC, OPT_DNSSEC, NULL, gettext_noop("Proxy DNSSEC validation results from upstream nameservers"), NULL },
{ 0, 0, NULL, NULL, NULL }
};
#ifdef HAVE_DHCP
-/* makes options which take a list of addresses */
#define OT_ADDR_LIST 0x80
-/* DHCP-internal options, for logging. not valid in config file */
-#define OT_INTERNAL 0x40
-#define OT_NAME 0x20
+#define OT_RFC1035_NAME 0x40
+#define OT_INTERNAL 0x20
+#define OT_NAME 0x10
+
static const struct {
char *name;
@@ -365,8 +371,8 @@ static const struct {
{ "boot-file-size", 13, 2 },
{ "domain-name", 15, OT_NAME },
{ "swap-server", 16, OT_ADDR_LIST },
- { "root-path", 17, 0 },
- { "extension-path", 18, 0 },
+ { "root-path", 17, OT_NAME },
+ { "extension-path", 18, OT_NAME },
{ "ip-forward-enable", 19, 1 },
{ "non-local-source-routing", 20, 1 },
{ "policy-filter", 21, OT_ADDR_LIST },
@@ -383,7 +389,7 @@ static const struct {
{ "ethernet-encap", 36, 1 },
{ "tcp-ttl", 37, 1 },
{ "tcp-keepalive", 38, 4 },
- { "nis-domain", 40, 0 },
+ { "nis-domain", 40, OT_NAME },
{ "nis-server", 41, OT_ADDR_LIST },
{ "ntp-server", 42, OT_ADDR_LIST },
{ "vendor-encap", 43, OT_INTERNAL },
@@ -405,10 +411,10 @@ static const struct {
{ "T2", 59, OT_INTERNAL },
{ "vendor-class", 60, 0 },
{ "client-id", 61,OT_INTERNAL },
- { "nis+-domain", 64, 0 },
+ { "nis+-domain", 64, OT_NAME },
{ "nis+-server", 65, OT_ADDR_LIST },
- { "tftp-server", 66, 0 },
- { "bootfile-name", 67, 0 },
+ { "tftp-server", 66, OT_NAME },
+ { "bootfile-name", 67, OT_NAME },
{ "mobile-ip-home", 68, OT_ADDR_LIST },
{ "smtp-server", 69, OT_ADDR_LIST },
{ "pop3-server", 70, OT_ADDR_LIST },
@@ -421,7 +427,7 @@ static const struct {
{ "client-interface-id", 94, 0 },
{ "client-machine-id", 97, 0 },
{ "subnet-select", 118, OT_INTERNAL },
- { "domain-search", 119, 0 },
+ { "domain-search", 119, OT_RFC1035_NAME },
{ "sip-server", 120, 0 },
{ "classless-static-route", 121, 0 },
{ "vendor-id-encap", 125, 0 },
@@ -776,6 +782,17 @@ static char *parse_dhcp_opt(char *arg, int flags)
arg = comma;
}
+ if (opt_len == 0 &&
+ !(new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE | DHOPT_RFC3925)))
+ for (i = 0; opttab[i].name; i++)
+ if (new->opt == opttab[i].val)
+ {
+ opt_len = opttab[i].size;
+ if (opt_len & OT_INTERNAL)
+ opt_len = 0;
+ break;
+ }
+
/* option may be missing with rfc3925 match */
if (new->opt == 0)
problem = _("bad dhcp-option");
@@ -783,6 +800,7 @@ static char *parse_dhcp_opt(char *arg, int flags)
{
/* characterise the value */
char c;
+ int found_dig = 0;
is_addr = is_hex = is_dec = is_string = 1;
addrs = digs = 1;
dots = 0;
@@ -828,15 +846,22 @@ static char *parse_dhcp_opt(char *arg, int flags)
(c == '*' && (flags & DHOPT_MATCH))))
is_hex = 0;
}
+ else
+ found_dig = 1;
+ if (!found_dig)
+ is_dec = is_addr = 0;
+
/* We know that some options take addresses */
-
if (opt_len & OT_ADDR_LIST)
{
is_string = is_dec = is_hex = 0;
if (!is_addr || dots == 0)
problem = _("bad IP address");
}
+ /* or names */
+ else if (opt_len & (OT_NAME | OT_RFC1035_NAME))
+ is_addr = is_dec = is_hex = 0;
if (is_hex && digs > 1)
{
@@ -1032,7 +1057,15 @@ static char *parse_dhcp_opt(char *arg, int flags)
#endif
-static char *one_opt(int option, char *arg, char *gen_prob, int nest)
+void set_option_bool(unsigned int opt)
+{
+ if (opt < 32)
+ daemon->options |= 1u << opt;
+ else
+ daemon->options2 |= 1u << (opt - 32);
+}
+
+static char *one_opt(int option, char *arg, char *gen_prob, int command_line)
{
int i;
char *comma, *problem = NULL;;
@@ -1045,7 +1078,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
{
int rept = usage[i].rept;
- if (nest == 0)
+ if (command_line)
{
/* command line */
if (rept == ARG_USED_CL)
@@ -1064,7 +1097,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
if (rept != ARG_DUP && rept != ARG_ONE && rept != ARG_USED_CL)
{
- daemon->options |= rept;
+ set_option_bool(rept);
return NULL;
}
@@ -1078,7 +1111,7 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
char *file = opt_string_alloc(arg);
if (file)
{
- one_file(file, nest, 0);
+ one_file(file, 0);
free(file);
}
break;
@@ -1145,8 +1178,8 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
if (!S_ISREG(buf.st_mode))
continue;
- /* dir is one level, so files must be readable */
- one_file(path, nest + 1, 0);
+ /* files must be readable */
+ one_file(path, 0);
free(path);
}
@@ -1183,20 +1216,6 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
daemon->runfile = opt_string_alloc(arg);
break;
- case LOPT_DHCP_HOST: /* --dhcp-hostfile */
- if (daemon->dhcp_hosts_file)
- problem = _("only one dhcp-hostsfile allowed");
- else
- daemon->dhcp_hosts_file = opt_string_alloc(arg);
- break;
-
- case LOPT_DHCP_OPTS: /* --dhcp-optsfile */
- if (daemon->dhcp_opts_file)
- problem = _("only one dhcp-optsfile allowed");
- else
- daemon->dhcp_opts_file = opt_string_alloc(arg);
- break;
-
case 'r': /* --resolv-file */
{
char *name = opt_string_alloc(arg);
@@ -1275,6 +1294,8 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
break;
#endif
+ case LOPT_DHCP_HOST: /* --dhcp-hostfile */
+ case LOPT_DHCP_OPTS: /* --dhcp-optsfile */
case 'H': /* --addn-hosts */
{
struct hostsfile *new = opt_malloc(sizeof(struct hostsfile));
@@ -1282,14 +1303,27 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
new->fname = opt_string_alloc(arg);
new->index = hosts_index++;
new->flags = 0;
- new->next = daemon->addn_hosts;
- daemon->addn_hosts = new;
+ if (option == 'H')
+ {
+ new->next = daemon->addn_hosts;
+ daemon->addn_hosts = new;
+ }
+ else if (option == LOPT_DHCP_HOST)
+ {
+ new->next = daemon->dhcp_hosts_file;
+ daemon->dhcp_hosts_file = new;
+ }
+ else if (option == LOPT_DHCP_OPTS)
+ {
+ new->next = daemon->dhcp_opts_file;
+ daemon->dhcp_opts_file = new;
+ }
break;
}
case 's': /* --domain */
if (strcmp (arg, "#") == 0)
- daemon->options |= OPT_RESOLV_DOMAIN;
+ set_option_bool(OPT_RESOLV_DOMAIN);
else
{
char *d;
@@ -1301,18 +1335,59 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
if (comma)
{
struct cond_domain *new = safe_malloc(sizeof(struct cond_domain));
+ char *netpart;
+
unhide_metas(comma);
- if ((arg = split_chr(comma, '/')))
+ if ((netpart = split_chr(comma, '/')))
{
- int mask;
+ int msize, mask;
+ arg = split(netpart);
if ((new->start.s_addr = inet_addr(comma)) == (in_addr_t)-1 ||
- !atoi_check(arg, &mask))
+ !atoi_check(netpart, &msize))
option = '?';
else
{
- mask = (1 << (32 - mask)) - 1;
+ mask = (1 << (32 - msize)) - 1;
new->start.s_addr = ntohl(htonl(new->start.s_addr) & ~mask);
new->end.s_addr = new->start.s_addr | htonl(mask);
+ if (arg)
+ {
+ /* generate the equivalent of
+ local=/<domain>/
+ local=/xxx.yyy.zzz.in-addr.arpa/ */
+
+ if (strcmp(arg, "local") != 0 ||
+ (msize != 8 && msize != 16 && msize != 24))
+ option = '?';
+ else
+ {
+ struct server *serv = opt_malloc(sizeof(struct server));
+ in_addr_t a = ntohl(new->start.s_addr) >> 8;
+ char *p;
+
+ memset(serv, 0, sizeof(struct server));
+ serv->domain = d;
+ serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
+ serv->next = daemon->servers;
+ daemon->servers = serv;
+
+ serv = opt_malloc(sizeof(struct server));
+ memset(serv, 0, sizeof(struct server));
+ p = serv->domain = opt_malloc(25); /* strlen("xxx.yyy.zzz.in-addr.arpa")+1 */
+
+ if (msize == 24)
+ p += sprintf(p, "%d.", a & 0xff);
+ a = a >> 8;
+ if (msize != 8)
+ p += sprintf(p, "%d.", a & 0xff);
+ a = a >> 8;
+ p += sprintf(p, "%d.in-addr.arpa", a & 0xff);
+
+ serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
+ serv->next = daemon->servers;
+ daemon->servers = serv;
+ }
+ }
}
}
else if ((arg = split(comma)))
@@ -1934,7 +2009,9 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
len = (int) strlen(arg);
}
- if ((new->clid = opt_malloc(len)))
+ if (len == -1)
+ problem = _("bad hex constant");
+ else if ((new->clid = opt_malloc(len)))
{
new->flags |= CONFIG_CLID;
new->clid_len = len;
@@ -1957,10 +2034,15 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
else
{
struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
- newhw->next = new->hwaddr;
- new->hwaddr = newhw;
- newhw->hwaddr_len = parse_hex(a[j], newhw->hwaddr, DHCP_CHADDR_MAX,
- &newhw->wildcard_mask, &newhw->hwaddr_type);
+ if ((newhw->hwaddr_len = parse_hex(a[j], newhw->hwaddr, DHCP_CHADDR_MAX,
+ &newhw->wildcard_mask, &newhw->hwaddr_type)) == -1)
+ problem = _("bad hex constant");
+ else
+ {
+
+ newhw->next = new->hwaddr;
+ new->hwaddr = newhw;
+ }
}
}
else if (strchr(a[j], '.') && (in.s_addr = inet_addr(a[j])) != (in_addr_t)-1)
@@ -2295,8 +2377,13 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
new->netid.net = opt_string_alloc(set_prefix(arg));
unhide_metas(comma);
new->hwaddr_len = parse_hex(comma, new->hwaddr, DHCP_CHADDR_MAX, &new->mask, &new->hwaddr_type);
- new->next = daemon->dhcp_macs;
- daemon->dhcp_macs = new;
+ if (new->hwaddr_len == -1)
+ option = '?';
+ else
+ {
+ new->next = daemon->dhcp_macs;
+ daemon->dhcp_macs = new;
+ }
}
}
break;
@@ -2587,63 +2674,49 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
case 'Y': /* --txt-record */
{
struct txt_record *new;
- unsigned char *p, *q;
-
- if ((comma = split(arg)))
- comma--;
-
- gen_prob = _("TXT record string too long");
-
- if ((q = (unsigned char *)comma))
- while (1)
- {
- size_t len;
- if ((p = (unsigned char *)strchr((char*)q+1, ',')))
- {
- if ((len = p - q - 1) > 255)
- option = '?';
- *q = len;
- for (q = q+1; q < p; q++)
- *q = unhide_meta(*q);
- }
- else
- {
- if ((len = strlen((char *)q+1)) > 255)
- option = '?';
- *q = len;
- for (q = q+1; *q; q++)
- *q = unhide_meta(*q);
- break;
- }
- }
-
+ unsigned char *p, *cnt;
+ size_t len;
+
+ comma = split(arg);
+
new = opt_malloc(sizeof(struct txt_record));
new->next = daemon->txt;
daemon->txt = new;
new->class = C_IN;
- if (comma)
- {
- new->len = q - ((unsigned char *)comma);
- new->txt = opt_malloc(new->len);
- memcpy(new->txt, comma, new->len);
- }
- else
- {
- static char empty[] = "";
- new->len = 1;
- new->txt = empty;
- }
- /* ensure arg is terminated */
- if (comma)
- *comma = 0;
-
if (!(new->name = canonicalise_opt(arg)))
{
problem = _("bad TXT record");
break;
}
+ len = comma ? strlen(comma) : 0;
+ len += (len/255) + 1; /* room for extra counts */
+ new->txt = p = opt_malloc(len);
+
+ cnt = p++;
+ *cnt = 0;
+
+ while (comma && *comma)
+ {
+ unsigned char c = (unsigned char)*comma++;
+
+ if (c == ',' || *cnt == 255)
+ {
+ if (c != ',')
+ comma--;
+ cnt = p++;
+ *cnt = 0;
+ }
+ else
+ {
+ *p++ = unhide_meta(c);
+ (*cnt)++;
+ }
+ }
+
+ new->len = p - new->txt;
+
break;
}
@@ -2716,53 +2789,10 @@ static char *one_opt(int option, char *arg, char *gen_prob, int nest)
return NULL;
}
-static void one_file(char *file, int nest, int hard_opt)
+static void read_file(char *file, FILE *f, int hard_opt)
{
volatile int lineno = 0;
- FILE *f;
char *buff = daemon->namebuff;
- static struct fileread {
- dev_t dev;
- ino_t ino;
- struct fileread *next;
- } *filesread = NULL;
- struct stat statbuf;
-
- /* ignore repeated files. */
- if (hard_opt == 0 && stat(file, &statbuf) == 0)
- {
- struct fileread *r;
-
- for (r = filesread; r; r = r->next)
- if (r->dev == statbuf.st_dev && r->ino == statbuf.st_ino)
- return;
-
- r = safe_malloc(sizeof(struct fileread));
- r->next = filesread;
- filesread = r;
- r->dev = statbuf.st_dev;
- r->ino = statbuf.st_ino;
- }
-
- if (nest > 20)
- die(_("files nested too deep in %s"), file, EC_BADCONF);
-
- if (!(f = fopen(file, "r")))
- {
- if (errno == ENOENT && nest == 0)
- return; /* No conffile, all done. */
- else
- {
- char *str = _("cannot read %s: %s");
- if (hard_opt != 0)
- {
- my_syslog(LOG_ERR, str, file, strerror(errno));
- return;
- }
- else
- die(str, file, EC_FILE);
- }
- }
while (fgets(buff, MAXDNAME, f))
{
@@ -2877,7 +2907,7 @@ static void one_file(char *file, int nest, int hard_opt)
}
if (!errmess)
- errmess = one_opt(option, arg, _("error"), nest + 1);
+ errmess = one_opt(option, arg, _("error"), 0);
if (errmess)
{
@@ -2894,13 +2924,183 @@ static void one_file(char *file, int nest, int hard_opt)
fclose(f);
}
+static void one_file(char *file, int hard_opt)
+{
+ FILE *f;
+ int nofile_ok = 0;
+ static int read_stdin = 0;
+ static struct fileread {
+ dev_t dev;
+ ino_t ino;
+ struct fileread *next;
+ } *filesread = NULL;
+
+ if (hard_opt == '7')
+ {
+ /* default conf-file reading */
+ hard_opt = 0;
+ nofile_ok = 1;
+ }
+
+ if (hard_opt == 0 && strcmp(file, "-") == 0)
+ {
+ if (read_stdin == 1)
+ return;
+ read_stdin = 1;
+ file = "stdin";
+ f = stdin;
+ }
+ else
+ {
+ /* ignore repeated files. */
+ struct stat statbuf;
+
+ if (hard_opt == 0 && stat(file, &statbuf) == 0)
+ {
+ struct fileread *r;
+
+ for (r = filesread; r; r = r->next)
+ if (r->dev == statbuf.st_dev && r->ino == statbuf.st_ino)
+ return;
+
+ r = safe_malloc(sizeof(struct fileread));
+ r->next = filesread;
+ filesread = r;
+ r->dev = statbuf.st_dev;
+ r->ino = statbuf.st_ino;
+ }
+
+ if (!(f = fopen(file, "r")))
+ {
+ if (errno == ENOENT && nofile_ok)
+ return; /* No conffile, all done. */
+ else
+ {
+ char *str = _("cannot read %s: %s");
+ if (hard_opt != 0)
+ {
+ my_syslog(LOG_ERR, str, file, strerror(errno));
+ return;
+ }
+ else
+ die(str, file, EC_FILE);
+ }
+ }
+ }
+
+ read_file(file, f, hard_opt);
+}
+
+/* expand any name which is a directory */
+struct hostsfile *expand_filelist(struct hostsfile *list)
+{
+ int i;
+ struct hostsfile *ah;
+
+ for (i = 0, ah = list; ah; ah = ah->next)
+ {
+ if (i <= ah->index)
+ i = ah->index + 1;
+
+ if (ah->flags & AH_DIR)
+ ah->flags |= AH_INACTIVE;
+ else
+ ah->flags &= ~AH_INACTIVE;
+ }
+
+ for (ah = list; ah; ah = ah->next)
+ if (!(ah->flags & AH_INACTIVE))
+ {
+ struct stat buf;
+ if (stat(ah->fname, &buf) != -1 && S_ISDIR(buf.st_mode))
+ {
+ DIR *dir_stream;
+ struct dirent *ent;
+
+ /* don't read this as a file */
+ ah->flags |= AH_INACTIVE;
+
+ if (!(dir_stream = opendir(ah->fname)))
+ my_syslog(LOG_ERR, _("cannot access directory %s: %s"),
+ ah->fname, strerror(errno));
+ else
+ {
+ while ((ent = readdir(dir_stream)))
+ {
+ size_t lendir = strlen(ah->fname);
+ size_t lenfile = strlen(ent->d_name);
+ struct hostsfile *ah1;
+ char *path;
+
+ /* ignore emacs backups and dotfiles */
+ if (lenfile == 0 ||
+ ent->d_name[lenfile - 1] == '~' ||
+ (ent->d_name[0] == '#' && ent->d_name[lenfile - 1] == '#') ||
+ ent->d_name[0] == '.')
+ continue;
+
+ /* see if we have an existing record.
+ dir is ah->fname
+ file is ent->d_name
+ path to match is ah1->fname */
+
+ for (ah1 = list; ah1; ah1 = ah1->next)
+ {
+ if (lendir < strlen(ah1->fname) &&
+ strstr(ah1->fname, ah->fname) == ah1->fname &&
+ ah1->fname[lendir] == '/' &&
+ strcmp(ah1->fname + lendir + 1, ent->d_name) == 0)
+ {
+ ah1->flags &= ~AH_INACTIVE;
+ break;
+ }
+ }
+
+ /* make new record */
+ if (!ah1)
+ {
+ if (!(ah1 = whine_malloc(sizeof(struct hostsfile))))
+ continue;
+
+ if (!(path = whine_malloc(lendir + lenfile + 2)))
+ {
+ free(ah1);
+ continue;
+ }
+
+ strcpy(path, ah->fname);
+ strcat(path, "/");
+ strcat(path, ent->d_name);
+ ah1->fname = path;
+ ah1->index = i++;
+ ah1->flags = AH_DIR;
+ ah1->next = list;
+ list = ah1;
+ }
+
+ /* inactivate record if not regular file */
+ if ((ah1->flags & AH_DIR) && stat(ah1->fname, &buf) != -1 && !S_ISREG(buf.st_mode))
+ ah1->flags |= AH_INACTIVE;
+
+ }
+ closedir(dir_stream);
+ }
+ }
+ }
+
+ return list;
+}
+
+
#ifdef HAVE_DHCP
void reread_dhcp(void)
{
+ struct hostsfile *hf;
+
if (daemon->dhcp_hosts_file)
{
struct dhcp_config *configs, *cp, **up;
-
+
/* remove existing... */
for (up = &daemon->dhcp_conf, configs = daemon->dhcp_conf; configs; configs = cp)
{
@@ -2930,7 +3130,6 @@ void reread_dhcp(void)
if (configs->flags & CONFIG_NAME)
free(configs->hostname);
-
*up = configs->next;
free(configs);
}
@@ -2938,8 +3137,13 @@ void reread_dhcp(void)
up = &configs->next;
}
- one_file(daemon->dhcp_hosts_file, 1, LOPT_BANK);
- my_syslog(MS_DHCP | LOG_INFO, _("read %s"), daemon->dhcp_hosts_file);
+ daemon->dhcp_hosts_file = expand_filelist(daemon->dhcp_hosts_file);
+ for (hf = daemon->dhcp_hosts_file; hf; hf = hf->next)
+ if (!(hf->flags & AH_INACTIVE))
+ {
+ one_file(hf->fname, LOPT_BANK);
+ my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
+ }
}
if (daemon->dhcp_opts_file)
@@ -2969,8 +3173,13 @@ void reread_dhcp(void)
up = &opts->next;
}
- one_file(daemon->dhcp_opts_file, 1, LOPT_OPTS);
- my_syslog(MS_DHCP | LOG_INFO, _("read %s"), daemon->dhcp_opts_file);
+ daemon->dhcp_opts_file = expand_filelist(daemon->dhcp_opts_file);
+ for (hf = daemon->dhcp_opts_file; hf; hf = hf->next)
+ if (!(hf->flags & AH_INACTIVE))
+ {
+ one_file(hf->fname, LOPT_OPTS);
+ my_syslog(MS_DHCP | LOG_INFO, _("read %s"), hf->fname);
+ }
}
}
#endif
@@ -2978,7 +3187,7 @@ void reread_dhcp(void)
void read_opts(int argc, char **argv, char *compile_opts)
{
char *buff = opt_malloc(MAXDNAME);
- int option, nest = 0, testmode = 0;
+ int option, conffile_opt = '7', testmode = 0;
char *errmess, *arg, *conffile = CONFFILE;
opterr = 0;
@@ -3015,8 +3224,12 @@ void read_opts(int argc, char **argv, char *compile_opts)
#endif
if (option == -1)
- break;
-
+ {
+ if (optind < argc)
+ die(_("junk found in command line"), NULL, EC_BADCONF);
+ break;
+ }
+
/* Copy optarg so that argv doesn't get changed */
if (optarg)
{
@@ -3051,15 +3264,15 @@ void read_opts(int argc, char **argv, char *compile_opts)
}
else if (option == 'C')
{
+ conffile_opt = 0; /* file must exist */
conffile = opt_string_alloc(arg);
- nest++;
}
else
{
#ifdef HAVE_GETOPT_LONG
- errmess = one_opt(option, arg, _("try --help"), 0);
+ errmess = one_opt(option, arg, _("try --help"), 1);
#else
- errmess = one_opt(option, arg, _("try -w"), 0);
+ errmess = one_opt(option, arg, _("try -w"), 1);
#endif
if (errmess)
die(_("bad command line options: %s"), errmess, EC_BADCONF);
@@ -3067,7 +3280,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
}
if (conffile)
- one_file(conffile, nest, 0);
+ one_file(conffile, conffile_opt);
/* port might not be known when the address is parsed - fill in here */
if (daemon->servers)
@@ -3098,7 +3311,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
}
/* only one of these need be specified: the other defaults to the host-name */
- if ((daemon->options & OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget)
+ if (option_bool(OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget)
{
struct mx_srv_record *mx;
@@ -3109,7 +3322,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
if (!mx->issrv && hostname_isequal(mx->name, buff))
break;
- if ((daemon->mxtarget || (daemon->options & OPT_LOCALMX)) && !mx)
+ if ((daemon->mxtarget || option_bool(OPT_LOCALMX)) && !mx)
{
mx = opt_malloc(sizeof(struct mx_srv_record));
mx->next = daemon->mxnames;
@@ -3127,18 +3340,18 @@ void read_opts(int argc, char **argv, char *compile_opts)
mx->target = daemon->mxtarget;
}
- if (!(daemon->options & OPT_NO_RESOLV) &&
+ if (!option_bool(OPT_NO_RESOLV) &&
daemon->resolv_files &&
daemon->resolv_files->next &&
- (daemon->options & OPT_NO_POLL))
+ option_bool(OPT_NO_POLL))
die(_("only one resolv.conf file allowed in no-poll mode."), NULL, EC_BADCONF);
- if (daemon->options & OPT_RESOLV_DOMAIN)
+ if (option_bool(OPT_RESOLV_DOMAIN))
{
char *line;
FILE *f;
- if ((daemon->options & OPT_NO_RESOLV) ||
+ if (option_bool(OPT_NO_RESOLV) ||
!daemon->resolv_files ||
(daemon->resolv_files)->next)
die(_("must have exactly one resolv.conf to read domain from."), NULL, EC_BADCONF);
@@ -3181,7 +3394,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
srv->name = opt_string_alloc(buff);
}
}
- else if (daemon->options & OPT_DHCP_FQDN)
+ else if (option_bool(OPT_DHCP_FQDN))
die(_("there must be a default domain when --dhcp-fqdn is set"), NULL, EC_BADCONF);
if (testmode)