You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
775 lines
18 KiB
775 lines
18 KiB
autofs-5.0.9 - amd lookup add selector handling |
|
|
|
From: Ian Kent <raven@themaw.net> |
|
|
|
|
|
--- |
|
include/parse_subs.h | 2 |
|
lib/parse_subs.c | 127 ++++++++++++++++++ |
|
modules/amd_parse.y | 49 ++++++- |
|
modules/amd_tok.l | 73 ++++++++++ |
|
modules/parse_amd.c | 348 ++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
5 files changed, 586 insertions(+), 13 deletions(-) |
|
|
|
diff --git a/include/parse_subs.h b/include/parse_subs.h |
|
index a416c59..43da182 100644 |
|
--- a/include/parse_subs.h |
|
+++ b/include/parse_subs.h |
|
@@ -111,6 +111,8 @@ struct map_type_info { |
|
}; |
|
|
|
unsigned int get_proximity(struct sockaddr *); |
|
+unsigned int get_network_proximity(const char *); |
|
+unsigned int in_network(char *); |
|
const char *skipspace(const char *); |
|
int check_colon(const char *); |
|
int chunklen(const char *, int); |
|
diff --git a/lib/parse_subs.c b/lib/parse_subs.c |
|
index f485a4c..de5319f 100644 |
|
--- a/lib/parse_subs.c |
|
+++ b/lib/parse_subs.c |
|
@@ -19,9 +19,13 @@ |
|
#include <string.h> |
|
#include <ctype.h> |
|
#include <sys/types.h> |
|
+#include <sys/socket.h> |
|
#include <ifaddrs.h> |
|
#include <libgen.h> |
|
#include <net/if.h> |
|
+#include <arpa/inet.h> |
|
+#include <netdb.h> |
|
+ |
|
#include "automount.h" |
|
|
|
#define MAX_OPTIONS_LEN 256 |
|
@@ -370,6 +374,129 @@ unsigned int get_proximity(struct sockaddr *host_addr) |
|
return PROXIMITY_OTHER; |
|
} |
|
|
|
+static char *inet_fill_net(const char *net_num, char *net) |
|
+{ |
|
+ char *np; |
|
+ unsigned int dots = 3; |
|
+ |
|
+ if (strlen(net_num) > INET_ADDRSTRLEN) |
|
+ return NULL; |
|
+ |
|
+ if (!isdigit(*net_num)) |
|
+ return NULL; |
|
+ |
|
+ *net = '\0'; |
|
+ strcpy(net, net_num); |
|
+ |
|
+ np = net; |
|
+ while (*np++) { |
|
+ if (*np == '.') { |
|
+ np++; |
|
+ dots--; |
|
+ if (!*np && dots) |
|
+ strcat(net, "0"); |
|
+ continue; |
|
+ } |
|
+ |
|
+ if ((*np && !isdigit(*np)) || dots < 0) { |
|
+ *net = '\0'; |
|
+ return NULL; |
|
+ } |
|
+ } |
|
+ |
|
+ while (dots--) |
|
+ strcat(net, ".0"); |
|
+ |
|
+ return net; |
|
+} |
|
+ |
|
+static char *get_network_number(const char *network) |
|
+{ |
|
+ struct netent *netent; |
|
+ char cnet[MAX_NETWORK_LEN]; |
|
+ uint32_t h_net; |
|
+ size_t len; |
|
+ |
|
+ len = strlen(network) + 1; |
|
+ if (len > MAX_NETWORK_LEN) |
|
+ return NULL; |
|
+ |
|
+ netent = getnetbyname(network); |
|
+ if (!netent) |
|
+ return NULL; |
|
+ h_net = ntohl(netent->n_net); |
|
+ |
|
+ if (!inet_ntop(AF_INET, &h_net, cnet, INET_ADDRSTRLEN)) |
|
+ return NULL; |
|
+ |
|
+ return strdup(cnet); |
|
+} |
|
+ |
|
+unsigned int get_network_proximity(const char *name) |
|
+{ |
|
+ struct addrinfo hints; |
|
+ struct addrinfo *ni, *this; |
|
+ char name_or_num[NI_MAXHOST]; |
|
+ unsigned int proximity; |
|
+ char *net; |
|
+ int ret; |
|
+ |
|
+ if (!name) |
|
+ return PROXIMITY_ERROR; |
|
+ |
|
+ net = get_network_number(name); |
|
+ if (net) |
|
+ strcpy(name_or_num, net); |
|
+ else { |
|
+ char this[NI_MAXHOST]; |
|
+ char *mask; |
|
+ |
|
+ strcpy(this, name); |
|
+ if ((mask = strchr(this, '/'))) |
|
+ *mask++ = '\0'; |
|
+ if (!strchr(this, '.')) |
|
+ strcpy(name_or_num, this); |
|
+ else { |
|
+ char buf[NI_MAXHOST], *new; |
|
+ new = inet_fill_net(this, buf); |
|
+ if (!new) |
|
+ return PROXIMITY_ERROR; |
|
+ strcpy(name_or_num, new); |
|
+ } |
|
+ } |
|
+ |
|
+ memset(&hints, 0, sizeof(struct addrinfo)); |
|
+ hints.ai_family = AF_UNSPEC; |
|
+ hints.ai_socktype = SOCK_DGRAM; |
|
+ |
|
+ ret = getaddrinfo(name_or_num, NULL, &hints, &ni); |
|
+ if (ret) { |
|
+ logerr("getaddrinfo: %s", gai_strerror(ret)); |
|
+ return PROXIMITY_ERROR; |
|
+ } |
|
+ |
|
+ proximity = PROXIMITY_OTHER; |
|
+ |
|
+ this = ni; |
|
+ while (this) { |
|
+ unsigned int prx = get_proximity(this->ai_addr); |
|
+ if (prx < proximity) |
|
+ proximity = prx; |
|
+ this = this->ai_next; |
|
+ } |
|
+ |
|
+ return proximity; |
|
+} |
|
+ |
|
+unsigned int in_network(char *network) |
|
+{ |
|
+ unsigned int proximity = get_network_proximity(network); |
|
+ if (proximity == PROXIMITY_ERROR || |
|
+ proximity > PROXIMITY_SUBNET) |
|
+ return 0; |
|
+ return 1; |
|
+} |
|
+ |
|
/* |
|
* Skip whitespace in a string; if we hit a #, consider the rest of the |
|
* entry a comment. |
|
diff --git a/modules/amd_parse.y b/modules/amd_parse.y |
|
index 33106a1..71fd569 100644 |
|
--- a/modules/amd_parse.y |
|
+++ b/modules/amd_parse.y |
|
@@ -92,6 +92,9 @@ static int amd_fprintf(FILE *, char *, ...); |
|
%token NOT_EQUAL |
|
%token COMMA |
|
%token OPTION_ASSIGN |
|
+%token LBRACKET |
|
+%token RBRACKET |
|
+%token NOT |
|
%token NILL |
|
|
|
%token <strtype> MAP_OPTION |
|
@@ -102,6 +105,7 @@ static int amd_fprintf(FILE *, char *, ...); |
|
%token <strtype> MNT_OPTION |
|
%token <strtype> SELECTOR |
|
%token <strtype> SELECTOR_VALUE |
|
+%token <strtype> SEL_ARG_VALUE |
|
%token <strtype> OPTION |
|
%token <strtype> MACRO |
|
%token <strtype> OTHER |
|
@@ -187,18 +191,46 @@ selector_or_option: selection |
|
|
|
selection: SELECTOR IS_EQUAL SELECTOR_VALUE |
|
{ |
|
- if (!make_selector($1, $3, NULL, SEL_TYPE_EQUAL)) { |
|
+ if (!make_selector($1, $3, NULL, SEL_COMP_EQUAL)) { |
|
amd_notify($1); |
|
YYABORT; |
|
} |
|
} |
|
| SELECTOR NOT_EQUAL SELECTOR_VALUE |
|
{ |
|
- if (!make_selector($1, $3, NULL, SEL_TYPE_NOTEQUAL)) { |
|
+ if (!make_selector($1, $3, NULL, SEL_COMP_NOTEQUAL)) { |
|
amd_notify($1); |
|
YYABORT; |
|
} |
|
} |
|
+ | SELECTOR LBRACKET SEL_ARG_VALUE RBRACKET |
|
+ { |
|
+ if (!make_selector($1, $3, NULL, SEL_COMP_NONE)) { |
|
+ amd_notify($1); |
|
+ YYABORT; |
|
+ } |
|
+ } |
|
+ | SELECTOR LBRACKET SEL_ARG_VALUE COMMA SEL_ARG_VALUE RBRACKET |
|
+ { |
|
+ if (!make_selector($1, $3, $5, SEL_COMP_NONE)) { |
|
+ amd_notify($1); |
|
+ YYABORT; |
|
+ } |
|
+ } |
|
+ | NOT SELECTOR LBRACKET SEL_ARG_VALUE RBRACKET |
|
+ { |
|
+ if (!make_selector($2, $4, NULL, SEL_COMP_NOT)) { |
|
+ amd_notify($2); |
|
+ YYABORT; |
|
+ } |
|
+ } |
|
+ | NOT SELECTOR LBRACKET SEL_ARG_VALUE COMMA SEL_ARG_VALUE RBRACKET |
|
+ { |
|
+ if (!make_selector($2, $4, $6, SEL_COMP_NOT)) { |
|
+ amd_notify($2); |
|
+ YYABORT; |
|
+ } |
|
+ } |
|
; |
|
|
|
option_assignment: MAP_OPTION OPTION_ASSIGN FS_TYPE |
|
@@ -388,9 +420,6 @@ static int make_selector(char *name, |
|
if (!sel_lookup(name)) |
|
return 0; |
|
|
|
- if (!value1) |
|
- return 0; |
|
- |
|
s = get_selector(name); |
|
if (!s) |
|
return 0; |
|
@@ -401,9 +430,13 @@ static int make_selector(char *name, |
|
goto error; |
|
s->comp.value = tmp; |
|
} else if (s->sel->flags & SEL_FLAG_FUNC1) { |
|
- char *tmp = amd_strdup(value1); |
|
- if (!tmp) |
|
- goto error; |
|
+ if (!value1) |
|
+ tmp = NULL; |
|
+ else { |
|
+ char *tmp = amd_strdup(value1); |
|
+ if (!tmp) |
|
+ goto error; |
|
+ } |
|
s->func.arg1 = tmp; |
|
} else if (s->sel->flags & SEL_FLAG_FUNC2) { |
|
char *tmp = amd_strdup(value1); |
|
diff --git a/modules/amd_tok.l b/modules/amd_tok.l |
|
index afa3a87..cea9ea5 100644 |
|
--- a/modules/amd_tok.l |
|
+++ b/modules/amd_tok.l |
|
@@ -70,22 +70,29 @@ int amd_yyinput(char *, int); |
|
|
|
%option nounput |
|
|
|
-%x MAPOPTVAL FSOPTVAL MNTOPTVAL SELOPTVAL |
|
+%x MAPOPTVAL FSOPTVAL MNTOPTVAL SELOPTVAL SELARGVAL |
|
|
|
NL \r?\n |
|
OPTWS [[:blank:]]* |
|
OTHR [^!;:=/|\- \t\r\n#]* |
|
|
|
+V4NUM ([01]?[0-9][0-9]?|2[0-4][0-9]|25[0-5]) |
|
+ |
|
MACRO (\$\{([[:alpha:]_/]([[:alnum:]_\-])([[:alnum:]_\-/])*)\}) |
|
QSTR (\"([^"\\]|\\.)*\") |
|
OSTR ([[:alpha:]]([[:alnum:]_\-])+) |
|
FSTR ([[:alnum:]_/\.]([[:alnum:]_\-/\.]|(\\.))*) |
|
VSTR (([[:alnum:]_\-\:/\.])+) |
|
SSTR ([[:alpha:]]([[:alnum:]\-\.])+) |
|
+IP4ADDR ({V4NUM}\.((({V4NUM}\.){0,2}){V4NUM}?)) |
|
+V4MASK ({IP4ADDR}|([1-2][0-9]|3[0-2]|[1-9])) |
|
+IP6ADDR ((([A-Fa-f0-9]{1,4}\:\:?){1,7}[A-Fa-f0-9]{1,4})|(\:\:1)) |
|
+V6MASK (12[0-8]|1[0-1][0-9]|[1-9][0-9]|[1-9]) |
|
|
|
FOPT (({QSTR}|{FSTR}|{MACRO})+) |
|
OPTS ({OSTR}(=({VSTR}|{QSTR}|{MACRO})+)?) |
|
SOPT (({SSTR}|{QSTR}|{MACRO})+) |
|
+NOPT ({SSTR}|(({IP4ADDR}(\/{V4MASK})?)|({IP6ADDR}(\/{V6MASK})?))) |
|
|
|
MAPOPT (fs|type|maptype|pref|sublink|delay) |
|
MNTOPT (opts|addopts|remopts) |
|
@@ -94,13 +101,16 @@ MAPTYPE (file|nis|nisplus|ldap|hesiod|exec|ndbm|passwd|union) |
|
FSTYPE (auto|nfs|link|host|nfsx|ufs|xfs|efs) |
|
|
|
OSSEL (arch|karch|os|osver|full_os|vendor) |
|
-HSTSEL (host|hostd|xhost|domain|byte|cluster) |
|
-NETSEL (netnumber|network|wire|netgrp|netgrpd|in_network) |
|
+HSTSEL (host|hostd|domain|byte|cluster) |
|
+NETSEL (netnumber|network|wire|in_network) |
|
USRSEL (uid|gid) |
|
MAPSEL (key|map|path) |
|
-OTRSEL (exists|autodir|dollar) |
|
+OTRSEL (autodir|dollar) |
|
BOLSEL (true|false) |
|
-SELOPT ({OSSEL}|{HSTSEL}|{NETSEL}|{BOLSEL}|{USRSEL}|{MAPSEL}|{OTRSEL}) |
|
+ |
|
+SELOPT ({OSSEL}|{HSTSEL}|{USRSEL}|{MAPSEL}|{OTRSEL}) |
|
+SEL1ARG (xhost|exists|{NETSEL}|{BOLSEL}) |
|
+SEL2ARG (netgrp|netgrpd) |
|
|
|
CUTSEP (\|\||\/) |
|
|
|
@@ -135,6 +145,20 @@ CUTSEP (\|\||\/) |
|
return SELECTOR; |
|
} |
|
|
|
+ "!"/({SEL1ARG}|{SEL2ARG}) { return NOT; } |
|
+ |
|
+ {SEL1ARG} { |
|
+ BEGIN(SELARGVAL); |
|
+ strcpy(amd_lval.strtype, amd_text); |
|
+ return SELECTOR; |
|
+ } |
|
+ |
|
+ {SEL2ARG} { |
|
+ BEGIN(SELARGVAL); |
|
+ strcpy(amd_lval.strtype, amd_text); |
|
+ return SELECTOR; |
|
+ } |
|
+ |
|
{CUTSEP} { return CUT; } |
|
|
|
"-" { return HYPHEN; } |
|
@@ -263,6 +287,45 @@ CUTSEP (\|\||\/) |
|
} |
|
} |
|
|
|
+<SELARGVAL>{ |
|
+ {NL} | |
|
+ \x00 { |
|
+ BEGIN(INITIAL); |
|
+ yyless(1); |
|
+ } |
|
+ |
|
+ ";" { |
|
+ BEGIN(INITIAL); |
|
+ return SEPERATOR; |
|
+ } |
|
+ |
|
+ "(" { return LBRACKET; } |
|
+ |
|
+ {NOPT} { |
|
+ strcpy(amd_lval.strtype, amd_text); |
|
+ return SEL_ARG_VALUE; |
|
+ } |
|
+ |
|
+ {SOPT}/"," { |
|
+ strcpy(amd_lval.strtype, amd_text); |
|
+ return SEL_ARG_VALUE; |
|
+ } |
|
+ |
|
+ "," { return COMMA; } |
|
+ |
|
+ {SOPT} { |
|
+ strcpy(amd_lval.strtype, amd_text); |
|
+ return SEL_ARG_VALUE; |
|
+ } |
|
+ |
|
+ {FOPT} { |
|
+ strcpy(amd_lval.strtype, amd_text); |
|
+ return SEL_ARG_VALUE; |
|
+ } |
|
+ |
|
+ ")" { return RBRACKET; } |
|
+} |
|
+ |
|
%% |
|
|
|
#include "automount.h" |
|
diff --git a/modules/parse_amd.c b/modules/parse_amd.c |
|
index 35cc5dc..d9c7d9b 100644 |
|
--- a/modules/parse_amd.c |
|
+++ b/modules/parse_amd.c |
|
@@ -223,6 +223,307 @@ static struct substvar *add_lookup_vars(struct autofs_point *ap, |
|
return list; |
|
} |
|
|
|
+static int match_my_name(unsigned int logopt, const char *name, struct substvar *sv) |
|
+{ |
|
+ struct addrinfo hints, *cni, *ni, *haddr; |
|
+ char host[NI_MAXHOST + 1], numeric[NI_MAXHOST + 1]; |
|
+ const struct substvar *v; |
|
+ int rv = 0, ret; |
|
+ |
|
+ v = macro_findvar(sv, "host", 4); |
|
+ if (v) { |
|
+ if (!strcmp(v->val, name)) |
|
+ return 1; |
|
+ } |
|
+ |
|
+ /* Check if comparison value is an alias */ |
|
+ |
|
+ memset(&hints, 0, sizeof(hints)); |
|
+ hints.ai_flags = AI_CANONNAME; |
|
+ hints.ai_family = AF_UNSPEC; |
|
+ hints.ai_socktype = SOCK_DGRAM; |
|
+ |
|
+ /* Get host canonical name */ |
|
+ ret = getaddrinfo(v->val, NULL, &hints, &cni); |
|
+ if (ret) { |
|
+ error(logopt, |
|
+ "hostname lookup failed: %s\n", gai_strerror(ret)); |
|
+ goto out; |
|
+ } |
|
+ |
|
+ hints.ai_flags = 0; |
|
+ |
|
+ /* Resolve comparison name to its names and compare */ |
|
+ ret = getaddrinfo(name, NULL, &hints, &ni); |
|
+ if (ret) { |
|
+ error(logopt, |
|
+ "hostname lookup failed: %s\n", gai_strerror(ret)); |
|
+ freeaddrinfo(cni); |
|
+ goto out; |
|
+ } |
|
+ |
|
+ haddr = ni; |
|
+ while (haddr) { |
|
+ /* Translate the host address into a numeric string form */ |
|
+ ret = getnameinfo(haddr->ai_addr, haddr->ai_addrlen, |
|
+ numeric, sizeof(numeric), NULL, 0, |
|
+ NI_NUMERICHOST); |
|
+ if (ret) { |
|
+ error(logopt, |
|
+ "host address info lookup failed: %s\n", |
|
+ gai_strerror(ret)); |
|
+ freeaddrinfo(cni); |
|
+ goto next; |
|
+ } |
|
+ |
|
+ /* Try to resolve back again to get the canonical name */ |
|
+ ret = getnameinfo(haddr->ai_addr, haddr->ai_addrlen, |
|
+ host, NI_MAXHOST, NULL, 0, 0); |
|
+ if (ret) { |
|
+ error(logopt, |
|
+ "host address info lookup failed: %s\n", |
|
+ gai_strerror(ret)); |
|
+ freeaddrinfo(cni); |
|
+ goto next; |
|
+ } |
|
+ |
|
+ if (!strcmp(host, cni->ai_canonname)) { |
|
+ rv = 1; |
|
+ break; |
|
+ } |
|
+next: |
|
+ haddr = haddr->ai_next; |
|
+ } |
|
+ freeaddrinfo(ni); |
|
+ freeaddrinfo(cni); |
|
+out: |
|
+ return rv; |
|
+} |
|
+ |
|
+static int eval_selector(unsigned int logopt, |
|
+ struct amd_entry *this, struct substvar *sv) |
|
+{ |
|
+ struct selector *s = this->selector; |
|
+ const struct substvar *v; |
|
+ unsigned int s_type; |
|
+ unsigned int v_type; |
|
+ struct stat st; |
|
+ char *host; |
|
+ int res, val, ret = 0; |
|
+ |
|
+ s_type = s->sel->flags & SEL_FLAGS_TYPE_MASK; |
|
+ |
|
+ switch (s_type) { |
|
+ case SEL_FLAG_MACRO: |
|
+ v = macro_findvar(sv, s->sel->name, strlen(s->sel->name)); |
|
+ if (!v) { |
|
+ error(logopt, "failed to get selector %s", s->sel->name); |
|
+ return 0; |
|
+ } |
|
+ |
|
+ v_type = s->sel->flags & SEL_FLAGS_VALUE_MASK; |
|
+ |
|
+ switch (v_type) { |
|
+ case SEL_FLAG_STR: |
|
+ res = strcmp(v->val, s->comp.value); |
|
+ if (s->compare & SEL_COMP_EQUAL && !res) { |
|
+ debug(logopt, MODPREFIX |
|
+ "matched selector %s(%s) == %s", |
|
+ v->def, v->val, s->comp.value); |
|
+ ret = 1; |
|
+ break; |
|
+ } else if (s->compare & SEL_COMP_NOTEQUAL && res) { |
|
+ debug(logopt, MODPREFIX |
|
+ "matched selector %s(%s) != %s", |
|
+ v->def, v->val, s->comp.value); |
|
+ ret = 1; |
|
+ break; |
|
+ } |
|
+ |
|
+ debug(logopt, MODPREFIX |
|
+ "did not match selector %s(%s) %s %s", |
|
+ v->def, v->val, |
|
+ (s->compare & SEL_COMP_EQUAL ? "==" : "!="), |
|
+ s->comp.value); |
|
+ break; |
|
+ |
|
+ case SEL_FLAG_NUM: |
|
+ res = atoi(v->val); |
|
+ val = atoi(s->comp.value); |
|
+ if (s->compare & SEL_COMP_EQUAL && res == val) { |
|
+ debug(logopt, MODPREFIX |
|
+ "matched selector %s(%s) equal to %s", |
|
+ v->def, v->val, s->comp.value); |
|
+ ret = 1; |
|
+ break; |
|
+ } else if (s->compare & SEL_COMP_NOTEQUAL && res != val) { |
|
+ debug(logopt, MODPREFIX |
|
+ "matched selector %s(%s) not equal to %s", |
|
+ v->def, v->val, s->comp.value); |
|
+ ret = 1; |
|
+ break; |
|
+ } |
|
+ |
|
+ debug(logopt, MODPREFIX |
|
+ "did not match selector %s(%s) %s %s", |
|
+ v->def, v->val, |
|
+ (s->compare & SEL_COMP_EQUAL ? "==" : "!="), |
|
+ s->comp.value); |
|
+ break; |
|
+ |
|
+ default: |
|
+ break; |
|
+ } |
|
+ break; |
|
+ |
|
+ case SEL_FLAG_FUNC1: |
|
+ if (s->sel->selector != SEL_TRUE && |
|
+ s->sel->selector != SEL_FALSE && |
|
+ !s->func.arg1) { |
|
+ error(logopt, MODPREFIX |
|
+ "expected argument missing for selector %s", |
|
+ s->sel->name); |
|
+ break; |
|
+ } |
|
+ |
|
+ switch (s->sel->selector) { |
|
+ case SEL_TRUE: |
|
+ ret = 1; |
|
+ if (s->compare == SEL_COMP_NOT) |
|
+ ret = !ret; |
|
+ if (ret) |
|
+ debug(logopt, MODPREFIX |
|
+ "matched selector %s(%s)", |
|
+ s->sel->name, s->func.arg1); |
|
+ else |
|
+ debug(logopt, MODPREFIX |
|
+ "did not match selector %s(%s)", |
|
+ s->sel->name, s->func.arg1); |
|
+ break; |
|
+ |
|
+ case SEL_FALSE: |
|
+ if (s->compare == SEL_COMP_NOT) |
|
+ ret = !ret; |
|
+ if (ret) |
|
+ debug(logopt, MODPREFIX |
|
+ "matched selector %s(%s)", |
|
+ s->sel->name, s->func.arg1); |
|
+ else |
|
+ debug(logopt, MODPREFIX |
|
+ "did not match selector %s(%s)", |
|
+ s->sel->name, s->func.arg1); |
|
+ break; |
|
+ |
|
+ case SEL_XHOST: |
|
+ ret = match_my_name(logopt, s->func.arg1, sv); |
|
+ if (s->compare == SEL_COMP_NOT) |
|
+ ret = !ret; |
|
+ if (ret) |
|
+ debug(logopt, MODPREFIX |
|
+ "matched selector %s(%s) to host name", |
|
+ s->sel->name, s->func.arg1); |
|
+ else |
|
+ debug(logopt, MODPREFIX |
|
+ "did not match selector %s(%s) to host name", |
|
+ s->sel->name, s->func.arg1); |
|
+ break; |
|
+ |
|
+ case SEL_EXISTS: |
|
+ /* Sould be OK to fail on any error here */ |
|
+ ret = !lstat(s->func.arg1, &st); |
|
+ if (s->compare == SEL_COMP_NOT) |
|
+ ret = !ret; |
|
+ if (ret) |
|
+ debug(logopt, MODPREFIX |
|
+ "matched selector %s(%s)", |
|
+ s->sel->name, s->func.arg1); |
|
+ else |
|
+ debug(logopt, MODPREFIX |
|
+ "did not match selector %s(%s)", |
|
+ s->sel->name, s->func.arg1); |
|
+ break; |
|
+ |
|
+ case SEL_IN_NETWORK: |
|
+ ret = in_network(s->func.arg1); |
|
+ if (s->compare == SEL_COMP_NOT) |
|
+ ret = !ret; |
|
+ if (ret) |
|
+ debug(logopt, MODPREFIX |
|
+ "matched selector %s(%s)", |
|
+ s->sel->name, s->func.arg1); |
|
+ else |
|
+ debug(logopt, MODPREFIX |
|
+ "did not match selector %s(%s)", |
|
+ s->sel->name, s->func.arg1); |
|
+ break; |
|
+ |
|
+ default: |
|
+ break; |
|
+ } |
|
+ break; |
|
+ |
|
+ case SEL_FLAG_FUNC2: |
|
+ if (!s->func.arg1) { |
|
+ error(logopt, MODPREFIX |
|
+ "expected argument missing for selector %s", |
|
+ s->sel->name); |
|
+ break; |
|
+ } |
|
+ |
|
+ switch (s->sel->selector) { |
|
+ case SEL_NETGRP: |
|
+ case SEL_NETGRPD: |
|
+ if (s->func.arg2) |
|
+ host = s->func.arg2; |
|
+ else { |
|
+ if (s->sel->selector == SEL_NETGRP) |
|
+ v = macro_findvar(sv, "host", 4); |
|
+ else |
|
+ v = macro_findvar(sv, "hostd", 5); |
|
+ if (!v || !*v->val) { |
|
+ error(logopt, |
|
+ "failed to get value of ${host}"); |
|
+ break; |
|
+ } |
|
+ host = v->val; |
|
+ } |
|
+ ret = innetgr(s->func.arg1, host, NULL, NULL); |
|
+ if (s->compare == SEL_COMP_NOT) |
|
+ ret = !ret; |
|
+ if (ret) { |
|
+ if (!s->func.arg2) |
|
+ debug(logopt, MODPREFIX |
|
+ "matched selector %s(%s)", |
|
+ s->sel->name, s->func.arg1); |
|
+ else |
|
+ debug(logopt, MODPREFIX |
|
+ "matched selector %s(%s,%s)", |
|
+ s->sel->name, s->func.arg1, |
|
+ s->func.arg2); |
|
+ } else { |
|
+ if (!s->func.arg2) |
|
+ debug(logopt, MODPREFIX |
|
+ "did not match selector %s(%s)", |
|
+ s->sel->name, s->func.arg1); |
|
+ else |
|
+ debug(logopt, MODPREFIX |
|
+ "did not match selector %s(%s,%s)", |
|
+ s->sel->name, s->func.arg1, s->func.arg2); |
|
+ } |
|
+ break; |
|
+ |
|
+ default: |
|
+ break; |
|
+ } |
|
+ break; |
|
+ |
|
+ default: |
|
+ break; |
|
+ } |
|
+ |
|
+ return ret; |
|
+} |
|
+ |
|
static void update_with_defaults(struct amd_entry *defaults, |
|
struct amd_entry *entry, |
|
struct substvar *sv) |
|
@@ -884,6 +1185,33 @@ static void update_prefix(struct autofs_point *ap, |
|
return; |
|
} |
|
|
|
+static int match_selectors(unsigned int logopt, |
|
+ struct amd_entry *entry, struct substvar *sv) |
|
+{ |
|
+ struct selector *s = entry->selector; |
|
+ int ret; |
|
+ |
|
+ /* No selectors, always match */ |
|
+ if (!s) { |
|
+ debug(logopt, "no selectors found in location"); |
|
+ return 1; |
|
+ } |
|
+ |
|
+ ret = 0; |
|
+ |
|
+ /* All selectors must match */ |
|
+ while (s) { |
|
+ ret = eval_selector(logopt, entry, sv); |
|
+ if (!ret) |
|
+ break; |
|
+ s = s->next; |
|
+ } |
|
+ if (!s) |
|
+ ret = 1; |
|
+ |
|
+ return ret; |
|
+} |
|
+ |
|
static struct amd_entry *dup_defaults_entry(struct amd_entry *defaults) |
|
{ |
|
struct amd_entry *entry; |
|
@@ -1008,6 +1336,23 @@ static struct amd_entry *select_default_entry(struct autofs_point *ap, |
|
free_amd_entry(this); |
|
continue; |
|
} |
|
+ |
|
+ /* |
|
+ * This probably should be a fail since we expect |
|
+ * selectors to pick the default entry. |
|
+ */ |
|
+ if (!this->selector) |
|
+ continue; |
|
+ |
|
+ if (match_selectors(ap->logopt, this, sv)) { |
|
+ if (entry_default) { |
|
+ /*update_with_defaults(entry_default, this, sv);*/ |
|
+ free_amd_entry(entry_default); |
|
+ } |
|
+ list_del_init(&this->list); |
|
+ defaults_entry = this; |
|
+ break; |
|
+ } |
|
} |
|
|
|
/* Not strickly amd semantics but ... */ |
|
@@ -1195,6 +1540,9 @@ int parse_mount(struct autofs_point *ap, const char *name, |
|
continue; |
|
} |
|
|
|
+ if (!match_selectors(ap->logopt, this, sv)) |
|
+ continue; |
|
+ |
|
update_with_defaults(cur_defaults, this, sv); |
|
sv = expand_entry(ap, this, flags, sv); |
|
sv = merge_entry_options(ap, this, sv);
|
|
|