MINOR: spoe: add register-var-names directive in spoe-agent configuration

In addition to "option force-set-var", recently added, this directive can be
used to selectivelly register unknown variable names, without totally relaxing
their registration during the runtime, like "option force-set-var" does.

So there is no way for a malicious agent to exhaust memory by defining a too
high number of variable names. In other hand, you need to enumerate all
variable names. This could be painfull in some circumstances.

Remember, this directive is only usefull when the variable names are not
referenced anywhere in the HAProxy configuration or the SPOE one.

Thanks to Etienne Carrière for his help on this part.
diff --git a/src/flt_spoe.c b/src/flt_spoe.c
index 1b69ee2..e70cf11 100644
--- a/src/flt_spoe.c
+++ b/src/flt_spoe.c
@@ -87,6 +87,7 @@
 struct list curgrps;
 struct list curmphs;
 struct list curgphs;
+struct list curvars;
 
 /* Pools used to allocate SPOE structs */
 static struct pool_head *pool_head_spoe_ctx = NULL;
@@ -3483,6 +3484,33 @@
 			goto out;
 		}
 	}
+	else if (!strcmp(args[0], "register-var-names")) {
+		int   cur_arg;
+
+		if (!*args[1]) {
+			ha_alert("parsing [%s:%d] : '%s' expects one or more variable names.\n",
+				 file, linenum, args[0]);
+                        err_code |= ERR_ALERT | ERR_FATAL;
+                        goto out;
+                }
+		cur_arg = 1;
+		while (*args[cur_arg]) {
+			struct spoe_var_placeholder *vph;
+
+			if ((vph = calloc(1, sizeof(*vph))) == NULL) {
+				ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
+				err_code |= ERR_ALERT | ERR_ABORT;
+				goto out;
+			}
+			if ((vph->name  = strdup(args[cur_arg])) == NULL) {
+				ha_alert("parsing [%s:%d] : out of memory.\n", file, linenum);
+				err_code |= ERR_ALERT | ERR_ABORT;
+				goto out;
+			}
+			LIST_ADDQ(&curvars, &vph->list);
+			cur_arg++;
+		}
+	}
 	else if (*args[0]) {
 		ha_alert("parsing [%s:%d] : unknown keyword '%s' in spoe-agent section.\n",
 			 file, linenum, args[0]);
@@ -3779,6 +3807,7 @@
 	struct spoe_message         *msg, *msgback;
 	struct spoe_group           *grp, *grpback;
 	struct spoe_placeholder     *ph, *phback;
+	struct spoe_var_placeholder *vph, *vphback;
 	char                        *file = NULL, *engine = NULL;
 	int                          ret, pos = *cur_arg + 1;
 
@@ -3834,6 +3863,7 @@
 	LIST_INIT(&curgrps);
 	LIST_INIT(&curmphs);
 	LIST_INIT(&curgphs);
+	LIST_INIT(&curvars);
 	ret = readcfgfile(file);
 	curproxy = NULL;
 
@@ -4061,6 +4091,25 @@
 		LIST_DEL(&ph->list);
 		spoe_release_placeholder(ph);
 	}
+	list_for_each_entry_safe(vph, vphback, &curvars, list) {
+		struct arg arg;
+
+		trash.len = snprintf(trash.str, trash.size, "proc.%s.%s",
+				     curagent->var_pfx, vph->name);
+
+		arg.type = ARGT_STR;
+		arg.data.str.str = trash.str;
+		arg.data.str.len = trash.len;
+		if (!vars_check_arg(&arg, err)) {
+			memprintf(err, "SPOE agent '%s': failed to register variable %s.%s (%s)",
+				  curagent->id, curagent->var_pfx, vph->name, *err);
+			goto error;
+		}
+
+		LIST_DEL(&vph->list);
+		free(vph->name);
+		free(vph);
+	}
 	list_for_each_entry_safe(grp, grpback, &curgrps, list) {
 		LIST_DEL(&grp->list);
 		spoe_release_group(grp);
@@ -4081,6 +4130,11 @@
 		LIST_DEL(&ph->list);
 		spoe_release_placeholder(ph);
 	}
+	list_for_each_entry_safe(vph, vphback, &curvars, list) {
+		LIST_DEL(&vph->list);
+		free(vph->name);
+		free(vph);
+	}
 	list_for_each_entry_safe(grp, grpback, &curgrps, list) {
 		LIST_DEL(&grp->list);
 		spoe_release_group(grp);