autofs-5.1.7 - dont use realloc in host exports list processing

From: Ian Kent <raven@themaw.net>

If a server exports list is very large calling realloc(3) for each
export is slow. It's better to traverse the exports list twice, once
to calculate the length of the mapent then allocate the memory and
traverse the exports list again to construct the mapent.

Signed-off-by: Ian Kent <raven@themaw.net>
---
 CHANGELOG              |    1 +
 modules/lookup_hosts.c |   59 +++++++++++++++++++++---------------------------
 2 files changed, 27 insertions(+), 33 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 19af245e..1bd6ac7f 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,7 @@
 
 - add xdr_exports().
 - remove mount.x and rpcgen dependencies.
+- dont use realloc in host exports list processing.
 
 25/01/2021 autofs-5.1.7
 - make bind mounts propagation slave by default.
diff --git a/modules/lookup_hosts.c b/modules/lookup_hosts.c
index 81a4eb18..e3ee0ab8 100644
--- a/modules/lookup_hosts.c
+++ b/modules/lookup_hosts.c
@@ -89,44 +89,40 @@ static char *get_exports(struct autofs_point *ap, const char *host)
 	char buf[MAX_ERR_BUF];
 	char *mapent;
 	struct exportinfo *exp, *this;
+	size_t hostlen = strlen(host);
+	size_t mapent_len;
 
 	debug(ap->logopt, MODPREFIX "fetchng export list for %s", host);
 
 	exp = rpc_get_exports(host, 10, 0, RPC_CLOSE_NOLINGER);
 
-	mapent = NULL;
 	this = exp;
+	mapent_len = 0;
 	while (this) {
-		if (mapent) {
-			int len = strlen(mapent) + 1;
-
-			len += strlen(host) + 2*(strlen(this->dir) + 2) + 3;
-			mapent = realloc(mapent, len);
-			if (!mapent) {
-				char *estr;
-				estr = strerror_r(errno, buf, MAX_ERR_BUF);
-				error(ap->logopt, MODPREFIX "malloc: %s", estr);
-				rpc_exports_free(exp);
-				return NULL;
-			}
-			strcat(mapent, " \"");
-			strcat(mapent, this->dir);
-			strcat(mapent, "\"");
-		} else {
-			int len = 2*(strlen(this->dir) + 2) + strlen(host) + 3;
-
-			mapent = malloc(len);
-			if (!mapent) {
-				char *estr;
-				estr = strerror_r(errno, buf, MAX_ERR_BUF);
-				error(ap->logopt, MODPREFIX "malloc: %s", estr);
-				rpc_exports_free(exp);
-				return NULL;
-			}
+		mapent_len += hostlen + 2*(strlen(this->dir) + 2) + 3;
+		this = this->next;
+	}
+
+	mapent = malloc(mapent_len + 1);
+	if (!mapent) {
+		char *estr;
+		estr = strerror_r(errno, buf, MAX_ERR_BUF);
+		error(ap->logopt, MODPREFIX "malloc: %s", estr);
+		error(ap->logopt, MODPREFIX "exports lookup failed for %s", host);
+		rpc_exports_free(exp);
+		return NULL;
+	}
+	*mapent = 0;
+
+	this = exp;
+	while (this) {
+		if (!*mapent)
 			strcpy(mapent, "\"");
-			strcat(mapent, this->dir);
-			strcat(mapent, "\"");
-		}
+		else
+			strcat(mapent, " \"");
+		strcat(mapent, this->dir);
+		strcat(mapent, "\"");
+
 		strcat(mapent, " \"");
 		strcat(mapent, host);
 		strcat(mapent, ":");
@@ -137,9 +133,6 @@ static char *get_exports(struct autofs_point *ap, const char *host)
 	}
 	rpc_exports_free(exp);
 
-	if (!mapent)
-		error(ap->logopt, MODPREFIX "exports lookup failed for %s", host);
-
 	return mapent;
 }
 
