]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: arg: Be able to forbid unresolved args when building an argument list
authorChristopher Faulet <cfaulet@haproxy.com>
Thu, 30 Sep 2021 06:48:56 +0000 (08:48 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Thu, 30 Sep 2021 14:37:05 +0000 (16:37 +0200)
In make_arg_list() function, unresolved dependencies are pushed in an
argument list to be resolved later, during the configuration validity
check. It is now possible to forbid such unresolved dependencies by omitting
<al> parameter (setting it to NULL). It is usefull when the parsing context
is not the same than the running context or when the parsing context is lost
after the startup stage. For instance, an argument may be defined in
defaults section during parsing and executed in a frontend/backend section.

src/acl.c
src/arg.c
src/sample.c

index b2b0f0c1cf60e8869187e6f0a5c7e3fe89b20b43..6d11a0b35e17a3a70444d86ed7ccf0d08fe4b11b 100644 (file)
--- a/src/acl.c
+++ b/src/acl.c
@@ -121,7 +121,8 @@ static struct acl_expr *prune_acl_expr(struct acl_expr *expr)
 /* Parse an ACL expression starting at <args>[0], and return it. If <err> is
  * not NULL, it will be filled with a pointer to an error message in case of
  * error. This pointer must be freeable or NULL. <al> is an arg_list serving
- * as a list head to report missing dependencies.
+ * as a list head to report missing dependencies. It may be NULL if such
+ * dependencies are not allowed.
  *
  * Right now, the only accepted syntax is :
  * <subject> [<value>...]
@@ -162,9 +163,11 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
         * keyword.
         */
 
-       al->ctx  = ARGC_ACL;   // to report errors while resolving args late
-       al->kw   = *args;
-       al->conv = NULL;
+       if (al) {
+               al->ctx  = ARGC_ACL;   // to report errors while resolving args late
+               al->kw   = *args;
+               al->conv = NULL;
+       }
 
        aclkw = find_acl_kw(args[0]);
        if (aclkw) {
@@ -280,8 +283,10 @@ struct acl_expr *parse_acl_expr(const char **args, char **err, struct arg_list *
                        conv_expr->conv = conv;
                        acl_conv_found = 1;
 
-                       al->kw = smp->fetch->kw;
-                       al->conv = conv_expr->conv->kw;
+                       if (al) {
+                               al->kw = smp->fetch->kw;
+                               al->conv = conv_expr->conv->kw;
+                       }
                        argcnt = make_arg_list(endw, -1, conv->arg_mask, &conv_expr->arg_p, err, &arg, &err_arg, al);
                        if (argcnt < 0) {
                                memprintf(err, "ACL keyword '%s' : invalid arg %d in converter '%s' : %s.",
@@ -665,7 +670,7 @@ struct acl *prune_acl(struct acl *acl) {
  * an anonymous one and it won't be merged with any other one. If <err> is not
  * NULL, it will be filled with an appropriate error. This pointer must be
  * freeable or NULL. <al> is the arg_list serving as a head for unresolved
- * dependencies.
+ * dependencies. It may be NULL if such dependencies are not allowed.
  *
  * args syntax: <aclname> <acl_expr>
  */
@@ -778,7 +783,8 @@ const struct {
  * If <known_acl> is not NULL, the ACL will be queued at its tail. If <err> is
  * not NULL, it will be filled with an error message if an error occurs. This
  * pointer must be freeable or NULL. <al> is an arg_list serving as a list head
- * to report missing dependencies.
+ * to report missing dependencies. It may be NULL if such dependencies are not
+ * allowed.
  */
 static struct acl *find_acl_default(const char *acl_name, struct list *known_acl,
                                     char **err, struct arg_list *al,
@@ -858,7 +864,8 @@ struct acl_cond *prune_acl_cond(struct acl_cond *cond)
  * <err> is not NULL, it will be filled with a pointer to an error message in
  * case of error, that the caller is responsible for freeing. The initial
  * location must either be freeable or NULL. The list <al> serves as a list head
- * for unresolved dependencies.
+ * for unresolved dependencies. It may be NULL if such dependencies are not
+ * allowed.
  */
 struct acl_cond *parse_acl_cond(const char **args, struct list *known_acl,
                                 enum acl_cond_pol pol, char **err, struct arg_list *al,
index 140fbeff9c3b1e7027b2c26db29af403243e8753..039602a494b09d2dfb435f214917866d9d64ee2e 100644 (file)
--- a/src/arg.c
+++ b/src/arg.c
@@ -97,14 +97,15 @@ struct arg_list *arg_list_add(struct arg_list *orig, struct arg *arg, int pos)
  * The returned array is always terminated by an arg of type ARGT_STOP (0),
  * unless the mask indicates that no argument is supported. Unresolved arguments
  * are appended to arg list <al>, which also serves as a template to create new
- * entries. The mask is composed of a number of mandatory arguments in its lower
- * ARGM_BITS bits, and a concatenation of each argument type in each subsequent
- * ARGT_BITS-bit sblock. If <err_msg> is not NULL, it must point to a freeable
- * or NULL pointer. The caller is expected to restart the parsing from the new
- * pointer set in <end_ptr>, which is the first character considered as not
- * being part of the arg list. The input string ends on the first between <len>
- * characters (when len is positive) or the first NUL character. Placing -1 in
- * <len> will make it virtually unbounded (~2GB long strings).
+ * entries. <al> may be NULL if unresolved arguments are not allowed. The mask
+ * is composed of a number of mandatory arguments in its lower ARGM_BITS bits,
+ * and a concatenation of each argument type in each subsequent ARGT_BITS-bit
+ * sblock. If <err_msg> is not NULL, it must point to a freeable or NULL
+ * pointer. The caller is expected to restart the parsing from the new pointer
+ * set in <end_ptr>, which is the first character considered as not being part
+ * of the arg list. The input string ends on the first between <len> characters
+ * (when len is positive) or the first NUL character. Placing -1 in <len> will
+ * make it virtually unbounded (~2GB long strings).
  */
 int make_arg_list(const char *in, int len, uint64_t mask, struct arg **argp,
                   char **err_msg, const char **end_ptr, int *err_arg,
@@ -245,6 +246,8 @@ int make_arg_list(const char *in, int len, uint64_t mask, struct arg **argp,
                        /* These argument types need to be stored as strings during
                         * parsing then resolved later.
                         */
+                       if (!al)
+                               goto resolve_err;
                        arg->unresolved = 1;
                        new_al = arg_list_add(al, arg, pos);
 
@@ -447,6 +450,11 @@ int make_arg_list(const char *in, int len, uint64_t mask, struct arg **argp,
 alloc_err:
        memprintf(err_msg, "out of memory");
        goto err;
+
+ resolve_err:
+       memprintf(err_msg, "unresolved argument of type '%s' at position %d not allowed",
+                 arg_type_names[(mask >> (pos * ARGT_BITS)) & ARGT_MASK], pos + 1);
+       goto err;
 }
 
 /* Free all args of an args array, taking care of unresolved arguments as well.
index ab37a9674b15663630016f06430c4ac4a9d33bc4..ed95545c8e840582be5f272966d0dbd0f279b2b6 100644 (file)
@@ -861,7 +861,9 @@ sample_cast_fct sample_casts[SMP_TYPES][SMP_TYPES] = {
  * Parse a sample expression configuration:
  *        fetch keyword followed by format conversion keywords.
  * Returns a pointer on allocated sample expression structure.
- * The caller must have set al->ctx.
+ * <al> is an arg_list serving as a list head to report missing dependencies.
+ * It may be NULL if such dependencies are not allowed. Otherwise, the caller
+ * must have set al->ctx if al is set.
  * If <endptr> is non-nul, it will be set to the first unparsed character
  * (which may be the final '\0') on success. If it is nul, the expression
  * must be properly terminated by a '\0' otherwise an error is reported.
@@ -920,8 +922,10 @@ struct sample_expr *sample_parse_expr(char **str, int *idx, const char *file, in
         * this allows it to automatically create entries for mandatory
         * implicit arguments (eg: local proxy name).
         */
-       al->kw = expr->fetch->kw;
-       al->conv = NULL;
+       if (al) {
+               al->kw = expr->fetch->kw;
+               al->conv = NULL;
+       }
        if (make_arg_list(endw, -1, fetch->arg_mask, &expr->arg_p, err_msg, &endt, &err_arg, al) < 0) {
                memprintf(err_msg, "fetch method '%s' : %s", fkw, *err_msg);
                goto out_error;
@@ -1021,8 +1025,10 @@ struct sample_expr *sample_parse_expr(char **str, int *idx, const char *file, in
                LIST_APPEND(&(expr->conv_exprs), &(conv_expr->list));
                conv_expr->conv = conv;
 
-               al->kw = expr->fetch->kw;
-               al->conv = conv_expr->conv->kw;
+               if (al) {
+                       al->kw = expr->fetch->kw;
+                       al->conv = conv_expr->conv->kw;
+               }
                argcnt = make_arg_list(endw, -1, conv->arg_mask, &conv_expr->arg_p, err_msg, &endt, &err_arg, al);
                if (argcnt < 0) {
                        memprintf(err_msg, "invalid arg %d in converter '%s' : %s", err_arg+1, ckw, *err_msg);