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.
462 lines
12 KiB
462 lines
12 KiB
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); |
|
|
|
|