Blame SOURCES/autofs-5.0.9-amd-lookup-update-lookup-program-to-handle-amd-keys.patch

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