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);