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.
463 lines
12 KiB
463 lines
12 KiB
7 years ago
|
autofs-5.0.9 - amd lookup update lookup program to handle amd keys
|
||
|
|
||
|
From: Ian Kent <raven@themaw.net>
|
||
|
|
||
|
|
||
|
---
|
||
|
modules/lookup_program.c | 390 +++++++++++++++++++++++++++++++++-------------
|
||
|
1 file changed, 282 insertions(+), 108 deletions(-)
|
||
|
|
||
|
diff --git a/modules/lookup_program.c b/modules/lookup_program.c
|
||
|
index 6ce94e4..08d14ff 100644
|
||
|
--- a/modules/lookup_program.c
|
||
|
+++ b/modules/lookup_program.c
|
||
|
@@ -113,123 +113,30 @@ int lookup_read_map(struct autofs_point *ap, time_t age, void *context)
|
||
|
return NSS_STATUS_UNKNOWN;
|
||
|
}
|
||
|
|
||
|
-int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *context)
|
||
|
+static char *lookup_one(struct autofs_point *ap,
|
||
|
+ const char *name, int name_len,
|
||
|
+ struct lookup_context *ctxt)
|
||
|
{
|
||
|
- struct lookup_context *ctxt = (struct lookup_context *) context;
|
||
|
- struct map_source *source;
|
||
|
- struct mapent_cache *mc;
|
||
|
char *mapent = NULL, *mapp, *tmp;
|
||
|
- struct mapent *me;
|
||
|
char buf[MAX_ERR_BUF];
|
||
|
char errbuf[1024], *errp;
|
||
|
char ch;
|
||
|
int pipefd[2], epipefd[2];
|
||
|
struct pollfd pfd[2];
|
||
|
pid_t f;
|
||
|
- int status;
|
||
|
enum state { st_space, st_map, st_done } state;
|
||
|
int quoted = 0;
|
||
|
- int ret = 1;
|
||
|
int distance;
|
||
|
int alloci = 1;
|
||
|
-
|
||
|
- source = ap->entry->current;
|
||
|
- ap->entry->current = NULL;
|
||
|
- master_source_current_signal(ap->entry);
|
||
|
-
|
||
|
- mc = source->mc;
|
||
|
-
|
||
|
- /* Check if we recorded a mount fail for this key anywhere */
|
||
|
- me = lookup_source_mapent(ap, name, LKP_DISTINCT);
|
||
|
- if (me) {
|
||
|
- if (me->status >= time(NULL)) {
|
||
|
- cache_unlock(me->mc);
|
||
|
- return NSS_STATUS_NOTFOUND;
|
||
|
- } else {
|
||
|
- struct mapent_cache *smc = me->mc;
|
||
|
- struct mapent *sme;
|
||
|
-
|
||
|
- if (me->mapent)
|
||
|
- cache_unlock(smc);
|
||
|
- else {
|
||
|
- cache_unlock(smc);
|
||
|
- cache_writelock(smc);
|
||
|
- sme = cache_lookup_distinct(smc, name);
|
||
|
- /* Negative timeout expired for non-existent entry. */
|
||
|
- if (sme && !sme->mapent) {
|
||
|
- if (cache_pop_mapent(sme) == CHE_FAIL)
|
||
|
- cache_delete(smc, name);
|
||
|
- }
|
||
|
- cache_unlock(smc);
|
||
|
- }
|
||
|
- }
|
||
|
- }
|
||
|
-
|
||
|
- /* Catch installed direct offset triggers */
|
||
|
- cache_readlock(mc);
|
||
|
- me = cache_lookup_distinct(mc, name);
|
||
|
- if (!me) {
|
||
|
- cache_unlock(mc);
|
||
|
- /*
|
||
|
- * If there's a '/' in the name and the offset is not in
|
||
|
- * the cache then it's not a valid path in the mount tree.
|
||
|
- */
|
||
|
- if (strchr(name, '/')) {
|
||
|
- debug(ap->logopt,
|
||
|
- MODPREFIX "offset %s not found", name);
|
||
|
- return NSS_STATUS_NOTFOUND;
|
||
|
- }
|
||
|
- } else {
|
||
|
- /* Otherwise we found a valid offset so try mount it */
|
||
|
- debug(ap->logopt, MODPREFIX "%s -> %s", name, me->mapent);
|
||
|
-
|
||
|
- /*
|
||
|
- * If this is a request for an offset mount (whose entry
|
||
|
- * must be present in the cache to be valid) or the entry
|
||
|
- * is newer than the negative timeout value then just
|
||
|
- * try and mount it. Otherwise try and remove it and
|
||
|
- * proceed with the program map lookup.
|
||
|
- */
|
||
|
- if (strchr(name, '/') ||
|
||
|
- me->age + ap->negative_timeout > time(NULL)) {
|
||
|
- char *ent = NULL;
|
||
|
-
|
||
|
- if (me->mapent) {
|
||
|
- ent = alloca(strlen(me->mapent) + 1);
|
||
|
- strcpy(ent, me->mapent);
|
||
|
- }
|
||
|
- cache_unlock(mc);
|
||
|
- master_source_current_wait(ap->entry);
|
||
|
- ap->entry->current = source;
|
||
|
- ret = ctxt->parse->parse_mount(ap, name,
|
||
|
- name_len, ent, ctxt->parse->context);
|
||
|
- goto out_free;
|
||
|
- } else {
|
||
|
- if (me->multi) {
|
||
|
- cache_unlock(mc);
|
||
|
- warn(ap->logopt, MODPREFIX
|
||
|
- "unexpected lookup for active multi-mount"
|
||
|
- " key %s, returning fail", name);
|
||
|
- return NSS_STATUS_UNAVAIL;
|
||
|
- }
|
||
|
- cache_unlock(mc);
|
||
|
- cache_writelock(mc);
|
||
|
- me = cache_lookup_distinct(mc, name);
|
||
|
- if (me)
|
||
|
- cache_delete(mc, name);
|
||
|
- cache_unlock(mc);
|
||
|
- }
|
||
|
- }
|
||
|
+ int status;
|
||
|
|
||
|
mapent = (char *) malloc(MAPENT_MAX_LEN + 1);
|
||
|
if (!mapent) {
|
||
|
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
|
||
|
logerr(MODPREFIX "malloc: %s", estr);
|
||
|
- return NSS_STATUS_UNAVAIL;
|
||
|
+ return NULL;
|
||
|
}
|
||
|
|
||
|
- debug(ap->logopt, MODPREFIX "looking up %s", name);
|
||
|
-
|
||
|
/*
|
||
|
* We don't use popen because we don't want to run /bin/sh plus we
|
||
|
* want to send stderr to the syslog, and we don't use spawnl()
|
||
|
@@ -238,12 +145,12 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
|
||
|
if (open_pipe(pipefd)) {
|
||
|
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
|
||
|
logerr(MODPREFIX "pipe: %s", estr);
|
||
|
- goto out_free;
|
||
|
+ goto out_error;
|
||
|
}
|
||
|
if (open_pipe(epipefd)) {
|
||
|
close(pipefd[0]);
|
||
|
close(pipefd[1]);
|
||
|
- goto out_free;
|
||
|
+ goto out_error;
|
||
|
}
|
||
|
|
||
|
f = fork();
|
||
|
@@ -254,7 +161,7 @@ int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *
|
||
|
close(pipefd[1]);
|
||
|
close(epipefd[0]);
|
||
|
close(epipefd[1]);
|
||
|
- goto out_free;
|
||
|
+ goto out_error;
|
||
|
} else if (f == 0) {
|
||
|
reset_signals();
|
||
|
close(pipefd[0]);
|
||
|
@@ -420,21 +327,288 @@ next:
|
||
|
if (waitpid(f, &status, 0) != f) {
|
||
|
char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
|
||
|
logerr(MODPREFIX "waitpid: %s", estr);
|
||
|
- goto out_free;
|
||
|
+ goto out_error;
|
||
|
}
|
||
|
|
||
|
if (mapp == mapent || !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
||
|
info(ap->logopt, MODPREFIX "lookup for %s failed", name);
|
||
|
- goto out_free;
|
||
|
+ goto out_error;
|
||
|
}
|
||
|
|
||
|
- cache_writelock(mc);
|
||
|
- ret = cache_update(mc, source, name, mapent, time(NULL));
|
||
|
- cache_unlock(mc);
|
||
|
- if (ret == CHE_FAIL) {
|
||
|
+ return mapent;
|
||
|
+
|
||
|
+out_error:
|
||
|
+ if (mapent)
|
||
|
free(mapent);
|
||
|
- return NSS_STATUS_UNAVAIL;
|
||
|
+
|
||
|
+ return NULL;
|
||
|
+}
|
||
|
+
|
||
|
+static int lookup_amd_defaults(struct autofs_point *ap,
|
||
|
+ struct map_source *source,
|
||
|
+ struct lookup_context *ctxt)
|
||
|
+{
|
||
|
+ struct mapent_cache *mc = source->mc;
|
||
|
+ char *ment = lookup_one(ap, "/defaults", 9, ctxt);
|
||
|
+ if (ment) {
|
||
|
+ char *start = ment + 9;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ while (isblank(*start))
|
||
|
+ start++;
|
||
|
+ cache_writelock(mc);
|
||
|
+ ret = cache_update(mc, source, "/defaults", start, time(NULL));
|
||
|
+ cache_unlock(mc);
|
||
|
+ if (ret == CHE_FAIL) {
|
||
|
+ free(ment);
|
||
|
+ return NSS_STATUS_UNAVAIL;
|
||
|
+ }
|
||
|
+ free(ment);
|
||
|
}
|
||
|
+ return NSS_STATUS_SUCCESS;
|
||
|
+}
|
||
|
+
|
||
|
+static int match_key(struct autofs_point *ap,
|
||
|
+ struct map_source *source,
|
||
|
+ const char *name, int name_len,
|
||
|
+ char **mapent, struct lookup_context *ctxt)
|
||
|
+{
|
||
|
+ unsigned int is_amd_format = source->flags & MAP_FLAG_FORMAT_AMD;
|
||
|
+ struct mapent_cache *mc = source->mc;
|
||
|
+ char buf[MAX_ERR_BUF];
|
||
|
+ char *ment;
|
||
|
+ char *lkp_key;
|
||
|
+ size_t lkp_len;
|
||
|
+ char *prefix;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ if (source->flags & MAP_FLAG_FORMAT_AMD) {
|
||
|
+ ret = lookup_amd_defaults(ap, source, ctxt);
|
||
|
+ if (ret != NSS_STATUS_SUCCESS) {
|
||
|
+ warn(ap->logopt,
|
||
|
+ MODPREFIX "failed to save /defaults entry");
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!is_amd_format) {
|
||
|
+ lkp_key = strdup(name);
|
||
|
+ lkp_len = name_len;
|
||
|
+ } else {
|
||
|
+ size_t len;
|
||
|
+
|
||
|
+ if (ap->pref)
|
||
|
+ len = strlen(ap->pref) + strlen(name);
|
||
|
+ else
|
||
|
+ len = strlen(name);
|
||
|
+
|
||
|
+ lkp_key = malloc(len + 1);
|
||
|
+ if (!lkp_key) {
|
||
|
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
|
||
|
+ error(ap->logopt, MODPREFIX "malloc: %s", estr);
|
||
|
+ return NSS_STATUS_UNAVAIL;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (ap->pref) {
|
||
|
+ strcpy(lkp_key, ap->pref);
|
||
|
+ strcat(lkp_key, name);
|
||
|
+ } else
|
||
|
+ strcpy(lkp_key, name);
|
||
|
+
|
||
|
+ lkp_len = len;
|
||
|
+ }
|
||
|
+
|
||
|
+ ment = lookup_one(ap, lkp_key, lkp_len, ctxt);
|
||
|
+ if (ment) {
|
||
|
+ char *start = ment;
|
||
|
+ if (source->flags & MAP_FLAG_FORMAT_AMD) {
|
||
|
+ start = ment + lkp_len;
|
||
|
+ while (isblank(*start))
|
||
|
+ start++;
|
||
|
+ }
|
||
|
+ cache_writelock(mc);
|
||
|
+ ret = cache_update(mc, source, lkp_key, start, time(NULL));
|
||
|
+ cache_unlock(mc);
|
||
|
+ if (ret == CHE_FAIL) {
|
||
|
+ free(ment);
|
||
|
+ free(lkp_key);
|
||
|
+ return NSS_STATUS_UNAVAIL;
|
||
|
+ }
|
||
|
+ *mapent = strdup(start);
|
||
|
+ if (!*mapent) {
|
||
|
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
|
||
|
+ error(ap->logopt, MODPREFIX "malloc: %s", estr);
|
||
|
+ free(lkp_key);
|
||
|
+ free(ment);
|
||
|
+ return NSS_STATUS_UNAVAIL;
|
||
|
+ }
|
||
|
+ free(lkp_key);
|
||
|
+ free(ment);
|
||
|
+ return NSS_STATUS_SUCCESS;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!is_amd_format) {
|
||
|
+ free(lkp_key);
|
||
|
+ return NSS_STATUS_NOTFOUND;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = NSS_STATUS_NOTFOUND;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Now strip successive directory components and try a
|
||
|
+ * match against map entries ending with a wildcard and
|
||
|
+ * finally try the wilcard entry itself.
|
||
|
+ */
|
||
|
+ while ((prefix = strrchr(lkp_key, '/'))) {
|
||
|
+ char *match;
|
||
|
+ size_t len;
|
||
|
+ *prefix = '\0';
|
||
|
+ len = strlen(lkp_key) + 3;
|
||
|
+ match = malloc(len);
|
||
|
+ if (!match) {
|
||
|
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
|
||
|
+ error(ap->logopt, MODPREFIX "malloc: %s", estr);
|
||
|
+ free(lkp_key);
|
||
|
+ return NSS_STATUS_UNAVAIL;
|
||
|
+ }
|
||
|
+ len--;
|
||
|
+ strcpy(match, lkp_key);
|
||
|
+ strcat(match, "/*");
|
||
|
+ ment = lookup_one(ap, match, len, ctxt);
|
||
|
+ if (ment) {
|
||
|
+ char *start = ment + len;
|
||
|
+ while (isblank(*start))
|
||
|
+ start++;
|
||
|
+ cache_writelock(mc);
|
||
|
+ ret = cache_update(mc, source, match, start, time(NULL));
|
||
|
+ cache_unlock(mc);
|
||
|
+ if (ret == CHE_FAIL) {
|
||
|
+ free(match);
|
||
|
+ free(ment);
|
||
|
+ free(lkp_key);
|
||
|
+ return NSS_STATUS_UNAVAIL;
|
||
|
+ }
|
||
|
+ free(match);
|
||
|
+ *mapent = strdup(start);
|
||
|
+ if (!*mapent) {
|
||
|
+ char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
|
||
|
+ error(ap->logopt, MODPREFIX "malloc: %s", estr);
|
||
|
+ free(ment);
|
||
|
+ free(lkp_key);
|
||
|
+ return NSS_STATUS_UNAVAIL;
|
||
|
+ }
|
||
|
+ free(ment);
|
||
|
+ free(lkp_key);
|
||
|
+ return NSS_STATUS_SUCCESS;
|
||
|
+ }
|
||
|
+ free(match);
|
||
|
+ }
|
||
|
+ free(lkp_key);
|
||
|
+
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+int lookup_mount(struct autofs_point *ap, const char *name, int name_len, void *context)
|
||
|
+{
|
||
|
+ struct lookup_context *ctxt = (struct lookup_context *) context;
|
||
|
+ struct map_source *source;
|
||
|
+ struct mapent_cache *mc;
|
||
|
+ char *mapent = NULL;
|
||
|
+ struct mapent *me;
|
||
|
+ int ret = 1;
|
||
|
+
|
||
|
+ source = ap->entry->current;
|
||
|
+ ap->entry->current = NULL;
|
||
|
+ master_source_current_signal(ap->entry);
|
||
|
+
|
||
|
+ mc = source->mc;
|
||
|
+
|
||
|
+ /* Check if we recorded a mount fail for this key anywhere */
|
||
|
+ me = lookup_source_mapent(ap, name, LKP_DISTINCT);
|
||
|
+ if (me) {
|
||
|
+ if (me->status >= time(NULL)) {
|
||
|
+ cache_unlock(me->mc);
|
||
|
+ return NSS_STATUS_NOTFOUND;
|
||
|
+ } else {
|
||
|
+ struct mapent_cache *smc = me->mc;
|
||
|
+ struct mapent *sme;
|
||
|
+
|
||
|
+ if (me->mapent)
|
||
|
+ cache_unlock(smc);
|
||
|
+ else {
|
||
|
+ cache_unlock(smc);
|
||
|
+ cache_writelock(smc);
|
||
|
+ sme = cache_lookup_distinct(smc, name);
|
||
|
+ /* Negative timeout expired for non-existent entry. */
|
||
|
+ if (sme && !sme->mapent) {
|
||
|
+ if (cache_pop_mapent(sme) == CHE_FAIL)
|
||
|
+ cache_delete(smc, name);
|
||
|
+ }
|
||
|
+ cache_unlock(smc);
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Catch installed direct offset triggers */
|
||
|
+ cache_readlock(mc);
|
||
|
+ me = cache_lookup_distinct(mc, name);
|
||
|
+ if (!me) {
|
||
|
+ cache_unlock(mc);
|
||
|
+ /*
|
||
|
+ * If there's a '/' in the name and the offset is not in
|
||
|
+ * the cache then it's not a valid path in the mount tree.
|
||
|
+ */
|
||
|
+ if (strchr(name, '/')) {
|
||
|
+ debug(ap->logopt,
|
||
|
+ MODPREFIX "offset %s not found", name);
|
||
|
+ return NSS_STATUS_NOTFOUND;
|
||
|
+ }
|
||
|
+ } else {
|
||
|
+ /* Otherwise we found a valid offset so try mount it */
|
||
|
+ debug(ap->logopt, MODPREFIX "%s -> %s", name, me->mapent);
|
||
|
+
|
||
|
+ /*
|
||
|
+ * If this is a request for an offset mount (whose entry
|
||
|
+ * must be present in the cache to be valid) or the entry
|
||
|
+ * is newer than the negative timeout value then just
|
||
|
+ * try and mount it. Otherwise try and remove it and
|
||
|
+ * proceed with the program map lookup.
|
||
|
+ */
|
||
|
+ if (strchr(name, '/') ||
|
||
|
+ me->age + ap->negative_timeout > time(NULL)) {
|
||
|
+ char *ent = NULL;
|
||
|
+
|
||
|
+ if (me->mapent) {
|
||
|
+ ent = alloca(strlen(me->mapent) + 1);
|
||
|
+ strcpy(ent, me->mapent);
|
||
|
+ }
|
||
|
+ cache_unlock(mc);
|
||
|
+ master_source_current_wait(ap->entry);
|
||
|
+ ap->entry->current = source;
|
||
|
+ ret = ctxt->parse->parse_mount(ap, name,
|
||
|
+ name_len, ent, ctxt->parse->context);
|
||
|
+ goto out_free;
|
||
|
+ } else {
|
||
|
+ if (me->multi) {
|
||
|
+ cache_unlock(mc);
|
||
|
+ warn(ap->logopt, MODPREFIX
|
||
|
+ "unexpected lookup for active multi-mount"
|
||
|
+ " key %s, returning fail", name);
|
||
|
+ return NSS_STATUS_UNAVAIL;
|
||
|
+ }
|
||
|
+ cache_unlock(mc);
|
||
|
+ cache_writelock(mc);
|
||
|
+ me = cache_lookup_distinct(mc, name);
|
||
|
+ if (me)
|
||
|
+ cache_delete(mc, name);
|
||
|
+ cache_unlock(mc);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ debug(ap->logopt, MODPREFIX "looking up %s", name);
|
||
|
+
|
||
|
+ ret = match_key(ap, source, name, name_len, &mapent, ctxt);
|
||
|
+ if (ret != NSS_STATUS_SUCCESS)
|
||
|
+ goto out_free;
|
||
|
|
||
|
debug(ap->logopt, MODPREFIX "%s -> %s", name, mapent);
|
||
|
|