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

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